xref: /template/ad-hominem/script.js (revision 53dcb6a92128465b96fcf56b8e95bf45d5129c12)
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_en' 	: {
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_de' 	: {
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
198					var div = form.getElementsByClassName('search-field')[0];
199					$p.search.gui._container = div;
200
201					var field = div.getElementsByTagName('input')[0];
202					$p.search.gui._elements.field = field;
203					field.addEventListener('focus', $p.search.gui.__elementFocus);
204					field.addEventListener('blur', $p.search.gui.__elementBlur);
205
206					var buttons = div.getElementsByTagName('button');
207					Array.prototype.forEach.call(buttons, function(b) {
208						var type = b.getAttribute('type');
209						if (type == 'reset') {
210							$p.search.gui._elements.clear = b;
211						} else if (type == 'submit') {
212							$p.search.gui._elements.search = b;
213						}
214						b.addEventListener('focus', $p.search.gui.__elementFocus);
215						b.addEventListener('blur', $p.search.gui.__elementBlur);
216					});
217
218				} catch (e) {
219					console.warn("Can’t initialize search form.");
220					console.error(e);
221				}
222			},
223
224			/* call back for fields */
225			__elementFocus: function() {
226				$p.search.gui._container.classList.add("focus");
227			},
228			__elementBlur: function() {
229				$p.search.gui._container.classList.remove("focus");
230
231			}
232		}
233	},
234
235	/* expaning sections, for menus, etc. */
236	togglers: {
237
238		/* initialize togglers */
239		init:	function() {
240
241			const togglers = document.getElementsByClassName("toggle");
242
243			Array.prototype.forEach.call(togglers, function(t) {
244
245				/* add default state  */
246				if (!(t.classList.contains('show') || (t.classList.contains('hide')))) {
247					t.classList.add('auto');
248				}
249
250				/* add a callback to the toggler buttons */
251				var btn = t.getElementsByClassName('tg_button');
252				Array.prototype.forEach.call(btn, function(b) {
253					b.addEventListener('click', $p.togglers._buttonCallback);
254					b.classList.add('active');
255				});
256
257			});
258		},
259
260		/* callback for the toggler button click */
261		_buttonCallback: function() {
262
263			var t = this.parentNode;
264
265			/* current state of the toggler: */
266			var state = 'auto';
267			if (t.classList.contains('show')) state = 'show';
268			if (t.classList.contains('hide')) state = 'hide';
269			if (t.classList.contains('alt')) state = 'alt';
270
271			/* set new state: */
272			var newState = 'alt';
273			if (state == 'show') { newState = 'hide' }
274			else if (state == 'hide') { newState = 'show' }
275			else if (state == 'alt') { newState = 'auto' }
276
277			t.classList.remove(state);
278			t.classList.add(newState);
279
280		}
281	},
282
283	/* Cookies info banner */
284	cookie_banner: {
285
286		/* initialize Cookies info banner */
287		init: function() {
288
289			// find the cookiebanner elements:
290			var btn = jQuery('#cookiebanner button');
291
292			var cookie = jQuery.cookie('cookielaw');
293
294			if ( (cookie !== '1') && (btn.length >= 1) ) { // if found only
295
296				// assign callback:
297				jQuery(btn).click($p.cookie_banner._buttonCallback);
298
299				// show the banner
300				jQuery('#cookiebanner').show();
301
302				// set focus:
303				jQuery(btn).first().focus();
304			}
305		},
306
307		/* callback for the "OK" button */
308		_buttonCallback: function() {
309
310			const date = new Date();
311			date.setFullYear(date.getFullYear() + 1);
312
313			var path = ( typeof BASEDIR !== 'undefined' ? BASEDIR : '/');
314
315			document.cookie = 'cookielaw=1; path=' + path + '; expires=' + date.toUTCString() + '; SameSite=Lax';
316			jQuery('#cookiebanner').remove();
317		}
318	}
319};
320
321/* load the script when the DOM is ready */
322
323window.addEventListener("DOMContentLoaded", $p.init);
324