grid.grouping.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*jshint eqeqeq:false, eqnull:true */
  2. /*global jQuery, define, exports, module, require */
  3. /*jslint plusplus: true, unparam: true, eqeq: true, nomen: true, todo: true, continue: true */
  4. // Grouping module
  5. (function (factory) {
  6. "use strict";
  7. if (typeof define === "function" && define.amd) {
  8. // AMD. Register as an anonymous module.
  9. define([
  10. "jquery",
  11. "./grid.base"
  12. ], factory);
  13. } else if (typeof module === "object" && module.exports) {
  14. // Node/CommonJS
  15. module.exports = function (root, $) {
  16. if (!root) {
  17. root = window;
  18. }
  19. if ($ === undefined) {
  20. // require("jquery") returns a factory that requires window to
  21. // build a jQuery instance, we normalize how we use modules
  22. // that require this pattern but the window provided is a noop
  23. // if it's defined (how jquery works)
  24. $ = typeof window !== "undefined" ?
  25. require("jquery") :
  26. require("jquery")(root);
  27. }
  28. require("./grid.base");
  29. factory($);
  30. return $;
  31. };
  32. } else {
  33. // Browser globals
  34. factory(jQuery);
  35. }
  36. }(function ($) {
  37. "use strict";
  38. var jgrid = $.jgrid, base = $.fn.jqGrid;
  39. // begin module grid.grouping
  40. jgrid.extend({
  41. groupingSetup: function () {
  42. return this.each(function () {
  43. var $t = this, i, j, cml, p = $t.p, colModel = p.colModel, grp = p.groupingView, cm, summary,
  44. emptyFormatter = function () {
  45. return "";
  46. };
  47. if (grp !== null && ((typeof grp === "object") || $.isFunction(grp))) {
  48. if (!grp.groupField.length) {
  49. p.grouping = false;
  50. } else {
  51. if (grp.visibiltyOnNextGrouping === undefined) {
  52. grp.visibiltyOnNextGrouping = [];
  53. }
  54. grp.lastvalues = [];
  55. if (!grp._locgr) {
  56. grp.groups = [];
  57. }
  58. grp.counters = [];
  59. for (i = 0; i < grp.groupField.length; i++) {
  60. if (!grp.groupOrder[i]) {
  61. grp.groupOrder[i] = "asc";
  62. }
  63. if (!grp.groupText[i]) {
  64. grp.groupText[i] = "{0}";
  65. }
  66. if (typeof grp.groupColumnShow[i] !== "boolean") {
  67. grp.groupColumnShow[i] = true;
  68. }
  69. if (typeof grp.groupSummary[i] !== "boolean") {
  70. grp.groupSummary[i] = false;
  71. }
  72. if (!grp.groupSummaryPos[i]) {
  73. grp.groupSummaryPos[i] = "footer";
  74. }
  75. // TODO: allow groupField be from additionalProperties
  76. // and not only from colModel
  77. cm = colModel[p.iColByName[grp.groupField[i]]];
  78. if (grp.groupColumnShow[i] === true) {
  79. grp.visibiltyOnNextGrouping[i] = true;
  80. if (cm != null && cm.hidden === true) {
  81. base.showCol.call($($t), grp.groupField[i]);
  82. }
  83. } else {
  84. grp.visibiltyOnNextGrouping[i] = $("#" + jgrid.jqID(p.id + "_" + grp.groupField[i])).is(":visible");
  85. if (cm != null && cm.hidden !== true) {
  86. base.hideCol.call($($t), grp.groupField[i]);
  87. }
  88. }
  89. }
  90. grp.summary = [];
  91. if (grp.hideFirstGroupCol) {
  92. grp.formatDisplayField[0] = function (v) {
  93. return v;
  94. };
  95. }
  96. for (j = 0, cml = colModel.length; j < cml; j++) {
  97. cm = colModel[j];
  98. if (grp.hideFirstGroupCol) {
  99. if (!cm.hidden && grp.groupField[0] === cm.name) {
  100. cm.formatter = emptyFormatter;
  101. }
  102. }
  103. if (cm.summaryType) {
  104. summary = {
  105. nm: cm.name,
  106. st: cm.summaryType,
  107. v: "",
  108. sr: cm.summaryRound,
  109. srt: cm.summaryRoundType || "round"
  110. };
  111. if (cm.summaryDivider) {
  112. summary.sd = cm.summaryDivider;
  113. summary.vd = "";
  114. }
  115. grp.summary.push(summary);
  116. }
  117. }
  118. }
  119. } else {
  120. p.grouping = false;
  121. }
  122. });
  123. },
  124. groupingPrepare: function (record, irow) {
  125. this.each(function () {
  126. var $t = this, p = $t.p, grp = p.groupingView, groups = grp.groups, counters = grp.counters,
  127. lastvalues = grp.lastvalues, isInTheSameGroup = grp.isInTheSameGroup, groupLength = grp.groupField.length,
  128. i, j, keys, newGroup, counter, fieldName, v, displayName, displayValue, changed = false,
  129. groupingCalculationsHandler = base.groupingCalculations.handler, key,
  130. buildSummary = function () {
  131. var iSummary, summary, st;
  132. for (iSummary = 0; iSummary < counter.summary.length; iSummary++) {
  133. summary = counter.summary[iSummary];
  134. st = $.isArray(summary.st) ? summary.st[newGroup.idx] : summary.st;
  135. if ($.isFunction(st)) {
  136. summary.v = st.call($t, summary.v, summary.nm, record, newGroup);
  137. } else {
  138. summary.v = groupingCalculationsHandler.call($($t), st, summary.v, summary.nm, summary.sr, summary.srt, record);
  139. if (st.toLowerCase() === "avg" && summary.sd) {
  140. summary.vd = groupingCalculationsHandler.call($($t), st, summary.vd, summary.sd, summary.sr, summary.srt, record);
  141. }
  142. }
  143. }
  144. return counter.summary;
  145. },
  146. normilizeValue = function (value, cmOrPropName) {
  147. if (value == null && grp.useDefaultValuesOnGrouping) {
  148. var cm = p.iColByName[cmOrPropName] !== undefined ?
  149. p.colModel[p.iColByName[cmOrPropName]] :
  150. p.additionalProperties[p.iPropByName[cmOrPropName]],
  151. defaultValue;
  152. if (cm != null && cm.formatter != null) {
  153. if (cm.formatoptions != null && cm.formatoptions.defaultValue !== undefined) {
  154. value = cm.formatoptions.defaultValue;
  155. } else if (typeof cm.formatter === "string") {
  156. defaultValue = $($t).jqGrid("getGridRes", "formatter." + cm.formatter + ".defaultValue");
  157. if (defaultValue !== undefined) {
  158. value = defaultValue;
  159. }
  160. }
  161. }
  162. }
  163. return value;
  164. };
  165. for (i = 0; i < groupLength; i++) {
  166. fieldName = grp.groupField[i];
  167. v = normilizeValue(record[fieldName], fieldName);
  168. key = v;
  169. displayName = grp.displayField[i];
  170. displayValue = displayName == null ?
  171. null :
  172. normilizeValue(record[displayName], displayName);
  173. if (displayValue == null) {
  174. displayValue = v;
  175. }
  176. if (v !== undefined) {
  177. keys = [];
  178. for (j = 0; j <= i; j++) {
  179. keys.push(record[grp.groupField[j]]);
  180. }
  181. newGroup = {
  182. idx: i, // index in grp.groupField array
  183. dataIndex: fieldName,
  184. value: v,
  185. displayValue: displayValue,
  186. startRow: irow,
  187. cnt: 1,
  188. keys: keys,
  189. summary: []
  190. };
  191. counter = {
  192. cnt: 1,
  193. pos: groups.length,
  194. summary: $.extend(true, [], grp.summary)
  195. };
  196. if (irow === 0) {
  197. // First record always starts a new group
  198. groups.push(newGroup);
  199. lastvalues[i] = v;
  200. counters[i] = counter;
  201. } else {
  202. if (typeof v !== "object" && ($.isArray(isInTheSameGroup) && $.isFunction(isInTheSameGroup[i]) ? !isInTheSameGroup[i].call($t, lastvalues[i], v, i, grp) : lastvalues[i] !== v)) {
  203. // This record is not in same group as previous one
  204. groups.push(newGroup);
  205. lastvalues[i] = v;
  206. changed = true;
  207. counters[i] = counter;
  208. } else {
  209. if (changed) {
  210. // This group has changed because an earlier group changed.
  211. groups.push(newGroup);
  212. lastvalues[i] = v;
  213. counters[i] = counter;
  214. } else {
  215. counter = counters[i];
  216. counter.cnt += 1;
  217. groups[counter.pos].cnt = counter.cnt;
  218. }
  219. }
  220. }
  221. groups[counter.pos].summary = buildSummary();
  222. for (j = counter.pos - 1; j >= 0; j--) {
  223. // find the parent group (the grouping header)
  224. if (groups[j].idx < groups[counter.pos].idx) {
  225. groups[counter.pos].parentGroupIndex = j;
  226. groups[counter.pos].parentGroup = groups[j];
  227. break;
  228. }
  229. }
  230. }
  231. }
  232. //gdata.push( rData );
  233. });
  234. return this;
  235. },
  236. getGroupHeaderIndex: function (hid, clickedElem) {
  237. var $self = this, self = $self[0], p = self.p,
  238. $tr = clickedElem ?
  239. $(clickedElem).closest("tr.jqgroup") :
  240. $("#" + jgrid.jqID(hid)),
  241. groupLevel = parseInt($tr.data("jqgrouplevel"), 10),
  242. hPrefix = p.id + "ghead_" + groupLevel + "_";
  243. if (isNaN(groupLevel) || !$tr.hasClass("jqgroup") || hid.length <= hPrefix.length) {
  244. return -1;
  245. }
  246. return parseInt(hid.substring(hPrefix.length), 10);
  247. },
  248. groupingToggle: function (hid, clickedElem) {
  249. this.each(function () {
  250. var $t = this, p = $t.p, grp = p.groupingView,
  251. minusClasses = grp.minusicon, plusClasses = grp.plusicon,
  252. $tr = clickedElem ?
  253. $(clickedElem).closest("tr.jqgroup") :
  254. $("#" + jgrid.jqID(hid)),
  255. getGroupHeaderIcon = function ($trElem) {
  256. return $trElem.find(">td>span." + "tree-wrap");
  257. },
  258. itemGroupingLevel, iRowStart, showDataRowsOnExpending = true,
  259. $groupIcon, collapsed = false, rowsToHideOrShow = [],
  260. addToHideOrShow = function ($elem) {
  261. var i, l = $elem.length;
  262. for (i = 0; i < l; i++) {
  263. rowsToHideOrShow.push($elem[i]);
  264. }
  265. },
  266. num = parseInt($tr.data("jqgrouplevel"), 10);
  267. if (p.frozenColumns && $tr.length > 0) {
  268. // always get row from non-frozen column
  269. iRowStart = $tr[0].rowIndex;
  270. $tr = $($t.rows[iRowStart]);
  271. $tr = $tr.add($t.grid.fbRows[iRowStart]);
  272. }
  273. $groupIcon = getGroupHeaderIcon($tr);
  274. if (jgrid.hasAllClasses($groupIcon, minusClasses)) {
  275. $groupIcon.removeClass(minusClasses).addClass(plusClasses);
  276. collapsed = true;
  277. } else {
  278. $groupIcon.removeClass(plusClasses).addClass(minusClasses);
  279. }
  280. for ($tr = $tr.next(); $tr.length; $tr = $tr.next()) {
  281. if ($tr.hasClass("jqfoot")) {
  282. itemGroupingLevel = parseInt($tr.data("jqfootlevel"), 10);
  283. if (collapsed) {
  284. // hide all till the summary row of the same level.
  285. // don't hide the summary row if grp.showSummaryOnHide === true
  286. itemGroupingLevel = parseInt($tr.data("jqfootlevel"), 10);
  287. if ((!grp.showSummaryOnHide && itemGroupingLevel === num) || itemGroupingLevel > num) {
  288. addToHideOrShow($tr);
  289. }
  290. // stop hiding of rows if the footer of parent group are found
  291. if (itemGroupingLevel < num) { break; }
  292. } else {
  293. if (itemGroupingLevel === num || (grp.showSummaryOnHide && itemGroupingLevel === num + 1)) {
  294. addToHideOrShow($tr);
  295. }
  296. if (itemGroupingLevel <= num) { break; }
  297. }
  298. } else if ($tr.hasClass("jqgroup")) {
  299. itemGroupingLevel = parseInt($tr.data("jqgrouplevel"), 10);
  300. if (collapsed) {
  301. // stop hiding of rows if the grouping header of the next group
  302. // of the same (or higher) level are found
  303. if (itemGroupingLevel <= num) { break; }
  304. addToHideOrShow($tr);
  305. } else {
  306. // stop next grouping header of the same lever are found
  307. if (itemGroupingLevel <= num) { break; }
  308. if (itemGroupingLevel === num + 1) {
  309. // one should display subgroupes in collaped form
  310. getGroupHeaderIcon($tr).removeClass(minusClasses).addClass(plusClasses);
  311. addToHideOrShow($tr);
  312. }
  313. // one need hide all data if subgroup is found
  314. showDataRowsOnExpending = false;
  315. }
  316. } else { // data
  317. // we set currently no information about the level of data
  318. // se we use showDataRowsOnExpending variable which will be
  319. // used during expanding of data
  320. if (collapsed || showDataRowsOnExpending) {
  321. // grouping data need be displayed only
  322. // if the last level group with data (no subgroups)
  323. // is expanded
  324. addToHideOrShow($tr);
  325. }
  326. }
  327. }
  328. //$(rowsToHideOrShow)[collapsed ? "hide" : "show"]();
  329. $(rowsToHideOrShow).css("display", collapsed ? "none" : "");
  330. // fix position of elements of frozen divs
  331. if (p.frozenColumns) {
  332. $($t).triggerHandler("jqGridResetFrozenHeights", [{
  333. header: {
  334. resizeDiv: false,
  335. resizedRows: {
  336. iRowStart: -1, // -1 means don't recalculate heights or rows
  337. iRowEnd: -1
  338. }
  339. },
  340. resizeFooter: false,
  341. body: {
  342. resizeDiv: true,
  343. resizedRows: {
  344. iRowStart: iRowStart,
  345. iRowEnd: ($tr.length ? $tr[0].rowIndex - 1 : -1)
  346. }
  347. }
  348. }]);
  349. }
  350. // recalculate the width because vertical scrollbar can
  351. // appears/disappears after expanding/collapsing
  352. $t.fixScrollOffsetAndhBoxPadding();
  353. $($t).triggerHandler("jqGridGroupingClickGroup", [hid, collapsed]);
  354. if ($.isFunction(p.onClickGroup)) {
  355. p.onClickGroup.call($t, hid, collapsed);
  356. }
  357. });
  358. return false;
  359. },
  360. groupingRender: function (grdata, rn) {
  361. // input parameter grdata is array of strings, which are either opening <tr> element
  362. // or full HTML fragment (outer HTML) of <td> element, inclusive the closing tag </td>
  363. // or it contains the closing </tr> tag. The array grdata contains HTML fragments
  364. // of all rows from the current group.
  365. // The exact contain of the grdata is the following:
  366. // "<tr ...>" - the opening tag of the first row of the group
  367. // "<td>...</td>" - the irst cell of the first row
  368. // "<td>...</td>" - the second cell of the first row
  369. // ...
  370. // "<td>...</td>" - the last cell of the first row
  371. // "</tr>" - closing tag of the first row of the group
  372. // "<tr ...>" - the opening tag of the second row of the group
  373. // ... - all <td> elements of the second row
  374. // "</tr>" - closing tag of the second row of the group
  375. // ...
  376. // "<tr ...>" - the opening tag of the last row of the group
  377. // ... - all <td> elements of the last row
  378. // "</tr>" - closing tag of the last row of the group
  379. // The input parameter rn corresponds to p.rowNum in the most cases.
  380. var str = "", $t = this[0], p = $t.p, toEnd = 0, cp = [],
  381. grp = p.groupingView, sumreverse = $.makeArray(grp.groupSummary),
  382. groupLength = grp.groupField.length, groups = grp.groups, colModel = p.colModel,
  383. cmLength = colModel.length, page = p.page,
  384. eventNames = "jqGridShowHideCol.groupingRender",
  385. getGridRowStyles = function (classes) {
  386. return base.getGuiStyles.call($t, "gridRow", classes);
  387. },
  388. jqgroupClass = getGridRowStyles("jqgroup ui-row-" + p.direction),
  389. jqfootClass = getGridRowStyles("jqfoot ui-row-" + p.direction);
  390. function buildSummaryTd(iEndGroup, offset, g, foffset, iconHtml) {
  391. var fdata = groups[iEndGroup], i, groupCount, strTd = "", tmpdata, colSpan, align, vv,
  392. madeHidden, nMakeHidden = 0, iSummary, summary, cm, iCol, summaryType, summaryTpl,
  393. isColumnForIconNotFound = true;
  394. if (offset !== 0 && groups[iEndGroup].idx !== 0) {
  395. for (i = iEndGroup; i >= 0; i--) {
  396. if (groups[i].idx === groups[iEndGroup].idx - offset) {
  397. fdata = groups[i];
  398. break;
  399. }
  400. }
  401. }
  402. groupCount = fdata.cnt;
  403. for (iCol = (iconHtml === undefined ? foffset : 0); iCol < cmLength; iCol++) {
  404. tmpdata = "&#160;";
  405. cm = colModel[iCol];
  406. for (iSummary = 0; iSummary < fdata.summary.length; iSummary++) {
  407. summary = fdata.summary[iSummary];
  408. summaryType = $.isArray(summary.st) ? summary.st[g.idx] : summary.st;
  409. summaryTpl = $.isArray(cm.summaryTpl) ? cm.summaryTpl[g.idx] : (cm.summaryTpl || "{0}");
  410. if (summary.nm === cm.name) {
  411. if (typeof summaryType === "string" && summaryType.toLowerCase() === "avg") {
  412. if (summary.sd && summary.vd) {
  413. summary.v = (summary.v / summary.vd);
  414. } else if (summary.v && groupCount > 0) {
  415. summary.v = (summary.v / groupCount);
  416. }
  417. }
  418. try {
  419. summary.groupCount = fdata.cnt;
  420. summary.groupIndex = fdata.dataIndex;
  421. summary.groupValue = fdata.value;
  422. vv = $t.formatter("", summary.v, iCol, summary);
  423. } catch (ef) {
  424. vv = summary.v;
  425. }
  426. tmpdata = jgrid.format(summaryTpl, vv);
  427. if (cm.summaryFormat) {
  428. tmpdata = cm.summaryFormat.call($t, g, tmpdata, vv, cm, summary);
  429. }
  430. break;
  431. }
  432. }
  433. colSpan = false;
  434. align = false;
  435. if (iconHtml !== undefined && isColumnForIconNotFound) {
  436. if (!cm.hidden) {
  437. // the icon need be placed in the first non-hidden column
  438. tmpdata = iconHtml;
  439. isColumnForIconNotFound = false;
  440. if (foffset > 1) {
  441. colSpan = true;
  442. // if foffset > 1 then the next foffset-1 non-hidden columns
  443. // must be displayed hidden.
  444. nMakeHidden = foffset - 1;
  445. }
  446. // the icon in the column header must be left aligned
  447. align = cm.align; // save the original align value
  448. cm.align = p.direction === "rtl" ? "right" : "left";
  449. grp.iconColumnName = cm.name;
  450. }
  451. }
  452. madeHidden = false;
  453. if (nMakeHidden > 0 && !cm.hidden && tmpdata === "&#160;") {
  454. madeHidden = true;
  455. if (align) {
  456. cm.align = align; // restore the original align value
  457. }
  458. nMakeHidden--;
  459. continue;
  460. }
  461. strTd += "<td role='gridcell' " + $t.formatCol(iCol, 1, "") +
  462. (colSpan ? "colspan='" + foffset + "'" : "") + ">" + tmpdata + "</td>";
  463. colSpan = false;
  464. if (align) {
  465. cm.align = align; // restore the original align value
  466. }
  467. if (madeHidden) {
  468. cm.hidden = false;
  469. nMakeHidden--;
  470. }
  471. }
  472. return strTd;
  473. }
  474. // TODO: allow groupField be from additionalProperties
  475. // and not only from colModel
  476. $.each(colModel, function (i, n) {
  477. var iGroup;
  478. for (iGroup = 0; iGroup < groupLength; iGroup++) {
  479. if (grp.groupField[iGroup] === n.name) {
  480. cp[iGroup] = i;
  481. break;
  482. }
  483. }
  484. });
  485. sumreverse.reverse();
  486. $.each(groups, function (i, n) {
  487. var gv, clid = p.id + "ghead_" + n.idx, hid = clid + "_" + i,
  488. groupCollapse = $.isFunction(grp.groupCollapse) ?
  489. grp.groupCollapse.call($t, { group: n, rowid: hid }) :
  490. grp.groupCollapse,
  491. jj, kk, ik, colspan = 1, offset = 0, sgr, gg, end, grpTextStr,
  492. leaf = groupLength - 1 === n.idx,
  493. parentGroupCollapse = n.parentGroup != null ?
  494. n.parentGroup.collapsed :
  495. false,
  496. icon = "<span style='cursor:pointer;margin-" +
  497. (p.direction === "rtl" ? "right:" : "left:") + (n.idx * 12) +
  498. "px;' class='" + grp.commonIconClass + " " +
  499. (groupCollapse ? grp.plusicon : grp.minusicon) + " tree-wrap'></span>";
  500. if (grp._locgr) {
  501. if (!(n.startRow + n.cnt > (page - 1) * rn && n.startRow < page * rn)) {
  502. return true;
  503. }
  504. }
  505. if (parentGroupCollapse) {
  506. groupCollapse = true;
  507. }
  508. if (groupCollapse !== undefined) {
  509. n.collapsed = groupCollapse;
  510. }
  511. toEnd++;
  512. try {
  513. if ($.isArray(grp.formatDisplayField) && $.isFunction(grp.formatDisplayField[n.idx])) {
  514. n.displayValue = grp.formatDisplayField[n.idx].call($t, n.displayValue, n.value, colModel[cp[n.idx]], n.idx, n, i);
  515. gv = n.displayValue;
  516. } else {
  517. gv = $t.formatter(hid, n.displayValue, cp[n.idx], n.value, n);
  518. }
  519. } catch (egv) {
  520. gv = n.displayValue;
  521. }
  522. str += "<tr id='" + hid + "' data-jqgrouplevel='" + n.idx + "' " +
  523. (groupCollapse && parentGroupCollapse ? "style='display:none;' " : "") +
  524. "role='row' class='" + jqgroupClass + " " + clid + "'>";
  525. grpTextStr = $.isFunction(grp.groupText[n.idx]) ?
  526. grp.groupText[n.idx].call($t, gv, n.cnt, n.summary) :
  527. jgrid.template(grp.groupText[n.idx], gv, n.cnt, n.summary);
  528. if (typeof grpTextStr !== "string" && typeof grpTextStr !== "number") {
  529. grpTextStr = gv;
  530. }
  531. if (grp.groupSummaryPos[n.idx] === "header") {
  532. colspan = 1;
  533. if (colModel[0].name === "cb" || colModel[1].name === "cb") {
  534. colspan++;
  535. }
  536. if (colModel[0].name === "subgrid" || colModel[1].name === "subgrid") {
  537. colspan++;
  538. }
  539. str += buildSummaryTd(i, 0, n, colspan, icon + "<span class='cell-wrapper'>" + grpTextStr + "</span>");
  540. } else {
  541. str += "<td role='gridcell' style='padding-left:" + (n.idx * 12) + "px;'" +
  542. " colspan='" + cmLength + "'>" + icon + grpTextStr + "</td>";
  543. }
  544. str += "</tr>";
  545. if (leaf) {
  546. gg = groups[i + 1];
  547. sgr = n.startRow;
  548. end = gg !== undefined ? gg.startRow : groups[i].startRow + groups[i].cnt;
  549. if (grp._locgr) {
  550. offset = (page - 1) * rn;
  551. if (offset > n.startRow) {
  552. sgr = offset;
  553. }
  554. }
  555. for (kk = sgr; kk < end; kk++) {
  556. if (!grdata[kk - offset]) {
  557. break;
  558. }
  559. str += grdata[kk - offset].join("");
  560. }
  561. if (grp.groupSummaryPos[n.idx] !== "header") {
  562. if (gg !== undefined) {
  563. for (jj = 0; jj < grp.groupField.length; jj++) {
  564. if (gg.dataIndex === grp.groupField[jj]) {
  565. break;
  566. }
  567. }
  568. toEnd = grp.groupField.length - jj;
  569. }
  570. for (ik = 0; ik < toEnd; ik++) {
  571. if (!sumreverse[ik]) {
  572. continue;
  573. }
  574. str += "<tr data-jqfootlevel='" + (n.idx - ik) +
  575. (groupCollapse && ((n.idx - ik) > 0 || !grp.showSummaryOnHide) ? "' style='display:none;'" : "'") +
  576. " role='row' class='" + jqfootClass + "'>";
  577. str += buildSummaryTd(i, ik, groups[n.idx - ik], 0);
  578. str += "</tr>";
  579. }
  580. toEnd = jj;
  581. }
  582. }
  583. });
  584. this.off(eventNames)
  585. .on(eventNames, function () { //e, show, cmName, iColShow) {
  586. // TODO fix the code after resorting columns
  587. var iCol = p.iColByName[grp.iconColumnName], iRow, row, iColNew, i; //$cellData;
  588. if ($.inArray("header", grp.groupSummaryPos) >= 0) {
  589. for (i = 0; i < colModel.length; i++) {
  590. if (!colModel[i].hidden) {
  591. iColNew = i;
  592. break;
  593. }
  594. }
  595. if (iColNew === undefined || iCol === iColNew) { return; }
  596. for (iRow = 0; iRow < $t.rows.length; iRow++) {
  597. row = $t.rows[iRow];
  598. if ($(row).hasClass("jqgroup")) {
  599. /*$cellData = $(row.cells[iCol]).children(".cell-wrapper").detach();
  600. $.wrapInner(row.cells[iColNew], function () {//"<span class='cell-wrapper'></span>");
  601. return "<span class='cell-wrapper'>" + this.nodeValue + "</span>";
  602. });
  603. row.cells[iColNew]
  604. $cellData = $(row.cells[iCol]).children(".cell-wrapper").detach();
  605. $(row.cells[iCol]).html($(row.cells[iCol]).children("").html());*/
  606. $(row.cells[iColNew]).html(row.cells[iCol].innerHTML);
  607. $(row.cells[iCol]).html("&nbsp;");
  608. }
  609. }
  610. grp.iconColumnName = colModel[iColNew].name;
  611. }
  612. });
  613. return str;
  614. },
  615. groupingGroupBy: function (name, options) {
  616. return this.each(function () {
  617. var $t = this, p = $t.p, grp = p.groupingView, i, cm;
  618. if (typeof name === "string") {
  619. name = [name];
  620. }
  621. p.grouping = true;
  622. grp._locgr = false;
  623. //Set default, in case visibilityOnNextGrouping is undefined
  624. if (grp.visibiltyOnNextGrouping === undefined) {
  625. grp.visibiltyOnNextGrouping = [];
  626. }
  627. // show previous hidden groups if they are hidden and weren't removed yet
  628. for (i = 0; i < grp.groupField.length; i++) {
  629. cm = p.colModel[p.iColByName[grp.groupField[i]]];
  630. if (!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i] && cm != null && cm.hidden === true) {
  631. base.showCol.call($($t), grp.groupField[i]);
  632. }
  633. }
  634. // set visibility status of current group columns on next grouping
  635. for (i = 0; i < name.length; i++) {
  636. grp.visibiltyOnNextGrouping[i] = $(p.idSel + "_" + jgrid.jqID(name[i])).is(":visible");
  637. }
  638. p.groupingView = $.extend(p.groupingView, options || {});
  639. grp.groupField = name;
  640. $($t).trigger("reloadGrid");
  641. });
  642. },
  643. groupingRemove: function (current) {
  644. return this.each(function () {
  645. var $t = this, p = $t.p, tbody = $t.tBodies[0], grp = p.groupingView, i;
  646. if (current === undefined) {
  647. current = true;
  648. }
  649. p.grouping = false;
  650. if (current === true) {
  651. // show previous hidden groups if they are hidden and weren't removed yet
  652. for (i = 0; i < grp.groupField.length; i++) {
  653. if (!grp.groupColumnShow[i] && grp.visibiltyOnNextGrouping[i]) {
  654. base.showCol.call($($t), grp.groupField);
  655. }
  656. }
  657. $("tr.jqgroup, tr.jqfoot", tbody).remove();
  658. $("tr.jqgrow", tbody).filter(":hidden").show();
  659. } else {
  660. $($t).trigger("reloadGrid");
  661. }
  662. });
  663. },
  664. groupingCalculations: {
  665. handler: function (fn, v, field, round, roundType, rc) {
  666. var funcs = {
  667. sum: function () {
  668. return parseFloat(v || 0) + parseFloat((rc[field] || 0));
  669. },
  670. min: function () {
  671. if (v === "") {
  672. return parseFloat(rc[field] || 0);
  673. }
  674. return Math.min(parseFloat(v), parseFloat(rc[field] || 0));
  675. },
  676. max: function () {
  677. if (v === "") {
  678. return parseFloat(rc[field] || 0);
  679. }
  680. return Math.max(parseFloat(v), parseFloat(rc[field] || 0));
  681. },
  682. count: function () {
  683. if (v === "") {
  684. v = 0;
  685. }
  686. if (rc.hasOwnProperty(field)) {
  687. return v + 1;
  688. }
  689. return 0;
  690. },
  691. avg: function () {
  692. // the same as sum, but at end we divide it
  693. // so use sum instead of duplicating the code (?)
  694. return funcs.sum();
  695. }
  696. },
  697. res,
  698. mul;
  699. if (!funcs[fn]) {
  700. throw ("jqGrid Grouping No such method: " + fn);
  701. }
  702. res = funcs[fn]();
  703. if (round != null) {
  704. if (roundType === "fixed") {
  705. res = res.toFixed(round);
  706. } else {
  707. mul = Math.pow(10, round);
  708. res = Math.round(res * mul) / mul;
  709. }
  710. }
  711. return res;
  712. }
  713. }
  714. });
  715. // end module grid.grouping
  716. }));