PageSourceSearch

https://web.ecainc.org/External/WCControls/V12/WebDeps/Core/scripts/wli-lib-1.0.0.js

js ecainc.org collected 2026-10-08 15:57:54 UTC 39,382 bytes, 1,357 lines download raw bytes

1/** @namespace */
2var wli = wli || {};
3
4var scriptDataObj = jQuery("[data-wli-lib]").data();
5
6wli.widgetUrl = scriptDataObj.secureDomain.toLowerCase();
7wli.homeUrl = scriptDataObj.homeDomain.toLowerCase();
8wli.compUrl = scriptDataObj.componentDomain.toLowerCase();
9
10var stylesheetURL = wli.widgetUrl + "/External/WCControls/V12/WebDeps/Widgets/styles/wli-widget-styles.css";
11
12if (scriptDataObj.defaultStyles != false) {
13	jQuery("head").prepend('<link rel="stylesheet" href="' + stylesheetURL + '" />');
14}
15
16/**
17 * Represents the web menu for quicklinks, breadcrumbs, sitemap, etc.
18 * @constructor
19 * @param {String} domain - The home page URL or root domain URL of the website.
20 * @property {Object} Root - The home page or root domain page.
21 * @property {Object} L2 - The top level navigation items.
22 * @property {Object} CurrentPage - The current page the browser has loaded.
23 * @property {Object} Section - The L2 item that each L3 and lower page belongs to.
24 */
25wli.WebMenu = function(domain) {
26	this.Root = {
27		URL : domain,
28		Target : "",
29		Name : "Home"
30	};
31	this.L2 = {};
32	this.CurrentPage = {};
33	this.Section = {};
34
35	/**
36	 * Array of nodes in the web menu that will represent the L2 nodes.
37	 * @type {Array}
38	*/
39	var nodeTree = [];
40
41	/**
42	 * Iterator variable for use in loops.
43	 * @type {Number}
44	 */
45	var i;
46
47	/**
48	 * Iterator variable for use in loops.
49	 * @type {Number}
50	 */
51	var x;
52
53	// Constructor processes
54	jQuery(".wsite-menu-default > li").each(function(index) {
55		jQuery(this).children("a").each(function() {
56			var linkName = jQuery(this).text();
57
58			if (linkName.indexOf("&amp;") !== -1) {
59				linkName = linkName.replace("&amp;", "&");
60			}
61
62			nodeTree.push({
63				URL : this.href,
64				Target : jQuery(this).attr("target"),
65				Name : linkName
66			});
67		});
68
69		var L2node = nodeTree[nodeTree.length - 1];
70
71		L2node["SubMenu"] = getChildMenuStructure(this);
72
73		for (i in L2node.SubMenu) {
74			L2node.SubMenu[i]["Parent"] = L2node;
75		}
76	});
77
78	for (i in nodeTree) {
79		// Push the nodeTree array objects into the L2 object property
80		this.L2[i] = nodeTree[i];
81	}
82
83	// Set the CurrentPage property
84	this.CurrentPage = this.findCurrentPage(this.L2, document.URL);
85	// Set the SectionName property
86	this.Section = this.findSectionName(this.CurrentPage);
87
88	/**
89	 * Recursive function for building out children pages in the web menu.
90	 * @param {HTMLElement} parentli - The parent page in the web menu that may have children nodes.
91	 * @returns {Array} - Array of all children nodes for the page the function was called on.
92	 */
93	function getChildMenuStructure(parentli) {
94		/** @type {Array} */
95		var subMenu = [];
96
97		jQuery("> div > ul > li > a, > ul > li > a", parentli).each(function() {
98			var linkName = jQuery(this).children(".wsite-menu-title").text();
99
100			if (linkName.indexOf("&amp;") !== -1) {
101				linkName = linkName.replace("&amp;", "&");
102			}
103
104			var subNode = {
105				URL : this.href,
106				Target : jQuery(this).attr("target"),
107				Name : linkName,
108				SubMenu : getChildMenuStructure(jQuery(this).closest("li")[0]),
109				Level : function(){ if (this.Parent && this.Parent.Level) { return this.Parent.Level() + 1;} else return 3;}
110			};
111
112			for (i in subNode.SubMenu) {
113				subNode.SubMenu[i]["Parent"] = subNode;
114			}
115
116			subMenu.push(subNode);
117		});
118
119		return subMenu;
120	}
121};
122
123	/**
124	 * Method for generating breadcrumb links that show the site hierarchy from the current page.
125	 * @param {Object} [opts] - Optional object used to override default properties.
126	 * @returns {String} - HTML String of all breadcrumb links wrapped in <ul>.
127	 */
128	wli.WebMenu.prototype.Breadcrumbs = function(opts) {
129		/** @type {number} */
130		var x;
131		
132		/** @type {number} */
133		var i;
134
135		/** @type {Object} */
136		var settings = {};
137
138		/** @type {Object} */
139		// The divider default property is the text character used to separate the breadcrumb links.
140		var defaults = {
141			divider : " | "
142		};
143
144		// Merge default properties into settings
145		for (x in defaults) {
146			settings[x] = defaults[x];
147		}
148
149		// Merge options provided into settings, overriding defaults
150		for (x in opts) {
151			settings[x] = opts[x];
152		}
153
154		/** @type {Array} */
155		var breadcrumbNodes = [];
156		
157		/** @type {Array} */
158		var nodes = [];
159		
160		/** @type {Array} */
161		var breadcrumbHTML = [];
162
163		// Add the current page to the breadcrumbs
164		if (this.CurrentPage) {
165			breadcrumbNodes.push(this.CurrentPage);
166		}
167
168		// Add the current page's parent and its parents to the breadcrumbs
169		if (this.CurrentPage.Parent) {
170			var returnedNodes = findBreadcrumbs(this.CurrentPage.Parent);
171
172			for (i in returnedNodes) {
173				breadcrumbNodes.push(returnedNodes[i]);
174			}
175		}
176
177		// Add the homepage to the breadcrumbs
178		breadcrumbNodes.push(this.Root);	
179
180		// Parse the breadcrumbs array and build an HTML structure for outputting to the DOM
181		for (i in breadcrumbNodes) {
182			// Set the "target" attribute for the <a> tags to an empty string if the node has no Target property
183			if (!breadcrumbNodes[i].Target) {
184				breadcrumbNodes[i].Target = "";
185			}
186
187			if (i == 0) {
188				breadcrumbHTML[i] = '<li><a href="' + breadcrumbNodes[i].URL + '" target="'
189									+ breadcrumbNodes[i].Target + '">' + breadcrumbNodes[i].Name
190									+ '</a></li>';
191
192				continue;
193			}
194
195			breadcrumbHTML[i] = '<li><a href="' + breadcrumbNodes[i].URL + '" target="'
196								+ breadcrumbNodes[i].Target + '">' + breadcrumbNodes[i].Name
197								+ '</a>' + settings.divider + '</li>';
198		}
199
200		breadcrumbHTML.reverse();
201
202		return "<ul>" + breadcrumbHTML.join("") + "</ul>";
203
204		/**
205		 * Recursive function used for finding the breadcrumb nodes.
206		 * @param {object} parent - The parent node object for the current page.
207		 * @returns {Array} - Array of breadcrumb node objects.
208		 */
209		function findBreadcrumbs(parent) {
210			nodes.push(parent);
211
212			if (parent.Parent) {
213				findBreadcrumbs(parent.Parent);
214			}
215
216			return nodes;
217		}
218	};
219
220	/**
221	 * Method for generating quicklinks that show all of the sibling pages and children pages of the current page.
222	 * @param {object} [opts] - Optional object used to override default properties.
223	 * @returns {string} - HTML String of all quicklinks wrapped in <ul>.
224	 */
225	wli.WebMenu.prototype.Quicklinks = function(opts) {
226	var quicklinkNodes = [];
227	var quicklinkHTML = [];
228	var i;
229	var x;
230	
231	if (this.CurrentPage) {
232		
233		if (this.CurrentPage.Parent) {
234			var currentPage = this.CurrentPage;
235			var siblingNodes = this.CurrentPage.Parent.SubMenu;
236			var childrenNodes = this.CurrentPage.SubMenu;
237			
238			if (this.CurrentPage.Parent.Parent) {
239				var parentNodes = this.CurrentPage.Parent.Parent.SubMenu;
240				
241				if (parentNodes.length > 0) {
242					for (i in parentNodes) {
243						parentNodes[i]["Class"] = "wli-quicklink-parent";
244						quicklinkNodes.push(parentNodes[i]);
245					}
246				}
247			}
248			
249			for (i in siblingNodes) {
250				if (siblingNodes[i].URL == currentPage.URL) {
251					siblingNodes[i]["Class"] = "wli-quicklink-sibling wli-quicklink-current";
252					quicklinkNodes.push(siblingNodes[i]);
253					
254					if (siblingNodes[i].SubMenu.length > 0) {
255						for (x in childrenNodes) {
256							childrenNodes[x]["Class"] = "wli-quicklink-child";
257							quicklinkNodes.push(childrenNodes[x]);
258						}
259					}
260				}
261				
262				if (siblingNodes[i].URL !== currentPage.URL) {
263					siblingNodes[i]["Class"] = "wli-quicklink-sibling";
264					quicklinkNodes.push(siblingNodes[i]);
265				}
266			}
267		}
268		
269		if (!this.CurrentPage.Parent) {
270			var childrenNodes = this.CurrentPage.SubMenu;
271			
272			for (i in childrenNodes) {
273				quicklinkNodes.push(childrenNodes[i]);
274			}
275		}
276	}
277	
278	for (i in quicklinkNodes) {
279		if (!quicklinkNodes[i].Target) {
280			quicklinkNodes[i].Target = "";
281		}
282		
283		if (!quicklinkNodes[i].Class) {
284			quicklinkNodes[i].Class = "";
285		}
286			
287		quicklinkHTML[i] = '<li class="' + quicklinkNodes[i].Class + '"><a href="' 
288						   + quicklinkNodes[i].URL + '" target="' + quicklinkNodes[i].Target 
289						   + '">' + quicklinkNodes[i].Name + '</a></li>';
290	}
291	
292	if (quicklinkHTML.length > 0) {
293		return '<ul class="wli-quicklinks">' + quicklinkHTML.join("") + '</ul>';
294	} else {
295		return "";
296	}
297};
298
299	/**
300	 * Method for generating a sitemap that shows all of the pages in the web menu.
301	 * @param {object} [opts] - Optional object used to override default properties.
302	 * @returns {string} - HTML String of the sitemap wrapped in <ul>.
303	 */
304	wli.WebMenu.prototype.Sitemap = function(opts) {
305		/** @type {Array} */
306		var sitemapNodes = [];
307
308		/** @type {Array} */
309		var sitemapHTML = [];
310
311		/** @type {Array} */
312		var i;
313
314		/** @type {Array} */
315		var level = 2;
316
317		/** @type {Object} */
318		var settings = {};
319
320		/** @type {Object} */
321		var defaults = {
322			showRoot : false
323		};
324
325		for (x in defaults) {
326			settings[x] = defaults[x];
327		}
328
329		for (x in opts) {
330			settings[x] = opts[x];
331		}
332
333		// Method processes
334		for (i in this.L2) {
335			if (typeof this.L2[i] !== "function") {
336				sitemapNodes.push(this.L2[i]);
337
338				if (this.L2[i].SubMenu.length > 0) {
339					level = 3;
340				}
341			}
342		}
343
344		for (i in sitemapNodes) {
345			if (!sitemapNodes[i].Target) {
346				sitemapNodes[i].Target = "";
347			}
348
349			sitemapHTML[i] = '<li><a href="' + sitemapNodes[i].URL + '" '
350							 + 'target="' + sitemapNodes[i].Target + '">'
351							 + sitemapNodes[i].Name + '</a>' + buildSiteMap(sitemapNodes[i].SubMenu)
352							 + '</li>';
353		}
354
355		/**
356		 * Recursive function used for building the sitemap.
357		 * @param {Object} menuItem - The SubMenu of a given node in the web menu.
358		 * @returns {String} - HTML string of children nodes wrapped in <ul>.
359		 */
360		function buildSiteMap(menuItem) {
361			if (menuItem && menuItem.length < 1) {
362				return "";
363			}
364
365			/** @type {Number} */
366			var x;		
367
368			/** @type {HTMLElement} */
369			var ul = document.createElement("ul");
370
371			for (x in menuItem) {
372				if (typeof menuItem[x] !== "function") {
373					level = menuItem[x].Level();
374
375					var li = document.createElement("li");
376					var a = document.createElement("a");
377					var linktext = document.createTextNode(menuItem[x].Name);
378
379					a.href = menuItem[x].URL;
380					a.target = menuItem[x].Target;
381
382					a.appendChild(linktext);
383					li.appendChild(a);
384
385					ul.appendChild(li);
386
387					if (menuItem[x].SubMenu.length > 0) {
388						li.appendChild(jQuery(buildSiteMap(menuItem[x].SubMenu))[0]);
389					}
390				}
391			}
392
393			return "<ul>" + ul.innerHTML + "</ul>";
394		}
395
396		/**
397		 * Recursive function not currently used, intended use is for finding how many levels deep in web menu the page is.
398		 * @param {Object} parentItem - The parent node of the current page in the web menu.
399		 */
400		function findSiteMapParent(parentItem) {
401			if (parentItem.Parent) {
402				level++;
403				findSiteMapParent(parentItem.Parent);
404			}
405		}
406
407		if (settings.showRoot === true) {
408			return '<ul class="wli-sitemap-root"><li><a href="' + this.Root.URL + '">'
409				   + this.Root.Name + '</a>'
410				   + '<ul class="wli-sitemap">' + sitemapHTML.join("") + '</ul></li></ul>';
411		}
412		else {
413			return '<ul class="wli-sitemap">' + sitemapHTML.join("") + '</ul>';
414		}
415	};
416
417	/**
418	 * Method for finding the current page in the supplied node tree object.
419	 * @param {Object} tree - An object of web menu nodes to search through.
420	 * @param {String} searchURL - The URL of the current page to look for in the tree argument.
421	 * @returns {Object|String} - The node of the current page in the web menu or an empty string.
422	 */
423	wli.WebMenu.prototype.findCurrentPage = function(tree, searchURL) {
424		/** @type {Number} */
425		var i;
426
427		for (i in tree) {
428			if (tree[i].URL == searchURL) {
429				return tree[i];
430			}
431			else {
432				var node = this.findCurrentPage(tree[i].SubMenu, searchURL);
433
434				if (node) {
435					return node;
436				}
437			}
438		}
439
440		return "";
441	};
442
443	/**
444	 * Method for finding the L2 node in the web menu of the current page.
445	 * @param {Object} currentPage - The node of the current page in the web menu.
446	 * @returns {Object|String} - The L2 node of the current page or an empty string.
447	 */
448	wli.WebMenu.prototype.findSectionName = function(currentPage) {
449		/** @type {Number} */
450		var i;
451
452		for (i in this.L2) {
453			if (this.L2[i].URL == currentPage.URL) {
454				return currentPage;
455			}
456		}
457
458		if (currentPage.Parent) {
459			return this.findSectionName(currentPage.Parent);
460		}
461
462		return "";
463	};
464
465	/**
466	 * Method for setting up all dynamic page elements pulled from the web menu.
467	 * @param {Object} [opts] - Optional object used to override default properties.
468	 */
469	wli.WebMenu.prototype.PageSetup = function(opts) {
470		/** @type {Object} */
471		var settings = {};
472
473		/** @type {Object} */
474		var defaults = {
475			componentURL : "",
476			componentPageTitle : "",
477			pageTitle : "",
478			sectionTitle : "",
479			breadcrumbs : "",
480			quicklinks : {},
481			sitemap : "",
482			oldQuicklinks : false,
483			onComplete : function() {}, // Callback function to execute when page setup is complete.
484		};
485
486		for (x in defaults) {
487			settings[x] = defaults[x];
488		}
489
490		for (x in opts) {
491			settings[x] = opts[x];
492		}
493
494		// Function processes		
495		if (settings.componentPageTitle) {
496			if (this.CurrentPage != "" && this.CurrentPage.URL.indexOf(settings.componentURL) > -1) {
497				jQuery(settings.componentPageTitle).html(this.CurrentPage.Name);
498			}
499		}
500		
501		if (settings.pageTitle) {
502			jQuery(settings.pageTitle).html(this.CurrentPage.Name);
503		}
504
505		if (settings.sectionTitle) {
506			jQuery(settings.sectionTitle).html(this.Section.Name);
507		}
508
509		if (settings.breadcrumbs) {
510			jQuery(settings.breadcrumbs).html(this.Breadcrumbs());
511		}
512		
513		if (!settings.oldQuicklinks) {
514			if (settings.quicklinks.target) {
515				var targetNode = document.querySelector(settings.quicklinks.nodeList);
516				
517				wli.buildQuicklinks(targetNode, settings.quicklinks, 0);	
518			};
519		}
520		
521		if (settings.oldQuicklinks) {
522			jQuery(settings.quicklinks.target).addClass("wli-old-quicklinks").html(this.Quicklinks());
523		}
524
525		if (settings.sitemap) {
526			jQuery(settings.sitemap).html(this.Sitemap());
527		}
528
529		if (settings.onComplete && typeof(settings.onComplete) == "function") {
530			settings.onComplete();
531		}
532	};
533
534	// Factory method for creating new instances of WebMenu()
535	/**
536	 * Method for creating new instances of WebMenu() with a factory pattern.
537	 * @param {String} domain - The home page URL or root domain URL of the website.
538	 * @returns {Object} - A new instance of WebMenu().
539	 */
540	wli.WebMenu.Create = function(domain) {
541		return new wli.WebMenu(domain);
542	};
543
544
545
546/**
547 * Represents the functionality of the UI widgets on web pages.
548 * @constructor
549 * @param {String} domain - The URL that will be used to pull data from for the widgets.
550 * @property {String} Root - The URL that will be used to pull data from for the widgets.
551 */
552wli.Widget = function(domain) {
553	this.Root = domain;
554};
555
556	/**
557	 * Method for making cross-domain API calls to obtain data used by the widgets.
558	 * @param {Object} [opts] - Optional object used to override default properties.
559	 */
560	wli.Widget.prototype.XSLT = function(opts) {	
561		/** @type {Number} */
562		var x;
563
564		/** @type {Object} */
565		var settings = {};
566
567		/**
568		 * Default options object used for base configuration options.
569		 * @type {Object}
570		 * @property {String} xmlURL - The path for the XML file.
571		 * @property {String} xslURL - The path for the XSL file.
572		 * @property {String} domainURL - The URL that will be used to pull data from for this widget.
573		 * @property {String} fullURL - A full custom URL for the API call.
574		 * @property {String} jsLoad - The location for API file.
575		 * @property {String} target - The CSS/jQuery selector of DOM element that will receive the widget output.
576		 * @property {Boolean} scrolling - Determines if the widget should be scrolling its content on the page.
577		 * @property {Number} scrollingItemsToShow - The number of items to show at once while scrolling.
578		 * @property {Function} onComplete - The callback function to execute after the widget has been rendered in the DOM.
579		 */
580		var defaults = {
581			xmlURL : "",
582			xslURL : "",
583			domainURL : this.Root,
584			fullURL : "",
585			jsLoad : "/WCControls/V12/WebDeps/Widgets/api/xsltransform_js-load.aspx",
586			target : "",
587			scrolling : false,
588			scrollingItemsToShow : 3,
589			onComplete : function() {}
590		};
591
592		for (x in defaults) {
593			settings[x] = defaults[x];
594		}
595
596		for (x in opts) {
597			settings[x] = opts[x];
598		}
599
600		// Set order for asynchronous Ajax calls to execute on jsonp return
601		var jsonpIndex = wli.xsltIndexer.length + 1;
602
603		wli.xsltIndexer.push({
604			id : jsonpIndex,
605			target : settings.target,
606			domainURL : settings.domainURL,
607			scrolling : settings.scrolling,
608			scrollingItemsToShow : settings.scrollingItemsToShow,
609			onComplete : settings.onComplete
610		});
611
612		// Function Processes
613		var jsonpURL = 
614			settings.domainURL + 
615			"/external/" +  
616			settings.jsLoad + 
617			"?xmlurl=" +  
618			encodeURIComponent(settings.xmlURL) + 
619			"&xslurl=" + 
620			encodeURIComponent(settings.xslURL) + 
621			"&jsonp=wli.transformhandler&jsonp_param=" + 
622			encodeURIComponent(jsonpIndex);
623
624		// When a full URL is provided to the js-load file, override the other
625		// options setting the domain and js-load file location
626		if (settings.fullURL) {
627			jsonpURL = settings.fullURL;
628		}
629
630		// Make the API call and ensure cross-domain requests are acceptable
631		jQuery.ajax({
632			cache : false,
633			async : true,
634			url : jsonpURL,
635			dataType : "jsonp"
636		});
637	};
638
639	/**
640	 * Method for creating a new instance of Widget() with a factory pattern.
641	 * @param {String} domain - The URL that will be used to pull data from for the widgets.
642	 * @returns {Object} - A new instance of Widget().
643	 */
644	wli.Widget.Create = function(domain) {
645		return new wli.Widget(domain);
646	};
647
648
649
650/**
651 * The index order of asynchronous callbacks for widget API calls.
652 * @type {Array}
653 */
654wli.xsltIndexer = [];
655
656/**
657 * The callback handler function for widget API calls.
658 * @param {String} data - The stringified HTML returned by the API.
659 * @param {String} index - The stringified number value of the API call index returned by the API.
660 */
661wli.transformhandler = function(data, index) {
662	var x;
663	var i;
664	var opts = {};
665
666	for (x in wli.xsltIndexer) {
667		if (wli.xsltIndexer[x].id == index) {
668			for (i in wli.xsltIndexer[x]) {
669				opts[i] = wli.xsltIndexer[x][i];
670			}
671		}
672	}
673
674	// Default settings
675	var settings = {};
676
677	var defaults = {
678		target : "",
679		domainURL : "",
680		onComplete : false
681	};
682
683	for (x in defaults) {
684		settings[x] = defaults[x];
685	}
686
687	for (x in opts) {
688		settings[x] = opts[x];
689	}
690
691	jQuery(settings.target).html(data);
692
693	if (settings.scrolling == true) {
694		if (jQuery(settings.target).length > 0) {
695			if (jQuery.isFunction(jQuery.fn.carouFredSel)) {
696				jQuery("[data-wli-role='scrolling']", settings.target).carouFredSel({
697					items : settings.scrollingItemsToShow,
698					direction : "up",
699					scroll : {
700						items : 1,
701						duration : 1000
702					}
703				});
704			} else {
705				jQuery.getScript(wli.widgetUrl + "/External/WCControls/V12/WebDeps/Widgets/scripts/caroufredsel.js").done(function() {
706					jQuery("[data-wli-role='scrolling']", settings.target).carouFredSel({
707						items : settings.scrollingItemsToShow,
708						direction : "up",
709						scroll : {
710							items : 1,
711							duration : 1000
712						}
713					});
714				}).fail(function() {
715					console.log("Failed to load Caroufredsel");
716				});
717			}
718		}
719	}
720
721	if ((settings.onComplete) && (typeof(settings.onComplete) === "function")) {
722		settings.onComplete(settings.domainURL);
723	}
724		
725	if (wli.compUrl) {
726		jQuery("a", settings.target).each(function() {
727			this.href = this.href.replace(wli.widgetUrl, wli.compUrl)
728		});
729	}
730};
731
732
733
734/**
735 * Helper function for getting the value of known GET variables in the query string.
736 * @param {String} param - The GET variable being looked for in the URL.
737 * @returns {String} - The value of the GET variable being looked for in the URL.
738 */
739wli.urlGET = function(param) {
740	var query = window.location.search.substring(1);
741	var variables = query.split("&");
742	var i;
743
744	for (i = 0; i < variables.length; i++) {
745		var get = variables[i].split("=");
746		
747		if (get[0] == param) {
748			return get[1];
749		}
750	}
751
752	console.log("Query variable " + param + " not found");
753	return "";
754};
755
756/**
757 * Function for removing existing inline styles, classes, and ID from existing node tree. NOTE: This mutates the passed nodeList. Only pass in what you want changed.
758 * @param {nodeList} elem - The passed nodeList to be scrubbed of style/classes/ID.
759 */
760var topLevel = true;
761var foundOnce = false;
762var currURL = window.location.href;
763
764wli.ScrubAll = function(elem) {
765	if (jQuery(elem).hasClass("wsite-nav-current") || elem.id == "active" || elem.href == currURL) {
766		var currPage = true;
767	}
768	else {
769		var currPage = false;
770	}
771	if (elem.id) {elem.removeAttribute("id");}
772	if (elem.className) {elem.removeAttribute("class");}
773	if (elem.style) {elem.removeAttribute("style");}
774	
775	if (topLevel) {
776		topLevel = false;
777		
778		elem.className = "wli-div-level-0";
779	}
780	else {
781		var parentDiv = jQuery(elem).parents("div")[0].className;
782		
783		if (elem.tagName == "DIV") {
784			var currNum = parentDiv.replace("wli-div-level-", "");
785			currNum++;
786			elem.className = "wli-div-level-" + currNum;
787		};
788		
789		if (elem.tagName == "SPAN") {
790			if ( /^[<>]{1}$/.test( elem.innerText.trim() ) ) {
791				elem.innerHTML = "";
792			};
793		};
794		
795		if (elem.tagName == "UL") {
796			elem.className = parentDiv.replace("div", "ul");
797		};
798		
799		if (elem.tagName == "LI") {
800			if (currPage) {
801				jQuery(elem).addClass("wli-current-list-item");
802				jQuery(elem).closest("ul").addClass("wli-current-list");
803			}
804			else {
805				elem.className = parentDiv.replace("div", "li");
806			};
807		};
808		
809		if (elem.tagName == "A") {
810			if ( jQuery(elem).parent(".wli-current-list-item").length > 0 || currPage ) {
811				if (!foundOnce) {
812					elem.className = "wli-current-page";
813					jQuery(elem).parents("li").addClass("active");
814					foundOnce = true;
815				};
816			};
817		};
818		
819		if (elem.tagName == "BUTTON") {
820			elem.style = "display: none";
821		}
822	};
823	
824	if (elem.children) {
825		for ( var i = elem.children.length - 1, j = 0; i >= j; j++ ) {
826			wli.ScrubAll( elem.children[j] );
827		};
828	};
829 };
830 
831 wli.buildQuicklinks = function(targetNode,quicklinksObj, retryTimes) {
832	 if (targetNode != null) {
833		var copiedNode = targetNode.cloneNode(true);
834		wli.ScrubAll(copiedNode);
835		
836		if (quicklinksObj.title) {
837			var quicklinksTitle = document.createElement("h2");
838			var quicklinksTitleText = document.createTextNode(quicklinksObj.title);
839			
840			quicklinksTitle.appendChild(quicklinksTitleText);
841			jQuery(copiedNode).prepend(quicklinksTitle);
842		};
843		jQuery(quicklinksObj.target).html(copiedNode);
844	}
845	
846	if (targetNode == null && retryTimes < 20) {
847		wli.wait(200).then(function() {
848			targetNode = document.querySelector(quicklinksObj.nodeList);
849			
850			wli.buildQuicklinks(targetNode,quicklinksObj, retryTimes + 1);
851		});
852	}
853	
854	if (targetNode == null && retryTimes >= 20) {
855		console.log("Cannot find the node with selector " + quicklinksObj.nodeList + ", please make sure mobileNavContainer has been updated with the proper selector.");
856	}
857 };
858
859/**
860 * Helper function for correcting relative path URLs on background-images scraped from cross-domain web pages.
861 * @param {Object} opts - Optional object used to override default properties.
862 */
863wli.ImageCorrect = function(opts) {
864	/**
865	 * Iterator variable for use in loops.
866	 * @type {Number}
867	 */
868	var x;
869
870	/**
871	 * Settings object used for storing configuration options.
872	 * @type {Object}
873	 */
874	var settings = {};
875
876	/**
877	 * Default options object used for base configuration options.
878	 * @type {Object}
879	 * @property {String} target - The CSS/jQuery selector of DOM element that needs a background-image corrected.
880	 * @property {String} wrongDomain - The URL of the erroneous domain caused by relative pathing in CSS on the scraped web page.
881	 * @property {String} rightDomain - The URL of the correct domain where the background-image files are located.
882	 */
883	var defaults = {
884		target : "",
885		wrongDomain : "",
886		rightDomain : ""
887	};
888
889	for (x in defaults) {
890		settings[x] = defaults[x];
891	}
892
893	for (x in opts) {
894		settings[x] = opts[x];
895	}
896
897	var wrongDomain = settings.wrongDomain.toLowerCase();
898	var rightDomain = settings.rightDomain.toLowerCase();
899
900	jQuery(settings.target).each(function() {
901		var relativeURL = jQuery(this).css("background-image");
902		if (relativeURL.indexOf(wrongDomain) > -1 && relativeURL.indexOf("repeater.aspx") == -1) {
903			var fixedURL = relativeURL.replace(wrongDomain, rightDomain);
904			var currentInlineStyles = jQuery(this).attr("style");
905			if (currentInlineStyles == null) { currentInlineStyles = ""; };
906			var fixedInlineStyles = currentInlineStyles + "background-image: " + fixedURL + " !important;";
907			jQuery(this).attr("style", fixedInlineStyles);
908		};
909	});
910};
911
912
913/**
914 * Initiate a marquee style image rotator for client sponsor images on the web page.
915 * @param {Object} opts - Optional object used to override default properties.
916 */
917wli.SponsorScroll = function(opts) {
918	/**
919	 * Iterator variable for use in loops.
920	 * @type {Number}
921	 */
922	var x;
923
924	/**
925	 * Settings object used for storing configuration options.
926	 * @type {Object}
927	 */
928	var settings = {};
929
930	/**
931	 * Default options object used for base configuration options.
932	 * @type {Object}
933	 * @property {String} target - The CSS/jQuery selector of DOM element that contains sponsor images to be scrolled.
934	 */
935	var defaults = {
936		target : "",
937		scrollSpeed : 1,
938		mouseScrollSpeed : 1,
939	};
940
941	for (x in defaults) {
942		settings[x] = defaults[x];
943	}
944
945	for (x in opts) {
946		settings[x] = opts[x];
947	}
948	
949	jQuery("img", settings.target).load(function() {
950		wli.wait(50).then(function() {
951			marqueeInit({
952				uniqueid: "sponsor-crawler",
953				inc: settings.mouseScrollSpeed, //speed - pixel increment for each iteration of this marquee's movement
954				mouse: 'cursor driven', //mouseover behavior ('pause' 'cursor driven' or false)
955				moveatleast: settings.scrollSpeed,
956				neutral: 150,
957				persist: true,
958				savedirection: true
959			});
960		});
961	});
962};
963
964
965/**
966 * Helper function used for handling timeout requests with jQuery's promise/deferred pattern.
967 * @param {Number} ms - The number of milliseconds to wait until resolving the returned promise.
968 * @returns {Object} - A promise object that will be resolved after the supplied number of milliseconds have passed.
969 */
970wli.wait = function(ms) {
971	/**
972	 * The deferred object to resolve after the supplied number of milliseconds have passed.
973	 * @type {Object}
974	 */
975	var deferred = new jQuery.Deferred();
976
977	setTimeout(deferred.resolve, ms);
978
979	return deferred.promise();
980};
981
982wli.updateSlider = function(direction) {
983	var activeIndex = 0;
984	
985	for (var i = wli.featuredSlidesArray.length - 1; i >= 0; i--) {
986		if (jQuery(wli.featuredSlidesArray[i]).hasClass("featured-active")) {
987			activeIndex = i;
988		}
989	}
990	
991	if (!isNaN(direction)) {
992		oldIndex = activeIndex;
993		activeIndex = Number(direction) - 1;
994		
995		if (oldIndex == activeIndex) {
996			return;
997		}
998		
999		jQuery(wli.featuredSlidesArray).removeClass("featured-visible");
1000		
1001		if (oldIndex < activeIndex) {
1002			for (var i = oldIndex; i < activeIndex; i++) {
1003				jQuery(wli.featuredSlidesArray[i]).addClass("featured-left").removeClass("featured-right");
1004			};
1005			
1006			jQuery(wli.featuredSlidesArray[oldIndex]).addClass("featured-visible").removeClass("featured-active");
1007			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-active featured-visible").removeClass("featured-right");
1008		}
1009		
1010		if (oldIndex > activeIndex) {
1011			for (var i = oldIndex; i > activeIndex; i--) {
1012				jQuery(wli.featuredSlidesArray[i]).addClass("featured-right").removeClass("featured-left");
1013			};
1014			
1015			jQuery(wli.featuredSlidesArray[oldIndex]).addClass("featured-visible").removeClass("featured-active");
1016			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-active featured-visible").removeClass("featured-left");
1017		}
1018	}
1019	
1020	if (direction == "right") {
1021		if (activeIndex != 0) {
1022			jQuery(wli.featuredSlidesArray).removeClass("featured-visible");
1023			
1024			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-right featured-visible").removeClass("featured-active");
1025			activeIndex -= 1;
1026			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-active featured-visible").removeClass("featured-left");
1027		}
1028	};
1029	
1030	if (direction == "left") {
1031		if (activeIndex != wli.featuredSlidesArray.length - 1) {
1032			jQuery(wli.featuredSlidesArray).removeClass("featured-visible");
1033			
1034			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-left featured-visible").removeClass("featured-active");
1035			activeIndex += 1;
1036			jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-active featured-visible").removeClass("featured-right");
1037		}
1038	};
1039	
1040	if (direction == "initialize") {
1041		jQuery(wli.featuredSlidesArray[activeIndex]).addClass("featured-active featured-visible").removeClass("featured-right");
1042	}
1043	
1044	if (activeIndex == 0) {
1045		jQuery(".featured-event-nav-left").addClass("featured-invisible");
1046	} else {
1047		jQuery(".featured-event-nav-left").removeClass("featured-invisible");
1048	}
1049	
1050	if (activeIndex == wli.featuredSlidesArray.length - 1) {
1051		jQuery(".featured-event-nav-right").addClass("featured-invisible");
1052	} else {
1053		jQuery(".featured-event-nav-right").removeClass("featured-invisible");
1054	}
1055	
1056	jQuery(".featured-event-nav-item").removeClass("active-item");
1057	jQuery(".nav-item-" + (activeIndex + 1)).addClass("active-item");
1058};
1059
1060wli.getTallestHeight = function(elemArr) {
1061	var tallest = 0;
1062	
1063	for (var i = elemArr.length - 1; i >= 0; i--) {;
1064		tallest = Math.max(tallest, jQuery(elemArr[i]).outerHeight());
1065	};
1066	
1067	return tallest;
1068}
1069	
1070wli.normalizeWidth = function(elemArr) {
1071	var widestWidth = 0;
1072
1073	jQuery(elemArr).each(function() {
1074		widestWidth = Math.max(this.getBoundingClientRect().width, widestWidth);
1075	});
1076	
1077	jQuery(elemArr).width(widestWidth + 1);
1078};
1079
1080wli.widgetTypes = {
1081	"event-plain"		:	{
1082		EntityId : '0',
1083		maxResults : 5,
1084		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events.aspx",
1085		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events.xsl"
1086	},
1087	"event-block"		:	{
1088		EntityId : '0',
1089		maxResults : 5,
1090		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events2.aspx",
1091		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events2.xsl"
1092	},
1093	"event-block-type"		:	{
1094		EntityId : '0',
1095		maxResults : 5,
1096		eventType : "%",
1097		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events-type.aspx",
1098		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-events-type.xsl"
1099	},
1100	"event-featured"	:	{
1101		EntityId : '0',
1102		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-featured-events.aspx",
1103		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-featured-events.xsl",
1104		onComplete : function() {			
1105			wli.featuredSlidesArray = jQuery(".wli-featured-event-item").toArray();
1106			
1107			if (wli.featuredSlidesArray.length > 1) {
1108				jQuery(".featured-event-nav-right").click(function() {
1109					wli.updateSlider("left");
1110				});
1111				
1112				jQuery(".featured-event-nav-left").click(function() {
1113					wli.updateSlider("right");
1114				});
1115				
1116				jQuery(".featured-event-nav-item").click(function() {
1117					wli.updateSlider(this.dataset.wliNavItem);
1118				});
1119			} else {
1120				jQuery(".featured-event-nav-left, .featured-event-nav-right").remove();
1121			};
1122			
1123			wli.updateSlider("initialize");
1124				
1125			jQuery(".wli-featured-event-description").each(function() {
1126				jQuery(this).html(jQuery(this).text());
1127			});
1128			
1129			var tallestHeight = wli.getTallestHeight(wli.featuredSlidesArray);
1130			
1131			jQuery(".wli-featured-event-slide-container").height(tallestHeight);
1132			
1133			jQuery(window).on("load resize", function() {
1134				if (jQuery(window).width() <= 1024) {
1135					jQuery(".wli-featured-event-image-container, .wli-dettailed-event-details-container").css("display", "table-row");
1136					jQuery(".wli-featured-event-address-container, .wli-featured-event-datetime-container").addClass("centerFullWidth");
1137				} else {
1138					jQuery(".wli-featured-event-image-container, .wli-dettailed-event-details-container").css("display", "table-cell");
1139					jQuery(".wli-featured-event-address-container, .wli-featured-event-datetime-container").removeClass("centerFullWidth");
1140				};
1141				
1142				var tallestHeight = wli.getTallestHeight(wli.featuredSlidesArray);
1143			
1144				jQuery(".wli-featured-event-slide-container").height(tallestHeight);
1145			});
1146		}
1147	},
1148	"event-org-plain"			:	{
1149		EntityId : '0',
1150		maxResults : 5,
1151		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-org-events.aspx",
1152		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-org-events.xsl"
1153	},
1154	"event-com-plain"		:	{
1155		EntityId : '0',
1156		maxResults : 5,
1157		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-community-events.aspx",
1158		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-community-events.xsl"
1159	},
1160	"event-org-block"			:	{
1161		EntityId : '0',
1162		maxResults : 5,
1163		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-org-events2.aspx",
1164		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-org-events2.xsl"
1165	},
1166	"event-com-block"		:	{
1167		EntityId : '0',
1168		maxResults : 5,
1169		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-community-events2.aspx",
1170		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-community-events2.xsl"
1171	},
1172	"event-mo-block"		:	{
1173		EntityId : '0',
1174		maxResults : 5,
1175		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-member-events.aspx",
1176		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/events/wli-member-events.xsl"
1177	},
1178	"jobs-plain"			:	{
1179		maxResults : 5,
1180		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/jobs/wli-job-openings.aspx",
1181		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/jobs/wli-job-openings.xsl"
1182	},
1183	"members-plain"	:	{
1184		EntityId : '0',
1185		maxResults : 5,
1186		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/members/wli-new-members.aspx",
1187		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/members/wli-new-members.xsl"
1188	},
1189	"members-block"	:	{
1190		EntityId : '0',
1191		maxResults : 3,
1192		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/members/wli-new-members2.aspx",
1193		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/members/wli-new-members2.xsl"
1194	},
1195	"news-plain"		:	{
1196		articleType : '%',
1197		maxResults : 5,
1198		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/news/wli-news.aspx",
1199		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/news/wli-news.xsl"
1200	},
1201	"news-block"		:	{
1202		articleType : '%',
1203		maxResults : 5,
1204		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/news/wli-news2.aspx",
1205		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/news/wli-news2.xsl"
1206	},
1207	"sponsor-plain"	:	{
1208		contenttypeid : 11,
1209		xmlURL :  "/External/WCControls/V12/WebDeps/Widgets/sponsor/wli-sponsors.aspx",
1210		xslURL :  "/External/WCControls/V12/WebDeps/Widgets/sponsor/wli-sponsors.xsl",
1211		onComplete : function() {
1212			if (typeof marqueeInit !== "function") {
1213				var sponsorScript = document.createElement('script');
1214				
1215				sponsorScript.src = wli.widgetUrl + "/External/WCControls/V12/WebDeps/Widgets/scripts/crawler.js";
1216				
1217				sponsorScript.onload = function () {
1218					wli.SponsorScroll({
1219						target : ".wli-sponsor-scroller",
1220						scrollSpeed : 1,
1221						mouseScrollSpeed : 5
1222					});
1223				};
1224
1225				document.head.appendChild(sponsorScript);
1226			} else {
1227				wli.SponsorScroll({
1228					target : ".wli-sponsor-scroller",
1229					scrollSpeed : 1,
1230					mouseScrollSpeed : 5
1231				});
1232			};
1233		}
1234	}
1235}
1236
1237wli.queryStringBuilder = function(arr) {
1238	for (var i = 0, j = arr.length; i < j; i++) {
1239		arr[i] = encodeURI(arr[i]);
1240	}
1241
1242	return "?" + arr.join("&");
1243}
1244
1245wli.widgetWrapper = function(obj) {
1246	var currObj = {};
1247	for (setting in obj) {
1248		currObj[setting] = obj[setting];
1249	}
1250	
1251	if (currObj.widgetType) {
1252		for (setting in wli.widgetTypes[currObj.widgetType]) {
1253			currObj[setting] = wli.widgetTypes[currObj.widgetType][setting];
1254		}
1255	};
1256	
1257	if (currObj.target) {
1258		if (jQuery(currObj.target).length > 0) {
1259			var elemData = jQuery(currObj.target).data();
1260		} else {
1261			return
1262		}
1263	} else {
1264		console.log("Widget called without a target");
1265		return
1266	};
1267	
1268	if (currObj.xmlURL) {
1269		var qsArr = [];
1270		
1271		if (elemData.wliGet) {
1272			 qsArr.push("maxresults=" + elemData.wliGet);
1273		}
1274		else if (currObj.maxResults) {
1275			qsArr.push("maxresults=" + currObj.maxResults);
1276		};
1277		
1278		if (elemData.wliEventType) {
1279			 qsArr.push("eventtype=" + elemData.wliEventType);
1280		}
1281		else if (currObj.eventType) {
1282			qsArr.push("eventtype=" + currObj.eventType);
1283		};
1284		
1285		if (elemData.wliEntityId) {
1286			 qsArr.push("entityid=" + elemData.wliEntityId);
1287		}
1288		else if (currObj.EntityId) {
1289			qsArr.push("entityid=" + currObj.EntityId);
1290		};
1291		
1292		if (elemData.wliArticleType) {
1293			qsArr.push("articletype=" + elemData.wliArticleType);
1294		} else if (currObj.articleType) {
1295			qsArr.push("articletype=" + currObj.articleType);
1296		};
1297
1298		if (elemData.wliWidget == "sponsor-plain") {
1299			if (elemData.wliContentTypeId) {
1300				qsArr.push("contenttypeid=" + elemData.wliContentTypeId);
1301			} else {
1302				qsArr.push("contenttypeid=11");
1303			}
1304			
1305			if (elemData.wliElementName) {
1306				qsArr.push("element=" + elemData.wliElementName);
1307			}
1308			else {
1309				qsArr.push("element=sponsor");
1310			}
1311		};
1312
1313		if (elemData.wliWidget == "members-plain" || elemData.wliWidget == "members-block") {
1314			if (elemData.wliDaysNew) {
1315				qsArr.push("membersince=" + elemData.wliDaysNew);
1316			} else {
1317				qsArr.push("membersince=45");
1318			}
1319		}
1320		
1321		currObj.xmlURL = currObj.xmlURL + wli.queryStringBuilder(qsArr);
1322	} else {
1323		console.log("Widget called without xmlURL");
1324		return
1325	}
1326	
1327	if (currObj.xslURL) {
1328		
1329	} else {
1330		console.log("Widget called without xslURL");
1331		return
1332	}
1333	
1334	if (elemData.wliScrolling) {
1335		currObj.scrolling = true;
1336	}
1337	
1338	if (elemData.wliShow) {
1339		currObj.scrollingItemsToShow = Number(elemData.wliShow);
1340	}
1341	
1342	wli.Widget.Create(wli.widgetUrl).XSLT(currObj);
1343}
1344
1345jQuery("[data-wli-widget]").each(function() {
1346	var currObj = {
1347		"target"			:	this,
1348		"widgetType"	:	this.dataset.wliWidget
1349	}
1350	
1351	wli.widgetWrapper(currObj);
1352});
1353
1354wli.WebMenu.Create(wli.homeUrl).PageSetup({
1355	breadcrumbs : ".wli-breadcrumbs-container",
1356	sitemap : ".wli-sitemap-container"
1357});

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.