PageSourceSearch

https://enx.com/js/portal.js

js enx.com collected 2026-09-24 09:15:33 UTC 26,394 bytes, 677 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
6var portal = portal || {};
7
8portal.convertAbbrDateTimesToTimeAgo = function ($) {
9	$("abbr.timeago").each(function () {
10		var $this = $(this),
11		  dateTime = Date.parse($this.text()),
12		  momentDateTime;
13
14		if (dateTime) {
15			momentDateTime = moment(dateTime);
16			var dateFormat = dateFormatConverter.convert($this.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
17			var timeFormat = dateFormatConverter.convert($this.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
18			var datetimeFormat = dateFormatConverter.convert($this.attr('data-format'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat);
19			$this.attr("title", momentDateTime.format("YYYY-MM-DDTHH:mm:ss"));
20			$this.text(momentDateTime.format(datetimeFormat));
21		}
22	});
23
24	$("abbr.timeago").timeago();
25
26	$("abbr.posttime").each(function () {
27		var $this = $(this),
28		  dateTime = Date.parse($this.text()),
29		  momentDateTime;
30
31		if (dateTime) {
32			momentDateTime = moment(dateTime);
33			var dateFormat = dateFormatConverter.convert($this.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
34			var timeFormat = dateFormatConverter.convert($this.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
35			var datetimeFormat = dateFormatConverter.convert($this.attr('data-format'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat);
36			$this.attr("title", momentDateTime.format(datetimeFormat));
37			$this.text(momentDateTime.format(datetimeFormat));
38		}
39	});
40};
41
42portal.initializeHtmlEditors = function () {
43	var appPath = $('[data-app-path]').data('app-path') || '/';
44
45	$(document).on('focusin', function (e) {
46		if ($(e.target).closest(".mce-window").length) {
47			e.stopImmediatePropagation();
48		}
49	});
50
51	$(".html-editors textarea").each(function () {
52		CKEDITOR.replace(this, {
53			customConfig: '',
54			language: $(this).closest('[crm-lang]').attr('crm-lang'),	// ckeditor only supports the CRM languages
55			height: 240,
56			uiColor: '#EEEEEE',
57			contentsCss: [appPath + 'css/bootstrap.min.css', appPath + 'css/ckeditor.css'],
58			stylesSet: 'portal',
59			format_tags: 'p;h1;h2;h3;h4;h5;h6;pre',
60			disableNativeSpellChecker: false,
61			toolbarGroups: [
62			  { name: 'clipboard', groups: ['clipboard', 'undo'] },
63			  { name: 'links', groups: ['links'] },
64			  { name: 'editing', groups: ['find', 'selection', 'spellchecker', 'editing'] },
65			  { name: 'insert', groups: ['insert'] },
66			  { name: 'forms', groups: ['forms'] },
67			  { name: 'tools', groups: ['tools'] },
68			  { name: 'document', groups: ['document', 'doctools', 'mode'] },
69			  '/',
70			  { name: 'basicstyles', groups: ['basicstyles', 'cleanup'] },
71			  { name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi', 'paragraph'] },
72			  { name: 'styles', groups: ['styles'] },
73			  { name: 'colors', groups: ['colors'] },
74			  { name: 'others', groups: ['others'] },
75			  { name: 'about', groups: ['about'] }
76			],
77			removeButtons: 'Save,NewPage,Preview,Print,Templates,SelectAll,Find,Replace,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,Anchor,Flash,Smiley,PageBreak,Iframe,ShowBlocks,Font,FontSize,CreateDiv,JustifyLeft,JustifyCenter,JustifyRight,JustifyBlock,BidiRtl,BidiLtr,Language,TextColor,BGColor,About,Subscript,Superscript,Underline',
78			on: {
79				change: function () {
80					this.updateElement();
81				}
82			}
83		});
84	});
85};
86
87(function ($, XRM) {
88	CKEDITOR.stylesSet.add('portal', [
89	  { name: window.ResourceManager['CKEditor_Code_Style'], element: 'code' },
90	  { name: window.ResourceManager['CKEditor_Code_Block_Style'], element: 'pre', attributes: { 'class': 'linenums prettyprint' } }
91	]);
92
93	portal.initializeHtmlEditors();
94
95	$(function () {
96		moment.locale($('html').attr('lang'));
97		portal.convertAbbrDateTimesToTimeAgo($);
98
99		var facebookSignin = $(".facebook-signin");
100		facebookSignin.on("click", function (e) {
101			e.preventDefault();
102			window.open(facebookSignin.attr("href"), "facebook_auth", "menubar=1,resizable=1,scrollbars=yes,width=800,height=600");
103		});
104
105		$(".crmEntityFormView input:not([value])[readonly]:not([placeholder]), .crmEntityFormView input[value=''][readonly]:not([placeholder])").filter(function () {
106			var value = $(this).val();
107			return value == null || value.length === 0;
108		}).each(function () {
109			$(this).parent().css("position", "relative");
110			$(this).after($("<div>&mdash;</div>").addClass("text-muted").css("position", "absolute").css("top", 4));
111		});
112		$(".crmEntityFormView select[disabled] option:checked[value='']").closest("select").each(function () {
113			$(this).parent().css("position", "relative");
114			$(this).after($("<div>&mdash;</div>").addClass("text-muted").css("position", "absolute").css("top", 4));
115		});
116		$(".crmEntityFormView textarea[readonly]").filter(function () {
117			return $(this).val().length === 0;
118		}).each(function () {
119			$(this).parent().css("position", "relative");
120			$(this).after($("<div>&mdash;</div>").addClass("text-muted").css("position", "absolute").css("top", 4));
121		});
122
123		// Map dropdowns with .btn-select class to backing field.
124		$('.btn-select').each(function () {
125			var select = $(this),
126				target = $(select.data('target')),
127				focus = $(select.data('focus')),
128				label = $('.btn .selected', select);
129
130			target.change(function () {
131				var changedSelected = $('option:selected', target);
132				select.find('.dropdown-menu li.active a').attr("aria-selected", false);
133				select.find('.dropdown-menu li.active').removeClass('active');
134				label.text(changedSelected.text());
135			});
136
137			$('.dropdown-menu li > a', select).click(function () {
138				var option = $(this),
139					value = option.data('value');
140				
141				$('.dropdown-menu li a', select).attr("aria-selected", false);
142				$('.dropdown-menu li', select).removeClass("active");
143				option.parent('li').addClass("active");
144				option.attr("aria-selected", true);
145				target.val(value);
146				label.text(option.text());
147				focus.focus();
148			});
149		});
150
151		// Convert GMT timestamps to client time.
152		$('abbr.timestamp').each(function () {
153			var $this = $(this),
154			  dateTime = Date.parse($this.text()),
155			  momentDateTime;
156
157			if (dateTime) {
158				momentDateTime = moment(dateTime);
159				var dateFormat = dateFormatConverter.convert(element.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
160				var timeFormat = dateFormatConverter.convert(element.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
161				var datetimeFormat = dateFormatConverter.convert(element.attr('data-format'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat);
162
163				$this.text(momentDateTime.format(datetimeFormat));
164				$this.attr("title", momentDateTime.format(datetimeFormat));
165			}
166		});
167
168		// Format time elements.
169		$("time").each(function () {
170			var $this = $(this),
171			  dateTime = moment($this.attr("datetime"));
172
173			if (dateTime) {
174				var dateFormat = dateFormatConverter.convert($this.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
175				var timeFormat = dateFormatConverter.convert($this.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
176				var datetimeFormat = dateFormat + ' ' + timeFormat;
177
178				$this.text(dateTime.format($this.hasClass("date-only") ? dateFormat : datetimeFormat));
179			}
180		});
181
182		// Convert GMT date ranges to client time.
183		$('.vevent').each(function () {
184			var start = $('.dtstart', this),
185			  end = $('.dtend', this),
186			  startDate = Date.parse(start.text()),
187			  endDate = Date.parse(end.text()),
188			  dateFormat,
189			  timeFormat,
190			  datetimeFormat,
191			  momentStartDate,
192			  momentEndDate;
193
194			if (startDate) {
195				momentStartDate = moment(startDate);
196				dateFormat = dateFormatConverter.convert(start.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
197				timeFormat = dateFormatConverter.convert(start.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
198				datetimeFormat = dateFormatConverter.convert(start.attr('data-format'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat);
199
200				start.text(momentStartDate.format(datetimeFormat));
201				start.attr('title', momentStartDate.format(datetimeFormat));
202			}
203
204			if (endDate) {
205				momentEndDate = moment(endDate);
206				dateFormat = dateFormatConverter.convert(end.closest("[data-dateformat]").data("dateformat") || "MMMM d, yyyy", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
207				timeFormat = dateFormatConverter.convert(end.closest("[data-timeformat]").data("timeformat") || "h:mm tt", dateFormatConverter.dotNet, dateFormatConverter.momentJs);
208				datetimeFormat = dateFormatConverter.convert(end.attr('data-format'), dateFormatConverter.dotNet, dateFormatConverter.momentJs) || (dateFormat + ' ' + timeFormat);
209
210				end.text(momentEndDate.format(startDate && momentEndDate.isSame(moment(startDate), 'day') ? timeFormat : datetimeFormat));
211				end.attr('title', momentEndDate.format(datetimeFormat));
212			}
213		});
214
215		// Initialize Bootstrap Carousel for any elements with the .carousel class.
216		$('.carousel').carousel();
217
218		// Workaround for jQuery UI and Bootstrap tooltip name conflict
219		if ($.ui && $.ui.tooltip) {
220			$.widget.bridge('uitooltip', $.ui.tooltip);
221		}
222
223		$('.has-tooltip').tooltip();
224
225		prettyPrint();
226
227		// Initialize any shopping cart status displays.
228		(function () {
229			var shoppingCartStatuses = {};
230
231			$('.shopping-cart-status').each(function () {
232				var element = $(this),
233				  service = element.attr('data-href'),
234				  count = element.find('.count'),
235				  countValue = count.find('.value'),
236				  serviceQueue;
237
238				if (!service) {
239					return;
240				}
241
242				serviceQueue = shoppingCartStatuses[service];
243
244				if (!$.isArray(serviceQueue)) {
245					serviceQueue = shoppingCartStatuses[service] = [];
246				}
247
248				serviceQueue.push(function (data) {
249					if (data != null && data.Count && data.Count > 0) {
250						countValue.text(data.Count);
251						count.addClass('visible');
252						element.addClass('visible');
253					}
254				});
255			});
256
257			$.each(shoppingCartStatuses, function (service, queue) {
258				$.getJSON(service, function (data) {
259					$.each(queue, function (index, fn) {
260						fn(data);
261					});
262				});
263			});
264		})();
265
266		$('[data-state="sitemap"]').each(function () {
267			var $nav = $(this),
268			  current = $nav.data('sitemap-current'),
269			  ancestor = $nav.data('sitemap-ancestor'),
270			  state = $nav.closest('[data-sitemap-state]').data('sitemap-state'),
271			  statePath,
272			  stateRootKey;
273
274			if (!(state && (current || ancestor))) {
275				return;
276			}
277
278			statePath = state.split(':');
279			stateRootKey = statePath[statePath.length - 1];
280
281			$nav.find('[data-sitemap-node]').each(function () {
282				var $node = $(this),
283				  key = $node.data('sitemap-node');
284
285				if (!key) {
286					return;
287				}
288
289				$.each(statePath, function (stateIndex, stateKey) {
290					if (stateIndex === 0) {
291						if (current && stateKey == key) {
292							$node.addClass(current);
293						}
294					} else {
295						if (ancestor && stateKey == key && key != stateRootKey) {
296							$node.addClass(ancestor);
297						}
298					}
299				});
300			});
301		});
302
303		(function () {
304			var query = URI ? URI(document.location.href).search(true) || {} : {};
305
306			$('[data-query]').each(function () {
307				var $this = $(this),
308				  value = query[$this.data('query')];
309
310				if (typeof value === 'undefined') {
311					return;
312				}
313
314				$this.val(value).change();
315			});
316		})();
317	});
318
319	if (typeof XRM != 'undefined' && XRM) {
320		XRM.zindex = 2000;
321
322		(function () {
323			var ckeditorConfigs = [XRM.ckeditorSettings, XRM.ckeditorCompactSettings];
324
325			for (var i = 0; i < ckeditorConfigs.length; i++) {
326				var config = ckeditorConfigs[i];
327
328				if (!config) continue;
329
330				// Load all page stylesheets into CKEditor, for as close to WYSIWYG as possible.
331				var stylesheets = $('head > link[rel="stylesheet"]').map(function (_, e) {
332					var href = $(e).attr('href');
333					return href.match(/,/) ? null : href;
334				}).get();
335
336				stylesheets.push(($('[data-app-path]').data('app-path') || '/') + 'css/ckeditor.css');
337
338				config.contentsCss = stylesheets;
339			}
340
341			var styles = CKEDITOR.stylesSet.get('cms');
342
343			if (styles) {
344				var newStyles = [
345				  { name: window.ResourceManager['CKEditor_Page_Header_Style'], element: 'div', attributes: { 'class': 'page-header' } },
346				  { name: window.ResourceManager['CKEditor_Alert_Info_Style'], element: 'div', attributes: { 'class': 'alert alert-info' } },
347				  { name: window.ResourceManager['CKEditor_Alert_Success_Style'], element: 'div', attributes: { 'class': 'alert alert-success' } },
348				  { name: window.ResourceManager['CKEditor_Alert_Warning_Style'], element: 'div', attributes: { 'class': 'alert alert-warning' } },
349				  { name: window.ResourceManager['CKEditor_Alert_Danger_Style'], element: 'div', attributes: { 'class': 'alert alert-danger' } },
350				  { name: window.ResourceManager['CKEditor_Well_Style'], element: 'div', attributes: { 'class': 'well' } },
351				  { name: window.ResourceManager['CKEditor_Well_Small_Style'], element: 'div', attributes: { 'class': 'well well-sm' } },
352				  { name: window.ResourceManager['CKEditor_Well_Large_Style'], element: 'div', attributes: { 'class': 'well well-lg' } },
353				  { name: window.ResourceManager['CKEditor_Label_Style'], element: 'span', attributes: { 'class': 'label label-default' } },
354				  { name: window.ResourceManager['CKEditor_Label_Info_Style'], element: 'span', attributes: { 'class': 'label label-info' } },
355				  { name: window.ResourceManager['CKEditor_Label_Success_Style'], element: 'span', attributes: { 'class': 'label label-success' } },
356				  { name: window.ResourceManager['CKEditor_Label_Warning_Style'], element: 'span', attributes: { 'class': 'label label-warning' } },
357				  { name: window.ResourceManager['CKEditor_Label_Danger_Style'], element: 'span', attributes: { 'class': 'label label-danger' } }
358				];
359
360				for (var i = 0; i < newStyles.length; i++) {
361					styles.push(newStyles[i]);
362				}
363			}
364
365			//temporary fix for bug: http://dev.ckeditor.com/ticket/14591
366			$(document).bind('DOMNodeInserted', function () {
367				if ($(".cke_dialog_ui_labeled_label").length)
368					$(".cke_dialog_ui_labeled_label").attr("title", function () { return $(this).text() });
369			});
370		})();
371	}
372
373	var notification = $.cookie("adx-notification");
374	if (typeof (notification) === typeof undefined || notification == null) return;
375	displaySuccessAlert(notification, true);
376	$.cookie("adx-notification", null);
377
378	function displaySuccessAlert(success, autohide) {
379		var $container = $(".notifications");
380		if ($container.length == 0) {
381			var $pageheader = $(".page-heading");
382			if ($pageheader.length == 0) {
383				$container = $("<div class='notifications'></div>").prependTo($("#content-container"));
384			} else {
385				$container = $("<div class='notifications'></div>").appendTo($pageheader);
386			}
387		}
388		$container.find(".notification").slideUp().remove();
389		if (typeof success !== typeof undefined && success !== false && success != null && success != '') {
390			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>")
391                .on('closed.bs.alert', function () {
392                	if ($container.find(".notification").length == 0) $container.hide();
393                }).prependTo($container);
394			$container.show();
395			window.scrollTo(0, 0);
396			if (autohide) {
397				setTimeout(function () {
398					$alert.slideUp(100).remove();
399					if ($container.find(".notification").length == 0) $container.hide();
400				}, 5000);
401			}
402		}
403	}
404
405})(window.jQuery, window.XRM);
406
407$(document).ready(function () {
408	// Note: for accessibility, sync focused and selected dropdown item.
409	$(".dropdown-menu li a")
410		.focus(
411			function (e) {
412				var $target = $(e.target);
413				$target.attr("aria-selected", true);
414				$target.parent().toggleClass("active", true);
415			});
416	// Note: unselect dropdown item that gets unfocused.
417	$(".dropdown-menu li a")
418	.focusout(
419		function (e) {
420			var $target = $(e.target);
421			$target.attr("aria-selected", false);
422			$target.parent().toggleClass("active", false);
423		});
424
425	$(".dropdown-submenu").on("click", function (e) {
426		// Note: we prevent default button handler of Bootstrap,
427		// bacause it closes all other manus except the current one.
428		// This is unwanted behavour, bacause we have a nested dropdown menus in the top bar.
429		// Default behavour caused parent menu to close when we try to open child menu.
430
431		$(this).toggleClass("open");
432
433		var $searchButton = $(this).find('#search-filter');
434		var isExpanded = $searchButton.attr("aria-expanded") === "true";
435		$searchButton.attr("aria-expanded", !isExpanded);
436
437		if (!isExpanded) {
438			var firstMenuItem = $(this).find(".dropdown-menu li:first-child a");
439			firstMenuItem.focus();
440		}
441
442		e.stopPropagation();
443		e.preventDefault();
444	});
445
446	$(".dropdown-menu li a").on("click", function (e) {
447		// return focus to dropdown button, when menu item is clicked.
448		var dropdownButton = $(this).parent().parent().prev().first();
449		dropdownButton.focus();
450	});
451
452
453	// Search button in the top navigation menu is a dropdown that toggles a search form.
454	// Search form has a dropdown too -- the Search Filter dropdown.
455	// But *Bootstrap* explicitly forbids dropdown logic to be triggered by this combination of elements.
456	// See: https://github.com/twbs/bootstrap/blob/v3-dev/js/dropdown.js#L160
457	// So, we listen to same event and close `.dropdown-submenu` inside the form.
458	$(document).on(
459		"click.bs.dropdown.data-api",
460		".dropdown form",
461		function (e) {
462			var $submenu = $(e.target).closest("form").find(".dropdown-submenu");
463			$submenu.toggleClass("open", false);
464
465			var $searchButton = $submenu.find("#search-filter");
466			$searchButton.attr("aria-expanded", false);
467		});
468});
469
470$(document).ready(function () {
471	$('#profile-dropdown').find('a').each(function () {
472		$(this).attr('role', 'button');
473	});
474	$('li.weblink>a[title="Home"]').attr('aria-label', window.ResourceManager["Home_DefaultText"]);
475	$('li.dropdown>a.navbar-icon').attr('title', window.ResourceManager["Search_DefaultText"]);
476	$('label.required').next().find('input').each(function () {
477		$(this).attr('aria-label', $(this).closest().attr('name'));
478		$(this).attr('aria-required', true);
479	});
480	$('li.dropdown>a.dropdown-toggle').each(function () {
481		$(this).attr('aria-label', $(this).attr('title') + window.ResourceManager["DropDown_DefaultText"]);
482	});
483	$('li.weblink.dropdown>a').each(function () {
484		$(this).attr('aria-label', $(this).attr('title') + window.ResourceManager["DropDown_DefaultText"]);
485	});
486	$('section.modal input[type="file"]').on("keydown", function (event) {
487		if (event.shiftKey && event.keyCode == 9) {
488			if ($('input[type="file"]').is(":focus")) {
489				setTimeout(function () { $('section.modal textarea[name="text"]').focus(); }, 0);
490			}
491		}
492	});
493	$('div.list-group>a').each(function () {
494		$(this).attr('aria-label', $(this).attr('title'));
495	});
496});
497
498
499$(document).ready(function () {
500	$('.navbar-nav .weblink.dropdown>a').attr('role', 'button');
501	$('.navbar-nav .weblink.dropdown>ul>li>a').attr('role', 'link');
502});
503
504$(document).ready(function () {
505	$('input#AttachFile').attr('aria-label', window.ResourceManager["FileUpload_Browse_Button_Text"]);
506});
507$(document).ready(function () {
508	var options = $("select>option");
509	$.each(options, function (i, op) {
510		if ($(op).text() == "") {
511			$(op).text($(op).attr("label"))
512		}
513	});
514});
515
516portal.CompositeControl = function (trigger) {
517	var self = this;
518	self.controlTrigger = trigger;
519	self.$popverTriger = null;
520	self.contentid = "";
521	self.$content = null;
522	self.$contentInputs = null;
523	self.valueTemplate = "";
524	self.isPopoverOpen = false;
525	self.isEditable = false;
526	self.showOrHidePopover = function() {
527		if (self.isPopoverOpen) {
528			self.$popverTriger.popover("hide");
529		} else {
530			self.$popverTriger.popover("show");
531		}
532	}
533	self.updateContent = function() {
534		var popeverInputs = $("." + self.contentid).find("input");
535		self.$contentInputs.each(function(index, value) {
536			var mainInputId = $(value).prop("id");
537			popeverInputs.each(function(innerIndex, innnerValue) {
538				var $innnerValue = $(innnerValue);
539				if ($innnerValue.prop("id") == mainInputId) {
540					$(value).attr("value", $innnerValue.val());
541				}
542			});
543		});
544		self.updateValue();
545	};
546	self.updateValue = function () {
547		if (!self.isEditable) return;
548		var triggerValue = self.valueTemplate.split("{BREAK}");
549		self.$contentInputs.each(function (index, value) {
550			var inputId = $(value).attr("id");
551			var inputVlaue = $('#' + $(value).attr("id")).attr("value");
552			for (var i = 0; i < triggerValue.length; i++) {
553
554				triggerValue[i] = triggerValue[i].replace("{" + inputId + "}", inputVlaue).trim();
555			}
556		});
557		self.$popverTriger.attr("value", triggerValue.join("\r\n"));
558	};
559	self.init = function() {
560		self.$popverTriger = $(self.controlTrigger);
561		self.contentid = self.$popverTriger.attr("data-content-id");
562		self.valueTemplate = self.$popverTriger.attr("data-content-template");
563		self.isEditable = self.$popverTriger.attr("data-editable").toLowerCase() === "true";
564		self.$popverTriger.click(function() {
565			self.showOrHidePopover();
566		});
567		console.log(self.contentid);
568		self.$content = $("#" + self.contentid);
569		self.$contentInputs = self.$content.find("input");
570		self.$popverTriger.attr("readonly", "true");
571		self.updateValue();
572		if (self.isEditable) {
573			self.$popverTriger.popover({
574				trigger: "manual",
575				html: true,
576				template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content ' + self.contentid + ' "></div></div>',
577				content: function () {
578					return self.$content.html();
579				},
580				placement: function() {
581					return "bottom";
582				}
583			});
584
585			self.$popverTriger.on("inserted.bs.popover", function () {
586				var $insertedPopover = $("." + self.contentid);
587				$insertedPopover.css("width", "270px");
588				$insertedPopover.find("input").removeAttr("name");
589				self.isPopoverOpen = true;
590			});
591
592			self.$popverTriger.on('hide.bs.popover', function () {
593				self.updateContent();
594				self.isPopoverOpen = false;
595			});
596
597			self.$popverTriger.on("shown.bs.popover",
598				function() {
599					$("." + self.contentid + " .btn").click(function() {
600						self.$popverTriger.popover("hide");
601					});
602				});
603		}
604
605		$('body').on('click', function(e) {
606			if (!$(self.$popverTriger).is(e.target)
607				&& $('.popover-content').length !== 0
608				&& $(e.target).data('toggle') !== 'popover'
609				&& $(e.target).parents('[data-toggle="popover"]').length === 0
610				&& $(e.target).parents('.popover.in').length === 0) {
611				self.$popverTriger.popover("hide");
612			}
613		});
614
615		$("#" + self.contentid).parent().on("keydown", function (event) {
616			//'Enter' key press opens closed composite control and only closes opened control on 'enter' keypress on button
617			if (event.keyCode === 13 && (self.isPopoverOpen && event.target.id.indexOf('Button') !== -1 || !self.isPopoverOpen)) {
618				self.showOrHidePopover();
619			}
620			//Hide popover on 'Esc' key press
621			if (event.keyCode === 27) {
622				self.$popverTriger.popover("hide");
623			}
624			//Focus is returned to first input field of composite control if user presses "Tab" on the button of composite control 
625			if (event.target.id.indexOf('Button') !== -1 && event.keyCode === 9) {
626				$(jQuery(this).find('*').filter(':input')[0]).focus();
627			}
628		});
629	};
630}
631
632$(document).ready(function () {
633	$("*[data-composite-control]")
634		.each(function (index, value) {
635			var control = new portal.CompositeControl(value);
636			control.init();
637		});
638});
639
640$('body').on("keydown", ".dropdown", function (event) {
641	var parentElement = event.srcElement.parentElement.parentElement;
642	// Checking that li element is in dropdown menu
643	if (event.keyCode === 9 && parentElement !== null && parentElement.className.indexOf("dropdown") !== -1) {
644		// Checking if tab was pressed from last element in dropdown
645		if ($(parentElement).children().last().attr("class") === "active") {
646			$(parentElement).children().first().children().first().focus();
647			event.preventDefault();
648		}
649	}
650});
651
652// multilanguage - in dropdown, on item click, update the cookie with the selected item.
653$(document).ready(function () {
654	try {
655		var selectedLanguage = $("html").attr("data-lang");
656		if (selectedLanguage) {
657			$.cookie("ContextLanguageCode", selectedLanguage, { path: "/" });
658		}
659
660		var langOptionsMenu = $(".drop_language").parents().next("ul").last()[0];
661		if (langOptionsMenu) {
662			var langOptions = $("a", langOptionsMenu);
663			$(langOptions).each(function() {
664				var code = $(this).attr("data-code");
665				if (code) {
666					$(this).on("click", function() {
667								$.cookie("ContextLanguageCode", code, { path: "/" });
668							});
669				}
670			});
671		}
672	} catch(ex){
673		// do nothing
674	}
675
676	return true;
677});

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.