PageSourceSearch

https://emountainworks.com/assets/js/util.js

js emountainworks.com collected 2026-09-24 20:00:08 UTC 12,433 bytes, 587 lines download raw bytes

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