source: main/waeup-hugo/public/js/util.js @ 15086

Last change on this file since 15086 was 14926, checked in by Henrik Bettermann, 7 years ago
File size: 11.6 KB
Line 
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);
Note: See TracBrowser for help on using the repository browser.