User:V111P/js/webRefSetup.js

Source: Wikipedia, the free encyclopedia.
<
js
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// This script is used in combination with the WebRef script, which is not yet uploaded for use for the English Wikipedia.
// v. 2013-04-23 / 0.01.2
if (!window.webRef || !window.webRef.getRef) alert('WebRef Setup error: Please, load WebRef first!');
else webRef.webRefSetup = (function () {
	'use strict';
	function prt(txt) {
		if (window.console && console.log)
			console.log(txt);
	}

	window.webRef.webRefSetupVer = 1;

	// Shortcuts
	var refDocData = window.webRef.refDocData;
	var domain = window.webRef.domain;
	var dom = window.webRef.dom;
	var newEl = dom.newEl;
	var aux = window.webRef.aux;
	var idToText = webRef.idToText;

	var maxStrLengthInOption = 100;
	var showCharsFromEnd = 20;

	var frameBodyStyleObj = {
			margin: '0 auto',
			color: '#ffffff', backgroundColor: '#000077',
			border: '5px solid gray', borderWidth: '5px 0',
			padding: '1px', font: 'normal normal normal medium serif',
			textAlign: 'left'
	};


	var refFrame = {
		frame: null,
		win: null,
		doc: null,
		body: null
	};

	// a collection of references to the form controls
	var ctrls = {}; // site, title, date, author, publisher, visited, url, code, etc.

	refDocData.searchSection = {
		things: ['title', 'date', 'author'],
		fieldIdEndings: ['Search'], //['SeparatorBefore', 'Search', 'SeparatorAfter']
		fieldSizes: [70] //[5, 70, 5]
	};
	refDocData.aboutSiteFields = [
		'siteName',
		'lang',
		'publisher',
		'authorName',
		'authorWikiArticle',
		'notAnAuthor'
	];

	refDocData.buttonSectionButtons = [
		{id: 'toCode', onclick: toCode},
		{id: 'saveToStorage', onclick: saveToStorage},
		{id: 'loadFromVar', onclick: loadFromVar},
		{id: 'loadFromStorage', onclick: loadFromStorage},
		{id: 'deleteFromStorage', onclick: deleteFromStorage},
		{id: 'resetForm', onclick: resetForm},
		{id: 'useOnceFromTA', onclick: useOnceFromTA},
		{id: 'closeSetup', onclick: closeSetup}
	];


	function loadFromStorage() {
		var code = localStorage && localStorage.getItem('webRef-1') || '';
		ctrls.code.value = (code && '"' + domain + '": ' + code) || '';
	}
	function deleteFromStorage() {
		if (localStorage && localStorage.getItem('webRef-1') && confirm(idToText['delStorageConfirm']))
			localStorage.removeItem('webRef-1');
	}
	function saveToStorage() {
		var code, obj;
		if (!window.localStorage || !window.JSON)
			alert(idToText['noStorage']);
		else {
			code = ctrls.code.value.replace(/^[^{]*/, '');
			try { obj = JSON.parse(code); }
			catch (e) {
				alert(idToText['invalidCode']);
				return;
			}
			if ( !localStorage.getItem('webRef-1') || confirm(idToText['overwriteStorageConfirm']) )
				localStorage.setItem('webRef-1', JSON.stringify(obj, null, '\t'));
		}
	}
	function useOnceFromTA() {
		var code, obj;
		code = ctrls.code.value.replace(/^[^{]*/, '');
		try { obj = JSON.parse(code); }
		catch (e) {
			alert(idToText['invalidCode']);
			return;
		}
		if (!window.webRefSiteData)
			window.webRefSiteData = {};
		webRefSiteData[domain] = obj;
		closeSetup();
		webRef.getRef();
	}
	function closeSetup() {
		dom.byId('ref01ref').style.display = 'none';
		dom.byId('ref01refDiv').style.display = 'none';
		webRef.displayWebRefFrame(true);
		document.body.scrollTop = document.documentElement.scrollTop = 0;
	}
	function resetForm() {
		if (confirm(idToText['resetFormConfirm']))
			autoFillInfo();
	}

	aux.shorten = function (longStr) { // shorten a string for display
		var str = longStr;
		if (str.length > maxStrLengthInOption)
			str = str.substr(0, maxStrLengthInOption - 5 - showCharsFromEnd)
				+ ' ... ' + str.substr(str.length - showCharsFromEnd, showCharsFromEnd);
		return str;
	};


	function autoFillInfo() {
		// Auto fill fields in the Search Results section
		var i, str, o, autoIn, things = refDocData.searchSection.things;
		for (o in things) {
			if (!things.hasOwnProperty(o))
				continue;
			autoIn = refDocData.things[things[o]] && refDocData.things[things[o]].autoSearchIn;
			if (!autoIn)
				continue;
			var selEl = ctrls[things[o] + 'Results'];
			selEl.innerHTML = '';
			var n = 0;
			for (i = 0; i < autoIn.length; i++) {
				str = window.webRef.textFromAddr(autoIn[i], false);
				if (str) {
					var txt = aux.shorten(autoIn[i]) + ' (' + aux.shorten(str) + ')';
					if (n == 0)
						selEl.appendChild(newEl('option', {
							value: '',
							text: idToText['default'] + ': ' + txt
						}));
					n++;
					selEl.appendChild(newEl('option', {
						value: autoIn[i],
						text: txt
					}));
				}
			}
		}

		// Auto fill fields in the About the Site section
		var searchInArr, thing, formatter;
		var abtFields = refDocData.aboutSiteFields;
		var things = refDocData.things;
		for (var i = 0; i < abtFields.length; i++) {
			thing = abtFields[i];
			searchInArr = (things[thing] && things[thing].autoSearchIn) || [];
			for (var j = 0; j < searchInArr.length; j++) {
				str = window.webRef.metaContent[searchInArr[j]];
				if (str) {
					formatter = things[thing].formatter;
					if (formatter)
						str = formatter(str);
					dom.byId(thing + 'DefaultSpan', refFrame.doc)
					.innerHTML = idToText['default'] + ': ' + str;
					break;
				}
			}
		}
	} // autoFillInfo


	function createUI() {
		if (!document.body || !document.body.firstChild) {
			aux.fatalError('Web page is empty!');
		}
		var i, id, docFrag = document.createDocumentFragment();
		var subDiv;

		function br() {
			docFrag.appendChild(newEl('br'));
		}

		docFrag.appendChild(newEl('strong', {text: idToText['searchSectionH']})); br();
		dom.text(idToText['searchSectionIntro'], docFrag); br(); br();

		var searchThings = refDocData.searchSection.things;
		var fieldIdEndings = refDocData.searchSection.fieldIdEndings;
		var fieldSizes = refDocData.searchSection.fieldSizes;

		for (i = 0; i < searchThings.length; i++) {
			dom.text(idToText[searchThings[i] + 'Results'], docFrag);
			br(docFrag);
			for (var j = 0; j < fieldIdEndings.length; j++) { //'
				id = searchThings[i] + fieldIdEndings[j];
				ctrls[id] = newEl('input', {
					id: id,
					size: fieldSizes[j],
					css: {backgroundColor: (fieldSizes[j] == 5 ? 'gray' : 'white')}
				});
				docFrag.appendChild(ctrls[id]);
			}
			br();
		}

		var goButton = newEl('input', {
			type: 'button',
			value: idToText['searchButton'],
			onclick: findContainingEls // doesn't work
		});
		goButton.onclick = findContainingEls;
		docFrag.appendChild(goButton);
		br(); br();

		docFrag.appendChild(newEl('strong', {text: idToText['resultsH']})); br();
		dom.text(idToText['resultsSectionIntro'], docFrag); br(); br();

		for (i = 0; i < searchThings.length; i++) {
			id = searchThings[i] + 'Results';
			dom.text(idToText[id], docFrag); br();
			ctrls[id] = newEl('select', {id: id});
			docFrag.appendChild(ctrls[id]);
			br();
		}

		br();
		docFrag.appendChild(newEl('strong', {text: idToText['aboutSiteH']})); br();
		dom.text(idToText['aboutSiteSectionIntro'], docFrag); br(); br();
		for (var i = 0, fieldId; i < refDocData.aboutSiteFields.length; i++) {
			fieldId = refDocData.aboutSiteFields[i];
			dom.text(idToText[fieldId + '_L'], docFrag); br();
			ctrls[fieldId] = newEl('input', {id: fieldId});
			docFrag.appendChild(ctrls[fieldId]);
			dom.text(' ', docFrag);
			docFrag.appendChild(newEl('span', {
				id: fieldId + 'DefaultSpan',
				css: {color: '#bbbbbb'}
			}));
			br();
		}

		br();
		dom.text(idToText['buttonsIntro'], docFrag); br();
		for (var i = 0, buttonData, button; i < refDocData.buttonSectionButtons.length; i++) {
			buttonData = refDocData.buttonSectionButtons[i];
			button = newEl('input', {
				type: 'button',
				value: idToText[buttonData.id],
				onclick: buttonData.onclick //' doesn't work
			});
			button.onclick = buttonData.onclick;
			docFrag.appendChild(button);
		}

		br(); br();
		docFrag.appendChild(newEl('strong', {text: idToText['codeTaH']}));
		br();
		ctrls.code = newEl('textarea', {
			id: 'codeTA',
			cols: 100,
			rows: 8
		});
		docFrag.appendChild(ctrls.code);

		refFrame.frame = dom.byId('ref00ref');
		if (refFrame.frame)
			refFrame.frame.style.display = 'none';

		refFrame.frame = newEl('iframe', {
			id: 'ref01ref',
			resizable: 'resizable',
			css: {width: '100%', position: 'absolute', zIndex: '2147483647', top: 0, left: 0}
		});
		document.body.insertBefore(refFrame.frame, document.body.firstChild);

		refFrame.win = (refFrame.frame.contentWindow
			|| refFrame.frame.contentDocument);
		refFrame.doc = refFrame.win.document;
		refFrame.doc.open();
		refFrame.doc.write('<!DOCTYPE html>\n<html>\n<head>\n<title>Ref</title>\n</head>'
			+ '<body>\n</body>\n</html>');
		refFrame.doc.close();
		refFrame.body = refFrame.doc.body;
		dom.setStyle(refFrame.body, frameBodyStyleObj);
		refFrame.body.appendChild(docFrag);

		var frameHeight = getDocHeight(refFrame.body, refFrame.doc) + 'px';
		refFrame.frame.style.height = frameHeight;
		subDiv = dom.newEl('div', {
			id: 'ref01refDiv',
			css: {height: frameHeight}
		});
		document.body.insertBefore(subDiv, document.body.firstChild);

		function getDocHeight(b,D) {
			return Math.max(
				Math.max(b.scrollHeight, D.documentElement.scrollHeight),
				Math.max(b.offsetHeight, D.documentElement.offsetHeight)//,
				//Math.max(b.clientHeight, D.documentElement.clientHeight)
			);
		}
	} // createUI


	function findContainingEls() { // getElAddr
		var i, o;
		var all = dom.byTagName("*");
		var patternsToSearchFor = {};
		var things = refDocData.searchSection.things;
		var idEndings = refDocData.searchSection.fieldIdEndings;

		for (i = 0; i < things.length; i++) {
			var pattern = '';
			for (var j = 0; j < idEndings.length; j++) {
				var id = things[i] + idEndings[j];
				if (!refFrame.doc.getElementById(id)) {
					aux.fatalError("findContainingEls: No element with id " + id);
				}
				var val = aux.trimStr(refFrame.doc.getElementById(id).value);
				if (val) {
					val = val
					.replace(/[-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&') // escape
					.replace(/\s+/g, '\\s+');
					pattern += val + '\\s*';
				}
			}
			if (pattern) {
				pattern = pattern.slice(0, -3); // removing the final \s*
				patternsToSearchFor[things[i]] = pattern;
			}
		}

		var matchedEls = {};
		for (o in patternsToSearchFor) {
			if (!patternsToSearchFor.hasOwnProperty(o))
				continue;
			matchedEls[o] = [];
		}

		// loop through all elements in the document and add to matchedEls[o]
		//  all elements within which the text string patternsToSearchFor[o] is found,
		//  but only if it's not also found in a child node of the element
		//  ("o" is one of 'title', 'date' and 'authors').
		for (i = 0; i < all.length; i++) {
			var el = all[i];
			var str = dom.getText(el);
			var tagName = el.tagName.toLowerCase();

			// replace el's parent node with el in the list of elements (matchedEls[o])
			//  containing the string str.
			for (o in patternsToSearchFor) {
				if (!patternsToSearchFor.hasOwnProperty(o))
					continue;
				if (str && str.search(patternsToSearchFor[o]) > -1) {
					if (el.parentNode) {
						var n = -1; // matchedEls[o].indexOf(el.parentNode);
						for (var ii = 0; ii < matchedEls[o].length; ii++) {
							if (matchedEls[o][ii] == el.parentNode) {
								n = ii;
								break;
							}
							
						}
						if (n > -1)
							matchedEls[o].splice(n, 1); // remove parent if child has the string
					}
					if (tagName != 'script' && tagName != 'style' && el != 'refFrame')
						matchedEls[o].push(el);
				}
			}
		}

		var rules = {};
		var content;
		// Add meta info: title, author/authors, date, og:title, og:site_name,
		var metaC = window.webRef.metaContent;
		for (o in patternsToSearchFor) {
			if (!patternsToSearchFor.hasOwnProperty(o))
				continue;
			for (var address in metaC) {
				if (!metaC.hasOwnProperty(address))
					continue;
				content = metaC[address];
				if (content.search(patternsToSearchFor[o]) > -1) {
					rules[o] = rules[o] || [];
					rules[o].push({
						addr: address,
						textContent: content
					});
				}
			}
		}

		// from the element references of the elements found above,
		//  find their text "addresses" (similar to CSS selectors)
		for (o in matchedEls) {
			if (matchedEls[o].length == 0)
				continue;
			rules[o] = rules[o] || [];

			for (var i = 0, k = rules[o].length, el, address; i < matchedEls[o].length; i++) {
				el = matchedEls[o][i];
				address = getElAddr(el, 50); // second arg is maximum element depth
				if (address)
					rules[o][k+i] = {
						addr: address,
						textContent: dom.getText(el)
					};
			}
		}

		// add results to the drop-down menus in the Results section
		for (o in rules) {
			var ctrl = ctrls[o + 'Results'];
			ctrl.innerHTML = ''; // remove all option's from the drop down menu
			for (var i = 0, rule, option; i < rules[o].length; i++) {
				rule = rules[o][i];
				option = newEl('option', {
					value: rule.addr,
					text: aux.shorten(rule.addr) + ' (' + aux.shorten(rule.textContent) + ')'
				});
				ctrl.appendChild(option);
			}
		}

	} // findContainingEls()


	// returns null if maxRecursion is reached and in the case of other errors
	function getElAddr(el, maxRecursion) {
		if (el.id)
			return '#' + el.id;
		//window.docSelAll = document.querySelectorAll || docSelAll; document.querySelectorAll=null;
		var compact = true;//false;
		// example from novatv.bg :
		// compact : span.medium.black
		// not comp: #main_column div div div.news_sidebar.right div span
		// compact ,querySelectorAll=null; = #main_column div div 4div div
		// not comp,querySelectorAll=null; = #main_column div div 4div div span
		// bbc compact = span.date
		// bbc-noncomp = #main-content div.layout-block-a div span span
		var parent = el.parentNode;

		if (maxRecursion < 0) {
			prt('WebRef debug info: Element is too deep in document structure? (error code: getElAddr(): '
				+ 'maxRecursion)');
			return null;
		}
		maxRecursion--;

		var tagName = el.tagName.toLowerCase();
		var classes = aux.collapseWhitespace(el.getAttribute('class') || '').replace(/ /g, '.');
		var nodePlusClasses = tagName + (classes ? '.' + classes : '');

		if (parent == document.body || parent == document)
			return numInParent(el) + tagName;

		if (compact) {
			if (el == dom.byTagName('title')[0])
				return 'title';

			// if only one h1 tag in document, accept this as a unique id
			if (tagName == 'h1' && dom.byTagName('h1').length == 1)
				return 'h1';

			// if in the whole document there is only one element of this type with these classes,
			//  accept that as a unique id for this tag
			// only for browsers supporting document.querySelectorAll (IE8+)
			if (document.querySelectorAll) {
				var selEls;
				try {
					selEls = document.querySelectorAll(nodePlusClasses);
				} catch (e) {
					aux.error('getElAddr(): invalid selector: ' + nodePlusClasses);
					return null;
				}
				if (classes && selEls.length == 1)
					return nodePlusClasses;
			}
		}

		var thisElAddr = '';  // do not record this tag if parent has the same text content
		if (!compact || dom.getText(parent) != dom.getText(el)) {
			var n = numInParent(el);
			if (n && classes // use classes only if there are siblings w/ same tag name
				&& document.querySelectorAll    // and no siblings w/ same tag name & same classes
				&& parent.querySelectorAll(nodePlusClasses).length == 1
			)
				thisElAddr = nodePlusClasses;
			else
				thisElAddr = n + tagName; // n is '' for 0
		}

		return getElAddr(parent) + (thisElAddr ? ' ' + thisElAddr : '');
	} // getElAddr()


	function numInParent(el) {
		var tagName = el.tagName.toLowerCase();
		if (!el.parentNode)
			aux.fatalError('NO PARENT! ' + tagName);
		var elsOfThisType = el.parentNode.getElementsByTagName(tagName);
		var foundNum = -1;
		for (var i = 0; i < elsOfThisType.length; i++) {
			if (elsOfThisType[i] == el) {
				foundNum = i;
				break;
			}
		}
		if (foundNum == -1)
			aux.fatalError('CHILD NOT FOUND IN PARENT!'
				+ tagName + ' Total children of this type found = ' + i
			);

		return (foundNum ? foundNum : '');
	} // numInParent()


	function toCode() {
		var str = '"' + domain + '": {\n';
		var arr = refDocData.searchSection.things;
		for (var i = 0, val, name; i < arr.length; i++) {
			name = arr[i];
			val = ctrls[name + 'Results'].value;
			if (val)
				str += '\t"' + name + '": "' + val + '",\n';
		}
		arr = refDocData.aboutSiteFields;
		for (var i = 0, val, name; i < arr.length; i++) {
			name = arr[i];
			val = ctrls[name].value;
			if (val)
				str += '\t"' + name + '": "' + val + '",\n';
		}
		if (str.charAt(str.length - 2) == ',')
			str = str.slice(0, -2); // remove last comma
		str += "\n}";
		ctrls.code.value = str;
	} // toCode


	// shows in the textarea the currently used settings for this site
	//  (by reading the variable siteRefs[domain] or reading from local storage)
	function loadFromVar() {
		var str = '';
		if (!window.webRefSiteData || !webRefSiteData[domain]) {
			loadFromStorage();
			return;
		}

		str = '"' + domain + '": {\n';
		for (var thing in refDocData.things)
			if (typeof webRefSiteData[domain][thing] != 'undefined')
				str += '\t"' + thing + '": "' + webRefSiteData[domain][thing] + '",\n';
		str = str.slice(0, -2) + '\n}';
		ctrls.code.value = str;
	}


	return function () {
		var setupFrame = dom.byId('ref01ref');
		webRef.displayWebRefFrame(false);
		if (setupFrame) {
			setupFrame.style.display = 'block';
			dom.byId('ref01refDiv').style.display = 'block';
		}
		else {
			createUI();
			autoFillInfo();
		}
	};
})();

if (window.webRef && webRef.webRefSetupStartOnLoad) {
	webRef.webRefSetupStartOnLoad = false;
	webRef.webRefSetup();
}