kuji-mercury-rails 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. data/LICENSE +25 -0
  2. data/POST_INSTALL +15 -0
  3. data/app/controllers/mercury/images_controller.rb +19 -0
  4. data/app/controllers/mercury_controller.rb +34 -0
  5. data/app/models/mercury/image.rb +16 -0
  6. data/app/views/layouts/mercury.html.erb +33 -0
  7. data/app/views/mercury/lightviews/about.html +11 -0
  8. data/app/views/mercury/modals/character.html +255 -0
  9. data/app/views/mercury/modals/htmleditor.html +13 -0
  10. data/app/views/mercury/modals/link.html +75 -0
  11. data/app/views/mercury/modals/media.html +82 -0
  12. data/app/views/mercury/modals/table.html +84 -0
  13. data/app/views/mercury/palettes/backcolor.html +73 -0
  14. data/app/views/mercury/palettes/forecolor.html +73 -0
  15. data/app/views/mercury/panels/history.html +3 -0
  16. data/app/views/mercury/panels/notes.html +3 -0
  17. data/app/views/mercury/panels/snippets.html +12 -0
  18. data/app/views/mercury/selects/formatblock.html +11 -0
  19. data/app/views/mercury/selects/style.html +5 -0
  20. data/app/views/mercury/snippets/example/options.html.erb +34 -0
  21. data/app/views/mercury/snippets/example/preview.html.erb +1 -0
  22. data/config/engine.rb +41 -0
  23. data/db/migrate/20110526035601_create_mercury_images.rb +11 -0
  24. data/features/loading/loading.feature +22 -0
  25. data/features/loading/navigating.feature +77 -0
  26. data/features/loading/user_interface.feature +67 -0
  27. data/features/regions/editable/advanced_editing.feature +0 -0
  28. data/features/regions/editable/basic_editing.feature +195 -0
  29. data/features/regions/editable/inserting_links.feature +98 -0
  30. data/features/regions/editable/inserting_media.feature +110 -0
  31. data/features/regions/editable/inserting_snippets.feature +102 -0
  32. data/features/regions/editable/inserting_special_characters.feature +24 -0
  33. data/features/regions/editable/inserting_tables.feature +109 -0
  34. data/features/regions/editable/pasting.feature +0 -0
  35. data/features/regions/editable/uploading_images.feature +0 -0
  36. data/features/regions/image/uploading_images.feature +0 -0
  37. data/features/regions/markupable/advanced_editing.feature +0 -0
  38. data/features/regions/markupable/basic_editing.feature +0 -0
  39. data/features/regions/markupable/inserting_links.feature +0 -0
  40. data/features/regions/markupable/inserting_media.feature +0 -0
  41. data/features/regions/markupable/inserting_snippets.feature +0 -0
  42. data/features/regions/markupable/inserting_special_characters.feature +0 -0
  43. data/features/regions/markupable/inserting_tables.feature +0 -0
  44. data/features/regions/markupable/uploading_images.feature +0 -0
  45. data/features/regions/simple/basic_editing.feature +5 -0
  46. data/features/regions/snippetable/advanced_editing.feature +0 -0
  47. data/features/regions/snippetable/basic_editing.feature +0 -0
  48. data/features/regions/snippetable/inserting_snippets.feature +0 -0
  49. data/features/saving/saving.feature +33 -0
  50. data/features/step_definitions/debug_steps.rb +14 -0
  51. data/features/step_definitions/mercury_steps.rb +438 -0
  52. data/features/step_definitions/web_steps.rb +211 -0
  53. data/features/support/env.rb +46 -0
  54. data/features/support/mercury_contents.rb +25 -0
  55. data/features/support/mercury_selectors.rb +148 -0
  56. data/features/support/paths.rb +38 -0
  57. data/features/support/selectors.rb +44 -0
  58. data/lib/generators/mercury/install/install_generator.rb +49 -0
  59. data/lib/generators/mercury/install/templates/mongoid_paperclip_image.rb +17 -0
  60. data/lib/mercury-rails.rb +3 -0
  61. data/lib/mercury/authentication.rb +8 -0
  62. data/spec/javascripts/mercury/dialog_spec.js.coffee +281 -0
  63. data/spec/javascripts/mercury/dialogs/backcolor_spec.js.coffee +37 -0
  64. data/spec/javascripts/mercury/dialogs/forecolor_spec.js.coffee +37 -0
  65. data/spec/javascripts/mercury/dialogs/formatblock_spec.js.coffee +25 -0
  66. data/spec/javascripts/mercury/dialogs/snippetpanel_spec.js.coffee +30 -0
  67. data/spec/javascripts/mercury/dialogs/style_spec.js.coffee +25 -0
  68. data/spec/javascripts/mercury/history_buffer_spec.js.coffee +76 -0
  69. data/spec/javascripts/mercury/lightview_spec.js.coffee +497 -0
  70. data/spec/javascripts/mercury/mercury_spec.js.coffee +132 -0
  71. data/spec/javascripts/mercury/modal_spec.js.coffee +504 -0
  72. data/spec/javascripts/mercury/modals/htmleditor_spec.js.coffee +30 -0
  73. data/spec/javascripts/mercury/modals/insertcharacter_spec.js.coffee +29 -0
  74. data/spec/javascripts/mercury/modals/insertlink_spec.js.coffee +220 -0
  75. data/spec/javascripts/mercury/modals/insertmedia_spec.js.coffee +167 -0
  76. data/spec/javascripts/mercury/modals/insertsnippet_spec.js.coffee +52 -0
  77. data/spec/javascripts/mercury/modals/inserttable_spec.js.coffee +160 -0
  78. data/spec/javascripts/mercury/native_extensions_spec.js.coffee +60 -0
  79. data/spec/javascripts/mercury/page_editor_spec.js.coffee +757 -0
  80. data/spec/javascripts/mercury/palette_spec.js.coffee +49 -0
  81. data/spec/javascripts/mercury/panel_spec.js.coffee +183 -0
  82. data/spec/javascripts/mercury/region_spec.js.coffee +298 -0
  83. data/spec/javascripts/mercury/regions/editable_spec.js.coffee +561 -0
  84. data/spec/javascripts/mercury/regions/image_spec.js.coffee +34 -0
  85. data/spec/javascripts/mercury/regions/markupable_spec.js.coffee +367 -0
  86. data/spec/javascripts/mercury/regions/simple_spec.js.coffee +33 -0
  87. data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +370 -0
  88. data/spec/javascripts/mercury/select_spec.js.coffee +49 -0
  89. data/spec/javascripts/mercury/snippet_spec.js.coffee +253 -0
  90. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +184 -0
  91. data/spec/javascripts/mercury/statusbar_spec.js.coffee +150 -0
  92. data/spec/javascripts/mercury/table_editor_spec.js.coffee +194 -0
  93. data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +90 -0
  94. data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +360 -0
  95. data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +118 -0
  96. data/spec/javascripts/mercury/toolbar_spec.js.coffee +222 -0
  97. data/spec/javascripts/mercury/tooltip_spec.js.coffee +186 -0
  98. data/spec/javascripts/mercury/uploader_spec.js.coffee +530 -0
  99. data/spec/javascripts/spec_helper.js +513 -0
  100. data/spec/javascripts/templates/mercury/dialog.html +2 -0
  101. data/spec/javascripts/templates/mercury/dialogs/backcolor.html +5 -0
  102. data/spec/javascripts/templates/mercury/dialogs/forecolor.html +5 -0
  103. data/spec/javascripts/templates/mercury/dialogs/formatblock.html +3 -0
  104. data/spec/javascripts/templates/mercury/dialogs/snippetpanel.html +16 -0
  105. data/spec/javascripts/templates/mercury/dialogs/style.html +3 -0
  106. data/spec/javascripts/templates/mercury/lightview.html +13 -0
  107. data/spec/javascripts/templates/mercury/modal.html +13 -0
  108. data/spec/javascripts/templates/mercury/modals/htmleditor.html +5 -0
  109. data/spec/javascripts/templates/mercury/modals/insertcharacter.html +5 -0
  110. data/spec/javascripts/templates/mercury/modals/insertlink.html +30 -0
  111. data/spec/javascripts/templates/mercury/modals/insertmedia.html +35 -0
  112. data/spec/javascripts/templates/mercury/modals/insertsnippet.html +6 -0
  113. data/spec/javascripts/templates/mercury/modals/inserttable.html +27 -0
  114. data/spec/javascripts/templates/mercury/page_editor.html +35 -0
  115. data/spec/javascripts/templates/mercury/palette.html +16 -0
  116. data/spec/javascripts/templates/mercury/panel.html +16 -0
  117. data/spec/javascripts/templates/mercury/region.html +2 -0
  118. data/spec/javascripts/templates/mercury/regions/editable.html +3 -0
  119. data/spec/javascripts/templates/mercury/regions/image.html +1 -0
  120. data/spec/javascripts/templates/mercury/regions/simple.html +3 -0
  121. data/spec/javascripts/templates/mercury/regions/snippetable.html +4 -0
  122. data/spec/javascripts/templates/mercury/select.html +16 -0
  123. data/spec/javascripts/templates/mercury/snippet.html +1 -0
  124. data/spec/javascripts/templates/mercury/snippet_toolbar.html +16 -0
  125. data/spec/javascripts/templates/mercury/statusbar.html +8 -0
  126. data/spec/javascripts/templates/mercury/table_editor.html +65 -0
  127. data/spec/javascripts/templates/mercury/toolbar.button.html +64 -0
  128. data/spec/javascripts/templates/mercury/toolbar.button_group.html +9 -0
  129. data/spec/javascripts/templates/mercury/toolbar.expander.html +18 -0
  130. data/spec/javascripts/templates/mercury/toolbar.html +11 -0
  131. data/spec/javascripts/templates/mercury/tooltip.html +12 -0
  132. data/spec/javascripts/templates/mercury/uploader.html +11 -0
  133. data/vendor/assets/images/mercury/button.png +0 -0
  134. data/vendor/assets/images/mercury/close.png +0 -0
  135. data/vendor/assets/images/mercury/default-snippet.png +0 -0
  136. data/vendor/assets/images/mercury/loading-dark.gif +0 -0
  137. data/vendor/assets/images/mercury/loading-light.gif +0 -0
  138. data/vendor/assets/images/mercury/missing-image.png +0 -0
  139. data/vendor/assets/images/mercury/search-icon.png +0 -0
  140. data/vendor/assets/images/mercury/temp-logo.png +0 -0
  141. data/vendor/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  142. data/vendor/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  143. data/vendor/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
  144. data/vendor/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
  145. data/vendor/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
  146. data/vendor/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
  147. data/vendor/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
  148. data/vendor/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
  149. data/vendor/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
  150. data/vendor/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
  151. data/vendor/assets/images/mercury/toolbar/primary/preview.png +0 -0
  152. data/vendor/assets/images/mercury/toolbar/primary/redo.png +0 -0
  153. data/vendor/assets/images/mercury/toolbar/primary/save.png +0 -0
  154. data/vendor/assets/images/mercury/toolbar/primary/snippetpanel.png +0 -0
  155. data/vendor/assets/images/mercury/toolbar/primary/undo.png +0 -0
  156. data/vendor/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  157. data/vendor/assets/javascripts/mercury.js +479 -0
  158. data/vendor/assets/javascripts/mercury/dependencies/jquery-1.7.js +9300 -0
  159. data/vendor/assets/javascripts/mercury/dependencies/jquery-ui-1.8.13.custom.js +1328 -0
  160. data/vendor/assets/javascripts/mercury/dependencies/jquery.additions.js +206 -0
  161. data/vendor/assets/javascripts/mercury/dependencies/jquery.htmlClean.js +527 -0
  162. data/vendor/assets/javascripts/mercury/dependencies/liquidmetal.js +88 -0
  163. data/vendor/assets/javascripts/mercury/dependencies/showdown.js +1340 -0
  164. data/vendor/assets/javascripts/mercury/dialog.js.coffee +159 -0
  165. data/vendor/assets/javascripts/mercury/dialogs/backcolor.js.coffee +6 -0
  166. data/vendor/assets/javascripts/mercury/dialogs/forecolor.js.coffee +6 -0
  167. data/vendor/assets/javascripts/mercury/dialogs/formatblock.js.coffee +4 -0
  168. data/vendor/assets/javascripts/mercury/dialogs/snippetpanel.js.coffee +10 -0
  169. data/vendor/assets/javascripts/mercury/dialogs/style.js.coffee +4 -0
  170. data/vendor/assets/javascripts/mercury/finalize.js.coffee +3 -0
  171. data/vendor/assets/javascripts/mercury/history_buffer.js.coffee +30 -0
  172. data/vendor/assets/javascripts/mercury/lightview.js.coffee +205 -0
  173. data/vendor/assets/javascripts/mercury/locales/ar.locale.js.coffee +207 -0
  174. data/vendor/assets/javascripts/mercury/locales/da.locale.js.coffee +211 -0
  175. data/vendor/assets/javascripts/mercury/locales/de.locale.js.coffee +206 -0
  176. data/vendor/assets/javascripts/mercury/locales/es.locale.js.coffee +211 -0
  177. data/vendor/assets/javascripts/mercury/locales/example.local.js.coffee +211 -0
  178. data/vendor/assets/javascripts/mercury/locales/fr.locale.js.coffee +211 -0
  179. data/vendor/assets/javascripts/mercury/locales/it.locale.js.coffee +208 -0
  180. data/vendor/assets/javascripts/mercury/locales/ko.local.js.coffee +206 -0
  181. data/vendor/assets/javascripts/mercury/locales/nl.locale.js.coffee +206 -0
  182. data/vendor/assets/javascripts/mercury/locales/pt.locale.js.coffee +211 -0
  183. data/vendor/assets/javascripts/mercury/locales/sv.local.js.coffee +209 -0
  184. data/vendor/assets/javascripts/mercury/locales/swedish_chef.locale.js.coffee +213 -0
  185. data/vendor/assets/javascripts/mercury/mercury.js.coffee +109 -0
  186. data/vendor/assets/javascripts/mercury/modal.js.coffee +198 -0
  187. data/vendor/assets/javascripts/mercury/modals/htmleditor.js.coffee +11 -0
  188. data/vendor/assets/javascripts/mercury/modals/insertcharacter.js.coffee +4 -0
  189. data/vendor/assets/javascripts/mercury/modals/insertlink.js.coffee +92 -0
  190. data/vendor/assets/javascripts/mercury/modals/insertmedia.js.coffee +81 -0
  191. data/vendor/assets/javascripts/mercury/modals/insertsnippet.js.coffee +12 -0
  192. data/vendor/assets/javascripts/mercury/modals/inserttable.js.coffee +54 -0
  193. data/vendor/assets/javascripts/mercury/native_extensions.js.coffee +55 -0
  194. data/vendor/assets/javascripts/mercury/page_editor.js.coffee +225 -0
  195. data/vendor/assets/javascripts/mercury/palette.js.coffee +29 -0
  196. data/vendor/assets/javascripts/mercury/panel.js.coffee +115 -0
  197. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/mercury/page_editor.js.coffee +28 -0
  198. data/vendor/assets/javascripts/mercury/plugins/save_as_xml/plugin.js +9 -0
  199. data/vendor/assets/javascripts/mercury/region.js.coffee +107 -0
  200. data/vendor/assets/javascripts/mercury/regions/editable.js.coffee +600 -0
  201. data/vendor/assets/javascripts/mercury/regions/image.js.coffee +114 -0
  202. data/vendor/assets/javascripts/mercury/regions/markupable.js.coffee +398 -0
  203. data/vendor/assets/javascripts/mercury/regions/simple.js.coffee +325 -0
  204. data/vendor/assets/javascripts/mercury/regions/snippetable.js.coffee +124 -0
  205. data/vendor/assets/javascripts/mercury/select.js.coffee +44 -0
  206. data/vendor/assets/javascripts/mercury/snippet.js.coffee +106 -0
  207. data/vendor/assets/javascripts/mercury/snippet_toolbar.js.coffee +72 -0
  208. data/vendor/assets/javascripts/mercury/statusbar.js.coffee +51 -0
  209. data/vendor/assets/javascripts/mercury/support/history.js +1 -0
  210. data/vendor/assets/javascripts/mercury/table_editor.js.coffee +265 -0
  211. data/vendor/assets/javascripts/mercury/toolbar.button.js.coffee +173 -0
  212. data/vendor/assets/javascripts/mercury/toolbar.button_group.js.coffee +42 -0
  213. data/vendor/assets/javascripts/mercury/toolbar.expander.js.coffee +56 -0
  214. data/vendor/assets/javascripts/mercury/toolbar.js.coffee +86 -0
  215. data/vendor/assets/javascripts/mercury/tooltip.js.coffee +74 -0
  216. data/vendor/assets/javascripts/mercury/uploader.js.coffee +244 -0
  217. data/vendor/assets/javascripts/mercury_loader.js +193 -0
  218. data/vendor/assets/javascripts/mercury_overrides.js +6 -0
  219. data/vendor/assets/stylesheets/mercury.css +28 -0
  220. data/vendor/assets/stylesheets/mercury/all_images.css.erb +89 -0
  221. data/vendor/assets/stylesheets/mercury/dialog.css +212 -0
  222. data/vendor/assets/stylesheets/mercury/form.css +118 -0
  223. data/vendor/assets/stylesheets/mercury/lightview.css +151 -0
  224. data/vendor/assets/stylesheets/mercury/mercury.css +37 -0
  225. data/vendor/assets/stylesheets/mercury/modal.css +183 -0
  226. data/vendor/assets/stylesheets/mercury/statusbar.css +32 -0
  227. data/vendor/assets/stylesheets/mercury/toolbar.css +304 -0
  228. data/vendor/assets/stylesheets/mercury/tooltip.css +26 -0
  229. data/vendor/assets/stylesheets/mercury/uploader.css +111 -0
  230. data/vendor/assets/stylesheets/mercury_overrides.css +17 -0
  231. metadata +572 -0
@@ -0,0 +1,52 @@
1
+ describe "Mercury.modalHandlers.insertSnippet", ->
2
+
3
+ template 'mercury/modals/insertsnippet.html'
4
+
5
+ beforeEach ->
6
+ Mercury.Snippet.all = []
7
+ Mercury.Snippet.load({
8
+ 'snippet_0': {name: 'foo', options: {'first_name': "Jeremy", 'last_name': "Jackson"}},
9
+ })
10
+ @modal =
11
+ element: $('#test')
12
+ hide: ->
13
+ options: {snippetName: 'test'}
14
+ Mercury.modalHandlers.insertSnippet.call(@modal)
15
+
16
+ describe "submitting", ->
17
+
18
+ it "hides the modal", ->
19
+ spy = spyOn(@modal, 'hide').andCallFake(=>)
20
+ jasmine.simulate.click($('#submit').get(0))
21
+ expect(spy.callCount).toEqual(1)
22
+
23
+ describe "if there's an active snippet", ->
24
+
25
+ beforeEach ->
26
+ Mercury.snippet = Mercury.Snippet.all[0]
27
+
28
+ it "updates the snippet", ->
29
+ spy = spyOn(Mercury.Snippet.prototype, 'setOptions').andCallThrough()
30
+ jasmine.simulate.click($('#submit').get(0))
31
+ expect(spy.callCount).toEqual(1)
32
+ expect(Mercury.Snippet.all[0]['options']).toEqual({first_name: 'Wilma', last_name: 'Flintstone'})
33
+
34
+ it "triggers an action", ->
35
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
36
+ jasmine.simulate.click($('#submit').get(0))
37
+ expect(spy.callCount).toEqual(1)
38
+ expect(spy.argsForCall[0]).toEqual(['action', {action: 'insertSnippet', value: Mercury.Snippet.all[0]}])
39
+
40
+ describe "if there's no active snippet", ->
41
+
42
+ it "creates a snippet", ->
43
+ spy = spyOn(Mercury.Snippet, 'create').andCallThrough()
44
+ jasmine.simulate.click($('#submit').get(0))
45
+ expect(spy.callCount).toEqual(1)
46
+ expect(Mercury.Snippet.all[1]['options']).toEqual({first_name: 'Wilma', last_name: 'Flintstone'})
47
+
48
+ it "triggers an action", ->
49
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
50
+ jasmine.simulate.click($('#submit').get(0))
51
+ expect(spy.callCount).toEqual(1)
52
+ expect(spy.argsForCall[0]).toEqual(['action', {action: 'insertSnippet', value: Mercury.Snippet.all[1]}])
@@ -0,0 +1,160 @@
1
+ describe "Mercury.modalHandlers.insertTable", ->
2
+
3
+ template 'mercury/modals/inserttable.html'
4
+
5
+ beforeEach ->
6
+ @modal =
7
+ element: $('#test')
8
+ hide: ->
9
+
10
+ describe "initializing", ->
11
+
12
+ beforeEach ->
13
+ @tableEditorSpy = spyOn(Mercury, 'tableEditor').andCallFake(=>)
14
+ Mercury.modalHandlers.insertTable.call(@modal)
15
+
16
+ it "selects the first cell", ->
17
+ expect($('#cell1').hasClass('selected')).toEqual(true)
18
+
19
+ it "sets the table editor up", ->
20
+ expect(@tableEditorSpy.callCount).toEqual(1)
21
+ expect(@tableEditorSpy.argsForCall[0][0].get(0)).toEqual($('#table').get(0))
22
+ expect(@tableEditorSpy.argsForCall[0][1].get(0)).toEqual($('#cell1').get(0))
23
+
24
+ describe "clicking on the cells", ->
25
+
26
+ beforeEach ->
27
+ @tableEditorSpy = spyOn(Mercury, 'tableEditor').andCallFake(=>)
28
+ Mercury.modalHandlers.insertTable.call(@modal)
29
+
30
+ it "should unselect any selected cells", ->
31
+ jasmine.simulate.click($('#cell2').get(0))
32
+ expect($('#cell1').hasClass('selected')).toEqual(false)
33
+
34
+ it "selects the cell clicked on", ->
35
+ jasmine.simulate.click($('#cell2').get(0))
36
+ expect($('#cell2').hasClass('selected')).toEqual(true)
37
+
38
+ it "sets the table editor to use the selected cell", ->
39
+ jasmine.simulate.click($('#cell2').get(0))
40
+ expect(@tableEditorSpy.callCount).toEqual(2)
41
+ expect(@tableEditorSpy.argsForCall[1][1].get(0)).toEqual($('#cell2').get(0))
42
+
43
+
44
+ describe "clicking on the action buttons", ->
45
+
46
+ beforeEach ->
47
+ @addRowSpy = spyOn(Mercury.tableEditor, 'addRow').andCallFake(=>)
48
+ @removeRowSpy = spyOn(Mercury.tableEditor, 'removeRow').andCallFake(=>)
49
+ @addColumnSpy = spyOn(Mercury.tableEditor, 'addColumn').andCallFake(=>)
50
+ @removeColumnSpy = spyOn(Mercury.tableEditor, 'removeColumn').andCallFake(=>)
51
+ @increaseColspanSpy = spyOn(Mercury.tableEditor, 'increaseColspan').andCallFake(=>)
52
+ @decreaseColspanSpy = spyOn(Mercury.tableEditor, 'decreaseColspan').andCallFake(=>)
53
+ @increaseRowspanSpy = spyOn(Mercury.tableEditor, 'increaseRowspan').andCallFake(=>)
54
+ @decreaseRowspanSpy = spyOn(Mercury.tableEditor, 'decreaseRowspan').andCallFake(=>)
55
+ Mercury.modalHandlers.insertTable.call(@modal)
56
+
57
+ it "adds a row before the selected cell", ->
58
+ jasmine.simulate.click($('input[name=insertRowBefore]').get(0))
59
+ expect(@addRowSpy.callCount).toEqual(1)
60
+ expect(@addRowSpy.argsForCall[0]).toEqual(['before'])
61
+
62
+ it "adds a row after the selected cell", ->
63
+ jasmine.simulate.click($('input[name=insertRowAfter]').get(0))
64
+ expect(@addRowSpy.callCount).toEqual(1)
65
+ expect(@addRowSpy.argsForCall[0]).toEqual(['after'])
66
+
67
+ it "deletes the row of the selected cell", ->
68
+ jasmine.simulate.click($('input[name=deleteRow]').get(0))
69
+ expect(@removeRowSpy.callCount).toEqual(1)
70
+
71
+ it "adds a column before the selected cell", ->
72
+ jasmine.simulate.click($('input[name=insertColumnBefore]').get(0))
73
+ expect(@addColumnSpy.callCount).toEqual(1)
74
+ expect(@addColumnSpy.argsForCall[0]).toEqual(['before'])
75
+
76
+ it "adds a column after the selected cell", ->
77
+ jasmine.simulate.click($('input[name=insertColumnAfter]').get(0))
78
+ expect(@addColumnSpy.callCount).toEqual(1)
79
+ expect(@addColumnSpy.argsForCall[0]).toEqual(['after'])
80
+
81
+ it "deletes the column of the selected cell", ->
82
+ jasmine.simulate.click($('input[name=deleteColumn]').get(0))
83
+ expect(@removeColumnSpy.callCount).toEqual(1)
84
+
85
+ it "increases the colspan of the selected cell", ->
86
+ jasmine.simulate.click($('input[name=increaseColspan]').get(0))
87
+ expect(@increaseColspanSpy.callCount).toEqual(1)
88
+
89
+ it "decreases the colspan of the selected cell", ->
90
+ jasmine.simulate.click($('input[name=decreaseColspan]').get(0))
91
+ expect(@decreaseColspanSpy.callCount).toEqual(1)
92
+
93
+ it "increases the rowspan of the selected cell", ->
94
+ jasmine.simulate.click($('input[name=increaseRowspan]').get(0))
95
+ expect(@increaseRowspanSpy.callCount).toEqual(1)
96
+
97
+ it "decreases the rowspan of the selected cell", ->
98
+ jasmine.simulate.click($('input[name=decreaseRowspan]').get(0))
99
+ expect(@decreaseRowspanSpy.callCount).toEqual(1)
100
+
101
+
102
+ describe "changing the alignment", ->
103
+
104
+ it "changes the alignment of the table", ->
105
+
106
+
107
+ describe "changing the border", ->
108
+
109
+ beforeEach ->
110
+ Mercury.modalHandlers.insertTable.call(@modal)
111
+
112
+ it "changes the border of the table", ->
113
+ $('#table_border').val('19')
114
+ jasmine.simulate.keyup($('#table_border').get(0))
115
+ expect($('#table').attr('border')).toEqual('19')
116
+
117
+ it "handles non-numeric values", ->
118
+ $('#table_border').val('2x')
119
+ jasmine.simulate.keyup($('#table_border').get(0))
120
+ expect($('#table').attr('border')).toEqual('2')
121
+
122
+
123
+ describe "changing the cellspacing", ->
124
+
125
+ beforeEach ->
126
+ Mercury.modalHandlers.insertTable.call(@modal)
127
+
128
+ it "changes the cellspacing of the table", ->
129
+ $('#table_spacing').val('5')
130
+ jasmine.simulate.keyup($('#table_spacing').get(0))
131
+ expect($('#table').attr('cellspacing')).toEqual('5')
132
+
133
+ it "handles non-numeric values", ->
134
+ $('#table_spacing').val('12x')
135
+ jasmine.simulate.keyup($('#table_spacing').get(0))
136
+ expect($('#table').attr('cellspacing')).toEqual('12')
137
+
138
+
139
+ describe "submitting", ->
140
+
141
+ beforeEach ->
142
+ Mercury.modalHandlers.insertTable.call(@modal)
143
+
144
+ it "triggers an action", ->
145
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
146
+ jasmine.simulate.click($('#submit').get(0))
147
+ expect(spy.callCount).toEqual(1)
148
+ expect(spy.argsForCall[0][0]).toEqual('action')
149
+ expect(spy.argsForCall[0][1]['action']).toEqual('insertTable')
150
+ value = spy.argsForCall[0][1]['value']
151
+ expect(value).toContain('border="1"')
152
+ expect(value).toContain('cellspacing="0"')
153
+ expect(value).toContain('<td id="cell2"><br></td>')
154
+
155
+ it "hides the modal", ->
156
+ spy = spyOn(@modal, 'hide').andCallFake(=>)
157
+ jasmine.simulate.click($('#submit').get(0))
158
+ expect(spy.callCount).toEqual(1)
159
+
160
+
@@ -0,0 +1,60 @@
1
+ describe "String", ->
2
+
3
+ describe "#titleize", ->
4
+
5
+ it "should capitalize the first letter in a string", ->
6
+ expect('wow!'.titleize()).toEqual('Wow!')
7
+
8
+
9
+ describe "#toHex", ->
10
+
11
+ it "converts a rgb(0, 0, 0) type string to hex", ->
12
+ expect('rgb(0, 0, 0)'.toHex()).toEqual('#000000')
13
+ expect('rgb(255, 255, 0)'.toHex()).toEqual('#FFFF00')
14
+
15
+
16
+ describe "#regExpEscape", ->
17
+
18
+ it "escapes characters used in regular expressions", ->
19
+ expect('/.*+?|()[]{}\\'.regExpEscape()).toEqual('\\/\\.\\*\\+\\?\\|\\(\\)\\[\\]\\{\\}\\\\')
20
+
21
+
22
+ describe "#printf", ->
23
+
24
+ it "works something like a basic implementation of the standard sprintf", ->
25
+ expect('int %d'.printf(2.1)).toEqual('int 2')
26
+ expect('int%d'.printf(2.1)).toEqual('int2')
27
+ expect('%d-int'.printf(2.1)).toEqual('2-int')
28
+ expect('%f float'.printf(2.1)).toEqual('2.1 float')
29
+ expect('%s string'.printf(2.1)).toEqual('2.1 string')
30
+ expect('%% a'.printf(2.1)).toEqual('% a')
31
+ expect('a %% b'.printf()).toEqual('a % b')
32
+ expect('a %% %d'.printf(2.1)).toEqual('a % 2')
33
+ expect('%d\n%s'.printf(2.1, 'string')).toEqual('2\nstring')
34
+
35
+
36
+ describe "Number", ->
37
+
38
+ describe "#toHex", ->
39
+
40
+ it "converts a number to it's hex value", ->
41
+ expect(100.toHex()).toEqual('64')
42
+ expect(255.toHex()).toEqual('FF')
43
+
44
+ it "pads 0-F with a 0", ->
45
+ expect(0.toHex()).toEqual('00')
46
+ expect(15.toHex()).toEqual('0F')
47
+
48
+ describe "#toBytes", ->
49
+
50
+ it "converts a number to a readable byte representation (eg. 1.2 kb, 3.4 Mb)", ->
51
+ kb = 1024
52
+ expect(kb.toBytes()).toEqual('1.00 kb')
53
+ expect((kb + 100).toBytes()).toEqual('1.10 kb')
54
+ expect((kb * 1000).toBytes()).toEqual('1000.00 kb')
55
+ expect((kb * 1024).toBytes()).toEqual('1.00 Mb')
56
+ expect((kb * 1024 * 1024).toBytes()).toEqual('1.00 Gb')
57
+ expect((kb * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Tb')
58
+ expect((kb * 1024 * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Pb')
59
+ expect((kb * 1024 * 1024 * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Eb')
60
+
@@ -0,0 +1,757 @@
1
+ describe "Mercury.PageEditor", ->
2
+
3
+ template 'mercury/page_editor.html'
4
+
5
+ beforeEach ->
6
+ Mercury.config.regions.className = 'custom-region-class'
7
+
8
+ afterEach ->
9
+ @pageEditor = null
10
+ delete(@pageEditor)
11
+ window.mercuryInstance = null
12
+ $(window).unbind('mercury:initialize:frame')
13
+ $(window).unbind('mercury:focus:frame')
14
+ $(window).unbind('mercury:focus:window')
15
+ $(window).unbind('mercury:toggle:interface')
16
+ $(window).unbind('mercury:reinitialize')
17
+ $(window).unbind('mercury:mode')
18
+ $(window).unbind('mercury:action')
19
+ $(window).unbind('resize')
20
+ $(document).unbind('mousedown')
21
+
22
+ describe "constructor", ->
23
+
24
+ beforeEach ->
25
+ @initializeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'initializeInterface').andCallFake(=>)
26
+
27
+ it "throws an error if it's already instantiated", ->
28
+ window.mercuryInstance = true
29
+ expect(=>
30
+ new Mercury.PageEditor()
31
+ ).toThrow('Mercury.PageEditor can only be instantiated once.')
32
+ window.mercuryInstance = false
33
+
34
+ it "sets the mercuryInstance to window", ->
35
+ @pageEditor = new Mercury.PageEditor()
36
+ expect(window.mercuryInstance).toEqual(@pageEditor)
37
+
38
+ it "accepts a saveUrl, and options", ->
39
+ @pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar', saveDataType: 'text'})
40
+ expect(@pageEditor.saveUrl).toEqual('/foo/1')
41
+ expect(@pageEditor.options).toEqual({foo: 'bar', saveDataType: 'text', visible: true})
42
+
43
+ it "sets the visible option to true unless it's set", ->
44
+ @pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar', visible: false})
45
+ expect(@pageEditor.options.visible).toEqual(false)
46
+ window.mercuryInstance = null
47
+ @pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar', visible: true})
48
+ expect(@pageEditor.options.visible).toEqual(true)
49
+
50
+ it "sets visible based on the options", ->
51
+ @pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar', visible: false})
52
+ expect(@pageEditor.visible).toEqual(false)
53
+ window.mercuryInstance = null
54
+ @pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar', visible: true})
55
+ expect(@pageEditor.visible).toEqual(true)
56
+
57
+ it "calls initializeInterface", ->
58
+ @pageEditor = new Mercury.PageEditor()
59
+ expect(@initializeInterfaceSpy.callCount).toEqual(1)
60
+
61
+ it "gets the csrf token if there's one available", ->
62
+ new Mercury.PageEditor()
63
+ expect(Mercury.csrfToken).toEqual('K6JhyfOVKJX8X2ZkiJXSf491fc1fF+k79wzrChHQa0g=')
64
+
65
+
66
+ describe "#initializeInterface", ->
67
+
68
+ beforeEach ->
69
+ @resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
70
+ Mercury.Toolbar = -> {toolbar: true}
71
+ Mercury.Statusbar = -> {statusbar: true}
72
+ @iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo')
73
+
74
+ it "builds a focusable element (so we can get focus off the iframe)", ->
75
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
76
+ expect($('input.mercury-focusable[type=text]').length).toEqual(1)
77
+
78
+ it "builds an iframe", ->
79
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
80
+ expect($('iframe.mercury-iframe').length).toEqual(1)
81
+
82
+ it "appends the elements to any node", ->
83
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#page_editor_container')})
84
+ expect($('#page_editor_container input[type=text]').length).toEqual(1)
85
+ expect($('#page_editor_container iframe.mercury-iframe').length).toEqual(1)
86
+
87
+ it "instantiates the toolbar", ->
88
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
89
+ expect(@pageEditor.toolbar).toEqual({toolbar: true})
90
+
91
+ it "instantiates the statusbar", ->
92
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
93
+ expect(@pageEditor.statusbar).toEqual({statusbar: true})
94
+
95
+ it "calls resize", ->
96
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
97
+ expect(@resizeSpy.callCount).toEqual(1)
98
+
99
+
100
+ describe "#initializeFrame", ->
101
+
102
+ beforeEach ->
103
+ @resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
104
+ @bindEventsSpy = spyOn(Mercury.PageEditor.prototype, 'bindEvents').andCallFake(=>)
105
+ @initializeRegionsSpy = spyOn(Mercury.PageEditor.prototype, 'initializeRegions').andCallFake(=>)
106
+ @finalizeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'finalizeInterface')
107
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
108
+
109
+ it "does nothing if the iframe is already loaded", ->
110
+ @finalizeInterfaceSpy.andCallFake(=>)
111
+ @pageEditor.iframe.data('loaded', true)
112
+ @pageEditor.initializeFrame()
113
+ expect(@pageEditor.document).toBeUndefined()
114
+
115
+ it "tells the iframe that it's loaded", ->
116
+ @finalizeInterfaceSpy.andCallFake(=>)
117
+ @pageEditor.initializeFrame()
118
+ expect(@pageEditor.iframe.data('loaded')).toEqual(true)
119
+
120
+ it "gets the document from the iframe", ->
121
+ @finalizeInterfaceSpy.andCallFake(=>)
122
+ @pageEditor.initializeFrame()
123
+ expect(@pageEditor.document).toBeDefined()
124
+
125
+ it "injects needed mercury styles", ->
126
+ @finalizeInterfaceSpy.andCallFake(=>)
127
+ spy = spyOn($.fn, 'appendTo').andCallFake(=>)
128
+ @pageEditor.initializeFrame()
129
+ expect(spy.callCount).toEqual(1)
130
+
131
+ it "injects mercury namespace into the iframe", ->
132
+ @finalizeInterfaceSpy.andCallFake(=>)
133
+ @pageEditor.initializeFrame()
134
+ expect(@pageEditor.iframe.get(0).contentWindow.Mercury).toEqual(window.Mercury)
135
+
136
+ it "provides the iframe with History (history.js)", ->
137
+ @finalizeInterfaceSpy.andCallFake(=>)
138
+ window.History = {Adapter: 'foo'}
139
+ @pageEditor.initializeFrame()
140
+ expect(@pageEditor.iframe.get(0).contentWindow.History).toEqual(window.History)
141
+
142
+ it "calls bindEvents", ->
143
+ @finalizeInterfaceSpy.andCallFake(=>)
144
+ @pageEditor.initializeFrame()
145
+ expect(@bindEventsSpy.callCount).toEqual(1)
146
+
147
+ it "calls resize", ->
148
+ @finalizeInterfaceSpy.andCallFake(=>)
149
+ @pageEditor.initializeFrame()
150
+ expect(@resizeSpy.callCount).toEqual(2)
151
+
152
+ it "calls initializeRegions", ->
153
+ @finalizeInterfaceSpy.andCallFake(=>)
154
+ @pageEditor.initializeFrame()
155
+ expect(@initializeRegionsSpy.callCount).toEqual(1)
156
+
157
+ it "calls finalizeInterface", ->
158
+ @finalizeInterfaceSpy.andCallFake(=>)
159
+ @pageEditor.initializeFrame()
160
+ expect(@finalizeInterfaceSpy.callCount).toEqual(1)
161
+
162
+ it "fires the ready event (Mercury.trigger)", ->
163
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
164
+ @finalizeInterfaceSpy.andCallFake(=>)
165
+ @pageEditor.initializeFrame()
166
+ expect(spy.callCount).toEqual(1)
167
+ expect(spy.argsForCall[0]).toEqual(['ready'])
168
+
169
+ it "fires the ready event (jQuery.trigger)", ->
170
+ spy = spyOn(jQuery.fn, 'trigger').andCallFake(=>)
171
+ @finalizeInterfaceSpy.andCallFake(=>)
172
+ @pageEditor.initializeFrame()
173
+ expect(spy.callCount).toEqual(2)
174
+ expect(spy.argsForCall[0]).toEqual(['mercury:ready', undefined])
175
+
176
+ it "fires the ready event (Event.fire)", ->
177
+ @finalizeInterfaceSpy.andCallFake(=>)
178
+ iframeWindow = @pageEditor.iframe.get(0).contentWindow
179
+ iframeWindow.Event = {fire: ->}
180
+ spy = spyOn(iframeWindow.Event, 'fire').andCallFake(=>)
181
+ @pageEditor.initializeFrame()
182
+ expect(spy.callCount).toEqual(1)
183
+ expect(spy.argsForCall[0][1]).toEqual('mercury:ready')
184
+
185
+ it "calls onMercuryReady in the iframe", ->
186
+ @finalizeInterfaceSpy.andCallFake(=>)
187
+ iframeWindow = @pageEditor.iframe.get(0).contentWindow
188
+ iframeWindow.onMercuryReady = ->
189
+ spy = spyOn(iframeWindow, 'onMercuryReady').andCallFake(=>)
190
+ @pageEditor.initializeFrame()
191
+ expect(spy.callCount).toEqual(1)
192
+
193
+ it "shows the iframe", ->
194
+ @pageEditor.iframe.css({visibility: 'visible'})
195
+ @finalizeInterfaceSpy.andCallFake(=>)
196
+ @pageEditor.initializeFrame()
197
+ expect(@pageEditor.iframe.css('visibility')).toEqual('visible')
198
+
199
+ it "captures errors and alerts them", ->
200
+ @finalizeInterfaceSpy.andCallFake(=> throw('unknown error' ))
201
+ spy = spyOn(window, 'alert').andCallFake(=>)
202
+ @pageEditor.initializeFrame()
203
+ expect(spy.callCount).toEqual(1)
204
+ expect(spy.argsForCall[0]).toEqual(['Mercury.PageEditor failed to load: unknown error\n\nPlease try refreshing.'])
205
+
206
+
207
+ describe "#initializeRegions", ->
208
+
209
+ beforeEach ->
210
+ @resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
211
+ Mercury.PageEditor.prototype.initializeFrame = ->
212
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
213
+ @pageEditor.document = $(document)
214
+
215
+ it "it calls buildRegion for all the regions found in a document", ->
216
+ spy = spyOn(Mercury.PageEditor.prototype, 'buildRegion').andCallFake(=>)
217
+ @pageEditor.initializeRegions()
218
+ expect(spy.callCount).toEqual(4)
219
+
220
+ it "focuses the first region", ->
221
+ regionIndex = 0
222
+ regionFocusCall = null;
223
+ spy = spyOn(Mercury.PageEditor.prototype, 'buildRegion').andCallFake ->
224
+ @regions.push({focus: ->
225
+ regionIndex += 1
226
+ regionFocusCall = regionIndex
227
+ })
228
+ @pageEditor.initializeRegions()
229
+ expect(spy.callCount).toEqual(4)
230
+ expect(regionFocusCall).toEqual(1)
231
+
232
+ it "doesn't focus the first region if it's not supposed to be visible", ->
233
+ spy = spyOn(Mercury.PageEditor.prototype, 'buildRegion').andCallFake(=>)
234
+ firstFocusCalled = false
235
+ @pageEditor.regions = [{focus: => firstFocusCalled = true}, {}, {}]
236
+ @pageEditor.options.visible = false
237
+ @pageEditor.initializeRegions()
238
+ expect(firstFocusCalled).toEqual(false)
239
+
240
+
241
+ describe "#buildRegion", ->
242
+ # it "throws an error if it's not supported", ->
243
+ # Mercury.supported = false
244
+ # expect(=>
245
+ # new Mercury.PageEditor()
246
+ # ).toThrow('Mercury.PageEditor is unsupported in this client. Supported browsers are chrome 10+, firefix 4+, and safari 5+.')
247
+ # Mercury.supported = true
248
+ #
249
+
250
+ beforeEach ->
251
+ @resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
252
+ Mercury.PageEditor.prototype.initializeFrame = ->
253
+ Mercury.Regions.Editable = -> {region: true}
254
+ Mercury.Regions.Editable.supported = true
255
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
256
+
257
+ it "instantiates the region and pushes it into the regions array", ->
258
+ @pageEditor.buildRegion($('#region2'))
259
+ expect(@pageEditor.regions.length).toEqual(1)
260
+ expect(@pageEditor.regions[0]).toEqual({region: true})
261
+
262
+ it "throws an exception when there's no data-type attribute", ->
263
+ expect(=> @pageEditor.buildRegion($('#region4'))).toThrow('Region type is malformed, no data-type provided, or "Unknown" is unknown for the "region4" region.')
264
+ expect(=> @pageEditor.buildRegion($('#region4'))).toThrow('Region type is malformed, no data-type provided, or "Unknown" is unknown for the "region4" region.')
265
+
266
+ it "throws an exception when the data-type isn't known", ->
267
+ expect(=> @pageEditor.buildRegion($('#region4'))).toThrow('Region type is malformed, no data-type provided, or "Unknown" is unknown for the "region4" region.')
268
+ $('#region4').attr('data-type', 'foo')
269
+ expect(=> @pageEditor.buildRegion($('#region4'))).toThrow('Region type is malformed, no data-type provided, or "Foo" is unknown for the "region4" region.')
270
+
271
+ it "doesn't re-instantiate the region if the element's already initialized", ->
272
+ $('#region2').data('region', {foo: 'bar'})
273
+ @pageEditor.buildRegion($('#region2'))
274
+ expect(@pageEditor.regions.length).toEqual(1)
275
+ expect(@pageEditor.regions[0]).toEqual({foo: 'bar'})
276
+
277
+ it "calls togglePreview on the region if in preview mode", ->
278
+ callCount = 0
279
+ Mercury.Regions.Editable = -> {region: true, togglePreview: -> callCount += 1 }
280
+ Mercury.Regions.Editable.supported = true
281
+ @pageEditor.previewing = true
282
+ @pageEditor.buildRegion($('#region2'))
283
+ expect(callCount).toEqual(1)
284
+
285
+ it "doesn't call togglePreview if not in preview mode", ->
286
+ callCount = 0
287
+ Mercury.Regions.Editable = -> {region: true, togglePreview: -> callCount += 1 }
288
+ Mercury.Regions.Editable.supported = true
289
+ @pageEditor.buildRegion($('#region2'))
290
+ expect(callCount).toEqual(0)
291
+
292
+
293
+ describe "#finalizeInterface", ->
294
+
295
+ beforeEach ->
296
+ @resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
297
+ Mercury.PageEditor.prototype.initializeFrame = ->
298
+ Mercury.SnippetToolbar = -> {snippetToolbar: true}
299
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
300
+ @highjackLinksAndFormsSpy = spyOn(Mercury.PageEditor.prototype, 'hijackLinksAndForms').andCallFake(=>)
301
+
302
+ it "injects an sanitizing element used for sanitizing content", ->
303
+ @pageEditor.finalizeInterface()
304
+ expect($('#mercury_sanitizer[contenteditable]').length).toEqual(1)
305
+
306
+ it "builds a snippetToolbar", ->
307
+ @pageEditor.finalizeInterface()
308
+ expect(@pageEditor.snippetToolbar).toEqual({snippetToolbar: true})
309
+
310
+ it "calls hijackLinksAndForms", ->
311
+ @pageEditor.finalizeInterface()
312
+ expect(@highjackLinksAndFormsSpy.callCount).toEqual(1)
313
+
314
+ it "fires a mode event to put things into preview mode if it's not visible yet", ->
315
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
316
+ @pageEditor.options.visible = false
317
+ @pageEditor.finalizeInterface()
318
+ expect(spy.callCount).toEqual(1)
319
+
320
+
321
+ describe "observed events", ->
322
+
323
+ beforeEach ->
324
+ @initializeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'initializeInterface').andCallFake(=>)
325
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
326
+ @pageEditor.document = $(document)
327
+ @pageEditor.bindEvents()
328
+
329
+ describe "custom event: initialize:frame", ->
330
+
331
+ it "calls initializeFrame", ->
332
+ @initializeFrameSpy = spyOn(Mercury.PageEditor.prototype, 'initializeFrame').andCallFake(=>)
333
+ @setTimeoutSpy = spyOn(window, 'setTimeout').andCallFake((timeout, callback) -> callback())
334
+ Mercury.trigger('initialize:frame')
335
+ expect(@initializeFrameSpy.callCount).toEqual(1)
336
+ expect(@setTimeoutSpy.callCount).toEqual(1)
337
+
338
+ describe "custom event: focus:frame", ->
339
+
340
+ it "calls focus on the iframe", ->
341
+ callCount = 0
342
+ @pageEditor.iframe = {focus: -> callCount += 1}
343
+ Mercury.trigger('focus:frame')
344
+ expect(callCount).toEqual(1)
345
+
346
+ describe "custom event: focus:window", ->
347
+
348
+ it "calls focus on a focusable element", ->
349
+ callCount = 0
350
+ @pageEditor.focusableElement = {focus: -> callCount += 1}
351
+ @setTimeoutSpy = spyOn(window, 'setTimeout').andCallFake((timeout, callback) -> callback())
352
+ Mercury.trigger('focus:window')
353
+ expect(callCount).toEqual(1)
354
+
355
+ describe "custom event: toggle:interface", ->
356
+
357
+ it "calls toggleInterface", ->
358
+ spy = spyOn(Mercury.PageEditor.prototype, 'toggleInterface').andCallFake(=>)
359
+ Mercury.trigger('toggle:interface')
360
+ expect(spy.callCount).toEqual(1)
361
+
362
+ describe "custom event: mode", ->
363
+
364
+ it "toggles preview mode if needed", ->
365
+ Mercury.trigger('mode', {mode: 'preview'})
366
+ expect(@pageEditor.previewing).toEqual(true)
367
+ Mercury.trigger('mode', {mode: 'preview'})
368
+ expect(@pageEditor.previewing).toEqual(false)
369
+ Mercury.trigger('mode', {mode: 'foo'})
370
+ expect(@pageEditor.previewing).toEqual(false)
371
+
372
+ describe "custom event: reinitialize", ->
373
+
374
+ it "calls initializeRegions", ->
375
+ spy = spyOn(Mercury.PageEditor.prototype, 'initializeRegions').andCallFake(=>)
376
+ Mercury.trigger('reinitialize')
377
+ expect(spy.callCount).toEqual(1)
378
+
379
+ describe "custom event: action", ->
380
+
381
+ it "calls save if the action was save", ->
382
+ spy = spyOn(Mercury.PageEditor.prototype, 'save').andCallFake(=>)
383
+ Mercury.trigger('action', {action: 'foo'})
384
+ expect(spy.callCount).toEqual(0)
385
+
386
+ Mercury.trigger('action', {action: 'save'})
387
+ expect(spy.callCount).toEqual(1)
388
+
389
+ describe "mousedown on document", ->
390
+
391
+ beforeEach ->
392
+ @triggerSpy = spyOn(Mercury, 'trigger').andCallFake(=>)
393
+
394
+ it "triggers hide:dialogs", ->
395
+ Mercury.region = {element: $('#region3')}
396
+ jasmine.simulate.mousedown($('#anchor1r').get(0))
397
+ expect(@triggerSpy.callCount).toEqual(1)
398
+ expect(@triggerSpy.argsForCall[0]).toEqual(['hide:dialogs'])
399
+
400
+ it "triggers unfocus:regions unless the event happened in a region", ->
401
+ Mercury.region = {element: {get: -> null}}
402
+ jasmine.simulate.mousedown(document)
403
+ expect(@triggerSpy.callCount).toEqual(2)
404
+ expect(@triggerSpy.argsForCall[1]).toEqual(['unfocus:regions'])
405
+
406
+ describe "window resize", ->
407
+
408
+ # untestable
409
+ it "calls resize", ->
410
+ #spy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
411
+ #resizeTo($(window).width() - 1, $(window).height() - 1)
412
+ #expect(spy.callCount).toEqual(1)
413
+
414
+ describe "onbeforeunload", ->
415
+
416
+ # untestable
417
+ it "calls Mercury.beforeUnload", ->
418
+ #spy = spyOn(Mercury, 'beforeUnload').andCallFake(=>)
419
+ #window.onbeforeunload()
420
+ #expect(spy.callCount).toEqual(1)
421
+
422
+
423
+ describe "#toggleInterface", ->
424
+
425
+ beforeEach ->
426
+ spec = @
427
+ spec.toolbarShowCallCount = 0
428
+ spec.toolbarHideCallCount = 0
429
+ spec.statusbarShowCallCount = 0
430
+ spec.statusbarHideCallCount = 0
431
+ Mercury.Toolbar = -> {
432
+ toolbar: true,
433
+ height: (-> 100),
434
+ show: (=> spec.toolbarShowCallCount += 1),
435
+ hide: (=> spec.toolbarHideCallCount += 1)
436
+ }
437
+ Mercury.Statusbar = -> {
438
+ statusbar: true,
439
+ top: (-> 500),
440
+ show: (=> spec.statusbarShowCallCount += 1),
441
+ hide: (=> spec.statusbarHideCallCount += 1)
442
+ }
443
+ Mercury.PageEditor.prototype.initializeFrame = ->
444
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
445
+
446
+ it "calls resize", ->
447
+ spy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
448
+ @pageEditor.toggleInterface()
449
+ expect(spy.callCount).toEqual(1)
450
+
451
+ it "triggers the mode event to toggle preview mode", ->
452
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
453
+ @pageEditor.toggleInterface()
454
+ expect(spy.callCount).toEqual(2)
455
+ expect(spy.argsForCall[0]).toEqual(['mode', {mode: 'preview'}])
456
+ expect(spy.argsForCall[1]).toEqual(['resize'])
457
+
458
+ describe "when visible", ->
459
+
460
+ beforeEach ->
461
+ @pageEditor.visible = true
462
+
463
+ it "triggers an extra preview mode event if currently previewing", ->
464
+ @pageEditor.previewing = true
465
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
466
+ @pageEditor.toggleInterface()
467
+ expect(spy.callCount).toEqual(3)
468
+ expect(spy.argsForCall[0]).toEqual(['mode', {mode: 'preview'}])
469
+ expect(spy.argsForCall[1]).toEqual(['mode', {mode: 'preview'}])
470
+
471
+ it "sets visible to false", ->
472
+ @pageEditor.toggleInterface()
473
+ expect(@pageEditor.visible).toEqual(false)
474
+
475
+ it "calls hide on the toolbar", ->
476
+ @pageEditor.toggleInterface()
477
+ expect(@toolbarHideCallCount).toEqual(1)
478
+
479
+ it "calls hide on the statusbar", ->
480
+ @pageEditor.toggleInterface()
481
+ expect(@statusbarHideCallCount).toEqual(1)
482
+
483
+ describe "when not visible", ->
484
+
485
+ beforeEach ->
486
+ @pageEditor.visible = false
487
+
488
+ it "sets visible to true", ->
489
+ @pageEditor.toggleInterface()
490
+ expect(@pageEditor.visible).toEqual(true)
491
+
492
+ it "calls show on the toolbar", ->
493
+ @pageEditor.toggleInterface()
494
+ expect(@toolbarShowCallCount).toEqual(1)
495
+
496
+ it "calls show on the statusbar", ->
497
+ @pageEditor.toggleInterface()
498
+ expect(@statusbarShowCallCount).toEqual(1)
499
+
500
+
501
+ describe "#resize", ->
502
+
503
+ beforeEach ->
504
+ Mercury.Toolbar = -> {toolbar: true, height: -> 100}
505
+ Mercury.Statusbar = -> {statusbar: true, top: -> 500}
506
+ Mercury.PageEditor.prototype.initializeFrame = ->
507
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
508
+
509
+ it "sets the display rectangle to displayRect", ->
510
+ @pageEditor.resize()
511
+ expect(Mercury.displayRect.top).toEqual(100)
512
+ expect(Mercury.displayRect.height).toEqual(500 - 100)
513
+
514
+ it "resizes the iframe", ->
515
+ @pageEditor.resize()
516
+ expect($('.mercury-iframe').css('height')).toEqual("#{500 - 100}px")
517
+
518
+ it "triggers a resize event", ->
519
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
520
+ @pageEditor.resize()
521
+ expect(spy.callCount).toEqual(1)
522
+
523
+
524
+ describe "#iframeSrc", ->
525
+
526
+ beforeEach ->
527
+ Mercury.PageEditor.prototype.initializeFrame = ->
528
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
529
+
530
+ it "takes the location and removes the /editor", ->
531
+ expect(@pageEditor.iframeSrc('http://foo.com/editor/path')).toEqual('http://foo.com/path')
532
+
533
+ it "uses the configured url regex to remove the editor", ->
534
+ original = Mercury.config.editorUrlRegEx
535
+ Mercury.config.editorUrlRegEx = /([http|https]:\/\/[^\/]*)\/(.*)\/edit\/?/i
536
+ expect(@pageEditor.iframeSrc('http://foo.com/path/edit')).toEqual('http://foo.com/path')
537
+ Mercury.config.editorUrlRegEx = original
538
+
539
+ it "adds query params", ->
540
+ expect(@pageEditor.iframeSrc('http://foo.com/editor/path', true)).toEqual('http://foo.com/path?mercury_frame=true')
541
+ expect(@pageEditor.iframeSrc('http://foo.com/editor/path?something=true', true)).toEqual('http://foo.com/path?something=true&mercury_frame=true')
542
+
543
+
544
+ describe "#hijackLinksAndForms", ->
545
+
546
+ beforeEach ->
547
+ Mercury.config.nonHijackableClasses = ['lightview']
548
+
549
+ Mercury.PageEditor.prototype.initializeFrame = ->
550
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
551
+ @pageEditor.document = $(document)
552
+
553
+ afterEach ->
554
+ Mercury.config.nonHijackableClasses = []
555
+
556
+ it "finds links and forms and sets their target to top if it's not already set", ->
557
+ @pageEditor.hijackLinksAndForms()
558
+ expect($('#anchor1').attr('target')).toEqual('_top')
559
+ expect($('#anchor2').attr('target')).toEqual('_blank')
560
+ expect($('#anchor3').attr('target')).toEqual('_parent')
561
+ expect($('#anchor4').attr('target')).toEqual('_parent')
562
+ expect($('#form1').attr('target')).toEqual('_top')
563
+ expect($('#form2').attr('target')).toEqual('_blank')
564
+ expect($('#form3').attr('target')).toEqual('_parent')
565
+ expect($('#form4').attr('target')).toEqual('_parent')
566
+
567
+ it "ignores links in regions", ->
568
+ @pageEditor.hijackLinksAndForms()
569
+ expect($('#anchor1r').attr('target')).toEqual('_top')
570
+ expect($('#anchor2r').attr('target')).toEqual('_blank')
571
+ expect($('#anchor3r').attr('target')).toEqual('_self')
572
+ expect($('#anchor4r').attr('target')).toBeUndefined()
573
+ expect($('#form1r').attr('target')).toEqual('_top')
574
+ expect($('#form2r').attr('target')).toEqual('_blank')
575
+ expect($('#form3r').attr('target')).toEqual('_self')
576
+ expect($('#form4r').attr('target')).toBeUndefined()
577
+
578
+ it "ignores links and forms that are in the config to be ignored (by class)", ->
579
+ @pageEditor.hijackLinksAndForms()
580
+ expect($('#anchor5').attr('target')).toEqual('_self')
581
+ expect($('#form5').attr('target')).toEqual('_self')
582
+
583
+ it "doesn't change targets of links and forms that are set to anything besides _self", ->
584
+ @pageEditor.hijackLinksAndForms()
585
+ expect($('#anchor6').attr('target')).toEqual('foo')
586
+ expect($('#form6').attr('target')).toEqual('foo')
587
+
588
+
589
+ describe "#beforeUnload", ->
590
+
591
+ beforeEach ->
592
+ Mercury.PageEditor.prototype.initializeInterface = ->
593
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
594
+ Mercury.silent = false
595
+ Mercury.changes = true
596
+
597
+ it "returns a message if changes were made", ->
598
+ expect(@pageEditor.beforeUnload()).toEqual('You have unsaved changes. Are you sure you want to leave without saving them first?')
599
+
600
+ Mercury.changes = false
601
+ expect(@pageEditor.beforeUnload()).toEqual(null)
602
+
603
+ it "does nothing if in silent mode", ->
604
+ Mercury.silent = true
605
+ expect(@pageEditor.beforeUnload()).toEqual(null)
606
+
607
+
608
+ describe "#getRegionByName", ->
609
+
610
+ beforeEach ->
611
+ Mercury.PageEditor.prototype.initializeInterface = ->
612
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
613
+ @iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo/baz')
614
+ @ajaxSpy = spyOn($, 'ajax')
615
+
616
+ it "returns the region if a match is found", ->
617
+ @pageEditor.regions = [{name: 'foo'}, {name: 'bar'}, {name: 'baz'}]
618
+ expect(@pageEditor.getRegionByName('foo')).toEqual(@pageEditor.regions[0])
619
+ expect(@pageEditor.getRegionByName('baz')).toEqual(@pageEditor.regions[2])
620
+
621
+ it "returns null if no match was found", ->
622
+ @pageEditor.regions = [{name: 'bar'}]
623
+ expect(@pageEditor.getRegionByName('foo')).toEqual(null)
624
+
625
+
626
+ describe "#save", ->
627
+
628
+ describe "POST", ->
629
+ beforeEach ->
630
+ Mercury.PageEditor.prototype.initializeInterface = ->
631
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test'), saveDataType: 'text'})
632
+ @iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo/baz')
633
+ @ajaxSpy = spyOn($, 'ajax')
634
+
635
+ it "doesn't set the _method in the request data", ->
636
+ @ajaxSpy.andCallFake(=>)
637
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
638
+ @pageEditor.save()
639
+ expect(@ajaxSpy.argsForCall[0][1]['data']['_method']).toEqual(undefined)
640
+
641
+ it "makes an ajax request", ->
642
+ @ajaxSpy.andCallFake(=>)
643
+ @pageEditor.save()
644
+ expect(@ajaxSpy.callCount).toEqual(1)
645
+
646
+ it "uses the save url passed in via options, the configured save url, or the iframe src", ->
647
+ @ajaxSpy.andCallFake(=>)
648
+ @pageEditor.saveUrl = '/foo/bar'
649
+ @pageEditor.save()
650
+ expect(@ajaxSpy.argsForCall[0][0]).toEqual('/foo/bar')
651
+
652
+ @pageEditor.saveUrl = null
653
+ Mercury.saveUrl = '/foo/bit'
654
+ @pageEditor.save()
655
+ expect(@ajaxSpy.argsForCall[1][0]).toEqual('/foo/bit')
656
+
657
+ @pageEditor.saveUrl = null
658
+ Mercury.saveUrl = null
659
+ @pageEditor.save()
660
+ expect(@ajaxSpy.argsForCall[2][0]).toEqual('/foo/baz')
661
+
662
+ it "serializes the data in json", ->
663
+ @ajaxSpy.andCallFake(=>)
664
+ Mercury.config.saveStyle = 'json'
665
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
666
+ @pageEditor.save()
667
+ expect(@ajaxSpy.argsForCall[0][1]['data']).toEqual({content: '{"region1":"region1"}' })
668
+
669
+ it "can serialize as form values", ->
670
+ @ajaxSpy.andCallFake(=>)
671
+ @pageEditor.options.saveStyle = 'form'
672
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
673
+ @pageEditor.save()
674
+ expect(@ajaxSpy.argsForCall[0][1]['data']).toEqual({content: {region1: 'region1'}})
675
+
676
+ it "sets headers by calling Mercury.ajaxHeaders", ->
677
+ @ajaxSpy.andCallFake(=>)
678
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
679
+ spyOn(Mercury, 'ajaxHeaders').andCallFake(=> {'X-CSRFToken': 'f00'})
680
+ @pageEditor.save()
681
+ expect(@ajaxSpy.argsForCall[0][1]['headers']).toEqual({'X-CSRFToken': 'f00'})
682
+
683
+ it "sets the data type from options", ->
684
+ @ajaxSpy.andCallFake(=>)
685
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
686
+ @pageEditor.save()
687
+ expect(@ajaxSpy.argsForCall[0][1]['dataType']).toEqual('text')
688
+
689
+ describe "on successful ajax request", ->
690
+
691
+ beforeEach ->
692
+ @ajaxSpy.andCallFake((url, options) => options.success('data') )
693
+
694
+ it "sets changes back to false", ->
695
+ Mercury.changes = true
696
+ @pageEditor.save()
697
+ expect(Mercury.changes).toEqual(false)
698
+
699
+ it "calls a callback if one was provided", ->
700
+ callback = -> callback.callCount += 1
701
+ callback.callCount = 0;
702
+ @pageEditor.save(callback)
703
+ expect(callback.callCount).toEqual(1)
704
+
705
+ it "fires an event", ->
706
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
707
+ @pageEditor.save()
708
+ expect(spy.callCount).toEqual(1)
709
+ expect(spy.argsForCall[0]).toEqual(['saved'])
710
+
711
+ describe "on failed ajax request", ->
712
+
713
+ beforeEach ->
714
+ @ajaxSpy.andCallFake((url, options) => options.error({'response': 'object'}) )
715
+
716
+ it "alerts and triggers save_failed with the url", ->
717
+ alert_spy = spyOn(window, 'alert').andCallFake(=>)
718
+ trigger_spy = spyOn(Mercury, 'trigger').andCallFake(=>)
719
+
720
+ @pageEditor.saveUrl = '/foo/bar'
721
+ @pageEditor.save()
722
+
723
+ expect(alert_spy.callCount).toEqual(1)
724
+ expect(alert_spy.argsForCall[0]).toEqual(['Mercury was unable to save to the url: /foo/bar'])
725
+
726
+ expect(trigger_spy.callCount).toEqual(1)
727
+ expect(trigger_spy.argsForCall[0][0]).toEqual('save_failed')
728
+ expect(trigger_spy.argsForCall[0][1]).toBeDefined()
729
+
730
+ describe "PUT", ->
731
+
732
+ beforeEach ->
733
+ Mercury.PageEditor.prototype.initializeInterface = ->
734
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test'), saveMethod: 'PUT'})
735
+ @iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo/baz')
736
+ @ajaxSpy = spyOn($, 'ajax')
737
+
738
+ it "sets the _method in the request", ->
739
+ @ajaxSpy.andCallFake(=>)
740
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
741
+ @pageEditor.save()
742
+ expect(@ajaxSpy.argsForCall[0][1]['data']['_method']).toEqual('PUT')
743
+
744
+
745
+ describe "#serialize", ->
746
+
747
+ beforeEach ->
748
+ Mercury.PageEditor.prototype.initializeInterface = ->
749
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
750
+ @pageEditor.regions = [
751
+ {name: 'region1', serialize: -> 'region1'},
752
+ {name: 'region2', serialize: -> 'region2'}
753
+ ]
754
+
755
+ it "returns an object with the region name, and it's serialized value", ->
756
+ ret = @pageEditor.serialize()
757
+ expect(ret).toEqual({region1: 'region1', region2: 'region2'})