// --------------------------------------------------------------------------------------------------------------------------

// Support script for Extended API demonstration

// --------------------------------------------------------------------------------------------------------------------------

// --------------------------------------------------------------------------------------------------------------------------

// Members in red are JavaScript keywords

// Members in blue are TreeGrid functions and properties, contain link to documentation

// Members in bold are global functions and variables in this script

// Strings are "pink", numbers are blue

// --------------------------------------------------------------------------------------------------------------------------

// --------------------------------------------------------------------------------------------------------------------------

var IDisable, IStyle, DLog; // Pointers to html controls

var FRow; // Actual focused row for update

var Styles = [ // Style settings

"Style='G' Grid = 'Grid.gif' Toolbar='Toolbar.gif' Height = '17' Line = '21' Tree = '26' Panel = '13' Sort = '14' Filter = '17' Row = '17'",

"Style='GL' Grid = 'GridLight.gif' Toolbar='ToolbarLight.gif' Height = '17' Line = '21' Tree = '26' Panel = '13' Sort = '14' Filter = '17' Row = '17'",

"Style='GB' Grid = 'GridBigger.gif' Toolbar='Toolbar.gif' Height = '21' Line = '21' Tree = '26' Panel = '18' Sort = '14' Filter = '17' Row = '17'",

"Style='GG' Grid = 'GridGame.gif' Toolbar='Toolbar.gif' Height = '17' Line = '21' Tree = '26' Panel = '13' Sort = '14' Filter = '17' Row = '17'"

];

// --------------------------------------------------------------------------------------------------------------------------

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Main and starting functions

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// --------------------------------------------------------------------------------------------------------------------------

// Creates grid from JavaScript

function Start(){

// --- Prepares and clears controls on pages ---

DLog = GetElem("LOG");

IStyle = GetElem("IStyle");

IDisable = GetElem("IDisable");

DLog.value = "";

IDisable.checked = false;

IStyle.checked = false;

GetElem("IColor").value = "002";

GetElem("SData").selectedIndex = 0;

GetElem("SStyle").selectedIndex = 0;

// --- creates grid ---

var D = new TDataIO(); // new object for communication

D.Layout.Url = "../Data/CalcAPIDef.xml";

D.Data.Url = "../Data/CalcAPIData.xml";

Resize(); // User function to resize main tag to resize it to whole window

TreeGrid(D,"GRID"); // Creates new grid, this grid will now be accessed from Grids[0] property

}

// --------------------------------------------------------------------------------------------------------------------------

// Loads data chosen from the first combo

function LoadData(){

var idx = GetElem("SData").selectedIndex; // The first combo, contains selected data

var Def = [ // Def contain layout definitions, for examples only, for tutorials is used only data file

"CalcAPIDef.xml","CalcDef.xml","UserDef.xml","BooksDef.xml","Data1Def.xml","Data2Def.xml","Data3Def.xml","Data4Def.xml","UnknownDef.xml",""

];

var Data = [ // Data contain data xml, for examples there are also used layouts from Def, for tutorials this is the only data

"CalcAPIData.xml","CalcData.xml","UserData.xml","BooksData.xml","Data1S.xml","Data2S.xml","Data3S.xml","Data4S.xml","UnknownData.xml",

"Basic1 Empty grid.xml","Basic2 Rows.xml","Basic3 Fixed rows.xml","Basic4 Columns.xml","Basic5 Fixed columns.xml","Basic6 Tree.xml","Basic7 Settings.xml",

"Advanced1 Cells.xml","Advanced2 Formats.xml","Advanced3 Permissions.xml","Advanced4 Sorting.xml","Advanced5 Filters.xml","Advanced6 Defaults.xml","Advanced7 Defaults children.xml",

"Calc1 Columns.xml","Calc2 Rows.xml","Calc3 Order.xml","Calc4 Tree.xml",

"Editing1 Basics.xml","Editing2 Multiline.xml","Editing3 Mask.xml","Editing4 Advanced types.xml",

"Expert1 Spanning.xml","Expert2 User rows.xml","Expert3 Header.xml","Expert4 Body.xml"];

var G = Grids[0];

var D = G.Data;

if(idx>=9){ // Tutorials

D.Layout.Url = null;

D.Data.Url = "../../Tutorials/"+Data[idx];

}

else { // Examples

D.Layout.Url = "../Data/"+Def[idx];

D.Data.Url = "../Data/"+Data[idx];

}

if(idx==34) D.Page.Url="../../Tutorials/Expert4 Page.xml"; // special case, this tutorial uses paging

else D.Page.Url = null; // standard case

if(idx==30) D.Layout.Bonus="<Grid><Cfg BaseUrl='../'/></Grid>"; // special case, this tutorial uses Img expected to be from another location

else D.Layout.Bonus=null; // standard case

var sidx = GetElem("SStyle").selectedIndex;

D.Data.Bonus="<Grid><Cfg MaxWidth='0' MaxHeight='0'/><Img "+Styles[sidx]+"/></Grid>"; // Suppresses MaxHeigth and MaxWidth for any data that has them set, because main tag is positioned in <TABLE> and sets selected style

G.Reload(); // Reloads new data to grid

FRow = null; // Nulls FRow - no focused row in grid

}

// --------------------------------------------------------------------------------------------------------------------------

// Called when window is resized to set extents of the grid to maximize its area

function Resize(){

var D = GetElem("GRID");

var R = GetElem("RIGHT");

var S = GetWindowSize();

D.style.width = S[0] - 240;

var h = S[1] - 270 - D.parentNode.offsetTop;;

if(h<R.offsetHeight) h = R.offsetHeight;

D.style.height = h;

}

// --------------------------------------------------------------------------------------------------------------------------

// Helper function, logs string to LOG DIV

function Log(str,ln,color,size){

if(IDisable.checked) return;

var D = document.createElement(ln?"DIV":"SPAN");

D.innerHTML = str+(ln?"":"; ");

if(color) D.style.color = color;

if(size) D.style.fontSize = size;

DLog.appendChild(D);

DLog.scrollTop = 10000;

}

// --------------------------------------------------------------------------------------------------------------------------

// Helper function, escapes the string for using in XML/HTML (to display in log)

function Esc(str){

if(str.length>50) str = str.slice(0,50)+" ... ";

return str.replace(/&/g,"&amp;").replace(/</g,"&lt;");

}

// --------------------------------------------------------------------------------------------------------------------------

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Event handlers

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// --------------------------------------------------------------------------------------------------------------------------

// Style event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnGetColor = function(G,row,col,r,g,b,type){

if(IStyle.checked) Log("OnGetColor("+row.id+","+col+","+r+","+g+","+b+","+type+")",0,"#CAC");

if(row[col+"Marked"] && !type) return "rgb("+r+","+(g-64)+","+b+")"; // Checks custom attribute set by function Color

if(G.id=="Books" && !Get(row,"Spanned")) return "rgb("+r+","+g+","+(b-20)+")";// Support function for particular example

}

Grids.OnGetClass = function(G,row,col,cls){

if(IStyle.checked) Log("OnGetClass("+row.id+","+col+","+cls+")",0,"#ACC");

if(G.id.slice(0,4)=="List") return ListGetClass(G,row,col,cls);

return cls;

}

Grids.OnGetType = function(G,row,col,type){

if(IStyle.checked) Log("OnGetType("+row.id+","+col+","+type+")",0,"#CCA");

return type;

}

Grids.OnGetFormat = function(G,row,col,format,edit){

if(IStyle.checked) Log("OnGetFormat("+row.id+","+col+","+format+","+edit+")",0,"#CAA");

return format;

}

Grids.OnGetEnum = function(G,row,col,enuma){

if(IStyle.checked) Log("OnGetEnum("+row.id+","+col+","+enuma.join("|")+")",0,"#ACA");

if(G.id=="List3") return List3GetEnum(G,row,col,enuma); // Support function for particular example

return enuma;

}

Grids.OnCanEdit = function(G,row,col,can){

if(IStyle.checked) Log("OnCanEdit("+row.id+","+col+","+can+")",0,"#AAC");

if(G.id=="List3") return List3CanEdit(G,row,col,can); // Support function for particular example

return can;

}

// --------------------------------------------------------------------------------------------------------------------------

// State event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnValueChanged = function(G,row,col,val){

Log("OnValueChanged: User <b>set value</b> in cell ["+row.id+","+col+"], from value '"+Esc(G.GetString(row,col))+"' to '"+Esc(G.ValueToString(val,G.GetType(row,col),G.GetFormat(row,col)))+"'.",1);

if(G.id.slice(0,4)=="List") return List3ValueChanged(G,row,col,val); // Support function for particular example

return val;

}

Grids.OnAfterValueChanged = function(G,row,col){

Log("OnAfterValueChanged: User <b>CHANGED value</b> in cell ["+row.id+","+col+"] to '"+G.GetString(row,col)+"'.",1);

}

Grids.OnResultMask = function(G,row,col,val){

Log("OnResultMask: Value '"+Esc(val)+"' tried to save to cell ["+row.id+","+col+"] collides with mask.",1,"red");

return 0;

}

Grids.OnRowMoveToGrid = function(G,row,togrid,torow,copy){

// not used in this example

}

Grids.OnRowMove = function(G,row,oldparent,oldnext){

var log = "OnRowMove: User <b>MOVED row</b> '"+row.id+"' ";

if(oldparent==row.parentNode) log+="inside "+(oldparent.tagName=='I'?"parent row '"+oldparent.id+"'":"root");

else log+="from "+(oldparent.tagName=='I'?"parent row '"+oldparent.id+"'":"root")+" to "+(row.parentNode.tagName=='I'?"parent row '"+row.parentNode.id+"'":"root");

log+=" "+(row.nextSibling?"before row '"+row.nextSibling.id+"'":"as the last row");

Log(log,1);

}

Grids.OnCanDrag = function(G,row,togrid,torow,type){

// log is not used due too many statements

return type;

}

Grids.OnRowDelete = function(G,row,type){

Log("OnRowDelete: User <b>"+(type==1?"DELETED":"UNDELETED")+" row</b> '"+row.id+"'.",1);

}

Grids.OnCanRowDelete = function(G,row,type){

Log("OnCanRowDelete: User tries to <b>"+(type!=3?"DELETE":"UNDELETE")+" row</b> '"+row.id+"'.",1);

return type;

}

Grids.OnCanRowAdd = function(G,parent,next){

Log("OnCanRowAdd: User tries to <b>ADD new row</b> to "+(parent&&parent.tagName=='I'?"parent row '"+parent.id+"'":"root") + " " + (next?"before row '"+next.id+"'":"as the last row"),1);

return true;

}

Grids.OnRowAdd = function(G,row){

Log("OnRowAdd: User <b>ADDED new row</b> '"+row.id+"' to "+(row.parentNode.tagName=='I'?"parent row '"+row.parentNode.id+"'":"root") + " " + (row.nextSibling?"before row '"+row.nextSibling.id+"'":"as the last row"),1);

if(G.id=="CalcAPI") row.X = row.id; // Support code for particular example

FillIds();

return true;

}

Grids.OnExpand = function(G,row){

Log("OnExpand: User <b>"+(row.Expanded?"COLLAPSES":"EXPANDS")+" row</b> '"+row.id+"'",1);

}

// --------------------------------------------------------------------------------------------------------------------------

// Sort and filter event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnSort = function(G,col){

Log("OnSort: User <b>SORTS</b> grid according to column '"+col+"'",1);

}

Grids.OnCanFilter = function(G,start){

var F = G.GetRowById("Filter"), cls="";

if(F){

for(var c=G.GetFirstCol();c;c=G.GetNextCol(c)){

if(Get(F,c+"Filter")) cls+=(cls?",":"")+c;

}

if(start){

if(cls) Log("OnCanFilter: TreeGrid is <b>filtered</b> according to columns "+cls,1,"#aaa");

else Log("OnCanFilter: TreeGrid is <b>not filtered</b>",1,"#aaa");

}

else {

if(cls) Log("OnCanFilter: User <b>FILTERS</b> grid according to columns "+cls,1);

else Log("OnCanFilter: User <b>CLEARS FILTERS</b> in grid",1);

}

}

else {

Log("OnCanFilter: TreeGrid has no filter",1,"#aaa");

}

return true;

}

Grids.OnRowFilter = function(G,row,show){

//if(row.firstChild) show = true; // suppress filter for rows with children

Log("OnRowFilter: row '"+row.id+"' is "+(show?"VISIBLE":"HIDDEN"),0,"#CCC");

return show;

}

// --------------------------------------------------------------------------------------------------------------------------

// Click and key event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnButtonClick = function(G,row,col){

Log("OnButtonClick: User <b>clicked right button</b> in cell ["+row.id+","+col+"]",1);

G.ShowDialog(row,col,"<DIV style='background:#ffffaa;border:2px inset #ddaadd; padding:10px;'> User dialog on<br>row '"

+ Esc(G.GetString)(row,"A")+"'<br>column '" + Esc(G.GetCaption(col))+"'<br>"

+"<BR><DIV align=center><BUTTON style='width:60;' onclick='Grids[0].CloseDialog();'>OK</BUTTON></DIV></DIV>");

}

Grids.OnLinkClick = function(G,row,col,url,target){

Log("OnLinkClick: User <b>clicked link</b> at cell ["+row.id+","+col+"]. Url is '"+Esc(url)+"', target is "+target+".",1);

}

Grids.OnClick = function(G,row,col,x,y,handled){

Log("OnClick: User <b>clicked</b> cell ["+row.id+","+col+"] at ["+x+","+y+"]."+(col!="Panel"&&row!=G.XHeader?" Cell value is '"+Esc(G.GetString(row,col))+"'.":"")+" Event "+(handled?"WAS":"was NOT")+" handled yet.",1);

}

Grids.OnDblClick = function(G,row,col,x,y){

Log("OnDblClick: User <b>double clicked</b> cell ["+row.id+","+col+"] at ["+x+","+y+"]."+(col!="Panel"&&row!=G.XHeader?" Cell value is '"+Esc(G.GetString(row,col))+"'.":""),1);

}

Grids.OnRightClick = function(G,row,col,x,y){

Log("OnRightClick: User <b>right clicked</b> cell ["+row.id+","+col+"] at ["+x+","+y+"]."+(col!="Panel"&&row!=G.XHeader?" Cell value is '"+Esc(G.GetString(row,col))+"'.":""),1);

ShowMenu(G,row,col,x,y);

return true;

}

Grids.OnKeyDown = function(G,key){ Log("Keydown: "+key,0,"#CCC"); }

Grids.OnKeyPress = function(G,key){ Log("Keypress: "+key,0,"#CCC"); }

Grids.OnTabOutside = function(G,move){

if(move>0){

Log("User pressed tab key on the last cell and focus is moved to next control");

GetElem("SData").focus();

return true;

}

else {

Log("User pressed tab key on the first cell and focus is moved to previous control");

GetElem("IStyle").focus();

return true;

}

}

Grids.OnFocus = function(G,row,col,orow,ocol,fpagepos){

if(fpagepos!=null) var S = "OnFocus: User <b>focused</b> cell on page ["+(row.id?row.id:G.GetPageNum(row))+","+col+"] on position "+fpagepos+".";

else var S = "OnFocus: User <b>focused</b> cell ["+row.id+","+col+"]"+(col?", with value '"+Esc(G.GetString(row,col))+"'":"")+".";

Log(S+" Original focused cell was ["+(orow?orow.id:"none")+","+(ocol?ocol:"none")+"].",1);

FRow = row;

if(fpagepos==null) SetDRow(G,row); // Sets row values in DRow tag's inputs

}

Grids.OnSelect = function(G,row,type){

var t = ["unselected","selected","changed selection of"];

Log("OnSelect: User <b>"+t[type-0]+"</b> row "+row.id+".",1);

}

Grids.OnStartEdit = function(G,row,col){

Log("OnStartEdit: User <b>STARTED editation</b> in cell ["+row.id+","+col+"], with value '"+Esc(G.GetString(row,col))+"'.",1);

}

Grids.OnEndEdit = function(G,row,col,save){

Log("OnEndEdit: User <b>"+(save?"FINISHED":"CANCELED")+" editation</b> in cell ["+row.id+","+col+"], with original value '"+Esc(G.GetString(row,col))+"'.",1);

}

// --------------------------------------------------------------------------------------------------------------------------

// Data event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnDataSend = function(G,D,Data){

if(!Data) Data="";

if(Data.length>50) Data = Data.slice(0,50)+" ...";

Log("OnDataSend: TreeGrid sends data '"+Esc(Data)+"' to '"+D.Url+"'",1,"#CCC");

}

Grids.OnDataError = function(G,code,mess,dataio,row){ Log("OnDataError: TreeGrid failed in data communication with code["+code+"] and message '"+mess+"'. Url was "+dataio.Url+".",1,"red"); }

Grids.OnDataReceive = function(G,row){ Log("OnDataReceive: TreeGrid receives data "+(row?" for row "+row.id:""),1,"#CCC"); }

Grids.OnDownloadPage = function(G,row,func){ Log("OnDownloadPage: TreeGrid requests data for page "+(row.id?row.id:G.GetPageNum(row)),1); }

Grids.OnReadData = function(G,D){ Log("OnReadData: TreeGrid reads data from '"+(D.Url?D.Url:D.Tag)+"'",1,"#AAA"); }

Grids.OnSave = function (G,row,autoupdate){ Log("OnSave: TreeGrid saves changes"+(row?" in row "+row.id:"")+" to server."+(autoupdate?" Event was fired from auto update.":""),1); }

Grids.OnReload = function(G){ Log("OnReload: TreeGrid starts reloading",1,"blue"); }

Grids.OnLoaded = function(G){ Log("OnLoaded: TreeGrid loaded its data",1,"#CCC"); }

Grids.OnLoadError = function(G) { Log("OnLoadError: TreeGrid failed to load",1,"red"); }

Grids.OnRenderStart = function(G){ Log("OnRenderStart: TreeGrid started rendering",1,"#CCC"); }

Grids.OnRenderFinish = function(G){

FillIds();

Log("OnRenderFinish: TreeGrid finished rendering",1,"blue");

Log("&nbsp;",1); Log("&nbsp;",1); Log("&nbsp;",1);

Log("--------------------------",1);

Log("<b>TreeGrid Extended API example</b>",1,"red","16px");

Log("<i>In </i><b>this window</b><i> are displayed all events fired by TreeGrid and logged from user event handlers by </i><b>Log</b><i> function. You can </i><b>clear</b><i>, </i><b>disable</b><i> event log or </i><b>enable style events</b><i>.</i>",1,"#0AA","14px");

Log("<i>In the </i><b>right window</b><i> you can run functions to demonstrate TreeGrid Extended API. In the first combo you can select data example to load in grid. "

+"In second combo you can change TreeGrid's style. In next controls you can focus any cell. Color/Select/Filter any cell that contains given value. And also change any value of focused row.</i>",1,"#0AA","14px");

Log("<i>By </i><b>right click</b><i> on any cell you can display </i><b>pop-up menu</b><i> and select presented options. For various cells and rows are different menu options, for </i><b>header</b><i> is there also another set of options.</i>",1,"#0AA","14px");

Log("<i>Remember, some functions can be very slow, especially with logging enabled and large data. Also remember, this example is universal and some functions can be unsuitable for some data examples.</i>",1,"#066","14px");

Log("--------------------------",1);

}

Grids.OnRenderPageStart = function(G,row){ Log("OnRenderPageStart: TreeGrid started rendering "+(row.id?"row '"+row.id+"' children":"page "+G.GetPageNum(row)),1,"#CCC"); }

Grids.OnRenderPageFinish = function(G,row){ Log("OnRenderPageFinish: TreeGrid finished rendering page "+(row.id?"row '"+row.id+"' children":"page "+G.GetPageNum(row)),1,"#CCC"); }

Grids.OnLoadCfg = function(G){ Log("OnLoadCfg: TreeGrid loads configuration from cookies",1,"#CCC"); }

Grids.OnCfgLoaded = function(G){ Log("OnCfgLoaded: TreeGrid loaded configuration from cookies",1,"#CCC"); }

Grids.OnSaveCfg = function(G){ Log("OnSaveCfg: TreeGrid saves configuration to cookies",1,"#CCC"); }

// --------------------------------------------------------------------------------------------------------------------------

// Panel event handlers

// --------------------------------------------------------------------------------------------------------------------------

Grids.OnGetUserPanel = function (G){

Log("OnGetUserPanel: User defined panel returned",1,"#ccc");

return "<td><button class=GButton onclick='alert(\"User toolbar button clicked!\");'>User</button></td>";

}

Grids.OnPanelClick = function(G,idx){ Log("OnPanelClick: User clicked to toolbar button with idx "+idx,1); }

Grids.OnCanShowPanelItem = function(G,idx,show){

Log("OnCanShowPanelItem: Panel button ["+idx+"] is <b>"+(show?"visible":"hidden")+"</b>",0,"#ccc");

return show;

}

Grids.OnCanShowCfgItem = function(G,idx,show){

Log("OnCanShowCfgItem: Configuration menu item ["+idx+"] is <b>"+(show?"visible":"hidden")+"</b>",0,"#ccc");

return show;

}

// --------------------------------------------------------------------------------------------------------------------------

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Controlling functions

// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// --------------------------------------------------------------------------------------------------------------------------

// Function called after click on any item of user right click menu

// Runs appropriate command

// idx is option index, Items is array of option names

function MenuClick(idx,G, row,col,Items){

Log("User menu item '<b>"+Items[idx]+"</b>' selected.",1,"red");

switch(Items[idx]){

case 'Unselect':

case 'Select' :

G.SelectRow(row); break; // Changes selection of the row

case 'Select all':

case 'Unselect all':

G.SelectAllRows(); break; // Changes selection of all rows

case 'Delete' :

G.DeleteRow(row,2); break; // Deletes the row

case 'Undelete' :

G.DeleteRow(row,3); break; // Undeletes the row

case 'Delete selected':

case 'Undelete selected':

G.DeleteSelectedRows(); // Deletes or undeletes all selected rows

break;

case 'Collapse' :

G.Collapse(row); break; // Collapses the row

case 'Expand' :

G.Expand(row); break; // Expands the row

case 'Change value' :

var val = prompt('Change cell value',G.GetString(row,col)); // Lets user to change the value as string

if(val!=null) {

G.SetString(row,col,val); // Sets the changed value and recalculates the grid

G.RefreshCell(row,col); // Refreshes the cell to display new value

G.ColorRow(row); // Colors the row to change color according to changes

}

break;

case 'Add child' :

var r = G.AddRow(row,null,true); // Adds new row to the children of the row, to the end

G.ScrollIntoView(r); // Scrolls grid to display new row

break;

case 'Add next' :

var r = G.AddRow(row.parentNode,G.GetNext(row),true); // Adds new row after the row, to the same parent

G.ScrollIntoView(r); // Scrolls grid to display new row

break;

case 'Sort descending':

G.SortClick(col,0); // Sorts grid descending according to the col

break;

case 'Sort ascending':

G.SortClick(col,1); // Sorts grid ascending according to the col

break;

case 'Hide column':

G.HideCol(col); // Hides the column (column can be displayed from menu columns, it can be run from toolbar)

G.SaveCfg(); // Updates configuration in cookies

break;

}

}

// --------------------------------------------------------------------------------------------------------------------------

// Function shows popup menu on cell

// Called from OnRightClick event

function ShowMenu(G,row,col,x,y){

Log("User displayed popup menu",1);

var Items=new Array(), p = 0;

if(row==G.XHeader){ // row is header row

var R = G.GetSelRows(); // returns all selected rows as array

if(R.length){ // If there is at least one selected row

Items[p++] = "Unselect all";

for(var i=0,del=0;i<R.length;i++) if(Is(R[i],"Deleted")) { del=1; break; }

if(del) Items[p++] = "Undelete selected"; // If there is at least one delete row in grid

else Items[p++] = "Delete selected"; // No deleted row in grid

}

else Items[p++] = "Select all"; // No selected row in grid

if(col!="Panel"){ // Column is not left panel

Items[p++] = "Sort descending";

Items[p++] = "Sort ascending";

Items[p++] = "Hide column";

}

}

else { // row is not header row

Items[p++] = Is(row,"Selected") ? "Unselect" : "Select";

Items[p++] = Is(row,"Deleted") ? "Undelete" : "Delete";

if(G.HasChildren(row)){ // If row has at least one visible child

if(Is(row,"Expanded")) Items[p++] = "Collapse"; // For expanded row

else Items[p++] = "Expand"; // For collapsed row

}

if(G.CanEdit(row,col)) Items[p++] = "Change value";// If value can be edited by user

if(!row.Fixed && G.GetCDef(row)) Items[p++] = "Add child"; // If this is body row (no foot or head) and has set CDef attribute

if(!row.Fixed) Items[p++] = "Add next"; // If this is body row (no foot or head)

}

G.ShowMenu(row,col,Items,null,MenuClick,null,"User&nbsp;menu",x,y,Items); // Shows user menu with given items and caption on given position

}

// --------------------------------------------------------------------------------------------------------------------------

// Function called from button Focus to focus chosen row

// Also called when SIds or SCols combo changed

function Focus(e){

// --- gets row and col from combos ---

var S = GetElem('SIds');

var id = S.options[S.selectedIndex].value;

var G = Grids[0];

var row = G.GetRowById(id);

var S = GetElem('SCols');

var col = S.options[S.selectedIndex].value;

Log("User run command <b>Focus</b> for cell ["+id+","+col+"].",1,"red");

if(!row){ // Row with given id is not present in the grid

alert("Unknown id");

return;

}

if(!Is(row,"Visible")){ // Row is not visible (is hidden by filter or is deleted

alert("Selected row is hidden and cannot be focused");

return;

}

setTimeout(function(){ // Delays the code, otherwise the grid will loose focus to the select box

G.Focus(row,col,null,true); // Focuses the row and also expands row's parent if it is collapsed (set by last parameter)

},10);

}

// --------------------------------------------------------------------------------------------------------------------------

// Called to prepare controls for new data

// Called from OnRenderFinish and OnRowAdd event handlers

// Fills all ids of rows to SIds select box

// Fills all column names to SCols select box

// Generates inputs in DRow tag for every column, to let user to change values

function FillIds(){

var G = Grids[0]; // There is only one grid on page

// --- fills all rows' ids ---

var S = GetElem("SIds");

S.options.length = 0;

var A = new Array(), id=1;

// Variable rows

for(var r=G.GetFirst();r;r=G.GetNext(r)) { // Base cycle for iteration through all variable rows

if(!r.id) r.id = "R"+(id<10?'0':"")+(id++); // Generate id, if row has not any

A[A.length] = r.id;

}

A.sort(); // sorts ids to better display in combo

// Fixed rows

var F = G.GetFixedRows(); id=1;

for(var i=0;i<F.length;i++){

if(!F[i].id) F[i].id = "F"+(id<10?'0':"")+(id++);

A[A.length] = F[i].id;

}

for(var i=0;i<A.length;i++){ // generates new options in select box

S.options[S.options.length] = new Option(A[i],A[i]);

}

// --- fills all columns' names ---

var S = GetElem("SCols");

S.options.length = 0;

var A = new Array();

//for(var c=G.GetFirstCol();c;c=G.GetNextCol(c)) A[A.length] = c; // Base cycle for iteration through all visible columns according to their position

for(var c in G.Cols) if(c!='Panel') A[A.length] = c; // Base cycle for iteration throught all columns

A.sort(); // sorts column names to better display in combo

for(var i=0;i<A.length;i++){ // generates new options in select box

S.options[S.options.length] = new Option(A[i],A[i]);

}

// --- creates inputs for every column ---

var D = GetElem("DRow"), A = new Array(), p=0;

A[p++] = "<div id=ID_ID>Row</div>";

for(var c in G.Cols) if(c!='Panel'){ // Base cycle for iteration throught all columns

A[p++] = G.GetCaption(c)+"&nbsp";

A[p++] = "<input id=ID"+c+" type=text style='width:80;font-size:10px;' onkeydown='if(event.keyCode==13 || event.charCode==13) Update(this);'><br>";

}

D.innerHTML = A.join("");

var I = D.getElementsByTagName("input");

for(var i=0;i<I.length;i++){ // Sets with of all inputs to maximize it

I[i].style.width = D.offsetWidth-I[i].offsetLeft-10;

}

Resize(); // Height of the tag was changed

}

// --------------------------------------------------------------------------------------------------------------------------

// Function for coloring/filtering/selecting found rows/cells

// Fro button=0 restores all rows

// For button=1 sets user attribute col+"Marked" if cell contains the searched value

// For button=2 hides row if any cell contains the searched value

// For button=3 selects rows if any cell contains the searched value

// Called when user presses the button or presses enter in input tag

function Color(button){

var G = Grids[0];

var V = GetElem("IColor").value;

Log("User run command <b>Color ("+button+")</b> with value '"+Esc(V)+"'.",1,"red");

// --- main function to change row's state or color ---

function color(r){

var found = false;

for(var c in G.Cols){

if(c=="Panel") continue;

var t = G.GetType(r,c), M = 0;

if(t=="Int" || t=="Float") { // Number types compares as number

M = V-0==G.GetValue(r,c);

}

else {

var S = G.GetString(r,c);

if(!S) M=!V;

else M = V?S.search(V)>=0:0; // Other then number types searches for appearance

}

if(M) found = true;

if(button!=1) M=0; // only button 'Color' colors the rows

r[c+"Marked"]=M; // Color, sets custom attribute, this attribute will be used in event OnGetColor

}

if(button==2 && !found) G.HideRow(r); // Filter

else G.ShowRow(r);

if(!Is(r,"Selected") && button==3 && found || Is(r,"Selected") && (button!=3 || !found)) G.SelectRow(r); // Select

if(found && button) G.ExpandParents(r); // Expands all parents of the row to make the row visible

G.ColorRow(r); // Updates color of the row

}

// --- iteration of all rows ---

G.Rendering = true; // Suppresses updating grid layout after every change, speeds up the action. It is good especially for Filter (button==2), because it shows/hides rows

//for(var r=G.GetFirstVisible();r;r=G.GetNextVisible(r)) color(r); // Base cycle for iteration through all visible variable rows

for(var r=G.GetFirst();r;r=G.GetNext(r)) if(!Is(r,"Deleted")) color(r); // Base cycle for iteration through all non deleted rows

var F = G.GetFixedRows(); for(var i=0;i<F.length;i++) color(F[i]); // Base cycle for iteration through fixed rows

G.Rendering = false; // Restores original state

G.SetScrollBars(); // Updates grid layout

}

// --------------------------------------------------------------------------------------------------------------------------

// Sets focused row values in DRow tag's inputs

// Called from OnFocus event handler

function SetDRow(G,row){

// --- sets the first row - id, parents, page ---

var I = document.getElementById("ID_ID");

var S = "", r = row.parentNode;

while(r.tagName=="I"){ S += (S?",":"")+(r.id?r.id:"???"); r=r.parentNode; } // fills parents from tree

S = "Id="+(row.id?row.id:"???")+(S?"; parents="+S:"")+"; page="+(r.id?r.id:G.GetPageNum(r));

I.innerHTML = S;

// --- sets values ---

for(var col in G.Cols) if(col!='Panel'){ // Base cycle for iteration throught all columns

var I = document.getElementById("ID"+col);

if(I){

var type = G.GetType(row,col);

I.value = G.ValueToString(G.GetValue(row,col),type,type=="Enum" ? G.GetEnum(row,col) : G.GetFormat(row,col,1)); // Gets string in editing format

I.disabled = !G.CanEdit(row,col); // Disables input if value cannot be edited

}

}

}

// --------------------------------------------------------------------------------------------------------------------------

// Updates inputs value after change

// Called when user presses enter in any input tag in DRow tag

// I is the tag input

function Update(I){

var G = Grids[0], row = FRow; // FRow is backup of focused row in the grid, because if grid user clicks on any control on page, the grid looses focus and clears Grids[0].FRow property

if(!FRow){ // (new) data was loaded and user did not clicked on any row yet

alert("No row focused yet");

return;

}

var col = I.id.slice(2); // input's id is "ID"+column_name

var type = G.GetType(row,col);

var val = G.StringToValue(I.value,type,type=="Enum" ? G.GetEnum(row,col) : G.GetFormat(row,col,1)); // Converts string in editing format to value of given type

G.SetValue(row,col,val); // sets the value and recalculates grid

G.RefreshCell(row,col); // Refreshes the cell to display new value

G.ColorRow(row); // Colors the row to change color according to changes

}

// --------------------------------------------------------------------------------------------------------

// Changes style of TreeGrid, does not reload, just re-renders

function ChangeStyle(idx){

var G = Grids[0];

G.ChangeStyle("<Grid><Img "+Styles[idx]+"/></Grid>"); // Changes style by changing settings in <Img/>

}

// --------------------------------------------------------------------------------------------------------------------------