PageSourceSearch

https://www.stoughton.org/Assets/Scripts/LiveEditTabs.js

js stoughton.org collected 2026-09-25 05:08:14 UTC 37,502 bytes, 975 lines download raw bytes

1/// <reference path="../../../../Scripts/json2.js" />
2/// <reference name="MicrosoftAjax.js" />
3/// <reference name="Util.js" />
4/// <reference path="../../../../Common/GlobalJSFunctionsDetail.js" />
5
6// Define Notebook class.
7function LiveEditTabsClass(moduleID, categoryID, itemID) {
8	this.moduleID = moduleID;
9	this.categoryID = categoryID;
10	this.itemID = itemID;
11	this.$liveEditTabs = null;
12	this.$inner = null;
13	this.$tabs = null;
14	this.previousState = 'open';
15	this.currentState = this.previousState;
16	this.canResizeNow = false;
17	this.isResizing = false;
18	this.defaultHeight = 205;
19	this.defaultWidth = 350;
20	this.minimumWidth = 190;
21	this.minSize = 6;
22	this.maxSize = 0; // Set by browser.
23	this.currentSize = this.defaultHeight;
24	this.previousY = 0; // Set by browser during dragging.
25	this.previousX = 0; // Set by browser during dragging.
26	this.activeTab = "";
27	this.VERTICAL_OFFSET = 46;
28	this.HORIZONTAL_OFFSET = 35;
29	this.BUTTON_OFFSET = 55;
30	this.POSITION_BOTTOM = 0;
31	this.POSITION_RIGHT = 1;
32	this.POSITION_LEFT = 2;
33	this.position = this.POSITION_BOTTOM;
34	this.oldCursor = "default";
35	this.localResources = null;
36	this.stateChangeHandlers = [];
37	this.tabs = [];
38	this.userRights = 0;
39	this.allowToggleFeatureColumn = false;
40	this.RIGHTS_AUTHOR = 3;
41	this.RIGHTS_OWNER = 5;
42	this.liveEditResources = null;
43	this.isInitialized = false;
44	this.tooltipInterval = 0;
45	this.orientationChangedEvent = null;
46	this.cssManager = new StylesheetManagerClass('liveEditTabsCSS');
47	this.isDragging = false;
48}
49
50function LiveEditTabClass(id, title, url, activeClass) {
51	this.id = id;
52	this.title = title;
53	this.url = url;
54	this.activeClass = activeClass;
55}
56
57// Initializes live edit tabs
58LiveEditTabsClass.prototype.init = function () {
59	this.renderFramework();
60	this.$liveEditTabs = $('#liveEditTabs');
61	this.orientationChangedEvent = function () { this.$liveEditTabs.trigger('LiveEditTabs.OrientationChanged', { orientation: this.position }); };
62	this.$tabs = this.$liveEditTabs.find('.tabs');
63	this.$inner = this.$liveEditTabs.find('.inner');
64	this.$getAddVersionButton = function () { return $('#addVersion'); };
65	this.maxSize = document.documentElement.clientHeight - 149;
66	this.liveEditResources = GetJson("/Pages/Localization/Strings");
67	this.localResources = GetJson("/Notebook/Localization/Index");
68	this.userRights = this.$liveEditTabs.data('userrights');
69	this.IsAdminUser = this.$liveEditTabs.data('isadminuser');
70	this.IsSuperUser = this.$liveEditTabs.data('issuperuser');
71	this.allowToggleFeatureColumn = this.$liveEditTabs.data('allowtogglefeaturecolumn') == 'True';
72	if (this.userRights >= this.RIGHTS_AUTHOR)
73	{
74		this.initAnchor();
75		this.setOrientation();
76		this.initStyles();
77		this.initHandlers();
78	}
79	this.isInitialized = true;
80	this.oldTabClass = $('#liveEditTabsStateClass').val();
81};
82
83
84LiveEditTabsClass.prototype.renderFramework = function () {
85	var liveEditTabReference = this;
86
87	$.ajax({
88		type: "GET",
89		url: '/LiveEditTabs?moduleID={0}&pageID={1}'.replace('{0}', liveEditTabReference.moduleID).replace('{1}', liveEditTabReference.categoryID),
90		async: false,
91		success: function (response) {
92			if (response.ErrorMessage) {
93				console.log("Error rendering tab: " + tab.id);
94			}
95			else {
96				$('#liveEditTabs').remove();
97				$('body').append($(response));
98			}
99		},
100		error: function (jqXHR, textStatus, errorThrown) {
101			console.log("Error rendering tab: " + tab.id);
102		}
103	});
104};
105LiveEditTabsClass.prototype.addTab = function (id, title, url, active, stateChangeHandler) {
106	var liveEditTabReference = this;
107	if (active != true && active != false) {
108		active = false;
109	}
110	var tab = new LiveEditTabClass(id, title, url, active ? 'active' : '');
111	liveEditTabReference.tabs.push(tab);
112	if (stateChangeHandler != null && typeof (stateChangeHandler) == 'function') {
113		liveEditTabReference.stateChangeHandlers.push(stateChangeHandler);
114	}
115	liveEditTabReference.renderTab(tab);
116	if (active) {
117		liveEditTabReference.loadTab(tab);
118		liveEditTabReference.setActiveTab(id);
119	}
120};
121LiveEditTabsClass.prototype.renderTab = function (tab) {
122	var liveEditTabReference = this;
123	liveEditTabReference.$tabs.append('<li id="lnk{0}" class="{1}"><a id="innerLnk{0}" href="#liveEditTab_{0}"><span>{2}</span></a></li>'.replace('{0}', tab.id).replace('{0}', tab.id).replace('{0}', tab.id).replace('{1}', tab.activeClass).replace('{2}', tab.title));
124};
125LiveEditTabsClass.prototype.loadTab = function (tab) {
126	var liveEditTabReference = this;
127
128	$.ajax({
129		type: "GET",
130		url: tab.url,
131		async: false,
132		cache: false,
133		success: function (response) {
134			let errorMessage = response.ErrorMessage || response.error;
135			if (errorMessage) {
136				alert(errorMessage);
137				return;
138			}
139			if (tab.id === "contentAdvisor") {
140				let pathParts = window.location.pathname.split('/');
141				if (pathParts.length > 2 && /^\d+$/.test(pathParts[1]) && /^\d+$/.test(pathParts[2])) {
142				  // Remove pageversionid
143				  pathParts.splice(2, 1);
144				}
145				let relativePath = `${pathParts.join('/')}${window.location.search}`;
146				let urlSearchParams = new URLSearchParams({
147					organizationApplicationId: response.organizationApplicationId,
148					productType: 'Central',
149					sourceUri: relativePath
150				});
151				let contentAdvisorServiceUrl = `${response.contentAdvisorEndpoint}?${urlSearchParams.toString()}`;
152				let contentAdvisorIFrame = `<iframe id="contentAdvisorFrame" src="${contentAdvisorServiceUrl}"></iframe>`;
153
154				liveEditTabReference.$inner.append(
155					`<div class="inner panel cpGrid cpGrid12 ${tab.id}" id="liveEditTab_${tab.id}"><div class="row">${contentAdvisorIFrame}</div></div>`
156				);
157			} else {
158				liveEditTabReference.$inner.append(
159					`<div class="inner panel cpGrid cpGrid12 ${tab.id}" id="liveEditTab_${tab.id}"><div class="row">${response}</div></div>`
160				);
161			}
162		},
163		error: function (jqXHR, textStatus, errorThrown) {
164			console.log("Error encountered trying to load tab: " + tab.id);
165		}
166	});
167};
168LiveEditTabsClass.prototype.initializeTabs = function () {
169	var liveEditTabReference = this;
170
171	liveEditTabReference.$liveEditTabs.find('.panel').hide();
172	var activeTab = liveEditTabReference.$liveEditTabs.find('.tabs li.active a');
173	if (activeTab.length == 1) {
174		var activeTabId = activeTab.attr('href');
175		$(activeTabId).show();
176	}
177
178	// Hook tab, have it toggle between closed and whatever the previous state was.
179	liveEditTabReference.$liveEditTabs.find('.tabs a').click(function (event) {
180		event.preventDefault();
181		var id = $(this).attr('href');
182		if (liveEditTabReference.activeTab != id) {
183			liveEditTabReference.setActiveTab(id);
184			if (liveEditTabReference.currentState == 'closed') {
185				liveEditTabReference.toggleClose();
186			} else {
187				for (var index = 0; index < liveEditTabReference.stateChangeHandlers.length; index++) {
188					liveEditTabReference.stateChangeHandlers[index]();
189				}
190			}
191		} else {
192			liveEditTabReference.toggleClose();
193		}
194		return false;
195	});
196
197	if (liveEditTabReference.position == liveEditTabReference.POSITION_BOTTOM) {
198		liveEditTabReference.setMaxHeights(liveEditTabReference.currentSize);
199	} else {
200		this.toggleTabDisplay();
201	}
202
203	$('#liveEditTabs').click(setWidgetTabEditingState);
204
205	document.body.removeEventListener('spa:navigated', liveEditTabSpaNavigationHandler);
206	document.body.addEventListener('spa:navigated', liveEditTabSpaNavigationHandler);
207
208	let lastPath = window.location.pathname + window.location.search;
209	function liveEditTabSpaNavigationHandler(e) {
210		let tab = liveEditTabReference.tabs.find(function(t) { return t.id === "contentAdvisor"; });
211		let iframe = liveEditTabReference.$inner.find('#contentAdvisorFrame').first();
212		if (!tab || iframe.length !== 1 || !e.detail.path) {
213			return;
214		}
215		let newPath = e.detail.path + e.detail.query;
216		if (newPath !== lastPath) {
217			tab.url = '/ContentAdvisor/GetServiceUrlComponents';
218			liveEditTabReference.loadTab(tab);
219		}
220		lastPath = newPath;
221	}
222};
223LiveEditTabsClass.prototype.updateMaxHeightTabs = function () {
224	var liveEditTabReference = this;
225	if (liveEditTabReference.position == liveEditTabReference.POSITION_BOTTOM) {
226		liveEditTabReference.setMaxHeights(liveEditTabReference.currentSize);
227	} else if (liveEditTabReference.currentState == 'open') {
228		liveEditTabReference.setWidth(liveEditTabReference.currentSize);
229	}
230	liveEditTabReference.cssManager.getOrAddClass('.adminWrap.liveEditTab.side').getOrAddStyle('top').value = ($('#divToolbars').height() + $('div.cp-Toolbars').height()) + 'px';
231	liveEditTabReference.cssManager.saveStylesheet();
232};
233LiveEditTabsClass.prototype.setActiveTab = function (id) {
234	var liveEditTabReference = this;
235	if (id.indexOf('#liveEditTab_') < 0) {
236		id = '#liveEditTab_' + id;
237	}
238	var tab = document.getElementById(id.substring(1));
239	if (!tab) {
240		for (var index = 0; index < liveEditTabReference.tabs.length; index++) {
241			if (liveEditTabReference.tabs[index].id == id.replace('#liveEditTab_', '')) {
242				liveEditTabReference.loadTab(liveEditTabReference.tabs[index]);
243				tab = document.getElementById(id.substring(1));
244				break;
245			}
246		}
247	}
248
249	if (tab) {
250		liveEditTabReference.activeTab = id;
251		$('.panel', '.liveEditTab').hide();
252		$('ul.tabs .active').removeClass('active');
253		$(tab).fadeIn(300);
254		$(document.getElementById('lnk' + id.replace('#liveEditTab_', ''))).addClass('active');
255		liveEditTabReference.toggleTabDisplay();
256	}
257	return false;
258};
259// Internal. Sets the class used on the notebook panel/HUD.
260LiveEditTabsClass.prototype.changeStateClass = function (newState) {
261	if (newState == this.oldTabClass)
262		return;
263
264	this.previousState = this.currentState;
265	this.currentState = newState;
266
267	if (this.oldTabClass != null)
268		this.$liveEditTabs.removeClass(this.oldTabClass);
269
270	if (newState != null)
271		this.$liveEditTabs.addClass(newState);
272
273	this.oldTabClass = newState;
274};
275
276// Sets the state of the notebook panel/HUD.
277LiveEditTabsClass.prototype.setState = function (newState) {
278	if (this.currentState == newState) {
279		return;
280	}
281
282	this.changeStateClass(newState);
283	this.setBodyPadding();
284	this.setStateStyles(newState, this.currentSize);
285	this.toggleTabDisplay();
286	this.saveStateInfo();
287};
288
289// Toggles window state between closed and the previous state (open/maxed).
290LiveEditTabsClass.prototype.toggleClose = function () {
291	if (this.currentState == 'closed') {
292		this.open();
293	}
294	else {
295		this.close();
296	}
297};
298
299// Change notebook to maximized state.
300LiveEditTabsClass.prototype.maximize = function () {
301	this.setState('maxed');
302};
303
304// Change notebook to closed/minimized state.
305LiveEditTabsClass.prototype.close = function () {
306	this.setState('closed');
307};
308
309// Change notebook to open/restored state.
310LiveEditTabsClass.prototype.open = function () {
311	this.setState('open');
312};
313
314
315LiveEditTabsClass.prototype.animateFromSide = function (stateSizeString) {
316	var liveEditTabReference = this;
317	var multiplier = 1;
318	var originalWidth = liveEditTabReference.$liveEditTabs.width();
319
320	if (liveEditTabReference.position == liveEditTabReference.POSITION_LEFT) {
321		multiplier = -1;
322	}
323
324	if (!liveEditTabReference.isInitialized) { // If we aren't initialized delay the animation to let initialization complete before animating the tabs.
325		liveEditTabReference.$addVersionButton.hide();
326		liveEditTabReference.$liveEditTabs.css('margin-left', multiplier * liveEditTabReference.$tabs.width());
327		setTimeout(function () {
328			liveEditTabReference.cssManager.addClass('.adminWrap.liveEditTab.side').addStyle('width', stateSizeString);
329			liveEditTabReference.$liveEditTabs.width(liveEditTabReference.$tabs.width())
330				.animate({ width: stateSizeString, marginLeft: 0 },
331					function () {
332						liveEditTabReference.cssManager.addClass('.adminWrap.liveEditTab.side').addStyle('width', stateSizeString);
333						liveEditTabReference.$addVersionButton.show();
334						widgetsTabTooltip(false);
335					}).css('overflow', 'visible');
336		}, 1500);
337	} else {
338		if (originalWidth < parseInt(liveEditTabReference.$getAddVersionButton().css('max-width'))) {
339			liveEditTabReference.$getAddVersionButton().hide();
340		}
341		liveEditTabReference.$liveEditTabs.width(originalWidth).animate({ width: stateSizeString }, function () {
342			liveEditTabReference.cssManager.addClass('.adminWrap.liveEditTab.side').addStyle('width', stateSizeString);
343			liveEditTabReference.$getAddVersionButton().show();
344			widgetsTabTooltip(false);
345		}).css('overflow', 'visible');
346	}
347};
348
349LiveEditTabsClass.prototype.animateFromBottom = function (stateSizeString) {
350	var liveEditTabReference = this;
351	var originalHeight = liveEditTabReference.$liveEditTabs.height();
352
353	if (!this.isInitialized) { // If we aren't initialized delay the animation to let initialization complete before animating the tabs.
354		setTimeout(function () {
355			liveEditTabReference.$liveEditTabs.height(originalHeight - liveEditTabReference.$tabs.height()).animate({ height: stateSizeString }, function () {
356				widgetsTabTooltip(false);
357			}).css('overflow', 'visible');
358		}, 500);
359	} else {
360		liveEditTabReference.$liveEditTabs.height(originalHeight).animate({ height: stateSizeString }, function () {
361			widgetsTabTooltip(false);
362		}).css('overflow', 'visible');
363	}
364};
365
366
367
368// Internal. Initializes styles
369LiveEditTabsClass.prototype.initStyles = function () {
370	var savedState = $('#liveEditTabs').data('initialstate');
371	this.previousState = savedState;
372	this.currentSize = parseInt($('#liveEditTabs').data('initialheight'), 10);
373	this.setStateStyles(savedState, this.currentSize);
374};
375LiveEditTabsClass.prototype.setStateStyles = function (state, stateSize) {
376	var liveEditTabReference = this;
377
378	switch (state) {
379		case 'maxed':
380			stateSize = this.maxSize;
381			break;
382		case 'closed':
383			stateSize = this.minSize;
384			break;
385		case 'open':
386			stateSize = isNaN(stateSize) ? (this.position == this.POSITION_BOTTOM ? this.defaultHeight : this.defaultWidth) : stateSize;
387			if (stateSize > this.maxSize) {
388				stateSize = this.maxSize;
389			} else if (stateSize < this.minSize) {
390				stateSize = this.minSize;
391			}
392			this.currentSize = stateSize;
393			break;
394	}
395
396	this.previousState = this.currentState;
397	this.currentState = state;
398
399	$('.liveEditTab').attr('style', '');
400
401	var stateSizeString = stateSize + 'px';
402	if (state != 'closed') {
403
404		liveEditTabReference.cssManager.addClass('.adminWrap.liveEditTab.bottom').addStyle('height', stateSizeString);
405
406		liveEditTabReference.setMaxHeights(stateSize);
407	}
408	liveEditTabReference.setBodyPadding(stateSize);
409
410	if (liveEditTabReference.position == liveEditTabReference.POSITION_BOTTOM) {
411		liveEditTabReference.animateFromBottom(stateSizeString);
412	}
413
414	var timeOutLength = 1;
415	if (($('#divToolbars').height() + $('div.cp-Toolbars').height()) < 5) {
416		timeOutLength = 1000;
417	}
418
419
420	setTimeout(function () {
421		liveEditTabReference.cssManager.addClass('.adminWrap.liveEditTab.side').addStyle('top', ($('#divToolbars').height() + $('div.cp-Toolbars').height()) + 'px');
422		if (liveEditTabReference.position == liveEditTabReference.POSITION_LEFT || liveEditTabReference.position == liveEditTabReference.POSITION_RIGHT) {
423			liveEditTabReference.animateFromSide(stateSizeString);
424		}
425
426		liveEditTabReference.$liveEditTabs.removeClass('hidden');
427		liveEditTabReference.$liveEditTabs.css('display', '');
428		liveEditTabReference.cssManager.saveStylesheet();
429
430		//Rather than "button" width, some adjustable width content class; "scalable"?
431		if (liveEditTabReference.position == liveEditTabReference.POSITION_BOTTOM) {
432			$('.liveEditTab .buttons').css('width', 'auto');
433		} else {
434			var buttonsWidth = stateSize - 45;
435			$('.liveEditTab .buttons').css('width', buttonsWidth + 'px');
436		}
437
438		for (var index = 0; index < liveEditTabReference.stateChangeHandlers.length; index++) {
439			liveEditTabReference.stateChangeHandlers[index]();
440		}
441	}, timeOutLength);
442};
443
444LiveEditTabsClass.prototype.setBodyPadding = function (size) {
445	size = size || this.currentSize;
446	var paddingBottom = '0px';
447	var paddingLeft = '0px';
448	var paddingRight = '0px';
449	switch (this.position) {
450		case this.POSITION_BOTTOM:
451			paddingBottom = size + 'px';
452			break;
453		case this.POSITION_LEFT:
454			paddingLeft = size + 'px';
455			break;
456		case this.POSITION_RIGHT:
457			paddingRight = size + 'px';
458			break;
459	}
460	$('#bodyWrapper').css('padding-bottom', paddingBottom);
461	$('#bodyWrapper').css('padding-left', paddingLeft);
462	$('#bodyWrapper').css('padding-right', paddingRight);
463	$(window).resize();
464};
465LiveEditTabsClass.prototype.setMaxHeights = function (newHeight) {
466	newHeight -= this.VERTICAL_OFFSET;
467	$('.liveEditTab .offsetMaxHeight').css('max-height', newHeight + 'px');
468};
469LiveEditTabsClass.prototype.clearMaxHeights = function () {
470	$('.liveEditTab .offsetMaxHeight').css('max-height', 'none');
471};
472// Changes the height of the panel/HUD (for bottom orientation).
473LiveEditTabsClass.prototype.setHeight = function (value) {
474	if (value > this.maxSize)
475		value = this.maxSize;
476	else if (value < this.minSize)
477		value = this.minSize;
478
479	this.currentSize = value;
480	$('.liveEditTab').css('height', value + 'px');
481	$('#liveEditTab_versionsList .col').height($('#liveEditTab_versionsList .col').css('max-height'));
482	this.setBodyPadding();
483};
484
485// Changes the width of the panel/HUD (for right & left orientations).
486LiveEditTabsClass.prototype.setWidth = function (value) {
487	if (value > this.maxSize)
488		value = this.maxSize;
489	else if (value < this.minSize)
490		value = this.minSize;
491
492	this.currentSize = value;
493	$('.liveEditTab').css('width', value + 'px');
494
495	this.setBodyPadding();
496	var buttonsWidth = this.$liveEditTabs.width() - 45;
497	$('.liveEditTab .buttons').css('width', buttonsWidth + 'px');
498	this.toggleTabDisplay();
499};
500
501LiveEditTabsClass.prototype.toggleTabDisplay = function () {
502	var activeTab = document.getElementById(this.activeTab.substring(1));
503	if (this.position != this.POSITION_BOTTOM && (this.currentSize < this.minimumWidth || this.currentState == 'closed')) {
504		$(activeTab).hide();
505		if (this.currentSize < 70 || this.currentState == 'closed') {
506			$('#hiddenContentMessage').hide();
507		} else {
508			$('#hiddenContentMessage').show();
509		}
510	} else {
511		$(activeTab).show();
512		$('#hiddenContentMessage').hide();
513	}
514};
515// Internal. Registers dragger for resizing panel/HUD.
516LiveEditTabsClass.prototype.registerDragHooks = function () {
517	var liveEditTabReference = this;
518	var $body = $(document.body);
519
520	this.registerDragCursorHook(this.$liveEditTabs);
521	this.registerDragCursorHook(this.$inner);
522
523	$body.mouseup(function (event) {
524		if (liveEditTabReference.isResizing) {
525			event.preventDefault();
526			liveEditTabReference.isResizing = false;
527			document.body.style.cursor = liveEditTabReference.oldCursor;
528			liveEditTabReference.oldCursor = null;
529			liveEditTabReference.previousX = 0;
530			liveEditTabReference.previousY = 0;
531			liveEditTabReference.$liveEditTabs.removeClass('beingDragged');
532			liveEditTabReference.saveStateInfo();
533			//Clear the setinterval once the dragging is done.
534			clearInterval(liveEditTabReference.tooltipInterval);
535		}
536	});
537};
538
539// Internal. Helper function for registerDragHooks().
540LiveEditTabsClass.prototype.registerDragCursorHook = function ($liveEditDragBar) {
541	var liveEditTabReference = this;
542
543	var moveOrOver = function (event, doLog) {
544		liveEditTabReference.isDragging = true;
545		switch (liveEditTabReference.position) {
546			case liveEditTabReference.POSITION_BOTTOM:
547				var yPos = event.offsetY ? event.offsetY : event.layerY;
548				if (yPos >= 0 && yPos <= 8 && this == event.target) {
549					liveEditTabReference.canResizeNow = true;
550
551					if (this.style.cursor != 'n-resize')
552						this.style.cursor = 'n-resize';
553				}
554				else if (this.style.cursor == 'n-resize') {
555					liveEditTabReference.canResizeNow = false;
556
557					if (!liveEditTabReference.isResizing)
558						this.style.cursor = 'default'; // cannot use inherit, due to IE.
559				}
560				if (typeof yPos === 'undefined' && this == event.target) {
561					liveEditTabReference.canResizeNow = true;
562				} else if (this !== event.target) {
563					liveEditTabReference.canResizeNow = false;
564				}
565				break;
566			case liveEditTabReference.POSITION_LEFT:
567				var xPos = liveEditTabReference.$liveEditTabs.width() - (event.offsetX ? event.offsetX : event.layerX);
568
569				if (xPos >= 0 && xPos <= 8 && this == event.target) {
570					liveEditTabReference.canResizeNow = true;
571
572					if (this.style.cursor != 'e-resize')
573						this.style.cursor = 'e-resize';
574				}
575				else if (this.style.cursor == 'e-resize') {
576					liveEditTabReference.canResizeNow = false;
577
578					if (!liveEditTabReference.isResizing)
579						this.style.cursor = 'default'; // cannot use inherit, due to IE.
580				}
581				break;
582			case liveEditTabReference.POSITION_RIGHT:
583				var xPos = event.offsetX ? event.offsetX : event.layerX;
584
585				if (xPos >= 0 && xPos <= 8 && this == event.target) {
586					liveEditTabReference.canResizeNow = true;
587
588					if (this.style.cursor != 'e-resize')
589						this.style.cursor = 'e-resize';
590				}
591				else if (this.style.cursor == 'e-resize') {
592					liveEditTabReference.canResizeNow = false;
593
594					if (!liveEditTabReference.isResizing)
595						this.style.cursor = 'default'; // cannot use inherit, due to IE.
596				}
597				break;
598		}
599	};
600
601	$liveEditDragBar.mousedown(function (event) {
602		$(document).mousemove(function (event) {
603			if (liveEditTabReference.isResizing) {
604				// ==Resize Dragger Moved==
605				event.preventDefault();
606
607				switch (liveEditTabReference.position) {
608					case liveEditTabReference.POSITION_BOTTOM:
609						var proposedSize = liveEditTabReference.currentSize - (event.clientY - liveEditTabReference.previousY);
610
611						if (proposedSize >= liveEditTabReference.minSize && proposedSize <= liveEditTabReference.maxSize) {
612							liveEditTabReference.setHeight(proposedSize);
613							liveEditTabReference.previousY = event.clientY;
614							liveEditTabReference.setMaxHeights(proposedSize);
615						}
616						break;
617					case liveEditTabReference.POSITION_LEFT:
618						var proposedSize = liveEditTabReference.currentSize + (event.clientX - liveEditTabReference.previousX);
619
620						if (proposedSize >= liveEditTabReference.minSize && proposedSize <= liveEditTabReference.maxSize) {
621							liveEditTabReference.setWidth(proposedSize);
622							liveEditTabReference.previousX = event.clientX;
623							liveEditTabReference.clearMaxHeights();
624						}
625						break;
626					case liveEditTabReference.POSITION_RIGHT:
627						var proposedSize = liveEditTabReference.currentSize - (event.clientX - liveEditTabReference.previousX);
628
629						if (proposedSize >= liveEditTabReference.minSize && proposedSize <= liveEditTabReference.maxSize) {
630							liveEditTabReference.setWidth(proposedSize);
631							liveEditTabReference.previousX = event.clientX;
632							liveEditTabReference.clearMaxHeights();
633						}
634						break;
635				}
636			}
637		});
638
639		// Ensure canResizeNow value is proper.
640		moveOrOver.call(this, event);
641
642		if (liveEditTabReference.canResizeNow) {
643			// ==Resize Dragger Started==
644			event.preventDefault();
645
646			liveEditTabReference.isResizing = true;
647			liveEditTabReference.oldCursor = document.body.style.cursor;
648			liveEditTabReference.$liveEditTabs.addClass('beingDragged');
649
650			//Start a periodic call to reposition the tooltip accordingly.
651			liveEditTabReference.tooltipInterval = setInterval(function () { widgetsTabTooltip(true); }, 100);
652
653			if (liveEditTabReference.position == liveEditTabReference.POSITION_BOTTOM) {
654				// Handle maximized/closed so they drag properly.
655				if (liveEditTabReference.currentState == 'maxed') {
656					liveEditTabReference.setHeight(liveEditTabReference.maxSize);
657					liveEditTabReference.open();
658				}
659				else if (liveEditTabReference.currentState == 'closed') {
660					liveEditTabReference.setHeight(liveEditTabReference.minSize);
661					liveEditTabReference.open();
662				}
663
664				document.body.style.cursor = 'n-resize';
665				liveEditTabReference.previousY = event.clientY;
666			} else {
667				// Handle maximized/closed so they drag properly.
668				if (liveEditTabReference.currentState == 'maxed') {
669					liveEditTabReference.setWidth(liveEditTabReference.maxSize);
670					liveEditTabReference.open();
671				}
672				else if (liveEditTabReference.currentState == 'closed') {
673					liveEditTabReference.setWidth(liveEditTabReference.minSize);
674					liveEditTabReference.open();
675				}
676
677				document.body.style.cursor = 'e-resize';
678				liveEditTabReference.previousX = event.clientX;
679			}
680		}
681	});
682
683	$liveEditDragBar.mousemove(moveOrOver);
684	$liveEditDragBar.mouseover(moveOrOver);
685	$liveEditDragBar.mouseout(function (event) {
686		if ((this.style.cursor == 'n-resize' || this.style.cursor == 'e-resize') && this == event.target) {
687			liveEditTabReference.canResizeNow = false;
688
689			if (!liveEditTabReference.isResizing)
690				this.style.cursor = 'default'; // cannot use inherit, due to IE.
691		}
692	});
693
694	$liveEditDragBar.mouseup(function (event) {
695		var wasDragging = liveEditTabReference.isDragging;
696		liveEditTabReference.isDragging = false;
697		if (wasDragging)
698			window.dispatchEvent(new Event("resize"));
699
700		$(document.body).unbind('mousemove');
701	});
702};
703// Internal. Initializes event handlers.
704LiveEditTabsClass.prototype.initHandlers = function () {
705	var lnkClose = document.getElementById('lnkClose');
706	var lnkOpen = document.getElementById('lnkOpen');
707	var lnkMaximize = document.getElementById('lnkMaximize');
708
709	var liveEditTabReference = this; // jQuery event handlers change value of 'this' ref.
710
711	// Hook dragger for resizing.
712	this.registerDragHooks();
713
714	// Hook close/open/maximize buttons.
715	$(lnkClose).click(function (event) {
716		event.preventDefault();
717		liveEditTabReference.close();
718		return false;
719	});
720
721	$(lnkOpen).click(function (event) {
722		event.preventDefault();
723		liveEditTabReference.open();
724		return false;
725	});
726
727	$(lnkMaximize).click(function (event) {
728		event.preventDefault();
729		liveEditTabReference.maximize();
730		return false;
731	});
732
733	$('.liveEditTab').find('.changeOrientation').click(function (e) {
734		e.preventDefault();
735		if (liveEditTabReference.$liveEditTabs.hasClass('bottom')) {
736			liveEditTabReference.$liveEditTabs.removeClass('bottom').addClass('side left');
737		} else if (liveEditTabReference.$liveEditTabs.hasClass('left')) {
738			liveEditTabReference.$liveEditTabs.removeClass('left').addClass('right');
739		} else if (liveEditTabReference.$liveEditTabs.hasClass('right')) {
740			liveEditTabReference.$liveEditTabs.removeClass('side right').addClass('bottom');
741		}
742
743		liveEditTabReference.setOrientation();
744		widgetsTabTooltip(true);
745	});
746};
747
748LiveEditTabsClass.prototype.initAnchor = function () {
749	var liveEditTabReference = this;
750	if (document.cookie.indexOf("initLiveEditTabAnchor=true") !== -1) return;
751
752	document.cookie = "initLiveEditTabAnchor=true; path=/";
753
754	var isWideScreenMonitor = ($(window).width() / $(window).height()) >= (16 / 9);
755	if (isWideScreenMonitor) {
756		liveEditTabReference.$liveEditTabs.removeClass('bottom').addClass('side left');
757	} else {
758		liveEditTabReference.$liveEditTabs.removeClass('left').removeClass('right').removeClass('side').addClass('bottom');
759	}
760};
761
762LiveEditTabsClass.prototype.setOrientation = function () {
763	var liveEditTabReference = this;
764	liveEditTabReference.$liveEditTabs.attr('style', '');
765
766	if (liveEditTabReference.$liveEditTabs.hasClass('bottom')) {
767		liveEditTabReference.position = liveEditTabReference.POSITION_BOTTOM;
768		liveEditTabReference.maxSize = document.documentElement.clientHeight - 149;
769		liveEditTabReference.currentSize = liveEditTabReference.defaultHeight;
770		liveEditTabReference.setHeight(liveEditTabReference.currentSize);
771		liveEditTabReference.setMaxHeights(liveEditTabReference.currentSize);
772		$('.liveEditTab .buttons').css('width', 'auto');
773	} else if (liveEditTabReference.$liveEditTabs.hasClass('left')) {
774		liveEditTabReference.position = liveEditTabReference.POSITION_LEFT;
775		liveEditTabReference.maxSize = document.documentElement.clientWidth - liveEditTabReference.HORIZONTAL_OFFSET;
776		liveEditTabReference.currentSize = liveEditTabReference.defaultWidth;
777		liveEditTabReference.setWidth(liveEditTabReference.currentSize);
778	} else if (this.$liveEditTabs.hasClass('right')) {
779		liveEditTabReference.position = liveEditTabReference.POSITION_RIGHT;
780		liveEditTabReference.maxSize = document.documentElement.clientWidth - liveEditTabReference.HORIZONTAL_OFFSET;
781		liveEditTabReference.currentSize = liveEditTabReference.defaultWidth;
782		liveEditTabReference.setWidth(liveEditTabReference.currentSize);
783	}
784
785	if (this.isInitialized) {
786		liveEditTabReference.saveStateInfo();
787	}
788
789	for (var index = 0; index < liveEditTabReference.stateChangeHandlers.length; index++) {
790		liveEditTabReference.stateChangeHandlers[index]();
791	}
792	this.orientationChangedEvent();
793};
794// Saves state (height, panel/HUD window state) information to server.
795LiveEditTabsClass.prototype.saveStateInfo = function () {
796	var liveEditTabReference = this;
797
798	$.ajax({
799		url: '/LiveEditState/Save',
800		type: 'POST',
801		ignoreEditor: true, //prevent for executing global editor event
802		data: {
803			windowHeight: this.currentSize,
804			windowState: this.currentState,
805			position: this.position
806		},
807		success: function (data) {
808			if (!data.success) {
809				if (data.reason == 'not_logged_in')
810					alert(liveEditTabReference.localResources.ErrorStateSaveNotLoggedIn);
811				else if (data.reason == 'access_denied')
812					alert(liveEditTabReference.localResources.ErrorStateSaveAccessDenied);
813				else
814					alert(liveEditTabReference.localResources.ErrorStateSaveUnknown);
815			}
816			rearrangeFlyoutsOnResizeEvents();
817		}
818	});
819};
820
821function renderLiveEditTabs(moduleID) {
822	var thePage = this;
823
824	if (!window.ContentCollectionInstance) {
825		window.ContentCollectionInstance = new ContentCollectionClass();
826		window.ContentCollectionInstance.init();
827	}
828
829	if (!window.ResizeData) {
830		window.ResizeData = new ResizeClass();
831	}
832
833	if (moduleID == 76) {
834		if (ContentCollectionInstance.PageID == '' || ContentCollectionInstance.PageID == null) {
835			return;
836		}
837		thePage.liveEditTabs = new LiveEditTabsClass(moduleID, ContentCollectionInstance.PageID, null);
838		thePage.liveEditTabs.init();
839		if (!ContentCollectionInstance.IsLayoutPage && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR && window.isContentAdvisor && ContentCollectionInstance.PageStatus === "Published" ) {
840			thePage.liveEditTabs.addTab('contentAdvisor', 'SEO/AEO', '/ContentAdvisor/GetServiceUrlComponents', false);
841		}
842		if (!ContentCollectionInstance.IsLayoutPage && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR) {
843			thePage.liveEditTabs.addTab('versionsList', 'Versions', '/Pages/VersionList?versionID={0}&pageID={1}'.replace('{0}', ContentCollectionInstance.VersionID).replace('{1}', ContentCollectionInstance.PageID), true);
844		}
845		if (thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR) {
846			thePage.liveEditTabs.addTab('widgets', 'Widgets', '/Layout/WidgetsTab?moduleID={0}'.replace('{0}', moduleID), ContentCollectionInstance.IsLayoutPage, setWidgetTabEditingState);
847			toggleWidgetsLink(((ContentCollectionInstance.PageStatus != 'Active' && ContentCollectionInstance.PageStatus != 'Published') && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR)
848				|| ((ContentCollectionInstance.PageStatus === 'Active' || ContentCollectionInstance.PageStatus === 'Published') && thePage.liveEditTabs.userRights > thePage.liveEditTabs.RIGHTS_AUTHOR));
849		}
850		if (!ContentCollectionInstance.IsLayoutPage && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR) {
851			thePage.liveEditTabs.addTab('notebook', 'Notes', '/Notebook/Home/NotesTab?categoryID={0}'.replace('{0}', ContentCollectionInstance.PageID), false, setNoteHeights);
852		}
853		if (!ContentCollectionInstance.IsLayoutPage && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_OWNER) {
854			thePage.liveEditTabs.addTab('propertiesTab', 'Properties', '/Pages/PropertiesTab?id={0}'.replace('{0}', ContentCollectionInstance.PageID), false);
855		}
856		if (!ContentCollectionInstance.IsLayoutPage && (thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_OWNER || (thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR && thePage.liveEditTabs.allowToggleFeatureColumn))) {
857			thePage.liveEditTabs.addTab('layoutTab', 'Layout', '/Layout/LayoutTab?pageID={0}'.replace('{0}', ContentCollectionInstance.PageID), false);
858		}
859		thePage.liveEditTabs.initializeTabs();
860	} else {
861		thePage.liveEditTabs = new LiveEditTabsClass(moduleID, null, null);
862		thePage.liveEditTabs.init();
863		if (!ContentCollectionInstance.IsLayoutPage && thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_AUTHOR && window.isContentAdvisor) {
864			thePage.liveEditTabs.addTab('contentAdvisor', 'SEO/AEO', '/ContentAdvisor/GetServiceUrlComponents', false);
865		}
866		if (thePage.liveEditTabs.userRights >= thePage.liveEditTabs.RIGHTS_OWNER) {
867			thePage.liveEditTabs.addTab('widgets', 'Widgets', '/Layout/WidgetsTab?moduleID={0}'.replace('{0}', moduleID), !configureSiteMapVersionsTab(moduleID, thePage), setWi
867dgetTabEditingState);
868			thePage.liveEditTabs.addTab('layoutTab', 'Layout', '/Layout/LayoutTab?moduleID={0}'.replace('{0}', moduleID), false);
869		}
870		thePage.liveEditTabs.initializeTabs();
871	}
872
873	var activeLiveTab = GetQueryStringParameter('activeLiveTab');
874	if (activeLiveTab != '') {
875		thePage.liveEditTabs.setActiveTab(activeLiveTab);
876	}
877}
878
879function setNoteHeights() {
880	if ($('#liveEditTabs').hasClass('bottom')) {
881		$('.inner.notebook .notes').css('max-height', 'auto');
882		$('.inner.notebook .note').css('max-height', 'auto');
883	} else {
884		var tabInnerHeight = $('.liveEditTab .inner.notebook').height();
885		var notesHeight = Math.round(tabInnerHeight / 3);
886		var noteHeight = tabInnerHeight - notesHeight - 10;
887		$('.inner.notebook .notes').css('max-height', notesHeight + 'px');
888		$('.inner.notebook .note').css('max-height', noteHeight + 'px');
889	}
890}
891
892function setWidgetTabEditingState() {
893	var removeWidgetTabMessage = function () {
894		$("#subTabContent, #subTabModules").children("p.message").remove();
895		$('div.inner.panel.widgets').removeClass('withMessage');
896	};
897	var addWidgetTabMessage = function (message) {
898		var $message = $('<p class="message">' + message + '</p>');
899		$("#subTabContent, #subTabModules").prepend($message);
900		$('div.inner.panel.widgets').addClass('withMessage');
901	};
902	removeWidgetTabMessage();
903
904	if (window.ContentCollectionInstance.PageID != null) {
905		//Set message on widgets tab to prevent dragging widgets
906		var noVersions = $('div.items.noVersions').length > 0;
907		if (noVersions) {
908			addWidgetTabMessage(window.liveEditTabs.liveEditResources.WidgetsTabNoVersions);
909		} else {
910			var isLinkedVersion = $('p.alert.linkedVersion').length > 0;
911			if (isLinkedVersion) {
912				addWidgetTabMessage(window.liveEditTabs.liveEditResources.WidgetsTabLinkedVersion);
913			} else {
914				var editable = $('.indicator.horizontal, .indicator.vertical').length > 0;
915				if (!editable) {
916					var isLayoutPage = $('#layoutPageSelector').length > 0;
917					addWidgetTabMessage(isLayoutPage
918						? window.liveEditTabs.liveEditResources.WidgetsTabLockedLayoutPage
919						: window.liveEditTabs.liveEditResources.WidgetsTabLockedVersion);
920				}
921			}
922		}
923	}
924
925}
926
927function widgetsTabTooltip(doNotWait) {
928	var $liveEditTabs = $('#liveEditTabs');
929	var position = '';
930	var slideOrientation = 'down';
931	if ($liveEditTabs.hasClass('left')) {
932		position = 'right topEdge';
933		slideOrientation = 'left';
934	}
935	else if ($liveEditTabs.hasClass('right')) {
936		position = 'left topEdge';
937		slideOrientation = 'right';
938	}
939	else {
940		position = 'top center';
941		if ($liveEditTabs.hasClass('top'))
942			slideOrientation = 'up';
943		else
944			slideOrientation = 'down';
945	}
946
947	var showModal = function () {
948		$.showTooltip({
949			Id: 'widgetsTabTooltip',
950			tooltipContent: '<p>Add content by dragging-and-dropping widgets from this tab into containers on your page.</p><p><a href="#" class="button closeTooltip"><span>Thanks</span></a></p>',
951			className: 'newCP flyOut ' + position + ' withArrow fixed cpPopOver admin adminWrap helpTip',
952			$target: $('#lnkwidgets'),
953			$referenceElements: $('.tabs li a', "#liveEditTabs"),
954			slideOrientation: slideOrientation
955		});
956	};
957
958	if (doNotWait) {
959		showModal();
960	} else {
961		window.setTimeout(function () {
962			showModal();
963		}, 50);
964	}
965}
966
967var configureSiteMapVersionsTab = function (moduleID , thePage) {
968	var enableSitemapVersionTab = moduleID === 23 && (thePage.liveEditTabs.IsAdminUser === "True" || thePage.liveEditTabs.IsSuperUser === "True");
969	if (enableSitemapVersionTab) {
970		var versionHiddenInput = document.getElementById("versionId");
971		var versionId = (versionHiddenInput && versionHiddenInput.value) | 0;
972		thePage.liveEditTabs.addTab('versionsList', 'Versions', '/Sitemap/Version/List/' + versionId, true);
973	}
974	return enableSitemapVersionTab;
975};

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.