";
var i,r,c;
for (i=1; i<=this.options.numRows; i++)
s+="
"+i+"
";
s+="
";
this.frozenTabs.innerHTML=s;
s="
";
s+="
";
for (i=0; i
"+String.fromCharCode(65+i)+"
";
s+="
";
this.innerDiv.innerHTML=s;
s="
";
for (c=1; c<=this.options.numColumns; c++) {
s+="
";
for (r=0; r
";
s+="
";
}
s+="
";
this.scrollDiv.innerHTML=s;
},
initSheet: function() {
this.highlightDiv=[];
var i,r,c,col,cell;
for (i=0; i<4; i++) {
this.highlightDiv[i] = this.createDiv("highlight",this.scrollDiv);
this.highlightDiv[i].style.display="none";
this.highlightDiv[i].id+=i;
this.highlightDiv[i].style[i % 2==0 ? 'height' : 'width']="0px";
}
for (c=1; c s.r2) {
this.HideSelection();
return;
}
var top1=this.columns[s.c1].cell(s.r1).offsetTop;
var cell2=this.columns[s.c1].cell(s.r2);
var bottom2=cell2.offsetTop+cell2.offsetHeight;
var left1=this.columns[s.c1].dataCell.offsetLeft;
var left2=this.columns[s.c2].dataCell.offsetLeft;
var right2=left2+this.columns[s.c2].dataCell.offsetWidth;
//window.status='updateSelectOutline: '+s.r1+' '+s.r2+' top='+top1+' bot='+bottom2;
this.highlightDiv[0].style.top=this.highlightDiv[3].style.top=this.highlightDiv[1].style.top=(top1-3) + 'px';
this.highlightDiv[2].style.top=(bottom2-2)+'px';
this.highlightDiv[3].style.left=(left1-2)+'px';
this.highlightDiv[0].style.left=this.highlightDiv[2].style.left=(left1-1)+'px';
this.highlightDiv[1].style.left=(right2-1)+'px';
this.highlightDiv[0].style.width=this.highlightDiv[2].style.width=(right2-left1-1) + 'px';
this.highlightDiv[1].style.height=this.highlightDiv[3].style.height=(bottom2-top1) + 'px';
for (var i=0; i<4; i++)
this.highlightDiv[i].style.display='';
},
isSelected: function(r,c) {
var s=this.getSelection();
return s ? (s.r1 <= r) && (r <= s.r2) && (s.c1 <= c) && (c <= s.c2) : false;
},
HideSelection: function(cellList) {
for (var i=0; i<4; i++)
this.highlightDiv[i].style.display='none';
},
ShowSelection: function() {
this.updateSelectOutline();
},
/*
* @param what valid values are: null, 'all', 'formats', 'formulas', 'values'
*/
clearSelection: function() {
var s=this.getSelection();
if (!s) return;
var args=$A(arguments);
var what=args.shift();
if (typeof what=='object') what=args.shift(); // in case first arg is an event object
var v=(!what || what=='all') ? 1 : 0;
var whatobj={formats:v,formulas:v,values:v};
if (typeof what=='string') whatobj[what]=1;
if (whatobj.values) whatobj.formulas=1;
for (var r=s.r1; r<=s.r2; r++) {
for (var c=s.c1; c<=s.c2; c++) {
var gridcell=this.columns[c].cell(r);
if (whatobj.formats) {
gridcell.style.cssText='';
gridcell.RicoFormat={};
}
if (whatobj.formulas) gridcell.RicoFormula=null;
if (whatobj.values) gridcell.RicoValue=null;
this.formatCell(gridcell);
}
}
},
selectCellRC: function(r,c,adjFlag) {
if (r < 0 || r >= this.columns[0].numRows()) return;
this.HideSelection();
if (adjFlag) {
if (this.SelectIdxStart.tabIdx == this.columns[c].tabIdx)
this.SelectIdxEnd={row:r, column:c, tabIdx:this.columns[c].tabIdx};
} else {
this.SelectIdxStart=this.SelectIdxEnd={row:r, column:c, tabIdx:this.columns[c].tabIdx};
var cell=this.columns[c].cell(r);
if (Prototype.Browser.IE)
cell.focus(); // causes IE to scroll cell into view
else if (cell.scrollIntoView)
cell.scrollIntoView(false);
}
this.ShowSelection();
},
moveSelection: function(dr,dc,adjFlag,e) {
var selIdx=adjFlag ? this.SelectIdxEnd : this.SelectIdxStart;
var newr=selIdx.row+dr;
var newc=selIdx.column+dc;
if (newr>=0 && newr=1 && newcs.c1) clipstr+="\t";
clipstr+=this.columns[c].cell(r).RicoValue;
}
clipstr+="\r\n";
}
this.clipBox.style.display='block';
this.clipBox.value=clipstr;
this.clipBox.select();
},
cutSelection: function() {
var clipArray=this.copySelection();
this.clearSelection();
return clipArray;
},
copySelection: function() {
var s=this.getSelection();
if (!s) return;
var clipArray=[];
for (var r=s.r1; r<=s.r2; r++) {
var cliprow=[];
for (var c=s.c1; c<=s.c2; c++) {
var clipcell={};
var gridcell=this.columns[c].cell(r);
clipcell.value=gridcell.RicoValue;
clipcell.style=gridcell.style.cssText;
if (typeof gridcell.RicoFormat=='object')
clipcell.format=Object.extend({}, gridcell.RicoFormat || {});
else
clipcell.format=gridcell.RicoFormat;
if (gridcell.RicoFormula)
clipcell.formula=Object.extend({}, gridcell.RicoFormula);
cliprow[c-s.c1]=clipcell;
}
clipArray[r-s.r1]=cliprow;
}
return clipArray;
},
pasteSelection: function(clipArray,pasteType) {
var s=this.getSelection();
if (!s || !clipArray) return;
pasteType=pasteType || 'all';
var clipclen=clipArray[0].length;
if (s.r1==s.r2 && s.c1==s.c2) {
s.r2=Math.min(s.r1+clipArray.length,this.columns[0].numRows())-1;
s.c2=Math.min(s.c1+clipclen,this.columns.length)-1;
}
for (var r=s.r1,clipr=0; r<=s.r2; r++) {
var arow=clipArray[clipr];
for (var c=s.c1,clipc=0; c<=s.c2; c++) {
var clipcell=arow[clipc];
var gridcell=this.columns[c].cell(r);
if (pasteType=='all') {
this.updateDependencies(gridcell,'remove');
gridcell.RicoFormula=null;
if (clipcell.formula) {
gridcell.RicoFormula=Object.extend({}, clipcell.formula);
gridcell.RicoFormula.cell=gridcell;
gridcell.RicoValue = gridcell.RicoFormula.eval();
this.updateDependencies(gridcell,'add');
} else {
gridcell.RicoValue=clipcell.value;
}
this.checkDependencies(gridcell);
}
if (pasteType=='all' || pasteType=='formats') {
gridcell.style.cssText=clipcell.style;
if (typeof clipcell.format=='object')
gridcell.RicoFormat=Object.extend({}, clipcell.format);
else
gridcell.RicoFormat=clipcell.format;
}
this.formatCell(gridcell);
clipc=(clipc+1) % clipclen;
}
clipr=(clipr+1) % clipArray.length;
}
},
formatSelection: function(newFormat) {
var s=this.getSelection();
if (!s) return;
for (var r=s.r1; r<=s.r2; r++) {
for (var c=s.c1; c<=s.c2; c++) {
var gridcell=this.cell(r,c);
gridcell.RicoFormat=newFormat;
this.formatCell(gridcell);
}
}
},
handleCtrlKey: function(e) {
switch (e.keyCode) {
// Ctrl-C
case 67:
window.status='copy';
this.clip=this.copySelection();
Event.stop(e);
break;
// Ctrl-X
case 88:
window.status='cut';
this.clip=this.cutSelection();
Event.stop(e);
break;
// Ctrl-V
case 86:
window.status='paste';
this.pasteSelection(this.clip);
Event.stop(e);
break;
// Ctrl-B
case 66:
this.toggleAttr('font-weight','normal','bold');
Event.stop(e);
break;
// Ctrl-I
case 73:
this.toggleAttr('font-style','normal','italic');
Event.stop(e);
break;
// home
case 36:
this.selectCellRC(0,1);
Event.stop(e);
break;
default:
window.status=e.keyCode;
break;
}
},
handleNormalKey: function(e) {
switch (e.keyCode) {
case 112:
case 114:
case 115:
case 116:
case 117:
case 118:
case 119:
case 120:
case 121:
case 122:
case 123:
case 91:
case 45:
case 46:
case 16:
case 17:
case 18:
case 20:
case 27: return;
// tab
case 9: this.moveSelection(0,e.shiftKey ? -1 : 1,false,e); break;
// enter/return
case 13: this.moveSelection(1,0,false,e); break;
// arrow keys
case 37: this.moveSelection(0,-1,e.shiftKey,e); break;
case 38: this.moveSelection(-1,0,e.shiftKey,e); break;
case 39: this.moveSelection(0,1,e.shiftKey,e); break;
case 40: this.moveSelection(1,0,e.shiftKey,e); break;
// page up
case 33: this.moveSelection(-Math.min(this.SelectIdxStart.row,10),0,e.shiftKey,e); break;
// page down
case 34: this.moveSelection(Math.min(this.pageSize-this.SelectIdxStart.row-1,10),0,e.shiftKey,e); break;
// end
case 35: this.selectCellRC(this.SelectIdxStart.row,this.columns.length-1); Event.stop(e); break;
// home
case 36: this.selectCellRC(this.SelectIdxStart.row,1); Event.stop(e); break;
// F2
case 113: this.showInputArea(false,e); break;
default:
window.status=e.keyCode;
this.showInputArea(true,e); break;
}
return false;
},
gridKeydown: function(e) {
if (e.altKey) return;
var elem=Event.element(e);
if (elem.id=='inputArea') return true;
//window.status='gridKeydown keyCode='+e.keyCode;
if (e.ctrlKey)
this.handleCtrlKey(e);
else
this.handleNormalKey(e);
},
toggleAttr: function(attr,v1,v2) {
var v=this.getStyle(this.SelectIdxStart.row,this.SelectIdxStart.column,attr);
v=v==v2 ? v1 : v2;
this.updateSelectionStyle(attr,v);
},
getStyle: function(row,col,attr) {
var csstxt=this.columns[col].cell(row).style.cssText;
if (!csstxt) return;
if (csstxt.charAt(csstxt.length-1)!=';') csstxt+=';'; // opera
csstxt=' '+csstxt;
var re=new RegExp("[ ;]"+attr+"\\s*:\\s*([^ ;]*)\\s*;","i");
if (re.test(csstxt))
return RegExp.$1;
else
return;
},
updateStyleText: function(csstxt,attr,value) {
var newval=attr+':'+value+';';
if (!csstxt) return newval;
csstxt=' '+csstxt.strip();
if (csstxt.charAt(csstxt.length-1)!=';') csstxt+=';'; // opera
var re=new RegExp("([ ;])"+attr+"\\s*:\\s*([^ ;]*)\\s*;","i");
// safari must process the regexp twice, everyone else can run it once
if (re.test(csstxt))
return Prototype.Browser.WebKit ? csstxt.replace(re,"$1"+newval) : RegExp.leftContext+RegExp.$1+newval+RegExp.rightContext;
else
return csstxt+newval;
},
updateSelectionStyle: function(attr,newVal) {
var s=this.getSelection();
if (!s) return;
for (var c=s.c1; c<=s.c2; c++) {
var col=this.columns[c];
for (var r=s.r1; r<=s.r2; r++)
col.cell(r).style.cssText=this.updateStyleText(col.cell(r).style.cssText,attr,newVal);
}
},
showHelp: function(e) {
Event.stop(e);
if (this.helpWindow) {
this.helpWindow.openPopup();
} else {
var msg="
Keys";
msg+="
The following keyboard actions are supported:";
msg+="
";
msg+="
Arrows keys";
msg+="
Home, End, PgUp, PgDn";
msg+="
F2 - edit cell";
msg+="
Ctrl-C = copy";
msg+="
Ctrl-X = cut";
msg+="
Ctrl-V = paste";
msg+="
";
msg+="
Formulas";
msg+="
Formulas starting with '=' are supported.";
msg+="
";
msg+="
Formulas may contain parentheses and the following operators:";
msg+=" + - * / & % = > < <= >= <>";
msg+="
'+' follows javascript rules regarding type conversion (which are slightly different from Excel)";
msg+="
Formulas may refer to cells using 'A1' notation (and 'A1:B2' for ranges).";
msg+="
The following functions are supported in formulas:";
var funclist=[];
for (var funcname in Rico.Formula.prototype) {
if (funcname.substring(0,5)=='eval_') funclist.push(funcname.substring(5));
}
funclist.sort();
msg+=" "+funclist.join(', ');
msg+="
";
msg+="
Copy/Paste";
msg+="
You can only copy/paste data within this spreadsheet - not from/to external applications.";
msg+="
Future functionality may include copy/paste from external applications, load/save, date formatting, and support for additional functions.";
this.helpWindow=new Rico.Popup({canDragFunc:true});
this.helpWindow.createWindow('Rico Spreadsheet',msg,'300px','300px','ricoLG_help');
this.helpWindow.openPopup(20,20);
}
},
createFormatNumber: function() {
var div = this.createDiv("fmtnum",this.outerDiv);
div.innerHTML="
"+
"
Decimal Places
"+
"
"+
"
"+
"
Negative Values
"+
"
"+
"
"+
"
Prefix
"+
"
"+
"
Suffix
"+
"
"+
"
Multiplier
"+
"
"+
"
Decimal Point
"+
"
"+
"
"+
"
Thousands Sep.
"+
"
"+
"
"+
"
"+
"
";
this.fmtNumberObj=new Rico.Popup({ignoreClicks:true, canDragFunc:function(elem){return elem.tagName.toUpperCase()!='INPUT';} }, div);
Event.observe(div, "keydown", this.checkKey.bindAsEventListener(this));
Event.observe('NumberFormat_OK', "click", this.setNumberFormat.bindAsEventListener(this));
Event.observe('NumberFormat_Cancel', "click", this.cancelNumberFormat.bindAsEventListener(this));
this.formatNumberDiv=div;
},
openFormatNumber: function(e) {
Event.stop(e || event);
this.menu.cancelmenu();
var cell=this.cell(this.SelectIdxStart.row,this.SelectIdxStart.column);
if (cell && cell.RicoFormat) {
for (var p in cell.RicoFormat) {
var elem=$(p);
if (!elem || !elem.tagName) continue;
var v=cell.RicoFormat[p].toString();
switch (elem.tagName.toLowerCase()) {
case 'input':
elem.value=v;
break;
case 'select':
var opts=elem.options;
for (var i=0; i 1, 'AA' -> 27
colLetter2Num: function(colstr) {
colstr=colstr.toUpperCase();
switch (colstr.length) {
case 1: return colstr.charCodeAt(0)-64;
case 2: return (colstr.charCodeAt(0)-64) * 26 + colstr.charCodeAt(1)-64;
default: return -1;
}
},
// 1 -> 'A', 27 -> 'AA'
colNum2Letter: function(colnum) {
if (colnum <= 26) return String.fromCharCode(64+colnum);
colnum-=1;
return String.fromCharCode(64+Math.floor(colnum / 26),65+(colnum % 26));
},
toHTML: function() {
var indentCount = 0;
var indent = function() {
var s = "|";
for (var i = 0; i < indentCount; i++) {
s += " |";
}
return s;
};
var tokensHtml = "
";
tokensHtml += "
";
tokensHtml += "
index
";
tokensHtml += "
type
";
tokensHtml += "
subtype
";
tokensHtml += "
token
";
tokensHtml += "
token tree
";
this.tokens.reset();
while (this.tokens.moveNext()) {
var token = this.tokens.current();
if (token.subtype == Rico.Formula.TOK_SUBTYPE_STOP)
indentCount -= ((indentCount > 0) ? 1 : 0);
tokensHtml += "