PageSourceSearch

https://memoriaparatodos.pt/scripts/js/util.js

js memoriaparatodos.pt collected 2026-09-26 12:12:29 UTC 12,335 bytes, 552 lines download raw bytes

1(function($) {
2
3	/**
4	 * Generate an indented list of links from a nav. Meant for use with panel().
5	 * @return {jQuery} jQuery object.
6	 */
7	$.fn.navList = function() {
8
9		var	$this = $(this);
10			$a = $this.find('a'),
11			b = [];
12
13		$a.each(function() {
14
15			var	$this = $(this),
16				indent = Math.max(0, $this.parents('li').length - 1),
17				href = $this.attr('href'),
18				target = $this.attr('target');
19
20			b.push(
21				'<a ' +
22					'class="link depth-' + indent + '"' +
23					( (typeof target !== 'undefined' && target != '') ? ' target="' + target + '"' : '') +
24					( (typeof href !== 'undefined' && href != '') ? ' href="' + href + '"' : '') +
25				'>' +
26					'<span class="indent-' + indent + '"></span>' +
27					$this.text() +
28				'</a>'
29			);
30		});
31		return b.join('');
32
33	};
34
35	/**
36	 * Panel-ify an element.
37	 * @param {object} userConfig User config.
38	 * @return {jQuery} jQuery object.
39	 */
40	$.fn.panel = function(userConfig) {
41
42		// No elements?
43			if (this.length == 0)
44				return $this;
45
46		// Multiple elements?
47			if (this.length > 1) {
48
49				for (var i=0; i < this.length; i++)
50					$(this[i]).panel(userConfig);
51
52				return $this;
53			}
54
55		// Vars.
56			var	$this = $(this),
57				$body = $('body'),
58				$window = $(window),
59				id = $this.attr('id'),
60				config;
61
62		// Config.
63			config = $.extend({
64
65				// Delay.
66					delay: 0,
67				// Hide panel on link click.
68					hideOnClick: false,
69				// Hide panel on escape keypress.
70				hideOnEscape: false,
71					// Hide panel on swipe.
72					hideOnSwipe: false,
73				// Reset scroll position on hide.
74					resetScroll: false,
75				// Reset forms on hide.
76					resetForms: false,
77				// Side of viewport the panel will appear.
78					side: null,
79				// Target element for "class".
80					target: $this,
81				// Class to toggle.
82					visibleClass: 'visible'
83			}, userConfig);
84
85			// Expand "target" if it's not a jQuery object already.
86				if (typeof config.target != 'jQuery')
87					config.target = $(config.target);
88		// Panel.
89
90			// Methods.
91				$this._hide = function(event) {
92
93					// Already hidden? Bail.
94						if (!config.target.hasClass(config.visibleClass))
95							return;
96
97					// If an event was provided, cancel it.
98						if (event) {
99							event.preventDefault();
100							event.stopPropagation();
101						}
102
103					// Hide.
104						config.target.removeClass(config.visibleClass);
105
106					// Post-hide stuff.
107						window.setTimeout(function() {
108
109							// Reset scroll position.
110								if (config.resetScroll)
111									$this.scrollTop(0);
112
113							// Reset forms.
114								if (config.resetForms)
115									$this.find('form').each(function() {
116										this.reset();
117									});
118
119						}, config.delay);
120
121				};
122
123			// Vendor fixes.
124				$this
125					.css('-ms-overflow-style', '-ms-autohiding-scrollbar')
126					.css('-webkit-overflow-scrolling', 'touch');
127
128			// Hide on click.
129				if (config.hideOnClick) {
130
131					$this.find('a')
132						.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
133
134					$this
135						.on('click', 'a', function(event) {
136
137							var $a = $(this),
138								href = $a.attr('href'),
139								target = $a.attr('target');
140
141							if (!href || href == '#' || href == '' || href == '#' + id)
142								return;
143
144							// Cancel original event.
145								event.preventDefault();
146								event.stopPropagation();
147
148							// Hide panel.
149								$this._hide();
150
151							// Redirect to href.
152								window.setTimeout(function() {
153
154									if (target == '_blank')
155										window.open(href);
156									else
157										window.location.href = href;
158
159								}, config.delay + 10);
160
161						});
162				}
163
164			// Event: Touch stuff.
165				$this.on('touchstart', function(event) {
166
167					$this.touchPosX = event.originalEvent.touches[0].pageX;
168					$this.touchPosY = event.originalEvent.touches[0].pageY;
169
170				})
171
172				$this.on('touchmove', function(event) {
173
174					if ($this.touchPosX === null
175					||	$this.touchPosY === null)
176						return;
177
178					var	diffX = $this.touchPosX - event.originalEvent.touches[0].pageX,
179						diffY = $this.touchPosY - event.originalEvent.touches[0].pageY,
180						th = $this.outerHeight(),
181						ts = ($this.get(0).scrollHeight - $this.scrollTop());
182
183					// Hide on swipe?
184						if (config.hideOnSwipe) {
185
186							var result = false,
187								boundary = 20,
188								delta = 50;
189
190							switch (config.side) {
191
192								case 'left':
193									result = (diffY < boundary && diffY >
193 (-1 * boundary)) && (diffX > delta);
194									break;
195
196								case 'right':
197									result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta));
198									break;
199
200								case 'top':
201									result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta);
202									break;
203
204								case 'bottom':
205									result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta));
206									break;
207
208								default:
209									break;
210
211							}
212
213							if (result) {
214
215								$this.touchPosX = null;
216								$this.touchPosY = null;
217								$this._hide();
218
219								return false;
220
221							}
222
223						}
224
225					// Prevent vertical scrolling past the top or bottom.
226						if (($this.scrollTop() < 0 && diffY < 0)
227						|| (ts > (th - 2) && ts < (th + 2) && diffY > 0)) {
228
229							event.preventDefault();
230							event.stopPropagation();
231						}
232				});
233
234			// Event: Prevent certain events inside the panel from bubbling.
235				$this.on('click touchend touchstart touchmove', function(event) {
236					event.stopPropagation();
237				});
238
239			// Event: Hide panel if a child anchor tag pointing to its ID is clicked.
240				$this.on('click', 'a[href="#' + id + '"]', function(event) {
241
242					event.preventDefault();
243					event.stopPropagation();
244
245					config.target.removeClass(config.visibleClass);
246
247				});
248
249		// Body.
250
251			// Event: Hide panel on body click/tap.
252				$body.on('click touchend', function(event) {
253					$this._hide(event);
254				});
255
256			// Event: Toggle.
257				$body.on('click', 'a[href="#' + id + '"]', function(event) {
258
259					event.preventDefault();
260					event.stopPropagation();
261
262					config.target.toggleClass(config.visibleClass);
263
264				});
265
266		// Window.
267
268			// Event: Hide on ESC.
269				if (config.hideOnEscape)
270					$window.on('keydown', function(event) {
271
272						if (event.keyCode == 27)
273							$this._hide(event);
274
275					});
276
277		return $this;
278
279	};
280
281	/**
282	 * Apply "placeholder" attribute polyfill to one or more forms.
283	 * @return {jQuery} jQuery object.
284	 */
285	$.fn.placeholder = function() {
286
287		// Browser natively supports placeholders? Bail.
288			if (typeof (document.createElement('input')).placeholder != 'undefined')
289				return $(this);
290
291		// No elements?
292			if (this.length == 0)
293				return $this;
294
295		// Multiple elements?
296			if (this.length > 1) {
297
298				for (var i=0; i < this.length; i++)
299					$(this[i]).placeholder();
300
301				return $this;
302
303			}
304
305		// Vars.
306			var $this = $(this);
307
308		// Text, TextArea.
309			$this.find('input[type=text],textarea')
310				.each(function() {
311
312					var i = $(this);
313
314					if (i.val() == ''
315					||  i.val() == i.attr('placeholder'))
316						i
317							.addClass('polyfill-placeholder')
318							.val(i.attr('placeholder'));
319
320				})
321				.on('blur', function() {
322
323					var i = $(this);
324
325					if (i.attr('name').match(/-polyfill-field$/))
326						return;
327
328					if (i.val() == '')
329						i
330							.addClass('polyfill-placeholder')
331							.val(i.attr('placeholder'));
332
333				})
334				.on('focus', function() {
335
336					var i = $(this);
337
338					if (i.attr('name').match(/-polyfill-field$/))
339						return;
340
341					if (i.val() == i.attr('placeholder'))
342						i
343							.removeClass('polyfill-placeholder')
344							.val('');
345
346				});
347
348		// Password.
349			$this.find('input[type=password]')
350				.each(function() {
351
352					var i = $(this);
353					var x = $(
354								$('<div>')
355									.append(i.clone())
356									.remove()
357									.html()
358									.replace(/type="password"/i, 'type="text"')
359									.replace(/type=password/i, 'type=text')
360					);
361
362					if (i.attr('id') != '')
363						x.attr('id', i.attr('id') + '-polyfill-field');
364
365					if (i.attr('name') != '')
366						x.attr('name', i.attr('name') + '-polyfill-field');
367
368					x.addClass('polyfill-placeholder')
369						.val(x.attr('placeholder')).insertAfter(i);
370
371					if (i.val() == '')
372						i.hide();
373					else
374						x.hide();
375
376					i.on('blur', function(event) {
377
378							event.preventDefault();
379
380							var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
381
382							if (i.val() == '') {
383								i.hide();
384								x.show();
385							}
386						});
387
388					x.on('focus', function(event) {
389
390							event.preventDefault();
391							var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']');
392
393							x.hide();
394							i.show()
395								.focus();
396
397						})
398						.on('keypress', function(event) {
399
400							event.preventDefault();
401							x.val('');
402						});
403				});
404
405		// Events.
406			$this
407				.on('submit', function() {
408
409					$this.find('input[type=text],input[type=password],textarea')
410						.each(function(event) {
411
412							var i = $(this);
413							if (i.attr('name').match(/-polyfill-field$/))
414								i.attr('name', '');
415
416							if (i.val() == i.attr('placeholder')) {
417								i.removeClass('polyfill-placeholder');
418								i.val('');
419
420							}
421
422						});
423
424				})
425				.on('reset', function(event) {
426
427					event.preventDefault();
428
429					$this.find('select')
430						.val($('option:first').val());
431
432					$this.find('input,textarea')
433						.each(function() {
434
435							var i = $(this),x;
436
437							i.removeClass('polyfill-placeholder');
438
439							switch (this.type) {
440
441								case 'submit':
442								case 'reset':
443									break;
444
445								case 'password':
446									i.val(i.attr('defaultValue'));
447
448									x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]');
449
450									if (i.val() == '') {
451										i.hide();
452										x.show();
453									}
454									else {
455										i.show();
456										x.hide();
457									}
458
459									break;
460
461								case 'checkbox':
462								case 'radio':
463									i.attr('checked', i.attr('defaultValue'));
464									break;
465
466								case 'text':
467								case 'textarea':
468									i.val(i.attr('defaultValue'));
469
470									if (i.val() == '') {
471										i.addClass('polyfill-placeholder');
472										i.val(i.attr('placeholder'));
473									}
474
475									break;
476
477								default:
478									i.val(i.attr('defaultValue'));
479									break;
480
481							}
482						});
483				});
484
485		return $this;
486
487	};
488
489	/**
490	 * Moves elements to/from the first positions of their respective parents.
491	 * @param {jQuery} $elements Elements (or selector) to move.
492	 * @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations.
493	 */
494	$.prioritize = function($elements, condition) {
495
496		var key = '__prioritize';
497
498		// Expand $elements if it's not already a jQuery object.
499			if (typeof $elements != 'jQuery')
500				$elements = $($elements);
501
502		// Step through elements.
503			$elements.each(function() {
504
505				var	$e = $(this), $p,
506					$parent = $e.parent();
507
508				// No parent? Bail.
509					if ($parent.length == 0)
510						return;
511
512				// Not moved? Move it.
513					if (!$e.data(key)) {
514
515						// Condition is false? Bail.
516							if (!condition)
517								return;
518
519						// Get placeholder (which will serve as our point of reference for when this element needs to move back).
520							$p = $e.prev();
521
522							// Couldn't find anything? Means this element's already at the top, so bail.
523								if ($p.length == 0)
524									return;
525
526						// Move element to top of parent.
527							$e.prependTo($parent);
528
529						// Mark element as moved.
530							$e.data(key, $p);
531
532					}
533
534				// Moved already?
535					else {
536
537						// Condition is true? Bail.
538							if (condition)
539								return;
540
541						$p = $e.data(key);
542						// Move element back to its original location (using our placeholder).
543							$e.insertAfter($p);
544
545						// Unmark element as moved.
546							$e.removeData(key);
547
548					}
549			});
550	};
551
552})(jQuery);

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.