zena 1.2.7 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
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
-