react-microspreadsheet
Version:
A pluggable spreadsheet component.
764 lines (684 loc) • 23.1 kB
JavaScript
// Generated by CoffeeScript 1.8.0
var Mori, RawStore, Store, expandPattern, recalc, selix, store, utils,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
Store = require('./base-store');
Mori = require('mori');
utils = require('./utils');
selix = require('selix');
RawStore = (function(_super) {
__extends(RawStore, _super);
function RawStore() {
return RawStore.__super__.constructor.apply(this, arguments);
}
RawStore.prototype.cells = Mori.js_to_clj([
[
{
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}
], [
{
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}
], [
{
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}, {
raw: '',
calc: ''
}
]
]);
RawStore.prototype.selectedCoord = [0, 0];
RawStore.prototype.multi = [[0, 0], [0, 0]];
RawStore.prototype.selectingMulti = false;
RawStore.prototype.strapping = false;
RawStore.prototype.strapVector = [null, null, null];
RawStore.prototype.editingCoord = null;
RawStore.prototype.volatileEdit = false;
RawStore.prototype.refEdit = false;
RawStore.prototype.caretPosition = null;
RawStore.prototype.select = function(coord) {
this.selectedCoord = coord;
return this.multi = [coord, coord];
};
RawStore.prototype.edit = function(coord) {
this.editingCoord = coord;
this.selectingMulti = false;
this.caretPosition = null;
this.volatileEdit = false;
return this.refEdit = false;
};
RawStore.prototype.getCells = function() {
var cells, highlight, i, j, _i, _j, _ref, _ref1, _ref2, _ref3;
cells = Mori.assoc_in(this.cells, this.selectedCoord.concat('selected'), true);
if (this.editingCoord) {
cells = Mori.assoc_in(cells, this.editingCoord.concat('editing'), true);
}
if (this.strapVector[1] !== null) {
highlight = [utils.firstCellFromMulti(this.multi), utils.lastCellFromMulti(this.multi)];
highlight[this.strapVector[1]][this.strapVector[0]] += this.strapVector[2];
} else {
highlight = this.multi;
}
for (i = _i = _ref = highlight[0][0], _ref1 = highlight[1][0]; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = _ref <= _ref1 ? ++_i : --_i) {
for (j = _j = _ref2 = highlight[0][1], _ref3 = highlight[1][1]; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; j = _ref2 <= _ref3 ? ++_j : --_j) {
cells = Mori.assoc_in(cells, [i, j, 'multi'], true);
}
}
cells = Mori.assoc_in(cells, utils.lastCellFromMulti(store.multi).concat('last-multi'), true);
return cells;
};
RawStore.prototype.undoStates = Mori.list();
RawStore.prototype.redoStates = Mori.list();
RawStore.prototype.canUndo = false;
RawStore.prototype.canRedo = false;
RawStore.prototype.redo = function() {
if (store.canRedo) {
store.undoStates = Mori.conj(store.undoStates, Mori.first(store.redoStates));
store.cells = Mori.first(store.redoStates);
store.redoStates = Mori.drop(1, store.redoStates);
store.canRedo = !Mori.is_empty(store.redoStates);
return store.canUndo = true;
}
};
RawStore.prototype.undo = function() {
if (store.canUndo) {
store.redoStates = Mori.conj(store.redoStates, Mori.first(this.undoStates));
store.undoStates = Mori.drop(1, store.undoStates);
store.cells = Mori.first(store.undoStates);
store.canUndo = !Mori.is_empty(store.undoStates);
return store.canRedo = true;
}
};
RawStore.prototype.clipboard = false;
RawStore.prototype.rawClipboard = {};
return RawStore;
})(Store);
store = new RawStore;
store.registerCallback('replace-cells', function(cellsArray) {
var newCells, rawValue, row;
newCells = Mori.js_to_clj((function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = cellsArray.length; _i < _len; _i++) {
row = cellsArray[_i];
_results.push((function() {
var _j, _len1, _results1;
_results1 = [];
for (_j = 0, _len1 = row.length; _j < _len1; _j++) {
rawValue = row[_j];
_results1.push({
raw: rawValue,
calc: ''
});
}
return _results1;
})());
}
return _results;
})());
store.cells = newCells;
store.edit(null);
store.select([0, 0]);
recalc();
return store.changed();
});
store.registerCallback('new-cell-value', function(value) {
store.cells = Mori.assoc_in(store.cells, store.editingCoord.concat('raw'), value);
store.caretPosition = null;
store.refEdit = true;
store.changed();
return store.rawClipboard = {};
});
store.registerCallback('input-clicked', function(element) {
var caret;
caret = selix.getCaret(element);
if (caret.end === caret.start) {
store.caretPosition = caret.end;
}
store.volatileEdit = false;
return store.refEdit = true;
});
store.registerCallback('input-selecttext', function(element) {
if (selix.getText(element)) {
return store.refEdit = true;
}
});
store.registerCallback('input-doubleclicked', function(element) {
return store.refEdit = true;
});
store.registerCallback('left-keyup', function(e) {
if (store.editingCoord && e.target.tagName === 'INPUT') {
return store.caretPosition = selix.getCaret(e.target).start;
}
});
store.registerCallback('right-keyup', function(e) {
if (store.editingCoord && e.target.tagName === 'INPUT') {
return store.caretPosition = selix.getCaret(e.target).end;
}
});
store.registerCallback('cell-clicked', function(coord) {
var addr, valueBeingEdited;
if (store.editingCoord) {
valueBeingEdited = Mori.get_in(store.cells, store.editingCoord.concat('raw'));
if (valueBeingEdited[0] === '=' && store.refEdit || store.volatileEdit) {
addr = utils.getAddressFromCoord(coord);
store.cells = Mori.update_in(store.cells, store.editingCoord.concat('raw'), function(val) {
var caretPosition, left, leftMatch, right, rightMatch;
caretPosition = store.caretPosition === null ? val.length : store.caretPosition;
left = val.substr(0, caretPosition);
right = val.substr(caretPosition);
leftMatch = /[+-\/:;.*(=^><!]([A-Za-z]?\d{0,2})$/.exec(left);
rightMatch = /^([A-Za-z]?\d{0,2})([+-\/:;.*)=^><!]|$)/.exec(right);
if (!leftMatch || !rightMatch) {
return val;
}
if ((leftMatch[1] || rightMatch[1]) && (!/[A-Za-z]\d{1,2}/.exec(leftMatch[1] + rightMatch[1]))) {
return val;
}
left = left.replace(/([+-/:;.*(=^><!])[^+-/:;.*(=^><!]*$/, '$1');
right = right.replace(/^[^+-/:;.*^><!)]*([+-/:;.*)^><!]|$)/, '$1');
store.caretPosition = (left + addr).length;
return left + addr + right;
});
} else {
store.select(coord);
store.edit(null);
recalc();
}
return store.changed();
}
});
store.registerCallback('cell-mousedown', function(coord) {
if (!store.editingCoord) {
store.select(coord);
store.changed();
return store.selectingMulti = true;
}
});
store.registerCallback('cell-mouseenter', function(coord) {
var x, y, _i, _j, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _results, _results1;
if (store.selectingMulti) {
store.multi = [store.selectedCoord, coord];
return store.changed();
} else if (store.strapping) {
/*
check if coord is at the same vertical or horizontal
lines of the multi-selection
example:
store.multi = [[3,1], [4,2]]
coord[0] must be within the range 3-4 -> same horizontal line
coord[1] must be within the range 1-2 -> same vertical line
the strapping zone will be described by a tuple of [
direction -> either 0 for 'vertical' or 1 for 'horizontal' (this is
because the first element (0) of any coord array describes
the number of rows, the second (1) describes the number
of columns)
sense -> either 0 for 'left' or 'top' or 1 for 'right' or 'bottom' (
this is because in the normalized store.multi, the first cell (0)
will describe the leftmost and uppermost point, the second cell (1)
will describe the rightmost and bottommost point, which we will
modify accordingly)
magnitude -> an integer describing how many columns/rows ocuppy
the strapping zone beggining where the multi-selection
ends and extending to where the mouse is.
]
*/
if (_ref = coord[0], __indexOf.call((function() {
_results = [];
for (var _i = _ref1 = store.multi[0][0], _ref2 = store.multi[1][0]; _ref1 <= _ref2 ? _i <= _ref2 : _i >= _ref2; _ref1 <= _ref2 ? _i++ : _i--){ _results.push(_i); }
return _results;
}).apply(this), _ref) >= 0) {
/* horizontal
in this case, we must check if the zone will be to the left of the
current selection or to the right, and the magnitude of the vector
example:
store.multi = [[5,2], [3,3]]
we get the minimum of (coord[1] - 3), (coord[1] - 2) if they are positive
and the maximum, if they are negative.
the result will be the magnitude, the sense will be 0
if the result is negative, 1 if it is positive.
*/
x = coord[1] - store.multi[0][1];
y = coord[1] - store.multi[1][1];
if (x > 0) {
store.strapVector = [1, 1, Math.min(x, y)];
} else if (x < 0) {
store.strapVector = [1, 0, Math.max(x, y)];
}
} else if (_ref3 = coord[1], __indexOf.call((function() {
_results1 = [];
for (var _j = _ref4 = store.multi[0][1], _ref5 = store.multi[1][1]; _ref4 <= _ref5 ? _j <= _ref5 : _j >= _ref5; _ref4 <= _ref5 ? _j++ : _j--){ _results1.push(_j); }
return _results1;
}).apply(this), _ref3) >= 0) {
/* vertical
the procedure is analogal with the horizontal.
but instead we use coord[0]
*/
x = coord[0] - store.multi[0][0];
y = coord[0] - store.multi[1][0];
if (x > 0) {
store.strapVector = [0, 1, Math.min(x, y)];
} else if (x < 0) {
store.strapVector = [0, 0, Math.max(x, y)];
}
}
return store.changed();
}
});
store.registerCallback('cell-mouseup', function(coord) {
if (!store.editingCoord) {
store.selectingMulti = false;
if (store.strapping && store.strapVector[1] !== null) {
expandPattern();
store.multi = [utils.firstCellFromMulti(store.multi), utils.lastCellFromMulti(store.multi)];
store.multi[store.strapVector[1]][store.strapVector[0]] += store.strapVector[2];
store.strapping = false;
store.strapVector = [null, null, null];
recalc();
return store.changed();
}
}
});
store.registerCallback('strap-mousedown', function(coord) {
if (!store.editingCoord) {
store.strapping = true;
return store.changed();
}
});
store.registerCallback('cell-doubleclicked', function(coord) {
store.select(coord);
store.edit(coord);
if (!Mori.get_in(store.cells, coord.concat('raw'))) {
store.volatileEdit = true;
}
return store.changed();
});
store.registerCallback('down', function(e) {
e.preventDefault();
if (store.editingCoord) {
store.edit(null);
recalc();
}
if (store.selectedCoord[0] < (Mori.count(store.cells) - 1)) {
store.select([store.selectedCoord[0] + 1, store.selectedCoord[1]]);
}
return store.changed();
});
store.registerCallback('up', function(e) {
e.preventDefault();
if (store.editingCoord) {
store.edit(null);
recalc();
}
if (store.selectedCoord[0] > 0) {
store.select([store.selectedCoord[0] - 1, store.selectedCoord[1]]);
}
return store.changed();
});
store.registerCallback('tab', function(e) {
e.preventDefault();
if (store.editingCoord) {
store.edit(null);
recalc();
}
if (store.selectedCoord[1] === (Mori.count(Mori.get(store.cells, 0)) - 1)) {
if (store.selectedCoord[0] + 1 <= (Mori.count(store.cells) - 1)) {
store.select([store.selectedCoord[0] + 1, 0]);
return store.changed();
}
} else {
return store.triggerCallback('right', e);
}
});
store.registerCallback('left', function(e) {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
if (store.selectedCoord[1] > 0) {
store.select([store.selectedCoord[0], store.selectedCoord[1] - 1]);
}
return store.changed();
}
});
store.registerCallback('right', function(e) {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
if (store.selectedCoord[1] < (Mori.count(Mori.get(store.cells, 0)) - 1)) {
store.select([store.selectedCoord[0], store.selectedCoord[1] + 1]);
}
return store.changed();
}
});
store.registerCallback('all-right', function() {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
store.select([store.selectedCoord[0], Mori.count(Mori.get(store.cells, 0)) - 1]);
}
return store.changed();
});
store.registerCallback('all-down', function() {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
store.select([Mori.count(store.cells) - 1, store.selectedCoord[1]]);
}
return store.changed();
});
store.registerCallback('all-up', function() {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
store.select([0, store.selectedCoord[1]]);
}
return store.changed();
});
store.registerCallback('all-left', function() {
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
store.select([store.selectedCoord[0], 0]);
}
return store.changed();
});
store.registerCallback('select-down', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
if (edge[0] < (Mori.count(store.cells) - 1)) {
store.multi = [store.selectedCoord, [edge[0] + 1, edge[1]]];
}
return store.changed();
}
});
store.registerCallback('select-up', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
if (edge[0] > 0) {
store.multi = [store.selectedCoord, [edge[0] - 1, edge[1]]];
}
return store.changed();
}
});
store.registerCallback('select-left', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
if (edge[1] > 0) {
store.multi = [store.selectedCoord, [edge[0], edge[1] - 1]];
}
return store.changed();
}
});
store.registerCallback('select-right', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
if (edge[1] < (Mori.count(Mori.get(store.cells, 0)) - 1)) {
store.multi = [store.selectedCoord, [edge[0], edge[1] + 1]];
}
return store.changed();
}
});
store.registerCallback('select-all-right', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
store.multi = [store.selectedCoord, [edge[0], Mori.count(Mori.get(store.cells, 0)) - 1]];
}
return store.changed();
});
store.registerCallback('select-all-down', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
store.multi = [store.selectedCoord, [Mori.count(store.cells) - 1, edge[1]]];
}
return store.changed();
});
store.registerCallback('select-all-up', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
store.multi = [store.selectedCoord, [0, edge[1]]];
}
return store.changed();
});
store.registerCallback('select-all-left', function(e) {
var edge;
if (store.volatileEdit) {
store.edit(null);
recalc();
}
if (!store.editingCoord) {
e.preventDefault();
edge = store.multi[1];
store.multi = [store.selectedCoord, [edge[0], 0]];
}
return store.changed();
});
store.registerCallback('del', function() {
var i, j, _i, _j, _ref, _ref1, _ref2, _ref3;
if (!store.editingCoord) {
store.cells = Mori.assoc_in(store.cells, store.selectedCoord.concat('raw'), '');
for (i = _i = _ref = store.multi[0][0], _ref1 = store.multi[1][0]; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = _ref <= _ref1 ? ++_i : --_i) {
for (j = _j = _ref2 = store.multi[0][1], _ref3 = store.multi[1][1]; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; j = _ref2 <= _ref3 ? ++_j : --_j) {
store.cells = Mori.assoc_in(store.cells, [i, j, 'raw'], '');
}
}
recalc();
return store.changed();
}
});
store.registerCallback('letter', function(e) {
if (!store.editingCoord) {
if (e.ctrlKey || e.metaKey || e.altKey) {
return;
}
store.cells = Mori.assoc_in(store.cells, store.selectedCoord.concat('raw'), String.fromCharCode(e.keyCode || e.charCode));
e.preventDefault();
e.stopPropagation();
store.edit(store.selectedCoord);
store.volatileEdit = true;
return store.changed();
}
});
store.registerCallback('esc', function() {
if (store.editingCoord) {
store.edit(null);
store.undo();
return store.changed();
}
});
store.registerCallback('sheet-clicked-out', function() {
store.selectingMulti = false;
store.multi = [store.selectedCoord, store.selectedCoord];
store.strapping = false;
store.strapVector = [null, null, null];
return store.changed();
});
store.registerCallback('sheet-mouseup-out', function() {
return store.selectingMulti = false;
});
store.registerCallback('undo', function(e) {
store.undo();
return store.changed();
});
store.registerCallback('redo', function() {
store.redo();
return store.changed();
});
store.registerCallback('before-copypaste', function(e) {
var clipCells, clipRows, i, j, multiRearranged, _i, _j, _ref, _ref1, _ref2, _ref3;
e.preventDefault();
if (window.getSelection && window.getSelection().toString()) {
return;
}
if (document.selection && document.selection.createRange()) {
return;
}
clipRows = [];
multiRearranged = [utils.firstCellFromMulti(store.multi), utils.lastCellFromMulti(store.multi)];
for (i = _i = _ref = multiRearranged[0][0], _ref1 = multiRearranged[1][0]; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = _ref <= _ref1 ? ++_i : --_i) {
clipCells = [];
for (j = _j = _ref2 = multiRearranged[0][1], _ref3 = multiRearranged[1][1]; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; j = _ref2 <= _ref3 ? ++_j : --_j) {
clipCells.push(Mori.get_in(store.cells, [i, j, 'calc']));
}
clipRows.push(clipCells.join('\t'));
}
store.clipboard = clipRows.join('\n');
return store.changed();
});
store.registerCallback('cutcopy', function(e) {
var clipboard, copied, copiedRows, i, j;
clipboard = document.querySelector('.clipboard-container .clipboard');
if (clipboard) {
copied = [utils.firstCellFromMulti(store.multi), utils.lastCellFromMulti(store.multi)];
copiedRows = (function() {
var _i, _ref, _ref1, _results;
_results = [];
for (i = _i = _ref = copied[0][0], _ref1 = copied[1][0]; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = _ref <= _ref1 ? ++_i : --_i) {
_results.push((function() {
var _j, _ref2, _ref3, _results1;
_results1 = [];
for (j = _j = _ref2 = copied[0][1], _ref3 = copied[1][1]; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; j = _ref2 <= _ref3 ? ++_j : --_j) {
_results1.push(Mori.get_in(store.cells, [i, j, 'raw']));
}
return _results1;
})());
}
return _results;
})();
store.rawClipboard = {};
return store.rawClipboard[selix.getText(clipboard)] = copiedRows;
}
});
store.registerCallback('clipboardchanged', function(what) {
var cell, firstSelected, i, j, pastedCell, pastedRow, pastedRows, qi, qj, row, _i, _j, _k, _l, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
if (what === '') {
for (i = _i = _ref = store.multi[0][0], _ref1 = store.multi[1][0]; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = _ref <= _ref1 ? ++_i : --_i) {
for (j = _j = _ref2 = store.multi[0][1], _ref3 = store.multi[1][1]; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; j = _ref2 <= _ref3 ? ++_j : --_j) {
store.cells = Mori.assoc_in(store.cells, [i, j, 'raw'], '');
}
}
} else {
if (what in store.rawClipboard) {
pastedRows = store.rawClipboard[what];
} else {
pastedRows = (function() {
var _k, _len, _ref4, _results;
_ref4 = what.split('\n');
_results = [];
for (_k = 0, _len = _ref4.length; _k < _len; _k++) {
row = _ref4[_k];
_results.push((function() {
var _l, _len1, _ref5, _results1;
_ref5 = row.split('\t');
_results1 = [];
for (_l = 0, _len1 = _ref5.length; _l < _len1; _l++) {
cell = _ref5[_l];
_results1.push(cell);
}
return _results1;
})());
}
return _results;
})();
}
firstSelected = utils.firstCellFromMulti(store.multi);
for (i = _k = 0, _ref4 = pastedRows.length - 1; 0 <= _ref4 ? _k <= _ref4 : _k >= _ref4; i = 0 <= _ref4 ? ++_k : --_k) {
pastedRow = pastedRows[i];
qi = i + firstSelected[0];
if (qi >= Mori.count(store.cells)) {
continue;
}
for (j = _l = 0, _ref5 = pastedRow.length - 1; 0 <= _ref5 ? _l <= _ref5 : _l >= _ref5; j = 0 <= _ref5 ? ++_l : --_l) {
pastedCell = pastedRow[j];
qj = j + firstSelected[1];
if (qj >= Mori.count(Mori.get(store.cells, 0))) {
continue;
}
store.cells = Mori.assoc_in(store.cells, [qi, qj, 'raw'], pastedCell);
}
}
}
recalc();
return store.changed();
});
store.registerCallback('after-copypaste', function() {
store.clipboard = null;
return store.changed();
});
module.exports = store;
recalc = require('./recalc').recalc;
expandPattern = require('./expand-pattern');