mercury-rails 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. data/POST_INSTALL +15 -0
  2. data/{vendor → app}/assets/images/mercury/button.png +0 -0
  3. data/{vendor → app}/assets/images/mercury/close.png +0 -0
  4. data/app/assets/images/mercury/default-snippet.png +0 -0
  5. data/{vendor → app}/assets/images/mercury/loading-dark.gif +0 -0
  6. data/{vendor → app}/assets/images/mercury/loading-light.gif +0 -0
  7. data/{vendor → app}/assets/images/mercury/missing-image.png +0 -0
  8. data/{vendor → app}/assets/images/mercury/search-icon.png +0 -0
  9. data/{vendor → app}/assets/images/mercury/temp-logo.png +0 -0
  10. data/app/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  11. data/app/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  12. data/app/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
  13. data/app/assets/images/mercury/toolbar/primary/action.png +0 -0
  14. data/app/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
  15. data/app/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
  16. data/app/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
  17. data/app/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
  18. data/app/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
  19. data/app/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
  20. data/app/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
  21. data/app/assets/images/mercury/toolbar/primary/preview.png +0 -0
  22. data/app/assets/images/mercury/toolbar/primary/redo.png +0 -0
  23. data/app/assets/images/mercury/toolbar/primary/save.png +0 -0
  24. data/app/assets/images/mercury/toolbar/primary/snippetpanel.png +0 -0
  25. data/app/assets/images/mercury/toolbar/primary/undo.png +0 -0
  26. data/app/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  27. data/{vendor → app}/assets/javascripts/mercury.js +4 -0
  28. data/{vendor → app}/assets/javascripts/mercury/dependencies/jquery-1.7.js +0 -0
  29. data/{vendor → app}/assets/javascripts/mercury/dependencies/jquery-ui-1.8.13.custom.js +0 -0
  30. data/{vendor → app}/assets/javascripts/mercury/dependencies/jquery.additions.js +0 -0
  31. data/{vendor → app}/assets/javascripts/mercury/dependencies/jquery.htmlClean.js +0 -0
  32. data/{vendor → app}/assets/javascripts/mercury/dependencies/liquidmetal.js +0 -0
  33. data/{vendor → app}/assets/javascripts/mercury/dependencies/showdown.js +0 -0
  34. data/{vendor → app}/assets/javascripts/mercury/dialog.js.coffee +0 -0
  35. data/{vendor → app}/assets/javascripts/mercury/dialogs/backcolor.js.coffee +0 -0
  36. data/{vendor → app}/assets/javascripts/mercury/dialogs/forecolor.js.coffee +0 -0
  37. data/{vendor → app}/assets/javascripts/mercury/dialogs/formatblock.js.coffee +0 -0
  38. data/{vendor → app}/assets/javascripts/mercury/dialogs/snippetpanel.js.coffee +0 -0
  39. data/{vendor → app}/assets/javascripts/mercury/dialogs/style.js.coffee +0 -0
  40. data/{vendor → app}/assets/javascripts/mercury/finalize.js.coffee +0 -0
  41. data/{vendor → app}/assets/javascripts/mercury/history_buffer.js.coffee +0 -0
  42. data/{vendor → app}/assets/javascripts/mercury/lightview.js.coffee +0 -0
  43. data/app/assets/javascripts/mercury/locales/ar.locale.js.coffee +207 -0
  44. data/{vendor → app}/assets/javascripts/mercury/locales/da.locale.js.coffee +7 -7
  45. data/{vendor → app}/assets/javascripts/mercury/locales/de.locale.js.coffee +0 -0
  46. data/{vendor → app}/assets/javascripts/mercury/locales/es.locale.js.coffee +0 -0
  47. data/{vendor → app}/assets/javascripts/mercury/locales/example.local.js.coffee +0 -0
  48. data/{vendor → app}/assets/javascripts/mercury/locales/fr.locale.js.coffee +0 -0
  49. data/{vendor → app}/assets/javascripts/mercury/locales/it.locale.js.coffee +0 -0
  50. data/{vendor → app}/assets/javascripts/mercury/locales/ko.local.js.coffee +0 -0
  51. data/{vendor → app}/assets/javascripts/mercury/locales/nl.locale.js.coffee +0 -0
  52. data/{vendor → app}/assets/javascripts/mercury/locales/pt.locale.js.coffee +0 -0
  53. data/{vendor → app}/assets/javascripts/mercury/locales/sv.local.js.coffee +0 -0
  54. data/{vendor → app}/assets/javascripts/mercury/locales/swedish_chef.locale.js.coffee +0 -0
  55. data/app/assets/javascripts/mercury/locales/zh.local.js.coffee +209 -0
  56. data/{vendor → app}/assets/javascripts/mercury/mercury.js.coffee +9 -1
  57. data/{vendor → app}/assets/javascripts/mercury/modal.js.coffee +0 -0
  58. data/{vendor → app}/assets/javascripts/mercury/modals/htmleditor.js.coffee +0 -0
  59. data/{vendor → app}/assets/javascripts/mercury/modals/insertcharacter.js.coffee +0 -0
  60. data/{vendor → app}/assets/javascripts/mercury/modals/insertlink.js.coffee +0 -0
  61. data/{vendor → app}/assets/javascripts/mercury/modals/insertmedia.js.coffee +0 -0
  62. data/{vendor → app}/assets/javascripts/mercury/modals/insertsnippet.js.coffee +1 -0
  63. data/{vendor → app}/assets/javascripts/mercury/modals/inserttable.js.coffee +0 -0
  64. data/{vendor → app}/assets/javascripts/mercury/native_extensions.js.coffee +0 -0
  65. data/{vendor → app}/assets/javascripts/mercury/page_editor.js.coffee +46 -19
  66. data/{vendor → app}/assets/javascripts/mercury/palette.js.coffee +0 -0
  67. data/{vendor → app}/assets/javascripts/mercury/panel.js.coffee +2 -2
  68. data/{vendor → app}/assets/javascripts/mercury/plugins/save_as_xml/mercury/page_editor.js.coffee +2 -2
  69. data/{vendor → app}/assets/javascripts/mercury/plugins/save_as_xml/plugin.js +0 -0
  70. data/{vendor → app}/assets/javascripts/mercury/region.js.coffee +0 -0
  71. data/{vendor → app}/assets/javascripts/mercury/regions/editable.js.coffee +5 -5
  72. data/app/assets/javascripts/mercury/regions/image.js.coffee +114 -0
  73. data/{vendor → app}/assets/javascripts/mercury/regions/markupable.js.coffee +0 -0
  74. data/app/assets/javascripts/mercury/regions/simple.js.coffee +325 -0
  75. data/{vendor → app}/assets/javascripts/mercury/regions/snippetable.js.coffee +0 -0
  76. data/{vendor → app}/assets/javascripts/mercury/select.js.coffee +0 -0
  77. data/{vendor → app}/assets/javascripts/mercury/snippet.js.coffee +23 -7
  78. data/{vendor → app}/assets/javascripts/mercury/snippet_toolbar.js.coffee +16 -4
  79. data/{vendor → app}/assets/javascripts/mercury/statusbar.js.coffee +0 -0
  80. data/{vendor → app}/assets/javascripts/mercury/support/history.js +0 -0
  81. data/{vendor → app}/assets/javascripts/mercury/table_editor.js.coffee +0 -0
  82. data/{vendor → app}/assets/javascripts/mercury/toolbar.button.js.coffee +8 -8
  83. data/{vendor → app}/assets/javascripts/mercury/toolbar.button_group.js.coffee +0 -0
  84. data/{vendor → app}/assets/javascripts/mercury/toolbar.expander.js.coffee +0 -0
  85. data/{vendor → app}/assets/javascripts/mercury/toolbar.js.coffee +0 -0
  86. data/{vendor → app}/assets/javascripts/mercury/tooltip.js.coffee +0 -0
  87. data/{vendor → app}/assets/javascripts/mercury/uploader.js.coffee +35 -17
  88. data/{vendor → app}/assets/javascripts/mercury_loader.js +0 -0
  89. data/{vendor → app}/assets/javascripts/mercury_overrides.js +0 -0
  90. data/{vendor → app}/assets/stylesheets/mercury.css +0 -0
  91. data/{vendor → app}/assets/stylesheets/mercury/all_images.css.erb +0 -0
  92. data/app/assets/stylesheets/mercury/buttons.css +73 -0
  93. data/{vendor → app}/assets/stylesheets/mercury/dialog.css +13 -4
  94. data/app/assets/stylesheets/mercury/form.css +125 -0
  95. data/{vendor → app}/assets/stylesheets/mercury/lightview.css +0 -0
  96. data/app/assets/stylesheets/mercury/mercury.css +45 -0
  97. data/{vendor → app}/assets/stylesheets/mercury/modal.css +1 -1
  98. data/{vendor → app}/assets/stylesheets/mercury/statusbar.css +0 -0
  99. data/{vendor → app}/assets/stylesheets/mercury/toolbar.css +0 -0
  100. data/{vendor → app}/assets/stylesheets/mercury/tooltip.css +0 -0
  101. data/{vendor → app}/assets/stylesheets/mercury/uploader.css +0 -0
  102. data/{vendor → app}/assets/stylesheets/mercury_overrides.css +0 -0
  103. data/app/views/mercury/modals/character.html +1 -1
  104. data/app/views/mercury/modals/htmleditor.html +1 -1
  105. data/app/views/mercury/modals/link.html +1 -1
  106. data/app/views/mercury/modals/media.html +1 -1
  107. data/app/views/mercury/modals/table.html +1 -1
  108. data/app/views/mercury/snippets/example/options.html.erb +1 -1
  109. data/features/generators/authentication.feature +10 -0
  110. data/features/generators/images.feature +41 -0
  111. data/features/generators/install.feature +21 -0
  112. data/features/loading/loading.feature +4 -1
  113. data/features/loading/user_interface.feature +9 -7
  114. data/features/regions/editable/basic_editing.feature +27 -26
  115. data/features/regions/editable/inserting_links.feature +8 -7
  116. data/features/regions/editable/inserting_snippets.feature +7 -7
  117. data/features/regions/image/uploading_images.feature +0 -0
  118. data/features/regions/simple/basic_editing.feature +5 -0
  119. data/features/step_definitions/generator_steps.rb +27 -0
  120. data/features/step_definitions/mercury_steps.rb +1 -0
  121. data/features/support/aruba.rb +28 -0
  122. data/features/support/env.rb +12 -2
  123. data/features/support/mercury_contents.rb +2 -2
  124. data/lib/generators/mercury/install/authentication/authentication_generator.rb +15 -0
  125. data/lib/generators/mercury/install/images/images_generator.rb +44 -0
  126. data/{app/models/mercury/image.rb → lib/generators/mercury/install/images/templates/ar_paperclip_image.rb} +3 -1
  127. data/{db/migrate/20110526035601_create_mercury_images.rb → lib/generators/mercury/install/images/templates/ar_paperclip_image_migration.rb} +0 -0
  128. data/{app/controllers/mercury → lib/generators/mercury/install/images/templates}/images_controller.rb +0 -0
  129. data/lib/generators/mercury/install/{templates → images/templates}/mongoid_paperclip_image.rb +0 -0
  130. data/lib/generators/mercury/install/install_generator.rb +3 -20
  131. data/lib/mercury-rails.rb +1 -2
  132. data/lib/mercury/authentication.rb +1 -0
  133. data/lib/mercury/engine.rb +17 -0
  134. data/lib/mercury/rails.rb +4 -0
  135. data/lib/mercury/version.rb +3 -0
  136. data/spec/dummy/Rakefile +7 -0
  137. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  138. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  139. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  140. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  141. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  142. data/spec/dummy/config.ru +4 -0
  143. data/spec/dummy/config/application.rb +57 -0
  144. data/spec/dummy/config/boot.rb +10 -0
  145. data/spec/dummy/config/database.example.yml +25 -0
  146. data/spec/dummy/config/database.travisci.yml +4 -0
  147. data/spec/dummy/config/environment.rb +5 -0
  148. data/spec/dummy/config/environments/development.rb +37 -0
  149. data/spec/dummy/config/environments/production.rb +67 -0
  150. data/spec/dummy/config/environments/test.rb +37 -0
  151. data/spec/dummy/config/evergreen.rb +47 -0
  152. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  153. data/spec/dummy/config/initializers/inflections.rb +15 -0
  154. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  155. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  156. data/spec/dummy/config/initializers/session_store.rb +8 -0
  157. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  158. data/spec/dummy/config/locales/en.yml +5 -0
  159. data/spec/dummy/config/routes.rb +5 -0
  160. data/spec/dummy/public/404.html +26 -0
  161. data/spec/dummy/public/422.html +26 -0
  162. data/spec/dummy/public/500.html +25 -0
  163. data/spec/dummy/public/blank.html +1 -0
  164. data/spec/dummy/public/canvastest.html +103 -0
  165. data/spec/dummy/public/distro.html +349 -0
  166. data/spec/dummy/public/favicon.ico +0 -0
  167. data/spec/dummy/public/frame.html +15 -0
  168. data/spec/dummy/public/images/bunny.gif +0 -0
  169. data/spec/dummy/public/images/bunny2.jpg +0 -0
  170. data/spec/dummy/public/index.html +392 -0
  171. data/spec/dummy/public/prototype.js +6082 -0
  172. data/spec/dummy/script/rails +6 -0
  173. data/spec/javascripts/mercury/page_editor_spec.js.coffee +55 -16
  174. data/spec/javascripts/mercury/panel_spec.js.coffee +2 -4
  175. data/spec/javascripts/mercury/regions/image_spec.js.coffee +34 -0
  176. data/spec/javascripts/mercury/regions/simple_spec.js.coffee +33 -0
  177. data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +1 -1
  178. data/spec/javascripts/mercury/snippet_spec.js.coffee +27 -2
  179. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +20 -4
  180. data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +30 -0
  181. data/spec/javascripts/mercury/uploader_spec.js.coffee +16 -0
  182. data/spec/javascripts/templates/mercury/regions/image.html +1 -0
  183. data/spec/javascripts/templates/mercury/regions/simple.html +3 -0
  184. metadata +310 -158
  185. data/config/engine.rb +0 -41
  186. data/vendor/assets/images/mercury/default-snippet.png +0 -0
  187. data/vendor/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  188. data/vendor/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  189. data/vendor/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
  190. data/vendor/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
  191. data/vendor/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
  192. data/vendor/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
  193. data/vendor/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
  194. data/vendor/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
  195. data/vendor/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
  196. data/vendor/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
  197. data/vendor/assets/images/mercury/toolbar/primary/preview.png +0 -0
  198. data/vendor/assets/images/mercury/toolbar/primary/redo.png +0 -0
  199. data/vendor/assets/images/mercury/toolbar/primary/save.png +0 -0
  200. data/vendor/assets/images/mercury/toolbar/primary/snippetpanel.png +0 -0
  201. data/vendor/assets/images/mercury/toolbar/primary/undo.png +0 -0
  202. data/vendor/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  203. data/vendor/assets/stylesheets/mercury/mercury.css +0 -151
@@ -34,7 +34,7 @@
34
34
  #
35
35
  @Mercury ||= {}
36
36
  jQuery.extend @Mercury,
37
- version: '0.3.0'
37
+ version: '0.5.0'
38
38
 
39
39
  # Mercury object namespaces
40
40
  Regions: Mercury.Regions || {}
@@ -55,6 +55,14 @@ jQuery.extend @Mercury,
55
55
  jQuery(window).on("mercury:#{eventName}", callback)
56
56
 
57
57
 
58
+ off: (eventName, callback) ->
59
+ jQuery(window).off("mercury:#{eventName}", callback)
60
+
61
+
62
+ one: (eventName, callback) ->
63
+ jQuery(window).one("mercury:#{eventName}", callback)
64
+
65
+
58
66
  trigger: (eventName, options) ->
59
67
  Mercury.log(eventName, options)
60
68
  jQuery(window).trigger("mercury:#{eventName}", options)
@@ -10,3 +10,4 @@
10
10
  snippet = Mercury.Snippet.create(@options.snippetName, serializedForm)
11
11
  Mercury.trigger('action', {action: 'insertSnippet', value: snippet})
12
12
  @hide()
13
+
@@ -9,6 +9,7 @@ class @Mercury.PageEditor
9
9
  throw Mercury.I18n('Mercury.PageEditor can only be instantiated once.') if window.mercuryInstance
10
10
 
11
11
  @options.visible = true unless (@options.visible == false || @options.visible == 'no')
12
+ @options.saveDataType = 'json' unless (@options.saveDataType == false || @options.saveDataType)
12
13
  @visible = @options.visible
13
14
 
14
15
  window.mercuryInstance = @
@@ -28,15 +29,19 @@ class @Mercury.PageEditor
28
29
  @resize()
29
30
 
30
31
  @iframe.on 'load', => @initializeFrame()
31
- @iframe.get(0).contentWindow.document.location.href = @iframeSrc(null, true)
32
-
32
+ @iframe.one 'load', => @bindEvents()
33
+ @loadIframeSrc(null)
33
34
 
34
35
  initializeFrame: ->
35
36
  try
36
37
  return if @iframe.data('loaded')
37
38
  @iframe.data('loaded', true)
38
39
  Mercury.notify("Opera isn't a fully supported browser, your results may not be optimal.") if jQuery.browser.opera
40
+
41
+ # set document reference of iframe
39
42
  @document = jQuery(@iframe.get(0).contentWindow.document)
43
+
44
+ # inject styles for document to be able to highlight regions and other tools
40
45
  stylesToInject = Mercury.config.injectedStyles.replace(/{{regionClass}}/g, Mercury.config.regions.className)
41
46
  jQuery("<style mercury-styles=\"true\">").html(stylesToInject).appendTo(@document.find('head'))
42
47
 
@@ -47,10 +52,13 @@ class @Mercury.PageEditor
47
52
  iframeWindow.Mercury = Mercury
48
53
  iframeWindow.History = History if window.History && History.Adapter
49
54
 
50
- @bindEvents()
55
+ # (re) initialize the editor against the new document
56
+ @bindDocumentEvents()
51
57
  @resize()
52
58
  @initializeRegions()
53
59
  @finalizeInterface()
60
+
61
+ # trigger ready events
54
62
  Mercury.trigger('ready')
55
63
  jQuery(iframeWindow).trigger('mercury:ready')
56
64
  iframeWindow.Event.fire(iframeWindow, 'mercury:ready') if iframeWindow.Event && iframeWindow.Event.fire
@@ -75,7 +83,11 @@ class @Mercury.PageEditor
75
83
  if region.data('region')
76
84
  region = region.data('region')
77
85
  else
78
- type = (region.data('type') || 'unknown').titleize()
86
+ type = (
87
+ region.data('type') ||
88
+ ( jQuery.type(Mercury.config.regions.determineType) == 'function' && Mercury.config.regions.determineType(region) ) ||
89
+ 'unknown'
90
+ ).titleize()
79
91
  throw Mercury.I18n('Region type is malformed, no data-type provided, or "%s" is unknown for the "%s" region.', type, region.attr('id') || 'unknown') if type == 'Unknown' || !Mercury.Regions[type]
80
92
  if !Mercury.Regions[type].supported
81
93
  Mercury.notify('Mercury.Regions.%s is unsupported in this client. Supported browsers are %s.', type, Mercury.Regions[type].supportedText)
@@ -89,12 +101,26 @@ class @Mercury.PageEditor
89
101
  @santizerElement = jQuery('<div>', {id: 'mercury_sanitizer', contenteditable: 'true', style: 'position:fixed;width:100px;height:100px;top:0;left:-100px;opacity:0;overflow:hidden'})
90
102
  @santizerElement.appendTo(@options.appendTo ? @document.find('body'))
91
103
 
104
+ @snippetToolbar.release() if @snippetToolbar
92
105
  @snippetToolbar = new Mercury.SnippetToolbar(@document)
93
106
 
94
107
  @hijackLinksAndForms()
95
108
  Mercury.trigger('mode', {mode: 'preview'}) unless @options.visible
96
109
 
97
110
 
111
+ bindDocumentEvents: ->
112
+ @document.on 'mousedown', (event) ->
113
+ Mercury.trigger('hide:dialogs')
114
+ if Mercury.region
115
+ Mercury.trigger('unfocus:regions') unless jQuery(event.target).closest(".#{Mercury.config.regions.className}").get(0) == Mercury.region.element.get(0)
116
+
117
+ jQuery(@document).bind 'keydown', (event) =>
118
+ return unless event.ctrlKey || event.metaKey
119
+ if (event.keyCode == 83) # meta+S
120
+ Mercury.trigger('action', {action: 'save'})
121
+ event.preventDefault()
122
+
123
+
98
124
  bindEvents: ->
99
125
  Mercury.on 'initialize:frame', => setTimeout(100, @initializeFrame)
100
126
  Mercury.on 'focus:frame', => @iframe.focus()
@@ -108,20 +134,9 @@ class @Mercury.PageEditor
108
134
  options.already_handled = true
109
135
  action.call(@, options)
110
136
 
111
- @document.on 'mousedown', (event) ->
112
- Mercury.trigger('hide:dialogs')
113
- if Mercury.region
114
- Mercury.trigger('unfocus:regions') unless jQuery(event.target).closest(".#{Mercury.config.regions.className}").get(0) == Mercury.region.element.get(0)
115
-
116
137
  jQuery(window).on 'resize', =>
117
138
  @resize()
118
139
 
119
- jQuery(@document).bind 'keydown', (event) =>
120
- return unless event.ctrlKey || event.metaKey
121
- if (event.keyCode == 83) # meta+S
122
- Mercury.trigger('action', {action: 'save'})
123
- event.preventDefault()
124
-
125
140
  jQuery(window).bind 'keydown', (event) =>
126
141
  return unless event.ctrlKey || event.metaKey
127
142
  if (event.keyCode == 83) # meta+S
@@ -162,13 +177,23 @@ class @Mercury.PageEditor
162
177
 
163
178
 
164
179
  iframeSrc: (url = null, params = false) ->
180
+ # remove the /editor segment of the url if it gets passed through
165
181
  url = (url ? window.location.href).replace(Mercury.config.editorUrlRegEx ?= /([http|https]:\/\/.[^\/]*)\/editor\/?(.*)/i, "$1/$2")
166
182
  url = url.replace(/[\?|\&]mercury_frame=true/gi, '')
183
+ url = url.replace(/\&_=i\d+/gi, '')
167
184
  if params
168
- return "#{url}#{if url.indexOf('?') > -1 then '&' else '?'}mercury_frame=true"
185
+ # add a param allowing the server to know that the request is coming from mercury
186
+ # and add a cache busting param so we don't get stale content
187
+ return "#{url}#{if url.indexOf('?') > -1 then '&' else '?'}mercury_frame=true&_=#{new Date().getTime()}"
169
188
  else
170
189
  return url
171
190
 
191
+ loadIframeSrc: (url)->
192
+ # clear any existing events if we are loading a new iframe to replace the existing one
193
+ @document.off() if @document
194
+
195
+ @iframe.data('loaded', false)
196
+ @iframe.get(0).contentWindow.document.location.href = @iframeSrc(url, true)
172
197
 
173
198
  hijackLinksAndForms: ->
174
199
  for element in jQuery('a, form', @document)
@@ -194,7 +219,7 @@ class @Mercury.PageEditor
194
219
 
195
220
 
196
221
  save: (callback) ->
197
- url = @saveUrl ? Mercury.saveURL ? @iframeSrc()
222
+ url = @saveUrl ? Mercury.saveUrl ? @iframeSrc()
198
223
  data = @serialize()
199
224
  Mercury.log('saving', data)
200
225
  data = jQuery.toJSON(data) unless @options.saveStyle == 'form'
@@ -202,13 +227,14 @@ class @Mercury.PageEditor
202
227
  jQuery.ajax url, {
203
228
  headers: Mercury.ajaxHeaders()
204
229
  type: method || 'POST'
205
- dataType: @options.saveDataType || 'json'
230
+ dataType: @options.saveDataType,
206
231
  data: {content: data, _method: method}
207
232
  success: =>
208
233
  Mercury.changes = false
209
234
  Mercury.trigger('saved')
210
235
  callback() if typeof(callback) == 'function'
211
- error: =>
236
+ error: (response) =>
237
+ Mercury.trigger('save_failed', response)
212
238
  Mercury.notify('Mercury was unable to save to the url: %s', url)
213
239
  }
214
240
 
@@ -217,3 +243,4 @@ class @Mercury.PageEditor
217
243
  serialized = {}
218
244
  serialized[region.name] = region.serialize() for region in @regions
219
245
  return serialized
246
+
@@ -6,7 +6,7 @@ class @Mercury.Panel extends Mercury.Dialog
6
6
 
7
7
  build: ->
8
8
  @element = jQuery('<div>', {class: 'mercury-panel loading', style: 'display:none;'})
9
- @titleElement = jQuery("<h1>#{Mercury.I18n(@options.title)}</h1>").appendTo(@element)
9
+ @titleElement = jQuery("<h1><span>#{Mercury.I18n(@options.title)}</span></h1>").appendTo(@element)
10
10
  @paneElement = jQuery('<div>', {class: 'mercury-panel-pane'}).appendTo(@element)
11
11
 
12
12
  if @options.closeButton
@@ -100,7 +100,7 @@ class @Mercury.Panel extends Mercury.Dialog
100
100
  makeDraggable: ->
101
101
  elementWidth = @element.width()
102
102
  @element.draggable {
103
- handle: 'h1',
103
+ handle: 'h1 span',
104
104
  axis: 'x',
105
105
  opacity: 0.70
106
106
  scroll: false,
@@ -1,7 +1,7 @@
1
1
  class Mercury.PageEditor extends Mercury.PageEditor
2
2
 
3
3
  save: ->
4
- url = @saveUrl ? Mercury.saveURL ? @iframeSrc()
4
+ url = @saveUrl ? Mercury.saveUrl ? @iframeSrc()
5
5
  data = @serializeAsXml()
6
6
  console.log('saving', data)
7
7
  return
@@ -25,4 +25,4 @@ class Mercury.PageEditor extends Mercury.PageEditor
25
25
  for snippetName, snippetProperties of regionProperties['snippets']
26
26
  snippetNodes.push("<#{snippetName} name=\"#{snippetProperties['name']}\"><![CDATA[#{jQuery.toJSON(snippetProperties['options'])}]]></#{snippetName}>")
27
27
  regionNodes.push("<region name=\"#{regionName}\" type=\"#{regionProperties['type']}\"><value>\n<![CDATA[#{regionProperties['value']}]]>\n</value><snippets>#{snippetNodes.join('')}</snippets></region>")
28
- return "<regions>#{regionNodes.join('')}</regions>"
28
+ return "<regions>#{regionNodes.join('')}</regions>"
@@ -93,9 +93,9 @@ class @Mercury.Regions.Editable extends Mercury.Region
93
93
  # read: http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
94
94
  @element.on 'possible:drop', =>
95
95
  return if @previewing
96
- if snippet = @element.find('img[data-snippet]').get(0)
96
+ if snippetPlaceHolder = @element.find('img[data-snippet]').get(0)
97
97
  @focus()
98
- Mercury.Snippet.displayOptionsFor(jQuery(snippet).data('snippet'))
98
+ Mercury.Snippet.displayOptionsFor(jQuery(snippetPlaceHolder).data('snippet'))
99
99
  @document.execCommand('undo', false, null)
100
100
 
101
101
  # custom paste handling: we have to do some hackery to get the pasted content since it's not exposed normally
@@ -509,14 +509,14 @@ class Mercury.Regions.Editable.Selection
509
509
 
510
510
  if @range
511
511
  if @commonAncestor(true).closest('.mercury-snippet').length
512
- lastChild = @context.createTextNode('\00')
512
+ lastChild = @context.createTextNode("\x00")
513
513
  element.appendChild(lastChild)
514
514
  else
515
515
  if element.lastChild && element.lastChild.nodeType == 3 && element.lastChild.textContent.replace(/^[\s+|\n+]|[\s+|\n+]$/, '') == ''
516
516
  lastChild = element.lastChild
517
- element.lastChild.textContent = '\00'
517
+ element.lastChild.textContent = "\x00"
518
518
  else
519
- lastChild = @context.createTextNode('\00')
519
+ lastChild = @context.createTextNode("\x00")
520
520
  element.appendChild(lastChild)
521
521
 
522
522
  if lastChild
@@ -0,0 +1,114 @@
1
+ # The image region is designed for a single, stand-along image. It
2
+ # allows drag & drop uploading of a replacement right into the page,
3
+ # but no editing of other DOM attributes at this time.
4
+ #
5
+ class @Mercury.Regions.Image extends Mercury.Region
6
+ @supported: document.getElementById
7
+ @supportedText: "IE 7+, Chrome 10+, Firefox 4+, Safari 5+, Opera 8+"
8
+
9
+ type = 'image'
10
+
11
+ constructor: (@element, @window, @options = {}) ->
12
+ @type = 'image'
13
+ super
14
+
15
+ build: ->
16
+ # We've going to drive all the interaction with events
17
+ # in bindEvent. Here we just highlight the elements to it
18
+ # appears "changeable" to the user.
19
+ @element.
20
+ addClass( Mercury.config.regions.className ).
21
+ removeClass( "#{Mercury.config.regions.className}-preview" )
22
+
23
+ bindEvents: ->
24
+ # This is standard stuff, take from the region parent
25
+ # class. We copy it instead of super() to avoid the snippet
26
+ # code.
27
+ #
28
+ Mercury.on 'mode', (event, options) => @togglePreview() if options.mode == 'preview'
29
+
30
+ Mercury.on 'focus:frame', =>
31
+ return if @previewing || Mercury.region != @
32
+ @focus()
33
+
34
+ Mercury.on 'action', (event, options) =>
35
+ return if @previewing || Mercury.region != @
36
+ @execCommand(options.action, options) if options.action
37
+
38
+ # The meat. D&D uploading similar to the editable class.
39
+ #
40
+ @element.on 'dragenter', (event) =>
41
+ return if @previewing
42
+ event.preventDefault()
43
+ event.originalEvent.dataTransfer.dropEffect = 'copy'
44
+
45
+ @element.on 'dragover', (event) =>
46
+ return if @previewing
47
+ event.preventDefault()
48
+ event.originalEvent.dataTransfer.dropEffect = 'copy'
49
+
50
+ @element.on 'drop', (event) =>
51
+ return if @previewing
52
+ # handle any files that were dropped
53
+ if event.originalEvent.dataTransfer.files.length
54
+ event.preventDefault()
55
+ # Mercury.uploader will call a Mercury action of insertImage
56
+ # as a callback. If this region is the currently focused one,
57
+ # then we process the callback. Focus, then fire the upload.
58
+ #
59
+ @focus()
60
+ Mercury.uploader(event.originalEvent.dataTransfer.files[0])
61
+
62
+ @element.on 'focus', =>
63
+ @focus()
64
+
65
+ togglePreview: ->
66
+ if @previewing
67
+ @previewing = false
68
+ @build()
69
+ else
70
+ @previewing = true
71
+ @element.
72
+ addClass( "#{Mercury.config.regions.className}-preview" ).
73
+ removeClass( Mercury.config.regions.className )
74
+ Mercury.trigger('region:blurred', {region: @})
75
+
76
+ focus: ->
77
+ return if @previewing
78
+ Mercury.region = @
79
+ Mercury.trigger('region:focused', {region: @})
80
+ Mercury.trigger('region:update', {region: @})
81
+
82
+ execCommand: (action, options = {}) ->
83
+ # Our history is pushed in the parent.
84
+ #
85
+ super
86
+ handler.call(@, options) if handler = Mercury.Regions.Image.actions[action]
87
+
88
+ pushHistory: () ->
89
+ # Store the current image src
90
+ #
91
+ @history.push(src: @element.attr('src'))
92
+
93
+ updateSrc: (src) ->
94
+ @element.attr('src', src)
95
+
96
+ serialize: ->
97
+ return {
98
+ type: @type
99
+ data: @dataAttributes()
100
+ attributes:
101
+ src: @element.attr('src')
102
+ }
103
+
104
+ # Actions. These are all fired by execCommand.
105
+ #
106
+ @actions: {
107
+
108
+ undo: -> if prev = @history.undo() then @updateSrc(prev.src)
109
+
110
+ redo: -> if next = @history.redo() then @updateSrc(next.src)
111
+
112
+ insertImage: (options) -> @updateSrc(options.value.src)
113
+
114
+ }
@@ -0,0 +1,325 @@
1
+ # todo:
2
+ # context for the toolbar buttons and groups needs to change so we can do the following:
3
+ # how to handle context for buttons? if the cursor is within a bold area (**bo|ld**), or selecting it -- it would be
4
+ # nice if we could activate the bold button for instance.
5
+
6
+ class @Mercury.Regions.Simple extends Mercury.Region
7
+ @supported: document.getElementById
8
+ @supportedText: "IE 7+, Chrome 10+, Firefox 4+, Safari 5+, Opera 8+"
9
+
10
+ type = 'simple'
11
+
12
+ constructor: (@element, @window, @options = {}) ->
13
+ @type = 'simple'
14
+ super
15
+
16
+
17
+ build: ->
18
+ if @element.css('display') == 'block'
19
+ width = '100%'
20
+ height = @element.height()
21
+ else
22
+ width = @element.width()
23
+ height = @element.height() # 'auto'
24
+
25
+ value = @element.text()
26
+ @element.removeClass(Mercury.config.regions.className)
27
+ @textarea = jQuery('<textarea>', @document).val(value)
28
+ @textarea.attr('class', @element.attr('class')).addClass('mercury-textarea')
29
+ @textarea.css
30
+ border: 0
31
+ background: 'transparent'
32
+ 'overflow-y': 'hidden'
33
+ width: width
34
+ height: height
35
+ fontFamily: 'inherit'
36
+ fontSize: 'inherit'
37
+ fontWeight: 'inherit'
38
+ fontStyle: 'inherit'
39
+ color: 'inherit'
40
+ 'min-height': 0
41
+ padding: '0'
42
+ margin: 0
43
+ 'border-radius': 0
44
+ display: 'inherit'
45
+ lineHeight: 'inherit'
46
+ textAlign: 'inherit'
47
+ @element.addClass(Mercury.config.regions.className)
48
+ @element.empty().append(@textarea)
49
+
50
+ @container = @element
51
+ @container.data('region', @)
52
+ @element = @textarea
53
+ @resize()
54
+
55
+
56
+ bindEvents: ->
57
+ Mercury.on 'mode', (event, options) => @togglePreview() if options.mode == 'preview'
58
+ Mercury.on 'focus:frame', => @focus() if !@previewing && Mercury.region == @
59
+
60
+ Mercury.on 'action', (event, options) =>
61
+ return if @previewing || Mercury.region != @
62
+ @execCommand(options.action, options) if options.action
63
+
64
+ Mercury.on 'unfocus:regions', =>
65
+ return if @previewing || Mercury.region != @
66
+ @element.blur()
67
+ @container.removeClass('focus')
68
+ Mercury.trigger('region:blurred', {region: @})
69
+
70
+ @element.on 'dragenter', (event) =>
71
+ return if @previewing
72
+ event.preventDefault()
73
+ event.originalEvent.dataTransfer.dropEffect = 'copy'
74
+
75
+ @element.on 'dragover', (event) =>
76
+ return if @previewing
77
+ event.preventDefault()
78
+ event.originalEvent.dataTransfer.dropEffect = 'copy'
79
+
80
+ @element.on 'drop', (event) =>
81
+ return if @previewing
82
+
83
+ # handle dropping snippets
84
+ if Mercury.snippet
85
+ event.preventDefault()
86
+ @focus()
87
+ Mercury.Snippet.displayOptionsFor(Mercury.snippet)
88
+
89
+ # handle any files that were dropped
90
+ if event.originalEvent.dataTransfer.files.length
91
+ event.preventDefault()
92
+ @focus()
93
+ Mercury.uploader(event.originalEvent.dataTransfer.files[0])
94
+
95
+ @element.on 'focus', =>
96
+ return if @previewing
97
+ Mercury.region = @
98
+ @container.addClass('focus')
99
+ Mercury.trigger('region:focused', {region: @})
100
+
101
+ @element.on 'keydown', (event) =>
102
+ return if @previewing
103
+ @resize()
104
+ switch event.keyCode
105
+ when 90 # undo / redo
106
+ return unless event.metaKey
107
+ event.preventDefault()
108
+ if event.shiftKey then @execCommand('redo') else @execCommand('undo')
109
+ return
110
+
111
+ when 13 # enter or return
112
+ selection = @selection()
113
+ text = @element.val()
114
+ start = text.lastIndexOf('\n', selection.start)
115
+ end = text.indexOf('\n', selection.end)
116
+ end = text.length if end < start
117
+ start = text.lastIndexOf('\n', selection.start - 1) if text[start] == '\n'
118
+ if text[start + 1] == '-'
119
+ selection.replace('\n- ', false, true)
120
+ if /\d/.test(text[start + 1])
121
+ lineText = text.substring(start, end)
122
+ if /(\d+)\./.test(lineText)
123
+ number = parseInt(RegExp.$1)
124
+ selection.replace("\n#{number += 1}. ", false, true)
125
+ # Never allow return. Newlines won't survive the
126
+ # change-over to HTML, so just don't encourage their
127
+ # use.
128
+ event.preventDefault()
129
+
130
+ when 9 # tab
131
+ event.preventDefault()
132
+ @execCommand('insertHTML', {value: ' '})
133
+
134
+ @pushHistory(event.keyCode)
135
+
136
+ @element.on 'keyup', =>
137
+ return if @previewing
138
+ Mercury.changes = true
139
+ @resize()
140
+ Mercury.trigger('region:update', {region: @})
141
+
142
+ @element.on 'mouseup', =>
143
+ return if @previewing
144
+ @focus()
145
+ Mercury.trigger('region:focused', {region: @})
146
+
147
+ @element.on 'paste', (event) =>
148
+ return if @previewing || Mercury.region != @
149
+ if @specialContainer
150
+ event.preventDefault()
151
+ return
152
+ return if @pasting
153
+ Mercury.changes = true
154
+ @handlePaste(event.originalEvent)
155
+
156
+
157
+ handlePaste: (event) ->
158
+ # get the text content from the clipboard and fall back to using the sanitizer if unavailable
159
+ @execCommand('insertHTML', {value: event.clipboardData.getData('text/plain').replace(/\n/g, ' ')})
160
+ event.preventDefault()
161
+ return
162
+
163
+
164
+ path: ->
165
+ [@container.get(0)]
166
+
167
+
168
+ focus: ->
169
+ @element.focus()
170
+
171
+
172
+ content: (value = null, filterSnippets = true) ->
173
+ if value != null
174
+ if jQuery.type(value) == 'string'
175
+ @element.val(value)
176
+ else
177
+ @element.val(value.html)
178
+ @selection().select(value.selection.start, value.selection.end)
179
+ else
180
+ return @element.val()
181
+
182
+
183
+ contentAndSelection: ->
184
+ return {html: @content(null, false), selection: @selection().serialize()}
185
+
186
+
187
+ togglePreview: ->
188
+ if @previewing
189
+ @previewing = false
190
+ @element = @container
191
+ @build()
192
+ @focus() if Mercury.region == @
193
+ # @container.addClass(Mercury.config.regions.className).removeClass("#{Mercury.config.regions.className}-preview")
194
+ # @previewElement.hide()
195
+ # @element.show()
196
+ else
197
+ @previewing = true
198
+ @container.addClass("#{Mercury.config.regions.className}-preview").removeClass(Mercury.config.regions.className)
199
+ value = jQuery('<div></div>').text(@element.val()).html()
200
+ @container.html(value)
201
+ Mercury.trigger('region:blurred', {region: @})
202
+
203
+
204
+ execCommand: (action, options = {}) ->
205
+ super
206
+
207
+ handler.call(@, @selection(), options) if handler = Mercury.Regions.Simple.actions[action]
208
+ @resize()
209
+
210
+
211
+ pushHistory: (keyCode) ->
212
+ # when pressing return, delete or backspace it should push to the history
213
+ # all other times it should store if there's a 1 second pause
214
+ keyCodes = [13, 46, 8]
215
+ waitTime = 2.5
216
+ knownKeyCode = keyCodes.indexOf(keyCode) if keyCode
217
+
218
+ # clear any pushes to the history
219
+ clearTimeout(@historyTimeout)
220
+
221
+ # if the key code was return, delete, or backspace store now -- unless it was the same as last time
222
+ if knownKeyCode >= 0 && knownKeyCode != @lastKnownKeyCode # || !keyCode
223
+ @history.push(@contentAndSelection())
224
+ else if keyCode
225
+ # set a timeout for pushing to the history
226
+ @historyTimeout = setTimeout(waitTime * 1000, => @history.push(@contentAndSelection()))
227
+ else
228
+ # push to the history immediately
229
+ @history.push(@contentAndSelection())
230
+
231
+ @lastKnownKeyCode = knownKeyCode
232
+
233
+
234
+ selection: ->
235
+ return new Mercury.Regions.Simple.Selection(@element)
236
+
237
+
238
+ resize: ->
239
+ @element.css({height: @element.get(0).scrollHeight - 100})
240
+ @element.css({height: @element.get(0).scrollHeight});
241
+
242
+
243
+ snippets: ->
244
+
245
+
246
+ # Actions
247
+ @actions: {
248
+
249
+ undo: -> @content(@history.undo())
250
+
251
+ redo: -> @content(@history.redo())
252
+
253
+ insertHTML: (selection, options) ->
254
+ if options.value.get && element = options.value.get(0)
255
+ options.value = jQuery('<div>').html(element).html()
256
+ selection.replace(options.value, false, true)
257
+
258
+ }
259
+
260
+
261
+ # Helper class for managing selection and getting information from it
262
+ class Mercury.Regions.Simple.Selection
263
+
264
+ constructor: (@element) ->
265
+ @el = @element.get(0)
266
+ @getDetails()
267
+
268
+
269
+ serialize: ->
270
+ return {start: @start, end: @end}
271
+
272
+
273
+ getDetails: ->
274
+ @length = @el.selectionEnd - @el.selectionStart
275
+ @start = @el.selectionStart
276
+ @end = @el.selectionEnd
277
+ @text = @element.val().substr(@start, @length)
278
+
279
+
280
+ replace: (text, select = false, placeCursor = false) ->
281
+ @getDetails()
282
+ val = @element.val()
283
+ savedVal = @element.val()
284
+ @element.val(val.substr(0, @start) + text + val.substr(@end, val.length))
285
+ changed = @element.val() != savedVal
286
+ @select(@start, @start + text.length) if select
287
+ @select(@start + text.length, @start + text.length) if placeCursor
288
+ return changed
289
+
290
+
291
+ select: (@start, @end) ->
292
+ @element.focus()
293
+ @el.selectionStart = @start
294
+ @el.selectionEnd = @end
295
+ @getDetails()
296
+
297
+
298
+ wrap: (left, right) ->
299
+ @getDetails()
300
+ @deselectNewLines()
301
+ @replace(left + @text + right, @text != '')
302
+ @select(@start + left.length, @start + left.length) if @text == ''
303
+
304
+
305
+ deselectNewLines: ->
306
+ text = @text
307
+ length = text.replace(/\n+$/g, '').length
308
+ @select(@start, @start + length)
309
+
310
+
311
+ placeMarker: ->
312
+ @wrap('[mercury-marker]', '[mercury-marker]')
313
+
314
+
315
+ removeMarker: ->
316
+ val = @element.val()
317
+ start = val.indexOf('[mercury-marker]')
318
+ return unless start > -1
319
+ end = val.indexOf('[mercury-marker]', start + 1) - '[mercury-marker]'.length
320
+ @element.val(@element.val().replace(/\[mercury-marker\]/g, ''))
321
+ @select(start, end)
322
+
323
+
324
+ textContent: ->
325
+ return @text