browsercms 3.1.5 → 3.3.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }