mercury-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +152 -0
  3. data/VERSION +1 -0
  4. data/app/assets/images/mercury/button.png +0 -0
  5. data/app/assets/images/mercury/clippy.png +0 -0
  6. data/app/assets/images/mercury/default-snippet.png +0 -0
  7. data/app/assets/images/mercury/loading-dark.gif +0 -0
  8. data/app/assets/images/mercury/loading-light.gif +0 -0
  9. data/app/assets/images/mercury/search-icon.png +0 -0
  10. data/app/assets/images/mercury/toolbar/editable/buttons.png +0 -0
  11. data/app/assets/images/mercury/toolbar/markupable/buttons.png +0 -0
  12. data/app/assets/images/mercury/toolbar/primary/_expander.png +0 -0
  13. data/app/assets/images/mercury/toolbar/primary/_pressed.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/objectspanel.png +0 -0
  22. data/app/assets/images/mercury/toolbar/primary/preview.png +0 -0
  23. data/app/assets/images/mercury/toolbar/primary/redo.png +0 -0
  24. data/app/assets/images/mercury/toolbar/primary/save.png +0 -0
  25. data/app/assets/images/mercury/toolbar/primary/todospanel.png +0 -0
  26. data/app/assets/images/mercury/toolbar/primary/undo.png +0 -0
  27. data/app/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
  28. data/app/assets/javascripts/mercury.js +30 -0
  29. data/app/assets/javascripts/mercury/dialog.js.coffee +75 -0
  30. data/app/assets/javascripts/mercury/dialogs/backcolor.js.coffee +6 -0
  31. data/app/assets/javascripts/mercury/dialogs/forecolor.js.coffee +6 -0
  32. data/app/assets/javascripts/mercury/dialogs/formatblock.js.coffee +4 -0
  33. data/app/assets/javascripts/mercury/dialogs/objectspanel.js.coffee +10 -0
  34. data/app/assets/javascripts/mercury/dialogs/style.js.coffee +4 -0
  35. data/app/assets/javascripts/mercury/history_buffer.js.coffee +30 -0
  36. data/app/assets/javascripts/mercury/mercury.js.coffee +293 -0
  37. data/app/assets/javascripts/mercury/modal.js.coffee +177 -0
  38. data/app/assets/javascripts/mercury/modals/htmleditor.js.coffee +10 -0
  39. data/app/assets/javascripts/mercury/modals/insertcharacter.js.coffee +4 -0
  40. data/app/assets/javascripts/mercury/modals/insertlink.js.coffee +92 -0
  41. data/app/assets/javascripts/mercury/modals/insertmedia.js.coffee +72 -0
  42. data/app/assets/javascripts/mercury/modals/insertsnippet.js.coffee +11 -0
  43. data/app/assets/javascripts/mercury/modals/inserttable.js.coffee +56 -0
  44. data/app/assets/javascripts/mercury/native_extensions.js.coffee +47 -0
  45. data/app/assets/javascripts/mercury/page_editor.js.coffee +139 -0
  46. data/app/assets/javascripts/mercury/palette.js.coffee +29 -0
  47. data/app/assets/javascripts/mercury/panel.js.coffee +97 -0
  48. data/app/assets/javascripts/mercury/region.js.coffee +103 -0
  49. data/app/assets/javascripts/mercury/regions/editable.js.coffee +546 -0
  50. data/app/assets/javascripts/mercury/regions/markupable.js.coffee +380 -0
  51. data/app/assets/javascripts/mercury/regions/snippetable.js.coffee +127 -0
  52. data/app/assets/javascripts/mercury/select.js.coffee +40 -0
  53. data/app/assets/javascripts/mercury/snippet.js.coffee +92 -0
  54. data/app/assets/javascripts/mercury/snippet_toolbar.js.coffee +69 -0
  55. data/app/assets/javascripts/mercury/statusbar.js.coffee +25 -0
  56. data/app/assets/javascripts/mercury/table_editor.js.coffee +266 -0
  57. data/app/assets/javascripts/mercury/toolbar.button.js.coffee +152 -0
  58. data/app/assets/javascripts/mercury/toolbar.button_group.js.coffee +42 -0
  59. data/app/assets/javascripts/mercury/toolbar.expander.js.coffee +56 -0
  60. data/app/assets/javascripts/mercury/toolbar.js.coffee +72 -0
  61. data/app/assets/javascripts/mercury/tooltip.js.coffee +67 -0
  62. data/app/assets/javascripts/mercury/uploader.js.coffee +213 -0
  63. data/app/assets/javascripts/mercury/websocket.js.coffee +34 -0
  64. data/app/assets/stylesheets/mercury.css +31 -0
  65. data/app/assets/stylesheets/mercury/dialog.scss +178 -0
  66. data/app/assets/stylesheets/mercury/mercury.scss +119 -0
  67. data/app/assets/stylesheets/mercury/modal.scss +192 -0
  68. data/app/assets/stylesheets/mercury/statusbar.scss +23 -0
  69. data/app/assets/stylesheets/mercury/toolbar.scss +417 -0
  70. data/app/assets/stylesheets/mercury/tooltip.scss +26 -0
  71. data/app/assets/stylesheets/mercury/uploader.scss +109 -0
  72. data/app/controllers/images_controller.rb +19 -0
  73. data/app/controllers/mercury_controller.rb +20 -0
  74. data/app/models/image.rb +14 -0
  75. data/app/views/layouts/mercury.html.haml +12 -0
  76. data/app/views/mercury/modals/character.html.haml +252 -0
  77. data/app/views/mercury/modals/htmleditor.html.haml +8 -0
  78. data/app/views/mercury/modals/link.html.haml +31 -0
  79. data/app/views/mercury/modals/media.html.haml +33 -0
  80. data/app/views/mercury/modals/sanitizer.html.haml +4 -0
  81. data/app/views/mercury/modals/table.html.haml +49 -0
  82. data/app/views/mercury/palettes/backcolor.html.haml +79 -0
  83. data/app/views/mercury/palettes/forecolor.html.haml +79 -0
  84. data/app/views/mercury/panels/history.html.haml +0 -0
  85. data/app/views/mercury/panels/notes.html.haml +0 -0
  86. data/app/views/mercury/panels/snippets.html.haml +10 -0
  87. data/app/views/mercury/selects/formatblock.html.haml +10 -0
  88. data/app/views/mercury/selects/style.html.haml +4 -0
  89. data/app/views/mercury/snippets/example.html.haml +2 -0
  90. data/app/views/mercury/snippets/example_options.html.haml +16 -0
  91. data/config/engine.rb +6 -0
  92. data/config/routes.rb +15 -0
  93. data/db/migrate/20110526035601_create_images.rb +11 -0
  94. data/features/editing/basic.feature +11 -0
  95. data/features/step_definitions/debug_steps.rb +14 -0
  96. data/features/step_definitions/web_steps.rb +211 -0
  97. data/features/support/env.rb +46 -0
  98. data/features/support/paths.rb +35 -0
  99. data/features/support/selectors.rb +42 -0
  100. data/lib/mercury-rails.rb +4 -0
  101. data/log/.gitkeep +0 -0
  102. data/mercury-rails.gemspec +230 -0
  103. data/spec/javascripts/mercury/dialog_spec.js.coffee +258 -0
  104. data/spec/javascripts/mercury/history_buffer_spec.js.coffee +79 -0
  105. data/spec/javascripts/mercury/mercury_spec.js.coffee +52 -0
  106. data/spec/javascripts/mercury/native_extensions_spec.js.coffee +66 -0
  107. data/spec/javascripts/mercury/page_editor_spec.js.coffee +435 -0
  108. data/spec/javascripts/mercury/palette_spec.js.coffee +51 -0
  109. data/spec/javascripts/mercury/panel_spec.js.coffee +147 -0
  110. data/spec/javascripts/mercury/region_spec.js.coffee +261 -0
  111. data/spec/javascripts/mercury/regions/_editable_.js.coffee +0 -0
  112. data/spec/javascripts/mercury/regions/_markupable_.js.coffee +0 -0
  113. data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +368 -0
  114. data/spec/javascripts/mercury/select_spec.js.coffee +51 -0
  115. data/spec/javascripts/mercury/snippet_spec.js.coffee +246 -0
  116. data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +186 -0
  117. data/spec/javascripts/mercury/statusbar_spec.js.coffee +78 -0
  118. data/spec/javascripts/mercury/table_editor_spec.js.coffee +192 -0
  119. data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +92 -0
  120. data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +341 -0
  121. data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +120 -0
  122. data/spec/javascripts/mercury/toolbar_spec.js.coffee +152 -0
  123. data/spec/javascripts/mercury/tooltip_spec.js.coffee +188 -0
  124. data/spec/javascripts/mercury/uploader_spec.js.coffee +512 -0
  125. data/spec/javascripts/responses/blank.html +1 -0
  126. data/spec/javascripts/spec_helper.js +513 -0
  127. data/spec/javascripts/templates/mercury/dialog.html +2 -0
  128. data/spec/javascripts/templates/mercury/page_editor.html +24 -0
  129. data/spec/javascripts/templates/mercury/palette.html +16 -0
  130. data/spec/javascripts/templates/mercury/panel.html +16 -0
  131. data/spec/javascripts/templates/mercury/region.html +2 -0
  132. data/spec/javascripts/templates/mercury/regions/snippetable.html +4 -0
  133. data/spec/javascripts/templates/mercury/select.html +16 -0
  134. data/spec/javascripts/templates/mercury/snippet.html +1 -0
  135. data/spec/javascripts/templates/mercury/snippet_toolbar.html +16 -0
  136. data/spec/javascripts/templates/mercury/statusbar.html +7 -0
  137. data/spec/javascripts/templates/mercury/table_editor.html +65 -0
  138. data/spec/javascripts/templates/mercury/toolbar.button.html +64 -0
  139. data/spec/javascripts/templates/mercury/toolbar.button_group.html +9 -0
  140. data/spec/javascripts/templates/mercury/toolbar.expander.html +18 -0
  141. data/spec/javascripts/templates/mercury/toolbar.html +10 -0
  142. data/spec/javascripts/templates/mercury/tooltip.html +12 -0
  143. data/spec/javascripts/templates/mercury/uploader.html +11 -0
  144. data/vendor/assets/javascripts/jquery-1.6.js +8865 -0
  145. data/vendor/assets/javascripts/jquery-ui-1.8.13.custom.min.js +249 -0
  146. data/vendor/assets/javascripts/jquery-ui-1.8.13.sortable.custom.js +1078 -0
  147. data/vendor/assets/javascripts/jquery.easing.js +173 -0
  148. data/vendor/assets/javascripts/jquery.json2.js +178 -0
  149. data/vendor/assets/javascripts/jquery.serialize_object.js +16 -0
  150. data/vendor/assets/javascripts/jquery.ujs.js +289 -0
  151. data/vendor/assets/javascripts/liquidmetal.js +88 -0
  152. data/vendor/assets/javascripts/showdown.js +1362 -0
  153. metadata +364 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jeremy Jackson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,152 @@
1
+ = Mercury Editor
2
+
3
+ Mercury Editor is a fully featured editor much like TinyMCE or CKEditor, but with a different usage paradigm. It
4
+ expects that an entire page is something that can be editable, and allows different types of editable regions to be
5
+ specified. It displays a single toolbar for every region on the page, and uses the HTML5 contentEditable features on
6
+ block elements, instead of iframes, which allows for CSS to be applied in ways that most other editors can't handle.
7
+
8
+ Mercury has been written using CoffeeScript and jQuery for the Javascript portions, and is written on top of Rails 3.1.
9
+
10
+
11
+ == Browser Support
12
+
13
+ Mercury has been written for the future, and thus doesn't support legacy browsers or browsers that don't follow the W3C
14
+ specifications for content editing. Any browser will be supported if they support the W3C specification in the future,
15
+ but there aren't plans for adding support for alternate implementations at this time.
16
+
17
+ Supported Browsers:
18
+ * Chrome 10+
19
+ * Safari 5+
20
+ * Firefox 4+
21
+
22
+
23
+ == The Story
24
+
25
+ I was looking for a fully featured editor that didn't use iframes, and there weren't any decent ones. My primary goal
26
+ was to have areas that were editable, but that also allowed CSS to flow naturally. A few have cropped up since then
27
+ (Aloha Editor for instance), and as good as they are, none had all the features I was looking for.
28
+
29
+ Mercury was written to be as simple as possible, while also providing an advanced feature set. Instead of complex
30
+ configuration, we chose a mix of configuration and code simplicity, which should give you a much better chance at
31
+ customizing Mercury to suit your exact needs. This doesn't mean there's not configuration, and what's there provides
32
+ much of what you'll need, but efforts were taken to keep it simple and powerful.
33
+
34
+ Even though it's a great editor, Mercury Editor may not be the best for your needs (based on browser support, javascript
35
+ library, etc.) so here's a list of some other editors that you might want to check out:
36
+
37
+ * {Aloha Editor}[http://www.aloha-editor.org/]
38
+ * {jHtmlArea}[http://jhtmlarea.codeplex.com/]
39
+ * {MarkItUp}[http://markitup.jaysalvat.com/home/]
40
+ * {TinyMCE}[http://tinymce.moxiecode.com/]
41
+ * {CKEditor}[http://ckeditor.com/]
42
+ * {NicEdit}[http://nicedit.com/]
43
+
44
+
45
+ == Project Details
46
+
47
+ === WYSIWYG Editors Suck
48
+
49
+ They just do. Which as I've learned, is primarily due to the browser implementations. Don't get me wrong, what the
50
+ browsers have implemented is amazing, because it's hard stuff, plain and simple. But if you're expecting a WYSIWYG
51
+ editor to solve all your content problems you're wrong. A better perception is that it will solve many of them, but
52
+ shifts some into a new area.
53
+
54
+ With that being said, Mercury tries to solve many of those issues and succeeds to a great degree, but alas, it's nearly
55
+ impossible to address everything, and the browsers don't expose enough to fix some things. This is true for every
56
+ editor that I've looked into as well.
57
+
58
+ It's important to understand this, and the details are more suited for long nerdy blog posts, so they won't be covered
59
+ here.
60
+
61
+ === The Code and Why
62
+
63
+ ==== CoffeeScript
64
+
65
+ Mercury has been written entirely in CoffeeScript because it simplifies a lot of the patterns that are used, and allows
66
+ for very readable code. The goal was to provide good readable code that could be adjusted based on need, instead of a
67
+ complex configuration that makes the code harder to understand and tweak.
68
+
69
+ ==== jQuery
70
+
71
+ jQuery was used as the javascript library, but is primarily used for the selectors, traversing, and manipulating the
72
+ DOM. Chaining is kept to a minimum for readability, and even though much of Mercury could've been written as jQuery
73
+ plugins, it was not.
74
+
75
+ ==== Rails
76
+
77
+ With the asset handling that comes bundled with Rails 3.1, Rails Engines, and the gem tools, there really wasn't any
78
+ other option. The javascript from Mercury can be used by any back end system, and isn't limited to Rails. Many of the
79
+ features do require a back end, and that stuff would have to be rewritten in whatever language you wanted support for.
80
+ The coffeescript files can be found in the repo, and I would be fully supportive of anyone who wanted to add support for
81
+ different back end frameworks or languages.
82
+
83
+ ==== Specs / Integration Tests
84
+
85
+ Mercury is fully tested using Jasmine (via Evergreen) and Cucumber. You can clone the project to run the full suite.
86
+
87
+ rake spec:javascripts
88
+ rake cucumber
89
+
90
+
91
+ == Features
92
+
93
+ The feature list is actually pretty long, so here's a short list that need highlighting.
94
+
95
+ * Previewing: Preview content while you're working to see exactly how it'll look.
96
+ * Link Tools: Insert and edit links, including TOC/Bookmark links.
97
+ * Media Tools: Insert and edit images, youtube videos, and vimeo videos.
98
+ * Image Uploading: Drag images from your desktop and they'll be automatically uploaded and inserted.
99
+ * Table Editing: Advanced table editing and creation.
100
+ * Snippets: Insert and edit predefined and reusable bits of markup/code using drag and drop.
101
+ * Notes: Attach notes to any page and communicate with other content authors.
102
+ * Colaborative Editing: Edit any page that others are editing at the same time and see their changes in real time.
103
+
104
+
105
+ == Installation
106
+
107
+ Include the gem in your Gemfile
108
+
109
+ gem 'mercury-rails'
110
+
111
+ Then just bundle install and you should be all set. Browse to any existing content page and prefix it's url with /edit,
112
+ so for instance, localhost:3000/edit/content/page to edit the content on /content/page.
113
+
114
+
115
+ == Usage
116
+
117
+ Mercury has an expectation that content regions will be on the page (not required, but probably useful). To define
118
+ content regions that Mercury will make editable you need to add a `mercury-region` class attribute to a div. Then
119
+ specify what region type by using the `data-type` attribute -- which can be *editable*, *markupable*, or *snippetable*.
120
+ Region types are outlined below.
121
+
122
+ <div class="mercury-region" data-type="editable">
123
+ default content
124
+ </div>
125
+
126
+
127
+ == Region Types
128
+
129
+ === Editable
130
+
131
+ Editable Regions are HTML markup, and use the HTML5 contentEditable feature. This is the core of what Mercury is about,
132
+ and provides the most flexibility and visual representation of what the content will look like when saved.
133
+
134
+ === Markupable
135
+
136
+ These regions are based on Markdown syntax (specifically the github flavored version), and isn't as full featured as the
137
+ editable region type -- primarily because markdown is meant to be simple, so to keep it such you can't do things like
138
+ set colors etc. This region type is super useful if you want to keep the markup clean and simple.
139
+
140
+ === Snippetable
141
+
142
+ Snippetable regions only allow snippets. There isn't any content editing in these regions, but snippets can sometimes
143
+ be the way to go with complex markup and functionality. Snippets are basically chunks of reusable markup, that can be
144
+ defined by a developer and placed into content regions later. More on this below.
145
+
146
+
147
+ == Snippets
148
+
149
+ Snippets are reusable and configurable chunks of markup. They can be defined by developers, and then placed anywhere in
150
+ content regions. When you drag a snippet into a region you'll be prompted to enter options, and after entering options
151
+ the snippet will be rendered into the page as a preview. Snippets can be dragged around (in snippetable regions) and
152
+ edited or removed.
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,30 @@
1
+ /*!
2
+ * Mercury Editor is a Coffeescript and jQuery based WYSIWYG editor. Mercury Editor utilizes the HTML5 ContentEditable
3
+ * spec to allow editing sections of a given page (instead of using iframes) and provides an editing experience that's as
4
+ * realistic as possible. By not using iframes for editable regions it allows CSS to behave naturally.
5
+ *
6
+ * Mercury Editor was written for the future, and doesn't attempt to support legacy implementations of document editing.
7
+ *
8
+ * Currently supported browsers are
9
+ * - Firefox 4+
10
+ * - Chrome 10+
11
+ * - Safari 5+
12
+ *
13
+ * Copyright (c) 2011 Jeremy Jackson
14
+ *
15
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
16
+ * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
17
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
18
+ * persons to whom the Software is furnished to do so, subject to the following conditions:
19
+ *
20
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
21
+ * Software.
22
+ *
23
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
25
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ *
28
+ *= require_self
29
+ *= require mercury/mercury
30
+ */
@@ -0,0 +1,75 @@
1
+ class @Mercury.Dialog
2
+
3
+ constructor: (@url, @name, @options = {}) ->
4
+ @button = @options.for
5
+
6
+ @build()
7
+ @bindEvents()
8
+ @preload()
9
+
10
+
11
+ build: ->
12
+ @element = $('<div>', {class: "mercury-dialog mercury-#{@name}-dialog loading", style: 'display:none'})
13
+ @element.appendTo($(@options.appendTo).get(0) ? 'body')
14
+
15
+
16
+ bindEvents: ->
17
+ @element.mousedown (event) -> event.stopPropagation()
18
+
19
+
20
+ preload: ->
21
+ @load() if @options.preload
22
+
23
+
24
+ toggle: (element) ->
25
+ if @visible then @hide() else @show()
26
+
27
+
28
+ resize: ->
29
+ @show()
30
+
31
+
32
+ show: ->
33
+ Mercury.trigger('hide:dialogs', @)
34
+ @visible = true
35
+ if @loaded
36
+ @element.css({width: 'auto', height: 'auto'})
37
+ @position(@visible)
38
+ @appear()
39
+ else
40
+ @position()
41
+ @appear()
42
+
43
+
44
+ position: (keepVisible) ->
45
+
46
+
47
+ appear: ->
48
+ @element.css({display: 'block', opacity: 0})
49
+ @element.animate {opacity: .95}, 200, 'easeInOutSine', =>
50
+ @load(=> @resize()) unless @loaded
51
+
52
+
53
+ hide: ->
54
+ @element.hide()
55
+ @visible = false
56
+
57
+
58
+ load: (callback) ->
59
+ return unless @url
60
+ $.ajax @url, {
61
+ success: (data) =>
62
+ @loadContent(data)
63
+ Mercury.dialogHandlers[@name].call(@) if Mercury.dialogHandlers[@name]
64
+ callback() if callback
65
+ error: =>
66
+ @hide()
67
+ @button.removeClass('pressed') if @button
68
+ alert("Mercury was unable to load #{@url} for the #{@name} dialog.")
69
+ }
70
+
71
+
72
+ loadContent: (data) ->
73
+ @loaded = true
74
+ @element.removeClass('loading')
75
+ @element.html(data)
@@ -0,0 +1,6 @@
1
+ @Mercury.dialogHandlers.backcolor = ->
2
+ @element.find('.picker, .last-picked').click (event) =>
3
+ color = $(event.target).css('background-color')
4
+ @element.find('.last-picked').css({background: color})
5
+ @button.css({backgroundColor: color})
6
+ Mercury.trigger('action', {action: 'backcolor', value: color})
@@ -0,0 +1,6 @@
1
+ @Mercury.dialogHandlers.forecolor = ->
2
+ @element.find('.picker, .last-picked').click (event) =>
3
+ color = $(event.target).css('background-color')
4
+ @element.find('.last-picked').css({background: color})
5
+ @button.css({backgroundColor: color})
6
+ Mercury.trigger('action', {action: 'forecolor', value: color})
@@ -0,0 +1,4 @@
1
+ @Mercury.dialogHandlers.formatblock = ->
2
+ @element.find('[data-tag]').click (event) =>
3
+ tag = $(event.target).data('tag')
4
+ Mercury.trigger('action', {action: 'formatblock', value: tag})
@@ -0,0 +1,10 @@
1
+ @Mercury.dialogHandlers.objectspanel = ->
2
+ # make the filter work
3
+ @element.find('input.filter').keyup =>
4
+ value = @element.find('input.filter').val()
5
+ for snippet in @element.find('li[data-filter]')
6
+ if LiquidMetal.score($(snippet).data('filter'), value) == 0 then $(snippet).hide() else $(snippet).show()
7
+
8
+ # when an element is dragged, set it so we have a global object
9
+ @element.find('img[data-snippet]').bind 'dragstart', (event) ->
10
+ Mercury.snippet = $(@).data('snippet')
@@ -0,0 +1,4 @@
1
+ @Mercury.dialogHandlers.style = ->
2
+ @element.find('[data-class]').click (event) =>
3
+ className = $(event.target).attr('class')
4
+ Mercury.trigger('action', {action: 'style', value: className})
@@ -0,0 +1,30 @@
1
+ class @Mercury.HistoryBuffer
2
+
3
+ constructor: (@maxLength = 200) ->
4
+ @index = 0
5
+ @stack = []
6
+ @markerRegExp = /<em class="mercury-marker"><\/em>/g
7
+
8
+
9
+ push: (item) ->
10
+ if $.type(item) == 'string'
11
+ return if @stack[@index] && @stack[@index].replace(@markerRegExp, '') == item.replace(@markerRegExp, '')
12
+ else if $.type(item) == 'object' && item.html
13
+ return if @stack[@index] && @stack[@index].html == item.html
14
+
15
+ @stack = @stack[0...@index + 1]
16
+ @stack.push(item)
17
+ @stack.shift() if @stack.length > @maxLength
18
+ @index = @stack.length - 1
19
+
20
+
21
+ undo: ->
22
+ return null if @index < 1
23
+ @index -= 1
24
+ return @stack[@index]
25
+
26
+
27
+ redo: ->
28
+ return null if @index >= @stack.length - 1
29
+ @index += 1
30
+ return @stack[@index]
@@ -0,0 +1,293 @@
1
+ #
2
+ #= require jquery-1.6
3
+ #= require jquery-ui-1.8.13.custom.min
4
+ #= require jquery-ui-1.8.13.sortable.custom
5
+ #= require jquery.easing
6
+ #= require jquery.json2
7
+ #= require jquery.ujs
8
+ #= require jquery.serialize_object
9
+ #= require liquidmetal
10
+ #
11
+ #= require_self
12
+ #= require ./native_extensions
13
+ #= require ./page_editor
14
+ #= require ./history_buffer
15
+ #= require ./table_editor
16
+ #= require ./dialog
17
+ #= require ./palette
18
+ #= require ./select
19
+ #= require ./panel
20
+ #= require ./modal
21
+ #= require ./statusbar
22
+ #= require ./toolbar
23
+ #= require ./toolbar.button
24
+ #= require ./toolbar.button_group
25
+ #= require ./toolbar.expander
26
+ #= require ./tooltip
27
+ #= require ./snippet
28
+ #= require ./snippet_toolbar
29
+ #= require ./region
30
+ #= require ./uploader
31
+ #= require_tree ./regions
32
+ #= require_tree ./dialogs
33
+ #= require_tree ./modals
34
+ #
35
+ #= require showdown
36
+ #
37
+
38
+ @Mercury = {
39
+
40
+ version: 1.0
41
+
42
+
43
+ # No IE support yet because it doesn't follow the W3C standards for HTML5 contentEditable (aka designMode).
44
+ supported: document.getElementById && document.designMode && !$.browser.konqueror && !$.browser.msie
45
+
46
+
47
+ # Silent mode disables things like asking about unsaved changes before leaving the page.
48
+ silent: true
49
+
50
+
51
+ # Turning debug mode on will log events and other various things (using console.log if available).
52
+ debug: true
53
+
54
+
55
+ # Configuration
56
+ config: {
57
+
58
+ # Pasting (in Chrome/Safari)
59
+ #
60
+ # When copying content using webkit, it embeds all the user defined styles (from the css files) into the html style
61
+ # attributes directly. When pasting this content into HTML5 contentEditable elements it leaves these intact. This
62
+ # can be a desired feature, or an annoyance, so you can enable it or disable it here. Keep in mind this will only
63
+ # change the behavior in webkit, as gecko doesn't do this.
64
+ #
65
+ cleanStylesOnPaste: true
66
+
67
+
68
+ # Image Uploading (in supported regions)
69
+ #
70
+ # If you drag images (while pressing shift) from your desktop into regions that support it, it will be uploaded to
71
+ # the server and inserted into the region. This configuration allows you to specify if you want to disable/enable
72
+ # this feature, the accepted mime-types, file size restrictions, and other things related to uploading.
73
+ #
74
+ uploading:
75
+ enabled: true
76
+ allowedMimeTypes: ['image/jpeg', 'image/gif', 'image/png']
77
+ maxFileSize: 1235242880 # bytes (5 Mb by default)
78
+ inputName: 'image[image]'
79
+ url: '/images'
80
+
81
+
82
+ # Toolbars
83
+ #
84
+ # This is where you can customize the toolbars by adding or removing buttons, or changing them and their behaviors.
85
+ # Any top level object put here will create a new toolbar. Buttons are simply nested inside the toolbars, along
86
+ # with button groups.
87
+ #
88
+ # Buttons can be grouped. A button group is simply a way to wrap buttons for styling, and can also handle enabling
89
+ # or disabling all the buttons within it by using a context. The table button group is a good example of this.
90
+ #
91
+ # The primary toolbar is always visible, but any other toolbar should have a name based on what type of region it's
92
+ # for. The toolbar will be enabled/disabled base on what region currently has focus. Some toolbars are custom (the
93
+ # snippetable toolbar for instance), and to denote that use _custom: true. You can then build the toolbar yourself
94
+ # with it's own behavior.
95
+ #
96
+ # It's important to note that each of the button names (keys), in each toolbar object must be unique, regardless of
97
+ # if it's in a button group, or nested, etc. This is because styling is applied to them by name.
98
+ #
99
+ # Button format: [label, description, {type: action, type: action, etc}] The available button types are:
100
+ #
101
+ # toggle: toggles on or off when clicked, otherwise behaves like a button
102
+ # modal: opens a modal window, expects the action to be one of:
103
+ # a string url
104
+ # a function that returns a string url
105
+ # panel: opens a panel dialog, expects the action to be one of:
106
+ # a string url
107
+ # a function that returns a string url
108
+ # palette: opens a palette window, expects the action to be one of:
109
+ # a string url
110
+ # a function that returns a string url
111
+ # select: opens a pulldown style window, expects the action to be one of:
112
+ # a string url
113
+ # a function that returns a string url
114
+ # context: calls a callback function, expects the action to be:
115
+ # a function that returns a boolean to highlight the button
116
+ # note: if a function isn't provided, the key will be passed to the contextHandler, in which case a
117
+ # default context will be used (for more info read the Contexts section below)
118
+ # mode: toggle a given mode in the editor, expects the action to be:
119
+ # a string, denoting the name of the mode
120
+ # note: it's assumed that when a specific mode is turned on, all other modes will be turned off, which
121
+ # happens automatically, thus putting the editor into a specific "state"
122
+ # regions: allows buttons to be enabled/disabled based on what region type has focus, expects the action to be:
123
+ # an array of region types (eg. ['editable', 'markupable']
124
+ # preload: allows some dialog views to be loaded whtn the button is created instead of on first open, expects:
125
+ # a boolean
126
+ # note: only used for panels, selects, and palettes
127
+ #
128
+ # Separators are any "button" that's not an array, and are expected to be a string. You can use two different
129
+ # separator styles: line ('-'), and spacer (' ').
130
+ #
131
+ toolbars:
132
+ primary:
133
+ save: ['Save', 'Save this page']
134
+ preview: ['Preview', 'Preview this page', {toggle: true, mode: true}]
135
+ sep1: ' '
136
+ undoredo:
137
+ undo: ['Undo', 'Undo your last action']
138
+ redo: ['Redo', 'Redo your last action']
139
+ sep: ' '
140
+ insertlink: ['Link', 'Insert Link', {modal: '/mercury/modals/link', regions: ['editable', 'markupable']}]
141
+ insertmedia: ['Media', 'Insert Media (images and videos)', {modal: '/mercury/modals/media', regions: ['editable', 'markupable']}]
142
+ inserttable: ['Table', 'Insert Table', {modal: '/mercury/modals/table', regions: ['editable', 'markupable']}]
143
+ insertcharacter: ['Character', 'Special Characters', {modal: '/mercury/modals/character', regions: ['editable', 'markupable']}]
144
+ objectspanel: ['Snippet', 'Snippet Panel', {panel: '/mercury/panels/snippets'}]
145
+ sep2: ' '
146
+ historypanel: ['History', 'Page Version History', {panel: '/mercury/panels/history'}]
147
+ sep3: ' '
148
+ notespanel: ['Notes', 'Page Notes', {panel: '/mercury/panels/notes'}]
149
+
150
+ editable:
151
+ _regions: ['editable', 'markupable']
152
+ predefined:
153
+ style: ['Style', null, {select: '/mercury/selects/style', preload: true}]
154
+ sep1: ' '
155
+ formatblock: ['Block Format', null, {select: '/mercury/selects/formatblock', preload: true}]
156
+ sep2: '-'
157
+ colors:
158
+ _regions: ['editable']
159
+ backcolor: ['Background Color', null, {palette: '/mercury/palettes/backcolor', context: true, preload: true}]
160
+ sep1: ' '
161
+ forecolor: ['Text Color', null, {palette: '/mercury/palettes/forecolor', context: true, preload: true}]
162
+ sep2: '-'
163
+ decoration:
164
+ bold: ['Bold', null, {context: true}]
165
+ italic: ['Italicize', null, {context: true}]
166
+ overline: ['Overline', null, {context: true, regions: ['editable']}]
167
+ strikethrough: ['Strikethrough', null, {context: true, regions: ['editable']}]
168
+ underline: ['Underline', null, {context: true, regions: ['editable']}]
169
+ sep: '-'
170
+ script:
171
+ subscript: ['Subscript', null, {context: true}]
172
+ superscript: ['Superscript', null, {context: true}]
173
+ sep: '-'
174
+ justify:
175
+ _regions: ['editable']
176
+ justifyleft: ['Align Left', null, {context: true}]
177
+ justifycenter: ['Center', null, {context: true}]
178
+ justifyright: ['Align Right', null, {context: true}]
179
+ justifyfull: ['Justify Full', null, {context: true}]
180
+ sep: '-'
181
+ list:
182
+ insertunorderedlist: ['Unordered List', null, {context: true}]
183
+ insertorderedlist: ['Numbered List', null, {context: true}]
184
+ sep: '-'
185
+ indent:
186
+ outdent: ['Decrease Indentation', null]
187
+ indent: ['Increase Indentation', null]
188
+ sep: '-'
189
+ table:
190
+ _context: true
191
+ _regions: ['editable']
192
+ insertrowbefore: ['Insert Table Row', 'Insert a table row before the cursor']
193
+ insertrowafter: ['Insert Table Row', 'Insert a table row after the cursor']
194
+ deleterow: ['Delete Table Row', 'Delete this table row']
195
+ insertcolumnbefore: ['Insert Table Column', 'Insert a table column before the cursor']
196
+ insertcolumnafter: ['Insert Table Column', 'Insert a table column after the cursor']
197
+ deletecolumn: ['Delete Table Column', 'Delete this table column']
198
+ sep1: ' '
199
+ increasecolspan: ['Increase Cell Columns', 'Increase the cells colspan']
200
+ decreasecolspan: ['Decrease Cell Columns', 'Decrease the cells colspan and add a new cell']
201
+ increaserowspan: ['Increase Cell Rows', 'Increase the cells rowspan']
202
+ decreaserowspan: ['Decrease Cell Rows', 'Decrease the cells rowspan and add a new cell']
203
+ sep2: '-'
204
+ rules:
205
+ horizontalrule: ['Horizontal Rule', 'Insert a horizontal rule']
206
+ sep1: '-'
207
+ formatting:
208
+ _regions: ['editable']
209
+ removeformatting: ['Remove Formatting', 'Remove formatting for the selection']
210
+ sep2: ' '
211
+ editors:
212
+ _regions: ['editable']
213
+ htmleditor: ['Edit HTML', 'Edit the HTML content'] # example behavior below
214
+
215
+ snippetable:
216
+ _custom: true
217
+ actions:
218
+ editsnippet: ['Edit Snippet Settings', null]
219
+ sep1: ' '
220
+ removesnippet: ['Remove Snippet', null]
221
+
222
+
223
+ # Behaviors
224
+ #
225
+ # Behaviors are used to change the default behaviors of a given region type when a given button is clicked. For
226
+ # example, you may prefer to add HR tags using an HR wrapped within a div with a classname (for styling). You can
227
+ # add your own complex behaviors here.
228
+ #
229
+ # You can see how the behavior matches up directly with the button name. It's also important to note that the
230
+ # callback functions are executed within the scope of the given region, so you have access to all it's methods.
231
+ # todo: figure out how this impacts different regions.. should they go away, or should they get moved into region types?
232
+ behaviors:
233
+ horizontalrule: (selection) -> selection.replace('<hr/>')
234
+
235
+ htmleditor: ->
236
+ Mercury.modal '/mercury/modals/htmleditor', {
237
+ title: 'HTML Editor',
238
+ fullHeight: true,
239
+ handler: 'htmleditor'
240
+ }
241
+
242
+
243
+ # Contexts
244
+ #
245
+ # Contexts are used callback functions used for highlighting and disabling/enabling buttons and buttongroups. When
246
+ # the cursor enters an element within an html region for instance we want to disable or highlight buttons based on
247
+ # the properties of the given node. You can see some examples of contexts in:
248
+ #
249
+ # Mercury.Toolbar.Button.contexts
250
+ # and
251
+ # Mercury.Toolbar.ButtonGroup.contexts
252
+ #
253
+
254
+
255
+ # Styles
256
+ #
257
+ # Mercury tries to stay as much out of your code as possible, but because regions appear within your document we
258
+ # need to include a few styles to indicate regions, as well as the different states of them (eg. focused). These
259
+ # styles are injected into your document, and as simple as they might be, you may want to change them. You can do
260
+ # so here.
261
+ #
262
+ injectedStyles: '''
263
+ .mercury-region, .mercury-textarea { min-height: 10px; outline: 1px dotted #09F }
264
+ .mercury-textarea { box-sizing: border-box; -moz-box-sizing: border-box; resize: vertical; }
265
+ .mercury-region:focus, .mercury-region.focus, .mercury-textarea.focus { outline: none; -webkit-box-shadow: 0 0 10px #09F, 0 0 1px #045; box-shadow: 0 0 10px #09F, 0 0 1px #045 }
266
+ .mercury-region:after { content: '\00a0'; display: block; visibility: hidden; clear: both; height: 0; overflow: hidden; }
267
+ .mercury-region table, .mercury-region td { border: 1px dotted red; }
268
+ '''
269
+ }
270
+
271
+
272
+ # Custom event and logging methods
273
+ bind: (eventName, callback) ->
274
+ $(document).bind("mercury:#{eventName}", callback)
275
+
276
+
277
+ trigger: (eventName, options) ->
278
+ Mercury.log(eventName, options)
279
+ $(document).trigger("mercury:#{eventName}", options)
280
+
281
+
282
+ log: ->
283
+ if Mercury.debug && console
284
+ return if arguments[0] == 'hide:toolbar'
285
+ try console.debug(arguments) catch e
286
+
287
+
288
+ # Mercury object namespaces
289
+ Regions: {}
290
+ modalHandlers: {}
291
+ dialogHandlers: {}
292
+
293
+ }