PageSourceSearch

https://gundremmingen.de/wp-content/themes/vgem2023/js/main.js?ver=1790313053

js gundremmingen.de collected 2026-09-25 05:11:14 UTC 130,143 bytes, 3,362 lines download raw bytes

vendor: 18,892 bytes, lines 1-349
1/**
2 * jBox is a jQuery plugin that makes it easy to create customizable tooltips, modal windows, image galleries and more.
3 *
4 * Author: Stephan Wagner <[email protected]> (https://stephanwagner.me)
5 *
6 * License: MIT (https://opensource.org/licenses/MIT)
7 *
8 * Requires: jQuery 3.5.0 (https://code.jquery.com/jquery-3.5.0.min.js)
9 *
10 * Documentation: https://stephanwagner.me/jBox/documentation
11 *
12 * Demos: https://stephanwagner.me/jBox/demos
13 */
14
15function jBoxWrapper(jQuery) {
16
17
18  var jBox = function jBox(type, options) {
19
20
21    // Options (https://stephanwagner.me/jBox/options)
22
23    this.options = {
24
25      // jBox ID
26      id: null,                    // Choose a unique id, otherwise jBox will set one for you (jBox1, jBox2, ...)
27
28      // Dimensions
29      width: 'auto',               // The width of the content area, e.g. 'auto', 200, '80%'
30      height: 'auto',              // The height of the content area
31      minWidth: null,              // Minimal width
32      minHeight: null,             // Minimal height
33      maxWidth: null,              // Maximal width
34      maxHeight: null,             // Maximal height
35
36      // Responsive dimensions
37      responsiveWidth: true,       // Adjusts the width to fit the viewport
38      responsiveHeight: true,      // Adjusts the height to fit the viewport
39      responsiveMinWidth: 100,     // Don't adjust width below this value (in pixel)
40      responsiveMinHeight: 100,    // Don't adjust height below this value (in pixel)
41
42      // Attach
43      attach: null,                // A jQuery selector to elements that will open and close your jBox, e.g. '.tooltip'
44      trigger: 'click',            // The event to open or close your jBox, use 'click', 'touchclick' or 'mouseenter'
45      preventDefault: false,       // Prevent the default event when opening jBox, e.g. don't follow the href in a link
46
47      // Content
48      content: null,               // You can use HTML or a jQuery element, e.g. jQuery('#jBox-content'). The elements will be appended to the content element and then made visible, so hide them with style="display: none" beforehand
49      getContent: null,            // Get the content from an attribute when jBox opens, e.g. getContent: 'data-content'. Use 'html' to get the attached elements HTML as content
50      title: null,                 // Adds a title to your jBox
51      getTitle: null,              // Get the title from an attribute when jBox opens, e.g. getTitle: 'data-title'
52      footer: null,                // Adds a footer to your jBox
53      isolateScroll: true,         // Isolates scrolling to the content container
54
55      // AJAX
56      ajax: {                      // Setting an URL will make an AJAX request when jBox opens. Optional you can add any jQuery AJAX option (http://api.jquery.com/jquery.ajax/)
57        url: null,                 // The URL to send the AJAX request to
58        data: '',                  // Data to send with your AJAX request, e.g. {id: 82, limit: 10}
59        reload: false,             // Resend the AJAX request when jBox opens. Use true to send the AJAX request only once for every attached element or 'strict' to resend every time jBox opens
60        getURL: 'data-url',        // The attribute in the source element where the AJAX request will look for the URL, e.g. data-url="https://reqres.in/api/users"
61        getData: 'data-ajax',      // The attribute in the source element where the AJAX request will look for the data, e.g. data-ajax="id=82&limit=10"
62        setContent: true,          // Automatically set the response as new content when the AJAX request is finished
63        loadingClass: true,        // Add a class to the wrapper when jBox is loading, set to class name or true to use the default class name 'jBox-loading'
64        spinner: true,             // Hides the current content and adds a spinner while loading. You can pass HTML content to add your own spinner, e.g. spinner: '<div class="mySpinner"></div>'
65        spinnerDelay: 300,         // Milliseconds to wait until spinner appears
66        spinnerReposition: true    // Repositions jBox when the spinner is added or removed
67      },
68      cancelAjaxOnClose: true,     // Cancels the ajax call when jBox closes and it hasn't finished loading yet
69
70      // Position
71      target: null,                // The jQuery selector to the target element where jBox will be opened. If no element is found, jBox will use the attached element as target
72      position: {
73        x: 'center',               // Horizontal position, use a number, 'left', 'right' or 'center'
74        y: 'center'                // Vertical position, use a number, 'top', 'bottom' or 'center'
75      },
76      outside: null,               // Use 'x', 'y', or 'xy' to move your jBox outside of the target element
77      offset: 0,                   // Offset to final position, you can set different values for x and y with an object, e.g. {x: 20, y: 10}
78      attributes: {                // Note that attributes can only be 'left' or 'right' when using numbers for position, e.g. {x: 300, y: 20}
79        x: 'left',                 // Horizontal position, use 'left' or 'right'
80        y: 'top'                   // Vertical position, use 'top' or 'bottom'
81      },
82      fixed: false,                // Your jBox will stay on position when scrolling
83      adjustPosition: true,        // Adjusts your jBoxes position if there is not enough space, use 'flip', 'move' or true for both. This option overrides the reposition options
84      adjustTracker: false,        // By default jBox adjusts its position when it opens or when the window size changes, set to true to also adjust when scrolling
85      adjustDistance: 5,           // The minimal distance to the viewport edge while adjusting. Use an object to set different values, e.g. {top: 50, right: 5, bottom: 20, left: 5}
86      reposition: true,            // Calculates new position when the window-size changes
87      repositionOnOpen: true,      // Calculates new position each time jBox opens (rather than only when it opens the first time)
88      repositionOnContent: true,   // Calculates new position when the content changes with .setContent() or .setTitle()
89      holdPosition: true,          // Keeps current position if space permits. Applies only to 'Modal' type.
90
91      // Pointer
92      pointer: false,              // Your pointer will always point towards the target element, so the option outside needs to be 'x' or 'y'. By default the pointer is centered, set a position to move it to any side. You can also add an offset, e.g. 'left:30' or 'center:-20'
93      pointTo: 'target',           // Setting something else than 'target' will add a pointer even if there is no target element set or found. Use 'top', 'right', 'bottom' or 'left'
94
95      // Animations
96      fade: 180,                   // Fade duration in ms, set to 0 or false to disable
97      animation: null,             // Animation when opening or closing, use 'pulse', 'zoomIn', 'zoomOut', 'move', 'slide', 'flip', 'tada' (CSS inspired from Daniel Edens Animate.css: http://daneden.me/animate)
98
99      // Appearance
100      theme: 'Default',            // Set a jBox theme class
101      addClass: null,              // Adds classes to the wrapper
102      overlay: false,              // Adds an overlay to hide page content when jBox opens (adjust color and opacity with CSS)
103      overlayClass: null,          // Add a class name to the overlay
104      zIndex: 10000,               // Use a high z-index, or set to 'auto' to bring to front on open
105
106      // Delays
107      delayOpen: 0,                // Delay opening in ms. Note that the delay will be ignored if your jBox didn't finish closing
108      delayClose: 0,               // Delay closing in ms. Nnote that there is always a closing delay of at least 10ms to ensure jBox won't be closed when opening right away
109
110      // Closing
111      closeOnEsc: false,           // Close jBox when pressing [esc] key
112      closeOnClick: false,         // Close jBox with mouseclick. Use true (click anywhere), 'box' (click on jBox itself), 'overlay' (click on the overlay), 'body' (click anywhere but jBox)
113      closeOnMouseleave: false,    // Close jBox when the mouse leaves the jBox area or the area of the attached element
114      closeButton: false,          // Adds a close button to your jBox. Use 'title', 'box', 'overlay' or true (true will add the button to the overlay, title or the jBox itself, in that order if any of those elements can be found)
115
116      // Other options
117      appendTo: jQuery('body'),    // The element your jBox will be appended to. Any other element than jQuery('body') is only useful for fixed positions or when position values are numbers
118      createOnInit: false,         // Creates jBox and makes it available in DOM when it's being initialized, otherwise it will be created when it opens for the first time
119      blockScroll: false,          // Blocks scrolling when jBox is open
120      blockScrollAdjust: true,     // Adjust page elements to avoid content jumps when scrolling is blocked. See more here: https://github.com/StephanWagner/unscroll
121      draggable: false,            // Make your jBox draggable (use 'true', 'title' or provide an element as handle) (inspired from Chris Coyiers CSS-Tricks http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/)
122      dragOver: true,              // When you have multiple draggable jBoxes, the one you select will always move over the other ones
123      autoClose: false,            // Time in ms when jBox will close automatically after it was opened
124      delayOnHover: false,         // Delay auto-closing while mouse is hovered
125      showCountdown: false,        // Display a nice progress-indicator when autoClose is enabled
126
127      // Audio                     // You can use the integrated audio function whenever you'd like to play an audio file, e.g. onInit: function () { this.audio('url_to_audio_file_without_file_extension', 75); }
128      preloadAudio: true,          // Preloads the audio files set in option audio. You can also preload other audio files, e.g. ['src_to_file.mp3', 'src_to_file.ogg']
129      audio: null,                 // The URL to an audio file to play when jBox opens. Set the URL without file extension, jBox will look for an .mp3 and .ogg file. To play audio when jBox closes, use an object, e.g. {open: 'src_to_audio1', close: 'src_to_audio2'}
130      volume: 100,                 // The volume in percent. To have different volumes for opening and closeing, use an object, e.g. {open: 75, close: 100}
131
132      // Events                    // Note that you can use 'this' in all event functions, it refers to your jBox object (e.g. onInit: function () { this.open(); })
133      onInit: null,                // Fired when jBox is initialized
134      onAttach: null,              // Fired when jBox attached itself to elements, the attached element will be passed as a parameter, e.g. onAttach: function (element) { element.css({color: 'red'}); }
135      onPosition: null,            // Fired when jBox is positioned
136      onCreated: null,             // Fired when jBox is created and availible in DOM
137      onOpen: null,                // Fired when jBox opens
138      onClose: null,               // Fired when jBox closes
139      onCloseComplete: null,       // Fired when jBox is completely closed (when fading is finished)
140      onDragStart: null,           // Fired when dragging starts
141      onDragEnd: null              // Fired when dragging finished
142    };
143
144
145    // Default plugin options
146
147    this._pluginOptions = {
148
149      // Default options for tooltips
150      'Tooltip': {
151        getContent: 'title',
152        trigger: 'mouseenter',
153        position: {
154          x: 'center',
155          y: 'top'
156        },
157        outside: 'y',
158        pointer: true
159      },
160
161      // Default options for mouse tooltips
162      'Mouse': {
163        responsiveWidth: false,
164        responsiveHeight: false,
165        adjustPosition: 'flip',
166        target: 'mouse',
167        trigger: 'mouseenter',
168        position: {
169          x: 'right',
170          y: 'bottom'
171        },
172        outside: 'xy',
173        offset: 5
174      },
175
176      // Default options for modal windows
177      'Modal': {
178        target: jQuery(window),
179        fixed: true,
180        blockScroll: true,
181        closeOnEsc: true,
182        closeOnClick: 'overlay',
183        closeButton: true,
184        overlay: true,
185        animation: 'zoomIn'
186      },
187    };
188
189
190    // Merge options
191
192    this.options = jQuery.extend(true, this.options, this._pluginOptions[type] ? this._pluginOptions[type] : jBox._pluginOptions[type], options);
193
194
195    // Set the jBox type
196
197    jQuery.type(type) == 'string' && (this.type = type);
198
199
200    // Checks if the user is on a touch device, borrowed from https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js
201
202    this.isTouchDevice = (function () {
203      var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
204      var mq = function (query) {
205        return window.matchMedia(query).matches;
206      }
207
208      if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
209        return true;
210      }
211
212      var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
213      return mq(query);
214    })();
215
216
217    // Add close event for body click when we are on touch device and jBox triggers on mouseenter
218
219    if (this.isTouchDevice && this.options.trigger === 'mouseenter' && this.options.closeOnClick === false) {
220      this.options.closeOnClick = 'body';
221    }
222
223
224    // Local function to fire events
225
226    this._fireEvent = function (event, pass)
227    {
228      this.options['_' + event] && (this.options['_' + event].bind(this))(pass);
229      this.options[event] && (this.options[event].bind(this))(pass);
230    };
231
232
233    // Get a unique jBox ID
234
235    this.options.id === null && (this.options.id = 'jBox' + jBox._getUniqueID());
236    this.id = this.options.id;
237
238
239    // Correct impossible options
240
241    ((this.options.position.x == 'center' && this.options.outside == 'x') || (this.options.position.y == 'center' && this.options.outside == 'y')) && (this.options.outside = null);
242    this.options.pointTo == 'target' && (!this.options.outside || this.options.outside == 'xy') && (this.options.pointer = false);
243
244
245    // Correct multiple choice options
246
247    jQuery.type(this.options.offset) != 'object' ? (this.options.offset = {x: this.options.offset, y: this.options.offset}) : (this.options.offset = jQuery.extend({x: 0, y: 0}, this.options.offset));
248    jQuery.type(this.options.adjustDistance) != 'object' ? (this.options.adjustDistance = {top: this.options.adjustDistance, right: this.options.adjustDistance, bottom: this.options.adjustDistance, left: this.options.adjustDistance}) : (this.options.adjustDistance = jQuery.extend({top: 5, left: 5, right: 5, bottom: 5}, this.options.adjustDistance));
249
250
251    // Save default outside position
252
253    this.outside = this.options.outside && this.options.outside != 'xy' ? this.options.position[this.options.outside] : false;
254
255
256    // Save where the jBox is aligned to
257
258    this.align = this.outside ? this.outside : (this.options.position.y != 'center' && jQuery.type(this.options.position.y) != 'number' ? this.options.position.x : (this.options.position.x != 'center' && jQuery.type(this.options.position.x) != 'number' ? this.options.position.y : this.options.attributes.x));
259
260
261    // Adjust option zIndex
262
263    jBox.zIndexMax = Math.max(jBox.zIndexMax || 0, this.options.zIndex === 'auto' ? 10000 : this.options.zIndex);
264    if (this.options.zIndex === 'auto') {
265      this.adjustZIndexOnOpen = true;
266      jBox.zIndexMax += 2;
267      this.options.zIndex = jBox.zIndexMax;
268      this.trueModal = this.options.overlay;
269    }
270
271    // Internal positioning functions
272
273    this._getOpp = function (opp) { return {left: 'right', right: 'left', top: 'bottom', bottom: 'top', x: 'y', y: 'x'}[opp]; };
274    this._getXY = function (xy) { return {left: 'x', right: 'x', top: 'y', bottom: 'y', center: 'x'}[xy]; };
275    this._getTL = function (tl) { return {left: 'left', right: 'left', top: 'top', bottom: 'top', center: 'left', x: 'left', y: 'top'}[tl]; };
276
277
278    // Get a dimension value in integer pixel dependent on appended element
279
280    this._getInt = function (value, dimension) {
281      if (value == 'auto') return 'auto';
282      if (value && jQuery.type(value) == 'string' && value.slice(-1) == '%') {
283        return jQuery(window)[dimension == 'height' ? 'innerHeight' : 'innerWidth']() * parseInt(value.replace('%', '')) / 100;
284      }
285      return value;
286    };
287
288
289    // Create an svg element
290
291    this._createSVG = function (type, options)
292    {
293      var svg = document.createElementNS('http://www.w3.org/2000/svg', type);
294      jQuery.each(options, function (index, item) {
295        svg.setAttribute(item[0], (item[1] || ''));
296      });
297      return svg;
298    };
299
300
301    // Isolate scrolling in a container
302
303    this._isolateScroll = function (el)
304    {
305      // Abort if element not found
306      if (!el || !el.length) return;
307
308      el.on('DOMMouseScroll.jBoxIsolateScroll mousewheel.jBoxIsolateScroll', function (ev) {
309        var delta = ev.wheelDelta || (ev.originalEvent && ev.originalEvent.wheelDelta) || -ev.detail;
310        var overflowBottom = this.scrollTop + el.outerHeight() - this.scrollHeight >= 0;
311        var overflowTop = this.scrollTop <= 0;
312        ((delta < 0 && overflowBottom) || (delta > 0 && overflowTop)) && ev.preventDefault();
313      });
314    };
315
316
317    // Set the title width to content width
318
319    this._setTitleWidth = function ()
320    {
321      // Abort if there is no title or width of content is auto
322      if (!this.titleContainer || (this.content[0].style.width == 'auto' && !this.content[0].style.maxWidth)) return null;
323
324      // Expose wrapper to get actual width
325      if (this.wrapper.css('display') == 'none') {
326        this.wrapper.css('display', 'block');
327        var contentWidth = this.content.outerWidth();
328        this.wrapper.css('display', 'none');
329      } else {
330        var contentWidth = this.content.outerWidth();
331      }
332
333      // Set max-width only
334      this.titleContainer.css({maxWidth: (Math.max(contentWidth, parseInt(this.content[0].style.maxWidth)) || null)});
335    }
336
337
338    // Make jBox draggable
339
340    this._draggable = function ()
341    {
342      // Abort if jBox is not draggable
343      if (!this.options.draggable) return false;
344
345      // Get the handle where jBox will be dragged with
346      var handle = this.options.draggable == 'title' ? this.titleContainer : (this.options.draggable instanceof jQuery ? this.options.draggable : (jQuery.type(this.options.draggable) == 'string' ? jQuery(this.options.draggable) : this.wrapper));
347
348      // Abort if no handle or if draggable was set already
349      if (!handle || !(handle instanceof jQuery) || !handle.length || handle.data('jBox-draggable')) 
vendor: 21,563 bytes, lines 349-836
349return false;
350
351      // Add mouse events
352      handle.addClass('jBox-draggable').data('jBox-draggable', true).on('touchstart mousedown', function (ev)
353      {
354        if (ev.button == 2 || jQuery(ev.target).hasClass('jBox-noDrag') || jQuery(ev.target).parents('.jBox-noDrag').length) return;
355
356        // Store current mouse position
357        this.draggingStartX = ev.pageX;
358        this.draggingStartY = ev.pageY;
359
360        // Adjust z-index when dragging jBox over another draggable jBox
361        if (this.options.dragOver && !this.trueModal && parseInt(this.wrapper.css('zIndex'), 10) <= jBox.zIndexMaxDragover) {
362          jBox.zIndexMaxDragover += 1;
363          this.wrapper.css('zIndex', jBox.zIndexMaxDragover);
364        }
365
366        var drg_h = this.wrapper.outerHeight();
367        var drg_w = this.wrapper.outerWidth();
368        var pos_y = this.wrapper.offset().top + drg_h - ev.pageY;
369        var pos_x = this.wrapper.offset().left + drg_w - ev.pageX;
370
371        jQuery(document).on('touchmove.jBox-draggable-' + this.id + ' mousemove.jBox-draggable-' + this.id, function (ev) {
372          // Fire onDragStart event when jBox moves
373          if (!this.dragging && this.draggingStartX != ev.pageX && this.draggingStartY != ev.pageY) {
374            this._fireEvent('onDragStart');
375            this.dragging = true;
376          }
377
378          // Adjust position
379          this.wrapper.offset({
380            top: ev.pageY + pos_y - drg_h,
381            left: ev.pageX + pos_x - drg_w
382          });
383        }.bind(this));
384        ev.preventDefault();
385
386      }.bind(this)).on('touchend mouseup', function () {
387        // Remove drag event
388        jQuery(document).off('touchmove.jBox-draggable-' + this.id + ' mousemove.jBox-draggable-' + this.id);
389
390        // Fire onDragEnd event
391        this.dragging && this._fireEvent('onDragEnd');
392
393        // Reset dragging reference
394        this.dragging = false;
395
396        if ((this.type == 'Modal' || this.type == 'Confirm') && this.options.holdPosition) {
397          // Drag end captures new position
398          var jBoxOffset = jQuery('#' + this.id).offset(),
399            pos = {
400              x: jBoxOffset.left - jQuery(document).scrollLeft(),
401              y: jBoxOffset.top - jQuery(document).scrollTop()
402            };
403          this.position({position: pos, offset: {x: 0, y: 0}});
404        }
405      }.bind(this));
406
407      // Get highest z-index
408      if (!this.trueModal) {
409        jBox.zIndexMaxDragover = !jBox.zIndexMaxDragover ? this.options.zIndex : Math.max(jBox.zIndexMaxDragover, this.options.zIndex);
410      }
411
412      return this;
413    };
414
415    // Create jBox
416
417    this._create = function ()
418    {
419      // Abort if jBox was created already
420      if (this.wrapper) return;
421
422      // Create wrapper
423      this.wrapper = jQuery('<div/>', {
424        id: this.id,
425        'class': 'jBox-wrapper' + (this.type ? ' jBox-' + this.type : '') + (this.options.theme ? ' jBox-' + this.options.theme : '') + (this.options.addClass ? ' ' + this.options.addClass : '')
426      }).css({
427        position: (this.options.fixed ? 'fixed' : 'absolute'),
428        display: 'none',
429        opacity: 0,
430        zIndex: this.options.zIndex
431
432        // Save the jBox instance in the wrapper, so you can get access to your jBox when you only have the element
433      }).data('jBox', this);
434
435      // Add mouseleave event, only close jBox when the new target is not the source element
436      this.options.closeOnMouseleave && this.wrapper.on('mouseleave', function (ev) {
437        !this.source || !(ev.relatedTarget == this.source[0] || jQuery.inArray(this.source[0], jQuery(ev.relatedTarget).parents('*')) !== -1) && this.close();
438      }.bind(this));
439
440      // Add closeOnClick: 'box' events
441      (this.options.closeOnClick == 'box') && this.wrapper.on('click', function () { this.close({ignoreDelay: true}); }.bind(this));
442
443      // Create container
444      this.container = jQuery('<div class="jBox-container"/>').appendTo(this.wrapper);
445
446      // Create content
447      this.content = jQuery('<div class="jBox-content"/>').appendTo(this.container);
448
449      // Create footer
450      this.options.footer && (this.footer = jQuery('<div class="jBox-footer"/>').append(this.options.footer).appendTo(this.container));
451
452      // Isolate scrolling
453      this.options.isolateScroll && this._isolateScroll(this.content);
454
455      // Create close button
456      if (this.options.closeButton) {
457        var closeButtonSVG = this._createSVG('svg', [['viewBox', '0 0 24 24']]);
458        closeButtonSVG.appendChild(this._createSVG('path', [['d', 'M22.2,4c0,0,0.5,0.6,0,1.1l-6.8,6.8l6.9,6.9c0.5,0.5,0,1.1,0,1.1L20,22.3c0,0-0.6,0.5-1.1,0L12,15.4l-6.9,6.9c-0.5,0.5-1.1,0-1.1,0L1.7,20c0,0-0.5-0.6,0-1.1L8.6,12L1.7,5.1C1.2,4.6,1.7,4,1.7,4L4,1.7c0,0,0.6-0.5,1.1,0L12,8.5l6.8-6.8c0.5-0.5,1.1,0,1.1,0L22.2,4z']]));
459        this.closeButton = jQuery('<div class="jBox-closeButton jBox-noDrag"/>').on('click', function (ev) { this.close({ignoreDelay: true}); }.bind(this)).append(closeButtonSVG);
460
461        // Add close button to jBox container
462        if (this.options.closeButton == 'box' || (this.options.closeButton === true && !this.options.overlay && !this.options.title && !this.options.getTitle)) {
463          this.wrapper.addClass('jBox-closeButton-box');
464          this.closeButton.appendTo(this.container);
465        }
466      }
467
468      // Append jBox to DOM
469      this.wrapper.appendTo(this.options.appendTo);
470
471      // Fix adjustDistance if there is a close button in the box
472      this.wrapper.find('.jBox-closeButton').length &&  jQuery.each(['top', 'right', 'bottom', 'left'], function (index, pos) {
473        this.wrapper.find('.jBox-closeButton').css(pos) && this.wrapper.find('.jBox-closeButton').css(pos) != 'auto' && (this.options.adjustDistance[pos] = Math.max(this.options.adjustDistance[pos], this.options.adjustDistance[pos] + (((parseInt(this.wrapper.find('.jBox-closeButton').css(pos)) || 0) + (parseInt(this.container.css('border-' + pos + '-width')) || 0)) * -1)));
474      }.bind(this));
475
476      // Create pointer
477      if (this.options.pointer) {
478
479        // Get pointer vars and save globally
480        this.pointer = {
481          position: (this.options.pointTo != 'target') ? this.options.pointTo : this._getOpp(this.outside),
482          xy: (this.options.pointTo != 'target') ? this._getXY(this.options.pointTo) : this._getXY(this.outside),
483          align: 'center',
484          offset: 0
485        };
486
487        this.pointer.element = jQuery('<div class="jBox-pointer jBox-pointer-' + this.pointer.position + '"/>').appendTo(this.wrapper);
488        this.pointer.dimensions = {
489          x: this.pointer.element.outerWidth(),
490          y: this.pointer.element.outerHeight()
491        };
492
493        if (jQuery.type(this.options.pointer) == 'string') {
494          var split = this.options.pointer.split(':');
495          split[0] && (this.pointer.align = split[0]);
496          split[1] && (this.pointer.offset = parseInt(split[1]));
497        }
498        this.pointer.alignAttribute = (this.pointer.xy == 'x' ? (this.pointer.align == 'bottom' ? 'bottom' : 'top') : (this.pointer.align == 'right' ? 'right' : 'left'));
499
500        // Set wrapper CSS
501        this.wrapper.css('padding-' + this.pointer.position, this.pointer.dimensions[this.pointer.xy]);
502
503        // Set pointer CSS
504        this.pointer.element.css(this.pointer.alignAttribute, (this.pointer.align == 'center' ? '50%' : 0)).css('margin-' + this.pointer.alignAttribute, this.pointer.offset);
505        this.pointer.margin = {};
506        this.pointer.margin['margin-' + this.pointer.alignAttribute] = this.pointer.offset;
507
508        // Add a transform to fix centered position
509        (this.pointer.align == 'center') && this.pointer.element.css('transform', 'translate(' + (this.pointer.xy == 'y' ? (this.pointer.dimensions.x * -0.5 + 'px') : 0) + ', ' + (this.pointer.xy == 'x' ? (this.pointer.dimensions.y * -0.5 + 'px') : 0) + ')');
510
511        this.pointer.element.css((this.pointer.xy == 'x' ? 'width' : 'height'), parseInt(this.pointer.dimensions[this.pointer.xy]) + parseInt(this.container.css('border-' + this.pointer.alignAttribute + '-width')));
512
513        // Add class to wrapper for CSS access
514        this.wrapper.addClass('jBox-pointerPosition-' + this.pointer.position);
515      }
516
517      // Set title and content
518      this.setContent(this.options.content, true);
519      this.setTitle(this.options.title, true);
520
521      this.options.draggable && this._draggable();
522
523      // Fire onCreated event
524      this._fireEvent('onCreated');
525    };
526
527
528    // Create jBox onInit
529
530    this.options.createOnInit && this._create();
531
532
533    // Attach jBox
534
535    this.options.attach && this.attach();
536
537
538    // Attach document and window events
539
540    this._attachEvents = function ()
541    {
542      // Cancel countdown on mouseenter if delayOnHover
543      this.options.delayOnHover && jQuery('#' + this.id).on('mouseenter', function (ev) { this.isHovered = true; }.bind(this));
544
545      // Resume countdown on mouseleave if delayOnHover
546      this.options.delayOnHover && jQuery('#' + this.id).on('mouseleave', function (ev) { this.isHovered = false; }.bind(this));
547
548      // Positioning events
549      if ((this.options.adjustPosition || this.options.reposition) && !this.fixed && this.outside) {
550
551        // Trigger position events when scrolling
552        this.options.adjustTracker && jQuery(window).on('scroll.jBox-' + this.id, function (ev) { this.position(); }.bind(this));
553
554        // Trigger position events when resizing
555        (this.options.adjustPosition || this.options.reposition) && jQuery(window).on('resize.jBox-' + this.id, function (ev) { this.position(); }.bind(this));
556      }
557
558      // Mousemove events
559      this.options.target == 'mouse' && jQuery('body').on('mousemove.jBox-' + this.id, function (ev) { this.position({mouseTarget: {top: ev.pageY, left: ev.pageX}}); }.bind(this));
560    };
561
562
563    // Detach document and window events
564
565    this._detachEvents = function ()
566    {
567      // Closing event: closeOnEsc
568      this.options.closeOnEsc && jQuery(document).off('keyup.jBox-' + this.id);
569
570      // Closing event: closeOnClick
571      (this.options.closeOnClick === true || this.options.closeOnClick == 'body') && jQuery(document).off('click.jBox-' + this.id);
572
573      // Positioning events
574      this.options.adjustTracker && jQuery(window).off('scroll.jBox-' + this.id);
575      (this.options.adjustPosition || this.options.reposition) && jQuery(window).off('resize.jBox-' + this.id);
576
577      // Mousemove events
578      this.options.target == 'mouse' && jQuery('body').off('mousemove.jBox-' + this.id);
579    };
580
581
582    // Show overlay
583
584    this._showOverlay = function ()
585    {
586      // Create the overlay if wasn't created already
587      if (!this.overlay) {
588
589        // Create element and append to the element where jBox is appended to
590        this.overlay = jQuery('<div id="' + this.id + '-overlay"/>').addClass('jBox-overlay' + (this.type ? ' jBox-overlay-' + this.type : '')).css({
591          display: 'none',
592          opacity: 0,
593          zIndex: this.options.zIndex - 1
594        }).appendTo(this.options.appendTo);
595
596        // Add a class name to the overlay
597        this.options.overlayClass && this.overlay.addClass(this.options.overlayClass);
598
599        // Add close button to overlay
600        (this.options.closeButton == 'overlay' || this.options.closeButton === true) && this.overlay.append(this.closeButton);
601
602        // Add closeOnClick: 'overlay' events
603        this.options.closeOnClick == 'overlay' && this.overlay.on('click', function () { this.close({ignoreDelay: true}); }.bind(this));
604
605        // Adjust option adjustDistance if there is a close button in the overlay
606        jQuery('#' + this.id + '-overlay .jBox-closeButton').length && (this.options.adjustDistance.top = Math.max(jQuery('#' + this.id + '-overlay .jBox-closeButton').outerHeight(), this.options.adjustDistance.top));
607      }
608
609      // Adjust zIndex
610      if (this.adjustZIndexOnOpen === true) {
611        this.overlay.css('zIndex', parseInt(this.wrapper.css('zIndex'), 10) - 1);
612      }
613
614      // Abort if overlay is already visible
615      if (this.overlay.css('display') == 'block') return;
616
617      // Show overlay
618      this.options.fade ? (this.overlay.stop() && this.overlay.animate({opacity: 1}, {
619        queue: false,
620        duration: this.options.fade,
621        start: function () { this.overlay.css({display: 'block'}); }.bind(this)
622      })) : this.overlay.css({display: 'block', opacity: 1});
623    };
624
625
626    // Hide overlay
627
628    this._hideOverlay = function ()
629    {
630      // Abort if the overlay wasn't created yet
631      if (!this.overlay) return;
632
633      // Hide overlay if no other jBox needs it
634      this.options.fade ? (this.overlay.stop() && this.overlay.animate({opacity: 0}, {
635        queue: false,
636        duration: this.options.fade,
637        complete: function () { this.overlay.css({display: 'none'}); }.bind(this)
638      })) : this.overlay.css({display: 'none', opacity: 0});
639    };
640
641
642    // Get the correct jBox dimensions by moving jBox out of viewport
643
644    this._exposeDimensions = function ()
645    {
646      // Move wrapper out of viewport
647      this.wrapper.css({
648        top: -10000,
649        left: -10000,
650        right: 'auto',
651        bottom: 'auto'
652      });
653
654      // Get jBox dimensions
655      var jBoxDimensions = {
656        x: this.wrapper.outerWidth(),
657        y: this.wrapper.outerHeight()
658      };
659
660      // Reset position to viewport
661      this.wrapper.css({
662        top: 'auto',
663        left: 'auto'
664      });
665
666      return jBoxDimensions;
667    };
668
669
670    // Generate CSS for animations and append to header
671
672    this._generateAnimationCSS = function ()
673    {
674      // Get open and close animations if none provided
675      (jQuery.type(this.options.animation) != 'object') && (this.options.animation = {
676        pulse: {open: 'pulse', close: 'zoomOut'},
677        zoomIn: {open: 'zoomIn', close: 'zoomIn'},
678        zoomOut: {open: 'zoomOut', close: 'zoomOut'},
679        move: {open: 'move', close: 'move'},
680        slide: {open: 'slide', close: 'slide'},
681        flip: {open: 'flip', close: 'flip'},
682        tada: {open: 'tada', close: 'zoomOut'}
683      }[this.options.animation]);
684
685      // Abort if animation not found
686      if (!this.options.animation) return null;
687
688      // Get direction var
689      this.options.animation.open && (this.options.animation.open = this.options.animation.open.split(':'));
690      this.options.animation.close && (this.options.animation.close = this.options.animation.close.split(':'));
691      this.options.animation.openDirection = this.options.animation.open[1] ? this.options.animation.open[1] : null;
692      this.options.animation.closeDirection = this.options.animation.close[1] ? this.options.animation.close[1] : null;
693      this.options.animation.open && (this.options.animation.open = this.options.animation.open[0]);
694      this.options.animation.close && (this.options.animation.close = this.options.animation.close[0]);
695
696      // Add 'Open' and 'Close' to animation names
697      this.options.animation.open && (this.options.animation.open += 'Open');
698      this.options.animation.close && (this.options.animation.close += 'Close');
699
700      // All animations
701      var animations = {
702        pulse: {
703          duration: 350,
704          css: [['0%', 'scale(1)'], ['50%', 'scale(1.1)'], ['100%', 'scale(1)']]
705        },
706        zoomInOpen: {
707          duration: (this.options.fade || 180),
708          css: [['0%', 'scale(0.9)'], ['100%', 'scale(1)']]
709        },
710        zoomInClose: {
711          duration: (this.options.fade || 180),
712          css: [['0%', 'scale(1)'], ['100%', 'scale(0.9)']]
713        },
714        zoomOutOpen: {
715          duration: (this.options.fade || 180),
716          css: [['0%', 'scale(1.1)'], ['100%', 'scale(1)']]
717        },
718        zoomOutClose: {
719          duration: (this.options.fade || 180),
720          css: [['0%', 'scale(1)'], ['100%', 'scale(1.1)']]
721        },
722        moveOpen: {
723          duration: (this.options.fade || 180),
724          positions: {top: {'0%': -12}, right: {'0%': 12}, bottom: {'0%': 12}, left: {'0%': -12}},
725          css: [['0%', 'translate%XY(%Vpx)'], ['100%', 'translate%XY(0px)']]
726        },
727        moveClose: {
728          duration: (this.options.fade || 180),
729          timing: 'ease-in',
730          positions: {top: {'100%': -12}, right: {'100%': 12}, bottom: {'100%': 12}, left: {'100%': -12}},
731          css: [['0%', 'translate%XY(0px)'], ['100%', 'translate%XY(%Vpx)']]
732        },
733        slideOpen: {
734          duration: 400,
735          positions: {top: {'0%': -400}, right: {'0%': 400}, bottom: {'0%': 400}, left: {'0%': -400}},
736          css: [['0%', 'translate%XY(%Vpx)'], ['100%', 'translate%XY(0px)']]
737        },
738        slideClose: {
739          duration: 400,
740          timing: 'ease-in',
741          positions: {top: {'100%': -400}, right: {'100%': 400}, bottom: {'100%': 400}, left: {'100%': -400}},
742          css: [['0%', 'translate%XY(0px)'], ['100%', 'translate%XY(%Vpx)']]
743        },
744        flipOpen: {
745          duration: 600,
746          css: [['0%', 'perspective(400px) rotateX(90deg)'], ['40%', 'perspective(400px) rotateX(-15deg)'], ['70%', 'perspective(400px) rotateX(15deg)'], ['100%', 'perspective(400px) rotateX(0deg)']]
747        },
748        flipClose: {
749          duration: (this.options.fade || 300),
750          css: [['0%', 'perspective(400px) rotateX(0deg)'], ['100%', 'perspective(400px) rotateX(90deg)']]
751        },
752        tada: {
753          duration: 800,
754          css: [['0%', 'scale(1)'], ['10%, 20%', 'scale(0.9) rotate(-3deg)'], ['30%, 50%, 70%, 90%', 'scale(1.1) rotate(3deg)'], ['40%, 60%, 80%', 'scale(1.1) rotate(-3deg)'], ['100%', 'scale(1) rotate(0)']]
755        }
756      };
757
758      // Set Open and Close names for standalone animations
759      jQuery.each(['pulse', 'tada'], function (index, item) { animations[item + 'Open'] = animations[item + 'Close'] = animations[item]; });
760
761      // Function to generate the CSS for the keyframes
762      var generateKeyframeCSS = function (ev, position)
763      {
764        // Generate keyframes CSS
765        keyframe_css = '@keyframes jBox-' + this.id + '-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ' {';
766        jQuery.each(animations[this.options.animation[ev]].css, function (index, item) {
767          var translate = position ? item[1].replace('%XY', this._getXY(position).toUpperCase()) : item[1];
768          animations[this.options.animation[ev]].positions && (translate = translate.replace('%V', animations[this.options.animation[ev]].positions[position][item[0]]));
769          keyframe_css += item[0] + ' {transform:' + translate + ';}';
770        }.bind(this));
771        keyframe_css += '}';
772
773        // Generate class CSS
774        keyframe_css += '.jBox-' + this.id + '-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ' {';
775        keyframe_css += 'animation-duration: ' + animations[this.options.animation[ev]].duration + 'ms;';
776        keyframe_css += 'animation-name: jBox-' + this.id + '-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ';';
777        keyframe_css += animations[this.options.animation[ev]].timing ? ('animation-timing-function: ' + animations[this.options.animation[ev]].timing + ';') : '';
778        keyframe_css += '}';
779
780        return keyframe_css;
781      }.bind(this);
782
783      // Generate css for each event and positions
784      this._animationCSS = '';
785      jQuery.each(['open', 'close'], function (index, ev)
786      {
787        // No CSS needed for closing with no fade
788        if (!this.options.animation[ev] || !animations[this.options.animation[ev]] || (ev == 'close' && !this.options.fade)) return '';
789
790        // Generate CSS
791        animations[this.options.animation[ev]].positions ?
792          jQuery.each(['top', 'right', 'bottom', 'left'], function (index2, position) { this._animationCSS += generateKeyframeCSS(ev, position); }.bind(this)) :
793          this._animationCSS += generateKeyframeCSS(ev);
794      }.bind(this));
795
796    };
797
798
799    // Add css for animations
800
801    this.options.animation && this._generateAnimationCSS();
802
803
804    // Block body clicks for 10ms to prevent extra event triggering
805
806    this._blockBodyClick = function ()
807    {
808      this.blockBodyClick = true;
809      setTimeout(function () { this.blockBodyClick = false; }.bind(this), 10);
810    };
811
812
813    // Animations
814
815    this._animate = function (ev)
816    {
817      // The event which triggers the animation
818      !ev && (ev = this.isOpen ? 'open' : 'close');
819
820      // Don't animate when closing with no fade duration
821      if (!this.options.fade && ev == 'close') return null;
822
823      // Get the current position, use opposite if jBox is flipped
824      var animationDirection = (this.options.animation[ev + 'Direction'] || ((this.align != 'center') ? this.align : this.options.attributes.x));
825      this.flipped && this._getXY(animationDirection) == (this._getXY(this.align)) && (animationDirection = this._getOpp(animationDirection));
826
827      // Add event and position classes
828      var classnames = 'jBox-' + this.id + '-animation-' + this.options.animation[ev] + '-' + ev + ' jBox-' + this.id + '-animation-' + this.options.animation[ev] + '-' + ev + '-' + animationDirection;
829      this.wrapper.addClass(classnames);
830
831      // Get duration of animation
832      var animationDuration = parseFloat(this.wrapper.css('animation-duration')) * 1000;
833      ev == 'close' && (animationDuration = Math.min(animationDuration, this.options.fade));
834
835      // Remove animation classes when animation is finished
836      setTimeout(function () { this.wrapper.removeClass(classnames);
vendor: 20,040 bytes, lines 836-1322
836 }.bind(this), animationDuration);
837    };
838
839
840    // Abort an animation
841
842    this._abortAnimation = function ()
843    {
844      // Remove all animation classes
845      var classes = this.wrapper.attr('class').split(' ').filter(function (c) {
846        return c.lastIndexOf('jBox-' + this.id + '-animation', 0) !== 0;
847      }.bind(this));
848      this.wrapper.attr('class', classes.join(' '));
849    };
850
851
852    // Adjust dimensions when browser is resized
853
854    if (this.options.responsiveWidth || this.options.responsiveHeight)
855    {
856      // Responsive positioning overrides options adjustPosition and reposition
857      // TODO: Only add this resize event when the other one from adjustPosition and reposition was not set
858      jQuery(window).on('resize.responsivejBox-' + this.id, function (ev) { if (this.isOpen) { this.position(); } }.bind(this));
859    }
860
861
862    // Fix audio options
863
864    jQuery.type(this.options.preloadAudio) === 'string' && (this.options.preloadAudio = [this.options.preloadAudio]);
865    jQuery.type(this.options.audio) === 'string' && (this.options.audio = {open: this.options.audio});
866    jQuery.type(this.options.volume) === 'number' && (this.options.volume = {open: this.options.volume, close: this.options.volume});
867
868    if (this.options.preloadAudio === true && this.options.audio) {
869      this.options.preloadAudio = [];
870      jQuery.each(this.options.audio, function (index, url) {
871        this.options.preloadAudio.push(url + '.mp3');
872        this.options.preloadAudio.push(url + '.ogg');
873      }.bind(this));
874    }
875
876
877    // Preload audio files
878
879    this.options.preloadAudio.length && jQuery.each(this.options.preloadAudio, function (index, url) {
880      var audio = new Audio();
881      audio.src = url;
882      audio.preload = 'auto';
883    });
884
885
886    // Fire onInit event
887
888    this._fireEvent('onInit');
889
890
891    return this;
892  };
893
894
895  // Attach jBox to elements
896
897  jBox.prototype.attach = function (elements, trigger)
898  {
899    // Get elements from options if none passed
900    !elements && (elements = this.options.attach);
901
902    // Convert selectors to jQuery objects
903    jQuery.type(elements) == 'string' && (elements = jQuery(elements));
904
905    // Get trigger event from options if not passed
906    !trigger && (trigger = this.options.trigger);
907
908    // Loop through elements and attach jBox
909    elements && elements.length && jQuery.each(elements, function (index, el) {
910      el = jQuery(el);
911
912      // Only attach if the element wasn't attached to this jBox already
913      if (!el.data('jBox-attached-' + this.id)) {
914
915        // Remove title attribute and store content on element
916        (this.options.getContent == 'title' && el.attr('title') != undefined) && el.data('jBox-getContent', el.attr('title')).removeAttr('title');
917
918        // Add Element to collection
919        this.attachedElements || (this.attachedElements = []);
920        this.attachedElements.push(el[0]);
921
922        // Add click or mouseenter event, click events can prevent default as well
923        el.on(trigger + '.jBox-attach-' + this.id, function (ev)
924        {
925          // Clear timer
926          this.timer && clearTimeout(this.timer);
927
928          // Block opening when jbox is open and the source element is triggering
929          if (trigger == 'mouseenter' && this.isOpen && this.source[0] == el[0]) return;
930
931          // Only close jBox if you click the current target element, otherwise open at new target
932          if (this.isOpen && this.source && this.source[0] != el[0]) var forceOpen = true;
933
934          // Set new source element
935          this.source = el;
936
937          // Set new target
938          !this.options.target && (this.target = el);
939
940          // Prevent default action on click
941          trigger == 'click' && this.options.preventDefault && ev.preventDefault();
942
943          // Toggle or open jBox
944          this[trigger == 'click' && !forceOpen ? 'toggle' : 'open']();
945
946        }.bind(this));
947
948        // Add close event for trigger event mouseenter
949        (this.options.trigger == 'mouseenter') && el.on('mouseleave', function (ev)
950        {
951          // Abort if jBox wasn't created yet
952          if (!this.wrapper) return null;
953
954          // If we have set closeOnMouseleave, do not close jBox when leaving attached element and mouse is over jBox
955          if (!this.options.closeOnMouseleave || !(ev.relatedTarget == this.wrapper[0] || jQuery(ev.relatedTarget).parents('#' + this.id).length)) this.close();
956        }.bind(this));
957
958        // Store
959        el.data('jBox-attached-' + this.id, trigger);
960
961        // Fire onAttach event
962        this._fireEvent('onAttach', el);
963      }
964
965    }.bind(this));
966
967    return this;
968  };
969
970
971  // Detach jBox from elements
972
973  jBox.prototype.detach = function (elements)
974  {
975    // Get elements from stores elements if none passed
976    !elements && (elements = this.attachedElements || []);
977
978    elements && elements.length && jQuery.each(elements, function (index, el) {
979      el = jQuery(el);
980
981      // Remove events
982      if (el.data('jBox-attached-' + this.id)) {
983        el.off(el.data('jBox-attached-' + this.id) + '.jBox-attach-' + this.id);
984        el.data('jBox-attached-' + this.id, null);
985      }
986      // Remove element from collection
987      this.attachedElements = jQuery.grep(this.attachedElements, function (value) {
988        return value != el[0];
989      });
990    }.bind(this));
991
992    return this;
993  };
994
995
996  // Set title
997
998  jBox.prototype.setTitle = function (title, ignore_positioning)
999  {
1000    // Abort if title to set
1001    if (title == null || title == undefined) return this;
1002
1003    // Create jBox if it wasn't created already
1004    !this.wrapper && this._create();
1005
1006    // Get the width and height of wrapper, only if they change we need to reposition
1007    var wrapperHeight = this.wrapper.outerHeight();
1008    var wrapperWidth = this.wrapper.outerWidth();
1009
1010    // Create title elements if they weren't created already
1011    if (!this.title) {
1012      this.titleContainer = jQuery('<div class="jBox-title"/>');
1013      this.title = jQuery('<div/>').appendTo(this.titleContainer);
1014      if (this.options.closeButton == 'title' || (this.options.closeButton === true && !this.options.overlay)) {
1015        this.wrapper.addClass('jBox-closeButton-title');
1016        this.closeButton.appendTo(this.titleContainer);
1017      }
1018      this.titleContainer.insertBefore(this.content);
1019      this._setTitleWidth();
1020    }
1021
1022    // Add or remove wrapper class
1023    this.wrapper[title ? 'addClass' : 'removeClass']('jBox-hasTitle');
1024
1025    // Set title html
1026    this.title.html(title);
1027
1028    // Adjust width of title
1029    wrapperWidth != this.wrapper.outerWidth() && this._setTitleWidth();
1030
1031    // Make jBox draggable
1032    this.options.draggable && this._draggable();
1033
1034    // Reposition if dimensions changed
1035    !ignore_positioning && this.options.repositionOnContent && (wrapperHeight != this.wrapper.outerHeight() || wrapperWidth != this.wrapper.outerWidth()) && this.position();
1036
1037    return this;
1038  };
1039
1040
1041  // Set content
1042
1043  jBox.prototype.setContent = function (content, ignore_positioning)
1044  {
1045    // Abort if no content to set
1046    if (content == null || content == undefined) return this;
1047
1048    // Create jBox if it wasn't created already
1049    !this.wrapper && this._create();
1050
1051    // Get the width and height of wrapper, only if they change we need to reposition
1052    var wrapperHeight = this.wrapper.outerHeight();
1053    var wrapperWidth = this.wrapper.outerWidth();
1054
1055    // Move all appended containers to body
1056    this.content.children('[data-jbox-content-appended]').appendTo('body').css({display: 'none'});
1057
1058    // Set the new content
1059    switch (jQuery.type(content)) {
1060      case 'string':
1061        this.content.html(content);
1062        break;
1063      case 'object':
1064        if (content && (content instanceof jQuery || content.constructor.prototype.jquery)) {
1065          this.content.html('');
1066          content.attr('data-jbox-content-appended', 1).appendTo(this.content).css({display: 'block'});
1067        } else {
1068          this.content.html(JSON.stringify(content));
1069        }
1070        break;
1071     }
1072
1073    // Adjust title width
1074    wrapperWidth != this.wrapper.outerWidth() && this._setTitleWidth();
1075
1076    // Make jBox draggable
1077    this.options.draggable && this._draggable();
1078
1079    // Reposition if dimensions changed
1080    !ignore_positioning && this.options.repositionOnContent && (wrapperHeight != this.wrapper.outerHeight() || wrapperWidth != this.wrapper.outerWidth()) && this.position();
1081
1082    return this;
1083  };
1084
1085
1086  // Set jBox dimensions
1087
1088  jBox.prototype.setDimensions = function (type, value, pos)
1089  {
1090    // Create jBox if it wasn't created already
1091    !this.wrapper && this._create();
1092
1093    // Default value is 'auto'
1094    value == undefined && (value = 'auto');
1095
1096    // Set CSS of content and title
1097    this.content.css(type, this._getInt(value));
1098
1099    // Adjust title width
1100    type == 'width' && this._setTitleWidth();
1101
1102    // Update options
1103    this.options[type] = value;
1104
1105    // Reposition by default
1106    (pos == undefined || pos) && this.position();
1107  };
1108
1109
1110  // Set jBox width or height
1111
1112  jBox.prototype.setWidth = function (value, pos) { this.setDimensions('width', value, pos); };
1113  jBox.prototype.setHeight = function (value, pos) { this.setDimensions('height', value, pos); };
1114
1115
1116  // Position jBox
1117
1118  jBox.prototype.position = function (options)
1119  {
1120    // Options are required
1121    !options && (options = {});
1122
1123    // Combine passed options with jBox options
1124    options = jQuery.extend(true, this.options, options);
1125
1126    // Get the target
1127    this.target = options.target || this.target || jQuery(window);
1128
1129    // Make sure target is a jQuery element
1130    !(this.target instanceof jQuery || this.target == 'mouse') && (this.target = jQuery(this.target));
1131
1132    // Abort if target is missing
1133    if (!this.target.length) return this;
1134
1135    // Reset content css to get original dimensions
1136    this.content.css({
1137      width: this._getInt(options.width, 'width'),
1138      height: this._getInt(options.height, 'height'),
1139      minWidth: this._getInt(options.minWidth, 'width'),
1140      minHeight: this._getInt(options.minHeight, 'height'),
1141      maxWidth: this._getInt(options.maxWidth, 'width'),
1142      maxHeight: this._getInt(options.maxHeight, 'height'),
1143    });
1144
1145    // Reset width of title
1146    this._setTitleWidth();
1147
1148    // Get jBox dimensions
1149    var jBoxDimensions = this._exposeDimensions();
1150
1151    // Check if target has fixed position, store in elements data
1152    this.target != 'mouse' && !this.target.data('jBox-' + this.id + '-fixed') && this.target.data('jBox-' + this.id + '-fixed', (this.target[0] != jQuery(window)[0] && (this.target.css('position') == 'fixed' || this.target.parents().filter(function () { return jQuery(this).css('position') == 'fixed'; }).length > 0)) ? 'fixed' : 'static');
1153
1154    // Get the window dimensions
1155    var windowDimensions = {
1156      x: jQuery(window).outerWidth(),
1157      y: jQuery(window).outerHeight(),
1158      top: (options.fixed && this.target.data('jBox-' + this.id + '-fixed') ? 0 : jQuery(window).scrollTop()),
1159      left: (options.fixed && this.target.data('jBox-' + this.id + '-fixed') ? 0 : jQuery(window).scrollLeft())
1160    };
1161    windowDimensions.bottom = windowDimensions.top + windowDimensions.y;
1162    windowDimensions.right = windowDimensions.left + windowDimensions.x;
1163
1164    // Get target offset
1165    try { var targetOffset = this.target.offset(); } catch (e) { var targetOffset = {top: 0, left: 0}; };
1166
1167    // When the target is fixed and jBox is fixed, remove scroll offset
1168    if (this.target != 'mouse' && this.target.data('jBox-' + this.id + '-fixed') == 'fixed' && options.fixed) {
1169      targetOffset.top = targetOffset.top - jQuery(window).scrollTop();
1170      targetOffset.left = targetOffset.left - jQuery(window).scrollLeft();
1171    }
1172
1173    // Get target dimensions
1174    var targetDimensions = {
1175      x: this.target == 'mouse' ? 12 : this.target.outerWidth(),
1176      y: this.target == 'mouse' ? 20 : this.target.outerHeight(),
1177      top: this.target == 'mouse' && options.mouseTarget ? options.mouseTarget.top : (targetOffset ? targetOffset.top : 0),
1178      left: this.target == 'mouse' && options.mouseTarget ? options.mouseTarget.left : (targetOffset ? targetOffset.left : 0)
1179    };
1180
1181    // Check if jBox is outside
1182    var outside = options.outside && !(options.position.x == 'center' && options.position.y == 'center');
1183
1184    // Get the available space on all sides
1185    var availableSpace = {
1186      x: windowDimensions.x - options.adjustDistance.left - options.adjustDistance.right, // TODO: substract position.x when they are numbers
1187      y: windowDimensions.y - options.adjustDistance.top - options.adjustDistance.bottom, // TODO: substract position.x when they are numbers
1188      left: !outside ? 0 : (targetDimensions.left - jQuery(window).scrollLeft() - options.adjustDistance.left),
1189      right: !outside ? 0 : (windowDimensions.x - targetDimensions.left + jQuery(window).scrollLeft() - targetDimensions.x - options.adjustDistance.right),
1190      top: !outside ? 0 : (targetDimensions.top - jQuery(window).scrollTop() - this.options.adjustDistance.top),
1191      bottom: !outside ? 0 : (windowDimensions.y - targetDimensions.top + jQuery(window).scrollTop() - targetDimensions.y - options.adjustDistance.bottom),
1192    };
1193
1194    // Get the default outside position, check if box will be flipped
1195    var jBoxOutsidePosition = {
1196      x: (options.outside == 'x' || options.outside == 'xy') && jQuery.type(options.position.x) != 'number' ? options.position.x : null,
1197      y: (options.outside == 'y' || options.outside == 'xy') && jQuery.type(options.position.y) != 'number' ? options.position.y : null
1198    };
1199    var flip = {x: false, y: false};
1200    (jBoxOutsidePosition.x && jBoxDimensions.x > availableSpace[jBoxOutsidePosition.x] && availableSpace[this._getOpp(jBoxOutsidePosition.x)] > availableSpace[jBoxOutsidePosition.x]) && (jBoxOutsidePosition.x = this._getOpp(jBoxOutsidePosition.x)) && (flip.x = true);
1201    (jBoxOutsidePosition.y && jBoxDimensions.y > availableSpace[jBoxOutsidePosition.y] && availableSpace[this._getOpp(jBoxOutsidePosition.y)] > availableSpace[jBoxOutsidePosition.y]) && (jBoxOutsidePosition.y = this._getOpp(jBoxOutsidePosition.y)) && (flip.y = true);
1202
1203    // Adjust responsive dimensions
1204    if (options.responsiveWidth || options.responsiveHeight) {
1205
1206      // Adjust width and height according to default outside position
1207      var adjustResponsiveWidth = function ()
1208      {
1209        if (options.responsiveWidth && jBoxDimensions.x > availableSpace[jBoxOutsidePosition.x || 'x']) {
1210          var contentWidth = availableSpace[jBoxOutsidePosition.x || 'x'] - (this.pointer && outside && options.outside == 'x' ? this.pointer.dimensions.x : 0) - parseInt(this.container.css('border-left-width')) - parseInt(this.container.css('border-right-width'));
1211          this.content.css({
1212            width: contentWidth > this.options.responsiveMinWidth ? contentWidth : null,
1213            minWidth: contentWidth < parseInt(this.content.css('minWidth')) ? 0 : null
1214          });
1215          this._setTitleWidth();
1216        }
1217        jBoxDimensions = this._exposeDimensions();
1218
1219      }.bind(this);
1220      options.responsiveWidth && adjustResponsiveWidth();
1221
1222      // After adjusting width, check if jBox will be flipped for y
1223      options.responsiveWidth && !flip.y && (jBoxOutsidePosition.y && jBoxDimensions.y > availableSpace[jBoxOutsidePosition.y] && availableSpace[this._getOpp(jBoxOutsidePosition.y)] > availableSpace[jBoxOutsidePosition.y]) && (jBoxOutsidePosition.y = this._getOpp(jBoxOutsidePosition.y)) && (flip.y = true);
1224
1225      // Adjust width and height according to default outside position
1226      var adjustResponsiveHeight = function ()
1227      {
1228        if (options.responsiveHeight && jBoxDimensions.y > availableSpace[jBoxOutsidePosition.y || 'y']) {
1229
1230          // Expose wrapper to get correct title height
1231          var exposeTitleFooterHeight = function () {
1232            if (!this.titleContainer && !this.footer) return 0;
1233            if (this.wrapper.css('display') == 'none') {
1234              this.wrapper.css('display', 'block');
1235              var height = (this.titleContainer ? this.titleContainer.outerHeight() : 0) + (this.footer ? this.footer.outerHeight() : 0);
1236              this.wrapper.css('display', 'none');
1237            } else {
1238              var height = (this.titleContainer ? this.titleContainer.outerHeight() : 0) + (this.footer ? this.footer.outerHeight() : 0);
1239            }
1240            return height || 0;
1241          }.bind(this);
1242
1243          var contentHeight = availableSpace[jBoxOutsidePosition.y || 'y'] - (this.pointer && outside && options.outside == 'y' ? this.pointer.dimensions.y : 0) - exposeTitleFooterHeight() - parseInt(this.container.css('border-top-width')) - parseInt(this.container.css('border-bottom-width'));
1244          this.content.css({height: contentHeight > this.options.responsiveMinHeight ? contentHeight : null});
1245          this._setTitleWidth();
1246        }
1247        jBoxDimensions = this._exposeDimensions();
1248
1249      }.bind(this);
1250      options.responsiveHeight && adjustResponsiveHeight();
1251
1252      // After adjusting height, check if jBox will be flipped for x
1253      options.responsiveHeight && !flip.x && (jBoxOutsidePosition.x && jBoxDimensions.x > availableSpace[jBoxOutsidePosition.x] && availableSpace[this._getOpp(jBoxOutsidePosition.x)] > availableSpace[jBoxOutsidePosition.x]) && (jBoxOutsidePosition.x = this._getOpp(jBoxOutsidePosition.x)) && (flip.x = true);
1254
1255      // Adjust width and height if jBox will be flipped
1256      if (options.adjustPosition && options.adjustPosition != 'move') {
1257        flip.x && adjustResponsiveWidth();
1258        flip.y && adjustResponsiveHeight();
1259      }
1260    }
1261
1262    // Store new positioning vars in local var
1263    var pos = {};
1264
1265    // Calculate positions
1266    var setPosition = function (p)
1267    {
1268      // Set number positions
1269      if (jQuery.type(options.position[p]) == 'number') {
1270        pos[options.attributes[p]] = options.position[p];
1271        return;
1272      }
1273
1274      // We have a target, so use 'left' or 'top' as attributes
1275      var a = options.attributes[p] = (p == 'x' ? 'left' : 'top');
1276
1277      // Start at target position
1278      pos[a] = targetDimensions[a];
1279
1280      // Set centered position
1281      if (options.position[p] == 'center') {
1282        pos[a] += Math.ceil((targetDimensions[p] - jBoxDimensions[p]) / 2);
1283
1284        // If the target is the window, adjust centered position depending on adjustDistance
1285        (this.target != 'mouse' && this.target[0] && this.target[0] == jQuery(window)[0]) && (pos[a] += (options.adjustDistance[a] - options.adjustDistance[this._getOpp(a)]) * 0.5);
1286        return;
1287      }
1288
1289      // Move inside
1290      (a != options.position[p]) && (pos[a] += targetDimensions[p] - jBoxDimensions[p]);
1291
1292      // Move outside
1293      (options.outside == p || options.outside == 'xy') && (pos[a] += jBoxDimensions[p] * (a != options.position[p] ? 1 : -1));
1294
1295    }.bind(this);
1296
1297    // Set position including offset
1298    setPosition('x');
1299    setPosition('y');
1300
1301    // Adjust position depending on pointer align
1302    if (this.pointer && options.pointTo == 'target' && jQuery.type(options.position.x) != 'number' && jQuery.type(options.position.y) != 'number') {
1303
1304      var adjustWrapper = 0;
1305
1306      // Where is the pointer aligned? Add or substract accordingly
1307      switch (this.pointer.align) {
1308        case 'center':
1309        if (options.position[this._getOpp(options.outside)] != 'center') {
1310          adjustWrapper += (jBoxDimensions[this._getOpp(options.outside)] / 2);
1311        }
1312        break;
1313        default:
1314        switch (options.position[this._getOpp(options.outside)]) {
1315          case 'center':
1316            adjustWrapper += ((jBoxDimensions[this._getOpp(options.outside)] / 2) - (this.pointer.dimensions[this._getOpp(options.outside)] / 2)) * (this.pointer.align == this._getTL(this.pointer.align) ? 1 : -1);
1317          break;
1318          default:
1319            adjustWrapper += (this.pointer.align != options.position[this._getOpp(options.outside)]) ?
1320
1321            // If pointer align is different to position align
1322            (
1322this.d
vendor: 12,437 bytes, lines 1322-1617
1322imensions[this._getOpp(options.outside)] * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? 1 : -1)) + ((this.pointer.dimensions[this._getOpp(options.outside)] / 2) * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? -1 : 1)) :
1323
1324            // If pointer align is same as position align
1325            (this.pointer.dimensions[this._getOpp(options.outside)] / 2) * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? 1 : -1);
1326          break;
1327        }
1328        break;
1329      }
1330
1331      adjustWrapper *= (options.position[this._getOpp(options.outside)] == this.pointer.alignAttribute ? -1 : 1);
1332      adjustWrapper += this.pointer.offset * (this.pointer.align == this._getOpp(this._getTL(this.pointer.align)) ? 1 : -1);
1333
1334      pos[this._getTL(this._getOpp(this.pointer.xy))] += adjustWrapper;
1335    }
1336
1337    // Add final offset
1338    pos[options.attributes.x] += options.offset.x;
1339    pos[options.attributes.y] += options.offset.y;
1340
1341    // Set CSS
1342    this.wrapper.css(pos);
1343
1344    // Adjust position
1345    if (options.adjustPosition) {
1346
1347      // Reset cached pointer position
1348      if (this.positionAdjusted) {
1349        this.pointer && this.wrapper.css('padding', 0).css('padding-' + this._getOpp(this.outside), this.pointer.dimensions[this._getXY(this.outside)]).removeClass('jBox-pointerPosition-' + this._getOpp(this.pointer.position)).addClass('jBox-pointerPosition-' + this.pointer.position);
1350        this.pointer && this.pointer.element.attr('class', 'jBox-pointer jBox-pointer-' + this._getOpp(this.outside)).css(this.pointer.margin);
1351        this.positionAdjusted = false;
1352        this.flipped = false;
1353      }
1354
1355      // Find out where the jBox is out of view area
1356      var outYT = (windowDimensions.top > pos.top - (options.adjustDistance.top || 0)),
1357        outXR = (windowDimensions.right < pos.left + jBoxDimensions.x + (options.adjustDistance.right || 0)),
1358        outYB = (windowDimensions.bottom < pos.top + jBoxDimensions.y + (options.adjustDistance.bottom || 0)),
1359        outXL = (windowDimensions.left > pos.left - (options.adjustDistance.left || 0)),
1360        outX = outXL ? 'left' : (outXR ? 'right' : null),
1361        outY = outYT ? 'top' : (outYB ? 'bottom' : null),
1362        out = outX || outY;
1363
1364      // Only continue if jBox is out of view area
1365      if (out) {
1366
1367        if ((this.type == 'Modal' || this.type == 'Confirm')
1368          && jQuery.type(this.options.position.x) == 'number'
1369          && jQuery.type(this.options.position.y) == 'number'
1370        ) {
1371          var diffX = 0, diffY = 0;
1372          if (this.options.holdPosition) {
1373
1374            // Adjust left or right
1375            if (outXL) {
1376              diffX = windowDimensions.left - (pos.left - (options.adjustDistance.left || 0));
1377            } else if (outXR) {
1378              diffX = windowDimensions.right - (pos.left + jBoxDimensions.x + (options.adjustDistance.right || 0));
1379            }
1380
1381            // Adjust top or bottom
1382            if (outYT) {
1383              diffY = windowDimensions.top - (pos.top - (options.adjustDistance.top || 0));
1384            } else if (outYB) {
1385              diffY = windowDimensions.bottom - (pos.top + jBoxDimensions.y + (options.adjustDistance.bottom || 0));
1386            }
1387
1388            this.options.position.x = Math.max(windowDimensions.top, this.options.position.x + diffX);
1389            this.options.position.y = Math.max(windowDimensions.left, this.options.position.y + diffY);
1390
1391            setPosition('x');
1392            setPosition('y');
1393            this.wrapper.css(pos);
1394          }
1395          // Fire onPosition event
1396          this._fireEvent('onPosition');
1397
1398          return this;
1399        }
1400
1401        // Function to flip position
1402        if (options.adjustPosition === true || options.adjustPosition === 'flip') {
1403          var flipJBox = function (xy) {
1404            this.wrapper.css(this._getTL(xy), pos[this._getTL(xy)] + ((jBoxDimensions[this._getXY(xy)] + (options.offset[this._getXY(xy)] * (xy == 'top' || xy == 'left' ? -2 : 2)) + targetDimensions[this._getXY(xy)]) * (xy == 'top' || xy == 'left' ? 1 : -1)));
1405            this.pointer && this.wrapper.removeClass('jBox-pointerPosition-' + this.pointer.position).addClass('jBox-pointerPosition-' + this._getOpp(this.pointer.position)).css('padding', 0).css('padding-' + xy, this.pointer.dimensions[this._getXY(xy)]);
1406            this.pointer && this.pointer.element.attr('class', 'jBox-pointer jBox-pointer-' + xy);
1407            this.positionAdjusted = true;
1408            this.flipped = true;
1409          }.bind(this);
1410
1411          // Flip jBox
1412          flip.x && flipJBox(this.options.position.x);
1413          flip.y && flipJBox(this.options.position.y);
1414        }
1415
1416        // Move jBox (only possible with pointer)
1417        var outMove = (this._getXY(this.outside) == 'x') ? outY : outX;
1418
1419        if (this.pointer && options.pointTo == 'target' && options.adjustPosition != 'flip' && this._getXY(outMove) == this._getOpp(this._getXY(this.outside))) {
1420
1421          // Get the maximum space we have availible to adjust
1422          if (this.pointer.align == 'center') {
1423            var spaceAvail = (jBoxDimensions[this._getXY(outMove)] / 2) - (this.pointer.dimensions[this._getOpp(this.pointer.xy)] / 2) - (parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) * (outMove != this._getTL(outMove) ? -1 : 1));
1424          } else {
1425            var spaceAvail = (outMove == this.pointer.alignAttribute) ?
1426              parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) :
1427              jBoxDimensions[this._getXY(outMove)] - parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) - this.pointer.dimensions[this._getXY(outMove)];
1428          }
1429
1430          // Get the overlapping space
1431          var spaceDiff = (outMove == this._getTL(outMove)) ?
1432            windowDimensions[this._getTL(outMove)] - pos[this._getTL(outMove)] + options.adjustDistance[outMove] :
1433            (windowDimensions[this._getOpp(this._getTL(outMove))] - pos[this._getTL(outMove)] - options.adjustDistance[outMove] - jBoxDimensions[this._getXY(outMove)]) * -1;
1434
1435          // Add overlapping space on left or top window edge
1436          if (outMove == this._getOpp(this._getTL(outMove)) && pos[this._getTL(outMove)] - spaceDiff < windowDimensions[this._getTL(outMove)] + options.adjustDistance[this._getTL(outMove)]) {
1437            spaceDiff -= windowDimensions[this._getTL(outMove)] + options.adjustDistance[this._getTL(outMove)] - (pos[this._getTL(outMove)] - spaceDiff);
1438          }
1439
1440          // Only adjust the maximum availible
1441          spaceDiff = Math.min(spaceDiff, spaceAvail);
1442
1443          // Move jBox
1444          if (spaceDiff <= spaceAvail && spaceDiff > 0) {
1445            this.pointer.element.css('margin-' + this.pointer.alignAttribute, parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) - (spaceDiff * (outMove != this.pointer.alignAttribute ? -1 : 1)));
1446            this.wrapper.css(this._getTL(outMove), pos[this._getTL(outMove)] + (spaceDiff * (outMove != this._getTL(outMove) ? -1 : 1)));
1447            this.positionAdjusted = true;
1448          }
1449        }
1450      }
1451    }
1452
1453    // Fire onPosition event
1454    this._fireEvent('onPosition');
1455
1456    return this;
1457  };
1458
1459
1460  // Block scrolling
1461  // Borrowed from https://github.com/StephanWagner/unscroll
1462
1463  jBox.prototype.unscroll = function (elements) {
1464
1465    // Store reusable vars
1466    this.set = function (id, value) {
1467      if (!window.unscrollStore) {
1468        window.unscrollStore = {};
1469      }
1470      window.unscrollStore[id] = value;
1471    };
1472
1473    // Get reusable vars
1474    this.get = function (id) {
1475      return window.unscrollStore ? window.unscrollStore[id] : null;
1476    };
1477
1478    // Get the width of the scroll bar in pixel
1479    this.getScrollbarWidth = function () {
1480      if (this.get('scrollbarWidth')) {
1481        return this.get('scrollbarWidth') + 'px';
1482      }
1483      var scrollElement = document.createElement('div');
1484      scrollElement.style.width = '100px';
1485      scrollElement.style.height = '100px';
1486      scrollElement.style.overflow = 'scroll';
1487      scrollElement.style.position = 'absolute';
1488      scrollElement.style.top = '-10000';
1489
1490      document.body.appendChild(scrollElement);
1491      var scrollbarWidth = scrollElement.offsetWidth - scrollElement.clientWidth;
1492      document.body.removeChild(scrollElement);
1493
1494      this.set('scrollbarWidth', scrollbarWidth);
1495      return scrollbarWidth + 'px';
1496    }
1497
1498    // Add unscroll class to head
1499    function addUnscrollClassName() {
1500      if (document.getElementById('unscroll-class-name')) {
1501        return;
1502      }
1503      var css = '.unscrollable { overflow: hidden !important; }',
1504        head = document.head || document.getElementsByTagName('head')[0],
1505        style = document.createElement('style');
1506      style.type = 'text/css';
1507      style.setAttribute('id', 'unscroll-class-name');
1508      style.appendChild(document.createTextNode(css));
1509      head.appendChild(style);
1510    }
1511
1512    // Get the elements to adjust, force body element
1513    this.getElementsToAdjust = function (elements) {
1514      !elements && (elements = []);
1515
1516      if (typeof elements === 'string') {
1517        elements = [
1518          [elements, 'padding-right']
1519        ];
1520      }
1521
1522      elements.forEach(function (element, index) {
1523        if (typeof element === 'string') {
1524          elements[index] = [element, 'padding-right'];
1525        }
1526      });
1527
1528      var bodyFound = false;
1529      for (var i = 0; i < elements.length; i++) {
1530        if (elements[i][0].indexOf('body') !== -1) {
1531          bodyFound = true;
1532        }
1533      };
1534
1535      if (bodyFound === false) {
1536        elements.push(['body', 'padding-right']);
1537      }
1538
1539      return elements;
1540    }
1541
1542    this.pageHasScrollbar = function () {
1543      return this.getScrollbarWidth() && document.body.offsetHeight > window.innerHeight;
1544    }
1545
1546    // Clean up elements
1547    if (this.pageHasScrollbar()) {
1548      elements = this.getElementsToAdjust(elements);
1549
1550      // Loop through elements and adjust accordingly
1551      for (var i = 0; i < elements.length; i++) {
1552        var elementsDOM = document.querySelectorAll(elements[i][0]);
1553        for (var j = 0; j < elementsDOM.length; j++) {
1554          if (elementsDOM[j].getAttribute('data-unscroll')) {
1555            return;
1556          }
1557          var attribute = elements[i][1];
1558          var computedStyles = window.getComputedStyle(elementsDOM[j]);
1559          var computedStyle = computedStyles.getPropertyValue(attribute);
1560          elementsDOM[j].setAttribute('data-unscroll', attribute);
1561          if (!computedStyle) {
1562            computedStyle = '0px';
1563          }
1564          var operator = attribute == 'padding-right' || attribute == 'right' ? '+' : '-';
1565          elementsDOM[j].style[attribute] = 'calc(' + computedStyle + ' ' + operator + ' ' + this.getScrollbarWidth() + ')';
1566        }
1567      }
1568    }
1569
1570    // Make the page unscrollable
1571    addUnscrollClassName();
1572    document.body.classList.add('unscrollable');
1573  }
1574
1575  jBox.prototype.unscroll.reset = function () {
1576    var elements = document.querySelectorAll('[data-unscroll]');
1577
1578    for (var i = 0; i < elements.length; i++) {
1579      var attribute = elements[i].getAttribute('data-unscroll');
1580      elements[i].style[attribute] = null;
1581      elements[i].removeAttribute('data-unscroll');
1582    }
1583    document.body.classList.remove('unscrollable');
1584  }
1585
1586
1587  // Open jBox
1588
1589  jBox.prototype.open = function (options)
1590  {
1591    // Create blank options if none passed
1592    !options && (options = {});
1593
1594    // Abort if jBox was destroyed
1595    if (this.isDestroyed) return this;
1596
1597    // Construct jBox if not already constructed
1598    !this.wrapper && this._create();
1599
1600    // Add css to header if not added already
1601    !this._styles && (this._styles = jQuery('<style/>').append(this._animationCSS).appendTo(jQuery('head')));
1602
1603    // Abort any opening or closing timer
1604    this.timer && clearTimeout(this.timer);
1605
1606    // Block body click for 10ms, so jBox can open on attached elements while closeOnClick = 'body'
1607    this._blockBodyClick();
1608
1609    // Block opening
1610    if (this.isDisabled) return this;
1611
1612    // Closing event: closeOnEsc
1613    this.options.closeOnEsc && jQuery(document).on('keyup.jBox-' + this.id, function (ev) { if (ev.keyCode == 27) { this.close({ignoreDelay: true}); }}.bind(this));
1614
1615    // Closing event: closeOnClick
1616    if (this.options.closeOnClick === true || this.options.closeOnClick === 'body') {
1617      jQuery('body').on('click.jBox-' + this.id
vendor: 5,224 bytes, lines 1617-1744
1617, function (ev) {
1618        if (this.blockBodyClick || (this.options.closeOnClick == 'body' && (ev.target == this.wrapper[0] || this.wrapper.has(ev.target).length))) return;
1619        this.close({ignoreDelay: true});
1620      }.bind(this));
1621
1622      // Fix for iOS event bubbling issue
1623      // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
1624      this.isTouchDevice && jQuery('body > *').on('click.jBox-' + this.id, function () {
1625        return true;
1626      });
1627    }
1628
1629    // Opening function
1630    var open = function () {
1631
1632      // Adjust zIndex
1633      if (this.adjustZIndexOnOpen === true) {
1634        jBox.zIndexMax = Math.max(
1635          parseInt(this.wrapper.css('zIndex'), 10),
1636          this.options.zIndex,
1637          jBox.zIndexMax || 0,
1638          jBox.zIndexMaxDragover || 0
1639        ) + 2;
1640        this.wrapper.css('zIndex', jBox.zIndexMax);
1641        this.options.zIndex = jBox.zIndexMax;
1642      }
1643
1644      // Set title from source element
1645      this.source && this.options.getTitle && (this.source.attr(this.options.getTitle) && this.setTitle(this.source.attr(this.options.getTitle), true));
1646
1647      // Set content from source element
1648      this.source && this.options.getContent && (this.source.data('jBox-getContent') ? this.setContent(this.source.data('jBox-getContent'), true) : (this.source.attr(this.options.getContent) ? this.setContent(this.source.attr(this.options.getContent), true) : (this.options.getContent == 'html' ? this.setContent(this.source.html(), true) : null)));
1649
1650      // Fire onOpen event
1651      this._fireEvent('onOpen');
1652
1653      // Get content from ajax
1654      if ((this.options.ajax && (this.options.ajax.url || (this.source && this.source.attr(this.options.ajax.getURL))) && (!this.ajaxLoaded || this.options.ajax.reload)) || (options.ajax && (options.ajax.url || options.ajax.data))) {
1655        // Send the content from stored data if there is any, otherwise load new data
1656        (this.options.ajax.reload != 'strict' && this.source && this.source.data('jBox-ajax-data') && !(options.ajax && (options.ajax.url || options.ajax.data))) ? this.setContent(this.source.data('jBox-ajax-data')) : this.ajax((options.ajax || null), true);
1657      }
1658
1659      // Set position
1660      (!this.positionedOnOpen || this.options.repositionOnOpen) && this.position(options) && (this.positionedOnOpen = true);
1661
1662      // Abort closing
1663      this.isClosing && this._abortAnimation();
1664
1665      // Open functions to call when jBox is closed
1666      if (!this.isOpen) {
1667
1668        // jBox is open now
1669        this.isOpen = true;
1670
1671        // Automatically close jBox after some time
1672        this.options.autoClose && (this.options.delayClose = this.options.autoClose) && this.close();
1673
1674        // Attach events
1675        this._attachEvents();
1676
1677        // Block scrolling
1678        if (this.options.blockScroll) {
1679          if (this.options.blockScrollAdjust) {
1680            if (jBox.blockScrollScopes) {
1681              jBox.blockScrollScopes++;
1682            } else {
1683              jBox.blockScrollScopes = 1;
1684              this.unscroll(Array.isArray(this.options.blockScrollAdjust) || typeof this.options.blockScrollAdjust === 'string' ? this.options.blockScrollAdjust : null);
1685            }
1686          } else {
1687            jQuery('body').addClass('jBox-blockScroll-' + this.id);
1688          }
1689        }
1690
1691        // Show overlay
1692        if (this.options.overlay) {
1693          this._showOverlay();
1694
1695          // TODO Optimize: We have to position here again, because if the overlay has a close button, the upper adjustDistance will be wrong
1696          this.position();
1697        }
1698
1699        // Only animate if jBox is completely closed
1700        this.options.animation && !this.isClosing && this._animate('open');
1701
1702        // Play audio file
1703        this.options.audio && this.options.audio.open && this.audio(this.options.audio.open, this.options.volume.open);
1704
1705        // Fading animation or show immediately
1706        if (this.options.fade) {
1707          this.wrapper.stop().animate({opacity: 1}, {
1708            queue: false,
1709            duration: this.options.fade,
1710            start: function () {
1711              this.isOpening = true;
1712              this.wrapper.css({display: 'block'});
1713            }.bind(this),
1714            always: function () {
1715              this.isOpening = false;
1716
1717              // Delay positioning for ajax to prevent positioning during animation
1718              setTimeout(function () { this.positionOnFadeComplete && this.position() && (this.positionOnFadeComplete = false); }.bind(this), 10);
1719            }.bind(this)
1720          });
1721        } else {
1722          this.wrapper.css({display: 'block', opacity: 1});
1723          this.positionOnFadeComplete && this.position() && (this.positionOnFadeComplete = false);
1724        }
1725      }
1726    }.bind(this);
1727
1728    // Open jBox
1729    this.options.delayOpen && !this.isOpen && !this.isClosing && !options.ignoreDelay ? (this.timer = setTimeout(open, this.options.delayOpen)) : open();
1730
1731    return this;
1732  };
1733
1734
1735  // Close jBox
1736
1737  jBox.prototype.close = function (options)
1738  {
1739    // Create blank options if none passed
1740    options || (options = {});
1741
1742    // Remove close events
1743    jQuery('body').off('click.jBox-' + this.id);
1744    this.isTouchDevice && jQuery('body > *').off('click
vendor: 9,545 bytes, lines 1744-2062
1744.jBox-' + this.id);
1745
1746    // Abort if jBox was destroyed or is currently closing
1747    if (this.isDestroyed || this.isClosing) return this;
1748
1749    // Abort opening
1750    this.timer && clearTimeout(this.timer);
1751
1752    // Block body click for 10ms, so jBox can open on attached elements while closeOnClick = 'body' is true
1753    this._blockBodyClick();
1754
1755    // Block closing
1756    if (this.isDisabled) return this;
1757
1758    // Close function
1759    var close = function () {
1760
1761      // Fire onClose event
1762      this._fireEvent('onClose');
1763
1764      // Cancel the ajax call
1765      if (this.options.cancelAjaxOnClose) {
1766        this.cancelAjax();
1767      }
1768
1769      // Only close if jBox is open
1770      if (this.isOpen) {
1771
1772        // jBox is not open anymore
1773        this.isOpen = false;
1774
1775        // Detach events
1776        this._detachEvents();
1777
1778        // Unblock scrolling
1779        if (this.options.blockScroll) {
1780          if (this.options.blockScrollAdjust) {
1781            jBox.blockScrollScopes = jBox.blockScrollScopes ? --jBox.blockScrollScopes : 0;
1782            !jBox.blockScrollScopes && this.unscroll.reset();
1783          } else {
1784            jQuery('body').removeClass('jBox-blockScroll-' + this.id);
1785          }
1786        }
1787
1788        // Hide overlay
1789        this.options.overlay && this._hideOverlay();
1790
1791        // Only animate if jBox is compleately closed
1792        this.options.animation && !this.isOpening && this._animate('close');
1793
1794        // Play audio file
1795        this.options.audio && this.options.audio.close && this.audio(this.options.audio.close, this.options.volume.close);
1796
1797        // Get fade duration
1798        var fadeDuration = this.isTouchDevice && this.options.target == 'mouse' ? 0 : this.options.fade;
1799
1800        // Fading animation or show immediately
1801        if (fadeDuration) {
1802          this.wrapper.stop().animate({opacity: 0}, {
1803            queue: false,
1804            duration: fadeDuration,
1805            start: function () {
1806              this.isClosing = true;
1807            }.bind(this),
1808            complete: function () {
1809              this.wrapper.css({display: 'none'});
1810              this._fireEvent('onCloseComplete');
1811            }.bind(this),
1812            always: function () {
1813              this.isClosing = false;
1814            }.bind(this)
1815          });
1816        } else {
1817          this.wrapper.css({display: 'none', opacity: 0});
1818          this._fireEvent('onCloseComplete');
1819        }
1820      }
1821    }.bind(this);
1822
1823    // Close jBox
1824    if (options.ignoreDelay || (this.isTouchDevice && this.options.target == 'mouse')) {
1825      close();
1826    } else if ((this.options.delayOnHover || this.options.showCountdown) && this.options.delayClose > 10) {
1827      var self = this;
1828      var remaining = this.options.delayClose;
1829      var prevFrame = Date.now();
1830      if (this.options.showCountdown && !this.inner) {
1831        var outer = jQuery('<div class="jBox-countdown" />');
1832        this.inner = jQuery('<div class="jBox-countdown-inner" />');
1833        outer.prepend(this.inner);
1834        jQuery('#' + this.id).append(outer);
1835      }
1836      this.countdown = function(){
1837        var dateNow = Date.now();
1838        if (!self.isHovered) {
1839          remaining -= dateNow - prevFrame;
1840        }
1841        prevFrame = dateNow;
1842        if (remaining > 0) {
1843          if (self.options.showCountdown) {
1844            self.inner.css('width', (remaining * 100 / self.options.delayClose) + '%');
1845          }
1846          window.requestAnimationFrame(self.countdown);
1847        } else {
1848          close();
1849        }
1850      };
1851      window.requestAnimationFrame(this.countdown);
1852    } else {
1853      this.timer = setTimeout(close, Math.max(this.options.delayClose, 10));
1854    }
1855
1856    return this;
1857  };
1858
1859
1860  // Open or close jBox
1861
1862  jBox.prototype.toggle = function (options)
1863  {
1864    this[this.isOpen ? 'close' : 'open'](options);
1865    return this;
1866  };
1867
1868
1869  // Block opening and closing
1870
1871  jBox.prototype.disable = function ()
1872  {
1873    this.isDisabled = true;
1874    return this;
1875  };
1876
1877
1878  // Unblock opening and closing
1879
1880  jBox.prototype.enable = function ()
1881  {
1882    this.isDisabled = false;
1883    return this;
1884  };
1885
1886
1887  // Hide jBox
1888
1889  jBox.prototype.hide = function ()
1890  {
1891    this.disable();
1892    if (this.wrapper) {
1893      this.cacheWrapperDisplay = this.wrapper.css('display');
1894      this.wrapper.css({display: 'none'});
1895    }
1896    if (this.overlay) {
1897      this.cacheOverlayDisplay = this.overlay.css('display');
1898      this.overlay.css({display: 'none'});
1899    }
1900    return this;
1901  };
1902
1903
1904  // Show jBox
1905
1906  jBox.prototype.show = function ()
1907  {
1908    this.enable();
1909    if (this.wrapper && this.cacheWrapperDisplay) {
1910      this.wrapper.css({display: this.cacheWrapperDisplay});
1911      this.cacheWrapperDisplay = null;
1912    }
1913    if (this.overlay && this.cacheOverlayDisplay) {
1914      this.overlay.css({display: this.cacheOverlayDisplay});
1915      this.cacheOverlayDisplay = null;
1916    }
1917    return this;
1918  };
1919
1920
1921  // Get content from ajax
1922
1923  jBox.prototype.ajax = function (options, opening)
1924  {
1925    options || (options = {});
1926
1927    // Add data or url from source element if none set in options
1928    jQuery.each([['getData', 'data'], ['getURL', 'url']], function (index, item) {
1929      (this.options.ajax[item[0]] && !options[item[1]] && this.source && this.source.attr(this.options.ajax[item[0]]) != undefined) && (options[item[1]] = this.source.attr(this.options.ajax[item[0]]) || '');
1930    }.bind(this));
1931
1932    // Clone the system options
1933    var sysOptions = jQuery.extend(true, {}, this.options.ajax);
1934
1935    // Abort running ajax call
1936    this.cancelAjax();
1937
1938    // Extract events
1939    var beforeSend = options.beforeSend || sysOptions.beforeSend || function () {};
1940    var complete = options.complete || sysOptions.complete || function () {};
1941    var success = options.success || sysOptions.success || function () {};
1942    var error = options.error || sysOptions.error || function () {};
1943
1944    // Merge options
1945    var userOptions = jQuery.extend(true, sysOptions, options);
1946
1947    // Set new beforeSend event
1948    userOptions.beforeSend = function (xhr)
1949    {
1950      // jBox is loading
1951      userOptions.loadingClass && this.wrapper.addClass(userOptions.loadingClass === true ? 'jBox-loading' : userOptions.loadingClass);
1952
1953      // Add loading spinner
1954      userOptions.spinner && (this.spinnerDelay = setTimeout(function ()
1955      {
1956        // Add class for loading spinner
1957        this.wrapper.addClass('jBox-loading-spinner');
1958
1959        // Reposition jBox
1960        // TODO: Only reposition if dimensions change
1961        userOptions.spinnerReposition && (opening ? (this.positionOnFadeComplete = true) : this.position());
1962
1963        // Add spinner to container
1964        this.spinner = jQuery(userOptions.spinner !== true ? userOptions.spinner : '<div class="jBox-spinner"></div>').appendTo(this.container);
1965
1966        // Fix spinners position if there is a title
1967        this.titleContainer && this.spinner.css('position') == 'absolute' && this.spinner.css({transform: 'translateY(' + (this.titleContainer.outerHeight() * 0.5) + 'px)'});
1968
1969      }.bind(this), (this.content.html() == '' ? 0 : (userOptions.spinnerDelay || 0))));
1970
1971      // Fire users beforeSend event
1972      (beforeSend.bind(this))(xhr);
1973
1974    }.bind(this);
1975
1976    // Set up new complete event
1977    userOptions.complete = function (response)
1978    {
1979      // Abort spinner timeout
1980      this.spinnerDelay && clearTimeout(this.spinnerDelay);
1981
1982      // jBox finished loading
1983      this.wrapper.removeClass('jBox-loading jBox-loading-spinner jBox-loading-spinner-delay');
1984
1985      // Remove spinner
1986      this.spinner && this.spinner.length && this.spinner.remove() && userOptions.spinnerReposition && (opening ? (this.positionOnFadeComplete = true) : this.position());
1987
1988      // Store that ajax loading finished
1989      this.ajaxLoaded = true;
1990
1991      // Fire users complete event
1992      (complete.bind(this))(response);
1993
1994    }.bind(this);
1995
1996    // Set up new success event
1997    userOptions.success = function (response)
1998    {
1999      // Set content
2000      userOptions.setContent && this.setContent(response, true) && (opening ? (this.positionOnFadeComplete = true) : this.position());
2001
2002      // Store content in source element
2003      userOptions.setContent && this.source && this.source.data('jBox-ajax-data', response);
2004
2005      // Fire users success event
2006      (success.bind(this))(response);
2007
2008    }.bind(this);
2009
2010    // Add error event
2011    userOptions.error = function (response) { (error.bind(this))(response); }.bind(this);
2012
2013    // Send new ajax request
2014    this.ajaxRequest = jQuery.ajax(userOptions);
2015
2016    return this;
2017  };
2018
2019
2020  // Abort an ajax call
2021
2022  jBox.prototype.cancelAjax = function () {
2023    if (this.ajaxRequest) {
2024      this.ajaxRequest.abort();
2025      this.ajaxLoaded = false;
2026    }
2027  };
2028
2029
2030  // Play an audio file
2031
2032  jBox.prototype.audio = function (url, volume)
2033  {
2034    // URL is required
2035    if (!url) return this;
2036
2037    // Create intern audio object if it wasn't created already
2038    !jBox._audio && (jBox._audio = {});
2039
2040    // Create an audio element specific to this audio file if it doesn't exist already
2041    if (!jBox._audio[url]) {
2042      var audio = jQuery('<audio/>');
2043      jQuery('<source/>', {src: url + '.mp3'}).appendTo(audio);
2044      jQuery('<source/>', {src: url + '.ogg'}).appendTo(audio);
2045      jBox._audio[url] = audio[0];
2046    }
2047
2048    // Set volume
2049    jBox._audio[url].volume = Math.min(((volume != undefined ? volume : 100) / 100), 1);
2050
2051    // Try to pause current audio
2052    try {
2053      jBox._audio[url].pause();
2054      jBox._audio[url].currentTime = 0;
2055    } catch (e) {}
2056
2057    // Play audio
2058    jBox._audio[url].play();
2059
2060    return this;
2061  };
2062
vendor: 28,215 bytes, lines 2063-2907
2063
2064  // Apply custom animations to jBox
2065
2066  jBox._animationSpeeds = {
2067    'tada': 1000,
2068    'tadaSmall': 1000,
2069    'flash': 500,
2070    'shake': 400,
2071    'pulseUp': 250,
2072    'pulseDown': 250,
2073    'popIn': 250,
2074    'popOut': 250,
2075    'fadeIn': 200,
2076    'fadeOut': 200,
2077    'slideUp': 400,
2078    'slideRight': 400,
2079    'slideLeft': 400,
2080    'slideDown': 400
2081  };
2082
2083  jBox.prototype.animate = function (animation, options)
2084  {
2085    // Options are required
2086    !options && (options = {});
2087
2088    // Timout needs to be an object
2089    !this.animationTimeout && (this.animationTimeout = {});
2090
2091    // Use jBox wrapper by default
2092    !options.element && (options.element = this.wrapper);
2093
2094    // Give the element an unique id
2095    !options.element.data('jBox-animating-id') && options.element.data('jBox-animating-id', jBox._getUniqueElementID());
2096
2097    // Abort if element is animating
2098    if (options.element.data('jBox-animating')) {
2099      options.element.removeClass(options.element.data('jBox-animating')).data('jBox-animating', null);
2100      this.animationTimeout[options.element.data('jBox-animating-id')] && clearTimeout(this.animationTimeout[options.element.data('jBox-animating-id')]);
2101    }
2102
2103    // Animate the element
2104    options.element.addClass('jBox-animated-' + animation).data('jBox-animating', 'jBox-animated-' + animation);
2105    this.animationTimeout[options.element.data('jBox-animating-id')] = setTimeout((function() { options.element.removeClass(options.element.data('jBox-animating')).data('jBox-animating', null); options.complete && options.complete(); }), jBox._animationSpeeds[animation]);
2106  };
2107
2108  // https://gist.github.com/AlexEmashev/ee8302b5036b01362f63dab35948401f
2109  jBox.prototype.swipeDetector = function (swipeTarget, options) {
2110    // States: 0 - no swipe, 1 - swipe started, 2 - swipe released
2111    var swipeState = 0;
2112    // Coordinates when swipe started
2113    var startX = 0;
2114    var startY = 0;
2115    // Distance of swipe
2116    var pixelOffsetX = 0;
2117    var pixelOffsetY = 0;
2118
2119    var defaultSettings = {
2120      // Amount of pixels, when swipe don't count.
2121      swipeThreshold: 70,
2122      // Flag that indicates that plugin should react only on touch events.
2123      // Not on mouse events too.
2124      useOnlyTouch: false
2125    };
2126
2127    // Initializer
2128    (function init() {
2129      options = jQuery.extend(defaultSettings, options);
2130      // Support touch and mouse as well.
2131      swipeTarget.on("mousedown touchstart", swipeStart);
2132      $("html").on("mouseup touchend", swipeEnd);
2133      $("html").on("mousemove touchmove", swiping);
2134    })();
2135
2136    function swipeStart(event) {
2137      if (options.useOnlyTouch && !event.originalEvent.touches) {
2138        return;
2139      }
2140
2141      if (event.originalEvent.touches) {
2142        event = event.originalEvent.touches[0];
2143      }
2144
2145      if (swipeState === 0) {
2146        swipeState = 1;
2147        startX = event.clientX;
2148        startY = event.clientY;
2149      }
2150    }
2151
2152    function swipeEnd(event) {
2153      if (swipeState === 2) {
2154        swipeState = 0;
2155
2156        if (
2157          Math.abs(pixelOffsetX) > Math.abs(pixelOffsetY) &&
2158          Math.abs(pixelOffsetX) > options.swipeThreshold
2159        ) {
2160          // Horizontal Swipe
2161          if (pixelOffsetX < 0) {
2162            swipeTarget.trigger($.Event("swipeLeft.sd"));
2163          } else {
2164            swipeTarget.trigger($.Event("swipeRight.sd"));
2165          }
2166        } else if (Math.abs(pixelOffsetY) > options.swipeThreshold) {
2167          // Vertical swipe
2168          if (pixelOffsetY < 0) {
2169            swipeTarget.trigger($.Event("swipeUp.sd"));
2170          } else {
2171            swipeTarget.trigger($.Event("swipeDown.sd"));
2172          }
2173        }
2174      }
2175    }
2176
2177    function swiping(event) {
2178      // If swipe don't occuring, do nothing.
2179      if (swipeState !== 1) return;
2180
2181      if (event.originalEvent.touches) {
2182        event = event.originalEvent.touches[0];
2183      }
2184
2185      var swipeOffsetX = event.clientX - startX;
2186      var swipeOffsetY = event.clientY - startY;
2187
2188      if (
2189        Math.abs(swipeOffsetX) > options.swipeThreshold ||
2190        Math.abs(swipeOffsetY) > options.swipeThreshold
2191      ) {
2192        swipeState = 2;
2193        pixelOffsetX = swipeOffsetX;
2194        pixelOffsetY = swipeOffsetY;
2195      }
2196    }
2197
2198    return swipeTarget; // Return element available for chaining.
2199  }
2200
2201
2202  // Destroy jBox and remove it from DOM
2203
2204  jBox.prototype.destroy = function ()
2205  {
2206    // Detach from attached elements
2207    this.detach();
2208
2209    // If jBox is open, close without delay
2210    this.isOpen && this.close({ignoreDelay: true});
2211
2212    // Remove wrapper
2213    this.wrapper && this.wrapper.remove();
2214
2215    // Remove overlay
2216    this.overlay && this.overlay.remove();
2217
2218    // Remove styles
2219    this._styles && this._styles.remove();
2220
2221    // Tell the jBox instance it is destroyed
2222    this.isDestroyed = true;
2223
2224    return this;
2225  };
2226
2227
2228  // Get a unique ID for jBoxes
2229
2230  jBox._getUniqueID = (function ()
2231  {
2232    var i = 1;
2233    return function () { return i++; };
2234  }());
2235
2236
2237  // Get a unique ID for animating elements
2238
2239  jBox._getUniqueElementID = (function ()
2240  {
2241    var i = 1;
2242    return function () { return i++; };
2243  }());
2244
2245
2246  // Function to create jBox plugins
2247
2248  jBox._pluginOptions = {};
2249  jBox.plugin = function (type, options)
2250  {
2251    jBox._pluginOptions[type] = options;
2252  };
2253
2254
2255  // Make jBox usable with jQuery selectors
2256
2257  jQuery.fn.jBox = function (type, options) {
2258    // Variables type and object are required
2259    !type && (type = {});
2260    !options && (options = {});
2261
2262    // Return a new instance of jBox with the selector as attached element
2263    return new jBox(type, jQuery.extend(options, {
2264      attach: this
2265    }));
2266  };
2267
2268  return jBox;
2269
2270};
2271
2272/**
2273 * jBox Confirm plugin: Add a confirm dialog to links, buttons, etc.
2274 *
2275 * Author: Stephan Wagner <[email protected]> (https://stephanwagner.me)
2276 *
2277 * License: MIT (https://opensource.org/licenses/MIT)
2278 *
2279 * Requires: jBox (https://cdn.jsdelivr.net/gh/StephanWagner/jBox@latest/dist/jBox.min.js)
2280 */
2281
2282function jBoxConfirmWrapper(jBox, jQuery) {
2283
2284  new jBox.plugin('Confirm', {
2285
2286
2287    // Options (https://stephanwagner.me/jBox/options#options-confirm)
2288
2289    confirmButton: 'Submit',  // Text for the submit button
2290    cancelButton: 'Cancel',   // Text for the cancel button
2291    confirm: null,            // Function to execute when clicking the submit button. By default jBox will use the onclick or href attribute in that order if found
2292    cancel: null,             // Function to execute when clicking the cancel button
2293    closeOnConfirm: true,     // Close jBox when the user clicks the confirm button
2294    target: window,
2295    fixed: true,
2296    attach: '[data-confirm]',
2297    getContent: 'data-confirm',
2298    content: 'Do you really want to do this?',
2299    minWidth: 360,
2300    maxWidth: 500,
2301    blockScroll: true,
2302    closeOnEsc: true,
2303    closeOnClick: false,
2304    closeButton: false,
2305    overlay: true,
2306    animation: 'zoomIn',
2307    preventDefault: true,
2308
2309
2310    // Triggered when jBox is attached to the element
2311
2312    _onAttach: function (el)
2313    {
2314      // Extract the href or the onclick event if no submit event is passed
2315      if (!this.options.confirm) {
2316        var submit = el.attr('onclick') ? el.attr('onclick') : (
2317          el.attr('href') ? (
2318            el.attr('target') ? 'window.open("' + el.attr('href') + '", "' + el.attr('target') + '");'  : 'window.location.href = "' + el.attr('href') + '";'
2319          ) : '');
2320        el.prop('onclick', null).data('jBox-Confirm-submit', submit);
2321      }
2322    },
2323
2324
2325    // Triggered when jBox was created
2326
2327    _onCreated: function ()
2328    {
2329      // Add modal class to mimic jBox modal
2330      this.wrapper.addClass('jBox-Modal');
2331
2332      // Add a footer to the jBox container
2333      this.footer = jQuery('<div class="jBox-Confirm-footer"/>');
2334
2335      jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-cancel"/>')
2336        .html(this.options.cancelButton)
2337        .click(function () {
2338          this.options.cancel && this.options.cancel(this.source);
2339          this.close();
2340        }.bind(this))
2341        .appendTo(this.footer);
2342
2343      this.submitButton = jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-submit"/>')
2344        .html(this.options.confirmButton)
2345        .appendTo(this.footer);
2346
2347      this.footer.appendTo(this.container);
2348    },
2349
2350
2351    // Triggered when jBox is opened
2352
2353    _onOpen: function ()
2354    {
2355      // Set the new action for the submit button
2356      this.submitButton
2357        .off('click.jBox-Confirm' + this.id)
2358        .on('click.jBox-Confirm' + this.id, function () {
2359          this.options.confirm ? this.options.confirm(this.source) : eval(this.source.data('jBox-Confirm-submit'));
2360          this.options.closeOnConfirm && this.close();
2361        }.bind(this));
2362    }
2363
2364  });
2365
2366};
2367
2368/**
2369 * jBox Image plugin: Adds a lightbox to your images
2370 *
2371 * Author: Stephan Wagner <[email protected]> (https://stephanwagner.me)
2372 *
2373 * License: MIT (https://opensource.org/licenses/MIT)
2374 *
2375 * Requires: jBox (https://cdn.jsdelivr.net/gh/StephanWagner/jBox@latest/dist/jBox.min.js)
2376 */
2377
2378function jBoxImageWrapper(jBox, jQuery) {
2379
2380  new jBox.plugin('Image', {
2381
2382
2383    // Options (https://stephanwagner.me/jBox/options#options-image)
2384
2385    src: 'href',                 // The attribute where jBox gets the image source from, e.g. href="/path_to_image/image.jpg"
2386    gallery: 'data-jbox-image',  // The attribute to set the galleries, e.g. data-jbox-image="gallery1"
2387    imageLabel: 'title',         // The attribute where jBox gets the image label from, e.g. title="My label"
2388    imageFade: 360,              // The fade duration for images in ms
2389    imageSize: 'contain',        // How to display the images. Use CSS background-position values, e.g. 'cover', 'contain', 'auto', 'initial', '50% 50%'
2390    imageCounter: false,         // Set to true to add an image counter, e.g. 4/20
2391    imageCounterSeparator: '/',  // HTML to separate the current image number from all image numbers, e.g. '/' or ' of '
2392    downloadButton: false,       // Adds a download button
2393    downloadButtonText: null,    // Text for the download button
2394    downloadButtonUrl: null,     // The attribute at the source element where to find the image to download, e.g. data-download="/path_to_image/image.jpg". If none provided, the currently active image will be downloaded
2395    mobileImageAttr: null,       // The attribute to look for an mobile version of the image
2396    mobileImageBreakpoint: null, // The upper breakpoint to load the mobile image
2397    preloadFirstImage: false,    // Preload the first image when page is loaded
2398    target: window,
2399    attach: '[data-jbox-image]',
2400    fixed: true,
2401    blockScroll: true,
2402    closeOnEsc: true,
2403    closeOnClick: 'button',
2404    closeButton: true,
2405    overlay: true,
2406    animation: 'zoomIn',
2407    preventDefault: true,
2408    width: '100%',
2409    height: '100%',
2410    adjustDistance: {
2411      top: 40,
2412      right: 0,
2413      bottom: 40,
2414      left: 0
2415    },
2416
2417
2418    // Triggered when jBox is initialized
2419
2420    _onInit: function ()
2421    {
2422      // Initial images and z-index
2423      this.images = this.currentImage = {};
2424      this.imageZIndex = 1;
2425
2426      this.initImage = function (item) {
2427        item = jQuery(item);
2428
2429        // Abort if the item was added to a gallery already
2430        if (item.data('jBox-image-gallery')) {
2431          return;
2432        }
2433
2434        // Get the image src
2435        var src = item.attr(this.options.src);
2436
2437        // Update responsive image src
2438        if (this.options.mobileImageAttr && this.options.mobileImageBreakpoint && item.attr(this.options.mobileImageAttr)) {
2439          if (jQuery(window).width() <= this.options.mobileImageBreakpoint) {
2440            src = item.attr(this.options.mobileImageAttr);
2441          }
2442        }
2443
2444        // Add item to a gallery
2445        var gallery = item.attr(this.options.gallery) || 'default';
2446        !this.images[gallery] && (this.images[gallery] = []);
2447        this.images[gallery].push({
2448          src: src,
2449          label: (item.attr(this.options.imageLabel) || ''),
2450          downloadUrl: this.options.downloadButtonUrl && item.attr(this.options.downloadButtonUrl) ? item.attr(this.options.downloadButtonUrl) : null
2451        });
2452
2453        // Remove the title attribute so it won't show the browsers tooltip
2454        this.options.imageLabel == 'title' && item.removeAttr('title');
2455
2456        // Store data in source element for easy access
2457        item.data('jBox-image-gallery', gallery);
2458        item.data('jBox-image-id', (this.images[gallery].length - 1));
2459      }.bind(this);
2460
2461      // Loop through images, sort and save in global variable
2462      this.attachedElements && this.attachedElements.length && jQuery.each(this.attachedElements, function (index, item) {
2463        this.initImage(item);
2464      }.bind(this));
2465
2466      // Helper to inject the image into content area
2467      var appendImage = function (gallery, id, show, instant) {
2468        // Abort if image was appended already
2469        if (jQuery('#jBox-image-' + gallery + '-' + id).length) {
2470          return;
2471        }
2472
2473        // Create image container
2474        var image = jQuery('<div/>', {
2475          id: 'jBox-image-' + gallery + '-' + id,
2476          'class': 'jBox-image-container' + (show ? ' jBox-image-' + gallery + '-current' : '')
2477        }).css({
2478          backgroundSize: this.options.imageSize,
2479          opacity: (instant ? 1 : 0),
2480          zIndex: (show ? this.imageZIndex++ : 0)
2481        }).appendTo(this.content);
2482
2483        // Add swipe events
2484        this.swipeDetector(image)
2485          .on("swipeLeft.sd swipeRight.sd", function (event) {
2486            if (event.type === "swipeLeft") {
2487              this.showImage('next');
2488            } else if (event.type === "swipeRight") {
2489              this.showImage('prev');
2490            }
2491          }.bind(this));
2492
2493        // Create labels
2494        jQuery('<div/>', {
2495          id: 'jBox-image-label-' + gallery + '-' + id,
2496          'class': 'jBox-image-label' + (show ? ' active' : '')
2497        }).html(this.images[gallery][id].label).click(function () { jQuery(this).toggleClass('expanded'); }).appendTo(this.imageLabelContainer);
2498
2499        // Show image
2500        show && image.animate({opacity: 1}, instant ? 0 : this.options.imageFade);
2501
2502        return image;
2503      }.bind(this);
2504
2505      // Function to download an image
2506      this.downloadImage = function (imageUrl) {
2507        var link = document.createElement('a');
2508        link.href = imageUrl;
2509        link.setAttribute('download', imageUrl.substring(imageUrl.lastIndexOf('/')+1));
2510        document.body.appendChild(link);
2511        link.click();
2512      };
2513
2514      // Helper to show new image label
2515      var showLabel = function (gallery, id) {
2516        jQuery('.jBox-image-label.active').removeClass('active expanded');
2517        jQuery('#jBox-image-label-' + gallery + '-' + id).addClass('active');
2518      };
2519
2520      // Helper to load image
2521      var loadImage = function (gallery, id, show, instant) {
2522        var imageContainer = appendImage(gallery, id, show, instant);
2523        imageContainer.addClass('jBox-image-loading');
2524
2525        jQuery('<img src="' + this.images[gallery][id].src + '" />').each(function () {
2526          var tmpImg = new Image();
2527          tmpImg.onload = function () {
2528            imageContainer.removeClass('jBox-image-loading');
2529            imageContainer.css({backgroundImage: 'url("' + this.images[gallery][id].src + '")'});
2530          }.bind(this);
2531
2532          tmpImg.onerror = function () {
2533            imageContainer.removeClass('jBox-image-loading');
2534            imageContainer.addClass('jBox-image-not-found');
2535          }.bind(this);
2536
2537          tmpImg.src = this.images[gallery][id].src;
2538        }.bind(this));
2539      }.bind(this);
2540
2541      // Show images when they are loaded or load them if not
2542      this.showImage = function (img) {
2543        // Get the gallery and the image id from the next or the previous image
2544        if (img != 'open') {
2545          var gallery = this.currentImage.gallery;
2546          var id = this.currentImage.id + (1 * (img == 'prev') ? -1 : 1);
2547          id = id > (this.images[gallery].length - 1) ? 0 : (id < 0 ? (this.images[gallery].length - 1) : id);
2548
2549        // Or get image data from source element
2550        } else {
2551          // Get gallery and image id from source element
2552          if (this.source) {
2553            var gallery = this.source.data('jBox-image-gallery');
2554            var id = this.source.data('jBox-image-id');
2555
2556          // Get gallery and image id attached elements
2557          } else if (this.attachedElements && this.attachedElements.length) {
2558            var gallery = jQuery(this.attachedElements[0]).data('jBox-image-gallery');
2559            var id = jQuery(this.attachedElements[0]).data('jBox-image-id');
2560          } else {
2561            return;
2562          }
2563
2564          // Remove or show the next and prev buttons
2565          jQuery('.jBox-image-pointer-prev, .jBox-image-pointer-next').css({display: (this.images[gallery].length > 1 ? 'block' : 'none')});
2566        }
2567
2568        // If there is a current image already shown, hide it
2569        if (jQuery('.jBox-image-' + gallery + '-current').length) {
2570          jQuery('.jBox-image-' + gallery + '-current').removeClass('jBox-image-' + gallery + '-current').animate({opacity: 0}, (img == 'open') ? 0 : this.options.imageFade);
2571        }
2572
2573        // Set new current image
2574        this.currentImage = {gallery: gallery, id: id};
2575
2576        // Show image if it already exists
2577        if (jQuery('#jBox-image-' + gallery + '-' + id).length) {
2578          jQuery('#jBox-image-' + gallery + '-' + id).addClass('jBox-image-' + gallery + '-current').css({zIndex: this.imageZIndex++, opacity: 0}).animate({opacity: 1}, (img == 'open') ? 0 : this.options.imageFade);
2579
2580        // Load image
2581        } else {
2582          loadImage(gallery, id, true, (img === 'open'));
2583        }
2584
2585        // Show label
2586        showLabel(gallery, id);
2587
2588        // Update the image counter numbers
2589        if (this.imageCounter) {
2590          if (this.images[gallery].length > 1) {
2591            this.wrapper.addClass('jBox-image-has-counter');
2592            this.imageCounter.find('.jBox-image-counter-all').html(this.images[gallery].length);
2593            this.imageCounter.find('.jBox-image-counter-current').html(id + 1);
2594          } else {
2595            this.wrapper.removeClass('jBox-image-has-counter');
2596          }
2597        }
2598
2599        // Preload next image
2600        if (this.images[gallery].length - 1) {
2601	        var next_id = id + 1;
2602	        next_id = next_id > (this.images[gallery].length - 1) ? 0 : (next_id < 0 ? (this.images[gallery].length - 1) : next_id);
2603
2604	        if (!jQuery('#jBox-image-' + gallery + '-' + next_id).length) {
2605            loadImage(gallery, next_id, false, false);
2606          }
2607	      }
2608      };
2609
2610      // Preload image
2611      if (this.options.preloadFirstImage) {
2612        jQuery(window).on('load', function() {
2613          this.showImage('open');
2614        }.bind(this));
2615      }
2616    },
2617
2618
2619    // Triggered when jBox attaches a new element
2620
2621    _onAttach: function (item) {
2622      this.initImage && this.initImage(item);
2623    },
2624
2625
2626    // Triggered when jBox was created
2627
2628    _onCreated: function ()
2629    {
2630      // Create image label and navigation buttons
2631      this.imageLabelWrapper = jQuery('<div class="jBox-image-label-wrapper"/>').appendTo(this.wrapper);
2632
2633      this.imagePrevButton = jQuery('<div class="jBox-image-pointer-prev"/>')
2634        .on('click', function () {
2635          this.showImage('prev');
2636        }.bind(this));
2637
2638      this.imageNextButton = jQuery('<div class="jBox-image-pointer-next"/>')
2639        .on('click', function () {
2640          this.showImage('next');
2641        }.bind(this));
2642
2643      this.imageLabelContainer = jQuery('<div class="jBox-image-label-container"/>');
2644
2645      this.imageLabelWrapper
2646        .append(this.imagePrevButton)
2647        .append(this.imageLabelContainer)
2648        .append(this.imageNextButton);
2649
2650      // Append the download button
2651      if (this.options.downloadButton) {
2652        this.downloadButton = jQuery('<div/>', {'class': 'jBox-image-download-button-wrapper'})
2653          .appendTo(this.wrapper)
2654          .append(
2655            this.options.downloadButtonText ? jQuery('<div/>', {'class': 'jBox-image-download-button-text'}).html(this.options.downloadButtonText) : null
2656          )
2657          .append(
2658            jQuery('<div/>', {'class': 'jBox-image-download-button-icon'})
2659          ).on('click touchdown', function () {
2660            if (this.images[this.currentImage.gallery][this.currentImage.id].downloadUrl) {
2661              var currentImageUrl = this.images[this.currentImage.gallery][this.currentImage.id].downloadUrl;
2662            } else {
2663              var currentImage = this.wrapper.find('.jBox-image-' + this.currentImage.gallery + '-current');
2664              var currentImageStyle = currentImage[0].style.backgroundImage;
2665              var currentImageUrl = currentImageStyle.slice(4, -1).replace(/["']/g, '');
2666            }
2667            this.downloadImage(currentImageUrl);
2668          }.bind(this));
2669      }
2670
2671      // Creating the image counter containers
2672      if (this.options.imageCounter) {
2673        this.imageCounter = jQuery('<div/>', {'class': 'jBox-image-counter-container'}).insertAfter(this.imageLabelContainer);
2674        this.imageCounter.append(jQuery('<span/>', {'class': 'jBox-image-counter-current'})).append(jQuery('<span/>').html(this.options.imageCounterSeparator)).append(jQuery('<span/>', {'class': 'jBox-image-counter-all'}));
2675      }
2676    },
2677
2678
2679    // Triggered when jBox opens
2680
2681    _onOpen: function ()
2682    {
2683      // Add key events
2684      jQuery(document).on('keyup.jBox-Image-' + this.id, function (ev) {
2685        (ev.keyCode == 37) && this.showImage('prev');
2686        (ev.keyCode == 39) && this.showImage('next');
2687      }.bind(this));
2688
2689      // Load the image from the attached element
2690      this.showImage('open');
2691    },
2692
2693
2694    // Triggered when jBox closes
2695
2696    _onClose: function ()
2697    {
2698      // Remove key events
2699      jQuery(document).off('keyup.jBox-Image-' + this.id);
2700    },
2701
2702
2703    // Triggered when jBox finished closing
2704
2705    _onCloseComplete: function ()
2706    {
2707      // Hide all image containers
2708      this.wrapper.find('.jBox-image-container').css('opacity', 0);
2709    }
2710
2711  });
2712
2713};
2714
2715/**
2716 * jBox Notice plugin: Opens a popup notice
2717 *
2718 * Author: Stephan Wagner <[email protected]> (https://stephanwagner.me)
2719 *
2720 * License: MIT (https://opensource.org/licenses/MIT)
2721 *
2722 * Requires: jBox (https://cdn.jsdelivr.net/gh/StephanWagner/jBox@latest/dist/jBox.min.js)
2723 */
2724
2725function jBoxNoticeWrapper(jBox, jQuery) {
2726
2727  new jBox.plugin('Notice', {
2728
2729
2730    // Options (https://stephanwagner.me/jBox/options#options-notice)
2731
2732    color: null,      // Add a color to your notices, use 'gray' (default), 'black', 'red', 'green', 'blue' or 'yellow'
2733    stack: true,      // Set to false to disable notice-stacking
2734    stackSpacing: 10, // Spacing between notices when they stack
2735    autoClose: 6000,  // Time in ms after which the notice will disappear
2736    attributes: {     // Defines where the notice will pop up
2737      x: 'right',     // 'left' or 'right'
2738      y: 'top'        // 'top' or 'bottom'
2739    },
2740    position: {       // Defines the distance to the viewport boundary
2741      x: 15,
2742      y: 15
2743    },
2744    responsivePositions: {  // Responsive positions
2745      500: {                // The key defines the maximum width of the viewport, the values will replace the default position options
2746        x: 5,               // Start with the lowest viewport
2747        y: 5
2748      },
2749      768: {
2750        x: 10,
2751        y: 10
2752      }
2753    },
2754    target: window,
2755    fixed: true,
2756    animation: 'zoomIn',
2757    closeOnClick: 'box',
2758    zIndex: 12000,
2759
2760
2761    // Triggered when notice is initialized
2762
2763    _onInit: function ()
2764    {
2765      // Cache position values
2766      this.defaultNoticePosition = jQuery.extend({}, this.options.position);
2767
2768      // Type Notice has its own adjust position function
2769      this._adjustNoticePositon = function () {
2770        var win = jQuery(window);
2771        var windowDimensions = {
2772          x: win.width(),
2773          y: win.height()
2774        };
2775
2776        // Reset default position
2777        this.options.position = jQuery.extend({}, this.defaultNoticePosition);
2778
2779        // Adjust depending on viewport
2780        jQuery.each(this.options.responsivePositions, function (viewport, position) {
2781          if (windowDimensions.x <= viewport) {
2782            this.options.position = position;
2783            return false;
2784          }
2785        }.bind(this));
2786
2787        // Set new padding options
2788        this.options.adjustDistance = {
2789          top: this.options.position.y,
2790          right: this.options.position.x,
2791          bottom: this.options.position.y,
2792          left: this.options.position.x
2793        };
2794      };
2795
2796      // If jBox grabs an element as content, crab a clone instead
2797      this.options.content instanceof jQuery && (this.options.content = this.options.content.clone().attr('id', ''));
2798
2799      // Adjust paddings when window resizes
2800      jQuery(window).on('resize.responsivejBoxNotice-' + this.id, function (ev) { if (this.isOpen) { this._adjustNoticePositon(); } }.bind(this));
2801
2802      this.open();
2803    },
2804
2805
2806    // Triggered when notice was created
2807
2808    _onCreated: function ()
2809    {
2810      // Add color class
2811      this.wrapper.addClass('jBox-Notice-color jBox-Notice-' + (this.options.color || 'gray'));
2812
2813      // Store position in jBox wrapper
2814      this.wrapper.data('jBox-Notice-position', this.options.attributes.x + '-' + this.options.attributes.y);
2815    },
2816
2817
2818    // Triggered when notice opens
2819
2820    _onOpen: function ()
2821    {
2822      // Bail if we're stacking
2823      if (this.options.stack) {
2824          return;
2825      }
2826
2827      // Adjust position when opening
2828      this._adjustNoticePositon();
2829
2830      // Loop through notices at same window corner destroy them
2831      jQuery.each(jQuery('.jBox-Notice'), function (index, el)
2832      {
2833        el = jQuery(el);
2834
2835        // Abort if the element is this notice or when it's not at the same position
2836        if (el.attr('id') == this.id || el.data('jBox-Notice-position') != this.options.attributes.x + '-' + this.options.attributes.y) {
2837          return;
2838        }
2839
2840        // Remove notice when we don't wont to stack them
2841        if (!this.options.stack) {
2842          el.data('jBox').close({ignoreDelay: true});
2843          return;
2844        }
2845      }.bind(this));
2846    },
2847
2848    // Triggered when resizing window etc.
2849
2850    _onPosition: function ()
2851    {
2852        var stacks = {};
2853        jQuery.each(jQuery('.jBox-Notice'), function (index, el)
2854        {
2855          el = jQuery(el);
2856          var pos = el.data('jBox-Notice-position');
2857          if (!stacks[pos]) {
2858              stacks[pos] = [];
2859          }
2860          stacks[pos].push(el);
2861        });
2862        for (var pos in stacks) {
2863            var position = pos.split('-');
2864            var direction = position[1];
2865            stacks[pos].reverse();
2866            var margin = 0;
2867            for (var i in stacks[pos]) {
2868                el = stacks[pos][i];
2869                el.css('margin-' + direction, margin);
2870                margin += el.outerHeight() + this.options.stackSpacing;
2871            }
2872        }
2873    },
2874
2875    // Remove notice from DOM and reposition other notices when closing finishes
2876
2877    _onCloseComplete: function ()
2878    {
2879        this.destroy();
2880        this.options._onPosition.bind(this).call();
2881    }
2882
2883  });
2884
2885};
2886
2887(function (root, factory) {
2888  if (typeof define === 'function' && define.amd) {
2889    define(['jquery'], function (jQuery) {
2890      return (root.jBox = factory(jQuery));
2891    });
2892  } else if (typeof module === 'object' && module.exports) {
2893    module.exports = (root.jBox = factory(require('jquery')));
2894  } else {
2895    root.jBox = factory(root.jQuery);
2896  }
2897}(this, function (jQuery) {
2898  var jBox = jBoxWrapper(jQuery);
2899  try { typeof jBoxConfirmWrapper !== 'undefined' && jBoxConfirmWrapper && jBoxConfirmWrapper(jBox, jQuery); } catch(e) { console.error(e); }
2900  try { typeof jBoxImageWrapper !== 'undefined' && jBoxImageWrapper && jBoxImageWrapper(jBox, jQuery); } catch(e) { console.error(e); }
2901  try { typeof jBoxNoticeWrapper !== 'undefined' && jBoxNoticeWrapper && jBoxNoticeWrapper(jBox, jQuery); } catch(e) { console.error(e); }
2902  return jBox;
2903}));
2904
2905//# sourceMappingURL=jBox.all.js.map
2906
2907// Store app data in global var
2908var app = {};
2909
2910// Document is ready
2911$(document).ready(function () {
2912  // Mobile menu
2913  /*$('.main-menu > li').on('click', function () {
2914    var classElement = $(this);
2915    if (classElement.hasClass('sub-menu-active')) {
2916      classElement.removeClass('sub-menu-active');
2917      return;
2918    }
2919    classElement.addClass('sub-menu-active');
2920  });*/
2921
2922  //External links
2923  $('a[href^="http"]').addClass('external');
2924  $('a[href*="://vgem-offingen."]').removeClass('external');
2925  $('a[href*="://offingen."]').removeClass('external');
2926  $('a[href*="://gundremmingen."]').removeClass('external');
2927  $('a[href*="://gemeinde-rettenbach."]').removeClass('external');
2928  $('a[href*="://rettenbach."]').removeClass('external');
2929  $('a[href*="://www.vgem-offingen."]').removeClass('external');
2930  $('a[href*="://www.offingen."]').removeClass('external');
2931  $('a[href*="://www.gundremmingen."]').removeClass('external');
2932  $('a[href*="://www.gemeinde-rettenbach."]').removeClass('external');
2933  $('.external-links__wrapper a').removeClass('external');
2934
2935  //Remove external link icons if the links are inside a wrapper with class "ignore-external" or have the class "ignore-external" themselves
2936  $('.ignore-external a').removeClass('external');
2937  $('a.ignore-external').removeClass('external');
2938
2939  // Move nav items to mobile menu
2940  var searchWrapper = $('.search').clone().addClass('search--mobile');
2941  searchWrapper.prependTo('.menu-main-container');
2942
2943  // Image overlays
2944  new jBox('Image', {
2945    imageLabel: 'data-title'
2946  });
2947
2948  $.each(
2949    $('.blocks-gallery-item img:not([data-full-url])'),
2950    function (index, el) {
2951      $(el).attr('data-full-url', $(el).attr('src'));
2952    }
2953  );
2954
2955  new jBox('Image', {
2956    attach: '.blocks-gallery-item img[data-full-url]',
2957    src: 'data-full-url',
2958    gallery: 'blocks-gallery',
2959    imageLabel: 'data-title',
2960    onAttach: function (el) {
2961      var title = $(el).next('figcaption').html();
2962      $(el).attr('title', title);
2963      $(el).attr('data-title', title);
2964    }
2965  });
2966  
2967  new jBox('Image', {
2968    attach: '.wp-block-image img',
2969    src: 'src',
2970    gallery: 'blocks-gallery',
2971    imageLabel: 'alt',
2972    onAttach: function (el) {
2973      var title = $(el).next('figcaption').html();
2974      $(el).attr('title', title);
2975      $(el).attr('data-title', title);
2976    }
2977  });
2978
2979  // Scroll events
2980  function initScroll() {
2981    var scrollTop = $(window).scrollTop();
2982
2983    /*if (scrollTop > 40) {
2984      var scrollAction = 'addClass';
2985    } else {
2986      var scrollAction = 'removeClass';
2987    }*/
2988	
2989    if (scrollTop < 110) {
2990      var scrollAction = 'removeClass';
2991    } else {
2992    	var scrollAction = 'addClass';
2993    }
2994
2995    $('body')[scrollAction]('nav-fixed');
2996  }
2997
2998  $(window).bind('DOMMouseScroll.kpScroll mousewheel.kpScroll', function (ev) {
2999    initScroll();
3000  });
3001  initScroll();
3002
3003  $('.main-menu').on('mousewheel DOMMouseScroll', function (e) {
3004    var e0 = e.originalEvent,
3005      delta = e0.wheelDelta || -e0.detail;
3006
3007    this.scrollTop += (delta < 0 ? 1 : -1) * 30;
3008    e.preventDefault();
3009  });
3010
3011  // Hack: Add read more link
3012  $.each(
3013    $(
3014      '.tribe-events-calendar-list .tribe-events-calendar-list__event-row, .tribe-events-calendar-latest-past .tribe-events-calendar-latest-past__event-row'
3015    ),
3016    function (index, item) {
3017      var wrapper = $(item);
3018      var appendTo = wrapper.find(
3019        '.tribe-events-calendar-list__event-details, .tribe-events-calendar-latest-past__event-details'
3020      );
3021      if (!appendTo.length) {
3022        appendTo = wrapper.find(
3023          '.tribe-events-calendar-list__event-header, .tribe-events-calendar-latest-past__event-header'
3024        );
3025      }
3026      var link = wrapper
3027        .find(
3028          '.tribe-events-calendar-list__event-title-link, .tribe-events-calendar-latest-past__event-title-link'
3029        )
3030        .attr('href');
3031      $('<a href="' + link + '" class="read-more-link">')
3032        .html('Weiterlesen')
3033        .appendTo(appendTo);
3034    }
3035  );
3036
3037  // Hack: Add read more link
3038  $.each(
3039    $('.homepage-list__content-container .ecs-event'),
3040    function (index, item) {
3041      var wrapper = $(item);
3042      var link = wrapper.find('.entry-title a').attr('href');
3043      $('<a href="' + link + '" class="read-more-link">')
3044        .html('Weiterlesen')
3045        .appendTo(wrapper);
3046    }
3047  );
3048
3049  // Hack: Add "Uhr" to time
3050  var addTimeStr = [
3051    '.tribe-events-calendar-list__event-header .tribe-events-calendar-list__event-datetime .tribe-event-time',
3052    '.tribe-events-calendar-latest-past__event-header .tribe-events-calendar-latest-past__event-datetime .tribe-event-time',
3053    '.homepage-list__content-container .tribe-event-time',
3054    '.tribe-events-schedule .tribe-event-time',
3055    '.tribe-events-abbr.tribe-events-start-time.dtstart',
3056    '.tribe-events-abbr.tribe-events-start-time.dtend',
3057    '.tribe-events-abbr.tribe-events-start-datetime',
3058    '.tribe-events-abbr.tribe-events-end-datetime',
3059    'h2 > span.tribe-event-date-start',
3060    'h2 > span.tribe-event-date-end',
3061    '.tribe-events-calendar-list__event-datetime > span.tribe-event-date-start',
3062    '.tribe-events-calendar-list__event-datetime > span.tribe-event-date-end',
3063  ];
3064  $.each($(addTimeStr.join(', ')), function (index, item) {
3065    var wrapper = $(item);
3066    if (wrapper.text().indexOf(':') != -1) {
3067      wrapper.append('<span> Uhr</span>');
3068    }
3069  });
3070
3071  // Hack: Add date
3072  $.each(
3073    $(
3074      '.tribe-events-abbr.tribe-events-start-date.dtstart, .tribe-events-abbr.tribe-events-end-date.dtend'
3075    ),
3076    function (index, item) {
3077      var wrapper = $(item);
3078      var date = wrapper.attr('title');
3079      var dateSplit = date.split('-');
3080      if (dateSplit && wrapper.text().indexOf(dateSplit[0]) === -1) {
3081        wrapper.append('<span>
3081 ' + (dateSplit[0] || '') + '</span>');
3082      }
3083    }
3084  );
3085
3086  // Hack: Add email to calendar infos
3087  $.each(
3088    $(
3089      '.tribe-events-meta-group.tribe-events-meta-group-organizer .tribe-organizer-email'
3090    ),
3091    function (index, item) {
3092      var wrapper = $(item);
3093      var email = wrapper.html().trim();
3094      wrapper.html('<a href="mailto:' + email + '">' + email + '</a>');
3095    }
3096  );
3097
3098  // Hack: Open Links in new window
3099  $('.tribe-organizer-url a').attr('target', '_blank');
3100
3101  // Hack: Change zip code and city
3102  $.each($('#tribe-events-content .tribe-address'), function (index, item) {
3103    var wrapper = $(item);
3104    if (
3105      wrapper.find('.tribe-street-address:nth-child(1)').length &&
3106      wrapper.find('.tribe-locality:nth-child(3)').length &&
3107      wrapper.find('.tribe-delimiter:nth-child(4)').length &&
3108      wrapper.find('.tribe-postal-code:nth-child(5)').length
3109    ) {
3110      wrapper
3111        .find('.tribe-postal-code')
3112        .after(wrapper.find('.tribe-locality'))
3113        .after(wrapper.find('.tribe-delimiter').html('&nbsp;'));
3114    }
3115
3116    if (
3117      wrapper.find('.tribe-street-address:nth-child(1)').length &&
3118      wrapper.find('.tribe-locality:nth-child(3)').length &&
3119      wrapper.find('.tribe-delimiter:nth-child(4)').length &&
3120      wrapper.find('.tribe-region:nth-child(5)').length &&
3121      wrapper.find('.tribe-postal-code:nth-child(6)').length
3122    ) {
3123      wrapper
3124        .find('.tribe-postal-code')
3125        .after(wrapper.find('.tribe-region'))
3126        .after($('<span/>').html(',&nbsp;'))
3127        .after(wrapper.find('.tribe-locality'))
3128        .after(wrapper.find('.tribe-delimiter').html('&nbsp;'));
3129    }
3130  });
3131
3132  // Hack: A - Z automatically add search links
3133  $.each($('.auto-search'), function (index, item) {
3134    var html = $(item).html();
3135    var items = html.split('<br>');
3136    $.each(items, function (index2, textNode) {
3137      items[index2] = '<a href="/?s=' + textNode + '">' + textNode + '</a>';
3138    });
3139    var searchHTML = items.join('<br>');
3140    $(item).html(searchHTML);
3141  });
3142
3143  // Hack next events month
3144  var eventsMonths = [
3145    'Januar',
3146    'Februar',
3147    'März',
3148    'April',
3149    'Mai',
3150    'Juni',
3151    'Juli',
3152    'August',
3153    'September',
3154    'Oktober',
3155    'November',
3156    'Dezember'
3157  ];
3158
3159  var urlParams = new URLSearchParams(window.location.search);
3160  var urlDate = urlParams.get('tribe-bar-date');
3161  var eventsNow = urlDate ? new Date(urlDate) : new Date();
3162
3163  var dateSelected = eventsNow.getFullYear() + '-';
3164  dateSelected += ('0' + (eventsNow.getMonth() + 1)).slice(-2) + '-';
3165  dateSelected += ('0' + eventsNow.getDate()).slice(-2);
3166
3167  var dateNow = new Date();
3168  var dateNowParsed = dateNow.getFullYear() + '-';
3169  dateNowParsed += ('0' + (dateNow.getMonth() + 1)).slice(-2) + '-';
3170  dateNowParsed += ('0' + dateNow.getDate()).slice(-2);
3171
3172  var selectHtml = '<select onchange="changeEventsDate(this)">';
3173  selectHtml +=
3174    '<option value="' +
3175    (dateSelected == dateNowParsed ? ' selected="selected"' : '') +
3176    '">Ab Heute</option>';
3177
3178  for (var i = 1; i <= 11; i++) {
3179    var monthDate = new Date(dateNow.getFullYear(), dateNow.getMonth() + i, 1);
3180
3181    var dateOptionParsed = monthDate.getFullYear() + '-';
3182    dateOptionParsed += ('0' + (monthDate.getMonth() + 1)).slice(-2) + '-';
3183    dateOptionParsed += ('0' + monthDate.getDate()).slice(-2);
3184
3185    selectHtml += '<option value="';
3186    selectHtml += dateOptionParsed;
3187    selectHtml += '"';
3188    selectHtml +=
3189      dateSelected == dateOptionParsed ? ' selected="selected"' : '';
3190    selectHtml +=
3191      '">Ab ' +
3192      eventsMonths[monthDate.getMonth()] +
3193      ' ' +
3194      monthDate.getFullYear();
3195    selectHtml += '</option>';
3196  }
3197
3198  selectHtml += '</select>';
3199
3200  $('.custom-events-header__nav').html(selectHtml);
3201
3202  if (
3203    $('.tribe-events-calendar-list').length &&
3204    !$('.tribe-events-calendar-list__event-row').length
3205  ) {
3206    $('.tribe-events-calendar-list')
3207      .append(
3208        $('<div class="tribe-events-calendar-list__month-separator"/>').append(
3209          $(
3210            '<time class="tribe-events-calendar-list__month-separator-text tribe-common-h7 tribe-common-h6--min-medium tribe-common-h--alt"/>'
3211          ).html(
3212            eventsMonths[eventsNow.getMonth()] + ' ' + eventsNow.getFullYear()
3213          )
3214        )
3215      )
3216      .append(
3217        $('<div class="custom-events-content__no-events"/>').html(
3218          'Zu dieser Auswahl wurden keine Veranstaltungen gefunden.'
3219        )
3220      );
3221  }
3222
3223  // Check for search queries
3224  var queryParamter = getParameterByName('query');
3225  if (queryParamter) {
3226    $.each($('.squareone-block-dropdown__wrapper'), function (index, el) {
3227      wrapper = $(el);
3228      var title = wrapper.find('.squareone-block-dropdown__title').text();
3229      var content = wrapper.find('.squareone-block-dropdown__content').text();
3230
3231      if (
3232        title.indexOf(queryParamter) > -1 ||
3233        content.indexOf(queryParamter) > -1
3234      ) {
3235        var wrapperId = wrapper.attr('data-id');
3236        toggleDropdown(wrapperId);
3237        $([document.documentElement, document.body]).animate(
3238          {
3239            scrollTop: wrapper.offset().top - 100
3240          },
3241          800
3242        );
3243        return false;
3244      }
3245    });
3246  }
3247
3248  // Create archive
3249  $.each($('.archive-dropdown'), function (index, item) {
3250    var wrapper = $(item);
3251    var items = wrapper.find('.wp-block-file');
3252
3253    var showItems = 4;
3254    if (wrapper.find('h2').length) {
3255      showItems += 1;
3256    }
3257
3258    if (items && items.length > showItems) {
3259      var archiveButton = $(
3260        '<div class="archive-dropdown__button button">'
3261      ).html('Amtsblatt-Archiv');
3262      archiveButton.on('click', function () {
3263        wrapper.toggleClass('archive-active');
3264      });
3265      archiveButton.insertAfter(
3266        wrapper.find('.wp-block-file:nth-child(' + showItems + ')')
3267      );
3268    }
3269  });
3270
3271  // Create newest amtsblatt download
3272  $.each($('.amtsblatt-container'), function (index, item) {
3273    var wrapper = $(item);
3274    var newestItem = wrapper.find('.wp-block-file a:first-child');
3275    var link = newestItem.attr('href');
3276    var title = newestItem.html();
3277
3278    wrapper.before(
3279      $(
3280        '<figure class="wp-block-image size-large is-resized is-style-default"/>'
3281      ).html(
3282        '<a href="' +
3283          link +
3284          '" target="_blank" rel="noopener noreferrer"><img src="/wp-content/themes/squareone/img/amtsblatt-bild.png" alt="" width="auto" height="205"></a><figcaption><a href="' +
3285          link +
3286          '" target="_blank" rel="noreferrer noopener">' +
3287          title +
3288          '</a></figcaption>'
3289      )
3290    );
3291
3292    wrapper.before($('<hr class="wp-block-separator"/>'));
3293  });
3294
3295  // accordion function call
3296  accordion();
3297});
3298
3299// Get query parameter by name
3300function getParameterByName(name, url) {
3301  url = url || window.location.href;
3302  name = name.replace(/[\[\]]/g, '\\$&');
3303  var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
3304    results = regex.exec(url);
3305  if (!results) return null;
3306  if (!results[2]) return '';
3307  return decodeURIComponent(results[2].replace(/\+/g, ' '));
3308}
3309
3310// Change the events date
3311function changeEventsDate(el) {
3312  var date = $(el).val();
3313  if (date) {
3314    window.location.href = '/termine?tribe-bar-date=' + date;
3315  } else {
3316    window.location.href = '/termine';
3317  }
3318}
3319
3320// Toggle mobile menu
3321function toggleMenu() {
3322  $('body').toggleClass('menu-toggled');
3323}
3324
3325// Toggle dropdown
3326function toggleDropdown(id) {
3327  if ($('.squareone-block-dropdown__wrapper' + id).hasClass('.active')) {
3328    $('.squareone-block-dropdown__wrapper' + id).removeClass('.active');
3329    $(
3330      '.squareone-block-dropdown__wrapper' +
3331        id +
3332        ' .squareone-block-dropdown__content'
3333    ).slideUp();
3334    return;
3335  }
3336  $('.squareone-block-dropdown__wrapper' + id).addClass('.active');
3337  $(
3338    '.squareone-block-dropdown__wrapper' +
3339      id +
3340      ' .squareone-block-dropdown__content'
3341  ).slideDown();
3342}
3343
3344//# sourceMappingURL=main.js.map
3345
3346//Accordion
3347function accordion() {
3348  $('.accordion-item .article-header').on('click', function() {
3349    $(this).parent().toggleClass('open');
3350    $(this).next().slideToggle();
3351  } )
3352}
3353
3354//Menu items toggle
3355$(document).ready(function(){
3356  $('.mega-menu__container ul.mega-menu > li .mega-menu__menu-item-toggler').click(function() {
3357    $(this).parent().toggleClass('opened');
3358  });
3359  $('.mega-menu__container ul.mega-menu > li .mega-menu__menu-item-toggler').siblings('a').click(function() {
3360    $(this).parent().toggleClass('opened');
3361  });
3362});

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.