mercury-rails 0.2.0 → 0.2.3
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/POST_INSTALL +15 -0
- data/README.md +27 -6
- data/VERSION +1 -1
- data/app/controllers/mercury_controller.rb +4 -4
- data/app/views/layouts/mercury.html.erb +14 -3
- data/app/views/mercury/panels/snippets.html +1 -1
- data/app/views/mercury/snippets/{example_options.html.erb → example/options.html.erb} +0 -0
- data/app/views/mercury/snippets/{example.html.erb → example/preview.html.erb} +0 -0
- data/config/routes.rb +2 -2
- data/features/loading/loading.feature +22 -0
- data/features/loading/navigating.feature +77 -0
- data/features/loading/user_interface.feature +67 -0
- data/features/regions/editable/advanced_editing.feature +0 -0
- data/features/regions/editable/basic_editing.feature +195 -0
- data/features/regions/editable/inserting_links.feature +98 -0
- data/features/regions/editable/inserting_media.feature +110 -0
- data/features/regions/editable/inserting_snippets.feature +103 -0
- data/features/regions/editable/inserting_special_characters.feature +24 -0
- data/features/regions/editable/inserting_tables.feature +109 -0
- data/features/regions/editable/pasting.feature +0 -0
- data/features/regions/editable/uploading_images.feature +0 -0
- data/features/regions/markupable/advanced_editing.feature +0 -0
- data/features/regions/markupable/basic_editing.feature +0 -0
- data/features/regions/markupable/inserting_links.feature +0 -0
- data/features/regions/markupable/inserting_media.feature +0 -0
- data/features/regions/markupable/inserting_snippets.feature +0 -0
- data/features/regions/markupable/inserting_special_characters.feature +0 -0
- data/features/regions/markupable/inserting_tables.feature +0 -0
- data/features/regions/markupable/uploading_images.feature +0 -0
- data/features/regions/snippetable/advanced_editing.feature +0 -0
- data/features/regions/snippetable/basic_editing.feature +0 -0
- data/features/regions/snippetable/inserting_snippets.feature +0 -0
- data/features/saving/saving.feature +33 -0
- data/features/step_definitions/debug_steps.rb +2 -2
- data/features/step_definitions/mercury_steps.rb +441 -0
- data/features/support/env.rb +3 -3
- data/features/support/mercury_contents.rb +25 -0
- data/features/support/mercury_selectors.rb +147 -0
- data/features/support/paths.rb +20 -18
- data/features/support/selectors.rb +5 -3
- data/lib/generators/mercury/install/install_generator.rb +14 -0
- data/mercury-rails.gemspec +50 -20
- data/spec/javascripts/mercury/lightview_spec.js.coffee +55 -27
- data/spec/javascripts/mercury/mercury_spec.js.coffee +3 -3
- data/spec/javascripts/mercury/modal_spec.js.coffee +2 -2
- data/spec/javascripts/mercury/native_extensions_spec.js.coffee +0 -24
- data/spec/javascripts/mercury/page_editor_spec.js.coffee +148 -67
- data/spec/javascripts/mercury/panel_spec.js.coffee +2 -2
- data/spec/javascripts/mercury/region_spec.js.coffee +10 -7
- data/spec/javascripts/mercury/regions/editable_spec.js.coffee +0 -20
- data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +2 -2
- data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +1 -1
- data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +1 -1
- data/spec/javascripts/templates/mercury/page_editor.html +3 -3
- data/vendor/assets/images/mercury/close.png +0 -0
- data/vendor/assets/javascripts/mercury.js +140 -73
- data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery-1.6.js +0 -0
- data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery-ui-1.8.13.custom.js +0 -0
- data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery.additions.js +0 -0
- data/vendor/assets/javascripts/mercury/dependencies/jquery.htmlClean.js +527 -0
- data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/liquidmetal.js +0 -0
- data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/showdown.js +0 -0
- data/vendor/assets/javascripts/mercury/lightview.js.coffee +5 -2
- data/vendor/assets/javascripts/mercury/mercury.js.coffee +9 -8
- data/vendor/assets/javascripts/mercury/modals/htmleditor.js.coffee +3 -1
- data/vendor/assets/javascripts/mercury/modals/inserttable.js.coffee +2 -2
- data/vendor/assets/javascripts/mercury/native_extensions.js.coffee +6 -17
- data/vendor/assets/javascripts/mercury/page_editor.js.coffee +29 -8
- data/vendor/assets/javascripts/mercury/plugins/save_as_xml/mercury/page_editor.js.coffee +27 -0
- data/vendor/assets/javascripts/mercury/plugins/save_as_xml/plugin.js +9 -0
- data/vendor/assets/javascripts/mercury/region.js.coffee +2 -2
- data/vendor/assets/javascripts/mercury/regions/editable.js.coffee +89 -93
- data/vendor/assets/javascripts/mercury/regions/markupable.js.coffee +1 -1
- data/vendor/assets/javascripts/mercury/support/history.js +1 -0
- data/vendor/assets/javascripts/mercury/uploader.js.coffee +0 -1
- data/vendor/assets/javascripts/mercury_loader.js +4 -4
- data/vendor/assets/stylesheets/mercury/lightview.css +8 -0
- data/vendor/assets/stylesheets/mercury/mercury.css +12 -0
- data/vendor/assets/stylesheets/mercury/modal.css +0 -12
- data/vendor/assets/stylesheets/mercury/toolbar.css +1 -0
- data/vendor/assets/stylesheets/mercury_overrides.css +17 -0
- metadata +73 -45
- data/app/views/mercury/lightviews/imageprocessor.html +0 -3
- data/app/views/mercury/modals/sanitizer.html +0 -9
- data/features/editing/basic.feature +0 -11
- data/vendor/assets/images/mercury/clippy.png +0 -0
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
@javascript
|
2
|
+
Feature:
|
3
|
+
As a content editor type person
|
4
|
+
In order to manage content
|
5
|
+
I should be able to save the content
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given I am on an editable page
|
9
|
+
And save results will be cached
|
10
|
+
|
11
|
+
|
12
|
+
Scenario: A user can change content in an editable region and save those changes
|
13
|
+
When I set the content of the editable region to "new content"
|
14
|
+
And I click on the "Save" button
|
15
|
+
Then the save should have "new content" for the editable region
|
16
|
+
|
17
|
+
|
18
|
+
Scenario: A user can change content in a markupable region and save those changes
|
19
|
+
When I set the content of the markupable region to "new content"
|
20
|
+
And I click on the "Save" button
|
21
|
+
Then the save should have "new content" for the markupable region
|
22
|
+
|
23
|
+
|
24
|
+
Scenario: A user can put snippets into an editable region and get the options on save
|
25
|
+
# todo: finish
|
26
|
+
|
27
|
+
|
28
|
+
Scenario: A user can expect the right version of the snippet options to be saved
|
29
|
+
# todo: finish
|
30
|
+
|
31
|
+
|
32
|
+
Scenario: A user can put snippets into a markupable region and get the options on save
|
33
|
+
# todo: finish
|
@@ -0,0 +1,441 @@
|
|
1
|
+
## Generic web steps
|
2
|
+
#------------------------------------------------------------------------------
|
3
|
+
When /^(?:|I )click on (.+)$/ do |locator|
|
4
|
+
selector = selector_for(locator)
|
5
|
+
find(selector, :message => "Unable to locate the element '#{selector}' to click on").click
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^(.+) should (not )?be visible$/ do |locator, boolean|
|
9
|
+
selector = selector_for(locator)
|
10
|
+
if boolean == 'not '
|
11
|
+
page.has_no_css?("#{selector}")
|
12
|
+
else
|
13
|
+
page.has_css?("#{selector}", :visible => true)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# scoping step for different windows
|
18
|
+
When /^(.*) in the "([^"]*)" window$/ do |step, window|
|
19
|
+
page.driver.within_window(window) do
|
20
|
+
When(step)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
## Mercury general steps
|
26
|
+
#------------------------------------------------------------------------------
|
27
|
+
Given /^(?:|I )adjust the configuration to have: "([^"]*)"$/ do |javascript|
|
28
|
+
Rails.application.config.mercury_config = javascript
|
29
|
+
end
|
30
|
+
|
31
|
+
# scoping step for the mercury content frame
|
32
|
+
When /^(.*) in the content frame$/ do |step|
|
33
|
+
page.driver.within_frame('mercury_iframe') do
|
34
|
+
When(step)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# silence mercury's onbeforeunload confirmation
|
39
|
+
Given /^the editor won't prompt when leaving the page$/ do
|
40
|
+
page.driver.execute_script('Mercury.silent = true;')
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
## Toolbar specific steps
|
45
|
+
#------------------------------------------------------------------------------
|
46
|
+
# for the select dropdowns
|
47
|
+
When /^(?:|I )select (.*?) from the dropdown$/ do |locator|
|
48
|
+
selector = selector_for(locator)
|
49
|
+
find(selector, :message => "Unable to locate the element '#{selector}' to click on").click
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
## Panel specific steps
|
54
|
+
#------------------------------------------------------------------------------
|
55
|
+
When /^(?:I )(?:open|close|toggle) the (.*?) panel$/ do |panel_locator|
|
56
|
+
When(%Q{I click on the "#{panel_locator}" button})
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
## Modal specific steps
|
61
|
+
#------------------------------------------------------------------------------
|
62
|
+
When /^(?:I )close the modal(?: window)?$/ do
|
63
|
+
When(%Q{I click on the modal close button})
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
## Region specific steps
|
68
|
+
#------------------------------------------------------------------------------
|
69
|
+
# setting content
|
70
|
+
Given /^the content of (.*?) (?:is|are|has|includes) (.*?)$/ do |region_locator, contents|
|
71
|
+
When(%Q{I set the contents of #{region_locator} to #{contents}})
|
72
|
+
end
|
73
|
+
|
74
|
+
When /^(?:|I )(?:change|set) the contents? of (.*?) to (.*?)$/ do |region_locator, contents|
|
75
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
76
|
+
content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
|
77
|
+
page.driver.within_frame('mercury_iframe') do
|
78
|
+
find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
|
79
|
+
page.driver.execute_script <<-JAVASCRIPT
|
80
|
+
var element = top.jQuery(document).find('##{region_id}');
|
81
|
+
if (element.data('type') == 'markupable') {
|
82
|
+
element.find('textarea').val(#{content});
|
83
|
+
} else {
|
84
|
+
var region = top.mercuryInstance.getRegionByName('#{region_id}');
|
85
|
+
region.content(#{content});
|
86
|
+
}
|
87
|
+
JAVASCRIPT
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# setting/making selections
|
92
|
+
When /^(?:|I )(?:make|have) a selection$/ do
|
93
|
+
When(%Q{I have a selection for "span"})
|
94
|
+
end
|
95
|
+
|
96
|
+
When /^(?:|I )(?:make|have) a selection (?:in (.*?) )?for "([^"]*)"$/ do |region_locator, selector|
|
97
|
+
Given(%Q{I can simulate complex javascript events})
|
98
|
+
# assume the first editable region if one wasn't provided'
|
99
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
100
|
+
page.driver.within_frame('mercury_iframe') do
|
101
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
102
|
+
find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'")
|
103
|
+
page.driver.execute_script <<-JAVASCRIPT
|
104
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
105
|
+
if (element.data('type') == 'markupable') {
|
106
|
+
alert('unimplemented');
|
107
|
+
throw('unimplemented');
|
108
|
+
} else {
|
109
|
+
var selectedElement = element.find('#{selector}');
|
110
|
+
var selection = new top.Mercury.Regions.Editable.Selection(window.getSelection(), document);
|
111
|
+
selection.selectNode(selectedElement.get(0));
|
112
|
+
selectedElement.simulate('mouseup');
|
113
|
+
}
|
114
|
+
JAVASCRIPT
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# other events
|
119
|
+
When /^(?:|I )double click on (.*?) in (.*?)$/ do |locator, region_locator|
|
120
|
+
Given(%Q{I can simulate complex javascript events})
|
121
|
+
selector = selector_for(locator)
|
122
|
+
# assume the first editable region if one wasn't provided'
|
123
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
124
|
+
page.driver.within_frame('mercury_iframe') do
|
125
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
126
|
+
find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'")
|
127
|
+
page.driver.execute_script <<-JAVASCRIPT
|
128
|
+
top.jQuery(document).find('#{region_selector} #{selector}').simulate('dblclick');
|
129
|
+
JAVASCRIPT
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# getting contents
|
134
|
+
Then /^the contents? of (.*?) should be "([^"]*)"$/ do |region_locator, content|
|
135
|
+
region_selector = region_selector_for(region_locator)
|
136
|
+
page.driver.within_frame('mercury_iframe') do
|
137
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
138
|
+
results = page.driver.execute_script <<-JAVASCRIPT
|
139
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
140
|
+
if (element.data('type') == 'markupable') {
|
141
|
+
return element.find('textarea').val();
|
142
|
+
} else {
|
143
|
+
return element.html();
|
144
|
+
}
|
145
|
+
JAVASCRIPT
|
146
|
+
assert_equal content, results.gsub('"', "'").gsub("\n", '')
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
## Saving specific steps
|
152
|
+
#------------------------------------------------------------------------------
|
153
|
+
# caching for the last save -- a request will still be made
|
154
|
+
Given /^save results will be cached$/ do
|
155
|
+
page.driver.execute_script <<-JAVASCRIPT
|
156
|
+
Mercury.PageEditor.prototype.oldSerialize = Mercury.PageEditor.prototype.serialize;
|
157
|
+
Mercury.PageEditor.prototype.serialize = function() {
|
158
|
+
results = this.oldSerialize.call(this, arguments);
|
159
|
+
window.cachedResults = results;
|
160
|
+
return results;
|
161
|
+
}
|
162
|
+
JAVASCRIPT
|
163
|
+
end
|
164
|
+
|
165
|
+
# check for the last save cached results
|
166
|
+
Then /^the save should have (.*?) for (.*?)$/ do |contents, region_locator|
|
167
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
168
|
+
content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
|
169
|
+
results = page.driver.execute_script <<-JAVASCRIPT
|
170
|
+
return (window.cachedResults['#{region_id}']) ?
|
171
|
+
window.cachedResults['#{region_id}']['value'] : null;
|
172
|
+
JAVASCRIPT
|
173
|
+
assert_equal content, "\"#{results}\""
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
## Table editing specific steps
|
178
|
+
#------------------------------------------------------------------------------
|
179
|
+
# in the modal window
|
180
|
+
When /^(?:|I )(?:add|insert) a (row|column) (before|after)(?: it)?$/ do |row_or_column, before_or_after|
|
181
|
+
name = "insert_#{row_or_column}_#{before_or_after}".camelcase(:lower)
|
182
|
+
When(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
183
|
+
end
|
184
|
+
|
185
|
+
When /^(?:|I )delete the(?: current)? (row|column)$/ do |row_or_column|
|
186
|
+
name = "delete_#{row_or_column}".camelcase(:lower)
|
187
|
+
When(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
188
|
+
end
|
189
|
+
|
190
|
+
When /^(?:|I )(increase|decrease) the (rowspan|colspan)$/ do |increase_or_decrease, rowspan_or_colspan|
|
191
|
+
name = "#{increase_or_decrease}_#{rowspan_or_colspan}".camelcase(:lower)
|
192
|
+
When(%Q{I click on ".mercury-modal-content input[name=#{name}]"})
|
193
|
+
end
|
194
|
+
|
195
|
+
Then /^the selected cell should be (.*?)$/ do |locator|
|
196
|
+
selector = selector_for(locator).gsub('td:', 'td.selected:')
|
197
|
+
find("#{selector}", :message => "Unable to locate the selected cell for '#{selector}'")
|
198
|
+
end
|
199
|
+
|
200
|
+
# in general
|
201
|
+
Then /^the(?: table)? (row|column) count should be (\d+)$/ do |row_or_column, expected_count|
|
202
|
+
method = "get_#{row_or_column}_count".camelcase(:lower)
|
203
|
+
actual_count = page.driver.execute_script("return Mercury.tableEditor.#{method}()")
|
204
|
+
assert_equal expected_count.to_i, actual_count.to_i
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
## Snippet specific steps
|
209
|
+
#------------------------------------------------------------------------------
|
210
|
+
# setting snippet options
|
211
|
+
Given /^the options for the (.*?) snippet "([^"]*)" are (.*?)$/ do |snippet_name, snippet_id, options|
|
212
|
+
@snippet_id = snippet_id
|
213
|
+
options_json = parse_snippet_options_from(options)
|
214
|
+
page.driver.execute_script <<-JAVASCRIPT
|
215
|
+
Mercury.Snippet.load({#{snippet_id}: {name: '#{snippet_name}', options: #{options_json}}});
|
216
|
+
JAVASCRIPT
|
217
|
+
end
|
218
|
+
|
219
|
+
# dragging/dropping
|
220
|
+
When /^(?:|I )(?:drag|drop) (.*?) (?:into|on) (.*?)$/ do |snippet_locator, region_locator|
|
221
|
+
snippet_name = snippet_name_for(snippet_locator)
|
222
|
+
region_id = region_selector_for(region_locator).gsub('#', '')
|
223
|
+
page.driver.within_frame('mercury_iframe') do
|
224
|
+
find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
|
225
|
+
page.driver.execute_script <<-JAVASCRIPT
|
226
|
+
var element = top.jQuery(document).find('##{region_id}');
|
227
|
+
if (element.data('type') == 'markupable') {
|
228
|
+
alert('unimplemented');
|
229
|
+
throw('unimplemented');
|
230
|
+
} else {
|
231
|
+
var region = top.mercuryInstance.getRegionByName('#{region_id}');
|
232
|
+
region.selection().range.collapse(true);
|
233
|
+
document.execCommand('insertHTML', false, '<img data-snippet="#{snippet_name}" src="/assets/mercury/default-snippet.png">');
|
234
|
+
element.trigger('possible:drop');
|
235
|
+
}
|
236
|
+
JAVASCRIPT
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
When /^(?:|I )hover over (.*?)(?: in (.*?))?$/ do |locator, region_locator|
|
241
|
+
Given(%Q{I can simulate complex javascript events})
|
242
|
+
selector = selector_for(locator)
|
243
|
+
region_selector = region_selector_for(region_locator || 'the editable region')
|
244
|
+
page.driver.within_frame('mercury_iframe') do
|
245
|
+
find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
246
|
+
page.driver.execute_script <<-JAVASCRIPT
|
247
|
+
var element = top.jQuery(document).find('#{region_selector}');
|
248
|
+
if (element.data('type') == 'markupable') {
|
249
|
+
alert('unimplemented');
|
250
|
+
throw('unimplemented');
|
251
|
+
} else {
|
252
|
+
element.find('#{selector}').simulate('mousemove');
|
253
|
+
}
|
254
|
+
JAVASCRIPT
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
When /^(?:|I )edit the snippet$/ do
|
259
|
+
When(%{I hover over the snippet})
|
260
|
+
And(%{click on the edit snippet settings toolbar button})
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
## Dropping image specific steps
|
265
|
+
#------------------------------------------------------------------------------
|
266
|
+
#When /^(?:|I )drop an image into (.*?) from a different browser/ do |region_locator|
|
267
|
+
# Given(%Q{I can simulate complex javascript events})
|
268
|
+
# region_selector = region_selector_for(region_locator || 'the editable region')
|
269
|
+
# page.driver.within_frame('mercury_iframe') do
|
270
|
+
# find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
|
271
|
+
# page.driver.execute_script <<-JAVASCRIPT
|
272
|
+
# var element = top.jQuery(document).find('#{region_selector}');
|
273
|
+
# if (element.data('type') == 'markupable') {
|
274
|
+
# alert('unimplemented');
|
275
|
+
# throw('unimplemented');
|
276
|
+
# } else {
|
277
|
+
# element.find('#{region_selector}').simulate('drop', {'text/html': '<img src="testing.gif"/>'});
|
278
|
+
# }
|
279
|
+
# JAVASCRIPT
|
280
|
+
# end
|
281
|
+
#end
|
282
|
+
|
283
|
+
|
284
|
+
## Javascript event simulation steps
|
285
|
+
#------------------------------------------------------------------------------
|
286
|
+
Given /^(?:|I )can simulate complex javascript events$/ do
|
287
|
+
page.driver.execute_script(EVENT_SIMULATION_JAVASCRIPT)
|
288
|
+
end
|
289
|
+
|
290
|
+
#------------------------------------------------------------------------------
|
291
|
+
|
292
|
+
EVENT_SIMULATION_JAVASCRIPT = <<-JAVASCRIPT
|
293
|
+
/*
|
294
|
+
* jquery.simulate - simulate browser mouse and keyboard events
|
295
|
+
*
|
296
|
+
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
297
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
298
|
+
* http://jquery.org/license
|
299
|
+
*
|
300
|
+
*/
|
301
|
+
;(function($) {
|
302
|
+
|
303
|
+
$.fn.extend({
|
304
|
+
simulate: function(type, options) {
|
305
|
+
return this.each(function() {
|
306
|
+
var opt = $.extend({}, $.simulate.defaults, options || {});
|
307
|
+
new $.simulate(this, type, opt);
|
308
|
+
});
|
309
|
+
}
|
310
|
+
});
|
311
|
+
|
312
|
+
$.simulate = function(el, type, options) {
|
313
|
+
this.target = el;
|
314
|
+
this.options = options;
|
315
|
+
|
316
|
+
if (/^drag$/.test(type)) {
|
317
|
+
this[type].apply(this, [this.target, options]);
|
318
|
+
} else {
|
319
|
+
this.simulateEvent(el, type, options);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
$.extend($.simulate.prototype, {
|
324
|
+
simulateEvent: function(el, type, options) {
|
325
|
+
var evt = this.createEvent(type, options);
|
326
|
+
this.dispatchEvent(el, type, evt, options);
|
327
|
+
return evt;
|
328
|
+
},
|
329
|
+
createEvent: function(type, options) {
|
330
|
+
if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) {
|
331
|
+
return this.mouseEvent(type, options);
|
332
|
+
} else if (/^key(up|down|press)$/.test(type)) {
|
333
|
+
return this.keyboardEvent(type, options);
|
334
|
+
}
|
335
|
+
},
|
336
|
+
mouseEvent: function(type, options) {
|
337
|
+
var evt;
|
338
|
+
var e = $.extend({
|
339
|
+
bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
|
340
|
+
screenX: 0, screenY: 0, clientX: 0, clientY: 0,
|
341
|
+
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
342
|
+
button: 0, relatedTarget: undefined
|
343
|
+
}, options);
|
344
|
+
|
345
|
+
var relatedTarget = $(e.relatedTarget)[0];
|
346
|
+
|
347
|
+
if ($.isFunction(document.createEvent)) {
|
348
|
+
evt = document.createEvent("MouseEvents");
|
349
|
+
evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
|
350
|
+
e.screenX, e.screenY, e.clientX, e.clientY,
|
351
|
+
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
352
|
+
e.button, e.relatedTarget || document.body.parentNode);
|
353
|
+
} else if (document.createEventObject) {
|
354
|
+
evt = document.createEventObject();
|
355
|
+
$.extend(evt, e);
|
356
|
+
evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
|
357
|
+
}
|
358
|
+
return evt;
|
359
|
+
},
|
360
|
+
keyboardEvent: function(type, options) {
|
361
|
+
var evt;
|
362
|
+
|
363
|
+
var e = $.extend({ bubbles: true, cancelable: true, view: window,
|
364
|
+
ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
|
365
|
+
keyCode: 0, charCode: 0
|
366
|
+
}, options);
|
367
|
+
|
368
|
+
if ($.isFunction(document.createEvent)) {
|
369
|
+
try {
|
370
|
+
evt = document.createEvent("KeyEvents");
|
371
|
+
evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view,
|
372
|
+
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
|
373
|
+
e.keyCode, e.charCode);
|
374
|
+
} catch(err) {
|
375
|
+
evt = document.createEvent("Events");
|
376
|
+
evt.initEvent(type, e.bubbles, e.cancelable);
|
377
|
+
$.extend(evt, { view: e.view,
|
378
|
+
ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey,
|
379
|
+
keyCode: e.keyCode, charCode: e.charCode
|
380
|
+
});
|
381
|
+
}
|
382
|
+
} else if (document.createEventObject) {
|
383
|
+
evt = document.createEventObject();
|
384
|
+
$.extend(evt, e);
|
385
|
+
}
|
386
|
+
if ($.browser.msie || $.browser.opera) {
|
387
|
+
evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode;
|
388
|
+
evt.charCode = undefined;
|
389
|
+
}
|
390
|
+
return evt;
|
391
|
+
},
|
392
|
+
dispatchEvent: function(el, type, evt) {
|
393
|
+
if (el.dispatchEvent) {
|
394
|
+
el.dispatchEvent(evt);
|
395
|
+
} else if (el.fireEvent) {
|
396
|
+
el.fireEvent('on' + type, evt);
|
397
|
+
}
|
398
|
+
return evt;
|
399
|
+
},
|
400
|
+
drag: function(el) {
|
401
|
+
var self = this, center = this.findCenter(this.target),
|
402
|
+
options = this.options, x = Math.floor(center.x), y = Math.floor(center.y),
|
403
|
+
dx = options.dx || 0, dy = options.dy || 0, target = this.target;
|
404
|
+
var coord = { clientX: x, clientY: y };
|
405
|
+
this.simulateEvent(target, "mousedown", coord);
|
406
|
+
coord = { clientX: x + 1, clientY: y + 1 };
|
407
|
+
this.simulateEvent(document, "mousemove", coord);
|
408
|
+
coord = { clientX: x + dx, clientY: y + dy };
|
409
|
+
this.simulateEvent(document, "mousemove", coord);
|
410
|
+
this.simulateEvent(document, "mousemove", coord);
|
411
|
+
this.simulateEvent(target, "mouseup", coord);
|
412
|
+
this.simulateEvent(target, "click", coord);
|
413
|
+
},
|
414
|
+
findCenter: function(el) {
|
415
|
+
var el = $(this.target), o = el.offset(), d = $(document);
|
416
|
+
return {
|
417
|
+
x: o.left + el.outerWidth() / 2 - d.scrollLeft(),
|
418
|
+
y: o.top + el.outerHeight() / 2 - d.scrollTop()
|
419
|
+
};
|
420
|
+
}
|
421
|
+
});
|
422
|
+
|
423
|
+
$.extend($.simulate, {
|
424
|
+
defaults: {
|
425
|
+
speed: 'sync'
|
426
|
+
},
|
427
|
+
VK_TAB: 9,
|
428
|
+
VK_ENTER: 13,
|
429
|
+
VK_ESC: 27,
|
430
|
+
VK_PGUP: 33,
|
431
|
+
VK_PGDN: 34,
|
432
|
+
VK_END: 35,
|
433
|
+
VK_HOME: 36,
|
434
|
+
VK_LEFT: 37,
|
435
|
+
VK_UP: 38,
|
436
|
+
VK_RIGHT: 39,
|
437
|
+
VK_DOWN: 40
|
438
|
+
});
|
439
|
+
|
440
|
+
})(jQuery);
|
441
|
+
JAVASCRIPT
|