kiteditor 1.0.1

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