PageSourceSearch

https://enx.com/js/entity-grid.js

js enx.com collected 2026-10-01 11:26:13 UTC 149,372 bytes, 3,676 lines download raw bytes

1/*
2  Copyright (c) Microsoft Corporation. All rights reserved.
3  Licensed under the MIT License. See License.txt in the project root for license information.
4*/
5
6(function ($) {
7
8	var actionTargetEntityForm = 0;
9	var actionTargetWebPage = 1;
10	var actionTargetUrl = 2;
11	var processingRequest = false;
12
13	function entityGrid(element) {
14		this._element = $(element);
15		this._layouts = this._element.data("view-layouts");
16		this._gridClass = this._element.data("grid-class");
17		this._serviceUrlForGet = this._element.data("get-url");
18		this._deferLoading = this._element.data("defer-loading");
19		this._enableActions = this._element.data("enable-actions");
20		this._selectMode = this._element.data("select-mode");
21		this._columnWidthStyle = this._element.data("column-width-style");
22		this._applyRelatedRecordFilter = this._element.data("apply-related-record-filter");
23		this._filterRelationshipName = this._element.data("filter-relationship-name");
24		this._filterEntityName = this._element.data("filter-entity-name");
25		this._filterAttributeName = this._element.data("filter-attribute-name");
26		this._allowFilterOff = this._element.data("allow-filter-off");
27		this._toggleFilterText = this._element.data("toggle-filter-text");
28		this._userIsAuthenticated = this._element.data("user-isauthenticated");
29		this._userParentAccountName = this._element.data("user-parent-account-name");
30		this._toggleFilterDisplayName = this._element.data("toggle-filter-display-name");
31		this._metaFilter = null;
32		this._compact = this._element.closest('[data-entitygrid-layout]').data('entitygrid-layout') === 'compact';
33		this._messageEventHandler = this.createWindowMessageEventHandler();
34
35		if (this._compact) {
36			this._element.addClass('entity-grid-compact');
37		}
38
39		var that = this;
40
41		$(element).on("refresh", function () {
42			that.load();
43		});
44
45		$(element).on("metafilter", function (e, metaFilter) {
46			that._metaFilter = metaFilter;
47			that.resetPagination();
48			that.load();
49		});
50	}
51
52	$(document).ready(function () {
53	    var eg = $(".entity-grid");
54	    eg.each(function () {
55			new entityGrid($(this)).render();
56		});
57
58	    if (eg.length === 0) {
59	        handleMobileHeaders($(".table-fluid"));
60	    }
61
62	    $(".entitylist").on("click.entitylist", ".entitylist-filter-option-breaker a", function(e) {
63			e.preventDefault();
64			e.stopPropagation();
65
66			var collapsed = $(this).data("collapsed");
67
68			var ul = $(this).closest("ul");
69
70			var pageSize = ul.data("pagesize");
71
72			ul.children("li.entitylist-filter-option").each(function (i) {
73				if (i >= pageSize) {
74					if (collapsed) {
75						$(this).attr("aria-hidden", "false");
76					} else {
77						$(this).attr("aria-hidden", "true");
78					}
79				}
80			});
81
82			$(this).find(".fa").toggleClass("fa-caret-down", collapsed).toggleClass("fa-caret-up", !collapsed);
83			$(this).find(".expand-label").text(collapsed ? "Less" : "More");
84
85			$(this).data("collapsed", !collapsed);
86		});
87	});
88
89	function getUrlWithRelatedReference($element, uri) {
90		uri = URI(uri);
91
92		var refEntityName = $element.data("ref-entity");
93		var refEntityId = $element.data("ref-id");
94		var refRelationship = $element.data("ref-rel");
95		var refRelationshipRole = $element.data("ref-rel-role");
96
97		if (refEntityName && refEntityId && refRelationship) {
98			uri.addSearch('refentity', refEntityName);
99			uri.addSearch('refid', refEntityId);
100			uri.addSearch('refrel', refRelationship);
101
102			if (refRelationshipRole) {
103				uri.addSearch('refrelrole', refRelationshipRole);
104			}
105		}
106
107		return uri.toString();
108	}
109
110	// Returns URL for Create Related Record action. 
111	// Contains params to fill referencing entity.
112	function getUrlForCreateRelatedRecordAction(uri, refEntityName, refEntityId, refRelationship) {
113		uri = URI(uri);
114
115		if (refEntityName && refEntityId && refRelationship) {
116			uri.addSearch('refentity', refEntityName);
117			uri.addSearch('refid', refEntityId);
118			uri.addSearch('refrel', refRelationship);
119		}
120
121		return uri.toString();
122	}
123
124	function getUrlFromActionLink(action) {
125		if (!action || !action.URL) return null;
126		return getUrlFromUrlBuilder(action.URL);
127	}
128
129	function displayErrorAlert(error, $element) {
130		if (typeof error !== typeof undefined && error !== false && error != null) {
131			console.log(error);
132			var message;
133			if (typeof error.InnerError !== typeof undefined && error.InnerError !== false && error.InnerError != null) {
134				message = error.InnerError.Message;
135			} else {
136				message = error.Message;
137			}
138			var $container = $(".notifications");
139			if ($container.length == 0) {
140				var $pageheader = $(".page-heading");
141				if ($pageheader.length == 0) {
142					$container = $("<div class='notifications'></div>").prependTo($("#content-container"));
143				} else {
144					$container = $("<div class='notifications'></div>").appendTo($pageheader);
145				}
146			}
147			$container.find(".notification").slideUp().remove();
148			var $alert = $("<div class='notification alert alert-danger error alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button><span class='fa fa-exclamation-triangle' aria-hidden='true'></span> " + message + "</div>")
149				.on('closed.bs.alert', function () {
150					if ($container.find(".notification").length == 0) $container.hide();
151				}).prependTo($container);
152			$container.show();
153			$('html, body').animate({
154				scrollTop: ($alert.offset().top - 20)
155			}, 200);
156		}
157	}
158
159	entityGrid.prototype.render = function (forceLoad) {
160		var $this = this;
161		var $element = $this._element;
162		var layouts = $this._layouts;
163		var cssClass = $this._gridClass;
164		var selectedViewId = $element.data("selected-view");
165		var deferLoading = $this._deferLoading;
166		var enableActions = $this._enableActions;
167		var allowFilterOff = $this._allowFilterOff;
168		var toggleFilterText = $this._toggleFilterText;
169		var selectMode = $this._selectMode;
170		var columnWidthStyle = $this._columnWidthStyle;
171		var userIsAuthenticated = $this._userIsAuthenticated;
172		var userParentAccountName = $this._userParentAccountName;
173		var toggleFilterDisplayName = $this._toggleFilterDisplayName;
174		var activeLayoutIndex = 0;
175		if (typeof selectedViewId !== typeof undefined && selectedViewId !== false && selectedViewId != null && selectedViewId != '') {
176			activeLayoutIndex = indexOf(layouts, "Id", selectedViewId);
177			if (activeLayoutIndex == -1) {
178				activeLayoutIndex = 0;
179			}
180		}
181		this._activeLayoutIndex = activeLayoutIndex;
182		var layout = layouts[activeLayoutIndex];
183		var queryString = URI(window.location).search(true);
184		var iframed = inIframe();
185		$this._metaFilter = queryString[layout.Configuration.FilterSettings.FilterQueryStringParameterName || "mf"] || null;
186		var enableFilter = (userIsAuthenticated && userParentAccountName && userParentAccountName != '' && ((layout.Configuration.FilterPortalUserAttributeName != null && layout.Configuration.FilterPortalUserAttributeName != '') && (layout.Configuration.FilterAccountAttributeName != null && layout.Configuration.FilterAccountAttributeName != '')));
187		var $container = $element.children(".view-grid");
188		$container.empty();
189		$element.children(".view-toolbar").remove();
190		var $toolbar = $("<div></div>").addClass("view-toolbar").addClass("grid-actions").addClass("clearfix");
191		var $rightElementsContainerDiv = $("<div></div>").addClass("pull-right").addClass("toolbar-actions");
192		var addToolbar = false;
193		if (allowFilterOff) {
194			var $toggleFilter = $("<a></a>")
195				.attr("href", "#")
196				.addClass("toggle-related-filter")
197				.data("placement", "bottom")
198				.data("toggle", "tooltip")
199				.addClass("btn btn-default")
200				.addClass("active")
201				.append($("<span></span>").addClass("fa").addClass("fa-filter").attr('aria-hidden', 'true'))
202				.append($("<span></span>").addClass("title").text(toggleFilterDisplayName))
203				.on("click", function(e) {
204					e.preventDefault();
205					$(this).toggleClass("active");
206					$this.load(0, $element.children(".view-toolbar").find(".view-filter-select").data("filter"), !$(this).hasClass("active"));
207				});
208			if (toggleFilterText && toggleFilterText != '') {
209				$toggleFilter.attr("title", toggleFilterText).tooltip();
210			}
211			if (this._compact) {
212				$toggleFilter.addClass('btn-xs');
213			}
214			$toggleFilter.prependTo($toolbar);
215			addToolbar = true;
216		}
217
218        var search = layout.Configuration.Search;
219        var $searchContainer, $searchButton, $searchButtonGroup, $searchInput;
220
221		if (search.Enabled) {
222			$searchContainer = $("<div></div>").addClass("input-group").addClass("pull-left").addClass("view-search").addClass("entitylist-search");
223			$searchButton = $("<button></button>")
224				.attr("type", "button")
225				.attr("aria-label", window.ResourceManager['Search_Results'])
226				.attr("title", window.ResourceManager['Search_Results'])
227				.addClass("btn")
228				.addClass("btn-default")
229				.append($("<span></span>").addClass("sr-only").html("Search Results"))
230				.append($("<span></span>").addClass("fa").addClass("fa-search"))
231				.on("click", function (e) {
232					e.preventDefault();
233					$this.load(1);
234				});
235			$searchButtonGroup = $("<div></div>").addClass("input-group-btn").attr("role", "presentation").append($searchButton);
236			$searchInput = $("<input/>")
237				.attr("placeholder", search.PlaceholderText)
238				.data("toggle", "tooltip")
239				.attr("title", search.TooltipText)
240				.attr("aria-label", search.TooltipText)
241				.tooltip()
242				.addClass("query")
243				.addClass("form-control")
244				.val("")
245				.on("keypress", function(e) {
246					var keyCode = e.keyCode ? e.keyCode : e.which;
247					if (keyCode == '13') {
248						e.preventDefault();
249						$searchButton.trigger("click");
250						$(this).trigger("focus");
251					}
252				});
253		}
254		
255		if (enableActions) {
256			window.removeEventListener('message', $this._messageEventHandler);
257			window.addEventListener('message', $this._messageEventHandler);
258		}
259		$element.children(".modal-form-details").on('hidden.bs.modal.entitygrid', function () {
260			var $iframe = $(this).find("iframe");
261			$iframe.attr("src", "");
262		});
263		$element.children(".modal-form-edit").on('hidden.bs.modal.entitygrid', function () {
264			var $iframe = $(this).find("iframe");
265			$iframe.attr("src", "");
266		});
267		$element.children(".modal-form-createrecord").on('hidden.bs.modal.entitygrid', function () {
268			var $iframe = $(this).find("iframe");
269			$iframe.attr("src", "");
270		});
271
272		var state = $element.closest(".entity-form").find("[id$='_EntityState']").val();
273		var isParentRecordInactive = typeof state != typeof undefined && state != null && state !== "" && state !== "0";
274
275		if (enableActions && layout.Configuration.InsertActionLink.Enabled && layout.Configuration.InsertActionLink.URL && !isParentRecordInactive) {
276			var $insertLink = $("<a></a>").attr("href", getUrlFromActionLink(layout.Configuration.InsertActionLink)).addClass("btn").addClass("insert-Action-link").addClass("btn-primary").addClass("pull-right").addClass("action").html(layout.Configuration.InsertActionLink.Label).attr("title", layout.Configuration.InsertActionLink.Tooltip);
277			if (iframed) $insertLink.attr("target", "_top");
278			$insertLink.prependTo($toolbar);
279			addToolbar = true;
280		}
281		var $insertActionLinkDiv = null;
282		if (enableActions) {
283			// Loop through the ViewActionLinks and output download links only at this time.
284			$.each(layout.Configuration.ViewActionLinks, function (i, viewActionLink) {
285				if (!viewActionLink.Enabled)
286					return;
287				switch (viewActionLink.Type) {
288					case 3: //Insert Action
289						if (isParentRecordInactive) {
290							return;
291						}
292						var href = "#";
293
294						var refEntityName = $element.data("ref-entity");
295						var refEntityId = $element.data("ref-id");
296						var refRelationship = $element.data("ref-rel");
297						var refRelationshipRole = $element.data("ref-rel-role");
298						var refQueryString = "";
299
300						if (refEntityName && refEntityId && refRelationship) {
301							refQueryString += "refentity=" + refEntityName + "&refid=" + refEntityId + "&refrel=" + refRelationship;
302							if (refRelationshipRole) {
303								refQueryString += "&refrelrole=" + refRelationshipRole;
304							}
305						}
306
307						if ((viewActionLink.Target == actionTargetWebPage || viewActionLink.Target == actionTargetUrl) && viewActionLink.URL != null) {
308							href = getUrlWithRelatedReference($element, URI(getUrlFromActionLink(viewActionLink)).toString());
309                        }
310
311						$insertActionLinkDiv = $("<div></div>").addClass("input-group").addClass("pull-left");
312						var $insertActionLink = $("<a></a>").attr("href", href).addClass("btn").addClass("btn-primary").addClass("pull-right").addClass("action create-action").html(viewActionLink.Label).attr("title", viewActionLink.Tooltip);
313						if (href != "#" && iframed) $insertActionLink.attr("target", "_top");
314						if (viewActionLink.Target == actionTargetEntityForm && viewActionLink.EntityForm) {
315							var $insertModal = $element.children(".modal-form-insert");
316							$insertModal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
317								$insertModal.attr("aria-hidden", "true");
318								var $iframe = $(this).find("iframe");
319								$iframe.attr("src", "");
320								$insertActionLink.trigger("focus");
321							});
322							$insertActionLink.on("click", function (e) {
323								e.preventDefault();
324								var $iframe = $insertModal.find("iframe");
325								var page = $iframe.data("page");
326								var entityformid = viewActionLink.EntityForm.Id.toString();
327								var src = getUrlWithRelatedReference($element, (page + "?entityformid=" + entityformid + "&languagecode=" + layout.Configuration.LanguageCode));
328
329								$iframe.attr("src", src);
330								$iframe.on("load", function () {
331									$insertModal.find(".form-loading").hide();
332									$insertModal.find("iframe").contents().find("#EntityFormControl").show();
333								});
334								$insertModal.find(".form-loading").show();
335								$insertModal.find("iframe").contents().find("#EntityFormControl").hide();
336								$insertModal.modal();
337							});
338							$insertModal.on('show.bs.modal', function () {
339								$insertModal.attr("aria-hidden", "false");
340							});
341						}
342
343						if ($this._compact) {
344							$insertActionLink.addClass('btn-xs');
345						}
346						
347						$insertActionLinkDiv.append($insertActionLink).appendTo($rightElementsContainerDiv);
348						addToolbar = true;
349						break;
350					case 5: //Associate Action
351						if (isParentRecordInactive) {
352							return;
353						}
354						var $associateLink = $("<a></a>").attr("href", "#").addClass("btn").addClass("btn-info").addClass("pull-right").addClass("action").html(viewActionLink.Label).attr("title", viewActionLink.Tooltip);
355						var $associateModal = $element.find(".associate-lookup .modal-associate");
356						$associateModal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
357							$associateLink.trigger("focus");
358						});
359						$associateLink.on("click", function (e) {
360							e.preventDefault();
361							$associateModal.modal();
362						});
363						if ($this._compact) {
364							$associateLink.addClass('btn-xs');
365						}
366						$associateLink.appendTo($rightElementsContainerDiv);
367						addToolbar = true;
368						break;
369					case 8: //Download Action
370					var $exportLinkDiv = $("<div></div>").addClass("input-group").addClass("pull-left");
371						var $downloadButton = $("<a></a>").attr("href", "#")
372							.addClass("entitylist-download")
373							.addClass("btn")
374							.addClass("btn-info")
375							.addClass("pull-right")
376							.addClass("action")
377							.attr("title", viewActionLink.Tooltip)
378							.html(viewActionLink.Label);
379						if ($this._compact) {
380							$downloadButton.addClass('btn-xs');
381						}
382						// Add download click event handler.
383						$downloadButton.on("click", function (e) {
384							e.preventDefault();
385							$downloadButton.attr("disabled", "disabled");
386
387							var dateTimeForOffset = new Date();
388
389							var data = {};
390							data.viewName = layout.ViewName;
391							data.columns = layout.Columns;
392							data.base64SecureConfiguration = layout.Base64SecureConfiguration;
393							data.sortExpression = $element.find(".view-grid > table").data("sort-expression") || layout.SortExpression;
394							data.search = $searchInput ? $searchInput.val() : null;
395							data.filter = $this.getCurrentFilter();
396							data.metaFilter = $this._metaFilter;
397							data.page = $element.children(".view-pagination").data("current-page");
398							data.pageSize = $element.children(".view-pagination").data("pagesize");
399							data.timezoneOffset = dateTimeForOffset.getTimezoneOffset();
400							var jsonData = JSON.stringify(data);
401
402						    shell.ajaxSafePost({
403								type: 'POST',
404								dataType: "json",
405								contentType: 'application/json; charset=utf-8',
406								url: viewActionLink.URL.Path,
407								data: jsonData,
408								global: false,
409								success: function(result) {
410									if (result.success) {
411										window.location = viewActionLink.URL.Path + "?key=" + result.sessionKey;
412									}
413								}
414							}).fail(function (jqXhr) {
415								var contentType = jqXhr.getResponseHeader("content-type");
416								var error = contentType.indexOf("json") > -1 ? $.parseJSON(jqXhr.responseText) : { Message: jqXhr.status, InnerError: { Message: jqXhr.statusText } };
417								displayErrorAlert(error, $element);
418							}).always(function () {
419								$downloadButton.removeAttr("disabled", "disabled");
420							});
421						});
422						$exportLinkDiv.append($downloadButton).appendTo($rightElementsContainerDiv);
423						addToolbar = true;
424						break;
425				}
426			});
427		}
428		if (enableFilter) {
429			var $filterSelectionContainer = $("<ul></ul>").addClass("view-filter-select").addClass("nav").addClass("nav-pills").addClass("pull-left").data("filter", "user");
430			var $filterSelectionDropdown = $("<li></li>").addClass("dropdown");
431			var $filterSelectionLink = $("<a></a>")
432				.addClass("dropdown-toggle")
433				.attr("data-toggle", "dropdown")
434				.attr("href", "#")
435				.append($("<span></span>").addClass("fa").addClass("fa-filter").attr('aria-hidden', 'true'))
436				.append($("<span></span>").addClass("title").html(" " + layout.Configuration.FilterByUserOptionLabel))
437				.append($("<span></span>").addClass("caret").attr('aria-hidden', 'true'))
438				.dropdown();
439			$filterSelectionDropdown.append($filterSelectionLink);
440			var $filterSelectionDropdownMenu = $("<ul></ul>").addClass("dropdown-menu");
441			var $liUserFilter = $("<li></li>");
442			$liUserFilter.addClass("active");
443			var $userFilterLink = $("<a></a>")
444				.attr("href", "#")
445				.addClass("filter-user")
446				.html(layout.Configuration.FilterByUserOptionLabel)
447				.on("click", function (e) {
448					e.preventDefault();
449					$filterSelectionContainer.find("li").removeClass("active");
450					$(this).closest("li").toggleClass("active");
451					$filterSelectionContainer.data("filter", "user");
452					$this.changeFilter();
453				});
454			$liUserFilter.append($userFilterLink).appendTo($filterSelectionDropdownMenu);
455			var $liUserAccountFilter = $("<li></li>");
456			var $userAccountFilterLink = $("<a></a>")
457				.attr("href", "#")
458				.addClass("filter-account")
459				.html(userParentAccountName)
460				.on("click", function (e) {
461					e.preventDefault();
462					$filterSelectionContainer.find("li").removeClass("active");
463					$(this).closest("li").toggleClass("active");
464					$filterSelectionContainer.data("filter", "account");
465					$this.changeFilter();
466				});
467			$liUserAccountFilter.append($userAccountFilterLink).appendTo($filterSelectionDropdownMenu);
468			$filterSelectionDropdown.append($filterSelectionDropdownMenu).appendTo($filterSelectionContainer);
469			$filterSelectionContainer.prependTo($toolbar);
470			addToolbar = true;
471		}
472		
473		if (search.Enabled && $searchContainer && !$this._compact) {
474			$searchContainer.append($searchInput).append($searchButtonGroup).prependTo($rightElementsContainerDiv);
475			addToolbar = true;
476		}
477
478		if (layouts.length > 1) {
479			var currentViewDisplayName = layout.Configuration.ViewDisplayName;
480			if (currentViewDisplayName == null || currentViewDisplayName == "") {
481				currentViewDisplayName = layout.ViewName;
482			}
483			var $viewSelectionContainer = $("<ul></ul>").addClass("view-select").addClass("nav").addClass("nav-pills").addClass("pull-left");
484			var $viewSelectionDropdown = $("<li></li>").addClass("dropdown");
485			var $viewSelectionLink = $("<a></a>")
486				.addClass('selected-view')
487				.addClass("dropdown-toggle")
488				.attr("data-toggle", "dropdown")
489				.attr("href", "#")
490				.attr("role", "button")
491				.attr("title", currentViewDisplayName)
492				.append($("<span></span>").addClass("fa").addClass("fa-list").attr('aria-hidden', 'true'))
493				.append($("<span></span>").addClass("title").html(" " + currentViewDisplayName))
494				.append($("<span></span>").addClass("caret").attr('aria-hidden', 'true'))
495				.dropdown();
496			$viewSelectionDropdown.append($viewSelectionLink);
497			var $viewSelectionDropdownMenu = $("<ul></ul>").addClass("dropdown-menu");
498			$.each(layouts, function (i, layoutItem) {
499				var $li = $("<li></li>");
500				if (i == activeLayoutIndex) {
501					$li.addClass("active");
502				}
503				var viewDisplayName = layoutItem.Configuration.ViewDisplayName;
504				if (viewDisplayName == null || viewDisplayName == "") {
505					viewDisplayName = layoutItem.ViewName;
506				}
507				var $a = $("<a></a>")
508					.attr("href", "#")
509					.data("id", layoutItem.Id)
510					.html(viewDisplayName)
511					.on("click", function (e) {
512						e.preventDefault();
513						var id = $(this).data("id");
514						$this.changeView(id);
515					});
516				$li.append($a).appendTo($viewSelectionDropdownMenu);
517			});
518			$viewSelectionDropdown.append($viewSelectionDropdownMenu).appendTo($viewSelectionContainer);
519			$viewSelectionContainer.prependTo($toolbar);
520			addToolbar = true;
521		} else if ($this._compact) {
522			$("<ul>").addClass("view-select").addClass("nav").addClass("nav-pills").addClass("pull-left")
523				.append($("<li>")
524					.append($("<div>")
525						.addClass("selected-view")
526						.append($("<span>")
527							.addClass("title").html(layout.Configuration.ViewDisplayName || layout.ViewName || ''))))
528				.prependTo($toolbar);
529			addToolbar = true;
530		}
531
532		if (search.Enabled && $searchContainer && $this._compact) {
533			$searchContainer.removeClass('pull-left').addClass('input-group-sm').append($searchInput).append($searchButtonGroup).prependTo($element);
534		}
535
536		if (addToolbar) {
537			$rightElementsContainerDiv.appendTo($toolbar);
538			$element.prepend($toolbar);
539		}
540		
541		if (layout.Columns.length == 0) {
542			return;
543		}
544		var $table = $("<table></table>").attr("aria-live", "polite").attr("aria-relevant", "additions");
545		$table.addClass("table");
546		$table.addClass(cssClass);
547		$table.addClass("table-fluid");
548		if (selectMode == "Single" || selectMode == "Multiple") {
549			$table.addClass("table-hover");
550		}
551		if (columnWidthStyle == "Pixels") {
552			$table.attr("style", "width:" + layout.ColumnsTotalWidth + "px !important; max-width:" + layout.ColumnsTotalWidth + "px !important;");
553		}
554		$table.data("sort-expression", layout.SortExpression);
555		var $thead = $("<thead></thead>");
556		var $tbody = $("<tbody></tbody>");
557		var $tr = $("<tr></tr>");
558		var sorts = parseSortExpression(layout.SortExpression);
559
560		$.each(layout.Columns, function (i, column) {
561			var $th = $("<th></th>")
562				.data("field", column.LogicalName);
563
564			if (column.LogicalName !== 'col-action') {
565				$th.data("columnname", column.Name);
566			}
567
568			if (columnWidthStyle == "Pixels") {
569				$th.attr("style", "width:" + column.Width + "px;");
570			} else {
571				$th.attr("style", "width:" + column.WidthAsPercent + "%;");
572			}
573			if (!column.SortDisabled) {
574				$th.addClass("sort-enabled").data("sort-name", column.LogicalName);
575				var $a = $("<a></a>").attr("href", "#").attr("role","button").attr("aria-label", column.Name);
576				var sortIndex = indexOf(sorts, "name", column.LogicalName);
577				if (sortIndex != -1) {
578					var sort = sorts[sortIndex];
579					if (sort.direction.toLowerCase().match("asc") != -1) {
580						$a.append(column.Name + " ").append($("<span></span>").addClass("fa").addClass("fa-arrow-up").attr('aria-hidden', 'true'))
581							.append("<span class='sr-only sort-hint'>. " + window.ResourceManager['Sort_Descending_Order'] + "</span>");
582						$th.data("sort-dir", "ASC").attr("aria-sort", "ascending")
583							.addClass("sort")
584							.addClass("sort-asc");
585					} else {
586					    $a.append(column.Name + " ").append($("<span></span>").append(window.ResourceManager['Sort_Ascending_Order']).addClass("fa").addClass("fa-arrow-down").attr('aria-hidden', 'true'))
587							.append("<span class='sr-only sort-hint'>. " + window.ResourceManager['Sort_Ascending_Order'] + "</span>");
588						$th.data("sort-dir", "DESC").attr("aria-sort", "descending")
589							.addClass("sort")
590							.addClass("sort-desc");
591					}
592				} else {
593				    $a.html(column.Name).append("<span class='sr-only sort-hint'>. " + window.ResourceManager['Sort_Descending_Order'] + "</span>");
594				}
595				$a.appendTo($th);
596			} else {
597				$th.html(column.Name);
598				$th.addClass("sort-disabled");
599			}
600			$th.appendTo($tr);
601		});
602		$tr.appendTo($thead);
603		$thead.appendTo($table);
604		$tbody.appendTo($table);
605		$table.appendTo($container);
606		$this.addSortEventHandlers();
607		if (!deferLoading) {
608			$this.load();
609		} else if (forceLoad) {
610			$this.load();
611		}
612	}
613
614	entityGrid.prototype.changeView = function (id) {
615		var $this = this;
616		var $element = $this._element;
617		$element.data("selected-view", id);
618		$this.resetPagination();
619		$this.render(true);
620	}
621
622	entityGrid.prototype.changeFilter = function () {
623		var $this = this;
624		var $element = $this._element;
625		var layouts = $this._layouts;
626		var selectedViewId = $element.data("selected-view");
627		var $filterSelect = $element.children(".view-toolbar").find(".view-filter-select");
628		var activeLayoutIndex = 0;
629		if (typeof selectedViewId !== typeof undefined && selectedViewId !== false && selectedViewId != null && selectedViewId != '') {
630			activeLayoutIndex = indexOf(layouts, "Id", selectedViewId);
631			if (activeLayoutIndex == -1) {
632				activeLayoutIndex = 0;
633			}
634		}
635		this._activeLayoutIndex = activeLayoutIndex;
636		var layout = layouts[activeLayoutIndex];
637		var userIsAuthenticated = $this._userIsAuthenticated;
638		var userParentAccountName = $this._userParentAccountName;
639		var enableFilter = (userIsAuthenticated && userParentAccountName && userParentAccountName != '' && ((layout.Configuration.FilterPortalUserAttributeName != null && layout.Configuration.FilterPortalUserAttributeName != '') || (layout.Configuration.FilterAccountAttributeName != null && layout.Configuration.FilterAccountAttributeName != '')));
640		if (!enableFilter) {
641			return;
642		}
643		var currentFilter = $this.getCurrentFilter();
644		var currentFilterName;
645		if (currentFilter == "user") {
646			currentFilterName = layout.Configuration.FilterByUserOptionLabel;
647		} else {
648			currentFilterName = userParentAccountName;
649		}
650		$filterSelect.find("li.dropdown").find("span.title").html(" " + currentFilterName);
651		$this.load(0, currentFilter);
652	}
653
654	entityGrid.prototype.getCurrentFilter = function() {
655		var $this = this;
656		var $element = $this._element;
657		var layouts = $this._layouts;
658		var selectedViewId = $element.data("selected-view");
659		var $filterSelect = $element.children(".view-toolbar").find(".view-filter-select");
660		var activeLayoutIndex = 0;
661		if (typeof selectedViewId !== typeof undefined && selectedViewId !== false && selectedViewId != null && selectedViewId != '') {
662			activeLayoutIndex = indexOf(layouts, "Id", selectedViewId);
663			if (activeLayoutIndex == -1) {
664				activeLayoutIndex = 0;
665			}
666		}
667		this._activeLayoutIndex = activeLayoutIndex;
668		var layout = layouts[activeLayoutIndex];
669		var userIsAuthenticated = $this._userIsAuthenticated;
670		var userParentAccountName = $this._userParentAccountName;
671		var defaultFilter = "user";
672
673		if (!userIsAuthenticated) {
674			return null;
675		}
676
677		if (layout.Configuration.FilterPortalUserAttributeName == null || layout.Configuration.FilterPortalUserAttributeName == '') {
678			if (!userParentAccountName || userParentAccountName == '' || layout.Configuration.FilterAccountAttributeName == null || layout.Configuration.FilterAccountAttributeName == '') {
679				return null;
680			} else {
681				return "account";
682			}
683		}
684
685		if (!userParentAccountName || userParentAccountName == '' || layout.Configuration.FilterAccountAttributeName == null || layout.Configuration.FilterAccountAttributeName == '') {
686			return defaultFilter;
687		}
688
689		var currentFilter = $filterSelect.data("filter") || defaultFilter;
690		if (currentFilter == "user" || currentFilter == "account") {
691			return currentFilter;
692		}
693		return defaultFilter;
694	}
695
696	entityGrid.prototype.isRelatedRecordFilterEnabled = function() {
697		var $this = this;
698		var $element = $this._element;
699		var applyRelatedRecordFilter;
700		if ($element.children(".view-toolbar").find(".toggle-related-filter").length == 0) {
701			applyRelatedRecordFilter = $this._applyRelatedRecordFilter || false;
702		} else {
703			applyRelatedRecordFilter = $element.children(".view-toolbar").find(".toggle-related-filter").hasClass("active");
704		}
705		return applyRelatedRecordFilter;
706	}
707
708	entityGrid.prototype.load = function (page, filter, relatedRecordfilterOff, callingElement) {
709		var $this = this;
710		var $element = $this._element;
711		var $table = $element.children(".view-grid").find("table");
712		var $tbody = $("<tbody></tbody>");
713		var $errorMessage = $element.children(".view-error");
714		var $emptyMessage = $element.children(".view-empty");
715		var $accessDeniedMessage = $element.children(".view-access-denied");
716		var $loadingMessage = $element.children(".view-loading");
717		var $pagination = $element.children(".view-pagination");
718		var $search = $element.children(".view-toolbar").find(".entitylist-search input.query");
719		var sortExpression = $table.data("sort-expression");
720		var serviceUrlGet = $this._serviceUrlForGet;
721		var layouts = $this._layouts;
722		var layout = layouts[$this._activeLayoutIndex];
723		var configuration = layout.Configuration;
724		var selectMode = $this._selectMode;
725		var enableActions = $this._enableActions;
726		var applyRelatedRecordFilter;
727		var filterRelationshipName = $this._filterRelationshipName;
728		var filterEntityName = $this._filterEntityName;
729		var filterAttributeName = $this._filterAttributeName;
730		var filterValue = null;
731		var entityName = $element.closest(".entity-form").children("input[type='hidden'][id$='EntityName']").val();
732		var entityId = $element.closest(".entity-form").children("input[type='hidden'][id$='EntityID']").val();
733		var metaFilter = $this._metaFilter;
734
735		$element.children(".view-grid").find("tbody").remove();
736
737		$errorMessage.hide().prop("aria-hidden", true);
738		$emptyMessage.hide().prop("aria-hidden", true);
739		$accessDeniedMessage.hide().prop("aria-hidden", true);
740
741		$loadingMessage.show().prop("aria-hidden", false);
742
743		$pagination.data("pagesize", configuration.PageSize);
744		var pageNumber = $pagination.data("current-page");
745		if (pageNumber == null || pageNumber == '') {
746			pageNumber = 1;
747		}
748		filter = filter || $this.getCurrentFilter();
749		page = page || pageNumber;
750		var pageSize = $pagination.data("pagesize");
751		if (pageSize == null || pageSize == '') {
752			pageSize = 10;
753		}
754		var search = $search.val();
755		if (typeof search === typeof undefined || search === false) {
756			search = null;
757		}
758
759		if (typeof relatedRecordfilterOff === typeof undefined) {
760			applyRelatedRecordFilter = $this.isRelatedRecordFilterEnabled();
761		} else {
762			applyRelatedRecordFilter = !relatedRecordfilterOff;
763		}
764		if (applyRelatedRecordFilter) {
765			if (filterEntityName && entityName && entityName != '' && filterEntityName == entityName && entityId && entityId != '') {
766				filterValue = entityId;
767			} else if (filterAttributeName && filterAttributeName != '') {
768				var $dependentField = $("#" + filterAttributeName);
769				if ($dependentField.length > 0) {
770					var dependentValue = $dependentField.val();
771					if (dependentValue && dependentValue != '') {
772						filterValue = dependentValue;
773					}
774				}
775			}
776		}
777
778		$this.hidePagination();
779
780		$this.getData(serviceUrlGet, configuration, layout.Base64SecureConfiguration, sortExpression, filter, metaFilter, search, page, pageSize, applyRelatedRecordFilter, filterRelationshipName, filterEntityName, filterAttributeName, filterValue,
781			function (data) {
782				// done
783				$tbody.empty();
784				if (typeof data === typeof undefined || data === false || data == null) {
785					$emptyMessage.fadeIn().prop("aria-hidden", false);
786					$element.trigger("loaded");
787					return;
788				}
789
790				if (data.CreateActionMetadata && data.CreateActionMetadata.Disabled) {
791					var $createAction = $element.find('.grid-actions .create-action').off('click');
792
793					if (data.CreateActionMetadata.DisabledMessage) {
794						$createAction.attr('title', data.CreateActionMetadata.DisabledMessage);
795					}
796
797					$createAction.click(function (e) {
798						e.preventDefault();
799
800						if (data.CreateActionMetadata.DisabledMessage) {
801							window.alert(data.CreateActionMetadata.DisabledMessage);
802						}
803					});
804				}
805
806				if (typeof data.Records !== typeof undefined && data.Records !== false && (data.Records == null || data.Records.length == 0)) {
807					$emptyMessage.fadeIn().prop("aria-hidden", false);
808					$element.trigger("loaded");
809					return;
810				}
811				if (typeof data.AccessDenied !== typeof undefined && data.AccessDenied !== false && data.AccessDenied) {
812					$accessDeniedMessage.fadeIn().prop("aria-hidden", false);
813					$element.trigger("loaded");
814					return;
815				}
816
817				var columns = $.map($table.find("th"), function (e) {
818					return $(e).data('field');
819				});
820
821				var nameColumn = columns.length == 0 ? "" : columns[0] == "col-select" ? columns[1] : columns[0];
822
823				$element.data("total-record-count", data.ItemCount);
824
825				for (var i = 0; i < data.Records.length; i++) {
826					var record = data.Records[i];
827					var name = getPrimaryName(record);
828					if (!name) {
829						var nameAttributeIndex = indexOf(record.Attributes, "Name", nameColumn);
830						if (nameAttributeIndex != -1) {
831							name = record.Attributes[nameAttributeIndex].DisplayValue;
832						}
833					}
834					var $tr = $("<tr></tr>")
835						.attr("data-id", record.Id)
836						.attr("data-entity", configuration.EntityName)
837						.attr("data-name", name || "")
838						.on("focus", function() {
839							$(this).addClass("active");
840						})
841						.on("blur", function() {
842							$(this).removeClass("active");
843						});
844
845					var select = $.noop;
846					if (selectMode == "Multiple") {
847						select = function() {
848							var selected = $(this).attr("aria-checked") === "true";
849							$(this).children("td:first").find(".fa-fw").toggleClass("fa-check", !selected);
850							$(this).toggleClass("selected").toggleClass("info").attr("aria-checked", !selected);
851						};
852						$tr.on("click", select).on("keypress", function(e) {
853							var keyCode = e.keyCode ? e.keyCode : e.which;
854							if (keyCode == '13' || keyCode == '32') {
855								e.preventDefault();
856								select.apply(this, arguments);
857							}
858						}).attr("tabindex", 0).attr("role", "checkbox").attr("aria-checked", "false");
859					} else if (selectMode == "Single") {
860						select = function() {
861							var selected = $(this).attr("aria-checked") === "true";
862
863							var $selectedRows = $table.find("tr.selected");
864							$selectedRows.each(function() {
865								$(this).children("td:first").find(".fa-fw").removeClass("fa-check");
866								$(this).removeClass("selected").removeClass("info").attr("aria-checked", false);
867							});
868
869							if (!selected) {
870								$(this).children("td:first").find(".fa-fw").addClass("fa-check");
871								$(this).addClass("selected").addClass("info").attr("aria-checked", true);
872							}
873						};
874						$tr.on("click", select).on("keypress", function(e) {
875							var keyCode = e.keyCode ? e.keyCode : e.which;
876							if (keyCode == '13' || keyCode == '32') {
877								e.preventDefault();
878								select.apply(this, arguments);
879							}
880						}).attr("tabindex", 0).attr("role", "radio").attr("aria-checked", "false");
881					}
882
883					for (var j = 0; j < columns.length; j++) {
884						var found = false;
885						for (var k = 0; k < record.Attributes.length; k++) {
886							var attribute = record.Attributes[k];
887							if (attribute.Name == columns[j]) {
888								var $td = $("<td></td>")
889									.attr("data-type", attribute.Type)
890									.attr("data-attribute", attribute.Name)
891									.attr("data-value", typeof attribute.Value === 'object' ? JSON.stringify(attribute.Value) : attribute.Value);
892
893								var html = $this.formatAttributeValue(attribute, attribute.AttributeMetadata, j, record, data);
894								if (html.isHtml) {
895									$td.html(html.value);
896								} else {
897									$td.text(attribute.DisplayValue);
898								}
899
900								if (attribute.AttributeMetadata) {
901									$td.data("attribute-metadata", attribute.AttributeMetadata);
902								}
903								$tr.append($td);
904								found = true;
905								break;
906							}
907						}
908						if (!found) {
909							if (columns[j] == "col-action") {
910								var $actions = $("<td></td>");
911								var $dropdown = $("<div class='dropdown action'></div>");
912							    $("<a class='btn btn-default btn-xs'><span class='fa fa-chevron-circle-down'></span></a>")
913									.attr("href", "#")
914									.attr("data-toggle", "dropdown")
915                                    .attr("aria-label", window.ResourceManager['ActionLink_Aria_Label'])
916									.appendTo($dropdown);
917								var $dropdownMenu = $("<ul class='dropdown-menu' role='menu'></ul>");
918								// start - hack to fix an issue with table container's overflow scroll affecting dropdown menu
919								$dropdownMenu.css("position", "fixed").appendTo($dropdown);
920								$dropdown.on("show.bs.dropdown", function () {
921									var rect = $(this).get(0).getBoundingClientRect();
922									var $dropdownmenu = $(this).find(".dropdown-menu:first");
923									var docWidth = $(window).width();
924									var isDropdownMenuVisible = (rect.left + $dropdownmenu.outerWidth() <= docWidth);
925									if (isDropdownMenuVisible) {
926										$dropdownmenu.css("left", rect.left).css("top", rect.top + $(this).outerHeight());
927									} else {
928										$dropdownmenu.css("left", rect.left + rect.width - $dropdownmenu.outerWidth()).css("top", rect.top + $(this).outerHeight());
929									}
930								});
931								$(window).scroll(function () {
932									var $openDropdown = $element.find(".dropdown.action.open");
933									if ($openDropdown.length == 0) {
934										return;
935									}
936									$openDropdown.removeClass("open");
937								});
938								// end - hack
939								var iframed = inIframe();
940
941								// Check Item Actions Links for empty collection.
942								if (!layout.Configuration.ItemActionLinks) {
943									layout.Configuration.ItemActionLinks = layout.Configuration.CreateRelatedRecordActionLinks;
944								}
945
946								if (enableActions && layout.Configuration.ItemActionLinks && layout.Configuration.ItemActionLinks.length > 0) {
947
948									// Check for Create Related Record Links.
949									if (layout.Configuration.CreateRelatedRecordActionLinks && layout.Configuration.CreateRelatedRecordActionLinks.length > 0) {
950										// Add Create Related Record Action Links to Item Links.
951										for (var m = 0; m < layout.Configuration.CreateRelatedRecordActionLinks.length; m++) {
952											if ($.inArray(layout.Configuration.CreateRelatedRecordActionLinks[m], layout.Configuration.ItemActionLinks) < 0) {
953												layout.Configuration.ItemActionLinks.push(layout.Configuration.CreateRelatedRecordActionLinks[m]);
954											}
955										}
956									}
957
958									var actions = layout.Configuration.ItemActionLinks;
959
960									for (var l = 0; l < actions.length; l++) {
961										var action = actions[l];
962										// disable Action based On Filter Criteria
963										if (data.DisabledItemActionLinks) {
964											var result = data.DisabledItemActionLinks.filter(function (link) {
965												return link.EntityId == record.Id && link.LinkUniqueId == action.FilterCriteriaId;
966											});
967											if (result && result.length) {
968												continue;
969											}
970										}
971										switch (action.Type) {
972										case 1:
973											if (action.Enabled) {
974												var href = "#";
975												if ((action.Target == actionTargetWebPage || action.Target == actionTargetUrl) && action.URL != null) {
976													href = getUrlWithRelatedReference($element, URI(getUrlFromActionLink(action)).addSearch(action.QueryStringIdParameterName, record.Id.toString()));
977												}
978												var $li = $("<li role='presentation'></li>");
979												var $a = $("<a class='details-link' role='menuitem' tabindex='0'></a>").attr("href", href).attr("title", action.Tooltip).html(action.Label);
980												if (href != "#" && iframed) $a.attr("target", "_top");
981												if (action.Target == actionTargetEntityForm && action.EntityForm) {
982													$a.addClass("launch-modal").attr("data-entityformid", action.EntityForm.Id);
983												}
984												$li.append($a).appendTo($dropdownMenu);
985											}
986											break;
987										case 2:
988											if (action.Enabled && record.CanWrite) {
989												var hrefEdit = "#";
990												if ((action.Target == actionTargetWebPage || action.Target == actionTargetUrl) && action.URL != null) {
991													hrefEdit = getUrlWithRelatedReference($element, URI(getUrlFromActionLink(action)).addSearch(action.QueryStringIdParameterName, record.Id.toString()).toString());
992												}
993												var $liEdit = $("<li role='presentation'></li>");
994												var $aEdit = $("<a class='edit-link' role='menuitem' tabindex='0'></a>").attr("href", hrefEdit).attr("title", action.Tooltip).html(action.Label);
995												if (hrefEdit != "#" && iframed) $aEdit.attr("target", "_top");
996												if (action.Target == actionTargetEntityForm && action.EntityForm) {
997													$aEdit.addClass("launch-modal").attr("data-entityformid", action.EntityForm.Id);
998												}
999												$liEdit.append($aEdit).appendTo($dropdownMenu);
1000											}
1001											break;
1002										case 4:
1003											if (action.Enabled && record.CanDelete) {
1004												$("<li role='presentation'></li>")
1005													.append($("<a class='delete-link' role='menuitem' tabindex='0' href='#'></a>").attr("title", action.Tooltip).html(action.Label))
1006													.appendTo($dropdownMenu);
1007											}
1008											break;
1009										case 6:
1010											if (action.Enabled && record.CanAppend) {
1011												$("<li role='presentation'></li>")
1012													.append($("<a class='disassociate-link' role='menuitem' tabindex='0' href='#'></a>").attr("title", action.Tooltip).html(action.Label))
1013													.appendTo($dropdownMenu);
1014											}
1015											break;
1016										case 7:
1017											if (action.URL) {
1018												var workflowLink = $("<a class='workflow-link' role='menuitem' tabindex='0' href='#'></a>")
1019													.attr("title", action.Tooltip).attr("data-workflowid", action.Workflow.Id).attr("data-url", getUrlFromActionLink(action)).html(action.Label);
1020												if (action.CustomizeModal === true) {
1021													workflowLink.attr("data-modal-title", action.Modal.Title);
1022													workflowLink.attr("data-modal-confirmation", action.Confirmation);
1023													workflowLink.attr("data-modal-primary-action", action.Modal.PrimaryButtonText);
1024													workflowLink.attr("data-modal-canled-action", action.Modal.CloseButtonText);
1025												}
1026												$("<li role='presentation'></li>").append(workflowLink).appendTo($dropdownMenu);
1027											}
1028											break;
1029										case 9:
1030											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1031												$("<li role='presentation'></li>")
1032													.append($("<a class='close-case-link' role='menuitem' tabindex='0' href='#'></a>")
1033														.attr("data-url", getUrlFromActionLink(action))
1034														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1035														.attr("data-resolution", action.DefaultResolution)
1036														.attr("data-description", action.DefaultResolutionDescription)
1037														.attr("title", action.Tooltip).html(action.Label))
1038													.appendTo($dropdownMenu);
1039											}
1040											break;
1041										case 10:
1042											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1043												$("<li role='presentation'></li>")
1044													.append($("<a class='qualify-lead-link' role='menuitem' tabindex='0' href='#'></a>")
1045														.attr("data-url", getUrlFromActionLink(action))
1046														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1047														.attr("title", action.Tooltip).html(action.Label))
1048													.appendTo($dropdownMenu);
1049											}
1050											break;
1051										case 11:
1052											if (action.Enabled && record.CanWrite && record.StateCode == "1") {
1053												$("<li role='presentation'></li>")
1054													.append($("<a class='convert-quote-link' role='menuitem' tabindex='0' href='#'></a>")
1055														.attr("data-url", getUrlFromActionLink(action))
1056														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1057														.attr("title", action.Tooltip).html(action.Label))
1058													.appendTo($dropdownMenu);
1059											}
1060											break;
1061										case 12:
1062											if (action.Enabled && record.CanWrite && record.StateCode != "2") {
1063												$("<li role='presentation'></li>")
1064													.append($("<a class='convert-order-link' role='menuitem' tabindex='0' href='#'></a>")
1065														.attr("data-url", getUrlFromActionLink(action))
1066														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1067														.attr("title", action.Tooltip).html(action.Label))
1068													.appendTo($dropdownMenu);
1069											}
1070											break;
1071										case 13:
1072											if (action.Enabled && record.CanWrite) {
1073												$("<li role='presentation'></li>")
1074													.append($("<a class='calculate-opportunity-link' role='menuitem' tabindex='0' href='#'></a>")
1075														.attr("data-url", getUrlFromActionLink(action))
1076														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1077														.attr("title", action.Tooltip).html(action.Label))
1078													.appendTo($dropdownMenu);
1079											}
1080											break;
1081										case 14:
1082											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1083												$("<li role='presentation'></li>")
1084													.append($("<a class='resolve-case-link' role='menuitem' tabindex='0' href='#'></a>")
1085														.attr("data-url", getUrlFromActionLink(action))
1086														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1087														.attr("title", action.Tooltip).html(action.Label))
1088													.appendTo($dropdownMenu);
1089											}
1090											break;
1091										case 15:
1092											if (action.Enabled && record.CanWrite && record.StateCode != "0") {
1093												$("<li role='presentation'></li>")
1094													.append($("<a class='reopen-case-link' role='menuitem' tabindex='0' href='#'></a>")
1095														.attr("title", action.Tooltip).html(action.Label))
1096													.appendTo($dropdownMenu);
1097											}
1098											break;
1099										case 16:
1100											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1101												$("<li role='presentation'></li>")
1102													.append($("<a class='cancel-case-link' role='menuitem' tabindex='0' href='#'></a>")
1103														.attr("data-url", getUrlFromActionLink(action))
1104														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1105														.attr("title", action.Tooltip).html(action.Label))
1106													.appendTo($dropdownMenu);
1107											}
1108											break;
1109										case 17:
1110											if (action.Enabled && record.CanWrite && record.StateCode != "1") {
1111												$("<li role='presentation'></li>")
1112													.append($("<a class='deactivate-link' role='menuitem' tabindex='0' href='#'></a>")
1113														.attr("title", action.Tooltip).html(action.Label))
1114													.appendTo($dropdownMenu);
1115											}
1116											break;
1117										case 18:
1118											if (action.Enabled && record.CanWrite && record.StateCode != "0") {
1119												$("<li role='presentation'></li>")
1120													.append($("<a class='activate-link' role='menuitem' tabindex='0' href='#'></a>")
1121														.attr("title", action.Tooltip).html(action.Label))
1122													.appendTo($dropdownMenu);
1123											}
1124											break;
1125										case 19:
1126											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1127												$("<li role='presentation'></li>")
1128													.append($("<a class='activate-quote-link' role='menuitem' tabindex='0' href='#'></a>")
1129														.attr("title", action.Tooltip).html(action.Label))
1130													.appendTo($dropdownMenu);
1131											}
1132											break;
1133										case 20:
1134											if (action.Enabled && record.CanWrite && record.StateCode == "0" && record.StatusCode != "2") {
1135												$("<li role='presentation'></li>")
1136													.append($("<a class='set-opportunity-on-hold-link' role='menuitem' tabindex='0' href='#'></a>")
1137														.attr("title", action.Tooltip).html(action.Label))
1138													.appendTo($dropdownMenu);
1139											}
1140											break;
1141										case 21:
1142											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1143												$("<li role='presentation'></li>")
1144													.append($("<a class='win-opportunity-link' role='menuitem' tabindex='0' href='#'></a>")
1145														.attr("data-url", getUrlFromActionLink(action))
1146														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1147														.attr("title", action.Tooltip).html(action.Label))
1148													.appendTo($dropdownMenu);
1149											}
1150											break;
1151										case 22:
1152											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1153												$("<li role='presentation'></li>")
1154													.append($("<a class='lose-opportunity-link' role='menuitem' tabindex='0' href='#'></a>")
1155														.attr("data-url", getUrlFromActionLink(action))
1156														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1157														.attr("title", action.Tooltip).html(action.Label))
1158													.appendTo($dropdownMenu);
1159											}
1160											break;
1161										case 23:
1162											if (action.Enabled && record.CanWrite && record.StateCode == "0") {
1163												$("<li role='presentation'></li>")
1164													.append($("<a class='generate-quote-from-opportunity-link' role='menuitem' tabindex='0' href='#'></a>")
1165														.attr("data-url", getUrlFromActionLink(action))
1166														.attr("data-redirecturl", getRedirectUrlFromActionLink(action))
1167														.attr("title", action.Tooltip).html(action.Label))
1168													.appendTo($dropdownMenu);
1169											}
1170											break;
1171										case 25:
1172											if (action.Enabled && record.CanWrite && record.StateCode != "0") {
1173												$("<li role='presentation'></li>")
1174													.append($("<a class='reopen-opportunity-link' role='menuitem' tabindex='0' href='#'></a>")
1175														.attr("title", action.Tooltip).html(action.Label))
1176													.appendTo($dropdownMenu);
1177											}
1178											break;
1179										case 29:
1180											var state = $element.closest(".entity-form").find("[id$='_EntityState']").val();
1181											var isParentRecordInactive = typeof state != typeof undefined && state != null && state !== "" && state !== "0";
1182
1183											if (action.Enabled && record.CanWrite && !isParentRecordInactive) {
1184												var hrefCreate = "#";
1185												var self = this;
1186
1187												if ((action.Target === actionTargetWebPage || action.Target === actionTargetUrl) && action.URL !== null) {
1188													hrefCreate = getUrlWithRelatedReference($element, URI(getUrlFromActionLink(action)).addSearch(record.Id.toString()).toString());
1189												}
1190												var $liCreate = $("<li role='presentation'></li>");
1191												var $aCreate = $("<a class='create-related-record-link' role='menuitem' tabindex='0'></a>").attr("href", hrefCreate).attr("title", action.Tooltip).html(action.Label);
1192												if (hrefCreate !== "#" && iframed) $aCreate.attr("target", "_top");
1193												if (action.Target === actionTargetEntityForm && action.EntityForm) {
1194													$aCreate.addClass("launch-modal").attr("data-entityformid", action.EntityForm.Id).attr("data-relationship", action.Relationship).attr("data-filtercriteriaid", action.FilterCriteriaId);
1195													var modals = $element.children(".modal-form-createrecord");
1196													if (modals.length) {
1197														for (var a = 0, len = modals.length; a < len; a++) {
1198															var createModal = $(modals[a]);
1199															createModal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1200																var $iframe = $(this).find("iframe");
1201																$iframe.attr("src", "");
1202																self.createModal.trigger("focus");
1203															});
1204															createModal.on("click", function (e) {
1205																e.preventDefault();
1206																var iframe = self.createModal.find("iframe");
1207																var page = iframe.data("page");
1208																var recordId = self.record.Id.toString();
1209																var relationship = action.Relationship;
1210																var recordName = self.record.EntityName;
1211
1212
1213																var uri = page + "?id=" + recordId + "&languagecode=" + layout.Configuration.LanguageCode + "&relationship=" + "&entityformid=" + layout.Configuration.CreateRelatedRecordActionLink.EntityForm.Id;
1214
1215																var src = getUrlForCreateRelatedRecordAction(uri, recordName, recordId, relationship);
1216
1217																iframe.attr("src", src);
1218																iframe.on("load", function () {
1219																	self.createModal.find(".form-loading").hide();
1220																	self.createModal.find("iframe").contents().find("#EntityFormControl").show();
1221																});
1222																self.createModal.find(".form-loading").show();
1223																self.createModal.find("iframe").contents().find("#EntityFormControl").hide();
1224																self.createModal.modal();
1225															});
1226														}
1227														$liCreate.append($aCreate).appendTo($dropdownMenu);
1228														}
1229													}
1230											}
1231											break;
1232										}
1233									}
1234								}
1235								if ($dropdownMenu.children("li").length > 0) {
1236									$dropdown.find(".fa").addClass("fa-fw");
1237									$actions.append($dropdown);
1238								}
1239								$actions.appendTo($tr);
1240							} else {
1241								$tr.append("<td></td>");
1242							}
1243						}
1244					}
1245
1246					if (selectMode == "Multiple" || selectMode == "Single") {
1247						$tr.children("td:first").append("<span class='fa fa-fw'></span>");
1248					}
1249					if (selectMode == "Single") {
1250						if (!$element.data("selected") && i == 0) {
1251							$tr.children("td:first").find(".fa-fw").addClass("fa-check");
1252							$tr.addClass("selected").addClass("info").attr("aria-checked", true);
1253						} else if ($element.data("selected") === $tr.attr("data-id")) {
1254							$tr.children("td:first").find(".fa-fw").addClass("fa-check");
1255							$tr.addClass("selected").addClass("info").attr("aria-checked", true);
1256						}
1257					}
1258
1259					$tbody.append($tr);
1260				}
1261
1262				if (selectMode === "Single") {
1263					$tbody.attr("role", "radiogroup");
1264				}
1265
1266				$element.children(".view-grid").find("tbody").remove();
1267				$table.append($tbody.hide());
1268				$tbody.fadeIn();
1269				$this.initializePagination(data, callingElement);
1270				$this.addDetailsActionLinkClickEventHandlers();
1271				$this.addEditActionLinkClickEventHandlers();
1272				$this.addDeleteActionLinkClickEventHandlers();
1273				$this.addQualifyLeadActionLinkClickEventHandlers();
1274				$this.addCloseCaseActionLinkClickEventHandlers();
1275				$this.addResolveCaseActionLinkClickEventHandlers();
1276				$this.addReopenCaseActionLinkClickEventHandlers();
1277				$this.addCancelCaseActionLinkClickEventHandlers();
1278				$this.addConvertQuoteActionLinkClickEventHandlers();
1279				$this.addConvertOrderActionLinkClickEventHandlers();
1280				$this.addCalculateOpportunityActionLinkClickEventHandlers();
1281				$this.addActivateActionLinkClickEventHandlers();
1282				$this.addDeactivateActionLinkClickEventHandlers();
1283				$this.addActivateQuoteActionLinkClickEventHandlers();
1284				$this.addSetOpportunityOnHoldActionLinkClickEventHandlers();
1285				$this.addReopenOpportunityActionLinkClickEventHandlers();
1286				$this.addWinOpportunityActionLinkClickEventHandlers();
1287				$this.addLoseOpportunityActionLinkClickEventHandlers();
1288				$this.addGenerateQuoteFromOpportunityActionLinkClickEventHandlers();
1289				$this.addDisassociateActionLinkClickEventHandlers();
1290				$this.addWorkflowActionLinkClickEventHandlers();
1291				$this.addCreateRelatedRecordLinkEventHandler();
1292				handleMobileHeaders($table);
1293
1294				$element.trigger("loaded");
1295			},
1296			function (jqXhr, textStatus, errorThrown) {
1297				// fail
1298				$errorMessage.html($("<div class='alert alert-block alert-danger'></div>").html(errorThrown));
1299				$errorMessage.show().prop("aria-hidden", false);
1300			},
1301			function () {
1302				// always
1303				$loadingMessage.hide().prop("aria-hidden", true);
1304				if (processingRequest) {
1305				$table.find("th.sort-enabled a").removeAttr('disabled').css({ 'pointer-events': '', 'cursor': '' });
1306				processingRequest = false;
1307}
1308			}, entityName, entityId);
1309	}
1310
1311	entityGrid.prototype.getData = function (url, configuration, base64SecureConfiguration, sortExpression, filter, metaFilter, search, page, pageSize, applyRelatedRecordFilter, filterRelationshipName, filterEntityName, filterAttributeName, filterValue, done, fail, always, entityName, entityId) {
1312		done = $.isFunction(done) ? done : function () { };
1313		fail = $.isFunction(fail) ? fail : function () { };
1314		always = $.isFunction(always) ? always : function () { };
1315		if (!url || url == '') {
1316			always.call(this);
1317			fail.call(this, null, "error", window.ResourceManager['EntityGrid_Url_NotFound']);
1318			return;
1319		}
1320		if (!base64SecureConfiguration) {
1321			always.call(this);
1322			fail.call(this, null, "error", window.ResourceManager['Required_Secure_ViewConfiguration_Not_Provided']);
1323			return;
1324		}
1325		pageSize = pageSize || -1;
1326		var data = {};
1327		data.base64SecureConfiguration = base64SecureConfiguration;
1328		data.sortExpression = sortExpression;
1329		data.search = search;
1330		data.page = page;
1331		data.pageSize = pageSize;
1332		data.filter = filter;
1333		data.metaFilter = metaFilter;
1334		if (applyRelatedRecordFilter) {
1335			data.applyRelatedRecordFilter = applyRelatedRecordFilter;
1336			data.filterRelationshipName = filterRelationshipName;
1337			data.filterEntityName = filterEntityName;
1338			data.filterAttributeName = filterAttributeName;
1339			if (filterValue) {
1340				data.filterValue = filterValue;
1341			}
1342		}
1343		data.customParameters = getCustomParameters(configuration);
1344		data.entityName = entityName;
1345		data.entityId = entityId;
1346
1347		var jsonData = JSON.stringify(data);
1348	    shell.ajaxSafePost({
1349			type: 'POST',
1350			dataType: "json",
1351			contentType: 'application/json; charset=utf-8',
1352			url: url,
1353			data: jsonData,
1354			global: false
1355		})
1356			.done(done)
1357			.fail(fail)
1358			.always(always);
1359	}
1360
1361	entityGrid.prototype.formatAttributeValue = function (attribute, attributeMetadata, index, record, data) {
1362		if (!attribute) {
1363			return null;
1364		}
1365		var $this = this;
1366		var $element = $this._element;
1367		var layouts = $this._layouts;
1368		var layout = layouts[$this._activeLayoutIndex];
1369		var enableActions = $this._enableActions;
1370		var iframed = inIframe();
1371		var html = {};
1372		var buildDetailsLink = index == 0 && enableActions && layout.Configuration.DetailsActionLink.Enabled; // If first column and details link is enabled then cell needs to be made clickable
1373		switch (attribute.Type) {
1374		case "System.DateTime":
1375			var moment = window.moment;
1376			if (moment) {
1377				//convert to moment format
1378				var dateFormat = dateFormatConverter.convert($element.closest("[data-dateformat]").data("dateformat") || "M/d/yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
1379				var timeFormat = dateFormatConverter.convert($element.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
1380				var datetimeFormat = dateFormatConverter.convert($element.closest("[data-datetimeformat]").data("datetimeformat") || (dateFormat + " " + timeFormat), dateFormatConverter.dotNet, dateFormatConverter.momentJs);
1381
1382				var behavior = attribute.DateTimeBehavior.Value;
1383				var format = attribute.DateTimeFormat;
1384
1385				// https://www.w3schools.com/Tags/att_time_datetime.asp
1386				// https://msdn.microsoft.com/en-us/library/dn996866.aspx
1387				// https://technet.microsoft.com/en-us/library/dn946904.aspx
1388				var html5Spec_Date = "YYYY-MM-DD";
1389				var html5Spec_LocalDateTime = "YYYY-MM-DDTHH:mm:ssZ";
1390				var html5Spec_IndependentDateTime = "YYYY-MM-DDTHH:mm:ss";
1391
1392				var displayFormat;
1393				var jqueryDateAttrFormat;
1394
1395				if (format == "DateOnly") {
1396					jqueryDateAttrFormat = html5Spec_Date;
1397					displayFormat = dateFormat;
1398				} else if (behavior == "TimeZoneIndependent") {
1399					// DateTime
1400					jqueryDateAttrFormat = html5Spec_IndependentDateTime;
1401					displayFormat = datetimeFormat;
1402				} else {
1403					// DateTime UserLocal
1404					jqueryDateAttrFormat = html5Spec_LocalDateTime;
1405					displayFormat = datetimeFormat;
1406				}
1407
1408				var attributeAsMoment = behavior == "TimeZoneIndependent" || behavior == "DateOnly"
1409					? moment.utc(attribute.Value)
1410					: moment(attribute.Value);
1411
1412				html.value = $("<time></time>")
1413					.attr("datetime", attributeAsMoment.format(jqueryDateAttrFormat))
1414					.text(attributeAsMoment.format(displayFormat));
1415			} else {
1416				html.value = $("<time></time>")
1417					.attr("datetime", attribute.DisplayValue)
1418					.text(attribute.DisplayValue);
1419			}
1420
1421			html.isHtml = true;
1422			break;
1423		case "System.String":
1424			if (!buildDetailsLink && typeof attributeMetadata !== typeof undefined && attributeMetadata != null && typeof attributeMetadata.Format !== typeof undefined) {
1425				if (attributeMetadata.Format == 0) { // Email
1426					var hrefEmail = attribute.DisplayValue;
1427					if (hrefEmail && hrefEmail != '') {
1428						if (!hrefEmail.toLowerCase().startsWith("mailto")) {
1429							hrefEmail = "mailto:" + hrefEmail;
1430						}
1431					}
1432					html.value = $("<a></a>").attr("href", hrefEmail).text(attribute.DisplayValue);
1433					html.isHtml = true;
1434				} else if (attributeMetadata.Format == 3) { // Url
1435					var url = attribute.DisplayValue;
1436					if (url && url != '') {
1437						if (!url.toLowerCase().startsWith("http")) {
1438							url = "http://" + url;
1439						}
1440					}
1441					var $link = $("<a></a>");
1442					$link.attr("href", url).text(attribute.DisplayValue);
1443					if (iframed) $link.attr("target", "_top");
1444					html.value = $link;
1445					html.isHtml = true;
1446				} else if (attributeMetadata.Format == 4) { // Ticker Symbol
1447					var symbol = attribute.DisplayValue;
1448					if (symbol && symbol != '') {
1449						var tickerUrl = "http://go.microsoft.com/fwlink?linkid=8506&Symbol=" + encodeURIComponent(symbol.toUpperCase());
1450						var $tickerLink = $("<a></a>");
1451						$tickerLink.attr("href", tickerUrl).text(attribute.DisplayValue);
1452						if (iframed) $tickerLink.attr("target", "_top");
1453						html.value = $tickerLink;
1454						html.isHtml = true;
1455					}
1456				}
1457			} else {
1458				html.value = attribute.DisplayValue;
1459				html.isHtml = false;
1460			}
1461		break;
1462			default:
1463				html.value = attribute.DisplayValue;
1464				html.isHtml = false;
1465				break;
1466		}
1467
1468		if (buildDetailsLink) {
1469			var hrefDetails = "#";
1470			var actionLink;
1471			// Assign the active Edit ItemActionLink to the DetailsAction, fall back to DetailsActionLink in case active Edit ItemActionLink not available.
1472			if (!layout.Configuration.DetailsActionLink.EntityForm && layout.Configuration.DetailsActionLink.URL != null) {
1473				for (var l = 0; l < layout.Configuration.ItemActionLinks.length; l++) {
1474					var action = layout.Configuration.ItemActionLinks[l];
1475
1476					// disable Action based On Filter Criteria
1477					if (data.DisabledItemActionLinks) {
1478						var result = data.DisabledItemActionLinks.filter(function (link) {
1479							return link.EntityId == record.Id && link.LinkUniqueId == action.FilterCriteriaId;
1480						});
1481
1482						if (result && result.length) {
1483							continue;
1484						}
1485						else if (action.Type === 2) {
1486							var actionLinkURL = getUrlFromActionLink(action);
1487							if (actionLinkURL != null) {
1488								hrefDetails = URI(actionLinkURL).addSearch(action.QueryStringIdParameterName, record.Id.toString());
1489							}
1490							else {
1491								actionLink = action;
1492							}
1493							break;
1494						}
1495					}
1496				}
1497
1498				if (hrefDetails === "#") {
1499					hrefDetails = URI(getUrlFromActionLink(layout.Configuration.DetailsActionLink)).addSearch(layout.Configuration.DetailsActionLink.QueryStringIdParameterName, record.Id.toString());
1500				}
1501			}
1502			var $detailsLink = $("<a></a>").attr("href", hrefDetails).addClass("details-link").addClass("has-tooltip").attr("data-toggle", "tooltip").attr("title", layout.Configuration.DetailsActionLink.Tooltip).html(html.value);
1503			if (hrefDetails != "#" && iframed) $detailsLink.attr("target", "_top");
1504
1505			if (actionLink && actionLink.EntityForm != null) {
1506				$detailsLink.addClass("launch-modal").attr("data-entityformid", actionLink.EntityForm.Id);
1507			}
1508			else if (layout.Configuration.DetailsActionLink.EntityForm) {
1509				$detailsLink.addClass("launch-modal").attr("data-entityformid", layout.Configuration.DetailsActionLink.EntityForm.Id);
1510			}
1511			html.value = $detailsLink;
1512			html.isHtml = true;
1513		}
1514
1515		return html;
1516	}
1517
1518	entityGrid.prototype.addSortEventHandlers = function () {
1519		var $this = this;
1520		var $element = $this._element;
1521		var $table = $element.children(".view-grid").find("table");
1522
1523		$table.find("th.sort-enabled a").on("click", function (e) {
1524				e.preventDefault();
1525				if (!processingRequest) {
1526				$table.find("th.sort-enabled a").attr('disabled', 'disabled').css({ 'pointer-events': 'none', 'cursor': 'default' });
1527				processingRequest = true;
1528			}
1529			var $header = $(this).closest("th");
1530			$(this).find(".fa-arrow-down").remove();
1531			$(this).find(".fa-arrow-up").remove();
1532			$(this).find(".sort-hint").remove();
1533			var name = $header.data("sort-name");
1534			var dir = $header.data("sort-dir");
1535			if (typeof name === typeof undefined || name === false || name === null || name === '') {
1536				return;
1537			}
1538			if (typeof dir === typeof undefined || dir === false) {
1539				dir = "";
1540			}
1541			var sortExpression;
1542			if (dir == "ASC") {
1543				sortExpression = name + " DESC";
1544				$header.data("sort-dir", "DESC").removeClass("sort-asc").addClass("sort-desc");
1545				$header.attr("aria-sort", "descending");
1546				$(this).append(" ").append($("<span></span>").addClass("fa").addClass("fa-arrow-down")).append("<span class='sr-only sort-hint'>. " + window.ResourceManager['Sort_Ascending_Order'] + "</span>");;
1547			} else {
1548				sortExpression = name + " ASC";
1549				$header.data("sort-dir", "ASC").removeClass("sort-desc").addClass("sort-asc");
1550				$header.attr("aria-sort", "ascending");
1551				$(this).append(" ").append($("<span></span>").addClass("fa").addClass("fa-arrow-up")).append("<span class='sr-only sort-hint'>. " + window.ResourceManager['Sort_Descending_Order'] + "</span>");;
1552			}
1553			$header.addClass("sort");
1554			$table.data("sort-expression", sortExpression);
1555			$table.find("th.sort a").each(function () {
1556				var $column = $(this).closest("th");
1557				var columnName = $column.data("sort-name");
1558				if (typeof columnName === typeof undefined || columnName === false || columnName === null || columnName === '') {
1559					return;
1560				}
1561				if (columnName != name) {
1562					$(this).find(".fa-arrow-down").remove();
1563					$(this).find(".fa-arrow-up").remove();
1564					$column.removeClass("sort-asc").removeClass("sort-desc").removeClass("sort").data("sort-dir", "").removeAttr("aria-sort");
1565				}
1566			});
1567			$this.load(1);
1568		});
1569	}
1570
1571	function displaySuccessAlert(success, $element, autohide) {
1572		var $container = $(".notifications");
1573		if ($container.length == 0) {
1574			var $pageheader = $(".page-heading");
1575			if ($pageheader.length == 0) {
1576				$container = $("<div class='notifications'></div>").prependTo($("#content-container"));
1577			} else {
1578				$container = $("<div class='notifications'></div>").appendTo($pageheader);
1579			}
1580		}
1581		$container.find(".notification").slideUp().remove();
1582		if (typeof success !== typeof undefined && success !== false && success != null && success != '') {
1583			var $alert = $("<div class='notification alert alert-success success alert-dismissible' role='alert'><button type='button' class='close' data-dismiss='alert' aria-label='Close'><span aria-hidden='true'>&times;</span></button>" + success + "</div>")
1584				.on('closed.bs.alert', function () {
1585					if ($container.find(".notification").length == 0) $container.hide();
1586				}).prependTo($container);
1587			$container.show();
1588			$('html, body').animate({
1589				scrollTop: ($alert.offset().top - 20)
1590			}, 200);
1591			if (autohide) {
1592				setTimeout(function () {
1593					$alert.slideUp(100).remove();
1594					if ($container.find(".notification").length == 0) $container.hide();
1595				}, 5000);
1596			}
1597		}
1598	}
1599
1600	function onComplete($gridElement, action) {
1601
1602		if (typeof action == typeof undefined || action == null) {
1603			$gridElement.trigger("refresh");
1604			return;
1605		}
1606
1607		var onCompleteRefresh = 0;
1608		var onCompleteRedirectToWebPage = 1;
1609		var onCompleteRedirectToUrl = 2;
1610		var onCompleteRedirect = typeof action.OnComplete != typeof undefined && action.OnComplete != null && action.OnComplete != onCompleteRefresh;
1611
1612		if (onCompleteRedirect) {
1613			var redirectUrl = getRedirectUrl(action);
1614
1615			if (redirectUrl != null && redirectUrl != '') {
1616				redirect(redirectUrl);
1617			} else {
1618				$gridElement.trigger("refresh");
1619			}
1620		} else {
1621			$gridElement.trigger("refresh");
1622		}
1623	}
1624
1625	function getError(jqXhr) {
1626		var error = { Message: window.ResourceManager['UnKnown_Error_Occurred'] };
1627		if (jqXhr == null) return error;
1628		try {
1629			var contentType = jqXhr.getResponseHeader("content-type");
1630			if (contentType != null) {
1631				error = contentType.indexOf("json") > -1 ? $.parseJSON(jqXhr.responseText) : { Message: jqXhr.status, InnerError: { Message: jqXhr.statusText } };
1632			} else {
1633				error = { Message: jqXhr.statusText };
1634			}
1635		} catch (e) {
1636			error = { Message: e.message }
1637		}
1638		return error;
1639	}
1640
1641	entityGrid.prototype.addCreateRelatedRecordLinkEventHandler = function() {
1642		var $this = this;
1643		var $element = $this._element;
1644		var layouts = $this._layouts;
1645		var layout = layouts[$this._activeLayoutIndex];
1646		var enableActions = $this._enableActions;
1647		var $table = $element.children(".view-grid").find("table");
1648		if (!enableActions) {
1649			return;
1650		}
1651		$table.find(".create-related-record-link.launch-modal").on("click", function (e) {
1652			e.preventDefault();
1653			var link = $(this);
1654			var $tr = $(this).closest("tr");
1655
1656			// ID of source entity which is used to create related record.
1657			var refEntityId = $tr.data("id");
1658			// Relationship name for which new related record need to be created.
1659			var relationship = link.data("relationship");;
1660			// Logical name of source entity.
1661			var refEntityName = $tr.data("entity");
1662			var entityFormId = $(this).data("entityformid");
1663
1664			var $modal = $element.children(".modal-form-createrecord[data-filtercriteriaid='" + link.data("filtercriteriaid") + "']");
1665			var $iframe = $modal.find("iframe");
1666			var page = $iframe.data("page");
1667			
1668			if (!entityFormId) {
1669				return;
1670			}
1671
1672			var uri = page + "?id=" + refEntityId + "&entityformid=" + entityFormId + "&languagecode=" + layout.Configuration.LanguageCode;
1673
1674			var src = getUrlForCreateRelatedRecordAction(uri, refEntityName, refEntityId, relationship);
1675
1676			$iframe.attr("src", src);
1677			$iframe.on("load", function () {
1678				$modal.find(".form-loading").hide();
1679				$modal.find("iframe").contents().find("#EntityFormControl").show();
1680			});
1681			$modal.find(".form-loading").show();
1682			$modal.find("iframe").contents().find("#EntityFormControl").hide();
1683			$modal.on('show.bs.modal', function () {
1684				$modal.attr("aria-hidden", "false");
1685			});
1686			$modal.modal();
1687			$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1688				$modal.attr("aria-hidden", "true");
1689				link.closest(".action").children("a").trigger("focus");
1690			});
1691		});
1692	}
1693
1694	entityGrid.prototype.addDetailsActionLinkClickEventHandlers = function() {
1695		var $this = this;
1696		var $element = $this._element;
1697		var layouts = $this._layouts;
1698		var layout = layouts[$this._activeLayoutIndex];
1699		var enableActions = $this._enableActions;
1700		var $table = $element.children(".view-grid").find("table");
1701		if (!enableActions) {
1702			return;
1703		}
1704		$table.find(".details-link.launch-modal").on("click", function (e) {
1705			e.preventDefault();
1706			var link = $(this);
1707			var $tr = $(this).closest("tr");
1708			var id = $tr.data("id");
1709			var $modal = $element.children(".modal-form-details");
1710			var $iframe = $modal.find("iframe");
1711			var page = $iframe.data("page");
1712			var entityformid = $(this).data("entityformid");
1713			if (!entityformid) return;
1714			var src = getUrlWithRelatedReference($element, (page + "?id=" + id + "&entityformid=" + entityformid + "&languagecode=" + layout.Configuration.LanguageCode));
1715			$iframe.attr("src", src);
1716			$iframe.on("load", function () {
1717				$modal.find(".form-loading").hide();
1718				$modal.find("iframe").contents().find("#EntityFormControl").show();
1719			});
1720			$modal.find(".form-loading").show();
1721			$modal.find("iframe").contents().find("#EntityFormControl").hide();
1722			$modal.on('show.bs.modal', function () {
1723				$modal.attr("aria-hidden", "false");
1724			});
1725			$modal.modal();
1726			$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1727				$modal.attr("aria-hidden", "true");
1728				link.closest(".action").children("a").trigger("focus");
1729			});
1730		});
1731	}
1732
1733	entityGrid.prototype.addEditActionLinkClickEventHandlers = function () {
1734		var $this = this;
1735		var $element = $this._element;
1736		var layouts = $this._layouts;
1737		var layout = layouts[$this._activeLayoutIndex];
1738		var enableActions = $this._enableActions;
1739		var $table = $element.children(".view-grid").find("table");
1740		if (!enableActions) {
1741			return;
1742		}
1743		$table.find(".edit-link.launch-modal").on("click", function (e) {
1744			e.preventDefault();
1745			var link = $(this);
1746			var $tr = $(this).closest("tr");
1747			var id = $tr.data("id");
1748			var $modal = $element.children(".modal-form-edit");
1749			var $iframe = $modal.find("iframe");
1750			var page = $iframe.data("page");
1751			var entityformid = $(this).data("entityformid");
1752			if (!entityformid) return;
1753			var src = getUrlWithRelatedReference($element, (page + "?id=" + id + "&entityformid=" + entityformid + "&languagecode=" + layout.Configuration.LanguageCode));
1754			$iframe.attr("src", src);
1755			$iframe.on("load", function () {
1756				$modal.find(".form-loading").hide();
1757				$modal.find("iframe").contents().find("#EntityFormControl").show();
1758			});
1759			$modal.find(".form-loading").show();
1760			$modal.find("iframe").contents().find("#EntityFormControl").hide();
1761			$modal.modal();
1762			$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1763				link.closest(".action").children("a").trigger("focus");
1764			});
1765		});
1766	}
1767
1768	entityGrid.prototype.addDeleteActionLinkClickEventHandlers = function () {
1769		var $this = this;
1770		var $element = $this._element;
1771		var layouts = $this._layouts;
1772		var layout = layouts[$this._activeLayoutIndex];
1773		var enableActions = $this._enableActions;
1774		var $table = $element.children(".view-grid").find("table");
1775		if (!enableActions || !layout.Configuration.DeleteActionLink.Enabled && !layout.Configuration.DeleteActionLink.URL) {
1776			return;
1777		}
1778		var url = getUrlFromActionLink(layout.Configuration.DeleteActionLink);
1779		$table.find(".delete-link").on("click", function (e) {
1780			e.preventDefault();
1781			var link = $(this);
1782			var $tr = $(this).closest("tr");
1783			var id = $tr.data("id");
1784			var $modal = $element.children(".modal-delete");
1785			var $button = $modal.find("button.primary");
1786			$button.off("click");
1787			$button.on("click", function (ev) {
1788				ev.preventDefault();
1789				$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
1790				var entityReference = {};
1791				entityReference.LogicalName = layout.Configuration.EntityName;
1792				entityReference.Id = id;
1793				var data = JSON.stringify(entityReference);
1794			    shell.ajaxSafePost({
1795					type: "POST",
1796					contentType: "application/json",
1797					url: url,
1798					data: data
1799				}).done(function () {
1800					var rowCount = $element.children(".view-grid").find("tbody tr").length;
1801					if (rowCount == 1) {
1802						// we are deleting the last item of the page so we need to decrement the page number
1803						var $pagination = $element.children(".view-pagination");
1804						var page = $pagination.data("current-page");
1805						if (page > 1) {
1806							page--;
1807							$pagination.data("current-page", page);
1808						}
1809					}
1810					$modal.modal("hide");
1811					displaySuccessAlert(layout.Configuration.DeleteActionLink.SuccessMessage, $element, true);
1812					onComplete($element, layout.Configuration.DeleteActionLink);
1813				}).fail(function (jqXhr) {
1814					$modal.modal("hide");
1815					displayErrorAlert(getError(jqXhr), $element);
1816				}).always(function () {
1817					$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
1818				});
1819			});
1820			$modal.modal();
1821			$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1822				link.closest(".action").children("a").trigger("focus");
1823			});
1824		});
1825	}
1826
1827	entityGrid.prototype.addQualifyLeadActionLinkClickEventHandlers = function () {
1828		var $this = this;
1829		var $element = $this._element;
1830		var layouts = $this._layouts;
1831		var layout = layouts[$this._activeLayoutIndex];
1832		var enableActions = $this._enableActions;
1833		var $table = $element.children(".view-grid").find("table");
1834		if (!enableActions || !layout.Configuration.QualifyLeadActionLink.Enabled && !layout.Configuration.QualifyLeadActionLink.URL) {
1835			return;
1836		}
1837		var url = getUrlFromActionLink(layout.Configuration.QualifyLeadActionLink);
1838
1839		if (layout.Configuration.QualifyLeadActionLink.ShowModal == 1) {
1840			$table.find(".qualify-lead-link").on("click", function(e) {
1841				e.preventDefault();
1842				var link = $(this);
1843				var $tr = $(this).closest("tr");
1844				var id = $tr.data("id");
1845				var $modal = $element.children(".modal-qualify");
1846				var $button = $modal.find("button.primary");
1847				$button.off("click");
1848				$button.on("click", function(ev) {
1849					ev.preventDefault();
1850					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
1851					var data = {};
1852					data.createAccount = true;
1853					data.createContact = true;
1854					data.createOpportunity = true;
1855					var entityReference = {};
1856					entityReference.LogicalName = layout.Configuration.EntityName;
1857					entityReference.Id = id;
1858					data.entityReference = entityReference;
1859					var json = JSON.stringify(data);
1860				    shell.ajaxSafePost({
1861					    type: "POST",
1862					    contentType: "application/json",
1863					    url: url,
1864						data: json
1865					}).done(function() {
1866						$modal.modal("hide");
1867						displaySuccessAlert(layout.Configuration.QualifyLeadActionLink.SuccessMessage, $element, true);
1868						onComplete($element, layout.Configuration.QualifyLeadActionLink);
1869					}).fail(function(jqXhr) {
1870						$modal.modal("hide");
1871						displayErrorAlert(getError(jqXhr), $element);
1872					}).always(function() {
1873						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
1874					});
1875				});
1876				$modal.modal();
1877				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1878					link.closest(".action").children("a").trigger("focus");
1879				});
1880			});
1881		} else {
1882			$table.find(".qualify-lead-link").on("click", function (e) {
1883				e.preventDefault();
1884				var $tr = $(this).closest("tr");
1885				var id = $tr.data("id");
1886				var data = {};
1887				data.createAccount = true;
1888				data.createContact = true;
1889				data.createOpportunity = true;
1890				var entityReference = {};
1891				entityReference.LogicalName = layout.Configuration.EntityName;
1892				entityReference.Id = id;
1893				data.entityReference = entityReference;
1894				var json = JSON.stringify(data);
1895			    shell.ajaxSafePost({
1896				    type: "POST",
1897				    contentType: "application/json",
1898				    url: url,
1899					data: json
1900				}).done(function () {
1901					displaySuccessAlert(layout.Configuration.QualifyLeadActionLink.SuccessMessage, $element, true);
1902					onComplete($element, layout.Configuration.QualifyLeadActionLink);
1903				}).fail(function (jqXhr) {
1904					displayErrorAlert(getError(jqXhr), $element);
1905				}).always(function () { });
1906			});
1907		}
1908	}
1909
1910	entityGrid.prototype.addCloseCaseActionLinkClickEventHandlers = function () {
1911		var $this = this;
1912		var $element = $this._element;
1913		var layouts = $this._layouts;
1914		var layout = layouts[$this._activeLayoutIndex];
1915		var enableActions = $this._enableActions;
1916		var $table = $element.children(".view-grid").find("table");
1917		if (!enableActions || !layout.Configuration.CloseIncidentActionLink.Enabled && !layout.Configuration.CloseIncidentActionLink.URL) {
1918			return;
1919		}
1920		var url = getUrlFromActionLink(layout.Configuration.CloseIncidentActionLink);
1921
1922		if (layout.Configuration.CloseIncidentActionLink.ShowModal == 1) {
1923			$table.find(".close-case-link").on("click", function(e) {
1924				e.preventDefault();
1925				var link = $(this);
1926				var $tr = $(this).closest("tr");
1927				var id = $tr.data("id");
1928				var $modal = $element.children(".modal-closecase");
1929				var $button = $modal.find("button.primary");
1930				$button.off("click");
1931				$button.on("click", function(ev) {
1932					ev.preventDefault();
1933					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
1934					var data = {};
1935					var entityReference = {};
1936					entityReference.LogicalName = layout.Configuration.EntityName;
1937					entityReference.Id = id;
1938					data.entityReference = entityReference;
1939					var resolution = layout.Configuration.CloseIncidentActionLink.DefaultResolution;
1940					var description = layout.Configuration.CloseIncidentActionLink.DefaultResolutionDescription;
1941					data.resolutionSubject = resolution;
1942					data.resolutionDescription = description;
1943					var json = JSON.stringify(data);
1944				    shell.ajaxSafePost({
1945					    type: "POST",
1946					    contentType: "application/json",
1947					    url: url,
1948						data: json
1949					}).done(function() {
1950						$modal.modal("hide");
1951						displaySuccessAlert(layout.Configuration.CloseIncidentActionLink.SuccessMessage, $element, true);
1952						onComplete($element, layout.Configuration.CloseIncidentActionLink);
1953					}).fail(function(jqXhr) {
1954						$modal.modal("hide");
1955						displayErrorAlert(getError(jqXhr), $element);
1956					}).always(function() {
1957						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
1958					});
1959				});
1960				$modal.on('show.bs.modal', function () {
1961					$modal.attr("aria-hidden", "false");
1962				});
1963				$modal.modal();
1964				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
1965					$modal.attr("aria-hidden", "true");
1966					link.closest(".action").children("a").trigger("focus");
1967				});
1968			});
1969		} else {
1970			$table.find(".close-case-link").on("click", function (e) {
1971				e.preventDefault();
1972				var link = $(this);
1973				var $tr = $(this).closest("tr");
1974				var id = $tr.data("id");
1975				var data = {};
1976				var entityReference = {};
1977				entityReference.LogicalName = layout.Configuration.EntityName;
1978				entityReference.Id = id;
1979				data.entityReference = entityReference;
1980				var resolution = layout.Configuration.CloseIncidentActionLink.DefaultResolution;
1981				var description = layout.Configuration.CloseIncidentActionLink.DefaultResolutionDescription;
1982				data.resolutionSubject = resolution;
1983				data.resolutionDescription = description;
1984				var json = JSON.stringify(data);
1985			    shell.ajaxSafePost({
1986				    type: "POST",
1987				    contentType: "application/json",
1988				    url: url,
1989					data: json
1990				}).done(function () {
1991					displaySuccessAlert(layout.Configuration.CloseIncidentActionLink.SuccessMessage, $element, true);
1992					onComplete($element, layout.Configuration.CloseIncidentActionLink);
1993				}).fail(function (jqXhr) {
1994					displayErrorAlert(getError(jqXhr), $element);
1995				}).always(function () { });
1996			});
1997		}
1998	}
1999
2000	entityGrid.prototype.addConvertQuoteActionLinkClickEventHandlers = function () {
2001		var $this = this;
2002		var $element = $this._element;
2003		var layouts = $this._layouts;
2004		var layout = layouts[$this._activeLayoutIndex];
2005		var enableActions = $this._enableActions;
2006		var $table = $element.children(".view-grid").find("table");
2007		if (!enableActions || !layout.Configuration.ConvertQuoteToOrderActionLink.Enabled && !layout.Configuration.ConvertQuoteToOrderActionLink.URL) {
2008			return;
2009		}
2010		var url = getUrlFromActionLink(layout.Configuration.ConvertQuoteToOrderActionLink);
2011
2012		if (layout.Configuration.ConvertQuoteToOrderActionLink.ShowModal == 1) {
2013			$table.find(".convert-quote-link").on("click", function(e) {
2014				e.preventDefault();
2015				var link = $(this);
2016				var $tr = $(this).closest("tr");
2017				var id = $tr.data("id");
2018				var $modal = $element.children(".modal-convert-quote");
2019				var $button = $modal.find("button.primary");
2020				$button.off("click");
2021				$button.on("click", function(ev) {
2022					ev.preventDefault();
2023					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2024					var entityReference = {};
2025					entityReference.LogicalName = layout.Configuration.EntityName;
2026					entityReference.Id = id;
2027					var data = JSON.stringify(entityReference);
2028				    shell.ajaxSafePost({
2029					    type: "POST",
2030					    contentType: "application/json",
2031					    url: url,
2032						data: data
2033					}).done(function() {
2034						$modal.modal("hide");
2035						displaySuccessAlert(layout.Configuration.ConvertQuoteToOrderActionLink.SuccessMessage, $element, true);
2036						onComplete($element, layout.Configuration.ConvertQuoteToOrderActionLink);
2037					}).fail(function(jqXhr) {
2038						$modal.modal("hide");
2039						displayErrorAlert(getError(jqXhr), $element);
2040					}).always(function() {
2041						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2042					});
2043				});
2044				$modal.modal();
2045				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2046					link.closest(".action").children("a").trigger("focus");
2047				});
2048			});
2049		} else {
2050			$table.find(".convert-quote-link").on("click", function (e) {
2051				e.preventDefault();
2052				var $tr = $(this).closest("tr");
2053				var id = $tr.data("id");
2054				var entityReference = {};
2055				entityReference.LogicalName = layout.Configuration.EntityName;
2056				entityReference.Id = id;
2057				var data = JSON.stringify(entityReference);
2058			    shell.ajaxSafePost({
2059				    type: "POST",
2060				    contentType: "application/json",
2061				    url: url,
2062					data: data
2063				}).done(function () {
2064					displaySuccessAlert(layout.Configuration.ConvertQuoteToOrderActionLink.SuccessMessage, $element, true);
2065					onComplete($element, layout.Configuration.ConvertQuoteToOrderActionLink);
2066				}).fail(function (jqXhr) {
2067					displayErrorAlert(getError(jqXhr), $element);
2068				}).always(function () { });
2069			});
2070		}
2071	}
2072
2073	entityGrid.prototype.addConvertOrderActionLinkClickEventHandlers = function () {
2074		var $this = this;
2075		var $element = $this._element;
2076		var layouts = $this._layouts;
2077		var layout = layouts[$this._activeLayoutIndex];
2078		var enableActions = $this._enableActions;
2079		var $table = $element.children(".view-grid").find("table");
2080		if (!enableActions || !layout.Configuration.ConvertOrderToInvoiceActionLink.Enabled && !layout.Configuration.ConvertOrderToInvoiceActionLink.URL) {
2081			return;
2082		}
2083		var url = getUrlFromActionLink(layout.Configuration.ConvertOrderToInvoiceActionLink);
2084
2085		if (layout.Configuration.ConvertOrderToInvoiceActionLink.ShowModal == 1) {
2086			$table.find(".convert-order-link").on("click", function(e) {
2087				e.preventDefault();
2088				var link = $(this);
2089				var $tr = $(this).closest("tr");
2090				var id = $tr.data("id");
2091				var $modal = $element.children(".modal-convert-order");
2092				var $button = $modal.find("button.primary");
2093				$button.off("click");
2094				$button.on("click", function(ev) {
2095					ev.preventDefault();
2096					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2097					var entityReference = {};
2098					entityReference.LogicalName = layout.Configuration.EntityName;
2099					entityReference.Id = id;
2100					var data = JSON.stringify(entityReference);
2101				    shell.ajaxSafePost({
2102					    type: "POST",
2103					    contentType: "application/json",
2104					    url: url,
2105						data: data
2106					}).done(function() {
2107						$modal.modal("hide");
2108						displaySuccessAlert(layout.Configuration.ConvertOrderToInvoiceActionLink.SuccessMessage, $element, true);
2109						onComplete($element, layout.Configuration.ConvertOrderToInvoiceActionLink);
2110					}).fail(function(jqXhr) {
2111						$modal.modal("hide");
2112						displayErrorAlert(getError(jqXhr), $element);
2113					}).always(function() {
2114						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2115					});
2116				});
2117				$modal.modal();
2118				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2119					link.closest(".action").children("a").trigger("focus");
2120				});
2121			});
2122		} else {
2123			$table.find(".convert-order-link").on("click", function (e) {
2124				e.preventDefault();
2125				var $tr = $(this).closest("tr");
2126				var id = $tr.data("id");
2127					var entityReference = {};
2128					entityReference.LogicalName = layout.Configuration.EntityName;
2129					entityReference.Id = id;
2130					var data = JSON.stringify(entityReference);
2131			        shell.ajaxSafePost({
2132					    type: "POST",
2133					    contentType: "application/json",
2134					    url: url,
2135						data: data
2136					}).done(function () {
2137						displaySuccessAlert(layout.Configuration.ConvertOrderToInvoiceActionLink.SuccessMessage, $element, true);
2138						onComplete($element, layout.Configuration.ConvertOrderToInvoiceActionLink);
2139					}).fail(function (jqXhr) {
2140						displayErrorAlert(getError(jqXhr), $element);
2141					}).always(function () { });
2142			});
2143		}
2144	}
2145
2146	entityGrid.prototype.addCalculateOpportunityActionLinkClickEventHandlers = function () {
2147		var $this = this;
2148		var $element = $this._element;
2149		var layouts = $this._layouts;
2150		var layout = layouts[$this._activeLayoutIndex];
2151		var enableActions = $this._enableActions;
2152		var $table = $element.children(".view-grid").find("table");
2153		if (!enableActions || !layout.Configuration.CalculateOpportunityActionLink.Enabled && !layout.Configuration.CalculateOpportunityActionLink.URL) {
2154			return;
2155		}
2156		var url = getUrlFromActionLink(layout.Configuration.CalculateOpportunityActionLink);
2157
2158		if (layout.Configuration.CalculateOpportunityActionLink.ShowModal == 1) {
2159			$table.find(".calculate-opportunity-link").on("click", function(e) {
2160				e.preventDefault();
2161				var link = $(this);
2162				var $tr = $(this).closest("tr");
2163				var id = $tr.data("id");
2164				var $modal = $element.children(".modal-calculate");
2165				var $button = $modal.find("button.primary");
2166				$button.off("click");
2167				$button.on("click", function(ev) {
2168					ev.preventDefault();
2169					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2170					var entityReference = {};
2171					entityReference.LogicalName = layout.Configuration.EntityName;
2172					entityReference.Id = id;
2173					var data = JSON.stringify(entityReference);
2174				    shell.ajaxSafePost({
2175					    type: "POST",
2176					    contentType: "application/json",
2177					    url: url,
2178						data: data
2179					}).done(function() {
2180						$modal.modal("hide");
2181						displaySuccessAlert(layout.Configuration.CalculateOpportunityActionLink.SuccessMessage, $element, true);
2182						onComplete($element, layout.Configuration.CalculateOpportunityActionLink);
2183					}).fail(function(jqXhr) {
2184						$modal.modal("hide");
2185						displayErrorAlert(getError(jqXhr), $element);
2186					}).always(function() {
2187						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2188					});
2189				});
2190				$modal.modal();
2191				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2192					link.closest(".action").children("a").trigger("focus");
2193				});
2194			});
2195		} else {
2196			$table.find(".calculate-opportunity-link").on("click", function (e) {
2197				e.preventDefault();
2198				var $tr = $(this).closest("tr");
2199				var id = $tr.data("id");
2200				var entityReference = {};
2201				entityReference.LogicalName = layout.Configuration.EntityName;
2202				entityReference.Id = id;
2203				var data = JSON.stringify(entityReference);
2204			    shell.ajaxSafePost({
2205				    type: "POST",
2206				    contentType: "application/json",
2207				    url: url,
2208					data: data
2209				}).done(function () {
2210					displaySuccessAlert(layout.Configuration.CalculateOpportunityActionLink.SuccessMessage, $element, true);
2211					onComplete($element, layout.Configuration.CalculateOpportunityActionLink);
2212				}).fail(function (jqXhr) {
2213					displayErrorAlert(getError(jqXhr), $element);
2214				}).always(function () { });
2215			});
2216		}
2217	}
2218
2219	entityGrid.prototype.addResolveCaseActionLinkClickEventHandlers = function () {
2220		var $this = this;
2221		var $element = $this._element;
2222		var layouts = $this._layouts;
2223		var layout = layouts[$this._activeLayoutIndex];
2224		var enableActions = $this._enableActions;
2225		var $table = $element.children(".view-grid").find("table");
2226		if (!enableActions || !layout.Configuration.ResolveCaseActionLink.Enabled && !layout.Configuration.ResolveCaseActionLink.URL) {
2227			return;
2228		}
2229		var url = getUrlFromActionLink(layout.Configuration.ResolveCaseActionLink);
2230		var $modal = $element.children(".modal-resolvecase");
2231		$table.find(".resolve-case-link").on("click", function (e) {
2232			e.preventDefault();
2233			var link = $(this);
2234			var $tr = $(this).closest("tr");
2235			var id = $tr.data("id");
2236			var $button = $modal.find("button.primary");
2237			$button.off("click");
2238			$button.on("click", function (ev) {
2239				ev.preventDefault();
2240				$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2241				var data = {};
2242				var entityReference = {};
2243				entityReference.LogicalName = layout.Configuration.EntityName;
2244				entityReference.Id = id;
2245				data.entityReference = entityReference;
2246				var $resolution = $modal.find(".resolution-input");
2247				data.resolutionSubject = $resolution.val();
2248				var $resolutionDescription = $modal.find(".resolution-description-input");
2249				data.resolutionDescription = $resolutionDescription.val();
2250				var json = JSON.stringify(data);
2251			    shell.ajaxSafePost({
2252				    type: "POST",
2253				    contentType: "application/json",
2254				    url: url,
2255					data: json
2256				}).done(function () {
2257					$modal.modal("hide");
2258					displaySuccessAlert(layout.Configuration.ResolveCaseActionLink.SuccessMessage, $element, true);
2259					onComplete($element, layout.Configuration.ResolveCaseActionLink);
2260				}).fail(function (jqXhr) {
2261					$modal.modal("hide");
2262					displayErrorAlert(getError(jqXhr), $element);
2263				}).always(function () {
2264					$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2265				});
2266			});
2267			$modal.modal();
2268			$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2269				$modal.find(".resolution-input").val('');
2270				$modal.find(".resolution-description-input").val('');
2271				link.closest(".action").children("a").trigger("focus");
2272			});
2273		});
2274	}
2275
2276	entityGrid.prototype.addReopenCaseActionLinkClickEventHandlers = function () {
2277		var $this = this;
2278		var $element = $this._element;
2279		var layouts = $this._layouts;
2280		var layout = layouts[$this._activeLayoutIndex];
2281		var enableActions = $this._enableActions;
2282		var $table = $element.children(".view-grid").find("table");
2283		if (!enableActions || !layout.Configuration.ReopenCaseActionLink.Enabled && !layout.Configuration.ReopenCaseActionLink.URL) {
2284			return;
2285		}
2286		var url = getUrlFromActionLink(layout.Configuration.ReopenCaseActionLink);
2287
2288		if (layout.Configuration.ReopenCaseActionLink.ShowModal == 1) {
2289			$table.find(".reopen-case-link").on("click", function(e) {
2290				e.preventDefault();
2291				var link = $(this);
2292				var $tr = $(this).closest("tr");
2293				var id = $tr.data("id");
2294				var $modal = $element.children(".modal-reopencase");
2295				var $button = $modal.find("button.primary");
2296				$button.off("click");
2297				$button.on("click", function(ev) {
2298					ev.preventDefault();
2299					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2300					var entityReference = {};
2301					entityReference.LogicalName = layout.Configuration.EntityName;
2302					entityReference.Id = id;
2303					var data = JSON.stringify(entityReference);
2304				    shell.ajaxSafePost({
2305					    type: "POST",
2306					    contentType: "application/json",
2307					    url: url,
2308						data: data
2309					}).done(function() {
2310						$modal.modal("hide");
2311						displaySuccessAlert(layout.Configuration.ReopenCaseActionLink.SuccessMessage, $element, true);
2312						onComplete($element, layout.Configuration.ReopenCaseActionLink);
2313					}).fail(function(jqXhr) {
2314						$modal.modal("hide");
2315						displayErrorAlert(getError(jqXhr), $element);
2316					}).always(function() {
2317						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2318					});
2319				});
2320				$modal.modal();
2321				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2322					link.closest(".action").children("a").trigger("focus");
2323				});
2324			});
2325		} else {
2326			$table.find(".reopen-case-link").on("click", function (e) {
2327				e.preventDefault();
2328				var $tr = $(this).closest("tr");
2329				var id = $tr.data("id");
2330				var entityReference = {};
2331				entityReference.LogicalName = layout.Configuration.EntityName;
2332				entityReference.Id = id;
2333				var data = JSON.stringify(entityReference);
2334			    shell.ajaxSafePost({
2335				    type: "POST",
2336				    contentType: "application/json",
2337				    url: url,
2338					data: data
2339				}).done(function () {
2340					displaySuccessAlert(layout.Configuration.ReopenCaseActionLink.SuccessMessage, $element, true);
2341					onComplete($element, layout.Configuration.ReopenCaseActionLink);
2342				}).fail(function (jqXhr) {
2343					displayErrorAlert(getError(jqXhr), $element);
2344				}).always(function () { });
2345			});
2346		}
2347	}
2348
2349	entityGrid.prototype.addCancelCaseActionLinkClickEventHandlers = function () {
2350		var $this = this;
2351		var $element = $this._element;
2352		var layouts = $this._layouts;
2353		var layout = layouts[$this._activeLayoutIndex];
2354		var enableActions = $this._enableActions;
2355		var $table = $element.children(".view-grid").find("table");
2356		if (!enableActions || !layout.Configuration.CancelCaseActionLink.Enabled && !layout.Configuration.CancelCaseActionLink.URL) {
2357			return;
2358		}
2359		var url = getUrlFromActionLink(layout.Configuration.CancelCaseActionLink);
2360
2361		if (layout.Configuration.CancelCaseActionLink.ShowModal == 1) {
2362			$table.find(".cancel-case-link").on("click", function(e) {
2363				e.preventDefault();
2364				var link = $(this);
2365				var $tr = $(this).closest("tr");
2366				var id = $tr.data("id");
2367				var $modal = $element.children(".modal-cancelcase");
2368				var $button = $modal.find("button.primary");
2369				$button.off("click");
2370				$button.on("click", function(ev) {
2371					ev.preventDefault();
2372					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2373					var entityReference = {};
2374					entityReference.LogicalName = layout.Configuration.EntityName;
2375					entityReference.Id = id;
2376					var data = JSON.stringify(entityReference);
2377				    shell.ajaxSafePost({
2378					    type: "POST",
2379					    contentType: "application/json",
2380					    url: url,
2381						data: data
2382					}).done(function() {
2383						$modal.modal("hide");
2384						displaySuccessAlert(layout.Configuration.CancelCaseActionLink.SuccessMessage, $element, true);
2385						onComplete($element, layout.Configuration.CancelCaseActionLink);
2386					}).fail(function(jqXhr) {
2387						$modal.modal("hide");
2388						displayErrorAlert(getError(jqXhr), $element);
2389					}).always(function() {
2390						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2391					});
2392				});
2393				$modal.on('show.bs.modal', function () {
2394					$modal.attr("aria-hidden", "false");
2395				});
2396				$modal.modal();
2397				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2398					$modal.attr("aria-hidden", "true");
2399					link.closest(".action").children("a").trigger("focus");
2400				});
2401			});
2402		} else {
2403			$table.find(".cancel-case-link").on("click", function (e) {
2404				e.preventDefault();
2405				var $tr = $(this).closest("tr");
2406				var id = $tr.data("id");
2407				var entityReference = {};
2408				entityReference.LogicalName = layout.Configuration.EntityName;
2409				entityReference.Id = id;
2410				var data = JSON.stringify(entityReference);
2411			    shell.ajaxSafePost({
2412				    type: "POST",
2413				    contentType: "application/json",
2414				    url: url,
2415					data: data
2416				}).done(function () {
2417					displaySuccessAlert(layout.Configuration.CancelCaseActionLink.SuccessMessage, $element, true);
2418					onComplete($element, layout.Configuration.CancelCaseActionLink);
2419				}).fail(function (jqXhr) {
2420					displayErrorAlert(getError(jqXhr), $element);
2421				}).always(function () { });
2422			});
2423		}
2424	}
2425
2426	entityGrid.prototype.addActivateActionLinkClickEventHandlers = function () {
2427		var $this = this;
2428		var $element = $this._element;
2429		var layouts = $this._layouts;
2430		var layout = layouts[$this._activeLayoutIndex];
2431		var enableActions = $this._enableActions;
2432		var $table = $element.children(".view-grid").find("table");
2433		if (!enableActions || !layout.Configuration.ActivateActionLink.Enabled && !layout.Configuration.ActivateActionLink.URL) {
2434			return;
2435		}
2436		var url = getUrlFromActionLink(layout.Configuration.ActivateActionLink);
2437
2438		if (layout.Configuration.ActivateActionLink.ShowModal == 1) {
2439			$table.find(".activate-link").on("click", function(e) {
2440				e.preventDefault();
2441				var link = $(this);
2442				var $tr = $(this).closest("tr");
2443				var id = $tr.data("id");
2444				var $modal = $element.children(".modal-activate");
2445				var $button = $modal.find("button.primary");
2446				$button.off("click");
2447				$button.on("click", function(ev) {
2448					ev.preventDefault();
2449					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2450					var entityReference = {};
2451					entityReference.LogicalName = layout.Configuration.EntityName;
2452					entityReference.Id = id;
2453					var data = JSON.stringify(entityReference);
2454				    shell.ajaxSafePost({
2455					    type: "POST",
2456					    contentType: "application/json",
2457					    url: url,
2458						data: data
2459					}).done(function() {
2460						$modal.modal("hide");
2461						displaySuccessAlert(layout.Configuration.ActivateActionLink.SuccessMessage, $element, true);
2462						onComplete($element, layout.Configuration.ActivateActionLink);
2463					}).fail(function(jqXhr) {
2464						$modal.modal("hide");
2465						displayErrorAlert(getError(jqXhr), $element);
2466					}).always(function() {
2467						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2468					});
2469				});
2470				$modal.modal();
2471				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2472					link.closest(".action").children("a").trigger("focus");
2473				});
2474			});
2475		} else {
2476			$table.find(".activate-link").on("click", function (e) {
2477				e.preventDefault();
2478				var $tr = $(this).closest("tr");
2479				var id = $tr.data("id");
2480				var entityReference = {};
2481				entityReference.LogicalName = layout.Configuration.EntityName;
2482				entityReference.Id = id;
2483				var data = JSON.stringify(entityReference);
2484			    shell.ajaxSafePost({
2485				    type: "POST",
2486				    contentType: "application/json",
2487				    url: url,
2488					data: data
2489				}).done(function () {
2490					displaySuccessAlert(layout.Configuration.ActivateActionLink.SuccessMessage, $element, true);
2491					onComplete($element, layout.Configuration.ActivateActionLink);
2492				}).fail(function (jqXhr) {
2493					displayErrorAlert(getError(jqXhr), $element);
2494				});
2495			});
2496		}
2497	}
2498
2499	entityGrid.prototype.addDeactivateActionLinkClickEventHandlers = function () {
2500		var $this = this;
2501		var $element = $this._element;
2502		var layouts = $this._layouts;
2503		var layout = layouts[$this._activeLayoutIndex];
2504		var enableActions = $this._enableActions;
2505		var $table = $element.children(".view-grid").find("table");
2506		if (!enableActions || !layout.Configuration.DeactivateActionLink.Enabled && !layout.Configuration.DeactivateActionLink.URL) {
2507			return;
2508		}
2509		var url = getUrlFromActionLink(layout.Configuration.DeactivateActionLink);
2510
2511		if (layout.Configuration.DeactivateActionLink.ShowModal == 1) {
2512			$table.find(".deactivate-link").on("click", function(e) {
2513				e.preventDefault();
2514				var link = $(this);
2515				var $tr = $(this).closest("tr");
2516				var id = $tr.data("id");
2517				var $modal = $element.children(".modal-deactivate");
2518				var $button = $modal.find("button.primary");
2519				$button.off("click");
2520				$button.on("click", function(ev) {
2521					ev.preventDefault();
2522					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2523					var entityReference = {};
2524					entityReference.LogicalName = layout.Configuration.EntityName;
2525					entityReference.Id = id;
2526					var data = JSON.stringify(entityReference);
2527				    shell.ajaxSafePost({
2528					    type: "POST",
2529					    contentType: "application/json",
2530					    url: url,
2531						data: data
2532					}).done(function() {
2533						$modal.modal("hide");
2534						displaySuccessAlert(layout.Configuration.DeactivateActionLink.SuccessMessage, $element, true);
2535						onComplete($element, layout.Configuration.DeactivateActionLink);
2536					}).fail(function(jqXhr) {
2537						$modal.modal("hide");
2538						displayErrorAlert(getError(jqXhr), $element);
2539					}).always(function() {
2540						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2541					});
2542				});
2543				$modal.modal();
2544				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2545					link.closest(".action").children("a").trigger("focus");
2546				});
2547			});
2548		} else {
2549			$table.find(".deactivate-link").on("click", function (e) {
2550				e.preventDefault();
2551				var $tr = $(this).closest("tr");
2552				var id = $tr.data("id");
2553					var entityReference = {};
2554					entityReference.LogicalName = layout.Configuration.EntityName;
2555					entityReference.Id = id;
2556					var data = JSON.stringify(entityReference);
2557			        shell.ajaxSafePost({
2558					    type: "POST",
2559					    contentType: "application/json",
2560						url: url,
2561						data: data
2562					}).done(function () {
2563						displaySuccessAlert(layout.Configuration.DeactivateActionLink.SuccessMessage, $element, true);
2564						onComplete($element, layout.Configuration.DeactivateActionLink);
2565					}).fail(function (jqXhr) {
2566						displayErrorAlert(getError(jqXhr), $element);
2567					});
2568			});
2569		}
2570	}
2571
2572	entityGrid.prototype.addActivateQuoteActionLinkClickEventHandlers = function () {
2573		var $this = this;
2574		var $element = $this._element;
2575		var layouts = $this._layouts;
2576		var layout = layouts[$this._activeLayoutIndex];
2577		var enableActions = $this._enableActions;
2578		var $table = $element.children(".view-grid").find("table");
2579		if (!enableActions || !layout.Configuration.ActivateQuoteActionLink.Enabled && !layout.Configuration.ActivateQuoteActionLink.URL) {
2580			return;
2581		}
2582		var url = getUrlFromActionLink(layout.Configuration.ActivateQuoteActionLink);
2583
2584		if (layout.Configuration.ActivateQuoteActionLink.ShowModal == 1) {
2585			$table.find(".activate-quote-link").on("click", function(e) {
2586				e.preventDefault();
2587				var link = $(this);
2588				var $tr = $(this).closest("tr");
2589				var id = $tr.data("id");
2590				var $modal = $element.children(".modal-activate-quote");
2591				var $button = $modal.find("button.primary");
2592				$button.off("click");
2593				$button.on("click", function(ev) {
2594					ev.preventDefault();
2595					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2596					var entityReference = {};
2597					entityReference.LogicalName = layout.Configuration.EntityName;
2598					entityReference.Id = id;
2599					var data = JSON.stringify(entityReference);
2600				    shell.ajaxSafePost({
2601					    type: "POST",
2602					    contentType: "application/json",
2603					    url: url,
2604						data: data
2605					}).done(function() {
2606						$modal.modal("hide");
2607						displaySuccessAlert(layout.Configuration.ActivateQuoteActionLink.SuccessMessage, $element, true);
2608						onComplete($element, layout.Configuration.ActivateQuoteActionLin);
2609					}).fail(function(jqXhr) {
2610						$modal.modal("hide");
2611						displayErrorAlert(getError(jqXhr), $element);
2612					}).always(function() {
2613						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2614					});
2615				});
2616				$modal.modal();
2617				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2618					link.closest(".action").children("a").trigger("focus");
2619				});
2620			});
2621		} else {
2622			$table.find(".activate-quote-link").on("click", function (e) {
2623				e.preventDefault();
2624				var $tr = $(this).closest("tr");
2625				var id = $tr.data("id");
2626				var entityReference = {};
2627				entityReference.LogicalName = layout.Configuration.EntityName;
2628				entityReference.Id = id;
2629				var data = JSON.stringify(entityReference);
2630			    shell.ajaxSafePost({
2631				    type: "POST",
2632				    contentType: "application/json",
2633				    url: url,
2634					data: data
2635				}).done(function () {
2636					displaySuccessAlert(layout.Configuration.ActivateQuoteActionLink.SuccessMessage, $element, true);
2637					onComplete($element, layout.Configuration.ActivateQuoteActionLin);
2638				}).fail(function (jqXhr) {
2639					displayErrorAlert(getError(jqXhr), $element);
2640				});
2641			});
2642		}
2643	}
2644
2645	entityGrid.prototype.addSetOpportunityOnHoldActionLinkClickEventHandlers = function () {
2646		var $this = this;
2647		var $element = $this._element;
2648		var layouts = $this._layouts;
2649		var layout = layouts[$this._activeLayoutIndex];
2650		var enableActions = $this._enableActions;
2651		var $table = $element.children(".view-grid").find("table");
2652		if (!enableActions || !layout.Configuration.SetOpportunityOnHoldActionLink.Enabled && !layout.Configuration.SetOpportunityOnHoldActionLink.URL) {
2653			return;
2654		}
2655		var url = getUrlFromActionLink(layout.Configuration.SetOpportunityOnHoldActionLink);
2656
2657		if (layout.Configuration.SetOpportunityOnHoldActionLink.ShowModal == 1) {
2658			$table.find(".set-opportunity-on-hold-link").on("click", function(e) {
2659				e.preventDefault();
2660				var link = $(this);
2661				var $tr = $(this).closest("tr");
2662				var id = $tr.data("id");
2663				var $modal = $element.children(".modal-set-opportunity-on-hold");
2664				var $button = $modal.find("button.primary");
2665				$button.off("click");
2666				$button.on("click", function(ev) {
2667					ev.preventDefault();
2668					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2669					var entityReference = {};
2670					entityReference.LogicalName = layout.Configuration.EntityName;
2671					entityReference.Id = id;
2672					var data = JSON.stringify(entityReference);
2673				    shell.ajaxSafePost({
2674					    type: "POST",
2675					    contentType: "application/json",
2676					    url: url,
2677						data: data
2678					}).done(function() {
2679						$modal.modal("hide");
2680						displaySuccessAlert(layout.Configuration.SetOpportunityOnHoldActionLink.SuccessMessage, $element, true);
2681						onComplete($element, layout.Configuration.SetOpportunityOnHoldActionLink);
2682					}).fail(function(jqXhr) {
2683						$modal.modal("hide");
2684						displayErrorAlert(getError(jqXhr), $element);
2685					}).always(function() {
2686						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2687					});
2688				});
2689				$modal.modal();
2690				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2691					link.closest(".action").children("a").trigger("focus");
2692				});
2693			});
2694		} else {
2695			$table.find(".set-opportunity-on-hold-link").on("click", function (e) {
2696				e.preventDefault();
2697				var $tr = $(this).closest("tr");
2698				var id = $tr.data("id");
2699				var entityReference = {};
2700				entityReference.LogicalName = layout.Configuration.EntityName;
2701				entityReference.Id = id;
2702				var data = JSON.stringify(entityReference);
2703			    shell.ajaxSafePost({
2704				    type: "POST",
2705				    contentType: "application/json",
2706				    url: url,
2707					data: data
2708				}).done(function () {
2709					displaySuccessAlert(layout.Configuration.SetOpportunityOnHoldActionLink.SuccessMessage, $element, true);
2710					onComplete($element, layout.Configuration.SetOpportunityOnHoldActionLink);
2711				}).fail(function (jqXhr) {
2712					displayErrorAlert(getError(jqXhr), $element);
2713				});
2714			});
2715		}
2716	}
2717
2718	entityGrid.prototype.addReopenOpportunityActionLinkClickEventHandlers = function () {
2719		var $this = this;
2720		var $element = $this._element;
2721		var layouts = $this._layouts;
2722		var layout = layouts[$this._activeLayoutIndex];
2723		var enableActions = $this._enableActions;
2724		var $table = $element.children(".view-grid").find("table");
2725		if (!enableActions || !layout.Configuration.ReopenOpportunityActionLink.Enabled && !layout.Configuration.ReopenOpportunityActionLink.URL) {
2726			return;
2727		}
2728		var url = getUrlFromActionLink(layout.Configuration.ReopenOpportunityActionLink);
2729
2730		if (layout.Configuration.ReopenOpportunityActionLink.ShowModal == 1) {
2731			$table.find(".reopen-opportunity-link").on("click", function (e) {
2732				e.preventDefault();
2733				var link = $(this);
2734				var $tr = $(this).closest("tr");
2735				var id = $tr.data("id");
2736				var $modal = $element.children(".modal-reopen-opportunity");
2737				var $button = $modal.find("button.primary");
2738				$button.off("click");
2739				$button.on("click", function (ev) {
2740					ev.preventDefault();
2741					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2742					var entityReference = {};
2743					entityReference.LogicalName = layout.Configuration.EntityName;
2744					entityReference.Id = id;
2745					var data = JSON.stringify(entityReference);
2746				    shell.ajaxSafePost({
2747					    type: "POST",
2748					    contentType: "application/json",
2749					    url: url,
2750						data: data
2751					}).done(function () {
2752						$modal.modal("hide");
2753						displaySuccessAlert(layout.Configuration.ReopenOpportunityActionLink.SuccessMessage, $element, true);
2754						onComplete($element, layout.Configuration.ReopenOpportunityActionLink);
2755					}).fail(function (jqXhr) {
2756						$modal.modal("hide");
2757						displayErrorAlert(getError(jqXhr), $element);
2758					}).always(function () {
2759						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2760					});
2761				});
2762				$modal.modal();
2763				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2764					link.closest(".action").children("a").trigger("focus");
2765				});
2766			});
2767		} else {
2768			$table.find(".reopen-opportunity-link").on("click", function (e) {
2769				e.preventDefault();
2770				var $tr = $(this).closest("tr");
2771				var id = $tr.data("id");
2772				var entityReference = {};
2773				entityReference.LogicalName = layout.Configuration.EntityName;
2774				entityReference.Id = id;
2775				var data = JSON.stringify(entityReference);
2776			    shell.ajaxSafePost({
2777				    type: "POST",
2778				    contentType: "application/json",
2779				    url: url,
2780					data: data
2781				}).done(function () {
2782					displaySuccessAlert(layout.Configuration.ReopenOpportunityActionLink.SuccessMessage, $element, true);
2783					onComplete($element, layout.Configuration.ReopenOpportunityActionLink);
2784				}).fail(function (jqXhr) {
2785					displayErrorAlert(getError(jqXhr), $element);
2786				});
2787			});
2788		}
2789	}
2790
2791	entityGrid.prototype.addWinOpportunityActionLinkClickEventHandlers = function () {
2792		var $this = this;
2793		var $element = $this._element;
2794		var layouts = $this._layouts;
2795		var layout = layouts[$this._activeLayoutIndex];
2796		var enableActions = $this._enableActions;
2797		var $table = $element.children(".view-grid").find("table");
2798		if (!enableActions || !layout.Configuration.WinOpportunityActionLink.Enabled && !layout.Configuration.WinOpportunityActionLink.URL) {
2799			return;
2800		}
2801		var url = getUrlFromActionLink(layout.Configuration.WinOpportunityActionLink);
2802
2803		if (layout.Configuration.WinOpportunityActionLink.ShowModal == 1) {
2804			$table.find(".win-opportunity-link").on("click", function(e) {
2805				e.preventDefault();
2806				var link = $(this);
2807				var $tr = $(this).closest("tr");
2808				var id = $tr.data("id");
2809				var $modal = $element.children(".modal-win-opportunity");
2810				var $button = $modal.find("button.primary");
2811				$button.off("click");
2812				$button.on("click", function(ev) {
2813					ev.preventDefault();
2814					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2815					var entityReference = {};
2816					entityReference.LogicalName = layout.Configuration.EntityName;
2817					entityReference.Id = id;
2818					var data = JSON.stringify(entityReference);
2819				    shell.ajaxSafePost({
2820					    type: "POST",
2821					    contentType: "application/json",
2822					    url: url,
2823						data: data
2824					}).done(function() {
2825						$modal.modal("hide");
2826						displaySuccessAlert(layout.Configuration.WinOpportunityActionLink.SuccessMessage, $element, true);
2827						onComplete($element, layout.Configuration.WinOpportunityActionLink);
2828					}).fail(function(jqXhr) {
2829						$modal.modal("hide");
2830						displayErrorAlert(getError(jqXhr), $element);
2831					}).always(function() {
2832						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2833					});
2834				});
2835				$modal.on('show.bs.modal', function () {
2836					$modal.attr("aria-hidden", "false");
2837				});
2838				$modal.modal();
2839				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2840					$modal.attr("aria-hidden", "true");
2841					link.closest(".action").children("a").trigger("focus");
2842				});
2843			});
2844		} else {
2845			$table.find(".win-opportunity-link").on("click", function (e) {
2846				e.preventDefault();
2847				var $tr = $(this).closest("tr");
2848				var id = $tr.data("id");
2849				var entityReference = {};
2850				entityReference.LogicalName = layout.Configuration.EntityName;
2851				entityReference.Id = id;
2852				var data = JSON.stringify(entityReference);
2853			    shell.ajaxSafePost({
2854				    type: "POST",
2855				    contentType: "application/json",
2856				    url: url,
2857					data: data
2858				}).done(function () {
2859					displaySuccessAlert(layout.Configuration.WinOpportunityActionLink.SuccessMessage, $element, true);
2860					onComplete($element, layout.Configuration.WinOpportunityActionLink);
2861				}).fail(function (jqXhr) {
2862					displayErrorAlert(getError(jqXhr), $element);
2863				});
2864			});
2865		}
2866	}
2867
2868	entityGrid.prototype.addLoseOpportunityActionLinkClickEventHandlers = function () {
2869		var $this = this;
2870		var $element = $this._element;
2871		var layouts = $this._layouts;
2872		var layout = layouts[$this._activeLayoutIndex];
2873		var enableActions = $this._enableActions;
2874		var $table = $element.children(".view-grid").find("table");
2875		if (!enableActions || !layout.Configuration.LoseOpportunityActionLink.Enabled && !layout.Configuration.LoseOpportunityActionLink.URL) {
2876			return;
2877		}
2878		var url = getUrlFromActionLink(layout.Configuration.LoseOpportunityActionLink);
2879
2880		if (layout.Configuration.LoseOpportunityActionLink.ShowModal == 1) {
2881			$table.find(".lose-opportunity-link").on("click", function(e) {
2882				e.preventDefault();
2883				var link = $(this);
2884				var $tr = $(this).closest("tr");
2885				var id = $tr.data("id");
2886				var $modal = $element.children(".modal-lose-opportunity");
2887				var $button = $modal.find("button.primary");
2888				$button.off("click");
2889				$button.on("click", function(ev) {
2890					ev.preventDefault();
2891					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2892					var entityReference = {};
2893					entityReference.LogicalName = layout.Configuration.EntityName;
2894					entityReference.Id = id;
2895					var data = JSON.stringify(entityReference);
2896				    shell.ajaxSafePost({
2897					    type: "POST",
2898					    contentType: "application/json",
2899					    url: url,
2900						data: data
2901					}).done(function() {
2902						$modal.modal("hide");
2903						displaySuccessAlert(layout.Configuration.LoseOpportunityActionLink.SuccessMessage, $element, true);
2904						onComplete($element, layout.Configuration.LoseOpportunityActionLink);
2905					}).fail(function(jqXhr) {
2906						$modal.modal("hide");
2907						displayErrorAlert(getError(jqXhr), $element);
2908					}).always(function() {
2909						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2910					});
2911				});
2912				$modal.on('show.bs.modal', function () {
2913					$modal.attr("aria-hidden", "false");
2914				});
2915				$modal.modal();
2916				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2917					$modal.attr("aria-hidden", "true");
2918					link.closest(".action").children("a").trigger("focus");
2919				});
2920			});
2921		} else {
2922			$table.find(".lose-opportunity-link").on("click", function (e) {
2923				e.preventDefault();
2924				var $tr = $(this).closest("tr");
2925				var id = $tr.data("id");
2926				var entityReference = {};
2927				entityReference.LogicalName = layout.Configuration.EntityName;
2928				entityReference.Id = id;
2929				var data = JSON.stringify(entityReference);
2930			    shell.ajaxSafePost({
2931				    type: "POST",
2932				    contentType: "application/json",
2933				    url: url,
2934					data: data
2935				}).done(function () {
2936					displaySuccessAlert(layout.Configuration.LoseOpportunityActionLink.SuccessMessage, $element, true);
2937					onComplete($element, layout.Configuration.LoseOpportunityActionLink);
2938				}).fail(function (jqXhr) {
2939					displayErrorAlert(getError(jqXhr), $element);
2940				});
2941			});
2942		}
2943	}
2944
2945	entityGrid.prototype.addGenerateQuoteFromOpportunityActionLinkClickEventHandlers = function () {
2946		var $this = this;
2947		var $element = $this._element;
2948		var layouts = $this._layouts;
2949		var layout = layouts[$this._activeLayoutIndex];
2950		var enableActions = $this._enableActions;
2951		var $table = $element.children(".view-grid").find("table");
2952		if (!enableActions || !layout.Configuration.GenerateQuoteFromOpportunityActionLink.Enabled && !layout.Configuration.GenerateQuoteFromOpportunityActionLink.URL) {
2953			return;
2954		}
2955		var url = getUrlFromActionLink(layout.Configuration.GenerateQuoteFromOpportunityActionLink);
2956
2957		if (layout.Configuration.GenerateQuoteFromOpportunityActionLink.ShowModal == 1) {
2958			$table.find(".generate-quote-from-opportunity-link").on("click", function(e) {
2959				e.preventDefault();
2960				var link = $(this);
2961				var $tr = $(this).closest("tr");
2962				var id = $tr.data("id");
2963				var $modal = $element.children(".modal-generate-quote-from-opportunity");
2964				var $button = $modal.find("button.primary");
2965				$button.off("click");
2966				$button.on("click", function(ev) {
2967					ev.preventDefault();
2968					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
2969					var entityReference = {};
2970					entityReference.LogicalName = layout.Configuration.EntityName;
2971					entityReference.Id = id;
2972					var data = JSON.stringify(entityReference);
2973				    shell.ajaxSafePost({
2974					    type: "POST",
2975					    contentType: "application/json",
2976					    url: url,
2977						data: data
2978					}).done(function () {
2979						$modal.modal("hide");
2980						displaySuccessAlert(layout.Configuration.GenerateQuoteFromOpportunityActionLink.SuccessMessage, $element, true);
2981						onComplete($element, layout.Configuration.GenerateQuoteFromOpportunityActionLink);
2982					}).fail(function(jqXhr) {
2983						$modal.modal("hide");
2984						displayErrorAlert(getError(jqXhr), $element);
2985					}).always(function() {
2986						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
2987					});
2988				});
2989				$modal.modal();
2990				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
2991					link.closest(".action").children("a").trigger("focus");
2992				});
2993			});
2994		} else {
2995			$table.find(".generate-quote-from-opportunity-link").on("click", function (e) {
2996				e.preventDefault();
2997				var $tr = $(this).closest("tr");
2998				var id = $tr.data("id");
2999				var entityReference = {};
3000				entityReference.LogicalName = layout.Configuration.EntityName;
3001				entityReference.Id = id;
3002				var data = JSON.stringify(entityReference);
3003			    shell.ajaxSafePost({
3004				    type: "POST",
3005				    contentType: "application/json",
3006				    url: url,
3007					data: data
3008				}).done(function () {
3009					displaySuccessAlert(layout.Configuration.GenerateQuoteFromOpportunityActionLink.SuccessMessage, $element, true);
3010					onComplete($element, layout.Configuration.GenerateQuoteFromOpportunityActionLink);
3011				}).fail(function (jqXhr) {
3012					displayErrorAlert(getError(jqXhr), $element);
3013				});
3014			});
3015		}
3016	}
3017
3018	entityGrid.prototype.addDisassociateActionLinkClickEventHandlers = function () {
3019		var $this = this;
3020		var $element = $this._element;
3021		var layouts = $this._layouts;
3022		var layout = layouts[$this._activeLayoutIndex];
3023		var enableActions = $this._enableActions;
3024		var $table = $element.children(".view-grid").find("table");
3025		if (!enableActions || !layout.Configuration.DisassociateActionLink.Enabled || !layout.Configuration.DisassociateActionLink.URL) {
3026			return;
3027		}
3028		var url = getUrlFromActionLink(layout.Configuration.DisassociateActionLink);
3029		if (layout.Configuration.DisassociateActionLink.ShowModal == 1) {
3030			$table.find(".disassociate-link").on("click", function (e) {
3031				e.preventDefault();
3032				var link = $(this);
3033				var $tr = $(this).closest("tr");
3034				var id = $tr.data("id");
3035				var $modal = $element.children(".modal-disassociate");
3036				var $button = $modal.find("button.primary");
3037				$button.off("click");
3038				$button.on("click", function(ev) {
3039					ev.preventDefault();
3040					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
3041					var refEntityName = $element.data("ref-entity");
3042					var refEntityId = $element.data("ref-id");
3043					var refRelationship = $element.data("ref-rel");
3044					var refRelationshipRole = $element.data("ref-rel-role");
3045					if (!refEntityName || !refEntityId || !refRelationship) {
3046						return;
3047					}
3048					var target = { LogicalName: refEntityName, Id: refEntityId };
3049					var relationship = { SchemaName: refRelationship };
3050					if (refRelationshipRole) {
3051						relationship.PrimaryEntityRole = refRelationshipRole;
3052					}
3053					var entityReference = {};
3054					entityReference.LogicalName = layout.Configuration.EntityName;
3055					entityReference.Id = id;
3056					var relatedEntities = [];
3057					relatedEntities[0] = entityReference;
3058					var disassociateRequest = {};
3059					disassociateRequest.target = target;
3060					disassociateRequest.RelatedEntities = relatedEntities;
3061					disassociateRequest.Relationship = relationship;
3062					var data = JSON.stringify(disassociateRequest);
3063				    shell.ajaxSafePost({
3064					    type: "POST",
3065					    contentType: "application/json",
3066					    url: url,
3067						data: data
3068					}).done(function () {
3069						$modal.modal("hide");
3070						displaySuccessAlert(layout.Configuration.DisassociateActionLink.SuccessMessage, $element, true);
3071						onComplete($element, layout.Configuration.DisassociateActionLink);
3072					}).fail(function (jqXhr) {
3073						$modal.modal("hide");
3074						displayErrorAlert(getError(jqXhr), $element);
3075					}).always(function() {
3076						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
3077					});
3078				});
3079				$modal.on('show.bs.modal', function () {
3080					$modal.attr("aria-hidden", "false");
3081				});
3082				$modal.modal();
3083				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
3084					$modal.attr("aria-hidden", "true");
3085					link.closest(".action").children("a").trigger("focus");
3086				});
3087			});
3088		} else {
3089			$table.find(".disassociate-link").on("click", function(e) {
3090				e.preventDefault();
3091				var link = $(this);
3092				var $tr = $(this).closest("tr");
3093				var id = $tr.data("id");
3094				var refEntityName = $element.data("ref-entity");
3095				var refEntityId = $element.data("ref-id");
3096				var refRelationship = $element.data("ref-rel");
3097				var refRelationshipRole = $element.data("ref-rel-role");
3098				if (!refEntityName || !refEntityId || !refRelationship) {
3099					return;
3100				}
3101				var target = { LogicalName: refEntityName, Id: refEntityId };
3102				var relationship = { SchemaName: refRelationship };
3103				if (refRelationshipRole) {
3104					relationship.PrimaryEntityRole = refRelationshipRole;
3105				}
3106				var entityReference = {};
3107				entityReference.LogicalName = layout.Configuration.EntityName;
3108				entityReference.Id = id;
3109				var relatedEntities = [];
3110				relatedEntities[0] = entityReference;
3111				var disassociateRequest = {};
3112				disassociateRequest.target = target;
3113				disassociateRequest.RelatedEntities = relatedEntities;
3114				disassociateRequest.Relationship = relationship;
3115				var data = JSON.stringify(disassociateRequest);
3116			    shell.ajaxSafePost({
3117				    type: "POST",
3118				    contentType: "application/json",
3119				    url: url,
3120					data: data
3121				}).done(function() {
3122					displaySuccessAlert(layout.Configuration.DisassociateActionLink.SuccessMessage, $element, true);
3123					onComplete($element, layout.Configuration.DisassociateActionLink);
3124				}).fail(function(jqXhr) {
3125					displayErrorAlert(getError(jqXhr), $element);
3126				});
3127			});
3128		}
3129	}
3130
3131	entityGrid.prototype.addWorkflowActionLinkClickEventHandlers = function () {
3132		var $this = this;
3133		var $element = $this._element;
3134		var layouts = $this._layouts;
3135		var layout = layouts[$this._activeLayoutIndex];
3136		var enableActions = $this._enableActions;
3137		var $table = $element.children(".view-grid").find("table");
3138		if (!enableActions || !layout.Configuration.ItemActionLinks || layout.Configuration.ItemActionLinks.length == 0) {
3139			return;
3140		}
3141		var actionLink = null;
3142		for (var i = 0; i < layout.Configuration.ItemActionLinks.length; i++) {
3143			var item = layout.Configuration.ItemActionLinks[i];
3144			if (item != null && typeof item.Type !== typeof undefined && item.Type == 7 && typeof item.Workflow !== typeof undefined && item.Workflow != null) {
3145				actionLink = item;
3146				break;
3147			}
3148		}
3149		if (actionLink == null) return;
3150		if (actionLink.ShowModal == 1) {
3151			$table.find(".workflow-link").on("click", function (e) {
3152				e.preventDefault();
3153				var link = $(this);
3154				var $tr = $(this).closest("tr");
3155				var id = $tr.data("id");
3156				var workflowid = $(this).data("workflowid");
3157				var $modal = $element.children(".modal-run-workflow");
3158				var $button = $modal.find("button.primary");
3159				var url = $(this).data("url");
3160				if (!workflowid || !url) {
3161					return;
3162				}
3163				var modalTitle = $(this).data("modal-title");
3164				if (modalTitle) {
3165					$modal.find(".modal-title").html(modalTitle);
3166				}
3167				var modalConfirmation = $(this).data("modal-confirmation");
3168				if (modalConfirmation) {
3169					$modal.find(".modal-body").html(modalConfirmation);
3170				}
3171				var modalPrimaryAction = $(this).data("modal-primary-action");
3172				if (modalPrimaryAction) {
3173					$button.html(modalPrimaryAction);
3174					$button.attr('title', modalPrimaryAction);
3175					$button.attr('aria-label', modalPrimaryAction);
3176				}
3177				var modalCancelAction = $(this).data("modal-cancel-action");
3178				if (modalCancelAction) {
3179					$modal.find(".cancel").html(modalCancelAction);
3180				}
3181				$button.off("click");
3182				$button.on("click", function(ev) {
3183					ev.preventDefault();
3184					$(this).attr("disabled", "disabled").prepend("<span class='fa fa-spinner fa-spin' aria-hidden='true'></span>");
3185					var workflowActionLink = null;
3186					for (var j = 0; j < layout.Configuration.ItemActionLinks.length; j++) {
3187						var action = layout.Configuration.ItemActionLinks[j];
3188						if (action != null && typeof action.Type !== typeof undefined && action.Type == 7 && typeof action.Workflow !== typeof undefined && action.Workflow != null && action.Workflow.Id == workflowid) {
3189							workflowActionLink = action;
3190							break;
3191						}
3192					}
3193					var data = {};
3194					var workflowReference = {};
3195					workflowReference.LogicalName = "workflow";
3196					workflowReference.Id = workflowid;
3197					data.workflow = workflowReference;
3198					var entityReference = {};
3199					entityReference.LogicalName = layout.Configuration.EntityName;
3200					entityReference.Id = id;
3201					data.entity = entityReference;
3202					var json = JSON.stringify(data);
3203				    shell.ajaxSafePost({
3204					    type: "POST",
3205					    contentType: "application/json",
3206					    url: url,
3207						data: json
3208					}).done(function() {
3209						$modal.modal("hide");
3210						displaySuccessAlert(workflowActionLink != null ? workflowActionLink.SuccessMessage : null, $element, true);
3211						onComplete($element, workflowActionLink);
3212					}).fail(function(jqXhr) {
3213						$modal.modal("hide");
3214						displayErrorAlert(getError(jqXhr), $element);
3215					}).always(function() {
3216						$button.removeAttr("disabled", "disabled").find(".fa-spin").remove();
3217					});
3218				});
3219				$modal.on('show.bs.modal', function () {
3220					$modal.attr("aria-hidden", "false");
3221				});
3222				$modal.modal();
3223				$modal.off("hidden.bs.modal.entitygrid").on("hidden.bs.modal.entitygrid", function () {
3224					$modal.attr("aria-hidden", "true");
3225					link.closest(".action").children("a").trigger("focus");
3226				});
3227			});
3228		} else {
3229			$table.find(".workflow-link").on("click", function(e) {
3230				e.preventDefault();
3231				var $tr = $(this).closest("tr");
3232				var id = $tr.data("id");
3233				var workflowid = $(this).data("workflowid");
3234				var url = $(this).data("url");
3235				if (!workflowid || !url) {
3236					return;
3237				}
3238				var workflowActionLink = null;
3239				for (var j = 0; j < layout.Configuration.ItemActionLinks.length; j++) {
3240					var action = layout.Configuration.ItemActionLinks[j];
3241					if (action != null && typeof action.Type !== typeof undefined && action.Type == 7 && typeof action.Workflow !== typeof undefined && action.Workflow != null && action.Workflow.Id == workflowid) {
3242						workflowActionLink = action;
3243						break;
3244					}
3245				}
3246				var data = {};
3247				var workflowReference = {};
3248				workflowReference.LogicalName = "workflow";
3249				workflowReference.Id = workflowid;
3250				data.workflow = workflowReference;
3251				var entityReference = {};
3252				entityReference.LogicalName = layout.Configuration.EntityName;
3253				entityReference.Id = id;
3254				data.entity = entityReference;
3255				var json = JSON.stringify(data);
3256			    shell.ajaxSafePost({
3257				    type: "POST",
3258				    contentType: "application/json",
3259				    url: url,
3260					data: json
3261				}).done(function() {
3262					displaySuccessAlert(workflowActionLink != null ? workflowActionLink.SuccessMessage : null, $element, true);
3263					onComplete($element, workflowActionLink);
3264				}).fail(function(jqXhr) {
3265					displayErrorAlert(getError(jqXhr), $element);
3266				});
3267			});
3268		}
3269	}
3270
3271	entityGrid.prototype.initializePagination = function (data, currentTarget) {
3272		// requires ~/js/jquery.bootstrap-pagination.js
3273
3274		var $this = this;
3275		var $element = $this._element;
3276		var $pagination = $element.children(".view-pagination");
3277
3278		if (typeof data === typeof undefined || data === false || data == null) {
3279			$pagination.hide();
3280			return;
3281		}
3282
3283		if ((typeof data.PageSize === typeof undefined || data.PageSize === false || data.PageSize == null) ||
3284		(typeof data.PageCount === typeof undefined || data.PageCount === false || data.PageCount == null) ||
3285		(typeof data.PageNumber === typeof undefined || data.PageNumber === false || data.PageNumber == null) ||
3286		(typeof data.ItemCount === typeof undefined || data.ItemCount === false || data.ItemCount == null)) {
3287			$pagination.hide();
3288			return;
3289		}
3290
3291		if (data.ItemCount === -1) {
3292			$this.initializePager($pagination, data, currentTarget);
3293			return;
3294		}
3295		
3296		if (data.PageCount <= 1) {
3297			$pagination.hide();
3298			return;
3299		}
3300
3301		$pagination
3302			.data("pagesize", data.PageSize)
3303			.data("pages", data.PageCount)
3304			.data("current-page", data.PageNumber)
3305			.data("count", data.ItemCount)
3306			.off("click")
3307			.pagination({
3308				total_pages: $pagination.data("pages"),
3309				current_page: $pagination.data("current-page"),
3310				callback: function (event, pg) {
3311					event.preventDefault();
3312					var $li = $(event.target).closest("li");
3313					if ($li.not(".disabled").length > 0 && $li.not(".active").length > 0) {
3314						var filter = $this.getCurrentFilter();
3315						$this.load(pg, filter, !$this.isRelatedRecordFilterEnabled(), event.currentTarget);
3316					}
3317				}
3318			})
3319			.show();
3320
3321		$element.children(".view-grid").addClass("has-pagination");
3322
3323		if (currentTarget) {
3324			$pagination.find("a").filter(function() {
3325				return $(this).text() == $(currentTarget).text();
3326			}).trigger("focus");
3327		}
3328	}
3329
3330	entityGrid.prototype.hidePagination = function () {
3331		this._element.children(".view-pagination").hide();
3332		this._element.children(".view-grid").removeClass("has-pagination");
3333	}
3334
3335	entityGrid.prototype.initializePager = function ($pagination, data, currentTarget) {
3336		var $this = this;
3337		var $element = $this._element;
3338
3339		var firstLabel = window.ResourceManager['Pagination_First_Page'];
3340		var $firstLink = $("<a>").attr("href", "#").data('page', 1)
3341			.attr("aria-label", firstLabel)
3342			.attr("title", firstLabel)
3343			.text("|<");
3344		var $first = $("<li>").append($firstLink);
3345
3346		var previousLabel = window.ResourceManager['Pagination_Previous_Page'];
3347		var $previousLink = $("<a>").attr("href", "#")
3348			.attr("aria-label", previousLabel)
3349			.attr("title", previousLabel)
3350			.text("<");
3351		var $previous = $("<li>").append($previousLink);
3352
3353		var $current = $("<li>").addClass("active").append($("<span>").text(data.PageNumber));
3354
3355		var nextLabel = window.ResourceManager['Pagination_Next_Page'];
3356		var $nextLink = $("<a>").attr("href", "#")
3357			.attr("aria-label", nextLabel)
3358			.attr("title", nextLabel)
3359			.text(">");
3360		var $next = $("<li>").append($nextLink);
3361
3362		var $pager = $("<ul>").addClass("pagination")
3363			.append($first)
3364			.append($previous)
3365			.append($current)
3366			.append($next);
3367
3368		$pagination.empty();
3369
3370		if (data.PageNumber === 1 && !data.MoreRecords) {
3371			$pagination.hide();
3372			return;
3373		}
3374
3375		if (data.PageNumber > 1) {
3376			$previousLink.data("page", data.PageNumber - 1);
3377		} else {
3378			$first.addClass("disabled");
3379			$firstLink.attr("aria-disabled", true);
3380			$previous.addClass("disabled");
3381			$previousLink.attr("aria-disabled", true);
3382		}
3383
3384		if (data.MoreRecords) {
3385			$nextLink.data("page", data.PageNumber + 1);
3386		} else {
3387			$next.addClass("disabled");
3388			$nextLink.attr("aria-disabled", true);
3389		}
3390
3391		$pagination
3392			.data("pagesize", data.PageSize)
3393			.data("current-page", data.PageNumber)
3394			.data("more-records", data.MoreRecords)
3395			.off('click')
3396			.append($pager)
3397			.on('click', 'a', function (event) {
3398				event.preventDefault();
3399				var $a = $(event.target);
3400				var page = $a.data("page");
3401				var $li = $a.closest("li");
3402				if ($li.not(".disabled").length > 0 && $li.not(".active").length > 0) {
3403					var filter = $this.getCurrentFilter();
3404					$this.load(page, filter, !$this.isRelatedRecordFilterEnabled(), event.currentTarget);
3405				}
3406			})
3407			.show();
3408
3409		$element.children(".view-grid").addClass("has-pagination");
3410
3411		if (currentTarget) {
3412			$pagination.find("a").filter(function() {
3413				return $(this).text() == $(currentTarget).text();
3414			}).trigger("focus");
3415		}
3416	}
3417
3418	entityGrid.prototype.createWindowMessageEventHandler = function () {
3419		return function(e) {
3420			var origin = null;
3421			if (!window.location.origin) {
3422				origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port : ''); // IE does not set origin
3423			} else {
3424				origin = window.location.origin;
3425			}
3426			if (e.origin != origin) {
3427				return;
3428			}
3429			if (e.data == 'Success') {
3430				this._element.children(".modal-form").modal('hide');
3431				this._element.trigger("refresh");
3432			}
3433		}.bind(this);
3434	}
3435
3436	entityGrid.prototype.resetPagination = function () {
3437		var $this = this;
3438		var $element = $this._element;
3439		var $pagination = $element.children(".view-pagination");
3440		$pagination
3441			.data("pages", 1)
3442			.data("current-page", 1);
3443	}
3444
3445	function handleMobileHeaders($table) {
3446		var headertext = [];
3447		var getHeaderText = function ($th) {
3448			var columnName = $th.data('columnname');
3449
3450			if (columnName) {
3451				columnName = columnName
3452					// removes all html tags from string
3453					.replace(/<(?:.|\n)*?>/gm, '')
3454					// removes whitespace from both sides of a string
3455					.trim();
3456				return columnName;
3457			}
3458
3459			var $headerControl = $th.children('a');
3460			var textContainer = $headerControl.length > 0 ? $headerControl.first() : $th;
3461			var textNode = textContainer.contents().get(0);
3462
3463			return textNode ? textNode.nodeValue : '';
3464		}
3465
3466		$table.find("thead th")
3467			.each(function () {
3468				var $th = $(this);
3469				headertext.push(getHeaderText($th));
3470			});
3471
3472		$table.find("tbody tr")
3473			.each(function () {
3474				$(this)
3475					.find("td")
3476					.each(function (i) {
3477						$(this).attr("data-th", headertext[i]);
3478					});
3479			});
3480	}
3481
3482	function displayErrorModal(error, $modal) {
3483		$modal.prop("aria-hidden", false);
3484
3485		if (typeof error !== typeof undefined && error !== false && error != null) {
3486			console.log(error);
3487
3488			var title = "Error";
3489			var $title = $modal.find(".modal-title");
3490			var $body = $modal.find(".modal-body");
3491
3492			$title.data("title", $title.html());
3493
3494			if (typeof error.Message !== typeof undefined && error.Message !== false && error.Message != null) {
3495				if (typeof error.Message === 'number') {
3496					title = error.Message + " Error";
3497				} else {
3498					title = error.Message;
3499				}
3500			}
3501
3502			$title.addClass("text-danger").html("<span class='fa fa-exclamation-triangle' aria-hidden='true'></span> " + title);
3503
3504			if (typeof error.InnerError !== typeof undefined && error.InnerError !== false && error.InnerError != null) {
3505				$body.html("<p>" + error.InnerError.Message + "</p>");
3506			}
3507		}
3508
3509		$modal.modal();
3510	}
3511
3512	function parseSortExpression(sortExpression) {
3513		var sorts = [];
3514		if (sortExpression == null) {
3515			return sorts;
3516		}
3517		var sortExpressionPattern = /(\w+)\s*(asc|ascending|desc|descending)?\s*(,)?/gi;
3518		var matches = sortExpression.match(sortExpressionPattern);
3519		if (matches == null) {
3520			return sorts;
3521		}
3522		for (var i = 0; i < matches.length; i++) {
3523			var match = matches[i];
3524			if (match != null && match != "") {
3525				var name;
3526				var direction = "ASC";
3527				var pos = match.indexOf(" ");
3528				if (pos != -1) {
3529					name = match.substr(0, pos);
3530					direction = match.substr(pos + 1, match.length - pos);
3531				} else {
3532					name = match;
3533				}
3534				if (name != null) {
3535					name = name.replace(/,\s*$/, "");
3536				}
3537				if (direction != null) {
3538					direction = direction.replace(/,\s*$/, "");
3539				}
3540				var sort = { name: name, direction: direction };
3541				sorts.push(sort);
3542			}
3543		}
3544		return sorts;
3545	}
3546
3547	function indexOf(list, attr, val) {
3548		// Determines the index of an object in an array by matching the value with the object property value.
3549		// Returns: -1 if object does not exist that matches the property value, otherwise returns integer index of the object in the array.
3550		var result = -1;
3551		$.each(list, function (index, item) {
3552			if (item[attr].toString().toLowerCase().indexOf(val.toString().toLowerCase()) != -1) {
3553				result = index;
3554				return false;
3555			}
3556		});
3557		return result;
3558	}
3559
3560	if (!String.prototype.startsWith) {
3561		String.prototype.startsWith = function(searchString, position) {
3562			position = position || 0;
3563			return this.lastIndexOf(searchString, position) === position;
3564		};
3565	}
3566
3567	function getPrimaryName(record) {
3568		var attributes,
3569			i,
3570			attribute;
3571
3572		if (!record) {
3573			return null;
3574		}
3575
3576		attributes = record.Attributes || [];
3577
3578		for (i = 0; i < attributes.length; i++) {
3579			attribute = attributes[i];
3580
3581			if (attribute && attribute.AttributeMetadata && attribute.AttributeMetadata.EntityLogicalName === record.EntityName && attribute.AttributeMetadata.IsPrimaryName) {
3582				return attribute.DisplayValue;
3583			}
3584		}
3585	}
3586
3587	function getRedirectUrlFromActionLink(action) {
3588		if (!action || !action.RedirectUrl) return null;
3589		return getUrlFromUrlBuilder(action.RedirectUrl);
3590	}
3591
3592	function getUrlFromUrlBuilder(urlBuilder) {
3593		if (!urlBuilder) return null;
3594		return URI(urlBuilder.PathWithQueryString);
3595	}
3596
3597	function getCustomParameters(configuration) {
3598		var customParameters = [];
3599		if (!configuration) return customParameters;
3600		if (configuration.EntityName === "entitlement") {
3601			// Entitlement records must be dynamically and conditionally filtered based on the primary input fields on an incident submission form.
3602			var customerid = $("#customerid").val();
3603			var customertype = $("#customerid_entityname").val();
3604			var primarycontactid = $("#primarycontactid").val();
3605			var productid = $("#productid").val();
3606			if (customerid) {
3607				customParameters = [
3608					{
3609						Key: "customerid",
3610						Value: customerid
3611					},
3612					{
3613						Key: "customertype",
3614						Value: customertype
3615					},
3616					{
3617						Key: "primarycontactid",
3618						Value: primarycontactid
3619					},
3620					{
3621						Key: "productid",
3622						Value: productid
3623					}
3624				];
3625			}
3626			return customParameters;
3627		} else if (configuration.ModalLookupEntityLogicalName === "opportunityproduct") {
3628			customParameters = [
3629				{
3630					Key: "productid",
3631					Value: $("#productid").val()
3632				},
3633				{
3634					Key: "uomid",
3635					Value: $("#uomid").val()
3636				}
3637			];
3638			
3639			return customParameters;
3640		} else {
3641			return customParameters;
3642		}
3643	}
3644
3645	function redirect(redirectUrl) {
3646		if (typeof redirectUrl == 'undefined' || redirectUrl == null || redirectUrl == '') return;
3647		$.blockUI({
3648			css: {
3649				border: 'none',
3650				backgroundColor: 'transparent',
3651				opacity: .5,
3652				color: '#fff'
3653			},
3654			message: "<span class='fa fa-2x fa-spinner fa-pulse' aria-hidden='true'></span>"
3655		});
3656		if (parent) {
3657			parent.location.replace(redirectUrl);
3658		} else {
3659			window.location.replace(redirectUrl);
3660		}
3661	}
3662
3663	function getRedirectUrl(action) {
3664		if (!action || !action.RedirectUrl) return null;
3665		return URI(action.RedirectUrl.PathWithQueryString);
3666	}
3667
3668	function inIframe() {
3669		try {
3670			return window.self !== window.top;
3671		} catch (e) {
3672			return true;
3673		}
3674	}
3675
3676}(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.