mercury-rails 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/app/assets/images/mercury/toolbar/primary/tools.png +0 -0
  2. data/app/assets/images/mercury/toolbar/primary/user.png +0 -0
  3. data/app/assets/javascripts/mercury/dialogs/snippetpanel.js.coffee +1 -1
  4. data/app/assets/javascripts/mercury/lightview.js.coffee +11 -4
  5. data/app/assets/javascripts/mercury/locales/ar.locale.js.coffee +0 -4
  6. data/app/assets/javascripts/mercury/locales/da.locale.js.coffee +0 -4
  7. data/app/assets/javascripts/mercury/locales/de.locale.js.coffee +0 -4
  8. data/app/assets/javascripts/mercury/locales/es.locale.js.coffee +0 -4
  9. data/app/assets/javascripts/mercury/locales/example.local.js.coffee +0 -4
  10. data/app/assets/javascripts/mercury/locales/fr.locale.js.coffee +0 -4
  11. data/app/assets/javascripts/mercury/locales/hu.locale.js.coffee +209 -0
  12. data/app/assets/javascripts/mercury/locales/it.locale.js.coffee +0 -4
  13. data/app/assets/javascripts/mercury/locales/ko.local.js.coffee +0 -4
  14. data/app/assets/javascripts/mercury/locales/nl.locale.js.coffee +0 -4
  15. data/app/assets/javascripts/mercury/locales/pt.locale.js.coffee +0 -4
  16. data/app/assets/javascripts/mercury/locales/ru.locale.js.coffee +200 -0
  17. data/app/assets/javascripts/mercury/locales/sv.local.js.coffee +0 -4
  18. data/app/assets/javascripts/mercury/locales/swedish_chef.locale.js.coffee +0 -4
  19. data/app/assets/javascripts/mercury/locales/zh.local.js.coffee +0 -4
  20. data/app/assets/javascripts/mercury/mercury-compiled.js +10720 -0
  21. data/app/assets/javascripts/mercury/mercury.js.coffee +1 -1
  22. data/app/assets/javascripts/mercury/modal.js.coffee +14 -7
  23. data/app/assets/javascripts/mercury/modals/htmleditor.js.coffee +1 -1
  24. data/app/assets/javascripts/mercury/modals/insertmedia.js.coffee +2 -0
  25. data/app/assets/javascripts/mercury/modals/inserttable.js.coffee +10 -4
  26. data/app/assets/javascripts/mercury/page_editor.js.coffee +9 -9
  27. data/app/assets/javascripts/mercury/palette.js.coffee +1 -1
  28. data/app/assets/javascripts/mercury/panel.js.coffee +1 -0
  29. data/app/assets/javascripts/mercury/region.js.coffee +3 -3
  30. data/app/assets/javascripts/mercury/regions/{full.coffee → full.js.coffee} +2 -2
  31. data/app/assets/javascripts/mercury/regions/{markdown.coffee → markdown.js.coffee} +7 -1
  32. data/app/assets/javascripts/mercury/regions/snippets.js.coffee +1 -1
  33. data/app/assets/javascripts/mercury/select.js.coffee +1 -1
  34. data/app/assets/javascripts/mercury/snippet.js.coffee +40 -21
  35. data/app/assets/javascripts/mercury/toolbar.button.js.coffee +35 -20
  36. data/app/assets/javascripts/mercury/toolbar.expander.js.coffee +4 -3
  37. data/app/assets/javascripts/mercury/toolbar.js.coffee +6 -2
  38. data/app/assets/stylesheets/_mercury-bootstrap-overrides.scss +61 -0
  39. data/app/assets/stylesheets/_mercury-sass.scss +33 -0
  40. data/app/assets/stylesheets/mercury.css +1 -0
  41. data/app/assets/stylesheets/mercury/all_images.css.erb +4 -0
  42. data/app/assets/stylesheets/mercury/dialog.css +5 -2
  43. data/app/assets/stylesheets/mercury/mercury.css +0 -1
  44. data/app/assets/stylesheets/mercury/toolbar.css +3 -0
  45. data/app/assets/stylesheets/mercury/uploader.css +1 -1
  46. data/app/views/mercury/modals/media.html +10 -0
  47. data/app/views/mercury/panels/snippets.html +6 -1
  48. data/app/views/mercury/snippets/example/options.html.erb +1 -1
  49. data/app/views/mercury/snippets/no_options/preview.html.erb +1 -0
  50. data/features/loading/loading.feature +1 -1
  51. data/features/regions/full/basic_editing.feature +2 -2
  52. data/features/regions/full/inserting_media.feature +18 -0
  53. data/features/regions/full/inserting_snippets.feature +11 -0
  54. data/features/step_definitions/custom_web_steps.rb +22 -0
  55. data/features/step_definitions/mercury_steps.rb +1 -439
  56. data/features/support/selectors.rb +23 -0
  57. data/lib/generators/mercury/install/images/templates/ar_paperclip_image.rb +2 -0
  58. data/lib/mercury/cucumber/step_definitions.rb +13 -0
  59. data/lib/mercury/cucumber/step_definitions/mercury_steps.rb +408 -0
  60. data/{features → lib/mercury/cucumber}/support/mercury_contents.rb +1 -1
  61. data/{features → lib/mercury/cucumber}/support/mercury_selectors.rb +0 -20
  62. data/lib/mercury/rails.rb +1 -0
  63. data/lib/mercury/version.rb +1 -1
  64. data/spec/dummy/config/application.rb +4 -1
  65. data/spec/dummy/config/database.yml +10 -0
  66. data/spec/dummy/db/.gitkeep +0 -0
  67. data/spec/dummy/public/index.html +13 -2
  68. data/spec/javascripts/mercury/lightview_spec.js.coffee +33 -1
  69. data/spec/javascripts/mercury/modal_spec.js.coffee +35 -3
  70. data/spec/javascripts/mercury/modals/htmleditor_spec.js.coffee +1 -1
  71. data/spec/javascripts/mercury/modals/insertmedia_spec.js.coffee +6 -2
  72. data/spec/javascripts/mercury/modals/inserttable_spec.js.coffee +10 -0
  73. data/spec/javascripts/mercury/page_editor_spec.js.coffee +6 -5
  74. data/spec/javascripts/mercury/region_spec.js.coffee +4 -0
  75. data/spec/javascripts/mercury/snippet_spec.js.coffee +65 -21
  76. data/spec/javascripts/mercury/toolbar_spec.js.coffee +22 -0
  77. data/spec/javascripts/templates/mercury/modals/insertmedia.html +10 -0
  78. metadata +26 -16
  79. data/spec/dummy/config/database.example.yml +0 -25
  80. data/spec/dummy/config/database.travisci.yml +0 -4
@@ -39,6 +39,29 @@ module HtmlSelectorsHelpers
39
39
  "Now, go and add a mapping in #{__FILE__}"
40
40
  end
41
41
  end
42
+
43
+ def region_selector_for(locator)
44
+ return '#full_1' if locator.blank? || locator == 'the region'
45
+ case locator.downcase
46
+
47
+ when 'the first full region', 'the full region' then '#full_1'
48
+ when 'the first markdown region', 'the markdown region' then '#markdown_1'
49
+ when 'the first snippets region', 'the first snippet region', 'the snippets region', 'the snippet region' then '#snippets_1'
50
+
51
+ else locator
52
+ end
53
+ end
54
+
55
+ def snippet_name_for(locator)
56
+ case locator.downcase
57
+
58
+ when 'the example snippet' then 'example'
59
+ when 'the snippet with no options' then 'no_options'
60
+
61
+ else locator
62
+ end
63
+ end
64
+
42
65
  end
43
66
 
44
67
  World(HtmlSelectorsHelpers)
@@ -2,6 +2,8 @@ class Mercury::Image < ActiveRecord::Base
2
2
 
3
3
  self.table_name = :mercury_images
4
4
 
5
+ attr_accessible :image
6
+
5
7
  has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" },
6
8
  :path => ":rails_root/public/system/:attachment/:id/:style/:filename",
7
9
  :url => "/system/:attachment/:id/:style/:filename"
@@ -0,0 +1,13 @@
1
+ require 'xpath'
2
+
3
+ World(ActionController::RecordIdentifier)
4
+
5
+ # require support files
6
+ Dir[File.join(File.dirname(__FILE__), 'support', '*')].each do |file|
7
+ require file
8
+ end
9
+
10
+ # require the common step defintions
11
+ Dir[File.join(File.dirname(__FILE__), 'step_definitions', '*')].each do |file|
12
+ require file
13
+ end
@@ -0,0 +1,408 @@
1
+ ## Mercury general steps
2
+ #------------------------------------------------------------------------------
3
+ Given /^(?:|I )adjust the configuration to have: \{([^\}]*)\}$/ do |javascript|
4
+ Rails.application.config.mercury_config = JSON.parse("{#{javascript}}")
5
+ end
6
+
7
+ # scoping step for the mercury content frame
8
+ When /^(.*) in the content frame$/ do |s|
9
+ page.driver.within_frame('mercury_iframe') do
10
+ step(s)
11
+ end
12
+ end
13
+
14
+ # silence mercury's onbeforeunload confirmation
15
+ Given /^the editor won't prompt when leaving the page$/ do
16
+ page.driver.execute_script('Mercury.silent = true;')
17
+ end
18
+
19
+
20
+ ## Toolbar specific steps
21
+ #------------------------------------------------------------------------------
22
+ # for the select dropdowns
23
+ When /^(?:|I )select (.*?) from the dropdown$/ do |locator|
24
+ selector = selector_for(locator)
25
+ find(selector, :message => "Unable to locate the element '#{selector}' to click on").click
26
+ end
27
+
28
+
29
+ ## Panel specific steps
30
+ #------------------------------------------------------------------------------
31
+ When /^(?:I )(?:open|close|toggle) the (.*?) panel$/ do |panel_locator|
32
+ step(%Q{I click on the "#{panel_locator}" button})
33
+ end
34
+
35
+
36
+ ## Modal specific steps
37
+ #------------------------------------------------------------------------------
38
+ When /^(?:I )close the modal(?: window)?$/ do
39
+ step(%Q{I click on the modal close button})
40
+ end
41
+
42
+
43
+ ## Region specific steps
44
+ #------------------------------------------------------------------------------
45
+ # setting content
46
+ Given /^the content of (.*?) (?:is|are|has|includes) (.*?)$/ do |region_locator, contents|
47
+ step(%Q{I set the contents of #{region_locator} to #{contents}})
48
+ end
49
+
50
+ When /^(?:|I )(?:change|set) the contents? of (.*?) to (.*?)$/ do |region_locator, contents|
51
+ region_id = region_selector_for(region_locator).gsub('#', '')
52
+ content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
53
+ page.driver.within_frame('mercury_iframe') do
54
+ find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
55
+ page.driver.execute_script <<-JAVASCRIPT
56
+ var element = top.jQuery(document).find('##{region_id}');
57
+ if (element.data('type') == 'markdown') {
58
+ element.find('textarea').val(#{content});
59
+ } else {
60
+ var region = top.mercuryInstance.getRegionByName('#{region_id}');
61
+ region.content(#{content});
62
+ }
63
+ JAVASCRIPT
64
+ end
65
+ end
66
+
67
+ When /^(?:|I )focus on (.*?)$/ do |region_locator|
68
+ step(%Q{I can simulate complex javascript events})
69
+ region_selector = region_selector_for(region_locator)
70
+ page.driver.within_frame('mercury_iframe') do
71
+ page.driver.execute_script <<-JAVASCRIPT
72
+ top.jQuery(document).find('#{region_selector}').simulate('mouseup')
73
+ JAVASCRIPT
74
+ end
75
+ end
76
+
77
+ # setting/making selections
78
+ When /^(?:|I )(?:make|have) a selection$/ do
79
+ step(%Q{I have a selection for "span"})
80
+ end
81
+
82
+ When /^(?:|I )(?:make|have) a selection (?:in (.*?) )?for "([^"]*)"$/ do |region_locator, selector|
83
+ step(%Q{I can simulate complex javascript events})
84
+ # assume the first full region if one wasn't provided'
85
+ region_selector = region_selector_for(region_locator)
86
+ page.driver.within_frame('mercury_iframe') do
87
+ find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
88
+ find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_locator}'")
89
+ page.driver.execute_script <<-JAVASCRIPT
90
+ var element = top.jQuery(document).find('#{region_selector}');
91
+ if (element.data('type') == 'markdown') {
92
+ alert('unimplemented');
93
+ throw('unimplemented');
94
+ } else {
95
+ var selectedElement = element.find('#{selector}');
96
+ var selection = new top.Mercury.Regions.Full.Selection(window.getSelection(), document);
97
+ selection.selectNode(selectedElement.get(0));
98
+ selectedElement.simulate('mouseup');
99
+ }
100
+ JAVASCRIPT
101
+ end
102
+ end
103
+
104
+ # other events
105
+ When /^(?:|I )double click on (.*?) in (.*?)$/ do |locator, region_locator|
106
+ step(%Q{I can simulate complex javascript events})
107
+ selector = selector_for(locator)
108
+ # assume the first full region if one wasn't provided'
109
+ region_selector = region_selector_for(region_locator)
110
+ page.driver.within_frame('mercury_iframe') do
111
+ find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
112
+ find("#{region_selector} #{selector}", :message => "Unable to locate a match for '#{selector}' inside '#{region_selector}'")
113
+ page.driver.execute_script <<-JAVASCRIPT
114
+ top.jQuery(document).find('#{region_selector} #{selector}').simulate('dblclick');
115
+ JAVASCRIPT
116
+ end
117
+ end
118
+
119
+ # getting contents
120
+ Then /^the contents? of (.*?) should be "([^"]*)"$/ do |region_locator, content|
121
+ region_selector = region_selector_for(region_locator)
122
+ page.driver.within_frame('mercury_iframe') do
123
+ find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
124
+ results = page.driver.execute_script <<-JAVASCRIPT
125
+ var element = top.jQuery(document).find('#{region_selector}');
126
+ if (element.data('type') == 'markdown') {
127
+ return element.find('textarea').val();
128
+ } else {
129
+ return element.html();
130
+ }
131
+ JAVASCRIPT
132
+ assert_equal content, results.gsub('"', "'").gsub("\n", '')
133
+ end
134
+ end
135
+
136
+
137
+ ## Saving specific steps
138
+ #------------------------------------------------------------------------------
139
+ # caching for the last save -- a request will still be made
140
+ Given /^save results will be cached$/ do
141
+ page.driver.execute_script <<-JAVASCRIPT
142
+ Mercury.PageEditor.prototype.save = function() {
143
+ window.cachedResults = this.serialize();
144
+ Mercury.changes = false;
145
+ }
146
+ JAVASCRIPT
147
+ end
148
+
149
+ # check for the last save cached results
150
+ Then /^the save should have (.*?) for (.*?)$/ do |contents, region_locator|
151
+ region_id = region_selector_for(region_locator).gsub('#', '')
152
+ content = contents[0] == '"' ? contents : "\"#{contents_for(contents)}\""
153
+ results = page.driver.execute_script <<-JAVASCRIPT
154
+ return (window.cachedResults['#{region_id}']) ?
155
+ window.cachedResults['#{region_id}']['value'] : null;
156
+ JAVASCRIPT
157
+ assert_equal content, "\"#{results}\""
158
+ end
159
+
160
+
161
+ ## Table editing specific steps
162
+ #------------------------------------------------------------------------------
163
+ # in the modal window
164
+ When /^(?:|I )(?:add|insert) a (row|column) (before|after)(?: it)?$/ do |row_or_column, before_or_after|
165
+ name = "add_#{row_or_column}_#{before_or_after}".camelcase(:lower)
166
+ step(%Q{I click on ".mercury-modal-content button[data-action='#{name}']"})
167
+ end
168
+
169
+ When /^(?:|I )delete the(?: current)? (row|column)$/ do |row_or_column|
170
+ name = "remove_#{row_or_column}".camelcase(:lower)
171
+ step(%Q{I click on ".mercury-modal-content button[data-action='#{name}']"})
172
+ end
173
+
174
+ When /^(?:|I )(increase|decrease) the (rowspan|colspan)$/ do |increase_or_decrease, rowspan_or_colspan|
175
+ name = "#{increase_or_decrease}_#{rowspan_or_colspan}".camelcase(:lower)
176
+ step(%Q{I click on ".mercury-modal-content button[data-action=#{name}]"})
177
+ end
178
+
179
+ Then /^the selected cell should be (.*?)$/ do |locator|
180
+ selector = selector_for(locator).gsub('td:', 'td.selected:')
181
+ find("#{selector}", :message => "Unable to locate the selected cell for '#{selector}'")
182
+ end
183
+
184
+ # in general
185
+ Then /^the(?: table)? (row|column) count should be (\d+)$/ do |row_or_column, expected_count|
186
+ method = "get_#{row_or_column}_count".camelcase(:lower)
187
+ actual_count = page.driver.execute_script("return Mercury.tableEditor.#{method}()")
188
+ assert_equal expected_count.to_i, actual_count.to_i
189
+ end
190
+
191
+
192
+ ## Snippet specific steps
193
+ #------------------------------------------------------------------------------
194
+ # setting snippet options
195
+ Given /^the options for the (.*?) snippet "([^"]*)" are (.*?)$/ do |snippet_name, snippet_id, options|
196
+ @snippet_id = snippet_id
197
+ options_json = parse_snippet_options_from(options)
198
+ page.driver.execute_script <<-JAVASCRIPT
199
+ Mercury.Snippet.load({#{snippet_id}: {name: '#{snippet_name}', options: #{options_json}}});
200
+ JAVASCRIPT
201
+ end
202
+
203
+ # dragging/dropping
204
+ When /^(?:|I )(?:drag|drop) (.*?) (?:into|on) (.*?)$/ do |snippet_locator, region_locator|
205
+ snippet_name = snippet_name_for(snippet_locator)
206
+ region_id = region_selector_for(region_locator).gsub('#', '')
207
+ page.driver.within_frame('mercury_iframe') do
208
+ find("##{region_id}", :message => "Unable to locate a region matching '##{region_id}'")
209
+ data = " data-snippet=\"#{snippet_name}\""
210
+ data << ' data-options="false"' if snippet_name == 'no_options'
211
+
212
+ page.driver.execute_script <<-JAVASCRIPT
213
+ var element = top.jQuery(document).find('##{region_id}');
214
+ if (element.data('type') == 'markdown') {
215
+ alert('unimplemented');
216
+ throw('unimplemented');
217
+ } else {
218
+ var region = top.mercuryInstance.getRegionByName('#{region_id}');
219
+ region.selection().range.collapse(true);
220
+ document.execCommand('insertHTML', false, '<img #{data} src="/assets/mercury/default-snippet.png">');
221
+ element.trigger('possible:drop');
222
+ }
223
+ JAVASCRIPT
224
+ end
225
+ end
226
+
227
+ When /^(?:|I )hover over (.*?)(?: in (.*?))?$/ do |locator, region_locator|
228
+ step(%Q{I can simulate complex javascript events})
229
+ selector = selector_for(locator)
230
+ region_selector = region_selector_for(region_locator)
231
+ page.driver.within_frame('mercury_iframe') do
232
+ find("#{region_selector}", :message => "Unable to locate a region matching '#{region_selector}'")
233
+ page.driver.execute_script <<-JAVASCRIPT
234
+ var element = top.jQuery(document).find('#{region_selector}');
235
+ if (element.data('type') == 'markdown') {
236
+ alert('unimplemented');
237
+ throw('unimplemented');
238
+ } else {
239
+ element.find('#{selector}').simulate('mousemove');
240
+ }
241
+ JAVASCRIPT
242
+ end
243
+ end
244
+
245
+ When /^(?:|I )edit the snippet$/ do
246
+ step(%{I hover over the snippet})
247
+ step(%{I click on the edit snippet settings toolbar button})
248
+ end
249
+
250
+
251
+ ## Javascript event simulation steps
252
+ #------------------------------------------------------------------------------
253
+ Given /^(?:|I )can simulate complex javascript events$/ do
254
+ page.driver.execute_script(JQUERY_EVENT_SIMULATION_JAVASCRIPT)
255
+ end
256
+
257
+ #------------------------------------------------------------------------------
258
+
259
+ JQUERY_EVENT_SIMULATION_JAVASCRIPT = <<-JAVASCRIPT
260
+ /*
261
+ * jquery.simulate - simulate browser mouse and keyboard events
262
+ *
263
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
264
+ * Dual licensed under the MIT or GPL Version 2 licenses.
265
+ * http://jquery.org/license
266
+ *
267
+ */
268
+ ;(function($) {
269
+
270
+ $.fn.extend({
271
+ simulate: function(type, options) {
272
+ return this.each(function() {
273
+ var opt = $.extend({}, $.simulate.defaults, options || {});
274
+ new $.simulate(this, type, opt);
275
+ });
276
+ }
277
+ });
278
+
279
+ $.simulate = function(el, type, options) {
280
+ this.target = el;
281
+ this.options = options;
282
+
283
+ if (/^drag$/.test(type)) {
284
+ this[type].apply(this, [this.target, options]);
285
+ } else {
286
+ this.simulateEvent(el, type, options);
287
+ }
288
+ }
289
+
290
+ $.extend($.simulate.prototype, {
291
+ simulateEvent: function(el, type, options) {
292
+ var evt = this.createEvent(type, options);
293
+ this.dispatchEvent(el, type, evt, options);
294
+ return evt;
295
+ },
296
+ createEvent: function(type, options) {
297
+ if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) {
298
+ return this.mouseEvent(type, options);
299
+ } else if (/^key(up|down|press)$/.test(type)) {
300
+ return this.keyboardEvent(type, options);
301
+ }
302
+ },
303
+ mouseEvent: function(type, options) {
304
+ var evt;
305
+ var e = $.extend({
306
+ bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0,
307
+ screenX: 0, screenY: 0, clientX: 0, clientY: 0,
308
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
309
+ button: 0, relatedTarget: undefined
310
+ }, options);
311
+
312
+ var relatedTarget = $(e.relatedTarget)[0];
313
+
314
+ if ($.isFunction(document.createEvent)) {
315
+ evt = document.createEvent("MouseEvents");
316
+ evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
317
+ e.screenX, e.screenY, e.clientX, e.clientY,
318
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
319
+ e.button, e.relatedTarget || document.body.parentNode);
320
+ } else if (document.createEventObject) {
321
+ evt = document.createEventObject();
322
+ $.extend(evt, e);
323
+ evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
324
+ }
325
+ return evt;
326
+ },
327
+ keyboardEvent: function(type, options) {
328
+ var evt;
329
+
330
+ var e = $.extend({ bubbles: true, cancelable: true, view: window,
331
+ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
332
+ keyCode: 0, charCode: 0
333
+ }, options);
334
+
335
+ if ($.isFunction(document.createEvent)) {
336
+ try {
337
+ evt = document.createEvent("KeyEvents");
338
+ evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view,
339
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
340
+ e.keyCode, e.charCode);
341
+ } catch(err) {
342
+ evt = document.createEvent("Events");
343
+ evt.initEvent(type, e.bubbles, e.cancelable);
344
+ $.extend(evt, { view: e.view,
345
+ ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey,
346
+ keyCode: e.keyCode, charCode: e.charCode
347
+ });
348
+ }
349
+ } else if (document.createEventObject) {
350
+ evt = document.createEventObject();
351
+ $.extend(evt, e);
352
+ }
353
+ if ($.browser.msie || $.browser.opera) {
354
+ evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode;
355
+ evt.charCode = undefined;
356
+ }
357
+ return evt;
358
+ },
359
+ dispatchEvent: function(el, type, evt) {
360
+ if (el.dispatchEvent) {
361
+ el.dispatchEvent(evt);
362
+ } else if (el.fireEvent) {
363
+ el.fireEvent('on' + type, evt);
364
+ }
365
+ return evt;
366
+ },
367
+ drag: function(el) {
368
+ var self = this, center = this.findCenter(this.target),
369
+ options = this.options, x = Math.floor(center.x), y = Math.floor(center.y),
370
+ dx = options.dx || 0, dy = options.dy || 0, target = this.target;
371
+ var coord = { clientX: x, clientY: y };
372
+ this.simulateEvent(target, "mousedown", coord);
373
+ coord = { clientX: x + 1, clientY: y + 1 };
374
+ this.simulateEvent(document, "mousemove", coord);
375
+ coord = { clientX: x + dx, clientY: y + dy };
376
+ this.simulateEvent(document, "mousemove", coord);
377
+ this.simulateEvent(document, "mousemove", coord);
378
+ this.simulateEvent(target, "mouseup", coord);
379
+ this.simulateEvent(target, "click", coord);
380
+ },
381
+ findCenter: function(el) {
382
+ var el = $(this.target), o = el.offset(), d = $(document);
383
+ return {
384
+ x: o.left + el.outerWidth() / 2 - d.scrollLeft(),
385
+ y: o.top + el.outerHeight() / 2 - d.scrollTop()
386
+ };
387
+ }
388
+ });
389
+
390
+ $.extend($.simulate, {
391
+ defaults: {
392
+ speed: 'sync'
393
+ },
394
+ VK_TAB: 9,
395
+ VK_ENTER: 13,
396
+ VK_ESC: 27,
397
+ VK_PGUP: 33,
398
+ VK_PGDN: 34,
399
+ VK_END: 35,
400
+ VK_HOME: 36,
401
+ VK_LEFT: 37,
402
+ VK_UP: 38,
403
+ VK_RIGHT: 39,
404
+ VK_DOWN: 40
405
+ });
406
+
407
+ })(jQuery);
408
+ JAVASCRIPT