mercury-rails 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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