'use strict'; Ox.Spreadsheet = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ columnPlaceholder: '', columns: [], columnTitleType: 'str', columnWidth: 64, rowPlaceholder: '', rows: [], rowTitleType: 'str', rowTitleWidth: 128, title: '', value: [] }) .options(options || {}) .addClass('OxSpreadsheet'); self.values = []; self.options.rows.forEach(function(row, r) { self.values.push([]); self.options.columns.forEach(function(column, c) { self.values[r].push(0); }); }); self.sums = getSums(); renderSpreadsheet(); function addColumn(index) { self.options.columns.splice(index, 0, ''); Ox.print('sv', JSON.stringify(self.values)) self.values.forEach(function(columns) { columns.splice(index, 0, 0); }); Ox.print('sv', JSON.stringify(self.values)) renderSpreadsheet(); } function addRow(index) { self.options.rows.splice(index, 0, ''); self.values.splice(index, 0, Ox.repeat([0], self.columns)); renderSpreadsheet(); } function getSums() { var sums = { column: Ox.repeat([0], self.columns), row: Ox.repeat([0], self.rows), sheet: 0 }; Ox.print('sv', self.values); self.values.forEach(function(columns, r) { columns.forEach(function(value, c) { sums.column[c] += value; sums.row[r] += value; sums.sheet += value; }); }); return sums; } function removeColumn(index) { self.options.columns.splice(index, 1); self.values.forEach(function(columns) { columns.splice(index, 1); }); renderSpreadsheet(); } function removeRow(index) { self.options.rows.splice(index, 1); self.values.splice(index, 1); renderSpreadsheet(); } function renderSpreadsheet() { self.columns = self.options.columns.length; self.rows = self.options.rows.length; self.sums = getSums(); self.$input = {}; that.empty() .css({ width: self.options.rowTitleWidth + self.options.columnWidth * (self.columns + 1) + 'px', height: 16 * (self.rows + 2) + 'px' }); Ox.merge([self.options.title], Ox.clone(self.options.rows), ['Total']).forEach(function(row, r) { r--; Ox.print('ROW', row); Ox.merge([''], Ox.clone(self.options.columns), ['Total']).forEach(function(column, c) { c--; if (r == -1) { if (c == -1 || c == self.columns) { Ox.print('c', c, 'row', row) Ox.Label({ style: 'square', textAlign: c == -1 ? 'left' : 'right', title: c == -1 ? self.options.title : 'Total', width: c == -1 ? self.options.rowTitleWidth : self.options.columnWidth }) .appendTo(that); } else { Ox.Select({ selectable: false, style: 'square', type: 'image', items: [ {id: 'before', title: 'Add column before'}, {id: 'after', title: 'Add column after'}, {id: 'remove', title: 'Remove this column', disabled: self.columns == 1} ] }) .bindEvent({ click: function(data) { if (data.id == 'remove') { removeColumn(c); } else { addColumn(c + (data.id == 'after')); } triggerChangeEvent(); } }) .appendTo(that); Ox.Input({ placeholder: self.options.columnPlaceholder, style: 'square', type: self.options.columnTitleType, value: column, width: self.options.columnWidth - 16 }) .bindEvent({ change: function(data) { self.options.columns[c] = data.value; triggerChangeEvent(); } }) .appendTo(that); } } else { if (c == -1) { if (r < self.rows) { Ox.Select({ selectable: false, style: 'square', type: 'image', items: [ {id: 'before', title: 'Add row above'}, {id: 'after', title: 'Add row below'}, {id: 'remove', title: 'Remove this row', disabled: self.rows == 1} ] }) .bindEvent({ click: function(data) { if (data.id == 'remove') { removeRow(r); } else { addRow(r + (data.id == 'after')); } triggerChangeEvent(); } }) .appendTo(that); Ox.Input({ placeholder: self.options.rowPlaceholder, style: 'square', type: self.options.rowTitleType, value: row, width: self.options.rowTitleWidth - 16 }) .bindEvent({ change: function(data) { self.options.rows[r] = data.value; triggerChangeEvent(); } }) .appendTo(that); } else { Ox.Label({ style: 'square', textAlign: 'right', title: row, width: self.options.rowTitleWidth }) .appendTo(that); } } else { var id = c + ',' + r, isColumnSum = r == self.rows, isRowSum = c == self.columns, isSheetSum = isColumnSum && isRowSum, isSum = isColumnSum || isRowSum; self.$input[id] = Ox.Input({ //changeOnKeypress: true, disabled: isSum, style: 'square', type: 'int', value: isSheetSum ? self.sums.sheet : isColumnSum ? self.sums.column[c] : isRowSum ? self.sums.row[r] : self.values[r][c], width: self.options.columnWidth }) .appendTo(that); !isSum && self.$input[id].bindEvent({ change: function(data) { self.values[r][c] = parseInt(data.value); self.sums = getSums(); self.$input[c + ',' + self.rows].options({value: self.sums.column[c]}); self.$input[self.columns + ',' + r].options({value: self.sums.row[r]}); self.$input[self.columns + ',' + self.rows].options({value: self.sums.sheet}); triggerChangeEvent(); } }); } } }); }); } function triggerChangeEvent() { that.triggerEvent('change', { value: that.value() }); } that.value = function() { return { columns: self.options.columns, rows: self.options.rows, values: self.values }; }; return that; };