browsercms 3.1.5 → 3.3.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (425) hide show
  1. data/app/controllers/cms/base_controller.rb +3 -3
  2. data/app/controllers/cms/content_block_controller.rb +2 -2
  3. data/app/controllers/cms/content_controller.rb +5 -4
  4. data/app/controllers/cms/error_handling.rb +1 -1
  5. data/app/controllers/cms/routes_controller.rb +4 -5
  6. data/app/controllers/cms/section_nodes_controller.rb +1 -6
  7. data/app/controllers/cms/sections_controller.rb +2 -3
  8. data/app/controllers/cms/tasks_controller.rb +3 -0
  9. data/app/controllers/cms/users_controller.rb +1 -1
  10. data/app/helpers/cms/application_helper.rb +137 -34
  11. data/app/helpers/cms/form_builder.rb +33 -21
  12. data/app/helpers/cms/page_helper.rb +43 -10
  13. data/app/helpers/cms/path_helper.rb +1 -1
  14. data/app/helpers/cms/rendering_helper.rb +3 -4
  15. data/app/helpers/cms/section_nodes_helper.rb +5 -43
  16. data/app/models/abstract_file_block.rb +1 -16
  17. data/app/models/attachment.rb +57 -22
  18. data/app/models/category.rb +4 -4
  19. data/app/models/category_type.rb +2 -2
  20. data/app/models/cms/view_context.rb +46 -0
  21. data/app/models/connector.rb +7 -6
  22. data/app/models/content_type.rb +3 -3
  23. data/app/models/dynamic_view.rb +1 -1
  24. data/app/models/email_message.rb +2 -2
  25. data/app/models/file_block.rb +12 -0
  26. data/app/models/group.rb +4 -4
  27. data/app/models/group_type.rb +4 -4
  28. data/app/models/html_block.rb +1 -1
  29. data/app/models/image_block.rb +12 -0
  30. data/app/models/link.rb +22 -5
  31. data/app/models/page.rb +87 -46
  32. data/app/models/page_route.rb +61 -6
  33. data/app/models/permission.rb +1 -1
  34. data/app/models/portlet.rb +14 -4
  35. data/app/models/section.rb +48 -86
  36. data/app/models/section_node.rb +25 -40
  37. data/app/models/site.rb +1 -1
  38. data/app/models/tag.rb +1 -1
  39. data/app/models/task.rb +8 -7
  40. data/app/models/user.rb +2 -7
  41. data/app/portlets/forgot_password_portlet.rb +6 -2
  42. data/app/portlets/reset_password_portlet.rb +1 -1
  43. data/app/views/cms/blocks/_toolbar.html.erb +1 -1
  44. data/app/views/cms/blocks/_toolbar_for_collection.html.erb +3 -6
  45. data/app/views/cms/blocks/_toolbar_for_member.html.erb +3 -5
  46. data/app/views/cms/blocks/edit.html.erb +4 -4
  47. data/app/views/cms/blocks/index.html.erb +7 -7
  48. data/app/views/cms/blocks/new.html.erb +4 -4
  49. data/app/views/cms/blocks/show.html.erb +2 -2
  50. data/app/views/cms/blocks/usages.html.erb +2 -2
  51. data/app/views/cms/blocks/versions.html.erb +4 -4
  52. data/app/views/cms/cache/show.html.erb +2 -2
  53. data/app/views/cms/categories/_form.html.erb +2 -2
  54. data/app/views/cms/connectors/new.html.erb +6 -8
  55. data/app/views/cms/content/no_page.html.erb +1 -1
  56. data/app/views/cms/content/show.html.erb +2 -7
  57. data/app/views/cms/dashboard/_page_drafts.html.erb +1 -1
  58. data/app/views/cms/dashboard/_tasks.html.erb +1 -1
  59. data/app/views/cms/dashboard/index.html.erb +1 -1
  60. data/app/views/cms/dynamic_views/_form.html.erb +2 -2
  61. data/app/views/cms/dynamic_views/index.html.erb +7 -10
  62. data/app/views/cms/email_messages/show.html.erb +2 -2
  63. data/app/views/cms/file_blocks/_form.html.erb +4 -4
  64. data/app/views/cms/form_builder/_cms_fancy_drop_down.html.erb +2 -2
  65. data/app/views/cms/form_builder/_cms_file_field.html.erb +2 -2
  66. data/app/views/cms/form_builder/_cms_tag_list.html.erb +2 -2
  67. data/app/views/cms/form_builder/_cms_text_editor.html.erb +2 -2
  68. data/app/views/cms/groups/_form.html.erb +5 -5
  69. data/app/views/cms/groups/_permissions.html.erb +4 -4
  70. data/app/views/cms/groups/_sections.html.erb +1 -2
  71. data/app/views/cms/groups/index.html.erb +1 -1
  72. data/app/views/cms/html_blocks/render.html.erb +1 -1
  73. data/app/views/cms/image_blocks/_form.html.erb +4 -5
  74. data/app/views/cms/links/_form.html.erb +1 -1
  75. data/app/views/cms/links/edit.html.erb +2 -2
  76. data/app/views/cms/links/new.html.erb +2 -2
  77. data/app/views/cms/page_routes/_form.html.erb +2 -2
  78. data/app/views/cms/page_routes/index.html.erb +6 -9
  79. data/app/views/cms/page_routes/show.html.erb +5 -8
  80. data/app/views/cms/pages/_edit_connector.html.erb +1 -1
  81. data/app/views/cms/pages/_form.html.erb +3 -3
  82. data/app/views/cms/pages/edit.html.erb +2 -2
  83. data/app/views/cms/pages/new.html.erb +7 -7
  84. data/app/views/cms/pages/versions.html.erb +4 -4
  85. data/app/views/cms/redirects/_form.html.erb +2 -2
  86. data/app/views/cms/redirects/index.html.erb +8 -7
  87. data/app/views/cms/routes/index.html.erb +2 -2
  88. data/app/views/cms/section_nodes/_link.html.erb +3 -6
  89. data/app/views/cms/section_nodes/_node.html.erb +4 -13
  90. data/app/views/cms/section_nodes/_page.html.erb +7 -13
  91. data/app/views/cms/section_nodes/_section.html.erb +8 -24
  92. data/app/views/cms/section_nodes/_section_node.html.erb +10 -0
  93. data/app/views/cms/section_nodes/index.html.erb +18 -30
  94. data/app/views/cms/sections/_form.html.erb +4 -6
  95. data/app/views/cms/sections/edit.html.erb +2 -2
  96. data/app/views/cms/sections/index.html.erb +3 -3
  97. data/app/views/cms/sections/new.html.erb +3 -3
  98. data/app/views/cms/sessions/new.html.erb +3 -3
  99. data/app/views/cms/shared/_pagination.html.erb +1 -1
  100. data/app/views/cms/shared/error.html.erb +1 -1
  101. data/app/views/cms/tags/render.html.erb +2 -2
  102. data/app/views/cms/tasks/new.html.erb +4 -4
  103. data/app/views/cms/users/_form.html.erb +3 -3
  104. data/app/views/cms/users/_toolbar.html.erb +3 -3
  105. data/app/views/cms/users/change_password.html.erb +5 -5
  106. data/app/views/cms/users/edit.html.erb +2 -2
  107. data/app/views/cms/users/index.html.erb +4 -4
  108. data/app/views/cms/users/new.html.erb +2 -2
  109. data/app/views/cms/users/show.html.erb +16 -16
  110. data/app/views/layouts/_cms_toolbar.html.erb +5 -5
  111. data/app/views/layouts/_page_toolbar.html.erb +11 -11
  112. data/app/views/layouts/cms/_footer.erb +1 -1
  113. data/app/views/layouts/cms/_head.html.erb +2 -6
  114. data/app/views/layouts/cms/administration.html.erb +32 -32
  115. data/app/views/layouts/cms/content_library.html.erb +5 -5
  116. data/app/views/layouts/cms/toolbar.html.erb +1 -1
  117. data/app/views/portlets/email_page/render.html.erb +2 -2
  118. data/app/views/portlets/forgot_password/render.html.erb +1 -1
  119. data/app/views/portlets/login/render.html.erb +4 -2
  120. data/app/views/portlets/reset_password/render.html.erb +1 -1
  121. data/app/views/tests/pretend/open_with_layout.html.erb +1 -1
  122. data/bin/bcms +0 -0
  123. data/bin/bcms-upgrade +232 -0
  124. data/bin/browsercms +2 -2
  125. data/browsercms.gemspec +16 -14
  126. data/db/migrate/20100705083859_browsercms_3_3_0.rb +56 -0
  127. data/db/seeds.rb +58 -0
  128. data/doc/guides/html/authentication.html +448 -192
  129. data/doc/guides/html/build_it_yourself.html +454 -175
  130. data/doc/guides/html/building_modules.html +451 -220
  131. data/doc/guides/html/building_templates.html +448 -498
  132. data/doc/guides/html/content_blocks.html +450 -470
  133. data/doc/guides/html/customizing_browsercms.html +453 -169
  134. data/doc/guides/html/deployment_guide.html +443 -82
  135. data/doc/guides/html/files/bcmsorg.js +28 -0
  136. data/doc/guides/html/files/clearfix.css +8 -0
  137. data/doc/guides/html/files/cufon.js +7 -0
  138. data/doc/guides/html/files/global.css +190 -0
  139. data/doc/guides/html/files/helvetica.js +91 -0
  140. data/doc/guides/html/files/jquery.js +11 -0
  141. data/doc/guides/html/getting_started.html +454 -213
  142. data/doc/guides/html/index.html +454 -174
  143. data/doc/guides/html/installing_modules.html +454 -186
  144. data/doc/guides/html/portlets.html +451 -232
  145. data/doc/guides/html/user_guide.html +452 -270
  146. data/doc/guides/html/writing_guides.html +454 -161
  147. data/lib/acts_as_list.rb +1 -1
  148. data/lib/browsercms.rb +10 -6
  149. data/lib/cms/acts.rb +7 -0
  150. data/lib/cms/authentication.rb +4 -0
  151. data/lib/cms/authentication/controller.rb +1 -1
  152. data/lib/cms/behaviors.rb +1 -1
  153. data/lib/cms/behaviors/archiving.rb +2 -2
  154. data/lib/cms/behaviors/attaching.rb +28 -43
  155. data/lib/cms/behaviors/categorizing.rb +1 -1
  156. data/lib/cms/behaviors/connecting.rb +27 -12
  157. data/lib/cms/behaviors/dynamic_attributes.rb +8 -5
  158. data/lib/cms/behaviors/hiding.rb +2 -2
  159. data/lib/cms/behaviors/publishing.rb +32 -22
  160. data/lib/cms/behaviors/rendering.rb +41 -18
  161. data/lib/cms/behaviors/searching.rb +1 -1
  162. data/lib/cms/behaviors/soft_deleting.rb +58 -29
  163. data/lib/cms/behaviors/taggable.rb +1 -1
  164. data/lib/cms/behaviors/userstamping.rb +5 -4
  165. data/lib/cms/behaviors/versioning.rb +192 -111
  166. data/lib/cms/content_rendering_support.rb +3 -3
  167. data/lib/cms/date_picker.rb +23 -0
  168. data/lib/cms/engine.rb +46 -0
  169. data/lib/cms/extensions.rb +1 -1
  170. data/lib/cms/extensions/active_record/errors.rb +2 -2
  171. data/lib/cms/extensions/hash.rb +4 -2
  172. data/lib/cms/extensions/string.rb +7 -2
  173. data/lib/cms/init.rb +32 -21
  174. data/lib/cms/module.rb +22 -0
  175. data/lib/cms/module_installation.rb +38 -0
  176. data/lib/cms/routes.rb +127 -115
  177. data/lib/cms/version.rb +2 -2
  178. data/lib/generators/browser_cms.rb +12 -0
  179. data/lib/generators/browser_cms/cms/USAGE +2 -0
  180. data/lib/generators/browser_cms/cms/cms_generator.rb +36 -0
  181. data/{rails_generators/browser_cms → lib/generators/browser_cms/cms}/templates/README +0 -0
  182. data/{rails_generators/browser_cms_demo_site → lib/generators/browser_cms/demo_site}/USAGE +0 -0
  183. data/lib/generators/browser_cms/demo_site/demo_site_generator.rb +138 -0
  184. data/lib/generators/browser_cms/demo_site/templates/demo_site.rake +11 -0
  185. data/{rails_generators/browser_cms_demo_site/templates/migration.rb → lib/generators/browser_cms/demo_site/templates/migration.erb} +2 -8
  186. data/lib/generators/cms/content_block/USAGE +22 -0
  187. data/lib/generators/cms/content_block/content_block_generator.rb +55 -0
  188. data/{rails_generators → lib/generators/cms}/content_block/templates/_form.html.erb +0 -0
  189. data/{rails_generators → lib/generators/cms}/content_block/templates/content_block.rb +0 -0
  190. data/{rails_generators → lib/generators/cms}/content_block/templates/controller.rb +0 -0
  191. data/{rails_generators → lib/generators/cms}/content_block/templates/functional_test.erb +0 -0
  192. data/{rails_generators/content_block/templates/migration.rb → lib/generators/cms/content_block/templates/migration.erb} +1 -1
  193. data/{rails_generators → lib/generators/cms}/content_block/templates/render.html.erb +0 -0
  194. data/{rails_generators → lib/generators/cms}/content_block/templates/unit_test.erb +0 -0
  195. data/lib/generators/cms/install/USAGE +8 -0
  196. data/lib/generators/cms/install/install_generator.rb +20 -0
  197. data/{rails_generators → lib/generators/cms}/portlet/USAGE +3 -16
  198. data/lib/generators/cms/portlet/portlet_generator.rb +38 -0
  199. data/{rails_generators → lib/generators/cms}/portlet/templates/_form.html.erb +0 -0
  200. data/{rails_generators → lib/generators/cms}/portlet/templates/portlet.rb +0 -0
  201. data/{rails_generators → lib/generators/cms}/portlet/templates/portlet_helper.rb +0 -0
  202. data/{rails_generators → lib/generators/cms}/portlet/templates/render.html.erb +0 -0
  203. data/{rails_generators → lib/generators/cms}/portlet/templates/unit_test.erb +0 -0
  204. data/{rails_generators → lib/generators/cms}/template/USAGE +1 -1
  205. data/lib/generators/cms/template/template_generator.rb +18 -0
  206. data/lib/generators/cms/template/templates/template.erb +2 -0
  207. data/lib/generators/cms/upgrade_module/README.txt +3 -0
  208. data/lib/generators/cms/upgrade_module/templates/20100705083859_browsercms_3_3_0.rb +56 -0
  209. data/lib/generators/cms/upgrade_module/templates/README +1 -0
  210. data/lib/generators/cms/upgrade_module/templates/USAGE.erb +10 -0
  211. data/lib/generators/cms/upgrade_module/templates/build_gem.rake +5 -0
  212. data/lib/generators/cms/upgrade_module/templates/engine.erb +7 -0
  213. data/lib/generators/cms/upgrade_module/templates/gemspec.erb +25 -0
  214. data/lib/generators/cms/upgrade_module/templates/gitignore.erb +11 -0
  215. data/lib/generators/cms/upgrade_module/templates/install.erb +9 -0
  216. data/lib/generators/cms/upgrade_module/templates/module_file.erb +3 -0
  217. data/lib/generators/cms/upgrade_module/templates/routes.erb +7 -0
  218. data/lib/generators/cms/upgrade_module/upgrade_module_generator.rb +61 -0
  219. data/lib/tasks/build_gem.rake +1 -0
  220. data/lib/tasks/cms.rake +34 -6
  221. data/lib/tasks/cucumber.rake +53 -0
  222. data/lib/tasks/db.rake +2 -2
  223. data/public/javascripts/cms/application.js +144 -135
  224. data/public/javascripts/cms/sitemap.js +383 -357
  225. data/public/javascripts/jquery-ui.js +782 -591
  226. data/public/javascripts/jquery.cookie.js +38 -43
  227. data/public/javascripts/jquery.js +13 -8
  228. data/public/javascripts/jquery.taglist.js +7 -0
  229. data/public/stylesheets/cms/date_picker.css +49 -40
  230. data/rails/init.rb +2 -3
  231. data/templates/blank.rb +13 -7
  232. data/templates/demo.rb +15 -7
  233. data/templates/module.rb +12 -75
  234. metadata +87 -407
  235. data/app/helpers/cms/content_block_helper.rb +0 -27
  236. data/app/views/layouts/cms/thickbox.html.erb +0 -24
  237. data/db/migrate/20120117144039_browsercms315.rb +0 -94
  238. data/db/migrate/20121114172307_load_seeds.rb +0 -70
  239. data/lib/cms/addressable.rb +0 -83
  240. data/lib/cms/error_pages.rb +0 -8
  241. data/public/images/cms/thickbox/loadingAnimation.gif +0 -0
  242. data/public/images/cms/thickbox/macFFBgHack.png +0 -0
  243. data/public/javascripts/jquery.contextMenu.js +0 -211
  244. data/public/javascripts/jquery.dimensions.js +0 -119
  245. data/public/javascripts/jquery.thickbox.js +0 -10
  246. data/public/stylesheets/cms/jquery.contextMenu.css +0 -61
  247. data/public/stylesheets/cms/thickbox.css +0 -163
  248. data/rails_generators/browser_cms/USAGE +0 -2
  249. data/rails_generators/browser_cms/browser_cms_generator.rb +0 -35
  250. data/rails_generators/browser_cms_demo_site/browser_cms_demo_site_generator.rb +0 -63
  251. data/rails_generators/content_block/USAGE +0 -32
  252. data/rails_generators/content_block/content_block_generator.rb +0 -69
  253. data/rails_generators/portlet/portlet_generator.rb +0 -35
  254. data/rails_generators/template/template_generator.rb +0 -18
  255. data/rails_generators/template/templates/template.erb +0 -3
  256. data/test/custom_assertions.rb +0 -74
  257. data/test/factories.rb +0 -111
  258. data/test/factories/sitemap_factories.rb +0 -28
  259. data/test/fixtures/connectors.yml +0 -97
  260. data/test/fixtures/content_type_groups.yml +0 -13
  261. data/test/fixtures/content_types.yml +0 -50
  262. data/test/fixtures/dynamic_view_versions.yml +0 -26
  263. data/test/fixtures/dynamic_views.yml +0 -26
  264. data/test/fixtures/group_permissions.yml +0 -16
  265. data/test/fixtures/group_sections.yml +0 -31
  266. data/test/fixtures/group_type_permissions.yml +0 -11
  267. data/test/fixtures/group_types.yml +0 -25
  268. data/test/fixtures/groups.yml +0 -25
  269. data/test/fixtures/html_block_versions.yml +0 -67
  270. data/test/fixtures/html_blocks.yml +0 -63
  271. data/test/fixtures/page_versions.yml +0 -265
  272. data/test/fixtures/pages.yml +0 -85
  273. data/test/fixtures/permissions.yml +0 -28
  274. data/test/fixtures/section_nodes.yml +0 -46
  275. data/test/fixtures/sections.yml +0 -19
  276. data/test/fixtures/sites.yml +0 -9
  277. data/test/fixtures/user_group_memberships.yml +0 -11
  278. data/test/fixtures/users.yml +0 -15
  279. data/test/functional/cms/cache_controller_test.rb +0 -14
  280. data/test/functional/cms/categories_controller_test.rb +0 -25
  281. data/test/functional/cms/connectors_controller_test.rb +0 -60
  282. data/test/functional/cms/content_block_controller_test.rb +0 -120
  283. data/test/functional/cms/content_controller_test.rb +0 -439
  284. data/test/functional/cms/content_types_controller_test.rb +0 -18
  285. data/test/functional/cms/dashboard_controller_test.rb +0 -16
  286. data/test/functional/cms/dynamic_views_controller_test.rb +0 -52
  287. data/test/functional/cms/file_blocks_controller_test.rb +0 -52
  288. data/test/functional/cms/groups_controller_test.rb +0 -50
  289. data/test/functional/cms/home_controller_test.rb +0 -156
  290. data/test/functional/cms/html_blocks_controller_test.rb +0 -164
  291. data/test/functional/cms/image_blocks_controller_test.rb +0 -82
  292. data/test/functional/cms/links_controller_test.rb +0 -148
  293. data/test/functional/cms/pages_controller_test.rb +0 -227
  294. data/test/functional/cms/portlets_controller_test.rb +0 -67
  295. data/test/functional/cms/section_nodes_controller_test.rb +0 -112
  296. data/test/functional/cms/sections_controller_test.rb +0 -227
  297. data/test/functional/cms/sessions_controller_test.rb +0 -76
  298. data/test/functional/cms/toolbar_controller_test.rb +0 -64
  299. data/test/functional/cms/users_controller_test.rb +0 -231
  300. data/test/functional/tests/pretend_controller_test.rb +0 -57
  301. data/test/integration/cms/ckeditor_test.rb +0 -30
  302. data/test/integration/cms/password_management_test.rb +0 -56
  303. data/test/integration/login_test.rb +0 -14
  304. data/test/integration/sitemap_performance_test.rb +0 -26
  305. data/test/selenium-core/Blank.html +0 -7
  306. data/test/selenium-core/InjectedRemoteRunner.html +0 -8
  307. data/test/selenium-core/RemoteRunner.html +0 -110
  308. data/test/selenium-core/SeleniumLog.html +0 -109
  309. data/test/selenium-core/TestPrompt.html +0 -145
  310. data/test/selenium-core/TestRunner-splash.html +0 -55
  311. data/test/selenium-core/TestRunner.hta +0 -176
  312. data/test/selenium-core/TestRunner.html +0 -176
  313. data/test/selenium-core/domviewer/butmin.gif +0 -0
  314. data/test/selenium-core/domviewer/butplus.gif +0 -0
  315. data/test/selenium-core/domviewer/domviewer.css +0 -298
  316. data/test/selenium-core/domviewer/domviewer.html +0 -16
  317. data/test/selenium-core/domviewer/selenium-domviewer.js +0 -205
  318. data/test/selenium-core/icons/all.png +0 -0
  319. data/test/selenium-core/icons/continue.png +0 -0
  320. data/test/selenium-core/icons/continue_disabled.png +0 -0
  321. data/test/selenium-core/icons/pause.png +0 -0
  322. data/test/selenium-core/icons/pause_disabled.png +0 -0
  323. data/test/selenium-core/icons/selected.png +0 -0
  324. data/test/selenium-core/icons/step.png +0 -0
  325. data/test/selenium-core/icons/step_disabled.png +0 -0
  326. data/test/selenium-core/iedoc-core.xml +0 -1515
  327. data/test/selenium-core/iedoc.xml +0 -1469
  328. data/test/selenium-core/lib/cssQuery/cssQuery-p.js +0 -6
  329. data/test/selenium-core/lib/cssQuery/src/cssQuery-level2.js +0 -142
  330. data/test/selenium-core/lib/cssQuery/src/cssQuery-level3.js +0 -150
  331. data/test/selenium-core/lib/cssQuery/src/cssQuery-standard.js +0 -53
  332. data/test/selenium-core/lib/cssQuery/src/cssQuery.js +0 -356
  333. data/test/selenium-core/lib/prototype.js +0 -2006
  334. data/test/selenium-core/lib/scriptaculous/builder.js +0 -101
  335. data/test/selenium-core/lib/scriptaculous/controls.js +0 -815
  336. data/test/selenium-core/lib/scriptaculous/dragdrop.js +0 -915
  337. data/test/selenium-core/lib/scriptaculous/effects.js +0 -958
  338. data/test/selenium-core/lib/scriptaculous/scriptaculous.js +0 -47
  339. data/test/selenium-core/lib/scriptaculous/slider.js +0 -283
  340. data/test/selenium-core/lib/scriptaculous/unittest.js +0 -383
  341. data/test/selenium-core/scripts/find_matching_child.js +0 -69
  342. data/test/selenium-core/scripts/htmlutils.js +0 -894
  343. data/test/selenium-core/scripts/injection.html +0 -72
  344. data/test/selenium-core/scripts/js2html.js +0 -70
  345. data/test/selenium-core/scripts/narcissus-defs.js +0 -175
  346. data/test/selenium-core/scripts/narcissus-exec.js +0 -1054
  347. data/test/selenium-core/scripts/narcissus-parse.js +0 -1003
  348. data/test/selenium-core/scripts/se2html.js +0 -63
  349. data/test/selenium-core/scripts/selenium-api.js +0 -2409
  350. data/test/selenium-core/scripts/selenium-browserbot.js +0 -2203
  351. data/test/selenium-core/scripts/selenium-browserdetect.js +0 -150
  352. data/test/selenium-core/scripts/selenium-commandhandlers.js +0 -377
  353. data/test/selenium-core/scripts/selenium-executionloop.js +0 -175
  354. data/test/selenium-core/scripts/selenium-logging.js +0 -147
  355. data/test/selenium-core/scripts/selenium-remoterunner.js +0 -571
  356. data/test/selenium-core/scripts/selenium-testrunner.js +0 -1333
  357. data/test/selenium-core/scripts/selenium-version.js +0 -5
  358. data/test/selenium-core/scripts/user-extensions.js +0 -3
  359. data/test/selenium-core/scripts/user-extensions.js.sample +0 -75
  360. data/test/selenium-core/scripts/xmlextras.js +0 -153
  361. data/test/selenium-core/selenium-logo.png +0 -0
  362. data/test/selenium-core/selenium-test.css +0 -43
  363. data/test/selenium-core/selenium.css +0 -299
  364. data/test/selenium-core/xpath/dom.js +0 -428
  365. data/test/selenium-core/xpath/misc.js +0 -252
  366. data/test/selenium-core/xpath/xpath.js +0 -2223
  367. data/test/selenium/_login_as_cmsadmin.rsel +0 -4
  368. data/test/selenium/dashboard.rsel +0 -5
  369. data/test/selenium/html_blocks.rsel +0 -4
  370. data/test/selenium/login/failed_login.rsel +0 -8
  371. data/test/selenium/login/successful_login.rsel +0 -9
  372. data/test/selenium/page_templates.rsel +0 -12
  373. data/test/selenium/pages/edit_properties.rsel +0 -5
  374. data/test/selenium/site/view_home_page.rsel +0 -4
  375. data/test/selenium/sitemap/move_page.rsel +0 -9
  376. data/test/selenium/sitemap/open_section.rsel +0 -6
  377. data/test/selenium/sitemap/select_page.rsel +0 -12
  378. data/test/selenium/sitemap/select_section.rsel +0 -17
  379. data/test/test_helper.rb +0 -193
  380. data/test/test_logging.rb +0 -67
  381. data/test/unit/behaviors/attaching_test.rb +0 -357
  382. data/test/unit/behaviors/connectable_test.rb +0 -29
  383. data/test/unit/behaviors/dynamic_attributes_test.rb +0 -38
  384. data/test/unit/behaviors/publishable_test.rb +0 -84
  385. data/test/unit/behaviors/searching_test.rb +0 -102
  386. data/test/unit/behaviors/taggable_test.rb +0 -109
  387. data/test/unit/behaviors/versioning_test.rb +0 -36
  388. data/test/unit/extensions/active_record/base_test.rb +0 -10
  389. data/test/unit/extensions/hash_test.rb +0 -17
  390. data/test/unit/extensions/integer_test.rb +0 -10
  391. data/test/unit/helpers/application_helper_test.rb +0 -77
  392. data/test/unit/helpers/form_builder_test.rb +0 -36
  393. data/test/unit/helpers/menu_helper_test.rb +0 -242
  394. data/test/unit/helpers/page_helper_test.rb +0 -67
  395. data/test/unit/helpers/path_helper_test.rb +0 -57
  396. data/test/unit/lib/acts_as_content_page_test.rb +0 -72
  397. data/test/unit/lib/cms/authentication/controller_test.rb +0 -20
  398. data/test/unit/lib/cms/sitemap_test.rb +0 -206
  399. data/test/unit/lib/cms_domain_support_test.rb +0 -43
  400. data/test/unit/lib/command_line_test.rb +0 -70
  401. data/test/unit/lib/content_block_test.rb +0 -203
  402. data/test/unit/lib/content_rendering_support_test.rb +0 -40
  403. data/test/unit/lib/generators_test.rb +0 -40
  404. data/test/unit/lib/routes_test.rb +0 -57
  405. data/test/unit/models/attachment_test.rb +0 -116
  406. data/test/unit/models/category_test.rb +0 -40
  407. data/test/unit/models/category_type_test.rb +0 -8
  408. data/test/unit/models/connector_test.rb +0 -152
  409. data/test/unit/models/content_type_test.rb +0 -56
  410. data/test/unit/models/email_page_portlet_test.rb +0 -14
  411. data/test/unit/models/file_block_test.rb +0 -230
  412. data/test/unit/models/group_test.rb +0 -13
  413. data/test/unit/models/html_block_test.rb +0 -102
  414. data/test/unit/models/link_test.rb +0 -52
  415. data/test/unit/models/page_partial_test.rb +0 -29
  416. data/test/unit/models/page_route_test.rb +0 -29
  417. data/test/unit/models/page_template_test.rb +0 -40
  418. data/test/unit/models/page_test.rb +0 -792
  419. data/test/unit/models/permission_test.rb +0 -10
  420. data/test/unit/models/portlet_test.rb +0 -69
  421. data/test/unit/models/sections_test.rb +0 -264
  422. data/test/unit/models/site_test.rb +0 -50
  423. data/test/unit/models/task_test.rb +0 -141
  424. data/test/unit/models/user_test.rb +0 -352
  425. data/test/unit/schema_statements_test.rb +0 -41
@@ -1,2223 +0,0 @@
1
- // Copyright 2005 Google Inc.
2
- // All Rights Reserved
3
- //
4
- // An XPath parser and evaluator written in JavaScript. The
5
- // implementation is complete except for functions handling
6
- // namespaces.
7
- //
8
- // Reference: [XPATH] XPath Specification
9
- // <http://www.w3.org/TR/1999/REC-xpath-19991116>.
10
- //
11
- //
12
- // The API of the parser has several parts:
13
- //
14
- // 1. The parser function xpathParse() that takes a string and returns
15
- // an expession object.
16
- //
17
- // 2. The expression object that has an evaluate() method to evaluate the
18
- // XPath expression it represents. (It is actually a hierarchy of
19
- // objects that resembles the parse tree, but an application will call
20
- // evaluate() only on the top node of this hierarchy.)
21
- //
22
- // 3. The context object that is passed as an argument to the evaluate()
23
- // method, which represents the DOM context in which the expression is
24
- // evaluated.
25
- //
26
- // 4. The value object that is returned from evaluate() and represents
27
- // values of the different types that are defined by XPath (number,
28
- // string, boolean, and node-set), and allows to convert between them.
29
- //
30
- // These parts are near the top of the file, the functions and data
31
- // that are used internally follow after them.
32
- //
33
- //
34
- // TODO(mesch): add jsdoc comments. Use more coherent naming.
35
- //
36
- //
37
- // Author: Steffen Meschkat <mesch@google.com>
38
-
39
-
40
- // The entry point for the parser.
41
- //
42
- // @param expr a string that contains an XPath expression.
43
- // @return an expression object that can be evaluated with an
44
- // expression context.
45
-
46
- function xpathParse(expr) {
47
- //xpathdebug = true;
48
- if (xpathdebug) {
49
- Log.write('XPath parse ' + expr);
50
- }
51
- xpathParseInit();
52
-
53
- var cached = xpathCacheLookup(expr);
54
- if (cached) {
55
- if (xpathdebug) {
56
- Log.write(' ... cached');
57
- }
58
- return cached;
59
- }
60
-
61
- // Optimize for a few common cases: simple attribute node tests
62
- // (@id), simple element node tests (page), variable references
63
- // ($address), numbers (4), multi-step path expressions where each
64
- // step is a plain element node test
65
- // (page/overlay/locations/location).
66
-
67
- if (expr.match(/^(\$|@)?\w+$/i)) {
68
- var ret = makeSimpleExpr(expr);
69
- xpathParseCache[expr] = ret;
70
- if (xpathdebug) {
71
- Log.write(' ... simple');
72
- }
73
- return ret;
74
- }
75
-
76
- if (expr.match(/^\w+(\/\w+)*$/i)) {
77
- var ret = makeSimpleExpr2(expr);
78
- xpathParseCache[expr] = ret;
79
- if (xpathdebug) {
80
- Log.write(' ... simple 2');
81
- }
82
- return ret;
83
- }
84
-
85
- var cachekey = expr; // expr is modified during parse
86
- if (xpathdebug) {
87
- Timer.start('XPath parse', cachekey);
88
- }
89
-
90
- var stack = [];
91
- var ahead = null;
92
- var previous = null;
93
- var done = false;
94
-
95
- var parse_count = 0;
96
- var lexer_count = 0;
97
- var reduce_count = 0;
98
-
99
- while (!done) {
100
- parse_count++;
101
- expr = expr.replace(/^\s*/, '');
102
- previous = ahead;
103
- ahead = null;
104
-
105
- var rule = null;
106
- var match = '';
107
- for (var i = 0; i < xpathTokenRules.length; ++i) {
108
- var result = xpathTokenRules[i].re.exec(expr);
109
- lexer_count++;
110
- if (result && result.length > 0 && result[0].length > match.length) {
111
- rule = xpathTokenRules[i];
112
- match = result[0];
113
- break;
114
- }
115
- }
116
-
117
- // Special case: allow operator keywords to be element and
118
- // variable names.
119
-
120
- // NOTE(mesch): The parser resolves conflicts by looking ahead,
121
- // and this is the only case where we look back to
122
- // disambiguate. So this is indeed something different, and
123
- // looking back is usually done in the lexer (via states in the
124
- // general case, called "start conditions" in flex(1)). Also,the
125
- // conflict resolution in the parser is not as robust as it could
126
- // be, so I'd like to keep as much off the parser as possible (all
127
- // these precedence values should be computed from the grammar
128
- // rules and possibly associativity declarations, as in bison(1),
129
- // and not explicitly set.
130
-
131
- if (rule &&
132
- (rule == TOK_DIV ||
133
- rule == TOK_MOD ||
134
- rule == TOK_AND ||
135
- rule == TOK_OR) &&
136
- (!previous ||
137
- previous.tag == TOK_AT ||
138
- previous.tag == TOK_DSLASH ||
139
- previous.tag == TOK_SLASH ||
140
- previous.tag == TOK_AXIS ||
141
- previous.tag == TOK_DOLLAR)) {
142
- rule = TOK_QNAME;
143
- }
144
-
145
- if (rule) {
146
- expr = expr.substr(match.length);
147
- if (xpathdebug) {
148
- Log.write('token: ' + match + ' -- ' + rule.label);
149
- }
150
- ahead = {
151
- tag: rule,
152
- match: match,
153
- prec: rule.prec ? rule.prec : 0, // || 0 is removed by the compiler
154
- expr: makeTokenExpr(match)
155
- };
156
-
157
- } else {
158
- if (xpathdebug) {
159
- Log.write('DONE');
160
- }
161
- done = true;
162
- }
163
-
164
- while (xpathReduce(stack, ahead)) {
165
- reduce_count++;
166
- if (xpathdebug) {
167
- Log.write('stack: ' + stackToString(stack));
168
- }
169
- }
170
- }
171
-
172
- if (xpathdebug) {
173
- Log.write(stackToString(stack));
174
- }
175
-
176
- // DGF any valid XPath should "reduce" to a single Expr token
177
- if (stack.length != 1) {
178
- throw 'XPath parse error ' + cachekey + ':\n' + stackToString(stack);
179
- }
180
-
181
- var result = stack[0].expr;
182
- xpathParseCache[cachekey] = result;
183
-
184
- if (xpathdebug) {
185
- Timer.end('XPath parse', cachekey);
186
- }
187
-
188
- if (xpathdebug) {
189
- Log.write('XPath parse: ' + parse_count + ' / ' +
190
- lexer_count + ' / ' + reduce_count);
191
- }
192
-
193
- return result;
194
- }
195
-
196
- var xpathParseCache = {};
197
-
198
- function xpathCacheLookup(expr) {
199
- return xpathParseCache[expr];
200
- }
201
-
202
- /*DGF xpathReduce is where the magic happens in this parser.
203
- Skim down to the bottom of this file to find the table of
204
- grammatical rules and precedence numbers, "The productions of the grammar".
205
-
206
- The idea here
207
- is that we want to take a stack of tokens and apply
208
- grammatical rules to them, "reducing" them to higher-level
209
- tokens. Ultimately, any valid XPath should reduce to exactly one
210
- "Expr" token.
211
-
212
- Reduce too early or too late and you'll have two tokens that can't reduce
213
- to single Expr. For example, you may hastily reduce a qname that
214
- should name a function, incorrectly treating it as a tag name.
215
- Or you may reduce too late, accidentally reducing the last part of the
216
- XPath into a top-level "Expr" that won't reduce with earlier parts of
217
- the XPath.
218
-
219
- A "cand" is a grammatical rule candidate, with a given precedence
220
- number. "ahead" is the upcoming token, which also has a precedence
221
- number. If the token has a higher precedence number than
222
- the rule candidate, we'll "shift" the token onto the token stack,
223
- instead of immediately applying the rule candidate.
224
-
225
- Some tokens have left associativity, in which case we shift when they
226
- have LOWER precedence than the candidate.
227
- */
228
- function xpathReduce(stack, ahead) {
229
- var cand = null;
230
-
231
- if (stack.length > 0) {
232
- var top = stack[stack.length-1];
233
- var ruleset = xpathRules[top.tag.key];
234
-
235
- if (ruleset) {
236
- for (var i = 0; i < ruleset.length; ++i) {
237
- var rule = ruleset[i];
238
- var match = xpathMatchStack(stack, rule[1]);
239
- if (match.length) {
240
- cand = {
241
- tag: rule[0],
242
- rule: rule,
243
- match: match
244
- };
245
- cand.prec = xpathGrammarPrecedence(cand);
246
- break;
247
- }
248
- }
249
- }
250
- }
251
-
252
- var ret;
253
- if (cand && (!ahead || cand.prec > ahead.prec ||
254
- (ahead.tag.left && cand.prec >= ahead.prec))) {
255
- for (var i = 0; i < cand.match.matchlength; ++i) {
256
- stack.pop();
257
- }
258
-
259
- if (xpathdebug) {
260
- Log.write('reduce ' + cand.tag.label + ' ' + cand.prec +
261
- ' ahead ' + (ahead ? ahead.tag.label + ' ' + ahead.prec +
262
- (ahead.tag.left ? ' left' : '')
263
- : ' none '));
264
- }
265
-
266
- var matchexpr = mapExpr(cand.match, function(m) { return m.expr; });
267
- if (xpathdebug) {
268
- Log.write('about to run ' + cand.rule[3].toString());
269
- }
270
- cand.expr = cand.rule[3].apply(null, matchexpr);
271
-
272
- stack.push(cand);
273
- ret = true;
274
-
275
- } else {
276
- if (ahead) {
277
- if (xpathdebug) {
278
- Log.write('shift ' + ahead.tag.label + ' ' + ahead.prec +
279
- (ahead.tag.left ? ' left' : '') +
280
- ' over ' + (cand ? cand.tag.label + ' ' +
281
- cand.prec : ' none'));
282
- }
283
- stack.push(ahead);
284
- }
285
- ret = false;
286
- }
287
- return ret;
288
- }
289
-
290
- function xpathMatchStack(stack, pattern) {
291
-
292
- // NOTE(mesch): The stack matches for variable cardinality are
293
- // greedy but don't do backtracking. This would be an issue only
294
- // with rules of the form A* A, i.e. with an element with variable
295
- // cardinality followed by the same element. Since that doesn't
296
- // occur in the grammar at hand, all matches on the stack are
297
- // unambiguous.
298
-
299
- var S = stack.length;
300
- var P = pattern.length;
301
- var p, s;
302
- var match = [];
303
- match.matchlength = 0;
304
- var ds = 0;
305
- for (p = P - 1, s = S - 1; p >= 0 && s >= 0; --p, s -= ds) {
306
- ds = 0;
307
- var qmatch = [];
308
- if (pattern[p] == Q_MM) {
309
- p -= 1;
310
- match.push(qmatch);
311
- while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
312
- qmatch.push(stack[s - ds]);
313
- ds += 1;
314
- match.matchlength += 1;
315
- }
316
-
317
- } else if (pattern[p] == Q_01) {
318
- p -= 1;
319
- match.push(qmatch);
320
- while (s - ds >= 0 && ds < 2 && stack[s - ds].tag == pattern[p]) {
321
- qmatch.push(stack[s - ds]);
322
- ds += 1;
323
- match.matchlength += 1;
324
- }
325
-
326
- } else if (pattern[p] == Q_1M) {
327
- p -= 1;
328
- match.push(qmatch);
329
- if (stack[s].tag == pattern[p]) {
330
- while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) {
331
- qmatch.push(stack[s - ds]);
332
- ds += 1;
333
- match.matchlength += 1;
334
- }
335
- } else {
336
- return [];
337
- }
338
-
339
- } else if (stack[s].tag == pattern[p]) {
340
- match.push(stack[s]);
341
- ds += 1;
342
- match.matchlength += 1;
343
-
344
- } else {
345
- return [];
346
- }
347
-
348
- reverseInplace(qmatch);
349
- qmatch.expr = mapExpr(qmatch, function(m) { return m.expr; });
350
- }
351
-
352
- reverseInplace(match);
353
-
354
- if (p == -1) {
355
- return match;
356
-
357
- } else {
358
- return [];
359
- }
360
- }
361
-
362
- function xpathTokenPrecedence(tag) {
363
- return tag.prec || 2;
364
- }
365
-
366
- function xpathGrammarPrecedence(frame) {
367
- var ret = 0;
368
-
369
- if (frame.rule) { /* normal reduce */
370
- if (frame.rule.length >= 3 && frame.rule[2] >= 0) {
371
- ret = frame.rule[2];
372
-
373
- } else {
374
- for (var i = 0; i < frame.rule[1].length; ++i) {
375
- var p = xpathTokenPrecedence(frame.rule[1][i]);
376
- ret = Math.max(ret, p);
377
- }
378
- }
379
- } else if (frame.tag) { /* TOKEN match */
380
- ret = xpathTokenPrecedence(frame.tag);
381
-
382
- } else if (frame.length) { /* Q_ match */
383
- for (var j = 0; j < frame.length; ++j) {
384
- var p = xpathGrammarPrecedence(frame[j]);
385
- ret = Math.max(ret, p);
386
- }
387
- }
388
-
389
- return ret;
390
- }
391
-
392
- function stackToString(stack) {
393
- var ret = '';
394
- for (var i = 0; i < stack.length; ++i) {
395
- if (ret) {
396
- ret += '\n';
397
- }
398
- ret += stack[i].tag.label;
399
- }
400
- return ret;
401
- }
402
-
403
-
404
- // XPath expression evaluation context. An XPath context consists of a
405
- // DOM node, a list of DOM nodes that contains this node, a number
406
- // that represents the position of the single node in the list, and a
407
- // current set of variable bindings. (See XPath spec.)
408
- //
409
- // The interface of the expression context:
410
- //
411
- // Constructor -- gets the node, its position, the node set it
412
- // belongs to, and a parent context as arguments. The parent context
413
- // is used to implement scoping rules for variables: if a variable
414
- // is not found in the current context, it is looked for in the
415
- // parent context, recursively. Except for node, all arguments have
416
- // default values: default position is 0, default node set is the
417
- // set that contains only the node, and the default parent is null.
418
- //
419
- // Notice that position starts at 0 at the outside interface;
420
- // inside XPath expressions this shows up as position()=1.
421
- //
422
- // clone() -- creates a new context with the current context as
423
- // parent. If passed as argument to clone(), the new context has a
424
- // different node, position, or node set. What is not passed is
425
- // inherited from the cloned context.
426
- //
427
- // setVariable(name, expr) -- binds given XPath expression to the
428
- // name.
429
- //
430
- // getVariable(name) -- what the name says.
431
- //
432
- // setNode(node, position) -- sets the context to the new node and
433
- // its corresponding position. Needed to implement scoping rules for
434
- // variables in XPath. (A variable is visible to all subsequent
435
- // siblings, not only to its children.)
436
-
437
- function ExprContext(node, position, nodelist, parent) {
438
- this.node = node;
439
- this.position = position || 0;
440
- this.nodelist = nodelist || [ node ];
441
- this.variables = {};
442
- this.parent = parent || null;
443
- this.root = parent ? parent.root : node.ownerDocument;
444
- }
445
-
446
- ExprContext.prototype.clone = function(node, position, nodelist) {
447
- return new
448
- ExprContext(node || this.node,
449
- typeof position != 'undefined' ? position : this.position,
450
- nodelist || this.nodelist, this);
451
- };
452
-
453
- ExprContext.prototype.setVariable = function(name, value) {
454
- this.variables[name] = value;
455
- };
456
-
457
- ExprContext.prototype.getVariable = function(name) {
458
- if (typeof this.variables[name] != 'undefined') {
459
- return this.variables[name];
460
-
461
- } else if (this.parent) {
462
- return this.parent.getVariable(name);
463
-
464
- } else {
465
- return null;
466
- }
467
- }
468
-
469
- ExprContext.prototype.setNode = function(node, position) {
470
- this.node = node;
471
- this.position = position;
472
- }
473
-
474
-
475
- // XPath expression values. They are what XPath expressions evaluate
476
- // to. Strangely, the different value types are not specified in the
477
- // XPath syntax, but only in the semantics, so they don't show up as
478
- // nonterminals in the grammar. Yet, some expressions are required to
479
- // evaluate to particular types, and not every type can be coerced
480
- // into every other type. Although the types of XPath values are
481
- // similar to the types present in JavaScript, the type coercion rules
482
- // are a bit peculiar, so we explicitly model XPath types instead of
483
- // mapping them onto JavaScript types. (See XPath spec.)
484
- //
485
- // The four types are:
486
- //
487
- // StringValue
488
- //
489
- // NumberValue
490
- //
491
- // BooleanValue
492
- //
493
- // NodeSetValue
494
- //
495
- // The common interface of the value classes consists of methods that
496
- // implement the XPath type coercion rules:
497
- //
498
- // stringValue() -- returns the value as a JavaScript String,
499
- //
500
- // numberValue() -- returns the value as a JavaScript Number,
501
- //
502
- // booleanValue() -- returns the value as a JavaScript Boolean,
503
- //
504
- // nodeSetValue() -- returns the value as a JavaScript Array of DOM
505
- // Node objects.
506
- //
507
-
508
- function StringValue(value) {
509
- this.value = value;
510
- this.type = 'string';
511
- }
512
-
513
- StringValue.prototype.stringValue = function() {
514
- return this.value;
515
- }
516
-
517
- StringValue.prototype.booleanValue = function() {
518
- return this.value.length > 0;
519
- }
520
-
521
- StringValue.prototype.numberValue = function() {
522
- return this.value - 0;
523
- }
524
-
525
- StringValue.prototype.nodeSetValue = function() {
526
- throw this + ' ' + Error().stack;
527
- }
528
-
529
- function BooleanValue(value) {
530
- this.value = value;
531
- this.type = 'boolean';
532
- }
533
-
534
- BooleanValue.prototype.stringValue = function() {
535
- return '' + this.value;
536
- }
537
-
538
- BooleanValue.prototype.booleanValue = function() {
539
- return this.value;
540
- }
541
-
542
- BooleanValue.prototype.numberValue = function() {
543
- return this.value ? 1 : 0;
544
- }
545
-
546
- BooleanValue.prototype.nodeSetValue = function() {
547
- throw this + ' ' + Error().stack;
548
- }
549
-
550
- function NumberValue(value) {
551
- this.value = value;
552
- this.type = 'number';
553
- }
554
-
555
- NumberValue.prototype.stringValue = function() {
556
- return '' + this.value;
557
- }
558
-
559
- NumberValue.prototype.booleanValue = function() {
560
- return !!this.value;
561
- }
562
-
563
- NumberValue.prototype.numberValue = function() {
564
- return this.value - 0;
565
- }
566
-
567
- NumberValue.prototype.nodeSetValue = function() {
568
- throw this + ' ' + Error().stack;
569
- }
570
-
571
- function NodeSetValue(value) {
572
- this.value = value;
573
- this.type = 'node-set';
574
- }
575
-
576
- NodeSetValue.prototype.stringValue = function() {
577
- if (this.value.length == 0) {
578
- return '';
579
- } else {
580
- return xmlValue(this.value[0]);
581
- }
582
- }
583
-
584
- NodeSetValue.prototype.booleanValue = function() {
585
- return this.value.length > 0;
586
- }
587
-
588
- NodeSetValue.prototype.numberValue = function() {
589
- return this.stringValue() - 0;
590
- }
591
-
592
- NodeSetValue.prototype.nodeSetValue = function() {
593
- return this.value;
594
- };
595
-
596
- // XPath expressions. They are used as nodes in the parse tree and
597
- // possess an evaluate() method to compute an XPath value given an XPath
598
- // context. Expressions are returned from the parser. Teh set of
599
- // expression classes closely mirrors the set of non terminal symbols
600
- // in the grammar. Every non trivial nonterminal symbol has a
601
- // corresponding expression class.
602
- //
603
- // The common expression interface consists of the following methods:
604
- //
605
- // evaluate(context) -- evaluates the expression, returns a value.
606
- //
607
- // toString() -- returns the XPath text representation of the
608
- // expression (defined in xsltdebug.js).
609
- //
610
- // parseTree(indent) -- returns a parse tree representation of the
611
- // expression (defined in xsltdebug.js).
612
-
613
- function TokenExpr(m) {
614
- this.value = m;
615
- }
616
-
617
- TokenExpr.prototype.evaluate = function() {
618
- return new StringValue(this.value);
619
- };
620
-
621
- function LocationExpr() {
622
- this.absolute = false;
623
- this.steps = [];
624
- }
625
-
626
- LocationExpr.prototype.appendStep = function(s) {
627
- this.steps.push(s);
628
- }
629
-
630
- LocationExpr.prototype.prependStep = function(s) {
631
- var steps0 = this.steps;
632
- this.steps = [ s ];
633
- for (var i = 0; i < steps0.length; ++i) {
634
- this.steps.push(steps0[i]);
635
- }
636
- };
637
-
638
- LocationExpr.prototype.evaluate = function(ctx) {
639
- var start;
640
- if (this.absolute) {
641
- start = ctx.root;
642
-
643
- } else {
644
- start = ctx.node;
645
- }
646
-
647
- var nodes = [];
648
- xPathStep(nodes, this.steps, 0, start, ctx);
649
- return new NodeSetValue(nodes);
650
- };
651
-
652
- function xPathStep(nodes, steps, step, input, ctx) {
653
- var s = steps[step];
654
- var ctx2 = ctx.clone(input);
655
- var nodelist = s.evaluate(ctx2).nodeSetValue();
656
-
657
- for (var i = 0; i < nodelist.length; ++i) {
658
- if (step == steps.length - 1) {
659
- nodes.push(nodelist[i]);
660
- } else {
661
- xPathStep(nodes, steps, step + 1, nodelist[i], ctx);
662
- }
663
- }
664
- }
665
-
666
- function StepExpr(axis, nodetest, predicate) {
667
- this.axis = axis;
668
- this.nodetest = nodetest;
669
- this.predicate = predicate || [];
670
- }
671
-
672
- StepExpr.prototype.appendPredicate = function(p) {
673
- this.predicate.push(p);
674
- }
675
-
676
- StepExpr.prototype.evaluate = function(ctx) {
677
- var input = ctx.node;
678
- var nodelist = [];
679
-
680
- // NOTE(mesch): When this was a switch() statement, it didn't work
681
- // in Safari/2.0. Not sure why though; it resulted in the JavaScript
682
- // console output "undefined" (without any line number or so).
683
-
684
- if (this.axis == xpathAxis.ANCESTOR_OR_SELF) {
685
- nodelist.push(input);
686
- for (var n = input.parentNode; n; n = input.parentNode) {
687
- nodelist.push(n);
688
- }
689
-
690
- } else if (this.axis == xpathAxis.ANCESTOR) {
691
- for (var n = input.parentNode; n; n = input.parentNode) {
692
- nodelist.push(n);
693
- }
694
-
695
- } else if (this.axis == xpathAxis.ATTRIBUTE) {
696
- copyArray(nodelist, input.attributes);
697
-
698
- } else if (this.axis == xpathAxis.CHILD) {
699
- copyArray(nodelist, input.childNodes);
700
-
701
- } else if (this.axis == xpathAxis.DESCENDANT_OR_SELF) {
702
- nodelist.push(input);
703
- xpathCollectDescendants(nodelist, input);
704
-
705
- } else if (this.axis == xpathAxis.DESCENDANT) {
706
- xpathCollectDescendants(nodelist, input);
707
-
708
- } else if (this.axis == xpathAxis.FOLLOWING) {
709
- for (var n = input.parentNode; n; n = n.parentNode) {
710
- for (var nn = n.nextSibling; nn; nn = nn.nextSibling) {
711
- nodelist.push(nn);
712
- xpathCollectDescendants(nodelist, nn);
713
- }
714
- }
715
-
716
- } else if (this.axis == xpathAxis.FOLLOWING_SIBLING) {
717
- for (var n = input.nextSibling; n; n = input.nextSibling) {
718
- nodelist.push(n);
719
- }
720
-
721
- } else if (this.axis == xpathAxis.NAMESPACE) {
722
- alert('not implemented: axis namespace');
723
-
724
- } else if (this.axis == xpathAxis.PARENT) {
725
- if (input.parentNode) {
726
- nodelist.push(input.parentNode);
727
- }
728
-
729
- } else if (this.axis == xpathAxis.PRECEDING) {
730
- for (var n = input.parentNode; n; n = n.parentNode) {
731
- for (var nn = n.previousSibling; nn; nn = nn.previousSibling) {
732
- nodelist.push(nn);
733
- xpathCollectDescendantsReverse(nodelist, nn);
734
- }
735
- }
736
-
737
- } else if (this.axis == xpathAxis.PRECEDING_SIBLING) {
738
- for (var n = input.previousSibling; n; n = input.previousSibling) {
739
- nodelist.push(n);
740
- }
741
-
742
- } else if (this.axis == xpathAxis.SELF) {
743
- nodelist.push(input);
744
-
745
- } else {
746
- throw 'ERROR -- NO SUCH AXIS: ' + this.axis;
747
- }
748
-
749
- // process node test
750
- var nodelist0 = nodelist;
751
- nodelist = [];
752
- for (var i = 0; i < nodelist0.length; ++i) {
753
- var n = nodelist0[i];
754
- if (this.nodetest.evaluate(ctx.clone(n, i, nodelist0)).booleanValue()) {
755
- nodelist.push(n);
756
- }
757
- }
758
-
759
- // process predicates
760
- for (var i = 0; i < this.predicate.length; ++i) {
761
- var nodelist0 = nodelist;
762
- nodelist = [];
763
- for (var ii = 0; ii < nodelist0.length; ++ii) {
764
- var n = nodelist0[ii];
765
- if (this.predicate[i].evaluate(ctx.clone(n, ii, nodelist0)).booleanValue()) {
766
- nodelist.push(n);
767
- }
768
- }
769
- }
770
-
771
- return new NodeSetValue(nodelist);
772
- };
773
-
774
- function NodeTestAny() {
775
- this.value = new BooleanValue(true);
776
- }
777
-
778
- NodeTestAny.prototype.evaluate = function(ctx) {
779
- return this.value;
780
- };
781
-
782
- function NodeTestElement() {}
783
-
784
- NodeTestElement.prototype.evaluate = function(ctx) {
785
- return new BooleanValue(ctx.node.nodeType == DOM_ELEMENT_NODE);
786
- }
787
-
788
- function NodeTestText() {}
789
-
790
- NodeTestText.prototype.evaluate = function(ctx) {
791
- return new BooleanValue(ctx.node.nodeType == DOM_TEXT_NODE);
792
- }
793
-
794
- function NodeTestComment() {}
795
-
796
- NodeTestComment.prototype.evaluate = function(ctx) {
797
- return new BooleanValue(ctx.node.nodeType == DOM_COMMENT_NODE);
798
- }
799
-
800
- function NodeTestPI(target) {
801
- this.target = target;
802
- }
803
-
804
- NodeTestPI.prototype.evaluate = function(ctx) {
805
- return new
806
- BooleanValue(ctx.node.nodeType == DOM_PROCESSING_INSTRUCTION_NODE &&
807
- (!this.target || ctx.node.nodeName == this.target));
808
- }
809
-
810
- function NodeTestNC(nsprefix) {
811
- this.regex = new RegExp("^" + nsprefix + ":");
812
- this.nsprefix = nsprefix;
813
- }
814
-
815
- NodeTestNC.prototype.evaluate = function(ctx) {
816
- var n = ctx.node;
817
- return new BooleanValue(this.regex.match(n.nodeName));
818
- }
819
-
820
- function NodeTestName(name) {
821
- this.name = name;
822
- }
823
-
824
- NodeTestName.prototype.evaluate = function(ctx) {
825
- var n = ctx.node;
826
- // NOTE (Patrick Lightbody): this change allows node selection to be case-insensitive
827
- return new BooleanValue(n.nodeName.toUpperCase() == this.name.toUpperCase());
828
- }
829
-
830
- function PredicateExpr(expr) {
831
- this.expr = expr;
832
- }
833
-
834
- PredicateExpr.prototype.evaluate = function(ctx) {
835
- var v = this.expr.evaluate(ctx);
836
- if (v.type == 'number') {
837
- // NOTE(mesch): Internally, position is represented starting with
838
- // 0, however in XPath position starts with 1. See functions
839
- // position() and last().
840
- return new BooleanValue(ctx.position == v.numberValue() - 1);
841
- } else {
842
- return new BooleanValue(v.booleanValue());
843
- }
844
- };
845
-
846
- function FunctionCallExpr(name) {
847
- this.name = name;
848
- this.args = [];
849
- }
850
-
851
- FunctionCallExpr.prototype.appendArg = function(arg) {
852
- this.args.push(arg);
853
- };
854
-
855
- FunctionCallExpr.prototype.evaluate = function(ctx) {
856
- var fn = '' + this.name.value;
857
- var f = this.xpathfunctions[fn];
858
- if (f) {
859
- return f.call(this, ctx);
860
- } else {
861
- Log.write('XPath NO SUCH FUNCTION ' + fn);
862
- return new BooleanValue(false);
863
- }
864
- };
865
-
866
- FunctionCallExpr.prototype.xpathfunctions = {
867
- 'last': function(ctx) {
868
- assert(this.args.length == 0);
869
- // NOTE(mesch): XPath position starts at 1.
870
- return new NumberValue(ctx.nodelist.length);
871
- },
872
-
873
- 'position': function(ctx) {
874
- assert(this.args.length == 0);
875
- // NOTE(mesch): XPath position starts at 1.
876
- return new NumberValue(ctx.position + 1);
877
- },
878
-
879
- 'count': function(ctx) {
880
- assert(this.args.length == 1);
881
- var v = this.args[0].evaluate(ctx);
882
- return new NumberValue(v.nodeSetValue().length);
883
- },
884
-
885
- 'id': function(ctx) {
886
- assert(this.args.length == 1);
887
- var e = this.args[0].evaluate(ctx);
888
- var ret = [];
889
- var ids;
890
- if (e.type == 'node-set') {
891
- ids = [];
892
- for (var i = 0; i < e.length; ++i) {
893
- var v = xmlValue(e[i]).split(/\s+/);
894
- for (var ii = 0; ii < v.length; ++ii) {
895
- ids.push(v[ii]);
896
- }
897
- }
898
- } else {
899
- ids = e.stringValue().split(/\s+/);
900
- }
901
- var contextNode = ctx.node;
902
- var d;
903
- if (contextNode.nodeName == "#document") {
904
- d = contextNode;
905
- } else {
906
- d = contextNode.ownerDocument;
907
- }
908
- for (var i = 0; i < ids.length; ++i) {
909
- var n = d.getElementById(ids[i]);
910
- if (n) {
911
- ret.push(n);
912
- }
913
- }
914
- return new NodeSetValue(ret);
915
- },
916
-
917
- 'local-name': function(ctx) {
918
- alert('not implmented yet: XPath function local-name()');
919
- },
920
-
921
- 'namespace-uri': function(ctx) {
922
- alert('not implmented yet: XPath function namespace-uri()');
923
- },
924
-
925
- 'name': function(ctx) {
926
- assert(this.args.length == 1 || this.args.length == 0);
927
- var n;
928
- if (this.args.length == 0) {
929
- n = [ ctx.node ];
930
- } else {
931
- n = this.args[0].evaluate(ctx).nodeSetValue();
932
- }
933
-
934
- if (n.length == 0) {
935
- return new StringValue('');
936
- } else {
937
- return new StringValue(n[0].nodeName);
938
- }
939
- },
940
-
941
- 'string': function(ctx) {
942
- assert(this.args.length == 1 || this.args.length == 0);
943
- if (this.args.length == 0) {
944
- return new StringValue(new NodeSetValue([ ctx.node ]).stringValue());
945
- } else {
946
- return new StringValue(this.args[0].evaluate(ctx).stringValue());
947
- }
948
- },
949
-
950
- 'concat': function(ctx) {
951
- var ret = '';
952
- for (var i = 0; i < this.args.length; ++i) {
953
- ret += this.args[i].evaluate(ctx).stringValue();
954
- }
955
- return new StringValue(ret);
956
- },
957
-
958
- 'starts-with': function(ctx) {
959
- assert(this.args.length == 2);
960
- var s0 = this.args[0].evaluate(ctx).stringValue();
961
- var s1 = this.args[1].evaluate(ctx).stringValue();
962
- return new BooleanValue(s0.indexOf(s1) == 0);
963
- },
964
-
965
- 'contains': function(ctx) {
966
- assert(this.args.length == 2);
967
- var s0 = this.args[0].evaluate(ctx).stringValue();
968
- var s1 = this.args[1].evaluate(ctx).stringValue();
969
- return new BooleanValue(s0.indexOf(s1) != -1);
970
- },
971
-
972
- 'substring-before': function(ctx) {
973
- assert(this.args.length == 2);
974
- var s0 = this.args[0].evaluate(ctx).stringValue();
975
- var s1 = this.args[1].evaluate(ctx).stringValue();
976
- var i = s0.indexOf(s1);
977
- var ret;
978
- if (i == -1) {
979
- ret = '';
980
- } else {
981
- ret = s0.substr(0,i);
982
- }
983
- return new StringValue(ret);
984
- },
985
-
986
- 'substring-after': function(ctx) {
987
- assert(this.args.length == 2);
988
- var s0 = this.args[0].evaluate(ctx).stringValue();
989
- var s1 = this.args[1].evaluate(ctx).stringValue();
990
- var i = s0.indexOf(s1);
991
- var ret;
992
- if (i == -1) {
993
- ret = '';
994
- } else {
995
- ret = s0.substr(i + s1.length);
996
- }
997
- return new StringValue(ret);
998
- },
999
-
1000
- 'substring': function(ctx) {
1001
- // NOTE: XPath defines the position of the first character in a
1002
- // string to be 1, in JavaScript this is 0 ([XPATH] Section 4.2).
1003
- assert(this.args.length == 2 || this.args.length == 3);
1004
- var s0 = this.args[0].evaluate(ctx).stringValue();
1005
- var s1 = this.args[1].evaluate(ctx).numberValue();
1006
- var ret;
1007
- if (this.args.length == 2) {
1008
- var i1 = Math.max(0, Math.round(s1) - 1);
1009
- ret = s0.substr(i1);
1010
-
1011
- } else {
1012
- var s2 = this.args[2].evaluate(ctx).numberValue();
1013
- var i0 = Math.round(s1) - 1;
1014
- var i1 = Math.max(0, i0);
1015
- var i2 = Math.round(s2) - Math.max(0, -i0);
1016
- ret = s0.substr(i1, i2);
1017
- }
1018
- return new StringValue(ret);
1019
- },
1020
-
1021
- 'string-length': function(ctx) {
1022
- var s;
1023
- if (this.args.length > 0) {
1024
- s = this.args[0].evaluate(ctx).stringValue();
1025
- } else {
1026
- s = new NodeSetValue([ ctx.node ]).stringValue();
1027
- }
1028
- return new NumberValue(s.length);
1029
- },
1030
-
1031
- 'normalize-space': function(ctx) {
1032
- var s;
1033
- if (this.args.length > 0) {
1034
- s = this.args[0].evaluate(ctx).stringValue();
1035
- } else {
1036
- s = new NodeSetValue([ ctx.node ]).stringValue();
1037
- }
1038
- s = s.replace(/^\s*/,'').replace(/\s*$/,'').replace(/\s+/g, ' ');
1039
- return new StringValue(s);
1040
- },
1041
-
1042
- 'translate': function(ctx) {
1043
- assert(this.args.length == 3);
1044
- var s0 = this.args[0].evaluate(ctx).stringValue();
1045
- var s1 = this.args[1].evaluate(ctx).stringValue();
1046
- var s2 = this.args[2].evaluate(ctx).stringValue();
1047
-
1048
- for (var i = 0; i < s1.length; ++i) {
1049
- s0 = s0.replace(new RegExp(s1.charAt(i), 'g'), s2.charAt(i));
1050
- }
1051
- return new StringValue(s0);
1052
- },
1053
-
1054
- 'boolean': function(ctx) {
1055
- assert(this.args.length == 1);
1056
- return new BooleanValue(this.args[0].evaluate(ctx).booleanValue());
1057
- },
1058
-
1059
- 'not': function(ctx) {
1060
- assert(this.args.length == 1);
1061
- var ret = !this.args[0].evaluate(ctx).booleanValue();
1062
- return new BooleanValue(ret);
1063
- },
1064
-
1065
- 'true': function(ctx) {
1066
- assert(this.args.length == 0);
1067
- return new BooleanValue(true);
1068
- },
1069
-
1070
- 'false': function(ctx) {
1071
- assert(this.args.length == 0);
1072
- return new BooleanValue(false);
1073
- },
1074
-
1075
- 'lang': function(ctx) {
1076
- assert(this.args.length == 1);
1077
- var lang = this.args[0].evaluate(ctx).stringValue();
1078
- var xmllang;
1079
- var n = ctx.node;
1080
- while (n && n != n.parentNode /* just in case ... */) {
1081
- xmllang = n.getAttribute('xml:lang');
1082
- if (xmllang) {
1083
- break;
1084
- }
1085
- n = n.parentNode;
1086
- }
1087
- if (!xmllang) {
1088
- return new BooleanValue(false);
1089
- } else {
1090
- var re = new RegExp('^' + lang + '$', 'i');
1091
- return new BooleanValue(xmllang.match(re) ||
1092
- xmllang.replace(/_.*$/,'').match(re));
1093
- }
1094
- },
1095
-
1096
- 'number': function(ctx) {
1097
- assert(this.args.length == 1 || this.args.length == 0);
1098
-
1099
- if (this.args.length == 1) {
1100
- return new NumberValue(this.args[0].evaluate(ctx).numberValue());
1101
- } else {
1102
- return new NumberValue(new NodeSetValue([ ctx.node ]).numberValue());
1103
- }
1104
- },
1105
-
1106
- 'sum': function(ctx) {
1107
- assert(this.args.length == 1);
1108
- var n = this.args[0].evaluate(ctx).nodeSetValue();
1109
- var sum = 0;
1110
- for (var i = 0; i < n.length; ++i) {
1111
- sum += xmlValue(n[i]) - 0;
1112
- }
1113
- return new NumberValue(sum);
1114
- },
1115
-
1116
- 'floor': function(ctx) {
1117
- assert(this.args.length == 1);
1118
- var num = this.args[0].evaluate(ctx).numberValue();
1119
- return new NumberValue(Math.floor(num));
1120
- },
1121
-
1122
- 'ceiling': function(ctx) {
1123
- assert(this.args.length == 1);
1124
- var num = this.args[0].evaluate(ctx).numberValue();
1125
- return new NumberValue(Math.ceil(num));
1126
- },
1127
-
1128
- 'round': function(ctx) {
1129
- assert(this.args.length == 1);
1130
- var num = this.args[0].evaluate(ctx).numberValue();
1131
- return new NumberValue(Math.round(num));
1132
- },
1133
-
1134
- // TODO(mesch): The following functions are custom. There is a
1135
- // standard that defines how to add functions, which should be
1136
- // applied here.
1137
-
1138
- 'ext-join': function(ctx) {
1139
- assert(this.args.length == 2);
1140
- var nodes = this.args[0].evaluate(ctx).nodeSetValue();
1141
- var delim = this.args[1].evaluate(ctx).stringValue();
1142
- var ret = '';
1143
- for (var i = 0; i < nodes.length; ++i) {
1144
- if (ret) {
1145
- ret += delim;
1146
- }
1147
- ret += xmlValue(nodes[i]);
1148
- }
1149
- return new StringValue(ret);
1150
- },
1151
-
1152
- // ext-if() evaluates and returns its second argument, if the
1153
- // boolean value of its first argument is true, otherwise it
1154
- // evaluates and returns its third argument.
1155
-
1156
- 'ext-if': function(ctx) {
1157
- assert(this.args.length == 3);
1158
- if (this.args[0].evaluate(ctx).booleanValue()) {
1159
- return this.args[1].evaluate(ctx);
1160
- } else {
1161
- return this.args[2].evaluate(ctx);
1162
- }
1163
- },
1164
-
1165
- 'ext-sprintf': function(ctx) {
1166
- assert(this.args.length >= 1);
1167
- var args = [];
1168
- for (var i = 0; i < this.args.length; ++i) {
1169
- args.push(this.args[i].evaluate(ctx).stringValue());
1170
- }
1171
- return new StringValue(sprintf.apply(null, args));
1172
- },
1173
-
1174
- // ext-cardinal() evaluates its single argument as a number, and
1175
- // returns the current node that many times. It can be used in the
1176
- // select attribute to iterate over an integer range.
1177
-
1178
- 'ext-cardinal': function(ctx) {
1179
- assert(this.args.length >= 1);
1180
- var c = this.args[0].evaluate(ctx).numberValue();
1181
- var ret = [];
1182
- for (var i = 0; i < c; ++i) {
1183
- ret.push(ctx.node);
1184
- }
1185
- return new NodeSetValue(ret);
1186
- }
1187
- };
1188
-
1189
- function UnionExpr(expr1, expr2) {
1190
- this.expr1 = expr1;
1191
- this.expr2 = expr2;
1192
- }
1193
-
1194
- UnionExpr.prototype.evaluate = function(ctx) {
1195
- var nodes1 = this.expr1.evaluate(ctx).nodeSetValue();
1196
- var nodes2 = this.expr2.evaluate(ctx).nodeSetValue();
1197
- var I1 = nodes1.length;
1198
- for (var i2 = 0; i2 < nodes2.length; ++i2) {
1199
- for (var i1 = 0; i1 < I1; ++i1) {
1200
- if (nodes1[i1] == nodes2[i2]) {
1201
- // break inner loop and continue outer loop, labels confuse
1202
- // the js compiler, so we don't use them here.
1203
- i1 = I1;
1204
- }
1205
- }
1206
- nodes1.push(nodes2[i2]);
1207
- }
1208
- return new NodeSetValue(nodes2);
1209
- };
1210
-
1211
- function PathExpr(filter, rel) {
1212
- this.filter = filter;
1213
- this.rel = rel;
1214
- }
1215
-
1216
- PathExpr.prototype.evaluate = function(ctx) {
1217
- var nodes = this.filter.evaluate(ctx).nodeSetValue();
1218
- var nodes1 = [];
1219
- for (var i = 0; i < nodes.length; ++i) {
1220
- var nodes0 = this.rel.evaluate(ctx.clone(nodes[i], i, nodes)).nodeSetValue();
1221
- for (var ii = 0; ii < nodes0.length; ++ii) {
1222
- nodes1.push(nodes0[ii]);
1223
- }
1224
- }
1225
- return new NodeSetValue(nodes1);
1226
- };
1227
-
1228
- function FilterExpr(expr, predicate) {
1229
- this.expr = expr;
1230
- this.predicate = predicate;
1231
- }
1232
-
1233
- FilterExpr.prototype.evaluate = function(ctx) {
1234
- var nodes = this.expr.evaluate(ctx).nodeSetValue();
1235
- for (var i = 0; i < this.predicate.length; ++i) {
1236
- var nodes0 = nodes;
1237
- nodes = [];
1238
- for (var j = 0; j < nodes0.length; ++j) {
1239
- var n = nodes0[j];
1240
- if (this.predicate[i].evaluate(ctx.clone(n, j, nodes0)).booleanValue()) {
1241
- nodes.push(n);
1242
- }
1243
- }
1244
- }
1245
-
1246
- return new NodeSetValue(nodes);
1247
- }
1248
-
1249
- function UnaryMinusExpr(expr) {
1250
- this.expr = expr;
1251
- }
1252
-
1253
- UnaryMinusExpr.prototype.evaluate = function(ctx) {
1254
- return new NumberValue(-this.expr.evaluate(ctx).numberValue());
1255
- };
1256
-
1257
- function BinaryExpr(expr1, op, expr2) {
1258
- this.expr1 = expr1;
1259
- this.expr2 = expr2;
1260
- this.op = op;
1261
- }
1262
-
1263
- BinaryExpr.prototype.evaluate = function(ctx) {
1264
- var ret;
1265
- switch (this.op.value) {
1266
- case 'or':
1267
- ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() ||
1268
- this.expr2.evaluate(ctx).booleanValue());
1269
- break;
1270
-
1271
- case 'and':
1272
- ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() &&
1273
- this.expr2.evaluate(ctx).booleanValue());
1274
- break;
1275
-
1276
- case '+':
1277
- ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() +
1278
- this.expr2.evaluate(ctx).numberValue());
1279
- break;
1280
-
1281
- case '-':
1282
- ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() -
1283
- this.expr2.evaluate(ctx).numberValue());
1284
- break;
1285
-
1286
- case '*':
1287
- ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() *
1288
- this.expr2.evaluate(ctx).numberValue());
1289
- break;
1290
-
1291
- case 'mod':
1292
- ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() %
1293
- this.expr2.evaluate(ctx).numberValue());
1294
- break;
1295
-
1296
- case 'div':
1297
- ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() /
1298
- this.expr2.evaluate(ctx).numberValue());
1299
- break;
1300
-
1301
- case '=':
1302
- ret = this.compare(ctx, function(x1, x2) { return x1 == x2; });
1303
- break;
1304
-
1305
- case '!=':
1306
- ret = this.compare(ctx, function(x1, x2) { return x1 != x2; });
1307
- break;
1308
-
1309
- case '<':
1310
- ret = this.compare(ctx, function(x1, x2) { return x1 < x2; });
1311
- break;
1312
-
1313
- case '<=':
1314
- ret = this.compare(ctx, function(x1, x2) { return x1 <= x2; });
1315
- break;
1316
-
1317
- case '>':
1318
- ret = this.compare(ctx, function(x1, x2) { return x1 > x2; });
1319
- break;
1320
-
1321
- case '>=':
1322
- ret = this.compare(ctx, function(x1, x2) { return x1 >= x2; });
1323
- break;
1324
-
1325
- default:
1326
- alert('BinaryExpr.evaluate: ' + this.op.value);
1327
- }
1328
- return ret;
1329
- };
1330
-
1331
- BinaryExpr.prototype.compare = function(ctx, cmp) {
1332
- var v1 = this.expr1.evaluate(ctx);
1333
- var v2 = this.expr2.evaluate(ctx);
1334
-
1335
- var ret;
1336
- if (v1.type == 'node-set' && v2.type == 'node-set') {
1337
- var n1 = v1.nodeSetValue();
1338
- var n2 = v2.nodeSetValue();
1339
- ret = false;
1340
- for (var i1 = 0; i1 < n1.length; ++i1) {
1341
- for (var i2 = 0; i2 < n2.length; ++i2) {
1342
- if (cmp(xmlValue(n1[i1]), xmlValue(n2[i2]))) {
1343
- ret = true;
1344
- // Break outer loop. Labels confuse the jscompiler and we
1345
- // don't use them.
1346
- i2 = n2.length;
1347
- i1 = n1.length;
1348
- }
1349
- }
1350
- }
1351
-
1352
- } else if (v1.type == 'node-set' || v2.type == 'node-set') {
1353
-
1354
- if (v1.type == 'number') {
1355
- var s = v1.numberValue();
1356
- var n = v2.nodeSetValue();
1357
-
1358
- ret = false;
1359
- for (var i = 0; i < n.length; ++i) {
1360
- var nn = xmlValue(n[i]) - 0;
1361
- if (cmp(s, nn)) {
1362
- ret = true;
1363
- break;
1364
- }
1365
- }
1366
-
1367
- } else if (v2.type == 'number') {
1368
- var n = v1.nodeSetValue();
1369
- var s = v2.numberValue();
1370
-
1371
- ret = false;
1372
- for (var i = 0; i < n.length; ++i) {
1373
- var nn = xmlValue(n[i]) - 0;
1374
- if (cmp(nn, s)) {
1375
- ret = true;
1376
- break;
1377
- }
1378
- }
1379
-
1380
- } else if (v1.type == 'string') {
1381
- var s = v1.stringValue();
1382
- var n = v2.nodeSetValue();
1383
-
1384
- ret = false;
1385
- for (var i = 0; i < n.length; ++i) {
1386
- var nn = xmlValue(n[i]);
1387
- if (cmp(s, nn)) {
1388
- ret = true;
1389
- break;
1390
- }
1391
- }
1392
-
1393
- } else if (v2.type == 'string') {
1394
- var n = v1.nodeSetValue();
1395
- var s = v2.stringValue();
1396
-
1397
- ret = false;
1398
- for (var i = 0; i < n.length; ++i) {
1399
- var nn = xmlValue(n[i]);
1400
- if (cmp(nn, s)) {
1401
- ret = true;
1402
- break;
1403
- }
1404
- }
1405
-
1406
- } else {
1407
- ret = cmp(v1.booleanValue(), v2.booleanValue());
1408
- }
1409
-
1410
- } else if (v1.type == 'boolean' || v2.type == 'boolean') {
1411
- ret = cmp(v1.booleanValue(), v2.booleanValue());
1412
-
1413
- } else if (v1.type == 'number' || v2.type == 'number') {
1414
- ret = cmp(v1.numberValue(), v2.numberValue());
1415
-
1416
- } else {
1417
- ret = cmp(v1.stringValue(), v2.stringValue());
1418
- }
1419
-
1420
- return new BooleanValue(ret);
1421
- }
1422
-
1423
- function LiteralExpr(value) {
1424
- this.value = value;
1425
- }
1426
-
1427
- LiteralExpr.prototype.evaluate = function(ctx) {
1428
- return new StringValue(this.value);
1429
- };
1430
-
1431
- function NumberExpr(value) {
1432
- this.value = value;
1433
- }
1434
-
1435
- NumberExpr.prototype.evaluate = function(ctx) {
1436
- return new NumberValue(this.value);
1437
- };
1438
-
1439
- function VariableExpr(name) {
1440
- this.name = name;
1441
- }
1442
-
1443
- VariableExpr.prototype.evaluate = function(ctx) {
1444
- return ctx.getVariable(this.name);
1445
- }
1446
-
1447
- // Factory functions for semantic values (i.e. Expressions) of the
1448
- // productions in the grammar. When a production is matched to reduce
1449
- // the current parse state stack, the function is called with the
1450
- // semantic values of the matched elements as arguments, and returns
1451
- // another semantic value. The semantic value is a node of the parse
1452
- // tree, an expression object with an evaluate() method that evaluates the
1453
- // expression in an actual context. These factory functions are used
1454
- // in the specification of the grammar rules, below.
1455
-
1456
- function makeTokenExpr(m) {
1457
- return new TokenExpr(m);
1458
- }
1459
-
1460
- function passExpr(e) {
1461
- return e;
1462
- }
1463
-
1464
- function makeLocationExpr1(slash, rel) {
1465
- rel.absolute = true;
1466
- return rel;
1467
- }
1468
-
1469
- function makeLocationExpr2(dslash, rel) {
1470
- rel.absolute = true;
1471
- rel.prependStep(makeAbbrevStep(dslash.value));
1472
- return rel;
1473
- }
1474
-
1475
- function makeLocationExpr3(slash) {
1476
- var ret = new LocationExpr();
1477
- ret.appendStep(makeAbbrevStep('.'));
1478
- ret.absolute = true;
1479
- return ret;
1480
- }
1481
-
1482
- function makeLocationExpr4(dslash) {
1483
- var ret = new LocationExpr();
1484
- ret.absolute = true;
1485
- ret.appendStep(makeAbbrevStep(dslash.value));
1486
- return ret;
1487
- }
1488
-
1489
- function makeLocationExpr5(step) {
1490
- var ret = new LocationExpr();
1491
- ret.appendStep(step);
1492
- return ret;
1493
- }
1494
-
1495
- function makeLocationExpr6(rel, slash, step) {
1496
- rel.appendStep(step);
1497
- return rel;
1498
- }
1499
-
1500
- function makeLocationExpr7(rel, dslash, step) {
1501
- rel.appendStep(makeAbbrevStep(dslash.value));
1502
- rel.appendStep(step);
1503
- return rel;
1504
- }
1505
-
1506
- function makeStepExpr1(dot) {
1507
- return makeAbbrevStep(dot.value);
1508
- }
1509
-
1510
- function makeStepExpr2(ddot) {
1511
- return makeAbbrevStep(ddot.value);
1512
- }
1513
-
1514
- function makeStepExpr3(axisname, axis, nodetest) {
1515
- return new StepExpr(axisname.value, nodetest);
1516
- }
1517
-
1518
- function makeStepExpr4(at, nodetest) {
1519
- return new StepExpr('attribute', nodetest);
1520
- }
1521
-
1522
- function makeStepExpr5(nodetest) {
1523
- return new StepExpr('child', nodetest);
1524
- }
1525
-
1526
- function makeStepExpr6(step, predicate) {
1527
- step.appendPredicate(predicate);
1528
- return step;
1529
- }
1530
-
1531
- function makeAbbrevStep(abbrev) {
1532
- switch (abbrev) {
1533
- case '//':
1534
- return new StepExpr('descendant-or-self', new NodeTestAny);
1535
-
1536
- case '.':
1537
- return new StepExpr('self', new NodeTestAny);
1538
-
1539
- case '..':
1540
- return new StepExpr('parent', new NodeTestAny);
1541
- }
1542
- }
1543
-
1544
- function makeNodeTestExpr1(asterisk) {
1545
- return new NodeTestElement;
1546
- }
1547
-
1548
- function makeNodeTestExpr2(ncname, colon, asterisk) {
1549
- return new NodeTestNC(ncname.value);
1550
- }
1551
-
1552
- function makeNodeTestExpr3(qname) {
1553
- return new NodeTestName(qname.value);
1554
- }
1555
-
1556
- function makeNodeTestExpr4(typeo, parenc) {
1557
- var type = typeo.value.replace(/\s*\($/, '');
1558
- switch(type) {
1559
- case 'node':
1560
- return new NodeTestAny;
1561
-
1562
- case 'text':
1563
- return new NodeTestText;
1564
-
1565
- case 'comment':
1566
- return new NodeTestComment;
1567
-
1568
- case 'processing-instruction':
1569
- return new NodeTestPI;
1570
- }
1571
- }
1572
-
1573
- function makeNodeTestExpr5(typeo, target, parenc) {
1574
- var type = typeo.replace(/\s*\($/, '');
1575
- if (type != 'processing-instruction') {
1576
- throw type + ' ' + Error().stack;
1577
- }
1578
- return new NodeTestPI(target.value);
1579
- }
1580
-
1581
- function makePredicateExpr(pareno, expr, parenc) {
1582
- return new PredicateExpr(expr);
1583
- }
1584
-
1585
- function makePrimaryExpr(pareno, expr, parenc) {
1586
- return expr;
1587
- }
1588
-
1589
- function makeFunctionCallExpr1(name, pareno, parenc) {
1590
- return new FunctionCallExpr(name);
1591
- }
1592
-
1593
- function makeFunctionCallExpr2(name, pareno, arg1, args, parenc) {
1594
- var ret = new FunctionCallExpr(name);
1595
- ret.appendArg(arg1);
1596
- for (var i = 0; i < args.length; ++i) {
1597
- ret.appendArg(args[i]);
1598
- }
1599
- return ret;
1600
- }
1601
-
1602
- function makeArgumentExpr(comma, expr) {
1603
- return expr;
1604
- }
1605
-
1606
- function makeUnionExpr(expr1, pipe, expr2) {
1607
- return new UnionExpr(expr1, expr2);
1608
- }
1609
-
1610
- function makePathExpr1(filter, slash, rel) {
1611
- return new PathExpr(filter, rel);
1612
- }
1613
-
1614
- function makePathExpr2(filter, dslash, rel) {
1615
- rel.prependStep(makeAbbrevStep(dslash.value));
1616
- return new PathExpr(filter, rel);
1617
- }
1618
-
1619
- function makeFilterExpr(expr, predicates) {
1620
- if (predicates.length > 0) {
1621
- return new FilterExpr(expr, predicates);
1622
- } else {
1623
- return expr;
1624
- }
1625
- }
1626
-
1627
- function makeUnaryMinusExpr(minus, expr) {
1628
- return new UnaryMinusExpr(expr);
1629
- }
1630
-
1631
- function makeBinaryExpr(expr1, op, expr2) {
1632
- return new BinaryExpr(expr1, op, expr2);
1633
- }
1634
-
1635
- function makeLiteralExpr(token) {
1636
- // remove quotes from the parsed value:
1637
- var value = token.value.substring(1, token.value.length - 1);
1638
- return new LiteralExpr(value);
1639
- }
1640
-
1641
- function makeNumberExpr(token) {
1642
- return new NumberExpr(token.value);
1643
- }
1644
-
1645
- function makeVariableReference(dollar, name) {
1646
- return new VariableExpr(name.value);
1647
- }
1648
-
1649
- // Used before parsing for optimization of common simple cases. See
1650
- // the begin of xpathParse() for which they are.
1651
- function makeSimpleExpr(expr) {
1652
- if (expr.charAt(0) == '$') {
1653
- return new VariableExpr(expr.substr(1));
1654
- } else if (expr.charAt(0) == '@') {
1655
- var a = new NodeTestName(expr.substr(1));
1656
- var b = new StepExpr('attribute', a);
1657
- var c = new LocationExpr();
1658
- c.appendStep(b);
1659
- return c;
1660
- } else if (expr.match(/^[0-9]+$/)) {
1661
- return new NumberExpr(expr);
1662
- } else {
1663
- var a = new NodeTestName(expr);
1664
- var b = new StepExpr('child', a);
1665
- var c = new LocationExpr();
1666
- c.appendStep(b);
1667
- return c;
1668
- }
1669
- }
1670
-
1671
- function makeSimpleExpr2(expr) {
1672
- var steps = expr.split('/');
1673
- var c = new LocationExpr();
1674
- for (var i in steps) {
1675
- var a = new NodeTestName(steps[i]);
1676
- var b = new StepExpr('child', a);
1677
- c.appendStep(b);
1678
- }
1679
- return c;
1680
- }
1681
-
1682
- // The axes of XPath expressions.
1683
-
1684
- var xpathAxis = {
1685
- ANCESTOR_OR_SELF: 'ancestor-or-self',
1686
- ANCESTOR: 'ancestor',
1687
- ATTRIBUTE: 'attribute',
1688
- CHILD: 'child',
1689
- DESCENDANT_OR_SELF: 'descendant-or-self',
1690
- DESCENDANT: 'descendant',
1691
- FOLLOWING_SIBLING: 'following-sibling',
1692
- FOLLOWING: 'following',
1693
- NAMESPACE: 'namespace',
1694
- PARENT: 'parent',
1695
- PRECEDING_SIBLING: 'preceding-sibling',
1696
- PRECEDING: 'preceding',
1697
- SELF: 'self'
1698
- };
1699
-
1700
- var xpathAxesRe = [
1701
- xpathAxis.ANCESTOR_OR_SELF,
1702
- xpathAxis.ANCESTOR,
1703
- xpathAxis.ATTRIBUTE,
1704
- xpathAxis.CHILD,
1705
- xpathAxis.DESCENDANT_OR_SELF,
1706
- xpathAxis.DESCENDANT,
1707
- xpathAxis.FOLLOWING_SIBLING,
1708
- xpathAxis.FOLLOWING,
1709
- xpathAxis.NAMESPACE,
1710
- xpathAxis.PARENT,
1711
- xpathAxis.PRECEDING_SIBLING,
1712
- xpathAxis.PRECEDING,
1713
- xpathAxis.SELF
1714
- ].join('|');
1715
-
1716
-
1717
- // The tokens of the language. The label property is just used for
1718
- // generating debug output. The prec property is the precedence used
1719
- // for shift/reduce resolution. Default precedence is 0 as a lookahead
1720
- // token and 2 on the stack. TODO(mesch): this is certainly not
1721
- // necessary and too complicated. Simplify this!
1722
-
1723
- // NOTE: tabular formatting is the big exception, but here it should
1724
- // be OK.
1725
-
1726
- var TOK_PIPE = { label: "|", prec: 17, re: new RegExp("^\\|") };
1727
- var TOK_DSLASH = { label: "//", prec: 19, re: new RegExp("^//") };
1728
- var TOK_SLASH = { label: "/", prec: 30, re: new RegExp("^/") };
1729
- var TOK_AXIS = { label: "::", prec: 20, re: new RegExp("^::") };
1730
- var TOK_COLON = { label: ":", prec: 1000, re: new RegExp("^:") };
1731
- var TOK_AXISNAME = { label: "[axis]", re: new RegExp('^(' + xpathAxesRe + ')') };
1732
- var TOK_PARENO = { label: "(", prec: 34, re: new RegExp("^\\(") };
1733
- var TOK_PARENC = { label: ")", re: new RegExp("^\\)") };
1734
- var TOK_DDOT = { label: "..", prec: 34, re: new RegExp("^\\.\\.") };
1735
- var TOK_DOT = { label: ".", prec: 34, re: new RegExp("^\\.") };
1736
- var TOK_AT = { label: "@", prec: 34, re: new RegExp("^@") };
1737
-
1738
- var TOK_COMMA = { label: ",", re: new RegExp("^,") };
1739
-
1740
- var TOK_OR = { label: "or", prec: 10, re: new RegExp("^or\\b") };
1741
- var TOK_AND = { label: "and", prec: 11, re: new RegExp("^and\\b") };
1742
- var TOK_EQ = { label: "=", prec: 12, re: new RegExp("^=") };
1743
- var TOK_NEQ = { label: "!=", prec: 12, re: new RegExp("^!=") };
1744
- var TOK_GE = { label: ">=", prec: 13, re: new RegExp("^>=") };
1745
- var TOK_GT = { label: ">", prec: 13, re: new RegExp("^>") };
1746
- var TOK_LE = { label: "<=", prec: 13, re: new RegExp("^<=") };
1747
- var TOK_LT = { label: "<", prec: 13, re: new RegExp("^<") };
1748
- var TOK_PLUS = { label: "+", prec: 14, re: new RegExp("^\\+"), left: true };
1749
- var TOK_MINUS = { label: "-", prec: 14, re: new RegExp("^\\-"), left: true };
1750
- var TOK_DIV = { label: "div", prec: 15, re: new RegExp("^div\\b"), left: true };
1751
- var TOK_MOD = { label: "mod", prec: 15, re: new RegExp("^mod\\b"), left: true };
1752
-
1753
- var TOK_BRACKO = { label: "[", prec: 32, re: new RegExp("^\\[") };
1754
- var TOK_BRACKC = { label: "]", re: new RegExp("^\\]") };
1755
- var TOK_DOLLAR = { label: "$", re: new RegExp("^\\$") };
1756
-
1757
- var TOK_NCNAME = { label: "[ncname]", re: new RegExp('^[a-z][-\\w]*','i') };
1758
-
1759
- var TOK_ASTERISK = { label: "*", prec: 15, re: new RegExp("^\\*"), left: true };
1760
- var TOK_LITERALQ = { label: "[litq]", prec: 20, re: new RegExp("^'[^\\']*'") };
1761
- var TOK_LITERALQQ = {
1762
- label: "[litqq]",
1763
- prec: 20,
1764
- re: new RegExp('^"[^\\"]*"')
1765
- };
1766
-
1767
- var TOK_NUMBER = {
1768
- label: "[number]",
1769
- prec: 35,
1770
- re: new RegExp('^\\d+(\\.\\d*)?') };
1771
-
1772
- var TOK_QNAME = {
1773
- label: "[qname]",
1774
- re: new RegExp('^([a-z][-\\w]*:)?[a-z][-\\w]*','i')
1775
- };
1776
-
1777
- var TOK_NODEO = {
1778
- label: "[nodetest-start]",
1779
- re: new RegExp('^(processing-instruction|comment|text|node)\\(')
1780
- };
1781
-
1782
- // The table of the tokens of our grammar, used by the lexer: first
1783
- // column the tag, second column a regexp to recognize it in the
1784
- // input, third column the precedence of the token, fourth column a
1785
- // factory function for the semantic value of the token.
1786
- //
1787
- // NOTE: order of this list is important, because the first match
1788
- // counts. Cf. DDOT and DOT, and AXIS and COLON.
1789
-
1790
- var xpathTokenRules = [
1791
- TOK_DSLASH,
1792
- TOK_SLASH,
1793
- TOK_DDOT,
1794
- TOK_DOT,
1795
- TOK_AXIS,
1796
- TOK_COLON,
1797
- TOK_AXISNAME,
1798
- TOK_NODEO,
1799
- TOK_PARENO,
1800
- TOK_PARENC,
1801
- TOK_BRACKO,
1802
- TOK_BRACKC,
1803
- TOK_AT,
1804
- TOK_COMMA,
1805
- TOK_OR,
1806
- TOK_AND,
1807
- TOK_NEQ,
1808
- TOK_EQ,
1809
- TOK_GE,
1810
- TOK_GT,
1811
- TOK_LE,
1812
- TOK_LT,
1813
- TOK_PLUS,
1814
- TOK_MINUS,
1815
- TOK_ASTERISK,
1816
- TOK_PIPE,
1817
- TOK_MOD,
1818
- TOK_DIV,
1819
- TOK_LITERALQ,
1820
- TOK_LITERALQQ,
1821
- TOK_NUMBER,
1822
- TOK_QNAME,
1823
- TOK_NCNAME,
1824
- TOK_DOLLAR
1825
- ];
1826
-
1827
- // All the nonterminals of the grammar. The nonterminal objects are
1828
- // identified by object identity; the labels are used in the debug
1829
- // output only.
1830
- var XPathLocationPath = { label: "LocationPath" };
1831
- var XPathRelativeLocationPath = { label: "RelativeLocationPath" };
1832
- var XPathAbsoluteLocationPath = { label: "AbsoluteLocationPath" };
1833
- var XPathStep = { label: "Step" };
1834
- var XPathNodeTest = { label: "NodeTest" };
1835
- var XPathPredicate = { label: "Predicate" };
1836
- var XPathLiteral = { label: "Literal" };
1837
- var XPathExpr = { label: "Expr" };
1838
- var XPathPrimaryExpr = { label: "PrimaryExpr" };
1839
- var XPathVariableReference = { label: "Variablereference" };
1840
- var XPathNumber = { label: "Number" };
1841
- var XPathFunctionCall = { label: "FunctionCall" };
1842
- var XPathArgumentRemainder = { label: "ArgumentRemainder" };
1843
- var XPathPathExpr = { label: "PathExpr" };
1844
- var XPathUnionExpr = { label: "UnionExpr" };
1845
- var XPathFilterExpr = { label: "FilterExpr" };
1846
- var XPathDigits = { label: "Digits" };
1847
-
1848
- var xpathNonTerminals = [
1849
- XPathLocationPath,
1850
- XPathRelativeLocationPath,
1851
- XPathAbsoluteLocationPath,
1852
- XPathStep,
1853
- XPathNodeTest,
1854
- XPathPredicate,
1855
- XPathLiteral,
1856
- XPathExpr,
1857
- XPathPrimaryExpr,
1858
- XPathVariableReference,
1859
- XPathNumber,
1860
- XPathFunctionCall,
1861
- XPathArgumentRemainder,
1862
- XPathPathExpr,
1863
- XPathUnionExpr,
1864
- XPathFilterExpr,
1865
- XPathDigits
1866
- ];
1867
-
1868
- // Quantifiers that are used in the productions of the grammar.
1869
- var Q_01 = { label: "?" };
1870
- var Q_MM = { label: "*" };
1871
- var Q_1M = { label: "+" };
1872
-
1873
- // Tag for left associativity (right assoc is implied by undefined).
1874
- var ASSOC_LEFT = true;
1875
-
1876
- // The productions of the grammar. Columns of the table:
1877
- //
1878
- // - target nonterminal,
1879
- // - pattern,
1880
- // - precedence,
1881
- // - semantic value factory
1882
- //
1883
- // The semantic value factory is a function that receives parse tree
1884
- // nodes from the stack frames of the matched symbols as arguments and
1885
- // returns an a node of the parse tree. The node is stored in the top
1886
- // stack frame along with the target object of the rule. The node in
1887
- // the parse tree is an expression object that has an evaluate() method
1888
- // and thus evaluates XPath expressions.
1889
- //
1890
- // The precedence is used to decide between reducing and shifting by
1891
- // comparing the precendence of the rule that is candidate for
1892
- // reducing with the precedence of the look ahead token. Precedence of
1893
- // -1 means that the precedence of the tokens in the pattern is used
1894
- // instead. TODO: It shouldn't be necessary to explicitly assign
1895
- // precedences to rules.
1896
-
1897
- // DGF Where do these precedence rules come from? I just tweaked some
1898
- // of these numbers to fix bug SEL-486.
1899
-
1900
- var xpathGrammarRules =
1901
- [
1902
- [ XPathLocationPath, [ XPathRelativeLocationPath ], 18,
1903
- passExpr ],
1904
- [ XPathLocationPath, [ XPathAbsoluteLocationPath ], 18,
1905
- passExpr ],
1906
-
1907
- [ XPathAbsoluteLocationPath, [ TOK_SLASH, XPathRelativeLocationPath ], 18,
1908
- makeLocationExpr1 ],
1909
- [ XPathAbsoluteLocationPath, [ TOK_DSLASH, XPathRelativeLocationPath ], 18,
1910
- makeLocationExpr2 ],
1911
-
1912
- [ XPathAbsoluteLocationPath, [ TOK_SLASH ], 0,
1913
- makeLocationExpr3 ],
1914
- [ XPathAbsoluteLocationPath, [ TOK_DSLASH ], 0,
1915
- makeLocationExpr4 ],
1916
-
1917
- [ XPathRelativeLocationPath, [ XPathStep ], 31,
1918
- makeLocationExpr5 ],
1919
- [ XPathRelativeLocationPath,
1920
- [ XPathRelativeLocationPath, TOK_SLASH, XPathStep ], 31,
1921
- makeLocationExpr6 ],
1922
- [ XPathRelativeLocationPath,
1923
- [ XPathRelativeLocationPath, TOK_DSLASH, XPathStep ], 31,
1924
- makeLocationExpr7 ],
1925
-
1926
- [ XPathStep, [ TOK_DOT ], 33,
1927
- makeStepExpr1 ],
1928
- [ XPathStep, [ TOK_DDOT ], 33,
1929
- makeStepExpr2 ],
1930
- [ XPathStep,
1931
- [ TOK_AXISNAME, TOK_AXIS, XPathNodeTest ], 33,
1932
- makeStepExpr3 ],
1933
- [ XPathStep, [ TOK_AT, XPathNodeTest ], 33,
1934
- makeStepExpr4 ],
1935
- [ XPathStep, [ XPathNodeTest ], 33,
1936
- makeStepExpr5 ],
1937
- [ XPathStep, [ XPathStep, XPathPredicate ], 33,
1938
- makeStepExpr6 ],
1939
-
1940
- [ XPathNodeTest, [ TOK_ASTERISK ], 33,
1941
- makeNodeTestExpr1 ],
1942
- [ XPathNodeTest, [ TOK_NCNAME, TOK_COLON, TOK_ASTERISK ], 33,
1943
- makeNodeTestExpr2 ],
1944
- [ XPathNodeTest, [ TOK_QNAME ], 33,
1945
- makeNodeTestExpr3 ],
1946
- [ XPathNodeTest, [ TOK_NODEO, TOK_PARENC ], 33,
1947
- makeNodeTestExpr4 ],
1948
- [ XPathNodeTest, [ TOK_NODEO, XPathLiteral, TOK_PARENC ], 33,
1949
- makeNodeTestExpr5 ],
1950
-
1951
- [ XPathPredicate, [ TOK_BRACKO, XPathExpr, TOK_BRACKC ], 33,
1952
- makePredicateExpr ],
1953
-
1954
- [ XPathPrimaryExpr, [ XPathVariableReference ], 33,
1955
- passExpr ],
1956
- [ XPathPrimaryExpr, [ TOK_PARENO, XPathExpr, TOK_PARENC ], 33,
1957
- makePrimaryExpr ],
1958
- [ XPathPrimaryExpr, [ XPathLiteral ], 30,
1959
- passExpr ],
1960
- [ XPathPrimaryExpr, [ XPathNumber ], 30,
1961
- passExpr ],
1962
- [ XPathPrimaryExpr, [ XPathFunctionCall ], 31,
1963
- passExpr ],
1964
-
1965
- [ XPathFunctionCall, [ TOK_QNAME, TOK_PARENO, TOK_PARENC ], -1,
1966
- makeFunctionCallExpr1 ],
1967
- [ XPathFunctionCall,
1968
- [ TOK_QNAME, TOK_PARENO, XPathExpr, XPathArgumentRemainder, Q_MM,
1969
- TOK_PARENC ], -1,
1970
- makeFunctionCallExpr2 ],
1971
- [ XPathArgumentRemainder, [ TOK_COMMA, XPathExpr ], -1,
1972
- makeArgumentExpr ],
1973
-
1974
- [ XPathUnionExpr, [ XPathPathExpr ], 20,
1975
- passExpr ],
1976
- [ XPathUnionExpr, [ XPathUnionExpr, TOK_PIPE, XPathPathExpr ], 20,
1977
- makeUnionExpr ],
1978
-
1979
- [ XPathPathExpr, [ XPathLocationPath ], 20,
1980
- passExpr ],
1981
- [ XPathPathExpr, [ XPathFilterExpr ], 19,
1982
- passExpr ],
1983
- [ XPathPathExpr,
1984
- [ XPathFilterExpr, TOK_SLASH, XPathRelativeLocationPath ], 19,
1985
- makePathExpr1 ],
1986
- [ XPathPathExpr,
1987
- [ XPathFilterExpr, TOK_DSLASH, XPathRelativeLocationPath ], 19,
1988
- makePathExpr2 ],
1989
-
1990
- [ XPathFilterExpr, [ XPathPrimaryExpr, XPathPredicate, Q_MM ], 31,
1991
- makeFilterExpr ],
1992
-
1993
- [ XPathExpr, [ XPathPrimaryExpr ], 16,
1994
- passExpr ],
1995
- [ XPathExpr, [ XPathUnionExpr ], 16,
1996
- passExpr ],
1997
-
1998
- [ XPathExpr, [ TOK_MINUS, XPathExpr ], -1,
1999
- makeUnaryMinusExpr ],
2000
-
2001
- [ XPathExpr, [ XPathExpr, TOK_OR, XPathExpr ], -1,
2002
- makeBinaryExpr ],
2003
- [ XPathExpr, [ XPathExpr, TOK_AND, XPathExpr ], -1,
2004
- makeBinaryExpr ],
2005
-
2006
- [ XPathExpr, [ XPathExpr, TOK_EQ, XPathExpr ], -1,
2007
- makeBinaryExpr ],
2008
- [ XPathExpr, [ XPathExpr, TOK_NEQ, XPathExpr ], -1,
2009
- makeBinaryExpr ],
2010
-
2011
- [ XPathExpr, [ XPathExpr, TOK_LT, XPathExpr ], -1,
2012
- makeBinaryExpr ],
2013
- [ XPathExpr, [ XPathExpr, TOK_LE, XPathExpr ], -1,
2014
- makeBinaryExpr ],
2015
- [ XPathExpr, [ XPathExpr, TOK_GT, XPathExpr ], -1,
2016
- makeBinaryExpr ],
2017
- [ XPathExpr, [ XPathExpr, TOK_GE, XPathExpr ], -1,
2018
- makeBinaryExpr ],
2019
-
2020
- [ XPathExpr, [ XPathExpr, TOK_PLUS, XPathExpr ], -1,
2021
- makeBinaryExpr, ASSOC_LEFT ],
2022
- [ XPathExpr, [ XPathExpr, TOK_MINUS, XPathExpr ], -1,
2023
- makeBinaryExpr, ASSOC_LEFT ],
2024
-
2025
- [ XPathExpr, [ XPathExpr, TOK_ASTERISK, XPathExpr ], -1,
2026
- makeBinaryExpr, ASSOC_LEFT ],
2027
- [ XPathExpr, [ XPathExpr, TOK_DIV, XPathExpr ], -1,
2028
- makeBinaryExpr, ASSOC_LEFT ],
2029
- [ XPathExpr, [ XPathExpr, TOK_MOD, XPathExpr ], -1,
2030
- makeBinaryExpr, ASSOC_LEFT ],
2031
-
2032
- [ XPathLiteral, [ TOK_LITERALQ ], -1,
2033
- makeLiteralExpr ],
2034
- [ XPathLiteral, [ TOK_LITERALQQ ], -1,
2035
- makeLiteralExpr ],
2036
-
2037
- [ XPathNumber, [ TOK_NUMBER ], -1,
2038
- makeNumberExpr ],
2039
-
2040
- [ XPathVariableReference, [ TOK_DOLLAR, TOK_QNAME ], 200,
2041
- makeVariableReference ]
2042
- ];
2043
-
2044
- // That function computes some optimizations of the above data
2045
- // structures and will be called right here. It merely takes the
2046
- // counter variables out of the global scope.
2047
-
2048
- var xpathRules = [];
2049
-
2050
- function xpathParseInit() {
2051
- if (xpathRules.length) {
2052
- return;
2053
- }
2054
-
2055
- // Some simple optimizations for the xpath expression parser: sort
2056
- // grammar rules descending by length, so that the longest match is
2057
- // first found.
2058
-
2059
- xpathGrammarRules.sort(function(a,b) {
2060
- var la = a[1].length;
2061
- var lb = b[1].length;
2062
- if (la < lb) {
2063
- return 1;
2064
- } else if (la > lb) {
2065
- return -1;
2066
- } else {
2067
- return 0;
2068
- }
2069
- });
2070
-
2071
- var k = 1;
2072
- for (var i = 0; i < xpathNonTerminals.length; ++i) {
2073
- xpathNonTerminals[i].key = k++;
2074
- }
2075
-
2076
- for (i = 0; i < xpathTokenRules.length; ++i) {
2077
- xpathTokenRules[i].key = k++;
2078
- }
2079
-
2080
- Log.write('XPath parse INIT: ' + k + ' rules');
2081
-
2082
- // Another slight optimization: sort the rules into bins according
2083
- // to the last element (observing quantifiers), so we can restrict
2084
- // the match against the stack to the subest of rules that match the
2085
- // top of the stack.
2086
- //
2087
- // TODO(mesch): What we actually want is to compute states as in
2088
- // bison, so that we don't have to do any explicit and iterated
2089
- // match against the stack.
2090
-
2091
- function push_(array, position, element) {
2092
- if (!array[position]) {
2093
- array[position] = [];
2094
- }
2095
- array[position].push(element);
2096
- }
2097
-
2098
- for (i = 0; i < xpathGrammarRules.length; ++i) {
2099
- var rule = xpathGrammarRules[i];
2100
- var pattern = rule[1];
2101
-
2102
- for (var j = pattern.length - 1; j >= 0; --j) {
2103
- if (pattern[j] == Q_1M) {
2104
- push_(xpathRules, pattern[j-1].key, rule);
2105
- break;
2106
-
2107
- } else if (pattern[j] == Q_MM || pattern[j] == Q_01) {
2108
- push_(xpathRules, pattern[j-1].key, rule);
2109
- --j;
2110
-
2111
- } else {
2112
- push_(xpathRules, pattern[j].key, rule);
2113
- break;
2114
- }
2115
- }
2116
- }
2117
-
2118
- Log.write('XPath parse INIT: ' + xpathRules.length + ' rule bins');
2119
-
2120
- var sum = 0;
2121
- mapExec(xpathRules, function(i) {
2122
- if (i) {
2123
- sum += i.length;
2124
- }
2125
- });
2126
-
2127
- Log.write('XPath parse INIT: ' + (sum / xpathRules.length) + ' average bin size');
2128
- }
2129
-
2130
- // Local utility functions that are used by the lexer or parser.
2131
-
2132
- function xpathCollectDescendants(nodelist, node) {
2133
- for (var n = node.firstChild; n; n = n.nextSibling) {
2134
- nodelist.push(n);
2135
- arguments.callee(nodelist, n);
2136
- }
2137
- }
2138
-
2139
- function xpathCollectDescendantsReverse(nodelist, node) {
2140
- for (var n = node.lastChild; n; n = n.previousSibling) {
2141
- nodelist.push(n);
2142
- arguments.callee(nodelist, n);
2143
- }
2144
- }
2145
-
2146
-
2147
- // The entry point for the library: match an expression against a DOM
2148
- // node. Returns an XPath value.
2149
- function xpathDomEval(expr, node) {
2150
- var expr1 = xpathParse(expr);
2151
- var ret = expr1.evaluate(new ExprContext(node));
2152
- return ret;
2153
- }
2154
-
2155
- // Utility function to sort a list of nodes. Used by xsltSort() and
2156
- // nxslSelect().
2157
- function xpathSort(input, sort) {
2158
- if (sort.length == 0) {
2159
- return;
2160
- }
2161
-
2162
- var sortlist = [];
2163
-
2164
- for (var i = 0; i < input.nodelist.length; ++i) {
2165
- var node = input.nodelist[i];
2166
- var sortitem = { node: node, key: [] };
2167
- var context = input.clone(node, 0, [ node ]);
2168
-
2169
- for (var j = 0; j < sort.length; ++j) {
2170
- var s = sort[j];
2171
- var value = s.expr.evaluate(context);
2172
-
2173
- var evalue;
2174
- if (s.type == 'text') {
2175
- evalue = value.stringValue();
2176
- } else if (s.type == 'number') {
2177
- evalue = value.numberValue();
2178
- }
2179
- sortitem.key.push({ value: evalue, order: s.order });
2180
- }
2181
-
2182
- // Make the sort stable by adding a lowest priority sort by
2183
- // id. This is very convenient and furthermore required by the
2184
- // spec ([XSLT] - Section 10 Sorting).
2185
- sortitem.key.push({ value: i, order: 'ascending' });
2186
-
2187
- sortlist.push(sortitem);
2188
- }
2189
-
2190
- sortlist.sort(xpathSortByKey);
2191
-
2192
- var nodes = [];
2193
- for (var i = 0; i < sortlist.length; ++i) {
2194
- nodes.push(sortlist[i].node);
2195
- }
2196
- input.nodelist = nodes;
2197
- input.setNode(nodes[0], 0);
2198
- }
2199
-
2200
-
2201
- // Sorts by all order criteria defined. According to the JavaScript
2202
- // spec ([ECMA] Section 11.8.5), the compare operators compare strings
2203
- // as strings and numbers as numbers.
2204
- //
2205
- // NOTE: In browsers which do not follow the spec, this breaks only in
2206
- // the case that numbers should be sorted as strings, which is very
2207
- // uncommon.
2208
-
2209
- function xpathSortByKey(v1, v2) {
2210
- // NOTE: Sort key vectors of different length never occur in
2211
- // xsltSort.
2212
-
2213
- for (var i = 0; i < v1.key.length; ++i) {
2214
- var o = v1.key[i].order == 'descending' ? -1 : 1;
2215
- if (v1.key[i].value > v2.key[i].value) {
2216
- return +1 * o;
2217
- } else if (v1.key[i].value < v2.key[i].value) {
2218
- return -1 * o;
2219
- }
2220
- }
2221
-
2222
- return 0;
2223
- }