'use strict'; /*@ Ox.TextList TextList Object ([options[, self]]) -> TextList Object options Options object columns <[o]|[]> Columns # Fixme: There's probably more... addable ... editable ... format ... id ... removable ... map function that maps values to sort values operator default sort operator title ... titleImage ... unformat Applied before editing unique If true, this column acts as unique id visible ... width ... columnsMovable If true, columns can be re-ordered columnsRemovable If true, columns are removable columnsResizable If true, columns are resizable columnsVisible If true, columns are visible columnWidth <[n]|[40, 800]> Minimum and maximum column width draggable If true, items can be dragged id Id items function() {} {sort, range, keys, callback} or array keys <[s]|[]> Additional keys (apart from keys of visible columns) max Maximum number of items that can be selected (-1 for all) min Minimum number of items that must be selected pageLength Number of items per page query Query scrollbarVisible If true, the scrollbar is always visible selected <[s]|[]> Array of selected ids sort <[o]|[s]|[]> ['+foo', ...] or [{key: 'foo', operator: '+'}, ...] sortable If true, elements can be re-ordered sums <[s]|[]> Sums to be included in totals columnresize columnresize columnchange columnchange self shared private variable @*/ // fixme: options.columnsMovable, but options.sortable ... pick one. Ox.TextList = function(options, self) { // fixme: rename to TableList // fixme: in columns, "operator" should be "sortOperator" self = self || {}; var that = Ox.Element({}, self) .defaults({ columns: [], columnsMovable: false, columnsRemovable: false, columnsResizable: false, columnsVisible: false, columnWidth: [40, 800], draggable: false, id: '', items: null, keys: [], max: -1, min: 0, pageLength: 100, query: {conditions: [], operator: '&'}, scrollbarVisible: false, selected: [], sort: [], sortable: false, sums: [] }) .options(options || {}) .update({ items: function() { that.$body.options({items: self.options.items}); }, paste: function() { that.$body.options({paste: self.options.paste}); }, query: function() { that.$body.options({query: self.options.query}); }, selected: function() { that.$body.options({selected: self.options.selected}); }, sort: function() { updateColumn(); that.$body.options({sort: self.options.sort}); } }) .addClass('OxTextList') .bindEvent({ key_left: function() { var $element = that.$body.$element, scrollLeft = $element[0].scrollLeft - $element.width(); $element.animate({scrollLeft: scrollLeft}, 250); }, key_right: function() { var $element = that.$body.$element, scrollLeft = $element[0].scrollLeft + $element.width(); $element.animate({scrollLeft: scrollLeft}, 250); }, keys: find }); self.options.sort = self.options.sort.map(function(sort) { return Ox.isString(sort) ? { key: sort.replace(/^[\+\-]/, ''), operator: sort[0] == '-' ? '-' : '+' } : sort; }); self.options.columns.forEach(function(column) { // fixme: can this go into a generic ox.js function? // fixme: and can't these just remain undefined? if (Ox.isUndefined(column.align)) { column.align = 'left'; } if (Ox.isUndefined(column.clickable)) { column.clickable = false; } if (Ox.isUndefined(column.editable)) { column.editable = false; } if (Ox.isUndefined(column.unique)) { column.unique = false; } if (Ox.isUndefined(column.visible)) { column.visible = false; } if (column.unique) { self.unique = column.id; } }); if (Ox.isEmpty(self.options.sort)) { self.options.sort = [{ key: self.unique, operator: Ox.getObjectById(self.options.columns, self.unique).operator }]; } Ox.extend(self, { columnPositions: [], defaultColumnWidths: self.options.columns.map(function(column) { return column.defaultWidth || column.width; }), itemHeight: 16, page: 0, pageLength: 100, scrollLeft: 0, selectedColumn: getColumnIndexById(self.options.sort[0].key), visibleColumns: self.options.columns.filter(function(column) { return column.visible; }) }); // fixme: there might be a better way than passing both visible and position self.options.columns.forEach(function(column) { if (!Ox.isUndefined(column.position)) { self.visibleColumns[column.position] = column; } }); Ox.extend(self, { columnWidths: self.visibleColumns.map(function(column) { return column.width; }), pageHeight: self.options.pageLength * self.itemHeight }); self.format = {}; self.options.columns.forEach(function(column) { if (column.format) { self.format[column.id] = column.format; } }); // Head if (self.options.columnsVisible) { that.$bar = Ox.Bar({ orientation: 'horizontal', size: 16 }).appendTo(that); that.$head = Ox.Container() .addClass('OxHead') .css({ right: self.options.scrollbarVisible ? Ox.UI.SCROLLBAR_SIZE + 'px' : 0 }) .appendTo(that.$bar); that.$head.$content.addClass('OxTitles'); constructHead(); if (self.options.columnsRemovable) { that.$select = Ox.Select({ id: self.options.id + 'SelectColumns', items: self.options.columns.map(function(column) { return { disabled: column.removable === false, id: column.id, title: column.title }; }), max: -1, min: 1, type: 'image', value: Ox.filter(self.options.columns, function(column) { return column.visible; }).map(function(column) { return column.id; }) }) .bindEvent('change', changeColumns) .appendTo(that.$bar.$element); } } // Body that.$body = Ox.List({ construct: constructItem, draggable: self.options.draggable, id: self.options.id, itemHeight: 16, items: self.options.items, itemWidth: getItemWidth(), format: self.format, // fixme: not needed, happens in TextList keys: self.visibleColumns.map(function(column) { return column.id; }).concat(self.options.keys), max: self.options.max, min: self.options.min, orientation: 'vertical', pageLength: self.options.pageLength, paste: self.options.paste, query: self.options.query, selected: self.options.selected, sort: self.options.sort, sortable: self.options.sortable, sums: self.options.sums, type: 'text', unique: self.unique }, Ox.extend(Ox.clone(self), {updateCallbacks: []})) // pass event handler .addClass('OxBody') .css({ top: (self.options.columnsVisible ? 16 : 0) + 'px', overflowY: (self.options.scrollbarVisible ? 'scroll' : 'hidden') }) .scroll(function() { var scrollLeft = $(this).scrollLeft(); if (scrollLeft != self.scrollLeft) { self.scrollLeft = scrollLeft; that.$head && that.$head.scrollLeft(scrollLeft); } }) .bindEvent({ cancel: function(data) { Ox.Log('List', 'cancel edit', data); }, edit: function(data) { that.editCell(data.id, data.key); }, select: function() { self.options.selected = that.$body.options('selected'); } }) .appendTo(that); that.$body.$content.css({ width: getItemWidth() + 'px' }); //Ox.Log('List', 's.vC', self.visibleColumns) function addColumn(id) { //Ox.Log('List', 'addColumn', id); var column, ids, index = 0; Ox.forEach(self.options.columns, function(v) { if (v.visible) { index++; } else if (v.id == id) { column = v; Ox.Break(); } }); column.visible = true; self.visibleColumns.splice(index, 0, column); self.columnWidths.splice(index, 0, column.width); that.$head.$content.empty(); constructHead(); that.$body.options({ keys: self.visibleColumns.map(function(column) { return column.id; }).concat(self.options.keys) }); that.$body.reloadPages(); } function changeColumns(data) { var add, ids = []; Ox.forEach(data.value, function(id) { var index = getColumnIndexById(id); if (!self.options.columns[index].visible) { addColumn(id); add = true; Ox.Break(); } ids.push(id); }); if (!add) { Ox.forEach(self.visibleColumns, function(column) { if (ids.indexOf(column.id) == -1) { removeColumn(column.id); Ox.Break(); } }); } triggerColumnChangeEvent(); } function clickColumn(id) { Ox.Log('List', 'clickColumn', id); var i = getColumnIndexById(id), isSelected = self.options.sort[0].key == self.options.columns[i].id; self.options.sort = [{ key: self.options.columns[i].id, operator: isSelected ? (self.options.sort[0].operator == '+' ? '-' : '+') : self.options.columns[i].operator, map: self.options.columns[i].map }]; updateColumn(); // fixme: strangely, sorting the list blocks updating the column, // so we use a timeout for now setTimeout(function() { that.$body.options({sort: self.options.sort}); }, 10); that.gainFocus().triggerEvent('sort', { key: self.options.sort[0].key, operator: self.options.sort[0].operator }); } function constructHead() { var pos; self.$heads = []; self.$titles = []; self.$orderButtons = []; self.visibleColumns.forEach(function(column, i) { var $resize; self.$heads[i] = Ox.Element() .addClass('OxHeadCell OxColumn' + Ox.toTitleCase(column.id)) .css({width: self.columnWidths[i] - 5 + 'px'}) .appendTo(that.$head.$content.$element); // if sort operator is set, bind click event if (column.operator) { self.$heads[i].bindEvent({ anyclick: function() { clickColumn(column.id); } }); } // if columns are movable, bind drag events if (self.options.columnsMovable) { self.$heads[i].bindEvent({ dragstart: function(data) { dragstartColumn(column.id, data); }, drag: function(data) { dragColumn(column.id, data); }, dragpause: function(data) { dragpauseColumn(column.id, data); }, dragend: function(data) { dragendColumn(column.id, data); } }); } self.$titles[i] = Ox.Element() .addClass('OxTitle') .css({ width: self.columnWidths[i] - 9 + 'px', textAlign: column.align }) .appendTo(self.$heads[i]); if (column.titleImage) { self.$titles[i].append( $('').attr({ src: Ox.UI.getImageURL('symbol' + Ox.toTitleCase(column.titleImage)) }) ); } else { self.$titles[i].html(column.title); } if (column.operator) { self.$orderButtons[i] = Ox.Button({ style: 'symbol', title: column.operator == '+' ? 'up' : 'down', type: 'image' }) .addClass('OxOrder') .css({marginTop: (column.operator == '+' ? 1 : -1) + 'px'}) .click(function() { $(this).parent().trigger('click'); }) .appendTo(self.$heads[i]); } $resize = Ox.Element() .addClass('OxResize') .appendTo(that.$head.$content.$element); $('
').appendTo($resize); $('
').addClass('OxCenter').appendTo($resize); $('
').appendTo($resize); // if columns are resizable, bind click and drag events if (self.options.columnsResizable && column.resizable !== false) { $resize.addClass('OxResizable') .bindEvent({ doubleclick: function(data) { resetColumn(column.id, data); }, dragstart: function(data) { dragstartResize(column.id, data); }, drag: function(data) { dragResize(column.id, data); }, dragend: function(data) { dragendResize(column.id, data); } }); } }); that.$head.$content.css({ width: (Ox.sum(self.columnWidths) + 2) + 'px' }); pos = getColumnPositionById(self.options.columns[self.selectedColumn].id); if (pos > -1) { toggleSelected(self.options.columns[self.selectedColumn].id); self.$titles[pos].css({ width: (self.options.columns[self.selectedColumn].width - 25) + 'px' }); } } function constructItem(data) { var $item = $('
') .addClass('OxTarget') .css({ width: getItemWidth(true) + 'px' }); self.visibleColumns.forEach(function(v, i) { var clickable = Ox.isBoolean(v.clickable) ? v.clickable : v.clickable(data), editable = Ox.isBoolean(v.editable) ? v.editable : v.editable(data), $cell; if (v.tooltip) { $cell = Ox.Element({ tooltip: function() { return self.options.selected.indexOf(data[self.unique]) > -1 ? (Ox.isString(v.tooltip) ? v.tooltip : v.tooltip(data)) : ''; } }); } else { // this is faster $cell = $('
'); } $cell.addClass( 'OxCell OxColumn' + Ox.toTitleCase(v.id) + (clickable ? ' OxClickable' : '') + (editable ? ' OxEditable' : '') ) .css({ width: (self.columnWidths[i] - (self.options.columnsVisible ? 9 : 8)) + 'px', borderRightWidth: (self.options.columnsVisible ? 1 : 0) + 'px', textAlign: v.align }) // if the column id is not in data, we're constructing an empty cell .html(v.id in data ? formatValue(v.id, data[v.id], data) : '') .appendTo($item); }); return $item; } function dragstartColumn(id, e) { self.drag = { columnOffsets: getColumnOffsets(), listOffset: that.$element.offset().left - that.$body.scrollLeft(), startPos: getColumnPositionById(id) } self.drag.stopPos = self.drag.startPos; $('.OxColumn' + Ox.toTitleCase(id)).css({opacity: 0.25}); self.drag.startPos > 0 && self.$heads[self.drag.startPos].prev().children().eq(2).css({opacity: 0.25}); self.$heads[self.drag.startPos].next().children().eq(0).css({opacity: 0.25}); self.$heads[self.drag.startPos].addClass('OxDrag').css({ // fixme: why does the class not work? cursor: 'move' }); } function dragColumn(id, e) { var listLeft = that.$element.offset().left, listRight = listLeft + that.$element.width(), pos = self.drag.stopPos; Ox.forEach(self.drag.columnOffsets, function(offset, i) { var x = self.drag.listOffset + offset + self.columnWidths[i] / 2; if (i < self.drag.startPos && e.clientX < x) { self.drag.stopPos = i; Ox.Break(); } else if (i > self.drag.startPos && e.clientX > x) { self.drag.stopPos = i; } }); if (self.drag.stopPos != pos) { moveColumn(id, self.drag.stopPos); self.drag.columnOffsets = getColumnOffsets(); self.drag.startPos = self.drag.stopPos; ///* var left = self.drag.columnOffsets[self.drag.startPos], right = left + self.columnWidths[self.drag.startPos]; if (left < that.$body.scrollLeft() || right > that.$element.width()) { that.$body.scrollLeft( left < that.$body.scrollLeft() ? left : right - that.$element.width() ); self.drag.listOffset = that.$element.offset().left - that.$body.scrollLeft(); } //*/ } if (e.clientX < listLeft + 16 || e.clientX > listRight - 16) { if (!self.scrollInterval) { self.scrollInterval = setInterval(function() { that.$body.scrollLeft( that.$body.scrollLeft() + (e.clientX < listLeft + 16 ? -16 : 16) ); self.drag.listOffset = that.$element.offset().left - that.$body.scrollLeft(); }, 100); } } else if (self.scrollInterval) { clearInterval(self.scrollInterval); self.scrollInterval = 0; } } function dragpauseColumn(id, e) { } function dragendColumn(id, e) { var column = self.visibleColumns.splice(self.drag.stopPos, 1)[0], width = self.columnWidths.splice(self.drag.stopPos, 1)[0]; self.visibleColumns.splice(self.drag.stopPos, 0, column); self.columnWidths.splice(self.drag.stopPos, 0, width); that.$head.$content.empty(); constructHead(); $('.OxColumn' + Ox.toTitleCase(id)).css({opacity: 1}); self.$heads[self.drag.stopPos].removeClass('OxDrag').css({ cursor: 'pointer' }); that.$body.clearCache(); triggerColumnChangeEvent(); } function dragstartResize(id, e) { var pos = getColumnPositionById(id); self.drag = { startWidth: self.columnWidths[pos] }; } function dragResize(id, e) { var width = Ox.limit( self.drag.startWidth + e.clientDX, self.options.columnWidth[0], self.options.columnWidth[1] ); resizeColumn(id, width); } function dragendResize(id, e) { var pos = getColumnPositionById(id); // fixme: shouldn't this be resizecolumn? that.triggerEvent('columnresize', { id: id, width: self.columnWidths[pos] }); } function find(data) { // fixme: works only if items are an array var query = data.keys, sort = self.options.sort[0]; Ox.Log('List', 'QUERY', query) Ox.forEach(self.options.items, function(item, i) { var value = ( sort.map ? sort.map(item[sort.key]) : item[sort.key] ).toString().toLowerCase(); if (Ox.startsWith(value, query)) { that.$body.options({selected: [item[self.unique]]}); Ox.Log('List', 'QUERY', query, 'VALUE', value) Ox.Break(); } }); } function formatValue(key, value, data) { // fixme: this may be obscure... // since the format of a value may depend on another value, // we pass all data as a second parameter to the supplied format function var format = self.format[key], formatFunction; // FIXME: this keeps null from ever reaching a format function! if (value === null) { value = ''; } else if (format) { if (Ox.isObject(format)) { value = ( /^color/.test(format.type.toLowerCase()) ? Ox.Theme : Ox )['format' + Ox.toTitleCase(format.type)].apply( this, [value].concat(format.args || []) ); } else { value = format(value, data); } } else if (Ox.isArray(value)) { value = value.join(', '); } return value; } function getCell(id, key) { var $item = getItem(id); key = key || ''; // fixme: what is this? return $($item.find('.OxCell.OxColumn' + Ox.toTitleCase(key))[0]); } function getColumnOffsets() { return self.visibleColumns.map(function(column, i) { return Ox.sum(self.visibleColumns.map(function(column_, i_) { return i_ < i ? self.columnWidths[i_] : 0; })); }); } function getColumnIndexById(id) { return Ox.getIndexById(self.options.columns, id); } function getColumnPositionById(id) { return Ox.getIndexById(self.visibleColumns, id); } function getItem(id) { //Ox.Log('List', 'getItem', id) var $item = null; that.find('.OxItem').each(function() { var $this = $(this); if ($this.data('id') == id) { $item = $this; return false; } }); return $item; } function getItemWidth(cached) { // fixme: this gets called for every constructItem and is slooow // the proper way to fix this would be to find out how and when // that.$element.width() might change... which would probably // mean binding to every SplitPanel and window resize... // for now, use a cached value if (!cached) { self.cachedWidth = that.$element.width(); } else if (!self.cachedWidth || self.cachedWidthTime < +new Date() - 5000) { self.cachedWidth = that.$element.width(); self.cachedWidthTime = +new Date(); } return Math.max( Ox.sum(self.columnWidths), self.cachedWidth - (self.options.scrollbarVisible ? Ox.UI.SCROLLBAR_SIZE : 0) ); } function moveColumn(id, pos) { //Ox.Log('List', 'moveColumn', id, pos) var startPos = getColumnPositionById(id), stopPos = pos, startSelector = '.OxColumn' + Ox.toTitleCase(id), stopSelector = '.OxColumn' + Ox.toTitleCase(self.visibleColumns[stopPos].id), insert = startPos < stopPos ? 'insertAfter' : 'insertBefore', $column = $('.OxHeadCell' + startSelector), $resize = $column.next(); //Ox.Log('List', startSelector, insert, stopSelector) $column.detach()[insert](insert == 'insertAfter' ? $('.OxHeadCell' + stopSelector).next() : $('.OxHeadCell' + stopSelector)); $resize.detach().insertAfter($column); that.$body.find('.OxItem').each(function() { var $this = $(this); $this.children(startSelector).detach()[insert]( $this.children(stopSelector) ); }); var $head = self.$heads.splice(startPos, 1)[0], columnWidth = self.columnWidths.splice(startPos, 1)[0], visibleColumn = self.visibleColumns.splice(startPos, 1)[0]; self.$heads.splice(stopPos, 0, $head); self.columnWidths.splice(stopPos, 0, columnWidth); self.visibleColumns.splice(stopPos, 0, visibleColumn); var pos = getColumnPositionById(self.options.columns[self.selectedColumn].id); if (pos > -1) { that.find('.OxResize .OxSelected').removeClass('OxSelected'); pos > 0 && self.$heads[pos].prev().children().eq(2).addClass('OxSelected'); self.$heads[pos].next().children().eq(0).addClass('OxSelected'); if (pos == stopPos) { pos > 0 && self.$heads[pos].prev().children().eq(2).css({opacity: 0.25}); self.$heads[pos].next().children().eq(0).css({opacity: 0.25}); } } } function removeColumn(id) { //Ox.Log('List', 'removeColumn', id); var index = getColumnIndexById(id), itemWidth, position = getColumnPositionById(id), selector = '.OxColumn' + Ox.toTitleCase(id), $column = $('.OxHeadCell ' + selector), $order = $column.next(), $resize = $order.next(); self.options.columns[index].visible = false; self.visibleColumns.splice(position, 1); self.columnWidths.splice(position, 1); that.$head.$content.empty(); constructHead(); itemWidth = getItemWidth(); that.$body.find('.OxItem').each(function() { var $this = $(this); $this.children(selector).remove(); $this.css({width: itemWidth + 'px'}); }); that.$body.$content.css({ width: itemWidth + 'px' }); that.$body.options({ keys: self.visibleColumns.map(function(column) { return column.id; }).concat(self.options.keys) }); //that.$body.clearCache(); } function resetColumn(id) { var width = self.defaultColumnWidths[getColumnIndexById(id)]; resizeColumn(id, width); that.triggerEvent('columnresize', { id: id, width: width }); } function resizeColumn(id, width) { var i = getColumnIndexById(id), pos = getColumnPositionById(id); self.options.columns[i].width = width; self.columnWidths[pos] = width; if (self.options.columnsVisible) { that.$head.$content.css({ width: (Ox.sum(self.columnWidths) + 2) + 'px' }); self.$heads[pos].css({ width: width - 5 + 'px' }); self.$titles[pos].css({ width: width - 9 - (i == self.selectedColumn ? 16 : 0) + 'px' }); } that.find('.OxCell.OxColumn' + Ox.toTitleCase(self.options.columns[i].id)).css({ width: width - (self.options.columnsVisible ? 9 : 8) + 'px' }); setWidth(); } function setWidth() { var width = getItemWidth(); that.$body.find('.OxItem').css({ // fixme: can we avoid this lookup? width: width + 'px' }); that.$body.$content.css({ width: width + 'px' // fixme: check if scrollbar visible, and listen to resize/toggle event }); } function toggleSelected(id) { var pos = getColumnPositionById(id); if (pos > -1) { updateOrder(id); pos > 0 && self.$heads[pos].prev().children().eq(2).toggleClass('OxSelected'); self.$heads[pos].toggleClass('OxSelected'); self.$heads[pos].next().children().eq(0).toggleClass('OxSelected'); self.$titles[pos].css({ width: self.$titles[pos].width() + (self.$heads[pos].hasClass('OxSelected') ? -16 : 16) + 'px' }); } } function triggerColumnChangeEvent() { that.triggerEvent('columnchange', { ids: self.visibleColumns.map(function(column) { return column.id; }) }); } function updateColumn() { var columnId = self.options.columns[self.selectedColumn].id, isSelected = columnId == self.options.sort[0].key; if (self.options.columnsVisible) { if (isSelected) { updateOrder(columnId); } else { toggleSelected(columnId); self.selectedColumn = getColumnIndexById(self.options.sort[0].key); toggleSelected(self.options.columns[self.selectedColumn].id); } } } function updateOrder(id) { var operator = self.options.sort[0].operator, pos = getColumnPositionById(id); if (pos > -1) { self.$orderButtons[pos].options({ title: operator == '+' ? 'up' : 'down' }).css({ marginTop: (operator == '+' ? 1 : -1) + 'px' }); } } that.addItem = function(item) { /* self.options.items.push(item); that.$body.options({items: self.options.items}); //that.$body.options({selected: [item.id]}); */ } /*@ closePreivew closePreview @*/ that.closePreview = function() { that.$body.closePreview(); return that; }; /*@ editCell editCell (id, key, select) -> edit cell @*/ that.editCell = function(id, key, select) { Ox.Log('List', 'editCell', id, key) var $item = getItem(id), $cell = getCell(id, key), $input, html = $cell.html(), index = getColumnIndexById(key), column = self.options.columns[index], width = column.width - self.options.columnsVisible; $cell.empty() .addClass('OxEdit') .css({width: width + 'px'}); $input = Ox.Input({ autovalidate: column.input ? column.input.autovalidate : null, style: 'square', value: column.unformat ? column.unformat(html) : html, width: width }) .on({ mousedown: function(e) { // keep mousedown from reaching list e.stopPropagation(); } }) .bindEvent({ blur: submit, cancel: submit, submit: submit }) .appendTo($cell); // use timeout to prevent key to be inserted // into $input if triggered via keyboard shortcut setTimeout(function() { $input.focusInput(select); }, 0); function submit() { var value = $input.value(); $input.remove(); $cell.removeClass('OxEdit') .css({ // account for padding width: (width - 8) + 'px' }) .html(value); that.triggerEvent('submit', { id: id, key: key, value: value }); } }; /*@ gainFocus gainFocus @*/ that.gainFocus = function() { that.$body.gainFocus(); return that; }; /*@ hasFocus hasFocus @*/ that.hasFocus = function() { return that.$body.hasFocus(); }; /*@ loseFocus loseFocus @*/ that.loseFocus = function() { that.$body.loseFocus(); return that; }; /*@ openPreview openPreview @*/ that.openPreview = function() { that.$body.openPreview(); return that; }; /*@ paste paste (data) -> paste data @*/ that.paste = function(data) { that.$body.paste(); return that; }; /*@ reloadList reloadList (stayAtPosition) -> reload list @*/ that.reloadList = function(stayAtPosition) { that.$body.reloadList(stayAtPosition); return that; }; /*@ resizeColumn resizeColumn (id, width) -> resize column id to width @*/ that.resizeColumn = function(id, width) { resizeColumn(id, width); return that; }; /*@ size size @*/ that.size = function() { setWidth(); that.$body.size(); }; // fixme: deprecated that.sortList = function(key, operator) { Ox.Log('List', '$$$$ DEPRECATED $$$$') var isSelected = key == self.options.sort[0].key; self.options.sort = [{ key: key, operator: operator, map: self.options.columns[self.selectedColumn].sort }]; if (self.options.columnsVisible) { if (isSelected) { updateOrder(self.options.columns[self.selectedColumn].id); } else { toggleSelected(self.options.columns[self.selectedColumn].id); self.selectedColumn = getColumnIndexById(key); toggleSelected(self.options.columns[self.selectedColumn].id); } } // fixme: strangely, sorting the list blocks toggling the selection, // so we use a timeout for now setTimeout(function() { that.$body.options({sort: self.options.sort}); /* that.$body.sortList( self.options.sort[0].key, self.options.sort[0].operator, self.options.sort[0].map ); */ }, 10); return that; }; /*@ value value (id) -> get values of row id (id, key) -> get value of cell id, key (id, key, value) -> set id, key to value @*/ that.value = function(id, key, value) { // fixme: make this accept id, {k: v, ...} //Ox.Log('List', 'value', id, key, value) var $cell, $item = getItem(id); //column = self.options.columns[getColumnIndexById(key)]; if (arguments.length == 1) { return that.$body.value(id); } else if (arguments.length == 2) { return that.$body.value(id, key); } else { that.$body.value(id, key, value); if (key == self.unique) { // unique id has changed self.options.selected = self.options.selected.map(function(id_) { return id_ == id ? value : id_ }); id = value; } $cell = getCell(id, key); $cell && $cell.html(formatValue(key, value, that.$body.value(id))); if (key == self.options.sort[0].key) { // sort key has changed that.$body.sort(); } return that; } }; return that; };