Copyright (c) 2005-2006 Tremend Software Consulting, Licensed under the
Academic Free License version 2.1 or BSD licenses
*/
dojo.provide("dojox.widget.iSpread");
dojo.provide("dojox.widget.iSpreadSheet");
the image from src/widget/spreadsheet/templates/buttons
* @param name the name of image (no extension)
*/
img: function(name) {
return this.iconMap[name] + " toolbarButton";
},
this.tabs[this.activeTab].sheet.insertColumnBefore();
break;
case "2": // insert row before
this.tabs[this.activeTab].sheet.insertColumnAfter();
break;
case "3": // insert row before
this.tabs[this.activeTab].sheet.removeCols();
break;
}
this.setSelectIndex(this.rowsMenu, 0);
}
},
/***Callbackforsheetmenu*@paramvalthevaluefortheitemselected*/sheetAction:function(val){if(val!="-1"){switch(val){case"1"://renamecurrentsheetvarnewVal=prompt("Enter the new name for the
sheet");
if(newVal) {
this.tabs[this.activeTab].attr("title", newVal);
this.tabs[this.activeTab].label = newVal;
}
break;
case "2": // delete current sheet
this.removeCurrentSheet();
break;
case "3": // new sheet
this.createSheet("sheet " + (this.tabs.length + 1));
break;
}
this.setSelectIndex(this.sheetMenu, 0);
}
},
setSelectIndex: function (select, index){
var options = select.getOptions();
if(options && options.length && options[index])
select.attr("value", options[index].value);
},
/** * Creates a new sheet (new ContentPane and a new sheet inside) * @param name the name of the sheet */createSheet:function(sheetName){//createthecontentpaneforthenewtabforthisnewsheetvarcurrentTabIdx=this.tabs.length;this.tabs[currentTabIdx]=newdijit.layout.ContentPane({id:"sheet"+currentTabIdx,title:sheetName});this.tabContainer.addChild(this.tabs[currentTabIdx]);//calledonce(otherwisetheselectiongetsbrokenthis.tabContainer.selectChild(this.tabs[currentTabIdx]);varv=newdojox.widget.iSpreadSheet();v.init(this.tabs[currentTabIdx]);this.tabs[currentTabIdx].sheet=v;this.activeTab=currentTabIdx;//secondcallisnecessary,sincesomepropsaresetbefore
this call
this.tabContainer.selectChild(this.tabs[currentTabIdx]);
//toolbartogglebuttonsneedtobenotifiedsothatthey
reflect the state
// of the cell (if cell has bold style, bold button must be
toggled)
dojo.connect(v, "setFormatting", this, "setFormatting");
},
object. This is useful for chaning button states
* according to cell's formatting. If one cell has bold style, the
toolbar should reflect this state
*
* @param spreadsheet the sheet that triggered the event
* @param _bold true if bold enabled, false otherwise
* @param _italic true if italic enabled, false otherwise
* @param _underline true if underline enabled, false otherwise
*/
setFormatting: function(spreadsheet, _bold, _italic, _underline) {
// this.boldItem.setSelected(_bold);
this.boldItem.attr("checked",_bold);
// this.italicItem.setSelected(_italic);
this.italicItem.attr("checked", _italic);
// this.underlineItem.setSelected(_underline);
this.underlineItem.attr("checked", _underline);
},
/** * Removes the current working sheet */removeCurrentSheet:function(){if(this.tabs.length>1){this.tabContainer.removeChild(this.tabs[this.activeTab]);for(vari=this.activeTab;i<this.tabs.length-1;i++){this.tabs[i]=this.tabs[i+1];}this.tabs.length--;this.activeTab=this.activeTab>0?this.activeTab-1:
this.activeTab;
} else {
alert("The document must have at least one sheet");
}
},
certain events that may mess up how sheet receive events
*/
tabChanged: function() {
for(var i = 0; i < this.tabs.length; i++) {
if(this.tabs[i] == this.tabContainer.selectedTabWidget) {
this.activeTab = i;
* Regular expressions for detecting cell intervals, cells or
functions /
reInterval: /[a-zA-Z]{1}[0-9]+:[a-zA-Z]{1}[0-9]+/g,
reCell: /[^a-zA-Z]{1}[a-zA-Z]{1}[0-9]+/g,
reFunction: /[a-zA-Z]{3,}[a-zA-Z0-9](/g,
/
* For detecting circular dependencies, the spreadsheet will be
represented as a
* directed graph
* The graph is represented as a matrix in which a value of 1 means
there's a direct dependency
* between node A and node B. For example, if A->B, A->C, B->D,
B->E, D->C, C->B, the graph will look like:
* A B C D E
* ____
* A | 0 1 1 0 0
* B | 0 0 0 1 1
* C | 0 1 0 0 0
* D | 0 0 1 0 0
* E | 0 0 0 0 0
*/
ssGraph: null,
/
* This object will hold a map with correspondences btw cell
notation and number in matrix
* (A1 - 0, A2 - 1, A3 - 2..., B15 - 20) /
cellGraphLookup: null,
domNode: null,
/
* /
months: ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug",
"sep", "oct", "nov", "dec"],
reDate1: /[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,4}/,
reDate2: /[0-9]{1,2}-[a-z]{3}-[0-9]{4}/,
reNumber1: /[^0-9e.]/,
getCursorPosition : function (e) {
e = e || window.event;
var cursor = {x:0, y:0};
if (e.pageX || e.pageY) {
cursor.x = e.pageX;
cursor.y = e.pageY;
} else {
var de = dojo.doc.documentElement;
var db = dojo.body;
cursor.x = e.clientX + ((de || db)["scrollLeft"]) - ((de ||
db)["clientLeft"]);
cursor.y = e.clientY + ((de || db)["scrollTop"]) - ((de ||
db)["clientTop"]);
}
return cursor;
},
postCreate:function(){},/** * Initializes the graphic widget (table, column/row headers, etc) * @param contentPane the ContentPane object corresponding to a tab
in a TabContainer
*/
init: function(contentPane) {
/***Calledwhenasheetisgainingfocus-reconnectseventhandlers*/gainFocus:function(){// make sure events are not connected twicethis.loseFocus();// dojo.event.connect(this.domNode, "onmousedown", this,
column and initializes internal data for each cell/header
*/
resetSpreadsheet: function() {
this.tbody = this.domNode.getElementsByTagName("tbody")[0];
this.rows = this.tbody.getElementsByTagName("tr");
/** * Creates the input element to display when editing a cell */createInputElem:function(){if(this.inputElem==null){this.inputElem=document.createElement("input");with(this.inputElem){type="text";className="sheetInput";style.position="absolute";style.display="none";tdElem=null;}document.body.appendChild(this.inputElem);dojo.setSelectable(this.inputElem,false);}},/***Handlesonmousedownwhichcancauseseveralrelevanteventsfor
this.debug("[onMouseUp]");
if(this.isSelectingCells) {
// unselect only if the mouse up occured on the same cell
if(this.selectionStartCell && this.selectionStartCell ==
dijit.range.getAncestor(e.target, /TD/i)) {
this.selectCellByTD(this.selectionStartCell, false);
this.focusOn(this.selectionStartCell);
}
/** * Focuses at a given location * @param _col the col coordinate where to focus * @param _row the row coordinate where to focus */focusAt:function(_col,_row){if(_row>=this.spreadsheetHeight){_row=this.spreadsheetHeight-1;}if(_col>=this.spreadsheetWidth){_col=this.spreadsheetWidth-1;}this.unfocus(this.currentFocusedCol,this.currentFocusedRow);this.currentFocusedCol=_col;this.currentFocusedRow=_row;this.selectionStartCell=this.getCell(_col,_row);this._focus(this.currentFocusedCol,this.currentFocusedRow);},/** * Internal fn which actually does the focusing * @param _col the col coordinate where to focus * @param _row the row coordinate where to focus */_focus:function(_col,_row){if(typeof(_col)!="undefined"&&typeof(_row)!="undefined"){if(_row<this.spreadsheetHeight&&_col<
this.spreadsheetWidth) {
var _tdElem = this.getCell(_col, _row);
/** * Unfocuses the cell at a given position * @param _col the col coordinate where to unfocus * @param _row the row coordinate where to unfocus */unfocus:function(_col,_row){this.hideInput();if(typeof(_col)!="undefined"&&typeof(_row)!="undefined"){if(_row<this.spreadsheetHeight&&_col<
this.spreadsheetWidth) {
var _tdElem = this.getCell(_col, _row);
to a lighter/darker blue depending on B's value (B from RGB)
* @param _col the column (0-n, where 0 corresponds to the A column
of the spreadsheet which is actually the second column of the table
* @param _row the row (0-n, 0 - corresponds similarly to row 1)
* @param _select whether to select or deselect the cell
*/
selectCell: function(_col, _row, _select) {
if(typeof(_col) != "undefined" && typeof(_row) != "undefined") {
if( _row < this.spreadsheetHeight && _col <
this.spreadsheetWidth) {
var tdElem = this.getCell(_col, _row);
if(_select){//varbgColor=
dojo.html.getBackgroundColor(tdElem.firstChild);
var bgColor = dojo.style(tdElem.firstChild, "backgroundColor");
maintained at mouse events
*/
selectRows: function(selectionEndRow) {
this.deselectAll();
this.lastSelectedRows = [];
var minRow = selectionEndRow < this.selectionStartRow ?
selectionEndRow : this.selectionStartRow;
var maxRow = selectionEndRow > this.selectionStartRow ?
selectionEndRow : this.selectionStartRow;
for(var i = minRow; i <= maxRow; i++) {
this.addRowToSelection(i);
this.selectRow(i, true);
}
// select first cell of first rowthis.focusAt(1,this.selectionStartRow);},/***Addsarowtothelistofrowstobeselected*@paramidxtheindexoftherowtobeselected*/addRowToSelection:function(idx){this.lastSelectedRows[this.lastSelectedRows.length]=idx;},/***Returnstheselectionmode.Possiblevaluesare:
SELECTION_MODES.RECTANGLE and SELECTION_MODES.RANDOM
* Random mode will be used when selecting random cells using SHIFT
& CTRL. Not supported yet.
* @return the selection mode
*/
getSelectionMode: function() {
return this.selectionMode;
},
/** * Deselects everything */deselectAll:function(){this.unfocus(this.currentFocusedCol,this.currentFocusedRow);this.resetSelectedColumns();this.resetSelectedRows();if(this.lastSelectedRegion&&this.lastSelectedRegion!=null){this.selectRegion(this.lastSelectedRegion[0],this.lastSelectedRegion[1],this.lastSelectedRegion[2],this.lastSelectedRegion[3],false);}},/** * Deselects selected columns if any */resetSelectedColumns:function(){for(vari=0;i<this.lastSelectedColumns.length;i++){this.selectColumn(this.lastSelectedColumns[i],false);}this.lastSelectedColumns=[];},/** * Deselects selected rows if any */resetSelectedRows:function(){for(vari=0;i<this.lastSelectedRows.length;i++){this.selectRow(this.lastSelectedRows[i],false);}this.lastSelectedRows=[];},/** * Resizes a column * @param e the DOM event * @param storePosition whether to store position or not (used when
the mouse is still moving)
*/
resizeCol: function(e, storePosition) {
var pos = this.getCursorPosition(e);
var newX = pos.x;
focus();}dijit.selectInputText(this.inputElem);},/** * Hides the input element and saves the value * @param isCancel whether to cancel or not the modifications to
the cell
*/
hideInput: function(isCancel) {
this.isEditing = false;
with(this.inputElem) {
// prevent this from executing twice - change the value and
hide the input only if input is visible
if(style.display == "") {
if(tdElem != null) {
if(isCancel) {
//tdElem.firstChild.innerHTML = oldValue;
tdElem.formula = oldValue;
} else {
//tdElem.firstChild.innerHTML = value;
tdElem.formula = value;
}
this.evalFormula(tdElem, true);
}
value = "";
style.display = "none";
}
}
},
(FORMATTING_TYPES.FONT, FORMATTING_TYPES.FONT_SIZE, etc)
* @param styleType the style to change
* @param styleValue the value for the style
*/
formatSelectedCells: function(styleType, styleValue) {
var sel = this.getSelection();
//sel[i][0]givesthecolumn,sel[i][1]givestherowfor(vari=0;i<sel.length;i++){vartdElem=this.getCell(sel[i][0],sel[i][1]);this.addStyleToCell(styleType,styleValue,tdElem);this.applyStylesToCell(tdElem);}},/** * Adds a style to the list of styles * @param styleType the style to change * @param styleValue the value for the style * @param tdElem the <TD> element to be formatted */addStyleToCell:function(styleType,styleValue,tdElem){if(typeof(tdElem.styleList)=="undefined"){tdElem.styleList=newArray();}//tdElem.styleList.add({style:styleType,value:styleValue});tdElem.styleList[styleType]=styleValue;},removeStyleForCell:function(style,tdElem){},/** * Applies the styles for a cell * @param tdElem the <TD> element for which styles are applied */applyStylesToCell:function(tdElem){varstyles=tdElem.styleList;if(typeof(styles)!="undefined"){//fontvarfont=styles[this.FORMATTING_TYPES.FONT];if(typeof(font)!="undefined"){tdElem.firstChild.style.fontFamily=font;}//fontsizevarfont_size=styles[this.FORMATTING_TYPES.FONT_SIZE];if(typeof(font_size)!="undefined"){tdElem.firstChild.style.fontSize=font_size;}//COLORvarcolor=styles[this.FORMATTING_TYPES.COLOR];if(typeof(color)!="undefined"){tdElem.firstChild.style.color=color;}//BG_COLORvarbgColor=styles[this.FORMATTING_TYPES.BG_COLOR];if(typeof(bgColor)!="undefined"){tdElem.firstChild.style.backgroundColor=bgColor;//varbgColor=
/***Appliesaformula*@paramformulathenameoftheformula*/applyFormula:function(functionName){// minX and maxY are used to determine where the result will be
written (in the bottom-left corner of the
// most comprehensive rectangle)
var minCol = 1000000;
var maxRow = -1;
/***Checkstheentiregraphforcircularities*@throwsanexceptionifcircularitiesaredetected*/checkCircularities:function(){varstack=newArray();try{for(vari=0;i<this.ssGraph.length;i++){stack.push(i);this.checkCircularitiesPerNode(stack,i);stack.pop();}}catch(e){throw(e);}},/***Checksthegraphforcircularitiesgivenastartvertex*@throwsanexceptionifcircularitiesaredetected*/checkCircularitiesFromNode:function(node){varstack=newArray();try{stack.push(node);this.checkCircularitiesPerNode(stack,node);stack.pop();}catch(e){throw(e+" when evaluating cell "+
circularity in the graph
* @stack the stack of visited nodes
* @param node the index of the node in the matrix (0,1,2...mxn)
where m = num cols and n = num rows
* @throws exception if circular dependencies are detected
*/
checkCircularitiesPerNode: function(stack, node) {
for(var i = 0; i < this.ssGraph.length; i++) {
// there's no need to avoid nodeX-nodeX relationships since
they're all going to be 0
if(this.ssGraph[node][i] == 1) {
// check whether the stack already contains node i
for(var k = 0; k < stack.length; k++) {
if(stack[k] == i) {
throw "Circular Dependency Detected";// for
cell: " + fromGraphNodeToCellNotation(i);
}
}
stack.push(i);
this.checkCircularitiesPerNode(stack, i);
stack.pop();
}
}
},
and reevaluating them
* @stack the stack of visited nodes
* @param node the index of the node in the matrix (0,1,2...mxn)
where m = num cols and n = num rows
* @throws exception if circular dependencies are detected
*/
reevalDependentCellsPerNode: function(stack, node) {
for(var i = 0; i < this.ssGraph.length; i++) {
if(this.ssGraph[i][node] == 1) {
for(var k = 0; k < stack.length; k++) {
if(stack[k] == i) {
throw "Circular Dependency Detected";// for
cell: " + fromGraphNodeToCellNotation(i);
}
}
this.evalFormula(cell, true, true);
stack.push(i);
this.reevalDependentCellsPerNode(stack, i);
stack.pop();
}
}
},
/**
* Returns an array containing (col,row) as they are retrieved from
the cell notation (A2, B33, etc).
* The indexes are relative to the cells spreadsheet (col 0 - is
actually the second column - 1st one is the header)
* @param cellNotation a string representing the cell notation
* @return an object with two properties: col and row /
fromCellNotationToArr: function(cellNotation) {
var letter = "" + cellNotation.match(/[a-zA-Z]/);
var number = "" + cellNotation.match(/[0-9]+/);
row must start from 0 (this means, you can't pass
* rowIndex and cellIndex properties of and elements. You
need to handle conversion from these properties
* to proper indexes (usually this is transparently handled by
getCellRow and getCellCol). A (0,0) will be A1 in cell
* notation
* @param col the column index (for 0 a value of 'A' will be
returned)
* @param row the row index (for 0 a value of 1 will be returned)
* @return a string representing the cell notation A1, C5, etc
*/
fromArrToCellNotation: function(col, row) {
return this.fromIdxToChar(col) + (row + 1);
},
/***Utilityfunctionfortransformingacharcodetoit's
correspondent in number (a-0, b-1,...)
* @param ch the char
* @return a number
*/
fromCharToIdx: function(ch) {
return ch.toLowerCase().charCodeAt(0) - "a".charCodeAt(0);
},
char (0-a, 1-b, ...)
* @idx the index
* @return an uppercase string with one letter
*/
fromIdxToChar: function(idx) {
return String.fromCharCode("a".charCodeAt(0) +
idx).toUpperCase();
},
spreadsheet for a element (ignoring cell headers)
* @param tdElem the element
* @return the column index
*/
getCellCol: function (tdElem) {
return tdElem.cellIndex - 1;
},
For example, getCell(0,0) should return the first cell
* on the first row (ignoring first column and the thead).
* @param col a number representing the col of the cell in the
spreadsheet. Starts from 0 (0 being the equivalent of column A).
* @param row a number representing the row of the cell in the
spreadsheet. Starts from 0 (0 being the equivalent of row 1).
* @return a object
*/
getCell: function (col, row) {
if(dojo.isIE) {
return this.rows[row].cells[col + 1];
} else {
return this.rows[row].cells[col + 1];
}
},
the dependencies
* @return a string with the entire graph
*/
debugGraph: function() {
var str = " ";
for(vari=0;i<this.ssGraph[0].length;i++){str+=this.fromGraphNodeToCellNotation(i)+" ";}str+="\n";for(varr=0;r<this.ssGraph.length;r++){str+=this.fromGraphNodeToCellNotation(r)+": [";for(varc=0;c<this.ssGraph[r].length;c++){str+=" "+this.ssGraph[r][c]+",";}str+="]\n"}returnstr;},/** * Returns the number of quotation marks ignoring the escaped one * @param str the string too look for quotation inside * @param start an integer representing the position to start
looking for
* @param stop an integer representing the position to stop
looking for
*/
getNumberOfQuotes: function(str, start, stop) {
var numQuotes = 0;
for(var i = start; i < stop; i++) {
if(str.charAt(i) == '"') {
if(numQuotes % 2 == 1 && i > 0 && str.charAt(i - 1) ==
"\") {
if(i > 1 && str.charAt(i - 2) == "\") {
numQuotes ++;
}
} else {
numQuotes ++;
}
}
}
return numQuotes;
},
cell
* @cell the spreadsheet cell which has amongst other
properties a formula property which is a
* String containing the formula. Examples of
strings are:
* sum(e4:b6),
sum(e2,b4,c5)+cos(3.14)avg(1,2,3), etc
* @evaluate if true, the cell's value will be evaluated
again. If false, if the cell's type has
* been detected and its formula has been
analyzed, return directly the value
* @noDependencies if true, dependencies are not re-evaluated
* @return the result of the formula /
evalFormula: function(_cell, evaluate, noDependencies) {
var cellNotation =
this.fromArrToCellNotation(this.getCellCol(_cell), this.getCellRow(_cell));
var formula = _cell.formula;
var errors = false;
if(formula==""||typeof(formula)=="undefined"){return"";}//acell's value it'saformulaonlyifitstartswith"="if(!evaluate&&_cell.cellType!=this.CELL_TYPES.FORMULA){return_cell.formula;}varresult;varoriginalGraphNode=
this.fromCellToGraphNode(this.getCellCol(_cell), this.getCellRow(_cell));
if(trim("" + formula).charAt(0) != "=") {
// try to detect a type for the cell (date, string, number)
var tmp = formula.toLowerCase();
//checkifit's a datevar_val;if((_val=this.parseDateFormat1(tmp))!=null){_cell.cellType=this.CELL_TYPES.DATE;}elseif((_val=this.parseDateFormat2(tmp))!=null){_cell.cellType=this.CELL_TYPES.DATE;}elseif((_val=this.parseNumberFormat1(tmp))!=null){//checkifit's a number_cell.cellType=this.CELL_TYPES.NUMBER;}else{//ifnoneoftheabove,consideritastring_val=formula;_cell.cellType=this.CELL_TYPES.STRING;}_cell.formula=_val;result=_val;}else{_cell.cellType=this.CELL_TYPES.FORMULA;this.debug("STEP 1: transform intervals of cells for "+
cellNotation + ": " + _cell.formula);
/**********
STEP 1: transform intervals of cells to array of cells
(B2:C3 => B2,B3,C2,C3
***********/
var pcs = formula.match(this.reInterval);
// remove the last commainlinedInterval=inlinedInterval.substring(0,
inlinedInterval.length - 1);
// replaced interval with inline formula// for each occ of cells, replace it with
inlinedInterval
var cellsPos = 0;
while((cellsPos = inlinedFormula.indexOf(pcs[i],
cellsPos)) != -1) {
// check the number of " chars before pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, cellsPos);
inside strings
var cellPos = 0;
while((cellPos = inlinedFormula.indexOf(cell,
cellPos)) != -1) {
// check the number of " chars before pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, cellPos);
has to contain the quotes
var toReplace = "";
if(cellObj.cellType ==
this.CELL_TYPES.NUMBER) {
toReplace = cellValue;
}
if(cellObj.cellType ==
this.CELL_TYPES.STRING) {
toReplace = "\"" + cellValue + "\"";
}
if(cellObj.cellType ==
this.CELL_TYPES.FORMULA) {
toReplace = cellValue;
}
// if cell has no value, remove
previous , if exists or if previous char is ( remove next ,
// make sure the cell that have no
value don't affect the formula by leaving random commas
if(toReplace == "") {
var tmp =
trim(inlinedFormula.substring(0, cellPos));
var tmp2 =
trim(inlinedFormula.substring(cellPos + cell.length));
inlinedFormula.indexOf(functions[i], fnPos)) != -1) {
// check the number of " chars before
pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, fnPos);
***********/
this.reevalDependentCells(originalGraphNode);
} else {
this.debug("STEP 6: dependencies will NOT be
re-evaluated for cell: " + cellNotation);
}
}
_cell.firstChild.innerHTML=result;this.debug("Final result for "+cellNotation+": "+result);returnresult;//returnthis.formatCellForPresentation(cell);;},/** * Fires an event * @param evt the event to be fired */_fireEvent:function(evt){if(typeofthis[evt]=="function"){varargs=[this];for(vari=1;i<arguments.length;i++){args.push(arguments[i]);}this[evt].apply(this,args);}},/** * Formats the cell for presentation. The formatting should be
based on cell's type (number, date, string) and cell's
* format. Possible formats for date are "MM/DD/YYYY",
"DD-MMM-YYYY", etc.
* Currently cell's formats are not supported yet.
* @param cell the element to be formatted for presentation
* @return the formatted value
*/
formatCellForPresentation: function(cell) {
var formula = cell.formula;
null) {
// now, the cell format should be checked...
if(formula instanceof Date) {
with (formula) {
return getDate() + "-" +
this.months[getMonth()].toUpperCase() + "-" + getFullYear();
}
}
// now, the cell format should be checked...if(typeof(formula)=="number"){returnformula;}}},/***Createsadatefromastringparsingformat1:MM/DD/YYYY*@paramstrthestringtobeparsed*@returnaDateobjectifparsingsucceededornullifstring
could not be parsed
*/
parseDateFormat1: function(str) {
var _date = str.match(this.reDate1);
if(_date && _date != null) {
_date = "" + _date;
if(_date == trim(str)) {
var vals = _date.split("/");
var month = parseInt(vals[0]);
var day = parseInt(vals[1]);
var year = parseInt(vals[2]);
could not be parsed
*/
parseDateFormat2: function(str) {
var _date = str.match(this.reDate2);
if(_date && _date != null) {
_date = "" + _date;
if(_date == trim(str)) {
var vals = _date.split("-");
varmonth=vals[1];varfound=-1;for(vari=0;i<this.months.length;i++){if(this.months[i]==month){found=i;break;}}if(found==-1){returnnull;}varday=parseInt(vals[0]);varyear=parseInt(vals[2]);if(this.isDateValid(day,month,year)){if(year<100&&year>=30){year=2000+year;}elseif(year<100){year=1900+year;}vardateObj=newDate();dateObj.setFullYear(year);dateObj.setMonth(found);dateObj.setUTCDate(day);returndateObj;}}}returnnull;},/** * Creates a number from a string * @param str the string to be parsed * @return an int or a float if parsing succeeded or null if string
could not be parsed
*/
parseNumberFormat1: function(str) {
var _num = str.match(this.reNumber1);
ranges for each param are good
* @param day
* @param month
* @param year
*/
isDateValid: function(day, month, year) {
if(month < 1 && month > 12 && day < 1 && day > 31) {
return false;
}
// TODO check valid date
return true;
},
function product() {
var _product = 1;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
_product *= arguments[i];
}
}
return _product;
}
var abs = Math.abs;
var acos = Math.acos;
var asin = Math.asin;
var atan = Math.atan;
var atan2 = Math.atan2;
var ceil = Math.ceil;
var cos = Math.cos;
var exp = Math.exp;
var floor = Math.floor;
var log = Math.log;
var pow = Math.pow;
var random = Math.random;
var round = Math.round;
var sin = Math.sin;
var sqrt = Math.sqrt;
var tan = Math.tan;
/**************
TEXT FUNCTIONS ***************/
function len() {
if(arguments != null && arguments.length > 0) {
return arguments[0].length;
}
}
/**
Academic Free License version 2.1 or BSD licenses
*/
dojo.provide("dojox.widget.iSpread");
dojo.provide("dojox.widget.iSpreadSheet");
dojo.require("dojo.string");
dojo.require("dojo.colors");
dojo.require("dijit._Widget");
dojo.require("dijit.ColorPalette");
dojo.require("dijit.Toolbar");
dojo.require("dijit.form.Button");
dojo.require("dijit.form.ToggleButton");
dojo.require("dijit.form.TextBox");
dojo.require("dijit.ColorPalette");
dojo.require("dijit.form.Select");
dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.ContentPane");
dojo.require("dijit._editor.range");
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number].toString()
: match
;
});
};
dojo.declare(
"dojox.widget.iSpread",
dijit._Widget,
{
templateCssPath: dojo.moduleUrl("dojox.widget",
"ispread/templates/common.css"),
tc: null,
tabContainer: null,
tabs: [],
activeTab: null,
boldItem: null,
italicItem: null,
underlineItem: null,
colorItem: null,
bgcolorItem: null,
fontMenu: null,
fontSizeMenu: null,
rowsMenu: null,
colsMenu: null,
sheetMenu: null,
functionsMenu: null,
iconMap: { justifyleft:"justifyleft",
justifycenter:"justifycenter",
justifyright:"justifyright",
justifyfull:"justifyfull",
bold:"bold",
italic:"italic",
underline: "underline",
forecolor:"forecolor",
backcolor:"backcolor"},
button: function(iconClass){
return new dijit.form.Button({label: "button", showLabel: false, iconClass:
iconClass});
},
this.domNode.appendChild(tb.domNode);
tb.addChild(this.button(this.img("justifyleft")));
tb.addChild(this.button(this.img("justifycenter")));
tb.addChild(this.button(this.img("justifyright")));
tb.addChild(this.button(this.img("justifyfull")));
this.fontMenu = new dijit.form.Select( {
name: "formatBlock",
options: [
{label: "Font", value: "-1"},
{label: "Serif", value: "serif"},
{label: "Sans-serif", value: "sans-serif"},
{label: "Cursive", value: "cursive"},
{label: "Fantasy", value: "fantasy"},
{label: "Monospace", value: "monospace"}
]
});
dojo.connect(this.fontMenu, "onChange", this, "changeFont");
//this.fontMenu.domNode.getElementsByTagName("select")[0].style.width="80px";
tb.addChild(this.fontMenu);
this.fontSizeMenu = new dijit.form.Select(
{
name: "formatBlock",
options: [
{label: "Size", value: "-1"},
{label: "10", value : "10"},
{label: "12", value : "12"},
{label: "14", value : "14"},
{label: "16", value : "16"},
{label: "18", value : "18"},
{label: "24", value : "24"},
{label: "32", value : "32"},
{label: "40", value : "40"}
]
});
dojo.connect(this.fontSizeMenu, "onChange", this, "changeFontSize");
//this.fontSizeMenu.domNode.style.width="55px";
tb.addChild(this.fontSizeMenu);
this.boldItem = new dijit.form.ToggleButton({showlabel:false, iconClass:
this.img("bold")});
dojo.connect(this.boldItem, "onClick", this, "makeBold");
tb.addChild(this.boldItem);
this.italicItem = new dijit.form.ToggleButton({showlabel:false, iconClass:
this.img("italic")});
dojo.connect(this.italicItem, "onClick", this, "makeItalic");
tb.addChild(this.italicItem);
this.underlineItem = new dijit.form.ToggleButton({showlabel:false,
iconClass: this.img("underline")});
dojo.connect(this.underlineItem, "onClick", this, "makeUnderline");
tb.addChild(this.underlineItem);
tb.addChild(new dijit.ToolbarSeparator());
// color dialog
var palette = new dijit.ColorPalette({palette:"3x4", style: "display:
none"});
this.colorItem = new dijit.form.DropDownButton(
{iconClass: this.img("forecolor"),
dropDown: palette});
this.colorItem.colorPalette = palette;
dojo.connect(this.colorItem.colorPalette, "onChange", this, "changeColor");
tb.addChild(this.colorItem);
palette = new dijit.ColorPalette({palette:"3x4", style: "display: none"});
this.bgcolorItem = new dijit.form.DropDownButton(
{iconClass: this.img("backcolor"),
dropDown: palette});
this.bgcolorItem.bgcolorPalette = palette;
dojo.connect(this.bgcolorItem.bgcolorPalette, "onChange", this,
"changeBGColor");
tb.addChild(this.bgcolorItem);
this.sheetMenu = new dijit.form.Select({
name: "sheetMenu",
options: [
{label: "Sheet", value : "-1"},
{label: "Rename", value : "1"},
{label: "Delete", value : "2"},
{label: "New", value : "3"}
]
});
dojo.connect(this.sheetMenu, "onChange", this, "sheetAction");
//this.sheetMenu.domNode.style.width="65px";
tb.addChild(this.sheetMenu);
this.functionsMenu = new dijit.form.Select({
name: "functionsMenu",
options: [
{label: "Functions", value : "-1"},
{label: "Sum", value: "sum"},
{label: "Product", value : "product"},
{label: "Average", value : "avg"},
{label: "Min", value : "min"},
{label: "Max", value : "max"},
{label: "Count", value: "count"}
]
});
dojo.connect(this.functionsMenu, "onChange", this, "applyFunction");
//this.functionsMenu.domNode.style.width="85px";
tb.addChild(this.functionsMenu);
},
the image from src/widget/spreadsheet/templates/buttons
* @param name the name of image (no extension)
*/
img: function(name) {
return this.iconMap[name] + " toolbarButton";
},
this.tabContainer = new dijit.layout.TabContainer({style: "height: 100%;
width: 100%;", tabPosition: "bottom"});
this.domNode.appendChild(this.tabContainer.domNode);
dojo.connect(this.tabContainer, "selectChild", this, "tabChanged");
this.tabContainer.startup();
},
this.tabs[this.activeTab].sheet.insertColumnBefore();
break;
case "2": // insert row before
this.tabs[this.activeTab].sheet.insertColumnAfter();
break;
case "3": // insert row before
this.tabs[this.activeTab].sheet.removeCols();
break;
}
this.setSelectIndex(this.rowsMenu, 0);
}
},
sheet");
if(newVal) {
this.tabs[this.activeTab].attr("title", newVal);
this.tabs[this.activeTab].label = newVal;
}
break;
case "2": // delete current sheet
this.removeCurrentSheet();
break;
case "3": // new sheet
this.createSheet("sheet " + (this.tabs.length + 1));
break;
}
this.setSelectIndex(this.sheetMenu, 0);
}
},
setSelectIndex: function (select, index){
var options = select.getOptions();
if(options && options.length && options[index])
select.attr("value", options[index].value);
},
this.tabs[this.activeTab].sheet.applyFormula(this.functionsMenu.attr("value"));
}
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.FONT_SIZE,
this.fontSizeMenu.attr("value"));
this.setSelectIndex(this.fontSizeMenu,0);
}
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.FONT,
this.fontMenu.attr("value"));
this.setSelectIndex(this.fontMenu, 0);
}
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.COLOR,
this.colorItem.colorPalette.attr("value"));
},
dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.BG_COLOR,
this.bgcolorItem.bgcolorPalette.attr("value"));
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.BOLD,
this.boldItem.attr("checked"));
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.ITALIC,
this.italicItem.attr("checked"));
},
this.tabs[this.activeTab].sheet.formatSelectedCells(dojox.widget.iSpreadSheet.prototype.FORMATTING_TYPES.UNDERLINE,
this.underlineItem.attr("checked"));
},
this call
this.tabContainer.selectChild(this.tabs[currentTabIdx]);
reflect the state
// of the cell (if cell has bold style, bold button must be
toggled)
dojo.connect(v, "setFormatting", this, "setFormatting");
},
object. This is useful for chaning button states
* according to cell's formatting. If one cell has bold style, the
toolbar should reflect this state
*
* @param spreadsheet the sheet that triggered the event
* @param _bold true if bold enabled, false otherwise
* @param _italic true if italic enabled, false otherwise
* @param _underline true if underline enabled, false otherwise
*/
setFormatting: function(spreadsheet, _bold, _italic, _underline) {
// this.boldItem.setSelected(_bold);
this.boldItem.attr("checked",_bold);
// this.italicItem.setSelected(_italic);
this.italicItem.attr("checked", _italic);
// this.underlineItem.setSelected(_underline);
this.underlineItem.attr("checked", _underline);
},
this.activeTab;
} else {
alert("The document must have at least one sheet");
}
},
certain events that may mess up how sheet receive events
*/
tabChanged: function() {
for(var i = 0; i < this.tabs.length; i++) {
if(this.tabs[i] == this.tabContainer.selectedTabWidget) {
this.activeTab = i;
);
// dojo.widget.defineWidget(
dojo.declare(
"dojox.widget.iSpreadSheet",
dijit._Widget,
{
CELL_TYPES: { NUMBER:0, STRING:1, DATE:2, FORMULA:3 },
FORMATTING_TYPES: { FONT:0, FONT_SIZE:1, COLOR:2, BG_COLOR:3,
BOLD:4, ITALIC:5, UNDERLINE:6, ALIGN:7 },
FORMULAS: { SUM:0, AVG:0 },
//serif', 'sans-serif', 'cursive', 'fantasy', and 'monospace
MINIMUM_CELL_WIDTH: 12,
MINIMUM_CELL_HEIGHT: 12,
currentFocusedCol : 0,
currentFocusedRow : 0,
tbody: null,
rows: null,
SELECTION_MODES: { RECTANGLE:0, RANDOM:1 },
selectionMode: 0,
// properties for cell selection
isSelectingCells: false,
selectionStartCell: null,
lastSelectedRegion : null,
// properties for column selection
isSelectingColumns: false,
selectionStartColumn: null,
lastSelectedColumns: [],
// properties for row selection
isSelectingRows: false,
selectionStartRow: null,
lastSelectedRows: [],
// properties needed for horizontal resizing of columns
isResizingHorizontal: false,
resizeOrigXPos: 0,
resizeOrigTH: null,
// properties needed for vertical resizing of rows
isResizingVertical: false,
resizeOrigYPos: 0,
resizeOrigTD: null,
// properties for editing
isEditing: false,
inputElem: null,
spreadsheetWidth: 0,
spreadsheetHeight: 0,
isChrome: false,
isIE: false,
/**
functions
/
reInterval: /[a-zA-Z]{1}[0-9]+:[a-zA-Z]{1}[0-9]+/g,
reCell: /[^a-zA-Z]{1}[a-zA-Z]{1}[0-9]+/g,
reFunction: /[a-zA-Z]{3,}[a-zA-Z0-9](/g,
/
* For detecting circular dependencies, the spreadsheet will be
represented as a
* directed graph
* The graph is represented as a matrix in which a value of 1 means
there's a direct dependency
* between node A and node B. For example, if A->B, A->C, B->D,
B->E, D->C, C->B, the graph will look like:
* A B C D E
* ____
* A | 0 1 1 0 0
* B | 0 0 0 1 1
* C | 0 1 0 0 0
* D | 0 0 1 0 0
* E | 0 0 0 0 0
*/
ssGraph: null,
/
* This object will hold a map with correspondences btw cell
notation and number in matrix
* (A1 - 0, A2 - 1, A3 - 2..., B15 - 20)
/
cellGraphLookup: null,
domNode: null,
/
*
/
months: ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug",
"sep", "oct", "nov", "dec"],
reDate1: /[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{1,4}/,
reDate2: /[0-9]{1,2}-[a-z]{3}-[0-9]{4}/,
reNumber1: /[^0-9e.]/,
getCursorPosition : function (e) {
e = e || window.event;
var cursor = {x:0, y:0};
if (e.pageX || e.pageY) {
cursor.x = e.pageX;
cursor.y = e.pageY;
} else {
var de = dojo.doc.documentElement;
var db = dojo.body;
cursor.x = e.clientX + ((de || db)["scrollLeft"]) - ((de ||
db)["clientLeft"]);
cursor.y = e.clientY + ((de || db)["scrollTop"]) - ((de ||
db)["clientTop"]);
}
return cursor;
},
in a TabContainer
*/
init: function(contentPane) {
dojo.setSelectable(this.domNode, false);
//browser detection
this.isIE = /msie/i.test(navigator.userAgent);
this.isChrome = /chrome/i.test(navigator.userAgent);
},
*/
loseFocus: function() {
// dojo.event.disconnect(this.domNode, "onmousedown", this,
"onMouseDown");
dojo.disconnect(this.domNode, "onmousedown", this, "onMouseDown");
// dojo.event.disconnect(this.domNode, "onmousemove", this,
"onMouseMove");
dojo.disconnect(this.domNode, "onmousemove", this, "onMouseMove");
// dojo.event.disconnect(this.domNode, "onmouseup", this,
"onMouseUp");
dojo.disconnect(this.domNode, "onmouseup", this, "onMouseUp");
// dojo.event.disconnect(this.domNode, "onmouseover", this,
"onMouseOver");
dojo.disconnect(this.domNode, "onmouseover", this, "onMouseOver");
// dojo.event.disconnect(document, "onkeypress", this,
"onKeyPress");
dojo.disconnect(document, "onkeypress", this, "onKeyPress");
// dojo.event.disconnect(document, "onkeyup", this, "onKeyUp");
dojo.disconnect(document, "onkeyup", this, "onKeyUp");
// dojo.event.disconnect(this.domNode, "ondblclick", this,
"onDblClick");
dojo.disconnect(this.domNode, "ondblclick", this, "onDblClick");
},
"onMouseDown");
dojo.connect(this.domNode, "onmousedown", this, "onMouseDown");
// dojo.event.connect(this.domNode, "onmousemove", this,
"onMouseMove");
dojo.connect(this.domNode, "onmousemove", this, "onMouseMove");
// dojo.event.connect(this.domNode, "onmouseup", this,
"onMouseUp");
dojo.connect(this.domNode, "onmouseup", this, "onMouseUp");
// dojo.event.connect(this.domNode, "onmouseover", this,
"onMouseOver");
dojo.connect(this.domNode, "onmouseover", this, "onMouseOver");
// dojo.event.connect(document, "onkeypress", this,
"onKeyPress");
dojo.connect(document, "onkeypress", this, "onKeyPress");
// dojo.event.connect(document, "onkeyup", this, "onKeyUp");
dojo.connect(document, "onkeyup", this, "onKeyUp");
// dojo.event.connect(this.domNode, "ondblclick", this,
"onDblClick");
dojo.connect(this.domNode, "ondblclick", this, "onDblClick");
},
TabContainer
*/
createSpreadsheetCells: function(contentPane) {
var html = '';
html += '
html += '<table class="sheet" cellspacing="0" cellpadding="0"
this.rows.length;
this.ssGraph = new Array();
this.cellGraphLookup[String.fromCharCode("A".charCodeAt(0) + i) + j] = j *
this.spreadsheetWidth + i;
}
}
},
column and initializes internal data for each cell/header
*/
resetSpreadsheet: function() {
this.tbody = this.domNode.getElementsByTagName("tbody")[0];
this.rows = this.tbody.getElementsByTagName("tr");
errors when using firstChild.firstChild
//if(this.rows[i].cells[0].firstChild &&
this.rows[i].cells[0].firstChild.firstChild) {
this.rows[i].cells[0].firstChild.firstChild.innerHTML =
"" + (i + 1);
//}
//[D]this.rows[i].dHeight =
dojo.html.getInnerHeight(this.rows[i]);
this.rows[i].dHeight = dojo.position(this.rows[i]).h;
for(var j = 0; j < this.rows[i].cells.length; j++) {
//[D]var tmpW =
dojo.html.getInnerWidth(this.rows[i].cells[j].firstChild) + (
dojo.render.html.ie ? 2 : 3);
var tmpW = dojo.position(this.rows[i].cells[j].firstChild).w + (dojo.isIE ?
2 : 3);
//[D]var tmpH =
dojo.html.getInnerHeight(this.rows[i].cells[j].firstChild) + (
dojo.render.html.ie ? 3 : 3);
var tmpH = dojo.position(this.rows[i].cells[j].firstChild).h + (dojo.isIE ?
3 : 3);
this.rows[i].cells[j].firstChild.dWidth = tmpW;
this.rows[i].cells[j].firstChild.style.width = tmpW;
this.rows[i].cells[j].firstChild.dHeight = tmpH;
this.rows[i].cells[j].firstChild.style.height = tmpH;
//var bgColor =
dojo.html.getBackgroundColor(this.rows[i].cells[j].firstChild);
var bgColor = dojo.style(this.rows[i].cells[j].firstChild,
"backgroundColor");
//[D]this.rows[i].cells[j].firstChild.dBackgroundColor
= dojo.graphics.color.rgb2hex(bgColor[0], bgColor[1], bgColor[2]);
this.rows[i].cells[j].firstChild.dBackgroundColor = bgColor;
// dojo.html.disableSelection(this.rows[i].cells[j]);
dojo.setSelectable(this.rows[i].cells[j], false);
//
dojo.html.disableSelection(this.rows[i].cells[j].firstChild);
dojo.setSelectable(this.rows[i].cells[j].firstChild, false);
}
this.rows[i].cells[0].getElementsByTagName("div");
for(var ss = 0; ss < cucu.length; ss++) {
cucu[ss].style.width = "20px";
}
this.rows[i].cells[0].style.width = "20px";
this.rows[i].cells[0].firstChild.style.height = "20px";
this.rows[i].cells[0].firstChild.firstChild.style.height =
"18px";
this.rows[i].cells[0].firstChild.firstChild.nextSibling.style.height =
"2px";
}
ths[i].dWidth = dojo.position(ths[i]).w;
if(ths[i].firstChild && ths[i].firstChild.firstChild) {
ths[i].firstChild.firstChild.innerHTML =
String.fromCharCode("A".charCodeAt(0) + i - 1);
}
dojo.setSelectable(ths[i], false);
dojo.setSelectable(ths[i].firstChild, false);
dojo.setSelectable(ths[i].firstChild.firstChild, false);
}
},
spreadsheet: focusing, selection, resizing
*/
onMouseDown: function(e) {
this.debug("[onMouseDown]");
var target = (e.target)? e.target: e.srcElement;
//[D]var inputElem = dojo.html.getParentByType(e.target,
"INPUT");
var inputElem = dijit.range.getAncestor(target,/INPUT/i);
if(inputElem && dojo.hasClass(inputElem, "sheetInput")) {
return;
}
"TD");
var currentTDElem = dijit.range.getAncestor(target, /TD/i);
if(currentTDElem && dojo.hasClass(currentTDElem, "sheetCell")) {
this.isSelectingCells = true;
this.selectionStartCell = currentTDElem;
this.selectCellByTD(this.selectionStartCell, true);
e.preventDefault();
}
"DIV");
var currentDIVElem = dijit.range.getAncestor(target, /DIV/i);
if(currentDIVElem && dojo.hasClass(currentDIVElem,
"horizontalResizer")) {
this.isResizingHorizontal = true;
var pos = this.getCursorPosition(e);
this.resizeOrigXPos = pos.x;
//[D]this.resizeOrigTH =
dojo.html.getParentByType(e.target, "TH");
this.resizeOrigTH = dijit.range.getAncestor(target, /TH/i);
}
if(currentDIVElem && dojo.hasClass(currentDIVElem,
"verticalResizer")) {
this.isResizingVertical = true;
var pos = this.getCursorPosition(e);
this.resizeOrigYPos = pos.y;
//[D]this.resizeOrigTD =
dojo.html.getParentByType(e.target, "TD");
this.resizeOrigTD = dijit.range.getAncestor(target, /TD/i);
}
"TH");
var currentTH = dijit.range.getAncestor(target, /TH/i);
if(currentTH) {
this.isSelectingColumns = true;
this.selectionStartColumn = currentTH.dCellIndex;
this.selectColumns(this.selectionStartColumn);
}
dojo.html.getParentByType(e.target, "TD");
var currentTDRowHeader = dijit.range.getAncestor(target, /TD/i);
if(currentTDRowHeader && dojo.hasClass(currentTDRowHeader,
"sheetRow1stCell")) {
this.isSelectingRows = true;
this.selectionStartRow =
this.getCellRow(currentTDRowHeader);
this.selectRows(this.selectionStartRow);
}
}
this.debug("[onMouseDown]");
},
as mouse moves
*/
onMouseMove: function(e) {
this.debug("[onMouseMove]");
if(this.isResizingHorizontal) {
this.resizeCol(e, false);
}
this.debug("[/onMouseMove]");
},
this.debug("[onMouseOver]");
if(this.isSelectingCells) {
var currentTDElem = dijit.range.getAncestor(e.target,
/TD/i);
if(currentTDElem && dojo.hasClass(currentTDElem,
"sheetCell")) {
this.deselectAll();
var sCol = this.getCellCol(this.selectionStartCell);
var sRow = this.getCellRow(this.selectionStartCell);
var cCol = this.getCellCol(currentTDElem);
var cRow = this.getCellRow(currentTDElem);
this.debug("isSelectingCells[c{0},r{1},c{2},r{3}]".format(sCol, sRow,
cCol, cRow));
this.selectRegion(
cCol,
sCol,
cRow,
sRow,
true);
}
}
detect in each case the column
var currentTDElem = dijit.range.getAncestor(e.target,
/TD/i);
"sheetCell")) {
var selectionEndColumn = this.getCellCol(currentTDElem);
this.selectColumns(selectionEndColumn);
} else {
var currentTHElem = dijit.range.getAncestor(e.target,
/TH/i);
/TD/i);
if(currentTDElem &&
(dojo.hasClass(currentTDElem, "sheetCell") ||
dojo.hasClass(currentTDElem, "sheetRow1stCell"))) {
var selectionEndRow = this.getCellRow(currentTDElem);
this.selectRows(selectionEndRow);
}
}
this.debug("[/onMouseOver]");
},
this.debug("[onMouseUp]");
if(this.isSelectingCells) {
// unselect only if the mouse up occured on the same cell
if(this.selectionStartCell && this.selectionStartCell ==
dijit.range.getAncestor(e.target, /TD/i)) {
this.selectCellByTD(this.selectionStartCell, false);
this.focusOn(this.selectionStartCell);
}
this.debug("[onMouseUp]");
},
this.currentFocusedRow);
this.showInputOverTD(tdElem);
keyHandled = true;
} else {
this.moveFocus(0, 1);
keyHandled = true;
}
}
if(keyCode == k.KEY_SPACE ||
(keyCode >= 41 && keyCode <= 44) ||
keyCode >= 47) {
if(!this.isEditing) {
var tdElem = this.getCell(this.currentFocusedCol,
this.currentFocusedRow);
this.showInputOverTD(tdElem);
if(!dojo.isIE) {
this.inputElem.value = String.fromCharCode(keyCode);
}
}
}
var k = dojo.keys;
var keyHandled = false;
this.currentFocusedRow);
this.currentFocusedCol = newCol;
this.currentFocusedRow = newRow;
this._focus(this.currentFocusedCol, this.currentFocusedRow);
}
},
this.spreadsheetWidth) {
this.focusAt(_col, _row);
}
},
this.spreadsheetWidth) {
var _tdElem = this.getCell(_col, _row);
_tdElem.styleList[this.FORMATTING_TYPES.BOLD] ?
_tdElem.styleList[this.FORMATTING_TYPES.BOLD] : false;
_italic =
_tdElem.styleList[this.FORMATTING_TYPES.ITALIC] ?
_tdElem.styleList[this.FORMATTING_TYPES.ITALIC] : false;
_underline =
_tdElem.styleList[this.FORMATTING_TYPES.UNDERLINE] ?
_tdElem.styleList[this.FORMATTING_TYPES.UNDERLINE] : false;
}
this._fireEvent("setFormatting", _bold, _italic,
_underline);
(dojo.isIE ? 0 : 4));
_tdElem.firstChild.style.height = this.toPx(h -
(dojo.isIE ? 0 : 4));
dojo.addClass(_tdElem.firstChild, "focused");
}
}
},
this.spreadsheetWidth) {
var _tdElem = this.getCell(_col, _row);
this.debug("col1={0}, col2={1}, row1={2}, row2={3},
_select={4}".format(col1, col2, row1, row2, _select));
var minCol = col1 < col2 ? col1 : col2;
var maxCol = col1 > col2 ? col1 : col2;
var minRow = row1 < row2 ? row1 : row2;
var maxRow = row1 > row2 ? row1 : row2;
this.getCellRow(_tdElem), _select);
}
},
to a lighter/darker blue depending on B's value (B from RGB)
* @param _col the column (0-n, where 0 corresponds to the A column
of the spreadsheet which is actually the second column of the table
* @param _row the row (0-n, 0 - corresponds similarly to row 1)
* @param _select whether to select or deselect the cell
*/
selectCell: function(_col, _row, _select) {
if(typeof(_col) != "undefined" && typeof(_row) != "undefined") {
if( _row < this.spreadsheetHeight && _col <
this.spreadsheetWidth) {
var tdElem = this.getCell(_col, _row);
dojo.html.getBackgroundColor(tdElem.firstChild);
var bgColor = dojo.style(tdElem.firstChild, "backgroundColor");
// bgColor[1] = bgColor[1] > 128 ? bgColor[1] - 32
//[D]tdElem.firstChild.style.backgroundColor =
dojo.graphics.color.rgb2hex(bgColor[0], bgColor[1], bgColor[2]);
//tdElem.firstChild.style.backgroundColor =
dojo.gfx.color.rgb2hex(bgColor[0], bgColor[1], bgColor[2]);
tdElem.firstChild.style.backgroundColor = bgColor;
} else {
tdElem.firstChild.style.backgroundColor =
tdElem.firstChild.dBackgroundColor;
}
}
}
},
one is maintained at mouse events
*/
selectColumns: function(selectionEndColumn) {
this.unfocus(this.currentFocusedCol, this.currentFocusedRow);
this.deselectAll();
this.lastSelectedColumns = [];
var minCol = selectionEndColumn < this.selectionStartColumn ?
selectionEndColumn : this.selectionStartColumn;
var maxCol = selectionEndColumn > this.selectionStartColumn ?
selectionEndColumn : this.selectionStartColumn;
for(var i = minCol; i <= maxCol; i++) {
this.addColumnToSelection(i);
this.selectColumn(i, true);
}
maintained at mouse events
*/
selectRows: function(selectionEndRow) {
this.deselectAll();
this.lastSelectedRows = [];
var minRow = selectionEndRow < this.selectionStartRow ?
selectionEndRow : this.selectionStartRow;
var maxRow = selectionEndRow > this.selectionStartRow ?
selectionEndRow : this.selectionStartRow;
for(var i = minRow; i <= maxRow; i++) {
this.addRowToSelection(i);
this.selectRow(i, true);
}
SELECTION_MODES.RECTANGLE and SELECTION_MODES.RANDOM
* Random mode will be used when selecting random cells using SHIFT
& CTRL. Not supported yet.
* @return the selection mode
*/
getSelectionMode: function() {
return this.selectionMode;
},
mode is SELECTION_MODES.RANDOM
* @return a list of selected cells
*/
getSelection: function() {
var selectedCells = new Array();
this.lastSelectedRegion[1]; i++) {
for(var j = this.lastSelectedRegion[2]; j <=
this.lastSelectedRegion[3]; j++) {
selectedCells[selectedCells.length] = [i, j];
}
}
} else {
selectedCells[selectedCells.length] =
[this.currentFocusedCol, this.currentFocusedRow];
}
}
is SELECTION_MODES.RECTANGLE
* @return an array with 4 coordinates: [colStart, colEnd,
rowStart, rowEnd]
*/
getSelectionRectangle: function() {
if(this.lastSelectedRegion && this.lastSelectedRegion != null) {
return this.lastSelectedRegion;
} else {
return [this.currentFocusedCol, this.currentFocusedCol,
this.currentFocusedRow, this.currentFocusedRow];
}
},
the mouse is still moving)
*/
resizeCol: function(e, storePosition) {
var pos = this.getCursorPosition(e);
var newX = pos.x;
this.toPx(newWidth - 3);
this.resizeOrigTH.firstChild.firstChild.style.width =
this.toPx(newWidth - 5);
this.toPx(newWidth);
}
newWidth;
}
this._focus(this.currentFocusedCol,
this.currentFocusedRow);
}
//}
},
the mouse is still moving)
*/
resizeRow: function(e, storePosition) {
var pos = this.getCursorPosition(e);
var newY = pos.y;
this.toPx(newHeight);
this.rows[currentRow].cells[0].firstChild.firstChild.style.height =
this.toPx(newHeight - (dojo.isIE ? 2 : 0));
this.toPx(newHeight);
}
newHeight;
}
this._focus(this.currentFocusedCol, this.currentFocusedRow);
}
},
to be displayed
*/
showInputOverTD: function(_tdElem) {
this.isEditing = true;
//var pos = dojo.html.getAbsolutePosition(_tdElem, true);
var pos = dojo.coords(_tdElem);
//style.width = dojo.html.getBorderBox(_tdElem).width + 8;
style.width = dojo.position(_tdElem).w + 8;
//[D]style.height = dojo.html.getInnerHeight(_tdElem) + 8;
style.height = dojo.position(_tdElem).h + 8;
style.left = pos.x - 4;
style.top = pos.y - 4;
style.zIndex = 100;
style.display = "";
if(tdElem != null) {
if(typeof(tdElem.formula) == "undefined") {
value = "";
} else {
value = _tdElem.formula;
}
/if(tdElem.cellType == this.CELL_TYPES.FORMULA) {
value = tdElem.formula;
} else {
value = tdElem.firstChild.innerHTML;
}/
} else {
value = "";
}
"undefined") {
oldValue = "";
}
the cell
*/
hideInput: function(isCancel) {
this.isEditing = false;
hide the input only if input is visible
if(style.display == "") {
if(tdElem != null) {
if(isCancel) {
//tdElem.firstChild.innerHTML = oldValue;
tdElem.formula = oldValue;
} else {
//tdElem.firstChild.innerHTML = value;
tdElem.formula = value;
}
this.evalFormula(tdElem, true);
}
value = "";
style.display = "none";
}
}
},
this.currentFocusedRow);
tdElem.firstChild.innerHTML = "";
},
cell
*/
insertColumnBefore: function() {
try{
var columnToInsertBefore = this.currentFocusedCol + 1;
var thead = this.domNode.getElementsByTagName("THEAD")[0];
var ths = thead.getElementsByTagName("TH");
var newTH = ths[columnToInsertBefore].cloneNode(true);
dojo.place(newTH, ths[columnToInsertBefore], "before");
this.rows[i].cells[columnToInsertBefore].cloneNode(true);
//dojo.html.insertBefore(newTD,
this.rows[i].cells[columnToInsertBefore]);
dojo.place(newTD, this.rows[i].cells[columnToInsertBefore], "before");
}
this.resetSpreadsheet();
this.rows[i].cells[columnToInsertBefore].firstChild.innerHTML = "";
this.unfocus(columnToInsertBefore, i);
this.selectCell(columnToInsertBefore, i, false);
}
}
}catch(e){
alert(e + " $$ " + e.name + " $$ " + e.message);
}
},
dojo.place(newTH, ths[this.currentFocusedCol],"after");
this.rows[i].cells[this.currentFocusedCol].cloneNode(true);
//dojo.html.insertAfter(newTD,
this.rows[i].cells[this.currentFocusedCol]);
dojo.place(newTD, this.rows[i].cells[this.currentFocusedCol], "after");
}
this.rows = this.loadRows();
this.resetSpreadsheet();
1].firstChild.innerHTML = "";
this.unfocus(this.currentFocusedCol + 1, i);
this.selectCell(this.currentFocusedCol + 1, i,
false);
}
}
}catch(e){
alert(e + " $$ " + e.name + " $$ " + e.message);
}
},
this.rows[this.currentFocusedRow].cloneNode(true);
//dojo.html.insertBefore(newTR,
this.rows[this.currentFocusedRow]);
dojo.place(newTR, this.rows[this.currentFocusedRow], "before");
this.rows[this.currentFocusedRow].cloneNode(true);
//dojo.html.insertAfter(newTR,
this.rows[this.currentFocusedRow]);
dojo.place(newTR, this.rows[this.currentFocusedRow], "after");
this.lastSelectedRows[i];
}
} else {
rowsToRemove[rowsToRemove.length] = this.currentFocusedRow;
}
this.rows[rowsToRemove[i]].cells[0].firstChild.firstChild.innerHTML + "\n";
}
(rowsToRemove.length == 1 ? "this row?\n" : "these rows?\n") + rowStr)) {
try{
for(var i = 0; i < rowsToRemove.length; i++) {
dojo.doc.documentElement.removeNode(this.rows[rowsToRemove[i]]);
}
this.resetSpreadsheet();
this.currentFocusedRow);
}catch(e){
alert(e + " $$ " + e.name + " $$ " + e.message);
}
}
},
this.lastSelectedColumns[i];
}
} else {
columnsToRemove[columnsToRemove.length] =
this.currentFocusedCol;
}
ths[columnsToRemove[i]].firstChild.firstChild.innerHTML + "\n";
}
(columnsToRemove.length == 1 ? "this column?\n" : "these columns?\n") +
colStr)) {
try{
for(var i = 0; i < columnsToRemove.length; i++) {
dojo.doc.documentElement.removeNode(ths[columnsToRemove[i]]);
dojo.doc.documentElement.removeNode(this.rows[j].cells[columnsToRemove[i]]);
}
}
this.resetSpreadsheet();
this.currentFocusedRow);
}catch(e){
alert(e + " $$ " + e.name + " $$ " + e.message);
}
}
},
(FORMATTING_TYPES.FONT, FORMATTING_TYPES.FONT_SIZE, etc)
* @param styleType the style to change
* @param styleValue the value for the style
*/
formatSelectedCells: function(styleType, styleValue) {
var sel = this.getSelection();
dojo.html.getBackgroundColor(tdElem.firstChild);
var bgColor = dojo.style(tdElem.firstChild, "backgroundColor");
//[D]tdElem.firstChild.dBackgroundColor =
dojo.graphics.color.rgb2hex(bgColor[0], bgColor[1], bgColor[2]);
//tdElem.firstChild.dBackgroundColor = dojo.gfx.rgb2hex(bgColor[0],
bgColor[1], bgColor[2]);
tdElem.firstChild.dBackgroundColor = bgColor;
}
"underline";
} else {
tdElem.firstChild.style.textDecoration = "";
}
}
}
},
written (in the bottom-left corner of the
// most comprehensive rectangle)
var minCol = 1000000;
var maxRow = -1;
this.SELECTION_MODES.RECTANGLE) {
var cellColStart =
this.fromArrToCellNotation(this.lastSelectedRegion[0],
this.lastSelectedRegion[2]);
var cellColStop =
this.fromArrToCellNotation(this.lastSelectedRegion[1],
this.lastSelectedRegion[3]);
resultCell.formula = "=" + functionName + "(" +
cellColStart + ":" + cellColStop + ")";
this.evalFormula(resultCell, true);
} else {
// only rectangle selection mode is supported for now,
so will NEVER get here
resultCell.formula = "=" + functionName + "(";
for(var i = 0; i < sel.length; i++) {
var tdElem = this.getCell(sel[i][1], sel[i][0]);
var cellCol = String.fromCharCode("A".charCodeAt(0)
resultCell.formula = "" + cellCol + (sel[i][1] + 1)
}
resultCell.formula = ")";
this.evalFormula(resultCell, true);
}
}
},
this.fromGraphNodeToCellNotation(node));
}
},
circularity in the graph
* @stack the stack of visited nodes
* @param node the index of the node in the matrix (0,1,2...mxn)
where m = num cols and n = num rows
* @throws exception if circular dependencies are detected
*/
checkCircularitiesPerNode: function(stack, node) {
for(var i = 0; i < this.ssGraph.length; i++) {
// there's no need to avoid nodeX-nodeX relationships since
they're all going to be 0
if(this.ssGraph[node][i] == 1) {
// check whether the stack already contains node i
for(var k = 0; k < stack.length; k++) {
if(stack[k] == i) {
throw "Circular Dependency Detected";// for
cell: " + fromGraphNodeToCellNotation(i);
}
}
stack.push(i);
this.checkCircularitiesPerNode(stack, i);
stack.pop();
}
}
},
circular dependencies.
* @throws an exception if circularities are detected
*/
reevalDependentCells: function(node) {
var stack = new Array();
this.fromGraphNodeToCellNotation(node));
}
},
and reevaluating them
* @stack the stack of visited nodes
* @param node the index of the node in the matrix (0,1,2...mxn)
where m = num cols and n = num rows
* @throws exception if circular dependencies are detected
*/
reevalDependentCellsPerNode: function(stack, node) {
for(var i = 0; i < this.ssGraph.length; i++) {
if(this.ssGraph[i][node] == 1) {
for(var k = 0; k < stack.length; k++) {
if(stack[k] == i) {
throw "Circular Dependency Detected";// for
cell: " + fromGraphNodeToCellNotation(i);
}
}
this.getCellByCellNotation(this.fromGraphNodeToCellNotation(i));
the cell notation (A2, B33, etc).
* The indexes are relative to the cells spreadsheet (col 0 - is
actually the second column - 1st one is the header)
* @param cellNotation a string representing the cell notation
* @return an object with two properties: col and row
/
fromCellNotationToArr: function(cellNotation) {
var letter = "" + cellNotation.match(/[a-zA-Z]/);
var number = "" + cellNotation.match(/[0-9]+/);
row must start from 0 (this means, you can't pass
* rowIndex and cellIndex properties of and elements. You
need to handle conversion from these properties
* to proper indexes (usually this is transparently handled by
getCellRow and getCellCol). A (0,0) will be A1 in cell
* notation
* @param col the column index (for 0 a value of 'A' will be
returned)
* @param row the row index (for 0 a value of 1 will be returned)
* @return a string representing the cell notation A1, C5, etc
*/
fromArrToCellNotation: function(col, row) {
return this.fromIdxToChar(col) + (row + 1);
},
correspondent in number (a-0, b-1,...)
* @param ch the char
* @return a number
*/
fromCharToIdx: function(ch) {
return ch.toLowerCase().charCodeAt(0) - "a".charCodeAt(0);
},
char (0-a, 1-b, ...)
* @idx the index
* @return an uppercase string with one letter
*/
fromIdxToChar: function(idx) {
return String.fromCharCode("a".charCodeAt(0) +
idx).toUpperCase();
},
dependencies
*/
fromCellToGraphNode: function (col, row) {
return col + row * this.spreadsheetWidth;
},
etc)
* @param cellStr a string representing the cell notation
* @return the object
*/
getCellByCellNotation: function(cellStr) {
var cellCoords = this.fromCellNotationToArr(cellStr);
element. Note IE keeps track of TH elements also.
* (ignoring cell headers)
* @param tdElem the element
* @return the row index
*/
getCellRow: function(tdElem) {
return tdElem.parentNode.rowIndex - 1;
},
spreadsheet for a element (ignoring cell headers)
* @param tdElem the element
* @return the column index
*/
getCellCol: function (tdElem) {
return tdElem.cellIndex - 1;
},
For example, getCell(0,0) should return the first cell
* on the first row (ignoring first column and the thead).
* @param col a number representing the col of the cell in the
spreadsheet. Starts from 0 (0 being the equivalent of column A).
* @param row a number representing the row of the cell in the
spreadsheet. Starts from 0 (0 being the equivalent of row 1).
* @return a object
*/
getCell: function (col, row) {
if(dojo.isIE) {
return this.rows[row].cells[col + 1];
} else {
return this.rows[row].cells[col + 1];
}
},
the dependencies
* @return a string with the entire graph
*/
debugGraph: function() {
var str = " ";
looking for
* @param stop an integer representing the position to stop
looking for
*/
getNumberOfQuotes: function(str, start, stop) {
var numQuotes = 0;
for(var i = start; i < stop; i++) {
if(str.charAt(i) == '"') {
if(numQuotes % 2 == 1 && i > 0 && str.charAt(i - 1) ==
"\") {
if(i > 1 && str.charAt(i - 2) == "\") {
numQuotes ++;
}
} else {
numQuotes ++;
}
}
}
return numQuotes;
},
cell
* @cell the spreadsheet cell which has amongst other
properties a formula property which is a
* String containing the formula. Examples of
strings are:
* sum(e4:b6),
sum(e2,b4,c5)+cos(3.14)avg(1,2,3), etc
* @evaluate if true, the cell's value will be evaluated
again. If false, if the cell's type has
* been detected and its formula has been
analyzed, return directly the value
* @noDependencies if true, dependencies are not re-evaluated
* @return the result of the formula
/
evalFormula: function(_cell, evaluate, noDependencies) {
var cellNotation =
this.fromArrToCellNotation(this.getCellCol(_cell), this.getCellRow(_cell));
var formula = _cell.formula;
var errors = false;
this.fromCellToGraphNode(this.getCellCol(_cell), this.getCellRow(_cell));
if(trim("" + formula).charAt(0) != "=") {
// try to detect a type for the cell (date, string, number)
var tmp = formula.toLowerCase();
cellNotation + ": " + _cell.formula);
/**********
STEP 1: transform intervals of cells to array of cells
(B2:C3 => B2,B3,C2,C3
***********/
var pcs = formula.match(this.reInterval);
colIdx++) {
for(var rowIdx = cell0.row; rowIdx <=
cell1.row; rowIdx++) {
inlinedInterval +=
this.fromIdxToChar(colIdx) + (rowIdx + 1) + ",";
}
}
inlinedInterval.length - 1);
inlinedInterval
var cellsPos = 0;
while((cellsPos = inlinedFormula.indexOf(pcs[i],
cellsPos)) != -1) {
// check the number of " chars before pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, cellsPos);
cellsPos) +
inlinedInterval +
inlinedFormula.substring(cellsPos + pcs[i].length);
}
cellsPos += pcs[i].length;
}
}
}
graph for " + cellNotation + ": " + inlinedFormula);
/**********
STEP 2: search for cell notations that are not inside
strings and mark the graph
***********/
// reset the graph dependencies for this cell
for(var grIdx = 0; grIdx < this.spreadsheetWidth *
this.spreadsheetHeight; grIdx++) {
this.ssGraph[originalGraphNode][grIdx] = 0;
}
inside strings
var cellPos = 0;
while((cellPos = inlinedFormula.indexOf(cell,
cellPos)) != -1) {
// check the number of " chars before pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, cellPos);
this.fromCellNotationToArr(cell);
var graphNode =
this.fromCellToGraphNode(cellCoords.col, cellCoords.row);
" + this.fromArrToCellNotation(cellCoords.col, cellCoords.row));
this.ssGraph[originalGraphNode][graphNode]
= 1;
}
cellNotation + ", formula: " + inlinedFormula);
/**********
STEP 3: check circularities
***********/
this.checkCircularitiesFromNode(originalGraphNode);
cellNotation);
/**********
STEP 4: if no circularities, replace each cell name
with its value
***********/
var cells = inlinedFormula.match(this.reCell);
cellPos)) != -1) {
// check the number of " chars before pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, cellPos);
this.getCellByCellNotation(cell);
try {
cellValue =
this.evalFormula(cellObj, false, true);
} catch(e) {
throw e;
}
has to contain the quotes
var toReplace = "";
if(cellObj.cellType ==
this.CELL_TYPES.NUMBER) {
toReplace = cellValue;
}
if(cellObj.cellType ==
this.CELL_TYPES.STRING) {
toReplace = "\"" + cellValue + "\"";
}
if(cellObj.cellType ==
this.CELL_TYPES.FORMULA) {
toReplace = cellValue;
}
previous , if exists or if previous char is ( remove next ,
// make sure the cell that have no
value don't affect the formula by leaving random commas
if(toReplace == "") {
var tmp =
trim(inlinedFormula.substring(0, cellPos));
var tmp2 =
trim(inlinedFormula.substring(cellPos + cell.length));
after
if(cellPos > 0 &&
tmp.charAt(tmp.length - 1) == ',') {
inlinedFormula =
inlinedFormula.substring(0, cellPos - 1) +
toReplace +
inlinedFormula.substring(cellPos + cell.length);
} else {
if(cellPos > 0 &&
tmp.charAt(tmp.length - 1) == '(' &&
cellPos <
inlinedFormula.length - 1 && tmp2.charAt(0) == ',') {
inlinedFormula =
tmp +
toReplace +
tmp2.substring(1);
}
}
} else {
inlinedFormula =
inlinedFormula.substring(0,
cellPos) +
toReplace +
inlinedFormula.substring(cellPos + cell.length);
}
}
cellPos += cell.length;
}
}
}
/**********
STEP 5: turn function to lower case
***********/
var functions = inlinedFormula.match(this.reFunction);
inlinedFormula.indexOf(functions[i], fnPos)) != -1) {
// check the number of " chars before
pcs[i]
var numQuotes =
this.getNumberOfQuotes(inlinedFormula, 0, fnPos);
inlinedFormula.substring(0, fnPos) +
fnToLower +
inlinedFormula.substring(fnPos + functions[i].length);
}
fnPos += functions[i].length;
}
}
}
}
formula: " + inlinedFormula);
} catch(e) {
this.debug(e);
//throw(e);
result = e;
errors = true;
}
}
very cell: " + cellNotation + ", formula: " + inlinedFormula);
/**********
STEP 6: reevaluate dependent cells
***********/
this.reevalDependentCells(originalGraphNode);
} else {
this.debug("STEP 6: dependencies will NOT be
re-evaluated for cell: " + cellNotation);
}
}
based on cell's type (number, date, string) and cell's
* format. Possible formats for date are "MM/DD/YYYY",
"DD-MMM-YYYY", etc.
* Currently cell's formats are not supported yet.
* @param cell the element to be formatted for presentation
* @return the formatted value
*/
formatCellForPresentation: function(cell) {
var formula = cell.formula;
null) {
// now, the cell format should be checked...
if(formula instanceof Date) {
with (formula) {
return getDate() + "-" +
this.months[getMonth()].toUpperCase() + "-" + getFullYear();
}
}
could not be parsed
*/
parseDateFormat1: function(str) {
var _date = str.match(this.reDate1);
if(_date && _date != null) {
_date = "" + _date;
if(_date == trim(str)) {
var vals = _date.split("/");
var month = parseInt(vals[0]);
var day = parseInt(vals[1]);
var year = parseInt(vals[2]);
could not be parsed
*/
parseDateFormat2: function(str) {
var _date = str.match(this.reDate2);
if(_date && _date != null) {
_date = "" + _date;
if(_date == trim(str)) {
var vals = _date.split("-");
could not be parsed
*/
parseNumberFormat1: function(str) {
var _num = str.match(this.reNumber1);
ranges for each param are good
* @param day
* @param month
* @param year
*/
isDateValid: function(day, month, year) {
if(month < 1 && month > 12 && day < 1 && day > 31) {
return false;
}
// TODO check valid date
return true;
},
date.getSeconds() + ":" + date.getMilliseconds() + " : " + msg;
var dbg = document.getElementById("debugDiv");
dbg.value = tmp + "\n" + dbg.value;
console.debug(tmp);
},
);
/**************
***************/
function sum() {
var _sum = 0;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
_sum += arguments[i];
}
}
return _sum;
}
function avg() {
var _avg = 0;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
_avg += arguments[i];
}
_avg /= arguments.length;
}
return _avg;
}
function min() {
var _min = Number.POSITIVE_INFINITY;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
if(_min > arguments[i]) {
_min = arguments[i];
}
}
}
return _min;
}
function max() {
var _max = Number.NEGATIVE_INFINITY;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
if(_max < arguments[i]) {
_max = arguments[i];
}
}
}
return _max;
}
function count() {
var _count = 0;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
if(arguments[i] != null && typeof(arguments[i]) != "undefined"
&& arguments[i] != "") {
_count ++;
}
}
}
}
function product() {
var _product = 1;
if(arguments != null && arguments.length > 0) {
for(var i = 0; i < arguments.length; i++) {
_product *= arguments[i];
}
}
}
var abs = Math.abs;
var acos = Math.acos;
var asin = Math.asin;
var atan = Math.atan;
var atan2 = Math.atan2;
var ceil = Math.ceil;
var cos = Math.cos;
var exp = Math.exp;
var floor = Math.floor;
var log = Math.log;
var pow = Math.pow;
var random = Math.random;
var round = Math.round;
var sin = Math.sin;
var sqrt = Math.sqrt;
var tan = Math.tan;
/**************
***************/
function len() {
if(arguments != null && arguments.length > 0) {
return arguments[0].length;
}
}
function lower() {
if(arguments != null && arguments.length > 0) {
return arguments[0].toLowerCase();
}
}
function upper() {
if(arguments != null && arguments.length > 0) {
return arguments[0].toUpperCase();
}
}
function left() {
if(arguments != null && arguments.length > 0) {
var endPos = 1;
if(arguments[1]) {
endPos = arguments[1];
}
return arguments[0].substring(0, endPos);
}
}
function right() {
if(arguments != null && arguments.length > 0) {
var startPos = 1;
if(arguments[1]) {
startPos = arguments[1];
}
return arguments[0].substring(arguments[0].length - startPos);
}
}
var trim = dojo.trim;