4 * jqGrid extension for cellediting Grid Data
\r
5 * Tony Tomov tony@trirand.com
\r
6 * http://trirand.com/blog/
\r
7 * Dual licensed under the MIT and GPL licenses:
\r
8 * http://www.opensource.org/licenses/mit-license.php
\r
9 * http://www.gnu.org/licenses/gpl.html
\r
12 * all events and options here are aded anonynous and not in the base grid
\r
13 * since the array is to big. Here is the order of execution.
\r
14 * From this point we use jQuery isFunction
\r
16 * onSelectCell (used only for noneditable cels)
\r
18 * beforeSaveCell, (called before validation of values if any)
\r
19 * beforeSubmitCell (if cellsubmit remote (ajax))
\r
20 * afterSubmitCell(if cellsubmit remote (ajax)),
\r
24 * cellsubmit (remote,clientArray) (added in grid options)
\r
28 editCell : function (iRow,iCol, ed, fg){
\r
29 return this.each(function (){
\r
30 var $t = this, nm, tmp,cc;
\r
31 if (!$t.grid || $t.p.cellEdit !== true) {return;}
\r
32 var currentFocus = null;
\r
34 if ($.browser.msie && $.browser.version <=6 && ed===true && fg===true) {
\r
35 iCol = getAbsoluteIndex($t.rows[iRow],iCol);
\r
37 // select the row that can be used for other methods
\r
38 $t.p.selrow = $t.rows[iRow].id;
\r
39 if (!$t.p.knv) {$($t).GridNav();}
\r
40 // check to see if we have already edited cell
\r
41 if ($t.p.savedRow.length>0) {
\r
42 // prevent second click on that field and enable selects
\r
44 if(iRow == $t.p.iRow && iCol == $t.p.iCol){
\r
48 // if so check to see if the content is changed
\r
49 var vl = $("td:eq("+$t.p.savedRow[0].ic+")>#"+$t.p.savedRow[0].id+"_"+$t.p.savedRow[0].name,$t.rows[$t.p.savedRow[0].id]).val();
\r
50 if ($t.p.savedRow[0].v != vl) {
\r
52 $($t).saveCell($t.p.savedRow[0].id,$t.p.savedRow[0].ic)
\r
55 $($t).restoreCell($t.p.savedRow[0].id,$t.p.savedRow[0].ic);
\r
58 window.setTimeout(function () { $("#"+$t.p.knv).attr("tabindex","-1").focus();},0);
\r
60 nm = $t.p.colModel[iCol].name;
\r
61 if (nm=='subgrid') {return;}
\r
62 if ($t.p.colModel[iCol].editable===true && ed===true) {
\r
63 cc = $("td:eq("+iCol+")",$t.rows[iRow]);
\r
64 if(parseInt($t.p.iCol)>=0 && parseInt($t.p.iRow)>=0) {
\r
65 $("td:eq("+$t.p.iCol+")",$t.rows[$t.p.iRow]).removeClass("edit-cell");
\r
67 $(cc).addClass("edit-cell");
\r
68 tmp = $(cc).html().replace(/\ \;/ig,'');
\r
69 var opt = $.extend($t.p.colModel[iCol].editoptions || {} ,{id:iRow+"_"+nm,name:nm});
\r
70 if (!$t.p.colModel[iCol].edittype) {$t.p.colModel[iCol].edittype = "text";}
\r
71 var elc = createEl($t.p.colModel[iCol].edittype,opt,tmp,cc);
\r
72 if ($.isFunction($t.p.beforeEditCell)) {
\r
73 $t.p.beforeEditCell($t.rows[iRow].id,nm,tmp,iRow,iCol);
\r
75 $(cc).html("").append(elc);
\r
76 window.setTimeout(function () { $(elc).focus();},0);
\r
77 $t.p.savedRow.push({id:iRow,ic:iCol,name:nm,v:tmp});
\r
78 $("input, select, textarea",cc).bind("keydown",function(e) {
\r
79 if (e.keyCode === 27) {$($t).restoreCell(iRow,iCol);} //ESC
\r
80 if (e.keyCode === 13) {$($t).saveCell(iRow,iCol);}//Enter
\r
81 if (e.keyCode == 9) {$($t).nextCell(iRow,iCol);} //Tab
\r
82 e.stopPropagation();
\r
84 if ($.isFunction($t.p.afterEditCell)) {
\r
85 $t.p.afterEditCell($t.rows[iRow].id,nm,tmp,iRow,iCol);
\r
88 if (parseInt($t.p.iCol)>=0 && parseInt($t.p.iRow)>=0) {
\r
89 $("td:eq("+$t.p.iCol+")",$t.rows[$t.p.iRow]).removeClass("edit-cell");
\r
91 $("td:eq("+iCol+")",$t.rows[iRow]).addClass("edit-cell");
\r
92 if ($.isFunction($t.p.onSelectCell)) {
\r
93 tmp = $("td:eq("+iCol+")",$t.rows[iRow]).html().replace(/\ \;/ig,'');
\r
94 $t.p.onSelectCell($t.rows[iRow].id,nm,tmp,iRow,iCol);
\r
97 $t.p.iCol = iCol; $t.p.iRow = iRow;
\r
99 function getAbsoluteIndex(t,relIndex)
\r
101 var countnotvisible=0;
\r
102 var countvisible=0;
\r
103 for (i=0;i<t.cells.length;i++) {
\r
104 var cell=t.cells(i);
\r
105 if (cell.style.display=='none') countnotvisible++; else countvisible++;
\r
106 if (countvisible>relIndex) return i;
\r
112 saveCell : function (iRow, iCol){
\r
113 return this.each(function(){
\r
114 var $t= this, nm, fr=null;
\r
115 if (!$t.grid || $t.p.cellEdit !== true) {return;}
\r
116 for( var k=0;k<$t.p.savedRow.length;k++) {
\r
117 if ( $t.p.savedRow[k].id===iRow) {fr = k; break;}
\r
120 var cc = $("td:eq("+iCol+")",$t.rows[iRow]);
\r
121 nm = $t.p.colModel[iCol].name;
\r
123 switch ($t.p.colModel[iCol].edittype) {
\r
125 v = $("#"+iRow+"_"+nm+">option:selected",$t.rows[iRow]).val();
\r
126 v2 = $("#"+iRow+"_"+nm+">option:selected",$t.rows[iRow]).text();
\r
129 var cbv = $t.p.colModel[iCol].editoptions.value.split(":") || ["Yes","No"];
\r
130 v = $("#"+iRow+"_"+nm,$t.rows[iRow]).attr("checked") ? cbv[0] : cbv[1];
\r
136 v = $("#"+iRow+"_"+nm,$t.rows[iRow]).val();
\r
140 // The common approach is if nothing changed do not do anything
\r
141 if (v2 != $t.p.savedRow[fr].v){
\r
142 if ($.isFunction($t.p.beforeSaveCell)) {
\r
143 var vv = $t.p.beforeSaveCell($t.rows[iRow].id,nm, v, iRow,iCol);
\r
146 var cv = checkValues(v,iCol,$t);
\r
147 if(cv[0] === true) {
\r
149 if ($.isFunction($t.p.beforeSubmitCell)) {
\r
150 addpost = $t.p.beforeSubmitCell($t.rows[iRow].id,nm, v, iRow,iCol);
\r
151 if (!addpost) {addpost={};}
\r
153 if ($t.p.cellsubmit == 'remote') {
\r
154 if ($t.p.cellurl) {
\r
157 postdata["id"] = $t.rows[iRow].id;
\r
158 postdata = $.extend(addpost,postdata);
\r
163 complete: function (result, stat) {
\r
164 if (stat == 'success') {
\r
165 if ($.isFunction($t.p.afterSubmitCell)) {
\r
166 var ret = $t.p.afterSubmitCell(result,postdata.id,nm,v,iRow,iCol);
\r
167 if(ret && ret[0] === true) {
\r
168 $(cc).empty().html(v2 || " ");
\r
169 $(cc).addClass("dirty-cell");
\r
170 $($t.rows[iRow]).addClass("edited");
\r
171 if ($.isFunction($t.p.afterSaveCell)) {
\r
172 $t.p.afterSaveCell($t.rows[iRow].id,nm, v, iRow,iCol);
\r
174 $t.p.savedRow.splice(fr,1);
\r
176 info_dialog($.jgrid.errors.errcap,ret[1],$.jgrid.edit.bClose, $t.p.imgpath);
\r
177 $($t).restoreCell(iRow,iCol);
\r
180 $(cc).empty().html(v2 || " ");
\r
181 $(cc).addClass("dirty-cell");
\r
182 $($t.rows[iRow]).addClass("edited");
\r
183 if ($.isFunction($t.p.afterSaveCell)) {
\r
184 $t.p.afterSaveCell($t.rows[iRow].id,nm, v, iRow,iCol);
\r
186 $t.p.savedRow.splice(fr,1);
\r
190 error:function(res,stat){
\r
191 if ($.isFunction($t.p.errorCell)) {
\r
192 $t.p.errorCell(res,stat);
\r
194 info_dialog($.jgrid.errors.errcap,res.status+" : "+res.statusText+"<br/>"+stat,$.jgrid.edit.bClose, $t.p.imgpath);
\r
195 $($t).restoreCell(iRow,iCol);
\r
201 info_dialog($.jgrid.errors.errcap,$.jgrid.errors.nourl,$.jgrid.edit.bClose, $t.p.imgpath);
\r
202 $($t).restoreCell(iRow,iCol);
\r
206 if ($t.p.cellsubmit == 'clientArray') {
\r
207 $(cc).empty().html(v2 || " ");
\r
208 $(cc).addClass("dirty-cell");
\r
209 $($t.rows[iRow]).addClass("edited");
\r
210 if ($.isFunction($t.p.afterSaveCell)) {
\r
211 $t.p.afterSaveCell($t.rows[iRow].id,nm, v, iRow,iCol);
\r
213 $t.p.savedRow.splice(fr,1);
\r
217 window.setTimeout(function(){info_dialog($.jgrid.errors.errcap,v+" "+cv[1],$.jgrid.edit.bClose, $t.p.imgpath)},100);
\r
218 $($t).restoreCell(iRow,iCol);
\r
222 $($t).restoreCell(iRow,iCol);
\r
225 if ($.browser.opera) {
\r
226 $("#"+$t.p.knv).attr("tabindex","-1").focus();
\r
228 window.setTimeout(function () { $("#"+$t.p.knv).attr("tabindex","-1").focus();},0);
\r
232 nextCell : function (iRow,iCol) {
\r
233 return this.each(function (){
\r
234 var $t = this, nCol=false, tmp;
\r
235 if (!$t.grid || $t.p.cellEdit !== true) {return;}
\r
236 // try to find next editable cell
\r
237 for (var i=iCol+1; i<$t.p.colModel.length; i++) {
\r
238 if ( $t.p.colModel[i].editable ===true) {
\r
242 if(nCol !== false) {
\r
243 $($t).saveCell(iRow,iCol);
\r
244 $($t).editCell(iRow,nCol,true);
\r
246 if ($t.p.savedRow.length >0) {
\r
247 $($t).saveCell(iRow,iCol);
\r
252 restoreCell : function(iRow, iCol) {
\r
253 return this.each(function(){
\r
254 var $t= this, nm, fr=null;
\r
255 if (!$t.grid || $t.p.cellEdit !== true ) {return;}
\r
256 for( var k=0;k<$t.p.savedRow.length;k++) {
\r
257 if ( $t.p.savedRow[k].id===iRow) {fr = k; break;}
\r
260 var cc = $("td:eq("+iCol+")",$t.rows[iRow]);
\r
263 $.datepicker.hideDatepicker();
\r
265 $.datepicker._hideDatepicker();
\r
267 $(":input",cc).unbind();
\r
268 nm = $t.p.colModel[iCol].name;
\r
270 .html($t.p.savedRow[fr].v || " ");
\r
271 //$t.p.savedRow.splice(fr,1);
\r
272 $t.p.savedRow = [];
\r
275 window.setTimeout(function () { $("#"+$t.p.knv).attr("tabindex","-1").focus();},0);
\r
278 GridNav : function() {
\r
279 return this.each(function () {
\r
281 if (!$t.grid || $t.p.cellEdit !== true ) {return;}
\r
282 // trick to process keydown on non input elements
\r
283 $t.p.knv = $("table:first",$t.grid.bDiv).attr("id") + "_kn";
\r
284 var selection = $("<span style='width:0px;height:0px;background-color:black;' tabindex='0'><span tabindex='-1' style='width:0px;height:0px;background-color:grey' id='"+$t.p.knv+"'></span></span>");
\r
285 $(selection).insertBefore($t.grid.cDiv);
\r
286 $("#"+$t.p.knv).focus();
\r
287 $("#"+$t.p.knv).keydown(function (e){
\r
288 switch (e.keyCode) {
\r
290 if ($t.p.iRow-1 >=1 ) {
\r
291 scrollGrid($t.p.iRow-1,$t.p.iCol,'vu');
\r
292 $($t).editCell($t.p.iRow-1,$t.p.iCol,false);
\r
296 if ($t.p.iRow+1 <= $t.rows.length-1) {
\r
297 scrollGrid($t.p.iRow+1,$t.p.iCol,'vd');
\r
298 $($t).editCell($t.p.iRow+1,$t.p.iCol,false);
\r
302 if ($t.p.iCol -1 >= 0) {
\r
303 var i = findNextVisible($t.p.iCol-1,'lft');
\r
304 scrollGrid($t.p.iRow, i,'h');
\r
305 $($t).editCell($t.p.iRow, i,false);
\r
309 if ($t.p.iCol +1 <= $t.p.colModel.length-1) {
\r
310 var i = findNextVisible($t.p.iCol+1,'rgt');
\r
311 scrollGrid($t.p.iRow,i,'h');
\r
312 $($t).editCell($t.p.iRow,i,false);
\r
316 if ($t.p.iCol && $t.p.iRow) {
\r
317 $($t).editCell($t.p.iRow,$t.p.iCol,true);
\r
323 function scrollGrid(iR, iC, tp){
\r
324 if (tp.substr(0,1)=='v') {
\r
325 var ch = $($t.grid.bDiv)[0].clientHeight;
\r
326 var st = $($t.grid.bDiv)[0].scrollTop;
\r
327 var nROT = $t.rows[iR].offsetTop+$t.rows[iR].clientHeight;
\r
328 var pROT = $t.rows[iR].offsetTop;
\r
331 $($t.grid.bDiv)[0].scrollTop = $($t.grid.bDiv)[0].scrollTop + $t.rows[iR].clientHeight;
\r
336 $($t.grid.bDiv)[0].scrollTop = $($t.grid.bDiv)[0].scrollTop - $t.rows[iR].clientHeight;
\r
341 var cw = $($t.grid.bDiv)[0].clientWidth;
\r
342 var sl = $($t.grid.bDiv)[0].scrollLeft;
\r
343 var nCOL = $t.rows[iR].cells[iC].offsetLeft+$t.rows[iR].cells[iC].clientWidth;
\r
344 var pCOL = $t.rows[iR].cells[iC].offsetLeft;
\r
345 if(nCOL >= cw+parseInt(sl)) {
\r
346 $($t.grid.bDiv)[0].scrollLeft = $($t.grid.bDiv)[0].scrollLeft + $t.rows[iR].cells[iC].clientWidth;
\r
347 } else if (pCOL < sl) {
\r
348 $($t.grid.bDiv)[0].scrollLeft = $($t.grid.bDiv)[0].scrollLeft - $t.rows[iR].cells[iC].clientWidth;
\r
352 function findNextVisible(iC,act){
\r
356 for (var i=iC;i>=0;i--){
\r
357 if ($t.p.colModel[i].hidden !== true) {
\r
365 for (var i=iC; i<$t.p.colModel.length;i++){
\r
366 if ($t.p.colModel[i].hidden !== true) {
\r
376 getChangedCells : function (mthd) {
\r
378 if (!mthd) {mthd='all';}
\r
379 this.each(function(){
\r
381 if (!$t.grid || $t.p.cellEdit !== true ) {return;}
\r
382 $($t.rows).slice(1).each(function(j){
\r
384 if ($(this).hasClass("edited")) {
\r
385 $('td',this).each( function(i) {
\r
386 nm = $t.p.colModel[i].name;
\r
387 if ( nm !== 'cb' && nm !== 'subgrid') {
\r
388 if (mthd=='dirty') {
\r
389 if ($(this).hasClass('dirty-cell')) {
\r
390 res[nm] = $(this).html().replace(/\ \;/ig,'');
\r
393 res[nm] = $(this).html().replace(/\ \;/ig,'');
\r
397 res["id"] = this.id;
\r
404 /// end cell editing
\r