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(' ')); 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(', ')) 3127 .after(wrapper.find('.tribe-locality')) 3128 .after(wrapper.find('.tribe-delimiter').html(' ')); 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.