mercury-rails 0.1.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.
- data/LICENSE +20 -0
- data/README.rdoc +152 -0
- data/VERSION +1 -0
- data/app/assets/images/mercury/button.png +0 -0
- data/app/assets/images/mercury/clippy.png +0 -0
- data/app/assets/images/mercury/default-snippet.png +0 -0
- data/app/assets/images/mercury/loading-dark.gif +0 -0
- data/app/assets/images/mercury/loading-light.gif +0 -0
- data/app/assets/images/mercury/search-icon.png +0 -0
- data/app/assets/images/mercury/toolbar/editable/buttons.png +0 -0
- data/app/assets/images/mercury/toolbar/markupable/buttons.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/_expander.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/_pressed.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/historypanel.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/insertcharacter.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/insertlink.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/insertmedia.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/inserttable.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/inspectorpanel.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/notespanel.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/objectspanel.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/preview.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/redo.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/save.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/todospanel.png +0 -0
- data/app/assets/images/mercury/toolbar/primary/undo.png +0 -0
- data/app/assets/images/mercury/toolbar/snippetable/buttons.png +0 -0
- data/app/assets/javascripts/mercury.js +30 -0
- data/app/assets/javascripts/mercury/dialog.js.coffee +75 -0
- data/app/assets/javascripts/mercury/dialogs/backcolor.js.coffee +6 -0
- data/app/assets/javascripts/mercury/dialogs/forecolor.js.coffee +6 -0
- data/app/assets/javascripts/mercury/dialogs/formatblock.js.coffee +4 -0
- data/app/assets/javascripts/mercury/dialogs/objectspanel.js.coffee +10 -0
- data/app/assets/javascripts/mercury/dialogs/style.js.coffee +4 -0
- data/app/assets/javascripts/mercury/history_buffer.js.coffee +30 -0
- data/app/assets/javascripts/mercury/mercury.js.coffee +293 -0
- data/app/assets/javascripts/mercury/modal.js.coffee +177 -0
- data/app/assets/javascripts/mercury/modals/htmleditor.js.coffee +10 -0
- data/app/assets/javascripts/mercury/modals/insertcharacter.js.coffee +4 -0
- data/app/assets/javascripts/mercury/modals/insertlink.js.coffee +92 -0
- data/app/assets/javascripts/mercury/modals/insertmedia.js.coffee +72 -0
- data/app/assets/javascripts/mercury/modals/insertsnippet.js.coffee +11 -0
- data/app/assets/javascripts/mercury/modals/inserttable.js.coffee +56 -0
- data/app/assets/javascripts/mercury/native_extensions.js.coffee +47 -0
- data/app/assets/javascripts/mercury/page_editor.js.coffee +139 -0
- data/app/assets/javascripts/mercury/palette.js.coffee +29 -0
- data/app/assets/javascripts/mercury/panel.js.coffee +97 -0
- data/app/assets/javascripts/mercury/region.js.coffee +103 -0
- data/app/assets/javascripts/mercury/regions/editable.js.coffee +546 -0
- data/app/assets/javascripts/mercury/regions/markupable.js.coffee +380 -0
- data/app/assets/javascripts/mercury/regions/snippetable.js.coffee +127 -0
- data/app/assets/javascripts/mercury/select.js.coffee +40 -0
- data/app/assets/javascripts/mercury/snippet.js.coffee +92 -0
- data/app/assets/javascripts/mercury/snippet_toolbar.js.coffee +69 -0
- data/app/assets/javascripts/mercury/statusbar.js.coffee +25 -0
- data/app/assets/javascripts/mercury/table_editor.js.coffee +266 -0
- data/app/assets/javascripts/mercury/toolbar.button.js.coffee +152 -0
- data/app/assets/javascripts/mercury/toolbar.button_group.js.coffee +42 -0
- data/app/assets/javascripts/mercury/toolbar.expander.js.coffee +56 -0
- data/app/assets/javascripts/mercury/toolbar.js.coffee +72 -0
- data/app/assets/javascripts/mercury/tooltip.js.coffee +67 -0
- data/app/assets/javascripts/mercury/uploader.js.coffee +213 -0
- data/app/assets/javascripts/mercury/websocket.js.coffee +34 -0
- data/app/assets/stylesheets/mercury.css +31 -0
- data/app/assets/stylesheets/mercury/dialog.scss +178 -0
- data/app/assets/stylesheets/mercury/mercury.scss +119 -0
- data/app/assets/stylesheets/mercury/modal.scss +192 -0
- data/app/assets/stylesheets/mercury/statusbar.scss +23 -0
- data/app/assets/stylesheets/mercury/toolbar.scss +417 -0
- data/app/assets/stylesheets/mercury/tooltip.scss +26 -0
- data/app/assets/stylesheets/mercury/uploader.scss +109 -0
- data/app/controllers/images_controller.rb +19 -0
- data/app/controllers/mercury_controller.rb +20 -0
- data/app/models/image.rb +14 -0
- data/app/views/layouts/mercury.html.haml +12 -0
- data/app/views/mercury/modals/character.html.haml +252 -0
- data/app/views/mercury/modals/htmleditor.html.haml +8 -0
- data/app/views/mercury/modals/link.html.haml +31 -0
- data/app/views/mercury/modals/media.html.haml +33 -0
- data/app/views/mercury/modals/sanitizer.html.haml +4 -0
- data/app/views/mercury/modals/table.html.haml +49 -0
- data/app/views/mercury/palettes/backcolor.html.haml +79 -0
- data/app/views/mercury/palettes/forecolor.html.haml +79 -0
- data/app/views/mercury/panels/history.html.haml +0 -0
- data/app/views/mercury/panels/notes.html.haml +0 -0
- data/app/views/mercury/panels/snippets.html.haml +10 -0
- data/app/views/mercury/selects/formatblock.html.haml +10 -0
- data/app/views/mercury/selects/style.html.haml +4 -0
- data/app/views/mercury/snippets/example.html.haml +2 -0
- data/app/views/mercury/snippets/example_options.html.haml +16 -0
- data/config/engine.rb +6 -0
- data/config/routes.rb +15 -0
- data/db/migrate/20110526035601_create_images.rb +11 -0
- data/features/editing/basic.feature +11 -0
- data/features/step_definitions/debug_steps.rb +14 -0
- data/features/step_definitions/web_steps.rb +211 -0
- data/features/support/env.rb +46 -0
- data/features/support/paths.rb +35 -0
- data/features/support/selectors.rb +42 -0
- data/lib/mercury-rails.rb +4 -0
- data/log/.gitkeep +0 -0
- data/mercury-rails.gemspec +230 -0
- data/spec/javascripts/mercury/dialog_spec.js.coffee +258 -0
- data/spec/javascripts/mercury/history_buffer_spec.js.coffee +79 -0
- data/spec/javascripts/mercury/mercury_spec.js.coffee +52 -0
- data/spec/javascripts/mercury/native_extensions_spec.js.coffee +66 -0
- data/spec/javascripts/mercury/page_editor_spec.js.coffee +435 -0
- data/spec/javascripts/mercury/palette_spec.js.coffee +51 -0
- data/spec/javascripts/mercury/panel_spec.js.coffee +147 -0
- data/spec/javascripts/mercury/region_spec.js.coffee +261 -0
- data/spec/javascripts/mercury/regions/_editable_.js.coffee +0 -0
- data/spec/javascripts/mercury/regions/_markupable_.js.coffee +0 -0
- data/spec/javascripts/mercury/regions/snippetable_spec.js.coffee +368 -0
- data/spec/javascripts/mercury/select_spec.js.coffee +51 -0
- data/spec/javascripts/mercury/snippet_spec.js.coffee +246 -0
- data/spec/javascripts/mercury/snippet_toolbar_spec.js.coffee +186 -0
- data/spec/javascripts/mercury/statusbar_spec.js.coffee +78 -0
- data/spec/javascripts/mercury/table_editor_spec.js.coffee +192 -0
- data/spec/javascripts/mercury/toolbar.button_group_spec.js.coffee +92 -0
- data/spec/javascripts/mercury/toolbar.button_spec.js.coffee +341 -0
- data/spec/javascripts/mercury/toolbar.expander_spec.js.coffee +120 -0
- data/spec/javascripts/mercury/toolbar_spec.js.coffee +152 -0
- data/spec/javascripts/mercury/tooltip_spec.js.coffee +188 -0
- data/spec/javascripts/mercury/uploader_spec.js.coffee +512 -0
- data/spec/javascripts/responses/blank.html +1 -0
- data/spec/javascripts/spec_helper.js +513 -0
- data/spec/javascripts/templates/mercury/dialog.html +2 -0
- data/spec/javascripts/templates/mercury/page_editor.html +24 -0
- data/spec/javascripts/templates/mercury/palette.html +16 -0
- data/spec/javascripts/templates/mercury/panel.html +16 -0
- data/spec/javascripts/templates/mercury/region.html +2 -0
- data/spec/javascripts/templates/mercury/regions/snippetable.html +4 -0
- data/spec/javascripts/templates/mercury/select.html +16 -0
- data/spec/javascripts/templates/mercury/snippet.html +1 -0
- data/spec/javascripts/templates/mercury/snippet_toolbar.html +16 -0
- data/spec/javascripts/templates/mercury/statusbar.html +7 -0
- data/spec/javascripts/templates/mercury/table_editor.html +65 -0
- data/spec/javascripts/templates/mercury/toolbar.button.html +64 -0
- data/spec/javascripts/templates/mercury/toolbar.button_group.html +9 -0
- data/spec/javascripts/templates/mercury/toolbar.expander.html +18 -0
- data/spec/javascripts/templates/mercury/toolbar.html +10 -0
- data/spec/javascripts/templates/mercury/tooltip.html +12 -0
- data/spec/javascripts/templates/mercury/uploader.html +11 -0
- data/vendor/assets/javascripts/jquery-1.6.js +8865 -0
- data/vendor/assets/javascripts/jquery-ui-1.8.13.custom.min.js +249 -0
- data/vendor/assets/javascripts/jquery-ui-1.8.13.sortable.custom.js +1078 -0
- data/vendor/assets/javascripts/jquery.easing.js +173 -0
- data/vendor/assets/javascripts/jquery.json2.js +178 -0
- data/vendor/assets/javascripts/jquery.serialize_object.js +16 -0
- data/vendor/assets/javascripts/jquery.ujs.js +289 -0
- data/vendor/assets/javascripts/liquidmetal.js +88 -0
- data/vendor/assets/javascripts/showdown.js +1362 -0
- metadata +364 -0
File without changes
|
File without changes
|
@@ -0,0 +1,368 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "Mercury.Regions.Snippetable", ->
|
4
|
+
|
5
|
+
template 'mercury/regions/snippetable.html'
|
6
|
+
|
7
|
+
beforeEach ->
|
8
|
+
@regionElement = $('#snippetable_region1')
|
9
|
+
|
10
|
+
afterEach ->
|
11
|
+
@region = null
|
12
|
+
delete(@region)
|
13
|
+
|
14
|
+
describe "constructor", ->
|
15
|
+
|
16
|
+
beforeEach ->
|
17
|
+
@buildSpy = spyOn(Mercury.Regions.Snippetable.prototype, 'build').andCallFake(=>)
|
18
|
+
@bindEventsSpy = spyOn(Mercury.Regions.Snippetable.prototype, 'bindEvents').andCallFake(=>)
|
19
|
+
@makeSortableSpy = spyOn(Mercury.Regions.Snippetable.prototype, 'makeSortable').andCallFake(=>)
|
20
|
+
|
21
|
+
it "expects an element, window", ->
|
22
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
23
|
+
expect(@region.element.get(0)).toEqual($('#snippetable_region1').get(0))
|
24
|
+
expect(@region.window).toEqual(window)
|
25
|
+
|
26
|
+
it "accepts options", ->
|
27
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window, {foo: 'something'})
|
28
|
+
expect(@region.options).toEqual({foo: 'something'})
|
29
|
+
|
30
|
+
it "calls build", ->
|
31
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
32
|
+
expect(@buildSpy.callCount).toEqual(1)
|
33
|
+
|
34
|
+
it "calls bindEvents", ->
|
35
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
36
|
+
expect(@bindEventsSpy.callCount).toEqual(1)
|
37
|
+
|
38
|
+
it "makes the snippets sortable", ->
|
39
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
40
|
+
expect(@makeSortableSpy.callCount).toEqual(1)
|
41
|
+
|
42
|
+
|
43
|
+
describe "#build", ->
|
44
|
+
|
45
|
+
beforeEach ->
|
46
|
+
spyOn(Mercury.Regions.Snippetable.prototype, 'bindEvents').andCallFake(=>)
|
47
|
+
|
48
|
+
it "sets the element min-height to 20 if it's min-height is 0 (or not set)", ->
|
49
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
50
|
+
expect($('#snippetable_region1').css('minHeight')).toEqual('20px')
|
51
|
+
|
52
|
+
|
53
|
+
describe "observed events", ->
|
54
|
+
|
55
|
+
beforeEach ->
|
56
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
57
|
+
Mercury.region = @region
|
58
|
+
|
59
|
+
describe "custom event: unfocus:regions", ->
|
60
|
+
|
61
|
+
it "removes the focus class", ->
|
62
|
+
@region.element.addClass('focus')
|
63
|
+
Mercury.trigger('unfocus:regions')
|
64
|
+
expect(@region.element.hasClass('focus')).toEqual(false)
|
65
|
+
|
66
|
+
it "destroys the sortable", ->
|
67
|
+
spy = spyOn($.fn, 'sortable').andCallFake(=>)
|
68
|
+
Mercury.trigger('unfocus:regions')
|
69
|
+
expect(spy.argsForCall[0]).toEqual(['destroy'])
|
70
|
+
|
71
|
+
it "triggers the region:blurred event", ->
|
72
|
+
spy = spyOn(Mercury, 'trigger').andCallThrough()
|
73
|
+
Mercury.trigger('unfocus:regions')
|
74
|
+
expect(spy.callCount).toEqual(2)
|
75
|
+
expect(spy.argsForCall[1]).toEqual(['region:blurred', {region: @region}])
|
76
|
+
|
77
|
+
it "does nothing if previewing", ->
|
78
|
+
@region.previewing = true
|
79
|
+
@region.element.addClass('focus')
|
80
|
+
Mercury.trigger('unfocus:regions')
|
81
|
+
expect(@region.element.hasClass('focus')).toEqual(true)
|
82
|
+
|
83
|
+
it "does nothing if it's not the active region", ->
|
84
|
+
Mercury.region = null
|
85
|
+
@region.element.addClass('focus')
|
86
|
+
Mercury.trigger('unfocus:regions')
|
87
|
+
expect(@region.element.hasClass('focus')).toEqual(true)
|
88
|
+
|
89
|
+
describe "custom event: focus:window", ->
|
90
|
+
|
91
|
+
it "removes the focus class", ->
|
92
|
+
@region.element.addClass('focus')
|
93
|
+
Mercury.trigger('focus:window')
|
94
|
+
expect(@region.element.hasClass('focus')).toEqual(false)
|
95
|
+
|
96
|
+
it "destroys the sortable", ->
|
97
|
+
spy = spyOn($.fn, 'sortable').andCallFake(=>)
|
98
|
+
Mercury.trigger('focus:window')
|
99
|
+
expect(spy.argsForCall[0]).toEqual(['destroy'])
|
100
|
+
|
101
|
+
it "triggers the region:blurred event", ->
|
102
|
+
spy = spyOn(Mercury, 'trigger').andCallThrough()
|
103
|
+
Mercury.trigger('focus:window')
|
104
|
+
expect(spy.callCount).toEqual(2)
|
105
|
+
expect(spy.argsForCall[1]).toEqual(['region:blurred', {region: @region}])
|
106
|
+
|
107
|
+
it "does nothing if previewing", ->
|
108
|
+
@region.previewing = true
|
109
|
+
@region.element.addClass('focus')
|
110
|
+
Mercury.trigger('focus:window')
|
111
|
+
expect(@region.element.hasClass('focus')).toEqual(true)
|
112
|
+
|
113
|
+
it "does nothing if it's not the active region", ->
|
114
|
+
Mercury.region = null
|
115
|
+
@region.element.addClass('focus')
|
116
|
+
Mercury.trigger('focus:window')
|
117
|
+
expect(@region.element.hasClass('focus')).toEqual(true)
|
118
|
+
|
119
|
+
describe "keydown on document (for undo / redo)", ->
|
120
|
+
|
121
|
+
it "calls execCommand with undo on meta+z", ->
|
122
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'execCommand')
|
123
|
+
jasmine.simulate.keydown(document, {shiftKey: false, metaKey: true, keyCode: 90})
|
124
|
+
expect(spy.callCount).toEqual(1)
|
125
|
+
expect(spy.argsForCall[0]).toEqual(['undo'])
|
126
|
+
|
127
|
+
it "calls execCommand with redo on shift+meta+z", ->
|
128
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'execCommand')
|
129
|
+
jasmine.simulate.keydown(document, {shiftKey: true, metaKey: true, keyCode: 90})
|
130
|
+
expect(spy.callCount).toEqual(1)
|
131
|
+
expect(spy.argsForCall[0]).toEqual(['redo'])
|
132
|
+
|
133
|
+
it "does nothing if previewing", ->
|
134
|
+
@region.previewing = true
|
135
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'execCommand')
|
136
|
+
jasmine.simulate.keydown(document, {shiftKey: true, metaKey: true, keyCode: 90})
|
137
|
+
expect(spy.callCount).toEqual(0)
|
138
|
+
|
139
|
+
it "does nothing if it's not the active region", ->
|
140
|
+
Mercury.region = null
|
141
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'execCommand')
|
142
|
+
jasmine.simulate.keydown(document, {shiftKey: true, metaKey: true, keyCode: 90})
|
143
|
+
expect(spy.callCount).toEqual(0)
|
144
|
+
|
145
|
+
describe "mouseup", ->
|
146
|
+
|
147
|
+
it "calls focus", ->
|
148
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'focus')
|
149
|
+
jasmine.simulate.mouseup(@region.element.get(0))
|
150
|
+
expect(spy.callCount).toEqual(1)
|
151
|
+
|
152
|
+
it "triggers the region:focused event", ->
|
153
|
+
spy = spyOn(Mercury, 'trigger')
|
154
|
+
jasmine.simulate.mouseup(@region.element.get(0))
|
155
|
+
expect(spy.callCount).toEqual(1)
|
156
|
+
|
157
|
+
it "does nothing if previewing", ->
|
158
|
+
@region.previewing = true
|
159
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'focus')
|
160
|
+
jasmine.simulate.mouseup(@region.element.get(0))
|
161
|
+
expect(spy.callCount).toEqual(0)
|
162
|
+
|
163
|
+
describe "dragover", ->
|
164
|
+
|
165
|
+
# todo: I'd like to find a nice way to test these things
|
166
|
+
it "prevents the default event", ->
|
167
|
+
it "does nothing if previewing", ->
|
168
|
+
|
169
|
+
describe "drop", ->
|
170
|
+
|
171
|
+
# todo: I'd like to find a nice way to test these things
|
172
|
+
it "calls focus", ->
|
173
|
+
it "prevents the default event", ->
|
174
|
+
it "displays the options for the snippet that was dropped", ->
|
175
|
+
it "does nothing if previewing", ->
|
176
|
+
it "does nothing if there's no active snippet", ->
|
177
|
+
|
178
|
+
|
179
|
+
describe "#focus", ->
|
180
|
+
|
181
|
+
beforeEach ->
|
182
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
183
|
+
|
184
|
+
it "sets the active mercury region", ->
|
185
|
+
Mercury.region = null
|
186
|
+
@region.focus()
|
187
|
+
expect(Mercury.region).toEqual(@region)
|
188
|
+
|
189
|
+
it "makes the snippets sortable again", ->
|
190
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'makeSortable')
|
191
|
+
@region.focus()
|
192
|
+
expect(spy.callCount).toEqual(1)
|
193
|
+
|
194
|
+
it "adds the focus class to the element", ->
|
195
|
+
@region.focus()
|
196
|
+
expect($('#snippetable_region1').hasClass('focus')).toEqual(true)
|
197
|
+
|
198
|
+
|
199
|
+
describe "#togglePreview", ->
|
200
|
+
|
201
|
+
beforeEach ->
|
202
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
203
|
+
|
204
|
+
describe "when not previewing", ->
|
205
|
+
|
206
|
+
it "it destroys the sortable", ->
|
207
|
+
spy = spyOn($.fn, 'sortable').andCallFake(=>)
|
208
|
+
@region.togglePreview()
|
209
|
+
expect(spy.callCount).toEqual(1)
|
210
|
+
expect(spy.argsForCall[0]).toEqual(['destroy'])
|
211
|
+
|
212
|
+
it "removes the focus class", ->
|
213
|
+
@regionElement.addClass('focus')
|
214
|
+
@region.togglePreview()
|
215
|
+
expect($('#snippetable_region1').hasClass('focus')).toEqual(false)
|
216
|
+
|
217
|
+
describe "when previewing", ->
|
218
|
+
|
219
|
+
beforeEach ->
|
220
|
+
@region.previewing = true
|
221
|
+
|
222
|
+
it "makes the snippets sortable again", ->
|
223
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'makeSortable')
|
224
|
+
@region.togglePreview()
|
225
|
+
expect(spy.callCount).toEqual(1)
|
226
|
+
|
227
|
+
|
228
|
+
describe "#execCommand", ->
|
229
|
+
|
230
|
+
beforeEach ->
|
231
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
232
|
+
Mercury.Regions.Snippetable.actions['foo'] = ->
|
233
|
+
@handlerSpy = spyOn(Mercury.Regions.Snippetable.actions, 'foo')
|
234
|
+
|
235
|
+
it "calls a handler (from the actions) if one exists", ->
|
236
|
+
@region.execCommand('foo', {value: 'something'})
|
237
|
+
expect(@handlerSpy.callCount).toEqual(1)
|
238
|
+
expect(@handlerSpy.argsForCall[0]).toEqual([{value: 'something'}])
|
239
|
+
|
240
|
+
|
241
|
+
describe "#makeSortable", ->
|
242
|
+
|
243
|
+
beforeEach ->
|
244
|
+
@region = new Mercury.Regions.Snippetable(@regionElement, window)
|
245
|
+
@sortableSpy = spyOn($.fn, 'sortable')
|
246
|
+
|
247
|
+
it "makes the snippets sortable", ->
|
248
|
+
@sortableSpy.andCallFake((arg) => return @region.element if arg == 'destroy' )
|
249
|
+
@region.makeSortable()
|
250
|
+
expect(@sortableSpy.callCount).toEqual(2)
|
251
|
+
expect(@sortableSpy.argsForCall[0]).toEqual(['destroy'])
|
252
|
+
expect(@sortableSpy.argsForCall[1][0]['document']).toEqual(@region.document)
|
253
|
+
|
254
|
+
it "triggers the hide:toolbar event at the end of the dragging", ->
|
255
|
+
spy = spyOn(Mercury, 'trigger').andCallFake(=>)
|
256
|
+
@sortableSpy.andCallFake((arg) => if arg == 'destroy' then return @region.element else arg.beforeStop())
|
257
|
+
@region.makeSortable()
|
258
|
+
expect(spy.callCount).toEqual(1)
|
259
|
+
expect(spy.argsForCall[0]).toEqual(['hide:toolbar', {type: 'snippet', immediately: true}])
|
260
|
+
|
261
|
+
it "pushes to the history after dragging", ->
|
262
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'pushHistory').andCallFake(=>)
|
263
|
+
spyOn(window, 'setTimeout').andCallFake((callback)=> callback())
|
264
|
+
@sortableSpy.andCallFake((arg) => if arg == 'destroy' then return @region.element else arg.stop())
|
265
|
+
@region.makeSortable()
|
266
|
+
expect(spy.callCount).toEqual(1)
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
describe "Mercury.Regions.Snippetable.actions", ->
|
271
|
+
|
272
|
+
template 'mercury/regions/snippetable.html'
|
273
|
+
|
274
|
+
beforeEach ->
|
275
|
+
@region = new Mercury.Regions.Snippetable($('#snippetable_region2'), window)
|
276
|
+
@actions = Mercury.Regions.Snippetable.actions
|
277
|
+
|
278
|
+
describe ".undo", ->
|
279
|
+
|
280
|
+
it "calls undo on the history buffer and sets the content", ->
|
281
|
+
htmlSpy = spyOn(Mercury.Regions.Snippetable.prototype, 'html').andCallFake(=>)
|
282
|
+
historySpy = spyOn(@region.history, 'undo').andCallFake(=> 'history -1')
|
283
|
+
@actions['undo'].call(@region)
|
284
|
+
expect(historySpy.callCount).toEqual(1)
|
285
|
+
expect(htmlSpy.callCount).toEqual(1)
|
286
|
+
expect(htmlSpy.argsForCall[0]).toEqual(['history -1'])
|
287
|
+
|
288
|
+
|
289
|
+
describe ".redo", ->
|
290
|
+
|
291
|
+
it "calls redo on the history buffer and sets the content", ->
|
292
|
+
htmlSpy = spyOn(Mercury.Regions.Snippetable.prototype, 'html').andCallFake(=>)
|
293
|
+
historySpy = spyOn(@region.history, 'redo').andCallFake(=> 'history +1')
|
294
|
+
@actions['redo'].call(@region)
|
295
|
+
expect(historySpy.callCount).toEqual(1)
|
296
|
+
expect(htmlSpy.callCount).toEqual(1)
|
297
|
+
expect(htmlSpy.argsForCall[0]).toEqual(['history +1'])
|
298
|
+
|
299
|
+
|
300
|
+
describe ".insertsnippet", ->
|
301
|
+
|
302
|
+
beforeEach ->
|
303
|
+
Mercury.Snippet.load({
|
304
|
+
'snippet_1': {name: 'example', options: {'foo': 'bar'}},
|
305
|
+
'snippet_2': {name: 'example', options: {'foo': 'bar'}},
|
306
|
+
})
|
307
|
+
spyOn(Mercury.Snippet.prototype, 'loadPreview').andCallFake(=>)
|
308
|
+
|
309
|
+
describe "updating a snippet", ->
|
310
|
+
|
311
|
+
it "finds the snippet by it's identity and replaces it with the new snippet", ->
|
312
|
+
@actions['insertsnippet'].call(@region, {value: Mercury.Snippet.find('snippet_1')})
|
313
|
+
expect($('#snippetable_region2').html()).toContain('class="mercury-snippet"')
|
314
|
+
expect($('#snippetable_region2').html()).toContain('contenteditable="false"')
|
315
|
+
expect($('#snippetable_region2').html()).toContain('data-version="1"')
|
316
|
+
expect($('#snippetable_region2').html()).toContain('data-snippet="snippet_1"')
|
317
|
+
expect($('#snippetable_region2').html()).toContain('[snippet_1]')
|
318
|
+
|
319
|
+
it "pushes to the history after it's been rendered", ->
|
320
|
+
spyOn(Mercury.Snippet.prototype, 'getHTML').andCallFake((x, callback) => callback() if callback)
|
321
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'pushHistory').andCallFake(=>)
|
322
|
+
@actions['insertsnippet'].call(@region, {value: Mercury.Snippet.find('snippet_1')})
|
323
|
+
expect(spy.callCount).toEqual(1)
|
324
|
+
|
325
|
+
describe "inserting a snippet", ->
|
326
|
+
|
327
|
+
it "appends the new snippet html to the element", ->
|
328
|
+
@actions['insertsnippet'].call(@region, {value: Mercury.Snippet.find('snippet_2')})
|
329
|
+
expect($('#snippetable_region2 .mercury-snippet').length).toEqual(2)
|
330
|
+
|
331
|
+
it "pushes to the history after it's been rendered", ->
|
332
|
+
spyOn(Mercury.Snippet.prototype, 'getHTML').andCallFake((x, callback) => callback() if callback)
|
333
|
+
spy = spyOn(Mercury.Regions.Snippetable.prototype, 'pushHistory').andCallFake(=>)
|
334
|
+
@actions['insertsnippet'].call(@region, {value: Mercury.Snippet.find('snippet_2')})
|
335
|
+
expect(spy.callCount).toEqual(1)
|
336
|
+
|
337
|
+
|
338
|
+
describe ".editsnippet", ->
|
339
|
+
|
340
|
+
beforeEach ->
|
341
|
+
@region.snippet = $('#snippetable_region2 .mercury-snippet')
|
342
|
+
|
343
|
+
it "finds and displays the options for the given snippet", ->
|
344
|
+
spy = spyOn(Mercury.Snippet.prototype, 'displayOptions')
|
345
|
+
@actions['editsnippet'].call(@region)
|
346
|
+
expect(spy.callCount).toEqual(1)
|
347
|
+
|
348
|
+
it "does nothing if there's no active snippet (eg. hovered over)", ->
|
349
|
+
@region.snippet = null
|
350
|
+
spy = spyOn(Mercury.Snippet.prototype, 'displayOptions')
|
351
|
+
@actions['editsnippet'].call(@region)
|
352
|
+
expect(spy.callCount).toEqual(0)
|
353
|
+
|
354
|
+
|
355
|
+
describe ".removesnippet", ->
|
356
|
+
|
357
|
+
beforeEach ->
|
358
|
+
@region.snippet = $('#snippetable_region2 .mercury-snippet')
|
359
|
+
|
360
|
+
it "removes the snippet if there's an active one", ->
|
361
|
+
@actions['removesnippet'].call(@region)
|
362
|
+
expect($('#snippetable_region2 .mercury-snippet').length).toEqual(0)
|
363
|
+
|
364
|
+
it "triggers the hide:toolbar event", ->
|
365
|
+
spy = spyOn(Mercury, 'trigger').andCallFake(=>)
|
366
|
+
@actions['removesnippet'].call(@region)
|
367
|
+
expect(spy.callCount).toEqual(1)
|
368
|
+
expect(spy.argsForCall[0]).toEqual(['hide:toolbar', {type: 'snippet', immediately: true}])
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "Mercury.Select", ->
|
4
|
+
|
5
|
+
template 'mercury/select.html'
|
6
|
+
|
7
|
+
beforeEach ->
|
8
|
+
$.fx.off = true
|
9
|
+
|
10
|
+
afterEach ->
|
11
|
+
@select = null
|
12
|
+
delete(@select)
|
13
|
+
|
14
|
+
describe "#build", ->
|
15
|
+
|
16
|
+
it "builds an element", ->
|
17
|
+
@select = new Mercury.Select('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
|
18
|
+
html = $('<div>').html(@select.element).html()
|
19
|
+
expect(html).toContain('class="mercury-select mercury-foo-select loading"')
|
20
|
+
expect(html).toContain('style="display:none"')
|
21
|
+
|
22
|
+
it "appends to any element", ->
|
23
|
+
@select = new Mercury.Select('/evergreen/responses/blank.html', 'foo', {appendTo: '#select_container', for: $('#button')})
|
24
|
+
expect($('#select_container .mercury-select').length).toEqual(1)
|
25
|
+
|
26
|
+
|
27
|
+
describe "observed events", ->
|
28
|
+
|
29
|
+
beforeEach ->
|
30
|
+
@select = new Mercury.Select('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
|
31
|
+
|
32
|
+
it "hides", ->
|
33
|
+
@select.element.css({display: 'block'})
|
34
|
+
Mercury.trigger('hide:dialogs')
|
35
|
+
expect(@select.element.css('display')).toEqual('none')
|
36
|
+
|
37
|
+
it "doesn't hide if it's the same dialog", ->
|
38
|
+
@select.element.css({display: 'block'})
|
39
|
+
Mercury.trigger('hide:dialogs', @select)
|
40
|
+
expect(@select.element.css('display')).toEqual('block')
|
41
|
+
|
42
|
+
|
43
|
+
describe "#position", ->
|
44
|
+
|
45
|
+
beforeEach ->
|
46
|
+
@select = new Mercury.Select('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
|
47
|
+
|
48
|
+
it "positions based on it's button", ->
|
49
|
+
@select.element.css({display: 'block'})
|
50
|
+
@select.position(true)
|
51
|
+
expect(@select.element.offset()).toEqual({top: 20, left: 42})
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "Mercury.Snippet", ->
|
4
|
+
|
5
|
+
template 'mercury/snippet.html'
|
6
|
+
|
7
|
+
afterEach ->
|
8
|
+
Mercury.Snippet.all = []
|
9
|
+
|
10
|
+
describe "constructor", ->
|
11
|
+
|
12
|
+
beforeEach ->
|
13
|
+
@setOptionsSpy = spyOn(Mercury.Snippet.prototype, 'setOptions').andCallFake(=>)
|
14
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
15
|
+
|
16
|
+
it "expects name and identity", ->
|
17
|
+
expect(@snippet.name).toEqual('foo')
|
18
|
+
expect(@snippet.identity).toEqual('identity')
|
19
|
+
|
20
|
+
it "sets the version", ->
|
21
|
+
expect(@snippet.version).toEqual(0)
|
22
|
+
expect(@snippet.identity).toEqual('identity')
|
23
|
+
|
24
|
+
it "creates a history buffer", ->
|
25
|
+
expect(@snippet.history).toBeDefined()
|
26
|
+
|
27
|
+
it "calls setOptions", ->
|
28
|
+
expect(@setOptionsSpy.callCount).toEqual(1)
|
29
|
+
|
30
|
+
|
31
|
+
describe "#getHTML", ->
|
32
|
+
|
33
|
+
beforeEach ->
|
34
|
+
@loadPreviewSpy = spyOn(Mercury.Snippet.prototype, 'loadPreview').andCallFake(=>)
|
35
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
36
|
+
|
37
|
+
it "builds an element (in whatever context is provided", ->
|
38
|
+
ret = @snippet.getHTML($(document))
|
39
|
+
html = $('<div>').html(ret).html()
|
40
|
+
expect(html).toContain('class="mercury-snippet"')
|
41
|
+
expect(html).toContain('contenteditable="false"')
|
42
|
+
expect(html).toContain('data-snippet="identity"')
|
43
|
+
expect(html).toContain('data-version="1"')
|
44
|
+
|
45
|
+
it "sets the default content to the identity", ->
|
46
|
+
ret = @snippet.getHTML($(document))
|
47
|
+
html = $('<div>').html(ret).html()
|
48
|
+
expect(ret.html()).toEqual('[identity]')
|
49
|
+
|
50
|
+
it "calls loadPreview", ->
|
51
|
+
@snippet.getHTML($(document))
|
52
|
+
expect(@loadPreviewSpy.callCount).toEqual(1)
|
53
|
+
|
54
|
+
it "passes callback method to loadPreview", ->
|
55
|
+
callback = =>
|
56
|
+
@snippet.getHTML($(document), callback)
|
57
|
+
expect(@loadPreviewSpy.argsForCall[0][1]).toEqual(callback)
|
58
|
+
|
59
|
+
|
60
|
+
describe "#getText", ->
|
61
|
+
|
62
|
+
beforeEach ->
|
63
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
64
|
+
|
65
|
+
it "returns an identity string", ->
|
66
|
+
expect(@snippet.getText()).toEqual('[--identity--]')
|
67
|
+
|
68
|
+
|
69
|
+
describe "#loadPreview", ->
|
70
|
+
|
71
|
+
beforeEach ->
|
72
|
+
@ajaxSpy = spyOn($, 'ajax')
|
73
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
74
|
+
|
75
|
+
it "makes an ajax request", ->
|
76
|
+
@ajaxSpy.andCallFake(=>)
|
77
|
+
@snippet.loadPreview()
|
78
|
+
expect(@ajaxSpy.callCount).toEqual(1)
|
79
|
+
expect(@ajaxSpy.argsForCall[0][0]).toEqual("/mercury/snippets/foo/preview")
|
80
|
+
expect(@ajaxSpy.argsForCall[0][1]['data']).toEqual({foo: 'bar'})
|
81
|
+
expect(@ajaxSpy.argsForCall[0][1]['type']).toEqual('POST')
|
82
|
+
|
83
|
+
describe "ajax success", ->
|
84
|
+
|
85
|
+
beforeEach ->
|
86
|
+
@ajaxSpy.andCallFake((url, options) => options.success('data'))
|
87
|
+
|
88
|
+
it "sets the data", ->
|
89
|
+
@snippet.loadPreview($('#snippet'))
|
90
|
+
expect(@snippet.data).toEqual('data')
|
91
|
+
|
92
|
+
it "puts the data into the element", ->
|
93
|
+
@snippet.loadPreview($('#snippet'))
|
94
|
+
expect($('#snippet').html()).toEqual('data')
|
95
|
+
|
96
|
+
it "calls the callback if one was provided", ->
|
97
|
+
callCount = 0
|
98
|
+
callback = => callCount += 1
|
99
|
+
@snippet.loadPreview($('#snippet'), callback)
|
100
|
+
expect(callCount).toEqual(1)
|
101
|
+
|
102
|
+
describe "ajax failure", ->
|
103
|
+
|
104
|
+
beforeEach ->
|
105
|
+
@ajaxSpy.andCallFake((url, options) => options.error())
|
106
|
+
|
107
|
+
it "alerts the error", ->
|
108
|
+
spy = spyOn(window, 'alert').andCallFake(=>)
|
109
|
+
@snippet.loadPreview($('#snippet'))
|
110
|
+
expect(spy.callCount).toEqual(1)
|
111
|
+
expect(spy.argsForCall[0]).toEqual(['Error loading the preview for the foo snippet.'])
|
112
|
+
|
113
|
+
|
114
|
+
describe "#displayOptions", ->
|
115
|
+
|
116
|
+
beforeEach ->
|
117
|
+
@modalSpy = spyOn(Mercury, 'modal').andCallFake(=>)
|
118
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
119
|
+
|
120
|
+
it "sets the global snippet to itself", ->
|
121
|
+
@snippet.displayOptions()
|
122
|
+
expect(Mercury.snippet).toEqual(@snippet)
|
123
|
+
|
124
|
+
it "opens a modal", ->
|
125
|
+
@snippet.displayOptions()
|
126
|
+
expect(@modalSpy.callCount).toEqual(1)
|
127
|
+
|
128
|
+
|
129
|
+
describe "#setOptions", ->
|
130
|
+
|
131
|
+
beforeEach ->
|
132
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
133
|
+
|
134
|
+
it "removes rails form default options that aren't for storing", ->
|
135
|
+
@snippet.setOptions({foo: 'baz', utf8: 'check', authenticity_token: 'auth_token'})
|
136
|
+
expect(@snippet.options).toEqual({foo: 'baz'})
|
137
|
+
|
138
|
+
it "increases the version", ->
|
139
|
+
@snippet.setOptions({foo: 'baz'})
|
140
|
+
expect(@snippet.version).toEqual(2)
|
141
|
+
|
142
|
+
it "pushes the options to the history buffer", ->
|
143
|
+
@snippet.setOptions({foo: 'baz'})
|
144
|
+
expect(@snippet.history.stack.length).toEqual(2)
|
145
|
+
|
146
|
+
|
147
|
+
describe "#setVersion", ->
|
148
|
+
|
149
|
+
beforeEach ->
|
150
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
151
|
+
@snippet.history.stack = [1, 2, {foo: 'baz'}, 4, 5, 6, 7, 8, 9, 10]
|
152
|
+
|
153
|
+
it "sets the version", ->
|
154
|
+
@snippet.setVersion(5)
|
155
|
+
expect(@snippet.version).toEqual(4)
|
156
|
+
|
157
|
+
it "accepts a version (can be a string)", ->
|
158
|
+
@snippet.setVersion('2')
|
159
|
+
expect(@snippet.version).toEqual(1)
|
160
|
+
|
161
|
+
it "pulls the version out of the history buffer", ->
|
162
|
+
@snippet.setVersion(3)
|
163
|
+
expect(@snippet.options).toEqual({foo: 'baz'})
|
164
|
+
|
165
|
+
it "returns true if successful", ->
|
166
|
+
ret = @snippet.setVersion('2')
|
167
|
+
expect(ret).toEqual(true)
|
168
|
+
|
169
|
+
it "returns false if not successful", ->
|
170
|
+
ret = @snippet.setVersion('abc')
|
171
|
+
expect(ret).toEqual(false)
|
172
|
+
|
173
|
+
|
174
|
+
describe "#serialize", ->
|
175
|
+
|
176
|
+
beforeEach ->
|
177
|
+
@snippet = new Mercury.Snippet('foo', 'identity', {foo: 'bar'})
|
178
|
+
|
179
|
+
it "returns an object with name and options", ->
|
180
|
+
ret = @snippet.serialize()
|
181
|
+
expect(ret).toEqual({name: 'foo', options: {foo: 'bar'}})
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
describe "Mercury.Snippet class methods", ->
|
186
|
+
|
187
|
+
afterEach ->
|
188
|
+
Mercury.Snippet.all = []
|
189
|
+
|
190
|
+
describe ".displayOptionsFor", ->
|
191
|
+
|
192
|
+
beforeEach ->
|
193
|
+
@modalSpy = spyOn(Mercury, 'modal').andCallFake(=>)
|
194
|
+
|
195
|
+
it "opens a modal with the name in the url", ->
|
196
|
+
Mercury.Snippet.displayOptionsFor('foo')
|
197
|
+
expect(@modalSpy.callCount).toEqual(1)
|
198
|
+
expect(@modalSpy.argsForCall[0]).toEqual(["/mercury/snippets/foo/options", {title: 'Snippet Options', handler: 'insertsnippet'}])
|
199
|
+
|
200
|
+
it "sets the snippet back to nothing", ->
|
201
|
+
Mercury.snippet = 'foo'
|
202
|
+
Mercury.Snippet.displayOptionsFor('foo')
|
203
|
+
expect(Mercury.snippet).toEqual(null)
|
204
|
+
|
205
|
+
|
206
|
+
describe ".create", ->
|
207
|
+
|
208
|
+
beforeEach ->
|
209
|
+
Mercury.Snippet.all = []
|
210
|
+
|
211
|
+
it "creates a new instance of Mercury.Snippet", ->
|
212
|
+
ret = Mercury.Snippet.create('foo', {foo: 'bar'})
|
213
|
+
expect(ret.options).toEqual({foo: 'bar'})
|
214
|
+
|
215
|
+
it "generates an identity and passes it to the instance", ->
|
216
|
+
ret = Mercury.Snippet.create('foo', {foo: 'bar'})
|
217
|
+
expect(ret.identity).toEqual('snippet_0')
|
218
|
+
|
219
|
+
it "pushes into the collection array", ->
|
220
|
+
Mercury.Snippet.create('foo', {foo: 'bar'})
|
221
|
+
expect(Mercury.Snippet.all.length).toEqual(1)
|
222
|
+
|
223
|
+
|
224
|
+
describe ".find", ->
|
225
|
+
|
226
|
+
beforeEach ->
|
227
|
+
Mercury.Snippet.create('foo', {foo: 'bar'})
|
228
|
+
|
229
|
+
it "finds a snippet by identity", ->
|
230
|
+
expect(Mercury.Snippet.find('snippet_0').options).toEqual({foo: 'bar'})
|
231
|
+
|
232
|
+
it "returns null if no snippet was found", ->
|
233
|
+
expect(Mercury.Snippet.find('snippet_x')).toEqual(null)
|
234
|
+
|
235
|
+
|
236
|
+
describe ".load", ->
|
237
|
+
|
238
|
+
beforeEach ->
|
239
|
+
@snippets = {
|
240
|
+
snippet_1: {name: 'foo', options: {foo: 'bar'}}
|
241
|
+
snippet_2: {name: 'bar', options: {baz: 'pizza'}}
|
242
|
+
}
|
243
|
+
|
244
|
+
it "creates a new instance for each item in the collection", ->
|
245
|
+
Mercury.Snippet.load(@snippets)
|
246
|
+
expect(Mercury.Snippet.all.length).toEqual(2)
|