cmsimple 0.2.0
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/.gitignore +31 -0
- data/.rspec +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +20 -0
- data/Gemfile.ci +5 -0
- data/LICENSE +19 -0
- data/README.md +118 -0
- data/Rakefile +47 -0
- data/app/assets/javascripts/cmsimple.js +61 -0
- data/app/assets/javascripts/cmsimple/controllers/editor.coffee +102 -0
- data/app/assets/javascripts/cmsimple/lib/namespaces.coffee +3 -0
- data/app/assets/javascripts/cmsimple/lib/support.coffee +4 -0
- data/app/assets/javascripts/cmsimple/mercury/config.js +462 -0
- data/app/assets/javascripts/cmsimple/mercury/handlers.coffee +9 -0
- data/app/assets/javascripts/cmsimple/models/image.coffee +49 -0
- data/app/assets/javascripts/cmsimple/models/page.coffee +106 -0
- data/app/assets/javascripts/cmsimple/models/path.coffee +31 -0
- data/app/assets/javascripts/cmsimple/models/version.coffee +29 -0
- data/app/assets/javascripts/cmsimple/panels/images/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/images/list.coffee +48 -0
- data/app/assets/javascripts/cmsimple/panels/images/panel.coffee +69 -0
- data/app/assets/javascripts/cmsimple/panels/images/selection.coffee +52 -0
- data/app/assets/javascripts/cmsimple/panels/page_metadata.coffee +42 -0
- data/app/assets/javascripts/cmsimple/panels/publish.coffee +32 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/form.coffee +51 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/list.coffee +34 -0
- data/app/assets/javascripts/cmsimple/panels/redirects/panel.coffee +39 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/panel.coffee +40 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/sortable.coffee +55 -0
- data/app/assets/javascripts/cmsimple/panels/sitemap/tree.coffee +61 -0
- data/app/assets/javascripts/cmsimple/panels/versions/index.coffee +2 -0
- data/app/assets/javascripts/cmsimple/panels/versions/list.coffee +51 -0
- data/app/assets/javascripts/cmsimple/panels/versions/panel.coffee +53 -0
- data/app/assets/javascripts/cmsimple/views/image_library/_item.jst.hamlc +24 -0
- data/app/assets/javascripts/cmsimple/views/image_library/list.jst.hamlc +8 -0
- data/app/assets/javascripts/cmsimple/views/redirects/_path.jst.hamlc +6 -0
- data/app/assets/javascripts/cmsimple/views/redirects/list.jst.hamlc +19 -0
- data/app/assets/javascripts/cmsimple/views/sitemap/_page.jst.hamlc +9 -0
- data/app/assets/javascripts/cmsimple/views/sitemap/tree.jst.hamlc +5 -0
- data/app/assets/javascripts/cmsimple/views/versions/_item.jst.hamlc +6 -0
- data/app/assets/javascripts/cmsimple/views/versions/list.jst.hamlc +4 -0
- data/app/assets/stylesheets/cmsimple.css +15 -0
- data/app/assets/stylesheets/cmsimple/forms.css +10 -0
- data/app/assets/stylesheets/cmsimple/panels.css +399 -0
- data/app/assets/stylesheets/cmsimple/toolbar-images.css +27 -0
- data/app/assets/stylesheets/mercury_overrides.css +2 -0
- data/app/controllers/cmsimple/front_controller.rb +38 -0
- data/app/controllers/cmsimple/images_controller.rb +28 -0
- data/app/controllers/cmsimple/mercury_controller.rb +7 -0
- data/app/controllers/cmsimple/pages_controller.rb +89 -0
- data/app/controllers/cmsimple/paths_controller.rb +23 -0
- data/app/controllers/cmsimple/snippets_controller.rb +23 -0
- data/app/controllers/cmsimple/versions_controller.rb +17 -0
- data/app/helpers/cmsimple/regions_helper.rb +38 -0
- data/app/models/cmsimple/image.rb +19 -0
- data/app/models/cmsimple/page.rb +203 -0
- data/app/models/cmsimple/path.rb +63 -0
- data/app/models/cmsimple/region.rb +43 -0
- data/app/models/cmsimple/snippet.rb +64 -0
- data/app/models/cmsimple/version.rb +18 -0
- data/app/uploaders/image_attachment_uploader.rb +53 -0
- data/app/views/cmsimple/images/_form.html.haml +13 -0
- data/app/views/cmsimple/images/new.html.haml +5 -0
- data/app/views/cmsimple/pages/_form.html.haml +49 -0
- data/app/views/cmsimple/pages/_form_extras.html.haml +2 -0
- data/app/views/cmsimple/pages/edit.html.haml +3 -0
- data/app/views/cmsimple/pages/new.html.haml +3 -0
- data/app/views/cmsimple/pages/publish.html.haml +12 -0
- data/app/views/cmsimple/snippets/index.html.haml +5 -0
- data/app/views/cmsimple/templates/default.html.haml +4 -0
- data/app/views/layouts/editor.html.haml +12 -0
- data/app/views/layouts/panel.html.haml +9 -0
- data/cmsimple.gemspec +44 -0
- data/config.ru +4 -0
- data/config/application.rb +1 -0
- data/config/cucumber.yml +8 -0
- data/config/environment.rb +2 -0
- data/config/routes.rb +34 -0
- data/db/migrate/20120201221410_create_cmsimple_pages.rb +10 -0
- data/db/migrate/20120222185901_add_title_parent_id_and_position_to_pages.rb +10 -0
- data/db/migrate/20120229185214_add_slug_to_pages.rb +7 -0
- data/db/migrate/20120323200439_add_is_root_to_page.rb +5 -0
- data/db/migrate/20120328174339_add_meta_info_to_cmsimple_pages.rb +9 -0
- data/db/migrate/20120329172857_create_cmsimple_path.rb +11 -0
- data/db/migrate/20120407024752_create_cmsimple_images.rb +13 -0
- data/db/migrate/20120410041105_add_timestamps_to_cmsimple_pages.rb +7 -0
- data/db/migrate/20120425211937_add_published_at_to_cmsimple_pages.rb +6 -0
- data/db/migrate/20120430175047_create_cmsimple_versions.rb +13 -0
- data/db/migrate/20120831233927_rename_path_to_current_uri_on_paths.rb +5 -0
- data/features/create.feature +18 -0
- data/features/delete.feature +12 -0
- data/features/edit.feature +54 -0
- data/features/publishing.feature +31 -0
- data/features/redirects.feature +27 -0
- data/features/step_definitions/mercury_steps.rb +440 -0
- data/features/step_definitions/page_steps.rb +269 -0
- data/features/step_definitions/web_steps.rb +254 -0
- data/features/support/env.rb +77 -0
- data/features/support/mercury_content.rb +25 -0
- data/features/support/mercury_selectors.rb +148 -0
- data/features/support/paths.rb +16 -0
- data/features/support/selectors.rb +26 -0
- data/features/support/utils.rb +18 -0
- data/features/versioning.feature +27 -0
- data/features/visit.feature +7 -0
- data/lib/cmsimple.rb +22 -0
- data/lib/cmsimple/configuration.rb +65 -0
- data/lib/cmsimple/exts/to_bool.rb +25 -0
- data/lib/cmsimple/page_responder.rb +46 -0
- data/lib/cmsimple/rails.rb +5 -0
- data/lib/cmsimple/regions_proxy.rb +32 -0
- data/lib/cmsimple/template_resolver.rb +14 -0
- data/lib/cmsimple/template_responder.rb +12 -0
- data/lib/cmsimple/version.rb +3 -0
- data/lib/generators/cmsimple/install/install_generator.rb +46 -0
- data/lib/generators/cmsimple/install/templates/default.html.erb +10 -0
- data/lib/generators/cmsimple/install/templates/default.html.haml +6 -0
- data/lib/generators/cmsimple/install/templates/initializer.rb +22 -0
- data/lib/generators/cmsimple/snippet/snippet_generator.rb +56 -0
- data/lib/generators/cmsimple/snippet/templates/cell.rb +18 -0
- data/lib/generators/cmsimple/snippet/templates/display.html.erb +14 -0
- data/lib/generators/cmsimple/snippet/templates/display.html.haml +11 -0
- data/lib/generators/cmsimple/snippet/templates/options.html.erb +18 -0
- data/lib/generators/cmsimple/snippet/templates/options.html.haml +12 -0
- data/script/app +2 -0
- data/script/migrate +2 -0
- data/script/rails +8 -0
- data/spec/fixtures/rails.png +0 -0
- data/spec/helpers/regions_helper_spec.rb +62 -0
- data/spec/javascripts/controllers/editor_spec.coffee +57 -0
- data/spec/javascripts/models/image_geometry_spec.coffee +64 -0
- data/spec/javascripts/models/image_spec.coffee +4 -0
- data/spec/javascripts/models/page_spec.coffee +121 -0
- data/spec/javascripts/models/path_spec.coffee +39 -0
- data/spec/javascripts/models/version_spec.coffee +31 -0
- data/spec/javascripts/panels/images/selection_spec.coffee +104 -0
- data/spec/javascripts/panels/sitemap/panel_spec.coffee +10 -0
- data/spec/javascripts/panels/sitemap/sortable_spec.coffee +63 -0
- data/spec/javascripts/panels/sitemap/tree_spec.coffee +62 -0
- data/spec/javascripts/spec_helper.coffee +25 -0
- data/spec/javascripts/support/stubs.coffee +16 -0
- data/spec/lib/page_responder_spec.rb +58 -0
- data/spec/lib/regions_proxy_spec.rb +47 -0
- data/spec/models/image_spec.rb +46 -0
- data/spec/models/page_spec.rb +237 -0
- data/spec/models/path_spec.rb +71 -0
- data/spec/models/region_spec.rb +14 -0
- data/spec/models/snippet_spec.rb +57 -0
- data/spec/models/version_spec.rb +7 -0
- data/spec/rails_app/.gitignore +33 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +9 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +7 -0
- data/spec/rails_app/app/cells/example/display.html.haml +2 -0
- data/spec/rails_app/app/cells/example/options.html.haml +15 -0
- data/spec/rails_app/app/cells/example_cell.rb +19 -0
- data/spec/rails_app/app/cells/image_example/display.html.haml +4 -0
- data/spec/rails_app/app/cells/image_example/options.html.haml +15 -0
- data/spec/rails_app/app/cells/image_example_cell.rb +18 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/views/cmsimple/_snippet_list.html.haml +8 -0
- data/spec/rails_app/app/views/cmsimple/templates/default.html.haml +19 -0
- data/spec/rails_app/app/views/cmsimple/templates/test.html.haml +2 -0
- data/spec/rails_app/app/views/layouts/application.html.haml +13 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +65 -0
- data/spec/rails_app/config/boot.rb +9 -0
- data/spec/rails_app/config/database.example.yml +22 -0
- data/spec/rails_app/config/database.travis.yml +8 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +30 -0
- data/spec/rails_app/config/environments/test.rb +39 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/cells.rb +1 -0
- data/spec/rails_app/config/initializers/cmsimple.rb +3 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/initializers/teabag.rb +58 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +61 -0
- data/spec/rails_app/db/seeds.rb +11 -0
- data/spec/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +26 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/active_model_lint_example.rb +14 -0
- data/spec/teabag_env.rb +28 -0
- data/vendor/assets/images/sitemap/has-changes.png +0 -0
- data/vendor/assets/images/sitemap/published.png +0 -0
- data/vendor/assets/images/sitemap/unpublished.png +0 -0
- data/vendor/assets/images/toolbar/metadata.png +0 -0
- data/vendor/assets/images/toolbar/publish.png +0 -0
- data/vendor/assets/images/toolbar/redirect.png +0 -0
- data/vendor/assets/images/toolbar/sitemap.png +0 -0
- data/vendor/assets/images/toolbar/snippets.png +0 -0
- data/vendor/assets/images/toolbar/unpublished.png +0 -0
- data/vendor/assets/images/tree-line-horizontal-last.png +0 -0
- data/vendor/assets/images/tree-line-horizontal.png +0 -0
- data/vendor/assets/images/tree-line-vertical.png +0 -0
- data/vendor/assets/javascripts/jquery-serializeObject.js +107 -0
- data/vendor/assets/javascripts/jquery.to-json.js +74 -0
- data/vendor/assets/javascripts/jquery.ui.nestedSortable-1.3.4.js +391 -0
- data/vendor/assets/javascripts/moment-1.6.2.js +918 -0
- data/vendor/assets/javascripts/underscore-1.3.1.js +31 -0
- data/vendor/assets/stylesheets/jasmine-modified.css +216 -0
- metadata +686 -0
data/config/routes.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Cmsimple::Engine.routes.draw do
|
|
2
|
+
|
|
3
|
+
match '/cmsimple/snippets/:name/preview' => 'snippets#preview'
|
|
4
|
+
match '/cmsimple/snippets/:name/options' => 'snippets#options'
|
|
5
|
+
match '/cmsimple/snippets' => 'snippets#index', :as => :snippets
|
|
6
|
+
|
|
7
|
+
resources :pages do
|
|
8
|
+
member do
|
|
9
|
+
get :publish
|
|
10
|
+
end
|
|
11
|
+
resources :versions, :only => [:index] do
|
|
12
|
+
member do
|
|
13
|
+
put :revert_to
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
resources :paths, :only => [:index, :create, :destroy]
|
|
19
|
+
|
|
20
|
+
scope '/cmsimple' do
|
|
21
|
+
resources :images
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
get '/mercury/:type/:resource' => "mercury#resource"
|
|
25
|
+
|
|
26
|
+
get '/editor(/*path)' => "pages#editor", :as => :mercury_editor
|
|
27
|
+
|
|
28
|
+
get '*path' => 'front#show'
|
|
29
|
+
root :to => 'front#show', :via => :get
|
|
30
|
+
|
|
31
|
+
put '*path' => 'pages#update_content'
|
|
32
|
+
root :to => 'pages#update_content', :via => :put
|
|
33
|
+
|
|
34
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class CreateCmsimpleImages < ActiveRecord::Migration
|
|
2
|
+
def change
|
|
3
|
+
create_table :cmsimple_images do |t|
|
|
4
|
+
t.string :attachment
|
|
5
|
+
t.string :width
|
|
6
|
+
t.string :height
|
|
7
|
+
t.string :file_size
|
|
8
|
+
t.string :content_type
|
|
9
|
+
t.string :title
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class CreateCmsimpleVersions < ActiveRecord::Migration
|
|
2
|
+
def up
|
|
3
|
+
create_table :cmsimple_versions do |t|
|
|
4
|
+
t.text :content
|
|
5
|
+
t.string :template
|
|
6
|
+
t.datetime :published_at
|
|
7
|
+
t.integer :page_id
|
|
8
|
+
t.timestamps
|
|
9
|
+
end
|
|
10
|
+
add_index :cmsimple_versions, :page_id
|
|
11
|
+
add_index :cmsimple_versions, :published_at
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@javascript
|
|
2
|
+
Feature: As a user I should be able to create pages on the site
|
|
3
|
+
|
|
4
|
+
Background:
|
|
5
|
+
Given a page exists at a custom path with custom content
|
|
6
|
+
And I visit that page's edit path
|
|
7
|
+
|
|
8
|
+
Scenario: As a user I add a page from the sitemap panel
|
|
9
|
+
When I open the sitemap
|
|
10
|
+
And I add a new page
|
|
11
|
+
Then I should be redirected to the new page
|
|
12
|
+
And I should see the page in the sitemap
|
|
13
|
+
|
|
14
|
+
Scenario: As a user I add a page from the sitemap panel
|
|
15
|
+
When I open the sitemap
|
|
16
|
+
And I add a new home page
|
|
17
|
+
Then I should be redirected to the home page
|
|
18
|
+
And I should see the page in the sitemap
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
@javascript
|
|
2
|
+
Feature: As a user I should be able to delete pages on the site
|
|
3
|
+
|
|
4
|
+
Scenario: As a user I should be able to delete a page
|
|
5
|
+
Given a page exists at a custom path with custom content
|
|
6
|
+
And I visit that page's edit path
|
|
7
|
+
And I edit the page's metadata
|
|
8
|
+
And the editor won't prompt when leaving the page
|
|
9
|
+
And I accept confirmations
|
|
10
|
+
When I follow "Delete"
|
|
11
|
+
Then I should be redirected to the home page
|
|
12
|
+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
@javascript
|
|
2
|
+
Feature: As a user I should be able to edit pages on the site
|
|
3
|
+
|
|
4
|
+
Scenario: As a user I should be able to view a page with custom content at a specified path
|
|
5
|
+
Given a page exists at a custom path with custom content
|
|
6
|
+
When I visit that page's edit path
|
|
7
|
+
Then I should be able to edit that page's content
|
|
8
|
+
|
|
9
|
+
Scenario: As a user I want to be able to insert a snippet into a pages content
|
|
10
|
+
Given a page exists at a custom path with custom content
|
|
11
|
+
And I visit that page's edit path
|
|
12
|
+
And the content of the editable region is simple content
|
|
13
|
+
And I make a selection
|
|
14
|
+
|
|
15
|
+
When I open the snippet panel
|
|
16
|
+
And I drag the example snippet into the editable region
|
|
17
|
+
Then the modal window should be visible
|
|
18
|
+
And I should see "Snippet Options" within the modal title
|
|
19
|
+
|
|
20
|
+
When I fill in "First name" with "Fred"
|
|
21
|
+
And fill in "Last name" with "Flinstone"
|
|
22
|
+
And press "Create Snippet"
|
|
23
|
+
Then the modal window should not be visible
|
|
24
|
+
And the contents of the editable region should be "this is <div data-version='1' data-snippet='snippet_0' class='example-snippet' contenteditable='false'><h1>Fred Flinstone</h1></div><span>simple</span> <b>content</b>"
|
|
25
|
+
|
|
26
|
+
When I save and reload the page
|
|
27
|
+
Then the contents of the editable region should be "this is <div data-version='1' data-snippet='snippet_0' class='example-snippet' contenteditable='false'><h1>Fred Flinstone</h1></div><span>simple</span> <b>content</b>"
|
|
28
|
+
|
|
29
|
+
When I edit the snippet
|
|
30
|
+
Then the "First name" field should contain "Fred"
|
|
31
|
+
And the "Last name" field should contain "Flinstone"
|
|
32
|
+
And the editor won't prompt when leaving the page
|
|
33
|
+
|
|
34
|
+
Scenario: As a user I want to be able to edit the meta data of a page
|
|
35
|
+
Given a page exists at a custom path with custom content
|
|
36
|
+
And I visit that page's edit path
|
|
37
|
+
When I edit the page's metadata
|
|
38
|
+
And I change the slug to "new_path"
|
|
39
|
+
Then I should be on "/editor/new_path"
|
|
40
|
+
|
|
41
|
+
Scenario: As a user I want to be able to change the template of a page
|
|
42
|
+
Given a page exists at a custom path with custom content
|
|
43
|
+
And I visit that page's edit path
|
|
44
|
+
When I edit the page's metadata
|
|
45
|
+
And I change the template to "test"
|
|
46
|
+
Then I should see "Test template with content" in the content frame
|
|
47
|
+
|
|
48
|
+
Scenario: As a user I want to be able to change the SEO info of a page
|
|
49
|
+
Given a page exists at a custom path with custom content
|
|
50
|
+
And I visit that page's edit path
|
|
51
|
+
When I edit the page's metadata
|
|
52
|
+
And I change the seo info of the page
|
|
53
|
+
Then I should see that seo info on the page
|
|
54
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@javascript
|
|
2
|
+
Feature: As a user I should be able to create pages on the site
|
|
3
|
+
|
|
4
|
+
Background:
|
|
5
|
+
Given a page exists at a custom path with custom content
|
|
6
|
+
And I visit that page's edit path
|
|
7
|
+
|
|
8
|
+
Scenario: As a user I have to publish pages for them to be public
|
|
9
|
+
Given I open the sitemap
|
|
10
|
+
And I add a new page
|
|
11
|
+
When I publish the current page
|
|
12
|
+
Then the current page should be publicly available
|
|
13
|
+
|
|
14
|
+
Scenario: As a user changes to a page don't appear to the public until they are published
|
|
15
|
+
Given I open the sitemap
|
|
16
|
+
And I add a new page
|
|
17
|
+
And I publish the current page
|
|
18
|
+
When I make changes to the current page
|
|
19
|
+
Then the current page should only show published content
|
|
20
|
+
|
|
21
|
+
Scenario: A user should see an indication of having unpublished changes
|
|
22
|
+
Given I open the sitemap
|
|
23
|
+
When I add a new page
|
|
24
|
+
Then there should be an indication of unpublished changes
|
|
25
|
+
|
|
26
|
+
When I publish the current page
|
|
27
|
+
Then there should not be an indication of unpublished changes
|
|
28
|
+
|
|
29
|
+
When I make changes to the current page
|
|
30
|
+
Then there should be an indication of unpublished changes
|
|
31
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
@javascript
|
|
2
|
+
Feature: As a user I should be able to add redirects on the site
|
|
3
|
+
|
|
4
|
+
Background:
|
|
5
|
+
Given a page exists at a custom path with custom content
|
|
6
|
+
And I visit that page's edit path
|
|
7
|
+
|
|
8
|
+
Scenario: As a user I add a redirect from the redirects panel
|
|
9
|
+
When I open the redirects
|
|
10
|
+
And I add a new redirect
|
|
11
|
+
Then I should see the path in the redirects
|
|
12
|
+
|
|
13
|
+
When I visit the new redirect
|
|
14
|
+
Then I should be redirected to the about page
|
|
15
|
+
|
|
16
|
+
Scenario: As a user I should not be able to add a duplicate redirect from the redirects panel
|
|
17
|
+
When I open the redirects
|
|
18
|
+
And I add a new duplicate redirect
|
|
19
|
+
Then I should not see the duplicate path in the redirects
|
|
20
|
+
And I should be alerted to the duplicate redirect
|
|
21
|
+
|
|
22
|
+
Scenario: As a user I delete a redirect from the redirects panel
|
|
23
|
+
Given I open the redirects
|
|
24
|
+
And I add a new redirect
|
|
25
|
+
When I delete the redirect
|
|
26
|
+
Then I should not see the path in the redirects
|
|
27
|
+
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
|
|
2
|
+
# Taken from /jejacks0n/mercury/master/features/step_definitions/mercury_steps.rb
|
|
3
|
+
## Generic web steps
|
|
4
|
+
#------------------------------------------------------------------------------
|
|
5
|
+
When /^(?:|I )click on (.+)$/ do |locator|
|
|
6
|
+
selector = selector_for(locator)
|
|
7
|
+
find(selector, :message => "Unable to locate the element '#{selector}' to click on").click
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Then /^(.+) should (not )?be visible$/ do |locator, boolean|
|
|
11
|
+
selector = selector_for(locator)
|
|
12
|
+
if boolean == 'not '
|
|
13
|
+
page.has_no_css?("#{selector}")
|
|
14
|
+
else
|
|
15
|
+
page.has_css?("#{selector}", :visible => true)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# scoping step for different windows
|
|
20
|
+
When /^(.*) in the "([^"]*)" window$/ do |s, window|
|
|
21
|
+
page.driver.within_window(window) do
|
|
22
|
+
step(s)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Mercury general steps
|
|
28
|
+
#------------------------------------------------------------------------------
|
|
29
|
+
Given /^(?:|I )adjust the configuration to have: \{([^\}]*)\}$/ do |javascript|
|
|
30
|
+
Rails.application.config.mercury_config = JSON.parse("{#{javascript}}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# scoping step for the mercury content frame
|
|
34
|
+
When /^(.*) in the content frame$/ do |s|
|
|
35
|
+
page.driver.within_frame('mercury_iframe') do
|
|
36
|
+
step(s)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# silence mercury's onbeforeunload confirmation
|
|
41
|
+
Given /^the editor won't prompt when leaving the page$/ do
|
|
42
|
+
page.driver.execute_script('Mercury.silent = true;')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Toolbar specific steps
|
|
47
|
+
#------------------------------------------------------------------------------
|
|
48
|
+
# for the select dropdowns
|
|
49
|
+
When /^(?:|I )select (.*?) from the dropdown$/ do |locator|
|
|
50
|
+
selector = selector_for(locator)
|
|
51
|
+
find(selector, :message => "Unable to locate the element '#{selector}' to click on").click
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Panel specific steps
|
|
56
|
+
#------------------------------------------------------------------------------
|
|
57
|
+
When /^(?:I )(?:open|close|toggle) the (.*?) panel$/ do |panel_locator|
|
|
58
|
+
step(%Q{I click on the "#{panel_locator}" button})
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Modal specific steps
|
|
63
|
+
#------------------------------------------------------------------------------
|
|
64
|
+
When /^(?:I )close the modal(?: window)?$/ do
|
|
65
|
+
step(%Q{I click on the modal close button})
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Region specific steps
|
|
70
|
+
#------------------------------------------------------------------------------
|
|
71
|
+
# setting content
|
|
72
|
+
Given /^the content of (.*?) (?:is|are|has|includes) (.*?)$/ do |region_locator, contents|
|
|
73
|
+
step(%Q{I set the contents of #{region_locator} to #{contents}})
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
When /^(?:|I )(?:change|set) the contents? of (.*?) to (.*?)$/ do |region_locator, contents|
|
|
77
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
|
78
|
+
content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
|
|
79
|
+
page.driver.within_frame('mercury_iframe') do
|
|
80
|
+
find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
|
|
81
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
82
|
+
var element = top.jQuery(document).find('##{region_id}');
|
|
83
|
+
if (element.data('mercury') == 'markdown') {
|
|
84
|
+
element.find('textarea').val(#{content});
|
|
85
|
+
} else {
|
|
86
|
+
var region = top.mercuryInstance.getRegionByName('#{region_id}');
|
|
87
|
+
region.content(#{content});
|
|
88
|
+
}
|
|
89
|
+
JAVASCRIPT
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# setting/making selections
|
|
94
|
+
When /^(?:|I )(?:make|have) a selection$/ do
|
|
95
|
+
step(%Q{I have a selection for "span"})
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
When /^(?:|I )(?:make|have) a selection (?:in (.*?) )?for "([^"]*)"$/ do |region_locator, selector|
|
|
99
|
+
step(%Q{I can simulate complex javascript events})
|
|
100
|
+
# assume the first editable region if one wasn't provided'
|
|
101
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
|
102
|
+
page.driver.within_frame('mercury_iframe') do
|
|
103
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
|
104
|
+
find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'")
|
|
105
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
106
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
|
107
|
+
if (element.data('mercury') == 'markdown') {
|
|
108
|
+
alert('unimplemented');
|
|
109
|
+
throw('unimplemented');
|
|
110
|
+
} else {
|
|
111
|
+
var selectedElement = element.find('#{selector}');
|
|
112
|
+
var selection = new top.Mercury.Regions.Full.Selection(window.getSelection(), document);
|
|
113
|
+
selection.selectNode(selectedElement.get(0));
|
|
114
|
+
selectedElement.simulate('mouseup');
|
|
115
|
+
}
|
|
116
|
+
JAVASCRIPT
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# other events
|
|
121
|
+
When /^(?:|I )double click on (.*?) in (.*?)$/ do |locator, region_locator|
|
|
122
|
+
step(%Q{I can simulate complex javascript events})
|
|
123
|
+
selector = selector_for(locator)
|
|
124
|
+
# assume the first editable region if one wasn't provided'
|
|
125
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
|
126
|
+
page.driver.within_frame('mercury_iframe') do
|
|
127
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
|
128
|
+
find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'")
|
|
129
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
130
|
+
top.jQuery(document).find('#{region_selector} #{selector}').simulate('dblclick');
|
|
131
|
+
JAVASCRIPT
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# getting contents
|
|
136
|
+
Then /^the contents? of (.*?) should be "([^"]*)"$/ do |region_locator, content|
|
|
137
|
+
region_selector = region_selector_for(region_locator)
|
|
138
|
+
page.driver.within_frame('mercury_iframe') do
|
|
139
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
|
140
|
+
results = page.driver.execute_script <<-JAVASCRIPT
|
|
141
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
|
142
|
+
if (element.data('mercury') == 'markdown') {
|
|
143
|
+
return element.find('textarea').val();
|
|
144
|
+
} else {
|
|
145
|
+
return element.html();
|
|
146
|
+
}
|
|
147
|
+
JAVASCRIPT
|
|
148
|
+
assert_equal content, results.gsub('"', "'").gsub("\n", '')
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## Saving specific steps
|
|
154
|
+
#------------------------------------------------------------------------------
|
|
155
|
+
# caching for the last save -- a request will still be made
|
|
156
|
+
Given /^save results will be cached$/ do
|
|
157
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
158
|
+
Mercury.PageEditor.prototype.save = function() {
|
|
159
|
+
window.cachedResults = this.serialize();
|
|
160
|
+
}
|
|
161
|
+
JAVASCRIPT
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# check for the last save cached results
|
|
165
|
+
Then /^the save should have (.*?) for (.*?)$/ do |contents, region_locator|
|
|
166
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
|
167
|
+
content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
|
|
168
|
+
results = page.driver.execute_script <<-JAVASCRIPT
|
|
169
|
+
return (window.cachedResults['#{region_id}']) ?
|
|
170
|
+
window.cachedResults['#{region_id}']['value'] : null;
|
|
171
|
+
JAVASCRIPT
|
|
172
|
+
assert_equal content, "\"#{results}\""
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
## Table editing specific steps
|
|
177
|
+
#------------------------------------------------------------------------------
|
|
178
|
+
# in the modal window
|
|
179
|
+
When /^(?:|I )(?:add|insert) a (row|column) (before|after)(?: it)?$/ do |row_or_column, before_or_after|
|
|
180
|
+
name = "insert_#{row_or_column}_#{before_or_after}".camelcase(:lower)
|
|
181
|
+
step(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
When /^(?:|I )delete the(?: current)? (row|column)$/ do |row_or_column|
|
|
185
|
+
name = "delete_#{row_or_column}".camelcase(:lower)
|
|
186
|
+
step(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
When /^(?:|I )(increase|decrease) the (rowspan|colspan)$/ do |increase_or_decrease, rowspan_or_colspan|
|
|
190
|
+
name = "#{increase_or_decrease}_#{rowspan_or_colspan}".camelcase(:lower)
|
|
191
|
+
step(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
Then /^the selected cell should be (.*?)$/ do |locator|
|
|
195
|
+
selector = selector_for(locator).gsub('td:', 'td.selected:')
|
|
196
|
+
find("#{selector}", :message => "Unable to locate the selected cell for '#{selector}'")
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# in general
|
|
200
|
+
Then /^the(?: table)? (row|column) count should be (\d+)$/ do |row_or_column, expected_count|
|
|
201
|
+
method = "get_#{row_or_column}_count".camelcase(:lower)
|
|
202
|
+
actual_count = page.driver.execute_script("return Mercury.tableEditor.#{method}()")
|
|
203
|
+
assert_equal expected_count.to_i, actual_count.to_i
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
## Snippet specific steps
|
|
208
|
+
#------------------------------------------------------------------------------
|
|
209
|
+
# setting snippet options
|
|
210
|
+
Given /^the options for the (.*?) snippet "([^"]*)" are (.*?)$/ do |snippet_name, snippet_id, options|
|
|
211
|
+
@snippet_id = snippet_id
|
|
212
|
+
options_json = parse_snippet_options_from(options)
|
|
213
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
214
|
+
Mercury.Snippet.load({#{snippet_id}: {name: '#{snippet_name}', options: #{options_json}}});
|
|
215
|
+
JAVASCRIPT
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# dragging/dropping
|
|
219
|
+
When /^(?:|I )(?:drag|drop) (.*?) (?:into|on) (.*?)$/ do |snippet_locator, region_locator|
|
|
220
|
+
snippet_name = snippet_name_for(snippet_locator)
|
|
221
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
|
222
|
+
page.driver.within_frame('mercury_iframe') do
|
|
223
|
+
find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
|
|
224
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
225
|
+
var element = top.jQuery(document).find('##{region_id}');
|
|
226
|
+
if (element.data('mercury') == 'markdown') {
|
|
227
|
+
alert('unimplemented');
|
|
228
|
+
throw('unimplemented');
|
|
229
|
+
} else {
|
|
230
|
+
var region = top.mercuryInstance.getRegionByName('#{region_id}');
|
|
231
|
+
region.selection().range.collapse(true);
|
|
232
|
+
document.execCommand('insertHTML', false, '<img data-snippet="#{snippet_name}" src="/assets/mercury/default-snippet.png">');
|
|
233
|
+
element.trigger('possible:drop');
|
|
234
|
+
}
|
|
235
|
+
JAVASCRIPT
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
When /^(?:|I )hover over (.*?)(?: in (.*?))?$/ do |locator, region_locator|
|
|
240
|
+
step(%Q{I can simulate complex javascript events})
|
|
241
|
+
selector = selector_for(locator)
|
|
242
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
|
243
|
+
page.driver.within_frame('mercury_iframe') do
|
|
244
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
|
245
|
+
page.driver.execute_script <<-JAVASCRIPT
|
|
246
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
|
247
|
+
if (element.data('mercury') == 'markdown') {
|
|
248
|
+
alert('unimplemented');
|
|
249
|
+
throw('unimplemented');
|
|
250
|
+
} else {
|
|
251
|
+
element.find('#{selector}').simulate('mousemove');
|
|
252
|
+
}
|
|
253
|
+
JAVASCRIPT
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
When /^(?:|I )edit the snippet$/ do
|
|
258
|
+
step(%{I hover over the snippet})
|
|
259
|
+
step(%{click on the edit snippet settings toolbar button})
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
## Dropping image specific steps
|
|
264
|
+
#------------------------------------------------------------------------------
|
|
265
|
+
#When /^(?:|I )drop an image into (.*?) from a different browser/ do |region_locator|
|
|
266
|
+
# Given(%Q{I can simulate complex javascript events})
|
|
267
|
+
# region_selector = region_selector_for(region_locator || 'the editable region')
|
|
268
|
+
# page.driver.within_frame('mercury_iframe') do
|
|
269
|
+
# find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
|
270
|
+
# page.driver.execute_script <<-JAVASCRIPT
|
|
271
|
+
# var element = top.jQuery(document).find('#{region_selector}');
|
|
272
|
+
# if (element.data('type') == 'markupable') {
|
|
273
|
+
# alert('unimplemented');
|
|
274
|
+
# throw('unimplemented');
|
|
275
|
+
# } else {
|
|
276
|
+
# element.find('#{region_selector}').simulate('drop', {'text/html': '<img src="testing.gif"/>'});
|
|
277
|
+
# }
|
|
278
|
+
# JAVASCRIPT
|
|
279
|
+
# end
|
|
280
|
+
#end
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
## Javascript event simulation steps
|
|
284
|
+
#------------------------------------------------------------------------------
|
|
285
|
+
Given /^(?:|I )can simulate complex javascript events$/ do
|
|
286
|
+
page.driver.execute_script(EVENT_SIMULATION_JAVASCRIPT)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
#------------------------------------------------------------------------------
|
|
290
|
+
|
|
291
|
+
EVENT_SIMULATION_JAVASCRIPT = <<-JAVASCRIPT
|
|
292
|
+
/*
|
|
293
|
+
* jquery.simulate - simulate browser mouse and keyboard events
|
|
294
|
+
*
|
|
295
|
+
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
|
296
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
297
|
+
* http://jquery.org/license
|
|
298
|
+
*
|
|
299
|
+
*/
|
|
300
|
+
;(function($) {
|
|
301
|
+
|
|
302
|
+
$.fn.extend({
|
|
303
|
+
simulate: function(type, options) {
|
|
304
|
+
return this.each(function() {
|
|
305
|
+
var opt = $.extend({}, $.simulate.defaults, options || {});
|
|
306
|
+
new $.simulate(this, type, opt);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
$.simulate = function(el, type, options) {
|
|
312
|
+
this.target = el;
|
|
313
|
+
this.options = options;
|
|
314
|
+
|
|
315
|
+
if (/^drag$/.test(type)) {
|
|
316
|
+
this[type].apply(this, [this.target, options]);
|
|
317
|
+
} else {
|
|
318
|
+
this.simulateEvent(el, type, options);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
$.extend($.simulate.prototype, {
|
|
323
|
+
simulateEvent: function(el, type, options) {
|
|
324
|
+
var evt = this.createEvent(type, options);
|
|
325
|
+
this.dispatchEvent(el, type, evt, options);
|
|
326
|
+
return evt;
|
|
327
|
+
},
|
|
328
|
+
createEvent: function(type, options) {
|
|
329
|
+
if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) {
|
|
330
|
+
return this.mouseEvent(type, options);
|
|
331
|
+
} else if (/^key(up|down|press)$/.test(type)) {
|
|
332
|
+
return this.keyboardEvent(type, options);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
mouseEvent: function(type, options) {
|
|
336
|
+
var evt;
|
|
337
|
+
var e = $.extend({
|
|
338
|
+
bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
|
|
339
|
+
screenX: 0, screenY: 0, clientX: 0, clientY: 0,
|
|
340
|
+
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
|
341
|
+
button: 0, relatedTarget: undefined
|
|
342
|
+
}, options);
|
|
343
|
+
|
|
344
|
+
var relatedTarget = $(e.relatedTarget)[0];
|
|
345
|
+
|
|
346
|
+
if ($.isFunction(document.createEvent)) {
|
|
347
|
+
evt = document.createEvent("MouseEvents");
|
|
348
|
+
evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
|
|
349
|
+
e.screenX, e.screenY, e.clientX, e.clientY,
|
|
350
|
+
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
|
351
|
+
e.button, e.relatedTarget || document.body.parentNode);
|
|
352
|
+
} else if (document.createEventObject) {
|
|
353
|
+
evt = document.createEventObject();
|
|
354
|
+
$.extend(evt, e);
|
|
355
|
+
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
|
|
356
|
+
}
|
|
357
|
+
return evt;
|
|
358
|
+
},
|
|
359
|
+
keyboardEvent: function(type, options) {
|
|
360
|
+
var evt;
|
|
361
|
+
|
|
362
|
+
var e = $.extend({ bubbles: true, cancelable: true, view: window,
|
|
363
|
+
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
|
364
|
+
keyCode: 0, charCode: 0
|
|
365
|
+
}, options);
|
|
366
|
+
|
|
367
|
+
if ($.isFunction(document.createEvent)) {
|
|
368
|
+
try {
|
|
369
|
+
evt = document.createEvent("KeyEvents");
|
|
370
|
+
evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view,
|
|
371
|
+
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
|
372
|
+
e.keyCode, e.charCode);
|
|
373
|
+
} catch(err) {
|
|
374
|
+
evt = document.createEvent("Events");
|
|
375
|
+
evt.initEvent(type, e.bubbles, e.cancelable);
|
|
376
|
+
$.extend(evt, { view: e.view,
|
|
377
|
+
ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey,
|
|
378
|
+
keyCode: e.keyCode, charCode: e.charCode
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
} else if (document.createEventObject) {
|
|
382
|
+
evt = document.createEventObject();
|
|
383
|
+
$.extend(evt, e);
|
|
384
|
+
}
|
|
385
|
+
if ($.browser.msie || $.browser.opera) {
|
|
386
|
+
evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode;
|
|
387
|
+
evt.charCode = undefined;
|
|
388
|
+
}
|
|
389
|
+
return evt;
|
|
390
|
+
},
|
|
391
|
+
dispatchEvent: function(el, type, evt) {
|
|
392
|
+
if (el.dispatchEvent) {
|
|
393
|
+
el.dispatchEvent(evt);
|
|
394
|
+
} else if (el.fireEvent) {
|
|
395
|
+
el.fireEvent('on' + type, evt);
|
|
396
|
+
}
|
|
397
|
+
return evt;
|
|
398
|
+
},
|
|
399
|
+
drag: function(el) {
|
|
400
|
+
var self = this, center = this.findCenter(this.target),
|
|
401
|
+
options = this.options, x = Math.floor(center.x), y = Math.floor(center.y),
|
|
402
|
+
dx = options.dx || 0, dy = options.dy || 0, target = this.target;
|
|
403
|
+
var coord = { clientX: x, clientY: y };
|
|
404
|
+
this.simulateEvent(target, "mousedown", coord);
|
|
405
|
+
coord = { clientX: x + 1, clientY: y + 1 };
|
|
406
|
+
this.simulateEvent(document, "mousemove", coord);
|
|
407
|
+
coord = { clientX: x + dx, clientY: y + dy };
|
|
408
|
+
this.simulateEvent(document, "mousemove", coord);
|
|
409
|
+
this.simulateEvent(document, "mousemove", coord);
|
|
410
|
+
this.simulateEvent(target, "mouseup", coord);
|
|
411
|
+
this.simulateEvent(target, "click", coord);
|
|
412
|
+
},
|
|
413
|
+
findCenter: function(el) {
|
|
414
|
+
var el = $(this.target), o = el.offset(), d = $(document);
|
|
415
|
+
return {
|
|
416
|
+
x: o.left + el.outerWidth() / 2 - d.scrollLeft(),
|
|
417
|
+
y: o.top + el.outerHeight() / 2 - d.scrollTop()
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
$.extend($.simulate, {
|
|
423
|
+
defaults: {
|
|
424
|
+
speed: 'sync'
|
|
425
|
+
},
|
|
426
|
+
VK_TAB: 9,
|
|
427
|
+
VK_ENTER: 13,
|
|
428
|
+
VK_ESC: 27,
|
|
429
|
+
VK_PGUP: 33,
|
|
430
|
+
VK_PGDN: 34,
|
|
431
|
+
VK_END: 35,
|
|
432
|
+
VK_HOME: 36,
|
|
433
|
+
VK_LEFT: 37,
|
|
434
|
+
VK_UP: 38,
|
|
435
|
+
VK_RIGHT: 39,
|
|
436
|
+
VK_DOWN: 40
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
})(jQuery);
|
|
440
|
+
JAVASCRIPT
|