mercury-rails 0.2.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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