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,750 @@
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'})
40
+ expect(@pageEditor.saveUrl).toEqual('/foo/1')
41
+ expect(@pageEditor.options).toEqual({foo: 'bar', 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() )
715
+
716
+ it "alerts with the url", ->
717
+ spy = spyOn(window, 'alert').andCallFake(=>)
718
+ @pageEditor.saveUrl = '/foo/bar'
719
+ @pageEditor.save()
720
+ expect(spy.callCount).toEqual(1)
721
+ expect(spy.argsForCall[0]).toEqual(['Mercury was unable to save to the url: /foo/bar'])
722
+
723
+ describe "PUT", ->
724
+
725
+ beforeEach ->
726
+ Mercury.PageEditor.prototype.initializeInterface = ->
727
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test'), saveMethod: 'PUT'})
728
+ @iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo/baz')
729
+ @ajaxSpy = spyOn($, 'ajax')
730
+
731
+ it "sets the _method in the request", ->
732
+ @ajaxSpy.andCallFake(=>)
733
+ spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
734
+ @pageEditor.save()
735
+ expect(@ajaxSpy.argsForCall[0][1]['data']['_method']).toEqual('PUT')
736
+
737
+
738
+ describe "#serialize", ->
739
+
740
+ beforeEach ->
741
+ Mercury.PageEditor.prototype.initializeInterface = ->
742
+ @pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
743
+ @pageEditor.regions = [
744
+ {name: 'region1', serialize: -> 'region1'},
745
+ {name: 'region2', serialize: -> 'region2'}
746
+ ]
747
+
748
+ it "returns an object with the region name, and it's serialized value", ->
749
+ ret = @pageEditor.serialize()
750
+ expect(ret).toEqual({region1: 'region1', region2: 'region2'})