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
@@ -0,0 +1,79 @@
|
|
1
|
+
Mercury = {}
|
2
|
+
require '/assets/mercury.js'
|
3
|
+
|
4
|
+
describe "Mercury.HistoryBuffer", ->
|
5
|
+
|
6
|
+
beforeEach ->
|
7
|
+
@buffer = new Mercury.HistoryBuffer(5)
|
8
|
+
|
9
|
+
afterEach ->
|
10
|
+
@buffer = null
|
11
|
+
delete(@buffer)
|
12
|
+
|
13
|
+
describe "constructor", ->
|
14
|
+
|
15
|
+
it "accepts a max length", ->
|
16
|
+
expect(@buffer.maxLength).toEqual(5)
|
17
|
+
|
18
|
+
it "initializes an empty stack", ->
|
19
|
+
expect(@buffer.index).toEqual(0)
|
20
|
+
expect(@buffer.stack).toEqual([])
|
21
|
+
|
22
|
+
|
23
|
+
describe "#push", ->
|
24
|
+
|
25
|
+
it "won't duplicate items if the content is the same", ->
|
26
|
+
@buffer.push('1')
|
27
|
+
expect(@buffer.stack).toEqual(['1'])
|
28
|
+
|
29
|
+
@buffer.push('2<em class="mercury-marker"></em>')
|
30
|
+
expect(@buffer.stack).toEqual(['1', '2<em class="mercury-marker"></em>'])
|
31
|
+
|
32
|
+
it "pushes onto the stack where it should", ->
|
33
|
+
@buffer.push('1')
|
34
|
+
@buffer.push('2')
|
35
|
+
expect(@buffer.stack).toEqual(['1', '2'])
|
36
|
+
|
37
|
+
@buffer.index = 0
|
38
|
+
@buffer.push('3')
|
39
|
+
expect(@buffer.stack).toEqual(['1', '3'])
|
40
|
+
|
41
|
+
it "keeps the number of items within the max length by dropping the oldest items", ->
|
42
|
+
@buffer.push('1')
|
43
|
+
@buffer.push('2')
|
44
|
+
@buffer.push('3')
|
45
|
+
@buffer.push('4')
|
46
|
+
@buffer.push('5')
|
47
|
+
expect(@buffer.stack).toEqual(['1', '2', '3', '4', '5'])
|
48
|
+
@buffer.push('6')
|
49
|
+
expect(@buffer.stack).toEqual(['2', '3', '4', '5', '6'])
|
50
|
+
|
51
|
+
|
52
|
+
describe "#undo", ->
|
53
|
+
|
54
|
+
beforeEach ->
|
55
|
+
@buffer.push('1')
|
56
|
+
@buffer.push('2')
|
57
|
+
|
58
|
+
it "returns the correct item", ->
|
59
|
+
expect(@buffer.undo()).toEqual('1')
|
60
|
+
|
61
|
+
it "returns null if there are no more items to undo", ->
|
62
|
+
expect(@buffer.undo()).toEqual('1')
|
63
|
+
expect(@buffer.undo()).toEqual(null)
|
64
|
+
|
65
|
+
|
66
|
+
describe "#redo", ->
|
67
|
+
|
68
|
+
beforeEach ->
|
69
|
+
@buffer.push('1')
|
70
|
+
@buffer.push('2')
|
71
|
+
|
72
|
+
it "returns the correct item", ->
|
73
|
+
@buffer.undo()
|
74
|
+
expect(@buffer.redo()).toEqual('2')
|
75
|
+
|
76
|
+
it "returns null if there are no more items to redo", ->
|
77
|
+
@buffer.undo()
|
78
|
+
expect(@buffer.redo()).toEqual('2')
|
79
|
+
expect(@buffer.redo()).toEqual(null)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "Mercury", ->
|
4
|
+
|
5
|
+
describe "supported:", ->
|
6
|
+
|
7
|
+
# this is here for documentation -- unable to test, because this is evaluated on script load
|
8
|
+
it "checks document.getElementById", ->
|
9
|
+
it "checks document.designMode", ->
|
10
|
+
it "disallows konqueror and msie", ->
|
11
|
+
|
12
|
+
|
13
|
+
describe "#bind", ->
|
14
|
+
|
15
|
+
it "binds an event prefixed with 'mercury:' to document", ->
|
16
|
+
callCount = 0
|
17
|
+
Mercury.bind('test', -> callCount += 1)
|
18
|
+
$(document).trigger("mercury:test")
|
19
|
+
expect(callCount).toEqual(1)
|
20
|
+
|
21
|
+
|
22
|
+
describe "#trigger", ->
|
23
|
+
|
24
|
+
it "triggers an event prefixed with 'mercury:' on document", ->
|
25
|
+
argsForCall = []
|
26
|
+
callCount = 0
|
27
|
+
Mercury.bind('test', -> argsForCall[callCount] = arguments; callCount += 1)
|
28
|
+
Mercury.trigger("test", {foo: 'bar'})
|
29
|
+
expect(callCount).toEqual(1)
|
30
|
+
expect(argsForCall[0][1]).toEqual({foo: 'bar'})
|
31
|
+
|
32
|
+
|
33
|
+
describe "#log", ->
|
34
|
+
|
35
|
+
beforeEach ->
|
36
|
+
window.console = {debug: -> ''}
|
37
|
+
@debugSpy = spyOn(window.console, 'debug').andCallFake(=>)
|
38
|
+
Mercury.debug = true
|
39
|
+
|
40
|
+
it "calls console.debug", ->
|
41
|
+
Mercury.log(1, 2)
|
42
|
+
expect(@debugSpy.callCount).toEqual(1)
|
43
|
+
|
44
|
+
it "does nothing if debug mode isn't on", ->
|
45
|
+
Mercury.debug = false
|
46
|
+
Mercury.log(1, 2)
|
47
|
+
expect(@debugSpy.callCount).toEqual(0)
|
48
|
+
|
49
|
+
it "does nothing if there's no console", ->
|
50
|
+
window.console = null
|
51
|
+
Mercury.log(1, 2)
|
52
|
+
expect(@debugSpy.callCount).toEqual(0)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "String", ->
|
4
|
+
|
5
|
+
describe "#titleize", ->
|
6
|
+
|
7
|
+
it "should capitalize the first letter in a string", ->
|
8
|
+
expect('wow!'.titleize()).toEqual('Wow!')
|
9
|
+
|
10
|
+
|
11
|
+
describe "#toHex", ->
|
12
|
+
|
13
|
+
it "converts a rgb(0, 0, 0) type string to hex", ->
|
14
|
+
expect('rgb(0, 0, 0)'.toHex()).toEqual('#000000')
|
15
|
+
expect('rgb(255, 255, 0)'.toHex()).toEqual('#FFFF00')
|
16
|
+
|
17
|
+
|
18
|
+
describe "#singleDiff", ->
|
19
|
+
|
20
|
+
it "takes a string to compare against, and returns the first diff it comes to", ->
|
21
|
+
expect('abcdefg'.singleDiff('ab[diff]cdefg')).toEqual('[diff]')
|
22
|
+
expect('abcd/e\\f.g'.singleDiff('ab[diff]cd/e\\f.g')).toEqual('[diff]')
|
23
|
+
|
24
|
+
|
25
|
+
describe "#regExpEscape", ->
|
26
|
+
|
27
|
+
it "escapes characters used in regular expressions", ->
|
28
|
+
expect('/.*+?|()[]{}\\'.regExpEscape()).toEqual('\\/\\.\\*\\+\\?\\|\\(\\)\\[\\]\\{\\}\\\\')
|
29
|
+
|
30
|
+
describe "#sanitizeHTML", ->
|
31
|
+
|
32
|
+
it "removes style tags", ->
|
33
|
+
expect('123<style></style>456'.sanitizeHTML()).toEqual('123456')
|
34
|
+
|
35
|
+
it "removes comment tags", ->
|
36
|
+
expect('123<!--this is a comment-->456'.sanitizeHTML()).toEqual('123456')
|
37
|
+
|
38
|
+
it "replaces new lines with br tags", ->
|
39
|
+
expect('123\n456'.sanitizeHTML()).toEqual('123<br/>456')
|
40
|
+
|
41
|
+
|
42
|
+
describe "Number", ->
|
43
|
+
|
44
|
+
describe "#toHex", ->
|
45
|
+
|
46
|
+
it "converts a number to it's hex value", ->
|
47
|
+
expect(100.toHex()).toEqual('64')
|
48
|
+
expect(255.toHex()).toEqual('FF')
|
49
|
+
|
50
|
+
it "pads 0-F with a 0", ->
|
51
|
+
expect(0.toHex()).toEqual('00')
|
52
|
+
expect(15.toHex()).toEqual('0F')
|
53
|
+
|
54
|
+
describe "#toBytes", ->
|
55
|
+
|
56
|
+
it "converts a number to a readable byte representation (eg. 1.2 kb, 3.4 Mb)", ->
|
57
|
+
kb = 1024
|
58
|
+
expect(kb.toBytes()).toEqual('1.00 kb')
|
59
|
+
expect((kb + 100).toBytes()).toEqual('1.10 kb')
|
60
|
+
expect((kb * 1000).toBytes()).toEqual('1000.00 kb')
|
61
|
+
expect((kb * 1024).toBytes()).toEqual('1.00 Mb')
|
62
|
+
expect((kb * 1024 * 1024).toBytes()).toEqual('1.00 Gb')
|
63
|
+
expect((kb * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Tb')
|
64
|
+
expect((kb * 1024 * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Pb')
|
65
|
+
expect((kb * 1024 * 1024 * 1024 * 1024 * 1024).toBytes()).toEqual('1.00 Eb')
|
66
|
+
|
@@ -0,0 +1,435 @@
|
|
1
|
+
require '/assets/mercury/mercury.js'
|
2
|
+
|
3
|
+
describe "Mercury.PageEditor", ->
|
4
|
+
|
5
|
+
template 'mercury/page_editor.html'
|
6
|
+
|
7
|
+
afterEach ->
|
8
|
+
@pageEditor = null
|
9
|
+
delete(@pageEditor)
|
10
|
+
window.mercuryInstance = null
|
11
|
+
$(document).unbind('mercury:initialize:frame')
|
12
|
+
$(document).unbind('mercury:focus:frame')
|
13
|
+
$(document).unbind('mercury:focus:window')
|
14
|
+
$(document).unbind('mercury:action')
|
15
|
+
$(document).unbind('mousedown')
|
16
|
+
$(window).unbind('resize')
|
17
|
+
|
18
|
+
describe "constructor", ->
|
19
|
+
|
20
|
+
beforeEach ->
|
21
|
+
@initializeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'initializeInterface').andCallFake(=>)
|
22
|
+
|
23
|
+
it "throws an error if it's not supported", ->
|
24
|
+
Mercury.supported = false
|
25
|
+
expect(=>
|
26
|
+
new Mercury.PageEditor()
|
27
|
+
).toThrow('Mercury.PageEditor is unsupported in this client. Supported browsers are chrome 10+, firefix 4+, and safari 5+.')
|
28
|
+
Mercury.supported = true
|
29
|
+
|
30
|
+
it "throws an error if it's already instantiated", ->
|
31
|
+
window.mercuryInstance = true
|
32
|
+
expect(=>
|
33
|
+
new Mercury.PageEditor()
|
34
|
+
).toThrow('Mercury.PageEditor can only be instantiated once.')
|
35
|
+
window.mercuryInstance = false
|
36
|
+
|
37
|
+
it "sets the mercuryInstance to window", ->
|
38
|
+
@pageEditor = new Mercury.PageEditor()
|
39
|
+
expect(window.mercuryInstance).toEqual(@pageEditor)
|
40
|
+
|
41
|
+
it "accepts a saveUrl, and options", ->
|
42
|
+
@pageEditor = new Mercury.PageEditor('/foo/1', {foo: 'bar'})
|
43
|
+
expect(@pageEditor.saveUrl).toEqual('/foo/1')
|
44
|
+
expect(@pageEditor.options).toEqual({foo: 'bar'})
|
45
|
+
|
46
|
+
it "calls initializeInterface", ->
|
47
|
+
@pageEditor = new Mercury.PageEditor()
|
48
|
+
expect(@initializeInterfaceSpy.callCount).toEqual(1)
|
49
|
+
|
50
|
+
it "gets the csrf token if there's one available", ->
|
51
|
+
new Mercury.PageEditor()
|
52
|
+
expect(Mercury.csrfToken).toEqual('K6JhyfOVKJX8X2ZkiJXSf491fc1fF+k79wzrChHQa0g=')
|
53
|
+
|
54
|
+
|
55
|
+
describe "#initializeInterface", ->
|
56
|
+
|
57
|
+
beforeEach ->
|
58
|
+
Mercury.Toolbar = -> {toolbar: true}
|
59
|
+
Mercury.Statusbar = -> {statusbar: true}
|
60
|
+
@iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo')
|
61
|
+
|
62
|
+
it "builds a focusable element (so we can get focus off the iframe)", ->
|
63
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
64
|
+
expect($('input[type=text]').length).toEqual(1)
|
65
|
+
|
66
|
+
it "builds an iframe", ->
|
67
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
68
|
+
expect($('iframe.mercury-iframe').length).toEqual(1)
|
69
|
+
expect($('iframe.mercury-iframe').attr('src')).toEqual('/foo')
|
70
|
+
|
71
|
+
it "appends the elements to any node", ->
|
72
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#page_editor_container')})
|
73
|
+
expect($('#page_editor_container input[type=text]').length).toEqual(1)
|
74
|
+
expect($('#page_editor_container iframe.mercury-iframe').length).toEqual(1)
|
75
|
+
|
76
|
+
it "instantiates the toolbar", ->
|
77
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
78
|
+
expect(@pageEditor.toolbar).toEqual({toolbar: true})
|
79
|
+
|
80
|
+
it "instantiates the statusbar", ->
|
81
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
82
|
+
expect(@pageEditor.statusbar).toEqual({statusbar: true})
|
83
|
+
|
84
|
+
|
85
|
+
describe "#initializeFrame", ->
|
86
|
+
|
87
|
+
beforeEach ->
|
88
|
+
@bindEventsSpy = spyOn(Mercury.PageEditor.prototype, 'bindEvents').andCallFake(=>)
|
89
|
+
@initializeRegionsSpy = spyOn(Mercury.PageEditor.prototype, 'initializeRegions').andCallFake(=>)
|
90
|
+
@finalizeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'finalizeInterface')
|
91
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
92
|
+
|
93
|
+
it "does nothing if the iframe is already loaded", ->
|
94
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
95
|
+
@pageEditor.iframe.data('loaded', true)
|
96
|
+
@pageEditor.initializeFrame()
|
97
|
+
expect(@pageEditor.document).toBeUndefined()
|
98
|
+
|
99
|
+
it "tells the iframe that it's loaded", ->
|
100
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
101
|
+
@pageEditor.initializeFrame()
|
102
|
+
expect(@pageEditor.iframe.data('loaded')).toEqual(true)
|
103
|
+
|
104
|
+
it "gets the document from the iframe", ->
|
105
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
106
|
+
@pageEditor.initializeFrame()
|
107
|
+
expect(@pageEditor.document).toBeDefined()
|
108
|
+
|
109
|
+
it "injects needed mercury styles", ->
|
110
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
111
|
+
spy = spyOn($.fn, 'appendTo').andCallFake(=>)
|
112
|
+
@pageEditor.initializeFrame()
|
113
|
+
expect(spy.callCount).toEqual(1)
|
114
|
+
|
115
|
+
it "calls bindEvents", ->
|
116
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
117
|
+
@pageEditor.initializeFrame()
|
118
|
+
expect(@bindEventsSpy.callCount).toEqual(1)
|
119
|
+
|
120
|
+
it "calls initializeRegions", ->
|
121
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
122
|
+
@pageEditor.initializeFrame()
|
123
|
+
expect(@initializeRegionsSpy.callCount).toEqual(1)
|
124
|
+
|
125
|
+
it "calls finalizeInterface", ->
|
126
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
127
|
+
@pageEditor.initializeFrame()
|
128
|
+
expect(@finalizeInterfaceSpy.callCount).toEqual(1)
|
129
|
+
|
130
|
+
it "shows the iframe", ->
|
131
|
+
@finalizeInterfaceSpy.andCallFake(=>)
|
132
|
+
@pageEditor.initializeFrame()
|
133
|
+
@pageEditor.iframe.css('loaded', true)
|
134
|
+
|
135
|
+
it "captures errors and alerts them", ->
|
136
|
+
@finalizeInterfaceSpy.andCallFake(=> throw('unknown error' ))
|
137
|
+
spy = spyOn(window, 'alert').andCallFake(=>)
|
138
|
+
@pageEditor.initializeFrame()
|
139
|
+
expect(spy.callCount).toEqual(1)
|
140
|
+
expect(spy.argsForCall[0]).toEqual(['Mercury.PageEditor failed to load: unknown error\n\nPlease try refreshing.'])
|
141
|
+
|
142
|
+
|
143
|
+
describe "#initializeRegions", ->
|
144
|
+
|
145
|
+
beforeEach ->
|
146
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
147
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
148
|
+
@pageEditor.document = $(document)
|
149
|
+
@buildRegionSpy = spyOn(Mercury.PageEditor.prototype, 'buildRegion').andCallFake(=>)
|
150
|
+
|
151
|
+
it "it calls buildRegion for all the regions found in a document", ->
|
152
|
+
@pageEditor.initializeRegions()
|
153
|
+
expect(@buildRegionSpy.callCount).toEqual(3)
|
154
|
+
|
155
|
+
it "focuses the first region", ->
|
156
|
+
firstFocusCalled = false
|
157
|
+
@pageEditor.regions = [{focus: => firstFocusCalled = true}, {}, {}]
|
158
|
+
@pageEditor.initializeRegions()
|
159
|
+
expect(firstFocusCalled).toEqual(true)
|
160
|
+
|
161
|
+
|
162
|
+
describe "#buildRegion", ->
|
163
|
+
|
164
|
+
beforeEach ->
|
165
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
166
|
+
Mercury.Regions.Editable = -> {region: true}
|
167
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
168
|
+
|
169
|
+
it "instantiates the region and pushes it into the regions array", ->
|
170
|
+
@pageEditor.buildRegion($('#region2'))
|
171
|
+
expect(@pageEditor.regions.length).toEqual(1)
|
172
|
+
expect(@pageEditor.regions[0]).toEqual({region: true})
|
173
|
+
|
174
|
+
it "alerts on errors", ->
|
175
|
+
Mercury.debug = false
|
176
|
+
Mercury.Regions.Editable = -> throw('error!')
|
177
|
+
spy = spyOn(window, 'alert').andCallFake(=>)
|
178
|
+
@pageEditor.buildRegion($('#region2'))
|
179
|
+
expect(spy.callCount).toEqual(1)
|
180
|
+
expect(spy.argsForCall[0]).toEqual(['Region type is malformed, no data-type provided, or "Editable" is unknown.'])
|
181
|
+
|
182
|
+
|
183
|
+
describe "#finalizeInterface", ->
|
184
|
+
|
185
|
+
beforeEach ->
|
186
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
187
|
+
Mercury.SnippetToolbar = -> {snippetToolbar: true}
|
188
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
189
|
+
@highjackLinksSpy = spyOn(Mercury.PageEditor.prototype, 'hijackLinks').andCallFake(=>)
|
190
|
+
@resizeSpy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
|
191
|
+
|
192
|
+
it "it builds a snippetToolbar", ->
|
193
|
+
@pageEditor.finalizeInterface()
|
194
|
+
expect(@pageEditor.snippetToolbar).toEqual({snippetToolbar: true})
|
195
|
+
|
196
|
+
it "calls hijackLinks", ->
|
197
|
+
@pageEditor.finalizeInterface()
|
198
|
+
expect(@highjackLinksSpy.callCount).toEqual(1)
|
199
|
+
|
200
|
+
it "calls resize", ->
|
201
|
+
@pageEditor.finalizeInterface()
|
202
|
+
expect(@resizeSpy.callCount).toEqual(1)
|
203
|
+
|
204
|
+
|
205
|
+
describe "observed events", ->
|
206
|
+
|
207
|
+
beforeEach ->
|
208
|
+
@initializeInterfaceSpy = spyOn(Mercury.PageEditor.prototype, 'initializeInterface').andCallFake(=>)
|
209
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
210
|
+
@pageEditor.document = $(document)
|
211
|
+
@pageEditor.bindEvents()
|
212
|
+
|
213
|
+
describe "custom event: initialize:frame", ->
|
214
|
+
|
215
|
+
it "calls initializeFrame", ->
|
216
|
+
@initializeFrameSpy = spyOn(Mercury.PageEditor.prototype, 'initializeFrame').andCallFake(=>)
|
217
|
+
@setTimeoutSpy = spyOn(window, 'setTimeout').andCallFake((callback) -> callback())
|
218
|
+
Mercury.trigger('initialize:frame')
|
219
|
+
expect(@initializeFrameSpy.callCount).toEqual(1)
|
220
|
+
expect(@setTimeoutSpy.callCount).toEqual(1)
|
221
|
+
|
222
|
+
describe "custom event: focus:frame", ->
|
223
|
+
|
224
|
+
it "calls focus on the iframe", ->
|
225
|
+
callCount = 0
|
226
|
+
@pageEditor.iframe = {focus: -> callCount += 1}
|
227
|
+
Mercury.trigger('focus:frame')
|
228
|
+
expect(callCount).toEqual(1)
|
229
|
+
|
230
|
+
describe "custom event: focus:window", ->
|
231
|
+
|
232
|
+
it "calls focus on a focusable element", ->
|
233
|
+
callCount = 0
|
234
|
+
@pageEditor.focusableElement = {focus: -> callCount += 1}
|
235
|
+
@setTimeoutSpy = spyOn(window, 'setTimeout').andCallFake((callback) -> callback())
|
236
|
+
Mercury.trigger('focus:window')
|
237
|
+
expect(callCount).toEqual(1)
|
238
|
+
|
239
|
+
describe "custom event: action", ->
|
240
|
+
|
241
|
+
it "calls save if the action was save", ->
|
242
|
+
spy = spyOn(Mercury.PageEditor.prototype, 'save').andCallFake(=>)
|
243
|
+
Mercury.trigger('action', {action: 'foo'})
|
244
|
+
expect(spy.callCount).toEqual(0)
|
245
|
+
|
246
|
+
Mercury.trigger('action', {action: 'save'})
|
247
|
+
expect(spy.callCount).toEqual(1)
|
248
|
+
|
249
|
+
describe "mousedown on document", ->
|
250
|
+
|
251
|
+
beforeEach ->
|
252
|
+
@triggerSpy = spyOn(Mercury, 'trigger').andCallFake(=>)
|
253
|
+
|
254
|
+
it "triggers hide:dialogs", ->
|
255
|
+
Mercury.region = {element: $('#region3')}
|
256
|
+
jasmine.simulate.mousedown($('#anchor1r').get(0))
|
257
|
+
expect(@triggerSpy.callCount).toEqual(1)
|
258
|
+
expect(@triggerSpy.argsForCall[0]).toEqual(['hide:dialogs'])
|
259
|
+
|
260
|
+
it "triggers unfocus:regions unless the event happened in a region", ->
|
261
|
+
Mercury.region = {element: {get: -> null}}
|
262
|
+
jasmine.simulate.mousedown(document)
|
263
|
+
expect(@triggerSpy.callCount).toEqual(2)
|
264
|
+
expect(@triggerSpy.argsForCall[1]).toEqual(['unfocus:regions'])
|
265
|
+
|
266
|
+
describe "window resize", ->
|
267
|
+
|
268
|
+
it "calls resize", ->
|
269
|
+
# untestable
|
270
|
+
#spy = spyOn(Mercury.PageEditor.prototype, 'resize').andCallFake(=>)
|
271
|
+
#resizeTo($(window).width() - 1, $(window).height() - 1)
|
272
|
+
#expect(spy.callCount).toEqual(1)
|
273
|
+
|
274
|
+
describe "onbeforeunload", ->
|
275
|
+
|
276
|
+
it "calls Mercury.beforeUnload", ->
|
277
|
+
# untestable
|
278
|
+
#spy = spyOn(Mercury, 'beforeUnload').andCallFake(=>)
|
279
|
+
#window.onbeforeunload()
|
280
|
+
#expect(spy.callCount).toEqual(1)
|
281
|
+
|
282
|
+
|
283
|
+
describe "#resize", ->
|
284
|
+
|
285
|
+
beforeEach ->
|
286
|
+
Mercury.Toolbar = -> {toolbar: true, height: -> 100}
|
287
|
+
Mercury.Statusbar = -> {statusbar: true, height: -> 10}
|
288
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
289
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
290
|
+
|
291
|
+
it "sets the display rectangle to displayRect", ->
|
292
|
+
@pageEditor.resize()
|
293
|
+
expect(Mercury.displayRect.top).toEqual(100)
|
294
|
+
expect(Mercury.displayRect.height).toEqual($(window).height() - 100 - 10)
|
295
|
+
|
296
|
+
it "resizes the iframe", ->
|
297
|
+
@pageEditor.resize()
|
298
|
+
expect($('.mercury-iframe').css('top')).toEqual('100px')
|
299
|
+
expect($('.mercury-iframe').css('height')).toEqual("#{$(window).height() - 100 - 10}px")
|
300
|
+
|
301
|
+
it "triggers a resize event", ->
|
302
|
+
spy = spyOn(Mercury, 'trigger').andCallFake(=>)
|
303
|
+
@pageEditor.resize()
|
304
|
+
expect(spy.callCount).toEqual(1)
|
305
|
+
|
306
|
+
|
307
|
+
describe "#iframeSrc", ->
|
308
|
+
|
309
|
+
beforeEach ->
|
310
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
311
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
312
|
+
|
313
|
+
it "takes the location and removes the /edit", ->
|
314
|
+
expect(@pageEditor.iframeSrc('http://something/edit/path')).toEqual('http://something/path')
|
315
|
+
|
316
|
+
|
317
|
+
describe "#hijackLinks", ->
|
318
|
+
|
319
|
+
beforeEach ->
|
320
|
+
Mercury.PageEditor.prototype.initializeFrame = ->
|
321
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
322
|
+
@pageEditor.options.ignoredLinks = ['lightview']
|
323
|
+
@pageEditor.document = $(document)
|
324
|
+
|
325
|
+
it "finds links and set their target to top if it's not already set", ->
|
326
|
+
@pageEditor.hijackLinks()
|
327
|
+
expect($('#anchor1').attr('target')).toEqual('_top')
|
328
|
+
expect($('#anchor2').attr('target')).toEqual('_blank')
|
329
|
+
expect($('#anchor3').attr('target')).toEqual('_top')
|
330
|
+
expect($('#anchor4').attr('target')).toEqual('_top')
|
331
|
+
|
332
|
+
it "ignores links in regions", ->
|
333
|
+
@pageEditor.hijackLinks()
|
334
|
+
expect($('#anchor1r').attr('target')).toEqual('_top')
|
335
|
+
expect($('#anchor2r').attr('target')).toEqual('_blank')
|
336
|
+
expect($('#anchor3r').attr('target')).toEqual('_self')
|
337
|
+
expect($('#anchor4r').attr('target')).toBeUndefined()
|
338
|
+
|
339
|
+
it "ignores links that are in the config to be ignored (by class)", ->
|
340
|
+
@pageEditor.hijackLinks()
|
341
|
+
expect($('#anchor5').attr('target')).toEqual('_self')
|
342
|
+
|
343
|
+
|
344
|
+
describe "#beforeUnload", ->
|
345
|
+
|
346
|
+
beforeEach ->
|
347
|
+
Mercury.PageEditor.prototype.initializeInterface = ->
|
348
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
349
|
+
Mercury.silent = false
|
350
|
+
Mercury.changes = true
|
351
|
+
|
352
|
+
it "returns a message if changes were made", ->
|
353
|
+
expect(@pageEditor.beforeUnload()).toEqual('You have unsaved changes. Are you sure you want to leave without saving them first?')
|
354
|
+
|
355
|
+
Mercury.changes = false
|
356
|
+
expect(@pageEditor.beforeUnload()).toEqual(null)
|
357
|
+
|
358
|
+
it "does nothing if in silent mode", ->
|
359
|
+
Mercury.silent = true
|
360
|
+
expect(@pageEditor.beforeUnload()).toEqual(null)
|
361
|
+
|
362
|
+
|
363
|
+
describe "#save", ->
|
364
|
+
|
365
|
+
beforeEach ->
|
366
|
+
Mercury.PageEditor.prototype.initializeInterface = ->
|
367
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
368
|
+
@iframeSrcSpy = spyOn(Mercury.PageEditor.prototype, 'iframeSrc').andCallFake(=> '/foo/baz')
|
369
|
+
@ajaxSpy = spyOn($, 'ajax')
|
370
|
+
|
371
|
+
it "makes an ajax request", ->
|
372
|
+
@ajaxSpy.andCallFake(=>)
|
373
|
+
@pageEditor.save()
|
374
|
+
expect(@ajaxSpy.callCount).toEqual(1)
|
375
|
+
|
376
|
+
it "uses the save url passed in via options, or the iframe src", ->
|
377
|
+
@ajaxSpy.andCallFake(=>)
|
378
|
+
@pageEditor.saveUrl = '/foo/bar'
|
379
|
+
@pageEditor.save()
|
380
|
+
expect(@ajaxSpy.argsForCall[0][0]).toEqual('/foo/bar')
|
381
|
+
|
382
|
+
@pageEditor.saveUrl = null
|
383
|
+
@pageEditor.save()
|
384
|
+
expect(@ajaxSpy.argsForCall[1][0]).toEqual('/foo/baz')
|
385
|
+
|
386
|
+
it "serializes the data in json", ->
|
387
|
+
@ajaxSpy.andCallFake(=>)
|
388
|
+
Mercury.config.saveStyle = 'json'
|
389
|
+
spy = spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
|
390
|
+
@pageEditor.save()
|
391
|
+
expect(@ajaxSpy.argsForCall[0][1]['data']).toEqual({content: '{"region1":"region1"}' })
|
392
|
+
|
393
|
+
it "can serialize as form values", ->
|
394
|
+
@ajaxSpy.andCallFake(=>)
|
395
|
+
@pageEditor.options.saveStyle = 'form'
|
396
|
+
spy = spyOn(Mercury.PageEditor.prototype, 'serialize').andCallFake(=> {region1: 'region1'})
|
397
|
+
@pageEditor.save()
|
398
|
+
expect(@ajaxSpy.argsForCall[0][1]['data']).toEqual({content: {region1: 'region1'}})
|
399
|
+
|
400
|
+
describe "on successful ajax request", ->
|
401
|
+
|
402
|
+
beforeEach ->
|
403
|
+
@ajaxSpy.andCallFake((url, options) => options.success('data') )
|
404
|
+
|
405
|
+
it "sets changes back to false", ->
|
406
|
+
Mercury.changes = true
|
407
|
+
@pageEditor.save()
|
408
|
+
expect(Mercury.changes).toEqual(false)
|
409
|
+
|
410
|
+
describe "on failed ajax request", ->
|
411
|
+
|
412
|
+
beforeEach ->
|
413
|
+
@ajaxSpy.andCallFake((url, options) => options.error() )
|
414
|
+
|
415
|
+
it "alerts with the url", ->
|
416
|
+
spy = spyOn(window, 'alert').andCallFake(=>)
|
417
|
+
@pageEditor.saveUrl = '/foo/bar'
|
418
|
+
@pageEditor.save()
|
419
|
+
expect(spy.callCount).toEqual(1)
|
420
|
+
expect(spy.argsForCall[0]).toEqual(['Mercury was unable to save to the url: /foo/bar'])
|
421
|
+
|
422
|
+
|
423
|
+
describe "#serialize", ->
|
424
|
+
|
425
|
+
beforeEach ->
|
426
|
+
Mercury.PageEditor.prototype.initializeInterface = ->
|
427
|
+
@pageEditor = new Mercury.PageEditor('', {appendTo: $('#test')})
|
428
|
+
@pageEditor.regions = [
|
429
|
+
{name: 'region1', serialize: -> 'region1'},
|
430
|
+
{name: 'region2', serialize: -> 'region2'}
|
431
|
+
]
|
432
|
+
|
433
|
+
it "returns an object with the region name, and it's serialized value", ->
|
434
|
+
ret = @pageEditor.serialize()
|
435
|
+
expect(ret).toEqual({region1: 'region1', region2: 'region2'})
|