browsercms 3.1.5 → 3.3.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/app/controllers/cms/base_controller.rb +3 -3
- data/app/controllers/cms/content_block_controller.rb +2 -2
- data/app/controllers/cms/content_controller.rb +5 -4
- data/app/controllers/cms/error_handling.rb +1 -1
- data/app/controllers/cms/routes_controller.rb +4 -5
- data/app/controllers/cms/section_nodes_controller.rb +1 -6
- data/app/controllers/cms/sections_controller.rb +2 -3
- data/app/controllers/cms/tasks_controller.rb +3 -0
- data/app/controllers/cms/users_controller.rb +1 -1
- data/app/helpers/cms/application_helper.rb +137 -34
- data/app/helpers/cms/form_builder.rb +33 -21
- data/app/helpers/cms/page_helper.rb +43 -10
- data/app/helpers/cms/path_helper.rb +1 -1
- data/app/helpers/cms/rendering_helper.rb +3 -4
- data/app/helpers/cms/section_nodes_helper.rb +5 -43
- data/app/models/abstract_file_block.rb +1 -16
- data/app/models/attachment.rb +57 -22
- data/app/models/category.rb +4 -4
- data/app/models/category_type.rb +2 -2
- data/app/models/cms/view_context.rb +46 -0
- data/app/models/connector.rb +7 -6
- data/app/models/content_type.rb +3 -3
- data/app/models/dynamic_view.rb +1 -1
- data/app/models/email_message.rb +2 -2
- data/app/models/file_block.rb +12 -0
- data/app/models/group.rb +4 -4
- data/app/models/group_type.rb +4 -4
- data/app/models/html_block.rb +1 -1
- data/app/models/image_block.rb +12 -0
- data/app/models/link.rb +22 -5
- data/app/models/page.rb +87 -46
- data/app/models/page_route.rb +61 -6
- data/app/models/permission.rb +1 -1
- data/app/models/portlet.rb +14 -4
- data/app/models/section.rb +48 -86
- data/app/models/section_node.rb +25 -40
- data/app/models/site.rb +1 -1
- data/app/models/tag.rb +1 -1
- data/app/models/task.rb +8 -7
- data/app/models/user.rb +2 -7
- data/app/portlets/forgot_password_portlet.rb +6 -2
- data/app/portlets/reset_password_portlet.rb +1 -1
- data/app/views/cms/blocks/_toolbar.html.erb +1 -1
- data/app/views/cms/blocks/_toolbar_for_collection.html.erb +3 -6
- data/app/views/cms/blocks/_toolbar_for_member.html.erb +3 -5
- data/app/views/cms/blocks/edit.html.erb +4 -4
- data/app/views/cms/blocks/index.html.erb +7 -7
- data/app/views/cms/blocks/new.html.erb +4 -4
- data/app/views/cms/blocks/show.html.erb +2 -2
- data/app/views/cms/blocks/usages.html.erb +2 -2
- data/app/views/cms/blocks/versions.html.erb +4 -4
- data/app/views/cms/cache/show.html.erb +2 -2
- data/app/views/cms/categories/_form.html.erb +2 -2
- data/app/views/cms/connectors/new.html.erb +6 -8
- data/app/views/cms/content/no_page.html.erb +1 -1
- data/app/views/cms/content/show.html.erb +2 -7
- data/app/views/cms/dashboard/_page_drafts.html.erb +1 -1
- data/app/views/cms/dashboard/_tasks.html.erb +1 -1
- data/app/views/cms/dashboard/index.html.erb +1 -1
- data/app/views/cms/dynamic_views/_form.html.erb +2 -2
- data/app/views/cms/dynamic_views/index.html.erb +7 -10
- data/app/views/cms/email_messages/show.html.erb +2 -2
- data/app/views/cms/file_blocks/_form.html.erb +4 -4
- data/app/views/cms/form_builder/_cms_fancy_drop_down.html.erb +2 -2
- data/app/views/cms/form_builder/_cms_file_field.html.erb +2 -2
- data/app/views/cms/form_builder/_cms_tag_list.html.erb +2 -2
- data/app/views/cms/form_builder/_cms_text_editor.html.erb +2 -2
- data/app/views/cms/groups/_form.html.erb +5 -5
- data/app/views/cms/groups/_permissions.html.erb +4 -4
- data/app/views/cms/groups/_sections.html.erb +1 -2
- data/app/views/cms/groups/index.html.erb +1 -1
- data/app/views/cms/html_blocks/render.html.erb +1 -1
- data/app/views/cms/image_blocks/_form.html.erb +4 -5
- data/app/views/cms/links/_form.html.erb +1 -1
- data/app/views/cms/links/edit.html.erb +2 -2
- data/app/views/cms/links/new.html.erb +2 -2
- data/app/views/cms/page_routes/_form.html.erb +2 -2
- data/app/views/cms/page_routes/index.html.erb +6 -9
- data/app/views/cms/page_routes/show.html.erb +5 -8
- data/app/views/cms/pages/_edit_connector.html.erb +1 -1
- data/app/views/cms/pages/_form.html.erb +3 -3
- data/app/views/cms/pages/edit.html.erb +2 -2
- data/app/views/cms/pages/new.html.erb +7 -7
- data/app/views/cms/pages/versions.html.erb +4 -4
- data/app/views/cms/redirects/_form.html.erb +2 -2
- data/app/views/cms/redirects/index.html.erb +8 -7
- data/app/views/cms/routes/index.html.erb +2 -2
- data/app/views/cms/section_nodes/_link.html.erb +3 -6
- data/app/views/cms/section_nodes/_node.html.erb +4 -13
- data/app/views/cms/section_nodes/_page.html.erb +7 -13
- data/app/views/cms/section_nodes/_section.html.erb +8 -24
- data/app/views/cms/section_nodes/_section_node.html.erb +10 -0
- data/app/views/cms/section_nodes/index.html.erb +18 -30
- data/app/views/cms/sections/_form.html.erb +4 -6
- data/app/views/cms/sections/edit.html.erb +2 -2
- data/app/views/cms/sections/index.html.erb +3 -3
- data/app/views/cms/sections/new.html.erb +3 -3
- data/app/views/cms/sessions/new.html.erb +3 -3
- data/app/views/cms/shared/_pagination.html.erb +1 -1
- data/app/views/cms/shared/error.html.erb +1 -1
- data/app/views/cms/tags/render.html.erb +2 -2
- data/app/views/cms/tasks/new.html.erb +4 -4
- data/app/views/cms/users/_form.html.erb +3 -3
- data/app/views/cms/users/_toolbar.html.erb +3 -3
- data/app/views/cms/users/change_password.html.erb +5 -5
- data/app/views/cms/users/edit.html.erb +2 -2
- data/app/views/cms/users/index.html.erb +4 -4
- data/app/views/cms/users/new.html.erb +2 -2
- data/app/views/cms/users/show.html.erb +16 -16
- data/app/views/layouts/_cms_toolbar.html.erb +5 -5
- data/app/views/layouts/_page_toolbar.html.erb +11 -11
- data/app/views/layouts/cms/_footer.erb +1 -1
- data/app/views/layouts/cms/_head.html.erb +2 -6
- data/app/views/layouts/cms/administration.html.erb +32 -32
- data/app/views/layouts/cms/content_library.html.erb +5 -5
- data/app/views/layouts/cms/toolbar.html.erb +1 -1
- data/app/views/portlets/email_page/render.html.erb +2 -2
- data/app/views/portlets/forgot_password/render.html.erb +1 -1
- data/app/views/portlets/login/render.html.erb +4 -2
- data/app/views/portlets/reset_password/render.html.erb +1 -1
- data/app/views/tests/pretend/open_with_layout.html.erb +1 -1
- data/bin/bcms +0 -0
- data/bin/bcms-upgrade +232 -0
- data/bin/browsercms +2 -2
- data/browsercms.gemspec +16 -14
- data/db/migrate/20100705083859_browsercms_3_3_0.rb +56 -0
- data/db/seeds.rb +58 -0
- data/doc/guides/html/authentication.html +448 -192
- data/doc/guides/html/build_it_yourself.html +454 -175
- data/doc/guides/html/building_modules.html +451 -220
- data/doc/guides/html/building_templates.html +448 -498
- data/doc/guides/html/content_blocks.html +450 -470
- data/doc/guides/html/customizing_browsercms.html +453 -169
- data/doc/guides/html/deployment_guide.html +443 -82
- data/doc/guides/html/files/bcmsorg.js +28 -0
- data/doc/guides/html/files/clearfix.css +8 -0
- data/doc/guides/html/files/cufon.js +7 -0
- data/doc/guides/html/files/global.css +190 -0
- data/doc/guides/html/files/helvetica.js +91 -0
- data/doc/guides/html/files/jquery.js +11 -0
- data/doc/guides/html/getting_started.html +454 -213
- data/doc/guides/html/index.html +454 -174
- data/doc/guides/html/installing_modules.html +454 -186
- data/doc/guides/html/portlets.html +451 -232
- data/doc/guides/html/user_guide.html +452 -270
- data/doc/guides/html/writing_guides.html +454 -161
- data/lib/acts_as_list.rb +1 -1
- data/lib/browsercms.rb +10 -6
- data/lib/cms/acts.rb +7 -0
- data/lib/cms/authentication.rb +4 -0
- data/lib/cms/authentication/controller.rb +1 -1
- data/lib/cms/behaviors.rb +1 -1
- data/lib/cms/behaviors/archiving.rb +2 -2
- data/lib/cms/behaviors/attaching.rb +28 -43
- data/lib/cms/behaviors/categorizing.rb +1 -1
- data/lib/cms/behaviors/connecting.rb +27 -12
- data/lib/cms/behaviors/dynamic_attributes.rb +8 -5
- data/lib/cms/behaviors/hiding.rb +2 -2
- data/lib/cms/behaviors/publishing.rb +32 -22
- data/lib/cms/behaviors/rendering.rb +41 -18
- data/lib/cms/behaviors/searching.rb +1 -1
- data/lib/cms/behaviors/soft_deleting.rb +58 -29
- data/lib/cms/behaviors/taggable.rb +1 -1
- data/lib/cms/behaviors/userstamping.rb +5 -4
- data/lib/cms/behaviors/versioning.rb +192 -111
- data/lib/cms/content_rendering_support.rb +3 -3
- data/lib/cms/date_picker.rb +23 -0
- data/lib/cms/engine.rb +46 -0
- data/lib/cms/extensions.rb +1 -1
- data/lib/cms/extensions/active_record/errors.rb +2 -2
- data/lib/cms/extensions/hash.rb +4 -2
- data/lib/cms/extensions/string.rb +7 -2
- data/lib/cms/init.rb +32 -21
- data/lib/cms/module.rb +22 -0
- data/lib/cms/module_installation.rb +38 -0
- data/lib/cms/routes.rb +127 -115
- data/lib/cms/version.rb +2 -2
- data/lib/generators/browser_cms.rb +12 -0
- data/lib/generators/browser_cms/cms/USAGE +2 -0
- data/lib/generators/browser_cms/cms/cms_generator.rb +36 -0
- data/{rails_generators/browser_cms → lib/generators/browser_cms/cms}/templates/README +0 -0
- data/{rails_generators/browser_cms_demo_site → lib/generators/browser_cms/demo_site}/USAGE +0 -0
- data/lib/generators/browser_cms/demo_site/demo_site_generator.rb +138 -0
- data/lib/generators/browser_cms/demo_site/templates/demo_site.rake +11 -0
- data/{rails_generators/browser_cms_demo_site/templates/migration.rb → lib/generators/browser_cms/demo_site/templates/migration.erb} +2 -8
- data/lib/generators/cms/content_block/USAGE +22 -0
- data/lib/generators/cms/content_block/content_block_generator.rb +55 -0
- data/{rails_generators → lib/generators/cms}/content_block/templates/_form.html.erb +0 -0
- data/{rails_generators → lib/generators/cms}/content_block/templates/content_block.rb +0 -0
- data/{rails_generators → lib/generators/cms}/content_block/templates/controller.rb +0 -0
- data/{rails_generators → lib/generators/cms}/content_block/templates/functional_test.erb +0 -0
- data/{rails_generators/content_block/templates/migration.rb → lib/generators/cms/content_block/templates/migration.erb} +1 -1
- data/{rails_generators → lib/generators/cms}/content_block/templates/render.html.erb +0 -0
- data/{rails_generators → lib/generators/cms}/content_block/templates/unit_test.erb +0 -0
- data/lib/generators/cms/install/USAGE +8 -0
- data/lib/generators/cms/install/install_generator.rb +20 -0
- data/{rails_generators → lib/generators/cms}/portlet/USAGE +3 -16
- data/lib/generators/cms/portlet/portlet_generator.rb +38 -0
- data/{rails_generators → lib/generators/cms}/portlet/templates/_form.html.erb +0 -0
- data/{rails_generators → lib/generators/cms}/portlet/templates/portlet.rb +0 -0
- data/{rails_generators → lib/generators/cms}/portlet/templates/portlet_helper.rb +0 -0
- data/{rails_generators → lib/generators/cms}/portlet/templates/render.html.erb +0 -0
- data/{rails_generators → lib/generators/cms}/portlet/templates/unit_test.erb +0 -0
- data/{rails_generators → lib/generators/cms}/template/USAGE +1 -1
- data/lib/generators/cms/template/template_generator.rb +18 -0
- data/lib/generators/cms/template/templates/template.erb +2 -0
- data/lib/generators/cms/upgrade_module/README.txt +3 -0
- data/lib/generators/cms/upgrade_module/templates/20100705083859_browsercms_3_3_0.rb +56 -0
- data/lib/generators/cms/upgrade_module/templates/README +1 -0
- data/lib/generators/cms/upgrade_module/templates/USAGE.erb +10 -0
- data/lib/generators/cms/upgrade_module/templates/build_gem.rake +5 -0
- data/lib/generators/cms/upgrade_module/templates/engine.erb +7 -0
- data/lib/generators/cms/upgrade_module/templates/gemspec.erb +25 -0
- data/lib/generators/cms/upgrade_module/templates/gitignore.erb +11 -0
- data/lib/generators/cms/upgrade_module/templates/install.erb +9 -0
- data/lib/generators/cms/upgrade_module/templates/module_file.erb +3 -0
- data/lib/generators/cms/upgrade_module/templates/routes.erb +7 -0
- data/lib/generators/cms/upgrade_module/upgrade_module_generator.rb +61 -0
- data/lib/tasks/build_gem.rake +1 -0
- data/lib/tasks/cms.rake +34 -6
- data/lib/tasks/cucumber.rake +53 -0
- data/lib/tasks/db.rake +2 -2
- data/public/javascripts/cms/application.js +144 -135
- data/public/javascripts/cms/sitemap.js +383 -357
- data/public/javascripts/jquery-ui.js +782 -591
- data/public/javascripts/jquery.cookie.js +38 -43
- data/public/javascripts/jquery.js +13 -8
- data/public/javascripts/jquery.taglist.js +7 -0
- data/public/stylesheets/cms/date_picker.css +49 -40
- data/rails/init.rb +2 -3
- data/templates/blank.rb +13 -7
- data/templates/demo.rb +15 -7
- data/templates/module.rb +12 -75
- metadata +87 -407
- data/app/helpers/cms/content_block_helper.rb +0 -27
- data/app/views/layouts/cms/thickbox.html.erb +0 -24
- data/db/migrate/20120117144039_browsercms315.rb +0 -94
- data/db/migrate/20121114172307_load_seeds.rb +0 -70
- data/lib/cms/addressable.rb +0 -83
- data/lib/cms/error_pages.rb +0 -8
- data/public/images/cms/thickbox/loadingAnimation.gif +0 -0
- data/public/images/cms/thickbox/macFFBgHack.png +0 -0
- data/public/javascripts/jquery.contextMenu.js +0 -211
- data/public/javascripts/jquery.dimensions.js +0 -119
- data/public/javascripts/jquery.thickbox.js +0 -10
- data/public/stylesheets/cms/jquery.contextMenu.css +0 -61
- data/public/stylesheets/cms/thickbox.css +0 -163
- data/rails_generators/browser_cms/USAGE +0 -2
- data/rails_generators/browser_cms/browser_cms_generator.rb +0 -35
- data/rails_generators/browser_cms_demo_site/browser_cms_demo_site_generator.rb +0 -63
- data/rails_generators/content_block/USAGE +0 -32
- data/rails_generators/content_block/content_block_generator.rb +0 -69
- data/rails_generators/portlet/portlet_generator.rb +0 -35
- data/rails_generators/template/template_generator.rb +0 -18
- data/rails_generators/template/templates/template.erb +0 -3
- data/test/custom_assertions.rb +0 -74
- data/test/factories.rb +0 -111
- data/test/factories/sitemap_factories.rb +0 -28
- data/test/fixtures/connectors.yml +0 -97
- data/test/fixtures/content_type_groups.yml +0 -13
- data/test/fixtures/content_types.yml +0 -50
- data/test/fixtures/dynamic_view_versions.yml +0 -26
- data/test/fixtures/dynamic_views.yml +0 -26
- data/test/fixtures/group_permissions.yml +0 -16
- data/test/fixtures/group_sections.yml +0 -31
- data/test/fixtures/group_type_permissions.yml +0 -11
- data/test/fixtures/group_types.yml +0 -25
- data/test/fixtures/groups.yml +0 -25
- data/test/fixtures/html_block_versions.yml +0 -67
- data/test/fixtures/html_blocks.yml +0 -63
- data/test/fixtures/page_versions.yml +0 -265
- data/test/fixtures/pages.yml +0 -85
- data/test/fixtures/permissions.yml +0 -28
- data/test/fixtures/section_nodes.yml +0 -46
- data/test/fixtures/sections.yml +0 -19
- data/test/fixtures/sites.yml +0 -9
- data/test/fixtures/user_group_memberships.yml +0 -11
- data/test/fixtures/users.yml +0 -15
- data/test/functional/cms/cache_controller_test.rb +0 -14
- data/test/functional/cms/categories_controller_test.rb +0 -25
- data/test/functional/cms/connectors_controller_test.rb +0 -60
- data/test/functional/cms/content_block_controller_test.rb +0 -120
- data/test/functional/cms/content_controller_test.rb +0 -439
- data/test/functional/cms/content_types_controller_test.rb +0 -18
- data/test/functional/cms/dashboard_controller_test.rb +0 -16
- data/test/functional/cms/dynamic_views_controller_test.rb +0 -52
- data/test/functional/cms/file_blocks_controller_test.rb +0 -52
- data/test/functional/cms/groups_controller_test.rb +0 -50
- data/test/functional/cms/home_controller_test.rb +0 -156
- data/test/functional/cms/html_blocks_controller_test.rb +0 -164
- data/test/functional/cms/image_blocks_controller_test.rb +0 -82
- data/test/functional/cms/links_controller_test.rb +0 -148
- data/test/functional/cms/pages_controller_test.rb +0 -227
- data/test/functional/cms/portlets_controller_test.rb +0 -67
- data/test/functional/cms/section_nodes_controller_test.rb +0 -112
- data/test/functional/cms/sections_controller_test.rb +0 -227
- data/test/functional/cms/sessions_controller_test.rb +0 -76
- data/test/functional/cms/toolbar_controller_test.rb +0 -64
- data/test/functional/cms/users_controller_test.rb +0 -231
- data/test/functional/tests/pretend_controller_test.rb +0 -57
- data/test/integration/cms/ckeditor_test.rb +0 -30
- data/test/integration/cms/password_management_test.rb +0 -56
- data/test/integration/login_test.rb +0 -14
- data/test/integration/sitemap_performance_test.rb +0 -26
- data/test/selenium-core/Blank.html +0 -7
- data/test/selenium-core/InjectedRemoteRunner.html +0 -8
- data/test/selenium-core/RemoteRunner.html +0 -110
- data/test/selenium-core/SeleniumLog.html +0 -109
- data/test/selenium-core/TestPrompt.html +0 -145
- data/test/selenium-core/TestRunner-splash.html +0 -55
- data/test/selenium-core/TestRunner.hta +0 -176
- data/test/selenium-core/TestRunner.html +0 -176
- data/test/selenium-core/domviewer/butmin.gif +0 -0
- data/test/selenium-core/domviewer/butplus.gif +0 -0
- data/test/selenium-core/domviewer/domviewer.css +0 -298
- data/test/selenium-core/domviewer/domviewer.html +0 -16
- data/test/selenium-core/domviewer/selenium-domviewer.js +0 -205
- data/test/selenium-core/icons/all.png +0 -0
- data/test/selenium-core/icons/continue.png +0 -0
- data/test/selenium-core/icons/continue_disabled.png +0 -0
- data/test/selenium-core/icons/pause.png +0 -0
- data/test/selenium-core/icons/pause_disabled.png +0 -0
- data/test/selenium-core/icons/selected.png +0 -0
- data/test/selenium-core/icons/step.png +0 -0
- data/test/selenium-core/icons/step_disabled.png +0 -0
- data/test/selenium-core/iedoc-core.xml +0 -1515
- data/test/selenium-core/iedoc.xml +0 -1469
- data/test/selenium-core/lib/cssQuery/cssQuery-p.js +0 -6
- data/test/selenium-core/lib/cssQuery/src/cssQuery-level2.js +0 -142
- data/test/selenium-core/lib/cssQuery/src/cssQuery-level3.js +0 -150
- data/test/selenium-core/lib/cssQuery/src/cssQuery-standard.js +0 -53
- data/test/selenium-core/lib/cssQuery/src/cssQuery.js +0 -356
- data/test/selenium-core/lib/prototype.js +0 -2006
- data/test/selenium-core/lib/scriptaculous/builder.js +0 -101
- data/test/selenium-core/lib/scriptaculous/controls.js +0 -815
- data/test/selenium-core/lib/scriptaculous/dragdrop.js +0 -915
- data/test/selenium-core/lib/scriptaculous/effects.js +0 -958
- data/test/selenium-core/lib/scriptaculous/scriptaculous.js +0 -47
- data/test/selenium-core/lib/scriptaculous/slider.js +0 -283
- data/test/selenium-core/lib/scriptaculous/unittest.js +0 -383
- data/test/selenium-core/scripts/find_matching_child.js +0 -69
- data/test/selenium-core/scripts/htmlutils.js +0 -894
- data/test/selenium-core/scripts/injection.html +0 -72
- data/test/selenium-core/scripts/js2html.js +0 -70
- data/test/selenium-core/scripts/narcissus-defs.js +0 -175
- data/test/selenium-core/scripts/narcissus-exec.js +0 -1054
- data/test/selenium-core/scripts/narcissus-parse.js +0 -1003
- data/test/selenium-core/scripts/se2html.js +0 -63
- data/test/selenium-core/scripts/selenium-api.js +0 -2409
- data/test/selenium-core/scripts/selenium-browserbot.js +0 -2203
- data/test/selenium-core/scripts/selenium-browserdetect.js +0 -150
- data/test/selenium-core/scripts/selenium-commandhandlers.js +0 -377
- data/test/selenium-core/scripts/selenium-executionloop.js +0 -175
- data/test/selenium-core/scripts/selenium-logging.js +0 -147
- data/test/selenium-core/scripts/selenium-remoterunner.js +0 -571
- data/test/selenium-core/scripts/selenium-testrunner.js +0 -1333
- data/test/selenium-core/scripts/selenium-version.js +0 -5
- data/test/selenium-core/scripts/user-extensions.js +0 -3
- data/test/selenium-core/scripts/user-extensions.js.sample +0 -75
- data/test/selenium-core/scripts/xmlextras.js +0 -153
- data/test/selenium-core/selenium-logo.png +0 -0
- data/test/selenium-core/selenium-test.css +0 -43
- data/test/selenium-core/selenium.css +0 -299
- data/test/selenium-core/xpath/dom.js +0 -428
- data/test/selenium-core/xpath/misc.js +0 -252
- data/test/selenium-core/xpath/xpath.js +0 -2223
- data/test/selenium/_login_as_cmsadmin.rsel +0 -4
- data/test/selenium/dashboard.rsel +0 -5
- data/test/selenium/html_blocks.rsel +0 -4
- data/test/selenium/login/failed_login.rsel +0 -8
- data/test/selenium/login/successful_login.rsel +0 -9
- data/test/selenium/page_templates.rsel +0 -12
- data/test/selenium/pages/edit_properties.rsel +0 -5
- data/test/selenium/site/view_home_page.rsel +0 -4
- data/test/selenium/sitemap/move_page.rsel +0 -9
- data/test/selenium/sitemap/open_section.rsel +0 -6
- data/test/selenium/sitemap/select_page.rsel +0 -12
- data/test/selenium/sitemap/select_section.rsel +0 -17
- data/test/test_helper.rb +0 -193
- data/test/test_logging.rb +0 -67
- data/test/unit/behaviors/attaching_test.rb +0 -357
- data/test/unit/behaviors/connectable_test.rb +0 -29
- data/test/unit/behaviors/dynamic_attributes_test.rb +0 -38
- data/test/unit/behaviors/publishable_test.rb +0 -84
- data/test/unit/behaviors/searching_test.rb +0 -102
- data/test/unit/behaviors/taggable_test.rb +0 -109
- data/test/unit/behaviors/versioning_test.rb +0 -36
- data/test/unit/extensions/active_record/base_test.rb +0 -10
- data/test/unit/extensions/hash_test.rb +0 -17
- data/test/unit/extensions/integer_test.rb +0 -10
- data/test/unit/helpers/application_helper_test.rb +0 -77
- data/test/unit/helpers/form_builder_test.rb +0 -36
- data/test/unit/helpers/menu_helper_test.rb +0 -242
- data/test/unit/helpers/page_helper_test.rb +0 -67
- data/test/unit/helpers/path_helper_test.rb +0 -57
- data/test/unit/lib/acts_as_content_page_test.rb +0 -72
- data/test/unit/lib/cms/authentication/controller_test.rb +0 -20
- data/test/unit/lib/cms/sitemap_test.rb +0 -206
- data/test/unit/lib/cms_domain_support_test.rb +0 -43
- data/test/unit/lib/command_line_test.rb +0 -70
- data/test/unit/lib/content_block_test.rb +0 -203
- data/test/unit/lib/content_rendering_support_test.rb +0 -40
- data/test/unit/lib/generators_test.rb +0 -40
- data/test/unit/lib/routes_test.rb +0 -57
- data/test/unit/models/attachment_test.rb +0 -116
- data/test/unit/models/category_test.rb +0 -40
- data/test/unit/models/category_type_test.rb +0 -8
- data/test/unit/models/connector_test.rb +0 -152
- data/test/unit/models/content_type_test.rb +0 -56
- data/test/unit/models/email_page_portlet_test.rb +0 -14
- data/test/unit/models/file_block_test.rb +0 -230
- data/test/unit/models/group_test.rb +0 -13
- data/test/unit/models/html_block_test.rb +0 -102
- data/test/unit/models/link_test.rb +0 -52
- data/test/unit/models/page_partial_test.rb +0 -29
- data/test/unit/models/page_route_test.rb +0 -29
- data/test/unit/models/page_template_test.rb +0 -40
- data/test/unit/models/page_test.rb +0 -792
- data/test/unit/models/permission_test.rb +0 -10
- data/test/unit/models/portlet_test.rb +0 -69
- data/test/unit/models/sections_test.rb +0 -264
- data/test/unit/models/site_test.rb +0 -50
- data/test/unit/models/task_test.rb +0 -141
- data/test/unit/models/user_test.rb +0 -352
- data/test/unit/schema_statements_test.rb +0 -41
|
@@ -1,2203 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2004 ThoughtWorks, Inc
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/*
|
|
19
|
-
* This script provides the Javascript API to drive the test application contained within
|
|
20
|
-
* a Browser Window.
|
|
21
|
-
* TODO:
|
|
22
|
-
* Add support for more events (keyboard and mouse)
|
|
23
|
-
* Allow to switch "user-entry" mode from mouse-based to keyboard-based, firing different
|
|
24
|
-
* events in different modes.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
// The window to which the commands will be sent. For example, to click on a
|
|
28
|
-
// popup window, first select that window, and then do a normal click command.
|
|
29
|
-
var BrowserBot = function(topLevelApplicationWindow) {
|
|
30
|
-
this.topWindow = topLevelApplicationWindow;
|
|
31
|
-
this.topFrame = this.topWindow;
|
|
32
|
-
this.baseUrl=window.location.href;
|
|
33
|
-
|
|
34
|
-
// the buttonWindow is the Selenium window
|
|
35
|
-
// it contains the Run/Pause buttons... this should *not* be the AUT window
|
|
36
|
-
this.buttonWindow = window;
|
|
37
|
-
this.currentWindow = this.topWindow;
|
|
38
|
-
this.currentWindowName = null;
|
|
39
|
-
this.allowNativeXpath = true;
|
|
40
|
-
|
|
41
|
-
// We need to know this in advance, in case the frame closes unexpectedly
|
|
42
|
-
this.isSubFrameSelected = false;
|
|
43
|
-
|
|
44
|
-
this.altKeyDown = false;
|
|
45
|
-
this.controlKeyDown = false;
|
|
46
|
-
this.shiftKeyDown = false;
|
|
47
|
-
this.metaKeyDown = false;
|
|
48
|
-
|
|
49
|
-
this.modalDialogTest = null;
|
|
50
|
-
this.recordedAlerts = new Array();
|
|
51
|
-
this.recordedConfirmations = new Array();
|
|
52
|
-
this.recordedPrompts = new Array();
|
|
53
|
-
this.openedWindows = {};
|
|
54
|
-
this.nextConfirmResult = true;
|
|
55
|
-
this.nextPromptResult = '';
|
|
56
|
-
this.newPageLoaded = false;
|
|
57
|
-
this.pageLoadError = null;
|
|
58
|
-
|
|
59
|
-
this.shouldHighlightLocatedElement = false;
|
|
60
|
-
|
|
61
|
-
this.uniqueId = "seleniumMarker" + new Date().getTime();
|
|
62
|
-
this.pollingForLoad = new Object();
|
|
63
|
-
this.permDeniedCount = new Object();
|
|
64
|
-
this.windowPollers = new Array();
|
|
65
|
-
// DGF for backwards compatibility
|
|
66
|
-
this.browserbot = this;
|
|
67
|
-
|
|
68
|
-
var self = this;
|
|
69
|
-
|
|
70
|
-
objectExtend(this, PageBot.prototype);
|
|
71
|
-
this._registerAllLocatorFunctions();
|
|
72
|
-
|
|
73
|
-
this.recordPageLoad = function(elementOrWindow) {
|
|
74
|
-
LOG.debug("Page load detected");
|
|
75
|
-
try {
|
|
76
|
-
if (elementOrWindow.location && elementOrWindow.location.href) {
|
|
77
|
-
LOG.debug("Page load location=" + elementOrWindow.location.href);
|
|
78
|
-
} else if (elementOrWindow.contentWindow && elementOrWindow.contentWindow.location && elementOrWindow.contentWindow.location.href) {
|
|
79
|
-
LOG.debug("Page load location=" + elementOrWindow.contentWindow.location.href);
|
|
80
|
-
} else {
|
|
81
|
-
LOG.debug("Page load location unknown, current window location=" + this.getCurrentWindow(true).location);
|
|
82
|
-
}
|
|
83
|
-
} catch (e) {
|
|
84
|
-
LOG.error("Caught an exception attempting to log location; this should get noticed soon!");
|
|
85
|
-
LOG.exception(e);
|
|
86
|
-
self.pageLoadError = e;
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
self.newPageLoaded = true;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
this.isNewPageLoaded = function() {
|
|
93
|
-
if (this.pageLoadError) {
|
|
94
|
-
LOG.error("isNewPageLoaded found an old pageLoadError");
|
|
95
|
-
var e = this.pageLoadError;
|
|
96
|
-
this.pageLoadError = null;
|
|
97
|
-
throw e;
|
|
98
|
-
}
|
|
99
|
-
return self.newPageLoaded;
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// DGF PageBot exists for backwards compatibility with old user-extensions
|
|
105
|
-
var PageBot = function(){};
|
|
106
|
-
|
|
107
|
-
BrowserBot.createForWindow = function(window, proxyInjectionMode) {
|
|
108
|
-
var browserbot;
|
|
109
|
-
LOG.debug('createForWindow');
|
|
110
|
-
LOG.debug("browserName: " + browserVersion.name);
|
|
111
|
-
LOG.debug("userAgent: " + navigator.userAgent);
|
|
112
|
-
if (browserVersion.isIE) {
|
|
113
|
-
browserbot = new IEBrowserBot(window);
|
|
114
|
-
}
|
|
115
|
-
else if (browserVersion.isKonqueror) {
|
|
116
|
-
browserbot = new KonquerorBrowserBot(window);
|
|
117
|
-
}
|
|
118
|
-
else if (browserVersion.isOpera) {
|
|
119
|
-
browserbot = new OperaBrowserBot(window);
|
|
120
|
-
}
|
|
121
|
-
else if (browserVersion.isSafari) {
|
|
122
|
-
browserbot = new SafariBrowserBot(window);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
// Use mozilla by default
|
|
126
|
-
browserbot = new MozillaBrowserBot(window);
|
|
127
|
-
}
|
|
128
|
-
// getCurrentWindow has the side effect of modifying it to handle page loads etc
|
|
129
|
-
browserbot.proxyInjectionMode = proxyInjectionMode;
|
|
130
|
-
browserbot.getCurrentWindow(); // for modifyWindow side effect. This is not a transparent style
|
|
131
|
-
return browserbot;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// todo: rename? This doesn't actually "do" anything.
|
|
135
|
-
BrowserBot.prototype.doModalDialogTest = function(test) {
|
|
136
|
-
this.modalDialogTest = test;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
BrowserBot.prototype.cancelNextConfirmation = function(result) {
|
|
140
|
-
this.nextConfirmResult = result;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
BrowserBot.prototype.setNextPromptResult = function(result) {
|
|
144
|
-
this.nextPromptResult = result;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
BrowserBot.prototype.hasAlerts = function() {
|
|
148
|
-
return (this.recordedAlerts.length > 0);
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
BrowserBot.prototype.relayBotToRC = function(s) {
|
|
152
|
-
// DGF need to do this funny trick to see if we're in PI mode, because
|
|
153
|
-
// "this" might be the window, rather than the browserbot (e.g. during window.alert)
|
|
154
|
-
var piMode = this.proxyInjectionMode;
|
|
155
|
-
if (!piMode) {
|
|
156
|
-
if (typeof(selenium) != "undefined") {
|
|
157
|
-
piMode = selenium.browserbot && selenium.browserbot.proxyInjectionMode;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (piMode) {
|
|
161
|
-
this.relayToRC("selenium." + s);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
BrowserBot.prototype.relayToRC = function(name) {
|
|
166
|
-
var object = eval(name);
|
|
167
|
-
var s = 'state:' + serializeObject(name, object) + "\n";
|
|
168
|
-
sendToRC(s,"state=true");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
BrowserBot.prototype.resetPopups = function() {
|
|
172
|
-
this.recordedAlerts = [];
|
|
173
|
-
this.recordedConfirmations = [];
|
|
174
|
-
this.recordedPrompts = [];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
BrowserBot.prototype.getNextAlert = function() {
|
|
178
|
-
var t = this.recordedAlerts.shift();
|
|
179
|
-
this.relayBotToRC("browserbot.recordedAlerts");
|
|
180
|
-
return t;
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
BrowserBot.prototype.hasConfirmations = function() {
|
|
184
|
-
return (this.recordedConfirmations.length > 0);
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
BrowserBot.prototype.getNextConfirmation = function() {
|
|
188
|
-
var t = this.recordedConfirmations.shift();
|
|
189
|
-
this.relayBotToRC("browserbot.recordedConfirmations");
|
|
190
|
-
return t;
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
BrowserBot.prototype.hasPrompts = function() {
|
|
194
|
-
return (this.recordedPrompts.length > 0);
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
BrowserBot.prototype.getNextPrompt = function() {
|
|
198
|
-
var t = this.recordedPrompts.shift();
|
|
199
|
-
this.relayBotToRC("browserbot.recordedPrompts");
|
|
200
|
-
return t;
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
/* Fire a mouse event in a browser-compatible manner */
|
|
204
|
-
|
|
205
|
-
BrowserBot.prototype.triggerMouseEvent = function(element, eventType, canBubble, clientX, clientY) {
|
|
206
|
-
clientX = clientX ? clientX : 0;
|
|
207
|
-
clientY = clientY ? clientY : 0;
|
|
208
|
-
|
|
209
|
-
LOG.debug("triggerMouseEvent assumes setting screenX and screenY to 0 is ok");
|
|
210
|
-
var screenX = 0;
|
|
211
|
-
var screenY = 0;
|
|
212
|
-
|
|
213
|
-
canBubble = (typeof(canBubble) == undefined) ? true : canBubble;
|
|
214
|
-
if (element.fireEvent) {
|
|
215
|
-
var evt = createEventObject(element, this.controlKeyDown, this.altKeyDown, this.shiftKeyDown, this.metaKeyDown);
|
|
216
|
-
evt.detail = 0;
|
|
217
|
-
evt.button = 1;
|
|
218
|
-
evt.relatedTarget = null;
|
|
219
|
-
if (!screenX && !screenY && !clientX && !clientY && !this.controlKeyDown && !this.altKeyDown && !this.shiftKeyDown && !this.metaKeyDown) {
|
|
220
|
-
element.fireEvent('on' + eventType);
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
evt.screenX = screenX;
|
|
224
|
-
evt.screenY = screenY;
|
|
225
|
-
evt.clientX = clientX;
|
|
226
|
-
evt.clientY = clientY;
|
|
227
|
-
|
|
228
|
-
// when we go this route, window.event is never set to contain the event we have just created.
|
|
229
|
-
// ideally we could just slide it in as follows in the try-block below, but this normally
|
|
230
|
-
// doesn't work. This is why I try to avoid this code path, which is only required if we need to
|
|
231
|
-
// set attributes on the event (e.g., clientX).
|
|
232
|
-
try {
|
|
233
|
-
window.event = evt;
|
|
234
|
-
}
|
|
235
|
-
catch(e) {
|
|
236
|
-
// getting an "Object does not support this action or property" error. Save the event away
|
|
237
|
-
// for future reference.
|
|
238
|
-
// TODO: is there a way to update window.event?
|
|
239
|
-
|
|
240
|
-
// work around for http://jira.openqa.org/browse/SEL-280 -- make the event available somewhere:
|
|
241
|
-
selenium.browserbot.getCurrentWindow().selenium_event = evt;
|
|
242
|
-
}
|
|
243
|
-
element.fireEvent('on' + eventType, evt);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
var evt = document.createEvent('MouseEvents');
|
|
248
|
-
if (evt.initMouseEvent)
|
|
249
|
-
{
|
|
250
|
-
//Safari
|
|
251
|
-
evt.initMouseEvent(eventType, canBubble, true, document.defaultView, 1, screenX, screenY, clientX, clientY,
|
|
252
|
-
this.controlKeyDown, this.altKeyDown, this.shiftKeyDown, this.metaKeyDown, 0, null);
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
LOG.warn("element doesn't have initMouseEvent; firing an event which should -- but doesn't -- have other mouse-event related attributes here, as well as controlKeyDown, altKeyDown, shiftKeyDown, metaKeyDown");
|
|
256
|
-
evt.initEvent(eventType, canBubble, true);
|
|
257
|
-
|
|
258
|
-
evt.shiftKey = this.shiftKeyDown;
|
|
259
|
-
evt.metaKey = this.metaKeyDown;
|
|
260
|
-
evt.altKey = this.altKeyDown;
|
|
261
|
-
evt.ctrlKey = this.controlKeyDown;
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
element.dispatchEvent(evt);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
BrowserBot.prototype._windowClosed = function(win) {
|
|
269
|
-
var c = win.closed;
|
|
270
|
-
if (c == null) return true;
|
|
271
|
-
return c;
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
BrowserBot.prototype._modifyWindow = function(win) {
|
|
275
|
-
// In proxyInjectionMode, have to suppress LOG calls in _modifyWindow to avoid an infinite loop
|
|
276
|
-
if (this._windowClosed(win)) {
|
|
277
|
-
if (!this.proxyInjectionMode) {
|
|
278
|
-
LOG.error("modifyWindow: Window was closed!");
|
|
279
|
-
}
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
if (!this.proxyInjectionMode) {
|
|
283
|
-
LOG.debug('modifyWindow ' + this.uniqueId + ":" + win[this.uniqueId]);
|
|
284
|
-
}
|
|
285
|
-
if (!win[this.uniqueId]) {
|
|
286
|
-
win[this.uniqueId] = 1;
|
|
287
|
-
this.modifyWindowToRecordPopUpDialogs(win, this);
|
|
288
|
-
}
|
|
289
|
-
// In proxyInjection mode, we have our own mechanism for detecting page loads
|
|
290
|
-
if (!this.proxyInjectionMode) {
|
|
291
|
-
this.modifySeparateTestWindowToDetectPageLoads(win);
|
|
292
|
-
}
|
|
293
|
-
if (win.frames && win.frames.length && win.frames.length > 0) {
|
|
294
|
-
for (var i = 0; i < win.frames.length; i++) {
|
|
295
|
-
try {
|
|
296
|
-
this._modifyWindow(win.frames[i]);
|
|
297
|
-
} catch (e) {} // we're just trying to be opportunistic; don't worry if this doesn't work out
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return win;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
BrowserBot.prototype.selectWindow = function(target) {
|
|
304
|
-
// TODO implement a locator syntax here
|
|
305
|
-
if (target && target != "null") {
|
|
306
|
-
try {
|
|
307
|
-
this._selectWindowByName(target);
|
|
308
|
-
}
|
|
309
|
-
catch (e) {
|
|
310
|
-
this._selectWindowByTitle(target);
|
|
311
|
-
}
|
|
312
|
-
} else {
|
|
313
|
-
this._selectTopWindow();
|
|
314
|
-
}
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
BrowserBot.prototype._selectTopWindow = function() {
|
|
318
|
-
this.currentWindowName = null;
|
|
319
|
-
this.currentWindow = this.topWindow;
|
|
320
|
-
this.topFrame = this.topWindow;
|
|
321
|
-
this.isSubFrameSelected = false;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
BrowserBot.prototype._selectWindowByName = function(target) {
|
|
325
|
-
this.currentWindow = this.getWindowByName(target, false);
|
|
326
|
-
this.topFrame = this.currentWindow;
|
|
327
|
-
this.currentWindowName = target;
|
|
328
|
-
this.isSubFrameSelected = false;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
BrowserBot.prototype._selectWindowByTitle = function(target) {
|
|
332
|
-
var windowName = this.getWindowNameByTitle(target);
|
|
333
|
-
if (!windowName) {
|
|
334
|
-
this._selectTopWindow();
|
|
335
|
-
} else {
|
|
336
|
-
this._selectWindowByName(windowName);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
BrowserBot.prototype.selectFrame = function(target) {
|
|
341
|
-
if (target.indexOf("index=") == 0) {
|
|
342
|
-
target = target.substr(6);
|
|
343
|
-
var frame = this.getCurrentWindow().frames[target];
|
|
344
|
-
if (frame == null) {
|
|
345
|
-
throw new SeleniumError("Not found: frames["+index+"]");
|
|
346
|
-
}
|
|
347
|
-
if (!frame.document) {
|
|
348
|
-
throw new SeleniumError("frames["+index+"] is not a frame");
|
|
349
|
-
}
|
|
350
|
-
this.currentWindow = frame;
|
|
351
|
-
this.isSubFrameSelected = true;
|
|
352
|
-
}
|
|
353
|
-
else if (target == "relative=up") {
|
|
354
|
-
this.currentWindow = this.getCurrentWindow().parent;
|
|
355
|
-
this.isSubFrameSelected = (this._getFrameElement(this.currentWindow) != null);
|
|
356
|
-
} else if (target == "relative=top") {
|
|
357
|
-
this.currentWindow = this.topFrame;
|
|
358
|
-
this.isSubFrameSelected = false;
|
|
359
|
-
} else {
|
|
360
|
-
var frame = this.findElement(target);
|
|
361
|
-
if (frame == null) {
|
|
362
|
-
throw new SeleniumError("Not found: " + target);
|
|
363
|
-
}
|
|
364
|
-
// now, did they give us a frame or a frame ELEMENT?
|
|
365
|
-
var match = false;
|
|
366
|
-
if (frame.contentWindow) {
|
|
367
|
-
// this must be a frame element
|
|
368
|
-
if (browserVersion.isHTA) {
|
|
369
|
-
// stupid HTA bug; can't get in the front door
|
|
370
|
-
target = frame.contentWindow.name;
|
|
371
|
-
} else {
|
|
372
|
-
this.currentWindow = frame.contentWindow;
|
|
373
|
-
this.isSubFrameSelected = true;
|
|
374
|
-
match = true;
|
|
375
|
-
}
|
|
376
|
-
} else if (frame.document && frame.location) {
|
|
377
|
-
// must be an actual window frame
|
|
378
|
-
this.currentWindow = frame;
|
|
379
|
-
this.isSubFrameSelected = true;
|
|
380
|
-
match = true;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (!match) {
|
|
384
|
-
// neither, let's loop through the frame names
|
|
385
|
-
var win = this.getCurrentWindow();
|
|
386
|
-
|
|
387
|
-
if (win && win.frames && win.frames.length) {
|
|
388
|
-
for (var i = 0; i < win.frames.length; i++) {
|
|
389
|
-
if (win.frames[i].name == target) {
|
|
390
|
-
this.currentWindow = win.frames[i];
|
|
391
|
-
this.isSubFrameSelected = true;
|
|
392
|
-
match = true;
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
if (!match) {
|
|
398
|
-
throw new SeleniumError("Not a frame: " + target);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
// modifies the window
|
|
403
|
-
this.getCurrentWindow();
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
BrowserBot.prototype.doesThisFrameMatchFrameExpression = function(currentFrameString, target) {
|
|
407
|
-
var isDom = false;
|
|
408
|
-
if (target.indexOf("dom=") == 0) {
|
|
409
|
-
target = target.substr(4);
|
|
410
|
-
isDom = true;
|
|
411
|
-
} else if (target.indexOf("index=") == 0) {
|
|
412
|
-
target = "frames[" + target.substr(6) + "]";
|
|
413
|
-
isDom = true;
|
|
414
|
-
}
|
|
415
|
-
var t;
|
|
416
|
-
try {
|
|
417
|
-
eval("t=" + currentFrameString + "." + target);
|
|
418
|
-
} catch (e) {
|
|
419
|
-
}
|
|
420
|
-
var autWindow = this.browserbot.getCurrentWindow();
|
|
421
|
-
if (t != null) {
|
|
422
|
-
try {
|
|
423
|
-
if (t.window == autWindow) {
|
|
424
|
-
return true;
|
|
425
|
-
}
|
|
426
|
-
if (t.window.uniqueId == autWindow.uniqueId) {
|
|
427
|
-
return true;
|
|
428
|
-
}
|
|
429
|
-
return false;
|
|
430
|
-
} catch (permDenied) {
|
|
431
|
-
// DGF if the windows are incomparable, they're probably not the same...
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
if (isDom) {
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
var currentFrame;
|
|
438
|
-
eval("currentFrame=" + currentFrameString);
|
|
439
|
-
if (target == "relative=up") {
|
|
440
|
-
if (currentFrame.window.parent == autWindow) {
|
|
441
|
-
return true;
|
|
442
|
-
}
|
|
443
|
-
return false;
|
|
444
|
-
}
|
|
445
|
-
if (target == "relative=top") {
|
|
446
|
-
if (currentFrame.window.top == autWindow) {
|
|
447
|
-
return true;
|
|
448
|
-
}
|
|
449
|
-
return false;
|
|
450
|
-
}
|
|
451
|
-
if (currentFrame.window == autWindow.parent) {
|
|
452
|
-
if (autWindow.name == target) {
|
|
453
|
-
return true;
|
|
454
|
-
}
|
|
455
|
-
try {
|
|
456
|
-
var element = this.findElement(target, currentFrame.window);
|
|
457
|
-
if (element.contentWindow == autWindow) {
|
|
458
|
-
return true;
|
|
459
|
-
}
|
|
460
|
-
} catch (e) {}
|
|
461
|
-
}
|
|
462
|
-
return false;
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
BrowserBot.prototype.openLocation = function(target) {
|
|
466
|
-
// We're moving to a new page - clear the current one
|
|
467
|
-
var win = this.getCurrentWindow();
|
|
468
|
-
LOG.debug("openLocation newPageLoaded = false");
|
|
469
|
-
this.newPageLoaded = false;
|
|
470
|
-
|
|
471
|
-
this.setOpenLocation(win, target);
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
BrowserBot.prototype.openWindow = function(url, windowID) {
|
|
475
|
-
if (url != "") {
|
|
476
|
-
url = absolutify(url, this.baseUrl);
|
|
477
|
-
}
|
|
478
|
-
if (browserVersion.isHTA) {
|
|
479
|
-
// in HTA mode, calling .open on the window interprets the url relative to that window
|
|
480
|
-
// we need to absolute-ize the URL to make it consistent
|
|
481
|
-
var child = this.getCurrentWindow().open(url, windowID);
|
|
482
|
-
selenium.browserbot.openedWindows[windowID] = child;
|
|
483
|
-
} else {
|
|
484
|
-
this.getCurrentWindow().open(url, windowID);
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
BrowserBot.prototype.setIFrameLocation = function(iframe, location) {
|
|
489
|
-
iframe.src = location;
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
BrowserBot.prototype.setOpenLocation = function(win, loc) {
|
|
493
|
-
loc = absolutify(loc, this.baseUrl);
|
|
494
|
-
if (browserVersion.isHTA) {
|
|
495
|
-
var oldHref = win.location.href;
|
|
496
|
-
win.location.href = loc;
|
|
497
|
-
var marker = null;
|
|
498
|
-
try {
|
|
499
|
-
marker = this.isPollingForLoad(win);
|
|
500
|
-
if (marker && win.location[marker]) {
|
|
501
|
-
win.location[marker] = false;
|
|
502
|
-
}
|
|
503
|
-
} catch (e) {} // DGF don't know why, but this often fails
|
|
504
|
-
} else {
|
|
505
|
-
win.location.href = loc;
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
BrowserBot.prototype.getCurrentPage = function() {
|
|
510
|
-
return this;
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
BrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
|
|
514
|
-
var self = this;
|
|
515
|
-
|
|
516
|
-
windowToModify.alert = function(alert) {
|
|
517
|
-
browserBot.recordedAlerts.push(alert);
|
|
518
|
-
self.relayBotToRC.call(self, "browserbot.recordedAlerts");
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
windowToModify.confirm = function(message) {
|
|
522
|
-
browserBot.recordedConfirmations.push(message);
|
|
523
|
-
var result = browserBot.nextConfirmResult;
|
|
524
|
-
browserBot.nextConfirmResult = true;
|
|
525
|
-
self.relayBotToRC.call(self, "browserbot.recordedConfirmations");
|
|
526
|
-
return result;
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
windowToModify.prompt = function(message) {
|
|
530
|
-
browserBot.recordedPrompts.push(message);
|
|
531
|
-
var result = !browserBot.nextConfirmResult ? null : browserBot.nextPromptResult;
|
|
532
|
-
browserBot.nextConfirmResult = true;
|
|
533
|
-
browserBot.nextPromptResult = '';
|
|
534
|
-
self.relayBotToRC.call(self, "browserbot.recordedPrompts");
|
|
535
|
-
return result;
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
// Keep a reference to all popup windows by name
|
|
539
|
-
// note that in IE the "windowName" argument must be a valid javascript identifier, it seems.
|
|
540
|
-
var originalOpen = windowToModify.open;
|
|
541
|
-
var originalOpenReference;
|
|
542
|
-
if (browserVersion.isHTA) {
|
|
543
|
-
originalOpenReference = 'selenium_originalOpen' + new Date().getTime();
|
|
544
|
-
windowToModify[originalOpenReference] = windowToModify.open;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
var isHTA = browserVersion.isHTA;
|
|
548
|
-
|
|
549
|
-
var newOpen = function(url, windowName, windowFeatures, replaceFlag) {
|
|
550
|
-
var myOriginalOpen = originalOpen;
|
|
551
|
-
if (isHTA) {
|
|
552
|
-
myOriginalOpen = this[originalOpenReference];
|
|
553
|
-
}
|
|
554
|
-
var openedWindow = myOriginalOpen(url, windowName, windowFeatures, replaceFlag);
|
|
555
|
-
LOG.debug("window.open call intercepted; window ID (which you can use with selectWindow()) is \"" + windowName + "\"");
|
|
556
|
-
if (windowName!=null) {
|
|
557
|
-
openedWindow["seleniumWindowName"] = windowName;
|
|
558
|
-
}
|
|
559
|
-
selenium.browserbot.openedWindows[windowName] = openedWindow;
|
|
560
|
-
return openedWindow;
|
|
561
|
-
};
|
|
562
|
-
|
|
563
|
-
if (browserVersion.isHTA) {
|
|
564
|
-
originalOpenReference = 'selenium_originalOpen' + new Date().getTime();
|
|
565
|
-
newOpenReference = 'selenium_newOpen' + new Date().getTime();
|
|
566
|
-
var setOriginalRef = "this['" + originalOpenReference + "'] = this.open;";
|
|
567
|
-
|
|
568
|
-
if (windowToModify.eval) {
|
|
569
|
-
windowToModify.eval(setOriginalRef);
|
|
570
|
-
windowToModify.open = newOpen;
|
|
571
|
-
} else {
|
|
572
|
-
// DGF why can't I eval here? Seems like I'm querying the window at a bad time, maybe?
|
|
573
|
-
setOriginalRef += "this.open = this['" + newOpenReference + "'];";
|
|
574
|
-
windowToModify[newOpenReference] = newOpen;
|
|
575
|
-
windowToModify.setTimeout(setOriginalRef, 0);
|
|
576
|
-
}
|
|
577
|
-
} else {
|
|
578
|
-
windowToModify.open = newOpen;
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Call the supplied function when a the current page unloads and a new one loads.
|
|
584
|
-
* This is done by polling continuously until the document changes and is fully loaded.
|
|
585
|
-
*/
|
|
586
|
-
BrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads = function(windowObject) {
|
|
587
|
-
// Since the unload event doesn't fire in Safari 1.3, we start polling immediately
|
|
588
|
-
if (!windowObject) {
|
|
589
|
-
LOG.warn("modifySeparateTestWindowToDetectPageLoads: no windowObject!");
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
if (this._windowClosed(windowObject)) {
|
|
593
|
-
LOG.info("modifySeparateTestWindowToDetectPageLoads: windowObject was closed");
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
var oldMarker = this.isPollingForLoad(windowObject);
|
|
597
|
-
if (oldMarker) {
|
|
598
|
-
LOG.debug("modifySeparateTestWindowToDetectPageLoads: already polling this window: " + oldMarker);
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
var marker = 'selenium' + new Date().getTime();
|
|
603
|
-
LOG.debug("Starting pollForLoad (" + marker + "): " + windowObject.location);
|
|
604
|
-
this.pollingForLoad[marker] = true;
|
|
605
|
-
// if this is a frame, add a load listener, otherwise, attach a poller
|
|
606
|
-
var frameElement = this._getFrameElement(windowObject);
|
|
607
|
-
// DGF HTA mode can't attach load listeners to subframes (yuk!)
|
|
608
|
-
var htaSubFrame = this._isHTASubFrame(windowObject);
|
|
609
|
-
if (frameElement && !htaSubFrame) {
|
|
610
|
-
LOG.debug("modifySeparateTestWindowToDetectPageLoads: this window is a frame; attaching a load listener");
|
|
611
|
-
addLoadListener(frameElement, this.recordPageLoad);
|
|
612
|
-
frameElement[marker] = true;
|
|
613
|
-
frameElement["frame"+this.uniqueId] = marker;
|
|
614
|
-
LOG.debug("dgf this.uniqueId="+this.uniqueId);
|
|
615
|
-
LOG.debug("dgf marker="+marker);
|
|
616
|
-
LOG.debug("dgf frameElement['frame'+this.uniqueId]="+frameElement['frame'+this.uniqueId]);
|
|
617
|
-
frameElement[this.uniqueId] = marker;
|
|
618
|
-
LOG.debug("dgf frameElement[this.uniqueId]="+frameElement[this.uniqueId]);
|
|
619
|
-
} else {
|
|
620
|
-
windowObject.location[marker] = true;
|
|
621
|
-
windowObject[this.uniqueId] = marker;
|
|
622
|
-
this.pollForLoad(this.recordPageLoad, windowObject, windowObject.document, windowObject.location, windowObject.location.href, marker);
|
|
623
|
-
}
|
|
624
|
-
};
|
|
625
|
-
|
|
626
|
-
BrowserBot.prototype._isHTASubFrame = function(win) {
|
|
627
|
-
if (!browserVersion.isHTA) return false;
|
|
628
|
-
// DGF this is wrong! what if "win" isn't the selected window?
|
|
629
|
-
return this.isSubFrameSelected;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
BrowserBot.prototype._getFrameElement = function(win) {
|
|
633
|
-
var frameElement = null;
|
|
634
|
-
var caught;
|
|
635
|
-
try {
|
|
636
|
-
frameElement = win.frameElement;
|
|
637
|
-
} catch (e) {
|
|
638
|
-
caught = true;
|
|
639
|
-
}
|
|
640
|
-
if (caught) {
|
|
641
|
-
// on IE, checking frameElement in a pop-up results in a "No such interface supported" exception
|
|
642
|
-
// but it might have a frame element anyway!
|
|
643
|
-
var parentContainsIdenticallyNamedFrame = false;
|
|
644
|
-
try {
|
|
645
|
-
parentContainsIdenticallyNamedFrame = win.parent.frames[win.name];
|
|
646
|
-
} catch (e) {} // this may fail if access is denied to the parent; in that case, assume it's not a pop-up
|
|
647
|
-
|
|
648
|
-
if (parentContainsIdenticallyNamedFrame) {
|
|
649
|
-
// it can't be a coincidence that the parent has a frame with the same name as myself!
|
|
650
|
-
var result;
|
|
651
|
-
try {
|
|
652
|
-
result = parentContainsIdenticallyNamedFrame.frameElement;
|
|
653
|
-
if (result) {
|
|
654
|
-
return result;
|
|
655
|
-
}
|
|
656
|
-
} catch (e) {} // it was worth a try! _getFrameElementsByName is often slow
|
|
657
|
-
result = this._getFrameElementByName(win.name, win.parent.document, win);
|
|
658
|
-
return result;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
LOG.debug("_getFrameElement: frameElement="+frameElement);
|
|
662
|
-
if (frameElement) {
|
|
663
|
-
LOG.debug("frameElement.name="+frameElement.name);
|
|
664
|
-
}
|
|
665
|
-
return frameElement;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
BrowserBot.prototype._getFrameElementByName = function(name, doc, win) {
|
|
669
|
-
var frames;
|
|
670
|
-
var frame;
|
|
671
|
-
var i;
|
|
672
|
-
frames = doc.getElementsByTagName("iframe");
|
|
673
|
-
for (i = 0; i < frames.length; i++) {
|
|
674
|
-
frame = frames[i];
|
|
675
|
-
if (frame.name === name) {
|
|
676
|
-
return frame;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
frames = doc.getElementsByTagName("frame");
|
|
680
|
-
for (i = 0; i < frames.length; i++) {
|
|
681
|
-
frame = frames[i];
|
|
682
|
-
if (frame.name === name) {
|
|
683
|
-
return frame;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
// DGF weird; we only call this function when we know the doc contains the frame
|
|
687
|
-
LOG.warn("_getFrameElementByName couldn't find a frame or iframe; checking every element for the name " + name);
|
|
688
|
-
return BrowserBot.prototype.locateElementByName(win.name, win.parent.document);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Set up a polling timer that will keep checking the readyState of the document until it's complete.
|
|
694
|
-
* Since we might call this before the original page is unloaded, we first check to see that the current location
|
|
695
|
-
* or href is different from the original one.
|
|
696
|
-
*/
|
|
697
|
-
BrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
698
|
-
LOG.debug("pollForLoad original (" + marker + "): " + originalHref);
|
|
699
|
-
try {
|
|
700
|
-
if (this._windowClosed(windowObject)) {
|
|
701
|
-
LOG.debug("pollForLoad WINDOW CLOSED (" + marker + ")");
|
|
702
|
-
delete this.pollingForLoad[marker];
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
var isSamePage = this._isSamePage(windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
707
|
-
var rs = this.getReadyState(windowObject, windowObject.document);
|
|
708
|
-
|
|
709
|
-
if (!isSamePage && rs == 'complete') {
|
|
710
|
-
var currentHref = windowObject.location.href;
|
|
711
|
-
LOG.debug("pollForLoad FINISHED (" + marker + "): " + rs + " (" + currentHref + ")");
|
|
712
|
-
delete this.pollingForLoad[marker];
|
|
713
|
-
this._modifyWindow(windowObject);
|
|
714
|
-
var newMarker = this.isPollingForLoad(windowObject);
|
|
715
|
-
if (!newMarker) {
|
|
716
|
-
LOG.debug("modifyWindow didn't start new poller: " + newMarker);
|
|
717
|
-
this.modifySeparateTestWindowToDetectPageLoads(windowObject);
|
|
718
|
-
}
|
|
719
|
-
newMarker = this.isPollingForLoad(windowObject);
|
|
720
|
-
var currentlySelectedWindow;
|
|
721
|
-
var currentlySelectedWindowMarker;
|
|
722
|
-
currentlySelectedWindow =this.getCurrentWindow(true);
|
|
723
|
-
currentlySelectedWindowMarker = currentlySelectedWindow[this.uniqueId];
|
|
724
|
-
|
|
725
|
-
LOG.debug("pollForLoad (" + marker + ") restarting " + newMarker);
|
|
726
|
-
if (/(TestRunner-splash|Blank)\.html\?start=true$/.test(currentHref)) {
|
|
727
|
-
LOG.debug("pollForLoad Oh, it's just the starting page. Never mind!");
|
|
728
|
-
} else if (currentlySelectedWindowMarker == newMarker) {
|
|
729
|
-
loadFunction(currentlySelectedWindow);
|
|
730
|
-
} else {
|
|
731
|
-
LOG.debug("pollForLoad page load detected in non-current window; ignoring (currentlySelected="+currentlySelectedWindowMarker+", detection in "+newMarker+")");
|
|
732
|
-
}
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
LOG.debug("pollForLoad continue (" + marker + "): " + currentHref);
|
|
736
|
-
this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
737
|
-
} catch (e) {
|
|
738
|
-
LOG.debug("Exception during pollForLoad; this should get noticed soon (" + e.message + ")!");
|
|
739
|
-
//DGF this is supposed to get logged later; log it at debug just in case
|
|
740
|
-
//LOG.exception(e);
|
|
741
|
-
this.pageLoadError = e;
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
|
|
745
|
-
BrowserBot.prototype._isSamePage = function(windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
746
|
-
var currentDocument = windowObject.document;
|
|
747
|
-
var currentLocation = windowObject.location;
|
|
748
|
-
var currentHref = currentLocation.href
|
|
749
|
-
|
|
750
|
-
var sameDoc = this._isSameDocument(originalDocument, currentDocument);
|
|
751
|
-
|
|
752
|
-
var sameLoc = (originalLocation === currentLocation);
|
|
753
|
-
|
|
754
|
-
// hash marks don't meant the page has loaded, so we need to strip them off if they exist...
|
|
755
|
-
var currentHash = currentHref.indexOf('#');
|
|
756
|
-
if (currentHash > 0) {
|
|
757
|
-
currentHref = currentHref.substring(0, currentHash);
|
|
758
|
-
}
|
|
759
|
-
var originalHash = originalHref.indexOf('#');
|
|
760
|
-
if (originalHash > 0) {
|
|
761
|
-
originalHref = originalHref.substring(0, originalHash);
|
|
762
|
-
}
|
|
763
|
-
LOG.debug("_isSamePage: currentHref: " + currentHref);
|
|
764
|
-
LOG.debug("_isSamePage: originalHref: " + originalHref);
|
|
765
|
-
|
|
766
|
-
var sameHref = (originalHref === currentHref);
|
|
767
|
-
var markedLoc = currentLocation[marker];
|
|
768
|
-
|
|
769
|
-
if (browserVersion.isKonqueror || browserVersion.isSafari) {
|
|
770
|
-
// the mark disappears too early on these browsers
|
|
771
|
-
markedLoc = true;
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// since this is some _very_ important logic, especially for PI and multiWindow mode, we should log all these out
|
|
775
|
-
LOG.debug("_isSamePage: sameDoc: " + sameDoc);
|
|
776
|
-
LOG.debug("_isSamePage: sameLoc: " + sameLoc);
|
|
777
|
-
LOG.debug("_isSamePage: sameHref: " + sameHref);
|
|
778
|
-
LOG.debug("_isSamePage: markedLoc: " + markedLoc);
|
|
779
|
-
|
|
780
|
-
return sameDoc && sameLoc && sameHref && markedLoc
|
|
781
|
-
};
|
|
782
|
-
|
|
783
|
-
BrowserBot.prototype._isSameDocument = function(originalDocument, currentDocument) {
|
|
784
|
-
return originalDocument === currentDocument;
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
BrowserBot.prototype.getReadyState = function(windowObject, currentDocument) {
|
|
789
|
-
var rs = currentDocument.readyState;
|
|
790
|
-
if (rs == null) {
|
|
791
|
-
if ((this.buttonWindow!=null && this.buttonWindow.document.readyState == null) // not proxy injection mode (and therefore buttonWindow isn't null)
|
|
792
|
-
|| (top.document.readyState == null)) { // proxy injection mode (and therefore everything's in the top window, but buttonWindow doesn't exist)
|
|
793
|
-
// uh oh! we're probably on Firefox with no readyState extension installed!
|
|
794
|
-
// We'll have to just take a guess as to when the document is loaded; this guess
|
|
795
|
-
// will never be perfect. :-(
|
|
796
|
-
if (typeof currentDocument.getElementsByTagName != 'undefined'
|
|
797
|
-
&& typeof currentDocument.getElementById != 'undefined'
|
|
798
|
-
&& ( currentDocument.getElementsByTagName('body')[0] != null
|
|
799
|
-
|| currentDocument.body != null )) {
|
|
800
|
-
if (windowObject.frameElement && windowObject.location.href == "about:blank" && windowObject.frameElement.src != "about:blank") {
|
|
801
|
-
LOG.info("getReadyState not loaded, frame location was about:blank, but frame src = " + windowObject.frameElement.src);
|
|
802
|
-
return null;
|
|
803
|
-
}
|
|
804
|
-
LOG.debug("getReadyState = windowObject.frames.length = " + windowObject.frames.length);
|
|
805
|
-
for (var i = 0; i < windowObject.frames.length; i++) {
|
|
806
|
-
LOG.debug("i = " + i);
|
|
807
|
-
if (this.getReadyState(windowObject.frames[i], windowObject.frames[i].document) != 'complete') {
|
|
808
|
-
LOG.debug("getReadyState aha! the nested frame " + windowObject.frames[i].name + " wasn't ready!");
|
|
809
|
-
return null;
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
rs = 'complete';
|
|
814
|
-
} else {
|
|
815
|
-
LOG.debug("pollForLoad readyState was null and DOM appeared to not be ready yet");
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
else if (rs == "loading" && browserVersion.isIE) {
|
|
820
|
-
LOG.debug("pageUnloading = true!!!!");
|
|
821
|
-
this.pageUnloading = true;
|
|
822
|
-
}
|
|
823
|
-
LOG.debug("getReadyState returning " + rs);
|
|
824
|
-
return rs;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
/** This function isn't used normally, but was the way we used to schedule pollers:
|
|
828
|
-
asynchronously executed autonomous units. This is deprecated, but remains here
|
|
829
|
-
for future reference.
|
|
830
|
-
*/
|
|
831
|
-
BrowserBot.prototype.XXXreschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
832
|
-
var self = this;
|
|
833
|
-
window.setTimeout(function() {
|
|
834
|
-
self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
835
|
-
}, 500);
|
|
836
|
-
};
|
|
837
|
-
|
|
838
|
-
/** This function isn't used normally, but is useful for debugging asynchronous pollers
|
|
839
|
-
* To enable it, rename it to "reschedulePoller", so it will override the
|
|
840
|
-
* existing reschedulePoller function
|
|
841
|
-
*/
|
|
842
|
-
BrowserBot.prototype.XXXreschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
843
|
-
var doc = this.buttonWindow.document;
|
|
844
|
-
var button = doc.createElement("button");
|
|
845
|
-
var buttonName = doc.createTextNode(marker + " - " + windowObject.name);
|
|
846
|
-
button.appendChild(buttonName);
|
|
847
|
-
var tools = doc.getElementById("tools");
|
|
848
|
-
var self = this;
|
|
849
|
-
button.onclick = function() {
|
|
850
|
-
tools.removeChild(button);
|
|
851
|
-
self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
852
|
-
};
|
|
853
|
-
tools.appendChild(button);
|
|
854
|
-
window.setTimeout(button.onclick, 500);
|
|
855
|
-
};
|
|
856
|
-
|
|
857
|
-
BrowserBot.prototype.reschedulePoller = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
858
|
-
var self = this;
|
|
859
|
-
var pollerFunction = function() {
|
|
860
|
-
self.pollForLoad(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
861
|
-
};
|
|
862
|
-
this.windowPollers.push(pollerFunction);
|
|
863
|
-
};
|
|
864
|
-
|
|
865
|
-
BrowserBot.prototype.runScheduledPollers = function() {
|
|
866
|
-
LOG.debug("runScheduledPollers");
|
|
867
|
-
var oldPollers = this.windowPollers;
|
|
868
|
-
this.windowPollers = new Array();
|
|
869
|
-
for (var i = 0; i < oldPollers.length; i++) {
|
|
870
|
-
oldPollers[i].call();
|
|
871
|
-
}
|
|
872
|
-
LOG.debug("runScheduledPollers DONE");
|
|
873
|
-
};
|
|
874
|
-
|
|
875
|
-
BrowserBot.prototype.isPollingForLoad = function(win) {
|
|
876
|
-
var marker;
|
|
877
|
-
var frameElement = this._getFrameElement(win);
|
|
878
|
-
var htaSubFrame = this._isHTASubFrame(win);
|
|
879
|
-
if (frameElement && !htaSubFrame) {
|
|
880
|
-
marker = frameElement["frame"+this.uniqueId];
|
|
881
|
-
} else {
|
|
882
|
-
marker = win[this.uniqueId];
|
|
883
|
-
}
|
|
884
|
-
if (!marker) {
|
|
885
|
-
LOG.debug("isPollingForLoad false, missing uniqueId " + this.uniqueId + ": " + marker);
|
|
886
|
-
return false;
|
|
887
|
-
}
|
|
888
|
-
if (!this.pollingForLoad[marker]) {
|
|
889
|
-
LOG.debug("isPollingForLoad false, this.pollingForLoad[" + marker + "]: " + this.pollingForLoad[marker]);
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
return marker;
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
BrowserBot.prototype.getWindowByName = function(windowName, doNotModify) {
|
|
896
|
-
LOG.debug("getWindowByName(" + windowName + ")");
|
|
897
|
-
// First look in the map of opened windows
|
|
898
|
-
var targetWindow = this.openedWindows[windowName];
|
|
899
|
-
if (!targetWindow) {
|
|
900
|
-
targetWindow = this.topWindow[windowName];
|
|
901
|
-
}
|
|
902
|
-
if (!targetWindow && windowName == "_blank") {
|
|
903
|
-
for (var winName in this.openedWindows) {
|
|
904
|
-
// _blank can match selenium_blank*, if it looks like it's OK (valid href, not closed)
|
|
905
|
-
if (/^selenium_blank/.test(winName)) {
|
|
906
|
-
targetWindow = this.openedWindows[winName];
|
|
907
|
-
var ok;
|
|
908
|
-
try {
|
|
909
|
-
if (!this._windowClosed(targetWindow)) {
|
|
910
|
-
ok = targetWindow.location.href;
|
|
911
|
-
}
|
|
912
|
-
} catch (e) {}
|
|
913
|
-
if (ok) break;
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
if (!targetWindow) {
|
|
918
|
-
throw new SeleniumError("Window does not exist");
|
|
919
|
-
}
|
|
920
|
-
if (browserVersion.isHTA) {
|
|
921
|
-
try {
|
|
922
|
-
targetWindow.location.href;
|
|
923
|
-
} catch (e) {
|
|
924
|
-
targetWindow = window.open("", targetWindow.name);
|
|
925
|
-
this.openedWindows[targetWindow.name] = targetWindow;
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
if (!doNotModify) {
|
|
929
|
-
this._modifyWindow(targetWindow);
|
|
930
|
-
}
|
|
931
|
-
return targetWindow;
|
|
932
|
-
};
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* Find a window name from the window title.
|
|
936
|
-
*/
|
|
937
|
-
BrowserBot.prototype.getWindowNameByTitle = function(windowTitle) {
|
|
938
|
-
LOG.debug("getWindowNameByTitle(" + windowTitle + ")");
|
|
939
|
-
|
|
940
|
-
// First look in the map of opened windows and iterate them
|
|
941
|
-
for (var windowName in this.openedWindows) {
|
|
942
|
-
var targetWindow = this.openedWindows[windowName];
|
|
943
|
-
|
|
944
|
-
// If the target window's title is our title
|
|
945
|
-
try {
|
|
946
|
-
// TODO implement Pattern Matching here
|
|
947
|
-
if (!this._windowClosed(targetWindow) &&
|
|
948
|
-
targetWindow.document.title == windowTitle) {
|
|
949
|
-
return windowName;
|
|
950
|
-
}
|
|
951
|
-
} catch (e) {
|
|
952
|
-
// You'll often get Permission Denied errors here in IE
|
|
953
|
-
// eh, if we can't read this window's title,
|
|
954
|
-
// it's probably not available to us right now anyway
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
try {
|
|
959
|
-
if (this.topWindow.document.title == windowTitle) {
|
|
960
|
-
return "";
|
|
961
|
-
}
|
|
962
|
-
} catch (e) {} // IE Perm denied
|
|
963
|
-
|
|
964
|
-
throw new SeleniumError("Could not find window with title " + windowTitle);
|
|
965
|
-
};
|
|
966
|
-
|
|
967
|
-
BrowserBot.prototype.getCurrentWindow = function(doNotModify) {
|
|
968
|
-
if (this.proxyInjectionMode) {
|
|
969
|
-
return window;
|
|
970
|
-
}
|
|
971
|
-
var testWindow = this.currentWindow;
|
|
972
|
-
if (!doNotModify) {
|
|
973
|
-
this._modifyWindow(testWindow);
|
|
974
|
-
LOG.debug("getCurrentWindow newPageLoaded = false");
|
|
975
|
-
this.newPageLoaded = false;
|
|
976
|
-
}
|
|
977
|
-
testWindow = this._handleClosedSubFrame(testWindow, doNotModify);
|
|
978
|
-
return testWindow;
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
BrowserBot.prototype._handleClosedSubFrame = function(testWindow, doNotModify) {
|
|
982
|
-
if (this.proxyInjectionMode) {
|
|
983
|
-
return testWindow;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
if (this.isSubFrameSelected) {
|
|
987
|
-
var missing = true;
|
|
988
|
-
if (testWindow.parent && testWindow.parent.frames && testWindow.parent.frames.length) {
|
|
989
|
-
for (var i = 0; i < testWindow.parent.frames.length; i++) {
|
|
990
|
-
if (testWindow.parent.frames[i] == testWindow) {
|
|
991
|
-
missing = false;
|
|
992
|
-
break;
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
if (missing) {
|
|
997
|
-
LOG.warn("Current subframe appears to have closed; selecting top frame");
|
|
998
|
-
this.selectFrame("relative=top");
|
|
999
|
-
return this.getCurrentWindow(doNotModify);
|
|
1000
|
-
}
|
|
1001
|
-
} else if (this._windowClosed(testWindow)) {
|
|
1002
|
-
var closedError = new SeleniumError("Current window or frame is closed!");
|
|
1003
|
-
closedError.windowClosed = true;
|
|
1004
|
-
throw closedError;
|
|
1005
|
-
}
|
|
1006
|
-
return testWindow;
|
|
1007
|
-
};
|
|
1008
|
-
|
|
1009
|
-
BrowserBot.prototype.highlight = function (element, force) {
|
|
1010
|
-
if (force || this.shouldHighlightLocatedElement) {
|
|
1011
|
-
try {
|
|
1012
|
-
highlight(element);
|
|
1013
|
-
} catch (e) {} // DGF element highlighting is low-priority and possibly dangerous
|
|
1014
|
-
}
|
|
1015
|
-
return element;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
BrowserBot.prototype.setShouldHighlightElement = function (shouldHighlight) {
|
|
1019
|
-
this.shouldHighlightLocatedElement = shouldHighlight;
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
/*****************************************************************/
|
|
1023
|
-
/* BROWSER-SPECIFIC FUNCTIONS ONLY AFTER THIS LINE */
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
BrowserBot.prototype._registerAllLocatorFunctions = function() {
|
|
1027
|
-
// TODO - don't do this in the constructor - only needed once ever
|
|
1028
|
-
this.locationStrategies = {};
|
|
1029
|
-
for (var functionName in this) {
|
|
1030
|
-
var result = /^locateElementBy([A-Z].+)$/.exec(functionName);
|
|
1031
|
-
if (result != null) {
|
|
1032
|
-
var locatorFunction = this[functionName];
|
|
1033
|
-
if (typeof(locatorFunction) != 'function') {
|
|
1034
|
-
continue;
|
|
1035
|
-
}
|
|
1036
|
-
// Use a specified prefix in preference to one generated from
|
|
1037
|
-
// the function name
|
|
1038
|
-
var locatorPrefix = locatorFunction.prefix || result[1].toLowerCase();
|
|
1039
|
-
this.locationStrategies[locatorPrefix] = locatorFunction;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
/**
|
|
1044
|
-
* Find a locator based on a prefix.
|
|
1045
|
-
*/
|
|
1046
|
-
this.findElementBy = function(locatorType, locator, inDocument, inWindow) {
|
|
1047
|
-
var locatorFunction = this.locationStrategies[locatorType];
|
|
1048
|
-
if (! locatorFunction) {
|
|
1049
|
-
throw new SeleniumError("Unrecognised locator type: '" + locatorType + "'");
|
|
1050
|
-
}
|
|
1051
|
-
return locatorFunction.call(this, locator, inDocument, inWindow);
|
|
1052
|
-
};
|
|
1053
|
-
|
|
1054
|
-
/**
|
|
1055
|
-
* The implicit locator, that is used when no prefix is supplied.
|
|
1056
|
-
*/
|
|
1057
|
-
this.locationStrategies['implicit'] = function(locator, inDocument, inWindow) {
|
|
1058
|
-
if (locator.startsWith('//')) {
|
|
1059
|
-
return this.locateElementByXPath(locator, inDocument, inWindow);
|
|
1060
|
-
}
|
|
1061
|
-
if (locator.startsWith('document.')) {
|
|
1062
|
-
return this.locateElementByDomTraversal(locator, inDocument, inWindow);
|
|
1063
|
-
}
|
|
1064
|
-
return this.locateElementByIdentifier(locator, inDocument, inWindow);
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
BrowserBot.prototype.getDocument = function() {
|
|
1069
|
-
return this.getCurrentWindow().document;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
BrowserBot.prototype.getTitle = function() {
|
|
1073
|
-
var t = this.getDocument().title;
|
|
1074
|
-
if (typeof(t) == "string") {
|
|
1075
|
-
t = t.trim();
|
|
1076
|
-
}
|
|
1077
|
-
return t;
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
/*
|
|
1081
|
-
* Finds an element recursively in frames and nested frames
|
|
1082
|
-
* in the specified document, using various lookup protocols
|
|
1083
|
-
*/
|
|
1084
|
-
BrowserBot.prototype.findElementRecursive = function(locatorType, locatorString, inDocument, inWindow) {
|
|
1085
|
-
|
|
1086
|
-
var element = this.findElementBy(locatorType, locatorString, inDocument, inWindow);
|
|
1087
|
-
if (element != null) {
|
|
1088
|
-
return element;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
for (var i = 0; i < inWindow.frames.length; i++) {
|
|
1092
|
-
element = this.findElementRecursive(locatorType, locatorString, inWindow.frames[i].document, inWindow.frames[i]);
|
|
1093
|
-
|
|
1094
|
-
if (element != null) {
|
|
1095
|
-
return element;
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
|
|
1100
|
-
/*
|
|
1101
|
-
* Finds an element on the current page, using various lookup protocols
|
|
1102
|
-
*/
|
|
1103
|
-
BrowserBot.prototype.findElementOrNull = function(locator, win) {
|
|
1104
|
-
var locatorType = 'implicit';
|
|
1105
|
-
var locatorString = locator;
|
|
1106
|
-
|
|
1107
|
-
// If there is a locator prefix, use the specified strategy
|
|
1108
|
-
var result = locator.match(/^([A-Za-z]+)=(.+)/);
|
|
1109
|
-
if (result) {
|
|
1110
|
-
locatorType = result[1].toLowerCase();
|
|
1111
|
-
locatorString = result[2];
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
if (win == null) {
|
|
1115
|
-
win = this.getCurrentWindow();
|
|
1116
|
-
}
|
|
1117
|
-
var element = this.findElementRecursive(locatorType, locatorString, win.document, win);
|
|
1118
|
-
|
|
1119
|
-
if (element != null) {
|
|
1120
|
-
return this.browserbot.highlight(element);
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
// Element was not found by any locator function.
|
|
1124
|
-
return null;
|
|
1125
|
-
};
|
|
1126
|
-
|
|
1127
|
-
BrowserBot.prototype.findElement = function(locator, win) {
|
|
1128
|
-
var element = this.findElementOrNull(locator, win);
|
|
1129
|
-
if (element == null) throw new SeleniumError("Element " + locator + " not found");
|
|
1130
|
-
return element;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
/**
|
|
1134
|
-
* In non-IE browsers, getElementById() does not search by name. Instead, we
|
|
1135
|
-
* we search separately by id and name.
|
|
1136
|
-
*/
|
|
1137
|
-
BrowserBot.prototype.locateElementByIdentifier = function(identifier, inDocument, inWindow) {
|
|
1138
|
-
return BrowserBot.prototype.locateElementById(identifier, inDocument, inWindow)
|
|
1139
|
-
|| BrowserBot.prototype.locateElementByName(identifier, inDocument, inWindow)
|
|
1140
|
-
|| null;
|
|
1141
|
-
};
|
|
1142
|
-
|
|
1143
|
-
/**
|
|
1144
|
-
* Find the element with id - can't rely on getElementById, coz it returns by name as well in IE..
|
|
1145
|
-
*/
|
|
1146
|
-
BrowserBot.prototype.locateElementById = function(identifier, inDocument, inWindow) {
|
|
1147
|
-
var element = inDocument.getElementById(identifier);
|
|
1148
|
-
if (element && element.id === identifier) {
|
|
1149
|
-
return element;
|
|
1150
|
-
}
|
|
1151
|
-
else {
|
|
1152
|
-
return null;
|
|
1153
|
-
}
|
|
1154
|
-
};
|
|
1155
|
-
|
|
1156
|
-
/**
|
|
1157
|
-
* Find an element by name, refined by (optional) element-filter
|
|
1158
|
-
* expressions.
|
|
1159
|
-
*/
|
|
1160
|
-
BrowserBot.prototype.locateElementByName = function(locator, document, inWindow) {
|
|
1161
|
-
var elements = document.getElementsByTagName("*");
|
|
1162
|
-
|
|
1163
|
-
var filters = locator.split(' ');
|
|
1164
|
-
filters[0] = 'name=' + filters[0];
|
|
1165
|
-
|
|
1166
|
-
while (filters.length) {
|
|
1167
|
-
var filter = filters.shift();
|
|
1168
|
-
elements = this.selectElements(filter, elements, 'value');
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
if (elements.length > 0) {
|
|
1172
|
-
return elements[0];
|
|
1173
|
-
}
|
|
1174
|
-
return null;
|
|
1175
|
-
};
|
|
1176
|
-
|
|
1177
|
-
/**
|
|
1178
|
-
* Finds an element using by evaluating the specfied string.
|
|
1179
|
-
*/
|
|
1180
|
-
BrowserBot.prototype.locateElementByDomTraversal = function(domTraversal, document, window) {
|
|
1181
|
-
|
|
1182
|
-
var browserbot = this.browserbot;
|
|
1183
|
-
var element = null;
|
|
1184
|
-
try {
|
|
1185
|
-
element = eval(domTraversal);
|
|
1186
|
-
} catch (e) {
|
|
1187
|
-
return null;
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
if (!element) {
|
|
1191
|
-
return null;
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
return element;
|
|
1195
|
-
};
|
|
1196
|
-
BrowserBot.prototype.locateElementByDomTraversal.prefix = "dom";
|
|
1197
|
-
|
|
1198
|
-
/**
|
|
1199
|
-
* Finds an element identified by the xpath expression. Expressions _must_
|
|
1200
|
-
* begin with "//".
|
|
1201
|
-
*/
|
|
1202
|
-
BrowserBot.prototype.locateElementByXPath = function(xpath, inDocument, inWindow) {
|
|
1203
|
-
// Trim any trailing "/": not valid xpath, and remains from attribute
|
|
1204
|
-
// locator.
|
|
1205
|
-
if (xpath.charAt(xpath.length - 1) == '/') {
|
|
1206
|
-
xpath = xpath.slice(0, -1);
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// Handle //tag
|
|
1210
|
-
var match = xpath.match(/^\/\/(\w+|\*)$/);
|
|
1211
|
-
if (match) {
|
|
1212
|
-
var elements = inDocument.getElementsByTagName(match[1].toUpperCase());
|
|
1213
|
-
if (elements == null) return null;
|
|
1214
|
-
return elements[0];
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
// Handle //tag[@attr='value']
|
|
1218
|
-
var match = xpath.match(/^\/\/(\w+|\*)\[@(\w+)=('([^\']+)'|"([^\"]+)")\]$/);
|
|
1219
|
-
if (match) {
|
|
1220
|
-
// We don't return the value without checking if it is null first.
|
|
1221
|
-
// This is beacuse in some rare cases, this shortcut actually WONT work
|
|
1222
|
-
// but that the full XPath WILL. A known case, for example, is in IE
|
|
1223
|
-
// when the attribute is onclick/onblur/onsubmit/etc. Due to a bug in IE
|
|
1224
|
-
// this shortcut won't work because the actual function is returned
|
|
1225
|
-
// by getAttribute() rather than the text of the attribute.
|
|
1226
|
-
var val = this._findElementByTagNameAndAttributeValue(
|
|
1227
|
-
inDocument,
|
|
1228
|
-
match[1].toUpperCase(),
|
|
1229
|
-
match[2].toLowerCase(),
|
|
1230
|
-
match[3].slice(1, -1)
|
|
1231
|
-
);
|
|
1232
|
-
if (val) {
|
|
1233
|
-
return val;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
// Handle //tag[text()='value']
|
|
1238
|
-
var match = xpath.match(/^\/\/(\w+|\*)\[text\(\)=('([^\']+)'|"([^\"]+)")\]$/);
|
|
1239
|
-
if (match) {
|
|
1240
|
-
return this._findElementByTagNameAndText(
|
|
1241
|
-
inDocument,
|
|
1242
|
-
match[1].toUpperCase(),
|
|
1243
|
-
match[2].slice(1, -1)
|
|
1244
|
-
);
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
return this._findElementUsingFullXPath(xpath, inDocument);
|
|
1248
|
-
};
|
|
1249
|
-
|
|
1250
|
-
BrowserBot.prototype._findElementByTagNameAndAttributeValue = function(
|
|
1251
|
-
inDocument, tagName, attributeName, attributeValue
|
|
1252
|
-
) {
|
|
1253
|
-
if (browserVersion.isIE && attributeName == "class") {
|
|
1254
|
-
attributeName = "className";
|
|
1255
|
-
}
|
|
1256
|
-
var elements = inDocument.getElementsByTagName(tagName);
|
|
1257
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1258
|
-
var elementAttr = elements[i].getAttribute(attributeName);
|
|
1259
|
-
if (elementAttr == attributeValue) {
|
|
1260
|
-
return elements[i];
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
return null;
|
|
1264
|
-
};
|
|
1265
|
-
|
|
1266
|
-
BrowserBot.prototype._findElementByTagNameAndText = function(
|
|
1267
|
-
inDocument, tagName, text
|
|
1268
|
-
) {
|
|
1269
|
-
var elements = inDocument.getElementsByTagName(tagName);
|
|
1270
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1271
|
-
if (getText(elements[i]) == text) {
|
|
1272
|
-
return elements[i];
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
return null;
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
BrowserBot.prototype._namespaceResolver = function(prefix) {
|
|
1279
|
-
if (prefix == 'html' || prefix == 'xhtml' || prefix == 'x') {
|
|
1280
|
-
return 'http://www.w3.org/1999/xhtml';
|
|
1281
|
-
} else if (prefix == 'mathml') {
|
|
1282
|
-
return 'http://www.w3.org/1998/Math/MathML';
|
|
1283
|
-
} else {
|
|
1284
|
-
throw new Error("Unknown namespace: " + prefix + ".");
|
|
1285
|
-
}
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
BrowserBot.prototype._findElementUsingFullXPath = function(xpath, inDocument, inWindow) {
|
|
1289
|
-
// HUGE hack - remove namespace from xpath for IE
|
|
1290
|
-
if (browserVersion.isIE) {
|
|
1291
|
-
xpath = xpath.replace(/x:/g, '')
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
// Use document.evaluate() if it's available
|
|
1295
|
-
if (this.allowNativeXpath && inDocument.evaluate) {
|
|
1296
|
-
return inDocument.evaluate(xpath, inDocument, this._namespaceResolver, 0, null).iterateNext();
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
// If not, fall back to slower JavaScript implementation
|
|
1300
|
-
// DGF set xpathdebug = true (using getEval, if you like) to turn on JS XPath debugging
|
|
1301
|
-
//xpathdebug = true;
|
|
1302
|
-
var context = new ExprContext(inDocument);
|
|
1303
|
-
var xpathObj = xpathParse(xpath);
|
|
1304
|
-
var xpathResult = xpathObj.evaluate(context);
|
|
1305
|
-
if (xpathResult && xpathResult.value) {
|
|
1306
|
-
return xpathResult.value[0];
|
|
1307
|
-
}
|
|
1308
|
-
return null;
|
|
1309
|
-
|
|
1310
|
-
};
|
|
1311
|
-
|
|
1312
|
-
// DGF this may LOOK identical to _findElementUsingFullXPath, but
|
|
1313
|
-
// fEUFX pops the first element off the resulting nodelist; this function
|
|
1314
|
-
// wraps the xpath in a count() operator and returns the numeric value directly
|
|
1315
|
-
BrowserBot.prototype.evaluateXPathCount = function(xpath, inDocument) {
|
|
1316
|
-
// HUGE hack - remove namespace from xpath for IE
|
|
1317
|
-
if (browserVersion.isIE) {
|
|
1318
|
-
xpath = xpath.replace(/x:/g, '')
|
|
1319
|
-
}
|
|
1320
|
-
xpath = new String(xpath);
|
|
1321
|
-
if (xpath.indexOf("xpath=") == 0) {
|
|
1322
|
-
xpath = xpath.substring(6);
|
|
1323
|
-
}
|
|
1324
|
-
if (xpath.indexOf("count(") == 0) {
|
|
1325
|
-
// DGF we COULD just fix this up for the user, but we might get it wrong (parens?)
|
|
1326
|
-
throw new SeleniumError("XPath count expressions must not be wrapped in count() function: " + xpath);
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
xpath="count("+xpath+")";
|
|
1330
|
-
|
|
1331
|
-
// Use document.evaluate() if it's available
|
|
1332
|
-
if (this.allowNativeXpath && inDocument.evaluate) {
|
|
1333
|
-
var result = inDocument.evaluate(xpath, inDocument, this._namespaceResolver, XPathResult.NUMBER_TYPE, null);
|
|
1334
|
-
return result.numberValue;
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
// If not, fall back to slower JavaScript implementation
|
|
1338
|
-
// DGF set xpathdebug = true (using getEval, if you like) to turn on JS XPath debugging
|
|
1339
|
-
//xpathdebug = true;
|
|
1340
|
-
var context = new ExprContext(inDocument);
|
|
1341
|
-
var xpathObj = xpathParse(xpath);
|
|
1342
|
-
var xpathResult = xpathObj.evaluate(context);
|
|
1343
|
-
if (xpathResult && xpathResult.value) {
|
|
1344
|
-
return xpathResult.value;
|
|
1345
|
-
}
|
|
1346
|
-
return 0;
|
|
1347
|
-
};
|
|
1348
|
-
|
|
1349
|
-
/**
|
|
1350
|
-
* Finds a link element with text matching the expression supplied. Expressions must
|
|
1351
|
-
* begin with "link:".
|
|
1352
|
-
*/
|
|
1353
|
-
BrowserBot.prototype.locateElementByLinkText = function(linkText, inDocument, inWindow) {
|
|
1354
|
-
var links = inDocument.getElementsByTagName('a');
|
|
1355
|
-
for (var i = 0; i < links.length; i++) {
|
|
1356
|
-
var element = links[i];
|
|
1357
|
-
if (PatternMatcher.matches(linkText, getText(element))) {
|
|
1358
|
-
return element;
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
return null;
|
|
1362
|
-
};
|
|
1363
|
-
BrowserBot.prototype.locateElementByLinkText.prefix = "link";
|
|
1364
|
-
|
|
1365
|
-
/**
|
|
1366
|
-
* Returns an attribute based on an attribute locator. This is made up of an element locator
|
|
1367
|
-
* suffixed with @attribute-name.
|
|
1368
|
-
*/
|
|
1369
|
-
BrowserBot.prototype.findAttribute = function(locator) {
|
|
1370
|
-
// Split into locator + attributeName
|
|
1371
|
-
var attributePos = locator.lastIndexOf("@");
|
|
1372
|
-
var elementLocator = locator.slice(0, attributePos);
|
|
1373
|
-
var attributeName = locator.slice(attributePos + 1);
|
|
1374
|
-
|
|
1375
|
-
// Find the element.
|
|
1376
|
-
var element = this.findElement(elementLocator);
|
|
1377
|
-
|
|
1378
|
-
// Handle missing "class" attribute in IE.
|
|
1379
|
-
if (browserVersion.isIE && attributeName == "class") {
|
|
1380
|
-
attributeName = "className";
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
// Get the attribute value.
|
|
1384
|
-
var attributeValue = element.getAttribute(attributeName);
|
|
1385
|
-
|
|
1386
|
-
return attributeValue ? attributeValue.toString() : null;
|
|
1387
|
-
};
|
|
1388
|
-
|
|
1389
|
-
/*
|
|
1390
|
-
* Select the specified option and trigger the relevant events of the element.
|
|
1391
|
-
*/
|
|
1392
|
-
BrowserBot.prototype.selectOption = function(element, optionToSelect) {
|
|
1393
|
-
triggerEvent(element, 'focus', false);
|
|
1394
|
-
var changed = false;
|
|
1395
|
-
for (var i = 0; i < element.options.length; i++) {
|
|
1396
|
-
var option = element.options[i];
|
|
1397
|
-
if (option.selected && option != optionToSelect) {
|
|
1398
|
-
option.selected = false;
|
|
1399
|
-
changed = true;
|
|
1400
|
-
}
|
|
1401
|
-
else if (!option.selected && option == optionToSelect) {
|
|
1402
|
-
option.selected = true;
|
|
1403
|
-
changed = true;
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
if (changed) {
|
|
1408
|
-
triggerEvent(element, 'change', true);
|
|
1409
|
-
}
|
|
1410
|
-
};
|
|
1411
|
-
|
|
1412
|
-
/*
|
|
1413
|
-
* Select the specified option and trigger the relevant events of the element.
|
|
1414
|
-
*/
|
|
1415
|
-
BrowserBot.prototype.addSelection = function(element, option) {
|
|
1416
|
-
this.checkMultiselect(element);
|
|
1417
|
-
triggerEvent(element, 'focus', false);
|
|
1418
|
-
if (!option.selected) {
|
|
1419
|
-
option.selected = true;
|
|
1420
|
-
triggerEvent(element, 'change', true);
|
|
1421
|
-
}
|
|
1422
|
-
};
|
|
1423
|
-
|
|
1424
|
-
/*
|
|
1425
|
-
* Select the specified option and trigger the relevant events of the element.
|
|
1426
|
-
*/
|
|
1427
|
-
BrowserBot.prototype.removeSelection = function(element, option) {
|
|
1428
|
-
this.checkMultiselect(element);
|
|
1429
|
-
triggerEvent(element, 'focus', false);
|
|
1430
|
-
if (option.selected) {
|
|
1431
|
-
option.selected = false;
|
|
1432
|
-
triggerEvent(element, 'change', true);
|
|
1433
|
-
}
|
|
1434
|
-
};
|
|
1435
|
-
|
|
1436
|
-
BrowserBot.prototype.checkMultiselect = function(element) {
|
|
1437
|
-
if (!element.multiple)
|
|
1438
|
-
{
|
|
1439
|
-
throw new SeleniumError("Not a multi-select");
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
};
|
|
1443
|
-
|
|
1444
|
-
BrowserBot.prototype.replaceText = function(element, stringValue) {
|
|
1445
|
-
triggerEvent(element, 'focus', false);
|
|
1446
|
-
triggerEvent(element, 'select', true);
|
|
1447
|
-
var maxLengthAttr = element.getAttribute("maxLength");
|
|
1448
|
-
var actualValue = stringValue;
|
|
1449
|
-
if (maxLengthAttr != null) {
|
|
1450
|
-
var maxLength = parseInt(maxLengthAttr);
|
|
1451
|
-
if (stringValue.length > maxLength) {
|
|
1452
|
-
actualValue = stringValue.substr(0, maxLength);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
|
|
1456
|
-
if (getTagName(element) == "body") {
|
|
1457
|
-
if (element.ownerDocument && element.ownerDocument.designMode) {
|
|
1458
|
-
var designMode = new String(element.ownerDocument.designMode).toLowerCase();
|
|
1459
|
-
if (designMode = "on") {
|
|
1460
|
-
// this must be a rich text control!
|
|
1461
|
-
element.innerHTML = actualValue;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
} else {
|
|
1465
|
-
element.value = actualValue;
|
|
1466
|
-
}
|
|
1467
|
-
// DGF this used to be skipped in chrome URLs, but no longer. Is xpcnativewrappers to blame?
|
|
1468
|
-
try {
|
|
1469
|
-
triggerEvent(element, 'change', true);
|
|
1470
|
-
} catch (e) {}
|
|
1471
|
-
};
|
|
1472
|
-
|
|
1473
|
-
BrowserBot.prototype.submit = function(formElement) {
|
|
1474
|
-
var actuallySubmit = true;
|
|
1475
|
-
this._modifyElementTarget(formElement);
|
|
1476
|
-
if (formElement.onsubmit) {
|
|
1477
|
-
if (browserVersion.isHTA) {
|
|
1478
|
-
// run the code in the correct window so alerts are handled correctly even in HTA mode
|
|
1479
|
-
var win = this.browserbot.getCurrentWindow();
|
|
1480
|
-
var now = new Date().getTime();
|
|
1481
|
-
var marker = 'marker' + now;
|
|
1482
|
-
win[marker] = formElement;
|
|
1483
|
-
win.setTimeout("var actuallySubmit = "+marker+".onsubmit();" +
|
|
1484
|
-
"if (actuallySubmit) { " +
|
|
1485
|
-
marker+".submit(); " +
|
|
1486
|
-
"if ("+marker+".target && !/^_/.test("+marker+".target)) {"+
|
|
1487
|
-
"window.open('', "+marker+".target);"+
|
|
1488
|
-
"}"+
|
|
1489
|
-
"};"+
|
|
1490
|
-
marker+"=null", 0);
|
|
1491
|
-
// pause for up to 2s while this command runs
|
|
1492
|
-
var terminationCondition = function () {
|
|
1493
|
-
return !win[marker];
|
|
1494
|
-
}
|
|
1495
|
-
return Selenium.decorateFunctionWithTimeout(terminationCondition, 2000);
|
|
1496
|
-
} else {
|
|
1497
|
-
actuallySubmit = formElement.onsubmit();
|
|
1498
|
-
if (actuallySubmit) {
|
|
1499
|
-
formElement.submit();
|
|
1500
|
-
if (formElement.target && !/^_/.test(formElement.target)) {
|
|
1501
|
-
this.browserbot.openWindow('', formElement.target);
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
} else {
|
|
1506
|
-
formElement.submit();
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
BrowserBot.prototype.clickElement = function(element, clientX, clientY) {
|
|
1511
|
-
this._fireEventOnElement("click", element, clientX, clientY);
|
|
1512
|
-
};
|
|
1513
|
-
|
|
1514
|
-
BrowserBot.prototype.doubleClickElement = function(element, clientX, clientY) {
|
|
1515
|
-
this._fireEventOnElement("dblclick", element, clientX, clientY);
|
|
1516
|
-
};
|
|
1517
|
-
|
|
1518
|
-
BrowserBot.prototype._modifyElementTarget = function(element) {
|
|
1519
|
-
if (element.target) {
|
|
1520
|
-
if (element.target == "_blank" || /^selenium_blank/.test(element.target) ) {
|
|
1521
|
-
var tagName = getTagName(element);
|
|
1522
|
-
if (tagName == "a" || tagName == "form") {
|
|
1523
|
-
var newTarget = "selenium_blank" + Math.round(100000 * Math.random());
|
|
1524
|
-
LOG.warn("Link has target '_blank', which is not supported in Selenium! Randomizing target to be: " + newTarget);
|
|
1525
|
-
this.browserbot.openWindow('', newTarget);
|
|
1526
|
-
element.target = newTarget;
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
BrowserBot.prototype._handleClickingImagesInsideLinks = function(targetWindow, element) {
|
|
1534
|
-
var itrElement = element;
|
|
1535
|
-
while (itrElement != null) {
|
|
1536
|
-
if (itrElement.href) {
|
|
1537
|
-
targetWindow.location.href = itrElement.href;
|
|
1538
|
-
break;
|
|
1539
|
-
}
|
|
1540
|
-
itrElement = itrElement.parentNode;
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
BrowserBot.prototype._getTargetWindow = function(element) {
|
|
1545
|
-
var targetWindow = element.ownerDocument.defaultView;
|
|
1546
|
-
if (element.target) {
|
|
1547
|
-
targetWindow = this._getFrameFromGlobal(element.target);
|
|
1548
|
-
}
|
|
1549
|
-
return targetWindow;
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
BrowserBot.prototype._getFrameFromGlobal = function(target) {
|
|
1553
|
-
|
|
1554
|
-
if (target == "_top") {
|
|
1555
|
-
return this.topFrame;
|
|
1556
|
-
} else if (target == "_parent") {
|
|
1557
|
-
return this.getCurrentWindow().parent;
|
|
1558
|
-
} else if (target == "_blank") {
|
|
1559
|
-
// TODO should this set cleverer window defaults?
|
|
1560
|
-
return this.getCurrentWindow().open('', '_blank');
|
|
1561
|
-
}
|
|
1562
|
-
var frameElement = this.findElementBy("implicit", target, this.topFrame.document, this.topFrame);
|
|
1563
|
-
if (frameElement) {
|
|
1564
|
-
return frameElement.contentWindow;
|
|
1565
|
-
}
|
|
1566
|
-
var win = this.getWindowByName(target);
|
|
1567
|
-
if (win) return win;
|
|
1568
|
-
return this.getCurrentWindow().open('', target);
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
BrowserBot.prototype.bodyText = function() {
|
|
1573
|
-
if (!this.getDocument().body) {
|
|
1574
|
-
throw new SeleniumError("Couldn't access document.body. Is this HTML page fully loaded?");
|
|
1575
|
-
}
|
|
1576
|
-
return getText(this.getDocument().body);
|
|
1577
|
-
};
|
|
1578
|
-
|
|
1579
|
-
BrowserBot.prototype.getAllButtons = function() {
|
|
1580
|
-
var elements = this.getDocument().getElementsByTagName('input');
|
|
1581
|
-
var result = [];
|
|
1582
|
-
|
|
1583
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1584
|
-
if (elements[i].type == 'button' || elements[i].type == 'submit' || elements[i].type == 'reset') {
|
|
1585
|
-
result.push(elements[i].id);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
return result;
|
|
1590
|
-
};
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
BrowserBot.prototype.getAllFields = function() {
|
|
1594
|
-
var elements = this.getDocument().getElementsByTagName('input');
|
|
1595
|
-
var result = [];
|
|
1596
|
-
|
|
1597
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1598
|
-
if (elements[i].type == 'text') {
|
|
1599
|
-
result.push(elements[i].id);
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
return result;
|
|
1604
|
-
};
|
|
1605
|
-
|
|
1606
|
-
BrowserBot.prototype.getAllLinks = function() {
|
|
1607
|
-
var elements = this.getDocument().getElementsByTagName('a');
|
|
1608
|
-
var result = [];
|
|
1609
|
-
|
|
1610
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1611
|
-
result.push(elements[i].id);
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
return result;
|
|
1615
|
-
};
|
|
1616
|
-
|
|
1617
|
-
function isDefined(value) {
|
|
1618
|
-
return typeof(value) != undefined;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
BrowserBot.prototype.goBack = function() {
|
|
1622
|
-
this.getCurrentWindow().history.back();
|
|
1623
|
-
};
|
|
1624
|
-
|
|
1625
|
-
BrowserBot.prototype.goForward = function() {
|
|
1626
|
-
this.getCurrentWindow().history.forward();
|
|
1627
|
-
};
|
|
1628
|
-
|
|
1629
|
-
BrowserBot.prototype.close = function() {
|
|
1630
|
-
if (browserVersion.isChrome || browserVersion.isSafari || browserVersion.isOpera) {
|
|
1631
|
-
this.getCurrentWindow().close();
|
|
1632
|
-
} else {
|
|
1633
|
-
this.getCurrentWindow().eval("window.close();");
|
|
1634
|
-
}
|
|
1635
|
-
};
|
|
1636
|
-
|
|
1637
|
-
BrowserBot.prototype.refresh = function() {
|
|
1638
|
-
this.getCurrentWindow().location.reload(true);
|
|
1639
|
-
};
|
|
1640
|
-
|
|
1641
|
-
/**
|
|
1642
|
-
* Refine a list of elements using a filter.
|
|
1643
|
-
*/
|
|
1644
|
-
BrowserBot.prototype.selectElementsBy = function(filterType, filter, elements) {
|
|
1645
|
-
var filterFunction = BrowserBot.filterFunctions[filterType];
|
|
1646
|
-
if (! filterFunction) {
|
|
1647
|
-
throw new SeleniumError("Unrecognised element-filter type: '" + filterType + "'");
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
return filterFunction(filter, elements);
|
|
1651
|
-
};
|
|
1652
|
-
|
|
1653
|
-
BrowserBot.filterFunctions = {};
|
|
1654
|
-
|
|
1655
|
-
BrowserBot.filterFunctions.name = function(name, elements) {
|
|
1656
|
-
var selectedElements = [];
|
|
1657
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1658
|
-
if (elements[i].name === name) {
|
|
1659
|
-
selectedElements.push(elements[i]);
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
return selectedElements;
|
|
1663
|
-
};
|
|
1664
|
-
|
|
1665
|
-
BrowserBot.filterFunctions.value = function(value, elements) {
|
|
1666
|
-
var selectedElements = [];
|
|
1667
|
-
for (var i = 0; i < elements.length; i++) {
|
|
1668
|
-
if (elements[i].value === value) {
|
|
1669
|
-
selectedElements.push(elements[i]);
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
return selectedElements;
|
|
1673
|
-
};
|
|
1674
|
-
|
|
1675
|
-
BrowserBot.filterFunctions.index = function(index, elements) {
|
|
1676
|
-
index = Number(index);
|
|
1677
|
-
if (isNaN(index) || index < 0) {
|
|
1678
|
-
throw new SeleniumError("Illegal Index: " + index);
|
|
1679
|
-
}
|
|
1680
|
-
if (elements.length <= index) {
|
|
1681
|
-
throw new SeleniumError("Index out of range: " + index);
|
|
1682
|
-
}
|
|
1683
|
-
return [elements[index]];
|
|
1684
|
-
};
|
|
1685
|
-
|
|
1686
|
-
BrowserBot.prototype.selectElements = function(filterExpr, elements, defaultFilterType) {
|
|
1687
|
-
|
|
1688
|
-
var filterType = (defaultFilterType || 'value');
|
|
1689
|
-
|
|
1690
|
-
// If there is a filter prefix, use the specified strategy
|
|
1691
|
-
var result = filterExpr.match(/^([A-Za-z]+)=(.+)/);
|
|
1692
|
-
if (result) {
|
|
1693
|
-
filterType = result[1].toLowerCase();
|
|
1694
|
-
filterExpr = result[2];
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
return this.selectElementsBy(filterType, filterExpr, elements);
|
|
1698
|
-
};
|
|
1699
|
-
|
|
1700
|
-
/**
|
|
1701
|
-
* Find an element by class
|
|
1702
|
-
*/
|
|
1703
|
-
BrowserBot.prototype.locateElementByClass = function(locator, document) {
|
|
1704
|
-
return elementFindFirstMatchingChild(document,
|
|
1705
|
-
function(element) {
|
|
1706
|
-
return element.className == locator
|
|
1707
|
-
}
|
|
1708
|
-
);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
/**
|
|
1712
|
-
* Find an element by alt
|
|
1713
|
-
*/
|
|
1714
|
-
BrowserBot.prototype.locateElementByAlt = function(locator, document) {
|
|
1715
|
-
return elementFindFirstMatchingChild(document,
|
|
1716
|
-
function(element) {
|
|
1717
|
-
return element.alt == locator
|
|
1718
|
-
}
|
|
1719
|
-
);
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
/**
|
|
1723
|
-
* Find an element by css selector
|
|
1724
|
-
*/
|
|
1725
|
-
BrowserBot.prototype.locateElementByCss = function(locator, document) {
|
|
1726
|
-
var elements = cssQuery(locator, document);
|
|
1727
|
-
if (elements.length != 0)
|
|
1728
|
-
return elements[0];
|
|
1729
|
-
return null;
|
|
1730
|
-
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
/*****************************************************************/
|
|
1734
|
-
/* BROWSER-SPECIFIC FUNCTIONS ONLY AFTER THIS LINE */
|
|
1735
|
-
|
|
1736
|
-
function MozillaBrowserBot(frame) {
|
|
1737
|
-
BrowserBot.call(this, frame);
|
|
1738
|
-
}
|
|
1739
|
-
objectExtend(MozillaBrowserBot.prototype, BrowserBot.prototype);
|
|
1740
|
-
|
|
1741
|
-
function KonquerorBrowserBot(frame) {
|
|
1742
|
-
BrowserBot.call(this, frame);
|
|
1743
|
-
}
|
|
1744
|
-
objectExtend(KonquerorBrowserBot.prototype, BrowserBot.prototype);
|
|
1745
|
-
|
|
1746
|
-
KonquerorBrowserBot.prototype.setIFrameLocation = function(iframe, location) {
|
|
1747
|
-
// Window doesn't fire onload event when setting src to the current value,
|
|
1748
|
-
// so we set it to blank first.
|
|
1749
|
-
iframe.src = "about:blank";
|
|
1750
|
-
iframe.src = location;
|
|
1751
|
-
};
|
|
1752
|
-
|
|
1753
|
-
KonquerorBrowserBot.prototype.setOpenLocation = function(win, loc) {
|
|
1754
|
-
// Window doesn't fire onload event when setting src to the current value,
|
|
1755
|
-
// so we just refresh in that case instead.
|
|
1756
|
-
loc = absolutify(loc, this.baseUrl);
|
|
1757
|
-
loc = canonicalize(loc);
|
|
1758
|
-
var startUrl = win.location.href;
|
|
1759
|
-
if ("about:blank" != win.location.href) {
|
|
1760
|
-
var startLoc = parseUrl(win.location.href);
|
|
1761
|
-
startLoc.hash = null;
|
|
1762
|
-
var startUrl = reassembleLocation(startLoc);
|
|
1763
|
-
}
|
|
1764
|
-
LOG.debug("startUrl="+startUrl);
|
|
1765
|
-
LOG.debug("win.location.href="+win.location.href);
|
|
1766
|
-
LOG.debug("loc="+loc);
|
|
1767
|
-
if (startUrl == loc) {
|
|
1768
|
-
LOG.debug("opening exact same location");
|
|
1769
|
-
this.refresh();
|
|
1770
|
-
} else {
|
|
1771
|
-
LOG.debug("locations differ");
|
|
1772
|
-
win.location.href = loc;
|
|
1773
|
-
}
|
|
1774
|
-
// force the current polling thread to detect a page load
|
|
1775
|
-
var marker = this.isPollingForLoad(win);
|
|
1776
|
-
if (marker) {
|
|
1777
|
-
delete win.location[marker];
|
|
1778
|
-
}
|
|
1779
|
-
};
|
|
1780
|
-
|
|
1781
|
-
KonquerorBrowserBot.prototype._isSameDocument = function(originalDocument, currentDocument) {
|
|
1782
|
-
// under Konqueror, there may be this case:
|
|
1783
|
-
// originalDocument and currentDocument are different objects
|
|
1784
|
-
// while their location are same.
|
|
1785
|
-
if (originalDocument) {
|
|
1786
|
-
return originalDocument.location == currentDocument.location
|
|
1787
|
-
} else {
|
|
1788
|
-
return originalDocument === currentDocument;
|
|
1789
|
-
}
|
|
1790
|
-
};
|
|
1791
|
-
|
|
1792
|
-
function SafariBrowserBot(frame) {
|
|
1793
|
-
BrowserBot.call(this, frame);
|
|
1794
|
-
}
|
|
1795
|
-
objectExtend(SafariBrowserBot.prototype, BrowserBot.prototype);
|
|
1796
|
-
|
|
1797
|
-
SafariBrowserBot.prototype.setIFrameLocation = KonquerorBrowserBot.prototype.setIFrameLocation;
|
|
1798
|
-
SafariBrowserBot.prototype.setOpenLocation = KonquerorBrowserBot.prototype.setOpenLocation;
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
function OperaBrowserBot(frame) {
|
|
1802
|
-
BrowserBot.call(this, frame);
|
|
1803
|
-
}
|
|
1804
|
-
objectExtend(OperaBrowserBot.prototype, BrowserBot.prototype);
|
|
1805
|
-
OperaBrowserBot.prototype.setIFrameLocation = function(iframe, location) {
|
|
1806
|
-
if (iframe.src == location) {
|
|
1807
|
-
iframe.src = location + '?reload';
|
|
1808
|
-
} else {
|
|
1809
|
-
iframe.src = location;
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
|
-
function IEBrowserBot(frame) {
|
|
1814
|
-
BrowserBot.call(this, frame);
|
|
1815
|
-
}
|
|
1816
|
-
objectExtend(IEBrowserBot.prototype, BrowserBot.prototype);
|
|
1817
|
-
|
|
1818
|
-
IEBrowserBot.prototype._handleClosedSubFrame = function(testWindow, doNotModify) {
|
|
1819
|
-
if (this.proxyInjectionMode) {
|
|
1820
|
-
return testWindow;
|
|
1821
|
-
}
|
|
1822
|
-
|
|
1823
|
-
try {
|
|
1824
|
-
testWindow.location.href;
|
|
1825
|
-
this.permDenied = 0;
|
|
1826
|
-
} catch (e) {
|
|
1827
|
-
this.permDenied++;
|
|
1828
|
-
}
|
|
1829
|
-
if (this._windowClosed(testWindow) || this.permDenied > 4) {
|
|
1830
|
-
if (this.isSubFrameSelected) {
|
|
1831
|
-
LOG.warn("Current subframe appears to have closed; selecting top frame");
|
|
1832
|
-
this.selectFrame("relative=top");
|
|
1833
|
-
return this.getCurrentWindow(doNotModify);
|
|
1834
|
-
} else {
|
|
1835
|
-
var closedError = new SeleniumError("Current window or frame is closed!");
|
|
1836
|
-
closedError.windowClosed = true;
|
|
1837
|
-
throw closedError;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
return testWindow;
|
|
1841
|
-
};
|
|
1842
|
-
|
|
1843
|
-
IEBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
|
|
1844
|
-
BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
|
|
1845
|
-
|
|
1846
|
-
// we will call the previous version of this method from within our own interception
|
|
1847
|
-
oldShowModalDialog = windowToModify.showModalDialog;
|
|
1848
|
-
|
|
1849
|
-
windowToModify.showModalDialog = function(url, args, features) {
|
|
1850
|
-
// Get relative directory to where TestRunner.html lives
|
|
1851
|
-
// A risky assumption is that the user's TestRunner is named TestRunner.html
|
|
1852
|
-
var doc_location = document.location.toString();
|
|
1853
|
-
var end_of_base_ref = doc_location.indexOf('TestRunner.html');
|
|
1854
|
-
var base_ref = doc_location.substring(0, end_of_base_ref);
|
|
1855
|
-
var runInterval = '';
|
|
1856
|
-
|
|
1857
|
-
// Only set run interval if options is defined
|
|
1858
|
-
if (typeof(window.runOptions) != undefined) {
|
|
1859
|
-
runInterval = "&runInterval=" + runOptions.runInterval;
|
|
1860
|
-
}
|
|
1861
|
-
|
|
1862
|
-
var testRunnerURL = "TestRunner.html?auto=true&singletest="
|
|
1863
|
-
+ escape(browserBot.modalDialogTest)
|
|
1864
|
-
+ "&autoURL="
|
|
1865
|
-
+ escape(url)
|
|
1866
|
-
+ runInterval;
|
|
1867
|
-
var fullURL = base_ref + testRunnerURL;
|
|
1868
|
-
browserBot.modalDialogTest = null;
|
|
1869
|
-
|
|
1870
|
-
// If using proxy injection mode
|
|
1871
|
-
if (this.proxyInjectionMode) {
|
|
1872
|
-
var sessionId = runOptions.getSessionId();
|
|
1873
|
-
if (sessionId == undefined) {
|
|
1874
|
-
sessionId = injectedSessionId;
|
|
1875
|
-
}
|
|
1876
|
-
if (sessionId != undefined) {
|
|
1877
|
-
LOG.debug("Invoking showModalDialog and injecting URL " + fullURL);
|
|
1878
|
-
}
|
|
1879
|
-
fullURL = url;
|
|
1880
|
-
}
|
|
1881
|
-
var returnValue = oldShowModalDialog(fullURL, args, features);
|
|
1882
|
-
return returnValue;
|
|
1883
|
-
};
|
|
1884
|
-
};
|
|
1885
|
-
|
|
1886
|
-
IEBrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads = function(windowObject) {
|
|
1887
|
-
this.pageUnloading = false;
|
|
1888
|
-
var self = this;
|
|
1889
|
-
var pageUnloadDetector = function() {
|
|
1890
|
-
self.pageUnloading = true;
|
|
1891
|
-
};
|
|
1892
|
-
windowObject.attachEvent("onbeforeunload", pageUnloadDetector);
|
|
1893
|
-
BrowserBot.prototype.modifySeparateTestWindowToDetectPageLoads.call(this, windowObject);
|
|
1894
|
-
};
|
|
1895
|
-
|
|
1896
|
-
IEBrowserBot.prototype.pollForLoad = function(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker) {
|
|
1897
|
-
LOG.debug("IEBrowserBot.pollForLoad: " + marker);
|
|
1898
|
-
if (!this.permDeniedCount[marker]) this.permDeniedCount[marker] = 0;
|
|
1899
|
-
BrowserBot.prototype.pollForLoad.call(this, loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
1900
|
-
if (this.pageLoadError) {
|
|
1901
|
-
if (this.pageUnloading) {
|
|
1902
|
-
var self = this;
|
|
1903
|
-
LOG.debug("pollForLoad UNLOADING (" + marker + "): caught exception while firing events on unloading page: " + this.pageLoadError.message);
|
|
1904
|
-
this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
1905
|
-
this.pageLoadError = null;
|
|
1906
|
-
return;
|
|
1907
|
-
} else if (((this.pageLoadError.message == "Permission denied") || (/^Access is denied/.test(this.pageLoadError.message)))
|
|
1908
|
-
&& this.permDeniedCount[marker]++ < 8) {
|
|
1909
|
-
if (this.permDeniedCount[marker] > 4) {
|
|
1910
|
-
var canAccessThisWindow;
|
|
1911
|
-
var canAccessCurrentlySelectedWindow;
|
|
1912
|
-
try {
|
|
1913
|
-
windowObject.location.href;
|
|
1914
|
-
canAccessThisWindow = true;
|
|
1915
|
-
} catch (e) {}
|
|
1916
|
-
try {
|
|
1917
|
-
this.getCurrentWindow(true).location.href;
|
|
1918
|
-
canAccessCurrentlySelectedWindow = true;
|
|
1919
|
-
} catch (e) {}
|
|
1920
|
-
if (canAccessCurrentlySelectedWindow & !canAccessThisWindow) {
|
|
1921
|
-
LOG.debug("pollForLoad (" + marker + ") ABORTING: " + this.pageLoadError.message + " (" + this.permDeniedCount[marker] + "), but the currently selected window is fine");
|
|
1922
|
-
// returning without rescheduling
|
|
1923
|
-
this.pageLoadError = null;
|
|
1924
|
-
return;
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
var self = this;
|
|
1929
|
-
LOG.debug("pollForLoad (" + marker + "): " + this.pageLoadError.message + " (" + this.permDeniedCount[marker] + "), waiting to see if it goes away");
|
|
1930
|
-
this.reschedulePoller(loadFunction, windowObject, originalDocument, originalLocation, originalHref, marker);
|
|
1931
|
-
this.pageLoadError = null;
|
|
1932
|
-
return;
|
|
1933
|
-
}
|
|
1934
|
-
//handy for debugging!
|
|
1935
|
-
//throw this.pageLoadError;
|
|
1936
|
-
}
|
|
1937
|
-
};
|
|
1938
|
-
|
|
1939
|
-
IEBrowserBot.prototype._windowClosed = function(win) {
|
|
1940
|
-
try {
|
|
1941
|
-
var c = win.closed;
|
|
1942
|
-
// frame windows claim to be non-closed when their parents are closed
|
|
1943
|
-
// but you can't access their document objects in that case
|
|
1944
|
-
if (!c) {
|
|
1945
|
-
try {
|
|
1946
|
-
win.document;
|
|
1947
|
-
} catch (de) {
|
|
1948
|
-
if (de.message == "Permission denied") {
|
|
1949
|
-
// the window is probably unloading, which means it's probably not closed yet
|
|
1950
|
-
return false;
|
|
1951
|
-
}
|
|
1952
|
-
else if (/^Access is denied/.test(de.message)) {
|
|
1953
|
-
// rare variation on "Permission denied"?
|
|
1954
|
-
LOG.debug("IEBrowserBot.windowClosed: got " + de.message + " (this.pageUnloading=" + this.pageUnloading + "); assuming window is unloading, probably not closed yet");
|
|
1955
|
-
return false;
|
|
1956
|
-
} else {
|
|
1957
|
-
// this is probably one of those frame window situations
|
|
1958
|
-
LOG.debug("IEBrowserBot.windowClosed: couldn't read win.document, assume closed: " + de.message + " (this.pageUnloading=" + this.pageUnloading + ")");
|
|
1959
|
-
return true;
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
if (c == null) {
|
|
1964
|
-
LOG.debug("IEBrowserBot.windowClosed: win.closed was null, assuming closed");
|
|
1965
|
-
return true;
|
|
1966
|
-
}
|
|
1967
|
-
return c;
|
|
1968
|
-
} catch (e) {
|
|
1969
|
-
LOG.debug("IEBrowserBot._windowClosed: Got an exception trying to read win.closed; we'll have to take a guess!");
|
|
1970
|
-
|
|
1971
|
-
if (browserVersion.isHTA) {
|
|
1972
|
-
if (e.message == "Permission denied") {
|
|
1973
|
-
// the window is probably unloading, which means it's not closed yet
|
|
1974
|
-
return false;
|
|
1975
|
-
} else {
|
|
1976
|
-
// there's a good chance that we've lost contact with the window object if it is closed
|
|
1977
|
-
return true;
|
|
1978
|
-
}
|
|
1979
|
-
} else {
|
|
1980
|
-
// the window is probably unloading, which means it's not closed yet
|
|
1981
|
-
return false;
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
};
|
|
1985
|
-
|
|
1986
|
-
/**
|
|
1987
|
-
* In IE, getElementById() also searches by name - this is an optimisation for IE.
|
|
1988
|
-
*/
|
|
1989
|
-
IEBrowserBot.prototype.locateElementByIdentifer = function(identifier, inDocument, inWindow) {
|
|
1990
|
-
return inDocument.getElementById(identifier);
|
|
1991
|
-
};
|
|
1992
|
-
|
|
1993
|
-
IEBrowserBot.prototype._findElementByTagNameAndAttributeValue = function(
|
|
1994
|
-
inDocument, tagName, attributeName, attributeValue
|
|
1995
|
-
) {
|
|
1996
|
-
if (attributeName == "class") {
|
|
1997
|
-
attributeName = "className";
|
|
1998
|
-
}
|
|
1999
|
-
var elements = inDocument.getElementsByTagName(tagName);
|
|
2000
|
-
for (var i = 0; i < elements.length; i++) {
|
|
2001
|
-
var elementAttr = elements[i].getAttribute(attributeName);
|
|
2002
|
-
if (elementAttr == attributeValue) {
|
|
2003
|
-
return elements[i];
|
|
2004
|
-
}
|
|
2005
|
-
// DGF SEL-347, IE6 URL-escapes javascript href attribute
|
|
2006
|
-
if (!elementAttr) continue;
|
|
2007
|
-
elementAttr = unescape(new String(elementAttr));
|
|
2008
|
-
if (elementAttr == attributeValue) {
|
|
2009
|
-
return elements[i];
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
return null;
|
|
2013
|
-
};
|
|
2014
|
-
|
|
2015
|
-
SafariBrowserBot.prototype.modifyWindowToRecordPopUpDialogs = function(windowToModify, browserBot) {
|
|
2016
|
-
BrowserBot.prototype.modifyWindowToRecordPopUpDialogs(windowToModify, browserBot);
|
|
2017
|
-
|
|
2018
|
-
var originalOpen = windowToModify.open;
|
|
2019
|
-
/*
|
|
2020
|
-
* Safari seems to be broken, so that when we manually trigger the onclick method
|
|
2021
|
-
* of a button/href, any window.open calls aren't resolved relative to the app location.
|
|
2022
|
-
* So here we replace the open() method with one that does resolve the url correctly.
|
|
2023
|
-
*/
|
|
2024
|
-
windowToModify.open = function(url, windowName, windowFeatures, replaceFlag) {
|
|
2025
|
-
|
|
2026
|
-
if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("/")) {
|
|
2027
|
-
return originalOpen(url, windowName, windowFeatures, replaceFlag);
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
|
-
// Reduce the current path to the directory
|
|
2031
|
-
var currentPath = windowToModify.location.pathname || "/";
|
|
2032
|
-
currentPath = currentPath.replace(/\/[^\/]*$/, "/");
|
|
2033
|
-
|
|
2034
|
-
// Remove any leading "./" from the new url.
|
|
2035
|
-
url = url.replace(/^\.\//, "");
|
|
2036
|
-
|
|
2037
|
-
newUrl = currentPath + url;
|
|
2038
|
-
|
|
2039
|
-
var openedWindow = originalOpen(newUrl, windowName, windowFeatures, replaceFlag);
|
|
2040
|
-
LOG.debug("window.open call intercepted; window ID (which you can use with selectWindow()) is \"" + windowName + "\"");
|
|
2041
|
-
if (windowName!=null) {
|
|
2042
|
-
openedWindow["seleniumWindowName"] = windowName;
|
|
2043
|
-
}
|
|
2044
|
-
return openedWindow;
|
|
2045
|
-
};
|
|
2046
|
-
};
|
|
2047
|
-
|
|
2048
|
-
MozillaBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {
|
|
2049
|
-
var win = this.getCurrentWindow();
|
|
2050
|
-
triggerEvent(element, 'focus', false);
|
|
2051
|
-
|
|
2052
|
-
// Add an event listener that detects if the default action has been prevented.
|
|
2053
|
-
// (This is caused by a javascript onclick handler returning false)
|
|
2054
|
-
// we capture the whole event, rather than the getPreventDefault() state at the time,
|
|
2055
|
-
// because we need to let the entire event bubbling and capturing to go through
|
|
2056
|
-
// before making a decision on whether we should force the href
|
|
2057
|
-
var savedEvent = null;
|
|
2058
|
-
|
|
2059
|
-
element.addEventListener(eventType, function(evt) {
|
|
2060
|
-
savedEvent = evt;
|
|
2061
|
-
}, false);
|
|
2062
|
-
|
|
2063
|
-
this._modifyElementTarget(element);
|
|
2064
|
-
|
|
2065
|
-
// Trigger the event.
|
|
2066
|
-
this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);
|
|
2067
|
-
|
|
2068
|
-
if (this._windowClosed(win)) {
|
|
2069
|
-
return;
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
// Perform the link action if preventDefault was set.
|
|
2073
|
-
// In chrome URL, the link action is already executed by triggerMouseEvent.
|
|
2074
|
-
if (!browserVersion.isChrome && savedEvent != null && !savedEvent.getPreventDefault()) {
|
|
2075
|
-
var targetWindow = this.browserbot._getTargetWindow(element);
|
|
2076
|
-
if (element.href) {
|
|
2077
|
-
targetWindow.location.href = element.href;
|
|
2078
|
-
} else {
|
|
2079
|
-
this.browserbot._handleClickingImagesInsideLinks(targetWindow, element);
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
|
|
2083
|
-
};
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
OperaBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {
|
|
2087
|
-
var win = this.getCurrentWindow();
|
|
2088
|
-
triggerEvent(element, 'focus', false);
|
|
2089
|
-
|
|
2090
|
-
this._modifyElementTarget(element);
|
|
2091
|
-
|
|
2092
|
-
// Trigger the click event.
|
|
2093
|
-
this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);
|
|
2094
|
-
|
|
2095
|
-
if (this._windowClosed(win)) {
|
|
2096
|
-
return;
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
};
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
KonquerorBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {
|
|
2103
|
-
var win = this.getCurrentWindow();
|
|
2104
|
-
triggerEvent(element, 'focus', false);
|
|
2105
|
-
|
|
2106
|
-
this._modifyElementTarget(element);
|
|
2107
|
-
|
|
2108
|
-
if (element[eventType]) {
|
|
2109
|
-
element[eventType]();
|
|
2110
|
-
}
|
|
2111
|
-
else {
|
|
2112
|
-
this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);
|
|
2113
|
-
}
|
|
2114
|
-
|
|
2115
|
-
if (this._windowClosed(win)) {
|
|
2116
|
-
return;
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
};
|
|
2120
|
-
|
|
2121
|
-
SafariBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {
|
|
2122
|
-
triggerEvent(element, 'focus', false);
|
|
2123
|
-
var wasChecked = element.checked;
|
|
2124
|
-
|
|
2125
|
-
this._modifyElementTarget(element);
|
|
2126
|
-
|
|
2127
|
-
// For form element it is simple.
|
|
2128
|
-
if (element[eventType]) {
|
|
2129
|
-
element[eventType]();
|
|
2130
|
-
}
|
|
2131
|
-
// For links and other elements, event emulation is required.
|
|
2132
|
-
else {
|
|
2133
|
-
var targetWindow = this.browserbot._getTargetWindow(element);
|
|
2134
|
-
// todo: deal with anchors?
|
|
2135
|
-
this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);
|
|
2136
|
-
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2139
|
-
};
|
|
2140
|
-
|
|
2141
|
-
SafariBrowserBot.prototype.refresh = function() {
|
|
2142
|
-
var win = this.getCurrentWindow();
|
|
2143
|
-
if (win.location.hash) {
|
|
2144
|
-
// DGF Safari refuses to refresh when there's a hash symbol in the URL
|
|
2145
|
-
win.location.hash = "";
|
|
2146
|
-
var actuallyReload = function() {
|
|
2147
|
-
win.location.reload(true);
|
|
2148
|
-
}
|
|
2149
|
-
window.setTimeout(actuallyReload, 1);
|
|
2150
|
-
} else {
|
|
2151
|
-
win.location.reload(true);
|
|
2152
|
-
}
|
|
2153
|
-
};
|
|
2154
|
-
|
|
2155
|
-
IEBrowserBot.prototype._fireEventOnElement = function(eventType, element, clientX, clientY) {
|
|
2156
|
-
var win = this.getCurrentWindow();
|
|
2157
|
-
triggerEvent(element, 'focus', false);
|
|
2158
|
-
|
|
2159
|
-
var wasChecked = element.checked;
|
|
2160
|
-
|
|
2161
|
-
// Set a flag that records if the page will unload - this isn't always accurate, because
|
|
2162
|
-
// <a href="javascript:alert('foo'):"> triggers the onbeforeunload event, even thought the page won't unload
|
|
2163
|
-
var pageUnloading = false;
|
|
2164
|
-
var pageUnloadDetector = function() {
|
|
2165
|
-
pageUnloading = true;
|
|
2166
|
-
};
|
|
2167
|
-
win.attachEvent("onbeforeunload", pageUnloadDetector);
|
|
2168
|
-
this._modifyElementTarget(element);
|
|
2169
|
-
if (element[eventType]) {
|
|
2170
|
-
element[eventType]();
|
|
2171
|
-
}
|
|
2172
|
-
else {
|
|
2173
|
-
this.browserbot.triggerMouseEvent(element, eventType, true, clientX, clientY);
|
|
2174
|
-
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
// If the page is going to unload - still attempt to fire any subsequent events.
|
|
2178
|
-
// However, we can't guarantee that the page won't unload half way through, so we need to handle exceptions.
|
|
2179
|
-
try {
|
|
2180
|
-
win.detachEvent("onbeforeunload", pageUnloadDetector);
|
|
2181
|
-
|
|
2182
|
-
if (this._windowClosed(win)) {
|
|
2183
|
-
return;
|
|
2184
|
-
}
|
|
2185
|
-
|
|
2186
|
-
// Onchange event is not triggered automatically in IE.
|
|
2187
|
-
if (isDefined(element.checked) && wasChecked != element.checked) {
|
|
2188
|
-
triggerEvent(element, 'change', true);
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
}
|
|
2192
|
-
catch (e) {
|
|
2193
|
-
// If the page is unloading, we may get a "Permission denied" or "Unspecified error".
|
|
2194
|
-
// Just ignore it, because the document may have unloaded.
|
|
2195
|
-
if (pageUnloading) {
|
|
2196
|
-
LOG.logHook = function() {
|
|
2197
|
-
};
|
|
2198
|
-
LOG.warn("Caught exception when firing events on unloading page: " + e.message);
|
|
2199
|
-
return;
|
|
2200
|
-
}
|
|
2201
|
-
throw e;
|
|
2202
|
-
}
|
|
2203
|
-
};
|