grid.inlinedit.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. /**
  2. * jqGrid extension for manipulating 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. /*jslint browser: true, eqeq: true, nomen: true, vars: true, devel: true, unparam: true, plusplus: true, white: true, todo: true */
  10. /*global jQuery, define, exports, module, require */
  11. (function (factory) {
  12. "use strict";
  13. if (typeof define === "function" && define.amd) {
  14. // AMD. Register as an anonymous module.
  15. define([
  16. "jquery",
  17. "./grid.base",
  18. "./jquery.fmatter",
  19. "./grid.common"
  20. ], factory);
  21. } else if (typeof module === "object" && module.exports) {
  22. // Node/CommonJS
  23. module.exports = function (root, $) {
  24. if (!root) {
  25. root = window;
  26. }
  27. if ($ === undefined) {
  28. // require("jquery") returns a factory that requires window to
  29. // build a jQuery instance, we normalize how we use modules
  30. // that require this pattern but the window provided is a noop
  31. // if it's defined (how jquery works)
  32. $ = typeof window !== "undefined" ?
  33. require("jquery") :
  34. require("jquery")(root);
  35. }
  36. require("./grid.base");
  37. require("./jquery.fmatter");
  38. require("./grid.common");
  39. factory($);
  40. return $;
  41. };
  42. } else {
  43. // Browser globals
  44. factory(jQuery);
  45. }
  46. }(function ($) {
  47. "use strict";
  48. var jgrid = $.jgrid, fullBoolFeedback = jgrid.fullBoolFeedback, hasOneFromClasses = jgrid.hasOneFromClasses,
  49. base = $.fn.jqGrid,
  50. getGuiStateStyles = function (path) {
  51. return base.getGuiStyles.call(this, "states." + path);
  52. };
  53. // begin module grid.inlinedit
  54. var editFeedback = function (o) {
  55. var args = $.makeArray(arguments).slice(1);
  56. args.unshift("");
  57. args.unshift("Inline");
  58. args.unshift(o);
  59. return jgrid.feedback.apply(this, args);
  60. };
  61. jgrid.inlineEdit = jgrid.inlineEdit || {};
  62. jgrid.extend({
  63. //Editing
  64. editRow: function (rowid, keys, oneditfunc, successfunc, url, extraparam, aftersavefunc, errorfunc, afterrestorefunc, beforeEditRow) {
  65. // Compatible mode old versions
  66. var oMuligrid = {}, args = $.makeArray(arguments).slice(1);
  67. if ($.type(args[0]) === "object") {
  68. oMuligrid = args[0];
  69. } else {
  70. if (keys !== undefined) { oMuligrid.keys = keys; }
  71. if ($.isFunction(oneditfunc)) { oMuligrid.oneditfunc = oneditfunc; }
  72. if ($.isFunction(successfunc)) { oMuligrid.successfunc = successfunc; }
  73. if (url !== undefined) { oMuligrid.url = url; }
  74. if (extraparam != null) { oMuligrid.extraparam = extraparam; }
  75. if ($.isFunction(aftersavefunc)) { oMuligrid.aftersavefunc = aftersavefunc; }
  76. if ($.isFunction(errorfunc)) { oMuligrid.errorfunc = errorfunc; }
  77. if ($.isFunction(afterrestorefunc)) { oMuligrid.afterrestorefunc = afterrestorefunc; }
  78. if ($.isFunction(beforeEditRow)) { oMuligrid.beforeEditRow = beforeEditRow; }
  79. // last two not as param, but as object (sorry)
  80. //if (restoreAfterError !== undefined) { oMuligrid.restoreAfterError = restoreAfterError; }
  81. //if (mtype !== undefined) { oMuligrid.mtype = mtype || "POST"; }
  82. }
  83. // End compatible
  84. return this.each(function () {
  85. var $t = this, $self = $($t), p = $t.p, cnt = 0, focus = null, svr = {}, editableValues = {}, colModel = p.colModel, opers = p.prmNames;
  86. if (!$t.grid) { return; }
  87. var o = $.extend(true, {
  88. keys: false,
  89. oneditfunc: null,
  90. successfunc: null,
  91. url: null,
  92. extraparam: {},
  93. aftersavefunc: null,
  94. errorfunc: null,
  95. afterrestorefunc: null,
  96. restoreAfterError: true,
  97. beforeEditRow: null,
  98. //mtype: "POST",
  99. focusField: true
  100. }, jgrid.inlineEdit, p.inlineEditing || {}, oMuligrid),
  101. ind = $self.jqGrid("getInd", rowid, true),
  102. focusField = o.focusField,
  103. td = typeof focusField === "object" && focusField != null ?
  104. $(focusField.target || focusField).closest("tr.jqgrow>td")[0] : null;
  105. if (ind === false) { return; }
  106. if (o.extraparam[opers.oper] !== opers.addoper) {
  107. if (!editFeedback.call($t, o, "beforeEditRow", o, rowid)) { return; }
  108. }
  109. if (($(ind).attr("editable") || "0") === "0" && !$(ind).hasClass("not-editable-row")) {
  110. var editingInfo = jgrid.detectRowEditing.call($t, rowid);
  111. if (editingInfo != null && editingInfo.mode === "cellEditing") {
  112. var savedRowInfo = editingInfo.savedRow, tr = $t.rows[savedRowInfo.id],
  113. highlightClass = getGuiStateStyles.call($t, "select");
  114. $self.jqGrid("restoreCell", savedRowInfo.id, savedRowInfo.ic);
  115. // remove highlighting of the cell
  116. $(tr.cells[savedRowInfo.ic]).removeClass("edit-cell " + highlightClass);
  117. $(tr).addClass(highlightClass).attr({ "aria-selected": "true", "tabindex": "0" });
  118. }
  119. jgrid.enumEditableCells.call($t, ind, $(ind).hasClass("jqgrid-new-row") ? "add" : "edit", function (options) {
  120. var cm = options.cm, $dataFiled = $(options.dataElement), dataWidth = options.dataWidth, tmp, opt, elc,
  121. nm = cm.name, edittype = cm.edittype, iCol = options.iCol, editoptions = cm.editoptions || {};
  122. editableValues[nm] = options.editable;
  123. if (options.editable === "hidden") { return; }
  124. try {
  125. tmp = $.unformat.call(this, options.td, { rowId: rowid, colModel: cm }, iCol);
  126. } catch (_) {
  127. tmp = edittype === "textarea" ? $dataFiled.text() : $dataFiled.html();
  128. }
  129. svr[nm] = tmp; // include only editable fields in svr object
  130. $dataFiled.html("");
  131. opt = $.extend({}, editoptions,
  132. { id: rowid + "_" + nm, name: nm, rowId: rowid, mode: options.mode, cm: cm, iCol: iCol });
  133. if (tmp === " " || tmp === " " || (tmp.length === 1 && tmp.charCodeAt(0) === 160)) { tmp = ""; }
  134. elc = jgrid.createEl.call($t, edittype, opt, tmp, true, $.extend({}, jgrid.ajaxOptions, p.ajaxSelectOptions || {}));
  135. $(elc).addClass("editable");
  136. $dataFiled.append(elc);
  137. if (dataWidth) {
  138. // change the width from auto or the value from editoptions
  139. // in case of editing ExpandColumn of TreeGrid
  140. $(elc).width(options.dataWidth);
  141. }
  142. jgrid.bindEv.call($t, elc, opt);
  143. //Again IE
  144. if (edittype === "select" && editoptions.multiple === true && editoptions.dataUrl === undefined && jgrid.msie) {
  145. $(elc).width($(elc).width());
  146. }
  147. if (focus === null) { focus = iCol; }
  148. cnt++;
  149. });
  150. if (cnt > 0) {
  151. svr.id = rowid;
  152. p.savedRow.push(svr);
  153. p.editingInfo[rowid] = {
  154. mode: "inlineEditing",
  155. savedRow: svr,
  156. editable: editableValues
  157. };
  158. $(ind).attr("editable", "1");
  159. if (focusField) {
  160. if (typeof focusField === "number" && parseInt(focusField, 10) <= colModel.length) {
  161. focus = focusField;
  162. } else if (typeof focusField === "string") {
  163. focus = p.iColByName[focusField];
  164. } else if (td != null) {
  165. focus = td.cellIndex;
  166. }
  167. setTimeout(function () {
  168. // we want to use ":focusable"
  169. var nFrozenColumns = $self.jqGrid("getNumberOfFrozenColumns"),
  170. getTdByColIndex = function (iCol) {
  171. return p.frozenColumns && nFrozenColumns > 0 && focus < nFrozenColumns ?
  172. $t.grid.fbRows[ind.rowIndex].cells[iCol] :
  173. ind.cells[iCol];
  174. },
  175. getFocusable = function (elem) {
  176. return $(elem).find("input,textarea,select,button,object,*[tabindex]")
  177. .filter(":input:visible:not(:disabled)");
  178. },
  179. getFirstFocusable = function () {
  180. return getFocusable(p.frozenColumns && nFrozenColumns > 0 ? $t.grid.fbRows[ind.rowIndex] : ind)
  181. .first();
  182. },
  183. $fe = getFocusable(getTdByColIndex(focus));
  184. if ($fe.length > 0) {
  185. $fe.first().focus();
  186. } else if (typeof o.defaultFocusField === "number" || typeof o.defaultFocusField === "string") {
  187. $fe = getFocusable(getTdByColIndex(typeof o.defaultFocusField === "number" ? o.defaultFocusField : p.iColByName[o.defaultFocusField]));
  188. if ($fe.length === 0) {
  189. $fe = getFirstFocusable();
  190. }
  191. $fe.first().focus();
  192. } else {
  193. getFirstFocusable().focus();
  194. }
  195. }, 0);
  196. }
  197. if (o.keys === true) {
  198. var $ind = $(ind);
  199. if (p.frozenColumns) {
  200. $ind = $ind.add($t.grid.fbRows[ind.rowIndex]);
  201. }
  202. $ind.on("keydown", function (e) {
  203. if (e.keyCode === 27) {
  204. $self.jqGrid("restoreRow", rowid, o.afterrestorefunc);
  205. return false;
  206. }
  207. if (e.keyCode === 13) {
  208. var ta = e.target;
  209. if (ta.tagName === "TEXTAREA") { return true; }
  210. $self.jqGrid("saveRow", rowid, o);
  211. return false;
  212. }
  213. });
  214. }
  215. fullBoolFeedback.call($t, o.oneditfunc, "jqGridInlineEditRow", rowid, o);
  216. }
  217. }
  218. });
  219. },
  220. saveRow: function (rowid, successfunc, url, extraparam, aftersavefunc, errorfunc, afterrestorefunc, beforeSaveRow) {
  221. // Compatible mode old versions
  222. var args = $.makeArray(arguments).slice(1), o = {}, $t = this[0], $self = $($t),
  223. p = $t != null ? $t.p : null, editOrAdd, infoDialog = jgrid.info_dialog,
  224. isFunction = $.isFunction,
  225. fatalErrorFunction = jgrid.defaults != null && isFunction(jgrid.defaults.fatalError) ? jgrid.defaults.fatalError : alert;
  226. if (!$t.grid || p == null) { return; }
  227. if ($.type(args[0]) === "object") {
  228. o = args[0];
  229. } else {
  230. if (isFunction(successfunc)) { o.successfunc = successfunc; }
  231. if (url !== undefined) { o.url = url; }
  232. if (extraparam !== undefined) { o.extraparam = extraparam; }
  233. if (isFunction(aftersavefunc)) { o.aftersavefunc = aftersavefunc; }
  234. if (isFunction(errorfunc)) { o.errorfunc = errorfunc; }
  235. if (isFunction(afterrestorefunc)) { o.afterrestorefunc = afterrestorefunc; }
  236. if (isFunction(beforeSaveRow)) { o.beforeSaveRow = beforeSaveRow; }
  237. }
  238. var getRes = function (path) { return $self.jqGrid("getGridRes", path); };
  239. o = $.extend(true, {
  240. successfunc: null,
  241. url: null,
  242. extraparam: {},
  243. aftersavefunc: null,
  244. errorfunc: null,
  245. afterrestorefunc: null,
  246. restoreAfterError: true,
  247. beforeSaveRow: null,
  248. ajaxSaveOptions: {},
  249. serializeSaveData: null,
  250. mtype: "POST",
  251. saveui: "enable",
  252. savetext: getRes("defaults.savetext") || "Saving..."
  253. }, jgrid.inlineEdit, p.inlineEditing || {}, o);
  254. // End compatible
  255. // TODO: add return this.each(function(){....}
  256. var tmp = {}, tmp2 = {}, postData = {}, editable, k, fr, resp, cv, editingInfo, ind = $self.jqGrid("getInd", rowid, true), $tr = $(ind),
  257. opers = p.prmNames, errcap = getRes("errors.errcap"), bClose = getRes("edit.bClose"), isRemoteSave, isError,
  258. displayErrorMessage = function (text, relativeElem) {
  259. try {
  260. var relativeRect = jgrid.getRelativeRect.call($t, relativeElem);
  261. infoDialog.call($t, errcap, text, bClose, {
  262. top: relativeRect.top,
  263. left: relativeRect.left + $($t).closest(".ui-jqgrid").offset().left
  264. });
  265. } catch (e) {
  266. fatalErrorFunction(text);
  267. }
  268. };
  269. if (ind === false) { return; }
  270. editOrAdd = o.extraparam[opers.oper] === opers.addoper ? "add" : "edit";
  271. if (!editFeedback.call($t, o, "beforeSaveRow", o, rowid, editOrAdd)) { return; }
  272. editable = $tr.attr("editable");
  273. o.url = o.url || p.editurl;
  274. isRemoteSave = o.url !== "clientArray";
  275. if (editable === "1") {
  276. editingInfo = $.jgrid.detectRowEditing.call($t, rowid);
  277. jgrid.enumEditableCells.call($t, ind, $tr.hasClass("jqgrid-new-row") ? "add" : "edit", function (options) {
  278. var cm = options.cm, formatter = cm.formatter, editoptions = cm.editoptions || {},
  279. formatoptions = cm.formatoptions || {}, valueText = {},
  280. v = jgrid.getEditedValue.call($t, $(options.dataElement), cm, valueText, options.editable);
  281. if (cm.edittype === "select" && cm.formatter !== "select") {
  282. tmp2[cm.name] = valueText.text;
  283. }
  284. cv = jgrid.checkValues.call($t, v, options.iCol, undefined, undefined,
  285. $.extend(options, {
  286. oldValue: editingInfo != null ? editingInfo.savedRow[cm.name] : null,
  287. newValue: v,
  288. oldRowData: editingInfo != null ? editingInfo.savedRow : null }));
  289. if (cv != null && cv[0] === false) {
  290. isError = true;
  291. displayErrorMessage(cv[1], options.td);
  292. return false;
  293. }
  294. if (formatter === "date" && formatoptions.sendFormatted !== true) {
  295. // TODO: call all other predefined formatters!!! Not only formatter: "date" have the problem.
  296. // Floating point separator for example
  297. v = $.unformat.date.call($t, v, cm);
  298. }
  299. if (isRemoteSave && editoptions.NullIfEmpty === true) {
  300. if (v === "") {
  301. v = "null";
  302. }
  303. }
  304. tmp[cm.name] = v;
  305. });
  306. if (isError) {
  307. return;
  308. }
  309. var idname;
  310. opers = p.prmNames;
  311. if (p.keyName === false) {
  312. idname = opers.id;
  313. } else {
  314. idname = p.keyName;
  315. }
  316. if (tmp) {
  317. tmp[opers.oper] = opers.editoper;
  318. if (tmp[idname] === undefined || tmp[idname] === "") {
  319. tmp[idname] = jgrid.stripPref(p.idPrefix, rowid);
  320. }
  321. tmp = $.extend({}, tmp, p.inlineData || {}, o.extraparam);
  322. }
  323. var validationOptions = {
  324. options: o,
  325. rowid: rowid,
  326. tr: ind,
  327. iRow: ind.rowIndex,
  328. savedRow: editingInfo.savedRow,
  329. newData: tmp,
  330. mode: editOrAdd
  331. };
  332. if (!editFeedback.call($t, o, "saveRowValidation", validationOptions)) {
  333. if (validationOptions.errorText) {
  334. displayErrorMessage(validationOptions.errorText, ind);
  335. }
  336. return;
  337. }
  338. if (!isRemoteSave) {
  339. tmp = $.extend({}, tmp, tmp2);
  340. resp = $self.jqGrid("setRowData", rowid, tmp);
  341. $tr.attr("editable", "0");
  342. for (k = 0; k < p.savedRow.length; k++) {
  343. if (String(p.savedRow[k].id) === String(rowid)) { fr = k; break; }
  344. }
  345. if (fr >= 0) {
  346. p.savedRow.splice(fr, 1);
  347. delete p.editingInfo[rowid];
  348. }
  349. fullBoolFeedback.call($t, o.aftersavefunc, "jqGridInlineAfterSaveRow", rowid, resp, tmp, o);
  350. $tr.removeClass("jqgrid-new-row").off("keydown");
  351. if (ind.id !== p.idPrefix + tmp[idname]) {
  352. $self.jqGrid("changeRowid", ind.id, p.idPrefix + tmp[idname]);
  353. }
  354. } else {
  355. $self.jqGrid("progressBar", { method: "show", loadtype: o.saveui, htmlcontent: o.savetext });
  356. postData = $.extend({}, tmp, postData);
  357. postData[idname] = jgrid.stripPref(p.idPrefix, postData[idname]);
  358. if (p.autoEncodeOnEdit) {
  359. $.each(postData, function (n, v) {
  360. if (!isFunction(v)) {
  361. postData[n] = jgrid.oldEncodePostedData(v);
  362. }
  363. });
  364. }
  365. if (ind.id !== p.idPrefix + postData[idname] && opers.idold != null &&
  366. !postData.hasOwnProperty(opers.idold)) {
  367. postData[opers.idold] = jgrid.stripPref(p.idPrefix, ind.id);
  368. }
  369. $.ajax($.extend({
  370. url: isFunction(o.url) ? o.url.call($t, postData[idname], editOrAdd, postData, o) : o.url,
  371. data: jgrid.serializeFeedback.call($t,
  372. isFunction(o.serializeSaveData) ? o.serializeSaveData : p.serializeRowData,
  373. "jqGridInlineSerializeSaveData",
  374. postData),
  375. type: isFunction(o.mtype) ? o.mtype.call($t, editOrAdd, o, postData[idname], postData) : o.mtype,
  376. complete: function (jqXHR, textStatus) {
  377. $self.jqGrid("progressBar", { method: "hide", loadtype: o.saveui });
  378. // textStatus can be "abort", "timeout", "error", "parsererror" or some text from text part of HTTP error occurs
  379. // see the answer http://stackoverflow.com/a/3617710/315935 about xhr.readyState === 4 && xhr.status === 0
  380. if ((jqXHR.status < 300 || jqXHR.status === 304) && (jqXHR.status !== 0 || jqXHR.readyState !== 4)) {
  381. var ret, sucret, j;
  382. sucret = $self.triggerHandler("jqGridInlineSuccessSaveRow", [jqXHR, rowid, o, editOrAdd, postData]);
  383. if (sucret == null || sucret === true) { sucret = [true, tmp]; }
  384. if (sucret[0] && isFunction(o.successfunc)) { sucret = o.successfunc.call($t, jqXHR, rowid, o, editOrAdd, postData); }
  385. if ($.isArray(sucret)) {
  386. // expect array - status, data, rowid
  387. ret = sucret[0];
  388. tmp = sucret[1] || tmp;
  389. } else {
  390. ret = sucret;
  391. }
  392. if (ret === true) {
  393. if (p.autoEncodeOnEdit) {
  394. $.each(tmp, function (n, v) {
  395. tmp[n] = jgrid.oldDecodePostedData(v);
  396. });
  397. }
  398. tmp = $.extend({}, tmp, tmp2);
  399. $self.jqGrid("setRowData", rowid, tmp);
  400. $tr.attr("editable", "0");
  401. for (j = 0; j < p.savedRow.length; j++) {
  402. if (String(p.savedRow[j].id) === String(rowid)) { fr = j; break; }
  403. }
  404. if (fr >= 0) {
  405. p.savedRow.splice(fr, 1);
  406. delete p.editingInfo[rowid];
  407. }
  408. fullBoolFeedback.call($t, o.aftersavefunc, "jqGridInlineAfterSaveRow", rowid, jqXHR, tmp, o);
  409. if (sucret[2] != null) {
  410. $self.jqGrid("changeRowid", rowid, p.idPrefix + sucret[2]);
  411. } else if (ind.id !== p.idPrefix + tmp[idname]) {
  412. $self.jqGrid("changeRowid", ind.id, p.idPrefix + tmp[idname]);
  413. }
  414. $tr.removeClass("jqgrid-new-row").off("keydown");
  415. } else {
  416. fullBoolFeedback.call($t, o.errorfunc, "jqGridInlineErrorSaveRow", rowid, jqXHR, textStatus, null, o);
  417. if (o.restoreAfterError === true) {
  418. $self.jqGrid("restoreRow", rowid, o.afterrestorefunc);
  419. }
  420. }
  421. }
  422. },
  423. error: function (res, stat, err) {
  424. $self.triggerHandler("jqGridInlineErrorSaveRow", [rowid, res, stat, err, o]);
  425. if (isFunction(o.errorfunc)) {
  426. o.errorfunc.call($t, rowid, res, stat, err);
  427. } else {
  428. var rT = res.responseText || res.statusText;
  429. try {
  430. infoDialog.call($t, errcap, '<div class="' + getGuiStateStyles.call($t, "error") + '">' + rT + "</div>", bClose, { buttonalign: "right" });
  431. } catch (e1) {
  432. fatalErrorFunction(rT);
  433. }
  434. }
  435. if (o.restoreAfterError === true) {
  436. $self.jqGrid("restoreRow", rowid, o.afterrestorefunc);
  437. }
  438. }
  439. }, jgrid.ajaxOptions, p.ajaxRowOptions, o.ajaxSaveOptions || {}));
  440. }
  441. }
  442. return;
  443. },
  444. restoreRow: function (rowid, afterrestorefunc) {
  445. // Compatible mode old versions
  446. var args = $.makeArray(arguments).slice(1), oMuligrid = {};
  447. if ($.type(args[0]) === "object") {
  448. oMuligrid = args[0];
  449. } else {
  450. if ($.isFunction(afterrestorefunc)) { oMuligrid.afterrestorefunc = afterrestorefunc; }
  451. }
  452. // End compatible
  453. return this.each(function () {
  454. var $t = this, $self = $($t), p = $t.p, fr = -1, ares = {}, k;
  455. if (!$t.grid) { return; }
  456. var o = $.extend(true, {}, jgrid.inlineEdit, p.inlineEditing || {}, oMuligrid);
  457. var ind = $self.jqGrid("getInd", rowid, true);
  458. if (ind === false) { return; }
  459. if (!editFeedback.call($t, o, "beforeCancelRow", o, rowid)) { return; }
  460. for (k = 0; k < p.savedRow.length; k++) {
  461. if (String(p.savedRow[k].id) === String(rowid)) {
  462. fr = k;
  463. break;
  464. }
  465. }
  466. if (fr >= 0) {
  467. if ($.isFunction($.fn.datepicker)) {
  468. try {
  469. $("input.hasDatepicker", "#" + jgrid.jqID(ind.id)).datepicker("hide");
  470. } catch (ignore) { }
  471. }
  472. $.each(p.colModel, function () {
  473. var nm = this.name;
  474. if (p.savedRow[fr].hasOwnProperty(nm)) {
  475. ares[nm] = p.savedRow[fr][nm];
  476. if (this.formatter && this.formatter === "date" && (this.formatoptions == null || this.formatoptions.sendFormatted !== true)) {
  477. // TODO: call all other predefined formatters!!! Not only formatter: "date" have the problem.
  478. // Floating point separator for example
  479. ares[nm] = $.unformat.date.call($t, ares[nm], this);
  480. }
  481. }
  482. });
  483. $self.jqGrid("setRowData", rowid, ares);
  484. $(ind).attr("editable", "0").off("keydown");
  485. p.savedRow.splice(fr, 1);
  486. delete p.editingInfo[rowid];
  487. if ($("#" + jgrid.jqID(rowid), $t).hasClass("jqgrid-new-row")) {
  488. setTimeout(function () {
  489. $self.jqGrid("delRowData", rowid);
  490. $self.jqGrid("showAddEditButtons", false);
  491. }, 0);
  492. }
  493. }
  494. fullBoolFeedback.call($t, o.afterrestorefunc, "jqGridInlineAfterRestoreRow", rowid);
  495. });
  496. },
  497. addRow: function (oMuligrid) {
  498. return this.each(function () {
  499. if (!this.grid) { return; }
  500. var $t = this, $self = $($t), p = $t.p,
  501. o = $.extend(true, {
  502. rowID: null,
  503. initdata: {},
  504. position: "first",
  505. useDefValues: true,
  506. useFormatter: false,
  507. beforeAddRow: null,
  508. //srcRowid: undefined,
  509. addRowParams: { extraparam: {} }
  510. }, jgrid.inlineEdit, p.inlineEditing || {}, oMuligrid || {});
  511. if (!editFeedback.call($t, o, "beforeAddRow", o.addRowParams)) { return; }
  512. o.rowID = $.isFunction(o.rowID) ? o.rowID.call($t, o) : ((o.rowID != null) ? o.rowID : jgrid.randId());
  513. if (o.useDefValues === true) {
  514. $(p.colModel).each(function () {
  515. if (this.editoptions && this.editoptions.defaultValue) {
  516. var opt = this.editoptions.defaultValue;
  517. o.initdata[this.name] = $.isFunction(opt) ? opt.call($t, o) : opt;
  518. }
  519. });
  520. }
  521. o.rowID = p.idPrefix + o.rowID;
  522. $self.jqGrid("addRowData", o.rowID, o.initdata, o.position, o.srcRowid);
  523. $("#" + jgrid.jqID(o.rowID), $t).addClass("jqgrid-new-row");
  524. if (o.useFormatter) {
  525. $("#" + jgrid.jqID(o.rowID) + " .ui-inline-edit", $t).click();
  526. } else {
  527. var opers = p.prmNames, oper = opers.oper;
  528. o.addRowParams.extraparam[oper] = opers.addoper;
  529. $self.jqGrid("editRow", o.rowID, o.addRowParams);
  530. $self.jqGrid("setSelection", o.rowID);
  531. }
  532. });
  533. },
  534. inlineNav: function (elem, oMuligrid) {
  535. if (typeof elem === "object") {
  536. // the option pager are skipped
  537. oMuligrid = elem;
  538. elem = undefined;
  539. }
  540. return this.each(function () {
  541. var $t = this, $self = $($t), p = $t.p;
  542. if (!this.grid || p == null) { return; }
  543. var $elem, gID = elem === p.toppager ? p.idSel + "_top" : p.idSel,
  544. gid = elem === p.toppager ? p.id + "_top" : p.id, disabledClass = getGuiStateStyles.call($t, "disabled"),
  545. o = $.extend(true,
  546. {
  547. edit: true,
  548. editicon: "ui-icon-pencil",
  549. add: true,
  550. addicon: "ui-icon-plus",
  551. save: true,
  552. saveicon: "ui-icon-disk",
  553. cancel: true,
  554. cancelicon: "ui-icon-cancel",
  555. commonIconClass: "ui-icon",
  556. iconsOverText: false,
  557. //alertToTop: false, use undefined to be able to use defaults from $.jgrid.jqModal or later from p.jqModal
  558. addParams: { addRowParams: { extraparam: {} } },
  559. editParams: {},
  560. restoreAfterSelect: true
  561. },
  562. //TODO make getRes(locales[p.locale], "nav"), jgrid.nav || {}, p.navOptions || {}
  563. // as the result of working getRes("nav")
  564. //getRes(locales[p.locale], "nav"),
  565. $self.jqGrid("getGridRes", "nav"),
  566. jgrid.nav || {},
  567. p.navOptions || {},
  568. jgrid.inlineNav || {},
  569. p.inlineNavOptions || {},
  570. oMuligrid || {}
  571. ),
  572. viewModalAlert = function () {
  573. $t.modalAlert();
  574. };
  575. if (elem === undefined) {
  576. if (p.pager) {
  577. $self.jqGrid("inlineNav", p.pager, o);
  578. if (p.toppager) {
  579. elem = p.toppager;
  580. gID = p.idSel + "_top";
  581. gid = p.id + "_top";
  582. } else {
  583. return;
  584. }
  585. } else if (p.toppager) {
  586. elem = p.toppager;
  587. gID = p.idSel + "_top";
  588. gid = p.id + "_top";
  589. }
  590. }
  591. if (elem === undefined) {
  592. return; // error
  593. }
  594. $elem = $(elem);
  595. if ($elem.length <= 0) {
  596. return; // error
  597. }
  598. if ($elem.find(".navtable").length <= 0) {
  599. // create navigator bar if it is not yet exist
  600. $self.jqGrid("navGrid", elem, { add: false, edit: false, del: false, search: false, refresh: false, view: false });
  601. }
  602. p._inlinenav = true;
  603. // detect the formatactions column
  604. if (o.addParams.useFormatter === true) {
  605. var cm = p.colModel, i, defaults, ap;
  606. for (i = 0; i < cm.length; i++) {
  607. if (cm[i].formatter && cm[i].formatter === "actions") {
  608. if (cm[i].formatoptions) {
  609. defaults = {
  610. keys: false,
  611. onEdit: null,
  612. onSuccess: null,
  613. afterSave: null,
  614. onError: null,
  615. afterRestore: null,
  616. extraparam: {},
  617. url: null
  618. };
  619. ap = $.extend(defaults, cm[i].formatoptions);
  620. o.addParams.addRowParams = {
  621. "keys": ap.keys,
  622. "oneditfunc": ap.onEdit,
  623. "successfunc": ap.onSuccess,
  624. "url": ap.url,
  625. "extraparam": ap.extraparam,
  626. "aftersavefunc": ap.afterSave,
  627. "errorfunc": ap.onError,
  628. "afterrestorefunc": ap.afterRestore
  629. };
  630. }
  631. break;
  632. }
  633. }
  634. }
  635. if (o.add) {
  636. $self.jqGrid("navButtonAdd", elem, {
  637. caption: o.addtext,
  638. title: o.addtitle,
  639. commonIconClass: o.commonIconClass,
  640. buttonicon: o.addicon,
  641. iconsOverText: o.iconsOverText,
  642. id: gid + "_iladd",
  643. onClickButton: function () {
  644. if (!hasOneFromClasses(this, disabledClass)) {
  645. $self.jqGrid("addRow", o.addParams);
  646. }
  647. }
  648. });
  649. }
  650. if (o.edit) {
  651. $self.jqGrid("navButtonAdd", elem, {
  652. caption: o.edittext,
  653. title: o.edittitle,
  654. commonIconClass: o.commonIconClass,
  655. buttonicon: o.editicon,
  656. iconsOverText: o.iconsOverText,
  657. id: gid + "_iledit",
  658. onClickButton: function () {
  659. if (!hasOneFromClasses(this, disabledClass)) {
  660. var sr = p.selrow;
  661. if (sr) {
  662. $self.jqGrid("editRow", sr, o.editParams);
  663. } else {
  664. viewModalAlert();
  665. }
  666. }
  667. }
  668. });
  669. }
  670. if (o.save) {
  671. $self.jqGrid("navButtonAdd", elem, {
  672. caption: o.savetext,
  673. title: o.savetitle,
  674. commonIconClass: o.commonIconClass,
  675. buttonicon: o.saveicon,
  676. iconsOverText: o.iconsOverText,
  677. id: gid + "_ilsave",
  678. onClickButton: function () {
  679. if (!hasOneFromClasses(this, disabledClass) && p.savedRow.length > 0) {
  680. var sr = p.savedRow[0].id;
  681. if (sr) {
  682. var opers = p.prmNames, oper = opers.oper, tmpParams = o.editParams;
  683. if ($("#" + jgrid.jqID(sr), $t).hasClass("jqgrid-new-row")) {
  684. o.addParams.addRowParams.extraparam[oper] = opers.addoper;
  685. tmpParams = o.addParams.addRowParams;
  686. } else {
  687. if (!o.editParams.extraparam) {
  688. o.editParams.extraparam = {};
  689. }
  690. o.editParams.extraparam[oper] = opers.editoper;
  691. }
  692. $self.jqGrid("saveRow", sr, tmpParams);
  693. } else {
  694. viewModalAlert();
  695. }
  696. }
  697. }
  698. });
  699. $(gID + "_ilsave").addClass(disabledClass);
  700. }
  701. if (o.cancel) {
  702. $self.jqGrid("navButtonAdd", elem, {
  703. caption: o.canceltext,
  704. title: o.canceltitle,
  705. commonIconClass: o.commonIconClass,
  706. buttonicon: o.cancelicon,
  707. iconsOverText: o.iconsOverText,
  708. id: gid + "_ilcancel",
  709. onClickButton: function () {
  710. if (!hasOneFromClasses(this, disabledClass) && p.savedRow.length > 0) {
  711. var sr = p.savedRow[0].id, cancelPrm = o.editParams;
  712. if (sr) {
  713. if ($("#" + jgrid.jqID(sr), $t).hasClass("jqgrid-new-row")) {
  714. cancelPrm = o.addParams.addRowParams;
  715. }
  716. $self.jqGrid("restoreRow", sr, cancelPrm);
  717. } else {
  718. viewModalAlert();
  719. }
  720. }
  721. }
  722. });
  723. $(gID + "_ilcancel").addClass(disabledClass);
  724. }
  725. if (o.restoreAfterSelect === true) {
  726. $self.on("jqGridSelectRow", function (e, rowid) {
  727. if (p.savedRow.length > 0 && p._inlinenav === true) {
  728. var editingRowId = p.savedRow[0].id;
  729. if (rowid !== editingRowId && typeof editingRowId !== "number") {
  730. $self.jqGrid("restoreRow", editingRowId, o.editParams);
  731. }
  732. }
  733. });
  734. }
  735. $self.on("jqGridInlineAfterRestoreRow jqGridInlineAfterSaveRow", function () {
  736. $self.jqGrid("showAddEditButtons", false);
  737. });
  738. $self.on("jqGridInlineEditRow", function (e, rowid) {
  739. $self.jqGrid("showAddEditButtons", true, rowid);
  740. });
  741. });
  742. },
  743. showAddEditButtons: function (isEditing) {
  744. return this.each(function () {
  745. var $t = this;
  746. if (!$t.grid) { return; }
  747. var p = $t.p, idSel = p.idSel, disabledClass = getGuiStateStyles.call($t, "disabled"),
  748. saveCancel = idSel + "_ilsave," + idSel + "_ilcancel" + (p.toppager ? "," + idSel + "_top_ilsave," + idSel + "_top_ilcancel" : ""),
  749. addEdit = idSel + "_iladd," + idSel + "_iledit" + (p.toppager ? "," + idSel + "_top_iladd," + idSel + "_top_iledit" : "");
  750. $(isEditing ? addEdit : saveCancel).addClass(disabledClass);
  751. $(isEditing ? saveCancel : addEdit).removeClass(disabledClass);
  752. });
  753. }
  754. });
  755. // end module grid.inlinedit
  756. }));