zena 1.2.7 → 1.2.8
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +80 -25
- data/Rakefile +2 -2
- data/app/controllers/columns_controller.rb +2 -2
- data/app/controllers/nodes_controller.rb +22 -29
- data/app/controllers/user_sessions_controller.rb +35 -10
- data/app/controllers/users_controller.rb +2 -2
- data/app/controllers/versions_controller.rb +2 -2
- data/app/models/group.rb +15 -1
- data/app/models/node.rb +109 -8
- data/app/models/role.rb +4 -0
- data/app/models/site.rb +64 -58
- data/app/models/template.rb +1 -1
- data/app/models/user.rb +135 -29
- data/app/models/user_session.rb +0 -1
- data/app/models/virtual_class.rb +11 -6
- data/app/views/columns/_form.html.erb +3 -1
- data/app/views/columns/_li.html.erb +1 -1
- data/app/views/columns/create.rjs +1 -1
- data/app/views/groups/_form.rhtml +16 -13
- data/app/views/relations/_form.erb +18 -6
- data/app/views/sites/_form.erb +12 -6
- data/app/views/users/_form.rhtml +23 -8
- data/app/views/users/_li.rhtml +14 -3
- data/app/views/users/index.rhtml +1 -1
- data/app/views/virtual_classes/_form.erb +12 -2
- data/app/views/zafu/default/Node-+login.zafu +8 -1
- data/app/views/zafu/default/Node-+search.zafu +1 -1
- data/bricks/acls/lib/bricks/acls.rb +1 -0
- data/bricks/acls/zena/migrate/20130903150356_longer_names_for_acl.rb +9 -0
- data/bricks/acls/zena/test/integration/acl_integration_test.rb +2 -2
- data/bricks/currency/lib/bricks/currency.rb +120 -0
- data/bricks/currency/zena/test/unit/currency_test.rb +43 -0
- data/bricks/fs_skin/lib/bricks/fs_skin.rb +1 -1
- data/bricks/fs_skin/zena/skins/blog/Node-+search.zafu +1 -1
- data/bricks/fs_skin/zena/skins/blog/Node.zafu +1 -1
- data/bricks/fs_skin/zena/test/unit/fs_skin_view_test.rb +35 -0
- data/bricks/pdf/lib/bricks/pdf.rb +1 -1
- data/bricks/sphinx/lib/bricks/sphinx.rb +2 -0
- data/bricks/sphinx/zena/init.rb +14 -0
- data/bricks/tags/zena/test/zafu/tags.yml +5 -1
- data/bricks/worker/lib/bricks/worker.rb +3 -2
- data/bricks/zena/zena/migrate/20130829093753_add_versioned_flag_to_column.rb +10 -0
- data/bricks/zena/zena/migrate/20130903084909_count_login_attempts.rb +11 -0
- data/bricks/zena/zena/migrate/20131104153126_index_fullpath.rb +10 -0
- data/bricks/zena/zena/migrate/20131104210011_rebuild_fullpath_after_change.rb +10 -0
- data/bricks/zena/zena/migrate/20131105160420_add_skin_id_to_sites.rb +9 -0
- data/bricks/zena/zena/migrate/20131105175822_add_profile_to_users.rb +11 -0
- data/bricks/zena/zena/migrate/20140213120038_fix_idx_scope.rb +13 -0
- data/bricks/zena/zena/migrate/20140628140247_add_site_readonly.rb +9 -0
- data/config/bricks.yml +8 -4
- data/config/gems.yml +5 -3
- data/db/init/base/skins/default/Node-+login.zafu +8 -1
- data/db/init/base/skins/default/Node-+search.zafu +1 -1
- data/lib/bricks/loader.rb +5 -5
- data/lib/gettext_strings.rb +3 -0
- data/lib/tasks/zena.rake +25 -22
- data/lib/zafu/process/context.rb +4 -0
- data/lib/zena/acts/secure_node.rb +3 -3
- data/lib/zena/app.rb +1 -0
- data/lib/zena/deploy.rb +1 -1
- data/lib/zena/deploy/template.rb +1 -1
- data/lib/zena/foxy_parser.rb +5 -2
- data/lib/zena/info.rb +1 -1
- data/lib/zena/site_worker.rb +2 -2
- data/lib/zena/test_controller.rb +5 -2
- data/lib/zena/use/action.rb +9 -2
- data/lib/zena/use/ajax.rb +20 -4
- data/lib/zena/use/ancestry.rb +89 -15
- data/lib/zena/use/authlogic.rb +8 -2
- data/lib/zena/use/context.rb +1 -0
- data/lib/zena/use/display.rb +1 -97
- data/lib/zena/use/forms.rb +28 -8
- data/lib/zena/use/html_tags.rb +16 -7
- data/lib/zena/use/i18n.rb +1 -1
- data/lib/zena/use/prop_eval.rb +6 -1
- data/lib/zena/use/query_node.rb +69 -4
- data/lib/zena/use/recursion.rb +1 -1
- data/lib/zena/use/refactor.rb +5 -2
- data/lib/zena/use/relations.rb +1 -0
- data/lib/zena/use/rendering.rb +7 -4
- data/lib/zena/use/test_helper.rb +8 -4
- data/lib/zena/use/upload.rb +14 -0
- data/lib/zena/use/urls.rb +39 -23
- data/lib/zena/use/version_hash.rb +5 -2
- data/lib/zena/use/workflow.rb +116 -70
- data/lib/zena/use/zafu_eval.rb +41 -0
- data/lib/zena/use/zafu_safe_definitions.rb +1 -0
- data/lib/zena/use/zafu_templates.rb +32 -26
- data/lib/zena/use/zazen.rb +8 -7
- data/locale/app.pot +5 -1
- data/locale/de/LC_MESSAGES/zena.mo +0 -0
- data/locale/de/zena.po +385 -281
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +378 -271
- data/locale/fr/LC_MESSAGES/zena.mo +0 -0
- data/locale/fr/zena.po +387 -272
- data/locale/it/LC_MESSAGES/zena.mo +0 -0
- data/locale/it/zena.po +433 -404
- data/locale/zena.pot +362 -268
- data/public/javascripts/grid.js +280 -104
- data/public/javascripts/zena.js +43 -15
- data/public/stylesheets/admin.css +8 -2
- data/public/stylesheets/grid.css +5 -2
- data/public/stylesheets/popup.css +1 -1
- data/test/fixtures/files/TestNode.zafu +51 -0
- data/test/functional/nodes_controller_test.rb +20 -5
- data/test/functional/user_sessions_controller_test.rb +41 -6
- data/test/functional/users_controller_test.rb +1 -2
- data/test/integration/navigation_test.rb +22 -4
- data/test/integration/query_node/basic.yml +7 -0
- data/test/integration/query_node/complex.yml +1 -1
- data/test/integration/query_node/errors.yml +1 -1
- data/test/integration/query_node/filters.yml +34 -1
- data/test/integration/query_node/relations.yml +6 -13
- data/test/integration/query_node_test.rb +22 -3
- data/test/integration/zafu_compiler/action.yml +1 -1
- data/test/integration/zafu_compiler/alias_site.yml +52 -0
- data/test/integration/zafu_compiler/complex.yml +1 -1
- data/test/integration/zafu_compiler/complex_ok.yml +5 -5
- data/test/integration/zafu_compiler/context.yml +1 -1
- data/test/integration/zafu_compiler/display.yml +56 -5
- data/test/integration/zafu_compiler/forms.yml +35 -2
- data/test/integration/zafu_compiler/meta.yml +4 -0
- data/test/integration/zafu_compiler/rubyless.yml +1 -1
- data/test/integration/zafu_compiler/safe_definitions.yml +4 -0
- data/test/integration/zafu_compiler/security.yml +10 -0
- data/test/integration/zafu_compiler/site.yml +5 -1
- data/test/integration/zafu_compiler/urls.yml +8 -2
- data/test/integration/zafu_compiler/zafu_attributes.yml +2 -1
- data/test/integration/zafu_compiler/zazen.yml +4 -0
- data/test/integration/zafu_compiler_test.rb +47 -4
- data/test/selenium/Grid/grid1.rsel +8 -8
- data/test/sites/complex/sites.yml +2 -2
- data/test/sites/complex/users.yml +1 -0
- data/test/sites/zena/columns.yml +4 -0
- data/test/sites/zena/sites.yml +1 -0
- data/test/sites/zena/users.yml +1 -0
- data/test/unit/node_test.rb +53 -5
- data/test/unit/note_test.rb +1 -1
- data/test/unit/relation_proxy_test.rb +20 -0
- data/test/unit/role_test.rb +2 -0
- data/test/unit/site_test.rb +28 -6
- data/test/unit/user_test.rb +332 -1
- data/test/unit/virtual_class_test.rb +55 -0
- data/test/unit/workflow_test.rb +175 -0
- data/test/unit/zena/use/ancestry_test.rb +52 -10
- data/test/unit/zena/use/prop_eval_test.rb +44 -0
- data/test/unit/zena/use/rendering_test.rb +48 -2
- data/test/unit/zena/use/upload_test.rb +15 -13
- data/test/unit/zena/use/urls_test.rb +1 -0
- data/vendor/plugins/ar_mysql_full_text/lib/ar_mysql_full_text.rb +39 -25
- data/zena.gemspec +69 -307
- metadata +143 -368
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run 2.tmCommand +0 -24
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Context.tmCommand +0 -58
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Focused Should.tmCommand +0 -88
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run.tmCommand +0 -27
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/YAML to Shoulda.tmCommand +0 -23
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Context.tmPreferences +0 -19
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Should.tmPreferences +0 -19
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory attributes for.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory build.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define with class.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_next.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_sequence.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_bad_value.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_contains.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_does_not_contain.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_good_value.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_same_elements.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_save.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_sent_email.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_valid.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/association.tmSnippet +0 -17
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/attribute.tmSnippet +0 -17
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/before_should block.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block get.tmSnippet +0 -22
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block post.tmSnippet +0 -23
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block with setup.tmSnippet +0 -25
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/setup.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block with before proc.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_allow_values_for.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_assign_to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful denied.tmSnippet +0 -20
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful.tmSnippet +0 -20
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_belong_to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change by.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change from to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_at_least.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_in_range.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_is.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_value_in_range.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_eventually.tmSnippet +0 -18
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_filter_params.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_and_belong_to_many.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_class_methods.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_column.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_columns.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_index.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_indices.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_instance_methods.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_many.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_named_scope.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_one.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_readonly_attributes.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_mass_assignment_of.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_values_for.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_assign_to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_change.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_set_the_flash.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_redirect_to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_a_form.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_template.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_with_layout.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_without_layout.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with_content_type.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_return_from_session.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_route.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_set_the_flash_to.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_acceptance_of.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_numericality_of.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_presence_of.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of with scope.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of.tmSnippet +0 -16
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/catch_exception.rb +0 -39
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/run_script.rb +0 -104
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/stdin_dialog.rb +0 -14
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/test.rb +0 -17
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/todo.txt +0 -13
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/bin/yaml_to_shoulda.rb +0 -25
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Syntaxes/Ruby on Rails (Shoulda).tmLanguage +0 -166
- data/vendor/TextMate/Ruby Shoulda.tmbundle/info.plist +0 -304
- data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +0 -37
- data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +0 -52
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/catch_exception.rb +0 -39
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +0 -118
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/stdin_dialog.rb +0 -14
- data/vendor/TextMate/Zena.tmbundle/info.plist +0 -17
- data/vendor/plugins/selenium-on-rails/CHANGELOG +0 -125
- data/vendor/plugins/selenium-on-rails/LICENSE-2.0.txt +0 -202
- data/vendor/plugins/selenium-on-rails/README.md +0 -202
- data/vendor/plugins/selenium-on-rails/Rakefile +0 -38
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumController.html +0 -265
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumHelper.html +0 -148
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails.html +0 -126
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/FixtureLoader.html +0 -231
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/PartialsSupport.html +0 -195
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Paths.html +0 -295
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/RSelenese.html +0 -219
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Renderer.html +0 -156
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/Selenese.html +0 -179
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/SuiteRenderer.html +0 -223
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilder.html +0 -441
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderAccessors.html +0 -3098
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderActions.html +0 -2080
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserAccessors.html +0 -116
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRails/TestBuilderUserActions.html +0 -116
- data/vendor/plugins/selenium-on-rails/doc/classes/SeleniumOnRailsConfig.html +0 -150
- data/vendor/plugins/selenium-on-rails/doc/files/CHANGELOG.html +0 -422
- data/vendor/plugins/selenium-on-rails/doc/files/README.html +0 -321
- data/vendor/plugins/selenium-on-rails/doc/files/lib/controllers/selenium_controller_rb.html +0 -108
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_helper_rb.html +0 -101
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/acceptance_test_runner_rb.html +0 -222
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/fixture_loader_rb.html +0 -109
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/partials_support_rb.html +0 -111
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/paths_rb.html +0 -101
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/renderer_rb.html +0 -101
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/rselenese_rb.html +0 -118
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/selenese_rb.html +0 -101
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/suite_renderer_rb.html +0 -101
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_accessors_rb.html +0 -114
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_actions_rb.html +0 -113
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails/test_builder_rb.html +0 -120
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_config_rb.html +0 -108
- data/vendor/plugins/selenium-on-rails/doc/files/lib/selenium_on_rails_rb.html +0 -115
- data/vendor/plugins/selenium-on-rails/doc/fr_class_index.html +0 -42
- data/vendor/plugins/selenium-on-rails/doc/fr_file_index.html +0 -43
- data/vendor/plugins/selenium-on-rails/doc/fr_method_index.html +0 -182
- data/vendor/plugins/selenium-on-rails/doc/index.html +0 -24
- data/vendor/plugins/selenium-on-rails/doc/rdoc-style.css +0 -208
- data/vendor/plugins/selenium-on-rails/generators/selenium/USAGE +0 -19
- data/vendor/plugins/selenium-on-rails/generators/selenium/selenium_generator.rb +0 -50
- data/vendor/plugins/selenium-on-rails/generators/selenium/templates/rhtml.rhtml +0 -16
- data/vendor/plugins/selenium-on-rails/generators/selenium/templates/rselenese.rhtml +0 -14
- data/vendor/plugins/selenium-on-rails/generators/selenium/templates/selenese.rhtml +0 -11
- data/vendor/plugins/selenium-on-rails/init.rb +0 -15
- data/vendor/plugins/selenium-on-rails/lib/controllers/selenium_controller.rb +0 -122
- data/vendor/plugins/selenium-on-rails/lib/controllers/switch_environment_controller.rb +0 -16
- data/vendor/plugins/selenium-on-rails/lib/selenium_helper.rb +0 -8
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails.rb +0 -11
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/acceptance_test_runner.rb +0 -215
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/fixture_loader.rb +0 -57
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/partials_support.rb +0 -36
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/paths.rb +0 -61
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/renderer.rb +0 -20
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/rselenese.rb +0 -44
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/selenese.rb +0 -87
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/suite_renderer.rb +0 -56
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder.rb +0 -116
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_accessors.rb +0 -1002
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_actions.rb +0 -514
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_accessors.rb.example +0 -91
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_actions.rb.example +0 -24
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb +0 -30
- data/vendor/plugins/selenium-on-rails/lib/views/layouts/layout.rhtml +0 -18
- data/vendor/plugins/selenium-on-rails/lib/views/record.rhtml +0 -5
- data/vendor/plugins/selenium-on-rails/lib/views/selenium_helper.rb +0 -9
- data/vendor/plugins/selenium-on-rails/lib/views/setup.rhtml +0 -67
- data/vendor/plugins/selenium-on-rails/lib/views/test_suite.rhtml +0 -26
- data/vendor/plugins/selenium-on-rails/routes.rb +0 -24
- data/vendor/plugins/selenium-on-rails/selenium-core/Blank.html +0 -7
- data/vendor/plugins/selenium-on-rails/selenium-core/InjectedRemoteRunner.html +0 -8
- data/vendor/plugins/selenium-on-rails/selenium-core/RemoteRunner.html +0 -110
- data/vendor/plugins/selenium-on-rails/selenium-core/SeleniumLog.html +0 -109
- data/vendor/plugins/selenium-on-rails/selenium-core/TestPrompt.html +0 -145
- data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner-splash.html +0 -55
- data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner.hta +0 -177
- data/vendor/plugins/selenium-on-rails/selenium-core/TestRunner.html +0 -177
- data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/butmin.gif +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/butplus.gif +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.css +0 -298
- data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/domviewer.html +0 -16
- data/vendor/plugins/selenium-on-rails/selenium-core/domviewer/selenium-domviewer.js +0 -205
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/all.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/continue.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/continue_disabled.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/pause.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/pause_disabled.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/selected.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/step.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/icons/step_disabled.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/iedoc-core.xml +0 -1759
- data/vendor/plugins/selenium-on-rails/selenium-core/iedoc.xml +0 -1800
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/cssQuery-p.js +0 -6
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level2.js +0 -142
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-level3.js +0 -150
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery-standard.js +0 -53
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/cssQuery/src/cssQuery.js +0 -356
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/prototype.js +0 -2006
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/builder.js +0 -101
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/controls.js +0 -815
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/dragdrop.js +0 -915
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/effects.js +0 -958
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/scriptaculous.js +0 -47
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/slider.js +0 -283
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/scriptaculous/unittest.js +0 -383
- data/vendor/plugins/selenium-on-rails/selenium-core/lib/snapsie.js +0 -91
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/find_matching_child.js +0 -69
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/htmlutils.js +0 -1616
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/injection.html +0 -72
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-api.js +0 -3184
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserbot.js +0 -2300
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-browserdetect.js +0 -153
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-commandhandlers.js +0 -377
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-executionloop.js +0 -175
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-logging.js +0 -148
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-remoterunner.js +0 -695
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-testrunner.js +0 -1362
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/selenium-version.js +0 -5
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-doc.html +0 -803
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-element.js +0 -1537
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/ui-map-sample.js +0 -979
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js +0 -3
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/user-extensions.js.sample +0 -75
- data/vendor/plugins/selenium-on-rails/selenium-core/scripts/xmlextras.js +0 -153
- data/vendor/plugins/selenium-on-rails/selenium-core/selenium-logo.png +0 -0
- data/vendor/plugins/selenium-on-rails/selenium-core/selenium-test.css +0 -43
- data/vendor/plugins/selenium-on-rails/selenium-core/selenium.css +0 -316
- data/vendor/plugins/selenium-on-rails/selenium-core/xpath/dom.js +0 -566
- data/vendor/plugins/selenium-on-rails/selenium-core/xpath/javascript-xpath-0.1.11.js +0 -2816
- data/vendor/plugins/selenium-on-rails/selenium-core/xpath/util.js +0 -549
- data/vendor/plugins/selenium-on-rails/selenium-core/xpath/xmltoken.js +0 -149
- data/vendor/plugins/selenium-on-rails/selenium-core/xpath/xpath.js +0 -2450
- data/vendor/plugins/selenium-on-rails/tasks/test_acceptance.rake +0 -8
- data/vendor/plugins/selenium-on-rails/test/fixtures/config.yml +0 -37
- data/vendor/plugins/selenium-on-rails/test/fixtures/selenium.yml +0 -27
- data/vendor/plugins/selenium-on-rails/test/paths_test.rb +0 -72
- data/vendor/plugins/selenium-on-rails/test/renderer_test.rb +0 -157
- data/vendor/plugins/selenium-on-rails/test/rselenese_test.rb +0 -708
- data/vendor/plugins/selenium-on-rails/test/selenese_test.rb +0 -242
- data/vendor/plugins/selenium-on-rails/test/selenium_controller_test.rb +0 -67
- data/vendor/plugins/selenium-on-rails/test/selenium_on_rails_config_test.rb +0 -43
- data/vendor/plugins/selenium-on-rails/test/selenium_support_test.rb +0 -35
- data/vendor/plugins/selenium-on-rails/test/setup_test.rb +0 -31
- data/vendor/plugins/selenium-on-rails/test/suite_renderer_test.rb +0 -109
- data/vendor/plugins/selenium-on-rails/test/switch_environment_controller_test.rb +0 -17
- data/vendor/plugins/selenium-on-rails/test/test_builder_functions_authortest.rb +0 -51
- data/vendor/plugins/selenium-on-rails/test/test_helper.rb +0 -101
- data/vendor/plugins/selenium-on-rails/test_data/_partial.rsel +0 -1
- data/vendor/plugins/selenium-on-rails/test_data/own_layout.html +0 -12
- data/vendor/plugins/selenium-on-rails/test_data/partials/_html.html +0 -6
- data/vendor/plugins/selenium-on-rails/test_data/partials/_nesting.rsel +0 -2
- data/vendor/plugins/selenium-on-rails/test_data/partials/_rhtml.rhtml +0 -6
- data/vendor/plugins/selenium-on-rails/test_data/partials/_rsel.rsel +0 -1
- data/vendor/plugins/selenium-on-rails/test_data/partials/_sel.sel +0 -5
- data/vendor/plugins/selenium-on-rails/test_data/partials/all_partials.rsel +0 -5
- data/vendor/plugins/selenium-on-rails/test_data/rhtml.rhtml +0 -7
- data/vendor/plugins/selenium-on-rails/test_data/rselenese.rsel +0 -8
- data/vendor/plugins/selenium-on-rails/test_data/selenese.sel +0 -7
- data/vendor/plugins/selenium-on-rails/test_data/suite_one/subsuite/suite_one_subsuite_testcase.sel +0 -1
- data/vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase1.sel +0 -1
- data/vendor/plugins/selenium-on-rails/test_data/suite_one/suite_one_testcase2.sel +0 -1
- 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
|
-
|