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
@@ -0,0 +1,51 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Palette", ->
4
+
5
+ template 'mercury/palette.html'
6
+
7
+ beforeEach ->
8
+ $.fx.off = true
9
+
10
+ afterEach ->
11
+ @palette = null
12
+ delete(@palette)
13
+
14
+ describe "#build", ->
15
+
16
+ it "builds an element", ->
17
+ @palette = new Mercury.Palette('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
18
+ html = $('<div>').html(@palette.element).html()
19
+ expect(html).toContain('class="mercury-palette mercury-foo-palette loading"')
20
+ expect(html).toContain('style="display:none"')
21
+
22
+ it "appends to any element", ->
23
+ @palette = new Mercury.Palette('/evergreen/responses/blank.html', 'foo', {appendTo: '#palette_container', for: $('#button')})
24
+ expect($('#palette_container .mercury-palette').length).toEqual(1)
25
+
26
+
27
+ describe "observed events", ->
28
+
29
+ beforeEach ->
30
+ @palette = new Mercury.Palette('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
31
+
32
+ it "hides", ->
33
+ @palette.element.css({display: 'block'})
34
+ Mercury.trigger('hide:dialogs')
35
+ expect(@palette.element.css('display')).toEqual('none')
36
+
37
+ it "doesn't hide if it's the same dialog", ->
38
+ @palette.element.css({display: 'block'})
39
+ Mercury.trigger('hide:dialogs', @palette)
40
+ expect(@palette.element.css('display')).toEqual('block')
41
+
42
+
43
+ describe "#position", ->
44
+
45
+ beforeEach ->
46
+ @palette = new Mercury.Palette('/evergreen/responses/blank.html', 'foo', {appendTo: '#test', for: $('#button')})
47
+
48
+ it "positions based on it's button", ->
49
+ @palette.element.css({display: 'block'})
50
+ @palette.position(true)
51
+ expect(@palette.element.offset()).toEqual({top: 62, left: 42})
@@ -0,0 +1,147 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Panel", ->
4
+
5
+ template 'mercury/panel.html'
6
+
7
+ beforeEach ->
8
+ Mercury.displayRect = {top: 20, left: 20, width: 200, height: 200}
9
+ $.fx.off = true
10
+
11
+ afterEach ->
12
+ @panel = null
13
+ delete(@panel)
14
+ $(document).unbind('mercury:resize')
15
+ $(document).unbind('mercury:hide:panels')
16
+
17
+ describe "#build", ->
18
+
19
+ it "builds an element", ->
20
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#test', title: 'foo panel'})
21
+ html = $('<div>').html(@panel.element).html()
22
+ expect(html).toContain('class="mercury-panel loading"')
23
+ expect(html).toContain('style="display:none;"')
24
+ expect(html).toContain('<h1>foo panel</h1><div class="mercury-panel-pane"></div>')
25
+
26
+ it "appends to any element", ->
27
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#panel_container', title: 'foo panel'})
28
+ expect($('#panel_container .mercury-panel').length).toEqual(1)
29
+
30
+
31
+ describe "observed events", ->
32
+
33
+ beforeEach ->
34
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#test', title: 'foo panel', for: $('#button')})
35
+
36
+ describe "custom event: resize", ->
37
+
38
+ it "calls position", ->
39
+ spy = spyOn(Mercury.Panel.prototype, 'position').andCallFake(=>)
40
+ Mercury.trigger('resize')
41
+ expect(spy.callCount).toEqual(1)
42
+
43
+ describe "custom event: hide:panels", ->
44
+
45
+ it "hides", ->
46
+ @panel.element.css({display: 'block'})
47
+ Mercury.trigger('hide:panels')
48
+ expect(@panel.element.css('display')).toEqual('none')
49
+
50
+ it "doesn't hide if it's the same dialog", ->
51
+ @panel.element.css({display: 'block'})
52
+ Mercury.trigger('hide:panels', @panel)
53
+ expect(@panel.element.css('display')).toEqual('block')
54
+
55
+
56
+ describe "#show", ->
57
+
58
+ beforeEach ->
59
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#test', title: 'foo panel'})
60
+
61
+ it "hides other panels and dialogs", ->
62
+ spyOn(Mercury.Panel.prototype, 'position')
63
+ spyOn(Mercury.Panel.prototype, 'appear')
64
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
65
+ @panel.show()
66
+ expect(spy.callCount).toEqual(2)
67
+ expect(spy.argsForCall[0]).toEqual(['hide:panels', @panel])
68
+ expect(spy.argsForCall[1]).toEqual(['hide:dialogs', @panel])
69
+
70
+
71
+ describe "#resize", ->
72
+
73
+ beforeEach ->
74
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#panel_container', title: 'foo panel'})
75
+ @panel.element.css({display: 'block'})
76
+ @panel.visible = true
77
+
78
+ it "figures out what size it should be and resizes", ->
79
+ @panel.resize()
80
+ expect(@panel.element.offset()).toEqual({top: 42, left: 84})
81
+ expect(@panel.element.css('display')).toEqual('block')
82
+
83
+ it "calls makeDraggable", ->
84
+ spy = spyOn(Mercury.Panel.prototype, 'makeDraggable').andCallFake(=>)
85
+ @panel.resize()
86
+ expect(spy.callCount).toEqual(1)
87
+
88
+ it "keeps it hidden if it's not supposed to be visible", ->
89
+ @panel.visible = false
90
+ @panel.resize()
91
+ expect(@panel.element.css('display')).toEqual('none')
92
+
93
+
94
+ describe "#position", ->
95
+
96
+ beforeEach ->
97
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#panel_container', title: 'foo panel'})
98
+ @panel.element.css({display: 'block'})
99
+ @panel.visible = true
100
+
101
+ it "positions based on the display rectangle", ->
102
+ @panel.position(true)
103
+ expect(@panel.element.offset()).toEqual({top: 70, left: 122})
104
+ expect(@panel.element.css('display')).toEqual('block')
105
+
106
+ it "calls makeDraggable", ->
107
+ spy = spyOn(Mercury.Panel.prototype, 'makeDraggable').andCallFake(=>)
108
+ @panel.position()
109
+ expect(spy.callCount).toEqual(1)
110
+
111
+ it "keeps it hidden if it's not supposed to be visible", ->
112
+ @panel.visible = false
113
+ @panel.position()
114
+ expect(@panel.element.css('display')).toEqual('none')
115
+
116
+
117
+ describe "#loadContent", ->
118
+
119
+ beforeEach ->
120
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#test', title: 'foo panel'})
121
+
122
+ it "sets loaded to be true", ->
123
+ @panel.loadContent()
124
+ expect(@panel.loaded).toEqual(true)
125
+
126
+ it "removes the loading class from the element", ->
127
+ @panel.loadContent()
128
+ expect(@panel.element.hasClass('loading')).toEqual(false)
129
+
130
+ it "sets the element html to be the data passed to it", ->
131
+ @panel.loadContent('hello world!')
132
+ html = @panel.element.html()
133
+ expect(html).toContain('<h1>foo panel</h1>')
134
+ expect(html).toContain('class="mercury-panel-pane"')
135
+ expect(html).toContain('style="visibility: hidden;"')
136
+ expect(html).toContain('hello world')
137
+
138
+
139
+ describe "#makesDraggable", ->
140
+
141
+ beforeEach ->
142
+ @panel = new Mercury.Panel('/evergreen/resources/panel.html', 'foo', {appendTo: '#test', title: 'foo panel'})
143
+
144
+ it "makes the element draggable", ->
145
+ spy = spyOn($.fn, 'draggable').andCallFake(=>)
146
+ @panel.makeDraggable()
147
+ expect(spy.callCount).toEqual(1)
@@ -0,0 +1,261 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Region", ->
4
+
5
+ template 'mercury/region.html'
6
+
7
+ afterEach ->
8
+ @region = null
9
+ delete(@region)
10
+ $(document).unbind('mercury:mode')
11
+ $(document).unbind('mercury:focus:frame')
12
+ $(document).unbind('mercury:action')
13
+
14
+ describe "constructor", ->
15
+
16
+ beforeEach ->
17
+ @buildSpy = spyOn(Mercury.Region.prototype, 'build').andCallFake(=>)
18
+ @bindEventsSpy = spyOn(Mercury.Region.prototype, 'bindEvents').andCallFake(=>)
19
+ @pushHistorySpy = spyOn(Mercury.Region.prototype, 'pushHistory').andCallFake(=>)
20
+
21
+ it "expects an element and window (for context)", ->
22
+ @region = new Mercury.Region($('#region'), window)
23
+ expect(@region.element.get(0)).toEqual($('#region').get(0))
24
+
25
+ it "accepts options", ->
26
+ @region = new Mercury.Region($('#region'), window, {foo: 'bar'})
27
+ expect(@region.options).toEqual({foo: 'bar'})
28
+
29
+ it "sets variables we need", ->
30
+ @region = new Mercury.Region($('#region'), window, {foo: 'bar'})
31
+ expect(@region.name).toEqual('region')
32
+ expect(@region.history).toBeDefined()
33
+
34
+ it "calls build", ->
35
+ @region = new Mercury.Region($('#region'), window, {foo: 'bar'})
36
+ expect(@buildSpy.callCount).toEqual(1)
37
+
38
+ it "calls bindEvents", ->
39
+ @region = new Mercury.Region($('#region'), window, {foo: 'bar'})
40
+ expect(@bindEventsSpy.callCount).toEqual(1)
41
+
42
+ it "pushes the initial state to the history buffer", ->
43
+ @region = new Mercury.Region($('#region'), window, {foo: 'bar'})
44
+ expect(@pushHistorySpy.callCount).toEqual(1)
45
+
46
+
47
+ describe "#build", ->
48
+
49
+ it "does nothing and is there as an interface"
50
+
51
+
52
+ describe "#focus", ->
53
+
54
+ it "does nothing and is there as an interface"
55
+
56
+
57
+ describe "observed events", ->
58
+
59
+ beforeEach ->
60
+ @region = new Mercury.Region($('#region_with_snippet'), window)
61
+
62
+ describe "custom event: mode", ->
63
+
64
+ it "calls togglePreview if the mode is preview", ->
65
+ spy = spyOn(Mercury.Region.prototype, 'togglePreview').andCallFake(=>)
66
+ Mercury.trigger('mode', {mode: 'foo'})
67
+ expect(spy.callCount).toEqual(0)
68
+ Mercury.trigger('mode', {mode: 'preview'})
69
+ expect(spy.callCount).toEqual(1)
70
+
71
+ describe "custom event: focus:frame", ->
72
+
73
+ beforeEach ->
74
+ @focusSpy = spyOn(Mercury.Region.prototype, 'focus').andCallFake(=>)
75
+
76
+ it "does nothing if in preview mode", ->
77
+ @region.previewing = true
78
+ Mercury.trigger('focus:frame', {region: @region})
79
+ expect(@focusSpy.callCount).toEqual(0)
80
+
81
+ it "does nothing if it's not active region", ->
82
+ Mercury.region = {}
83
+ Mercury.trigger('focus:frame', {region: @region})
84
+ expect(@focusSpy.callCount).toEqual(0)
85
+
86
+ it "calls focus", ->
87
+ Mercury.region = @region
88
+ Mercury.trigger('focus:frame', {region: @region})
89
+ expect(@focusSpy.callCount).toEqual(1)
90
+
91
+ describe "custom event: action", ->
92
+
93
+ beforeEach ->
94
+ @execCommandSpy = spyOn(Mercury.Region.prototype, 'execCommand').andCallFake(=>)
95
+
96
+ it "does nothing if in preview mode", ->
97
+ @region.previewing = true
98
+ Mercury.trigger('action', {action: 'foo', value: 'bar'})
99
+ expect(@execCommandSpy.callCount).toEqual(0)
100
+
101
+ it "does nothing if it's not active region", ->
102
+ Mercury.region = {}
103
+ Mercury.trigger('action', {action: 'foo', value: 'bar'})
104
+ expect(@execCommandSpy.callCount).toEqual(0)
105
+
106
+ it "calls execCommand with the action and options", ->
107
+ Mercury.region = @region
108
+ Mercury.trigger('action', {action: 'foo', value: 'bar'})
109
+ expect(@execCommandSpy.callCount).toEqual(1)
110
+ expect(@execCommandSpy.argsForCall[0]).toEqual(['foo', {action: 'foo', value: 'bar'}])
111
+
112
+ describe "mouseover", ->
113
+
114
+ beforeEach ->
115
+ @triggerSpy = spyOn(Mercury, 'trigger').andCallFake(=>)
116
+
117
+ it "does nothing if in preview mode", ->
118
+ @region.previewing = true
119
+ jasmine.simulate.mousemove($('#region_with_snippet .mercury-snippet').get(0))
120
+ expect(@triggerSpy.callCount).toEqual(0)
121
+
122
+ it "does nothing if it's not the active region", ->
123
+ Mercury.region = {}
124
+ jasmine.simulate.mousemove($('#region_with_snippet .mercury-snippet').get(0))
125
+ expect(@triggerSpy.callCount).toEqual(0)
126
+
127
+ it "shows the snippet toolbar if a snippet was moused over", ->
128
+ Mercury.region = @region
129
+ jasmine.simulate.mousemove($('#region_with_snippet .mercury-snippet').get(0))
130
+ expect(@triggerSpy.callCount).toEqual(1)
131
+ expect(@triggerSpy.argsForCall[0][0]).toEqual('show:toolbar')
132
+
133
+ describe "mouseout", ->
134
+
135
+ beforeEach ->
136
+ @triggerSpy = spyOn(Mercury, 'trigger').andCallFake(=>)
137
+
138
+ it "does nothing if previewing", ->
139
+ @region.previewing = true
140
+ jasmine.simulate.mouseout(@region.element.get(0))
141
+ expect(@triggerSpy.callCount).toEqual(0)
142
+
143
+ it "hides the snippet toolbar", ->
144
+ jasmine.simulate.mouseout(@region.element.get(0))
145
+ expect(@triggerSpy.callCount).toEqual(1)
146
+ expect(@triggerSpy.argsForCall[0]).toEqual(['hide:toolbar', {type: 'snippet', immediately: false}])
147
+
148
+
149
+ describe "#html", ->
150
+
151
+ beforeEach ->
152
+ @region = new Mercury.Region($('#region_with_snippet'), window)
153
+
154
+ describe "getting html", ->
155
+
156
+ it "returns the html of the element", ->
157
+ html = @region.html()
158
+ expect(html).toEqual('contents<div class="mercury-snippet" data-snippet="snippet_1" data-version="1">snippet</div>')
159
+
160
+ it "replaces snippet content with an indentifier if asked", ->
161
+ html = @region.html(null, true)
162
+ expect(html).toEqual('contents<div class="mercury-snippet" data-snippet="snippet_1">[snippet_1]</div>')
163
+
164
+ describe "setting html", ->
165
+
166
+ it "sets the value of the html", ->
167
+ @region.html('new html')
168
+ expect($('#region_with_snippet').html()).toEqual('new html')
169
+
170
+
171
+ describe "#togglePreview", ->
172
+
173
+ beforeEach ->
174
+ @region = new Mercury.Region($('#region'), window)
175
+ Mercury.region = @region
176
+ @focusSpy = spyOn(Mercury.Region.prototype, 'focus').andCallFake(=>)
177
+ @triggerSpy = spyOn(Mercury, 'trigger').andCallFake(=>)
178
+
179
+ describe "when not previewing", ->
180
+
181
+ beforeEach ->
182
+ @region.togglePreview()
183
+
184
+ it "sets previewing to true", ->
185
+ expect(@region.previewing).toEqual(true)
186
+
187
+ it "swaps classes on the element", ->
188
+ expect(@region.element.hasClass('mercury-region')).toEqual(false)
189
+ expect(@region.element.hasClass('mercury-region-preview')).toEqual(true)
190
+
191
+ it "triggers a blur event", ->
192
+ expect(@triggerSpy.callCount).toEqual(1)
193
+ expect(@triggerSpy.argsForCall[0]).toEqual(['region:blurred', {region: @region}])
194
+
195
+ describe "when previewing", ->
196
+
197
+ beforeEach ->
198
+ @region.previewing = true
199
+ @region.togglePreview()
200
+
201
+ it "sets previewing to false", ->
202
+ expect(@region.previewing).toEqual(false)
203
+
204
+ it "swaps classes on the element", ->
205
+ expect(@region.element.hasClass('mercury-region-preview')).toEqual(false)
206
+ expect(@region.element.hasClass('mercury-region')).toEqual(true)
207
+
208
+ it "calls focus if it's the active region", ->
209
+ expect(@focusSpy.callCount).toEqual(1)
210
+
211
+
212
+ describe "#execCommand", ->
213
+
214
+ beforeEach ->
215
+ Mercury.changes = false
216
+ @region = new Mercury.Region($('#region'), window)
217
+
218
+ it "calls focus", ->
219
+ spy = spyOn(Mercury.Region.prototype, 'focus').andCallFake(=>)
220
+ @region.execCommand('foo')
221
+ expect(spy.callCount).toEqual(1)
222
+
223
+ it "pushes to the history (unless the action is redo)", ->
224
+ spy = spyOn(Mercury.Region.prototype, 'pushHistory').andCallFake(=>)
225
+ @region.execCommand('redo')
226
+ expect(spy.callCount).toEqual(0)
227
+ @region.execCommand('foo')
228
+ expect(spy.callCount).toEqual(1)
229
+
230
+ it "tells Mercury that changes have been made", ->
231
+ @region.execCommand('foo')
232
+ expect(Mercury.changes).toEqual(true)
233
+
234
+
235
+ describe "#pushHistory", ->
236
+
237
+ beforeEach ->
238
+ Mercury.changes = false
239
+ @region = new Mercury.Region($('#region'), window)
240
+
241
+ it "pushes the current content (html) of the region to the history buffer", ->
242
+ spy = spyOn(@region.history, 'push').andCallFake(=>)
243
+ @region.pushHistory('foo')
244
+ expect(spy.callCount).toEqual(1)
245
+
246
+
247
+ describe "#snippets", ->
248
+
249
+ it "does nothing and is there as an interface", ->
250
+
251
+
252
+ describe "#serialize", ->
253
+
254
+ beforeEach ->
255
+ @region = new Mercury.Region($('#region'), window)
256
+
257
+ it "returns an object with it's type, value, and snippets", ->
258
+ serialized = @region.serialize()
259
+ expect(serialized.type).toEqual('region')
260
+ expect(serialized.value).toEqual('contents')
261
+ expect(serialized.snippets).toEqual({})