mercury-rails 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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