App-SocialCalc-Multiplayer
view release on metacpan or search on metacpan
socialcalc/socialcalctableeditor.js view on Meta::CPAN
this.lastvisiblecol = null; // used for paging right
this.rowpositions = []; // screen positions of the top of some rows
this.colpositions = []; // screen positions of the left side of some rows
this.rowheight = []; // size in pixels of each row when last checked, or null/undefined, for page up
this.colwidth = []; // size in pixels of each column when last checked, or null/undefined, for page left
this.ecell = null; // either null or {coord: c, row: r, col: c}
this.state = "start"; // the keyboard states: see EditorProcessKey
this.workingvalues = {}; // values used during keyboard editing, etc.
// Constants:
this.imageprefix = scc.defaultImagePrefix; // URL prefix for images (e.g., "/images/sc")
this.idPrefix = scc.defaultTableEditorIDPrefix;
this.pageUpDnAmount = scc.defaultPageUpDnAmount; // number of rows to move cursor on PgUp/PgDn keys (numeric)
// Callbacks
// recalcFunction: if present, function(editor) {...}, called to do a recalc
// Default (sheet.RecalcSheet) does all the right stuff.
this.recalcFunction = function(editor) {
if (editor.context.sheetobj.RecalcSheet) {
editor.context.sheetobj.RecalcSheet(SocialCalc.EditorSheetStatusCallback, editor);
}
else return null;
};
// ctrlkeyFunction: if present, function(editor, charname) {...}, called to handle ctrl-V, etc., at top level
// Returns true (pass through for continued processing) or false (stop processing this key).
this.ctrlkeyFunction = function(editor, charname) {
var ta, ha, cell, position, cmd, sel, cliptext;
switch (charname) {
case "[ctrl-c]":
case "[ctrl-x]":
ta = editor.pasteTextarea;
ta.value = "";
cell=SocialCalc.GetEditorCellElement(editor, editor.ecell.row, editor.ecell.col);
if (cell) {
position = SocialCalc.GetElementPosition(cell.element);
ta.style.left = (position.left-1)+"px";
ta.style.top = (position.top-1)+"px";
}
if (editor.range.hasrange) {
sel = SocialCalc.crToCoord(editor.range.left, editor.range.top)+
":"+SocialCalc.crToCoord(editor.range.right, editor.range.bottom);
}
else {
sel = editor.ecell.coord;
}
// get what to copy to clipboard
cliptext = SocialCalc.ConvertSaveToOtherFormat(SocialCalc.CreateSheetSave(editor.context.sheetobj, sel), "tab");
if (charname == "[ctrl-c]" || editor.noEdit) { // if copy or cut but in no edit
cmd = "copy "+sel+" formulas";
}
else { // [ctrl-x]
cmd = "cut "+sel+" formulas";
}
editor.EditorScheduleSheetCommands(cmd, true, false); // queue up command to put on SocialCalc clipboard
/* Copy as HTML: This fails rather badly as it won't paste into Notepad as tab-delimited text. Oh well.
ha = editor.pasteHTMLarea;
if (editor.range.hasrange) {
cell = SocialCalc.GetEditorCellElement(editor, editor.range.top, editor.range.left);
}
else {
cell = SocialCalc.GetEditorCellElement(editor, editor.ecell.row, editor.ecell.col);
}
if (cell) position = SocialCalc.GetElementPosition(cell.element);
if (ha) {
if (position) {
ha.style.left = (position.left-1)+"px";
ha.style.top = (position.top-1)+"px";
}
ha.style.visibility="visible";
cliptext = SocialCalc.ConvertSaveToOtherFormat(SocialCalc.CreateSheetSave(editor.context.sheetobj, sel), "html");
ha.innerHTML = cliptext.replace(/<tr\b[^>]*>[\d\D]*?<\/tr\b[^>]*>/i, '');
ha.focus();
var range = document.body.createControlRange();
range.addElement(ha.childNodes[0]);
range.select();
}
*/
ta.style.display = "block";
ta.value = cliptext; // must follow "block" setting for Webkit
ta.focus();
ta.select();
window.setTimeout(function() {
if (!SocialCalc.GetSpreadsheetControlObject) return; // in case not loaded
var s = SocialCalc.GetSpreadsheetControlObject();
if (!s) return;
var editor = s.editor;
/*
var ha = editor.pasteHTMLarea;
if (ha) {
ha.blur();
ha.innerHTML = '';
ha.style.visibility = 'hidden';
}
*/
var ta = editor.pasteTextarea;
ta.blur();
ta.style.display = "none";
SocialCalc.KeyboardFocus();
}, 200);
return true;
case "[ctrl-v]":
if (editor.noEdit) return true; // not if no edit
var showPasteTextArea = function() {
ta = editor.pasteTextarea;
ta.value = "";
socialcalc/socialcalctableeditor.js view on Meta::CPAN
var isPasteSameAsClipboard = false;
ha = editor.pasteHTMLarea;
if (ha) {
/* IE: We append a U+FFFC to every TD that's not the last of its row,
* then we obtain innerText, then turn U+FFFC back to \t,
* thereby preserving the cell separations (which gets discarded
* if we simply paste via textarea.
*/
var _ObjectReplacementCharacter_ = String.fromCharCode(0xFFFC);
var html = ha.innerHTML;
if (html.search(/<(?![Bb][Rr])[A-Za-z]/) >= 0) {
/* HTML Paste: Mark TDs with U+FFFC accordingly.. */
ha.innerHTML = html.replace(
/(?:<\/[Tt][Dd]>)/g,
_ObjectReplacementCharacter_
);
}
else {
/* Text Paste: In IE, \t is transformed into , so replace them with U+FFFC. */
ha.innerHTML = html.replace(
/&[Nn][Bb][Ss][Pp];/g,
_ObjectReplacementCharacter_
);
}
value = ha.innerText.replace(new RegExp(_ObjectReplacementCharacter_, 'g'), '\t');
ha.innerHTML = '';
ha.blur();
ha.style.visibility = "hidden";
}
else {
var ta = editor.pasteTextarea;
value = ta.value;
ta.blur();
ta.style.display = "none";
}
value = value.replace(/\r\n/g, "\n").replace(/\n?$/, '\n');
var clipstr = SocialCalc.ConvertSaveToOtherFormat(SocialCalc.Clipboard.clipboard, "tab");
if (value == clipstr || (value.length-clipstr.length==1 && value.substring(0,value.length-1)==clipstr)) {
isPasteSameAsClipboard = true;
}
var cmd = "";
// pastes SocialCalc clipboard if did a Ctrl-C and contents still the same
// Webkit adds an extra blank line, so need to allow for that
if (!isPasteSameAsClipboard) {
cmd = "loadclipboard "+
SocialCalc.encodeForSave(SocialCalc.ConvertOtherFormatToSave(value, "tab")) + "\n";
}
var cr;
if (editor.range.hasrange) {
cr = SocialCalc.crToCoord(editor.range.left, editor.range.top);
}
else {
cr = editor.ecell.coord;
}
cmd += "paste "+cr+" formulas";
editor.EditorScheduleSheetCommands(cmd, true, false);
SocialCalc.KeyboardFocus();
}, 200);
return true;
case "[ctrl-z]":
editor.EditorScheduleSheetCommands("undo", true, false);
return false;
case "[ctrl-s]": // !!!! temporary hack
window.setTimeout(
function() {
if (!SocialCalc.GetSpreadsheetControlObject) return;
var s = SocialCalc.GetSpreadsheetControlObject();
if (!s) return;
var editor = s.editor;
var sheet = editor.context.sheetobj;
var cell = sheet.GetAssuredCell(editor.ecell.coord);
var ntvf = cell.nontextvalueformat ? sheet.valueformats[cell.nontextvalueformat-0] || "" : "";
var newntvf = window.prompt("Advanced Feature:\n\nCustom Numeric Format or Command", ntvf);
if (newntvf != null) { // not cancelled
if (newntvf.match(/^cmd:/)) {
cmd = newntvf.substring(4); // execute as command
}
else if (newntvf.match(/^edit:/)) {
cmd = newntvf.substring(5); // execute as command
if (SocialCalc.CtrlSEditor) {
SocialCalc.CtrlSEditor(cmd);
}
return;
}
else {
if (editor.range.hasrange) {
sel = SocialCalc.crToCoord(editor.range.left, editor.range.top)+
":"+SocialCalc.crToCoord(editor.range.right, editor.range.bottom);
}
else {
sel = editor.ecell.coord;
}
cmd = "set "+sel+" nontextvalueformat "+newntvf;
}
editor.EditorScheduleSheetCommands(cmd, true, false);
}
},
200);
return false;
default:
break;
}
return true;
};
// Set sheet's status callback:
context.sheetobj.statuscallback = SocialCalc.EditorSheetStatusCallback;
context.sheetobj.statuscallbackparams = this; // this object: the table editor object
// StatusCallback: all values are called at appropriate times, add with unique name, delete when done
socialcalc/socialcalctableeditor.js view on Meta::CPAN
var wval = editor.workingvalues;
if (editor.noEdit) return;
switch (editor.state) {
case "start":
editor.state = "input";
editor.inputBox.ShowInputBox(true);
editor.inputBox.element.disabled = false; // make sure editable and overwrite old
editor.inputBox.Focus();
editor.inputBox.SetText((prefix||"")+str);
editor.inputBox.Select("end");
wval.partialexpr = "";
wval.ecoord = editor.ecell.coord;
wval.erow = editor.ecell.row;
wval.ecol = editor.ecell.col;
editor.RangeRemove();
break;
case "input":
case "inputboxdirect":
editor.inputBox.element.focus();
if (wval.partialexpr) {
editor.inputBox.SetText(wval.partialexpr);
wval.partialexpr = "";
editor.RangeRemove();
editor.MoveECell(wval.ecoord);
}
editor.inputBox.SetText(editor.inputBox.GetText()+str);
break;
default:
break;
}
}
SocialCalc.EditorDisplayCellContents = function(editor) {
if (editor.inputBox) editor.inputBox.DisplayCellContents();
}
SocialCalc.EditorSaveEdit = function(editor, text) {
var result, cell, valueinfo, fch, type, value, oldvalue, cmdline;
var sheetobj = editor.context.sheetobj;
var wval = editor.workingvalues;
type = "text t";
value = typeof text == "string" ? text : editor.inputBox.GetText(); // either explicit or from input box
oldvalue = SocialCalc.GetCellContents(sheetobj, wval.ecoord)+"";
if (value == oldvalue) { // no change
return;
}
fch = value.charAt(0);
if (fch=="=" && value.indexOf("\n")==-1) {
type = "formula";
value = value.substring(1);
}
else if (fch=="'") {
type = "text t";
value = value.substring(1);
}
else if (value.length==0) {
type = "empty";
}
else {
valueinfo = SocialCalc.DetermineValueType(value)
if (valueinfo.type=="n" && value==(valueinfo.value+"")) { // see if don't need "constant"
type = "value n";
}
else if (valueinfo.type.charAt(0)=="t") {
type = "text "+valueinfo.type;
}
else if (valueinfo.type=="") {
type = "text t";
}
else {
type = "constant "+valueinfo.type+" "+valueinfo.value;
}
}
if (type.charAt(0)=="t") { // text
value = SocialCalc.encodeForSave(value); // newlines, :, and \ are escaped
}
cmdline = "set "+wval.ecoord+" "+type+" "+value;
editor.EditorScheduleSheetCommands(cmdline, true, false);
return;
}
//
// SocialCalc.EditorApplySetCommandsToRange(editor, cmd)
//
// Takes ecell or range and does a "set" command with cmd.
//
SocialCalc.EditorApplySetCommandsToRange = function(editor, cmd) {
var cell, row, col, line, errortext;
var sheetobj = editor.context.sheetobj;
var ecell = editor.ecell;
var range = editor.range;
if (range.hasrange) {
coord = SocialCalc.crToCoord(range.left, range.top)+":"+SocialCalc.crToCoord(range.right, range.bottom);
line = "set "+coord+" "+cmd;
errortext = editor.EditorScheduleSheetCommands(line, true, false);
}
else {
line = "set "+ecell.coord+" "+cmd;
errortext = editor.EditorScheduleSheetCommands(line, true, false);
}
socialcalc/socialcalctableeditor.js view on Meta::CPAN
newrownum=context.rowpanes[rowpane].first;
for (colpane=0; colpane<context.colpanes.length; colpane++) {
for (colnum=context.colpanes[colpane].first; colnum<=context.colpanes[colpane].last; colnum++) {
coord=SocialCalc.crToCoord(colnum, newrownum);
if (context.cellskip[coord]) continue;
cell=sheetobj.cells[coord];
if (cell && cell.rowspan>maxrowspan) maxrowspan=cell.rowspan;
}
}
if (maxrowspan>1) {
for (rownum=1; rownum<maxrowspan; rownum++) {
if (rownum+newrownum > context.rowpanes[rowpane].last) break;
newrow=context.RenderRow(rownum+newrownum, rowpane);
oldchild=tbodyobj.childNodes[toprow+rownum];
tbodyobj.replaceChild(newrow,oldchild);
}
}
// if last row now includes rowspans or rowspans from above, update the size of those to remove deleted row
bottomrownum=context.rowpanes[rowpane].last;
for (colpane=0; colpane<context.colpanes.length; colpane++) {
for (colnum=context.colpanes[colpane].first; colnum<=context.colpanes[colpane].last; colnum++) {
coord=SocialCalc.crToCoord(colnum, bottomrownum);
cell=sheetobj.cells[coord];
if (cell && cell.rowspan>1) {
rowneedsrefresh[bottomrownum]=true; // need to update this row
continue;
}
coord=context.cellskip[SocialCalc.crToCoord(colnum, bottomrownum)];
if (!coord) continue; // only look at spanned cells
rownum=context.coordToCR[coord].row-0;
if (rownum==bottomrownum ||
rownum<context.rowpanes[rowpane].first) continue; // this row (colspan) or starts above pane
cell=sheetobj.cells[coord];
if (cell && cell.rowspan>1) rowneedsrefresh[rownum]=true; // remember row num to update
}
}
for (rownum in rowneedsrefresh) {
newrow=context.RenderRow(rownum, rowpane);
oldchild=tbodyobj.childNodes[(toprow+(rownum-context.rowpanes[rowpane].first))];
tbodyobj.replaceChild(newrow,oldchild);
}
return tableobj;
}
// *************************************
//
// InputBox class:
//
// This class deals with the text box for editing cell contents.
// It mainly controls a user input box for typed content and is used to interact with
// the keyboard code, etc.
//
// You can use this inside a formula bar control of some sort.
// You create this after you have created a table editor object (but not necessarily
// done the CreateTableEditor method).
//
// When the user starts typing text, or double-clicks on a cell, this object
// comes into play.
//
// The element given when this is first constructed should be an input HTMLElement or
// something that acts like one. Check the code here to see what is done to it.
//
// *************************************
SocialCalc.InputBox = function(element, editor) {
if (!element) return; // invoked without enough data to work
this.element = element; // the input element associated with this InputBox
this.editor = editor; // the TableEditor this belongs to
this.inputEcho = null;
editor.inputBox = this;
element.onmousedown = SocialCalc.InputBoxOnMouseDown;
editor.MoveECellCallback.formulabar = function(e){
if (e.state!="start") return; // if not in normal keyboard mode don't replace formula bar
editor.inputBox.DisplayCellContents(e.ecell.coord);
};
}
// Methods:
SocialCalc.InputBox.prototype.DisplayCellContents = function(coord) {SocialCalc.InputBoxDisplayCellContents(this, coord);};
SocialCalc.InputBox.prototype.ShowInputBox = function(show) {this.editor.inputEcho.ShowInputEcho(show);};
SocialCalc.InputBox.prototype.GetText = function() {return this.element.value;};
SocialCalc.InputBox.prototype.SetText = function(newtext) {
if (!this.element) return;
this.element.value=newtext;
this.editor.inputEcho.SetText(newtext+"_");
};
SocialCalc.InputBox.prototype.Focus = function() {SocialCalc.InputBoxFocus(this);};
SocialCalc.InputBox.prototype.Blur = function() {return this.element.blur();};
SocialCalc.InputBox.prototype.Select = function(t) {
if (!this.element) return;
switch (t) {
case "end":
if (document.selection && document.selection.createRange) {
/* IE 4+ - Safer than setting .selectionEnd as it also works for Textareas. */
var range = document.selection.createRange().duplicate();
range.moveToElementText(this.element);
range.collapse(false);
range.select();
} else if (this.element.selectionStart!=undefined) {
this.element.selectionStart=this.element.value.length;
this.element.selectionEnd=this.element.value.length;
}
break;
}
};
// Functions:
//
// SocialCalc.InputBoxDisplayCellContents(inputbox, coord)
//
// Sets input box to the contents of the specified cell (or ecell if null).
//
SocialCalc.InputBoxDisplayCellContents = function(inputbox, coord) {
var scc = SocialCalc.Constants;
if (!inputbox) return;
if (!coord) coord = inputbox.editor.ecell.coord;
var text = SocialCalc.GetCellContents(inputbox.editor.context.sheetobj, coord);
if (text.indexOf("\n")!=-1) {
text = scc.s_inputboxdisplaymultilinetext;
inputbox.element.disabled = true;
}
else {
inputbox.element.disabled = false;
}
inputbox.SetText(text);
}
socialcalc/socialcalctableeditor.js view on Meta::CPAN
}
newcoord = SocialCalc.crToCoord(crend.col, crend.row);
if (newcoord!=mouseinfo.mouselastcoord) {
editor.MoveECell(newcoord);
c = editor.range2.right - editor.range2.left + crend.col;
r = editor.range2.bottom - editor.range2.top + crend.row;
editor.RangeAnchor(SocialCalc.crToCoord(c, r));
editor.RangeExtend();
}
break;
}
mouseinfo.mouselastcoord = newcoord;
}
SocialCalc.CellHandlesMouseUp = function(e) {
var editor, element, result, coord, now, textarea, sheetobj, cellobj, wval, cstr, cmdtype, cmdtype2;
var crstart, crend;
var sizec, sizer, deltac, deltar;
var event = e || window.event;
var viewport = SocialCalc.GetViewportInfo();
var clientX = event.clientX + viewport.horizontalScroll;
var clientY = event.clientY + viewport.verticalScroll;
var mouseinfo = SocialCalc.EditorMouseInfo;
editor = mouseinfo.editor;
if (!editor) return; // not us, ignore
var cellhandles = editor.cellhandles;
element = mouseinfo.element;
mouseinfo.ignore = false;
result = SocialCalc.GridMousePosition(editor, clientX, clientY); // get cell with up
SocialCalc.SetDragAutoRepeat(editor, null); // stop repeating if it was
cellhandles.mouseDown = false;
cellhandles.noCursorSuffix = false;
cellhandles.fillinghandle.style.display = "none";
if (!result) result = {};
if (!result.coord) result.coord = editor.ecell.coord;
switch (cellhandles.dragtype) {
case "Fill":
case "Move":
case "MoveI":
cmdtype2 = " all";
break;
case "FillC":
case "MoveC":
case "MoveIC":
cmdtype2 = " formulas";
break;
}
if (!cellhandles.movedmouse) { // didn't move: just leave one cell selected
cellhandles.dragtype = "Nothing";
}
switch (cellhandles.dragtype) {
case "Nothing":
editor.Range2Remove();
editor.RangeRemove();
break;
case "Fill":
case "FillC":
crstart = SocialCalc.coordToCr(cellhandles.startingcoord);
crend = SocialCalc.coordToCr(result.coord);
if (cellhandles.filltype) {
if (cellhandles.filltype=="Down") {
crend.col = crstart.col;
}
else {
crend.row = crstart.row;
}
}
result.coord = SocialCalc.crToCoord(crend.col, crend.row);
editor.MoveECell(result.coord);
editor.RangeExtend();
if (editor.cellhandles.filltype=="Right") {
cmdtype = "right";
}
else {
cmdtype = "down";
}
cstr = "fill"+cmdtype+" "+SocialCalc.crToCoord(editor.range.left, editor.range.top)+
":"+SocialCalc.crToCoord(editor.range.right, editor.range.bottom)+cmdtype2;
editor.EditorScheduleSheetCommands(cstr, true, false);
break;
case "Move":
case "MoveC":
editor.context.cursorsuffix = "";
cstr = "movepaste "+
SocialCalc.crToCoord(editor.range2.left, editor.range2.top) + ":" +
SocialCalc.crToCoord(editor.range2.right, editor.range2.bottom)
+" "+editor.ecell.coord+cmdtype2;
editor.EditorScheduleSheetCommands(cstr, true, false);
editor.Range2Remove();
break;
case "MoveI":
case "MoveIC":
editor.context.cursorsuffix = "";
sizec = editor.range2.right - editor.range2.left;
sizer = editor.range2.bottom - editor.range2.top;
deltac = editor.ecell.col - editor.range2.left;
( run in 3.645 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )