coffeescript-ui
Version:
Coffeescript User Interface System
1,242 lines (974 loc) • 34 kB
text/coffeescript
###
* coffeescript-ui - Coffeescript User Interface System (CUI)
* Copyright (c) 2013 - 2016 Programmfabrik GmbH
* MIT Licence
* https://github.com/programmfabrik/coffeescript-ui, http://www.coffeescript-ui.org
###
class CUI.ListView extends CUI.SimplePane
:
row_move_handle_tooltip: "Drag to move row"
#Construct a new CUI.ListView.
#
# [Object] options for listview creation
# options [String] TODO
constructor: (opts) ->
super(opts)
initListView: ->
=
=
= .slice(0)
if
= .slice(0)
if
CUI.util.assert(not , "new CUI.ListView", "opts.rowMove cannot be used with opts.rowMovePlaceholder", opts: )
if or
.splice(0,0, "fixed")
if not
= []
.splice(0,0, "cui-lv-row-move-handle-column")
CUI.util.assert( < .length, "new CUI.ListView", "opts.fixedCols must be less than column count.", opts: )
if
= true
else if > 0 and == undefined
= true
if
CUI.util.assert( > 0, "new CUI.ListView", "Cannot enable col resize with no fixed rows.", opts: )
= []
for col, col_i in
CUI.util.assert(col in ["auto", "maximize", "fixed", "manual"], "new #{@__cls}", "Unknown type of col: \"#{col}\". opts.cols can only contain \"auto\" and \"maximize\" elements.")
if col == "maximize"
# CUI.util.assert(, "new CUI.ListView", "maximized columns can only exist inside an maximized ListView", opts: )
CUI.util.assert(col_i >= , "new CUI.ListView", "maximized columns can only be in the non-fixed side of the ListView.", opts: )
.push(col_i)
if and .length == 0
# auto-max the last column
len = .length - 1
if len >=
.push(len)
[len] = 'maximize'
= 0
= .length
= CUI.ListView.counter++
= []
= {}
= []
for col_i in [0...]
.push(col_i)
= []
= -1
= []
= []
= "cui-lv-#{@listViewCounter}"
= []
= false
= =>
initOpts: ->
super()
colClasses:
check: "Array"
cols:
mandatory: true
check: "Array"
fixedCols:
default: 0
check: "Integer"
fixedRows:
default: 0
check: "Integer"
# this adds an extra column at the beginning
# it also adds a dummy colClasses item if colClasses
# are set
rowMove:
default: false
check: Boolean
rowMoveFixedRows:
default: 0
check: "Integer"
# if set, add a rowMovePlaceholder to
# all rows
rowMovePlaceholder:
default: false
check: Boolean
colResize:
check: Boolean
selectableRows:
check: (v) ->
v == false or v == true or v == "multiple"
focusable:
check: Boolean
default: false
onRowMove:
check: Function
onScroll:
check: Function
header:
deprecated: true
footer:
deprecated: true
onSelect:
check: Function
onDeselect:
check: Function
readOpts: ->
if .header
.header_center = .header
if .footer
.footer_left = .footer
super()
=
@
destroy: ->
# console.error "#{CUI.util.getObjectClass(@)}.destroy list-view-#{@listViewCounter} called. This is NOT an error."
delete()
delete()
delete()
#
= null
CUI.scheduleCallbackCancel(call: )
?.destroy()
= false
super()
@
getListViewClass: ->
getGrid: ->
hasResizableColumns: ->
hasMovableRows: ->
isInactive: ->
!!
setInactive: (inactive, addClass="inactive") ->
= !!inactive
if
if
CUI.dom.addClass(, addClass)
= new CUI.WaitBlock(element: , inactive: true).show()
else
?.destroy()
= null
CUI.dom.removeClass(, addClass)
@
render: ->
CUI.util.assert(not , "ListView.render", "ListView already rendered", opts: )
html = []
cls = ["cui-list-view-grid", ]
if == 1 and ( or )
cls.push("cui-list-view-grid-fixed-col-has-only-row-move-handle")
if
cls.push("cui-list-view-has-row-move-placeholder")
if
cls.push("cui-list-view-has-row-move")
if .length > 0
cls.push("cui-list-view-grid-has-maximized-columns")
if > 0
cls.push("cui-list-view-grid-has-fixed-cols")
if > 0
cls.push("cui-list-view-grid-has-fixed-rows")
html.push("<div class=\"")
html.push(cls.join(" "))
html.push("\">")
html.push("<style></style>")
add_quadrant = (qi) =>
if
# add tabindex="-1"
html.push("<div cui-lv-quadrant=\"#{qi}\" class=\"cui-drag-scroll cui-list-view-grid-quadrant cui-lv-tbody cui-list-view-grid-quadrant-#{qi} #{@__lvClass}-quadrant\">")
else
html.push("<div cui-lv-quadrant=\"#{qi}\" class=\"cui-drag-scroll cui-list-view-grid-quadrant cui-lv-tbody cui-list-view-grid-quadrant-#{qi} #{@__lvClass}-quadrant\">")
if qi in [2, 3]
html.push("<div class=\"cui-lv-tr-fill-outer\"><div class=\"cui-lv-tr\">")
ft =
for col_i in [ft.from..ft.to] by 1
cls =
html.push("<div class=\"#{cls} cui-lv-td cui-lv-td-fill cui-list-view-grid-fill-col-#{col_i}\"></div>")
html.push("</div></div>")
html.push("</div>")
return
if > 0 and > 0
html.push("<div class=\"cui-list-view-grid-inner-top\">")
add_quadrant(0)
add_quadrant(1)
html.push("</div>")
html.push("<div class=\"cui-list-view-grid-inner-bottom\">")
add_quadrant(2)
add_quadrant(3)
html.push("</div>")
else if > 0
html.push("<div class=\"cui-list-view-grid-inner-bottom\">")
add_quadrant(2)
add_quadrant(3)
html.push("</div>")
else if > 0
html.push("<div class=\"cui-list-view-grid-inner-top\">")
add_quadrant(1)
html.push("</div>")
html.push("<div class=\"cui-list-view-grid-inner-bottom\">")
add_quadrant(3)
html.push("</div>")
else
add_quadrant(3)
html.push("</div>")
outer =
outer.innerHTML = html.join("")
= outer.firstChild
= [
CUI.dom.matchSelector(outer, ".cui-list-view-grid-quadrant-0")[0]
CUI.dom.matchSelector(outer, ".cui-list-view-grid-quadrant-1")[0]
CUI.dom.matchSelector(outer, ".cui-list-view-grid-quadrant-2")[0]
CUI.dom.matchSelector(outer, ".cui-list-view-grid-quadrant-3")[0]
]
= CUI.dom.matchSelector(outer, "style")[0]
= CUI.dom.matchSelector(, ".cui-list-view-grid-fills-3")[0]
= CUI.dom.matchSelector(outer, ".cui-list-view-grid-inner-top")[0]
if ( == 0 and == 0 ) # we only have Q3
= [3]
else
= CUI.dom.matchSelector(outer, ".cui-list-view-grid-inner-bottom")[0]
= []
for col in [0..-1] by 1
.push(CUI.dom.matchSelector(outer, ".cui-list-view-grid-fill-col-#{col}")[0])
on_scroll = =>
?()
CUI.Events.listen
node: [3]
type: "scroll"
call: on_scroll
= top: 0, left: 0
if
selector = "."++"-quadrant > .cui-lv-tr-outer"
CUI.Events.listen
type: ["click"]
node:
selector: selector
call: (ev) =>
row = CUI.dom.data(ev.getCurrentTarget(), "listViewRow")
if not row.isSelectable()
return
ev.stopImmediatePropagation()
return
if
selectorFocus = "."++"-quadrant > .cui-lv-tr-outer:focus"
CUI.Events.listen
type: ["keydown"]
node:
selector: selectorFocus
call: (ev) =>
if ev.getKeyboard() not in ["Return", "Space"]
return
row = CUI.dom.data(ev.getCurrentTarget(), "listViewRow")
if not row.isSelectable()
return
ev.stopImmediatePropagation()
return
if [2]
CUI.Events.listen
type: "wheel"
node: [2]
call: (ev) =>
scroll_delta = 100
if ev.wheelDeltaY() > 0
if [3].scrollTop == ([3].scrollHeight - [3].offsetHeight)
# at bottom
return
[3].scrollTop += scroll_delta
else if ev.wheelDeltaY() < 0
if [3].scrollTop == 0
# at top
return
[3].scrollTop -= scroll_delta
else
return
ev.preventDefault()
on_scroll()
return
CUI.Events.listen
type: "viewport-resize"
node:
call: (ev, info) =>
if not
return
return
CUI.Events.listen
type: "content-resize"
node:
call: (ev, info) =>
if not
return
cell = CUI.dom.closest(ev.getNode(), ".cui-lv-td")
if not cell
return
ev.stopPropagation()
row = parseInt(cell.getAttribute("row"))
col = parseInt(cell.getAttribute("col"))
if > 0 and CUI.dom.getAttribute(cell.parentNode, "cui-lv-tr-unmeasured")
# row has not been measured
return
return
if
# if
#
CUI.dom.waitForDOMInsert(node: )
.done =>
= true
__getScrolling: ->
dim =
top: [3].scrollTop
left: [3].scrollLeft
height: [3].scrollHeight
dim
getScrollingContainer: ->
[3]
__setScrolling: (scroll) ->
[3].scrollTop = scroll.top
[3].scrollLeft = scroll.left
__syncScrolling: ->
=
if > 0
[2].scrollTop = .top
if > 0
[1].scrollLeft = .left
if
.style.width = ""
.style.width =
@
__setMargins: ->
width = [3].offsetWidth - [3].clientWidth
height = [3].offsetHeight - [3].clientHeight
[1]?.style.marginRight =
[2]?.style.marginBottom =
@
getSelectedRows: ->
# console.time "getSelectedRows"
sel_rows = []
for row_i in
listViewRow =
if listViewRow.isSelected()
sel_rows.push(listViewRow)
# console.timeEnd "getSelectedRows"
sel_rows
hasSelectableRows: ->
!!
__isFocusable: ->
return
selectRowById: (row_id) ->
selectRowByDisplayIdx: (row_display_idx) ->
# deselectRow deselects the given row, this
# method is here, so it can be overwritten in ListViewTree where
# we support different selection groups
deselectRow: (ev, row, newRow) ->
return row.deselect(ev, newRow)
selectRow: (ev, rowChosen, noDeselect=false) ->
CUI.util.assert(CUI.util.isNull(rowChosen) or rowChosen instanceof CUI.ListViewRow, "#{@__cls}.setSelectedRow", "Parameter needs to be instance of CUI.ListViewRow.", selectedRow: rowChosen)
dfr = new CUI.Deferred()
selectRowChosen = =>
if rowChosen.isSelected()
if not noDeselect
# this is a "toggle", so if the row is selected, we deselect it
# otherwise it is selected.
else
dfr.resolve()
else
rowChosen.select(ev).done(dfr.resolve).fail(dfr.reject)
return
deselectAllRows = (skipSelf = true) =>
promises = []
for _row in
if rowChosen == _row and skipSelf
# we handle this in do_select
continue
promise = # null is sent as event parameter, to avoids checks.
if CUI.util.isPromise(promise)
promises.push(promise)
CUI.when(promises).done(selectRowChosen).fail(dfr.reject)
if == true # only one row
deselectAllRows()
else if == "multiple"
# If CTRL key is pressed, then It is allowed to select more rows.
if ev?.ctrlKey()
selectRowChosen()
# If Shift key is pressed then all next or previous rows are selected.
else if ev?.shiftKey() and .length > 0
selectedRow = .pop()
idxSelectedRow = selectedRow.getRowIdx()
idxClickedRow = rowChosen.getRowIdx()
while(idxClickedRow != idxSelectedRow)
.select(ev)
if idxClickedRow > idxSelectedRow then idxClickedRow-- else idxClickedRow++
else
# Otherwise all rows are deselected except for the clicked one.
deselectAllRows(false)
else
selectRowChosen()
dfr.promise()
getCellByTarget: ($target) ->
if CUI.dom.is($target, ".cui-lv-td")
cell =
col_i: parseInt($target.getAttribute("col"))
row_i: parseInt($target.getAttribute("row"))
cell.display_col_i =
cell.display_row_i =
cell
else
null
getRowMoveTool: (opts = {}) ->
new CUI.ListViewRowMove(opts)
getListViewRow: (row_i) ->
CUI.dom.data([0], "listViewRow")
getDisplayColIdx: (col_i) ->
.indexOf(parseInt(col_i))
getDisplayRowIdx: (row_i) ->
.indexOf(parseInt(row_i))
getColIdx: (display_col_i) ->
CUI.util.assert(CUI.util.isArray(), "ListView[#{@listViewCounter}].getColIdx", "colsOrder Array is missing", this: @, display_col_i: display_col_i)
[display_col_i]
getRowIdx: (display_row_i) ->
[display_row_i]
moveInOrderArray: (from_i, to_i, array, after) ->
display_from_i = array.indexOf(from_i)
display_to_i = array.indexOf(to_i)
CUI.util.moveInArray(display_from_i, display_to_i, array, after)
null
moveRow: (from_i, to_i, after=false, trigger_row_moved=true) ->
CUI.util.assert(from_i >= and to_i >= , "ListView.moveRow", "from_i and to_i must not be in flexible area of the list view", from_i: from_i, to_i: to_i, fixed_i: )
if after
func = CUI.dom.insertAfter
else
func = CUI.dom.insertBefore
for row, idx in
func([idx], (row))
display_from_i =
display_to_i =
if trigger_row_moved
?(display_from_i, display_to_i, after)
CUI.Events.trigger
type: "row_moved"
node:
info:
from_i: from_i
to_i: to_i
display_from_i: display_from_i
display_to_i: display_to_i
after: after
@
rowAddClass: (row_i, cls) ->
rows =
if not rows
return
for row in rows
CUI.dom.addClass(row, cls)
@
rowRemoveClass: (row_i, cls) ->
rows =
if not rows
return
for row in rows
CUI.dom.removeClass(row, cls)
@
getColdef: (col_i) ->
[col_i]
getColsCount: ->
resetColWidth: (col_i) ->
delete([col_i])
@
setColWidth: (col_i, width) ->
[col_i] = Math.max(5, width)
delete([col_i])
@
getManualColWidth: (col_i) ->
[col_i]
getRowHeight: (row_i) ->
[row_i][0].offsetHeight
getColWidth: (col_i) ->
[col_i]
getCellGridRect: (row_i, col_i) ->
cell = [row_i]?[col_i]
if not cell
return null
grid_rect = CUI.dom.getRect()
pos_grid =
top: grid_rect.top
left: grid_rect.left
dim = CUI.dom.getDimensions(cell)
rect =
left_abs: dim.clientBoundingRect.left
top_abs: dim.clientBoundingRect.top
left: dim.clientBoundingRect.left - pos_grid.left
top: dim.clientBoundingRect.top - pos_grid.top
width: dim.borderBoxWidth
height: dim.borderBoxHeight
contentWidthAdjust: dim.contentWidthAdjust
contentHeightAdjust: dim.contentHeightAdjust
rect
getRowGridRect: (row_i) ->
_rect =
width: 0
for row in [row_i]
dim = CUI.dom.getDimensions(row)
_rect.width = _rect.width + dim.borderBoxWidth
if not _rect.hasOwnProperty("height")
_rect.height = dim.borderBoxHeight
_rect.top = dim.clientBoundingRect.top
if not _rect.hasOwnProperty("left")
_rect.left = dim.clientBoundingRect.left
grid_rect = CUI.dom.getRect()
_pos_grid =
top: grid_rect.top
left: grid_rect.left
rect =
left_abs: _rect.left
top_abs: _rect.top
left: _rect.left - _pos_grid.left
top: _rect.top - _pos_grid.top
height: _rect.height
rect.width = CUI.dom.width()
return rect
# rect =
# rect.width = .width()
# rect
appendRow: (row, _defer=!) ->
if _defer
else
prependRow: (row) ->
CUI.util.assert(not , "ListView.prependRow", "ListView #{@listViewCounter} is already destroyed.")
row_i = ++
++
.splice(0, 0, row_i)
replaceRow: (row_i, row) ->
insertRowAt: (display_row_i, row) ->
CUI.util.assert(not , "ListView.insertRowAfter", "ListView #{@listViewCounter} is already destroyed.")
if display_row_i == or == 0
else if display_row_i == 0
else
insertRowAfter: (sibling_row_i, row) ->
CUI.util.assert(not , "ListView.insertRowAfter", "ListView ##{@listViewCounter} is already destroyed.")
sibling_display_row_i =
CUI.util.assert(sibling_display_row_i > -1, "ListView.insertRowAfter", "ListView ##{@listViewCounter}: Row #{sibling_row_i} not found.", row_i: sibling_row_i, row: row, rowsCount: )
row_i = ++
++
.splice(sibling_display_row_i+1, 0, row_i)
insertRowBefore: (sibling_row_i, row) ->
CUI.util.assert(not , "ListView.insertRowBefore", "ListView ##{@listViewCounter} is already destroyed.")
sibling_display_row_i =
if sibling_display_row_i == 0
return
before_row_i =
row_i = ++
++
.splice(sibling_display_row_i, 0, row_i)
removeAllRows: ->
for row_i in .slice(0)
@
removeDeferredRow: (listViewRow) ->
count = CUI.util.removeFromArray(listViewRow, )
CUI.util.assert(count == 1, "ListView.removeListViewRow", "row not found", listViewRow: listViewRow)
@
removeRow: (row_i) ->
CUI.util.assert(row_i != null and row_i >= 0, "ListView.removeRow", "row_i must be >= 0", row_i: row_i)
display_row_i =
CUI.util.assert(display_row_i > -1, "ListView.removeRow", "display_row_id not found for row_i", row_i: row_i)
.splice(display_row_i, 1)
--
delete([row_i])
for row in
CUI.dom.remove(row)
delete([row_i])
delete([row_i])
@
appendDeferredRows: ->
if .length
= []
@
getRow: (row_i) ->
[row_i]
getBottom: ->
getTop: ->
__scheduleLayout: ->
# console.error "ListView.__scheduleLayout",
if not
return
if
= true
return
CUI.scheduleCallback(ms: 10, call: )
@
layoutIsStopped: ->
stopLayout: ->
# console.error , "stopping layout..."
if
false
else
= true
true
startLayout: ->
# console.error , "starting layout..."
if
= false
= null
@
__doLayout: (opts={}) ->
css = []
add_css = (col_i, width) =>
css.push("."++"-cell[col=\""+col_i+"\"] { width: #{width}px !important; flex: 0 0 auto !important;}")
has_max_cols = false
has_manually_sized_column = false
# set width on colspan cells
= []
for fc, display_col_i in
col_i =
manual_col_width = [col_i]
if manual_col_width > 0
has_manually_sized_column = true
add_css(col_i, manual_col_width)
fc.style.setProperty("width", manual_col_width+"px")
fc.style.setProperty("flex", "0 0 auto")
else
if col_i in
has_max_cols = true
fc.style.removeProperty("width")
fc.style.removeProperty("flex")
for fc, display_col_i in
col_i =
[col_i] = fc.offsetWidth
if
if not has_max_cols and has_manually_sized_column
CUI.dom.addClass(, "cui-lv--max-last-col")
else
CUI.dom.removeClass(, "cui-lv--max-last-col")
.innerHTML = css.join("\n")
for row_i, row_info of
for col_i, colspan of row_info
cell = CUI.dom.matchSelector(, "."++"-cell[row=\""+row_i+"\"][col=\""+col_i+"\"]")[0]
width = 0
for i in [0...colspan] by 1
# we assume that colspanned columns
# are never torn apart, so it is
# safe to add "1" here
width = width + [parseInt(col_i)+i]
dim = CUI.dom.getDimensions(cell)
if dim.computedStyle.boxSizing == "border-box"
cell.style.setProperty("width", width+"px", "important")
else
cell.style.setProperty("width", (width - dim.paddingHorizontal - dim.borderHorizontal)+"px", "important")
if > 0
# find unmeasured rows in Q2 & Q3 and set height
# in Q2
for qi in [0, 2]
rows = []
if opts.resetRows
sel = ".cui-lv-tr-outer"
else
sel = "[cui-lv-tr-unmeasured=\""++"\"]"
for row in CUI.dom.matchSelector(, "."++"-quadrant[cui-lv-quadrant='#{qi}'] > "+sel)
rows[parseInt(CUI.dom.getAttribute(row, "row"))] = row
CUI.dom.removeAttribute(row, "cui-lv-tr-unmeasured")
for row, idx in CUI.dom.matchSelector(, "."++"-quadrant[cui-lv-quadrant='#{qi+1}'] > "+sel)
row_i2 = parseInt(CUI.dom.getAttribute(row, "row"))
CUI.dom.prepareSetDimensions(rows[row_i2])
row.__offsetHeight = row.offsetHeight
for row, idx in CUI.dom.matchSelector(, "."++"-quadrant[cui-lv-quadrant='#{qi+1}'] > "+sel)
row_i2 = parseInt(CUI.dom.getAttribute(row, "row"))
CUI.dom.setDimensions(rows[row_i2], borderBoxHeight: row.__offsetHeight)
delete(row.__offsetHeight)
CUI.dom.removeAttribute(row, "cui-lv-tr-unmeasured")
= true
@
__addRowsOddEvenClasses: ->
if ( - )%2 == 0
CUI.dom.addClass(, "cui-list-view-grid-rows-even")
CUI.dom.removeClass(, "cui-list-view-grid-rows-odd")
else
CUI.dom.removeClass(, "cui-list-view-grid-rows-even")
CUI.dom.addClass(, "cui-list-view-grid-rows-odd")
@
__getValue: (px) ->
if not isNaN(parseFloat(px))
px+"px"
else if CUI.util.isNull(px)
""
else
px
hideWaitBlock: ->
if
.destroy()
delete()
@
showWaitBlock: ->
if
return @
= new CUI.WaitBlock(element: )
.show()
@
appendRows: (rows) ->
CUI.util.assert(not , "ListView.appendRow", "ListView #{@listViewCounter} is already destroyed.")
for row, idx in rows
row_i = ++
if idx == 0
start_row_i = row_i
++
.push(row_i)
@
__getColsFromAndTo: (qi) ->
switch qi
when 0, 2
from: 0
to: -1
when 1, 3
from:
to: -1
__deferRow: (row) ->
.push(row)
__addRow: (row_i, listViewRow=null, mode="append", sibling_row_i=null) ->
# return the two quadrant pairs for the
# given row.
__getQuadrants: (row_i) ->
if <
[0,1]
else
[2,3]
__addRows: (_row_i, listViewRows=[], mode="append", sibling_row_i=null) ->
CUI.util.assert(, "ListView.__addRows", "ListView.render has not been called yet.", row_i: _row_i, listView: @)
CUI.util.assert(mode in ["append", "prepend", "after", "replace"], "ListView.__addRows", "mode \"#{mode}\" not supported", row_i: _row_i)
html = [[],[],[],[]]
# if
#
_mode = mode
if _mode == "after" and ==
# sibling is in other quadrant
mode = "prepend"
if mode in ["replace", "after"]
switch mode
when "replace"
CUI.util.assert(listViewRows.length == 1, "ListView.__addRows", "Can only use mode \"#{mode}\" on one row", listViewRows: listViewRows)
row_i = _row_i
when "after"
row_i = sibling_row_i
anchor_row = [row_i]
CUI.util.assert(anchor_row.length >= 1, "ListView.__addRows", "anchor row #{row_i} for mode #{mode} not found.", rows: , row_i: row_i, mode: _mode, mode_used: mode)
# prepare html for all rows
for row_i in [_row_i..row_i+listViewRows.length-1] by 1
[row_i] = []
[row_i] = []
for qi in
ft =
if ft.to < ft.from
continue
tabindex = if then "tabindex=\"1\"" else ""
unmeasuredAttribute = if > 0 then "cui-lv-tr-unmeasured=\"#{@listViewCounter}\"" else ""
html[qi].push("<div class=\"cui-lv-tr-outer\" #{tabindex} #{unmeasuredAttribute} row=\"#{row_i}\"><div class=\"cui-lv-tr\">")
for display_col_i in [ft.from..ft.to] by 1
col_i =
[width, maxi] =
cls =
html[qi].push("<div class=\"cui-lv-td #{cls} #{@__lvClass}-cell\" col=\"#{col_i}\" row=\"#{row_i}\"></div>")
html[qi].push("</div></div>")
find_cells_and_rows = (top) =>
# find rows and cells in newly prepared html
_cells = CUI.dom.matchSelector(top, ".cui-lv-td")
for cell in _cells
_col = parseInt(cell.getAttribute("col"))
_row = parseInt(cell.getAttribute("row"))
[_row][_col] = cell
_rows = CUI.dom.matchSelector(top, ".cui-lv-tr-outer")
for row in _rows
row_i = parseInt(row.getAttribute("row"))
[row_i].push(row)
return
anchor_row_idx = 0
for qi in [0..3]
if html[qi].length == 0
continue
outer = document.createElement("div")
outer.innerHTML = html[qi].join("")
find_cells_and_rows(outer)
if mode == "append"
if qi in [2, 3]
# the last row is the fill row, make sure to
# insert our node before
while node = outer.firstChild
[qi].insertBefore(node, [qi].lastChild)
else
while node = outer.firstChild
[qi].appendChild(node)
continue
if mode == "prepend"
while node = outer.lastChild
[qi].insertBefore(node, [qi].firstChild)
continue
row = anchor_row[anchor_row_idx]
anchor_row_idx++
if mode == "after"
while node = outer.lastChild
CUI.dom.insertAfter(row, node)
continue
if mode == "replace"
node = outer.firstChild
CUI.dom.replaceWith(row, node)
# check for overflow in fixed qudrant
if > 0
fixedRows = [1].childNodes
if < fixedRows.length
if > 0
_qi_s = [0,1]
else
_qi_s = [1]
for i in [0...fixedRows.length-] by 1
for _qi in _qi_s
if [_qi+2].firstChild
[_qi+2].insertBefore([_qi].lastChild, [_qi+2].firstChild)
else
[_qi+2].appendChild([_qi].lastChild)
for listViewRow, idx in listViewRows
if CUI.util.isPromise(listViewRow)
do (idx) =>
listViewRow.done (_listViewRow) =>
else
@
__appendCells: (listViewRow, row_i) ->
CUI.util.assert(listViewRow instanceof CUI.ListViewRow, "ListView.addRow", "listViewRow needs to be instance of ListViewRow or Deferred which returns a ListViewRow", listViewRow: listViewRow)
listViewRow.setRowIdx(row_i).setListView(@)
for row in [row_i]
CUI.dom.data(row, "listViewRow", listViewRow)
listViewRow.addClass((listViewRow.getClass() or "")+" "+CUI.util.toDash(CUI.util.getObjectClass(listViewRow)))
if
if >= +
if listViewRow.getColumns()[0] not instanceof CUI.ListViewColumnRowMoveHandle
listViewRow.prependColumn(new CUI.ListViewColumnRowMoveHandle())
else
if listViewRow.getColumns()[0] not instanceof CUI.ListViewColumnRowMoveHandlePlaceholder
listViewRow.prependColumn(new CUI.ListViewColumnRowMoveHandlePlaceholder())
else if
if listViewRow.getColumns()[0] not instanceof CUI.ListViewColumnRowMoveHandlePlaceholder
listViewRow.prependColumn(new CUI.ListViewColumnRowMoveHandlePlaceholder())
_cols = listViewRow.getColumns()
colspan_offset = 0
for col, col_i in _cols
node = col.render()
cell = [row_i][col_i+colspan_offset]
CUI.util.assert(cell, "ListView.__appendCells", "Cell not found: row: "+row_i+" column: "+(col_i+colspan_offset+1)+". colsCount: "+, row: listViewRow)
if not CUI.util.isNull(node)
CUI.dom.append(cell, node)
col.setColumnIdx(col_i)
col.setElement(cell)
colspan = col.getColspan()
CUI.util.assert(col_i+colspan_offset+colspan-1 < , "ListView.__appendCells", "Colspan #{colspan} exceeds cols count #{@colsCount}, unable to append cell.", row_i: row_i, col_i: col_i, colspan_offset: colspan_offset, colspan: colspan, column: col, row: listViewRow, ListView: @)
if colspan > 1
cell.setAttribute("colspan", colspan)
# we remember the colspan here for the addCss
# class, its important to do this before we change
# colspan_offset
if not [row_i]
[row_i] = {}
[row_i][col_i+colspan_offset] = colspan
# delete the real column ids which are supposed
# to hide to the right of us
# if they are not in order, this is not our problem
# at this point
for i in [1...colspan]
CUI.dom.remove([row_i][col_i+colspan_offset+1])
delete([row_i][col_i+colspan_offset+1])
colspan_offset++
CUI.util.assert(_cols.length+colspan_offset <= , "ListView.addRow", "ListViewRow provided more columns (#{_cols.length+colspan_offset}) than colsCount (#{@colsCount}) is set to", colsCount: , cols: _cols)
listViewRow.addedToListView([row_i])
return
__getColClass: (col_i) ->
col_cls = ?[col_i]
cls = []
if CUI.util.isArray(col_cls)
cls.push.apply(cls, col_cls)
else if not CUI.util.isEmpty(col_cls)
cls.push(col_cls)
if col_i in
cls.push("cui-lv-td-max")
cls.join(" ")
__resetRowDim: (row_i) ->
delete([row_i])
if > 0 and [row_i]
for row in [row_i]
CUI.dom.setAttribute(row, "cui-lv-tr-unmeasured", )
for display_col_i in [0..-1]
col_i =
@
__resetCellStyle: (row_i, col_i) ->
cell = [row_i]?[col_i]
if cell
CUI.dom.setStyleOne(cell, "cssText", "")
cell
__resetColWidth: (col_i) ->
for dim in
if dim
delete(dim[col_i])
for display_row_i in [0..-1]
row_i =
[col_i].style.cssText = ""
@
__resetCellDims: (col_i) ->
= []
= []
__isMaximizedCol: (col_i) ->
col_i in and not .hasOwnProperty(col_i)
: 0
# use row_i == null to not check for colspan
__getColWidth: (row_i, col_i) ->
colspan = [row_i]?[col_i]
if colspan > 1
accWidth = 0
maxi = false
for _col_i in [col_i..col_i+colspan-1] by 1
if
maxi = true
accWidth += [_col_i]
[accWidth, maxi]
else
[[col_i], ]