1/**
2 *  Page scripts for Ad Hominem Info Template
3 *
4 * @author     Sascha Leib <sascha@leib.be>
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 */
7
8/* everything is contained in the $p namespace: */
9$p = {
10
11	/* called to initialize the entire script */
12	init:	function() {
13
14		$p.cookie_banner.init();
15		$p.linkinfo.init();
16		$p.search.init();
17		$p.togglers.init();
18
19	},
20
21	/* link information */
22	linkinfo: {
23		init: function() {
24
25			/* find all links in the main section */
26			var main = document.getElementById("main-layout");
27			var al = main.getElementsByTagName("a");
28			Array.prototype.forEach.call(al, function (a) {
29
30				Object.entries($p.linkinfo._restURLs).forEach((c) => {
31					var cls = c[0];
32					if (a.classList.contains(cls)) {
33						a.addEventListener('mouseover', $p.linkinfo._linkHoverCallback);
34					}
35				});
36			});
37		},
38
39		/* pre-defined REST API URLs for different sites. */
40		/* variables are enclosed in %, allowed vars are: */
41		/* - basedir = this site's basedir (e.g. "/"), */
42		/* - id = the data id of the link (internal only) */
43		/* - ln = the link name (e.g. for Wikipedia links) */
44		/* types can be 'internal', 'wikimedia', or 'ahtpl' */
45		/*  for other sites using this template. */
46		_restURLs : {
47			'wikilink1'	: {
48				url: '%basedir%lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview',
49				type:'internal'
50			},
51			'iw_wp'		: {
52				url:'https://en.wikipedia.org/api/rest_v1/page/summary/%id%',
53				type:'wikimedia'
54			},
55			'iw_wpfr' 	: {
56				url:'https://fr.wikipedia.org/api/rest_v1/page/summary/%id%',
57				type:'wikimedia'
58			},
59			'iw_wpde' 	: {
60				url:'https://de.wikipedia.org/api/rest_v1/page/summary/%id%',
61				type:'wikimedia'
62			},
63			'iw_wpes' 	: {
64				url:'https://es.wikipedia.org/api/rest_v1/page/summary/%id%',
65				type:'wikimedia'
66			},
67			'iw_wppl' 	: {
68				url:'https://pl.wikipedia.org/api/rest_v1/page/summary/%id%',
69				type:'wikimedia'
70			},
71			'iw_wpja' 	: {
72				url:'https://it.wikipedia.org/api/rest_v1/page/summary/%id%',
73				type:'wikimedia'
74			},
75			'iw_wpru' 	: {
76				url:'https://ru.wikipedia.org/api/rest_v1/page/summary/%id%',
77				type:'wikimedia'
78			},
79			'iw_meta' 	: {
80				url:'https://meta.wikipedia.org/api/rest_v1/page/summary/%id%',
81				type:'wikimedia'
82			},
83			'iw_fo' 	: {
84				url:'https://fallacies.online/wiki/lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview',
85				base:'https://fallacies.online/wiki/',
86				type:'ahtpl'
87			},
88			'iw_dfo' 	: {
89				url:'https://denkfehler.online/wiki/lib/tpl/ad-hominem/rest/pageinfo.php?id=%id%&v=preview',
90				base:'https://denkfehler.online/wiki/',
91				type:'ahtpl'
92			}
93		},
94		/* note: this covers the internal links and the most common
95		   wikipedia lang versions. If you know about any other
96		   relevant sites to be added here, let the author of this
97		   template know (ad@hominem.info) */
98
99		/* TODO: mechanism to dynamically add sites by site admin */
100
101		/* callback for the onhover event of links: */
102		_linkHoverCallback: function() {
103
104			var a = jQuery(this);
105			var hi = jQuery.data(this, 'has-info');
106			var href = jQuery(this).attr('href');
107			var wid = null;
108			var url = null;
109			var type = '';
110
111			/* only if the info hasn't been set yet: */
112			if (hi == undefined || hi == '') {
113
114				// remember that we are now working on the link:
115				jQuery.data(this, 'has-info', '0');
116
117				// find the URL to query:
118				try {
119					for (var cls in $p.linkinfo._restURLs) {
120						if (a.hasClass(cls)) {
121							url = $p.linkinfo._restURLs[cls].url;
122							type = $p.linkinfo._restURLs[cls].type;
123							break;
124						}
125					};
126				} catch (e) {}
127
128				/* get the ID to request: */
129				switch(type) {
130
131					case 'internal': // internal links
132						url = url.replace('%basedir%', (typeof BASEDIR!=='undefined'?BASEDIR:'/'));
133						wid = jQuery(this).data('wiki-id');
134						break;
135					case 'wikimedia': // wikipedia sites
136						wid = href.substring(href.lastIndexOf('/')+1);
137						break;
138					case 'ahtpl': // Other sites with this template
139						wid = href.substring($p.linkinfo._restURLs[cls].base.length).replaceAll('/', ':');
140						break;
141					default: // unknown -> skip
142						return;
143				}
144
145				// URL & ID found?
146				if (url !== null && typeof wid !== 'undefined') {
147
148					/* load the page info */
149					jQuery.ajax({
150						url:		url.replace('%id%', encodeURIComponent(wid)),
151						context:	a,
152						dataType:	'json',
153						crossDomain: true,
154						error:		function(xhr, msg, e) {
155										console.error(msg);
156									},
157						success:	function(data, msg, xhr) {
158										// build the new title for the element:
159										if (typeof data.title !== 'undefined') {
160											jQuery(this).attr('title', data.title + "\n" + data.extract);
161											jQuery.data(this, 'has-info', '1');
162										}
163									},
164						complete:	function() {
165										if (jQuery.data(this, 'has-info') == '0') {
166											jQuery.removeData(this, 'has-info');
167										}
168									}
169					});
170				}
171			}
172		}
173	},
174
175	/* anything related to the search */
176	search: {
177
178		/* initializer */
179		init: function() {
180			$p.search.gui.init();
181		},
182
183		/* the search gui */
184		gui: {
185
186			_container: null,
187			_elements: { field: null, clear: null, search: null },
188
189			/* init the gui */
190			init: function() {
191
192				try {
193
194					/* find all the search elements: */
195					var form = document.getElementById('dw__search');
196
197					var div = form.getElementsByClassName('search-field')[0];
198					$p.search.gui._container = div;
199
200					var field = div.getElementsByTagName('input')[0];
201					$p.search.gui._elements.field = field;
202					field.addEventListener('focus', $p.search.gui.__elementFocus);
203					field.addEventListener('blur', $p.search.gui.__elementBlur);
204
205					var buttons = div.getElementsByTagName('button');
206					Array.prototype.forEach.call(buttons, function(b) {
207						var type = b.getAttribute('type');
208						if (type == 'reset') {
209							$p.search.gui._elements.clear = b;
210						} else if (type == 'submit') {
211							$p.search.gui._elements.search = b;
212						}
213						b.addEventListener('focus', $p.search.gui.__elementFocus);
214						b.addEventListener('blur', $p.search.gui.__elementBlur);
215					});
216
217				} catch (e) {
218					console.warn("Can’t initialize search form.");
219					console.error(e);
220				}
221			},
222
223			/* call back for fields */
224			__elementFocus: function() {
225				$p.search.gui._container.classList.add("focus");
226			},
227			__elementBlur: function() {
228				$p.search.gui._container.classList.remove("focus");
229
230			}
231		}
232	},
233
234	/* expaning sections, for menus, etc. */
235	togglers: {
236
237		/* initialize togglers */
238		init:	function() {
239
240			const togglers = document.getElementsByClassName("toggle");
241
242			Array.prototype.forEach.call(togglers, function(t) {
243
244				/* add default state  */
245				if (!(t.classList.contains('show') || (t.classList.contains('hide')))) {
246					t.classList.add('auto');
247				}
248
249				/* add a callback to the toggler buttons */
250				var btn = t.getElementsByClassName('tg_button');
251				Array.prototype.forEach.call(btn, function(b) {
252					b.addEventListener('click', $p.togglers._buttonCallback);
253					b.classList.add('active');
254				});
255
256			});
257		},
258
259		/* callback for the toggler button click */
260		_buttonCallback: function() {
261
262			var t = this.parentNode;
263
264			/* current state of the toggler: */
265			var state = 'auto';
266			if (t.classList.contains('show')) state = 'show';
267			if (t.classList.contains('hide')) state = 'hide';
268			if (t.classList.contains('alt')) state = 'alt';
269
270			/* set new state: */
271			var newState = 'alt';
272			if (state == 'show') { newState = 'hide' }
273			else if (state == 'hide') { newState = 'show' }
274			else if (state == 'alt') { newState = 'auto' }
275
276			t.classList.remove(state);
277			t.classList.add(newState);
278
279		}
280	},
281
282	/* Cookies info banner */
283	cookie_banner: {
284
285		/* initialize Cookies info banner */
286		init: function() {
287
288			// find the cookiebanner elements:
289			var btn = jQuery('#cookiebanner button');
290
291			var cookie = jQuery.cookie('cookielaw');
292
293			if ( (cookie !== '1') && (btn.length >= 1) ) { // if found only
294
295				// assign callback:
296				jQuery(btn).click($p.cookie_banner._buttonCallback);
297
298				// show the banner
299				jQuery('#cookiebanner').show();
300
301				// set focus:
302				jQuery(btn).first().focus();
303			}
304		},
305
306		/* callback for the "OK" button */
307		_buttonCallback: function() {
308
309			const date = new Date();
310			date.setFullYear(date.getFullYear() + 1);
311
312			var path = ( typeof BASEDIR !== 'undefined' ? BASEDIR : '/');
313
314			document.cookie = 'cookielaw=1; path=' + path + '; expires=' + date.toUTCString() + '; SameSite=Lax';
315			jQuery('#cookiebanner').remove();
316		}
317	}
318};
319
320/* load the script when the DOM is ready */
321
322window.addEventListener("DOMContentLoaded", $p.init);
323