App-SocialCalc-Multiplayer
view release on metacpan or search on metacpan
socialcalc/socialcalc-3.js view on Meta::CPAN
// Callbacks
SocialCalc.Callbacks = {
// The next two are used by SocialCalc.format_text_for_display
// The function to expand wiki text - should be set if you want wikitext expansion
// The form is: expand_wiki(displayvalue, sheetobj, linkstyle, valueformat)
// valueformat is text-wiki followed by optional sub-formats, e.g., text-wikipagelink
expand_wiki: null,
expand_markup: function(displayvalue, sheetobj, linkstyle) // the old function to expand wiki text - may be replaced
{return SocialCalc.default_expand_markup(displayvalue, sheetobj, linkstyle);},
// MakePageLink is used to create the href for a link to another "page"
// The form is: MakePageLink(pagename, workspacename, linktyle, valueformat), returns string
MakePageLink: null,
// NormalizeSheetName is used to make different variations of sheetnames use the same cache slot
NormalizeSheetName: null // use default - lowercase
};
// Shared flags
// none at present
// *************************************
//
// Cell class:
//
// *************************************
//
// Class SocialCalc.Cell
//
// Usage: var s = new SocialCalc.Cell(coord);
//
// Cell attributes include:
//
// coord: the column/row as a string, e.g., "A1"
// datavalue: the value to be used for computation and formatting for display,
// string or numeric (tolerant of numbers stored as strings)
// datatype: if present, v=numeric value, t=text value, f=formula,
// or c=constant that is not a simple number (like "$1.20")
// formula: if present, the formula (without leading "=") for computation or the constant
// valuetype: first char is main type, the following are sub-types.
// Main types are b=blank cell, n=numeric, t=text, e=error
// Examples of using sub-types would be "nt" for a numeric time value, "n$" for currency, "nl" for logical
// displayvalue: if present, rendered version of datavalue with formatting attributes applied
// parseinfo: if present, cached parsed version of formula
//
// The following optional values, if present, are mainly used in rendering, overriding defaults:
//
// bt, br, bb, bl: number of border's definition
// layout: layout (vertical alignment, padding) definition number
// font: font definition number
// color: text color definition number
// bgcolor: background color definition number
// cellformat: cell format (horizontal alignment) definition number
// nontextvalueformat: custom format definition number for non-text values, e.g., numbers
// textvalueformat: custom format definition number for text values
// colspan, rowspan: number of cells to span for merged cells (only on main cell)
// cssc: custom css classname for cell, as text (no special chars)
// csss: custom css style definition
// mod: modification allowed flag "y" if present
// comment: cell comment string
//
SocialCalc.Cell = function(coord) {
this.coord = coord;
this.datavalue = "";
this.datatype = null;
this.formula = "";
this.valuetype = "b";
}
// The types of cell properties
//
// Type 1: Base, Type 2: Attribute, Type 3: Special (e.g., displaystring, parseinfo)
SocialCalc.CellProperties = {
coord: 1, datavalue: 1, datatype: 1, formula: 1, valuetype: 1, errors: 1, comment: 1,
bt: 2, br: 2, bb: 2, bl: 2, layout: 2, font: 2, color: 2, bgcolor: 2,
cellformat: 2, nontextvalueformat: 2, textvalueformat: 2, colspan: 2, rowspan: 2,
cssc: 2, csss: 2, mod: 2,
displaystring: 3, // used to cache rendered HTML of cell contents
parseinfo: 3, // used to cache parsed formulas
hcolspan: 3, hrowspan: 3 // spans taking hidden cols/rows into account (!!! NOT YET !!!)
};
SocialCalc.CellPropertiesTable = {
bt: "borderstyle", br: "borderstyle", bb: "borderstyle", bl: "borderstyle",
layout: "layout", font: "font", color: "color", bgcolor: "color",
cellformat: "cellformat", nontextvalueformat: "valueformat", textvalueformat: "valueformat"
};
// *************************************
//
// Sheet class:
//
// *************************************
//
// Class SocialCalc.Sheet
//
// Usage: var s = new SocialCalc.Sheet();
//
SocialCalc.Sheet = function() {
SocialCalc.ResetSheet(this);
// Set other values:
//
// sheet.statuscallback(data, status, arg, this.statuscallbackparams) is called
// during recalc and commands.
//
// During recalc, data is the current recalcdata.
// The values for status and the corresponding arg are:
//
// calcorder, {coord: coord, total: celllist length, count: count} [0 or more times per recalc]
// calccheckdone, calclist length [once per recalc]
// calcstep, {coord: coord, total: calclist length, count: count} [0 or more times per recalc]
// calcloading, {sheetname: name-of-sheet}
// calcserverfunc, {funcname: name-of-function, coord: coord, total: calclist length, count: count}
// calcfinished, time in milliseconds [once per recalc]
//
// During commands, data is SocialCalc.SheetCommandInfo.
// These values for status and arg are:
//
// cmdstart, cmdstr
// cmdend
//
this.statuscallback = null; // routine called with cmdstart, calcstart, etc., status and args:
// sheet.statuscallback(data, status, arg, params)
this.statuscallbackparams = null; // parameters passed to that routine
}
//
// SocialCalc.ResetSheet(sheet)
//
// Resets (and/or initializes) sheet data values.
//
SocialCalc.ResetSheet = function(sheet, reload) {
// properties:
sheet.cells = {}; // at least one for each non-blank cell: coord: cell-object
sheet.attribs = // sheet attributes
{
lastcol: 1,
lastrow: 1,
defaultlayout: 0
};
sheet.rowattribs =
{
hide: {}, // access by row number
height: {}
};
sheet.colattribs =
{
width: {}, // access by col name
hide: {}
};
sheet.names={}; // Each is: {desc: "optional description", definition: "B5, A1:B7, or =formula"}
sheet.layouts=[];
sheet.layouthash={};
sheet.fonts=[];
sheet.fonthash={};
sheet.colors=[];
sheet.colorhash={};
sheet.borderstyles=[];
sheet.borderstylehash={};
sheet.cellformats=[];
sheet.cellformathash={};
sheet.valueformats=[];
sheet.valueformathash={};
sheet.copiedfrom = ""; // if a range, then this was loaded from a saved range as clipboard content
sheet.changes = new SocialCalc.UndoStack();
sheet.renderneeded = false;
sheet.changedrendervalues = true; // if true, spans and/or fonts have changed (set by ExecuteSheetCommand & GetStyle)
sheet.recalcchangedavalue = false; // true if a recalc resulted in a change to a cell's calculated value
}
// Methods:
SocialCalc.Sheet.prototype.ResetSheet = function() {SocialCalc.ResetSheet(this);};
SocialCalc.Sheet.prototype.AddCell = function(newcell) {return this.cells[newcell.coord]=newcell;};
SocialCalc.Sheet.prototype.GetAssuredCell = function(coord) {
return this.cells[coord] || this.AddCell(new SocialCalc.Cell(coord));
};
SocialCalc.Sheet.prototype.ParseSheetSave = function(savedsheet) {SocialCalc.ParseSheetSave(savedsheet,this);};
SocialCalc.Sheet.prototype.CellFromStringParts = function(cell, parts, j) {return SocialCalc.CellFromStringParts(this, cell, parts, j);};
SocialCalc.Sheet.prototype.CreateSheetSave = function(range, canonicalize) {return SocialCalc.CreateSheetSave(this, range, canonicalize);};
SocialCalc.Sheet.prototype.CellToString = function(cell) {return SocialCalc.CellToString(this, cell);};
SocialCalc.Sheet.prototype.CanonicalizeSheet = function(full) {return SocialCalc.CanonicalizeSheet(this, full);};
SocialCalc.Sheet.prototype.EncodeCellAttributes = function(coord) {return SocialCalc.EncodeCellAttributes(this, coord);};
SocialCalc.Sheet.prototype.EncodeSheetAttributes = function() {return SocialCalc.EncodeSheetAttributes(this);};
SocialCalc.Sheet.prototype.DecodeCellAttributes = function(coord, attribs, range) {return SocialCalc.DecodeCellAttributes(this, coord, attribs, range);};
SocialCalc.Sheet.prototype.DecodeSheetAttributes = function(attribs) {return SocialCalc.DecodeSheetAttributes(this, attribs);};
SocialCalc.Sheet.prototype.ScheduleSheetCommands = function(cmd, saveundo, isRemote) {return SocialCalc.ScheduleSheetCommands(this, cmd, saveundo, isRemote);};
SocialCalc.Sheet.prototype.SheetUndo = function() {return SocialCalc.SheetUndo(this);};
SocialCalc.Sheet.prototype.SheetRedo = function() {return SocialCalc.SheetRedo(this);};
SocialCalc.Sheet.prototype.CreateAuditString = function() {return SocialCalc.CreateAuditString(this);};
SocialCalc.Sheet.prototype.GetStyleNum = function(atype, style) {return SocialCalc.GetStyleNum(this, atype, style);};
SocialCalc.Sheet.prototype.GetStyleString = function(atype, num) {return SocialCalc.GetStyleString(this, atype, num);};
SocialCalc.Sheet.prototype.RecalcSheet = function() {return SocialCalc.RecalcSheet(this);};
//
// Sheet save format:
//
// linetype:param1:param2:...
//
// Linetypes are:
//
// version:versionname - version of this format. Currently 1.4.
//
// cell:coord:type:value...:type:value... - Types are as follows:
//
// v:value - straight numeric value
// t:value - straight text/wiki-text in cell, encoded to handle \, :, newlines
// vt:fulltype:value - value with value type/subtype
// vtf:fulltype:value:formulatext - formula resulting in value with value type/subtype, value and text encoded
// vtc:fulltype:value:valuetext - formatted text constant resulting in value with value type/subtype, value and text encoded
// vf:fvalue:formulatext - formula resulting in value, value and text encoded (obsolete: only pre format version 1.1)
// fvalue - first char is "N" for numeric value, "T" for text value, "H" for HTML value, rest is the value
// e:errortext - Error text. Non-blank means formula parsing/calculation results in error.
// b:topborder#:rightborder#:bottomborder#:leftborder# - border# in sheet border list or blank if none
// l:layout# - number in cell layout list
// f:font# - number in sheet fonts list
// c:color# - sheet color list index for text
// bg:color# - sheet color list index for background color
// cf:format# - sheet cell format number for explicit format (align:left, etc.)
// cvf:valueformat# - sheet cell value format number (obsolete: only pre format v1.2)
// tvf:valueformat# - sheet cell text value format number
// ntvf:valueformat# - sheet cell non-text value format number
// colspan:numcols - number of columns spanned in merged cell
// rowspan:numrows - number of rows spanned in merged cell
// cssc:classname - name of CSS class to be used for cell when published instead of one calculated here
// csss:styletext - explicit CSS style information, encoded to handle :, etc.
// mod:allow - if "y" allow modification of cell for live "view" recalc
// comment:value - encoded text of comment for this cell (added in v1.5)
//
// col:
// w:widthval - number, "auto" (no width in <col> tag), number%, or blank (use default)
// hide: - yes/no, no is assumed if missing
// row:
// hide - yes/no, no is assumed if missing
//
// sheet:
// c:lastcol - number
// r:lastrow - number
// w:defaultcolwidth - number, "auto", number%, or blank (default->80)
// h:defaultrowheight - not used
// tf:format# - cell format number for sheet default for text values
// ntf:format# - cell format number for sheet default for non-text values (i.e., numbers)
// layout:layout# - default cell layout number in cell layout list
// font:font# - default font number in sheet font list
// vf:valueformat# - default number value format number in sheet valueformat list (obsolete: only pre format version 1.2)
// ntvf:valueformat# - default non-text (number) value format number in sheet valueformat list
// tvf:valueformat# - default text value format number in sheet valueformat list
// color:color# - default number for text color in sheet color list
// bgcolor:color# - default number for background color in sheet color list
// circularreferencecell:coord - cell coord with a circular reference
// recalc:value - on/off (on is default). If not "off", appropriate changes to the sheet cause a recalc
// needsrecalc:value - yes/no (no is default). If "yes", formula values are not up to date
//
// name:name:description:value - name definition, name in uppercase, with value being "B5", "A1:B7", or "=formula";
// description and value are encoded.
// font:fontnum:value - text of font definition (style weight size family) for font fontnum
// "*" for "style weight", size, or family, means use default (first look to sheet, then builtin)
// color:colornum:rgbvalue - text of color definition (e.g., rgb(255,255,255)) for color colornum
// border:bordernum:value - text of border definition (thickness style color) for border bordernum
// layout:layoutnum:value - text of vertical alignment and padding style for cell layout layoutnum (* for default):
// vertical-alignment:vavalue;padding:topval rightval bottomval leftval;
// cellformat:cformatnum:value - text of cell alignment (left/center/right) for cellformat cformatnum
// valueformat:vformatnum:value - text of number format (see FormatValueForDisplay) for valueformat vformatnum (changed in v1.2)
// clipboardrange:upperleftcoord:bottomrightcoord - ignored -- from wikiCalc
// clipboard:coord:type:value:... - ignored -- from wikiCalc
//
// If this is clipboard contents, then there is also information to facilitate pasting:
//
// copiedfrom:upperleftcoord:bottomrightcoord - range from which this was copied
//
// Functions:
SocialCalc.ParseSheetSave = function(savedsheet,sheetobj) {
var lines=savedsheet.split(/\r\n|\n/);
var parts=[];
var line;
var i, j, t, v, coord, cell, attribs, name;
var scc = SocialCalc.Constants;
for (i=0;i<lines.length;i++) {
line=lines[i];
parts = line.split(":");
switch (parts[0]) {
case "cell":
cell=sheetobj.GetAssuredCell(parts[1]);
j=2;
sheetobj.CellFromStringParts(cell, parts, j);
break;
case "col":
coord=parts[1];
j=2;
while (t=parts[j++]) {
switch (t) {
case "w":
sheetobj.colattribs.width[coord]=parts[j++]; // must be text - could be auto or %, etc.
break;
case "hide":
sheetobj.colattribs.hide[coord]=parts[j++];
break;
default:
throw scc.s_pssUnknownColType+" '"+t+"'";
break;
}
}
break;
case "row":
coord=parts[1]-0;
j=2;
while (t=parts[j++]) {
switch (t) {
case "h":
sheetobj.rowattribs.height[coord]=parts[j++]-0;
break;
case "hide":
sheetobj.rowattribs.hide[coord]=parts[j++];
break;
default:
throw scc.s_pssUnknownRowType+" '"+t+"'";
break;
}
}
break;
case "sheet":
attribs=sheetobj.attribs;
j=1;
while (t=parts[j++]) {
switch (t) {
case "c":
attribs.lastcol=parts[j++]-0;
break;
case "r":
attribs.lastrow=parts[j++]-0;
break;
case "w":
attribs.defaultcolwidth=parts[j++]+"";
break;
case "h":
attribs.defaultrowheight=parts[j++]-0;
break;
case "tf":
attribs.defaulttextformat=parts[j++]-0;
break;
case "ntf":
attribs.defaultnontextformat=parts[j++]-0;
break;
case "layout":
attribs.defaultlayout=parts[j++]-0;
break;
case "font":
attribs.defaultfont=parts[j++]-0;
break;
case "tvf":
attribs.defaulttextvalueformat=parts[j++]-0;
break;
case "ntvf":
attribs.defaultnontextvalueformat=parts[j++]-0;
break;
case "color":
attribs.defaultcolor=parts[j++]-0;
break;
case "bgcolor":
attribs.defaultbgcolor=parts[j++]-0;
break;
case "circularreferencecell":
attribs.circularreferencecell=parts[j++];
break;
case "recalc":
attribs.recalc=parts[j++];
break;
case "needsrecalc":
attribs.needsrecalc=parts[j++];
break;
default:
j+=1;
break;
}
}
break;
case "name":
name = SocialCalc.decodeFromSave(parts[1]).toUpperCase();
sheetobj.names[name] = {desc: SocialCalc.decodeFromSave(parts[2])};
sheetobj.names[name].definition = SocialCalc.decodeFromSave(parts[3]);
break;
case "layout":
parts=lines[i].match(/^layout\:(\d+)\:(.+)$/); // layouts can have ":" in them
sheetobj.layouts[parts[1]-0]=parts[2];
sheetobj.layouthash[parts[2]]=parts[1]-0;
break;
case "font":
sheetobj.fonts[parts[1]-0]=parts[2];
sheetobj.fonthash[parts[2]]=parts[1]-0;
break;
case "color":
sheetobj.colors[parts[1]-0]=parts[2];
sheetobj.colorhash[parts[2]]=parts[1]-0;
break;
case "border":
sheetobj.borderstyles[parts[1]-0]=parts[2];
sheetobj.borderstylehash[parts[2]]=parts[1]-0;
break;
case "cellformat":
v=SocialCalc.decodeFromSave(parts[2]);
sheetobj.cellformats[parts[1]-0]=v;
sheetobj.cellformathash[v]=parts[1]-0;
break;
case "valueformat":
v=SocialCalc.decodeFromSave(parts[2]);
sheetobj.valueformats[parts[1]-0]=v;
sheetobj.valueformathash[v]=parts[1]-0;
break;
case "version":
break;
case "copiedfrom":
sheetobj.copiedfrom = parts[1]+":"+parts[2];
break;
case "clipboardrange": // in save versions up to 1.3. Ignored.
case "clipboard":
break;
case "":
break;
default:
alert(scc.s_pssUnknownLineType+" '"+parts[0]+"'");
throw scc.s_pssUnknownLineType+" '"+parts[0]+"'";
break;
}
parts = null;
}
}
//
// SocialCalc.CellFromStringParts(sheet, cell, parts, j)
//
// Takes string that has been split by ":" in parts, starting at item j,
// and fills in cell assuming save format.
//
SocialCalc.CellFromStringParts = function(sheet, cell, parts, j) {
var cell, t, v;
while (t=parts[j++]) {
switch (t) {
case "v":
cell.datavalue=SocialCalc.decodeFromSave(parts[j++])-0;
cell.datatype="v";
cell.valuetype="n";
break;
case "t":
cell.datavalue=SocialCalc.decodeFromSave(parts[j++]);
cell.datatype="t";
cell.valuetype=SocialCalc.Constants.textdatadefaulttype;
break;
case "vt":
v=parts[j++];
cell.valuetype=v;
if (v.charAt(0)=="n") {
cell.datatype="v";
cell.datavalue=SocialCalc.decodeFromSave(parts[j++])-0;
}
else {
cell.datatype="t";
cell.datavalue=SocialCalc.decodeFromSave(parts[j++]);
}
break;
case "vtf":
v=parts[j++];
cell.valuetype=v;
if (v.charAt(0)=="n") {
cell.datavalue=SocialCalc.decodeFromSave(parts[j++])-0;
}
else {
cell.datavalue=SocialCalc.decodeFromSave(parts[j++]);
}
cell.formula=SocialCalc.decodeFromSave(parts[j++]);
cell.datatype="f";
break;
case "vtc":
v=parts[j++];
cell.valuetype=v;
if (v.charAt(0)=="n") {
cell.datavalue=SocialCalc.decodeFromSave(parts[j++])-0;
}
else {
cell.datavalue=SocialCalc.decodeFromSave(parts[j++]);
}
cell.formula=SocialCalc.decodeFromSave(parts[j++]);
cell.datatype="c";
break;
case "e":
cell.errors=SocialCalc.decodeFromSave(parts[j++]);
break;
case "b":
cell.bt=parts[j++]-0;
cell.br=parts[j++]-0;
cell.bb=parts[j++]-0;
cell.bl=parts[j++]-0;
break;
case "l":
cell.layout=parts[j++]-0;
break;
case "f":
cell.font=parts[j++]-0;
break;
case "c":
cell.color=parts[j++]-0;
break;
case "bg":
cell.bgcolor=parts[j++]-0;
break;
case "cf":
cell.cellformat=parts[j++]-0;
break;
case "ntvf":
cell.nontextvalueformat=parts[j++]-0;
break;
case "tvf":
cell.textvalueformat=parts[j++]-0;
break;
case "colspan":
cell.colspan=parts[j++]-0;
break;
case "rowspan":
cell.rowspan=parts[j++]-0;
break;
case "cssc":
cell.cssc=parts[j++];
break;
case "csss":
cell.csss=SocialCalc.decodeFromSave(parts[j++]);
break;
case "mod":
j+=1;
break;
case "comment":
cell.comment=SocialCalc.decodeFromSave(parts[j++]);
break;
default:
throw SocialCalc.Constants.s_cfspUnknownCellType+" '"+t+"'";
break;
}
}
}
SocialCalc.sheetfields = ["defaultrowheight", "defaultcolwidth", "circularreferencecell", "recalc", "needsrecalc"];
SocialCalc.sheetfieldsshort = ["h", "w", "circularreferencecell", "recalc", "needsrecalc"];
SocialCalc.sheetfieldsxlat = ["defaulttextformat", "defaultnontextformat",
"defaulttextvalueformat", "defaultnontextvalueformat",
"defaultcolor", "defaultbgcolor", "defaultfont", "defaultlayout"];
SocialCalc.sheetfieldsxlatshort = ["tf", "ntf", "tvf", "ntvf", "color", "bgcolor", "font", "layout"];
SocialCalc.sheetfieldsxlatxlt = ["cellformat", "cellformat", "valueformat", "valueformat",
"color", "color", "font", "layout"];
//
// sheetstr = SocialCalc.CreateSheetSave(sheetobj, range, canonicalize)
//
// Creates a text representation of the sheetobj data.
// If the range is present then only those cells are saved
// (as clipboard data with "copiedfrom" set).
//
SocialCalc.CreateSheetSave = function(sheetobj, range, canonicalize) {
var cell, cr1, cr2, row, col, coord, attrib, line, value, formula, i, t, r, b, l, name, blanklen;
var result=[];
var prange;
sheetobj.CanonicalizeSheet(canonicalize || SocialCalc.Constants.doCanonicalizeSheet);
var xlt = sheetobj.xlt;
if (range) {
prange = SocialCalc.ParseRange(range);
}
else {
prange = {cr1: {row: 1, col:1},
cr2: {row: xlt.maxrow, col: xlt.maxcol}};
}
cr1 = prange.cr1;
cr2 = prange.cr2;
result.push("version:1.5");
for (row=cr1.row; row <= cr2.row; row++) {
for (col=cr1.col; col <= cr2.col; col++) {
coord = SocialCalc.crToCoord(col, row);
cell=sheetobj.cells[coord];
if (!cell) continue;
line=sheetobj.CellToString(cell);
if (line.length==0) continue; // ignore completely empty cells
line="cell:"+coord+line;
result.push(line);
}
}
for (col=1; col <= xlt.maxcol; col++) {
coord = SocialCalc.rcColname(col);
if (sheetobj.colattribs.width[coord])
result.push("col:"+coord+":w:"+sheetobj.colattribs.width[coord]);
if (sheetobj.colattribs.hide[coord])
result.push("col:"+coord+":hide:"+sheetobj.colattribs.hide[coord]);
}
for (row=1; row <= xlt.maxrow; row++) {
if (sheetobj.rowattribs.height[row])
result.push("row:"+row+":h:"+sheetobj.rowattribs.height[row]);
if (sheetobj.rowattribs.hide[row])
result.push("row:"+row+":hide:"+sheetobj.rowattribs.hide[row]);
}
line="sheet:c:"+xlt.maxcol+":r:"+xlt.maxrow;
for (i=0; i<SocialCalc.sheetfields.length; i++) { // non-xlated values
value = SocialCalc.encodeForSave(sheetobj.attribs[SocialCalc.sheetfields[i]]);
if (value) line+=":"+SocialCalc.sheetfieldsshort[i]+":"+value;
}
for (i=0; i<SocialCalc.sheetfieldsxlat.length; i++) { // xlated values
value = sheetobj.attribs[SocialCalc.sheetfieldsxlat[i]];
if (value) line+=":"+SocialCalc.sheetfieldsxlatshort[i]+":"+xlt[SocialCalc.sheetfieldsxlatxlt[i]+"sxlat"][value];
}
result.push(line);
for (i=1;i<xlt.newborderstyles.length;i++) {
result.push("border:"+i+":"+xlt.newborderstyles[i]);
}
for (i=1;i<xlt.newcellformats.length;i++) {
result.push("cellformat:"+i+":"+SocialCalc.encodeForSave(xlt.newcellformats[i]));
}
for (i=1;i<xlt.newcolors.length;i++) {
result.push("color:"+i+":"+xlt.newcolors[i]);
}
for (i=1;i<xlt.newfonts.length;i++) {
result.push("font:"+i+":"+xlt.newfonts[i]);
}
for (i=1;i<xlt.newlayouts.length;i++) {
result.push("layout:"+i+":"+xlt.newlayouts[i]);
}
for (i=1;i<xlt.newvalueformats.length;i++) {
result.push("valueformat:"+i+":"+SocialCalc.encodeForSave(xlt.newvalueformats[i]));
}
for (i=0; i<xlt.namesorder.length; i++) {
name = xlt.namesorder[i];
result.push("name:"+SocialCalc.encodeForSave(name).toUpperCase()+":"+
SocialCalc.encodeForSave(sheetobj.names[name].desc)+":"+
SocialCalc.encodeForSave(sheetobj.names[name].definition));
}
if (range) {
result.push("copiedfrom:"+SocialCalc.crToCoord(cr1.col, cr1.row)+":"+
SocialCalc.crToCoord(cr2.col, cr2.row));
}
result.push(""); // one extra to get extra \n
delete sheetobj.xlt; // clean up
return result.join("\n");
}
//
// line = SocialCalc.CellToString(sheet, cell)
//
SocialCalc.CellToString = function(sheet, cell) {
var cell, line, value, formula, t, r, b, l, xlt;
line = "";
if (!cell) return line;
value = SocialCalc.encodeForSave(cell.datavalue);
if (cell.datatype=="v") {
if (cell.valuetype=="n") line += ":v:"+value;
else line += ":vt:"+cell.valuetype+":"+value;
}
else if (cell.datatype=="t") {
if (cell.valuetype==SocialCalc.Constants.textdatadefaulttype)
line += ":t:"+value;
else line += ":vt:"+cell.valuetype+":"+value;
}
else {
formula = SocialCalc.encodeForSave(cell.formula);
if (cell.datatype=="f") {
line += ":vtf:"+cell.valuetype+":"+value+":"+formula;
}
else if (cell.datatype=="c") {
line += ":vtc:"+cell.valuetype+":"+value+":"+formula;
}
}
if (cell.errors) {
line += ":e:"+SocialCalc.encodeForSave(cell.errors);
}
t = cell.bt || "";
r = cell.br || "";
b = cell.bb || "";
l = cell.bl || "";
if (sheet.xlt) { // if have canonical save info
xlt = sheet.xlt;
if (t || r || b || l)
line += ":b:"+xlt.borderstylesxlat[t||0]+":"+xlt.borderstylesxlat[r||0]+":"+xlt.borderstylesxlat[b||0]+":"+xlt.borderstylesxlat[l||0];
if (cell.layout) line += ":l:"+xlt.layoutsxlat[cell.layout];
if (cell.font) line += ":f:"+xlt.fontsxlat[cell.font];
if (cell.color) line += ":c:"+xlt.colorsxlat[cell.color];
if (cell.bgcolor) line += ":bg:"+xlt.colorsxlat[cell.bgcolor];
if (cell.cellformat) line += ":cf:"+xlt.cellformatsxlat[cell.cellformat];
if (cell.textvalueformat) line += ":tvf:"+xlt.valueformatsxlat[cell.textvalueformat];
if (cell.nontextvalueformat) line += ":ntvf:"+xlt.valueformatsxlat[cell.nontextvalueformat];
}
else {
if (t || r || b || l)
line += ":b:"+t+":"+r+":"+b+":"+l;
if (cell.layout) line += ":l:"+cell.layout;
if (cell.font) line += ":f:"+cell.font;
if (cell.color) line += ":c:"+cell.color;
if (cell.bgcolor) line += ":bg:"+cell.bgcolor;
if (cell.cellformat) line += ":cf:"+cell.cellformat;
if (cell.textvalueformat) line += ":tvf:"+cell.textvalueformat;
if (cell.nontextvalueformat) line += ":ntvf:"+cell.nontextvalueformat;
}
if (cell.colspan) line += ":colspan:"+cell.colspan;
if (cell.rowspan) line += ":rowspan:"+cell.rowspan;
if (cell.cssc) line += ":cssc:"+cell.cssc;
if (cell.csss) line += ":csss:"+SocialCalc.encodeForSave(cell.csss);
if (cell.mod) line += ":mod:"+cell.mod;
if (cell.comment) line += ":comment:"+SocialCalc.encodeForSave(cell.comment);
return line;
}
//
// SocialCalc.CanonicalizeSheet(sheetobj, full)
//
// Goes through the sheet and fills in sheetobj.xlt with the following:
//
// .maxrow, .maxcol - lastrow and lastcol are as small as possible
// .newlayouts - new version of sheetobj.layouts without unused ones and all in ascending order
// .layoutsxlat - maps old layouts index to new one
// same ".new" and ".xlat" for fonts, colors, borderstyles, cell and value formats
// .namesorder - array with names sorted
//
// If full or SocialCalc.Constants.doCanonicalizeSheet are not true, then the values will leave things unchanged (to save time, etc.)
//
// sheetobj.xlt should be deleted when you are finished using it
//
SocialCalc.CanonicalizeSheet = function(sheetobj, full) {
var l, coord, cr, cell, filled, an, a, newa, newxlat, used, ahash, i, v;
var maxrow = 0;
var maxcol = 0;
var alist = ["borderstyle", "cellformat", "color", "font", "layout", "valueformat"];
var xlt = {};
xlt.namesorder = []; // always return a sorted list
for (a in sheetobj.names) {
xlt.namesorder.push(a);
}
xlt.namesorder.sort();
if (!SocialCalc.Constants.doCanonicalizeSheet || !full) { // return make-no-changes values if not wanted
for (an=0; an<alist.length; an++) {
a = alist[an];
xlt["new"+a+"s"] = sheetobj[a+"s"];
l = sheetobj[a+"s"].length;
newxlat = new Array(l);
newxlat[0] = "";
for (i=1; i<l; i++) {
newxlat[i] = i;
}
xlt[a+"sxlat"] = newxlat;
}
xlt.maxrow = sheetobj.attribs.lastrow;
xlt.maxcol = sheetobj.attribs.lastcol;
sheetobj.xlt = xlt;
return;
}
for (an=0; an<alist.length; an++) {
a = alist[an];
xlt[a+"sUsed"] = {};
}
var colorsUsed = xlt.colorsUsed;
var borderstylesUsed = xlt.borderstylesUsed;
var fontsUsed = xlt.fontsUsed;
var layoutsUsed = xlt.layoutsUsed;
var cellformatsUsed = xlt.cellformatsUsed;
var valueformatsUsed = xlt.valueformatsUsed;
for (coord in sheetobj.cells) { // check all cells to see which values are used
cr = SocialCalc.coordToCr(coord);
cell = sheetobj.cells[coord];
filled = false;
if (cell.valuetype && cell.valuetype!="b") filled = true;
if (cell.color) {
colorsUsed[cell.color] = 1;
filled = true;
}
if (cell.bgcolor) {
colorsUsed[cell.bgcolor] = 1;
filled = true;
}
if (cell.bt) {
borderstylesUsed[cell.bt] = 1;
filled = true;
}
if (cell.br) {
borderstylesUsed[cell.br] = 1;
filled = true;
}
if (cell.bb) {
borderstylesUsed[cell.bb] = 1;
filled = true;
}
if (cell.bl) {
borderstylesUsed[cell.bl] = 1;
filled = true;
}
if (cell.layout) {
layoutsUsed[cell.layout] = 1;
filled = true;
}
if (cell.font) {
fontsUsed[cell.font] = 1;
filled = true;
}
if (cell.cellformat) {
cellformatsUsed[cell.cellformat] = 1;
filled = true;
}
if (cell.textvalueformat) {
valueformatsUsed[cell.textvalueformat] = 1;
filled = true;
}
if (cell.nontextvalueformat) {
valueformatsUsed[cell.nontextvalueformat] = 1;
filled = true;
}
if (filled) {
if (cr.row > maxrow) maxrow = cr.row;
if (cr.col > maxcol) maxcol = cr.col;
}
}
for (i=0; i<SocialCalc.sheetfieldsxlat.length; i++) { // do sheet values, too
v = sheetobj.attribs[SocialCalc.sheetfieldsxlat[i]];
if (v) {
xlt[SocialCalc.sheetfieldsxlatxlt[i]+"sUsed"][v] = 1;
}
}
a = {"height": 1, "hide": 1}; // look at explicit row settings
for (v in a) {
for (cr in sheetobj.rowattribs[v]) {
if (cr > maxrow) maxrow = cr;
}
}
a = {"hide": 1, "width": 1}; // look at explicit col settings
for (v in a) {
for (coord in sheetobj.colattribs[v]) {
cr = SocialCalc.coordToCr(coord+"1");
if (cr.col > maxcol) maxcol = cr.col;
}
}
for (an=0; an<alist.length; an++) { // go through the attribs we want
a = alist[an];
newa = [];
used = xlt[a+"sUsed"];
for (v in used) {
newa.push(sheetobj[a+"s"][v]);
}
newa.sort();
newa.unshift("");
newxlat = [""];
ahash = sheetobj[a+"hash"];
for (i=1; i<newa.length; i++) {
socialcalc/socialcalc-3.js view on Meta::CPAN
sheetobj.xlt = xlt; // leave for use by caller
}
//
// result = SocialCalc.EncodeCellAttributes(sheet, coord)
//
// Returns the cell's attributes in an object, each in the following form:
//
// attribname: {def: true/false, val: full-value}
//
SocialCalc.EncodeCellAttributes = function(sheet, coord) {
var value, i, b, bb, parts;
var result = {};
var InitAttrib = function(name) {
result[name] = {def: true, val: ""};
}
var InitAttribs = function(namelist) {
for (var i=0; i<namelist.length; i++) {
InitAttrib(namelist[i]);
}
}
var SetAttrib = function(name, v) {
result[name].def = false;
result[name].val = v || "";
}
var SetAttribStar = function(name, v) {
if (v=="*") return;
result[name].def = false;
result[name].val = v;
}
var cell = sheet.GetAssuredCell(coord);
// cellformat: alignhoriz
InitAttrib("alignhoriz");
if (cell.cellformat) {
SetAttrib("alignhoriz", sheet.cellformats[cell.cellformat]);
}
// layout: alignvert, padtop, padright, padbottom, padleft
InitAttribs(["alignvert", "padtop", "padright", "padbottom", "padleft"]);
if (cell.layout) {
parts = sheet.layouts[cell.layout].match(/^padding:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+);vertical-align:\s*(\S+);/);
SetAttribStar("padtop", parts[1]);
SetAttribStar("padright", parts[2]);
SetAttribStar("padbottom", parts[3]);
SetAttribStar("padleft", parts[4]);
SetAttribStar("alignvert", parts[5]);
}
// font: fontfamily, fontlook, fontsize
InitAttribs(["fontfamily", "fontlook", "fontsize"]);
if (cell.font) {
parts = sheet.fonts[cell.font].match(/^(\*|\S+? \S+?) (\S+?) (\S.*)$/);
SetAttribStar("fontfamily", parts[3]);
SetAttribStar("fontsize", parts[2]);
SetAttribStar("fontlook", parts[1]);
}
// color: textcolor
InitAttrib("textcolor");
if (cell.color) {
SetAttrib("textcolor", sheet.colors[cell.color]);
}
// bgcolor: bgcolor
InitAttrib("bgcolor");
if (cell.bgcolor) {
SetAttrib("bgcolor", sheet.colors[cell.bgcolor]);
}
// formatting: numberformat, textformat
InitAttribs(["numberformat", "textformat"]);
if (cell.nontextvalueformat) {
SetAttrib("numberformat", sheet.valueformats[cell.nontextvalueformat]);
}
if (cell.textvalueformat) {
SetAttrib("textformat", sheet.valueformats[cell.textvalueformat]);
}
// merges: colspan, rowspan
InitAttribs(["colspan", "rowspan"]);
SetAttrib("colspan", cell.colspan || 1);
SetAttrib("rowspan", cell.rowspan || 1);
// borders: bXthickness, bXstyle, bXcolor for X = t, r, b, and l
for (i=0; i<4; i++) {
b = "trbl".charAt(i);
bb = "b"+b;
InitAttrib(bb);
SetAttrib(bb, cell[bb] ? sheet.borderstyles[cell[bb]] : "");
InitAttrib(bb+"thickness");
InitAttrib(bb+"style");
InitAttrib(bb+"color");
if (cell[bb]) {
parts = sheet.borderstyles[cell[bb]].match(/(\S+)\s+(\S+)\s+(\S.+)/);
SetAttrib(bb+"thickness", parts[1]);
SetAttrib(bb+"style", parts[2]);
SetAttrib(bb+"color", parts[3]);
}
}
// misc: cssc, csss, mod
InitAttribs(["cssc", "csss", "mod"]);
SetAttrib("cssc", cell.cssc || "");
SetAttrib("csss", cell.csss || "");
SetAttrib("mod", cell.mod || "n");
return result;
}
socialcalc/socialcalc-3.js view on Meta::CPAN
var attribs = sheet.attribs;
var result = {};
var InitAttrib = function(name) {
result[name] = {def: true, val: ""};
}
var InitAttribs = function(namelist) {
for (var i=0; i<namelist.length; i++) {
InitAttrib(namelist[i]);
}
}
var SetAttrib = function(name, v) {
result[name].def = false;
result[name].val = v || value;
}
var SetAttribStar = function(name, v) {
if (v=="*") return;
result[name].def = false;
result[name].val = v;
}
// sizes: colwidth, rowheight
InitAttrib("colwidth");
if (attribs.defaultcolwidth) {
SetAttrib("colwidth", attribs.defaultcolwidth);
}
InitAttrib("rowheight");
if (attribs.rowheight) {
SetAttrib("rowheight", attribs.defaultrowheight);
}
// cellformat: textalignhoriz, numberalignhoriz
InitAttrib("textalignhoriz");
if (attribs.defaulttextformat) {
SetAttrib("textalignhoriz", sheet.cellformats[attribs.defaulttextformat]);
}
InitAttrib("numberalignhoriz");
if (attribs.defaultnontextformat) {
SetAttrib("numberalignhoriz", sheet.cellformats[attribs.defaultnontextformat]);
}
// layout: alignvert, padtop, padright, padbottom, padleft
InitAttribs(["alignvert", "padtop", "padright", "padbottom", "padleft"]);
if (attribs.defaultlayout) {
parts = sheet.layouts[attribs.defaultlayout].match(/^padding:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+);vertical-align:\s*(\S+);/);
SetAttribStar("padtop", parts[1]);
SetAttribStar("padright", parts[2]);
SetAttribStar("padbottom", parts[3]);
SetAttribStar("padleft", parts[4]);
SetAttribStar("alignvert", parts[5]);
}
// font: fontfamily, fontlook, fontsize
InitAttribs(["fontfamily", "fontlook", "fontsize"]);
if (attribs.defaultfont) {
parts = sheet.fonts[attribs.defaultfont].match(/^(\*|\S+? \S+?) (\S+?) (\S.*)$/);
SetAttribStar("fontfamily", parts[3]);
SetAttribStar("fontsize", parts[2]);
SetAttribStar("fontlook", parts[1]);
}
// color: textcolor
InitAttrib("textcolor");
if (attribs.defaultcolor) {
SetAttrib("textcolor", sheet.colors[attribs.defaultcolor]);
}
// bgcolor: bgcolor
InitAttrib("bgcolor");
if (attribs.defaultbgcolor) {
SetAttrib("bgcolor", sheet.colors[attribs.defaultbgcolor]);
}
// formatting: numberformat, textformat
InitAttribs(["numberformat", "textformat"]);
if (attribs.defaultnontextvalueformat) {
SetAttrib("numberformat", sheet.valueformats[attribs.defaultnontextvalueformat]);
}
if (attribs.defaulttextvalueformat) {
SetAttrib("textformat", sheet.valueformats[attribs.defaulttextvalueformat]);
}
// recalc: recalc
InitAttrib("recalc");
if (attribs.recalc) {
SetAttrib("recalc", attribs.recalc);
}
return result;
}
//
// cmdstr = SocialCalc.DecodeCellAttributes(sheet, coord, attribs, range)
//
// Takes cell attributes in an object, each in the following form:
//
// attribname: {def: true/false, val: full-value}
//
// and returns the sheet commands to make the actual attributes correspond.
// Returns a non-null string if any commands are to be executed, null otherwise.
//
// If range is provided, the commands are executed on the whole range.
//
SocialCalc.DecodeCellAttributes = function(sheet, coord, newattribs, range) {
var value, b, bb;
var cell = sheet.GetAssuredCell(coord);
var changed = false;
var CheckChanges = function(attribname, oldval, cmdname) {
var val;
if (newattribs[attribname]) {
if (newattribs[attribname].def) {
val = "";
}
else {
val = newattribs[attribname].val;
}
if (val != (oldval || "")) {
DoCmd(cmdname+" "+val);
}
}
}
var cmdstr = "";
var DoCmd = function(str) {
if (cmdstr) cmdstr += "\n";
cmdstr += "set "+(range || coord)+" "+str;
changed = true;
}
// cellformat: alignhoriz
CheckChanges("alignhoriz", sheet.cellformats[cell.cellformat], "cellformat");
// layout: alignvert, padtop, padright, padbottom, padleft
if (!newattribs.alignvert.def || !newattribs.padtop.def || !newattribs.padright.def ||
!newattribs.padbottom.def || !newattribs.padleft.def) {
value = "padding:" +
(newattribs.padtop.def ? "* " : newattribs.padtop.val + " ") +
(newattribs.padright.def ? "* " : newattribs.padright.val + " ") +
(newattribs.padbottom.def ? "* " : newattribs.padbottom.val + " ") +
(newattribs.padleft.def ? "*" : newattribs.padleft.val) +
";vertical-align:" +
(newattribs.alignvert.def ? "*;" : newattribs.alignvert.val+";");
}
else {
value = "";
}
if (value != (sheet.layouts[cell.layout] || "")) {
DoCmd("layout "+value);
}
// font: fontfamily, fontlook, fontsize
if (!newattribs.fontlook.def || !newattribs.fontsize.def || !newattribs.fontfamily.def) {
value =
(newattribs.fontlook.def ? "* " : newattribs.fontlook.val + " ") +
(newattribs.fontsize.def ? "* " : newattribs.fontsize.val + " ") +
(newattribs.fontfamily.def ? "*" : newattribs.fontfamily.val);
}
else {
value = "";
}
if (value != (sheet.fonts[cell.font] || "")) {
DoCmd("font "+value);
}
// color: textcolor
CheckChanges("textcolor", sheet.colors[cell.color], "color");
// bgcolor: bgcolor
CheckChanges("bgcolor", sheet.colors[cell.bgcolor], "bgcolor");
// formatting: numberformat, textformat
CheckChanges("numberformat", sheet.valueformats[cell.nontextvalueformat], "nontextvalueformat");
CheckChanges("textformat", sheet.valueformats[cell.textvalueformat], "textvalueformat");
// merges: colspan, rowspan - NOT HANDLED: IGNORED!
// borders: bX for X = t, r, b, and l; bXthickness, bXstyle, bXcolor ignored
for (var i=0; i<4; i++) {
b = "trbl".charAt(i);
bb = "b"+b;
CheckChanges(bb, sheet.borderstyles[cell[bb]], bb);
}
// misc: cssc, csss, mod
CheckChanges("cssc", cell.cssc, "cssc");
CheckChanges("csss", cell.csss, "csss");
if (newattribs.mod) {
if (newattribs.mod.def) {
value = "n";
}
else {
value = newattribs.mod.val;
}
if (value != (cell.mod || "n")) {
if (value=="n") value = ""; // restrict to "y" and "" normally
DoCmd("mod "+value);
}
}
// if any changes return command(s)
if (changed) {
return cmdstr;
}
else {
return null;
}
}
//
// changed = SocialCalc.DecodeSheetAttributes(sheet, newattribs)
//
socialcalc/socialcalc-3.js view on Meta::CPAN
var value;
var attribs = sheet.attribs;
var changed = false;
var CheckChanges = function(attribname, oldval, cmdname) {
var val;
if (newattribs[attribname]) {
if (newattribs[attribname].def) {
val = "";
}
else {
val = newattribs[attribname].val;
}
if (val != (oldval || "")) {
DoCmd(cmdname+" "+val);
}
}
}
var cmdstr = "";
var DoCmd = function(str) {
if (cmdstr) cmdstr += "\n";
cmdstr += "set sheet "+str;
changed = true;
}
// sizes: colwidth, rowheight
CheckChanges("colwidth", attribs.defaultcolwidth, "defaultcolwidth");
CheckChanges("rowheight", attribs.defaultrowheight, "defaultrowheight");
// cellformat: textalignhoriz, numberalignhoriz
CheckChanges("textalignhoriz", sheet.cellformats[attribs.defaulttextformat], "defaulttextformat");
CheckChanges("numberalignhoriz", sheet.cellformats[attribs.defaultnontextformat], "defaultnontextformat");
// layout: alignvert, padtop, padright, padbottom, padleft
if (!newattribs.alignvert.def || !newattribs.padtop.def || !newattribs.padright.def ||
!newattribs.padbottom.def || !newattribs.padleft.def) {
value = "padding:" +
(newattribs.padtop.def ? "* " : newattribs.padtop.val + " ") +
(newattribs.padright.def ? "* " : newattribs.padright.val + " ") +
(newattribs.padbottom.def ? "* " : newattribs.padbottom.val + " ") +
(newattribs.padleft.def ? "*" : newattribs.padleft.val) +
";vertical-align:" +
(newattribs.alignvert.def ? "*;" : newattribs.alignvert.val+";");
}
else {
value = "";
}
if (value != (sheet.layouts[attribs.defaultlayout] || "")) {
DoCmd("defaultlayout "+value);
}
// font: fontfamily, fontlook, fontsize
if (!newattribs.fontlook.def || !newattribs.fontsize.def || !newattribs.fontfamily.def) {
value =
(newattribs.fontlook.def ? "* " : newattribs.fontlook.val + " ") +
(newattribs.fontsize.def ? "* " : newattribs.fontsize.val + " ") +
(newattribs.fontfamily.def ? "*" : newattribs.fontfamily.val);
}
else {
value = "";
}
if (value != (sheet.fonts[attribs.defaultfont] || "")) {
DoCmd("defaultfont "+value);
}
// color: textcolor
CheckChanges("textcolor", sheet.colors[attribs.defaultcolor], "defaultcolor");
// bgcolor: bgcolor
CheckChanges("bgcolor", sheet.colors[attribs.defaultbgcolor], "defaultbgcolor");
// formatting: numberformat, textformat
CheckChanges("numberformat", sheet.valueformats[attribs.defaultnontextvalueformat], "defaultnontextvalueformat");
CheckChanges("textformat", sheet.valueformats[attribs.defaulttextvalueformat], "defaulttextvalueformat");
// recalc: recalc
CheckChanges("recalc", sheet.attribs.recalc, "recalc");
// if any changes return command(s)
if (changed) {
return cmdstr;
}
else {
return null;
}
}
// *************************************
//
// Sheet command routines
//
// *************************************
//
// SocialCalc.SheetCommandInfo - object with information used during command execution
//
SocialCalc.SheetCommandInfo = { // only one of these
sheetobj: null, // sheet being operated on
parseobj: null, // SocialCalc.Parse object with the command string, etc.
timerobj: null, // used for timeslicing
firsttimerdelay: 50, // wait before starting cmds (for Chrome - to give time to update)
timerdelay: 1, // wait between slices
maxtimeslice: 100, // do another slice after this many milliseconds
saveundo: false, // arg for ExecuteSheetCommand
CmdExtensionCallbacks: {}, // for startcmdextension, in form: cmdname, {func:function(cmdname, data, sheet, SocialCalc.Parse object, saveundo), data:whatever}
cmdextensionbusy: "" // if length>0, command loop waits for SocialCalc.ResumeFromCmdExtension()
// statuscallback: null, // called during execution - obsolete: use sheet obj's
// statuscallbackparams: null
};
//
socialcalc/socialcalc-3.js view on Meta::CPAN
SocialCalc.ExecuteSheetCommand = function(sheet, cmd, saveundo) {
var cmdstr, cmd1, rest, what, attrib, num, pos, pos2, errortext, undostart, val;
var cr1, cr2, col, row, cr, cell, newcell;
var fillright, rowstart, colstart, crbase, rowoffset, coloffset, basecell;
var clipsheet, cliprange, numcols, numrows, attribtable;
var colend, rowend, newcolstart, newrowstart, newcolend, newrowend, rownext, colnext, colthis, cellnext;
var lastrow, lastcol, rowbefore, colbefore, oldformula, oldcr;
var cols, dirs, lastsortcol, i, sortlist, sortcells, sortvalues, sorttypes;
var sortfunction, slen, valtype, originalrow, sortedcr;
var name, v1, v2;
var cmdextension;
var attribs = sheet.attribs;
var changes = sheet.changes;
var cellProperties = SocialCalc.CellProperties;
var scc = SocialCalc.Constants;
var ParseRange =
function() {
var prange = SocialCalc.ParseRange(what);
cr1 = prange.cr1;
cr2 = prange.cr2;
if (cr2.col > attribs.lastcol) attribs.lastcol = cr2.col;
if (cr2.row > attribs.lastrow) attribs.lastrow = cr2.row;
};
errortext = "";
cmdstr = cmd.RestOfStringNoMove();
if (saveundo) {
sheet.changes.AddDo(cmdstr);
}
cmd1 = cmd.NextToken();
switch (cmd1) {
case "set":
what = cmd.NextToken();
attrib = cmd.NextToken();
rest = cmd.RestOfString();
undostart = "set "+what+" "+attrib;
if (what=="sheet") {
sheet.renderneeded = true;
switch (attrib) {
case "defaultcolwidth":
if (saveundo) changes.AddUndo(undostart, attribs[attrib]);
attribs[attrib] = rest;
break;
case "defaultcolor":
case "defaultbgcolor":
if (saveundo) changes.AddUndo(undostart, sheet.GetStyleString("color", attribs[attrib]));
attribs[attrib] = sheet.GetStyleNum("color", rest);
break;
case "defaultlayout":
if (saveundo) changes.AddUndo(undostart, sheet.GetStyleString("layout", attribs[attrib]));
attribs[attrib] = sheet.GetStyleNum("layout", rest);
break;
case "defaultfont":
if (saveundo) changes.AddUndo(undostart, sheet.GetStyleString("font", attribs[attrib]));
if (rest=="* * *") rest = ""; // all default
attribs[attrib] = sheet.GetStyleNum("font", rest);
break;
case "defaulttextformat":
case "defaultnontextformat":
if (saveundo) changes.AddUndo(undostart, sheet.GetStyleString("cellformat", attribs[attrib]));
attribs[attrib] = sheet.GetStyleNum("cellformat", rest);
break;
case "defaulttextvalueformat":
case "defaultnontextvalueformat":
if (saveundo) changes.AddUndo(undostart, sheet.GetStyleString("valueformat", attribs[attrib]));
attribs[attrib] = sheet.GetStyleNum("valueformat", rest);
for (cr in sheet.cells) { // forget all cached display strings
delete sheet.cells[cr].displaystring;
}
break;
case "lastcol":
case "lastrow":
if (saveundo) changes.AddUndo(undostart, attribs[attrib]-0);
num = rest-0;
if (typeof num == "number") attribs[attrib] = num > 0 ? num : 1;
break;
case "recalc":
if (saveundo) changes.AddUndo(undostart, attribs[attrib]);
if (rest == "off") {
attribs.recalc = rest; // manual recalc, not auto
}
else { // all values other than "off" mean "on"
delete attribs.recalc;
}
break;
default:
errortext = scc.s_escUnknownSheetCmd+cmdstr;
break;
}
}
else if (/(^[A-Z])([A-Z])?(:[A-Z][A-Z]?){0,1}$/i.test(what)) { // col attributes
sheet.renderneeded = true;
what = what.toUpperCase();
pos = what.indexOf(":");
if (pos>=0) {
cr1 = SocialCalc.coordToCr(what.substring(0,pos)+"1");
cr2 = SocialCalc.coordToCr(what.substring(pos+1)+"1");
}
else {
cr1 = SocialCalc.coordToCr(what+"1");
cr2 = cr1;
}
for (col=cr1.col; col <= cr2.col; col++) {
if (attrib=="width") {
cr = SocialCalc.rcColname(col);
if (saveundo) changes.AddUndo("set "+cr+" width", sheet.colattribs.width[cr]);
if (rest.length > 0 ) {
sheet.colattribs.width[cr] = rest;
}
else {
delete sheet.colattribs.width[cr];
}
}
}
}
socialcalc/socialcalc-3.js view on Meta::CPAN
attribs.needsrecalc = "yes";
}
else if (attrib=="formula") { // set coord formula formula-body-less-initial-=
cell.datavalue = 0; // until recalc
delete cell.errors;
cell.datatype = "f";
cell.valuetype = "e#N/A"; // until recalc
cell.formula = rest;
delete cell.displaystring;
delete cell.parseinfo;
attribs.needsrecalc = "yes";
}
else if (attrib=="constant") { // set coord constant type numeric-value source-text
pos = rest.indexOf(" ");
pos2 = rest.substring(pos+1).indexOf(" ");
cell.datavalue = rest.substring(pos+1,pos+1+pos2)-0;
cell.valuetype = rest.substring(0,pos);
if (cell.valuetype.charAt(0)=="e") { // error
cell.errors = cell.valuetype.substring(1);
}
else {
delete cell.errors;
}
cell.datatype = "c";
cell.formula = rest.substring(pos+pos2+2);
delete cell.displaystring;
delete cell.parseinfo;
attribs.needsrecalc = "yes";
}
else if (attrib=="empty") { // erase value
cell.datavalue = "";
delete cell.errors;
cell.datatype = null;
cell.formula = "";
cell.valuetype = "b";
delete cell.displaystring;
delete cell.parseinfo;
attribs.needsrecalc = "yes";
}
else if (attrib=="all") { // set coord all :this:val1:that:val2...
if (rest.length>0) {
cell = new SocialCalc.Cell(cr);
sheet.CellFromStringParts(cell, rest.split(":"), 1);
sheet.cells[cr] = cell;
}
else {
delete sheet.cells[cr];
}
attribs.needsrecalc = "yes";
}
else if (/^b[trbl]$/.test(attrib)) { // set coord bt 1px solid black
cell[attrib] = sheet.GetStyleNum("borderstyle", rest);
sheet.renderneeded = true; // affects more than just one cell
}
else if (attrib=="color" || attrib=="bgcolor") {
cell[attrib] = sheet.GetStyleNum("color", rest);
}
else if (attrib=="layout" || attrib=="cellformat") {
cell[attrib] = sheet.GetStyleNum(attrib, rest);
}
else if (attrib=="font") { // set coord font style weight size family
if (rest=="* * *") rest = "";
cell[attrib] = sheet.GetStyleNum("font", rest);
}
else if (attrib=="textvalueformat" || attrib=="nontextvalueformat") {
cell[attrib] = sheet.GetStyleNum("valueformat", rest);
delete cell.displaystring;
}
else if (attrib=="cssc") {
rest = rest.replace(/[^a-zA-Z0-9\-]/g, "");
cell.cssc = rest;
}
else if (attrib=="csss") {
rest = rest.replace(/\n/g, "");
cell.csss = rest;
}
else if (attrib=="mod") {
rest = rest.replace(/[^yY]/g, "").toLowerCase();
cell.mod = rest;
}
else if (attrib=="comment") {
cell.comment = SocialCalc.decodeFromSave(rest);
}
else {
errortext = scc.s_escUnknownSetCoordCmd+cmdstr;
}
}
}
}
break;
case "merge":
sheet.renderneeded = true;
what = cmd.NextToken();
rest = cmd.RestOfString();
ParseRange();
cell=sheet.GetAssuredCell(cr1.coord);
if (saveundo) changes.AddUndo("unmerge "+cr1.coord);
if (cr2.col > cr1.col) cell.colspan = cr2.col - cr1.col + 1;
else delete cell.colspan;
if (cr2.row > cr1.row) cell.rowspan = cr2.row - cr1.row + 1;
else delete cell.rowspan;
sheet.changedrendervalues = true;
break;
case "unmerge":
sheet.renderneeded = true;
what = cmd.NextToken();
rest = cmd.RestOfString();
ParseRange();
cell=sheet.GetAssuredCell(cr1.coord);
if (saveundo) changes.AddUndo("merge "+cr1.coord+":"+SocialCalc.crToCoord(cr1.col+(cell.colspan||1)-1, cr1.row+(cell.rowspan||1)-1));
delete cell.colspan;
delete cell.rowspan;
sheet.changedrendervalues = true;
break;
socialcalc/socialcalc-3.js view on Meta::CPAN
SocialCalc.Clipboard = {
// properties:
clipboard: "" // empty or string in save format with "copiedfrom:" set to a range
}
// *************************************
//
// RenderContext class:
//
// *************************************
SocialCalc.RenderContext = function(sheetobj) {
var parts, num, s;
var attribs = sheetobj.attribs;
var scc = SocialCalc.Constants;
// properties:
this.sheetobj = sheetobj;
this.hideRowsCols = false; // Rendering with panes only works with "false"
// !!!! Note: not implemented yet in rendering, just saved as an attribute
this.showGrid = false;
this.showRCHeaders = false;
this.rownamewidth = scc.defaultRowNameWidth;
this.pixelsPerRow = scc.defaultAssumedRowHeight;
this.cellskip = {}; // if present, coord of cell covering this cell
this.coordToCR = {}; // for cells starting spans, coordToCR[coord]={row:row, col:col}
this.colwidth = []; // precomputed column widths, taking into account defaults
this.totalwidth = 0; // precomputed total table width
this.rowpanes = []; // for each pane, {first: firstrow, last: lastrow}
this.colpanes = []; // for each pane, {first: firstrow, last: lastrow}
this.maxcol=0; // max col and row to display, adding long spans, etc.
this.maxrow=0;
this.highlights = {}; // for each cell with special display: coord:highlightType (see this.highlightTypes)
this.cursorsuffix = ""; // added to highlights[cr]=="cursor" to get type to lookup
this.highlightTypes = // attributes to change when highlit
{
cursor: {style: scc.defaultHighlightTypeCursorStyle, className: scc.defaultHighlightTypeCursorClass},
range: {style: scc.defaultHighlightTypeRangeStyle, className: scc.defaultHighlightTypeRangeClass},
cursorinsertup: {style: "color:#FFF;backgroundColor:#A6A6A6;backgroundRepeat:repeat-x;backgroundPosition:top left;backgroundImage:url("+scc.defaultImagePrefix+"cursorinsertup.gif);", className: scc.defaultHighlightTypeCursorClass},
cursorinsertleft: {style: "color:#FFF;backgroundColor:#A6A6A6;backgroundRepeat:repeat-y;backgroundPosition:top left;backgroundImage:url("+scc.defaultImagePrefix+"cursorinsertleft.gif);", className: scc.defaultHighlightTypeCursorClass},
range2: {style: "color:#000;backgroundColor:#FFF;backgroundImage:url("+scc.defaultImagePrefix+"range2.gif);", className: ""}
}
this.cellIDprefix = scc.defaultCellIDPrefix; // if non-null, each cell will render with an ID
this.defaultlinkstyle = null; // default linkstyle object (allows you to pass values to link renderer)
this.defaultHTMLlinkstyle = {type: "html"}; // default linkstyle for standalone HTML
// constants:
this.defaultfontstyle = scc.defaultCellFontStyle;
this.defaultfontsize = scc.defaultCellFontSize;
this.defaultfontfamily = scc.defaultCellFontFamily;
this.defaultlayout = scc.defaultCellLayout;
this.defaultpanedividerwidth = scc.defaultPaneDividerWidth;
this.defaultpanedividerheight = scc.defaultPaneDividerHeight;
this.gridCSS = scc.defaultGridCSS;
this.commentClassName = scc.defaultCommentClass; // for cells with non-blank comments when this.showGrid is true
this.commentCSS = scc.defaultCommentStyle; // any combination of classnames and styles may be used
this.commentNoGridClassName = scc.defaultCommentNoGridClass; // for cells when this.showGrid is false
this.commentNoGridCSS = scc.defaultCommentNoGridStyle; // any combination of classnames and styles may be used
this.classnames = // any combination of classnames and explicitStyles can be used
{
colname: scc.defaultColnameClass,
rowname: scc.defaultRownameClass,
selectedcolname: scc.defaultSelectedColnameClass,
selectedrowname: scc.defaultSelectedRownameClass,
upperleft: scc.defaultUpperLeftClass,
skippedcell: scc.defaultSkippedCellClass,
panedivider: scc.defaultPaneDividerClass
};
this.explicitStyles = // these may be used so you won't need a stylesheet with the classnames
{
colname: scc.defaultColnameStyle,
rowname: scc.defaultRownameStyle,
selectedcolname: scc.defaultSelectedColnameStyle,
selectedrowname: scc.defaultSelectedRownameStyle,
upperleft: scc.defaultUpperLeftStyle,
skippedcell: scc.defaultSkippedCellStyle,
panedivider: scc.defaultPaneDividerStyle
};
// processed info about cell skipping
this.cellskip = null;
this.needcellskip = true;
// precomputed values, filling in defaults indicated by "*"
this.fonts=[]; // for each fontnum, {style: fs, weight: fw, size: fs, family: ff}
this.layouts=[]; // for each layout, "padding:Tpx Rpx Bpx Lpx;vertical-align:va;"
this.needprecompute = true; // need to call PrecomputeSheetFontsAndLayouts
// if have a sheet object, initialize constants and precomputed values
if (sheetobj) {
this.rowpanes[0] = {first: 1, last: attribs.lastrow};
this.colpanes[0] = {first: 1, last: attribs.lastcol};
}
else throw scc.s_rcMissingSheet;
}
// Methods:
SocialCalc.RenderContext.prototype.PrecomputeSheetFontsAndLayouts = function() {SocialCalc.PrecomputeSheetFontsAndLayouts(this);};
SocialCalc.RenderContext.prototype.CalculateCellSkipData = function() {SocialCalc.CalculateCellSkipData(this);};
SocialCalc.RenderContext.prototype.CalculateColWidthData = function() {SocialCalc.CalculateColWidthData(this);};
SocialCalc.RenderContext.prototype.SetRowPaneFirstLast = function(panenum, first, last) {this.rowpanes[panenum]={first:first, last:last};};
SocialCalc.RenderContext.prototype.SetColPaneFirstLast = function(panenum, first, last) {this.colpanes[panenum]={first:first, last:last};};
SocialCalc.RenderContext.prototype.CoordInPane = function(coord, rowpane, colpane) {return SocialCalc.CoordInPane(this, coord, rowpane, colpane);};
SocialCalc.RenderContext.prototype.CellInPane = function(row, col, rowpane, colpane) {return SocialCalc.CellInPane(this, row, col, rowpane, colpane);};
SocialCalc.RenderContext.prototype.InitializeTable = function(tableobj) {SocialCalc.InitializeTable(this, tableobj);};
SocialCalc.RenderContext.prototype.RenderSheet = function(oldtable, linkstyle) {return SocialCalc.RenderSheet(this, oldtable, linkstyle);};
SocialCalc.RenderContext.prototype.RenderColGroup = function() {return SocialCalc.RenderColGroup(this);};
SocialCalc.RenderContext.prototype.RenderColHeaders = function() {return SocialCalc.RenderColHeaders(this);};
SocialCalc.RenderContext.prototype.RenderSizingRow = function() {return SocialCalc.RenderSizingRow(this);};
SocialCalc.RenderContext.prototype.RenderRow = function(rownum, rowpane, linkstyle) {return SocialCalc.RenderRow(this, rownum, rowpane, linkstyle);};
SocialCalc.RenderContext.prototype.RenderSpacingRow = function() {return SocialCalc.RenderSpacingRow(this);};
SocialCalc.RenderContext.prototype.RenderCell = function(rownum, colnum, rowpane, colpane, noElement, linkstyle)
{return SocialCalc.RenderCell(this, rownum, colnum, rowpane, colpane, noElement, linkstyle);};
// Functions:
SocialCalc.PrecomputeSheetFontsAndLayouts = function(context) {
var defaultfont, parts, layoutre, dparts, sparts, num, s, i;
var sheetobj = context.sheetobj;
var attribs = sheetobj.attribs;
if (attribs.defaultfont) {
defaultfont = sheetobj.fonts[attribs.defaultfont];
defaultfont = defaultfont.replace(/^\*/,SocialCalc.Constants.defaultCellFontStyle);
defaultfont = defaultfont.replace(/(.+)\*(.+)/,"$1"+SocialCalc.Constants.defaultCellFontSize+"$2");
defaultfont = defaultfont.replace(/\*$/,SocialCalc.Constants.defaultCellFontFamily);
parts=defaultfont.match(/^(\S+? \S+?) (\S+?) (\S.*)$/);
context.defaultfontstyle = parts[1];
context.defaultfontsize = parts[2];
context.defaultfontfamily = parts[3];
}
for (num=1; num<sheetobj.fonts.length; num++) { // precompute fonts by filling in the *'s
s=sheetobj.fonts[num];
s=s.replace(/^\*/,context.defaultfontstyle);
s=s.replace(/(.+)\*(.+)/,"$1"+context.defaultfontsize+"$2");
s=s.replace(/\*$/,context.defaultfontfamily);
parts=s.match(/^(\S+?) (\S+?) (\S+?) (\S.*)$/);
context.fonts[num] = {style: parts[1], weight: parts[2], size: parts[3], family: parts[4]};
}
layoutre = /^padding:\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+);vertical-align:\s*(\S+);/;
dparts = SocialCalc.Constants.defaultCellLayout.match(layoutre); // get built-in defaults
if (attribs.defaultlayout) {
sparts = sheetobj.layouts[attribs.defaultlayout].match(layoutre); // get sheet defaults, if set
}
else {
sparts = ["", "*", "*", "*", "*", "*"];
}
for (num=1; num<sheetobj.layouts.length; num++) { // precompute layouts by filling in the *'s
s=sheetobj.layouts[num];
parts = s.match(layoutre);
for (i=1; i<=5; i++) {
if (parts[i]=="*") {
parts[i] = (sparts[i] != "*" ? sparts[i] : dparts[i]); // if *, sheet default or built-in
}
}
context.layouts[num] = "padding:"+parts[1]+" "+parts[2]+" "+parts[3]+" "+parts[4]+
";vertical-align:"+parts[5]+";";
}
context.needprecompute = false;
}
SocialCalc.CalculateCellSkipData = function(context) {
var row, col, coord, cell, contextcell, colspan, rowspan, skiprow, skipcol, skipcoord;
var sheetobj=context.sheetobj;
var sheetrowattribs=sheetobj.rowattribs;
var sheetcolattribs=sheetobj.colattribs;
context.maxrow=0;
context.maxcol=0;
context.cellskip = {}; // reset
// Calculate cellskip data
for (row=1; row<=sheetobj.attribs.lastrow; row++) {
for (col=1; col<=sheetobj.attribs.lastcol; col++) { // look for spans and set cellskip for skipped cells
coord=SocialCalc.crToCoord(col, row);
cell=sheetobj.cells[coord];
// don't look at undefined cells (they have no spans) or skipped cells
if (cell===undefined || context.cellskip[coord]) continue;
colspan=cell.colspan || 1;
rowspan=cell.rowspan || 1;
if (colspan>1 || rowspan>1) {
for (skiprow=row; skiprow<row+rowspan; skiprow++) {
for (skipcol=col; skipcol<col+colspan; skipcol++) { // do the setting on individual cells
skipcoord=SocialCalc.crToCoord(skipcol,skiprow);
if (skipcoord==coord) { // for coord, remember row and col
context.coordToCR[coord]={row: row, col: col};
}
else { // for other cells, flag with coord of here
context.cellskip[skipcoord]=coord;
}
socialcalc/socialcalc-3.js view on Meta::CPAN
if (context.CoordInPane(context.cellskip[coord], rowpane, colpane)) {
return null; // span starts in this pane -- so just skip
}
result=noElement ? SocialCalc.CreatePseudoElement() : document.createElement("td"); // span start is scrolled away, so make a special cell
if (context.classnames.skippedcell) result.className=context.classnames.skippedcell;
if (context.explicitStyles.skippedcell) result.style.cssText=context.explicitStyles.skippedcell;
result.innerHTML=" "; // put something there so height is OK
// !!! Really need to add borders in case there isn't anything else shown in the pane to get height
return result;
}
result=noElement ? SocialCalc.CreatePseudoElement() : document.createElement("td");
if (context.cellIDprefix) {
result.id = context.cellIDprefix+coord;
}
cell=sheetobj.cells[coord];
if (!cell) {
cell=new SocialCalc.Cell(coord);
}
sheetattribs=sheetobj.attribs;
scc=SocialCalc.Constants;
if (cell.colspan>1) {
span=1;
for (num=1; num<cell.colspan; num++) {
if (sheetobj.colattribs.hide[SocialCalc.rcColname(colnum+num)]!="yes" &&
context.CellInPane(rownum, colnum+num, rowpane, colpane)) {
span++;
}
}
result.colSpan=span;
}
if (cell.rowspan>1) {
span=1;
for (num=1; num<cell.rowspan; num++) {
if (sheetobj.rowattribs.hide[(rownum+num)+""]!="yes" &&
context.CellInPane(rownum+num, colnum, rowpane, colpane))
span++;
}
result.rowSpan=span;
}
if (cell.displaystring==undefined) { // cache the display value
cell.displaystring = SocialCalc.FormatValueForDisplay(sheetobj, cell.datavalue, coord, (linkstyle || context.defaultlinkstyle));
}
result.innerHTML = cell.displaystring;
num=cell.layout || sheetattribs.defaultlayout;
if (num) {
stylestr+=context.layouts[num]; // use precomputed layout with "*"'s filled in
}
else {
stylestr+=scc.defaultCellLayout;
}
num=cell.font || sheetattribs.defaultfont;
if (num) { // get expanded font strings in context
t = context.fonts[num]; // do each - plain "font:" style sets all sorts of other values, too (Safari font-stretch problem on cssText)
stylestr+="font-style:"+t.style+";font-weight:"+t.weight+";font-size:"+t.size+";font-family:"+t.family+";";
}
else {
if (scc.defaultCellFontSize) {
stylestr+="font-size:"+scc.defaultCellFontSize+";";
}
if (scc.defaultCellFontFamily) {
stylestr+="font-family:"+scc.defaultCellFontFamily+";";
}
}
num=cell.color || sheetattribs.defaultcolor;
if (num) stylestr+="color:"+sheetobj.colors[num]+";";
num=cell.bgcolor || sheetattribs.defaultbgcolor;
if (num) stylestr+="background-color:"+sheetobj.colors[num]+";";
num=cell.cellformat;
if (num) {
stylestr+="text-align:"+sheetobj.cellformats[num]+";";
}
else {
t=cell.valuetype.charAt(0);
if (t=="t") {
num=sheetattribs.defaulttextformat;
if (num) stylestr+="text-align:"+sheetobj.cellformats[num]+";";
}
else if (t="n") {
num=sheetattribs.defaultnontextformat;
if (num) {
stylestr+="text-align:"+sheetobj.cellformats[num]+";";
}
else {
stylestr+="text-align:right;";
}
}
else stylestr+="text-align:left;";
}
num=cell.bt;
if (num) stylestr+="border-top:"+sheetobj.borderstyles[num]+";";
num=cell.br;
if (num) stylestr+="border-right:"+sheetobj.borderstyles[num]+";";
else if (context.showGrid) {
if (context.CellInPane(rownum, colnum+(cell.colspan || 1), rowpane, colpane))
t=SocialCalc.crToCoord(colnum+(cell.colspan || 1), rownum);
else t="nomatch";
if (context.cellskip[t]) t=context.cellskip[t];
if (!sheetobj.cells[t] || !sheetobj.cells[t].bl)
stylestr+="border-right:"+context.gridCSS;
}
num=cell.bb;
if (num) stylestr+="border-bottom:"+sheetobj.borderstyles[num]+";";
else if (context.showGrid) {
if (context.CellInPane(rownum+(cell.rowspan || 1), colnum, rowpane, colpane))
t=SocialCalc.crToCoord(colnum, rownum+(cell.rowspan || 1));
else t="nomatch";
if (context.cellskip[t]) t=context.cellskip[t];
if (!sheetobj.cells[t] || !sheetobj.cells[t].bt)
stylestr+="border-bottom:"+context.gridCSS;
}
num=cell.bl;
if (num) stylestr+="border-left:"+sheetobj.borderstyles[num]+";";
if (cell.comment) {
( run in 2.578 seconds using v1.01-cache-2.11-cpan-c221a9de4ec )