zena 1.2.7 → 1.2.8

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 (407) hide show
  1. data/History.txt +80 -25
  2. data/Rakefile +2 -2
  3. data/app/controllers/columns_controller.rb +2 -2
  4. data/app/controllers/nodes_controller.rb +22 -29
  5. data/app/controllers/user_sessions_controller.rb +35 -10
  6. data/app/controllers/users_controller.rb +2 -2
  7. data/app/controllers/versions_controller.rb +2 -2
  8. data/app/models/group.rb +15 -1
  9. data/app/models/node.rb +109 -8
  10. data/app/models/role.rb +4 -0
  11. data/app/models/site.rb +64 -58
  12. data/app/models/template.rb +1 -1
  13. data/app/models/user.rb +135 -29
  14. data/app/models/user_session.rb +0 -1
  15. data/app/models/virtual_class.rb +11 -6
  16. data/app/views/columns/_form.html.erb +3 -1
  17. data/app/views/columns/_li.html.erb +1 -1
  18. data/app/views/columns/create.rjs +1 -1
  19. data/app/views/groups/_form.rhtml +16 -13
  20. data/app/views/relations/_form.erb +18 -6
  21. data/app/views/sites/_form.erb +12 -6
  22. data/app/views/users/_form.rhtml +23 -8
  23. data/app/views/users/_li.rhtml +14 -3
  24. data/app/views/users/index.rhtml +1 -1
  25. data/app/views/virtual_classes/_form.erb +12 -2
  26. data/app/views/zafu/default/Node-+login.zafu +8 -1
  27. data/app/views/zafu/default/Node-+search.zafu +1 -1
  28. data/bricks/acls/lib/bricks/acls.rb +1 -0
  29. data/bricks/acls/zena/migrate/20130903150356_longer_names_for_acl.rb +9 -0
  30. data/bricks/acls/zena/test/integration/acl_integration_test.rb +2 -2
  31. data/bricks/currency/lib/bricks/currency.rb +120 -0
  32. data/bricks/currency/zena/test/unit/currency_test.rb +43 -0
  33. data/bricks/fs_skin/lib/bricks/fs_skin.rb +1 -1
  34. data/bricks/fs_skin/zena/skins/blog/Node-+search.zafu +1 -1
  35. data/bricks/fs_skin/zena/skins/blog/Node.zafu +1 -1
  36. data/bricks/fs_skin/zena/test/unit/fs_skin_view_test.rb +35 -0
  37. data/bricks/pdf/lib/bricks/pdf.rb +1 -1
  38. data/bricks/sphinx/lib/bricks/sphinx.rb +2 -0
  39. data/bricks/sphinx/zena/init.rb +14 -0
  40. data/bricks/tags/zena/test/zafu/tags.yml +5 -1
  41. data/bricks/worker/lib/bricks/worker.rb +3 -2
  42. data/bricks/zena/zena/migrate/20130829093753_add_versioned_flag_to_column.rb +10 -0
  43. data/bricks/zena/zena/migrate/20130903084909_count_login_attempts.rb +11 -0
  44. data/bricks/zena/zena/migrate/20131104153126_index_fullpath.rb +10 -0
  45. data/bricks/zena/zena/migrate/20131104210011_rebuild_fullpath_after_change.rb +10 -0
  46. data/bricks/zena/zena/migrate/20131105160420_add_skin_id_to_sites.rb +9 -0
  47. data/bricks/zena/zena/migrate/20131105175822_add_profile_to_users.rb +11 -0
  48. data/bricks/zena/zena/migrate/20140213120038_fix_idx_scope.rb +13 -0
  49. data/bricks/zena/zena/migrate/20140628140247_add_site_readonly.rb +9 -0
  50. data/config/bricks.yml +8 -4
  51. data/config/gems.yml +5 -3
  52. data/db/init/base/skins/default/Node-+login.zafu +8 -1
  53. data/db/init/base/skins/default/Node-+search.zafu +1 -1
  54. data/lib/bricks/loader.rb +5 -5
  55. data/lib/gettext_strings.rb +3 -0
  56. data/lib/tasks/zena.rake +25 -22
  57. data/lib/zafu/process/context.rb +4 -0
  58. data/lib/zena/acts/secure_node.rb +3 -3
  59. data/lib/zena/app.rb +1 -0
  60. data/lib/zena/deploy.rb +1 -1
  61. data/lib/zena/deploy/template.rb +1 -1
  62. data/lib/zena/foxy_parser.rb +5 -2
  63. data/lib/zena/info.rb +1 -1
  64. data/lib/zena/site_worker.rb +2 -2
  65. data/lib/zena/test_controller.rb +5 -2
  66. data/lib/zena/use/action.rb +9 -2
  67. data/lib/zena/use/ajax.rb +20 -4
  68. data/lib/zena/use/ancestry.rb +89 -15
  69. data/lib/zena/use/authlogic.rb +8 -2
  70. data/lib/zena/use/context.rb +1 -0
  71. data/lib/zena/use/display.rb +1 -97
  72. data/lib/zena/use/forms.rb +28 -8
  73. data/lib/zena/use/html_tags.rb +16 -7
  74. data/lib/zena/use/i18n.rb +1 -1
  75. data/lib/zena/use/prop_eval.rb +6 -1
  76. data/lib/zena/use/query_node.rb +69 -4
  77. data/lib/zena/use/recursion.rb +1 -1
  78. data/lib/zena/use/refactor.rb +5 -2
  79. data/lib/zena/use/relations.rb +1 -0
  80. data/lib/zena/use/rendering.rb +7 -4
  81. data/lib/zena/use/test_helper.rb +8 -4
  82. data/lib/zena/use/upload.rb +14 -0
  83. data/lib/zena/use/urls.rb +39 -23
  84. data/lib/zena/use/version_hash.rb +5 -2
  85. data/lib/zena/use/workflow.rb +116 -70
  86. data/lib/zena/use/zafu_eval.rb +41 -0
  87. data/lib/zena/use/zafu_safe_definitions.rb +1 -0
  88. data/lib/zena/use/zafu_templates.rb +32 -26
  89. data/lib/zena/use/zazen.rb +8 -7
  90. data/locale/app.pot +5 -1
  91. data/locale/de/LC_MESSAGES/zena.mo +0 -0
  92. data/locale/de/zena.po +385 -281
  93. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  94. data/locale/en/zena.po +378 -271
  95. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  96. data/locale/fr/zena.po +387 -272
  97. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  98. data/locale/it/zena.po +433 -404
  99. data/locale/zena.pot +362 -268
  100. data/public/javascripts/grid.js +280 -104
  101. data/public/javascripts/zena.js +43 -15
  102. data/public/stylesheets/admin.css +8 -2
  103. data/public/stylesheets/grid.css +5 -2
  104. data/public/stylesheets/popup.css +1 -1
  105. data/test/fixtures/files/TestNode.zafu +51 -0
  106. data/test/functional/nodes_controller_test.rb +20 -5
  107. data/test/functional/user_sessions_controller_test.rb +41 -6
  108. data/test/functional/users_controller_test.rb +1 -2
  109. data/test/integration/navigation_test.rb +22 -4
  110. data/test/integration/query_node/basic.yml +7 -0
  111. data/test/integration/query_node/complex.yml +1 -1
  112. data/test/integration/query_node/errors.yml +1 -1
  113. data/test/integration/query_node/filters.yml +34 -1
  114. data/test/integration/query_node/relations.yml +6 -13
  115. data/test/integration/query_node_test.rb +22 -3
  116. data/test/integration/zafu_compiler/action.yml +1 -1
  117. data/test/integration/zafu_compiler/alias_site.yml +52 -0
  118. data/test/integration/zafu_compiler/complex.yml +1 -1
  119. data/test/integration/zafu_compiler/complex_ok.yml +5 -5
  120. data/test/integration/zafu_compiler/context.yml +1 -1
  121. data/test/integration/zafu_compiler/display.yml +56 -5
  122. data/test/integration/zafu_compiler/forms.yml +35 -2
  123. data/test/integration/zafu_compiler/meta.yml +4 -0
  124. data/test/integration/zafu_compiler/rubyless.yml +1 -1
  125. data/test/integration/zafu_compiler/safe_definitions.yml +4 -0
  126. data/test/integration/zafu_compiler/security.yml +10 -0
  127. data/test/integration/zafu_compiler/site.yml +5 -1
  128. data/test/integration/zafu_compiler/urls.yml +8 -2
  129. data/test/integration/zafu_compiler/zafu_attributes.yml +2 -1
  130. data/test/integration/zafu_compiler/zazen.yml +4 -0
  131. data/test/integration/zafu_compiler_test.rb +47 -4
  132. data/test/selenium/Grid/grid1.rsel +8 -8
  133. data/test/sites/complex/sites.yml +2 -2
  134. data/test/sites/complex/users.yml +1 -0
  135. data/test/sites/zena/columns.yml +4 -0
  136. data/test/sites/zena/sites.yml +1 -0
  137. data/test/sites/zena/users.yml +1 -0
  138. data/test/unit/node_test.rb +53 -5
  139. data/test/unit/note_test.rb +1 -1
  140. data/test/unit/relation_proxy_test.rb +20 -0
  141. data/test/unit/role_test.rb +2 -0
  142. data/test/unit/site_test.rb +28 -6
  143. data/test/unit/user_test.rb +332 -1
  144. data/test/unit/virtual_class_test.rb +55 -0
  145. data/test/unit/workflow_test.rb +175 -0
  146. data/test/unit/zena/use/ancestry_test.rb +52 -10
  147. data/test/unit/zena/use/prop_eval_test.rb +44 -0
  148. data/test/unit/zena/use/rendering_test.rb +48 -2
  149. data/test/unit/zena/use/upload_test.rb +15 -13
  150. data/test/unit/zena/use/urls_test.rb +1 -0
  151. data/vendor/plugins/ar_mysql_full_text/lib/ar_mysql_full_text.rb +39 -25
  152. data/zena.gemspec +69 -307
  153. metadata +143 -368
  154. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run 2.tmCommand +0 -24
  155. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Context.tmCommand +0 -58
  156. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Focused Should.tmCommand +0 -88
  157. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run.tmCommand +0 -27
  158. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/YAML to Shoulda.tmCommand +0 -23
  159. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Context.tmPreferences +0 -19
  160. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Should.tmPreferences +0 -19
  161. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory attributes for.tmSnippet +0 -16
  162. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory build.tmSnippet +0 -16
  163. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory.tmSnippet +0 -16
  164. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define with class.tmSnippet +0 -18
  165. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define.tmSnippet +0 -18
  166. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_next.tmSnippet +0 -16
  167. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_sequence.tmSnippet +0 -18
  168. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_bad_value.tmSnippet +0 -16
  169. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_contains.tmSnippet +0 -16
  170. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_does_not_contain.tmSnippet +0 -16
  171. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_good_value.tmSnippet +0 -16
  172. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_same_elements.tmSnippet +0 -16
  173. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_save.tmSnippet +0 -16
  174. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_sent_email.tmSnippet +0 -18
  175. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_valid.tmSnippet +0 -16
  176. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/association.tmSnippet +0 -17
  177. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/attribute.tmSnippet +0 -17
  178. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/before_should block.tmSnippet +0 -18
  179. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block get.tmSnippet +0 -22
  180. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block post.tmSnippet +0 -23
  181. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block with setup.tmSnippet +0 -25
  182. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/setup.tmSnippet +0 -18
  183. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block with before proc.tmSnippet +0 -18
  184. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block.tmSnippet +0 -18
  185. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_allow_values_for.tmSnippet +0 -16
  186. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_assign_to.tmSnippet +0 -16
  187. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful denied.tmSnippet +0 -20
  188. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful.tmSnippet +0 -20
  189. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_belong_to.tmSnippet +0 -16
  190. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change by.tmSnippet +0 -16
  191. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change from to.tmSnippet +0 -16
  192. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_at_least.tmSnippet +0 -16
  193. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_in_range.tmSnippet +0 -16
  194. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_is.tmSnippet +0 -16
  195. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_value_in_range.tmSnippet +0 -16
  196. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_eventually.tmSnippet +0 -18
  197. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_filter_params.tmSnippet +0 -16
  198. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_and_belong_to_many.tmSnippet +0 -16
  199. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_class_methods.tmSnippet +0 -16
  200. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_column.tmSnippet +0 -16
  201. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_columns.tmSnippet +0 -16
  202. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_index.tmSnippet +0 -16
  203. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_indices.tmSnippet +0 -16
  204. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_instance_methods.tmSnippet +0 -16
  205. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_many.tmSnippet +0 -16
  206. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_named_scope.tmSnippet +0 -16
  207. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_one.tmSnippet +0 -16
  208. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_readonly_attributes.tmSnippet +0 -16
  209. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_mass_assignment_of.tmSnippet +0 -16
  210. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_values_for.tmSnippet +0 -16
  211. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_assign_to.tmSnippet +0 -16
  212. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_change.tmSnippet +0 -16
  213. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_set_the_flash.tmSnippet +0 -16
  214. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_redirect_to.tmSnippet +0 -16
  215. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_a_form.tmSnippet +0 -16
  216. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_template.tmSnippet +0 -16
  217. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_with_layout.tmSnippet +0 -16
  218. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_without_layout.tmSnippet +0 -16
  219. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with.tmSnippet +0 -16
  220. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with_content_type.tmSnippet +0 -16
  221. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_return_from_session.tmSnippet +0 -16
  222. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_route.tmSnippet +0 -16
  223. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_set_the_flash_to.tmSnippet +0 -16
  224. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_acceptance_of.tmSnippet +0 -16
  225. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_numericality_of.tmSnippet +0 -16
  226. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_presence_of.tmSnippet +0 -16
  227. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of with scope.tmSnippet +0 -16
  228. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of.tmSnippet +0 -16
  229. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/catch_exception.rb +0 -39
  230. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/run_script.rb +0 -104
  231. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/stdin_dialog.rb +0 -14
  232. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/test.rb +0 -17
  233. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/todo.txt +0 -13
  234. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/bin/yaml_to_shoulda.rb +0 -25
  235. data/vendor/TextMate/Ruby Shoulda.tmbundle/Syntaxes/Ruby on Rails (Shoulda).tmLanguage +0 -166
  236. data/vendor/TextMate/Ruby Shoulda.tmbundle/info.plist +0 -304
  237. data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +0 -37
  238. data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +0 -52
  239. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/catch_exception.rb +0 -39
  240. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +0 -118
  241. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/stdin_dialog.rb +0 -14
  242. data/vendor/TextMate/Zena.tmbundle/info.plist +0 -17
  243. data/vendor/plugins/selenium-on-rails/CHANGELOG +0 -125
  244. data/vendor/plugins/selenium-on-rails/LICENSE-2.0.txt +0 -202
  245. data/vendor/plugins/selenium-on-rails/README.md +0 -202
  246. data/vendor/plugins/selenium-on-rails/Rakefile +0 -38
  247. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumController.html +0 -265
  248. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumHelper.html +0 -148
  249. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails.html +0 -126
  250. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/FixtureLoader.html +0 -231
  251. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/PartialsSupport.html +0 -195
  252. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Paths.html +0 -295
  253. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/RSelenese.html +0 -219
  254. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Renderer.html +0 -156
  255. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Selenese.html +0 -179
  256. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/SuiteRenderer.html +0 -223
  257. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilder.html +0 -441
  258. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderAccessors.html +0 -3098
  259. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderActions.html +0 -2080
  260. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserAccessors.html +0 -116
  261. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserActions.html +0 -116
  262. data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRailsConfig.html +0 -150
  263. data/vendor/plugins/selenium-on-rails/doc/files/CHANGELOG.html +0 -422
  264. data/vendor/plugins/selenium-on-rails/doc/files/README.html +0 -321
  265. data/vendor/plugins/selenium-on-rails/doc/files/lib/controllers/selenium_controller_rb.html +0 -108
  266. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_helper_rb.html +0 -101
  267. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/acceptance_test_runner_rb.html +0 -222
  268. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/fixture_loader_rb.html +0 -109
  269. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/partials_support_rb.html +0 -111
  270. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/paths_rb.html +0 -101
  271. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/renderer_rb.html +0 -101
  272. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/rselenese_rb.html +0 -118
  273. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/selenese_rb.html +0 -101
  274. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/suite_renderer_rb.html +0 -101
  275. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_accessors_rb.html +0 -114
  276. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_actions_rb.html +0 -113
  277. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_rb.html +0 -120
  278. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_config_rb.html +0 -108
  279. data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_rb.html +0 -115
  280. data/vendor/plugins/selenium-on-rails/doc/fr_class_index.html +0 -42
  281. data/vendor/plugins/selenium-on-rails/doc/fr_file_index.html +0 -43
  282. data/vendor/plugins/selenium-on-rails/doc/fr_method_index.html +0 -182
  283. data/vendor/plugins/selenium-on-rails/doc/index.html +0 -24
  284. data/vendor/plugins/selenium-on-rails/doc/rdoc-style.css +0 -208
  285. data/vendor/plugins/selenium-on-rails/generators/selenium/USAGE +0 -19
  286. data/vendor/plugins/selenium-on-rails/generators/selenium/selenium_generator.rb +0 -50
  287. data/vendor/plugins/selenium-on-rails/generators/selenium/templates/rhtml.rhtml +0 -16
  288. data/vendor/plugins/selenium-on-rails/generators/selenium/templates/rselenese.rhtml +0 -14
  289. data/vendor/plugins/selenium-on-rails/generators/selenium/templates/selenese.rhtml +0 -11
  290. data/vendor/plugins/selenium-on-rails/init.rb +0 -15
  291. data/vendor/plugins/selenium-on-rails/lib/controllers/selenium_controller.rb +0 -122
  292. data/vendor/plugins/selenium-on-rails/lib/controllers/switch_environment_controller.rb +0 -16
  293. data/vendor/plugins/selenium-on-rails/lib/selenium_helper.rb +0 -8
  294. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails.rb +0 -11
  295. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/acceptance_test_runner.rb +0 -215
  296. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/fixture_loader.rb +0 -57
  297. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/partials_support.rb +0 -36
  298. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/paths.rb +0 -61
  299. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/renderer.rb +0 -20
  300. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/rselenese.rb +0 -44
  301. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/selenese.rb +0 -87
  302. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/suite_renderer.rb +0 -56
  303. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder.rb +0 -116
  304. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_accessors.rb +0 -1002
  305. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_actions.rb +0 -514
  306. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_accessors.rb.example +0 -91
  307. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_actions.rb.example +0 -24
  308. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb +0 -30
  309. data/vendor/plugins/selenium-on-rails/lib/views/layouts/layout.rhtml +0 -18
  310. data/vendor/plugins/selenium-on-rails/lib/views/record.rhtml +0 -5
  311. data/vendor/plugins/selenium-on-rails/lib/views/selenium_helper.rb +0 -9
  312. data/vendor/plugins/selenium-on-rails/lib/views/setup.rhtml +0 -67
  313. data/vendor/plugins/selenium-on-rails/lib/views/test_suite.rhtml +0 -26
  314. data/vendor/plugins/selenium-on-rails/routes.rb +0 -24
  315. data/vendor/plugins/selenium-on-rails/selenium-core/Blank.html +0 -7
  316. data/vendor/plugins/selenium-on-rails/selenium-core/InjectedRemoteRunner.html +0 -8
  317. data/vendor/plugins/selenium-on-rails/selenium-core/RemoteRunner.html +0 -110
  318. data/vendor/plugins/selenium-on-rails/selenium-core/SeleniumLog.html +0 -109
  319. data/vendor/plugins/selenium-on-rails/selenium-core/TestPrompt.html +0 -145
  320. data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner-splash.html +0 -55
  321. data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner.hta +0 -177
  322. data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner.html +0 -177
  323. data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/butmin.gif +0 -0
  324. data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/butplus.gif +0 -0
  325. data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.css +0 -298
  326. data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.html +0 -16
  327. data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/selenium-domviewer.js +0 -205
  328. data/vendor/plugins/selenium-on-rails/selenium-core/icons/all.png +0 -0
  329. data/vendor/plugins/selenium-on-rails/selenium-core/icons/continue.png +0 -0
  330. data/vendor/plugins/selenium-on-rails/selenium-core/icons/continue_disabled.png +0 -0
  331. data/vendor/plugins/selenium-on-rails/selenium-core/icons/pause.png +0 -0
  332. data/vendor/plugins/selenium-on-rails/selenium-core/icons/pause_disabled.png +0 -0
  333. data/vendor/plugins/selenium-on-rails/selenium-core/icons/selected.png +0 -0
  334. data/vendor/plugins/selenium-on-rails/selenium-core/icons/step.png +0 -0
  335. data/vendor/plugins/selenium-on-rails/selenium-core/icons/step_disabled.png +0 -0
  336. data/vendor/plugins/selenium-on-rails/selenium-core/iedoc-core.xml +0 -1759
  337. data/vendor/plugins/selenium-on-rails/selenium-core/iedoc.xml +0 -1800
  338. data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/cssQuery-p.js +0 -6
  339. data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level2.js +0 -142
  340. data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level3.js +0 -150
  341. data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-standard.js +0 -53
  342. data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery.js +0 -356
  343. data/vendor/plugins/selenium-on-rails/selenium-core/lib/prototype.js +0 -2006
  344. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/builder.js +0 -101
  345. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/controls.js +0 -815
  346. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/dragdrop.js +0 -915
  347. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/effects.js +0 -958
  348. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/scriptaculous.js +0 -47
  349. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/slider.js +0 -283
  350. data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/unittest.js +0 -383
  351. data/vendor/plugins/selenium-on-rails/selenium-core/lib/snapsie.js +0 -91
  352. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/find_matching_child.js +0 -69
  353. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/htmlutils.js +0 -1616
  354. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/injection.html +0 -72
  355. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-api.js +0 -3184
  356. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserbot.js +0 -2300
  357. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserdetect.js +0 -153
  358. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-commandhandlers.js +0 -377
  359. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-executionloop.js +0 -175
  360. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-logging.js +0 -148
  361. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-remoterunner.js +0 -695
  362. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-testrunner.js +0 -1362
  363. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-version.js +0 -5
  364. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-doc.html +0 -803
  365. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-element.js +0 -1537
  366. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-map-sample.js +0 -979
  367. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js +0 -3
  368. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js.sample +0 -75
  369. data/vendor/plugins/selenium-on-rails/selenium-core/scripts/xmlextras.js +0 -153
  370. data/vendor/plugins/selenium-on-rails/selenium-core/selenium-logo.png +0 -0
  371. data/vendor/plugins/selenium-on-rails/selenium-core/selenium-test.css +0 -43
  372. data/vendor/plugins/selenium-on-rails/selenium-core/selenium.css +0 -316
  373. data/vendor/plugins/selenium-on-rails/selenium-core/xpath/dom.js +0 -566
  374. data/vendor/plugins/selenium-on-rails/selenium-core/xpath/javascript-xpath-0.1.11.js +0 -2816
  375. data/vendor/plugins/selenium-on-rails/selenium-core/xpath/util.js +0 -549
  376. data/vendor/plugins/selenium-on-rails/selenium-core/xpath/xmltoken.js +0 -149
  377. data/vendor/plugins/selenium-on-rails/selenium-core/xpath/xpath.js +0 -2450
  378. data/vendor/plugins/selenium-on-rails/tasks/test_acceptance.rake +0 -8
  379. data/vendor/plugins/selenium-on-rails/test/fixtures/config.yml +0 -37
  380. data/vendor/plugins/selenium-on-rails/test/fixtures/selenium.yml +0 -27
  381. data/vendor/plugins/selenium-on-rails/test/paths_test.rb +0 -72
  382. data/vendor/plugins/selenium-on-rails/test/renderer_test.rb +0 -157
  383. data/vendor/plugins/selenium-on-rails/test/rselenese_test.rb +0 -708
  384. data/vendor/plugins/selenium-on-rails/test/selenese_test.rb +0 -242
  385. data/vendor/plugins/selenium-on-rails/test/selenium_controller_test.rb +0 -67
  386. data/vendor/plugins/selenium-on-rails/test/selenium_on_rails_config_test.rb +0 -43
  387. data/vendor/plugins/selenium-on-rails/test/selenium_support_test.rb +0 -35
  388. data/vendor/plugins/selenium-on-rails/test/setup_test.rb +0 -31
  389. data/vendor/plugins/selenium-on-rails/test/suite_renderer_test.rb +0 -109
  390. data/vendor/plugins/selenium-on-rails/test/switch_environment_controller_test.rb +0 -17
  391. data/vendor/plugins/selenium-on-rails/test/test_builder_functions_authortest.rb +0 -51
  392. data/vendor/plugins/selenium-on-rails/test/test_helper.rb +0 -101
  393. data/vendor/plugins/selenium-on-rails/test_data/_partial.rsel +0 -1
  394. data/vendor/plugins/selenium-on-rails/test_data/own_layout.html +0 -12
  395. data/vendor/plugins/selenium-on-rails/test_data/partials/_html.html +0 -6
  396. data/vendor/plugins/selenium-on-rails/test_data/partials/_nesting.rsel +0 -2
  397. data/vendor/plugins/selenium-on-rails/test_data/partials/_rhtml.rhtml +0 -6
  398. data/vendor/plugins/selenium-on-rails/test_data/partials/_rsel.rsel +0 -1
  399. data/vendor/plugins/selenium-on-rails/test_data/partials/_sel.sel +0 -5
  400. data/vendor/plugins/selenium-on-rails/test_data/partials/all_partials.rsel +0 -5
  401. data/vendor/plugins/selenium-on-rails/test_data/rhtml.rhtml +0 -7
  402. data/vendor/plugins/selenium-on-rails/test_data/rselenese.rsel +0 -8
  403. data/vendor/plugins/selenium-on-rails/test_data/selenese.sel +0 -7
  404. data/vendor/plugins/selenium-on-rails/test_data/suite_one/subsuite/suite_one_subsuite_testcase.sel +0 -1
  405. data/vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase1.sel +0 -1
  406. data/vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase2.sel +0 -1
  407. data/vendor/plugins/selenium-on-rails/test_data/suite_two/suite_two_testcase.sel +0 -1
@@ -1,1537 +0,0 @@
1
- //******************************************************************************
2
- // Globals, including constants
3
-
4
- var UI_GLOBAL = {
5
- UI_PREFIX: 'ui'
6
- , XHTML_DOCTYPE: '<!DOCTYPE html PUBLIC '
7
- + '"-//W3C//DTD XHTML 1.0 Strict//EN" '
8
- + '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
9
- , XHTML_XMLNS: 'http://www.w3.org/1999/xhtml'
10
- };
11
-
12
- //*****************************************************************************
13
- // Exceptions
14
-
15
- function UIElementException(message)
16
- {
17
- this.message = message;
18
- this.name = 'UIElementException';
19
- }
20
-
21
- function UIArgumentException(message)
22
- {
23
- this.message = message;
24
- this.name = 'UIArgumentException';
25
- }
26
-
27
- function PagesetException(message)
28
- {
29
- this.message = message;
30
- this.name = 'PagesetException';
31
- }
32
-
33
- function UISpecifierException(message)
34
- {
35
- this.message = message;
36
- this.name = 'UISpecifierException';
37
- }
38
-
39
- function CommandMatcherException(message)
40
- {
41
- this.message = message;
42
- this.name = 'CommandMatcherException';
43
- }
44
-
45
- //*****************************************************************************
46
- // UI-Element core
47
-
48
- /**
49
- * The UIElement object. This has been crafted along with UIMap to make
50
- * specifying UI elements using JSON as simple as possible. Object construction
51
- * will fail if 1) a proper name isn't provided, 2) a faulty args argument is
52
- * given, or 3) getLocator() returns undefined for a valid permutation of
53
- * default argument values. See ui-doc.html for the documentation on the
54
- * builder syntax.
55
- *
56
- * @param uiElementShorthand an object whose contents conform to the
57
- * UI-Element builder syntax.
58
- *
59
- * @return a new UIElement object
60
- * @throws UIElementException
61
- */
62
- function UIElement(uiElementShorthand)
63
- {
64
- // a shorthand object might look like:
65
- //
66
- // {
67
- // name: 'topic'
68
- // , description: 'sidebar links to topic categories'
69
- // , args: [
70
- // {
71
- // name: 'name'
72
- // , description: 'the name of the topic'
73
- // , defaultValues: topLevelTopics
74
- // }
75
- // ]
76
- // , getLocator: function(args) {
77
- // return this._listXPath +
78
- // "/a[text()=" + args.name.quoteForXPath() + "]";
79
- // }
80
- // , getGenericLocator: function() {
81
- // return this._listXPath + '/a';
82
- // }
83
- // // maintain testcases for getLocator()
84
- // , testcase1: {
85
- // // defaultValues used if args not specified
86
- // args: { name: 'foo' }
87
- // , xhtml: '<div id="topiclist">'
88
- // + '<ul><li><a expected-result="1">foo</a></li></ul>'
89
- // + '</div>'
90
- // }
91
- // // set a local element variable
92
- // , _listXPath: "//div[@id='topiclist']/ul/li"
93
- // }
94
- //
95
- // name cannot be null or an empty string. Enforce the same requirement for
96
- // the description.
97
-
98
- /**
99
- * Recursively returns all permutations of argument-value pairs, given
100
- * a list of argument definitions. Each argument definition will have
101
- * a set of default values to use in generating said pairs. If an argument
102
- * has no default values defined, it will not be included among the
103
- * permutations.
104
- *
105
- * @param args a list of UIArguments
106
- * @param opt_inDocument (optional)
107
- * @return a list of associative arrays containing key value pairs
108
- */
109
- this.permuteArgs = function(args, opt_inDocument) {
110
- var permutations = [];
111
- for (var i = 0; i < args.length; ++i) {
112
- var arg = args[i];
113
- var defaultValues = (arguments.length > 1)
114
- ? arg.getDefaultValues(opt_inDocument)
115
- : arg.getDefaultValues();
116
-
117
- // skip arguments for which no default values are defined
118
- if (defaultValues.length == 0) {
119
- continue;
120
- }
121
- for (var j = 0; j < defaultValues.length; ++j) {
122
- var value = defaultValues[j];
123
- var nextPermutations = this.permuteArgs(args.slice(i+1));
124
- if (nextPermutations.length == 0) {
125
- var permutation = {};
126
- permutation[arg.name] = value + ''; // make into string
127
- permutations.push(permutation);
128
- }
129
- else {
130
- for (var k = 0; k < nextPermutations.length; ++k) {
131
- nextPermutations[k][arg.name] = value + '';
132
- permutations.push(nextPermutations[k]);
133
- }
134
- }
135
- }
136
- break;
137
- }
138
- return permutations;
139
- }
140
-
141
-
142
-
143
- /**
144
- * Returns a list of all testcases for this UIElement.
145
- */
146
- this.getTestcases = function()
147
- {
148
- return this.testcases;
149
- }
150
-
151
-
152
-
153
- /**
154
- * Run all unit tests, stopping at the first failure, if any. Return true
155
- * if no failures encountered, false otherwise. See the following thread
156
- * regarding use of getElementById() on XML documents created by parsing
157
- * text via the DOMParser:
158
- *
159
- * http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/2b1b82b3c53a1282/
160
- */
161
- this.test = function()
162
- {
163
- var parser = new DOMParser();
164
- var testcases = this.getTestcases();
165
- testcaseLoop: for (var i = 0; i < testcases.length; ++i) {
166
- var testcase = testcases[i];
167
- var xhtml = UI_GLOBAL.XHTML_DOCTYPE + '<html xmlns="'
168
- + UI_GLOBAL.XHTML_XMLNS + '">' + testcase.xhtml + '</html>';
169
- var doc = parser.parseFromString(xhtml, "text/xml");
170
- if (doc.firstChild.nodeName == 'parsererror') {
171
- safe_alert('Error parsing XHTML in testcase "' + testcase.name
172
- + '" for UI element "' + this.name + '": ' + "\n"
173
- + doc.firstChild.firstChild.nodeValue);
174
- }
175
-
176
- // we're no longer using the default locators when testing, because
177
- // args is now required
178
- var locator = parse_locator(this.getLocator(testcase.args));
179
- var results;
180
- if (locator.type == 'xpath' || (locator.type == 'implicit' &&
181
- locator.string.substring(0, 2) == '//')) {
182
- // try using the javascript xpath engine to avoid namespace
183
- // issues. The xpath does have to be lowercase however, it
184
- // seems.
185
- results = eval_xpath(locator.string, doc,
186
- { allowNativeXpath: false, returnOnFirstMatch: true });
187
- }
188
- else {
189
- // piece the locator back together
190
- locator = (locator.type == 'implicit')
191
- ? locator.string
192
- : locator.type + '=' + locator.string;
193
- results = eval_locator(locator, doc);
194
- }
195
- if (results.length && results[0].hasAttribute('expected-result')) {
196
- continue testcaseLoop;
197
- }
198
-
199
- // testcase failed
200
- if (is_IDE()) {
201
- var msg = 'Testcase "' + testcase.name
202
- + '" failed for UI element "' + this.name + '":';
203
- if (!results.length) {
204
- msg += '\n"' + locator + '" did not match any elements!';
205
- }
206
- else {
207
- msg += '\n' + results[0] + ' was not the expected result!';
208
- }
209
- safe_alert(msg);
210
- }
211
- return false;
212
- }
213
- return true;
214
- };
215
-
216
-
217
-
218
- /**
219
- * Creates a set of locators using permutations of default values for
220
- * arguments used in the locator construction. The set is returned as an
221
- * object mapping locators to key-value arguments objects containing the
222
- * values passed to getLocator() to create the locator.
223
- *
224
- * @param opt_inDocument (optional) the document object of the "current"
225
- * page when this method is invoked. Some arguments
226
- * may have default value lists that are calculated
227
- * based on the contents of the page.
228
- *
229
- * @return a list of locator strings
230
- * @throws UIElementException
231
- */
232
- this.getDefaultLocators = function(opt_inDocument) {
233
- var defaultLocators = {};
234
- if (this.args.length == 0) {
235
- defaultLocators[this.getLocator({})] = {};
236
- }
237
- else {
238
- var permutations = this.permuteArgs(this.args, opt_inDocument);
239
- if (permutations.length != 0) {
240
- for (var i = 0; i < permutations.length; ++i) {
241
- var args = permutations[i];
242
- var locator = this.getLocator(args);
243
- if (!locator) {
244
- throw new UIElementException('Error in UIElement(): '
245
- + 'no getLocator return value for element "' + name
246
- + '"');
247
- }
248
- defaultLocators[locator] = args;
249
- }
250
- }
251
- else {
252
- // try using no arguments. If it doesn't work, fine.
253
- try {
254
- var locator = this.getLocator();
255
- defaultLocators[locator] = {};
256
- }
257
- catch (e) {
258
- safe_log('debug', e.message);
259
- }
260
- }
261
- }
262
- return defaultLocators;
263
- };
264
-
265
-
266
-
267
- /**
268
- * Validate the structure of the shorthand notation this object is being
269
- * initialized with. Throws an exception if there's a validation error.
270
- *
271
- * @param uiElementShorthand
272
- *
273
- * @throws UIElementException
274
- */
275
- this.validate = function(uiElementShorthand)
276
- {
277
- var msg = "UIElement validation error:\n" + print_r(uiElementShorthand);
278
- if (!uiElementShorthand.name) {
279
- throw new UIElementException(msg + 'no name specified!');
280
- }
281
- if (!uiElementShorthand.description) {
282
- throw new UIElementException(msg + 'no description specified!');
283
- }
284
- if (!uiElementShorthand.locator
285
- && !uiElementShorthand.getLocator
286
- && !uiElementShorthand.xpath
287
- && !uiElementShorthand.getXPath) {
288
- throw new UIElementException(msg + 'no locator specified!');
289
- }
290
- };
291
-
292
-
293
-
294
- this.init = function(uiElementShorthand)
295
- {
296
- this.validate(uiElementShorthand);
297
-
298
- this.name = uiElementShorthand.name;
299
- this.description = uiElementShorthand.description;
300
-
301
- // construct a new getLocator() method based on the locator property,
302
- // or use the provided function. We're deprecating the xpath property
303
- // and getXPath() function, but still allow for them for backwards
304
- // compatability.
305
- if (uiElementShorthand.locator) {
306
- this.getLocator = function(args) {
307
- return uiElementShorthand.locator;
308
- };
309
- }
310
- else if (uiElementShorthand.getLocator) {
311
- this.getLocator = uiElementShorthand.getLocator;
312
- }
313
- else if (uiElementShorthand.xpath) {
314
- this.getLocator = function(args) {
315
- return uiElementShorthand.xpath;
316
- };
317
- }
318
- else {
319
- this.getLocator = uiElementShorthand.getXPath;
320
- }
321
-
322
- if (uiElementShorthand.genericLocator) {
323
- this.getGenericLocator = function() {
324
- return uiElementShorthand.genericLocator;
325
- };
326
- }
327
- else if (uiElementShorthand.getGenericLocator) {
328
- this.getGenericLocator = uiElementShorthand.getGenericLocator;
329
- }
330
-
331
- if (uiElementShorthand.getOffsetLocator) {
332
- this.getOffsetLocator = uiElementShorthand.getOffsetLocator;
333
- }
334
-
335
- // get the testcases and local variables
336
- this.testcases = [];
337
- var localVars = {};
338
- for (var attr in uiElementShorthand) {
339
- if (attr.match(/^testcase/)) {
340
- var testcase = uiElementShorthand[attr];
341
- if (uiElementShorthand.args &&
342
- uiElementShorthand.args.length && !testcase.args) {
343
- safe_alert('No args defined in ' + attr + ' for UI element '
344
- + this.name + '! Skipping testcase.');
345
- continue;
346
- }
347
- testcase.name = attr;
348
- this.testcases.push(testcase);
349
- }
350
- else if (attr.match(/^_/)) {
351
- this[attr] = uiElementShorthand[attr];
352
- localVars[attr] = uiElementShorthand[attr];
353
- }
354
- }
355
-
356
- // create the arguments
357
- this.args = []
358
- this.argsOrder = [];
359
- if (uiElementShorthand.args) {
360
- for (var i = 0; i < uiElementShorthand.args.length; ++i) {
361
- var arg = new UIArgument(uiElementShorthand.args[i], localVars);
362
- this.args.push(arg);
363
- this.argsOrder.push(arg.name);
364
-
365
- // if an exception is thrown when invoking getDefaultValues()
366
- // with no parameters passed in, assume the method requires an
367
- // inDocument parameter, and thus may only be invoked at run
368
- // time. Mark the UI element object accordingly.
369
- try {
370
- arg.getDefaultValues();
371
- }
372
- catch (e) {
373
- this.isDefaultLocatorConstructionDeferred = true;
374
- }
375
- }
376
-
377
- }
378
-
379
- if (!this.isDefaultLocatorConstructionDeferred) {
380
- this.defaultLocators = this.getDefaultLocators();
381
- }
382
- };
383
-
384
-
385
-
386
- this.init(uiElementShorthand);
387
- }
388
-
389
- // hang this off the UIElement "namespace"
390
- UIElement.defaultOffsetLocatorStrategy = function(locatedElement, pageElement) {
391
- if (is_ancestor(locatedElement, pageElement)) {
392
- var offsetLocator;
393
- var recorder = Recorder.get(locatedElement.ownerDocument.defaultView);
394
- var builderNames = [
395
- 'xpath:link'
396
- , 'xpath:img'
397
- , 'xpath:attributes'
398
- , 'xpath:idRelative'
399
- , 'xpath:href'
400
- , 'xpath:position'
401
- ];
402
- for (var i = 0; i < builderNames.length; ++i) {
403
- offsetLocator = recorder.locatorBuilders
404
- .buildWith(builderNames[i], pageElement, locatedElement);
405
- if (offsetLocator) {
406
- return offsetLocator;
407
- }
408
- }
409
- }
410
- return null;
411
- };
412
-
413
-
414
-
415
- /**
416
- * Constructs a UIArgument. This is mostly for checking that the values are
417
- * valid.
418
- *
419
- * @param uiArgumentShorthand
420
- * @param localVars
421
- *
422
- * @throws UIArgumentException
423
- */
424
- function UIArgument(uiArgumentShorthand, localVars)
425
- {
426
- /**
427
- * @param uiArgumentShorthand
428
- *
429
- * @throws UIArgumentException
430
- */
431
- this.validate = function(uiArgumentShorthand)
432
- {
433
- var msg = "UIArgument validation error:\n"
434
- + print_r(uiArgumentShorthand);
435
-
436
- // try really hard to throw an exception!
437
- if (!uiArgumentShorthand.name) {
438
- throw new UIArgumentException(msg + 'no name specified!');
439
- }
440
- if (!uiArgumentShorthand.description) {
441
- throw new UIArgumentException(msg + 'no description specified!');
442
- }
443
- if (!uiArgumentShorthand.defaultValues &&
444
- !uiArgumentShorthand.getDefaultValues) {
445
- throw new UIArgumentException(msg + 'no default values specified!');
446
- }
447
- };
448
-
449
-
450
-
451
- /**
452
- * @param uiArgumentShorthand
453
- * @param localVars a list of local variables
454
- */
455
- this.init = function(uiArgumentShorthand, localVars)
456
- {
457
- this.validate(uiArgumentShorthand);
458
-
459
- this.name = uiArgumentShorthand.name;
460
- this.description = uiArgumentShorthand.description;
461
-
462
- if (uiArgumentShorthand.defaultValues) {
463
- var defaultValues = uiArgumentShorthand.defaultValues;
464
- this.getDefaultValues =
465
- function() { return defaultValues; }
466
- }
467
- else {
468
- this.getDefaultValues = uiArgumentShorthand.getDefaultValues;
469
- }
470
-
471
- for (var name in localVars) {
472
- this[name] = localVars[name];
473
- }
474
- }
475
-
476
-
477
-
478
- this.init(uiArgumentShorthand, localVars);
479
- }
480
-
481
-
482
-
483
- /**
484
- * The UISpecifier constructor is overloaded. If less than three arguments are
485
- * provided, the first argument will be considered a UI specifier string, and
486
- * will be split out accordingly. Otherwise, the first argument will be
487
- * considered the path.
488
- *
489
- * @param uiSpecifierStringOrPagesetName a UI specifier string, or the pageset
490
- * name of the UI specifier
491
- * @param elementName the name of the element
492
- * @param args an object associating keys to values
493
- *
494
- * @return new UISpecifier object
495
- */
496
- function UISpecifier(uiSpecifierStringOrPagesetName, elementName, args)
497
- {
498
- /**
499
- * Initializes this object from a UI specifier string of the form:
500
- *
501
- * pagesetName::elementName(arg1=value1, arg2=value2, ...)
502
- *
503
- * into its component parts, and returns them as an object.
504
- *
505
- * @return an object containing the components of the UI specifier
506
- * @throws UISpecifierException
507
- */
508
- this._initFromUISpecifierString = function(uiSpecifierString) {
509
- var matches = /^(.*)::([^\(]+)\((.*)\)$/.exec(uiSpecifierString);
510
- if (matches == null) {
511
- throw new UISpecifierException('Error in '
512
- + 'UISpecifier._initFromUISpecifierString(): "'
513
- + this.string + '" is not a valid UI specifier string');
514
- }
515
- this.pagesetName = matches[1];
516
- this.elementName = matches[2];
517
- this.args = (matches[3]) ? parse_kwargs(matches[3]) : {};
518
- };
519
-
520
-
521
-
522
- /**
523
- * Override the toString() method to return the UI specifier string when
524
- * evaluated in a string context. Combines the UI specifier components into
525
- * a canonical UI specifier string and returns it.
526
- *
527
- * @return a UI specifier string
528
- */
529
- this.toString = function() {
530
- // empty string is acceptable for the path, but it must be defined
531
- if (this.pagesetName == undefined) {
532
- throw new UISpecifierException('Error in UISpecifier.toString(): "'
533
- + this.pagesetName + '" is not a valid UI specifier pageset '
534
- + 'name');
535
- }
536
- if (!this.elementName) {
537
- throw new UISpecifierException('Error in UISpecifier.unparse(): "'
538
- + this.elementName + '" is not a valid UI specifier element '
539
- + 'name');
540
- }
541
- if (!this.args) {
542
- throw new UISpecifierException('Error in UISpecifier.unparse(): "'
543
- + this.args + '" are not valid UI specifier args');
544
- }
545
-
546
- uiElement = UIMap.getInstance()
547
- .getUIElement(this.pagesetName, this.elementName);
548
- if (uiElement != null) {
549
- var kwargs = to_kwargs(this.args, uiElement.argsOrder);
550
- }
551
- else {
552
- // probably under unit test
553
- var kwargs = to_kwargs(this.args);
554
- }
555
- return this.pagesetName + '::' + this.elementName + '(' + kwargs + ')';
556
- };
557
-
558
-
559
-
560
- // construct the object
561
- if (arguments.length < 2) {
562
- this._initFromUISpecifierString(uiSpecifierStringOrPagesetName);
563
- }
564
- else {
565
- this.pagesetName = uiSpecifierStringOrPagesetName;
566
- this.elementName = elementName;
567
- this.args = (args) ? clone(args) : {};
568
- }
569
- }
570
-
571
-
572
-
573
- function Pageset(pagesetShorthand)
574
- {
575
- /**
576
- * Returns true if the page is included in this pageset, false otherwise.
577
- * The page is specified by a document object.
578
- *
579
- * @param inDocument the document object representing the page
580
- */
581
- this.contains = function(inDocument)
582
- {
583
- var urlParts = parseUri(unescape(inDocument.location.href));
584
- var path = urlParts.path
585
- .replace(/^\//, "")
586
- .replace(/\/$/, "");
587
- if (!this.pathRegexp.test(path)) {
588
- return false;
589
- }
590
- for (var paramName in this.paramRegexps) {
591
- var paramRegexp = this.paramRegexps[paramName];
592
- if (!paramRegexp.test(urlParts.queryKey[paramName])) {
593
- return false;
594
- }
595
- }
596
- if (!this.pageContent(inDocument)) {
597
- return false;
598
- }
599
-
600
- return true;
601
- }
602
-
603
-
604
-
605
- this.getUIElements = function()
606
- {
607
- var uiElements = [];
608
- for (var uiElementName in this.uiElements) {
609
- uiElements.push(this.uiElements[uiElementName]);
610
- }
611
- return uiElements;
612
- };
613
-
614
-
615
-
616
- /**
617
- * Returns a list of UI specifier string stubs representing all UI elements
618
- * for this pageset. Stubs contain all required arguments, but leave
619
- * argument values blank. Each element stub is paired with the element's
620
- * description.
621
- *
622
- * @return a list of UI specifier string stubs
623
- */
624
- this.getUISpecifierStringStubs = function()
625
- {
626
- var stubs = [];
627
- for (var name in this.uiElements) {
628
- var uiElement = this.uiElements[name];
629
- var args = {};
630
- for (var i = 0; i < uiElement.args.length; ++i) {
631
- args[uiElement.args[i].name] = '';
632
- }
633
- var uiSpecifier = new UISpecifier(this.name, uiElement.name, args);
634
- stubs.push([
635
- UI_GLOBAL.UI_PREFIX + '=' + uiSpecifier.toString()
636
- , uiElement.description
637
- ]);
638
- }
639
- return stubs;
640
- }
641
-
642
-
643
-
644
- /**
645
- * Throws an exception on validation failure.
646
- */
647
- this._validate = function(pagesetShorthand)
648
- {
649
- var msg = "Pageset validation error:\n"
650
- + print_r(pagesetShorthand);
651
- if (!pagesetShorthand.name) {
652
- throw new PagesetException(msg + 'no name specified!');
653
- }
654
- if (!pagesetShorthand.description) {
655
- throw new PagesetException(msg + 'no description specified!');
656
- }
657
- if (!pagesetShorthand.paths &&
658
- !pagesetShorthand.pathRegexp &&
659
- !pagesetShorthand.pageContent) {
660
- throw new PagesetException(msg
661
- + 'no path, pathRegexp, or pageContent specified!');
662
- }
663
- };
664
-
665
-
666
-
667
- this.init = function(pagesetShorthand)
668
- {
669
- this._validate(pagesetShorthand);
670
-
671
- this.name = pagesetShorthand.name;
672
- this.description = pagesetShorthand.description;
673
-
674
- var pathPrefixRegexp = pagesetShorthand.pathPrefix
675
- ? RegExp.escape(pagesetShorthand.pathPrefix) : "";
676
- var pathRegexp = '^' + pathPrefixRegexp;
677
-
678
- if (pagesetShorthand.paths != undefined) {
679
- pathRegexp += '(?:';
680
- for (var i = 0; i < pagesetShorthand.paths.length; ++i) {
681
- if (i > 0) {
682
- pathRegexp += '|';
683
- }
684
- pathRegexp += RegExp.escape(pagesetShorthand.paths[i]);
685
- }
686
- pathRegexp += ')$';
687
- }
688
- else if (pagesetShorthand.pathRegexp) {
689
- pathRegexp += '(?:' + pagesetShorthand.pathRegexp + ')$';
690
- }
691
-
692
- this.pathRegexp = new RegExp(pathRegexp);
693
- this.paramRegexps = {};
694
- for (var paramName in pagesetShorthand.paramRegexps) {
695
- this.paramRegexps[paramName] =
696
- new RegExp(pagesetShorthand.paramRegexps[paramName]);
697
- }
698
- this.pageContent = pagesetShorthand.pageContent ||
699
- function() { return true; };
700
- this.uiElements = {};
701
- };
702
-
703
-
704
-
705
- this.init(pagesetShorthand);
706
- }
707
-
708
-
709
-
710
- /**
711
- * Construct the UI map object, and return it. Once the object is instantiated,
712
- * it binds to a global variable and will not leave scope.
713
- *
714
- * @return new UIMap object
715
- */
716
- function UIMap()
717
- {
718
- // the singleton pattern, split into two parts so that "new" can still
719
- // be used, in addition to "getInstance()"
720
- UIMap.self = this;
721
-
722
- // need to attach variables directly to the Editor object in order for them
723
- // to be in scope for Editor methods
724
- if (is_IDE()) {
725
- Editor.uiMap = this;
726
- Editor.UI_PREFIX = UI_GLOBAL.UI_PREFIX;
727
- }
728
-
729
- this.pagesets = new Object();
730
-
731
-
732
-
733
- /**
734
- * pageset[pagesetName]
735
- * regexp
736
- * elements[elementName]
737
- * UIElement
738
- */
739
- this.addPageset = function(pagesetShorthand)
740
- {
741
- try {
742
- var pageset = new Pageset(pagesetShorthand);
743
- }
744
- catch (e) {
745
- safe_alert("Could not create pageset from shorthand:\n"
746
- + print_r(pagesetShorthand) + "\n" + e.message);
747
- return false;
748
- }
749
-
750
- if (this.pagesets[pageset.name]) {
751
- safe_alert('Could not add pageset "' + pageset.name
752
- + '": a pageset with that name already exists!');
753
- return false;
754
- }
755
-
756
- this.pagesets[pageset.name] = pageset;
757
- return true;
758
- };
759
-
760
-
761
-
762
- /**
763
- * @param pagesetName
764
- * @param uiElementShorthand a representation of a UIElement object in
765
- * shorthand JSON.
766
- */
767
- this.addElement = function(pagesetName, uiElementShorthand)
768
- {
769
- try {
770
- var uiElement = new UIElement(uiElementShorthand);
771
- }
772
- catch (e) {
773
- safe_alert("Could not create UI element from shorthand:\n"
774
- + print_r(uiElementShorthand) + "\n" + e.message);
775
- return false;
776
- }
777
-
778
- // run the element's unit tests only for the IDE, and only when the
779
- // IDE is starting. Make a rough guess as to the latter condition.
780
- if (is_IDE() && !editor.selDebugger && !uiElement.test()) {
781
- safe_alert('Could not add UI element "' + uiElement.name
782
- + '": failed testcases!');
783
- return false;
784
- }
785
-
786
- try {
787
- this.pagesets[pagesetName].uiElements[uiElement.name] = uiElement;
788
- }
789
- catch (e) {
790
- safe_alert("Could not add UI element '" + uiElement.name
791
- + "' to pageset '" + pagesetName + "':\n" + e.message);
792
- return false;
793
- }
794
-
795
- return true;
796
- };
797
-
798
-
799
-
800
- /**
801
- * Returns the pageset for a given UI specifier string.
802
- *
803
- * @param uiSpecifierString
804
- * @return a pageset object
805
- */
806
- this.getPageset = function(uiSpecifierString)
807
- {
808
- try {
809
- var uiSpecifier = new UISpecifier(uiSpecifierString);
810
- return this.pagesets[uiSpecifier.pagesetName];
811
- }
812
- catch (e) {
813
- return null;
814
- }
815
- }
816
-
817
-
818
-
819
- /**
820
- * Returns the UIElement that a UISpecifierString or pageset and element
821
- * pair refer to.
822
- *
823
- * @param pagesetNameOrUISpecifierString
824
- * @return a UIElement, or null if none is found associated with
825
- * uiSpecifierString
826
- */
827
- this.getUIElement = function(pagesetNameOrUISpecifierString, uiElementName)
828
- {
829
- var pagesetName = pagesetNameOrUISpecifierString;
830
- if (arguments.length == 1) {
831
- var uiSpecifierString = pagesetNameOrUISpecifierString;
832
- try {
833
- var uiSpecifier = new UISpecifier(uiSpecifierString);
834
- pagesetName = uiSpecifier.pagesetName;
835
- var uiElementName = uiSpecifier.elementName;
836
- }
837
- catch (e) {
838
- return null;
839
- }
840
- }
841
- try {
842
- return this.pagesets[pagesetName].uiElements[uiElementName];
843
- }
844
- catch (e) {
845
- return null;
846
- }
847
- };
848
-
849
-
850
-
851
- /**
852
- * Returns a list of pagesets that "contains" the provided page,
853
- * represented as a document object. Containership is defined by the
854
- * Pageset object's contain() method.
855
- *
856
- * @param inDocument the page to get pagesets for
857
- * @return a list of pagesets
858
- */
859
- this.getPagesetsForPage = function(inDocument)
860
- {
861
- var pagesets = [];
862
- for (var pagesetName in this.pagesets) {
863
- var pageset = this.pagesets[pagesetName];
864
- if (pageset.contains(inDocument)) {
865
- pagesets.push(pageset);
866
- }
867
- }
868
- return pagesets;
869
- };
870
-
871
-
872
-
873
- /**
874
- * Returns a list of all pagesets.
875
- *
876
- * @return a list of pagesets
877
- */
878
- this.getPagesets = function()
879
- {
880
- var pagesets = [];
881
- for (var pagesetName in this.pagesets) {
882
- pagesets.push(this.pagesets[pagesetName]);
883
- }
884
- return pagesets;
885
- };
886
-
887
-
888
-
889
- /**
890
- * Returns a list of elements on a page that a given UI specifier string,
891
- * maps to. If no elements are mapped to, returns an empty list..
892
- *
893
- * @param uiSpecifierString a String that specifies a UI element with
894
- * attendant argument values
895
- * @param inDocument the document object the specified UI element
896
- * appears in
897
- * @return a potentially-empty list of elements
898
- * specified by uiSpecifierString
899
- */
900
- this.getPageElements = function(uiSpecifierString, inDocument)
901
- {
902
- var locator = this.getLocator(uiSpecifierString);
903
- var results = locator ? eval_locator(locator, inDocument) : [];
904
- return results;
905
- };
906
-
907
-
908
-
909
- /**
910
- * Returns the locator string that a given UI specifier string maps to, or
911
- * null if it cannot be mapped.
912
- *
913
- * @param uiSpecifierString
914
- */
915
- this.getLocator = function(uiSpecifierString)
916
- {
917
- try {
918
- var uiSpecifier = new UISpecifier(uiSpecifierString);
919
- }
920
- catch (e) {
921
- safe_alert('Could not create UISpecifier for string "'
922
- + uiSpecifierString + '": ' + e.message);
923
- return null;
924
- }
925
-
926
- var uiElement = this.getUIElement(uiSpecifier.pagesetName,
927
- uiSpecifier.elementName);
928
- try {
929
- return uiElement.getLocator(uiSpecifier.args);
930
- }
931
- catch (e) {
932
- return null;
933
- }
934
- }
935
-
936
-
937
-
938
- /**
939
- * Finds and returns a UI specifier string given an element and the page
940
- * that it appears on.
941
- *
942
- * @param pageElement the document element to map to a UI specifier
943
- * @param inDocument the document the element appears in
944
- * @return a UI specifier string, or false if one cannot be
945
- * constructed
946
- */
947
- this.getUISpecifierString = function(pageElement, inDocument)
948
- {
949
- var is_fuzzy_match =
950
- BrowserBot.prototype.locateElementByUIElement.is_fuzzy_match;
951
- var pagesets = this.getPagesetsForPage(inDocument);
952
- for (var i = 0; i < pagesets.length; ++i) {
953
- var pageset = pagesets[i];
954
- var uiElements = pageset.getUIElements();
955
- for (var j = 0; j < uiElements.length; ++j) {
956
- var uiElement = uiElements[j];
957
-
958
- // first test against the generic locator, if there is one.
959
- // This should net some performance benefit when recording on
960
- // more complicated pages.
961
- if (uiElement.getGenericLocator) {
962
- var passedTest = false;
963
- var results =
964
- eval_locator(uiElement.getGenericLocator(), inDocument);
965
- for (var i = 0; i < results.length; ++i) {
966
- if (results[i] == pageElement) {
967
- passedTest = true;
968
- break;
969
- }
970
- }
971
- if (!passedTest) {
972
- continue;
973
- }
974
- }
975
-
976
- var defaultLocators;
977
- if (uiElement.isDefaultLocatorConstructionDeferred) {
978
- defaultLocators = uiElement.getDefaultLocators(inDocument);
979
- }
980
- else {
981
- defaultLocators = uiElement.defaultLocators;
982
- }
983
-
984
- //safe_alert(print_r(uiElement.defaultLocators));
985
- for (var locator in defaultLocators) {
986
- var locatedElements = eval_locator(locator, inDocument);
987
- if (locatedElements.length) {
988
- var locatedElement = locatedElements[0];
989
- }
990
- else {
991
- continue;
992
- }
993
-
994
- // use a heuristic to determine whether the element
995
- // specified is the "same" as the element we're matching
996
- if (is_fuzzy_match) {
997
- if (is_fuzzy_match(locatedElement, pageElement)) {
998
- return UI_GLOBAL.UI_PREFIX + '=' +
999
- new UISpecifier(pageset.name, uiElement.name,
1000
- defaultLocators[locator]);
1001
- }
1002
- }
1003
- else {
1004
- if (locatedElement == pageElement) {
1005
- return UI_GLOBAL.UI_PREFIX + '=' +
1006
- new UISpecifier(pageset.name, uiElement.name,
1007
- defaultLocators[locator]);
1008
- }
1009
- }
1010
- // ok, matching the element failed. See if an offset
1011
- // locator can complete the match.
1012
- if (uiElement.getOffsetLocator) {
1013
- for (var i = 0; i < locatedElements.length; ++i) {
1014
- var offsetLocator = uiElement
1015
- .getOffsetLocator(locatedElement, pageElement);
1016
- if (offsetLocator) {
1017
- return UI_GLOBAL.UI_PREFIX + '=' +
1018
- new UISpecifier(pageset.name,
1019
- uiElement.name,
1020
- defaultLocators[locator])
1021
- + '->' + offsetLocator;
1022
- }
1023
- }
1024
- }
1025
- }
1026
- }
1027
- }
1028
- return false;
1029
- };
1030
-
1031
-
1032
-
1033
- /**
1034
- * Returns a sorted list of UI specifier string stubs representing possible
1035
- * UI elements for all pagesets, paired the their descriptions. Stubs
1036
- * contain all required arguments, but leave argument values blank.
1037
- *
1038
- * @return a list of UI specifier string stubs
1039
- */
1040
- this.getUISpecifierStringStubs = function() {
1041
- var stubs = [];
1042
- var pagesets = this.getPagesets();
1043
- for (var i = 0; i < pagesets.length; ++i) {
1044
- stubs = stubs.concat(pagesets[i].getUISpecifierStringStubs());
1045
- }
1046
- stubs.sort(function(a, b) {
1047
- if (a[0] < b[0]) {
1048
- return -1;
1049
- }
1050
- return a[0] == b[0] ? 0 : 1;
1051
- });
1052
- return stubs;
1053
- }
1054
- }
1055
-
1056
- UIMap.getInstance = function() {
1057
- return (UIMap.self == null) ? new UIMap() : UIMap.self;
1058
- }
1059
-
1060
- //******************************************************************************
1061
- // Rollups
1062
-
1063
- /**
1064
- * The Command object isn't available in the Selenium RC. We introduce an
1065
- * object with the identical constructor. In the IDE, this will be redefined,
1066
- * which is just fine.
1067
- *
1068
- * @param command
1069
- * @param target
1070
- * @param value
1071
- */
1072
- if (typeof(Command) == 'undefined') {
1073
- function Command(command, target, value) {
1074
- this.command = command != null ? command : '';
1075
- this.target = target != null ? target : '';
1076
- this.value = value != null ? value : '';
1077
- }
1078
- }
1079
-
1080
-
1081
-
1082
- /**
1083
- * A CommandMatcher object matches commands during the application of a
1084
- * RollupRule. It's specified with a shorthand format, for example:
1085
- *
1086
- * new CommandMatcher({
1087
- * command: 'click'
1088
- * , target: 'ui=allPages::.+'
1089
- * })
1090
- *
1091
- * which is intended to match click commands whose target is an element in the
1092
- * allPages PageSet. The matching expressions are given as regular expressions;
1093
- * in the example above, the command must be "click"; "clickAndWait" would be
1094
- * acceptable if 'click.*' were used. Here's a more complete example:
1095
- *
1096
- * new CommandMatcher({
1097
- * command: 'type'
1098
- * , target: 'ui=loginPages::username()'
1099
- * , value: '.+_test'
1100
- * , updateArgs: function(command, args) {
1101
- * args.username = command.value;
1102
- * }
1103
- * })
1104
- *
1105
- * Here, the command and target are fixed, but there is variability in the
1106
- * value of the command. When a command matches, the username is saved to the
1107
- * arguments object.
1108
- */
1109
- function CommandMatcher(commandMatcherShorthand)
1110
- {
1111
- /**
1112
- * Ensure the shorthand notation used to initialize the CommandMatcher has
1113
- * all required values.
1114
- *
1115
- * @param commandMatcherShorthand an object containing information about
1116
- * the CommandMatcher
1117
- */
1118
- this.validate = function(commandMatcherShorthand) {
1119
- var msg = "CommandMatcher validation error:\n"
1120
- + print_r(commandMatcherShorthand);
1121
- if (!commandMatcherShorthand.command) {
1122
- throw new CommandMatcherException(msg + 'no command specified!');
1123
- }
1124
- if (!commandMatcherShorthand.target) {
1125
- throw new CommandMatcherException(msg + 'no target specified!');
1126
- }
1127
- if (commandMatcherShorthand.minMatches &&
1128
- commandMatcherShorthand.maxMatches &&
1129
- commandMatcherShorthand.minMatches >
1130
- commandMatcherShorthand.maxMatches) {
1131
- throw new CommandMatcherException(msg + 'minMatches > maxMatches!');
1132
- }
1133
- };
1134
-
1135
- /**
1136
- * Initialize this object.
1137
- *
1138
- * @param commandMatcherShorthand an object containing information used to
1139
- * initialize the CommandMatcher
1140
- */
1141
- this.init = function(commandMatcherShorthand) {
1142
- this.validate(commandMatcherShorthand);
1143
-
1144
- this.command = commandMatcherShorthand.command;
1145
- this.target = commandMatcherShorthand.target;
1146
- this.value = commandMatcherShorthand.value || null;
1147
- this.minMatches = commandMatcherShorthand.minMatches || 1;
1148
- this.maxMatches = commandMatcherShorthand.maxMatches || 1;
1149
- this.updateArgs = commandMatcherShorthand.updateArgs ||
1150
- function(command, args) { return args; };
1151
- };
1152
-
1153
- /**
1154
- * Determines whether a given command matches. Updates args by "reference"
1155
- * and returns true if it does; return false otherwise.
1156
- *
1157
- * @param command the command to attempt to match
1158
- */
1159
- this.isMatch = function(command) {
1160
- var re = new RegExp('^' + this.command + '$');
1161
- if (! re.test(command.command)) {
1162
- return false;
1163
- }
1164
- re = new RegExp('^' + this.target + '$');
1165
- if (! re.test(command.target)) {
1166
- return false;
1167
- }
1168
- if (this.value != null) {
1169
- re = new RegExp('^' + this.value + '$');
1170
- if (! re.test(command.value)) {
1171
- return false;
1172
- }
1173
- }
1174
-
1175
- // okay, the command matches
1176
- return true;
1177
- };
1178
-
1179
- // initialization
1180
- this.init(commandMatcherShorthand);
1181
- }
1182
-
1183
-
1184
-
1185
- function RollupRuleException(message)
1186
- {
1187
- this.message = message;
1188
- this.name = 'RollupRuleException';
1189
- }
1190
-
1191
- function RollupRule(rollupRuleShorthand)
1192
- {
1193
- /**
1194
- * Ensure the shorthand notation used to initialize the RollupRule has all
1195
- * required values.
1196
- *
1197
- * @param rollupRuleShorthand an object containing information about the
1198
- * RollupRule
1199
- */
1200
- this.validate = function(rollupRuleShorthand) {
1201
- var msg = "RollupRule validation error:\n"
1202
- + print_r(rollupRuleShorthand);
1203
- if (!rollupRuleShorthand.name) {
1204
- throw new RollupRuleException(msg + 'no name specified!');
1205
- }
1206
- if (!rollupRuleShorthand.description) {
1207
- throw new RollupRuleException(msg + 'no description specified!');
1208
- }
1209
- // rollupRuleShorthand.args is optional
1210
- if (!rollupRuleShorthand.commandMatchers &&
1211
- !rollupRuleShorthand.getRollup) {
1212
- throw new RollupRuleException(msg
1213
- + 'no command matchers specified!');
1214
- }
1215
- if (!rollupRuleShorthand.expandedCommands &&
1216
- !rollupRuleShorthand.getExpandedCommands) {
1217
- throw new RollupRuleException(msg
1218
- + 'no expanded commands specified!');
1219
- }
1220
-
1221
- return true;
1222
- };
1223
-
1224
- /**
1225
- * Initialize this object.
1226
- *
1227
- * @param rollupRuleShorthand an object containing information used to
1228
- * initialize the RollupRule
1229
- */
1230
- this.init = function(rollupRuleShorthand) {
1231
- this.validate(rollupRuleShorthand);
1232
-
1233
- this.name = rollupRuleShorthand.name;
1234
- this.description = rollupRuleShorthand.description;
1235
- this.pre = rollupRuleShorthand.pre || '';
1236
- this.post = rollupRuleShorthand.post || '';
1237
- this.alternateCommand = rollupRuleShorthand.alternateCommand;
1238
- this.args = rollupRuleShorthand.args || [];
1239
-
1240
- if (rollupRuleShorthand.commandMatchers) {
1241
- // construct the rule from the list of CommandMatchers
1242
- this.commandMatchers = [];
1243
- var matchers = rollupRuleShorthand.commandMatchers;
1244
- for (var i = 0; i < matchers.length; ++i) {
1245
- if (matchers[i].updateArgs && this.args.length == 0) {
1246
- // enforce metadata for arguments
1247
- var msg = "RollupRule validation error:\n"
1248
- + print_r(rollupRuleShorthand)
1249
- + 'no argument metadata provided!';
1250
- throw new RollupRuleException(msg);
1251
- }
1252
- this.commandMatchers.push(new CommandMatcher(matchers[i]));
1253
- }
1254
-
1255
- // returns false if the rollup doesn't match, or a rollup command
1256
- // if it does. If returned, the command contains the
1257
- // replacementIndexes property, which indicates which commands it
1258
- // substitutes for.
1259
- this.getRollup = function(commands) {
1260
- // this is a greedy matching algorithm
1261
- var replacementIndexes = [];
1262
- var commandMatcherQueue = this.commandMatchers;
1263
- var matchCount = 0;
1264
- var args = {};
1265
- for (var i = 0, j = 0; i < commandMatcherQueue.length;) {
1266
- var matcher = commandMatcherQueue[i];
1267
- if (j >= commands.length) {
1268
- // we've run out of commands! If the remaining matchers
1269
- // do not have minMatches requirements, this is a
1270
- // match. Otherwise, it's not.
1271
- if (matcher.minMatches > 0) {
1272
- return false;
1273
- }
1274
- ++i;
1275
- matchCount = 0; // unnecessary, but let's be consistent
1276
- }
1277
- else {
1278
- if (matcher.isMatch(commands[j])) {
1279
- ++matchCount;
1280
- if (matchCount == matcher.maxMatches) {
1281
- // exhausted this matcher's matches ... move on
1282
- // to next matcher
1283
- ++i;
1284
- matchCount = 0;
1285
- }
1286
- args = matcher.updateArgs(commands[j], args);
1287
- replacementIndexes.push(j);
1288
- ++j; // move on to next command
1289
- }
1290
- else {
1291
- //alert(matchCount + ', ' + matcher.minMatches);
1292
- if (matchCount < matcher.minMatches) {
1293
- return false;
1294
- }
1295
- // didn't match this time, but we've satisfied the
1296
- // requirements already ... move on to next matcher
1297
- ++i;
1298
- matchCount = 0;
1299
- // still gonna look at same command
1300
- }
1301
- }
1302
- }
1303
-
1304
- var rollup;
1305
- if (this.alternateCommand) {
1306
- rollup = new Command(this.alternateCommand,
1307
- commands[0].target, commands[0].value);
1308
- }
1309
- else {
1310
- rollup = new Command('rollup', this.name);
1311
- rollup.value = to_kwargs(args);
1312
- }
1313
- rollup.replacementIndexes = replacementIndexes;
1314
- return rollup;
1315
- };
1316
- }
1317
- else {
1318
- this.getRollup = function(commands) {
1319
- var result = rollupRuleShorthand.getRollup(commands);
1320
- if (result) {
1321
- var rollup = new Command(
1322
- result.command
1323
- , result.target
1324
- , result.value
1325
- );
1326
- rollup.replacementIndexes = result.replacementIndexes;
1327
- return rollup;
1328
- }
1329
- return false;
1330
- };
1331
- }
1332
-
1333
- this.getExpandedCommands = function(kwargs) {
1334
- var commands = [];
1335
- var expandedCommands = (rollupRuleShorthand.expandedCommands
1336
- ? rollupRuleShorthand.expandedCommands
1337
- : rollupRuleShorthand.getExpandedCommands(
1338
- parse_kwargs(kwargs)));
1339
- for (var i = 0; i < expandedCommands.length; ++i) {
1340
- var command = expandedCommands[i];
1341
- commands.push(new Command(
1342
- command.command
1343
- , command.target
1344
- , command.value
1345
- ));
1346
- }
1347
- return commands;
1348
- };
1349
- };
1350
-
1351
- this.init(rollupRuleShorthand);
1352
- }
1353
-
1354
-
1355
-
1356
- /**
1357
- *
1358
- */
1359
- function RollupManager()
1360
- {
1361
- // singleton pattern
1362
- RollupManager.self = this;
1363
-
1364
- this.init = function()
1365
- {
1366
- this.rollupRules = {};
1367
- if (is_IDE()) {
1368
- Editor.rollupManager = this;
1369
- }
1370
- };
1371
-
1372
- /**
1373
- * Adds a new RollupRule to the repository. Returns true on success, or
1374
- * false if the rule couldn't be added.
1375
- *
1376
- * @param rollupRuleShorthand shorthand JSON specification of the new
1377
- * RollupRule, possibly including CommandMatcher
1378
- * shorthand too.
1379
- * @return true if the rule was added successfully,
1380
- * false otherwise.
1381
- */
1382
- this.addRollupRule = function(rollupRuleShorthand)
1383
- {
1384
- try {
1385
- var rule = new RollupRule(rollupRuleShorthand);
1386
- this.rollupRules[rule.name] = rule;
1387
- }
1388
- catch(e) {
1389
- smart_alert("Could not create RollupRule from shorthand:\n\n"
1390
- + e.message);
1391
- return false;
1392
- }
1393
- return true;
1394
- };
1395
-
1396
- /**
1397
- * Returns a RollupRule by name.
1398
- *
1399
- * @param rollupName the name of the rule to fetch
1400
- * @return the RollupRule, or null if it isn't found.
1401
- */
1402
- this.getRollupRule = function(rollupName)
1403
- {
1404
- return (this.rollupRules[rollupName] || null);
1405
- };
1406
-
1407
- /**
1408
- * Returns a list of name-description pairs for use in populating the
1409
- * auto-populated target dropdown in the IDE. Rules that have an alternate
1410
- * command defined are not included in the list, as they are not bona-fide
1411
- * rollups.
1412
- *
1413
- * @return a list of name-description pairs
1414
- */
1415
- this.getRollupRulesForDropdown = function()
1416
- {
1417
- var targets = [];
1418
- var names = keys(this.rollupRules).sort();
1419
- for (var i = 0; i < names.length; ++i) {
1420
- var name = names[i];
1421
- if (this.rollupRules[name].alternateCommand) {
1422
- continue;
1423
- }
1424
- targets.push([ name, this.rollupRules[name].description ]);
1425
- }
1426
- return targets;
1427
- };
1428
-
1429
- /**
1430
- * Applies all rules to the current editor commands, asking the user in
1431
- * each case if it's okay to perform the replacement. The rules are applied
1432
- * repeatedly until there are no more matches. The algorithm should
1433
- * remember when the user has declined a replacement, and not ask to do it
1434
- * again.
1435
- *
1436
- * @return the list of commands with rollup replacements performed
1437
- */
1438
- this.applyRollupRules = function()
1439
- {
1440
- var commands = editor.getTestCase().commands;
1441
- var blacklistedRollups = {};
1442
-
1443
- // so long as rollups were performed, we need to keep iterating through
1444
- // the commands starting at the beginning, because further rollups may
1445
- // potentially be applied on the newly created ones.
1446
- while (true) {
1447
- var performedRollup = false;
1448
- for (var i = 0; i < commands.length; ++i) {
1449
- // iterate through commands
1450
- for (var rollupName in this.rollupRules) {
1451
- var rule = this.rollupRules[rollupName];
1452
- var rollup = rule.getRollup(commands.slice(i));
1453
- if (rollup) {
1454
- // since we passed in a sliced version of the commands
1455
- // array to the getRollup() method, we need to re-add
1456
- // the offset to the replacementIndexes
1457
- var k = 0;
1458
- for (; k < rollup.replacementIndexes.length; ++k) {
1459
- rollup.replacementIndexes[k] += i;
1460
- }
1461
-
1462
- // build the confirmation message
1463
- var msg = "Perform the following command rollup?\n\n";
1464
- for (k = 0; k < rollup.replacementIndexes.length; ++k) {
1465
- var replacementIndex = rollup.replacementIndexes[k];
1466
- var command = commands[replacementIndex];
1467
- msg += '[' + replacementIndex + ']: ';
1468
- msg += command + "\n";
1469
- }
1470
- msg += "\n";
1471
- msg += rollup;
1472
-
1473
- // check against blacklisted rollups
1474
- if (blacklistedRollups[msg]) {
1475
- continue;
1476
- }
1477
-
1478
- // highlight the potentially replaced rows
1479
- for (k = 0; k < commands.length; ++k) {
1480
- var command = commands[k];
1481
- command.result = '';
1482
- if (rollup.replacementIndexes.indexOf(k) != -1) {
1483
- command.selectedForReplacement = true;
1484
- }
1485
- editor.view.rowUpdated(replacementIndex);
1486
- }
1487
-
1488
- // get confirmation from user
1489
- if (confirm(msg)) {
1490
- // perform rollup
1491
- var deleteRanges = [];
1492
- var replacementIndexes = rollup.replacementIndexes;
1493
- for (k = 0; k < replacementIndexes.length; ++k) {
1494
- // this is expected to be list of ranges. A
1495
- // range has a start, and a list of commands.
1496
- // The deletion only checks the length of the
1497
- // command list.
1498
- deleteRanges.push({
1499
- start: replacementIndexes[k]
1500
- , commands: [ 1 ]
1501
- });
1502
- }
1503
- editor.view.executeAction(new TreeView
1504
- .DeleteCommandAction(editor.view,deleteRanges));
1505
- editor.view.insertAt(i, rollup);
1506
-
1507
- performedRollup = true;
1508
- }
1509
- else {
1510
- // cleverly remember not to try this rollup again
1511
- blacklistedRollups[msg] = true;
1512
- }
1513
-
1514
- // unhighlight
1515
- for (k = 0; k < commands.length; ++k) {
1516
- commands[k].selectedForReplacement = false;
1517
- editor.view.rowUpdated(k);
1518
- }
1519
- }
1520
- }
1521
- }
1522
- if (!performedRollup) {
1523
- break;
1524
- }
1525
- }
1526
- return commands;
1527
- };
1528
-
1529
- this.init();
1530
- }
1531
-
1532
- RollupManager.getInstance = function() {
1533
- return (RollupManager.self == null)
1534
- ? new RollupManager()
1535
- : RollupManager.self;
1536
- }
1537
-