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.
Files changed (86) hide show
  1. data/POST_INSTALL +15 -0
  2. data/README.md +27 -6
  3. data/VERSION +1 -1
  4. data/app/controllers/mercury_controller.rb +4 -4
  5. data/app/views/layouts/mercury.html.erb +14 -3
  6. data/app/views/mercury/panels/snippets.html +1 -1
  7. data/app/views/mercury/snippets/{example_options.html.erb → example/options.html.erb} +0 -0
  8. data/app/views/mercury/snippets/{example.html.erb → example/preview.html.erb} +0 -0
  9. data/config/routes.rb +2 -2
  10. data/features/loading/loading.feature +22 -0
  11. data/features/loading/navigating.feature +77 -0
  12. data/features/loading/user_interface.feature +67 -0
  13. data/features/regions/editable/advanced_editing.feature +0 -0
  14. data/features/regions/editable/basic_editing.feature +195 -0
  15. data/features/regions/editable/inserting_links.feature +98 -0
  16. data/features/regions/editable/inserting_media.feature +110 -0
  17. data/features/regions/editable/inserting_snippets.feature +103 -0
  18. data/features/regions/editable/inserting_special_characters.feature +24 -0
  19. data/features/regions/editable/inserting_tables.feature +109 -0
  20. data/features/regions/editable/pasting.feature +0 -0
  21. data/features/regions/editable/uploading_images.feature +0 -0
  22. data/features/regions/markupable/advanced_editing.feature +0 -0
  23. data/features/regions/markupable/basic_editing.feature +0 -0
  24. data/features/regions/markupable/inserting_links.feature +0 -0
  25. data/features/regions/markupable/inserting_media.feature +0 -0
  26. data/features/regions/markupable/inserting_snippets.feature +0 -0
  27. data/features/regions/markupable/inserting_special_characters.feature +0 -0
  28. data/features/regions/markupable/inserting_tables.feature +0 -0
  29. data/features/regions/markupable/uploading_images.feature +0 -0
  30. data/features/regions/snippetable/advanced_editing.feature +0 -0
  31. data/features/regions/snippetable/basic_editing.feature +0 -0
  32. data/features/regions/snippetable/inserting_snippets.feature +0 -0
  33. data/features/saving/saving.feature +33 -0
  34. data/features/step_definitions/debug_steps.rb +2 -2
  35. data/features/step_definitions/mercury_steps.rb +441 -0
  36. data/features/support/env.rb +3 -3
  37. data/features/support/mercury_contents.rb +25 -0
  38. data/features/support/mercury_selectors.rb +147 -0
  39. data/features/support/paths.rb +20 -18
  40. data/features/support/selectors.rb +5 -3
  41. data/lib/generators/mercury/install/install_generator.rb +14 -0
  42. data/mercury-rails.gemspec +50 -20
  43. data/spec/javascripts/mercury/lightview_spec.js.coffee +55 -27
  44. data/spec/javascripts/mercury/mercury_spec.js.coffee +3 -3
  45. data/spec/javascripts/mercury/modal_spec.js.coffee +2 -2
  46. data/spec/javascripts/mercury/native_extensions_spec.js.coffee +0 -24
  47. data/spec/javascripts/mercury/page_editor_spec.js.coffee +148 -67
  48. data/spec/javascripts/mercury/panel_spec.js.coffee +2 -2
  49. data/spec/javascripts/mercury/region_spec.js.coffee +10 -7
  50. data/spec/javascripts/mercury/regions/editable_spec.js.coffee +0 -20
  51. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +2 -2
  52. data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +1 -1
  53. data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +1 -1
  54. data/spec/javascripts/templates/mercury/page_editor.html +3 -3
  55. data/vendor/assets/images/mercury/close.png +0 -0
  56. data/vendor/assets/javascripts/mercury.js +140 -73
  57. data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery-1.6.js +0 -0
  58. data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery-ui-1.8.13.custom.js +0 -0
  59. data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/jquery.additions.js +0 -0
  60. data/vendor/assets/javascripts/mercury/dependencies/jquery.htmlClean.js +527 -0
  61. data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/liquidmetal.js +0 -0
  62. data/vendor/assets/javascripts/{mercury_dependencies → mercury/dependencies}/showdown.js +0 -0
  63. data/vendor/assets/javascripts/mercury/lightview.js.coffee +5 -2
  64. data/vendor/assets/javascripts/mercury/mercury.js.coffee +9 -8
  65. data/vendor/assets/javascripts/mercury/modals/htmleditor.js.coffee +3 -1
  66. data/vendor/assets/javascripts/mercury/modals/inserttable.js.coffee +2 -2
  67. data/vendor/assets/javascripts/mercury/native_extensions.js.coffee +6 -17
  68. data/vendor/assets/javascripts/mercury/page_editor.js.coffee +29 -8
  69. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/mercury/page_editor.js.coffee +27 -0
  70. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/plugin.js +9 -0
  71. data/vendor/assets/javascripts/mercury/region.js.coffee +2 -2
  72. data/vendor/assets/javascripts/mercury/regions/editable.js.coffee +89 -93
  73. data/vendor/assets/javascripts/mercury/regions/markupable.js.coffee +1 -1
  74. data/vendor/assets/javascripts/mercury/support/history.js +1 -0
  75. data/vendor/assets/javascripts/mercury/uploader.js.coffee +0 -1
  76. data/vendor/assets/javascripts/mercury_loader.js +4 -4
  77. data/vendor/assets/stylesheets/mercury/lightview.css +8 -0
  78. data/vendor/assets/stylesheets/mercury/mercury.css +12 -0
  79. data/vendor/assets/stylesheets/mercury/modal.css +0 -12
  80. data/vendor/assets/stylesheets/mercury/toolbar.css +1 -0
  81. data/vendor/assets/stylesheets/mercury_overrides.css +17 -0
  82. metadata +73 -45
  83. data/app/views/mercury/lightviews/imageprocessor.html +0 -3
  84. data/app/views/mercury/modals/sanitizer.html +0 -9
  85. data/features/editing/basic.feature +0 -11
  86. data/vendor/assets/images/mercury/clippy.png +0 -0
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
@@ -5,8 +5,8 @@ When /^(?:|I )sleep for (\d+) seconds?$/ do |seconds|
5
5
  sleep(seconds.to_i)
6
6
  end
7
7
 
8
- When /^I debug?$/ do
9
- put 'Debugging...'
8
+ When /^I debug$/ do
9
+ puts 'Debugging...'
10
10
  unless ENV['RUBYMINE'].present?
11
11
  require 'debug'
12
12
  debugger
@@ -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