All Downloads are FREE. Search and download functionalities are using the official Maven repository.

template.js.base.grid.custom.js Maven / Gradle / Ivy

There is a newer version: 5.0.6
Show newest version
/**
 * jqGrid extension for custom methods
 * Tony Tomov [email protected], http://trirand.com/blog/
 *
 * Wildraid [email protected]
 * Oleg Kiriljuk [email protected]
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl-2.0.html
**/

/*jshint eqeqeq:false */
/*jslint browser: true, devel: true, eqeq: true, nomen: true, plusplus: true, vars: true, unparam: true, white: true, todo: true */
/*global jQuery, define, exports, module, require */
(function (global, factory) {
	"use strict";
	if (typeof define === "function" && define.amd) {
		// AMD. Register as an anonymous module.
		//console.log("grid.custom AMD");
		define([
			"jquery",
			"./grid.base",
			"./jquery.fmatter",
			"./grid.common"
		], function ($) {
			//console.log("grid.custom AMD: define callback");
			return factory($, global.document);
		});
	} else if (typeof module === "object" && module.exports) {
		// Node/CommonJS
		//console.log("grid.custom CommonJS, typeof define=" + typeof define + ", define=" + define);
		module.exports = function (root, $) {
			//console.log("grid.custom CommonJS: in module.exports");
			if (!root) {
				root = window;
			}
			//console.log("grid.custom CommonJS: before require('jquery')");
			if ($ === undefined) {
				// require("jquery") returns a factory that requires window to
				// build a jQuery instance, we normalize how we use modules
				// that require this pattern but the window provided is a noop
				// if it's defined (how jquery works)
				$ = typeof window !== "undefined" ?
						require("jquery") :
						require("jquery")(root);
			}
			//console.log("grid.custom CommonJS: before require('./grid.base')");
			require("./grid.base");
			//console.log("grid.custom CommonJS: before require('./jquery.fmatter')");
			require("./jquery.fmatter");
			//console.log("grid.custom CommonJS: before require('./grid.common')");
			require("./grid.common");
			factory($, root.document);
			return $;
		};
	} else {
		// Browser globals
		//console.log("grid.custom Browser: before factory");
		factory(jQuery, global.document);
	}
}(typeof window !== "undefined" ? window : this, function ($, document) {
	"use strict";
	var jgrid = $.jgrid, jqID = jgrid.jqID, base = $.fn.jqGrid,
		getGuiStyles = base.getGuiStyles, getGridRes = base.getGridRes;

	// begin module grid.custom
	jgrid.extend({
		getColProp: function (colname) {
			var ret = {}, t = this[0], iCol;
			if (t != null && t.grid) {
				iCol = t.p.iColByName[colname];
				if (iCol !== undefined) {
					return t.p.colModel[iCol];
				}
			}
			return ret;
		},
		setColProp: function (colname, obj) {
			//do not set width will not work
			return this.each(function () {
				var self = this, p = self.p, iCol;
				if (self.grid && p != null && obj) {
					iCol = p.iColByName[colname];
					if (iCol !== undefined) {
						$.extend(true, p.colModel[iCol], obj);
					}
				}
			});
		},
		sortGrid: function (colname, reload, sor) {
			return this.each(function () {
				var self = this, grid = self.grid, p = self.p, colModel = p.colModel, l = colModel.length, cm, i, sobj = false, sort;
				if (!grid) { return; }
				if (!colname) { colname = p.sortname; }
				if (typeof reload !== "boolean") { reload = false; }
				for (i = 0; i < l; i++) {
					cm = colModel[i];
					if (cm.index === colname || cm.name === colname) {
						if (p.frozenColumns === true && cm.frozen === true) {
							sobj = grid.fhDiv.find("#" + jqID(p.id + "_" + colname));
						}
						if (!sobj || sobj.length === 0) {
							sobj = grid.headers[i].el;
						}
						sort = cm.sortable;
						if (typeof sort !== "boolean" || sort) {
							self.sortData(cm.index || cm.name, i, reload, sor, sobj);
						}
						break;
					}
				}
			});
		},
		clearBeforeUnload: function () {
			return this.each(function () {
				var self = this, p = self.p, grid = self.grid, propOrMethod, clearArray = jgrid.clearArray,
					hasOwnProperty = Object.prototype.hasOwnProperty;
				if ($.isFunction(grid.emptyRows)) {
					grid.emptyRows.call(self, true, true); // this work quick enough and reduce the size of memory leaks if we have someone
				}

				$(document).off("mousemove.jqGrid mouseup.jqGrid" + p.id);
				$(self).off();

				/*grid.dragEnd = null;
				grid.dragMove = null;
				grid.dragStart = null;
				grid.emptyRows = null;
				grid.populate = null;
				grid.populateVisible = null;
				grid.scrollGrid = null;
				grid.selectionPreserver = null;

				grid.bDiv = null;
				grid.fbRows = null;
				grid.cDiv = null;
				grid.hDiv = null;
				grid.cols = null;*/
				var i, l = grid.headers.length;
				for (i = 0; i < l; i++) {
					grid.headers[i].el = null;
				}
				for (propOrMethod in grid) {
					if (grid.hasOwnProperty(propOrMethod)) {
						grid.propOrMethod = null;
					}
				}

				/*self.formatCol = null;
				self.sortData = null;
				self.updatepager = null;
				self.refreshIndex = null;
				self.setHeadCheckBox = null;
				self.constructTr = null;
				self.formatter = null;
				self.addXmlData = null;
				self.addJSONData = null;
				self.grid = null;*/

				var propOrMethods = ["formatCol", "sortData", "updatepager", "refreshIndex", "setHeadCheckBox", "constructTr", "clearToolbar", "fixScrollOffsetAndhBoxPadding", "rebuildRowIndexes", "modalAlert", "toggleToolbar", "triggerToolbar", "formatter", "addXmlData", "addJSONData", "ftoolbar", "_inlinenav", "nav", "grid", "p"];
				l = propOrMethods.length;
				for (i = 0; i < l; i++) {
					if (hasOwnProperty.call(self, propOrMethods[i])) {
						self[propOrMethods[i]] = null;
					}
				}
				self._index = {};
				clearArray(p.data);
				clearArray(p.lastSelectedData);
				clearArray(p.selarrrow);
				clearArray(p.savedRow);
				p.editingInfo = {};
			});
		},
		GridDestroy: function () {
			return this.each(function () {
				var self = this, p = self.p;
				if (self.grid && p != null) {
					if (p.pager) { // if not part of grid
						$(p.pager).remove();
					}
					try {
						$("#alertmod_" + jqID(p.id)).remove();
						$(self).jqGrid("clearBeforeUnload");
						$(p.gBox).remove();
					} catch (ignore) { }
				}
			});
		},
		GridUnload: function () {
			return this.each(function () {
				var self = this, $self = $(self), p = self.p, $j = $.fn.jqGrid;
				if (!self.grid) { return; }
				$self.removeClass($j.getGuiStyles.call($self, "grid", "ui-jqgrid-btable"));
				// The multiple removeAttr can be replace to one after dropping of support of old jQuery
				if (p.pager) {
					if (p.pager.substr(1, $.jgrid.uidPref.length) === $.jgrid.uidPref) {
						$(p.pager).remove();
					} else {
						$(p.pager).empty()
							.removeClass($j.getGuiStyles.call($self, "pager.pager", "ui-jqgrid-pager " +
								$j.getGuiStyles.call($self, "bottom")))
							.removeAttr("style")
							.removeAttr("dir");
					}
				}
				$self.jqGrid("clearBeforeUnload");
				$self.removeAttr("style")
					.removeAttr("tabindex")
					.removeAttr("role")
					.removeAttr("aria-labelledby")
					.removeAttr("style");
				$self.empty(); // remove the first line
				$self.insertBefore(p.gBox).show();
				$(p.pager).insertBefore(p.gBox).show();
				$(p.gBox).remove();
			});
		},
		setGridState: function (state) {
			return this.each(function () {
				var $t = this, p = $t.p, grid = $t.grid, cDiv = grid.cDiv, $uDiv = $(grid.uDiv), $ubDiv = $(grid.ubDiv);
				if (!grid || p == null) { return; }
				var getMinimizeIcon = function (path) {
						return base.getIconRes.call($t, "gridMinimize." + path);
					},
					visibleGridIcon = getMinimizeIcon("visible"),
					hiddenGridIcon = getMinimizeIcon("hidden");
				if (state === "hidden") {
					$(".ui-jqgrid-bdiv, .ui-jqgrid-hdiv", p.gView).slideUp("fast");
					if (p.pager) { $(p.pager).slideUp("fast"); }
					if (p.toppager) { $(p.toppager).slideUp("fast"); }
					if (p.toolbar[0] === true) {
						if (p.toolbar[1] === "both") {
							$ubDiv.slideUp("fast");
						}
						$uDiv.slideUp("fast");
					}
					if (p.footerrow) { $(".ui-jqgrid-sdiv", p.gBox).slideUp("fast"); }
					$(".ui-jqgrid-titlebar-close span", cDiv).removeClass(visibleGridIcon).addClass(hiddenGridIcon);
					p.gridstate = "hidden";
				} else if (state === "visible") {
					$(".ui-jqgrid-hdiv, .ui-jqgrid-bdiv", p.gView).slideDown("fast");
					if (p.pager) { $(p.pager).slideDown("fast"); }
					if (p.toppager) { $(p.toppager).slideDown("fast"); }
					if (p.toolbar[0] === true) {
						if (p.toolbar[1] === "both") {
							$ubDiv.slideDown("fast");
						}
						$uDiv.slideDown("fast");
					}
					if (p.footerrow) { $(".ui-jqgrid-sdiv", p.gBox).slideDown("fast"); }
					$(".ui-jqgrid-titlebar-close span", cDiv).removeClass(hiddenGridIcon).addClass(visibleGridIcon);
					p.gridstate = "visible";
				}
			});
		},
		filterToolbar: function (oMuligrid) {
			// if one uses jQuery wrapper with multiple grids, then oMultiple specify the object with common options
			return this.each(function () {
				var $t = this, grid = $t.grid, $self = $($t), p = $t.p, infoDialog = jgrid.info_dialog, htmlEncode = jgrid.htmlEncode;
				if (this.ftoolbar) { return; }
				// make new copy of the options and use it for ONE specific grid.
				// p.searching can contains grid specific options
				// we will don't modify the input options oMuligrid
				var o = $.extend(true, {
						autosearch: true,
						autosearchDelay: 500,
						searchOnEnter: true,
						beforeSearch: null,
						afterSearch: null,
						beforeClear: null,
						afterClear: null,
						searchurl: "",
						sField: "searchField",
						sValue: "searchString",
						sOper: "searchOper",
						sFilter: p.prmNames.filters,
						stringResult: false,
						groupOp: "AND",
						defaultSearch: "bw",
						idMode: "new", // support "old", "compatibility", "new"
						searchOperators: false,
						resetIcon: "×",
						applyLabelClasses: true,
						loadFilterDefaults: true, // this options activates loading of default filters from grid's postData for Multipe Search only.
						operands: { "eq": "==", "ne": "!", "lt": "<", "le": "<=", "gt": ">", "ge": ">=", "bw": "^", "bn": "!^", "in": "=", "ni": "!=", "ew": "|", "en": "!@", "cn": "~", "nc": "!~", "nu": "#", "nn": "!#" }
					}, jgrid.search, p.searching || {}, oMuligrid || {}),
					colModel = p.colModel,
					getRes = function (path) {
						return getGridRes.call($self, path);
					},
					errcap = getRes("errors.errcap"),
					bClose = getRes("edit.bClose"),
					editMsg = getRes("edit.msg"),
					hoverClasses = getGuiStyles.call($t, "states.hover"),
					highlightClass = getGuiStyles.call($t, "states.select"),
					dataFieldClass = getGuiStyles.call($t, "filterToolbar.dataField"),
					currentFilters = {},
					getId = function (cmName) {
						var prefix = "gs_";
						switch (o.idMode) {
							case "compatibility":
								prefix += p.idPrefix;
								break;
							case "new":
								prefix += p.id + "_";
								break;
							default: // "old"
								break;
						}
						return prefix + cmName;
					},
					getIdSel = function (cmName) {
						return "#" + jqID(getId(cmName));
					},
					getOnOffValue = function (soptions) {
						var checkboxValue = (soptions.value || "").split(":");

						return {
							on: checkboxValue[0] || "on",
							off: checkboxValue[1] || "off"
						};
					},
					parseFilter = function (fillAll) {
						var i, j, filters = p.postData[o.sFilter], filter = {}, rules, rule,
							iColByName = p.iColByName, cm, soptions;
						if (fillAll) {
							for (j = 0; j < colModel.length; j++) {
								cm = colModel[j];
								if (cm.search !== false) {
									soptions = cm.searchoptions || {};
									filter[cm.name] = {
										op: soptions.sopt ?
												soptions.sopt[0] :
												(cm.stype === "select" || cm.stype === "checkbox") ? "eq" : o.defaultSearch,
										data: soptions.defaultValue !== undefined ? soptions.defaultValue : ""
									};
								}
							}
						}

						// TODO: test for !o.stringResult && !o.searchOperators && p.datatype !== "local"
						// and use p.postData[cm.index || cm.name] instead of filter[cm.name]
						if (!filters || !p.search) { return filter; }
						if (typeof filters === "string") {
							try {
								filters = $.parseJSON(filters);
							} catch (ignore) {
								filters = {};
							}
						} else {
							filters = filters || {};
						}
						rules = filters.rules || {};
						if (filters == null ||
								(filters.groupOp != null && o.groupOp != null && filters.groupOp.toUpperCase() !== o.groupOp.toUpperCase()) ||
								rules == null || rules.length === 0 ||
								(filters.groups != null && filters.groups.length > 0)) {
							return filter;
						}
						for (j = 0; j < rules.length; j++) {
							rule = rules[j];
							// find all columns in colModel, where
							// colModel[i].index || colModel[i].name === rule.field
							cm = colModel[iColByName[rule.field]];
							for (i = 0; i < colModel.length; i++) {
								cm = colModel[i];
								if ((cm.index || cm.name) !== rule.field || cm.search === false) {
									continue;
								}
								soptions = cm.searchoptions || {};
								if (soptions.sopt) {
									if ($.inArray(rule.op, soptions.sopt) < 0) {
										continue;
									}
								} else if (cm.stype === "select" || cm.stype === "checkbox") {
									if (rule.op !== "eq") {
										continue;
									}
								} else if (rule.op !== o.defaultSearch) {
									continue;
								}
								filter[cm.name] = { op: rule.op, data: rule.data };
							}
						}
						return filter;
					},
					setThreeStateCheckbox = function ($checkbox, state) {
						switch (state) {
							case 1: // make checked
								$checkbox.data("state", 1)
									.prop({
										checked: true,
										indeterminate: false
									});
								break;
							case 0: // make unchecked
								$checkbox.data("state", 0)
									.prop({
										checked: false,
										indeterminate: false
									});
								break;
							default: // make indeterminate
								$checkbox.data("state", -1)
									.prop({
										checked: false,
										indeterminate: true
									});
								break;
						}
					},
					triggerToolbar = function () {
						var sdata = {}, j = 0, sopt = {};
						$.each(colModel, function () {
							var cm = this, nm = cm.index || cm.name, v, so, searchoptions = cm.searchoptions || {},
								$elem = $(getIdSel(cm.name), (cm.frozen === true && p.frozenColumns === true) ? grid.fhDiv : grid.hDiv),
								getFormaterOption = function (optionName, formatter) {
									var formatoptions = cm.formatoptions || {};
									return formatoptions[optionName] !== undefined ?
										formatoptions[optionName] :
										getRes("formatter." + (formatter || cm.formatter) + "." + optionName);
								},
								cutThousandsSeparator = function (val) {
									var separator = getFormaterOption("thousandsSeparator")
											.replace(/([\.\*\_\'\(\)\{\}\+\?\\])/g, "\\$1");
									return val.replace(new RegExp(separator, "g"), "");
								};

							if (o.searchOperators) {
								so = $elem.parent().prev().children("a").data("soper") || o.defaultSearch;
							} else {
								so = searchoptions.sopt ? searchoptions.sopt[0] : (cm.stype === "select" || cm.stype === "checkbox") ? "eq" : o.defaultSearch;
							}
							/* the format of element of the searching toolbar if ANOTHER
							 * as the format of cells in the grid. So one can't use
							 *     value = $.unformat.call($t, $elem, { colModel: cm }, iCol)
							 * to get the value. Even the access to the value should be
							 * $elem.val() instead of $elem.text() used in the common case of
							 * formatter. So we have to make manual conversion of searching filed
							 * used for integer/number/currency. The code will be duplicate */
							if (cm.stype === "custom" && $.isFunction(searchoptions.custom_value) && $elem.length > 0 && $elem[0].nodeName.toUpperCase() === "SPAN") {
								v = searchoptions.custom_value.call($t, $elem.children(".customelement").first(), "get");
							} else if (cm.stype === "select") {
								if ($elem.prop("multiple")) {
									v = $elem.val();
									if (v == null || v.length === 0) {
										v = "";
									} else {
										v = v.join(p.inFilterSeparator || ",");
									}
								} else {
									v = $elem.val();
								}
							} else if (cm.stype === "checkbox") {
								var onOffValue = getOnOffValue(searchoptions);

								switch ($elem.data("state")) {
									case -1:   // has indeterminate state
										v = "";
										break;
									case 0:    // is unchecked
										// make indeterminate
										v = onOffValue.off;
										break;
									default:    // is checked
										// make unchecked
										v = onOffValue.on;
										break;
								}
							} else {
								v = $.trim($elem.val());
								switch (cm.formatter) {
									case "integer":
										v = cutThousandsSeparator(v)
												.replace(getFormaterOption("decimalSeparator", "number"), ".");
										if (v !== "") {
											// normalize the strings like "010.01" to "10"
											v = String(parseInt(v, 10));
										}
										break;
									case "number":
										v = cutThousandsSeparator(v)
												.replace(getFormaterOption("decimalSeparator"), ".");
										if (v !== "" && String(v).charAt(0) === "0") {
											// normalize the strings like "010.00" to "10"
											// and "010.12" to "10.12"
											v = String(parseFloat(v));
										}
										break;
									case "currency":
										var prefix = getFormaterOption("prefix"),
											suffix = getFormaterOption("suffix");
										if (prefix && prefix.length && v.substr(0, prefix.length) === prefix) {
											v = v.substr(prefix.length);
										}
										if (suffix && suffix.length && v.length > suffix.length && v.substr(v.length - suffix.length, suffix.length) === suffix) {
											v = v.substr(0, v.length - suffix.length);
										}
										v = cutThousandsSeparator(v)
												.replace(getFormaterOption("decimalSeparator"), ".");
										if (v !== "") {
											// normalize the strings like "010.00" to "10"
											// and "010.12" to "10.12"
											v = String(parseFloat(v));
										}
										break;
									default:
										// TODO: call unformatter if it's defined.
										break;
								}
							}
							if (v || so === "nu" || so === "nn" || $.inArray(so, p.customUnaryOperations) >= 0) {
								sdata[nm] = v;
								sopt[nm] = so;
								j++;
							} else {
								if (sdata.hasOwnProperty(nm)) {
									delete sdata[nm];
								}
								if (!(o.stringResult || o.searchOperators || p.datatype === "local")) {
									try {
										if (p.postData != null && p.postData.hasOwnProperty(nm)) {
											delete p.postData[nm];
										}
									} catch (ignore) { }
								}
							}
						});
						var sd = j > 0 ? true : false;
						if (o.stringResult || o.searchOperators || p.datatype === "local") {
							var ruleGroup = '{"groupOp":"' + o.groupOp + '","rules":[';
							var gi = 0;
							$.each(sdata, function (cmName, n) {
								//var iCol = p.iColByName[cmName], cm = p.colModel[iCol],
								//	value = $.unformat.call($t, $("").text(n), { colModel: cm }, iCol);
								if (gi > 0) { ruleGroup += ","; }
								ruleGroup += '{"field":"' + cmName + '",';
								ruleGroup += '"op":"' + sopt[cmName] + '",';
								n += "";
								ruleGroup += '"data":"' + n.replace(/\\/g, "\\\\").replace(/\"/g, '\\"') + '"}';
								gi++;
							});
							ruleGroup += "]}";
							p.postData[o.sFilter] = ruleGroup;
							$.each([o.sField, o.sValue, o.sOper], function (i, n) {
								if (p.postData.hasOwnProperty(n)) { delete p.postData[n]; }
							});
						} else {
							$.extend(p.postData, sdata);
						}
						var saveurl;
						if (p.searchurl) {
							saveurl = p.url;
							$self.jqGrid("setGridParam", { url: p.searchurl });
						}
						var bsr = $self.triggerHandler("jqGridToolbarBeforeSearch") === "stop" ? true : false;
						if (!bsr && $.isFunction(o.beforeSearch)) { bsr = o.beforeSearch.call($t); }
						if (!bsr) {
							$self.jqGrid("setGridParam", { search: sd })
								.trigger("reloadGrid", [$.extend({ page: 1 }, o.reloadGridSearchOptions || {})]);
						}
						if (saveurl) { $self.jqGrid("setGridParam", { url: saveurl }); }
						$self.triggerHandler("jqGridToolbarAfterSearch");
						if ($.isFunction(o.afterSearch)) { o.afterSearch.call($t); }
					},
					clearToolbar = function (trigger) {
						var sdata = {}, j = 0, nm;
						trigger = (typeof trigger !== "boolean") ? true : trigger;
						$.each(colModel, function () {
							var v, cm = this, $elem = $(getIdSel(cm.name), (cm.frozen === true && p.frozenColumns === true) ? grid.fhDiv : grid.hDiv),
								isSindleSelect, searchoptions = cm.searchoptions || {};
							if (searchoptions.defaultValue !== undefined) { v = searchoptions.defaultValue; }
							nm = cm.index || cm.name;
							switch (cm.stype) {
								case "checkbox":
									// set indeterminate state
									setThreeStateCheckbox($elem, -1);
									break;
								case "select":
									isSindleSelect = $elem.length > 0 ? !$elem[0].multiple : true;
									$elem.find("option").each(function (i) {
										this.selected = i === 0 && isSindleSelect;
										if ($(this).val() === v) {
											this.selected = true;
											return false;
										}
									});
									if (v !== undefined) {
										// post the key and not the text
										sdata[nm] = v;
										j++;
									} else {
										try {
											delete p.postData[nm];
										} catch (ignore) { }
									}
									break;
								case "text":
									$elem.val(v || "");
									if (v !== undefined) {
										sdata[nm] = v;
										j++;
									} else {
										try {
											delete p.postData[nm];
										} catch (ignore) { }
									}
									break;
								case "custom":
									if ($.isFunction(searchoptions.custom_value) && $elem.length > 0 && $elem[0].nodeName.toUpperCase() === "SPAN") {
										if (v === undefined) {
											v = "";
										}
										searchoptions.custom_value.call($t, $elem.children(".customelement").first(), "set", v);
									}
									break;
							}
						});
						var sd = j > 0 ? true : false;
						p.resetsearch = true;
						if (o.stringResult || o.searchOperators || p.datatype === "local") {
							var ruleGroup = '{"groupOp":"' + o.groupOp + '","rules":[';
							var gi = 0;
							$.each(sdata, function (i, n) {
								if (gi > 0) { ruleGroup += ","; }
								ruleGroup += '{"field":"' + i + '",';
								ruleGroup += '"op":"' + "eq" + '",';
								n += "";
								ruleGroup += '"data":"' + n.replace(/\\/g, "\\\\").replace(/\"/g, '\\"') + '"}';
								gi++;
							});
							ruleGroup += "]}";
							p.postData[o.sFilter] = ruleGroup;
							$.each([o.sField, o.sValue, o.sOper], function (i, n) {
								if (p.postData.hasOwnProperty(n)) { delete p.postData[n]; }
							});
						} else {
							$.extend(p.postData, sdata);
						}
						var saveurl;
						if (p.searchurl) {
							saveurl = p.url;
							$self.jqGrid("setGridParam", { url: p.searchurl });
						}
						var bcv = $self.triggerHandler("jqGridToolbarBeforeClear") === "stop" ? true : false;
						if (!bcv && $.isFunction(o.beforeClear)) { bcv = o.beforeClear.call($t); }
						if (!bcv) {
							if (trigger) {
								$self.jqGrid("setGridParam", { search: sd })
									.trigger("reloadGrid", [$.extend({ page: 1 }, o.reloadGridResetOptions || {})]);
							}
						}
						if (saveurl) { $self.jqGrid("setGridParam", { url: saveurl }); }
						$self.triggerHandler("jqGridToolbarAfterClear");
						if ($.isFunction(o.afterClear)) { o.afterClear.call($t); }
					},
					toggleToolbar = function () {
						var trow = $("tr.ui-search-toolbar", grid.hDiv),
							trow2 = p.frozenColumns === true ? $("tr.ui-search-toolbar", grid.fhDiv) : false;
						if (trow.css("display") === "none") {
							trow.show();
							if (trow2) {
								trow2.show();
							}
						} else {
							trow.hide();
							if (trow2) {
								trow2.hide();
							}
						}
						if (p.frozenColumns === true) {
							$self.jqGrid("destroyFrozenColumns");
							$self.jqGrid("setFrozenColumns");
						}
					},
					odata = getRes("search.odata") || [],
					customSortOperations = p.customSortOperations,
					buildRuleMenu = function (elem, left, top) {
						$("#sopt_menu").remove();

						left = parseInt(left, 10);
						top = parseInt(top, 10) + 18;

						var selclass, ina, i = 0, aoprs = [], selected = $(elem).data("soper"), nm = $(elem).data("colname"),
							fs = $(".ui-jqgrid-view").css("font-size") || "11px",
							str = "";
						$("body").append(str);
						$("#sopt_menu > li > a").hover(
							function () { $(this).addClass(hoverClasses); },
							function () { $(this).removeClass(hoverClasses); }
						).click(function () {
							var v = $(this).attr("value"),
								oper = $(this).data("oper");
							$self.triggerHandler("jqGridToolbarSelectOper", [v, oper, elem]);
							$("#sopt_menu").hide();
							$(elem).data("soper", v).text(oper);
							if (o.autosearch === true) {
								var inpelm = $(elem).parent().next().children()[0];
								if ($(inpelm).val() || v === "nu" || v === "nn" || $.inArray(v, p.customUnaryOperations) >= 0) {
									triggerToolbar();
								}
							}
						});
					},
					timeoutHnd,
					bindings = [],
					$tr = $("", { "class": "ui-search-toolbar", role: "row form" });

				if (o.loadFilterDefaults) {
					currentFilters = parseFilter() || {};
				}
				// create the row
				$.each(colModel, function (ci) {
					var cm = this, soptions, mode = "filter", surl, sot, so, i, searchoptions = cm.searchoptions || {}, editoptions = cm.editoptions || {},
						$th = $("", {
							"class": getGuiStyles.call($t, "colHeaders", "ui-th-column ui-th-" + p.direction + " " + (o.applyLabelClasses ? cm.labelClasses || "" : "")),
							role: "gridcell",
							"aria-describedby": p.id + "_" + cm.name
						}),
						$thd = $("
"), elem, $elem, $stable = $("
"), $tds = $stable.children("tbody").children("tr").children("td"), $tdOper = $tds.eq(0), $tdInput = $tds.eq(1), $tdClear = $tds.eq(2); if (this.hidden === true) { $th.css("display", "none"); } this.search = this.search === false ? false : true; if (this.stype === undefined) { this.stype = "text"; } soptions = $.extend({ mode: mode, name: cm.name, cm: cm, iCol: ci, id: getId(cm.name) }, searchoptions); if (this.search) { if (o.searchOperators) { if (p.search && currentFilters[this.name] != null) { so = currentFilters[this.name].op; } else { so = (soptions.sopt) ? soptions.sopt[0] : (cm.stype === "select" || cm.stype === "checkbox") ? "eq" : o.defaultSearch; } for (i = 0; i < odata.length; i++) { if (odata[i].oper === so) { sot = o.operands[so] || ""; break; } } if (sot === undefined && customSortOperations != null) { var customOp; for (customOp in customSortOperations) { if (customSortOperations.hasOwnProperty(customOp) && customOp === so) { sot = customSortOperations[customOp].operand; break; //soptions.searchtitle = customSortOperations[customOp].title; } } } if (sot === undefined) { sot = "="; } $tdOper.append("" + sot + ""); } $tdOper.data("colindex", ci); if (soptions.sopt == null || soptions.sopt.length === 1) { $tdOper.hide(); } if (p.search && currentFilters[this.name] != null) { soptions.defaultValue = currentFilters[this.name].data; } if (soptions.clearSearch === undefined) { soptions.clearSearch = this.stype === "text" ? true : false; } if (soptions.clearSearch) { var csv = $.isFunction(o.resetTitle) ? o.resetTitle.call($t, { options: o, cm: cm, cmName: cm.name, iCol: ci }) : (getRes("search.resetTitle") || "Clear Search Value") + " " + jgrid.stripHtml(p.colNames[ci]); $tdClear.append("" + o.resetIcon + ""); } else { $tdClear.hide(); } $thd.append($stable); switch (this.stype) { case "checkbox": var state = soptions.defaultValue !== undefined ? soptions.defaultValue : "-1"; $elem = $(""); if (state === "-1") { $elem.prop("indeterminate", true); } else if (state === "1") { $elem.prop("checked", true); } $elem.click(function () { var $checkbox = $(this); switch ($checkbox.data("state")) { case -1: // has indeterminate state // make checked setThreeStateCheckbox($checkbox, 1); break; case 0: // is unchecked // set indeterminate state setThreeStateCheckbox($checkbox, -1); break; default: // is checked // make unchecked setThreeStateCheckbox($checkbox, 0); break; } if (o.autosearch === true) { triggerToolbar(); } }); $tdInput.append($elem); if (soptions.attr) { $elem.attr(soptions.attr); } bindings.push({ elem: $elem[0], options: soptions }); break; case "select": surl = this.surl || soptions.dataUrl; if (surl) { // data returned should have already constructed html select // primitive jQuery load $.ajax($.extend({ url: surl, context: { $tdInput: $tdInput, options: soptions, cm: cm, iCol: ci }, dataType: "html", success: function (data, textStatus, jqXHR) { var cm1 = this.cm, iCol1 = this.iCol, soptions1 = this.options, d, ov1, $td = this.$tdInput, $select; if (soptions1.buildSelect !== undefined) { d = soptions1.buildSelect.call($t, data, jqXHR, cm1, iCol1); if (d) { $td.append(d); } } else { $td.append(data); } $select = $td.children("select"); $select.attr({ name: cm1.index || cm1.name, id: getId(cm1.name) }); if (soptions1.attr) { $select.attr(soptions1.attr); } $select.addClass(dataFieldClass); $select.css({ width: "100%" }); if ($select.find("option[value='']").length === 0 && typeof soptions.noFilterText === "string") { ov1 = document.createElement("option"); ov1.value = ""; ov1.innerHTML = soptions.noFilterText; $select.prepend(ov1); if ($($select[0].options[$select[0].selectedIndex]).attr("selected") == null && !$select[0].multiple) { $select[0].selectedIndex = 0; } } if ($select[0].multiple && $select.find("option[selected]").length === 0 && $select[0].selectedIndex !== -1) { // It can be that multiselect (select with multiple attribute) will be returned from surl // or build with respect of buildSelect WITHOUT having multiple attribute // (just as instead of ) // and the multiple attribute will be assigned via soptions.attr (attr: { multiple: "multiple" }). // One will have non-multiple select initially, where the first element will be automatically selected. // After assigning the attribute multiple="multiple" the select will be able to have no selected elements, // but it will be too late. To fix the case we will unselect the first element in the special case. $select[0].options[$select[0].selectedIndex].selected = false; } if (soptions1.defaultValue !== undefined) { $select.val(soptions1.defaultValue); } // preserve autoserch jgrid.bindEv.call($t, $select[0], soptions1); jgrid.fullBoolFeedback.call($t, soptions1.selectFilled, "jqGridSelectFilled", { elem: $select[0], options: soptions1, cm: cm1, cmName: cm1.name, iCol: iCol1, mode: mode }); if (o.autosearch === true) { $select.change(function () { triggerToolbar(); return false; }); } } }, jgrid.ajaxOptions, p.ajaxSelectOptions || {})); } else { var oSv, sep, delim; if (cm.searchoptions) { oSv = searchoptions.value === undefined ? editoptions.value || "" : searchoptions.value; sep = searchoptions.separator === undefined ? editoptions.separator || ":" : searchoptions.separator; delim = searchoptions.delimiter === undefined ? editoptions.delimiter || ";" : searchoptions.delimiter; } else if (cm.editoptions) { oSv = editoptions.value === undefined ? "" : editoptions.value; sep = editoptions.separator === undefined ? ":" : editoptions.separator; delim = editoptions.delimiter === undefined ? ";" : editoptions.delimiter; } if (searchoptions.generateValue && p.indexByColumnData[cm.name] != null) { oSv = $t.generateValueFromColumnIndex(cm.name, sep, delim); } if (oSv) { elem = document.createElement("select"); elem.style.width = "100%"; $elem = $(elem).attr({ name: cm.index || cm.name, role: "search", id: getId(cm.name), "aria-describedby": p.id + "_" + cm.name }); if (soptions.attr) { $elem.attr(soptions.attr); } var isNoFilterValueExist = jgrid.fillSelectOptions( elem, oSv, sep, delim, soptions.attr != null && soptions.attr.multiple ); if (!isNoFilterValueExist && typeof soptions.noFilterText === "string") { var ov = document.createElement("option"); ov.value = ""; ov.innerHTML = soptions.noFilterText; ov.selected = true; $elem.prepend(ov); } if (soptions.defaultValue !== undefined) { $elem.val(soptions.defaultValue); } $elem.addClass(dataFieldClass); //bindEv.call($t, elem, soptions); bindings.push({ elem: elem, options: soptions }); $tdInput.append(elem); jgrid.fullBoolFeedback.call($t, soptions.selectFilled, "jqGridSelectFilled", { elem: elem, options: cm.searchoptions || editoptions, cm: cm, cmName: cm.name, iCol: ci, mode: mode }); if (o.autosearch === true) { $elem.change(function () { triggerToolbar(); return false; }); } } } break; case "text": $elem = $(""); $tdInput.append($elem); if (cm.createColumnIndex && soptions.generateDatalist) { var dataListId = "dl_" + getId(cm.name), $datalist = $self.jqGrid("generateDatalistFromColumnIndex", cm.name); if ($datalist != null && $datalist.length > 0) { $elem.attr("list", dataListId); $tdInput.append($datalist.attr("id", dataListId)); } } if (soptions.attr) { $elem.attr(soptions.attr); } bindings.push({ elem: $elem[0], options: soptions }); if (o.autosearch === true) { if (o.searchOnEnter) { $elem.keypress(function (e) { var key1 = e.charCode || e.keyCode || 0; if (key1 === 13) { triggerToolbar(); return false; } return this; }); } else { $elem.keydown(function (e) { var key1 = e.which; switch (key1) { case 13: return false; case 9: case 16: case 37: case 38: case 39: case 40: case 27: break; default: if (timeoutHnd) { clearTimeout(timeoutHnd); } timeoutHnd = setTimeout(function () { triggerToolbar(); }, o.autosearchDelay); } }); } } break; case "custom": $tdInput.append(""); try { if ($.isFunction(soptions.custom_element)) { var celm = soptions.custom_element.call($t, soptions.defaultValue !== undefined ? soptions.defaultValue : "", soptions); if (celm) { celm = $(celm).addClass("customelement"); $thd.find("span[name='" + (cm.index || cm.name) + "']").append(celm); } else { throw "e2"; } } else { throw "e1"; } } catch (ex) { if (ex === "e1") { infoDialog.call($t, errcap, "function 'custom_element' " + editMsg.nodefined, bClose); } if (ex === "e2") { infoDialog.call($t, errcap, "function 'custom_element' " + editMsg.novalue, bClose); } else { infoDialog.call($t, errcap, typeof ex === "string" ? ex : ex.message, bClose); } } break; } } $th.append($thd); $th.find(".ui-search-oper .soptclass,.ui-search-clear .clearsearchclass") .hover(function () { $(this).addClass(hoverClasses); }, function () { $(this).removeClass(hoverClasses); }); $tr.append($th); if (!o.searchOperators) { $tdOper.hide(); } }); $(grid.hDiv).find(">div>.ui-jqgrid-htable>thead").append($tr); $.each(bindings, function () { jgrid.bindEv.call($t, this.elem, this.options); }); if (o.searchOperators) { $(".soptclass", $tr).click(function (e) { var offset = $(this).offset(), left = (offset.left), top = (offset.top); buildRuleMenu(this, left, top); e.stopPropagation(); }); $("body").on("click", function (e) { if (e.target.className !== "soptclass") { $("#sopt_menu").hide(); } }); } $(".clearsearchclass", $tr).click(function () { var $tdOper = $(this).closest(".ui-search-clear"), $tdSearchOper = $tdOper.siblings(".ui-search-oper"), $oper = $tdSearchOper.children("a"), soper = $oper.data("soper"), v, operText, coli = parseInt($tdSearchOper.data("colindex"), 10), $tdInput = $tdOper.siblings(".ui-search-input"), cm = colModel[coli], sval = $.extend({}, cm.searchoptions || {}), dval = sval.defaultValue || ""; switch (cm.stype) { case "select": if (dval) { $tdInput.find("select").val(dval); } else { $tdInput.find("select")[0].selectedIndex = 0; } break; case "checkbox": // set indeterminate state setThreeStateCheckbox($tdInput.find("input[type=checkbox]"), -1); break; default: $tdInput.find("input").val(dval); break; } if (soper === "nu" || soper === "nn" || $.inArray(soper, p.customUnaryOperations) >= 0) { // one need reset an unary operation to default search operation v = sval.sopt ? sval.sopt[0] : (cm.stype === "select" || cm.stype === "checkbox") ? "eq" : o.defaultSearch; operText = customSortOperations != null && customSortOperations[v] != null ? customSortOperations[v].operand : o.operands[v] || ""; $oper.data("soper", v).text(operText); } // ToDo custom search type if (o.autosearch === true) { triggerToolbar(); } }); $t.ftoolbar = true; $t.triggerToolbar = triggerToolbar; $t.clearToolbar = clearToolbar; $t.toggleToolbar = toggleToolbar; if (p.frozenColumns === true) { $self.jqGrid("destroyFrozenColumns"); $self.jqGrid("setFrozenColumns"); } $self.on( "jqGridRefreshFilterValues.filterToolbar" + (o.loadFilterDefaults ? " jqGridAfterLoadComplete.filterToolbar" : ""), function () { var cmName, filter, newFilters = parseFilter(true) || {}, $input, $searchOper, i, $th, searchoptions; if (!o.stringResult && !o.searchOperators && p.datatype !== "local" && p.search) { return; // do nothing on legacy searching } for (cmName in newFilters) { if (newFilters.hasOwnProperty(cmName)) { filter = newFilters[cmName]; $input = $(getIdSel(cmName)); $th = $input.closest("th.ui-th-column"); if ($input.length > 0 && $th.length > 0) { searchoptions = (p.colModel[$th[0].cellIndex] || {}).searchoptions || {}; if ($input[0].tagName.toUpperCase() === "SELECT" && $input[0].multiple) { $input.val(filter.data.split(p.inFilterSeparator || ",")); } else if ($input.is("input[type=checkbox]")) { var onOffValue = getOnOffValue(searchoptions); setThreeStateCheckbox( $input, filter.data === onOffValue.on ? 1 : (filter.data === onOffValue.off ? 0 : -1) ); } else if ($input.find(".customelement").length > 0 && $.isFunction(searchoptions.custom_value)) { var oldValue = searchoptions.custom_value.call($t, $input.find(".customelement").first(), "get"); if (filter.data === "" && searchoptions.defaultValue !== undefined) { filter.data = searchoptions.defaultValue; } if (oldValue === undefined) { oldValue = ""; } if (filter.data !== oldValue && String(filter.data) !== String(oldValue)) { searchoptions.custom_value.call($t, $input.find(".customelement").first(), "set", filter.data); } } else { if (filter.data === "" && searchoptions.defaultValue !== undefined) { filter.data = searchoptions.defaultValue; } if ($.trim($input.val()) !== String(filter.data)) { $input.val(filter.data); } } $searchOper = $input.closest(".ui-search-input") .siblings(".ui-search-oper") .children(".soptclass"); $searchOper.data("soper", filter.op); $searchOper.text(o.operands[filter.op] || (p.customSortOperations[filter.op] || {}).operand); } } } for (i = 0; i < p.colModel.length; i++) { cmName = p.colModel[i].name; if (!newFilters.hasOwnProperty(cmName)) { $(getIdSel(cmName)).val(""); } } } ); }); }, destroyFilterToolbar: function () { return this.each(function () { var self = this; if (!self.ftoolbar) { return; } self.triggerToolbar = null; self.clearToolbar = null; self.toggleToolbar = null; self.ftoolbar = false; $(self.grid.hDiv).find("table thead tr.ui-search-toolbar").remove(); if (self.p.frozenColumns === true) { $(self).jqGrid("destroyFrozenColumns") .jqGrid("setFrozenColumns"); } }); }, destroyGroupHeader: function (nullHeader) { if (nullHeader === undefined) { nullHeader = true; } return this.each(function () { var $t = this, i, l, $th, $resizing, grid = $t.grid, cm = $t.p.colModel, hc, thead = $("table.ui-jqgrid-htable thead", grid.hDiv); if (!grid) { return; } $($t).off(".setGroupHeaders"); var $tr = $("", { role: "row" }).addClass("ui-jqgrid-labels"); var headers = grid.headers; for (i = 0, l = headers.length; i < l; i++) { hc = cm[i].hidden ? "none" : ""; $th = $(headers[i].el) .width(headers[i].width) .css("display", hc); try { $th.removeAttr("rowSpan"); } catch (rs) { //IE 6/7 $th.attr("rowSpan", 1); } $tr.append($th); $resizing = $th.children("span.ui-jqgrid-resize"); if ($resizing.length > 0) {// resizable column $resizing[0].style.height = ""; } $th.children("div")[0].style.top = ""; } $(thead).children("tr.ui-jqgrid-labels").remove(); $(thead).prepend($tr); if (nullHeader === true) { $($t).jqGrid("setGridParam", { "groupHeader": null }); } }); }, setGroupHeaders: function (o) { o = $.extend({ useColSpanStyle: false, applyLabelClasses: true, groupHeaders: [] }, o || {}); return this.each(function () { this.p.groupHeader = o; var ts = this, i, cmi, skip = 0, $tr, $colHeader, th, $th, thStyle, iCol, cghi, numberOfColumns, titleText, cVisibleColumns, p = ts.p, colModel = p.colModel, cml = colModel.length, ths = ts.grid.headers, $theadInTable, thClasses, $htable = $("table.ui-jqgrid-htable", ts.grid.hDiv), isCellClassHidden = jgrid.isCellClassHidden, $trLabels = $htable.children("thead").children("tr.ui-jqgrid-labels"), $trLastWithLabels = $trLabels.last().addClass("jqg-second-row-header"), $thead = $htable.children("thead"), $firstHeaderRow = $htable.find(".jqg-first-row-header"); if ($firstHeaderRow[0] === undefined) { $firstHeaderRow = $("", { role: "row", "aria-hidden": "true" }).addClass("jqg-first-row-header").css("height", "auto"); } else { $firstHeaderRow.empty(); } var inColumnHeader = function (cmName, columnHeaders) { var j; for (j = 0; j < columnHeaders.length; j++) { if (columnHeaders[j].startColumnName === cmName) { return columnHeaders[j]; } } return 0; // falsy value }; $(ts).prepend($thead); $tr = $("", { role: "row" }).addClass("ui-jqgrid-labels jqg-third-row-header"); for (i = 0; i < cml; i++) { th = ths[i].el; $th = $(th); cmi = colModel[i]; // build the next cell for the first header row // ??? cmi.hidden || isCellClassHidden(cmi.classes) || $th.is(":hidden") thStyle = { height: "0", width: ths[i].width + "px", display: (cmi.hidden ? "none" : "") }; $("", { role: "gridcell" }).css(thStyle).addClass("ui-first-th-" + p.direction + (o.applyLabelClasses ? " " + (cmi.labelClasses || "") : "")).appendTo($firstHeaderRow); th.style.width = ""; // remove unneeded style thClasses = getGuiStyles.call(ts, "colHeaders", "ui-th-column-header ui-th-" + p.direction + " " + (o.applyLabelClasses ? cmi.labelClasses || "" : "")); cghi = inColumnHeader(cmi.name, o.groupHeaders); if (cghi) { numberOfColumns = cghi.numberOfColumns; titleText = cghi.titleText; // caclulate the number of visible columns from the next numberOfColumns columns for (cVisibleColumns = 0, iCol = 0; iCol < numberOfColumns && (i + iCol < cml); iCol++) { if (!colModel[i + iCol].hidden && !isCellClassHidden(colModel[i + iCol].classes)) { cVisibleColumns++; } } // The next numberOfColumns headers will be moved in the next row // in the current row will be placed the new column header with the titleText. // The text will be over the cVisibleColumns columns $colHeader = $("") .addClass(thClasses) .html(titleText || " "); if (cVisibleColumns > 0) { $colHeader.attr("colspan", String(cVisibleColumns)); } if (p.headertitles) { $colHeader.attr("title", $colHeader.text()); } // hide if not a visible cols if (cVisibleColumns === 0) { $colHeader.hide(); } $th.before($colHeader); // insert new column header before the current $tr.append(th); // move the current header in the next row // set the counter of headers which will be moved in the next row skip = numberOfColumns - 1; } else { if (skip === 0) { if (o.useColSpanStyle) { // expand the header height to two rows $th.attr("rowspan", $trLabels.length + 1); // consider to use ($th.attr("rowspan") || 1) instead of $trLabels.length } else { $("") .addClass(thClasses) .css({ "display": cmi.hidden ? "none" : "", "border-top": "0 none" }) .insertBefore($th); $tr.append(th); } } else { // move the header to the next row $tr.append(th); skip--; } } } $theadInTable = $(ts).children("thead"); $theadInTable.prepend($firstHeaderRow); $tr.insertAfter($trLastWithLabels); $htable.prepend($theadInTable); $(ts).triggerHandler("jqGridAfterSetGroupHeaders"); }); }, getNumberOfFrozenColumns: function () { var $t = this; if ($t.length === 0) { return 0; } $t = $t[0]; var colModel = $t.p.colModel, len = colModel.length, maxfrozen = -1, i; // get the max index of frozen col for (i = 0; i < len; i++) { // from left, no breaking frozen if (colModel[i].frozen !== true) { break; } maxfrozen = i; } return maxfrozen + 1; }, setFrozenColumns: function (o) { o = o || {}; return this.each(function () { var $t = this, $self = $($t), p = $t.p, grid = $t.grid; if (!grid || p == null || p.frozenColumns === true) { return; } var cm = p.colModel, i, len = cm.length, maxfrozen = -1, frozen = false, frozenIds = [], $colHeaderRow,// nonFrozenIds = [], tid = jqID(p.id), // one can use p.idSel and remove "#" hoverClasses = getGuiStyles.call($t, "states.hover"); // TODO treeGrid and grouping Support // TODO: allow to edit columns AFTER frozen columns if (p.subGrid === true || p.treeGrid === true || p.scroll) { return; } // get the max index of frozen col for (i = 0; i < len; i++) { // from left, no breaking frozen if (cm[i].frozen !== true) { break; //nonFrozenIds.push("#jqgh_" + tid + "_" + jqID(cm[i].name)); } frozen = true; maxfrozen = i; frozenIds.push("#jqgh_" + tid + "_" + jqID(cm[i].name)); } if (p.sortable) { $colHeaderRow = $(grid.hDiv).find(".ui-jqgrid-htable .ui-jqgrid-labels"); try { $colHeaderRow.sortable("destroy"); } catch (ignore) { } $self.jqGrid("setGridParam", { sortable: { options: { items: frozenIds.length > 0 ? ">th:not(:has(" + frozenIds.join(",") + "),:hidden)" : ">th:not(:hidden)" } } }); $self.jqGrid("sortableColumns", $colHeaderRow); } if (maxfrozen >= 0 && frozen) { var top = p.caption ? $(grid.cDiv).outerHeight() : 0, hth = $(".ui-jqgrid-htable", p.gView).height(); //headers if (p.toppager) { top = top + $(grid.topDiv).outerHeight(); } if (p.toolbar[0] === true) { if (p.toolbar[1] !== "bottom") { top = top + $(grid.uDiv).outerHeight(); } } grid.fhDiv = $("
"); grid.fbDiv = $("
"); $(p.gView).append(grid.fhDiv); var htbl = $(".ui-jqgrid-htable", p.gView).clone(true), tHeadRows = htbl[0].tHead.rows; // groupheader support - only if useColSpanstyle is false if (p.groupHeader) { // TODO: remove all th which corresponds non-frozen columns. One can identify there by id // for example. Consider to use name attribute of th on column headers. It simplifies // identifying of the columns. $(tHeadRows[0].cells).filter(":gt(" + maxfrozen + ")").remove(); $(tHeadRows).filter(".jqg-third-row-header").each(function () { $(this).children("th[id]") .each(function () { var id = $(this).attr("id"), colName; if (id && id.substr(0, $t.id.length + 1) === $t.id + "_") { colName = id.substr($t.id.length + 1); if (p.iColByName[colName] > maxfrozen) { $(this).remove(); } } }); }); var swapfroz = -1, fdel = -1, cs, rs; // TODO: test carefully processing of hidden columns $(tHeadRows).filter(".jqg-second-row-header").children("th").each(function () { cs = parseInt($(this).attr("colspan") || 1, 10); rs = parseInt($(this).attr("rowspan") || 1, 10); if (rs > 1) { swapfroz++; fdel++; } else if (cs) { swapfroz = swapfroz + cs; fdel++; } if (swapfroz === maxfrozen) { return false; } }); if (swapfroz !== maxfrozen) { fdel = maxfrozen; } $(tHeadRows).filter(".jqg-second-row-header,.ui-search-toolbar").each(function () { $(this).children(":gt(" + fdel + ")").remove(); }); } else { $(tHeadRows).each(function () { $(this).children(":gt(" + maxfrozen + ")").remove(); }); } // htable, bdiv and ftable uses table-layout:fixed; style // to make it working one have to set ANY width value on table. // The value of the width will be ignored, the sum of widths // of the first column will be used as the width of tables // and all columns will have the same width like the first row. // We set below just width=1 of the tables. $(htbl).width(1); // resizing stuff $(grid.fhDiv).append(htbl) .scroll(function () { // the fhDiv can be scrolled because of tab keyboard navigation // we prevent horizontal scrolling of fhDiv this.scrollLeft = 0; }); if (p.footerrow) { var hbd = $(".ui-jqgrid-bdiv", p.gView).height(); grid.fsDiv = $("
"); $(p.gView).append(grid.fsDiv); var ftbl = $(".ui-jqgrid-ftable", p.gView).clone(true); $("tr", ftbl).each(function () { $("td:gt(" + maxfrozen + ")", this).remove(); }); $(ftbl).width(1); $(grid.fsDiv).append(ftbl); } // data stuff //TODO support for setRowData $(p.gView).append(grid.fbDiv); $(grid.bDiv).scroll(function () { $(grid.fbDiv).scrollTop($(this).scrollTop()); }); $(grid.fbDiv).on("mousewheel.setFrozenColumns DOMMouseScroll.setFrozenColumns", function (e) { grid.bDiv.scrollTop += $.isFunction(o.mouseWheel) ? o.mouseWheel.call($t, e) : e.type === "mousewheel" ? -e.originalEvent.wheelDelta / 10 : e.originalEvent.detail * 6; }); if (p.hoverrows === true) { $(p.idSel).off("mouseover.jqGrid mouseout.jqGrid"); } var safeHeightSet = function ($elem, newHeight) { var height = $elem.height(); if (Math.abs(height - newHeight) >= 1 && newHeight > 0) { $elem.height(newHeight); height = $elem.height(); if (Math.abs(newHeight - height) >= 1) { $elem.height(newHeight + Math.round((newHeight - height))); } } }, safeWidthSet = function ($elem, newWidth) { var width = $elem.width(); if (Math.abs(width - newWidth) >= 1) { $elem.width(newWidth); width = $elem.width(); if (Math.abs(newWidth - width) >= 1) { $elem.width(newWidth + Math.round((newWidth - width))); } } }, fixDiv = function ($hDiv, hDivBase, iRowStart, iRowEnd) { var iRow, n, $frozenRows, $rows, $row, $frozenRow, posFrozenTop, height, newHeightFrozen, td, posTop = $(hDivBase).position().top, frozenTableTop, tableTop, cells; if ($hDiv != null && $hDiv.length > 0) { $hDiv[0].scrollTop = hDivBase.scrollTop; $hDiv.css(p.direction === "rtl" ? { top: posTop, right: 0 } : { top: posTop, left: 0 } ); // first try with thead for the hdiv $frozenRows = $hDiv.children("table").children("thead").children("tr"); $rows = $(hDivBase).children("div").children("table").children("thead").children("tr"); if ($rows.length === 0 && $hDiv.children("table").length > 0) { // then use tbody for bdiv $frozenRows = $($hDiv.children("table")[0].rows); $rows = $($(hDivBase).children("div").children("table")[0].rows); } n = Math.min($frozenRows.length, $rows.length); frozenTableTop = n > 0 ? $($frozenRows[0]).position().top : 0; tableTop = n > 0 ? $($rows[0]).position().top : 0; // typically 0 if (iRowStart >= 0) { // negative iRowStart means no changing of the height of individual rows if (iRowEnd >= 0) { // negative iRowEnd means all rows n = Math.min(iRowEnd + 1, n); } for (iRow = iRowStart; iRow < n; iRow++) { // but after that one have to verify all scenarios $row = $($rows[iRow]); if ($row.css("display") !== "none" && $row.is(":visible")) { posTop = $row.position().top; $frozenRow = $($frozenRows[iRow]); posFrozenTop = $frozenRow.position().top; height = $row.height(); if (p.groupHeader != null && p.groupHeader.useColSpanStyle) { cells = $row[0].cells; for (i = 0; i < cells.length; i++) { // maxfrozen td = cells[i]; if (td != null && td.nodeName.toUpperCase() === "TH") { height = Math.max(height, $(td).height()); } } } newHeightFrozen = height + (posTop - tableTop) + (frozenTableTop - posFrozenTop); safeHeightSet($frozenRow, newHeightFrozen); } } } safeHeightSet($hDiv, hDivBase.clientHeight); } }, /** @const */ resizeAll = { resizeDiv: true, resizedRows: { iRowStart: 0, iRowEnd: -1 // -1 means "till the end" } }, /** @const */ fullResize = { header: resizeAll, resizeFooter: true, body: resizeAll }; $self.on("jqGridAfterGridComplete.setFrozenColumns", function () { $(p.idSel + "_frozen").remove(); $(grid.fbDiv).height(grid.hDiv.clientHeight); // clone with data and events !!! var $frozenBTable = $(this).clone(true), frozenRows = $frozenBTable[0].rows, rows = $self[0].rows; $(frozenRows).filter("tr[role=row]").each(function () { $(this.cells).filter("td[role=gridcell]:gt(" + maxfrozen + ")").remove(); /*if (this.id) { $(this).attr("id", this.id + "_frozen"); }*/ }); grid.fbRows = frozenRows; $frozenBTable.width(1).attr("id", p.id + "_frozen"); $frozenBTable.appendTo(grid.fbDiv); if (p.hoverrows === true) { var hoverRows = function (tr, method, additionalRows) { $(tr)[method](hoverClasses); $(additionalRows[tr.rowIndex])[method](hoverClasses); }; $(frozenRows).filter(".jqgrow").hover( function () { hoverRows(this, "addClass", rows); }, function () { hoverRows(this, "removeClass", rows); } ); $(rows).filter(".jqgrow").hover( function () { hoverRows(this, "addClass", frozenRows); }, function () { hoverRows(this, "removeClass", frozenRows); } ); } fixDiv(grid.fhDiv, grid.hDiv, 0, -1); fixDiv(grid.fbDiv, grid.bDiv, 0, -1); if (grid.sDiv) { fixDiv(grid.fsDiv, grid.sDiv, 0, -1); } }); var myResize = function (resizeOptions) { $(grid.fbDiv).scrollTop($(grid.bDiv).scrollTop()); // TODO: the width of all column headers can be changed // so one should recalculate frozenWidth in other way. if (resizeOptions.header.resizeDiv) { fixDiv(grid.fhDiv, grid.hDiv, resizeOptions.header.resizedRows.iRowStart, resizeOptions.header.resizedRows.iRowEnd); } if (resizeOptions.body.resizeDiv) { fixDiv(grid.fbDiv, grid.bDiv, resizeOptions.body.resizedRows.iRowStart, resizeOptions.body.resizedRows.iRowEnd); } if (resizeOptions.resizeFooter && grid.sDiv && resizeOptions.resizeFooter) { fixDiv(grid.fsDiv, grid.sDiv, 0, -1); } var frozenWidth = grid.fhDiv[0].clientWidth; if (resizeOptions.header.resizeDiv && grid.fhDiv != null && grid.fhDiv.length >= 1) { safeHeightSet($(grid.fhDiv), grid.hDiv.clientHeight); } if (resizeOptions.body.resizeDiv && grid.fbDiv != null && grid.fbDiv.length > 0) { safeWidthSet($(grid.fbDiv), frozenWidth); } if (resizeOptions.resizeFooter && grid.fsDiv != null && grid.fsDiv.length >= 0) { safeWidthSet($(grid.fsDiv), frozenWidth); } }; $(p.gBox).on("resizestop.setFrozenColumns", function () { setTimeout(function () { myResize(fullResize); }, 50); }); $self.on("jqGridInlineEditRow.setFrozenColumns jqGridInlineAfterRestoreRow.setFrozenColumns jqGridInlineAfterSaveRow.setFrozenColumns jqGridAfterEditCell.setFrozenColumns jqGridAfterRestoreCell.setFrozenColumns jqGridAfterSaveCell.setFrozenColumns jqGridResizeStop.setFrozenColumns", function (e, rowid) { // TODO: probably one should handle additional events like afterSetRow // and remove jqGridInlineAfterSaveRow and jqGridInlineAfterRestoreRow var iRow = $self.jqGrid("getInd", rowid); myResize({ header: { resizeDiv: false, // don't recalculate the position and the height of hDiv resizedRows: { iRowStart: -1, // -1 means don't recalculate heights or rows iRowEnd: -1 } }, resizeFooter: true, // recalculate the position and the height of sDiv body: { resizeDiv: true, // recalculate the position and the height of bDiv resizedRows: { // recalculate the height of only one row inside of bDiv iRowStart: iRow, iRowEnd: iRow } } }); }); $self.on("jqGridResizeStop.setFrozenColumns", function () { myResize(fullResize); }); $self.on("jqGridResetFrozenHeights.setFrozenColumns", function (e, o) { myResize(o || fullResize); }); if (!grid.hDiv.loading) { setTimeout(function () { $self.triggerHandler("jqGridAfterGridComplete"); }, 0); } p.frozenColumns = true; } }); }, destroyFrozenColumns: function () { return this.each(function () { var $t = this, $self = $($t), grid = $t.grid, p = $t.p, tid = jqID(p.id); if (!grid) { return; } if (p.frozenColumns === true) { $(grid.fhDiv).remove(); $(grid.fbDiv).off(".setFrozenColumns"); $(grid.fbDiv).remove(); grid.fhDiv = null; grid.fbDiv = null; grid.fbRows = null; if (p.footerrow) { $(grid.fsDiv).remove(); grid.fsDiv = null; } $self.off(".setFrozenColumns"); if (p.hoverrows === true) { var ptr, hoverClasses = getGuiStyles.call($t, "states.hover"); $self.on("mouseover.jqGrid", function (e) { ptr = $(e.target).closest("tr.jqgrow"); if ($(ptr).attr("class") !== "ui-subgrid") { $(ptr).addClass(hoverClasses); } }).on("mouseout.jqGrid", function (e) { ptr = $(e.target).closest("tr.jqgrow"); $(ptr).removeClass(hoverClasses); }); } p.frozenColumns = false; if (p.sortable) { var $colHeaderRow = $(grid.hDiv).find(".ui-jqgrid-htable .ui-jqgrid-labels"); $colHeaderRow.sortable("destroy"); $self.jqGrid("setGridParam", { sortable: { options: { items: ">th:not(:has(#jqgh_" + tid + "_cb" + ",#jqgh_" + tid + "_rn" + ",#jqgh_" + tid + "_subgrid),:hidden)" } } }); $self.jqGrid("sortableColumns", $colHeaderRow); } } }); } }); // end module grid.custom }));




© 2015 - 2025 Weber Informatics LLC | Privacy Policy