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.
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,92 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Toolbar.ButtonGroup", ->
4
+
5
+ template 'mercury/toolbar.button_group.html'
6
+
7
+ beforeEach ->
8
+ Mercury.Toolbar.ButtonGroup.contexts.foo = -> false
9
+ @region = {
10
+ element: $('<div class="mercury-region">')
11
+ currentElement: -> $('<div>')
12
+ }
13
+
14
+ afterEach ->
15
+ @buttonGroup = null
16
+ delete(@buttonGroup)
17
+ $(document).unbind('mercury:region:update')
18
+
19
+ describe "constructor", ->
20
+
21
+ beforeEach ->
22
+ @buildSpy = spyOn(Mercury.Toolbar.ButtonGroup.prototype, 'build').andCallThrough()
23
+ @bindEventsSpy = spyOn(Mercury.Toolbar.ButtonGroup.prototype, 'bindEvents').andCallThrough()
24
+ @buttonGroup = new Mercury.Toolbar.ButtonGroup('foo', {_context: true})
25
+
26
+ it "returns an element", ->
27
+ html = $('<div>').html(@buttonGroup).html()
28
+ expect(html).toEqual('<div class="mercury-button-group mercury-foo-group disabled"></div>')
29
+
30
+ it "calls build", ->
31
+ expect(@buildSpy.callCount).toEqual(1)
32
+
33
+ it "calls bindEvents", ->
34
+ expect(@bindEventsSpy.callCount).toEqual(1)
35
+
36
+
37
+ describe "observed events", ->
38
+
39
+ describe "custom event: region:update", ->
40
+
41
+ it "sets disabled/enabled state based on it's context", ->
42
+ @buttonGroup = new Mercury.Toolbar.ButtonGroup('foo', {_context: true})
43
+ contextSpy = spyOn(Mercury.Toolbar.ButtonGroup.contexts, 'foo').andCallFake(-> true)
44
+
45
+ expect(@buttonGroup.hasClass('disabled')).toEqual(true)
46
+
47
+ Mercury.trigger('region:update', {region: @region})
48
+ expect(contextSpy.callCount).toEqual(1)
49
+ expect(@buttonGroup.hasClass('disabled')).toEqual(false)
50
+
51
+ describe "custom event: region:focused", ->
52
+
53
+ beforeEach ->
54
+ @region = {
55
+ type: 'editable'
56
+ element: $('<div class="mercury-region">')
57
+ }
58
+
59
+ it "disables if the region type isn't supported", ->
60
+ @buttonGroup = new Mercury.Toolbar.ButtonGroup('foo', {_regions: ['foo']})
61
+ @buttonGroup.removeClass('disabled')
62
+ Mercury.trigger('region:focused', {region: @region})
63
+ expect(@buttonGroup.hasClass('disabled')).toEqual(true)
64
+
65
+ it "enables if the region type is supported", ->
66
+ @buttonGroup = new Mercury.Toolbar.ButtonGroup('foo', {_regions: ['editable']})
67
+ @buttonGroup.addClass('disabled')
68
+ Mercury.trigger('region:focused', {region: @region})
69
+ expect(@buttonGroup.hasClass('disabled')).toEqual(false)
70
+
71
+ describe "custom event: region:blurred", ->
72
+
73
+ it "disables if it's a button group for specific region types", ->
74
+ @buttonGroup = new Mercury.Toolbar.ButtonGroup('foo', {_regions: ['editable']})
75
+ @buttonGroup.removeClass('disabled')
76
+ Mercury.trigger('region:blurred', {region: @region})
77
+
78
+
79
+
80
+ describe "Mercury.Toolbar.ButtonGroup.contexts", ->
81
+
82
+ template 'mercury/toolbar.button_group.html'
83
+
84
+ beforeEach ->
85
+ @contexts = Mercury.Toolbar.ButtonGroup.contexts
86
+ @region = $('#context_container')
87
+
88
+ describe "table", ->
89
+
90
+ it "looks up for a table tag", ->
91
+ expect(@contexts.table($('#context_td'), @region)).toEqual(true)
92
+ expect(@contexts.table($('#context_em'), @region)).toEqual(false)
@@ -0,0 +1,341 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Toolbar.Button", ->
4
+
5
+ template 'mercury/toolbar.button.html'
6
+
7
+ beforeEach ->
8
+ Mercury.displayRect = {0, 0, 500, 200}
9
+ Mercury.Toolbar.Button.contexts.foo = -> true
10
+ @region = {
11
+ type: 'editable'
12
+ element: $('<div class="mercury-region">')
13
+ currentElement: -> $('<div>')
14
+ }
15
+
16
+ afterEach ->
17
+ @button = null
18
+ delete(@button)
19
+ $(document).unbind('mercury:region:update')
20
+ $(document).unbind('mercury:button')
21
+
22
+ describe "constructor", ->
23
+
24
+ it "expects name and title values", ->
25
+ @button = new Mercury.Toolbar.Button('foo', 'title')
26
+ html = $('<div>').html(@button).html()
27
+ expect(html).toContain('title="title"')
28
+ expect(html).toContain('class="mercury-button mercury-foo-button"')
29
+ expect(html).toContain('<em>title</em>')
30
+
31
+ it "accepts summary, types and options", ->
32
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {palette: '/nothing'}, {appendDialogsTo: $('#test')})
33
+ html = $('<div>').html(@button).html()
34
+ expect(html).toContain('title="summary"')
35
+ expect(html).toContain('class="mercury-button mercury-foo-button mercury-button-palette"')
36
+ expect(html).toContain('<em>title</em>')
37
+
38
+ it "calls build", ->
39
+ spy = spyOn(Mercury.Toolbar.Button.prototype, 'build').andCallFake(=>)
40
+ spyOn(Mercury.Toolbar.Button.prototype, 'bindEvents').andCallFake(=>)
41
+ @button = new Mercury.Toolbar.Button('foo', 'title')
42
+ expect(spy.callCount).toEqual(1)
43
+
44
+ it "calls bindEvents", ->
45
+ spyOn(Mercury.Toolbar.Button.prototype, 'build').andCallFake(=>)
46
+ spy = spyOn(Mercury.Toolbar.Button.prototype, 'bindEvents').andCallFake(=>)
47
+ @button = new Mercury.Toolbar.Button('foo', 'title')
48
+ expect(spy.callCount).toEqual(1)
49
+
50
+
51
+ describe "#build for various button types", ->
52
+
53
+ it "attaches an element meant for the expander in button data", ->
54
+ @button = new Mercury.Toolbar.Button('foo', 'title')
55
+ expect(@button.data('expander')).toEqual('<div class="mercury-expander-button" data-button="foo"><em></em><span>title</span></div>')
56
+
57
+ it "builds toggle buttons, that when clicked toggle their state", ->
58
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {toggle: true})
59
+
60
+ jasmine.simulate.click(@button.get(0))
61
+ expect(@button.hasClass('pressed')).toEqual(true)
62
+
63
+ jasmine.simulate.click(@button.get(0))
64
+ expect(@button.hasClass('pressed')).toEqual(false)
65
+
66
+ it "builds mode buttons, that when clicked fire a mode event", ->
67
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {mode: true})
68
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
69
+
70
+ jasmine.simulate.click(@button.get(0))
71
+ expect(spy.callCount).toEqual(2)
72
+ expect(spy.argsForCall[0]).toEqual(['mode', {mode: 'foo'}])
73
+
74
+ it "builds buttons that understand context", ->
75
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true})
76
+
77
+ expect(@button.hasClass('active')).toEqual(false)
78
+ Mercury.trigger('region:update', {region: @region})
79
+ expect(@button.hasClass('active')).toEqual(true)
80
+
81
+ it "builds panel buttons (and assigns toggle)", ->
82
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {panel: '/evergreen/responses/blank.html'}, {appendDialogsTo: $('#test')})
83
+ expect($('#test .mercury-panel').length).toEqual(1)
84
+
85
+ jasmine.simulate.click(@button.get(0))
86
+ expect(@button.hasClass('pressed')).toEqual(true)
87
+
88
+ jasmine.simulate.click(@button.get(0))
89
+ expect(@button.hasClass('pressed')).toEqual(false)
90
+
91
+ it "builds palette buttons", ->
92
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {palette: '/evergreen/responses/blank.html'}, {appendDialogsTo: $('#test')})
93
+ expect($('#test .mercury-palette').length).toEqual(1)
94
+
95
+ it "builds select buttons", ->
96
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {select: '/evergreen/responses/blank.html'}, {appendDialogsTo: $('#test')})
97
+ expect($('#test .mercury-select').length).toEqual(1)
98
+
99
+ it "builds modal buttons", ->
100
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {modal: '/evergreen/responses/blank.html'}, {appendDialogsTo: $('#test')})
101
+ # nothing unique about this in building -- the modal is built/fired on click
102
+
103
+ it "throws an error when an unknown type is encountered", ->
104
+ expect(=>
105
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {foo: '/evergreen/responses/blank.html'})
106
+ ).toThrow('Unknown button type foo used for the foo button.')
107
+
108
+
109
+ describe "observed events", ->
110
+
111
+ describe "custom event: button", ->
112
+
113
+ it "calls click on the button itself", ->
114
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true})
115
+ spy = spyOn(@button, 'click').andCallFake(=>)
116
+
117
+ Mercury.trigger('button', {action: 'foo'})
118
+ expect(spy.callCount).toEqual(1)
119
+
120
+ describe "custom event: region:update", ->
121
+
122
+ it "calls contexts if one is available and set", ->
123
+ contextSpy = spyOn(Mercury.Toolbar.Button.contexts, 'foo').andCallFake(-> true)
124
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true})
125
+
126
+ expect(@button.hasClass('active')).toEqual(false)
127
+
128
+ Mercury.trigger('region:update', {region: @region})
129
+ expect(contextSpy.callCount).toEqual(1)
130
+ expect(@button.hasClass('active')).toEqual(true)
131
+
132
+ describe "custom event: region:focused", ->
133
+
134
+ it "disables if the region type isn't supported", ->
135
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true, regions: ['foo']})
136
+ @button.removeClass('disabled')
137
+ Mercury.trigger('region:focused', {region: @region})
138
+ expect(@button.hasClass('disabled')).toEqual(true)
139
+
140
+ it "enables if the region type is supported", ->
141
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true, regions: ['editable']})
142
+ @button.addClass('disabled')
143
+ Mercury.trigger('region:focused', {region: @region})
144
+ expect(@button.hasClass('disabled')).toEqual(false)
145
+
146
+ describe "custom event: region:blurred", ->
147
+
148
+ it "disables if it's a button for specific region types", ->
149
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {context: true, regions: ['editable']})
150
+ @button.addClass('disabled')
151
+ Mercury.trigger('region:blurred', {region: @region})
152
+ expect(@button.hasClass('disabled')).toEqual(true)
153
+
154
+ describe "mousedown", ->
155
+
156
+ it "sets the active state", ->
157
+ @button = new Mercury.Toolbar.Button('foo', 'title')
158
+
159
+ expect(@button.hasClass('active')).toEqual(false)
160
+ jasmine.simulate.mousedown(@button.get(0))
161
+ expect(@button.hasClass('active')).toEqual(true)
162
+
163
+ describe "mouseup", ->
164
+
165
+ it "removes the active state", ->
166
+ @button = new Mercury.Toolbar.Button('foo', 'title')
167
+ @button.addClass('active')
168
+
169
+ jasmine.simulate.mouseup(@button.get(0))
170
+ expect(@button.hasClass('active')).toEqual(false)
171
+
172
+ describe "click for various button types", ->
173
+
174
+ it "does nothing if the button is disabled", ->
175
+ spy = spyOn(Mercury.Toolbar.Button.prototype, 'togglePressed').andCallThrough()
176
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {toggle: true})
177
+
178
+ jasmine.simulate.click(@button.get(0))
179
+ expect(spy.callCount).toEqual(1)
180
+
181
+ @button.addClass('disabled')
182
+ jasmine.simulate.click(@button.get(0))
183
+ expect(spy.callCount).toEqual(1)
184
+
185
+ it "triggers an action event", ->
186
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary')
187
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
188
+
189
+ jasmine.simulate.click(@button.get(0))
190
+ expect(spy.argsForCall[0]).toEqual(['action', {action: 'foo'}])
191
+
192
+ it "triggers a focus:frame event", ->
193
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
194
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary')
195
+
196
+ jasmine.simulate.click(@button.get(0))
197
+ expect(spy.argsForCall[1]).toEqual(['focus:frame'])
198
+
199
+ it "toggles toggle button pressed state", ->
200
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {toggle: true})
201
+
202
+ jasmine.simulate.click(@button.get(0))
203
+ expect(@button.hasClass('pressed')).toEqual(true)
204
+
205
+ jasmine.simulate.click(@button.get(0))
206
+ expect(@button.hasClass('pressed')).toEqual(false)
207
+
208
+ it "triggers a mode event", ->
209
+ spy = spyOn(Mercury, 'trigger').andCallFake(=>)
210
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {mode: true})
211
+
212
+ jasmine.simulate.click(@button.get(0))
213
+ expect(spy.argsForCall[0]).toEqual(['mode', {mode: 'foo'}])
214
+
215
+ it "opens a modal window", ->
216
+ spy = spyOn(Mercury, 'modal').andCallFake(=>)
217
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {modal: '/evergreen/responses/blank.html'})
218
+
219
+ jasmine.simulate.click(@button.get(0))
220
+ expect(spy.argsForCall[0]).toEqual(['/evergreen/responses/blank.html', {title: 'summary', handler: 'foo'}])
221
+
222
+ it "shows and hides palettes", ->
223
+ spy = spyOn(Mercury.Palette.prototype, 'toggle').andCallFake(=>)
224
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {palette: '/evergreen/responses/blank.html'})
225
+
226
+ jasmine.simulate.click(@button.get(0))
227
+ expect(spy.callCount).toEqual(1)
228
+
229
+ jasmine.simulate.click(@button.get(0))
230
+ expect(spy.callCount).toEqual(2)
231
+
232
+ it "shows and hides selects", ->
233
+ spy = spyOn(Mercury.Select.prototype, 'toggle').andCallFake(=>)
234
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {select: '/evergreen/responses/blank.html'})
235
+
236
+ jasmine.simulate.click(@button.get(0))
237
+ expect(spy.callCount).toEqual(1)
238
+
239
+ jasmine.simulate.click(@button.get(0))
240
+ expect(spy.callCount).toEqual(2)
241
+
242
+ it "shows and hides panels, and toggles the button pressed state", ->
243
+ spy = spyOn(Mercury.Panel.prototype, 'toggle').andCallFake(=>)
244
+ @button = new Mercury.Toolbar.Button('foo', 'title', 'summary', {panel: '/evergreen/responses/blank.html'})
245
+
246
+ jasmine.simulate.click(@button.get(0))
247
+ expect(spy.callCount).toEqual(1)
248
+
249
+ jasmine.simulate.click(@button.get(0))
250
+ expect(spy.callCount).toEqual(2)
251
+
252
+
253
+ describe "Mercury.Toolbar.Button.contexts", ->
254
+
255
+ template 'mercury/toolbar.button.html'
256
+
257
+ beforeEach ->
258
+ @contexts = Mercury.Toolbar.Button.contexts
259
+ @region = $('#context_container')
260
+ @element = $('#context_button')
261
+
262
+ it "handles background color", ->
263
+ @contexts.backcolor.call(@, $('#context_backcolor'), @region)
264
+ expect(@element.css('background-color')).toEqual('rgb(255, 0, 0)')
265
+
266
+ @contexts.backcolor.call(@, $('#context_none'), @region)
267
+ if $.browser.mozilla
268
+ expect(@element.css('background-color')).toEqual('transparent')
269
+ else
270
+ expect(@element.css('background-color')).toEqual('rgba(0, 0, 0, 0)')
271
+
272
+ it "handles foreground color", ->
273
+ @contexts.forecolor.call(@, $('#context_forecolor'), @region)
274
+ expect(@element.css('background-color')).toEqual('rgb(0, 255, 0)')
275
+
276
+ @contexts.forecolor.call(@, $('#context_none'), @region)
277
+ expect(@element.css('background-color')).toEqual('rgb(0, 0, 0)')
278
+
279
+ it "knows when something is bold", ->
280
+ expect(@contexts.bold.call(@, $('#context_bold1 span'), @region)).toEqual(true)
281
+ expect(@contexts.bold.call(@, $('#context_bold2 span'), @region)).toEqual(true)
282
+ expect(@contexts.bold.call(@, $('#context_bold3 span'), @region)).toEqual(true)
283
+ expect(@contexts.bold.call(@, $('#context_bold4 span'), @region)).toEqual(true)
284
+ expect(@contexts.bold.call(@, $('#context_bold5 span'), @region)).toEqual(false)
285
+ expect(@contexts.bold.call(@, $('#context_bold6 span'), @region)).toEqual(true)
286
+ expect(@contexts.bold.call(@, $('#context_none'), @region)).toEqual(false)
287
+
288
+ it "knows when something is italic", ->
289
+ expect(@contexts.italic.call(@, $('#context_italic1 span'), @region)).toEqual(true)
290
+ expect(@contexts.italic.call(@, $('#context_italic2 span'), @region)).toEqual(true)
291
+ expect(@contexts.italic.call(@, $('#context_none'), @region)).toEqual(false)
292
+
293
+ it "knows when something is overlined", ->
294
+ expect(@contexts.overline.call(@, $('#context_overline'), @region)).toEqual(true)
295
+ expect(@contexts.overline.call(@, $('#context_none'), @region)).toEqual(false)
296
+
297
+ it "knows when something is striked through", ->
298
+ expect(@contexts.strikethrough.call(@, $('#context_strikethrough1 span'), @region)).toEqual(true)
299
+ expect(@contexts.strikethrough.call(@, $('#context_strikethrough2'), @region)).toEqual(true)
300
+ expect(@contexts.strikethrough.call(@, $('#context_none'), @region)).toEqual(false)
301
+
302
+ it "knows when something is underlined", ->
303
+ expect(@contexts.underline.call(@, $('#context_underline1 span'), @region)).toEqual(true)
304
+ expect(@contexts.underline.call(@, $('#context_underline2'), @region)).toEqual(true)
305
+ expect(@contexts.underline.call(@, $('#context_none'), @region)).toEqual(false)
306
+
307
+ it "knows when something is subscript", ->
308
+ expect(@contexts.subscript.call(@, $('#context_subscript span'), @region)).toEqual(true)
309
+ expect(@contexts.subscript.call(@, $('#context_none'), @region)).toEqual(false)
310
+
311
+ it "knows when something is superscript", ->
312
+ expect(@contexts.superscript.call(@, $('#context_superscript span'), @region)).toEqual(true)
313
+ expect(@contexts.superscript.call(@, $('#context_none'), @region)).toEqual(false)
314
+
315
+ it "knows when something is justified left", ->
316
+ expect(@contexts.justifyleft.call(@, $('#context_justifyleft span'), @region)).toEqual(true)
317
+ expect(@contexts.justifyleft.call(@, $('#context_none'), @region)).toEqual(false)
318
+
319
+ it "knows when something is justified center", ->
320
+ expect(@contexts.justifycenter.call(@, $('#context_justifycenter span'), @region)).toEqual(true)
321
+ expect(@contexts.justifycenter.call(@, $('#context_none'), @region)).toEqual(false)
322
+
323
+ it "knows when something is justified right", ->
324
+ expect(@contexts.justifyright.call(@, $('#context_justifyright span'), @region)).toEqual(true)
325
+ expect(@contexts.justifyright.call(@, $('#context_none'), @region)).toEqual(false)
326
+
327
+ it "knows when something is justified fully", ->
328
+ expect(@contexts.justifyfull.call(@, $('#context_justifyfull span'), @region)).toEqual(true)
329
+ expect(@contexts.justifyfull.call(@, $('#context_none'), @region)).toEqual(false)
330
+
331
+ it "knows when something is inside an ordered list", ->
332
+ expect(@contexts.insertorderedlist.call(@, $('#context_orderedlist span'), @region)).toEqual(true)
333
+ expect(@contexts.insertorderedlist.call(@, $('#context_none'), @region)).toEqual(false)
334
+
335
+ it "knows when something is inside an unordered list", ->
336
+ expect(@contexts.insertunorderedlist.call(@, $('#context_unorderedlist span'), @region)).toEqual(true)
337
+ expect(@contexts.insertunorderedlist.call(@, $('#context_none'), @region)).toEqual(false)
338
+
339
+ # todo: fix in jquery
340
+ # it "understands nested text-decoration styles", ->
341
+ # expect(@contexts.underline.call(@, $('#context_decoration'), @region)).toEqual(true)
@@ -0,0 +1,120 @@
1
+ require '/assets/mercury/mercury.js'
2
+
3
+ describe "Mercury.Toolbar.Expander", ->
4
+
5
+ template 'mercury/toolbar.expander.html'
6
+
7
+ beforeEach ->
8
+ @container = $('#expander_container')
9
+
10
+ afterEach ->
11
+ @expander = null
12
+ delete(@expander)
13
+ $(document).unbind('mercury:resize')
14
+
15
+ describe "constructor", ->
16
+
17
+ beforeEach ->
18
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
19
+
20
+ it "expects a name, and options", ->
21
+ html = $('<div>').html(@expander).html()
22
+ expect(html).toContain('class="mercury-palette mercury-expander mercury-foo-expander"')
23
+ expect(html).toMatch(/style="display:\s?none/)
24
+ expect($('#test .mercury-toolbar-expander').length).toEqual(1)
25
+
26
+
27
+ describe "#build", ->
28
+
29
+ beforeEach ->
30
+ @resizeSpy = spyOn(Mercury.Toolbar.Expander.prototype, 'windowResize').andCallFake(=>)
31
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
32
+
33
+ it "sets the whitespace of the container to normal", ->
34
+ expect(@container.css('whiteSpace')).toEqual('normal')
35
+
36
+ it "builds an element", ->
37
+ html = $('<div>').html(@expander).html()
38
+ expect(html).toContain('class="mercury-palette mercury-expander mercury-foo-expander"')
39
+ expect(html).toMatch(/style="display:\s?none/)
40
+
41
+ it "builds a trigger button", ->
42
+ expect($('#test .mercury-toolbar-expander').length).toEqual(1)
43
+
44
+ it "calls windowResize", ->
45
+ expect(@resizeSpy.callCount).toEqual(1)
46
+
47
+
48
+ describe "observed events", ->
49
+
50
+ beforeEach ->
51
+ $('.mercury-button').data('expander', '<div data-button="test">expander</div>')
52
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
53
+
54
+ describe "custom event: hide:dialogs", ->
55
+
56
+ it "hides", ->
57
+ @expander.css({display: 'block'})
58
+ Mercury.trigger('hide:dialogs')
59
+ expect(@expander.css('display')).toEqual('none')
60
+
61
+ it "doesn't hide if it's the same dialog", ->
62
+ # there's no way to test this since we don't expose the instance -- just the element
63
+ #@expander.css({display: 'block'})
64
+ #Mercury.trigger('hide:dialogs', !instance!)
65
+ #expect(@expander.css('display')).toEqual('block')
66
+
67
+ describe "custom event: resize", ->
68
+
69
+ it "calls windowResize", ->
70
+ spy = spyOn(Mercury.Toolbar.Expander.prototype, 'windowResize').andCallFake(=>)
71
+ Mercury.trigger('resize')
72
+ expect(spy.callCount).toEqual(1)
73
+
74
+ describe "click (on trigger)", ->
75
+
76
+ it "pulls buttons into the palette", ->
77
+ jasmine.simulate.click($('.mercury-toolbar-expander').get(0))
78
+ expect(@expander.html()).toEqual('<div data-button="test">expander</div>')
79
+
80
+ describe "click", ->
81
+
82
+ it "calls click on the real button", ->
83
+ button = $('#button2')
84
+ spy = spyOn(button, 'click').andCallFake(=>)
85
+ @container.find = -> button
86
+ @expander.appendTo('#test')
87
+
88
+ jasmine.simulate.click($('.mercury-toolbar-expander').get(0))
89
+ jasmine.simulate.click($('[data-button=test]').get(0))
90
+ expect(spy.callCount).toEqual(1)
91
+
92
+ describe "#windowResize", ->
93
+
94
+ it "hides", ->
95
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
96
+ @expander.css({display: 'block'})
97
+
98
+ Mercury.trigger('resize')
99
+ expect(@expander.css('display')).toEqual('none')
100
+
101
+ it "shows the trigger if the container is wider than the window", ->
102
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
103
+ Mercury.trigger('resize')
104
+ expect($('.mercury-toolbar-expander').css('display')).toEqual('block')
105
+
106
+ it "hides the trigger if the container is narrower than the window", ->
107
+ @container.css({width: '1px'})
108
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
109
+ Mercury.trigger('resize')
110
+ expect($('.mercury-toolbar-expander').css('display')).toEqual('none')
111
+
112
+
113
+ describe "#position", ->
114
+
115
+ it "positions the element", ->
116
+ @expander = new Mercury.Toolbar.Expander('foo', {appendTo: '#test', for: @container})
117
+ @expander.appendTo('#positioned_container')
118
+ jasmine.simulate.click($('.mercury-toolbar-expander').get(0))
119
+
120
+ expect(@expander.offset()).toEqual({top: 42, left: 42})