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,40 @@
|
|
1
|
+
class @Mercury.Select extends Mercury.Dialog
|
2
|
+
|
3
|
+
constructor: (@url, @name, @options = {}) ->
|
4
|
+
super
|
5
|
+
|
6
|
+
|
7
|
+
build: ->
|
8
|
+
@element = $('<div>', {class: "mercury-select mercury-#{@name}-select loading", style: 'display:none'})
|
9
|
+
@element.appendTo($(@options.appendTo).get(0) ? 'body')
|
10
|
+
|
11
|
+
|
12
|
+
bindEvents: ->
|
13
|
+
Mercury.bind 'hide:dialogs', (event, dialog) => @hide() unless dialog == @
|
14
|
+
super
|
15
|
+
|
16
|
+
|
17
|
+
position: (keepVisible) ->
|
18
|
+
@element.css({top: 0, left: 0, display: 'block', visibility: 'hidden'})
|
19
|
+
position = @button.offset()
|
20
|
+
elementWidth = @element.width()
|
21
|
+
elementHeight = @element.height()
|
22
|
+
documentHeight = $(document).height()
|
23
|
+
|
24
|
+
top = position.top + (@button.height() / 2) - (elementHeight / 2)
|
25
|
+
top = position.top - 100 if top < position.top - 100
|
26
|
+
top = 20 if top < 20
|
27
|
+
|
28
|
+
height = if @loaded then 'auto' else elementHeight
|
29
|
+
height = documentHeight - top - 20 if top + elementHeight >= documentHeight - 20
|
30
|
+
|
31
|
+
left = position.left
|
32
|
+
left = left - elementWidth + @button.width() if left + elementWidth > $(window).width()
|
33
|
+
|
34
|
+
@element.css {
|
35
|
+
top: top,
|
36
|
+
left: left,
|
37
|
+
height: height,
|
38
|
+
display: if keepVisible then 'block' else 'none',
|
39
|
+
visibility: 'visible'
|
40
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class @Mercury.Snippet
|
2
|
+
|
3
|
+
@all: []
|
4
|
+
|
5
|
+
@displayOptionsFor: (name) ->
|
6
|
+
Mercury.modal("/mercury/snippets/#{name}/options", {title: 'Snippet Options', handler: 'insertsnippet'})
|
7
|
+
Mercury.snippet = null
|
8
|
+
|
9
|
+
|
10
|
+
@create: (name, options) ->
|
11
|
+
identity = "snippet_#{@all.length}"
|
12
|
+
instance = new Mercury.Snippet(name, identity, options)
|
13
|
+
@all.push(instance)
|
14
|
+
return instance
|
15
|
+
|
16
|
+
|
17
|
+
@find: (identity) ->
|
18
|
+
for snippet in @all
|
19
|
+
return snippet if snippet.identity == identity
|
20
|
+
return null
|
21
|
+
|
22
|
+
|
23
|
+
@load: (snippets) ->
|
24
|
+
for identity, details of snippets
|
25
|
+
instance = new Mercury.Snippet(details.name, identity, details.options)
|
26
|
+
@all.push(instance)
|
27
|
+
|
28
|
+
|
29
|
+
constructor: (@name, @identity, options = {}) ->
|
30
|
+
@version = 0
|
31
|
+
@data = ''
|
32
|
+
@history = new Mercury.HistoryBuffer()
|
33
|
+
@setOptions(options)
|
34
|
+
|
35
|
+
|
36
|
+
getHTML: (context, callback = null) ->
|
37
|
+
element = $('<div class="mercury-snippet" contenteditable="false">', context)
|
38
|
+
element.attr({'data-snippet': @identity})
|
39
|
+
element.attr({'data-version': @version})
|
40
|
+
element.html("[#{@identity}]")
|
41
|
+
@loadPreview(element, callback)
|
42
|
+
return element
|
43
|
+
|
44
|
+
|
45
|
+
getText: (callback) ->
|
46
|
+
return "[--#{@identity}--]"
|
47
|
+
|
48
|
+
|
49
|
+
loadPreview: (element, callback = null) ->
|
50
|
+
$.ajax "/mercury/snippets/#{@name}/preview", {
|
51
|
+
type: 'POST'
|
52
|
+
data: @options
|
53
|
+
success: (data) =>
|
54
|
+
@data = data
|
55
|
+
element.html(data)
|
56
|
+
callback() if callback
|
57
|
+
error: =>
|
58
|
+
alert("Error loading the preview for the #{@name} snippet.")
|
59
|
+
}
|
60
|
+
|
61
|
+
|
62
|
+
displayOptions: ->
|
63
|
+
Mercury.snippet = @
|
64
|
+
Mercury.modal "/mercury/snippets/#{@name}/options", {
|
65
|
+
title: 'Snippet Options',
|
66
|
+
handler: 'insertsnippet',
|
67
|
+
loadType: 'post',
|
68
|
+
loadData: @options
|
69
|
+
}
|
70
|
+
|
71
|
+
|
72
|
+
setOptions: (@options) ->
|
73
|
+
delete(@options['authenticity_token'])
|
74
|
+
delete(@options['utf8'])
|
75
|
+
@version += 1
|
76
|
+
@history.push(@options)
|
77
|
+
|
78
|
+
|
79
|
+
setVersion: (version = null) ->
|
80
|
+
version = parseInt(version)
|
81
|
+
if version && @history.stack[version - 1]
|
82
|
+
@version = version - 1
|
83
|
+
@options = @history.stack[@version]
|
84
|
+
return true
|
85
|
+
return false
|
86
|
+
|
87
|
+
|
88
|
+
serialize: ->
|
89
|
+
return {
|
90
|
+
name: @name,
|
91
|
+
options: @options
|
92
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class @Mercury.SnippetToolbar extends Mercury.Toolbar
|
2
|
+
|
3
|
+
constructor: (@document, @options = {}) ->
|
4
|
+
super(@options)
|
5
|
+
|
6
|
+
|
7
|
+
build: ->
|
8
|
+
@element = $('<div>', {class: 'mercury-toolbar mercury-snippet-toolbar', style: 'display:none'})
|
9
|
+
@element.appendTo($(@options.appendTo).get(0) ? 'body')
|
10
|
+
|
11
|
+
for buttonName, options of Mercury.config.toolbars.snippetable
|
12
|
+
button = @buildButton(buttonName, options)
|
13
|
+
button.appendTo(@element) if button
|
14
|
+
|
15
|
+
|
16
|
+
bindEvents: ->
|
17
|
+
Mercury.bind 'show:toolbar', (event, options) =>
|
18
|
+
return unless options.snippet
|
19
|
+
options.snippet.mouseout => @hide()
|
20
|
+
@show(options.snippet)
|
21
|
+
|
22
|
+
Mercury.bind 'hide:toolbar', (event, options) =>
|
23
|
+
return unless options.type && options.type == 'snippet'
|
24
|
+
@hide(options.immediately)
|
25
|
+
|
26
|
+
$(@document).scroll => @position() if @visible
|
27
|
+
|
28
|
+
@element.mousemove => clearTimeout(@hideTimeout)
|
29
|
+
@element.mouseout => @hide()
|
30
|
+
|
31
|
+
|
32
|
+
show: (@snippet) ->
|
33
|
+
Mercury.tooltip.hide()
|
34
|
+
@position()
|
35
|
+
@appear()
|
36
|
+
|
37
|
+
|
38
|
+
position: ->
|
39
|
+
offset = @snippet.offset()
|
40
|
+
|
41
|
+
top = offset.top + Mercury.displayRect.top - $(@document).scrollTop() - @height() + 10
|
42
|
+
left = offset.left - $(@document).scrollLeft()
|
43
|
+
|
44
|
+
@element.css {
|
45
|
+
top: top,
|
46
|
+
left: left
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
appear: ->
|
51
|
+
clearTimeout(@hideTimeout)
|
52
|
+
return if @visible
|
53
|
+
@visible = true
|
54
|
+
@element.css({display: 'block', opacity: 0})
|
55
|
+
@element.stop().animate({opacity: 1}, 200, 'easeInOutSine')
|
56
|
+
|
57
|
+
|
58
|
+
hide: (immediately = false) ->
|
59
|
+
clearTimeout(@hideTimeout)
|
60
|
+
if immediately
|
61
|
+
@element.hide()
|
62
|
+
@visible = false
|
63
|
+
else
|
64
|
+
@hideTimeout = setTimeout((=>
|
65
|
+
@element.stop().animate {opacity: 0}, 300, 'easeInOutSine', =>
|
66
|
+
@element.hide()
|
67
|
+
@visible = false
|
68
|
+
), 500)
|
69
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class @Mercury.Statusbar
|
2
|
+
|
3
|
+
constructor: (@options = {}) ->
|
4
|
+
@build()
|
5
|
+
@bindEvents()
|
6
|
+
|
7
|
+
|
8
|
+
build: ->
|
9
|
+
@element = $('<div>', {class: 'mercury-statusbar'}).appendTo($(@options.appendTo).get(0) ? 'body')
|
10
|
+
|
11
|
+
|
12
|
+
bindEvents: ->
|
13
|
+
Mercury.bind 'region:update', (event, options) =>
|
14
|
+
@setPath(options.region.path()) if options.region && $.type(options.region.path) == 'function'
|
15
|
+
|
16
|
+
|
17
|
+
height: ->
|
18
|
+
@element.outerHeight()
|
19
|
+
|
20
|
+
|
21
|
+
setPath: (elements) ->
|
22
|
+
path = []
|
23
|
+
path.push("<a>#{element.tagName.toLowerCase()}</a>") for element in elements
|
24
|
+
|
25
|
+
@element.html("<span><strong>Path: </strong></span>#{path.reverse().join(' » ')}")
|
@@ -0,0 +1,266 @@
|
|
1
|
+
@Mercury.tableEditor = (table, cell) ->
|
2
|
+
Mercury.tableEditor.load(table, cell)
|
3
|
+
return Mercury.tableEditor
|
4
|
+
|
5
|
+
$.extend Mercury.tableEditor, {
|
6
|
+
|
7
|
+
load: (@table, @cell) ->
|
8
|
+
@row = @cell.parent('tr')
|
9
|
+
@columnCount = @getColumnCount()
|
10
|
+
@rowCount = @getRowCount()
|
11
|
+
|
12
|
+
|
13
|
+
addColumn: (position = 'after') ->
|
14
|
+
sig = @cellSignatureFor(@cell)
|
15
|
+
|
16
|
+
for row, i in @table.find('tr')
|
17
|
+
rowSpan = 1
|
18
|
+
matchOptions = if position == 'after' then {right: sig.right} else {left: sig.left}
|
19
|
+
if matching = @findCellByOptionsFor(row, matchOptions)
|
20
|
+
newCell = $("<#{matching.cell.get(0).tagName}>").text('\00')
|
21
|
+
@setRowspanFor(newCell, matching.height)
|
22
|
+
if position == 'before' then matching.cell.before(newCell) else matching.cell.after(newCell)
|
23
|
+
i += matching.height - 1
|
24
|
+
else if intersecting = @findCellByIntersectionFor(row, sig)
|
25
|
+
@setColspanFor(intersecting.cell, intersecting.width + 1)
|
26
|
+
|
27
|
+
|
28
|
+
removeColumn: ->
|
29
|
+
sig = @cellSignatureFor(@cell)
|
30
|
+
return if sig.width > 1
|
31
|
+
|
32
|
+
removing = []
|
33
|
+
adjusting = []
|
34
|
+
for row, i in @table.find('tr')
|
35
|
+
if matching = @findCellByOptionsFor(row, {left: sig.left, width: sig.width})
|
36
|
+
removing.push(matching.cell)
|
37
|
+
i += matching.height - 1
|
38
|
+
else if intersecting = @findCellByIntersectionFor(row, sig)
|
39
|
+
adjusting.push(intersecting.cell)
|
40
|
+
|
41
|
+
$(cell).remove() for cell in removing
|
42
|
+
@setColspanFor(cell, @colspanFor(cell) - 1) for cell in adjusting
|
43
|
+
|
44
|
+
|
45
|
+
addRow: (position = 'after') ->
|
46
|
+
newRow = $('<tr>')
|
47
|
+
|
48
|
+
if (rowspan = @rowspanFor(@cell)) > 1 && position == 'after'
|
49
|
+
@row = $(@row.nextAll('tr')[rowspan - 2])
|
50
|
+
|
51
|
+
cellCount = 0
|
52
|
+
for cell in @row.find('th, td')
|
53
|
+
colspan = @colspanFor(cell)
|
54
|
+
newCell = $("<#{cell.tagName}>").text('\00')
|
55
|
+
@setColspanFor(newCell, colspan)
|
56
|
+
cellCount += colspan
|
57
|
+
if (rowspan = @rowspanFor(cell)) > 1 && position == 'after'
|
58
|
+
@setRowspanFor(cell, rowspan + 1)
|
59
|
+
continue
|
60
|
+
|
61
|
+
newRow.append(newCell)
|
62
|
+
|
63
|
+
if cellCount < @columnCount
|
64
|
+
rowCount = 0
|
65
|
+
for previousRow in @row.prevAll('tr')
|
66
|
+
rowCount += 1
|
67
|
+
for cell in $(previousRow).find('td[rowspan], th[rowspan]')
|
68
|
+
rowspan = @rowspanFor(cell)
|
69
|
+
if rowspan - 1 >= rowCount && position == 'before'
|
70
|
+
@setRowspanFor(cell, rowspan + 1)
|
71
|
+
else if rowspan - 1 >= rowCount && position == 'after'
|
72
|
+
if rowspan - 1 == rowCount
|
73
|
+
newCell = $("<#{cell.tagName}>", {colspan: @colspanFor(cell)})
|
74
|
+
newRow.append(newCell);
|
75
|
+
else
|
76
|
+
@setRowspanFor(cell, rowspan + 1)
|
77
|
+
|
78
|
+
if position == 'before' then @row.before(newRow) else @row.after(newRow)
|
79
|
+
|
80
|
+
|
81
|
+
removeRow: ->
|
82
|
+
# check to see that all cells have the same rowspan, and figure out the minimum rowspan
|
83
|
+
rowspansMatch = true
|
84
|
+
prevRowspan = 0
|
85
|
+
minRowspan = 0
|
86
|
+
for cell in @row.find('td, th')
|
87
|
+
rowspan = @rowspanFor(cell)
|
88
|
+
rowspansMatch = false if prevRowspan && rowspan != prevRowspan
|
89
|
+
minRowspan = rowspan if rowspan < minRowspan || !minRowspan
|
90
|
+
prevRowspan = rowspan
|
91
|
+
|
92
|
+
return if !rowspansMatch && @rowspanFor(@cell) > minRowspan
|
93
|
+
|
94
|
+
# remove any emtpy rows below
|
95
|
+
if minRowspan > 1
|
96
|
+
$(@row.nextAll('tr')[i]).remove() for i in [0..minRowspan - 2]
|
97
|
+
|
98
|
+
# find and move down any cells that have a larger rowspan
|
99
|
+
for cell in @row.find('td[rowspan], th[rowspan]')
|
100
|
+
sig = @cellSignatureFor(cell)
|
101
|
+
continue if sig.height == minRowspan
|
102
|
+
if match = @findCellByOptionsFor(@row.nextAll('tr')[minRowspan - 1], {left: sig.left, forceAdjacent: true})
|
103
|
+
@setRowspanFor(cell, @rowspanFor(cell) - @rowspanFor(@cell))
|
104
|
+
if match.direction == 'before' then match.cell.before($(cell).clone()) else match.cell.after($(cell).clone())
|
105
|
+
|
106
|
+
if @columnsFor(@row.find('td, th')) < @columnCount
|
107
|
+
# move up rows looking for cells with rowspans that might intersect
|
108
|
+
rowsAbove = 0
|
109
|
+
for aboveRow in @row.prevAll('tr')
|
110
|
+
rowsAbove += 1
|
111
|
+
for cell in $(aboveRow).find('td[rowspan], th[rowspan]')
|
112
|
+
# if the cell intersects with the row we're trying to calculate on, and it's index is less than where we've
|
113
|
+
# gotten so far, add it
|
114
|
+
rowspan = @rowspanFor(cell)
|
115
|
+
@setRowspanFor(cell, rowspan - @rowspanFor(@cell)) if rowspan > rowsAbove
|
116
|
+
|
117
|
+
@row.remove()
|
118
|
+
|
119
|
+
|
120
|
+
increaseColspan: ->
|
121
|
+
cell = @cell.next('td, th')
|
122
|
+
return unless cell.length
|
123
|
+
return if @rowspanFor(cell) != @rowspanFor(@cell)
|
124
|
+
return if @cellIndexFor(cell) > @cellIndexFor(@cell) + @colspanFor(@cell)
|
125
|
+
@setColspanFor(@cell, @colspanFor(@cell) + @colspanFor(cell))
|
126
|
+
cell.remove()
|
127
|
+
|
128
|
+
|
129
|
+
decreaseColspan: ->
|
130
|
+
return if @colspanFor(@cell) == 1
|
131
|
+
@setColspanFor(@cell, @colspanFor(@cell) - 1)
|
132
|
+
newCell = $("<#{@cell.get(0).tagName}>").text('\00')
|
133
|
+
@setRowspanFor(newCell, @rowspanFor(@cell))
|
134
|
+
@cell.after(newCell)
|
135
|
+
|
136
|
+
|
137
|
+
increaseRowspan: ->
|
138
|
+
sig = @cellSignatureFor(@cell)
|
139
|
+
nextRow = @row.nextAll('tr')[sig.height - 1]
|
140
|
+
if nextRow && match = @findCellByOptionsFor(nextRow, {left: sig.left, width: sig.width})
|
141
|
+
@setRowspanFor(@cell, sig.height + match.height)
|
142
|
+
match.cell.remove()
|
143
|
+
|
144
|
+
decreaseRowspan: ->
|
145
|
+
sig = @cellSignatureFor(@cell)
|
146
|
+
return if sig.height == 1
|
147
|
+
nextRow = @row.nextAll('tr')[sig.height - 2]
|
148
|
+
if match = @findCellByOptionsFor(nextRow, {left: sig.left, forceAdjacent: true})
|
149
|
+
newCell = $("<#{@cell.get(0).tagName}>").text('\00')
|
150
|
+
@setColspanFor(newCell, @colspanFor(@cell))
|
151
|
+
@setRowspanFor(@cell, sig.height - 1)
|
152
|
+
if match.direction == 'before' then match.cell.before(newCell) else match.cell.after(newCell)
|
153
|
+
|
154
|
+
# Counts the columns of the first row (alpha row) in the table. We can safely rely on the first row always being
|
155
|
+
# comprised of a full set of cells or cells with colspans.
|
156
|
+
getColumnCount: ->
|
157
|
+
return @columnsFor(@table.find('thead tr:first-child, tbody tr:first-child, tfoot tr:first-child').first().find('td, th'))
|
158
|
+
|
159
|
+
|
160
|
+
# Counts the rows of the table.
|
161
|
+
getRowCount: ->
|
162
|
+
return @table.find('tr').length
|
163
|
+
|
164
|
+
|
165
|
+
# Gets the index for a given cell, taking into account that rows above it can have cells that have rowspans.
|
166
|
+
cellIndexFor: (cell) ->
|
167
|
+
cell = $(cell)
|
168
|
+
|
169
|
+
# get the row for the cell and calculate all the columns in it
|
170
|
+
row = cell.parent('tr')
|
171
|
+
columns = @columnsFor(row.find('td, th'))
|
172
|
+
index = @columnsFor(cell.prevAll('td, th'))
|
173
|
+
|
174
|
+
# if the columns is less than expected, we need to look above for rowspans
|
175
|
+
if columns < @columnCount
|
176
|
+
# move up rows looking for cells with rowspans that might intersect
|
177
|
+
rowsAbove = 0
|
178
|
+
for aboveRow in row.prevAll('tr')
|
179
|
+
rowsAbove += 1
|
180
|
+
for aboveCell in $(aboveRow).find('td[rowspan], th[rowspan]')
|
181
|
+
# if the cell intersects with the row we're trying to calculate on, and it's index is less than where we've
|
182
|
+
# gotten so far, add it
|
183
|
+
if @rowspanFor(aboveCell) > rowsAbove && @cellIndexFor(aboveCell) <= index
|
184
|
+
index += @colspanFor(aboveCell)
|
185
|
+
|
186
|
+
return index
|
187
|
+
|
188
|
+
# Creates a signature for a given cell, which is made up if it's size, and itself.
|
189
|
+
cellSignatureFor: (cell) ->
|
190
|
+
sig = {cell: $(cell)}
|
191
|
+
sig.left = @cellIndexFor(cell)
|
192
|
+
sig.width = @colspanFor(cell)
|
193
|
+
sig.height = @rowspanFor(cell)
|
194
|
+
sig.right = sig.left + sig.width
|
195
|
+
return sig
|
196
|
+
|
197
|
+
# Find a cell based on options. Options can be:
|
198
|
+
# right
|
199
|
+
# or
|
200
|
+
# left, [width], [forceAdjacent]
|
201
|
+
# eg. findCellByOptionsFor(@row, {left: 1, width: 2, forceAdjacent: true})
|
202
|
+
findCellByOptionsFor: (row, options) ->
|
203
|
+
for cell in $(row).find('td, th')
|
204
|
+
sig = @cellSignatureFor(cell)
|
205
|
+
if typeof(options.right) != 'undefined'
|
206
|
+
return sig if sig.right == options.right
|
207
|
+
if typeof(options.left) != 'undefined'
|
208
|
+
|
209
|
+
if options.width
|
210
|
+
return sig if sig.left == options.left && sig.width == options.width
|
211
|
+
else if !options.forceAdjacent
|
212
|
+
return sig if sig.left == options.left
|
213
|
+
else if options.forceAdjacent
|
214
|
+
if sig.left > options.left
|
215
|
+
prev = $(cell).prev('td, th')
|
216
|
+
if prev.length
|
217
|
+
sig = @cellSignatureFor(prev)
|
218
|
+
sig.direction = 'after'
|
219
|
+
else
|
220
|
+
sig.direction = 'before'
|
221
|
+
return sig
|
222
|
+
|
223
|
+
if options.forceAdjacent
|
224
|
+
sig.direction = 'after'
|
225
|
+
return sig
|
226
|
+
|
227
|
+
return null
|
228
|
+
|
229
|
+
# Finds a cell that intersects with the current signature
|
230
|
+
findCellByIntersectionFor: (row, signature) ->
|
231
|
+
for cell in $(row).find('td, th')
|
232
|
+
sig = @cellSignatureFor(cell)
|
233
|
+
return sig if sig.right - signature.left >= 0 && sig.right > signature.left
|
234
|
+
return null
|
235
|
+
|
236
|
+
|
237
|
+
# Counts all the columns in a given array of columns, taking colspans into
|
238
|
+
# account.
|
239
|
+
columnsFor: (cells) ->
|
240
|
+
count = 0
|
241
|
+
count += @colspanFor(cell) for cell in cells
|
242
|
+
return count
|
243
|
+
|
244
|
+
|
245
|
+
# Tries to get the colspan of a cell, falling back to 1 if there's none
|
246
|
+
# specified.
|
247
|
+
colspanFor: (cell) ->
|
248
|
+
return parseInt($(cell).attr('colspan')) || 1
|
249
|
+
|
250
|
+
|
251
|
+
# Tries to get the rowspan of a cell, falling back to 1 if there's none
|
252
|
+
# specified.
|
253
|
+
rowspanFor: (cell) ->
|
254
|
+
return parseInt($(cell).attr('rowspan')) || 1
|
255
|
+
|
256
|
+
|
257
|
+
# Sets the colspan of a cell, removing it if it's 1.
|
258
|
+
setColspanFor: (cell, value) ->
|
259
|
+
$(cell).attr('colspan', if value > 1 then value else null)
|
260
|
+
|
261
|
+
|
262
|
+
# Sets the rowspan of a cell, removing it if it's 1
|
263
|
+
setRowspanFor: (cell, value) ->
|
264
|
+
$(cell).attr('rowspan', if value > 1 then value else null)
|
265
|
+
|
266
|
+
}
|