grid.celledit.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. /**
  2. * jqGrid extension for cellediting Grid Data
  3. * Copyright (c) 2008-2014, Tony Tomov, tony@trirand.com, http://trirand.com/blog/
  4. * Copyright (c) 2014-2018, Oleg Kiriljuk, oleg.kiriljuk@ok-soft-gmbh.com
  5. * Dual licensed under the MIT and GPL licenses:
  6. * http://www.opensource.org/licenses/mit-license.php
  7. * http://www.gnu.org/licenses/gpl-2.0.html
  8. **/
  9. /**
  10. * all events and options here are added anonymous and not in the base grid
  11. * since the array is to big. Here is the order of execution.
  12. * From this point we use jQuery isFunction
  13. * formatCell
  14. * beforeEditCell,
  15. * onSelectCell (used only for non-editable cells)
  16. * afterEditCell,
  17. * beforeSaveCell, (called before validation of values if any)
  18. * beforeSubmitCell (if cellsubmit remote (Ajax))
  19. * afterSubmitCell(if cellsubmit remote (Ajax)),
  20. * afterSaveCell,
  21. * errorCell,
  22. * serializeCellData - new
  23. * Options
  24. * cellsubmit ("remote","clientArray") (added in grid options)
  25. * cellurl
  26. * ajaxCellOptions
  27. **/
  28. /*jshint eqeqeq:false */
  29. /*global jQuery, define, exports, module, require */
  30. /*jslint browser: true, eqeq: true, plusplus: true, vars: true, white: true, todo: true */
  31. (function (factory) {
  32. "use strict";
  33. if (typeof define === "function" && define.amd) {
  34. // AMD. Register as an anonymous module.
  35. define([
  36. "jquery",
  37. "./grid.base",
  38. "./jquery.fmatter",
  39. "./grid.common"
  40. ], factory);
  41. } else if (typeof module === "object" && module.exports) {
  42. // Node/CommonJS
  43. module.exports = function (root, $) {
  44. if (!root) {
  45. root = window;
  46. }
  47. if ($ === undefined) {
  48. // require("jquery") returns a factory that requires window to
  49. // build a jQuery instance, we normalize how we use modules
  50. // that require this pattern but the window provided is a noop
  51. // if it's defined (how jquery works)
  52. $ = typeof window !== "undefined" ?
  53. require("jquery") :
  54. require("jquery")(root);
  55. }
  56. require("./grid.base");
  57. require("./jquery.fmatter");
  58. require("./grid.common");
  59. factory($, root);
  60. return $;
  61. };
  62. } else {
  63. // Browser globals
  64. factory(jQuery);
  65. }
  66. }(function ($) {
  67. "use strict";
  68. var jgrid = $.jgrid,
  69. feedback = function () {
  70. // short form of $.jgrid.feedback to save usage this.p as the first parameter
  71. var args = $.makeArray(arguments);
  72. args.unshift("");
  73. args.unshift("");
  74. args.unshift(this.p);
  75. return jgrid.feedback.apply(this, args);
  76. };
  77. // begin module grid.celledit
  78. var getTdByColumnIndex = function (tr, iCol) {
  79. var $t = this, frozenRows = $t.grid.fbRows;
  80. tr = frozenRows != null && frozenRows[0].cells.length > iCol ? frozenRows[tr.rowIndex] : tr;
  81. return tr != null && tr.cells != null ? $(tr.cells[iCol]) : $();
  82. },
  83. safeHeightSet = function ($elem, newHeight) {
  84. var height = $elem.height();
  85. if (Math.abs(height - newHeight) >= 1 && newHeight > 0) {
  86. $elem.height(newHeight);
  87. height = $elem.height();
  88. if (Math.abs(newHeight - height) >= 1) {
  89. $elem.height(newHeight + Math.round((newHeight - height)));
  90. }
  91. }
  92. };
  93. jgrid.extend({
  94. editCell: function (iRow, iCol, ed) {
  95. return this.each(function () {
  96. var $t = this, $self = $($t), p = $t.p, nm, tmp, $td, cm, rows = $t.rows;
  97. if (!$t.grid || p.cellEdit !== true || rows == null || rows[iRow] == null) {
  98. return;
  99. }
  100. iRow = parseInt(iRow, 10); // we change iRow and rows[iRow] can be change too
  101. iCol = parseInt(iCol, 10);
  102. if (isNaN(iRow) || isNaN(iCol)) {
  103. return;
  104. }
  105. var tr = rows[iRow], rowid = tr != null ? tr.id : null, $tr = $(tr), edittype,
  106. iColOld = parseInt(p.iCol, 10), iRowOld = parseInt(p.iRow, 10),
  107. $trOld = $(rows[iRowOld]), savedRow = p.savedRow;
  108. // select the row that can be used for other methods
  109. if (rowid == null) {
  110. return;
  111. }
  112. p.selrow = rowid;
  113. if (!p.knv) {
  114. $self.jqGrid("GridNav");
  115. }
  116. // check to see if we have already edited cell
  117. if (savedRow.length > 0 && $trOld.length > 0) {
  118. // prevent second click on that field and enable selects
  119. if (ed === true) {
  120. if (iRow === iRowOld && iCol === iColOld) {
  121. return;
  122. }
  123. }
  124. // save the cell
  125. $self.jqGrid("saveCell", savedRow[0].id, savedRow[0].ic);
  126. } else {
  127. setTimeout(function () {
  128. $("#" + jgrid.jqID(p.knv)).attr("tabindex", "-1").focus();
  129. }, 1);
  130. }
  131. cm = p.colModel[iCol];
  132. nm = cm.name;
  133. if (nm === "subgrid" || nm === "cb" || nm === "rn") {
  134. return;
  135. }
  136. $td = getTdByColumnIndex.call($t, tr, iCol);
  137. var editable = cm.editable, mode = "cell";
  138. if ($.isFunction(editable)) {
  139. editable = editable.call($t, {
  140. rowid: rowid,
  141. iCol: iCol,
  142. iRow: iRow,
  143. cmName: nm,
  144. cm: cm,
  145. mode: mode
  146. });
  147. }
  148. var highlightClasses = $self.jqGrid("getGuiStyles", "states.select", "edit-cell"),
  149. hoverClasses = $self.jqGrid("getGuiStyles", "states.hover", "selected-row");
  150. if (editable === true && ed === true && !$td.hasClass("not-editable-cell")) {
  151. if (!p.noCellSelection) {
  152. if (iColOld >= 0 && iRowOld >= 0) {
  153. getTdByColumnIndex.call($t, $trOld[0], iColOld).removeClass(highlightClasses);
  154. $trOld.removeClass(hoverClasses);
  155. }
  156. $td.addClass(highlightClasses);
  157. $tr.addClass(hoverClasses);
  158. }
  159. if (!cm.edittype) {
  160. cm.edittype = "text";
  161. }
  162. edittype = cm.edittype;
  163. try {
  164. tmp = $.unformat.call($t, $td, { rowId: rowid, colModel: cm }, iCol);
  165. } catch (ex) {
  166. tmp = edittype === "textarea" ? $td.text() : $td.html();
  167. }
  168. if (p.autoEncodeOnEdit) {
  169. tmp = jgrid.oldDecodePostedData(tmp);
  170. }
  171. if (tmp === " " || tmp === " " || (tmp.length === 1 && tmp.charCodeAt(0) === 160)) {
  172. tmp = "";
  173. }
  174. if ($.isFunction(p.formatCell)) {
  175. var tmp2 = p.formatCell.call($t, rowid, nm, tmp, iRow, iCol);
  176. if (tmp2 !== undefined) {
  177. tmp = tmp2;
  178. }
  179. }
  180. feedback.call($t, "beforeEditCell", rowid, nm, tmp, iRow, iCol);
  181. savedRow.push({ id: iRow, ic: iCol, name: nm, v: tmp });
  182. p.editingInfo[rowid] = {
  183. mode: "cellEditing",
  184. savedRow: savedRow[savedRow.length - 1],
  185. editable: {}
  186. };
  187. p.editingInfo[rowid].editable[nm] = editable;
  188. var opt = $.extend({}, cm.editoptions || {},
  189. { id: iRow + "_" + nm, name: nm, rowId: rowid, mode: mode, cm: cm, iCol: iCol });
  190. var elc = jgrid.createEl.call($t, edittype, opt, tmp, true, $.extend({}, jgrid.ajaxOptions, p.ajaxSelectOptions || {})),
  191. $dataFiled = $td,
  192. editingColumnWithTreeGridIcon = p.treeGrid === true && nm === p.ExpandColumn;
  193. if (editingColumnWithTreeGridIcon) {
  194. $dataFiled = $td.children("span.cell-wrapperleaf,span.cell-wrapper");
  195. }
  196. $dataFiled.html("").append(elc).attr("tabindex", "0");
  197. if (editingColumnWithTreeGridIcon) { // && elc.style.width === "100%"
  198. $(elc).width($td.width() - $td.children("div.tree-wrap").outerWidth());
  199. }
  200. jgrid.bindEv.call($t, elc, opt);
  201. if (p.frozenColumns && iCol < $self.jqGrid("getNumberOfFrozenColumns")) {
  202. safeHeightSet($($t.rows[tr.rowIndex].cells[iCol]), $td.height());
  203. }
  204. setTimeout(function () {
  205. $(elc).focus();
  206. }, 0);
  207. $("input, select, textarea", $td).on("keydown", function (e) {
  208. if (e.keyCode === 27) {
  209. if ($("input.hasDatepicker", $td).length > 0) {
  210. if ($(".ui-datepicker").is(":hidden")) {
  211. $self.jqGrid("restoreCell", iRow, iCol);
  212. } else {
  213. $("input.hasDatepicker", $td).datepicker("hide");
  214. }
  215. } else {
  216. $self.jqGrid("restoreCell", iRow, iCol);
  217. }
  218. } //ESC
  219. if (e.keyCode === 13 && !e.shiftKey) {
  220. $self.jqGrid("saveCell", iRow, iCol);
  221. // Prevent default action
  222. return false;
  223. } //Enter
  224. if (e.keyCode === 9) {
  225. if (!$t.grid.hDiv.loading) {
  226. if (e.shiftKey) {
  227. $self.jqGrid("prevCell", iRow, iCol); //Shift TAb
  228. } else {
  229. $self.jqGrid("nextCell", iRow, iCol); //Tab
  230. }
  231. } else {
  232. return false;
  233. }
  234. }
  235. e.stopPropagation();
  236. });
  237. feedback.call($t, "afterEditCell", rowid, nm, tmp, iRow, iCol);
  238. } else {
  239. if (!p.noCellSelection) {
  240. if (iColOld >= 0 && iRowOld >= 0) {
  241. getTdByColumnIndex.call($t, $trOld[0], iColOld).removeClass(highlightClasses);
  242. $trOld.removeClass(hoverClasses);
  243. }
  244. $td.addClass(highlightClasses);
  245. $tr.addClass(hoverClasses);
  246. }
  247. tmp = $td.html().replace(/&#160;/ig, "");
  248. feedback.call($t, "onSelectCell", rowid, nm, tmp, iRow, iCol);
  249. }
  250. p.iCol = iCol;
  251. p.iRow = iRow;
  252. });
  253. },
  254. saveCell: function (iRow, iCol) {
  255. return this.each(function () {
  256. var $t = this, $self = $($t), p = $t.p, grid = $t.grid, infoDialog = jgrid.info_dialog, jqID = jgrid.jqID;
  257. if (!grid || p.cellEdit !== true) {
  258. return;
  259. }
  260. var errors = $self.jqGrid("getGridRes", "errors"), errcap = errors.errcap,
  261. edit = $self.jqGrid("getGridRes", "edit"), bClose = edit.bClose,
  262. savedRow = p.savedRow, fr = savedRow.length >= 1 ? 0 : null;
  263. if (fr !== null) {
  264. var tr = $t.rows[iRow], rowid = tr != null ? tr.id : null, $tr = tr != null ? $(tr) : $(), cm = p.colModel[iCol], nm = cm.name, vv,
  265. $td = getTdByColumnIndex.call($t, tr, iCol), valueText = {},
  266. v = jgrid.getEditedValue.call($t, $td, cm, valueText);
  267. // The common approach is if nothing changed do not do anything
  268. if (v !== savedRow[fr].v) {
  269. vv = $self.triggerHandler("jqGridBeforeSaveCell", [rowid, nm, v, iRow, iCol]);
  270. if (vv !== undefined) {
  271. v = vv;
  272. }
  273. if ($.isFunction(p.beforeSaveCell)) {
  274. vv = p.beforeSaveCell.call($t, rowid, nm, v, iRow, iCol);
  275. if (vv !== undefined) {
  276. v = vv;
  277. }
  278. }
  279. var cv = jgrid.checkValues.call($t, v, iCol, undefined, undefined, {
  280. oldValue: savedRow[fr].v,
  281. newValue: v,
  282. cmName: nm,
  283. rowid: rowid,
  284. iCol: iCol,
  285. iRow: iRow,
  286. cm: cm,
  287. tr: tr,
  288. td: $td,
  289. mode: "cell"
  290. }),
  291. formatoptions = cm.formatoptions || {};
  292. if (cv == null || cv === true || cv[0] === true) {
  293. var addpost = $self.triggerHandler("jqGridBeforeSubmitCell", [rowid, nm, v, iRow, iCol]) || {};
  294. if ($.isFunction(p.beforeSubmitCell)) {
  295. addpost = p.beforeSubmitCell.call($t, rowid, nm, v, iRow, iCol);
  296. if (!addpost) {
  297. addpost = {};
  298. }
  299. }
  300. if ($("input.hasDatepicker", $td).length > 0) {
  301. $("input.hasDatepicker", $td).datepicker("hide");
  302. }
  303. if (cm.formatter === "date" && formatoptions.sendFormatted !== true) {
  304. // TODO: call all other predefined formatters!!! Not only formatter: "date" have the problem.
  305. // Floating point separator for example
  306. v = $.unformat.date.call($t, v, cm);
  307. }
  308. if (p.cellsubmit === "remote") {
  309. if (p.cellurl) {
  310. var postdata = {};
  311. postdata[nm] = v;
  312. var opers = p.prmNames, idname = opers.id, oper = opers.oper;
  313. postdata[idname] = jgrid.stripPref(p.idPrefix, rowid);
  314. postdata[oper] = opers.editoper;
  315. postdata = $.extend(addpost, postdata);
  316. if (p.autoEncodeOnEdit) {
  317. $.each(postdata, function (n, val) {
  318. if (!$.isFunction(val)) {
  319. postdata[n] = jgrid.oldEncodePostedData(val);
  320. }
  321. });
  322. }
  323. $self.jqGrid("progressBar", { method: "show", loadtype: p.loadui, htmlcontent: $self.jqGrid("getGridRes", "defaults.savetext") || "Saving..." });
  324. grid.hDiv.loading = true;
  325. $.ajax($.extend({
  326. url: $.isFunction(p.cellurl) ? p.cellurl.call($t, p.cellurl, iRow, iCol, rowid, v, nm) : p.cellurl,
  327. //data :$.isFunction(p.serializeCellData) ? p.serializeCellData.call($t, postdata) : postdata,
  328. data: jgrid.serializeFeedback.call($t, p.serializeCellData, "jqGridSerializeCellData", postdata),
  329. type: "POST",
  330. complete: function (jqXHR) {
  331. grid.endReq.call($t);
  332. if ((jqXHR.status < 300 || jqXHR.status === 304) && (jqXHR.status !== 0 || jqXHR.readyState !== 4)) {
  333. var ret = $self.triggerHandler("jqGridAfterSubmitCell", [$t, jqXHR, postdata.id, nm, v, iRow, iCol]) || [true, ""];
  334. if (ret === true || (ret[0] === true && $.isFunction(p.afterSubmitCell))) {
  335. ret = p.afterSubmitCell.call($t, jqXHR, postdata.id, nm, v, iRow, iCol);
  336. }
  337. if (ret == null || ret === true || ret[0] === true) {
  338. $self.jqGrid("setCell", rowid, iCol, v, false, false, true);
  339. $td.addClass("dirty-cell");
  340. $tr.addClass("edited");
  341. feedback.call($t, "afterSaveCell", rowid, nm, v, iRow, iCol);
  342. savedRow.splice(0, 1);
  343. delete p.editingInfo[rowid];
  344. } else {
  345. infoDialog.call($t, errcap, ret[1], bClose);
  346. $self.jqGrid("restoreCell", iRow, iCol);
  347. }
  348. }
  349. },
  350. error: function (jqXHR, textStatus, errorThrown) {
  351. $self.triggerHandler("jqGridErrorCell", [jqXHR, textStatus, errorThrown]);
  352. if ($.isFunction(p.errorCell)) {
  353. p.errorCell.call($t, jqXHR, textStatus, errorThrown);
  354. $self.jqGrid("restoreCell", iRow, iCol);
  355. } else {
  356. infoDialog.call($t, errcap, jqXHR.status + " : " + jqXHR.statusText + "<br/>" + textStatus, bClose);
  357. $self.jqGrid("restoreCell", iRow, iCol);
  358. }
  359. }
  360. }, jgrid.ajaxOptions, p.ajaxCellOptions || {}));
  361. } else {
  362. try {
  363. infoDialog.call($t, errcap, errors.nourl, bClose);
  364. $self.jqGrid("restoreCell", iRow, iCol);
  365. } catch (ignore) { }
  366. }
  367. }
  368. if (p.cellsubmit === "clientArray") {
  369. $self.jqGrid("setCell", rowid, iCol,
  370. cm.edittype === "select" && cm.formatter !== "select" ? valueText.text : v,
  371. false, false, true);
  372. $td.addClass("dirty-cell");
  373. $tr.addClass("edited");
  374. feedback.call($t, "afterSaveCell", rowid, nm, v, iRow, iCol);
  375. if (p.frozenColumns && iCol < $self.jqGrid("getNumberOfFrozenColumns")) {
  376. try {
  377. $t.rows[tr.rowIndex].cells[iCol].style.height = "";
  378. } catch (ignore) { }
  379. }
  380. savedRow.splice(0, 1);
  381. delete p.editingInfo[rowid];
  382. }
  383. } else {
  384. try {
  385. setTimeout(function () {
  386. var relativeRect = jgrid.getRelativeRect.call($t, $td);
  387. infoDialog.call($t, errcap, v + " " + cv[1], bClose, {
  388. top: relativeRect.top,
  389. left: relativeRect.left + $($t).closest(".ui-jqgrid").offset().left
  390. });
  391. }, 50);
  392. $self.jqGrid("restoreCell", iRow, iCol);
  393. } catch (ignore) { }
  394. }
  395. } else {
  396. $self.jqGrid("restoreCell", iRow, iCol);
  397. }
  398. }
  399. setTimeout(function () {
  400. $("#" + jqID(p.knv)).attr("tabindex", "-1").focus();
  401. }, 0);
  402. });
  403. },
  404. restoreCell: function (iRow, iCol) {
  405. return this.each(function () {
  406. var $t = this, p = $t.p, tr = $t.rows[iRow], rowid = tr.id, v, cm, formatoptions;
  407. if (!$t.grid || p.cellEdit !== true) {
  408. return;
  409. }
  410. var savedRow = p.savedRow, $td = getTdByColumnIndex.call($t, tr, iCol);
  411. if (savedRow.length >= 1) {
  412. // datepicker fix
  413. if ($.isFunction($.fn.datepicker)) {
  414. try {
  415. $("input.hasDatepicker", $td).datepicker("hide");
  416. } catch (ignore) { }
  417. }
  418. cm = p.colModel[iCol];
  419. if (p.treeGrid === true && cm != null && cm.name === p.ExpandColumn) {
  420. $td.children("span.cell-wrapperleaf,span.cell-wrapper").empty();
  421. } else {
  422. $td.empty();
  423. }
  424. $td.attr("tabindex", "-1");
  425. v = savedRow[0].v;
  426. if (cm != null) {
  427. formatoptions = cm.formatoptions || {};
  428. if (cm.formatter === "date" && formatoptions.sendFormatted !== true) {
  429. // TODO: call all other predefined formatters!!! Not only formatter: "date" have the problem.
  430. // Floating point separator for example
  431. v = $.unformat.date.call($t, v, cm);
  432. }
  433. $($t).jqGrid("setCell", rowid, iCol, v, false, false, true);
  434. if (p.frozenColumns && iCol < $($t).jqGrid("getNumberOfFrozenColumns")) {
  435. try {
  436. $t.rows[tr.rowIndex].cells[iCol].style.height = "";
  437. } catch (ignore) { }
  438. }
  439. }
  440. feedback.call($t, "afterRestoreCell", rowid, v, iRow, iCol);
  441. savedRow.splice(0, 1);
  442. delete p.editingInfo[rowid];
  443. }
  444. setTimeout(function () {
  445. $("#" + p.knv).attr("tabindex", "-1").focus();
  446. }, 0);
  447. });
  448. },
  449. nextCell: function (iRow, iCol) {
  450. return this.each(function () {
  451. var $t = this, $self = $($t), p = $t.p, nCol = false, i, editable, cm, rows = $t.rows;
  452. if (!$t.grid || p.cellEdit !== true || rows == null || rows[iRow] == null) {
  453. return;
  454. }
  455. // try to find next editable cell
  456. for (i = iCol + 1; i < p.colModel.length; i++) {
  457. cm = p.colModel[i];
  458. editable = cm.editable;
  459. if ($.isFunction(editable)) {
  460. editable = editable.call($t, {
  461. rowid: rows[iRow].id,
  462. iCol: i,
  463. iRow: iRow,
  464. cmName: cm.name,
  465. cm: cm,
  466. mode: "cell"
  467. });
  468. }
  469. if (editable === true) {
  470. nCol = i;
  471. break;
  472. }
  473. }
  474. if (nCol !== false) {
  475. $self.jqGrid("editCell", iRow, nCol, true);
  476. } else {
  477. if (p.savedRow.length > 0) {
  478. $self.jqGrid("saveCell", iRow, iCol);
  479. }
  480. }
  481. });
  482. },
  483. prevCell: function (iRow, iCol) {
  484. return this.each(function () {
  485. var $t = this, $self = $($t), p = $t.p, nCol = false, i, editable, cm, rows = $t.rows;
  486. if (!$t.grid || p.cellEdit !== true || rows == null || rows[iRow] == null) {
  487. return;
  488. }
  489. // try to find next editable cell
  490. for (i = iCol - 1; i >= 0; i--) {
  491. cm = p.colModel[i];
  492. editable = cm.editable;
  493. if ($.isFunction(editable)) {
  494. editable = editable.call($t, {
  495. rowid: rows[iRow].id,
  496. iCol: i,
  497. iRow: iRow,
  498. cmName: cm.name,
  499. cm: cm,
  500. mode: "cell"
  501. });
  502. }
  503. if (editable === true) {
  504. nCol = i;
  505. break;
  506. }
  507. }
  508. if (nCol !== false) {
  509. $self.jqGrid("editCell", iRow, nCol, true);
  510. } else {
  511. if (p.savedRow.length > 0) {
  512. $self.jqGrid("saveCell", iRow, iCol);
  513. }
  514. }
  515. });
  516. },
  517. GridNav: function () {
  518. return this.each(function () {
  519. var $t = this, $self = $($t), p = $t.p, grid = $t.grid, i, kdir;
  520. if (!grid || p.cellEdit !== true) {
  521. return;
  522. }
  523. var bDiv = grid.bDiv;
  524. // trick to process keydown on non input elements
  525. p.knv = p.id + "_kn";
  526. var selection = $("<div style='position:fixed;top:0px;width:1px;height:1px;' tabindex='0'><div tabindex='-1' style='width:1px;height:1px;' id='" + p.knv + "'></div></div>");
  527. function scrollGrid(iR, iC, tp) {
  528. var tr = $t.rows[iR];
  529. if (tp.substr(0, 1) === "v") {
  530. var ch = bDiv.clientHeight,
  531. st = bDiv.scrollTop,
  532. nRot = tr.offsetTop + tr.clientHeight,
  533. pRot = tr.offsetTop;
  534. if (tp === "vd") {
  535. if (nRot >= st + ch) {
  536. bDiv.scrollTop = bDiv.scrollTop + tr.clientHeight;
  537. }
  538. }
  539. if (tp === "vu") {
  540. if (pRot < st) {
  541. bDiv.scrollTop = bDiv.scrollTop - tr.clientHeight;
  542. }
  543. }
  544. }
  545. if (tp === "h") {
  546. var cw = bDiv.clientWidth,
  547. sl = bDiv.scrollLeft,
  548. td = tr.cells[iC],
  549. nCol = td.offsetLeft + td.clientWidth,
  550. pCol = td.offsetLeft;
  551. if (nCol >= cw + parseInt(sl, 10)) {
  552. bDiv.scrollLeft = bDiv.scrollLeft + td.clientWidth;
  553. } else if (pCol < sl) {
  554. bDiv.scrollLeft = bDiv.scrollLeft - td.clientWidth;
  555. }
  556. }
  557. }
  558. function findNextVisible(iC, act) {
  559. var ind = 0, j, colModel = p.colModel;
  560. if (act === "lft") {
  561. ind = iC + 1;
  562. for (j = iC; j >= 0; j--) {
  563. if (colModel[j].hidden !== true) {
  564. ind = j;
  565. break;
  566. }
  567. }
  568. }
  569. if (act === "rgt") {
  570. ind = iC - 1;
  571. for (j = iC; j < colModel.length; j++) {
  572. if (colModel[j].hidden !== true) {
  573. ind = j;
  574. break;
  575. }
  576. }
  577. }
  578. return ind;
  579. }
  580. $(selection).insertBefore(grid.cDiv);
  581. $("#" + p.knv)
  582. .focus()
  583. .keydown(function (e) {
  584. var iRowOld = parseInt(p.iRow, 10), iColOld = parseInt(p.iCol, 10);
  585. kdir = e.keyCode;
  586. if (p.direction === "rtl") {
  587. if (kdir === 37) {
  588. kdir = 39;
  589. } else if (kdir === 39) {
  590. kdir = 37;
  591. }
  592. }
  593. switch (kdir) {
  594. case 38:
  595. if (iRowOld - 1 > 0) {
  596. scrollGrid(iRowOld - 1, iColOld, "vu");
  597. $self.jqGrid("editCell", iRowOld - 1, iColOld, false);
  598. }
  599. break;
  600. case 40:
  601. if (iRowOld + 1 <= $t.rows.length - 1) {
  602. scrollGrid(iRowOld + 1, iColOld, "vd");
  603. $self.jqGrid("editCell", iRowOld + 1, iColOld, false);
  604. }
  605. break;
  606. case 37:
  607. if (iColOld - 1 >= 0) {
  608. i = findNextVisible(iColOld - 1, "lft");
  609. scrollGrid(iRowOld, i, "h");
  610. $self.jqGrid("editCell", iRowOld, i, false);
  611. }
  612. break;
  613. case 39:
  614. if (iColOld + 1 <= p.colModel.length - 1) {
  615. i = findNextVisible(iColOld + 1, "rgt");
  616. scrollGrid(iRowOld, i, "h");
  617. $self.jqGrid("editCell", iRowOld, i, false);
  618. }
  619. break;
  620. case 13:
  621. if (iColOld >= 0 && iRowOld >= 0) {
  622. $self.jqGrid("editCell", iRowOld, iColOld, true);
  623. }
  624. break;
  625. default:
  626. return true;
  627. }
  628. return false;
  629. });
  630. });
  631. },
  632. getChangedCells: function (mthd) {
  633. var ret = [];
  634. if (!mthd) {
  635. mthd = "all";
  636. }
  637. this.each(function () {
  638. var $t = this, p = $t.p, htmlDecode = jgrid.htmlDecode, rows = $t.rows;
  639. if (!$t.grid || p.cellEdit !== true) {
  640. return;
  641. }
  642. $(rows).each(function (j) {
  643. var res = {};
  644. if ($(this).hasClass("edited")) {
  645. var tr = this;
  646. $(this.cells).each(function (i) {
  647. var cm = p.colModel[i], nm = cm.name, $td = getTdByColumnIndex.call($t, tr, i); // $td = $(this);
  648. if (nm !== "cb" && nm !== "subgrid" && nm !== "rn" && (mthd !== "dirty" || $td.hasClass("dirty-cell"))) {
  649. try {
  650. res[nm] = $.unformat.call($t, $td[0], { rowId: rows[j].id, colModel: cm }, i);
  651. } catch (e) {
  652. res[nm] = htmlDecode($td.html());
  653. }
  654. }
  655. });
  656. res.id = this.id;
  657. ret.push(res);
  658. }
  659. });
  660. });
  661. return ret;
  662. }
  663. });
  664. // end module grid.celledit
  665. }));