PageSourceSearch

https://portal.insightglobal.com/App_Themes/Default/javascript/erecruit.js

js insightglobal.com collected 2026-10-02 05:11:06 UTC 65,549 bytes, 1,297 lines download raw bytes

1$(function () {
2	//restoring delayClick functionality for kendo, new version of jquery doesn't have this
3	//kendo has a dependency on it.
4	if (typeof kendo !== 'undefined' && kendo.support && !kendo.support.delayedClick) {
5		kendo.support.delayedClick = function () {
6			return true;
7		}
8	}
9})
10
11// Microsoft Ajax `String.format` replacement (for MVC page)
12if (!$.isFunction(String.format)) {
13	String.format = function () {
14		var s = arguments[0];
15		for (var i = 0; i < arguments.length - 1; i++) {
16			var reg = new RegExp("\\{" + i + "\\}", "gm");
17			s = s.replace(reg, arguments[i + 1]).replace('{{', '{').replace('}}', '}');
18		}
19		return s;
20	};
21}
22
23// Extends jQuery with browser.isIE check
24// $.browser.isIE()
25$.extend({
26	browser: {
27		isIE: function () {
28			return (window.navigator.userAgent.indexOf("MSIE ") > 0) || (window.navigator.userAgent.indexOf("Trident/") > 0);
29		}
30	}
31});
32
33
34function detectIEVersion() {
35  var ua = window.navigator.userAgent;
36
37  var msie = ua.indexOf('MSIE ');
38  if (msie > 0) {
39    // IE 10 or older => return version number
40    return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
41  }
42
43  var trident = ua.indexOf('Trident/');
44  if (trident > 0) {
45    // IE 11 => return version number
46    var rv = ua.indexOf('rv:');
47    return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
48  }
49
50  var edge = ua.indexOf('Edge/');
51  if (edge > 0) {
52    // Edge (IE 12+) => return version number
53    return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
54  }
55}
56
57
58// jQuery plugin that adds progress spinner to elements
59// $(el).progressloader(); // Show spinner
60// $(el).progressloader({show: false}); // Hide spinner
61$.fn.progressloader = function (customOptions) {
62
63	var options = $.extend("", $.fn.progressloader.defaultOptions, customOptions);
64
65	return this.each(function (e) {
66
67		var $element = $(this);
68
69		// $element is a jQuery object. The element must have a position:relative style applied
70		kendo.ui.progress($element, options.show);
71
72	});
73};
74
75$.fn.progressloader.defaultOptions = {
76	show: true
77};
78
79// Add Progress Spinner to element
80// showProgressSpinner("#element"); // Show spinner
81// showProgressSpinner("#element", false); // Hide spinner
82// The el must have a position:relative style applied
83function ShowSpinner(el, show) {
84	show = (show != null && show != "undefined") ? show : true;
85
86	$(el).progressloader({
87		show: show
88	});
89}
90
91var erecruit = {
92	Strings: {}
93};
94
95Object.assign(erecruit,
96	{
97		Notes:
98			{
99				// itemid is scheduleditemid if for confirmation but can be either note or scheduleditem id for deletion (depending on action)
100				DoAction: function (itemid, action, confirmtext) {
101					if (confirmtext && confirmtext != "" && !window.confirm(confirmtext))
102						return false;
103
104					$.ajax(
105						{
106							url: baseUrl + "Services/NoteService.asmx/" + action,
107							data: "{ itemid: '" + itemid + "', by: '" + erecruitcache.Current.UserID + "' }",
108							dataType: "json", type: "POST", contentType: "application/json; charset=utf-8",
109							success: function (result) {
110								result = $.parseJSON(result.d);
111
112								$(document).trigger("Note_Updated",
113									{
114										'UpdateAction': action,
115										'ItemID': itemid
116									});
117							},
118							error: function (err) {
119								alert(erecruit.String.TheItemWasNotUpdated + "\n" + $.parseJSON(err.responseText).Message);
120							}
121						});
122				}
123			},
124		CoolTips:
125			{
126				// divs to put into places while loading
127				MainLoaderDiv: "<div class='cooltiploading main'><img src='" + baseUrl + "Mvc/Content/Images/ajaxloader_small.gif' title='" + erecruit.Strings.Loading + "' /></div>",
128				TabLoaderDiv: "<div class='cooltiploading'><img src='" + baseUrl + "Mvc/Content/Images/ajaxloader_small.gif' title='" + erecruit.Strings.Loading + "' /></div>",
129				LoadingSpinner: "<div class='loading-container'>	<div class='loading-blocker'></div><div class='loading-spinner'></div></div>", //new loading spinner from erecruit style guide
130				// Defines options at the top of a cooltip that don't need an ajax load
131				ImmediateOptions:
132					{
133						Options: /* Localized text and tooltip properties post loading erecruit.js in source file 'LocalizationErecruitJs.cshtml' */
134							{
135								// {0} is always context, {1} is always refid
136								open: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "OpenPage('{0}', 'manage', '{1}');" },
137								newnote: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/note_add.png", clicktip: "data-tipsource='ManageScheduledItem, app/BL/ScheduledItem/ScheduledItem' data-tipmode='norc' data-tipargs=\"{{ AboutType: '{0}', ReferenceID:'{1}'}}\"" },
138								newscheduleditem: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/calendar_add.png", clicktip: "data-tipsource='ManageScheduledItem, app/BL/ScheduledItem/ScheduledItem' data-tipmode='norc' data-tipargs=\"{{ AboutType: '{0}', ReferenceID:'{1}', WithItem: true}}\"" },
139								newtask: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/task_add.png", clicktip: "data-tipsource='ManageScheduledItem, app/BL/ScheduledItem/ScheduledItem' data-tipmode='norc' data-tipargs=\"{{AboutType:'{0}', ReferenceID:'{1}', WithItem: true, TypeID: 110 }}\"" },
140								openattachment: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "require(['app/BL/Attachment/AttachmentPreview'], function (ap) { ap.OpenAttachment('{1}'); });" },
141								openattachmentinwindow: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "require(['app/BL/Attachment/AttachmentPreview'], function (ap) { ap.OpenAttachmentInWindow('" + baseUrl + "', '{1}'); });" },
142								downloadattachment: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "window.open('" + baseUrl + "Pages/General/ShowAttachment.aspx?refid={1}&mode=Download')" },
143								email: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newemail.png", js: "OpenPage('email', 'send', '{0}id_{1}', 'tomode={0}&ids={1}');" },
144								emailcandidate: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newemail.png", js: "OpenPage('email', 'send', '{0}id_{1}', 'tomode=candidate&referrer={0}:{1}');" },
145								emailcontact: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newemail.png", js: "OpenPage('email', 'send', '{0}id_{1}', 'tomode=contact&referrer={0}:{1}');" },
146								emailaddress: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newemail.png", js: "OpenPage('email', 'send', '{0}id_{1}', 'tomode={0}&ids={1}&to={3}');" },
147								emailaddressthroughoutlook: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newemail.png", js: "window.top.location='mailto:{2}{4}'" },
148								copyemailaddress: { iconUrl: baseUrl + "Mvc/Content/Images/icons/copy.png", js: "window.prompt(" + erecruit.Strings.CopyToClipboard + ", '{3}');" },
149								newcontact: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newcontact.png", js: "OpenPage('contact', 'new', '{0}id_{1}', '{0}id={1}');" },
150								newposition: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newposition.png", js: "OpenPage('position', 'new', '{0}id_{1}', '{0}id={1}');" },
151								newagreement: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newagreement.png", js: "OpenPage('agreement', 'new', '{0}id_{1}', '{0}id={1}');" },
152								newmatch: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newmatch.png", js: "OpenPage('match', 'new', '{0}id_{1}', '{0}id={1}');" },
153								newquickplacement: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newmatch.png", js: "OpenPage('match', 'new', '{0}id_{1}', 'quickplacement=true&{0}id={1}');" },
154								newopportunity: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newopportunity.png", js: "OpenPage('opportunity', 'new', '{0}id_{1}', '{0}id={1}');" },
155								newlegalcase: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/newlegalcase.png", js: "OpenPage('legalcase', 'new', '{0}id_{1}', '{0}id={1}');" },
156								opencandidatefromdatafield: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "OpenPage('candidate', 'manage', '{0}');" },
157								openpositionfromdatafield: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/open.png", js: "OpenPage('position', 'manage', '{0}');" },
158								editall: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/14/edit.png", clicktip: "data-tipname='{0}/editall' data-tipmode='norc' data-tipcontext='{0}' data-tiprefid='{1}'" },
159								bulkedithours: { text: "", iconUrl: baseUrl + "Mvc/Content/Images/icons/14/edit.png", clicktip: "data-tipname='{0}/bulkedithours' data-tipmode='norc' data-tipcontext='{0}' data-tiprefid='{1}'" },
160								findrelevantpositions: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/position.png", js: "OpenSearchPage('position', 'SimilarToCandidate','sourceCandidateId={1}');" },
161								findrelevantcandidates: { iconUrl: baseUrl + "Mvc/Content/Images/icons/14/candidate.png", js: "OpenSearchPage('candidate', 'SimilarToPosition','sourcePositionId={1}');" },
162								manageloginaccess: { iconUrl: baseUrl + "Mvc/Content/Images/icons/key.png", clicktip: "data-tipname='provision' data-tipmode='norc' data-tipcontext='{0}' data-tiprefid='{1}'" }
163							},
164						// Resolves an option for an element
165						ResolveOne: function (option, element) {
166							// catch special options in here
167							if (option == this.Options.opencandidatefromdatafield) // assumes presense of data-candidateid
168							{
169								return "<div " +
170									"class='rcoption' " +
171									"title=\"" + option.tooltip + "\" " +
172									"onclick=\"" + String.format(option.js, $(element).data("candidateid")) + "\">" +
173									"<img align='top' width='14' src='" + option.iconUrl + "'>" + option.text +
174									"</div>";
175							}
176							else if (option == this.Options.openpositionfromdatafield) // assumes presense of data-positionid
177							{
178								return "<div " +
179									"class='rcoption' " +
180									"title=\"" + option.tooltip + "\" " +
181									"onclick=\"" + String.format(option.js, $(element).data("positionid")) + "\">" +
182									"<img align='top' width='14' src='" + option.iconUrl + "'>" + option.text +
183									"</div>";
184							}
185							else if (option == this.Options.emailaddress || option == this.Options.emailaddressthroughoutlook || option == this.Options.copyemailaddress) // assumes presense of data-fullname and data-email
186							{
187								return "<div " +
188									"class='rcoption' " +
189									"title=\"" + String.format(option.tooltip, $(element).data("tipcontext"), $(element).data("tiprefid"), $(element).data("fullname"), $(element).data("email")) + "\" " +
190									"onclick=\"" + String.format(option.js, $(element).data("tipcontext"), $(element).data("tiprefid"), encodeURIComponent($(element).data("fullname")).replace(/'/g, "%27"), $(element).data("email"), ($(element).data("fullname") == "" ? $(element).data("email") : " <" + $(element).data("email") + ">")) + "\">" +
191									"<img align='top' width='14' src='" + option.iconUrl + "'>" + option.text +
192									"</div>";
193							}
194							else {
195								if (option.clicktip == null) // regular option
196								{
197									return "<div " +
198										"class='rcoption' " +
199										"title=\"" + String.format(option.tooltip, $(element).data("tipcontext"), $(element).data("tiprefid")) + "\" " +
200										"onclick=\"" + String.format(option.js, $(element).data("tipcontext"), $(element).data("tiprefid")) + "\">" +
201										"<img align='top' width='14' src='" + option.iconUrl + "'>" + option.text +
202										"</div>";
203								}
204								else // clicktip
205								{
206									return "<div class='rcoption' title=\"" + String.format(option.tooltip, $(element).data("tipcontext"), $(element).data("tiprefid")) + "\">" +
207										"<div class='clicktip' " + String.format(option.clicktip, $(element).data("tipcontext"), $(element).data("tiprefid")) + "><img align='top' width='14' src='" + option.iconUrl + "'>" + option.text + "</div></div>";
208								}
209							}
210						},
211						// Gets a list of all resolved options for an element
212						ResolveOptions: function (options, element) {
213							var returnlist = "";
214
215							for (var i = 0; i < options.length; i++) {
216								if (options[i] != null)
217									returnlist += this.ResolveOne(options[i], element);
218							}
219
220							return returnlist == "" ? returnlist :
221								"<div class='rcoptions ui-helper-clearfix'>" + returnlist + "</div>";
222						},
223						// Given an element, figures out the context and returns a list of ImmediateOptions.Option
224						GetElementOptions: function (element) {
225
226							// data-tipimmediateoptionscontext="emailaddress"
227							// for when you want to override the immidiate options but don't have an actual about type to do it with
228							if ($(element).data("tipimmediateoptionscontext") != null) {
229								switch ($(element).data("tipimmediateoptionscontext")) {
230									case "emailaddress": return [erecruit.CoolTips.ImmediateOptions.Options.emailaddress, erecruit.CoolTips.ImmediateOptions.Options.emailaddressthroughoutlook];
231								}
232							}
233							else {
234								var context = $(element).data("tipcontext");
235
236								if (isLegalCaseAboutTypeEnabled)
237									erecruit.CoolTips.ImmediateOptions.Options.newlegalcase = null;
238
239								switch (erecruitcache.Current.LoggedInAsMode) {
240									case "Vendor":
241										switch (context) {
242											case "candidate": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.email, erecruit.CoolTips.ImmediateOptions.Options.newmatch];
243											case "position": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newmatch];
244											case "match": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.emailcandidate];
245											case "timesheet": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote];
246											case "attachment": return [erecruit.CoolTips.ImmediateOptions.Options.openattachment, erecruit.CoolTips.ImmediateOptions.Options.openattachmentinwindow, erecruit.CoolTips.ImmediateOptions.Options.downloadattachment];
247											case "contact": return [];
248										}
249									case "VendorManager":
250										switch (context) {
251											case "candidate": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.email];
252											case "contact": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.email, erecruit.CoolTips.ImmediateOptions.Options.newposition, erecruit.CoolTips.ImmediateOptions.Options.newagreement, erecruit.CoolTips.ImmediateOptions.Options.newopportunity];
253											case "company": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newcontact, erecruit.CoolTips.ImmediateOptions.Options.newposition, erecruit.CoolTips.ImmediateOptions.Options.newagreement];
254											case "position": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
255											case "match": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.emailcandidate, erecruit.CoolTips.ImmediateOptions.Options.emailcontact];
256											case "candidateapplication": return [erecruit.CoolTips.ImmediateOptions.Options.opencandidatefromdatafield, erecruit.CoolTips.ImmediateOptions.Options.openpositionfromdatafield, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
257											case "agreement": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
258											case "opportunity": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newcontact];
259											case "legalcase": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
260											case "marketingcampaign": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
261											case "timesheet": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
262											case "attachment": return [erecruit.CoolTips.ImmediateOptions.Options.openattachment, erecruit.CoolTips.ImmediateOptions.Options.openattachmentinwindow, erecruit.CoolTips.ImmediateOptions.Options.downloadattachment];
263											case "seed": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
264											case "clientproject": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newposition];
265										}
266									default:
267										switch (context) {
268											case "candidate": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.email, erecruit.CoolTips.ImmediateOptions.Options.newmatch, erecruit.CoolTips.ImmediateOptions.Options.newquickplacement, erecruit.CoolTips.ImmediateOptions.Options.newopportunity, erecruit.CoolTips.ImmediateOptions.Options.findrelevantpositions];
269											case "contact": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.email, erecruit.CoolTips.ImmediateOptions.Options.newposition, erecruit.CoolTips.ImmediateOptions.Options.new
269agreement, erecruit.CoolTips.ImmediateOptions.Options.newopportunity, erecruit.CoolTips.ImmediateOptions.Options.manageloginaccess];
270											case "company": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newcontact, erecruit.CoolTips.ImmediateOptions.Options.newposition, erecruit.CoolTips.ImmediateOptions.Options.newagreement, erecruit.CoolTips.ImmediateOptions.Options.newopportunity];
271											case "position": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newmatch, erecruit.CoolTips.ImmediateOptions.Options.newquickplacement, erecruit.CoolTips.ImmediateOptions.Options.findrelevantcandidates];
272											case "match": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.editall, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.emailcandidate, erecruit.CoolTips.ImmediateOptions.Options.emailcontact];
273											case "candidateapplication": return [erecruit.CoolTips.ImmediateOptions.Options.newmatch, erecruit.CoolTips.ImmediateOptions.Options.newquickplacement, erecruit.CoolTips.ImmediateOptions.Options.opencandidatefromdatafield, erecruit.CoolTips.ImmediateOptions.Options.openpositionfromdatafield, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
274											case "agreement": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
275											case "opportunity": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newcontact, erecruit.CoolTips.ImmediateOptions.Options.newposition, erecruit.CoolTips.ImmediateOptions.Options.newlegalcase];
276											case "legalcase": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
277											case "marketingcampaign": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
278											case "timesheet":
279												if (erecruitcache.Current.LoggedInAsMode == "Recruiter") {
280													return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.bulkedithours];
281												} else {
282													return [erecruit.CoolTips.ImmediateOptions.Options.open];
283												}
284											case "attachment": return [erecruit.CoolTips.ImmediateOptions.Options.openattachment, erecruit.CoolTips.ImmediateOptions.Options.openattachmentinwindow, erecruit.CoolTips.ImmediateOptions.Options.downloadattachment];
285											case "seed": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask];
286											case "clientproject": return [erecruit.CoolTips.ImmediateOptions.Options.open, erecruit.CoolTips.ImmediateOptions.Options.newnote, erecruit.CoolTips.ImmediateOptions.Options.newscheduleditem, erecruit.CoolTips.ImmediateOptions.Options.newtask, erecruit.CoolTips.ImmediateOptions.Options.newposition];
287										}
288								}
289							}
290
291							return [];
292						}
293					},
294				// Defines methods and options that get and load widgets into the cooltip body
295				Widgets:
296					{
297						// returns common parameters used by most cooltips
298						GetCommonParameters: function (element) {
299							var tipdata = $(element).data("tipdata");
300							if (typeof tipdata !== "string") tipdata = JSON.stringify(tipdata);
301							return {
302								"AboutType": $(element).data("tipcontext"),
303								"ReferenceID": $(element).data("tiprefid"),
304								"LoggedInAsMode": erecruitcache.Current.LoggedInAsMode,
305								"CurrentUserID": erecruitcache.Current.UserID,
306								"CurrentEntityID": erecruitcache.Current.EntityID,
307								"AdditionalData": encodeURIComponent(tipdata).replace(/'/g, "%27")
308							};
309						},
310						// Figures out what ajax, if any, is required for given mode and context
311						RequiredAjax: function (element) {
312							var mode = $(element).data("tipmode");
313							var context = $(element).data("tipcontext");
314
315							switch (mode) {
316								case "overview":
317									switch (context) {
318										case "candidate": return { Tabs: { Main: true, Counts: ["Skill", "Match", "Note", "Involved"] } };
319										case "contact": return { Tabs: { Main: true, Counts: ["Position", "Match", "Note", "Involved"] } };
320										case "company": return { Tabs: { Main: true, Counts: ["Skill", "Contact", "Position", "Match", "Note", "Involved"] } };
321										case "position": return { Tabs: { Main: true, Counts: ["Skill", "Match", "Note", "Involved"] } };
322										case "seed": return { Tabs: { Main: true, Counts: ["Note", "Involved"] } };
323										case "clientproject": return { Tabs: { Main: true, Counts: ["Match", "Note", "Position"] } };
324										case "recruiter": return { Tabs: null, Widget: context + "overview" };
325										case "scheduleditem": return { Tabs: null, Widget: context + "overview" };
326										case "opportunity":
327											if (isLegalCaseAboutTypeEnabled)
328												return { Tabs: { Main: true, Counts: ["LegalCase", "Position", "Note"] } };
329											else
330												return { Tabs: { Main: true, Counts: ["Position", "Note"] } };
331									}
332									break;
333								default: // no mode - just a tipname
334									if ($(element).data("tipname") != null)
335										return { Widget: $(element).data("tipname") };
336									else if ($(element).data("tipsource"))
337										return { Source: $(element).data("tipsource"), Args: $(element).data("tipargs") };
338							}
339
340							return null;
341						},
342						// gets the html for a specific widget
343						// takes { Widget: widgetname, Mode: "replace", Where: element for mode, CoolTip: element of tip, Data: use if loading not from cooltip to directly pass required data) }
344						GetWidget: function (config, withSession) {
345							if (config.Source) {
346								// This is a Knockout-powered widget
347								// The tipsource parameter should have the form "ClassName, app/Path/To/Module"
348								// The tipargs parameter may be either an array or a single value
349								// The erecruit.autobind function is defined in /App_Themes/Default/js/autobind.ts
350								erecruit.autobind(config.Source, config.Args,
351									function () {
352										var where = $("<div " + ((config.Style !== undefined && config.Style["style"] !== undefined) ? "style='" + config.Style["style"] + "'" : "") + ">").insertBefore(config.Where);
353										config.Where.remove();
354										return where;
355									},
356									function (where, viewModel) {
357										where.data("ViewModel", viewModel).trigger("ViewModelLoaded", viewModel);
358										Tipped.refresh(where[0]);
359										if (viewModel.AutobindComplete) {
360											viewModel.AutobindComplete(where);
361										}
362									});
363
364								return;
365							}
366
367							var data = config.CoolTip ?
368								JSON.stringify(this.GetCommonParameters(config.CoolTip)) :
369								config.Data;
370
371							function success(result) {
372
373								if (!ismvcget) {
374									result = result.d; // not sure why... see other comment
375								}
376
377								var $result = $(result);
378								switch (config.Mode) {
379									case "replace":
380										config.Where.before($result).remove();
381										break;
382									case "replaceinside":
383										config.Where.html($result);
384										break;
385									default:
386										alert(erecruit.Strings.WidgetModeNotSupported + config.Mode);
387								}
388
389								erecruit.CoolTips.Widgets.LoadAutoWidgets($result);
390								//after jquery update $(document).ready() and $(function(){}) (which most of the time are the same based in jquery docs)
391								//are behaving a little bit different which is causing issues with tipped, since it requires to have UI final rendered before we call tipped.refresh
392								//set timeout makes sure refresh is pushed at the end of the queue and runs when UI is final
393								window.setTimeout(function () {
394									Tipped.refresh($result[0]);
395								})
396							}
397
398							function error(err) {
399								switch (config.Mode) {
400									case "replace":
401									case "replaceinside":
402										config.Where.replaceWith("<div class='warning messaging'>" + erecruit.Strings.OhNoYourWidgetCouldntBeLoaded + "<br />" + err.responseText + "</div>");
403										break;
404								}
405
406								Tipped.refresh(config.Where[0]);
407							}
408
409							var ismvcget = !!config.TipURL;
410
411							$.ajax({
412								type: ismvcget ? "GET" : "POST",
413								contentType: ismvcget ? "application/x-www-form-urlencoded; charset=utf-8" : "application/json; charset=utf-8",
414								url: ismvcget ? config.TipURL : baseUrl + "Services/CoolTipService.asmx/GetWidget" + (withSession ? "WithSession" : ""),
415								data: ismvcget ? null : "{'widgetname':'" + config.Widget + "','data':'" + data + "'}",
416								dataType: ismvcget ? "html" : "json",
417								success: success,
418								error: error
419							});
420						},
421						// Loads the widgets according to tip mode and context
422						// should only be called if requiredajax is not null
423						LoadWidgets: function (requiredajax, content, element) {
424							var context = $(element).data("tipcontext");
425							var refid = $(element).data("tiprefid");
426							var usesession = (typeof $(this).attr('data-session') != 'undefined' && $(this).attr('data-session') && $(this).data("session") == 'disabled') ? false : true;
427							var mode = $(element).data("tipmode");
428
429							if (mode == "overview" && erecruitcache.Current.LoggedInAsMode != "Recruiter" && erecruitcache.Current.LoggedInAsMode != "VendorManager") {
430								$(".cooltiploading.main", content).replaceWith("<div class='warning messaging'>" + erecruit.Strings.ThisFeatureIsAvailableOnlyToRecruiterAndVendorManager + "</div>");
431							}
432							else
433								// if Tabs is true, then this must have a name and therefore, we must call spview
434								// if counts are also true, then show the name and counts as tabs
435								if (requiredajax.Tabs != null) {
436									$.ajax(
437										{
438											type: "POST",
439											contentType: "application/json; charset=utf-8",
440											url: baseUrl + "Services/CoolTipService.asmx/GetCounts",
441											data: "{'abouttype':'" + context + "','referenceid':'" + refid + "','userid':'" + erecruitcache.Current.UserID + "','loggedinas':'" + erecruitcache.Current.LoggedInAsMode + "','entityid':'" + erecruitcache.Current.EntityID + "'}",
442											dataType: "json",
443											success: function (result) {
444												result = result.d; // I have no idea why this is needed but for some reason the json is coming as an object under a property called "d". :-/ - [if] It's used to prevent JSON hijack attack
445												var tabs = "";
446
447												// main tab
448												if (requiredajax.Tabs.Main)
449													tabs += "<li data-widgetname='" + context + "overview'><a href='#tab-Main'><img align='top' height='14' width='14' src='" + baseUrl + "Mvc/Content/Images/icons/abouttypes/" + erecruitcache.Lookup.AboutType(context) + ".png' />&nbsp;" + result.Name + "</a></li>";
450
451												// count tabs
452												for (var i = 0; i < requiredajax.Tabs.Counts.length; i++)
453													tabs += "<li style='float: right;' data-widgetname='" + requiredajax.Tabs.Counts[i].toString() + "List'><a href='#tab-" + requiredajax.Tabs.Counts[i] + "Count' title='" + requiredajax.Tabs.Counts[i] + " " + erecruit.Strings.Count + "'><img align='top' width='14px' height='14px' style='margin-right: 3px;' src='" + baseUrl + "Mvc/Content/Images/icons/" + requiredajax.Tabs.Counts[i] + ".png' />" + result[requiredajax.Tabs.Counts[i] + "Count"] + "</a></li>";
454
455												tabs = "<div class='cooltiptabs'><ul>" + tabs + "</ul>";
456
457												// main (overview) tab body
458												tabs += "<div id='tab-Main'>" + erecruit.CoolTips.TabLoaderDiv + "</div>";
459
460												// when a tab is selected, if tab body contains the loader div, it means it needs to be loaded
461												for (var i = 0; i < requiredajax.Tabs.Counts.length; i++)
462													tabs += "<div id='tab-" + requiredajax.Tabs.Counts[i] + "Count'>" + erecruit.CoolTips.TabLoaderDiv + "</div>";
463
464												tabs += "</div>";
465
466												// replace loader with tabs
467												$(".cooltiploading.main", content).before(tabs).remove();
468
469												// tabify tabs
470												$(".cooltiptabs", content).tabs(
471													{
472														create: function (event, ui) {
473															if ($(".cooltiploading", ui.panel).length > 0) {
474																erecruit.CoolTips.Widgets.GetWidget(
475																	{
476																		Widget: ui.tab.data("widgetname"),
477																		Mode: "replace",
478																		Where: $(".cooltiploading", ui.panel),
479																		CoolTip: element
480																	}, usesession);
481															}
482
483															Tipped.refresh(element);
484														},
485														activate: function (event, ui) {
486															if ($(".cooltiploading", ui.newPanel).length > 0) {
487																erecruit.CoolTips.Widgets.GetWidget(
488																	{
489																		Widget: ui.newTab.data("widgetname"),
490																		Mode: "replace",
491																		Where: $(".cooltiploading", ui.newPanel),
492																		CoolTip: element
493																	}, usesession);
494															}
495
496															if (ui && ui.newPanel) {
497																Tipped.refresh(ui.newPanel[0]);
498															}
499															Tipped.refresh(element);
500														}
501													});
502
503												Tipped.refresh(element);
504											},
505											error: function (err) {
506												$(".cooltiploading.main", content).replaceWith("<div class='warning messaging'>" + erecruit.Strings.OhNoYourWidgetCouldntBeLoaded + "<br />" + err.responseText + "</div>");
507											}
508										});
509								}
510								else // must be trying to open one widget
511								{
512									erecruit.CoolTips.Widgets.GetWidget(
513										{
514											Widget: requiredajax.Widget,
515											Source: requiredajax.Source,
516											Args: requiredajax.Args,
517											Mode: "replace",
518											Where: $(".cooltiploading.main", content),
519											CoolTip: element
520										}, usesession);
521								}
522						},
523						// checks for existence of .autowidget and loads them
524						LoadAutoWidgets: function (root) {
525							$.each($(".autowidget:not('.loading')", root || document), function (i, el) {
526								$(el).addClass('loading');
527								var usesession = (typeof $(this).attr('data-session') != 'undefined' && $(this).attr('data-session') && $(this).data("session") == 'disabled') ? false : true;
528
529								erecruit.CoolTips.Widgets.GetWidget(
530									{
531										Widget: $(this).data("tipname"),
532										TipURL: $(this).data("tipurl"),
533										Source: $(this).data("tipsource"),
534										Args: $(this).data("tipargs"),
535										Mode: "replace",
536										Where: $(this),
537										CoolTip: el,
538										Style: $(this).data("tipstyle")
539									}, usesession);
540							});
541						}
542					},
543				// element has the following data items: tipmode, tipcontext, tiprefid, tipname, tipdata
544				// mode can be overview, norc
545				// context is abouttype name lowercase
546				// refid is referenceid
547				// tipname is the name of the tip if mode is not overview
548				// tipdata is json
549				LoadCoolTip: function (content, element) {
550					var mode = $(element).data("tipmode");
551
552					var isOverview = (mode == "overview" && erecruitcache.Current.LoggedInAsMode != "Recruiter" && erecruitcache.Current.LoggedInAsMode != "VendorManager");
553
554					var immediateoptions = mode != "norc" && !isOverview ?
555						erecruit.CoolTips.ImmediateOptions.ResolveOptions(erecruit.CoolTips.ImmediateOptions.GetElementOptions(element), element) :
556						"";
557
558					var requiredajax = erecruit.CoolTips.Widgets.RequiredAjax(element);
559					var loaderdiv = requiredajax != null ? erecruit.CoolTips.MainLoaderDiv : "";
560
561					if (immediateoptions != "")
562						$(".cooltiploading.main", content).before(immediateoptions);
563
564					$(".cooltiploading.main", content).before("<div class='cooltipmessage bordered' style='display: none; margin: 5px 0; clear: both;'>backup messagebox</div>")
565
566					if (requiredajax != null)
567						erecruit.CoolTips.Widgets.LoadWidgets(requiredajax, content, element);
568					else
569						$(".cooltiploading.main", content).remove();
570				},
571				_findMessageDiv: function (widgetid, create) {
572					var messagediv = $("#" + widgetid + "_message");
573					if (!messagediv.length) messagediv = $(".cooltipmessage:first", $("#" + widgetid).closest(".t_Tooltip"));
574					if (!messagediv.length) messagediv = $(".cooltipmessage:first", $("#" + widgetid));
575					if (!messagediv.length && create) messagediv = $("<div>", { 'class': 'cooltipmessage' }).prependTo("#" + widgetid);
576
577					return messagediv;
578				},
579				// shows a message above a widget. message type is Info, Warning or Error
580				// widgetid_message is not found, travel up the dom from source to the closest .cooltipmessage and show it there
581				ShowMessage: function (widgetid, messagetype, message) {
582					var messagediv = erecruit.CoolTips._findMessageDiv(widgetid, true);
583					var refresh = function () { Tipped.refresh(messagediv[0]); };
584
585					messagediv
586						.hide()
587						.removeClass("info error warning")
588						.addClass(messagetype.toLowerCase())
589						.html("<div title='" + erecruit.Strings.CloseMessage + "' class=\"close\" onclick=\"erecruit.CoolTips.HideMessage('" + widgetid + "', $(this).closest('.cooltipmessage'))\"></div>" + message)
590						.slideDown("fast", refresh);
591					refresh();
592				},
593				HideMessage: function (widgetid, cooltipmessage) {
594					var d = erecruit.CoolTips._findMessageDiv(widgetid, false);
595					if (!d.length && cooltipmessage) d = cooltipmessage;
596					d.slideUp("fast", function () { Tipped.refresh(d[0]); });
597				},
598				ClearMessages: function (widgetid) {
599					var messagediv = erecruit.CoolTips._findMessageDiv(widgetid, true);
600					var refresh = function () { Tipped.refresh(messagediv[0]); };
601					messagediv.empty().hide();
602					refresh();
603				},
604				// hides all the cooltips for a selector
605				HideCoolTips: function (selector) {
606					$(selector).each(function () {
607						Tipped.hide(erecruit.CoolTips.FakeTrigger(this));
608					});
609				},
610
611				FakeTrigger: function (element, value) {
612					var key = "{8E0A03B5-02BE-4EA6-B011-616AC8FD1FFC}";
613					var $e = $(element);
614					if (value === undefined) {
615						return $e.data(key);
616					}
617					else {
618						$e.data(key, value);
619						erecruit.CoolTips.RealTrigger(value, $e);
620					}
621				},
622
623				RealTrigger: function (elementOrContentOrFakeTrigger, value) {
624					var key = "{34AC4343-7A38-4683-8292-D56C1875F5BE}";
625					var $e = $(elementOrContentOrFakeTrigger);
626					var fakeTrigger = erecruit.CoolTips.FakeTrigger($e) || Tipped.findElement($e[0]) || $e;
627					return value === undefined ? $(fakeTrigger).data(key) : $(fakeTrigger).data(key, value);
628				},
629
630				// hides the cooltip and causes the next click to recreate it
631				// if reload is true, calls click on the original trigger effectively reopening the tip
632				HideAndReset: function (id, timeout, callback, reload) {
633					var el = erecruit.CoolTips.RealTrigger("#" + id)
634					var fakeTrigger = erecruit.CoolTips.FakeTrigger(el);
635
636					window.setTimeout(function () {
637						Tipped.hide(fakeTrigger);
638						if (el) el.data("tiploaded", false);
639						Tipped.remove(fakeTrigger);
640
641						if (reload != null && reload && el)
642							el.trigger('click');
643
644						if (callback != null)
645							callback(el);
646					}, timeout);
647				},
648				// reloads a widget in place. pass either a widgetid or any element inside a widget
649				ReloadInPlace: function (selector, reloaddata) {
650					var wrapper = $(selector).closest(".widgetwrapper");
651					var usesession = (typeof wrapper.attr('data-session') != 'undefined' && wrapper.attr('data-session') && wrapper.data("session") == 'disabled') ? false : true;
652					if (wrapper.length > 0) {
653						erecruit.CoolTips.Widgets.GetWidget(
654							{
655								Widget: wrapper.data("widgetname"),
656								Mode: "replace",
657								Where: wrapper,
658								Data: (reloaddata == null ? wrapper.data("reloaddata") : reloaddata),
659								TipURL: wrapper.data("tipurl")
660							}, usesession);
661					}
662				},
663				Initialize: function () {
664					// var is overwritten when MVC tips were introduced (erecruit.js loaded multiple times per frame)
665					// lets save this at the body level instead so MVC and ASP can share
666					$(document.body).data('tipcount', 0);
667					erecruit.CoolTips.handlingtipclick = false;
668					function InitCommon(e) {
669						var $this = $(this);
670						var fakeTrigger = erecruit.CoolTips.FakeTrigger($this);
671						var isfirsttime = $this.data("tiploaded") != "true";
672						var target = $this.data("tiptarget") || 'element';
673						var hook = $this.data("tiphook") || (e.data.click == "right" ? 'righttop' : 'rightmiddle');
674						var tipUrl = $this.data("tipurl");
675						var tipElement = $this.data("tipelement");
676
677						if (isfirsttime) {
678							var insidetooltip = ($this.parents(".t_Tooltip").length > 0);
679
680							if (!fakeTrigger) {
681								erecruit.CoolTips.FakeTrigger($this, fakeTrigger = $("<div class='__fake_trigger'>").appendTo("body"));
682							}
683							fakeTrigger.css({ position: 'absolute', 'z-index': -1000 })
684								.position({ my: "left top", at: "left top", of: $this })
685								.width($this.width()).height($this.height());
686
687							var loader;
688							if ($this.data("tipshowspinner"))//if cooltip has data-tipshowspinner="true" then show a loading spinner while loading
689							{
690								//NOTE: in this version we dynamically add, show and later destroy the spinner
691								//other option would be to create it once and then show/hide but that would be more usefull if we extract spinner functionality as separate class and use it where needed
692								loader = $(erecruit.CoolTips.LoadingSpinner).insertAfter($this).addClass("show");
693							}
694							else {
695								loader = null;
696							}
697
698							Tipped.create(fakeTrigger[0], tipUrl || tipElement || function () { return erecruit.CoolTips.MainLoaderDiv; },
699								{
700									skin: 'erecruitDefault',
701									ajax: !!tipUrl,
702									fixed: true,
703									inline: !!tipElement,
704									// because of event delegation, must close cooltips manually on document click to be able to maintain stack properly
705									hideOn: false,
706									hideOthers: !insidetooltip,
707									closeButton: (e.data.click == "left"),
708									showOn: e.data.click == "right" ? 'contextmenu' : "click",
709									target: target,
710									// zindex has to be set to maintain stack properly
711									zIndex: 2000000,
712									hook: hook,
713									onShow: function (content, element) {
714										if (loader) {//if there is loading spinner remove it
715											loader.remove();
716										}
717										var isfirsttime = $this.data("tiploaded") != "true";
718										var tipcount = $(document.body).data('tipcount');
719										$this.data("tiporder", ++tipcount);
720										$(document.body).data('tipcount', tipcount);
721
722										if (isfirsttime) {
723											erecruit.CoolTips.LoadCoolTip(content, $this[0]);
724											$this.data("tiploaded", "true");
725										}
726									},
727									onHide: function (content, element) {
728										var wrapper = $(content).find(".widgetwrapper")[0];
729										if ($this.hasClass("clicktip") && !$this.hasClass("dont-close-tipstack")) {
730											CloseTipStackAbove(content);
731										}
732
733										if (wrapper) {
734											var id = wrapper.id.split("wrapper_")[1];
735											$(document).trigger("CoolTip_Hidden", { WidgetID: id });
736										}
737
738										var mct = $(content).find(":data(erecruit.CoolTips.ManagedCooltipFrame)");
739										if (mct) {
740											//Unwrap the cooltip frame and call OnHide if it's defined
741											var mcf = mct.data("erecruit.CoolTips.ManagedCooltipFrame");
742											if (mcf && mcf.OnHide) mcf.OnHide();
743										}
744									}
745								});
746						}
747
748						Tipped.show(fakeTrigger[0]);
749						return false;
750					}
751
752					// For all infotip blue skin cooltips which height dimension is larger then page body
753					// we need to make them scrollable
754					require(['app/Controls/Tipped'], function (tipped) {
755						tipped.getExtender().makeScrollable();
756					});
757
758					function InitHover(e) {
759						var tiptrigger = $(this);
760
761						if (tiptrigger.hasClass("infotip")) {
762							Tipped.create(this, tiptrigger.attr("title"),
763								{
764									skin: 'blue',
765									showDelay: tiptrigger.hasClass('fast') ? 0 : 2000,
766									maxWidth: tiptrigger.hasClass('wide') ? 500 : 230
767								});
768						}
769						else if (tiptrigger.hasClass("errortip")) {
770							var content = "";
771
772							if (tiptrigger.hasClass("has-validation") && tiptrigger.hasClass("input-validation-error")) {
773								content = function () { return tiptrigger.parent().find("span[generated='true']").html() };
774							}
775							else if (tiptrigger.hasClass("has-validation") && !tiptrigger.hasClass("input-validation-error")) {
776								content = "";
777							}
778							else {
779								content = tiptrigger.attr("title");
780							}
781
782							if (content != "") {
783								Tipped.create(this, content,
784									{
785										skin: 'red',
786										showDelay: 0,
787										maxWidth: 230
788									});
789							}
790						}
791						else if (tiptrigger.hasClass('menutip')) {
792							if (tiptrigger.data('tiploaded') != true) {
793								// string to object
794								var params = eval('(' + tiptrigger.data('tipdata') + ')');
795								var hook = tiptrigger.data('tiphook');
796								var aboutType = tiptrigger.data('tipcontext');
797								var referenceId = tiptrigger.data('tiprefid');
798
799								// object to parameter list
800								var str = "";
801								for (var key in params) {
802									if (str != "") {
803										str += "&";
804									}
805									str += key + "=" + params[key];
806								}
807
808								var menuUrl =
809									baseUrl +
810									'MVC/Menu/' +
811									tiptrigger.data('tipname') + '/' +
812									(aboutType != undefined ? aboutType + '/' : '') +
813									(referenceId != undefined ? referenceId + '/' : '') +
814									(str != "" ? '?' + str : '');
815
816								Tipped.create(tiptrigger, menuUrl, {
817									skin: 'white',
818									ajax: true,
819									hook: hook,
820									onShow: function (c, e) {
821										$(c).children('.clicktip').data('tiptarget', tiptrigger[0].id);
822									}
823								});
824
825								tiptrigger.data('tiploaded', true);
826							}
827						}
828					}
829
830					function CloseTipStackAbove(tip) {
831						var tips = $(".t_Tooltip");
832						var opentips = [];
833						$.each(tips, function (i, el) {
834							//necessary for firefox - reasonable ways to detect tipped's version of visibility are unreliable in firefox
835							if ($(el).css("top") != "-10000px") {
836								opentips.push(el);
837							}
838						});
839						if (opentips.length > 0) {
840							var highestclicktip = 0;
841							var curtiporder = (tip != null) ? $(erecruit.CoolTips.RealTrigger(tip)).data("tiporder") : 0;
842
843							//find the tiporder of the highest clicktip
844							$.each(opentips, function (i, el) {
845								var tipelement = $(erecruit.CoolTips.RealTrigger(el));
846								var tiporder = tipelement.data("tiporder");
847
848								if (tipelement.hasClass("clicktip") && tiporder > highestclicktip)
849									highestclicktip = tipelement.data("tiporder");
850							});
851
852							// traverse tips, check order of each and close any that are higher order unless there is a clicktip that's even higher
853							$.each(opentips, function (i, el) {
854								var tipelement = $(erecruit.CoolTips.RealTrigger(el));
855								var tiporder = tipelement.data("tiporder");
856
857								if (tiporder > curtiporder && tiporder > highestclicktip) {
858									Tipped.hide(erecruit.CoolTips.FakeTrigger(tipelement));
859								}
860							});
861						}
862					}
863
864					// YOU ONLY NEED TO INIT ONCE PER PAGE
865					// init rightclick tips
866					$(document).off("contextmenu", ".cooltip").on("contextmenu", ".cooltip", { click: "right" }, InitCommon);
867
868					// init leftclick tips
869					$(document).off("click", ".clicktip").on("click", ".clicktip", { click: "left" }, InitCommon);
870					// init leftclick cooltips (opened via left click but behaves like a cooltip without an x to close)
871					$(document).off("click", ".coolclicktip").on("click", ".coolclicktip", { click: "right" }, InitCommon);
872					// init infotips
873					$(document).off("mouseenter", ".infotip, .errortip").on("mouseenter", ".infotip, .errortip", InitHover);
874					// init rcoption black tips
875					$(document).off("mouseenter", ".rcoption").on("mouseenter", ".rcoption", function () { Tipped.create(this) });
876					// init 'quicktips'
877					$(document).off('mouseenter', '.menutip').on('mouseenter', '.menutip', InitHover);
878
879					// init click handling and stacking
880					$(document).off("click", ".t_Tooltip").on("click", ".t_Tooltip", function (e) {
881						erecruit.CoolTips.handlingtipclick = true;
882						CloseTipStackAbove(this);
883					});
884
885					// OTK (2019-08-28): This is a patch to support correct tooltip stack closing behavior
886					// At one time there will have been several Initialize closures run.
887					// However, we have to ensure there at that time there is just *one* click handler that 
888					// handles tip closing along the stack. The following hack will do the trick.
889					// *** BEGIN HACK ***
890					erecruit.CoolTips.clickHandler = erecruit.CoolTips.clickHandler || function (e) {
891						if (!erecruit.CoolTips.handlingtipclick) {
892 							CloseTipStackAbove(null);
893 						}
894						erecruit.CoolTips.handlingtipclick = false;
895					}
896					// init closing on click outside
897					if (erecruit.CoolTips.clickHandler.isClickBound === undefined) {
898						erecruit.CoolTips.clickHandler.isClickBound = true;
899						$(document).on("click", erecruit.CoolTips.clickHandler);
900					}
901					// *** END HACK ***
902					// init autowidgets
903					erecruit.CoolTips.Widgets.LoadAutoWidgets();
904				}
905			},
906		Controls:
907			{
908				InitializeFields: function (scopeid, callback, scope) {
909					require(['app/Localization/LocalizationService', 'app/Localization/LocalizationUtils'], function (localization, localizationInit) {
910						var localService = localization.GetService();
911
912						$("#" + scopeid + " input[data-inputtype='list']").each(function (index) {
913							$(this).dropdown({
914								minLength: 0,
915								allowEmpty: true,
916								initSelectedValue: $(this).val() == null || $(this).val() == '' ? null : $(this).val(),
917								source: $(this).data("values"),
918								select: function (event, ui) {
919									// must do this to keep state
920									$(this).dropdown("option", "selectedItem", ui.item);
921									$(this).val(ui.item.label);
922									return false;
923								}
924							});
925						});
926
927						$("#" + scopeid + " input[data-inputtype='date']:enabled").each(function (index) {
928							var el = $(this);
929
930							$(this).datepicker({
931								changeMonth: true,
932								changeYear: true,
933								numberOfMonths: 3,
934								showOtherMonths: true,
935								selectOtherMonths: true,
936								buttonImage: baseUrl + "Mvc/Content/images/icons/calendar.png",
937								buttonImageOnly: true,
938								showOn: 'both',
939								beforeShow: function () {
940									var strCtrl = $(this).attr("startDate-ControlId");
941									var endCtrl = $(this).attr("endDate-ControlId");
942									if (strCtrl) {
943										$date = new Date($("#" + strCtrl).val());
944										$(this).datepicker("option", "minDate", new Date($date.setDate($date.getDate() + 1)));
945									}
946									if (endCtrl) {
947										$date = new Date($("#" + endCtrl).val());
948										$(this).datepicker("option", "maxDate", new Date($date.setDate($date.getDate() - 1)));
949									}
950								}
951							});
952
953							el.data("fn-get-value", function () {
954								var d = formatDate(el.val());
955								return d ? d : "";
956							});
957						});
958
959						$("#" + scopeid + " input[data-inputtype='datetime']:enabled").each(function (index) {
960							var el = $(this),
961								val = el.val(),
962								time = formatTime(val),
963								date = formatDate(val),
964								tp = $("<input type=\"text\" style=\"width: 85px; margin-left: 5px;\" />")
965									.insertAfter(this)
966									.val(time);
967
968							el.val(date);
969
970							el.datepicker({
971								changeMonth: true,
972								changeYear: true,
973								numberOfMonths: 3,
974								showOtherMonths: true,
975								selectOtherMonths: true,
976								buttonImage: baseUrl + "Mvc/Content/images/icons/calendar.png",
977								buttonImageOnly: true,
978								showOn: 'both',
979								beforeShow: function () {
980									var strCtrl = $(this).attr("startDate-ControlId");
981									var endCtrl = $(this).attr("endDate-ControlId");
982									if (strCtrl) {
983										$date = new Date($("#" + strCtrl).val());
984										$(this).datepicker("option", "minDate", new Date($date.setDate($date.getDate() + 1)));
985									}
986									if (endCtrl) {
987										$date = new Date($("#" + endCtrl).val());
988										$(this).datepicker("option", "maxDate", new Date($date.setDate($date.getDate() - 1)));
989									}
990								}
991							});
992
993							// Add time-picker
994							tp.timepicker({
995								showLeadingZero: false,
996								showPeriod: localService.IsHour12Format(),
997								showPeriodLabels: localService.IsHour12Format()
998							}).after("<img title='" + erecruit.Strings.ChooseTime + "' src='" + baseUrl + "Mvc/Content/Images/icons/time.png' width='16' height='16' />");
999
1000							el.data("fn-get-value", function () {
1001								var d = formatDate(el.val());
1002								return d ? d + " " + tp.val() : "";
1003							});
1004						});
1005
1006						function formatDate(dateValue) {
1007							return dateTimeFormat(dateValue, {
1008								day: 'numeric',
1009								year: 'numeric',
1010								month: 'numeric',
1011								hour12: undefined
1012							});
1013						}
1014
1015						function formatTime(dateValue) {
1016							return dateTimeFormat(dateValue, {
1017								hour: 'numeric',
1018								minute: 'numeric',
1019								hour12: localService.IsHour12Format()
1020							});
1021						}
1022
1023						function dateTimeFormat(dateValue, format) {
1024							var d = localService.ParseDate(dateValue, {
1025								day: 'numeric',
1026								year: 'numeric',
1027								month: 'numeric',
1028								hour: 'numeric',
1029								minute: 'numeric',
1030								hour12: localService.IsHour12Format()
1031							});
1032
1033							d = d ? d : localService.ParseDate(dateValue, format);
1034							return d ? localService.FormatDate(d, format) : null;
1035						}
1036
1037						$("#" + scopeid + " select[data-inputtype='multiselect']").each(function (index) {
1038							$(this).multiselect({
1039								source: $(this).data("source"),
1040								selectedValues: $(this).data("selectedvalues") || $(this).val() || []
1041							});
1042						});
1043
1044						localizationInit.LocalizeNumericInputs(scope);
1045
1046						callback && callback.call(scope || this);
1047					});
1048				},
1049			}
1050	});
1051
1052// extending jquery ui datepicker
1053$.datepicker.setDefaults({
1054	beforeShow: function () {
1055		// stop datepicker click event propagation to prevent tooltips closing
1056		$("#ui-datepicker-div").on("click", function (event) {
1057			event.stopPropagation();
1058		});
1059	}
1060});
1061
1062// extending jquery ui autocomplete
1063$.widget("erecruit.dropdown", $.ui.autocomplete,
1064	{
1065		options:
1066			{
1067				position: { my: "left top", at: "left bottom", collision: "flip", offset: "0 -1" },
1068				// if set, will highlight on create for local data sources
1069				initSelectedValue: null,
1070				// this gets updated when the selected item is manually changed
1071				// there's no need to set this in the options - initSelectedValue is enough to prefill the value
1072				selectedItem: null,
1073				allowEmpty: false,
1074				allowCustomValues: false,
1075				// adds support for showing the label in the input when doing arrow up or down through the list
1076				focus: function (event, ui) {
1077					$(this).val(ui.item.label);
1078					return false;
1079				}
1080			},
1081		// adds support for initSelectedValue
1082		// adds support for opening menu on focus and click
1083		// adds support for not closing cooltip when selecting item
1084		_create: function () {
1085			var self = this;
1086
1087			if (this.element && typeof this.element.attr('data-source') != 'undefined' && this.element.attr('data-source') && this.element.data("source") != '') {
1088				this.options.source = this.element.data("source");
1089			}
1090
1091			$.ui.autocomplete.prototype._create.call(this);
1092
1093			if (this.options.initSelectedValue != null) {
1094				this.select(this.options.initSelectedValue);
1095			}
1096			else if (this.element && typeof this.element.attr('data-selectedvalue') != 'undefined' && this.element.attr('data-selectedvalue') && this.element.data("selectedvalue") != '') {
1097				this.select(this.element.data("selectedvalue"));
1098			}
1099
1100			this.element
1101				.focus(function () { $(this).dropdown("search", ""); })
1102				.on('click',function () {
1103					$(this).dropdown("search", "");
1104					$(this).trigger('select');
1105				});
1106
1107			this.menu.element.on('click',function (e) { e.stopPropagation(); });
1108		},
1109		// adds support for enabled=true/false, icon, and tooltip
1110		_renderItem: function (ul, item) {
1111			// if not defined, assume enabled
1112			var enabled = (item.enabled == undefined || item.enabled);
1113			var tooltip = (item.tooltip != null && item.tooltip != "") ? item.tooltip : "";
1114
1115			return $("<li></li>")
1116				.data("item.autocomplete", item)
1117				.append(enabled ?
1118					"<a style='background-color: " + (item.color != "" ? item.color : "auto") + ";' title='" + tooltip + "'>" + item.label + (item.icon == null || item.icon == "" ? "" : "<img style='margin-left: 3px; float: right' src='" + item.icon + "'>") + (item.additionalData || "") + "</a>" :
1119					"<span title='" + tooltip + "' style='padding: .2em .4em; line-height: 1.5; border: 1px solid transparent' class='ui-state-disabled'>" + item.label + "</span>")
1120				.appendTo(ul);
1121		},
1122		// adds support for reverting to previous value if left with a typed in value instead of a selected one
1123		_change: function (event) {
1124			if (this.element.val() == "" && this.options.allowEmpty) {
1125				// trying to change it to nothing
1126				this.options.selectedItem = null;
1127			}
1128			else if (this.options.allowCustomValues && Array.isArray(this.options.source) && this.element.val() != "") {
1129				// add custom value?
1130				var value = this.element.val();
1131				this.options.selectedItem = $.grep(this.options.source, function (el) { return el.value == value; })[0];
1132				if (this.options.selectedItem == null) {
1133					// add an new option and select it
1134					var item = new Object();
1135					item.label = value;
1136					item.value = value;
1137					this.options.source.push(item);
1138					this.options.selectedItem = $.grep(this.options.source, function (el) { return el.value == value; })[0];
1139				}
1140			}
1141			else {
1142				var isdifferent = this.options.selectedItem == undefined || this.options.selectedItem.label != this.element.val();
1143
1144				if (isdifferent) {
1145					if (this.options.selectedItem != null)
1146						this.element.val(this.options.selectedItem.label);
1147					else
1148						this.element.val("");
1149				}
1150			}
1151
1152			$(this.element).trigger("autocompletechange", { item: this.options.selectedItem });
1153
1154			$.ui.autocomplete.prototype._change.call(this, event);
1155		},
1156		select: function (value) {
1157			if (Array.isArray(this.options.source)) {
1158				this.options.selectedItem = $.grep(this.options.source, function (el) { return el.value == value; })[0];
1159				if (this.options.selectedItem != null) {
1160					this.element.val(this.options.selectedItem.label);
1161					this._trigger("select", null, { item: this.options.selectedItem });
1162				}
1163			}
1164			else {
1165				var self = this;
1166
1167				self.element.addClass("ui-autocomplete-loading");
1168
1169				this.options.source({ term: value }, function (data) {
1170					if (data.length > 0) {
1171						self.options.selectedItem = $.grep(data, function (el) { return el.value == value; })[0];
1172						if (self.options.selectedItem != null) {
1173							self.element.val(self.options.selectedItem.label);
1174							self._trigger("select", null, { item: self.options.selectedItem });
1175						}
1176					}
1177
1178					self.element.removeClass("ui-autocomplete-loading");
1179				});
1180			}
1181		},
1182		clear: function () {
1183			this.options.selectedItem = null;
1184			this.element.val("");
1185		}
1186	});
1187
1188$.widget("erecruit.multiselect",
1189	{
1190		options:
1191			{
1192				position: { my: "left top", at: "left bottom", collision: "flip", offset: "0 -1" },
1193				selectedValues: []
1194			},
1195
1196		_create: function () {
1197			var self = this,
1198				select = this.select = this.element.hide(),
1199				wrapper = this.wrapper = $("<span>")
1200					.insertAfter(select);
1201
1202			select.attr("multiple", "multiple");
1203			var input = this.input = $("<input>")
1204				.appendTo(wrapper)
1205				.autocomplete({
1206					source: self.options.source,
1207					appendTo: "body",
1208					minLength: 0,
1209					close: function (event, ui) {
1210						self._setDisplay(self._getItemsFromValues(self.options.selectedValues));
1211					}
1212				});
1213
1214			input.data("ui-autocomplete")._renderItem = function (ul, item) {
1215				$(ul).on("click", function (event) {
1216					event.stopPropagation();
1217				});
1218				var enabled = (item.enabled == undefined || item.enabled);
1219				var tooltip = (item.tooltip != null && item.tooltip != "") ? item.tooltip : "";
1220
1221				var li = $("<li>")
1222					.data("ui-autocomplete-item", item)
1223					.append(enabled ? "<label><input type='checkbox' />" + item.label + "</label>" : "<label><input title='" + tooltip + "' type='checkbox' disabled='disabled' />" + item.label + "</label>")
1224					.appendTo(ul);
1225
1226				$('input', li).on('change',function () {
1227					var value = $(this).parent().parent().data("ui-autocomplete-item").value;
1228
1229					//update the selectedValues based on what's actually selected
1230					if ($(this).is(":checked")) {
1231						//Add this item's value to the selectedValues array
1232						if ($.inArray(value, self.options.selectedValues) == -1) self.options.selectedValues.push(value);
1233					}
1234					else {
1235						var t = [];
1236						for (var i = 0; i < self.options.selectedValues.length; i++)
1237							if (self.options.selectedValues[i] != value) t.push(self.options.selectedValues[i]);
1238
1239						self.options.selectedValues = t;
1240					}
1241				});
1242
1243				if ($.inArray(item.value, self.options.selectedValues) > -1) {
1244					$('input', li).attr("checked", "checked");
1245				}
1246				return li;
1247			};
1248
1249			input.on('click',function () {
1250				if (input.autocomplete("widget").is(":visible")) {
1251					input.autocomplete("close");
1252					return;
1253				}
1254				$(input).val("");
1255				//display the drop down with all options
1256				input.autocomplete("search", "");
1257			});
1258
1259			this.sep = this.options.sep || ";";
1260			this.sep = String.prototype.trim.call(this.sep ? this.sep : '') + " ";
1261
1262			this._setDisplay(this._getItemsFromValues(this.options.selectedValues));
1263		},
1264		destroy: function () {
1265			this.wrapper.remove();
1266			this.element.show();
1267			$.Widget.prototype.destory.call(this);
1268		},
1269		_getItemsFromValues: function (values) {
1270			var items = [];
1271			//display the label of the selected options
1272			for (var i = 0; i < this.options.source.length; i++) {
1273				if ($.inArray(this.options.source[i].value, this.options.selectedValues) > -1)
1274					items.push(this.options.source[i]);
1275			}
1276			return items;
1277		},
1278		//Sets the display for the drop down and synchronizes the underlying select object
1279		_setDisplay: function (items) {
1280			var sep = "";
1281			var display = "";
1282			$(this.select).empty();
1283
1284			for (var i = 0; i < items.length; i++) {
1285				display += sep + items[i].label;
1286				sep = this.sep;
1287
1288				$("<option>")
1289					.attr("value", items[i].value)
1290					.attr("selected", "selected")
1291					.append(items[i].label)
1292					.appendTo(this.select);
1293			}
1294
1295			$(this.input).val(display);
1296		}
1297	});

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.