Commit a866cd37 authored by panpp's avatar panpp
Browse files

static init

parent 5c8b50e7
/* Global */
.jBox-wrapper {
text-align: left;
}
.jBox-wrapper,
.jBox-wrapper * {
-webkit-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.jBox-title,
.jBox-content,
.jBox-container {
position: relative;
word-break: break-word;
}
.jBox-container {
background: #fff;
}
.jBox-content {
padding: 8px 10px;
overflow: auto;
-webkit-transition: opacity .15s;
transition: opacity .15s;
}
/* jBox Tooltip */
.jBox-Tooltip .jBox-container,
.jBox-Mouse .jBox-container {
border-radius: 3px;
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.jBox-Tooltip .jBox-title,
.jBox-Mouse .jBox-title {
padding: 8px 10px 0;
font-weight: bold;
}
.jBox-hasTitle.jBox-Tooltip .jBox-content,
.jBox-hasTitle.jBox-Mouse .jBox-content {
padding-top: 5px;
}
/* Pointer */
.jBox-pointer {
position: absolute;
overflow: hidden;
}
.jBox-pointer-top { top: 0; }
.jBox-pointer-bottom { bottom: 0; }
.jBox-pointer-left { left: 0; }
.jBox-pointer-right { right: 0; }
.jBox-pointer-top,
.jBox-pointer-bottom {
width: 30px;
height: 12px;
}
.jBox-pointer-left,
.jBox-pointer-right {
width: 12px;
height: 30px;
}
.jBox-pointer:after {
content: '';
width: 20px;
height: 20px;
position: absolute;
background: #fff;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
.jBox-pointer-top:after {
left: 5px;
top: 6px;
box-shadow: -1px -1px 4px rgba(0, 0, 0, .2);
}
.jBox-pointer-right:after {
top: 5px;
right: 6px;
box-shadow: 1px -1px 4px rgba(0, 0, 0, .2);
}
.jBox-pointer-bottom:after {
left: 5px;
bottom: 6px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, .2);
}
.jBox-pointer-left:after {
top: 5px;
left: 6px;
box-shadow: -1px 1px 4px rgba(0, 0, 0, .2);
}
/* jBox Modal & jBox Confirm */
.jBox-Modal .jBox-container,
.jBox-Confirm .jBox-container {
border-radius: 3px;
box-shadow: 0 3px 15px rgba(0, 0, 0, .4), 0 0 5px rgba(0, 0, 0, .4);
}
.jBox-Modal .jBox-title,
.jBox-Confirm .jBox-title {
border-radius: 3px 3px 0 0;
padding: 10px 15px;
background: #f4f5f6;
border-bottom: 1px solid #ddd;
text-shadow: 0 1px 0 #fff;
}
.jBox-Modal.jBox-closeButton-title .jBox-title,
.jBox-Confirm.jBox-closeButton-title .jBox-title {
padding-right: 55px;
}
.jBox-Modal.jBox-closeButton-box:before,
.jBox-Confirm.jBox-closeButton-box:before {
box-shadow: 0 3px 15px rgba(0, 0, 0, .4), 0 0 5px rgba(0, 0, 0, .4);
}
/* jBox Modal */
.jBox-Modal .jBox-content {
padding: 12px 15px;
}
/* jBox Confirm */
.jBox-Confirm .jBox-content {
text-align: center;
padding: 45px 35px;
}
.jBox-Confirm-footer {
border-top: 1px solid #e2e2e2;
background: #fafafa;
border-radius: 0 0 3px 3px;
text-align: center;
padding: 10px 0;
}
.jBox-Confirm-button {
display: inline-block;
cursor: pointer;
font-size: 15px;
line-height: 30px;
height: 30px;
border-radius: 3px;
padding: 0 20px;
-webkit-transition: color .2s, background-color .2s;
transition: color .2s, background-color .2s;
}
.jBox-Confirm-button-cancel {
text-shadow: 0 1px 1px rgba(255, 255, 255, .6);
background: #ddd;
color: #999;
margin-right: 25px;
}
.jBox-Confirm-button-cancel:hover {
background: #ccc;
color: #666;
}
.jBox-Confirm-button-submit {
text-shadow: 0 -1px 1px rgba(0, 0, 0, .2);
background: #5fc04c;
color: #fff;
}
.jBox-Confirm-button-submit:hover {
background: #53a642;
}
.jBox-Confirm-button-cancel:active,
.jBox-Confirm-button-submit:active {
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .26);
}
/* jBox Notice */
.jBox-Notice {
-webkit-transition: margin .2s;
transition: margin .2s;
}
.jBox-Notice .jBox-container {
border-radius: 3px;
box-shadow: 0 0 3px rgba(0, 0, 0, .2);
color: #fff;
text-shadow: 0 -1px 0 #000;
background: #333;
background-image: linear-gradient(to bottom, #444, #222);
}
.jBox-Notice .jBox-content {
border-radius: 3px;
padding: 12px 20px;
}
.jBox-Notice .jBox-title {
padding: 8px 20px 0;
font-weight: bold;
}
.jBox-hasTitle.jBox-Notice .jBox-content {
padding-top: 5px;
}
.jBox-Notice-color .jBox-container {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
}
.jBox-Notice-gray .jBox-container {
color: #666;
text-shadow: 0 1px 0 #fff;
background: #f4f4f4;
background-image: linear-gradient(to bottom, #fafafa, #f0f0f0);
}
.jBox-Notice-red .jBox-container {
background: #b02222;
background-image: linear-gradient(to bottom, #ee2222, #b02222);
}
.jBox-Notice-green .jBox-container {
background: #70a800;
background-image: linear-gradient(to bottom, #95cc2a, #70a800);
}
.jBox-Notice-blue .jBox-container {
background: #2b91d9;
background-image: linear-gradient(to bottom, #5abaff, #2b91d9);
}
.jBox-Notice-yellow .jBox-container {
color: #744700;
text-shadow: 0 1px 0 rgba(255, 255, 255, .6);
background: #ffb11f;
background-image: linear-gradient(to bottom, #ffd665, #ffb11f);
}
/* jBox Image */
.jBox-Image {
background: #fff;
padding: 8px 8px 45px;
border-radius: 5px;
}
.jBox-Image .jBox-content {
padding: 0;
width: 100%;
height: 100%;
}
.jBox-image-container {
border-radius: 5px;
background: #fff center center no-repeat;
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
}
.jBox-image-label {
box-sizing: border-box;
position: absolute;
background: #fff;
top: 100%;
left: 0;
width: 100%;
color: #333;
margin-top: -35px;
padding: 0 90px 5px 10px;
border-radius: 0 0 5px 5px;
-webkit-transition: opacity .3s;
transition: opacity .3s;
opacity: 0;
}
.jBox-image-label.active {
opacity: 1;
}
.jBox-image-pointer-next,
.jBox-image-pointer-prev {
position: absolute;
bottom: 0px;
width: 22px;
height: 45px;
background: no-repeat center center url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ijc0LjcgMjI0IDE4LjcgMzIiPg0KPHBhdGggZmlsbD0iIzAwMDAwMCIgZD0iTTkzLDIyNy40TDgwLjQsMjQwTDkzLDI1Mi42YzAuNCwwLjQsMC40LDEuMSwwLDEuNWwtMS42LDEuNmMtMC40LDAuNC0xLDAuNS0xLjUsMEw3NSwyNDAuN2MtMC40LTAuNC0wLjUtMSwwLTEuNWwxNC45LTE0LjljMC40LTAuNCwxLTAuNCwxLjUsMGwxLjYsMS42QzkzLjUsMjI2LjQsOTMuNCwyMjcsOTMsMjI3LjR6Ii8+DQo8L3N2Zz4=);
background-size: 11px auto;
cursor: pointer;
opacity: .6;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transition: opacity .2s;
transition: opacity .2s;
}
.jBox-image-pointer-next:hover,
.jBox-image-pointer-prev:hover {
opacity: 1;
}
.jBox-image-pointer-next {
right: 8px;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
.jBox-image-pointer-prev {
right: 30px;
}
.jBox-image-open #jBox-overlay {
background-color: rgba(0, 0, 0, .86);
}
.jBox-Image.jBox-loading .jBox-container:before {
left: auto;
top: auto;
bottom: -33px;
right: 55px;
margin-top: -9px;
margin-left: -9px;
}
/* Close button */
.jBox-closeButton {
cursor: pointer;
position: absolute;
}
.jBox-closeButton svg {
position: absolute;
top: 50%;
right: 50%;
}
.jBox-closeButton path {
-webkit-transition: fill .2s;
transition: fill .2s;
}
.jBox-closeButton path {
fill: #aaa;
}
.jBox-closeButton:hover path {
fill: #888;
}
.jBox-closeButton:active path {
fill: #666;
}
/* Close button in overlay */
#jBox-overlay .jBox-closeButton {
top: 0;
right: 0;
width: 40px;
height: 40px;
}
#jBox-overlay .jBox-closeButton svg {
width: 20px;
height: 20px;
margin-top: -10px;
margin-right: -10px;
}
#jBox-overlay .jBox-closeButton path {
fill: #d2d4d6;
}
#jBox-overlay .jBox-closeButton:hover path {
fill: #fff;
}
#jBox-overlay .jBox-closeButton:active path {
fill: #b2b4b6;
}
/* Close button in title */
.jBox-closeButton-title .jBox-closeButton {
top: 0;
right: 0;
bottom: 0;
width: 40px;
}
.jBox-closeButton-title .jBox-closeButton svg {
width: 12px;
height: 12px;
margin-top: -6px;
margin-right: -6px;
}
/* Close button in box */
.jBox-closeButton-box .jBox-closeButton {
top: -8px;
right: -10px;
width: 24px;
height: 24px;
background: #fff;
border-radius: 50%;
}
.jBox-closeButton-box .jBox-closeButton svg {
width: 10px;
height: 10px;
margin-top: -5px;
margin-right: -5px;
}
.jBox-hasTitle.jBox-Modal.jBox-closeButton-box .jBox-closeButton {
background: #f4f5f6;
}
.jBox-closeButton-box:before {
content: '';
position: absolute;
top: -8px;
right: -10px;
width: 24px;
height: 24px;
border-radius: 50%;
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
}
.jBox-pointerPosition-top.jBox-closeButton-box:before {
top: 4px;
}
.jBox-pointerPosition-right.jBox-closeButton-box:before {
right: 2px;
}
/* Overlay */
#jBox-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
background-color: rgba(0, 0, 0, .6);
}
/* Block scrolling */
body[class^="jBox-blockScroll-"],
body[class*=" jBox-blockScroll-"] {
overflow: hidden;
}
/* Draggable */
.jBox-draggable {
cursor: move;
}
/* Spinner */
@keyframes jBoxLoading {
to {transform: rotate(360deg);}
}
@-webkit-keyframes jBoxLoading {
to {-webkit-transform: rotate(360deg);}
}
.jBox-loading .jBox-content {
min-height: 32px;
min-width: 38px;
opacity: 0;
}
.jBox-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: -10px;
}
.jBox-spinner:before {
content: 'Loading…';
display: block;
width: 20px;
height: 20px;
text-align: center;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.jBox-spinner:not(:required):before {
content: '';
border-radius: 50%;
border: 2px solid rgba(0, 0, 0, .3);
border-top-color: rgba(0, 0, 0, .6);
animation: jBoxLoading .6s linear infinite;
-webkit-animation: jBoxLoading .6s linear infinite;
}
/* IE8 fixes */
.jBox-IE8.jBox-Tooltip .jBox-container,
.jBox-IE8.jBox-Mouse .jBox-container {
border: 1px solid #aaa;
}
.jBox-IE8 .jBox-pointer:after {
display: none;
}
.jBox-IE8 .jBox-pointer {
border: 0;
background: no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNq01l0OwyAIAGAlvY+n8ZJ6Gk/EqqkNtf7ApCQ+LM34iuCmRUQzihjj6FH+kjWL8N4/Ph9GHpiTnC9SwDbhLGyvspSScc71KkOa/HpuuRhIK+psE2pjONouCQg7kBSEXUgC2tHo52mTTBpnaEATWlaYK6MrhIAaceWpOcsCrYp6FV4H/90zTWjUQ/gSevVQq0ecHqoOxWpYoO7p5O9ku2fnVtp7QAik2rsK3fnpWfjynJWpbw+1BkghurrYDjiCptg/4AxaYhJwBbEwDsiB2NgM5EIirAdKIDFGQSmU1+NaIPjJYt2I25vxT4ABAMhWvtle2YvmAAAAAElFTkSuQmCC);
}
.jBox-IE8 .jBox-pointer-top { background-position: center top; }
.jBox-IE8 .jBox-pointer-bottom { background-position: center bottom; }
.jBox-IE8 .jBox-pointer-left { background-position: left center; }
.jBox-IE8 .jBox-pointer-right { background-position: right center; }
.jBox-IE8.jBox-Modal .jBox-container {
border: 3px solid #aaa;
}
/* No SVG support fixes */
.jBox-nosvg .jBox-closeButton:before {
font-family: Verdana, sans-serif;
content: 'x';
text-align: center;
font-size: 18px;
color: #888;
}
/*
---
description: jBox is a powerful and flexible jQuery plugin, taking care of all your modal windows, tooltips, notices and more.
authors: Stephan Wagner (http://stephanwagner.me)
license: MIT (http://www.opensource.org/licenses/mit-license.php)
requires: jQuery 1.11.0 (http://code.jquery.com/jquery-1.11.0.min.js)
jQuery 2.1.0 (http://code.jquery.com/jquery-2.1.0.min.js)
documentation: http://stephanwagner.me/jBox/documentation
demos: http://stephanwagner.me/jBox/demos
...
*/
function jBox(type, options) {
this.options = {
// jBox ID
id: null, // Choose a unique id, otherwise jBox will set one for you (jBoxID1, jBoxID2, ...)
// Dimensions
width: 'auto', // Width of content area (e.g. 'auto', 100)
height: 'auto', // Height of content area
minWidth: null, // Minimum width
maxHeight: null, // Minimum height
minWidth: null, // Maximum width
maxHeight: null, // Minimum height
// Attach
attach: null, // Attach jBox to elements (if no target element is provided, jBox will use the attached element as target)
trigger: 'click', // The event to open or close your jBoxes, use 'click' or 'mouseenter'
preventDefault: false, // Prevent default event when opening jBox (e.g. don't follow the href in a link when clicking on it)
// Content
title: null, // Adds a title to your jBox
content: null, // You can use a string to set text or HTML as content, or an element selector (e.g. jQuery('#jBox-content')) to append one or several elements (elements appended will get style display: 'block', so hide them with CSS style display: 'none' beforehand)
getTitle: null, // Get the title from an attribute when jBox opens
getContent: null, // Get the content from an attribute when jBox opens
// AJAX request
ajax: { // Setting an url will make an AJAX call when jBox opens
url: null, // URL to send the AJAX request to
data: '', // Data to send with your AJAX call (e.g. 'id=82&limit=10')
// Optional you can add any jQuery AJAX option (http://api.jquery.com/jquery.ajax/)
reload: false, // Resend the ajax call every time jBox opens
getData: 'data-ajax', // The attribute in the source element where the AJAX will look for the data to send with, e.g. data-ajax="id=82&limit=10"
setContent: true, // Automatically set the response as new content when the AJAX call is finished
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>'
},
// Position
target: null, // The target element where jBox will be opened
position: {
x: 'center', // Horizontal Position (Use a number, 'left', 'right' or 'center')
y: 'center' // Vertical Position (Use a number, 'top', 'bottom' or 'center')
},
outside: null, // Use 'x', 'y', or 'xy' to move your jBox outside of the target element
offset: 0, // Offset to final position, you can set different values for x and y with an object e.g. {x: 15, y: 0}
attributes: { // Note that attributes can only be 'left' or 'right' when using numbers for position, e.g. {x: 300, y: 20}
x: 'left', // Horizontal position, use 'left' or 'right'
y: 'top' // Vertical position, use 'top' or 'bottom'
},
adjustPosition: false, // Adjusts the position when there is not enough space (use true, 'flip' or 'move')
adjustTracker: false, // By default jBox adjusts the position when opening, to adjust when scrolling or resizing, use 'scroll', 'resize' or 'true' (both events)
adjustDistance: 5, // How far from the window edge we start adjusting, use an object to set different values: {bottom: 5, top: 50, left: 5, right: 20}
fixed: false, // Your jBox will stay on position when scrolling
reposition: false, // Calculates new position when the window-size changes
repositionOnOpen: true, // Calculates new position each time jBox opens (rather than only when it opens the first time)
repositionOnContent: true, // Calculates new position when the content changes with .setContent() or .setTitle()
// Pointer
pointer: false, // Your pointer will always point towards the target element, so the option outside should be 'x' or 'y'
pointTo: 'target', // Setting something else than 'target' will add a pointer even if there is no target element set or found (Use 'top', 'bottom', 'left' or 'right')
// Animations
fade: 180, // Fade duration in ms, set to 0 or false to disable
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)
// Appearance
theme: 'Default', // Set a jBox theme class
addClass: '', // Adds classes to the wrapper
overlay: false, // Adds an overlay when jBox opens (set color and opacity with CSS)
zIndex: 10000, // Use a high zIndex (your overlay will have the lowest zIndex of all your jBoxes (with overlays) minus one)
// Delays
delayOpen: 0, // Delay opening in ms (Note that the delay will be ignored if your jBox didn't finish closing)
delayClose: 0, // Delay closing in ms (Note that there is always a closing delay of at least 10ms to ensure jBox won't be closed when opening right away)
// Closing events
closeOnEsc: false, // Close jBox when pressing [esc] key
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)
closeOnMouseleave: false, // Close jBox when the mouse leaves the jBox area or the area of the attached element
closeButton: false, // Adds a close button to your jBox, use 'title', 'overlay', 'box' or true (true will add the button to overlay, title or box, in that order if any of those elements can be found)
// Other options
constructOnInit: false, // Construct jBox when it's being initialized
blockScroll: false, // When jBox is open, block scrolling
appendTo: jQuery('body'), // Provide an element if you want the jBox to be positioned inside a specific element (only useful for fixed positions or when position values are numbers)
draggable: null, // 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/)
dragOver: true, // When you have multiple draggable jBoxes, the one you select will always move over the other ones
// Events // Note: You can use 'this' in the event functions, it refers to your jBox object (e.g. onInit: function() { this.open(); })
onInit: function() {}, // Triggered when jBox is initialized, just before it's being created
onCreated: function() {}, // Triggered when jBox is created and is availible in DOM
onOpen: function() {}, // Triggered when jBox is opened
onClose: function() {}, // Triggered when jBox is closed
onCloseComplete: function() {}, // Triggered when jBox is completely closed (when fading is finished, useful if you want to destroy the jBox when it is closed)
// Only for type "Confirm"
confirmButton: 'Submit', // Text for the submit button
cancelButton: 'Cancel', // Text for the cancel button
confirm: null, // Function to execute when clicking the submit button. By default jBox will use firstly the onclick and secondly the href attribute
cancel: null, // Function to execute when clicking the cancel button
// Only for type "Notice"
autoClose: 7000, // Time when jBox should close automatically
color: null, // Makes your notices colorful, use 'black', 'red', 'green', 'blue', 'yellow'
stack: true, // Set to false to disable notice-stacking
audio: false, // Set the url to an audio file without extention, e.g. '/url/filename'. jBox will look for an .mp3 and an .ogg file
volume: 100, // Percent of volume for audio files
// Only for type "Image"
src: 'href', // The attribute where jBox gets the image source from, e.g. href="/path_to_image/image.jpg"
gallery: 'data-jbox-image', // The attribute where you define the image gallery, e.g. data-jbox-image="gallery1"
imageLabel: 'title', // The attribute where jBox gets the image label from, e.g. title="My label"
imageFade: 600, // The fade duration for images
imageSize: 'contain' // How to display the images: Use CSS background-position values, e.g. 'cover', 'contain', 'auto', 'initial', '50% 50%'
};
// Default type options
this.defaultOptions = {
// Default options for tooltips
'Tooltip': {
getContent: 'title',
trigger: 'mouseenter',
position: {x: 'center', y: 'top'},
outside: 'y',
pointer: true,
adjustPosition: true,
reposition: true
},
// Default options for mouse tooltips
'Mouse': {
target: 'mouse',
position: {x: 'right', y: 'bottom'},
offset: 15,
trigger: 'mouseenter',
adjustPosition: 'flip'
},
// Default options for modal windows
'Modal': {
target: jQuery(window),
fixed: true,
blockScroll: true,
closeOnEsc: true,
closeOnClick: 'overlay',
closeButton: true,
overlay: true,
animation: 'zoomOut'
},
// Default options for modal confirm windows
'Confirm': {
target: jQuery(window),
fixed: true,
attach: jQuery('[data-confirm]'),
getContent: 'data-confirm',
content: 'Do you really want to do this?',
minWidth: 320,
maxWidth: 460,
blockScroll: true,
closeOnEsc: true,
closeOnClick: 'overlay',
closeButton: true,
overlay: true,
animation: 'zoomOut',
preventDefault: true,
_onAttach: function(el) {
// Extract the href or the onclick event if no submit event is passed
if (!this.options.confirm) {
var submit = el.attr('onclick') ? el.attr('onclick') : (el.attr('href') ? (el.attr('target') ? 'window.open("' + el.attr('href') + '", "' + el.attr('target') + '");' : 'window.location.href = "' + el.attr('href') + '";') : '');
el.prop('onclick', null).data('jBox-Confirm-submit', submit);
}
},
_onCreated: function() {
// Add a footer to the jBox container
this.footer = jQuery('<div class="jBox-Confirm-footer"/>');
jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-cancel"/>').html(this.options.cancelButton).click(function() { this.options.cancel && this.options.cancel(); this.close(); }.bind(this)).appendTo(this.footer);
this.submitButton = jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-submit"/>').html(this.options.confirmButton).appendTo(this.footer);
this.footer.appendTo(this.container);
},
_onOpen: function() {
// Set the new action for the submit button
this.submitButton.off('click.jBox-Confirm' + this.id).on('click.jBox-Confirm' + this.id, function() { this.options.confirm ? this.options.confirm() : eval(this.source.data('jBox-Confirm-submit')); this.close(); }.bind(this));
}
},
// Default options for notices
'Notice': {
target: jQuery(window),
fixed: true,
position: {x: 20, y: 20},
attributes: {x: 'right', y: 'top'},
animation: 'zoomIn',
closeOnClick: 'box',
_onInit: function () {
this.open();
this.options.delayClose = this.options.autoClose;
this.options.delayClose && this.close();
},
_onCreated: function() {
this.options.color && this.wrapper.addClass('jBox-Notice-color jBox-Notice-' + this.options.color);
this.wrapper.data('jBox-Notice-position', this.options.attributes.x + '-' + this.options.attributes.y);
},
_onOpen: function() {
// Loop through notices at same window corner and either move or destroy them
jQuery.each(jQuery('.jBox-Notice'), function(index, el) {
el = jQuery(el);
if (el.attr('id') == this.id || el.data('jBox-Notice-position') != this.options.attributes.x + '-' + this.options.attributes.y) return;
if (!this.options.stack) {
el.data('jBox').close({ignoreDelay: true});
return;
}
el.css('margin-' + this.options.attributes.y, parseInt(el.css('margin-' + this.options.attributes.y)) + this.wrapper.outerHeight() + 10);
}.bind(this));
// Play audio file, IE8 doesn't support audio
this.options.audio && this.audio({url: this.options.audio, valume: this.options.volume});
},
// Remove notice from DOM when closing finishes
_onCloseComplete: function() {
this.destroy();
}
},
// Default options for images
'Image': {
target: jQuery(window),
fixed: true,
blockScroll: true,
closeOnEsc: true,
closeOnClick: 'overlay',
closeButton: true,
overlay: true,
animation: 'zoomOut',
width: 800,
height: 533,
attach: jQuery('[data-jbox-image]'),
preventDefault: true,
// TODO: What if the image is not found?
// TODO: What if the first image of a gallery needs some time to load, but other images are in content. Maybe add a blank black container
_onInit: function() {
this.images = this.currentImage = {};
this.imageZIndex = 1;
// Loop through images, sort and save in global variable
this.attachedElements && jQuery.each(this.attachedElements, function (index, item) {
item = jQuery(item);
if (item.data('jBox-image-gallery')) return;
var gallery = item.attr(this.options.gallery) || 'default';
!this.images[gallery] && (this.images[gallery] = []);
this.images[gallery].push({src: item.attr(this.options.src), label: (item.attr(this.options.imageLabel) || '')});
// Remove the title attribute so it won't show the browsers tooltip
this.options.imageLabel == 'title' && item.removeAttr('title');
// Store data in source element for easy access
item.data('jBox-image-gallery', gallery);
item.data('jBox-image-id', (this.images[gallery].length - 1));
}.bind(this));
// Helper to inject the image into content area
var appendImage = function(gallery, id, preload, open) {
if (jQuery('#jBox-image-' + gallery + '-' + id).length) return;
var image = jQuery('<div/>', {
id: 'jBox-image-' + gallery + '-' + id,
'class': 'jBox-image-container'
}).css({
backgroundImage: 'url(' + this.images[gallery][id].src + ')',
backgroundSize: this.options.imageSize,
opacity: (open ? 1 : 0),
zIndex: (preload ? 0 : this.imageZIndex++)
}).appendTo(this.content);
var text = jQuery('<div/>', {
id: 'jBox-image-label-' + gallery + '-' + id,
'class': 'jBox-image-label' + (open ? ' active' : '')
}).html(this.images[gallery][id].label).appendTo(this.imageLabel);
!open && !preload && image.animate({opacity: 1}, this.options.imageFade);
}.bind(this);
// Helper to show new image label
var showLabel = function(gallery, id) {
jQuery('.jBox-image-label.active').removeClass('active');
jQuery('#jBox-image-label-' + gallery + '-' + id).addClass('active');
};
// Show images when they are loaded or load them if not
this.showImage = function(img) {
// Get the gallery and the image id from the next or the previous image
if (img != 'open') {
var gallery = this.currentImage.gallery;
var id = this.currentImage.id + (1 * (img == 'prev') ? -1 : 1);
id = id > (this.images[gallery].length - 1) ? 0 : (id < 0 ? (this.images[gallery].length - 1) : id);
// Or get image data from source element
} else {
var gallery = this.source.data('jBox-image-gallery');
var id = this.source.data('jBox-image-id');
// Remove or show the next and prev buttons
jQuery('.jBox-image-pointer-prev, .jBox-image-pointer-next').css({display: (this.images[gallery].length > 1 ? 'block' : 'none')});
}
// Set new current image
this.currentImage = {gallery: gallery, id: id};
// Show image if it already exists
if (jQuery('#jBox-image-' + gallery + '-' + id).length) {
jQuery('#jBox-image-' + gallery + '-' + id).css({zIndex: this.imageZIndex++, opacity: 0}).animate({opacity: 1}, (img == 'open') ? 0 : this.options.imageFade);
showLabel(gallery, id);
// Load image if not found
} else {
// TODO loading not working properly anymore
this.wrapper.addClass('jBox-loading');
var image = jQuery('<img src="' + this.images[gallery][id].src + '">').load(function() {
appendImage(gallery, id, false);
showLabel(gallery, id);
this.wrapper.removeClass('jBox-loading');
}.bind(this));
}
// Preload next image
var next_id = id + 1;
next_id = next_id > (this.images[gallery].length - 1) ? 0 : (next_id < 0 ? (this.images[gallery].length - 1) : next_id);
(!jQuery('#jBox-image-' + gallery + '-' + next_id).length) && jQuery('<img src="' + this.images[gallery][next_id].src + '">').load(function() {
appendImage(gallery, next_id, true);
});
};
},
_onCreated: function() {
// TODO: NO ID!!!
this.imageLabel = jQuery('<div/>', {'id': 'jBox-image-label'}).appendTo(this.wrapper);
this.wrapper.append(jQuery('<div/>', {'class': 'jBox-image-pointer-prev', click: function() { this.showImage('prev'); }.bind(this)})).append(jQuery('<div/>', {'class': 'jBox-image-pointer-next', click: function() { this.showImage('next'); }.bind(this)}));
},
_onOpen: function() {
// Add a class to body so you can control the appearance of the overlay, for images a darker one is better
jQuery('body').addClass('jBox-image-open');
// Add key events
jQuery(document).on('keyup.jBox-' + this.id, function(ev) {
(ev.keyCode == 37) && this.showImage('prev');
(ev.keyCode == 39) && this.showImage('next');
}.bind(this));
// Load the image from the attached element
this.showImage('open');
},
_onClose: function() {
jQuery('body').removeClass('jBox-image-open');
// Remove key events
jQuery(document).off('keyup.jBox-' + this.id);
},
_onCloseComplete: function() {
// Hide all images
this.wrapper.find('.jBox-image-container').css('opacity', 0);
}
}
};
// Set default options for jBox types
if (jQuery.type(type) == 'string') {
this.type = type;
type = this.defaultOptions[type];
}
// Merge options
this.options = jQuery.extend(true, this.options, type, options);
// Get unique ID
if (this.options.id === null) {
this.options.id = 'jBoxID' + jBox._getUniqueID();
}
this.id = this.options.id;
// Correct impossible options
((this.options.position.x == 'center' && this.options.outside == 'x') || (this.options.position.y == 'center' && this.options.outside == 'y')) && (this.options.outside = false);
(!this.options.outside || this.options.outside == 'xy') && (this.options.pointer = false);
// Correct multiple choice options
jQuery.type(this.options.offset) != 'object' && (this.options.offset = {x: this.options.offset, y: this.options.offset});
this.options.offset.x || (this.options.offset.x = 0);
this.options.offset.y || (this.options.offset.y = 0);
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));
// Save where the jBox is aligned to
this.align = (this.options.outside && this.options.outside != 'xy') ? this.options.position[this.options.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));
// Save default outside position
this.options.outside && this.options.outside != 'xy' && (this.outside = this.options.position[this.options.outside]);
// I know browser detection is bad practice, but for now it seems the only option to get jBox working in IE8
var userAgent = navigator.userAgent.toLowerCase();
this.IE8 = userAgent.indexOf('msie') != -1 && parseInt(userAgent.split('msie')[1]) == 8;
// Save global var for webkit prefix
this.prefix = userAgent.indexOf('webkit') != -1 ? '-webkit-' : '';
// Internal functions, used to easily get values
this._getOpp = function(opp) { return {left: 'right', right: 'left', top: 'bottom', bottom: 'top', x: 'y', y: 'x'}[opp]; };
this._getXY = function(xy) { return {left: 'x', right: 'x', top: 'y', bottom: 'y', center: 'x'}[xy]; };
this._getTL = function(tl) { return {left: 'left', right: 'left', top: 'top', bottom: 'top', center: 'left', x: 'left', y: 'top'}[tl]; };
// Check for SVG support
this._supportsSVG = function() {
return document.createElement('svg').getAttributeNS;
}
// Create an svg element
this._createSVG = function(type, options) {
var svg = document.createElementNS('http://www.w3.org/2000/svg', type);
jQuery.each(options, function (index, item) {
svg.setAttribute(item[0], (item[1] || ''));
});
return svg;
};
// Append a svg element to a svg container
this._appendSVG = function(source, target) {
return target.appendChild(source);
};
// Create jBox
this._create = function() {
if (this.wrapper) return;
// Create wrapper
this.wrapper = jQuery('<div/>', {
id: this.id,
'class': 'jBox-wrapper' + (this.type ? ' jBox-' + this.type : '') + (this.options.theme ? ' jBox-' + this.options.theme : '') + (this.options.addClass ? ' ' + this.options.addClass : '') + (this.IE8 ? ' jBox-IE8' : '')
}).css({
position: (this.options.fixed ? 'fixed' : 'absolute'),
display: 'none',
opacity: 0,
zIndex: this.options.zIndex
// Save the jBox instance in the wrapper, so you can get access to your jBox when you only have the element
}).data('jBox', this);
// Add mouseleave event (.parents('*') might be a performance nightmare! Maybe there is a better way)
this.options.closeOnMouseleave && this.wrapper.mouseleave(function(ev) {
// Only close when the new target is not the source element
!this.source || !(ev.relatedTarget == this.source[0] || jQuery.inArray(this.source[0], jQuery(ev.relatedTarget).parents('*')) !== -1) && this.close();
}.bind(this));
// Add closeOnClick: 'box' events
(this.options.closeOnClick == 'box') && this.wrapper.on('touchend click', function() { this.close({ignoreDelay: true}); }.bind(this));
// Create container
this.container = jQuery('<div/>', {'class': 'jBox-container'}).appendTo(this.wrapper);
// Create content
this.content = jQuery('<div/>', {'class': 'jBox-content'}).css({width: this.options.width, height: this.options.height, minWidth: this.options.minWidth, minHeight: this.options.minHeight, maxWidth: this.options.maxWidth, maxHeight: this.options.maxHeight}).appendTo(this.container);
// Create close button
if (this.options.closeButton) {
this.closeButton = jQuery('<div/>', {'class': 'jBox-closeButton jBox-noDrag'}).on('touchend click', function(ev) { this.isOpen && this.close({ignoreDelay: true}); }.bind(this));
if (this._supportsSVG()) {
var closeButtonSVG = this._createSVG('svg', [['viewBox', '0 0 24 24']]);
this._appendSVG(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']]), closeButtonSVG);
this.closeButton.append(closeButtonSVG);
} else {
this.wrapper.addClass('jBox-nosvg');
}
// Add close button to jBox container
if (this.options.closeButton == 'box' || (this.options.closeButton === true && !this.options.overlay && !this.options.title)) {
this.wrapper.addClass('jBox-closeButton-box');
this.closeButton.appendTo(this.container);
}
}
// Append jBox to DOM
this.wrapper.appendTo(this.options.appendTo);
// Create pointer
if (this.options.pointer) {
// Get pointer vars and save globally
this.pointer = {
position: (this.options.pointTo != 'target') ? this.options.pointTo : this._getOpp(this.outside),
xy: (this.options.pointTo != 'target') ? this._getXY(this.options.pointTo) : this._getXY(this.outside),
align: 'center',
offset: 0
};
this.pointer.element = jQuery('<div/>', {'class': 'jBox-pointer jBox-pointer-' + this.pointer.position}).appendTo(this.wrapper);
this.pointer.dimensions = {
x: this.pointer.element.outerWidth(),
y: this.pointer.element.outerHeight()
};
if (jQuery.type(this.options.pointer) == 'string') {
var split = this.options.pointer.split(':');
split[0] && (this.pointer.align = split[0]);
split[1] && (this.pointer.offset = parseInt(split[1]));
}
this.pointer.alignAttribute = (this.pointer.xy == 'x' ? (this.pointer.align == 'bottom' ? 'bottom' : 'top') : (this.pointer.align == 'right' ? 'right' : 'left'));
// Set wrapper CSS
this.wrapper.css('padding-' + this.pointer.position, this.pointer.dimensions[this.pointer.xy]);
// Set pointer CSS
this.pointer.element.css(this.pointer.alignAttribute, (this.pointer.align == 'center' ? '50%' : 0)).css('margin-' + this.pointer.alignAttribute, this.pointer.offset);
this.pointer.margin = {}; this.pointer.margin['margin-' + this.pointer.alignAttribute] = this.pointer.offset;
// Add a transform to fix centered position
(this.pointer.align == 'center') && this.pointer.element.css(this.prefix + '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) + ')');
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')));
// Add class to wrapper for CSS access
this.wrapper.addClass('jBox-pointerPosition-' + this.pointer.position);
}
// Set title and content
this.setContent(this.options.content, true);
this.setTitle(this.options.title, true);
// Make jBox draggable
if (this.options.draggable) {
var handle = (this.options.draggable == 'title') ? this.titleContainer : (this.options.draggable.length > 0 ? this.options.draggable : (this.options.draggable.selector ? jQuery(this.options.draggable.selector) : this.wrapper));
handle.addClass('jBox-draggable').on('mousedown', function(ev) {
if (ev.button == 2 || jQuery(ev.target).hasClass('jBox-noDrag') || jQuery(ev.target).parents('.jBox-noDrag').length) return;
if (this.options.dragOver && this.wrapper.css('zIndex') <= jBox.zIndexMax) {
jBox.zIndexMax += 1;
this.wrapper.css('zIndex', jBox.zIndexMax);
}
var drg_h = this.wrapper.outerHeight(),
drg_w = this.wrapper.outerWidth(),
pos_y = this.wrapper.offset().top + drg_h - ev.pageY,
pos_x = this.wrapper.offset().left + drg_w - ev.pageX;
jQuery(document).on('mousemove.jBox-draggable-' + this.id, function(ev) {
this.wrapper.offset({
top: ev.pageY + pos_y - drg_h,
left: ev.pageX + pos_x - drg_w
});
}.bind(this));
ev.preventDefault();
}.bind(this)).on('mouseup', function() { jQuery(document).off('mousemove.jBox-draggable-' + this.id); }.bind(this));
// Add z-index
jBox.zIndexMax = !jBox.zIndexMax ? this.options.zIndex : Math.max(jBox.zIndexMax, this.options.zIndex);
}
// Fire onCreated event
(this.options.onCreated.bind(this))();
this.options._onCreated && (this.options._onCreated.bind(this))();
};
// Create jBox onInit
this.options.constructOnInit && this._create();
// Attach jBox
this.options.attach && this.attach();
// Position jBox on mouse
this._positionMouse = function(ev) {
// Calculate positions
this.pos = {
left: ev.pageX,
top: ev.pageY
};
var setPosition = function(a, p) {
// Set centered position
if (this.options.position[p] == 'center') {
this.pos[a] -= Math.ceil(this.dimensions[p] / 2);
return;
}
// Move to left or top
this.pos[a] += (a == this.options.position[p]) ? ((this.dimensions[p] * -1) - this.options.offset[p]) : this.options.offset[p];
return this.pos[a];
}.bind(this);
// Set position to wrapper
this.wrapper.css({
left: setPosition('left', 'x'),
top: setPosition('top', 'y')
});
// Adjust mouse position
this.targetDimensions = {x: 0, y: 0, left: ev.pageX, top: ev.pageY};
this._adjustPosition();
};
// Attach document and window events
this._attachEvents = function() {
// Closing event: closeOnEsc
this.options.closeOnEsc && jQuery(document).on('keyup.jBox-' + this.id, function(ev) { if (ev.keyCode == 27) { this.close({ignoreDelay: true}); }}.bind(this));
// Closing event: closeOnClick
if (this.options.closeOnClick === true || this.options.closeOnClick == 'body') {
jQuery(document).on('touchend.jBox-' + this.id + ' click.jBox-' + this.id, function(ev) {
if (this.blockBodyClick || (this.options.closeOnClick == 'body' && (ev.target == this.wrapper[0] || this.wrapper.has(ev.target).length)))
return;
this.close({ignoreDelay: true});
}.bind(this));
}
// Positioning events
if (((this.options.adjustPosition && this.options.adjustTracker) || this.options.reposition) && !this.fixed && this.outside) {
var scrollTimer,
scrollTimerTriggered = 0,
scrollTriggerDelay = 150; // Trigger scroll and resize events every 150 ms (set a higher value to improve performance)
// Function to delay positioning event
var positionDelay = function () {
var now = new Date().getTime();
if (!scrollTimer) {
if (now - scrollTimerTriggered > scrollTriggerDelay) {
this.options.reposition && this.position();
this.options.adjustTracker && this._adjustPosition();
scrollTimerTriggered = now;
}
scrollTimer = setTimeout(function() {
scrollTimer = null;
scrollTimerTriggered = new Date().getTime();
this.options.reposition && this.position();
this.options.adjustTracker && this._adjustPosition();
}.bind(this), scrollTriggerDelay);
}
}.bind(this);
// Trigger position events when scrolling
(this.options.adjustTracker && this.options.adjustTracker != 'resize') && jQuery(window).on('scroll.jBox-' + this.id, function(ev) { positionDelay(); }.bind(this));
// Trigger position events when resizing
((this.options.adjustTracker && this.options.adjustTracker != 'scroll') || this.options.reposition) && jQuery(window).on('resize.jBox-' + this.id, function(ev) { positionDelay(); }.bind(this));
}
// Mousemove events
this.options.target == 'mouse' && jQuery('body').on('mousemove.jBox-' + this.id, function(ev) { this._positionMouse(ev); }.bind(this));
};
// Detach document and window events
this._detachEvents = function() {
// Closing event: closeOnEsc
this.options.closeOnEsc && jQuery(document).off('keyup.jBox-' + this.id);
// Closing event: closeOnClick
(this.options.closeOnClick === true || this.options.closeOnClick == 'body') && jQuery(document).off('touchend.jBox-' + this.id + ' click.jBox-' + this.id);
// Positioning events
if ((this.options.adjustPosition && this.options.adjustTracker) || this.options.reposition) {
jQuery(window).off('scroll.jBox-' + this.id);
jQuery(window).off('resize.jBox-' + this.id);
}
// Mousemove events
this.options.target == 'mouse' && jQuery('body').off('mousemove.jBox-' + this.id);
};
// Add overlay
this._addOverlay = function() {
// If the overlay isn't cached, set overlay or create it
if (!this.overlay) {
// Get the overlay and adjust z-Index
this.overlay = jQuery('#jBox-overlay').length ? jQuery('#jBox-overlay').css({zIndex: Math.min(jQuery('#jBox-overlay').css('z-index'), (this.options.zIndex - 1))}) : (jQuery('<div/>', {id: 'jBox-overlay'}).css({display: 'none', opacity: 0, zIndex: (this.options.zIndex - 1)}).appendTo(jQuery('body')));
// Add close button to overlay
(this.options.closeButton == 'overlay' || this.options.closeButton === true) && ((jQuery('#jBox-overlay .jBox-closeButton').length > 0) ? jQuery('#jBox-overlay .jBox-closeButton').on('touchend click', function() { this.isOpen && this.close({ignoreDelay: true}); }.bind(this)) : this.overlay.append(this.closeButton));
// Add closeOnClick: 'overlay' events
(this.options.closeOnClick == 'overlay') && this.overlay.on('touchend click', function() { this.isOpen && this.close({ignoreDelay: true}); }.bind(this));
}
// Add jBox to overlay data
var overlay_data = this.overlay.data('jBox') || {};
overlay_data['jBox-' + this.id] = true;
this.overlay.data('jBox', overlay_data);
// Abort if overlay is shown already
if (this.overlay.css('display') == 'block') return;
// Show overlay
this.options.fade ? (this.overlay.stop() && this.overlay.animate({opacity: 1}, {
queue: false,
duration: this.options.fade,
start: function() { this.overlay.css({display: 'block'}); }.bind(this)
})) : this.overlay.css({display: 'block', opacity: 1});
};
// Remove overlay
this._removeOverlay = function() {
// Abort if no overlay found
if (!this.overlay) return;
// Remove jBox from data
var overlay_data = this.overlay.data('jBox');
delete overlay_data['jBox-' + this.id];
this.overlay.data('jBox', overlay_data);
// Hide overlay if no other jBox needs it
if (jQuery.isEmptyObject(overlay_data)) {
this.options.fade ? (this.overlay.stop() && this.overlay.animate({opacity: 0}, {
queue: false,
duration: this.options.fade,
complete: function() { this.overlay.css({display: 'none'}); }.bind(this)
})) : this.overlay.css({display: 'none', opacity: 0});
}
};
// Generate CSS for animations and append to header
this._generateCSS = function() {
if (this.IE8) return;
// Get open and close animations if none provided
(jQuery.type(this.options.animation) != 'object') && (this.options.animation = {
pulse: {open: 'pulse', close: 'zoomOut'},
zoomIn: {open: 'zoomIn', close: 'zoomIn'},
zoomOut: {open: 'zoomOut', close: 'zoomOut'},
move: {open: 'move', close: 'move'},
slide: {open: 'slide', close: 'slide'},
flip: {open: 'flip', close: 'flip'},
tada: {open: 'tada', close: 'zoomOut'}
}[this.options.animation]);
// Get direction var
this.options.animation.open && (this.options.animation.open = this.options.animation.open.split(':'));
this.options.animation.close && (this.options.animation.close = this.options.animation.close.split(':'));
this.options.animation.openDirection = this.options.animation.open ? this.options.animation.open[1] : null;
this.options.animation.closeDirection = this.options.animation.close ? this.options.animation.close[1] : null;
this.options.animation.open && (this.options.animation.open = this.options.animation.open[0]);
this.options.animation.close && (this.options.animation.close = this.options.animation.close[0]);
// Add 'Open' and 'Close' to animation names
this.options.animation.open && (this.options.animation.open += 'Open');
this.options.animation.close && (this.options.animation.close += 'Close');
// All animations
var animations = {
pulse: {
duration: 350,
css: [['0%', 'scale(1)'], ['50%', 'scale(1.1)'], ['100%', 'scale(1)']]
},
zoomInOpen: {
duration: (this.options.fade || 180),
css: [['0%', 'scale(0.9)'], ['100%', 'scale(1)']]
},
zoomInClose: {
duration: (this.options.fade || 180),
css: [['0%', 'scale(1)'], ['100%', 'scale(0.9)']]
},
zoomOutOpen: {
duration: (this.options.fade || 180),
css: [['0%', 'scale(1.1)'], ['100%', 'scale(1)']]
},
zoomOutClose: {
duration: (this.options.fade || 180),
css: [['0%', 'scale(1)'], ['100%', 'scale(1.1)']]
},
moveOpen: {
duration: (this.options.fade || 180),
positions: {top: {'0%': -12}, right: {'0%': 12}, bottom: {'0%': 12}, left: {'0%': -12}},
css: [['0%', 'translate%XY(%Vpx)'], ['100%', 'translate%XY(0px)']]
},
moveClose: {
duration: (this.options.fade || 180),
timing: 'ease-in',
positions: {top: {'100%': -12}, right: {'100%': 12}, bottom: {'100%': 12}, left: {'100%': -12}},
css: [['0%', 'translate%XY(0px)'], ['100%', 'translate%XY(%Vpx)']]
},
slideOpen: {
duration: 400,
positions: {top: {'0%': -400}, right: {'0%': 400}, bottom: {'0%': 400}, left: {'0%': -400}},
css: [['0%', 'translate%XY(%Vpx)'], ['100%', 'translate%XY(0px)']]
},
slideClose: {
duration: 400,
timing: 'ease-in',
positions: {top: {'100%': -400}, right: {'100%': 400}, bottom: {'100%': 400}, left: {'100%': -400}},
css: [['0%', 'translate%XY(0px)'], ['100%', 'translate%XY(%Vpx)']]
},
flipOpen: {
duration: 600,
css: [['0%', 'perspective(400px) rotateX(90deg)'], ['40%', 'perspective(400px) rotateX(-15deg)'], ['70%', 'perspective(400px) rotateX(15deg)'], ['100%', 'perspective(400px) rotateX(0deg)']]
},
flipClose: {
duration: (this.options.fade || 300),
css: [['0%', 'perspective(400px) rotateX(0deg)'], ['100%', 'perspective(400px) rotateX(90deg)']]
},
tada: {
duration: 800,
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)']]
}
};
// Set Open and Close names for standalone animations
jQuery.each(['pulse', 'tada'], function(index, item) { animations[item + 'Open'] = animations[item + 'Close'] = animations[item]; });
// Function to generate the CSS for the keyframes
var generateKeyframeCSS = function(ev, position) {
// Generate keyframes CSS
keyframe_css = '@' + this.prefix + 'keyframes jBox-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ' {';
jQuery.each(animations[this.options.animation[ev]].css, function(index, item) {
var translate = position ? item[1].replace('%XY', this._getXY(position).toUpperCase()) : item[1];
animations[this.options.animation[ev]].positions && (translate = translate.replace('%V', animations[this.options.animation[ev]].positions[position][item[0]]));
keyframe_css += item[0] + ' {' + this.prefix + 'transform:' + translate + ';}';
}.bind(this));
keyframe_css += '}';
// Generate class CSS
keyframe_css += '.jBox-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ' {';
keyframe_css += this.prefix + 'animation-duration: ' + animations[this.options.animation[ev]].duration + 'ms;';
keyframe_css += this.prefix + 'animation-name: jBox-animation-' + this.options.animation[ev] + '-' + ev + (position ? '-' + position : '') + ';';
keyframe_css += animations[this.options.animation[ev]].timing ? (this.prefix + 'animation-timing-function: ' + animations[this.options.animation[ev]].timing + ';') : '';
keyframe_css += '}';
return keyframe_css;
}.bind(this);
// Generate css for each event and positions
var css = '';
jQuery.each(['open', 'close'], function(index, ev) {
// No CSS needed for closing with no fade
if (!this.options.animation[ev] || !animations[this.options.animation[ev]] || (ev == 'close' && !this.options.fade)) return '';
// Generate CSS
animations[this.options.animation[ev]].positions ?
jQuery.each(['top', 'right', 'bottom', 'left'], function(index2, position) { css += generateKeyframeCSS(ev, position); }) :
css += generateKeyframeCSS(ev);
}.bind(this));
jQuery('<style/>').append(css).appendTo(jQuery('head'));
};
// Block body clicks for 10ms to prevent extra event triggering
this._blockBodyClick = function() {
this.blockBodyClick = true;
setTimeout(function() { this.blockBodyClick = false; }.bind(this), 10);
};
// Add css for animations
this.options.animation && this._generateCSS();
// Animations
this._animate = function(ev) {
if (this.IE8) return;
ev || (ev = this.isOpen ? 'open' : 'close');
// Don't animate when closing with no fade duration
if (!this.options.fade && ev == 'close') return null;
// Get the current position, use opposite if jBox is flipped
var animationDirection = (this.options.animation[ev + 'Direction'] || ((this.align != 'center') ? this.align : this.options.attributes.x));
this.flipped && this._getXY(animationDirection) == (this._getXY(this.align)) && (animationDirection = this._getOpp(animationDirection));
// Add event and position classes
var classnames = 'jBox-animation-' + this.options.animation[ev] + '-' + ev + ' jBox-animation-' + this.options.animation[ev] + '-' + ev + '-' + animationDirection;
this.wrapper.addClass(classnames);
// Get duration of animation
var animationDuration = parseFloat(this.wrapper.css(this.prefix + 'animation-duration')) * 1000;
ev == 'close' && (animationDuration = Math.min(animationDuration, this.options.fade));
// Remove animation classes when animation is finished
setTimeout(function() { this.wrapper.removeClass(classnames); }.bind(this), animationDuration);
};
// Abort animation
this._abortAnimation = function() {
if (this.IE8) return;
// Remove all animation classes
var prefix = 'jBox-animation';
var classes = this.wrapper.attr('class').split(' ').filter(function(c) {
return c.lastIndexOf(prefix, 0) !== 0;
});
this.wrapper.attr('class', classes.join(' '));
};
// Adjust position
this._adjustPosition = function() {
if (!this.options.adjustPosition) return null;
// Reset cached pointer position
if (this.positionAdjusted) {
this.wrapper.css(this.pos);
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);
this.pointer && this.pointer.element.attr('class', 'jBox-pointer jBox-pointer-' + this._getOpp(this.outside)).css(this.pointer.margin);
this.positionAdjusted = false;
this.flipped = false;
}
// Get the window dimensions
var win = jQuery(window);
var windowDimensions = {
x: win.width(),
y: win.height(),
top: (this.options.fixed && this.target.data('jBox-fixed') ? 0 : win.scrollTop()),
left: (this.options.fixed && this.target.data('jBox-fixed') ? 0 : win.scrollLeft())
};
windowDimensions.bottom = windowDimensions.top + windowDimensions.y;
windowDimensions.right = windowDimensions.left + windowDimensions.x;
// Find out where the jBox is out of view area
var outYT = (windowDimensions.top > this.pos.top - (this.options.adjustDistance.top || 0)),
outXR = (windowDimensions.right < this.pos.left + this.dimensions.x + (this.options.adjustDistance.right || 0)),
outYB = (windowDimensions.bottom < this.pos.top + this.dimensions.y + (this.options.adjustDistance.bottom || 0)),
outXL = (windowDimensions.left > this.pos.left - (this.options.adjustDistance.left || 0)),
outX = outXL ? 'left' : (outXR ? 'right' : null),
outY = outYT ? 'top' : (outYB ? 'bottom' : null),
out = outX || outY;
// Stop here if jBox is not out of view area
if (!out) return;
// Flip jBox
if (this.options.adjustPosition != 'move' && (outX == this.outside || outY == this.outside)) {
this.target == 'mouse' && (this.outside = 'right');
// Check if enough space is availible on opposite position
if (((this.outside == 'top' || this.outside == 'left') ?
(windowDimensions[this._getXY(this.outside)] - (this.targetDimensions[this._getTL(this.outside)] - windowDimensions[this._getTL(this.outside)]) - this.targetDimensions[this._getXY(this.outside)]) + this.options.offset[this._getXY(this.outside)] :
(this.targetDimensions[this._getTL(this.outside)] - windowDimensions[this._getTL(this.outside)]) - this.options.offset[this._getXY(this.outside)]
) > this.dimensions[this._getXY(this.outside)] + parseInt(this.options.adjustDistance[this._getOpp(this.outside)])) {
// Adjust wrapper and pointer
this.wrapper.css(this._getTL(this.outside), this.pos[this._getTL(this.outside)] + ((this.dimensions[this._getXY(this.outside)] + (this.options.offset[this._getXY(this.outside)] * (this.outside == 'top' || this.outside == 'left' ? -2 : 2)) + this.targetDimensions[this._getXY(this.outside)]) * (this.outside == 'top' || this.outside == 'left' ? 1 : -1)));
this.pointer && this.wrapper.removeClass('jBox-pointerPosition-' + this.pointer.position).addClass('jBox-pointerPosition-' + this._getOpp(this.pointer.position)).css('padding', 0).css('padding-' + this.outside, this.pointer.dimensions[this._getXY(this.outside)]);
this.pointer && this.pointer.element.attr('class', 'jBox-pointer jBox-pointer-' + this.outside);
this.positionAdjusted = true;
this.flipped = true;
}
}
// Move jBox (only possible with pointer)
var outMove = (this._getXY(this.outside) == 'x') ? outY : outX;
if (this.pointer && this.options.adjustPosition != 'flip' && this._getXY(outMove) == this._getOpp(this._getXY(this.outside))) {
// Get the maximum space we have availible to adjust
if (this.pointer.align == 'center') {
var spaceAvail = (this.dimensions[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));
} else {
var spaceAvail = (outMove == this.pointer.alignAttribute) ?
parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) :
this.dimensions[this._getXY(outMove)] - parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) - this.pointer.dimensions[this._getXY(outMove)];
}
// Get the overlapping space
spaceDiff = (outMove == this._getTL(outMove)) ?
windowDimensions[this._getTL(outMove)] - this.pos[this._getTL(outMove)] + this.options.adjustDistance[outMove] :
(windowDimensions[this._getOpp(this._getTL(outMove))] - this.pos[this._getTL(outMove)] - this.options.adjustDistance[outMove] - this.dimensions[this._getXY(outMove)]) * -1;
// Add overlapping space on left or top window edge
if (outMove == this._getOpp(this._getTL(outMove)) && this.pos[this._getTL(outMove)] - spaceDiff < windowDimensions[this._getTL(outMove)] + this.options.adjustDistance[this._getTL(outMove)]) {
spaceDiff -= windowDimensions[this._getTL(outMove)] + this.options.adjustDistance[this._getTL(outMove)] - (this.pos[this._getTL(outMove)] - spaceDiff);
}
// Only adjust the maximum availible
spaceDiff = Math.min(spaceDiff, spaceAvail);
// Move jBox
if (spaceDiff <= spaceAvail && spaceDiff > 0) {
this.pointer.element.css('margin-' + this.pointer.alignAttribute, parseInt(this.pointer.element.css('margin-' + this.pointer.alignAttribute)) - (spaceDiff * (outMove != this.pointer.alignAttribute ? -1 : 1)));
this.wrapper.css(this._getTL(outMove), this.pos[this._getTL(outMove)] + (spaceDiff * (outMove != this._getTL(outMove) ? -1 : 1)));
this.positionAdjusted = true;
}
}
};
// Fire onInit event
(this.options.onInit.bind(this))();
this.options._onInit && (this.options._onInit.bind(this))();
return this;
};
// Attach jBox to elements
jBox.prototype.attach = function(elements, trigger) {
elements || (elements = jQuery(this.options.attach.selector || this.options.attach));
trigger || (trigger = this.options.trigger);
elements && elements.length && jQuery.each(elements, function(index, el) {
el = jQuery(el);
if (!el.data('jBox-attached-' + this.id)) {
// Remove title attribute and store content on element
(this.options.getContent == 'title' && el.attr('title') != undefined) && el.data('jBox-getContent', el.attr('title')).removeAttr('title');
// Add Element to collection
this.attachedElements || (this.attachedElements = []);
this.attachedElements.push(el[0]);
// Add click or mouseenter event, click events can prevent default as well
el.on(trigger + '.jBox-attach-' + this.id, function(ev) {
// Clear timer
this.timer && clearTimeout(this.timer);
// Block opening when jbox is open and the source element is triggering
if (trigger == 'mouseenter' && this.isOpen && this.source[0] == el[0])
return;
// Only close jBox if you click the current target element, otherwise open at new target
if (this.isOpen && this.source && this.source[0] != el[0]) var forceOpen = true;
// Set new source element
this.source = el;
// Set new target
!this.options.target && (this.target = el);
// Prevent default action on click
trigger == 'click' && this.options.preventDefault && ev.preventDefault();
// Toggle or open jBox
this[trigger == 'click' && !forceOpen ? 'toggle' : 'open']();
}.bind(this));
// Add close event for trigger event mouseenter
(this.options.trigger == 'mouseenter') && el.on('mouseleave', function(ev) {
// If we have set closeOnMouseleave, do not close jBox when leaving attached element and mouse is over jBox
if(!this.options.closeOnMouseleave || !(ev.relatedTarget == this.wrapper[0] || jQuery(ev.relatedTarget).parents('#' + this.id).length)) this.close();
}.bind(this));
el.data('jBox-attached-' + this.id, trigger);
// TODO // TODO TOO CLOSE
// Fire onAttach event
this.options._onAttach && (this.options._onAttach.bind(this))(el);
}
}.bind(this));
return this;
};
// Detach jBox from elements
jBox.prototype.detach = function(elements) {
elements || (elements = this.attachedElements || []);
elements && elements.length && jQuery.each(elements, function(index, el) {
el = jQuery(el);
// Remove events
if (el.data('jBox-attached-' + this.id)) {
el.off(el.data('jBox-attached-' + this.id) + '.jBox-attach-' + this.id);
el.data('jBox-attached-' + this.id, null);
}
// Remove element from collection
this.attachedElements = jQuery.grep(this.attachedElements, function(value) {
return value != el[0];
});
}.bind(this));
return this;
};
// Set title
jBox.prototype.setTitle = function(title, ignore_positioning) {
var wrapperHeight = this.wrapper.height(), wrapperWidth = this.wrapper.width();
if (title == null || title == undefined) return this;
!this.wrapper && this._create();
if (!this.title) {
this.titleContainer = jQuery('<div/>', {'class': 'jBox-title'});
this.title = jQuery('<div/>').appendTo(this.titleContainer);
this.wrapper.addClass('jBox-hasTitle');
if (this.options.closeButton == 'title' || (this.options.closeButton === true && !this.options.overlay)) {
this.wrapper.addClass('jBox-closeButton-title');
this.closeButton.appendTo(this.titleContainer);
}
this.titleContainer.insertBefore(this.content);
}
this.title.html(title);
// Reposition if dimensions changed
!ignore_positioning && this.options.repositionOnContent && (wrapperHeight != this.wrapper.height() || wrapperWidth != this.wrapper.width()) && this.position();
return this;
};
// Set content
jBox.prototype.setContent = function(content, ignore_positioning) {
if (content == null) return this;
// Create jBox if no wrapper found
!this.wrapper && this._create();
// Get the width and height of wrapper, only if they change we need to reposition
var wrapperHeight = this.wrapper.height(), wrapperWidth = this.wrapper.width();
// Get the width and height of body, if they change with new content, adjust accordingly (happens when a hidden scrollbar changes body dimensions)
var bodyHeight = jQuery('body').height(), bodyWidth = jQuery('body').width();
// Extract all appended containers to body
this.content.children('[data-jbox-content-appended]').appendTo('body').css({display: 'none'});
// Set the new content
switch (jQuery.type(content)) {
case 'string': this.content.html(content); break;
case 'object': this.content.html(''); content.attr('data-jbox-content-appended', 1).appendTo(this.content).css({display: 'block'}); break;
}
// Calculate the difference to before the content was set
var adjustOffset = {
x: bodyWidth - jQuery('body').width(),
y: bodyHeight - jQuery('body').height()
};
// Reposition if dimensions changed
!ignore_positioning && this.options.repositionOnContent && (wrapperHeight != this.wrapper.height() || wrapperWidth != this.wrapper.width()) && this.position({adjustOffset: adjustOffset});
return this;
};
// Set new dimensions
jBox.prototype.setDimensions = function(type, val, pos) {
// Create jBox if no wrapper found
!this.wrapper && this._create();
// Default value is 'auto'
val == undefined && (val == 'auto');
// Set CSS of content
this.content.css(type, val);
// Reposition by default
(pos == undefined || pos) && this.position();
};
// Set width or height
jBox.prototype.setWidth = function(val, pos) { this.setDimensions('width', val, pos); };
jBox.prototype.setHeight = function(val, pos) { this.setDimensions('height', val, pos); };
// Position jBox
jBox.prototype.position = function(options) {
options || (options = {});
// Get target
this.target = options.target || this.target || this.options.target || jQuery(window);
// Cache total current dimensions of jBox
this.dimensions = {
x: this.wrapper.outerWidth(),
y: this.wrapper.outerHeight()
};
// Mousemove can't be positioned
if (this.target == 'mouse') return;
// Set percent and margin for centered inside
if (this.options.position.x == 'center' && this.options.position.y == 'center') {
this.wrapper.css({left: '50%', top: '50%', marginLeft: (this.dimensions.x * -0.5 + this.options.offset.x), marginTop: (this.dimensions.y * -0.5 + this.options.offset.y)});
return this;
}
// Total current dimensions of target element
var targetOffset = this.target.offset();
// Add fixed data to target
!this.target.data('jBox-fixed') && this.target.data('jBox-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');
// When the target is fixed and jBox is fixed, remove scroll offset
if (this.target.data('jBox-fixed') == 'fixed' && this.options.fixed) {
targetOffset.top = targetOffset.top - jQuery(window).scrollTop();
targetOffset.left = targetOffset.left - jQuery(window).scrollLeft();
}
// Store target dimensions
this.targetDimensions = {
x: this.target.outerWidth(),
y: this.target.outerHeight(),
top: (targetOffset ? targetOffset.top : 0),
left: (targetOffset ? targetOffset.left : 0)
};
this.pos = {};
// Calculate positions
var setPosition = function(p) {
// Set number positions
if (jQuery.inArray(this.options.position[p], ['top', 'right', 'bottom', 'left', 'center']) == -1) {
this.pos[this.options.attributes[p]] = this.options.position[p];
return;
}
// We have a target, so use 'left' or 'top' as attributes
var a = this.options.attributes[p] = (p == 'x' ? 'left' : 'top');
// Start at target position
this.pos[a] = this.targetDimensions[a];
// Set centered position
if (this.options.position[p] == 'center') {
this.pos[a] += Math.ceil((this.targetDimensions[p] - this.dimensions[p]) / 2);
return;
}
// Move inside
(a != this.options.position[p]) && (this.pos[a] += this.targetDimensions[p] - this.dimensions[p]);
// Move outside
(this.options.outside == p || this.options.outside == 'xy') && (this.pos[a] += this.dimensions[p] * (a != this.options.position[p] ? 1 : -1));
}.bind(this);
// Set position including offset
setPosition('x');
setPosition('y');
// Adjust position depending on pointer align
if (this.options.pointer && jQuery.type(this.options.position.x) != 'number' && jQuery.type(this.options.position.y) != 'number') {
var adjustWrapper = 0;
// Where is the pointer aligned? Add or substract accordingly
switch (this.pointer.align) {
case 'center':
if (this.options.position[this._getOpp(this.options.outside)] != 'center') {
adjustWrapper += (this.dimensions[this._getOpp(this.options.outside)] / 2);
}
break;
default:
switch (this.options.position[this._getOpp(this.options.outside)]) {
case 'center':
adjustWrapper += ((this.dimensions[this._getOpp(this.options.outside)] / 2) - (this.pointer.dimensions[this._getOpp(this.options.outside)] / 2)) * (this.pointer.align == this._getTL(this.pointer.align) ? 1 : -1);
break;
default:
adjustWrapper += (this.pointer.align != this.options.position[this._getOpp(this.options.outside)]) ?
// If pointer align is different to position align
(this.dimensions[this._getOpp(this.options.outside)] * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? 1 : -1)) + ((this.pointer.dimensions[this._getOpp(this.options.outside)] / 2) * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? -1 : 1)) :
// If pointer align is same as position align
(this.pointer.dimensions[this._getOpp(this.options.outside)] / 2) * (jQuery.inArray(this.pointer.align, ['top', 'left']) !== -1 ? 1 : -1);
break;
}
break;
}
adjustWrapper *= (this.options.position[this._getOpp(this.options.outside)] == this.pointer.alignAttribute ? -1 : 1);
adjustWrapper += this.pointer.offset * (this.pointer.align == this._getOpp(this._getTL(this.pointer.align)) ? 1 : -1);
this.pos[this._getTL(this._getOpp(this.pointer.xy))] += adjustWrapper;
}
// Add adjustments
options.adjustOffset && options.adjustOffset.x && (this.pos[this.options.attributes.x] += parseInt(options.adjustOffset.x) * (this.options.attributes.x == 'left' ? 1 : -1));
options.adjustOffset && options.adjustOffset.y && (this.pos[this.options.attributes.y] += parseInt(options.adjustOffset.y) * (this.options.attributes.y == 'top' ? 1 : -1));
// Add final offset
this.pos[this.options.attributes.x] += this.options.offset.x;
this.pos[this.options.attributes.y] += this.options.offset.y;
// Set CSS
this.wrapper.css(this.pos);
// Adjust position
this._adjustPosition();
return this;
};
// Open jBox
jBox.prototype.open = function(options) {
options || (options = {});
// Abort if jBox was destroyed
if (this.isDestroyed) return false;
// Construct jBox if not already constructed
!this.wrapper && this._create();
// Abort any opening or closing timer
this.timer && clearTimeout(this.timer);
// Block body click for 10ms, so jBox can open on attached elements while closeOnClick = 'body'
this._blockBodyClick();
// Block opening
if (this.isDisabled) return this;
// Opening function
var open = function() {
// Set title from source element
this.source && this.options.getTitle && (this.source.attr(this.options.getTitle) && this.setTitle(this.source.attr(this.options.getTitle)), true);
// Set content from source element
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) : null));
// Fire onOpen event
(this.options.onOpen.bind(this))();
this.options._onOpen && (this.options._onOpen.bind(this))();
// Get content from ajax
((this.options.ajax && this.options.ajax.url && (!this.ajaxLoaded || this.options.ajax.reload)) || (options.ajax && options.ajax.url)) && this.ajax(options.ajax || null);
// Set position
(!this.positionedOnOpen || this.options.repositionOnOpen) && this.position({target: options.target}) && (this.positionedOnOpen = true);
// Abort closing
this.isClosing && this._abortAnimation();
// Open functions to call when jBox is closed
if (!this.isOpen) {
// jBox is open now
this.isOpen = true;
// Attach events
this._attachEvents();
// Block scrolling
this.options.blockScroll && jQuery('body').addClass('jBox-blockScroll-' + this.id);
// Add overlay
this.options.overlay && this._addOverlay();
// Only animate if jBox is compleately closed
this.options.animation && !this.isClosing && this._animate('open');
// Fading animation or show immediately
if (this.options.fade) {
this.wrapper.stop().animate({opacity: 1}, {
queue: false,
duration: this.options.fade,
start: function() {
this.isOpening = true;
this.wrapper.css({display: 'block'});
}.bind(this),
always: function() {
this.isOpening = false;
}.bind(this)
});
} else {
this.wrapper.css({display: 'block', opacity: 1});
}
}
}.bind(this);
// Open jBox
this.options.delayOpen && !this.isOpen && !this.isClosing && !options.ignoreDelay ? (this.timer = setTimeout(open, this.options.delayOpen)) : open();
return this;
};
// Close jBox
jBox.prototype.close = function(options) {
options || (options = {});
// Abort if jBox was destroyed
if (this.isDestroyed) return false;
// Abort opening
this.timer && clearTimeout(this.timer);
// Block body click for 10ms, so jBox can open on attached elements while closeOnClock = 'body' is true
this._blockBodyClick();
// Block closing
if (this.isDisabled) return this;
// Close function
var close = function() {
// Fire onClose event
(this.options.onClose.bind(this))();
this.options._onClose && (this.options._onClose.bind(this))();
// Only close if jBox is open
if (this.isOpen) {
// jBox is not open anymore
this.isOpen = false;
// Detach events
this._detachEvents();
// Unblock scrolling
this.options.blockScroll && jQuery('body').removeClass('jBox-blockScroll-' + this.id);
// Remove overlay
this.options.overlay && this._removeOverlay();
// Only animate if jBox is compleately closed
this.options.animation && !this.isOpening && this._animate('close');
// Fading animation or show immediately
if (this.options.fade) {
this.wrapper.stop().animate({opacity: 0}, {
queue: false,
duration: this.options.fade,
start: function() {
this.isClosing = true;
}.bind(this),
complete: function() {
this.wrapper.css({display: 'none'});
this.options.onCloseComplete && (this.options.onCloseComplete.bind(this))();
this.options._onCloseComplete && (this.options._onCloseComplete.bind(this))();
}.bind(this),
always: function() {
this.isClosing = false;
}.bind(this)
});
} else {
this.wrapper.css({display: 'none', opacity: 0});
this.options._onCloseComplete && (this.options._onCloseComplete.bind(this))();
}
}
}.bind(this);
// Close jBox
options.ignoreDelay ? close() : (this.timer = setTimeout(close, Math.max(this.options.delayClose, 10)));
return this;
};
// Open or close jBox
jBox.prototype.toggle = function(options) {
this[this.isOpen ? 'close' : 'open'](options);
return this;
};
// Block opening and closing
jBox.prototype.disable = function() {
this.isDisabled = true;
return this;
};
// Unblock opening and closing
jBox.prototype.enable = function() {
this.isDisabled = false;
return this;
};
// Get content from ajax
jBox.prototype.ajax = function(options) {
options || (options = {});
// Add data from source element if none set in options
(this.options.ajax.getData && !options.data && this.source && this.source.attr(this.options.ajax.getData) != undefined) && (options.data = this.source.attr(this.options.ajax.getData) || '');
// Clone the system options
var sysOptions = jQuery.extend(true, {}, this.options.ajax);
// Abort running ajax call
this.ajaxRequest && this.ajaxRequest.abort();
// Extract events
var beforeSend = options.beforeSend || sysOptions.beforeSend || function () {};
var complete = options.complete || sysOptions.complete || function () {};
// Merge options
var userOptions = jQuery.extend(true, sysOptions, options);
// Set new beforeSend event
userOptions.beforeSend = function () {
// Add loading spinner
if (userOptions.spinner) {
this.wrapper.addClass('jBox-loading');
this.spinner = jQuery(userOptions.spinner !== true ? userOptions.spinner : '<div class="jBox-spinner"></div>').appendTo(this.container);
}
(beforeSend.bind(this))();
}.bind(this);
// Set new complete event
userOptions.complete = function (response) {
// Remove spinner
this.wrapper.removeClass('jBox-loading');
this.spinner && this.spinner.remove();
// Set new content
userOptions.setContent && this.setContent(response.responseText);
this.ajaxLoaded = true;
(complete.bind(this))(response);
}.bind(this);
// Send new ajax request
this.ajaxRequest = jQuery.ajax(userOptions);
return this;
};
// Play an audio file
jBox.prototype.audio = function(options) {
options || (options = {});
jBox._audio || (jBox._audio = {});
// URL required, no IE8 support
if (!options.url || this.IE8) return this;
// Create audio if it doesn't exist
if (!jBox._audio[options.url]) {
var audio = jQuery('<audio/>');
jQuery('<source/>', {src: options.url + '.mp3'}).appendTo(audio);
jQuery('<source/>', {src: options.url + '.ogg'}).appendTo(audio);
jBox._audio[options.url] = audio[0];
}
// Set volume and play audio
jBox._audio[options.url].volume = Math.min((options.volume != undefined ? options.volume : (this.options.volume != undefined ? this.options.volume : 100) / 100), 1);
jBox._audio[options.url].pause();
try { jBox._audio[options.url].currentTime = 0; } catch (e) {}
jBox._audio[options.url].play();
return this;
};
// Destroy jBox and remove it from DOM
// TODO: If no other jBox needs an overlay remove it as well
jBox.prototype.destroy = function() {
this.detach().close({ignoreDelay: true});
this.wrapper && this.wrapper.remove();
this.isDestroyed = true;
return this;
};
// TODO: Find an option to preload audio files
// Get a unique ID for jBoxes
jBox._getUniqueID = (function () {
var i = 1;
return function () {
return i++;
};
}());
// Make jBox usable with jQuery selectors
jQuery.fn.jBox = function(type, options) {
type || (type = {});
options || (options = {});
return new jBox(type, jQuery.extend(options, {attach: this}));
};
// Add the .bind() function for IE 8 support
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); };
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
function jBox(type,options){this.options={id:null,width:"auto",height:"auto",minWidth:null,maxHeight:null,minWidth:null,maxHeight:null,attach:null,trigger:"click",preventDefault:!1,title:null,content:null,getTitle:null,getContent:null,ajax:{url:null,data:"",reload:!1,getData:"data-ajax",setContent:!0,spinner:!0},target:null,position:{x:"center",y:"center"},outside:null,offset:0,attributes:{x:"left",y:"top"},adjustPosition:!1,adjustTracker:!1,adjustDistance:5,fixed:!1,reposition:!1,repositionOnOpen:!0,repositionOnContent:!0,pointer:!1,pointTo:"target",fade:180,animation:null,theme:"Default",addClass:"",overlay:!1,zIndex:1e4,delayOpen:0,delayClose:0,closeOnEsc:!1,closeOnClick:!1,closeOnMouseleave:!1,closeButton:!1,constructOnInit:!1,blockScroll:!1,appendTo:jQuery("body"),draggable:null,dragOver:!0,onInit:function(){},onCreated:function(){},onOpen:function(){},onClose:function(){},onCloseComplete:function(){},confirmButton:"Submit",cancelButton:"Cancel",confirm:null,cancel:null,autoClose:7e3,color:null,stack:!0,audio:!1,volume:100,src:"href",gallery:"data-jbox-image",imageLabel:"title",imageFade:600,imageSize:"contain"},this.defaultOptions={Tooltip:{getContent:"title",trigger:"mouseenter",position:{x:"center",y:"top"},outside:"y",pointer:!0,adjustPosition:!0,reposition:!0},Mouse:{target:"mouse",position:{x:"right",y:"bottom"},offset:15,trigger:"mouseenter",adjustPosition:"flip"},Modal:{target:jQuery(window),fixed:!0,blockScroll:!0,closeOnEsc:!0,closeOnClick:"overlay",closeButton:!0,overlay:!0,animation:"zoomOut"},Confirm:{target:jQuery(window),fixed:!0,attach:jQuery("[data-confirm]"),getContent:"data-confirm",content:"Do you really want to do this?",minWidth:320,maxWidth:460,blockScroll:!0,closeOnEsc:!0,closeOnClick:"overlay",closeButton:!0,overlay:!0,animation:"zoomOut",preventDefault:!0,_onAttach:function(t){if(!this.options.confirm){var i=t.attr("onclick")?t.attr("onclick"):t.attr("href")?t.attr("target")?'window.open("'+t.attr("href")+'", "'+t.attr("target")+'");':'window.location.href = "'+t.attr("href")+'";':"";t.prop("onclick",null).data("jBox-Confirm-submit",i)}},_onCreated:function(){this.footer=jQuery('<div class="jBox-Confirm-footer"/>'),jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-cancel"/>').html(this.options.cancelButton).click(function(){this.options.cancel&&this.options.cancel(),this.close()}.bind(this)).appendTo(this.footer),this.submitButton=jQuery('<div class="jBox-Confirm-button jBox-Confirm-button-submit"/>').html(this.options.confirmButton).appendTo(this.footer),this.footer.appendTo(this.container)},_onOpen:function(){this.submitButton.off("click.jBox-Confirm"+this.id).on("click.jBox-Confirm"+this.id,function(){this.options.confirm?this.options.confirm():eval(this.source.data("jBox-Confirm-submit")),this.close()}.bind(this))}},Notice:{target:jQuery(window),fixed:!0,position:{x:20,y:20},attributes:{x:"right",y:"top"},animation:"zoomIn",closeOnClick:"box",_onInit:function(){this.open(),this.options.delayClose=this.options.autoClose,this.options.delayClose&&this.close()},_onCreated:function(){this.options.color&&this.wrapper.addClass("jBox-Notice-color jBox-Notice-"+this.options.color),this.wrapper.data("jBox-Notice-position",this.options.attributes.x+"-"+this.options.attributes.y)},_onOpen:function(){jQuery.each(jQuery(".jBox-Notice"),function(t,i){return i=jQuery(i),i.attr("id")!=this.id&&i.data("jBox-Notice-position")==this.options.attributes.x+"-"+this.options.attributes.y?this.options.stack?void i.css("margin-"+this.options.attributes.y,parseInt(i.css("margin-"+this.options.attributes.y))+this.wrapper.outerHeight()+10):void i.data("jBox").close({ignoreDelay:!0}):void 0}.bind(this)),this.options.audio&&this.audio({url:this.options.audio,valume:this.options.volume})},_onCloseComplete:function(){this.destroy()}},Image:{target:jQuery(window),fixed:!0,blockScroll:!0,closeOnEsc:!0,closeOnClick:"overlay",closeButton:!0,overlay:!0,animation:"zoomOut",width:800,height:533,attach:jQuery("[data-jbox-image]"),preventDefault:!0,_onInit:function(){this.images=this.currentImage={},this.imageZIndex=1,this.attachedElements&&jQuery.each(this.attachedElements,function(t,i){if(i=jQuery(i),!i.data("jBox-image-gallery")){var s=i.attr(this.options.gallery)||"default";!this.images[s]&&(this.images[s]=[]),this.images[s].push({src:i.attr(this.options.src),label:i.attr(this.options.imageLabel)||""}),"title"==this.options.imageLabel&&i.removeAttr("title"),i.data("jBox-image-gallery",s),i.data("jBox-image-id",this.images[s].length-1)}}.bind(this));var t=function(t,i,s,o){if(!jQuery("#jBox-image-"+t+"-"+i).length){{var e=jQuery("<div/>",{id:"jBox-image-"+t+"-"+i,"class":"jBox-image-container"}).css({backgroundImage:"url("+this.images[t][i].src+")",backgroundSize:this.options.imageSize,opacity:o?1:0,zIndex:s?0:this.imageZIndex++}).appendTo(this.content);jQuery("<div/>",{id:"jBox-image-label-"+t+"-"+i,"class":"jBox-image-label"+(o?" active":"")}).html(this.images[t][i].label).appendTo(this.imageLabel)}!o&&!s&&e.animate({opacity:1},this.options.imageFade)}}.bind(this),i=function(t,i){jQuery(".jBox-image-label.active").removeClass("active"),jQuery("#jBox-image-label-"+t+"-"+i).addClass("active")};this.showImage=function(s){if("open"!=s){var o=this.currentImage.gallery,e=this.currentImage.id+(1*("prev"==s)?-1:1);e=e>this.images[o].length-1?0:0>e?this.images[o].length-1:e}else{var o=this.source.data("jBox-image-gallery"),e=this.source.data("jBox-image-id");jQuery(".jBox-image-pointer-prev, .jBox-image-pointer-next").css({display:this.images[o].length>1?"block":"none"})}if(this.currentImage={gallery:o,id:e},jQuery("#jBox-image-"+o+"-"+e).length)jQuery("#jBox-image-"+o+"-"+e).css({zIndex:this.imageZIndex++,opacity:0}).animate({opacity:1},"open"==s?0:this.options.imageFade),i(o,e);else{this.wrapper.addClass("jBox-loading");{jQuery('<img src="'+this.images[o][e].src+'">').load(function(){t(o,e,!1),i(o,e),this.wrapper.removeClass("jBox-loading")}.bind(this))}}var n=e+1;n=n>this.images[o].length-1?0:0>n?this.images[o].length-1:n,!jQuery("#jBox-image-"+o+"-"+n).length&&jQuery('<img src="'+this.images[o][n].src+'">').load(function(){t(o,n,!0)})}},_onCreated:function(){this.imageLabel=jQuery("<div/>",{id:"jBox-image-label"}).appendTo(this.wrapper),this.wrapper.append(jQuery("<div/>",{"class":"jBox-image-pointer-prev",click:function(){this.showImage("prev")}.bind(this)})).append(jQuery("<div/>",{"class":"jBox-image-pointer-next",click:function(){this.showImage("next")}.bind(this)}))},_onOpen:function(){jQuery("body").addClass("jBox-image-open"),jQuery(document).on("keyup.jBox-"+this.id,function(t){37==t.keyCode&&this.showImage("prev"),39==t.keyCode&&this.showImage("next")}.bind(this)),this.showImage("open")},_onClose:function(){jQuery("body").removeClass("jBox-image-open"),jQuery(document).off("keyup.jBox-"+this.id)},_onCloseComplete:function(){this.wrapper.find(".jBox-image-container").css("opacity",0)}}},"string"==jQuery.type(type)&&(this.type=type,type=this.defaultOptions[type]),this.options=jQuery.extend(!0,this.options,type,options),null===this.options.id&&(this.options.id="jBoxID"+jBox._getUniqueID()),this.id=this.options.id,("center"==this.options.position.x&&"x"==this.options.outside||"center"==this.options.position.y&&"y"==this.options.outside)&&(this.options.outside=!1),(!this.options.outside||"xy"==this.options.outside)&&(this.options.pointer=!1),"object"!=jQuery.type(this.options.offset)&&(this.options.offset={x:this.options.offset,y:this.options.offset}),this.options.offset.x||(this.options.offset.x=0),this.options.offset.y||(this.options.offset.y=0),this.options.adjustDistance="object"!=jQuery.type(this.options.adjustDistance)?{top:this.options.adjustDistance,right:this.options.adjustDistance,bottom:this.options.adjustDistance,left:this.options.adjustDistance}:jQuery.extend({top:5,left:5,right:5,bottom:5},this.options.adjustDistance),this.align=this.options.outside&&"xy"!=this.options.outside?this.options.position[this.options.outside]:"center"!=this.options.position.y&&"number"!=jQuery.type(this.options.position.y)?this.options.position.x:"center"!=this.options.position.x&&"number"!=jQuery.type(this.options.position.x)?this.options.position.y:this.options.attributes.x,this.options.outside&&"xy"!=this.options.outside&&(this.outside=this.options.position[this.options.outside]);var userAgent=navigator.userAgent.toLowerCase();return this.IE8=-1!=userAgent.indexOf("msie")&&8==parseInt(userAgent.split("msie")[1]),this.prefix=-1!=userAgent.indexOf("webkit")?"-webkit-":"",this._getOpp=function(t){return{left:"right",right:"left",top:"bottom",bottom:"top",x:"y",y:"x"}[t]},this._getXY=function(t){return{left:"x",right:"x",top:"y",bottom:"y",center:"x"}[t]},this._getTL=function(t){return{left:"left",right:"left",top:"top",bottom:"top",center:"left",x:"left",y:"top"}[t]},this._supportsSVG=function(){return document.createElement("svg").getAttributeNS},this._createSVG=function(t,i){var s=document.createElementNS("http://www.w3.org/2000/svg",t);return jQuery.each(i,function(t,i){s.setAttribute(i[0],i[1]||"")}),s},this._appendSVG=function(t,i){return i.appendChild(t)},this._create=function(){if(!this.wrapper){if(this.wrapper=jQuery("<div/>",{id:this.id,"class":"jBox-wrapper"+(this.type?" jBox-"+this.type:"")+(this.options.theme?" jBox-"+this.options.theme:"")+(this.options.addClass?" "+this.options.addClass:"")+(this.IE8?" jBox-IE8":"")}).css({position:this.options.fixed?"fixed":"absolute",display:"none",opacity:0,zIndex:this.options.zIndex}).data("jBox",this),this.options.closeOnMouseleave&&this.wrapper.mouseleave(function(t){!this.source||!(t.relatedTarget==this.source[0]||-1!==jQuery.inArray(this.source[0],jQuery(t.relatedTarget).parents("*")))&&this.close()}.bind(this)),"box"==this.options.closeOnClick&&this.wrapper.on("touchend click",function(){this.close({ignoreDelay:!0})}.bind(this)),this.container=jQuery("<div/>",{"class":"jBox-container"}).appendTo(this.wrapper),this.content=jQuery("<div/>",{"class":"jBox-content"}).css({width:this.options.width,height:this.options.height,minWidth:this.options.minWidth,minHeight:this.options.minHeight,maxWidth:this.options.maxWidth,maxHeight:this.options.maxHeight}).appendTo(this.container),this.options.closeButton){if(this.closeButton=jQuery("<div/>",{"class":"jBox-closeButton jBox-noDrag"}).on("touchend click",function(){this.isOpen&&this.close({ignoreDelay:!0})}.bind(this)),this._supportsSVG()){var t=this._createSVG("svg",[["viewBox","0 0 24 24"]]);this._appendSVG(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"]]),t),this.closeButton.append(t)}else this.wrapper.addClass("jBox-nosvg");("box"==this.options.closeButton||this.options.closeButton===!0&&!this.options.overlay&&!this.options.title)&&(this.wrapper.addClass("jBox-closeButton-box"),this.closeButton.appendTo(this.container))}if(this.wrapper.appendTo(this.options.appendTo),this.options.pointer){if(this.pointer={position:"target"!=this.options.pointTo?this.options.pointTo:this._getOpp(this.outside),xy:this._getXY("target"!=this.options.pointTo?this.options.pointTo:this.outside),align:"center",offset:0},this.pointer.element=jQuery("<div/>",{"class":"jBox-pointer jBox-pointer-"+this.pointer.position}).appendTo(this.wrapper),this.pointer.dimensions={x:this.pointer.element.outerWidth(),y:this.pointer.element.outerHeight()},"string"==jQuery.type(this.options.pointer)){var i=this.options.pointer.split(":");i[0]&&(this.pointer.align=i[0]),i[1]&&(this.pointer.offset=parseInt(i[1]))}this.pointer.alignAttribute="x"==this.pointer.xy?"bottom"==this.pointer.align?"bottom":"top":"right"==this.pointer.align?"right":"left",this.wrapper.css("padding-"+this.pointer.position,this.pointer.dimensions[this.pointer.xy]),this.pointer.element.css(this.pointer.alignAttribute,"center"==this.pointer.align?"50%":0).css("margin-"+this.pointer.alignAttribute,this.pointer.offset),this.pointer.margin={},this.pointer.margin["margin-"+this.pointer.alignAttribute]=this.pointer.offset,"center"==this.pointer.align&&this.pointer.element.css(this.prefix+"transform","translate("+("y"==this.pointer.xy?this.pointer.dimensions.x*-.5+"px":0)+", "+("x"==this.pointer.xy?this.pointer.dimensions.y*-.5+"px":0)+")"),this.pointer.element.css("x"==this.pointer.xy?"width":"height",parseInt(this.pointer.dimensions[this.pointer.xy])+parseInt(this.container.css("border-"+this.pointer.alignAttribute+"-width"))),this.wrapper.addClass("jBox-pointerPosition-"+this.pointer.position)}if(this.setContent(this.options.content,!0),this.setTitle(this.options.title,!0),this.options.draggable){var s="title"==this.options.draggable?this.titleContainer:this.options.draggable.length>0?this.options.draggable:this.options.draggable.selector?jQuery(this.options.draggable.selector):this.wrapper;s.addClass("jBox-draggable").on("mousedown",function(t){if(2!=t.button&&!jQuery(t.target).hasClass("jBox-noDrag")&&!jQuery(t.target).parents(".jBox-noDrag").length){this.options.dragOver&&this.wrapper.css("zIndex")<=jBox.zIndexMax&&(jBox.zIndexMax+=1,this.wrapper.css("zIndex",jBox.zIndexMax));var i=this.wrapper.outerHeight(),s=this.wrapper.outerWidth(),o=this.wrapper.offset().top+i-t.pageY,e=this.wrapper.offset().left+s-t.pageX;jQuery(document).on("mousemove.jBox-draggable-"+this.id,function(t){this.wrapper.offset({top:t.pageY+o-i,left:t.pageX+e-s})}.bind(this)),t.preventDefault()}}.bind(this)).on("mouseup",function(){jQuery(document).off("mousemove.jBox-draggable-"+this.id)}.bind(this)),jBox.zIndexMax=jBox.zIndexMax?Math.max(jBox.zIndexMax,this.options.zIndex):this.options.zIndex}this.options.onCreated.bind(this)(),this.options._onCreated&&this.options._onCreated.bind(this)()}},this.options.constructOnInit&&this._create(),this.options.attach&&this.attach(),this._positionMouse=function(t){this.pos={left:t.pageX,top:t.pageY};var i=function(t,i){return"center"==this.options.position[i]?void(this.pos[t]-=Math.ceil(this.dimensions[i]/2)):(this.pos[t]+=t==this.options.position[i]?-1*this.dimensions[i]-this.options.offset[i]:this.options.offset[i],this.pos[t])}.bind(this);this.wrapper.css({left:i("left","x"),top:i("top","y")}),this.targetDimensions={x:0,y:0,left:t.pageX,top:t.pageY},this._adjustPosition()},this._attachEvents=function(){if(this.options.closeOnEsc&&jQuery(document).on("keyup.jBox-"+this.id,function(t){27==t.keyCode&&this.close({ignoreDelay:!0})}.bind(this)),(this.options.closeOnClick===!0||"body"==this.options.closeOnClick)&&jQuery(document).on("touchend.jBox-"+this.id+" click.jBox-"+this.id,function(t){this.blockBodyClick||"body"==this.options.closeOnClick&&(t.target==this.wrapper[0]||this.wrapper.has(t.target).length)||this.close({ignoreDelay:!0})}.bind(this)),(this.options.adjustPosition&&this.options.adjustTracker||this.options.reposition)&&!this.fixed&&this.outside){var t,i=0,s=150,o=function(){var o=(new Date).getTime();t||(o-i>s&&(this.options.reposition&&this.position(),this.options.adjustTracker&&this._adjustPosition(),i=o),t=setTimeout(function(){t=null,i=(new Date).getTime(),this.options.reposition&&this.position(),this.options.adjustTracker&&this._adjustPosition()}.bind(this),s))}.bind(this);this.options.adjustTracker&&"resize"!=this.options.adjustTracker&&jQuery(window).on("scroll.jBox-"+this.id,function(){o()}.bind(this)),(this.options.adjustTracker&&"scroll"!=this.options.adjustTracker||this.options.reposition)&&jQuery(window).on("resize.jBox-"+this.id,function(){o()}.bind(this))}"mouse"==this.options.target&&jQuery("body").on("mousemove.jBox-"+this.id,function(t){this._positionMouse(t)}.bind(this))},this._detachEvents=function(){this.options.closeOnEsc&&jQuery(document).off("keyup.jBox-"+this.id),(this.options.closeOnClick===!0||"body"==this.options.closeOnClick)&&jQuery(document).off("touchend.jBox-"+this.id+" click.jBox-"+this.id),(this.options.adjustPosition&&this.options.adjustTracker||this.options.reposition)&&(jQuery(window).off("scroll.jBox-"+this.id),jQuery(window).off("resize.jBox-"+this.id)),"mouse"==this.options.target&&jQuery("body").off("mousemove.jBox-"+this.id)},this._addOverlay=function(){this.overlay||(this.overlay=jQuery("#jBox-overlay").length?jQuery("#jBox-overlay").css({zIndex:Math.min(jQuery("#jBox-overlay").css("z-index"),this.options.zIndex-1)}):jQuery("<div/>",{id:"jBox-overlay"}).css({display:"none",opacity:0,zIndex:this.options.zIndex-1}).appendTo(jQuery("body")),("overlay"==this.options.closeButton||this.options.closeButton===!0)&&(jQuery("#jBox-overlay .jBox-closeButton").length>0?jQuery("#jBox-overlay .jBox-closeButton").on("touchend click",function(){this.isOpen&&this.close({ignoreDelay:!0})}.bind(this)):this.overlay.append(this.closeButton)),"overlay"==this.options.closeOnClick&&this.overlay.on("touchend click",function(){this.isOpen&&this.close({ignoreDelay:!0})}.bind(this)));var t=this.overlay.data("jBox")||{};t["jBox-"+this.id]=!0,this.overlay.data("jBox",t),"block"!=this.overlay.css("display")&&(this.options.fade?this.overlay.stop()&&this.overlay.animate({opacity:1},{queue:!1,duration:this.options.fade,start:function(){this.overlay.css({display:"block"})}.bind(this)}):this.overlay.css({display:"block",opacity:1}))},this._removeOverlay=function(){if(this.overlay){var t=this.overlay.data("jBox");delete t["jBox-"+this.id],this.overlay.data("jBox",t),jQuery.isEmptyObject(t)&&(this.options.fade?this.overlay.stop()&&this.overlay.animate({opacity:0},{queue:!1,duration:this.options.fade,complete:function(){this.overlay.css({display:"none"})}.bind(this)}):this.overlay.css({display:"none",opacity:0}))}},this._generateCSS=function(){if(!this.IE8){"object"!=jQuery.type(this.options.animation)&&(this.options.animation={pulse:{open:"pulse",close:"zoomOut"},zoomIn:{open:"zoomIn",close:"zoomIn"},zoomOut:{open:"zoomOut",close:"zoomOut"},move:{open:"move",close:"move"},slide:{open:"slide",close:"slide"},flip:{open:"flip",close:"flip"},tada:{open:"tada",close:"zoomOut"}}[this.options.animation]),this.options.animation.open&&(this.options.animation.open=this.options.animation.open.split(":")),this.options.animation.close&&(this.options.animation.close=this.options.animation.close.split(":")),this.options.animation.openDirection=this.options.animation.open?this.options.animation.open[1]:null,this.options.animation.closeDirection=this.options.animation.close?this.options.animation.close[1]:null,this.options.animation.open&&(this.options.animation.open=this.options.animation.open[0]),this.options.animation.close&&(this.options.animation.close=this.options.animation.close[0]),this.options.animation.open&&(this.options.animation.open+="Open"),this.options.animation.close&&(this.options.animation.close+="Close");var t={pulse:{duration:350,css:[["0%","scale(1)"],["50%","scale(1.1)"],["100%","scale(1)"]]},zoomInOpen:{duration:this.options.fade||180,css:[["0%","scale(0.9)"],["100%","scale(1)"]]},zoomInClose:{duration:this.options.fade||180,css:[["0%","scale(1)"],["100%","scale(0.9)"]]},zoomOutOpen:{duration:this.options.fade||180,css:[["0%","scale(1.1)"],["100%","scale(1)"]]},zoomOutClose:{duration:this.options.fade||180,css:[["0%","scale(1)"],["100%","scale(1.1)"]]},moveOpen:{duration:this.options.fade||180,positions:{top:{"0%":-12},right:{"0%":12},bottom:{"0%":12},left:{"0%":-12}},css:[["0%","translate%XY(%Vpx)"],["100%","translate%XY(0px)"]]},moveClose:{duration:this.options.fade||180,timing:"ease-in",positions:{top:{"100%":-12},right:{"100%":12},bottom:{"100%":12},left:{"100%":-12}},css:[["0%","translate%XY(0px)"],["100%","translate%XY(%Vpx)"]]},slideOpen:{duration:400,positions:{top:{"0%":-400},right:{"0%":400},bottom:{"0%":400},left:{"0%":-400}},css:[["0%","translate%XY(%Vpx)"],["100%","translate%XY(0px)"]]},slideClose:{duration:400,timing:"ease-in",positions:{top:{"100%":-400},right:{"100%":400},bottom:{"100%":400},left:{"100%":-400}},css:[["0%","translate%XY(0px)"],["100%","translate%XY(%Vpx)"]]},flipOpen:{duration:600,css:[["0%","perspective(400px) rotateX(90deg)"],["40%","perspective(400px) rotateX(-15deg)"],["70%","perspective(400px) rotateX(15deg)"],["100%","perspective(400px) rotateX(0deg)"]]},flipClose:{duration:this.options.fade||300,css:[["0%","perspective(400px) rotateX(0deg)"],["100%","perspective(400px) rotateX(90deg)"]]},tada:{duration:800,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)"]]}};jQuery.each(["pulse","tada"],function(i,s){t[s+"Open"]=t[s+"Close"]=t[s]});var i=function(i,s){return keyframe_css="@"+this.prefix+"keyframes jBox-animation-"+this.options.animation[i]+"-"+i+(s?"-"+s:"")+" {",jQuery.each(t[this.options.animation[i]].css,function(o,e){var n=s?e[1].replace("%XY",this._getXY(s).toUpperCase()):e[1];t[this.options.animation[i]].positions&&(n=n.replace("%V",t[this.options.animation[i]].positions[s][e[0]])),keyframe_css+=e[0]+" {"+this.prefix+"transform:"+n+";}"}.bind(this)),keyframe_css+="}",keyframe_css+=".jBox-animation-"+this.options.animation[i]+"-"+i+(s?"-"+s:"")+" {",keyframe_css+=this.prefix+"animation-duration: "+t[this.options.animation[i]].duration+"ms;",keyframe_css+=this.prefix+"animation-name: jBox-animation-"+this.options.animation[i]+"-"+i+(s?"-"+s:"")+";",keyframe_css+=t[this.options.animation[i]].timing?this.prefix+"animation-timing-function: "+t[this.options.animation[i]].timing+";":"",keyframe_css+="}"}.bind(this),s="";jQuery.each(["open","close"],function(o,e){return this.options.animation[e]&&t[this.options.animation[e]]&&("close"!=e||this.options.fade)?void(t[this.options.animation[e]].positions?jQuery.each(["top","right","bottom","left"],function(t,o){s+=i(e,o)}):s+=i(e)):""}.bind(this)),jQuery("<style/>").append(s).appendTo(jQuery("head"))}},this._blockBodyClick=function(){this.blockBodyClick=!0,setTimeout(function(){this.blockBodyClick=!1}.bind(this),10)},this.options.animation&&this._generateCSS(),this._animate=function(t){if(!this.IE8){if(t||(t=this.isOpen?"open":"close"),!this.options.fade&&"close"==t)return null;var i=this.options.animation[t+"Direction"]||("center"!=this.align?this.align:this.options.attributes.x);this.flipped&&this._getXY(i)==this._getXY(this.align)&&(i=this._getOpp(i));var s="jBox-animation-"+this.options.animation[t]+"-"+t+" jBox-animation-"+this.options.animation[t]+"-"+t+"-"+i;this.wrapper.addClass(s);var o=1e3*parseFloat(this.wrapper.css(this.prefix+"animation-duration"));"close"==t&&(o=Math.min(o,this.options.fade)),setTimeout(function(){this.wrapper.removeClass(s)}.bind(this),o)}},this._abortAnimation=function(){if(!this.IE8){var t="jBox-animation",i=this.wrapper.attr("class").split(" ").filter(function(i){return 0!==i.lastIndexOf(t,0)});this.wrapper.attr("class",i.join(" "))}},this._adjustPosition=function(){if(!this.options.adjustPosition)return null;this.positionAdjusted&&(this.wrapper.css(this.pos),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),this.pointer&&this.pointer.element.attr("class","jBox-pointer jBox-pointer-"+this._getOpp(this.outside)).css(this.pointer.margin),this.positionAdjusted=!1,this.flipped=!1);var t=jQuery(window),i={x:t.width(),y:t.height(),top:this.options.fixed&&this.target.data("jBox-fixed")?0:t.scrollTop(),left:this.options.fixed&&this.target.data("jBox-fixed")?0:t.scrollLeft()};i.bottom=i.top+i.y,i.right=i.left+i.x;var s=i.top>this.pos.top-(this.options.adjustDistance.top||0),o=i.right<this.pos.left+this.dimensions.x+(this.options.adjustDistance.right||0),e=i.bottom<this.pos.top+this.dimensions.y+(this.options.adjustDistance.bottom||0),n=i.left>this.pos.left-(this.options.adjustDistance.left||0),a=n?"left":o?"right":null,h=s?"top":e?"bottom":null,p=a||h;if(p){"move"==this.options.adjustPosition||a!=this.outside&&h!=this.outside||("mouse"==this.target&&(this.outside="right"),("top"==this.outside||"left"==this.outside?i[this._getXY(this.outside)]-(this.targetDimensions[this._getTL(this.outside)]-i[this._getTL(this.outside)])-this.targetDimensions[this._getXY(this.outside)]+this.options.offset[this._getXY(this.outside)]:this.targetDimensions[this._getTL(this.outside)]-i[this._getTL(this.outside)]-this.options.offset[this._getXY(this.outside)])>this.dimensions[this._getXY(this.outside)]+parseInt(this.options.adjustDistance[this._getOpp(this.outside)])&&(this.wrapper.css(this._getTL(this.outside),this.pos[this._getTL(this.outside)]+(this.dimensions[this._getXY(this.outside)]+this.options.offset[this._getXY(this.outside)]*("top"==this.outside||"left"==this.outside?-2:2)+this.targetDimensions[this._getXY(this.outside)])*("top"==this.outside||"left"==this.outside?1:-1)),this.pointer&&this.wrapper.removeClass("jBox-pointerPosition-"+this.pointer.position).addClass("jBox-pointerPosition-"+this._getOpp(this.pointer.position)).css("padding",0).css("padding-"+this.outside,this.pointer.dimensions[this._getXY(this.outside)]),this.pointer&&this.pointer.element.attr("class","jBox-pointer jBox-pointer-"+this.outside),this.positionAdjusted=!0,this.flipped=!0));var r="x"==this._getXY(this.outside)?h:a;if(this.pointer&&"flip"!=this.options.adjustPosition&&this._getXY(r)==this._getOpp(this._getXY(this.outside))){if("center"==this.pointer.align)var l=this.dimensions[this._getXY(r)]/2-this.pointer.dimensions[this._getOpp(this.pointer.xy)]/2-parseInt(this.pointer.element.css("margin-"+this.pointer.alignAttribute))*(r!=this._getTL(r)?-1:1);else var l=r==this.pointer.alignAttribute?parseInt(this.pointer.element.css("margin-"+this.pointer.alignAttribute)):this.dimensions[this._getXY(r)]-parseInt(this.pointer.element.css("margin-"+this.pointer.alignAttribute))-this.pointer.dimensions[this._getXY(r)];spaceDiff=r==this._getTL(r)?i[this._getTL(r)]-this.pos[this._getTL(r)]+this.options.adjustDistance[r]:-1*(i[this._getOpp(this._getTL(r))]-this.pos[this._getTL(r)]-this.options.adjustDistance[r]-this.dimensions[this._getXY(r)]),r==this._getOpp(this._getTL(r))&&this.pos[this._getTL(r)]-spaceDiff<i[this._getTL(r)]+this.options.adjustDistance[this._getTL(r)]&&(spaceDiff-=i[this._getTL(r)]+this.options.adjustDistance[this._getTL(r)]-(this.pos[this._getTL(r)]-spaceDiff)),spaceDiff=Math.min(spaceDiff,l),l>=spaceDiff&&spaceDiff>0&&(this.pointer.element.css("margin-"+this.pointer.alignAttribute,parseInt(this.pointer.element.css("margin-"+this.pointer.alignAttribute))-spaceDiff*(r!=this.pointer.alignAttribute?-1:1)),this.wrapper.css(this._getTL(r),this.pos[this._getTL(r)]+spaceDiff*(r!=this._getTL(r)?-1:1)),this.positionAdjusted=!0)}}},this.options.onInit.bind(this)(),this.options._onInit&&this.options._onInit.bind(this)(),this}jBox.prototype.attach=function(t,i){return t||(t=jQuery(this.options.attach.selector||this.options.attach)),i||(i=this.options.trigger),t&&t.length&&jQuery.each(t,function(t,s){s=jQuery(s),s.data("jBox-attached-"+this.id)||("title"==this.options.getContent&&void 0!=s.attr("title")&&s.data("jBox-getContent",s.attr("title")).removeAttr("title"),this.attachedElements||(this.attachedElements=[]),this.attachedElements.push(s[0]),s.on(i+".jBox-attach-"+this.id,function(t){if(this.timer&&clearTimeout(this.timer),"mouseenter"!=i||!this.isOpen||this.source[0]!=s[0]){if(this.isOpen&&this.source&&this.source[0]!=s[0])var o=!0;this.source=s,!this.options.target&&(this.target=s),"click"==i&&this.options.preventDefault&&t.preventDefault(),this["click"!=i||o?"open":"toggle"]()}}.bind(this)),"mouseenter"==this.options.trigger&&s.on("mouseleave",function(t){(!this.options.closeOnMouseleave||t.relatedTarget!=this.wrapper[0]&&!jQuery(t.relatedTarget).parents("#"+this.id).length)&&this.close()}.bind(this)),s.data("jBox-attached-"+this.id,i),this.options._onAttach&&this.options._onAttach.bind(this)(s))}.bind(this)),this},jBox.prototype.detach=function(t){return t||(t=this.attachedElements||[]),t&&t.length&&jQuery.each(t,function(t,i){i=jQuery(i),i.data("jBox-attached-"+this.id)&&(i.off(i.data("jBox-attached-"+this.id)+".jBox-attach-"+this.id),i.data("jBox-attached-"+this.id,null)),this.attachedElements=jQuery.grep(this.attachedElements,function(t){return t!=i[0]})}.bind(this)),this},jBox.prototype.setTitle=function(t,i){var s=this.wrapper.height(),o=this.wrapper.width();return null==t||void 0==t?this:(!this.wrapper&&this._create(),this.title||(this.titleContainer=jQuery("<div/>",{"class":"jBox-title"}),this.title=jQuery("<div/>").appendTo(this.titleContainer),this.wrapper.addClass("jBox-hasTitle"),("title"==this.options.closeButton||this.options.closeButton===!0&&!this.options.overlay)&&(this.wrapper.addClass("jBox-closeButton-title"),this.closeButton.appendTo(this.titleContainer)),this.titleContainer.insertBefore(this.content)),this.title.html(t),!i&&this.options.repositionOnContent&&(s!=this.wrapper.height()||o!=this.wrapper.width())&&this.position(),this)},jBox.prototype.setContent=function(t,i){if(null==t)return this;!this.wrapper&&this._create();var s=this.wrapper.height(),o=this.wrapper.width(),e=jQuery("body").height(),n=jQuery("body").width();switch(this.content.children("[data-jbox-content-appended]").appendTo("body").css({display:"none"}),jQuery.type(t)){case"string":this.content.html(t);break;case"object":this.content.html(""),t.attr("data-jbox-content-appended",1).appendTo(this.content).css({display:"block"})}var a={x:n-jQuery("body").width(),y:e-jQuery("body").height()};return!i&&this.options.repositionOnContent&&(s!=this.wrapper.height()||o!=this.wrapper.width())&&this.position({adjustOffset:a}),this},jBox.prototype.setDimensions=function(t,i,s){!this.wrapper&&this._create(),this.content.css(t,i),(void 0==s||s)&&this.position()},jBox.prototype.setWidth=function(t,i){this.setDimensions("width",t,i)},jBox.prototype.setHeight=function(t,i){this.setDimensions("height",t,i)},jBox.prototype.position=function(t){if(t||(t={}),this.target=t.target||this.target||this.options.target||jQuery(window),this.dimensions={x:this.wrapper.outerWidth(),y:this.wrapper.outerHeight()},"mouse"!=this.target){if("center"==this.options.position.x&&"center"==this.options.position.y)return this.wrapper.css({left:"50%",top:"50%",marginLeft:this.dimensions.x*-.5+this.options.offset.x,marginTop:this.dimensions.y*-.5+this.options.offset.y}),this;var i=this.target.offset();!this.target.data("jBox-fixed")&&this.target.data("jBox-fixed",this.target[0]==jQuery(window)[0]||"fixed"!=this.target.css("position")&&this.target.parents().filter(function(){return"fixed"==jQuery(this).css("position")}).length<=0?"static":"fixed"),"fixed"==this.target.data("jBox-fixed")&&this.options.fixed&&(i.top=i.top-jQuery(window).scrollTop(),i.left=i.left-jQuery(window).scrollLeft()),this.targetDimensions={x:this.target.outerWidth(),y:this.target.outerHeight(),top:i?i.top:0,left:i?i.left:0},this.pos={};var s=function(t){if(-1==jQuery.inArray(this.options.position[t],["top","right","bottom","left","center"]))return void(this.pos[this.options.attributes[t]]=this.options.position[t]);var i=this.options.attributes[t]="x"==t?"left":"top";return this.pos[i]=this.targetDimensions[i],"center"==this.options.position[t]?void(this.pos[i]+=Math.ceil((this.targetDimensions[t]-this.dimensions[t])/2)):(i!=this.options.position[t]&&(this.pos[i]+=this.targetDimensions[t]-this.dimensions[t]),void((this.options.outside==t||"xy"==this.options.outside)&&(this.pos[i]+=this.dimensions[t]*(i!=this.options.position[t]?1:-1))))}.bind(this);if(s("x"),s("y"),this.options.pointer&&"number"!=jQuery.type(this.options.position.x)&&"number"!=jQuery.type(this.options.position.y)){var o=0;switch(this.pointer.align){case"center":"center"!=this.options.position[this._getOpp(this.options.outside)]&&(o+=this.dimensions[this._getOpp(this.options.outside)]/2);break;default:switch(this.options.position[this._getOpp(this.options.outside)]){case"center":o+=(this.dimensions[this._getOpp(this.options.outside)]/2-this.pointer.dimensions[this._getOpp(this.options.outside)]/2)*(this.pointer.align==this._getTL(this.pointer.align)?1:-1);
break;default:o+=this.pointer.align!=this.options.position[this._getOpp(this.options.outside)]?this.dimensions[this._getOpp(this.options.outside)]*(-1!==jQuery.inArray(this.pointer.align,["top","left"])?1:-1)+this.pointer.dimensions[this._getOpp(this.options.outside)]/2*(-1!==jQuery.inArray(this.pointer.align,["top","left"])?-1:1):this.pointer.dimensions[this._getOpp(this.options.outside)]/2*(-1!==jQuery.inArray(this.pointer.align,["top","left"])?1:-1)}}o*=this.options.position[this._getOpp(this.options.outside)]==this.pointer.alignAttribute?-1:1,o+=this.pointer.offset*(this.pointer.align==this._getOpp(this._getTL(this.pointer.align))?1:-1),this.pos[this._getTL(this._getOpp(this.pointer.xy))]+=o}return t.adjustOffset&&t.adjustOffset.x&&(this.pos[this.options.attributes.x]+=parseInt(t.adjustOffset.x)*("left"==this.options.attributes.x?1:-1)),t.adjustOffset&&t.adjustOffset.y&&(this.pos[this.options.attributes.y]+=parseInt(t.adjustOffset.y)*("top"==this.options.attributes.y?1:-1)),this.pos[this.options.attributes.x]+=this.options.offset.x,this.pos[this.options.attributes.y]+=this.options.offset.y,this.wrapper.css(this.pos),this._adjustPosition(),this}},jBox.prototype.open=function(t){if(t||(t={}),this.isDestroyed)return!1;if(!this.wrapper&&this._create(),this.timer&&clearTimeout(this.timer),this._blockBodyClick(),this.isDisabled)return this;var i=function(){this.source&&this.options.getTitle&&(this.source.attr(this.options.getTitle)&&this.setTitle(this.source.attr(this.options.getTitle)),!0),this.source&&this.options.getContent&&(this.source.data("jBox-getContent")?this.setContent(this.source.data("jBox-getContent"),!0):this.source.attr(this.options.getContent)?this.setContent(this.source.attr(this.options.getContent),!0):null),this.options.onOpen.bind(this)(),this.options._onOpen&&this.options._onOpen.bind(this)(),(this.options.ajax&&this.options.ajax.url&&(!this.ajaxLoaded||this.options.ajax.reload)||t.ajax&&t.ajax.url)&&this.ajax(t.ajax||null),(!this.positionedOnOpen||this.options.repositionOnOpen)&&this.position({target:t.target})&&(this.positionedOnOpen=!0),this.isClosing&&this._abortAnimation(),this.isOpen||(this.isOpen=!0,this._attachEvents(),this.options.blockScroll&&jQuery("body").addClass("jBox-blockScroll-"+this.id),this.options.overlay&&this._addOverlay(),this.options.animation&&!this.isClosing&&this._animate("open"),this.options.fade?this.wrapper.stop().animate({opacity:1},{queue:!1,duration:this.options.fade,start:function(){this.isOpening=!0,this.wrapper.css({display:"block"})}.bind(this),always:function(){this.isOpening=!1}.bind(this)}):this.wrapper.css({display:"block",opacity:1}))}.bind(this);return!this.options.delayOpen||this.isOpen||this.isClosing||t.ignoreDelay?i():this.timer=setTimeout(i,this.options.delayOpen),this},jBox.prototype.close=function(t){if(t||(t={}),this.isDestroyed)return!1;if(this.timer&&clearTimeout(this.timer),this._blockBodyClick(),this.isDisabled)return this;var i=function(){this.options.onClose.bind(this)(),this.options._onClose&&this.options._onClose.bind(this)(),this.isOpen&&(this.isOpen=!1,this._detachEvents(),this.options.blockScroll&&jQuery("body").removeClass("jBox-blockScroll-"+this.id),this.options.overlay&&this._removeOverlay(),this.options.animation&&!this.isOpening&&this._animate("close"),this.options.fade?this.wrapper.stop().animate({opacity:0},{queue:!1,duration:this.options.fade,start:function(){this.isClosing=!0}.bind(this),complete:function(){this.wrapper.css({display:"none"}),this.options.onCloseComplete&&this.options.onCloseComplete.bind(this)(),this.options._onCloseComplete&&this.options._onCloseComplete.bind(this)()}.bind(this),always:function(){this.isClosing=!1}.bind(this)}):(this.wrapper.css({display:"none",opacity:0}),this.options._onCloseComplete&&this.options._onCloseComplete.bind(this)()))}.bind(this);return t.ignoreDelay?i():this.timer=setTimeout(i,Math.max(this.options.delayClose,10)),this},jBox.prototype.toggle=function(t){return this[this.isOpen?"close":"open"](t),this},jBox.prototype.disable=function(){return this.isDisabled=!0,this},jBox.prototype.enable=function(){return this.isDisabled=!1,this},jBox.prototype.ajax=function(t){t||(t={}),this.options.ajax.getData&&!t.data&&this.source&&void 0!=this.source.attr(this.options.ajax.getData)&&(t.data=this.source.attr(this.options.ajax.getData)||"");var i=jQuery.extend(!0,{},this.options.ajax);this.ajaxRequest&&this.ajaxRequest.abort();var s=t.beforeSend||i.beforeSend||function(){},o=t.complete||i.complete||function(){},e=jQuery.extend(!0,i,t);return e.beforeSend=function(){e.spinner&&(this.wrapper.addClass("jBox-loading"),this.spinner=jQuery(e.spinner!==!0?e.spinner:'<div class="jBox-spinner"></div>').appendTo(this.container)),s.bind(this)()}.bind(this),e.complete=function(t){this.wrapper.removeClass("jBox-loading"),this.spinner&&this.spinner.remove(),e.setContent&&this.setContent(t.responseText),this.ajaxLoaded=!0,o.bind(this)(t)}.bind(this),this.ajaxRequest=jQuery.ajax(e),this},jBox.prototype.audio=function(t){if(t||(t={}),jBox._audio||(jBox._audio={}),!t.url||this.IE8)return this;if(!jBox._audio[t.url]){var i=jQuery("<audio/>");jQuery("<source/>",{src:t.url+".mp3"}).appendTo(i),jQuery("<source/>",{src:t.url+".ogg"}).appendTo(i),jBox._audio[t.url]=i[0]}jBox._audio[t.url].volume=Math.min(void 0!=t.volume?t.volume:(void 0!=this.options.volume?this.options.volume:100)/100,1),jBox._audio[t.url].pause();try{jBox._audio[t.url].currentTime=0}catch(s){}return jBox._audio[t.url].play(),this},jBox.prototype.destroy=function(){return this.detach().close({ignoreDelay:!0}),this.wrapper&&this.wrapper.remove(),this.isDestroyed=!0,this},jBox._getUniqueID=function(){var t=1;return function(){return t++}}(),jQuery.fn.jBox=function(t,i){return t||(t={}),i||(i={}),new jBox(t,jQuery.extend(i,{attach:this}))},Function.prototype.bind||(Function.prototype.bind=function(t){var i=Array.prototype.slice.call(arguments,1),s=this,o=function(){},e=function(){return s.apply(this instanceof o&&t?this:t,i.concat(Array.prototype.slice.call(arguments)))};return o.prototype=this.prototype,e.prototype=new o,e});
/* Wrapper */
.jBox-ModalBorder {
border-radius: 8px;
background: rgba(0, 0, 0, .4);
padding: 8px;
box-shadow: 0 0 6px rgba(0, 0, 0, .2);
}
/* Container */
.jBox-ModalBorder .jBox-container {
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}
/* Close button */
.jBox-ModalBorder.jBox-closeButton-box {
border-top-right-radius: 0;
}
.jBox-ModalBorder.jBox-closeButton-box:before {
display: none;
}
.jBox-ModalBorder.jBox-hasTitle.jBox-closeButton-box .jBox-closeButton,
.jBox-ModalBorder.jBox-closeButton-box .jBox-closeButton {
background: rgba(0, 0, 0, .4);
border-radius: 0 50% 50% 0;
right: -32px;
top: -8px;
}
.jBox-ModalBorder.jBox-closeButton-box .jBox-closeButton path {
fill: #d2d4d6;
}
.jBox-ModalBorder.jBox-closeButton-box .jBox-closeButton:hover path {
fill: #fff;
}
.jBox-ModalBorder.jBox-closeButton-box .jBox-closeButton:active path {
fill: #b2b4b6;
}
\ No newline at end of file
/* jBox: Notice */
.jBox-NoticeBorder .jBox-container {
border-radius: 6px;
}
.jBox-NoticeBorder .jBox-content,
.jBox-NoticeBorder .jBox-title {
padding-left: 26px;
}
.jBox-NoticeBorder.jBox-Notice-color .jBox-container {
color: #fff;
text-shadow: 0 -1px 0 #000;
background: rgba(0, 0, 0, .92);
}
.jBox-NoticeBorder.jBox-Notice-color .jBox-container:after {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 8px;
border-radius: 5px 0 0 5px;
background-image: linear-gradient(45deg, rgba(255, 255, 255, .5) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, .5) 75%, transparent 75%, transparent);
background-size: 18px 18px;
}
.jBox-NoticeBorder.jBox-Notice-red .jBox-container:after {
background-color: #ee0000;
}
.jBox-NoticeBorder.jBox-Notice-green .jBox-container:after {
background-color: #95cc2a;
}
.jBox-NoticeBorder.jBox-Notice-blue .jBox-container:after {
background-color: #4cb4ff;
}
.jBox-NoticeBorder.jBox-Notice-yellow .jBox-container:after {
background-color: #ffba00;
}
\ No newline at end of file
/* Container */
.jBox-TooltipBorder .jBox-container {
border-radius: 5px;
border: 2px solid #52a2cb;
}
/* Pointer */
.jBox-TooltipBorder .jBox-pointer:after {
border: 2px solid #52a2cb;
}
.jBox-TooltipBorder .jBox-pointer-top,
.jBox-TooltipBorder .jBox-pointer-bottom {
width: 34px;
height: 12px;
}
.jBox-TooltipBorder .jBox-pointer-left,
.jBox-TooltipBorder .jBox-pointer-right {
width: 12px;
height: 34px;
}
/* Close button */
.jBox-TooltipBorder.jBox-closeButton-box:before {
width: 28px;
height: 28px;
background: #52a2cb;
}
\ No newline at end of file
/* Container */
.jBox-TooltipDark .jBox-container {
border-radius: 3px;
background: #222;
color: #fff;
box-shadow: 0 0 6px rgba(0, 0, 0, .4);
}
/* Pointer */
.jBox-TooltipDark .jBox-pointer:after {
background: #222;
}
/* Close button */
.jBox-TooltipDark .jBox-closeButton {
background: #222;
}
.jBox-TooltipDark.jBox-closeButton-box:before {
box-shadow: 0 0 6px rgba(0, 0, 0, .4);
}
.jBox-TooltipDark.jBox-closeButton-box .jBox-closeButton path {
fill: #d2d4d6;
}
.jBox-TooltipDark.jBox-closeButton-box .jBox-closeButton:hover path {
fill: #fff;
}
.jBox-TooltipDark.jBox-closeButton-box .jBox-closeButton:active path {
fill: #b2b4b6;
}
\ No newline at end of file
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
version 2.8.1 (Dec, 2016)
Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
(function (factory) {
if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') { // Node/CommonJS
var jQuery = require('jquery');
module.exports = factory(jQuery);
} else { // Browser globals (zepto supported)
factory(window.jQuery || window.Zepto || window.$); // Zepto supported on browsers as well
}
}(function ($) {
"use strict";
// jQuery('form').serializeJSON()
$.fn.serializeJSON = function (options) {
var f, $form, opts, formAsArray, serializedObject, name, value, parsedValue, _obj, nameWithNoType, type, keys, skipFalsy;
f = $.serializeJSON;
$form = this; // NOTE: the set of matched elements is most likely a form, but it could also be a group of inputs
opts = f.setupOpts(options); // calculate values for options {parseNumbers, parseBoolens, parseNulls, ...} with defaults
// Use native `serializeArray` function to get an array of {name, value} objects.
formAsArray = $form.serializeArray();
f.readCheckboxUncheckedValues(formAsArray, opts, $form); // add objects to the array from unchecked checkboxes if needed
// Convert the formAsArray into a serializedObject with nested keys
serializedObject = {};
$.each(formAsArray, function (i, obj) {
name = obj.name; // original input name
value = obj.value; // input value
_obj = f.extractTypeAndNameWithNoType(name);
nameWithNoType = _obj.nameWithNoType; // input name with no type (i.e. "foo:string" => "foo")
type = _obj.type; // type defined from the input name in :type colon notation
if (!type) type = f.attrFromInputWithName($form, name, 'data-value-type');
f.validateType(name, type, opts); // make sure that the type is one of the valid types if defined
if (type !== 'skip') { // ignore inputs with type 'skip'
keys = f.splitInputNameIntoKeysArray(nameWithNoType);
parsedValue = f.parseValue(value, name, type, opts); // convert to string, number, boolean, null or customType
skipFalsy = !parsedValue && f.shouldSkipFalsy($form, name, nameWithNoType, type, opts); // ignore falsy inputs if specified
if (!skipFalsy) {
f.deepSet(serializedObject, keys, parsedValue, opts);
}
}
});
return serializedObject;
};
// Use $.serializeJSON as namespace for the auxiliar functions
// and to define defaults
$.serializeJSON = {
defaultOptions: {
checkboxUncheckedValue: undefined, // to include that value for unchecked checkboxes (instead of ignoring them)
parseNumbers: false, // convert values like "1", "-2.33" to 1, -2.33
parseBooleans: false, // convert "true", "false" to true, false
parseNulls: false, // convert "null" to null
parseAll: false, // all of the above
parseWithFunction: null, // to use custom parser, a function like: function(val){ return parsed_val; }
skipFalsyValuesForTypes: [], // skip serialization of falsy values for listed value types
skipFalsyValuesForFields: [], // skip serialization of falsy values for listed field names
customTypes: {}, // override defaultTypes
defaultTypes: {
"string": function(str) { return String(str); },
"number": function(str) { return Number(str); },
"boolean": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1; },
"null": function(str) { var falses = ["false", "null", "undefined", "", "0"]; return falses.indexOf(str) === -1 ? str : null; },
"array": function(str) { return JSON.parse(str); },
"object": function(str) { return JSON.parse(str); },
"auto": function(str) { return $.serializeJSON.parseValue(str, null, null, {parseNumbers: true, parseBooleans: true, parseNulls: true}); }, // try again with something like "parseAll"
"skip": null // skip is a special type that makes it easy to ignore elements
},
useIntKeysAsArrayIndex: false // name="foo[2]" value="v" => {foo: [null, null, "v"]}, instead of {foo: ["2": "v"]}
},
// Merge option defaults into the options
setupOpts: function(options) {
var opt, validOpts, defaultOptions, optWithDefault, parseAll, f;
f = $.serializeJSON;
if (options == null) { options = {}; } // options ||= {}
defaultOptions = f.defaultOptions || {}; // defaultOptions
// Make sure that the user didn't misspell an option
validOpts = ['checkboxUncheckedValue', 'parseNumbers', 'parseBooleans', 'parseNulls', 'parseAll', 'parseWithFunction', 'skipFalsyValuesForTypes', 'skipFalsyValuesForFields', 'customTypes', 'defaultTypes', 'useIntKeysAsArrayIndex']; // re-define because the user may override the defaultOptions
for (opt in options) {
if (validOpts.indexOf(opt) === -1) {
throw new Error("serializeJSON ERROR: invalid option '" + opt + "'. Please use one of " + validOpts.join(', '));
}
}
// Helper to get the default value for this option if none is specified by the user
optWithDefault = function(key) { return (options[key] !== false) && (options[key] !== '') && (options[key] || defaultOptions[key]); };
// Return computed options (opts to be used in the rest of the script)
parseAll = optWithDefault('parseAll');
return {
checkboxUncheckedValue: optWithDefault('checkboxUncheckedValue'),
parseNumbers: parseAll || optWithDefault('parseNumbers'),
parseBooleans: parseAll || optWithDefault('parseBooleans'),
parseNulls: parseAll || optWithDefault('parseNulls'),
parseWithFunction: optWithDefault('parseWithFunction'),
skipFalsyValuesForTypes: optWithDefault('skipFalsyValuesForTypes'),
skipFalsyValuesForFields: optWithDefault('skipFalsyValuesForFields'),
typeFunctions: $.extend({}, optWithDefault('defaultTypes'), optWithDefault('customTypes')),
useIntKeysAsArrayIndex: optWithDefault('useIntKeysAsArrayIndex')
};
},
// Given a string, apply the type or the relevant "parse" options, to return the parsed value
parseValue: function(valStr, inputName, type, opts) {
var f, parsedVal;
f = $.serializeJSON;
parsedVal = valStr; // if no parsing is needed, the returned value will be the same
if (opts.typeFunctions && type && opts.typeFunctions[type]) { // use a type if available
parsedVal = opts.typeFunctions[type](valStr);
} else if (opts.parseNumbers && f.isNumeric(valStr)) { // auto: number
parsedVal = Number(valStr);
} else if (opts.parseBooleans && (valStr === "true" || valStr === "false")) { // auto: boolean
parsedVal = (valStr === "true");
} else if (opts.parseNulls && valStr == "null") { // auto: null
parsedVal = null;
}
if (opts.parseWithFunction && !type) { // custom parse function (apply after previous parsing options, but not if there's a specific type)
parsedVal = opts.parseWithFunction(parsedVal, inputName);
}
return parsedVal;
},
isObject: function(obj) { return obj === Object(obj); }, // is it an Object?
isUndefined: function(obj) { return obj === void 0; }, // safe check for undefined values
isValidArrayIndex: function(val) { return /^[0-9]+$/.test(String(val)); }, // 1,2,3,4 ... are valid array indexes
isNumeric: function(obj) { return obj - parseFloat(obj) >= 0; }, // taken from jQuery.isNumeric implementation. Not using jQuery.isNumeric to support old jQuery and Zepto versions
optionKeys: function(obj) { if (Object.keys) { return Object.keys(obj); } else { var key, keys = []; for(key in obj){ keys.push(key); } return keys;} }, // polyfill Object.keys to get option keys in IE<9
// Fill the formAsArray object with values for the unchecked checkbox inputs,
// using the same format as the jquery.serializeArray function.
// The value of the unchecked values is determined from the opts.checkboxUncheckedValue
// and/or the data-unchecked-value attribute of the inputs.
readCheckboxUncheckedValues: function (formAsArray, opts, $form) {
var selector, $uncheckedCheckboxes, $el, uncheckedValue, f, name;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
selector = 'input[type=checkbox][name]:not(:checked):not([disabled])';
$uncheckedCheckboxes = $form.find(selector).add($form.filter(selector));
$uncheckedCheckboxes.each(function (i, el) {
// Check data attr first, then the option
$el = $(el);
uncheckedValue = $el.attr('data-unchecked-value');
if (uncheckedValue == null) {
uncheckedValue = opts.checkboxUncheckedValue;
}
// If there's an uncheckedValue, push it into the serialized formAsArray
if (uncheckedValue != null) {
if (el.name && el.name.indexOf("[][") !== -1) { // identify a non-supported
throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+el.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");
}
formAsArray.push({name: el.name, value: uncheckedValue});
}
});
},
// Returns and object with properties {name_without_type, type} from a given name.
// The type is null if none specified. Example:
// "foo" => {nameWithNoType: "foo", type: null}
// "foo:boolean" => {nameWithNoType: "foo", type: "boolean"}
// "foo[bar]:null" => {nameWithNoType: "foo[bar]", type: "null"}
extractTypeAndNameWithNoType: function(name) {
var match;
if (match = name.match(/(.*):([^:]+)$/)) {
return {nameWithNoType: match[1], type: match[2]};
} else {
return {nameWithNoType: name, type: null};
}
},
// Check if this input should be skipped when it has a falsy value,
// depending on the options to skip values by name or type, and the data-skip-falsy attribute.
shouldSkipFalsy: function($form, name, nameWithNoType, type, opts) {
var f = $.serializeJSON;
var skipFromDataAttr = f.attrFromInputWithName($form, name, 'data-skip-falsy');
if (skipFromDataAttr != null) {
return skipFromDataAttr !== 'false'; // any value is true, except if explicitly using 'false'
}
var optForFields = opts.skipFalsyValuesForFields;
if (optForFields && (optForFields.indexOf(nameWithNoType) !== -1 || optForFields.indexOf(name) !== -1)) {
return true;
}
var optForTypes = opts.skipFalsyValuesForTypes;
if (type == null) type = 'string'; // assume fields with no type are targeted as string
if (optForTypes && optForTypes.indexOf(type) !== -1) {
return true
}
return false;
},
// Finds the first input in $form with this name, and get the given attr from it.
// Returns undefined if no input or no attribute was found.
attrFromInputWithName: function($form, name, attrName) {
var escapedName, selector, $input, attrValue;
escapedName = name.replace(/(:|\.|\[|\]|\s)/g,'\\$1'); // every non-standard character need to be escaped by \\
selector = '[name="' + escapedName + '"]';
$input = $form.find(selector).add($form.filter(selector)); // NOTE: this returns only the first $input element if multiple are matched with the same name (i.e. an "array[]"). So, arrays with different element types specified through the data-value-type attr is not supported.
return $input.attr(attrName);
},
// Raise an error if the type is not recognized.
validateType: function(name, type, opts) {
var validTypes, f;
f = $.serializeJSON;
validTypes = f.optionKeys(opts ? opts.typeFunctions : f.defaultOptions.defaultTypes);
if (!type || validTypes.indexOf(type) !== -1) {
return true;
} else {
throw new Error("serializeJSON ERROR: Invalid type " + type + " found in input name '" + name + "', please use one of " + validTypes.join(', '));
}
},
// Split the input name in programatically readable keys.
// Examples:
// "foo" => ['foo']
// "[foo]" => ['foo']
// "foo[inn][bar]" => ['foo', 'inn', 'bar']
// "foo[inn[bar]]" => ['foo', 'inn', 'bar']
// "foo[inn][arr][0]" => ['foo', 'inn', 'arr', '0']
// "arr[][val]" => ['arr', '', 'val']
splitInputNameIntoKeysArray: function(nameWithNoType) {
var keys, f;
f = $.serializeJSON;
keys = nameWithNoType.split('['); // split string into array
keys = $.map(keys, function (key) { return key.replace(/\]/g, ''); }); // remove closing brackets
if (keys[0] === '') { keys.shift(); } // ensure no opening bracket ("[foo][inn]" should be same as "foo[inn]")
return keys;
},
// Set a value in an object or array, using multiple keys to set in a nested object or array:
//
// deepSet(obj, ['foo'], v) // obj['foo'] = v
// deepSet(obj, ['foo', 'inn'], v) // obj['foo']['inn'] = v // Create the inner obj['foo'] object, if needed
// deepSet(obj, ['foo', 'inn', '123'], v) // obj['foo']['arr']['123'] = v //
//
// deepSet(obj, ['0'], v) // obj['0'] = v
// deepSet(arr, ['0'], v, {useIntKeysAsArrayIndex: true}) // arr[0] = v
// deepSet(arr, [''], v) // arr.push(v)
// deepSet(obj, ['arr', ''], v) // obj['arr'].push(v)
//
// arr = [];
// deepSet(arr, ['', v] // arr => [v]
// deepSet(arr, ['', 'foo'], v) // arr => [v, {foo: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}]
// deepSet(arr, ['', 'bar'], v) // arr => [v, {foo: v, bar: v}, {bar: v}]
//
deepSet: function (o, keys, value, opts) {
var key, nextKey, tail, lastIdx, lastVal, f;
if (opts == null) { opts = {}; }
f = $.serializeJSON;
if (f.isUndefined(o)) { throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined"); }
if (!keys || keys.length === 0) { throw new Error("ArgumentError: param 'keys' expected to be an array with least one element"); }
key = keys[0];
// Only one key, then it's not a deepSet, just assign the value.
if (keys.length === 1) {
if (key === '') {
o.push(value); // '' is used to push values into the array (assume o is an array)
} else {
o[key] = value; // other keys can be used as object keys or array indexes
}
// With more keys is a deepSet. Apply recursively.
} else {
nextKey = keys[1];
// '' is used to push values into the array,
// with nextKey, set the value into the same object, in object[nextKey].
// Covers the case of ['', 'foo'] and ['', 'var'] to push the object {foo, var}, and the case of nested arrays.
if (key === '') {
lastIdx = o.length - 1; // asume o is array
lastVal = o[lastIdx];
if (f.isObject(lastVal) && (f.isUndefined(lastVal[nextKey]) || keys.length > 2)) { // if nextKey is not present in the last object element, or there are more keys to deep set
key = lastIdx; // then set the new value in the same object element
} else {
key = lastIdx + 1; // otherwise, point to set the next index in the array
}
}
// '' is used to push values into the array "array[]"
if (nextKey === '') {
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array to push values
}
} else {
if (opts.useIntKeysAsArrayIndex && f.isValidArrayIndex(nextKey)) { // if 1, 2, 3 ... then use an array, where nextKey is the index
if (f.isUndefined(o[key]) || !$.isArray(o[key])) {
o[key] = []; // define (or override) as array, to insert values using int keys as array indexes
}
} else { // for anything else, use an object, where nextKey is going to be the attribute name
if (f.isUndefined(o[key]) || !f.isObject(o[key])) {
o[key] = {}; // define (or override) as object, to set nested properties
}
}
}
// Recursively set the inner object
tail = keys.slice(1);
f.deepSet(o[key], tail, value, opts);
}
}
};
}));
/*!
SerializeJSON jQuery plugin.
https://github.com/marioizquierdo/jquery.serializeJSON
version 2.8.1 (Dec, 2016)
Copyright (c) 2012, 2017 Mario Izquierdo
Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*/
!function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"==typeof exports){var b=require("jquery");module.exports=a(b)}else a(window.jQuery||window.Zepto||window.$)}(function(a){"use strict";a.fn.serializeJSON=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o;return c=a.serializeJSON,d=this,e=c.setupOpts(b),f=d.serializeArray(),c.readCheckboxUncheckedValues(f,e,d),g={},a.each(f,function(a,b){h=b.name,i=b.value,k=c.extractTypeAndNameWithNoType(h),l=k.nameWithNoType,m=k.type,m||(m=c.attrFromInputWithName(d,h,"data-value-type")),c.validateType(h,m,e),"skip"!==m&&(n=c.splitInputNameIntoKeysArray(l),j=c.parseValue(i,h,m,e),o=!j&&c.shouldSkipFalsy(d,h,l,m,e),o||c.deepSet(g,n,j,e))}),g},a.serializeJSON={defaultOptions:{checkboxUncheckedValue:void 0,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,skipFalsyValuesForTypes:[],skipFalsyValuesForFields:[],customTypes:{},defaultTypes:{string:function(a){return String(a)},number:function(a){return Number(a)},boolean:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1},null:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1?a:null},array:function(a){return JSON.parse(a)},object:function(a){return JSON.parse(a)},auto:function(b){return a.serializeJSON.parseValue(b,null,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})},skip:null},useIntKeysAsArrayIndex:!1},setupOpts:function(b){var c,d,e,f,g,h;h=a.serializeJSON,null==b&&(b={}),e=h.defaultOptions||{},d=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","skipFalsyValuesForTypes","skipFalsyValuesForFields","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(c in b)if(d.indexOf(c)===-1)throw new Error("serializeJSON ERROR: invalid option '"+c+"'. Please use one of "+d.join(", "));return f=function(a){return b[a]!==!1&&""!==b[a]&&(b[a]||e[a])},g=f("parseAll"),{checkboxUncheckedValue:f("checkboxUncheckedValue"),parseNumbers:g||f("parseNumbers"),parseBooleans:g||f("parseBooleans"),parseNulls:g||f("parseNulls"),parseWithFunction:f("parseWithFunction"),skipFalsyValuesForTypes:f("skipFalsyValuesForTypes"),skipFalsyValuesForFields:f("skipFalsyValuesForFields"),typeFunctions:a.extend({},f("defaultTypes"),f("customTypes")),useIntKeysAsArrayIndex:f("useIntKeysAsArrayIndex")}},parseValue:function(b,c,d,e){var f,g;return f=a.serializeJSON,g=b,e.typeFunctions&&d&&e.typeFunctions[d]?g=e.typeFunctions[d](b):e.parseNumbers&&f.isNumeric(b)?g=Number(b):!e.parseBooleans||"true"!==b&&"false"!==b?e.parseNulls&&"null"==b&&(g=null):g="true"===b,e.parseWithFunction&&!d&&(g=e.parseWithFunction(g,c)),g},isObject:function(a){return a===Object(a)},isUndefined:function(a){return void 0===a},isValidArrayIndex:function(a){return/^[0-9]+$/.test(String(a))},isNumeric:function(a){return a-parseFloat(a)>=0},optionKeys:function(a){if(Object.keys)return Object.keys(a);var b,c=[];for(b in a)c.push(b);return c},readCheckboxUncheckedValues:function(b,c,d){var e,f,g,h,i;null==c&&(c={}),i=a.serializeJSON,e="input[type=checkbox][name]:not(:checked):not([disabled])",f=d.find(e).add(d.filter(e)),f.each(function(d,e){if(g=a(e),h=g.attr("data-unchecked-value"),null==h&&(h=c.checkboxUncheckedValue),null!=h){if(e.name&&e.name.indexOf("[][")!==-1)throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+e.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");b.push({name:e.name,value:h})}})},extractTypeAndNameWithNoType:function(a){var b;return(b=a.match(/(.*):([^:]+)$/))?{nameWithNoType:b[1],type:b[2]}:{nameWithNoType:a,type:null}},shouldSkipFalsy:function(b,c,d,e,f){var g=a.serializeJSON,h=g.attrFromInputWithName(b,c,"data-skip-falsy");if(null!=h)return"false"!==h;var i=f.skipFalsyValuesForFields;if(i&&(i.indexOf(d)!==-1||i.indexOf(c)!==-1))return!0;var j=f.skipFalsyValuesForTypes;return null==e&&(e="string"),!(!j||j.indexOf(e)===-1)},attrFromInputWithName:function(a,b,c){var d,e,f;return d=b.replace(/(:|\.|\[|\]|\s)/g,"\\$1"),e='[name="'+d+'"]',f=a.find(e).add(a.filter(e)),f.attr(c)},validateType:function(b,c,d){var e,f;if(f=a.serializeJSON,e=f.optionKeys(d?d.typeFunctions:f.defaultOptions.defaultTypes),c&&e.indexOf(c)===-1)throw new Error("serializeJSON ERROR: Invalid type "+c+" found in input name '"+b+"', please use one of "+e.join(", "));return!0},splitInputNameIntoKeysArray:function(b){var c,d;return d=a.serializeJSON,c=b.split("["),c=a.map(c,function(a){return a.replace(/\]/g,"")}),""===c[0]&&c.shift(),c},deepSet:function(b,c,d,e){var f,g,h,i,j,k;if(null==e&&(e={}),k=a.serializeJSON,k.isUndefined(b))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!c||0===c.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");f=c[0],1===c.length?""===f?b.push(d):b[f]=d:(g=c[1],""===f&&(i=b.length-1,j=b[i],f=k.isObject(j)&&(k.isUndefined(j[g])||c.length>2)?i:i+1),""===g?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):e.useIntKeysAsArrayIndex&&k.isValidArrayIndex(g)?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):!k.isUndefined(b[f])&&k.isObject(b[f])||(b[f]={}),h=c.slice(1),k.deepSet(b[f],h,d,e))}}});
\ No newline at end of file
/**
* jQuery serializeObject
* @copyright 2014, macek <paulmacek@gmail.com>
* @link https://github.com/macek/jquery-serialize-object
* @license BSD
* @version 2.5.0
*/
!function(e,i){if("function"==typeof define&&define.amd)define(["exports","jquery"],function(e,r){return i(e,r)});else if("undefined"!=typeof exports){var r=require("jquery");i(exports,r)}else i(e,e.jQuery||e.Zepto||e.ender||e.$)}(this,function(e,i){function r(e,r){function n(e,i,r){return e[i]=r,e}function a(e,i){for(var r,a=e.match(t.key);void 0!==(r=a.pop());)if(t.push.test(r)){var u=s(e.replace(/\[\]$/,""));i=n([],u,i)}else t.fixed.test(r)?i=n([],r,i):t.named.test(r)&&(i=n({},r,i));return i}function s(e){return void 0===h[e]&&(h[e]=0),h[e]++}function u(e){switch(i('[name="'+e.name+'"]',r).attr("type")){case"checkbox":return"on"===e.value?!0:e.value;default:return e.value}}function f(i){if(!t.validate.test(i.name))return this;var r=a(i.name,u(i));return l=e.extend(!0,l,r),this}function d(i){if(!e.isArray(i))throw new Error("formSerializer.addPairs expects an Array");for(var r=0,t=i.length;t>r;r++)this.addPair(i[r]);return this}function o(){return l}function c(){return JSON.stringify(o())}var l={},h={};this.addPair=f,this.addPairs=d,this.serialize=o,this.serializeJSON=c}var t={validate:/^[a-z_][a-z0-9_]*(?:\[(?:\d*|[a-z0-9_]+)\])*$/i,key:/[a-z0-9_]+|(?=\[\])/gi,push:/^$/,fixed:/^\d+$/,named:/^[a-z0-9_]+$/i};return r.patterns=t,r.serializeObject=function(){return new r(i,this).addPairs(this.serializeArray()).serialize()},r.serializeJSON=function(){return new r(i,this).addPairs(this.serializeArray()).serializeJSON()},"undefined"!=typeof i.fn&&(i.fn.serializeObject=r.serializeObject,i.fn.serializeJSON=r.serializeJSON),e.FormSerializer=r,r});
/*
[Leo.C, Studio] (C)2004 - 2008
$Hanization: LeoChung $
$E-Mail: who@imll.net $
$HomePage: http://imll.net $
$Date: 2008/11/8 18:02 $
*/
/*
A simple class for displaying file information and progress
Note: This is a demonstration only and not part of SWFUpload.
Note: Some have had problems adapting this class in IE7. It may not be suitable for your application.
*/
// Constructor
// file is a SWFUpload file object
// targetID is the HTML element id attribute that the FileProgress HTML structure will be added to.
// Instantiating a new FileProgress object with an existing file will reuse/update the existing DOM elements
function FileProgress(file, targetID) {
this.fileProgressID = file.id;
this.opacity = 100;
this.height = 0;
this.fileProgressWrapper = document.getElementById(this.fileProgressID);
if (!this.fileProgressWrapper) {
this.fileProgressWrapper = document.createElement("div");
this.fileProgressWrapper.className = "progressWrapper";
this.fileProgressWrapper.id = this.fileProgressID;
this.fileProgressElement = document.createElement("div");
this.fileProgressElement.className = "progressContainer";
var progressCancel = document.createElement("a");
progressCancel.className = "progressCancel";
progressCancel.href = "#";
progressCancel.style.visibility = "hidden";
progressCancel.appendChild(document.createTextNode(" "));
var progressText = document.createElement("div");
progressText.className = "progressName";
progressText.appendChild(document.createTextNode(file.name));
var progressBar = document.createElement("div");
progressBar.className = "progressBarInProgress";
var progressStatus = document.createElement("div");
progressStatus.className = "progressBarStatus";
progressStatus.innerHTML = "&nbsp;";
this.fileProgressElement.appendChild(progressCancel);
this.fileProgressElement.appendChild(progressText);
this.fileProgressElement.appendChild(progressStatus);
this.fileProgressElement.appendChild(progressBar);
this.fileProgressWrapper.appendChild(this.fileProgressElement);
document.getElementById(targetID).appendChild(this.fileProgressWrapper);
} else {
this.fileProgressElement = this.fileProgressWrapper.firstChild;
}
this.height = this.fileProgressWrapper.offsetHeight;
}
FileProgress.prototype.setProgress = function (percentage) {
this.fileProgressElement.className = "progressContainer green";
this.fileProgressElement.childNodes[3].className = "progressBarInProgress";
this.fileProgressElement.childNodes[3].style.width = percentage + "%";
};
FileProgress.prototype.setComplete = function () {
this.fileProgressElement.className = "progressContainer blue";
this.fileProgressElement.childNodes[3].className = "progressBarComplete";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 10000);
};
FileProgress.prototype.setError = function () {
this.fileProgressElement.className = "progressContainer red";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 5000);
};
FileProgress.prototype.setCancelled = function () {
this.fileProgressElement.className = "progressContainer";
this.fileProgressElement.childNodes[3].className = "progressBarError";
this.fileProgressElement.childNodes[3].style.width = "";
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, 2000);
};
FileProgress.prototype.setStatus = function (status) {
this.fileProgressElement.childNodes[2].innerHTML = status;
};
// Show/Hide the cancel button
FileProgress.prototype.toggleCancel = function (show, swfUploadInstance) {
this.fileProgressElement.childNodes[0].style.visibility = show ? "visible" : "hidden";
if (swfUploadInstance) {
var fileID = this.fileProgressID;
this.fileProgressElement.childNodes[0].onclick = function () {
swfUploadInstance.cancelUpload(fileID);
return false;
};
}
};
// Fades out and clips away the FileProgress box.
FileProgress.prototype.disappear = function () {
var reduceOpacityBy = 15;
var reduceHeightBy = 4;
var rate = 30; // 15 fps
if (this.opacity > 0) {
this.opacity -= reduceOpacityBy;
if (this.opacity < 0) {
this.opacity = 0;
}
if (this.fileProgressWrapper.filters) {
try {
this.fileProgressWrapper.filters.item("DXImageTransform.Microsoft.Alpha").opacity = this.opacity;
} catch (e) {
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
this.fileProgressWrapper.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + this.opacity + ")";
}
} else {
this.fileProgressWrapper.style.opacity = this.opacity / 100;
}
}
if (this.height > 0) {
this.height -= reduceHeightBy;
if (this.height < 0) {
this.height = 0;
}
this.fileProgressWrapper.style.height = this.height + "px";
}
if (this.height > 0 || this.opacity > 0) {
var oSelf = this;
setTimeout(function () {
oSelf.disappear();
}, rate);
} else {
this.fileProgressWrapper.style.display = "none";
}
};
\ No newline at end of file
/*
[Leo.C, Studio] (C)2004 - 2008
$Hanization: LeoChung $
$E-Mail: who@imll.net $
$HomePage: http://imll.net $
$Date: 2008/11/8 18:02 $
*/
/* Demo Note: This demo uses a FileProgress class that handles the UI for displaying the file name and percent complete.
The FileProgress class is not part of SWFUpload.
*/
/* **********************
Event Handlers
These are my custom event handlers to make my
web application behave the way I went when SWFUpload
completes different tasks. These aren't part of the SWFUpload
package. They are part of my application. Without these none
of the actions SWFUpload makes will show up in my application.
********************** */
function fileQueued(file) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setStatus("正在等待...");
progress.toggleCancel(true, this);
} catch (ex) {
this.debug(ex);
}
}
function fileQueueError(file, errorCode, message) {
try {
if (errorCode === SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED) {
alert("您正在上传的文件队列过多.\n" + (message === 0 ? "您已达到上传限制" : "您最多能选择 " + (message > 1 ? "上传 " + message + " 文件." : "一个文件.")));
return;
}
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setError();
progress.toggleCancel(false);
switch (errorCode) {
case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:
progress.setStatus("文件尺寸过大.");
this.debug("错误代码: 文件尺寸过大, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
progress.setStatus("无法上传零字节文件.");
this.debug("错误代码: 零字节文件, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:
progress.setStatus("不支持的文件类型.");
this.debug("错误代码: 不支持的文件类型, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
default:
if (file !== null) {
progress.setStatus("未处理的错误");
}
this.debug("错误代码: " + errorCode + ", 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
}
} catch (ex) {
this.debug(ex);
}
}
function fileDialogComplete(numFilesSelected, numFilesQueued) {
try {
if (numFilesSelected > 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = false;
}
/* I want auto start the upload and I can do that here */
this.startUpload();
} catch (ex) {
this.debug(ex);
}
}
function uploadStart(file) {
try {
/* I don't want to do any file validation or anything, I'll just update the UI and
return true to indicate that the upload should start.
It's important to update the UI here because in Linux no uploadProgress events are called. The best
we can do is say we are uploading.
*/
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setStatus("正在上传...");
progress.toggleCancel(true, this);
}
catch (ex) {}
return true;
}
function uploadProgress(file, bytesLoaded, bytesTotal) {
try {
var percent = Math.ceil((bytesLoaded / bytesTotal) * 100);
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setProgress(percent);
progress.setStatus("正在上传...");
} catch (ex) {
this.debug(ex);
}
}
function uploadSuccess(file, serverData) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setComplete();
progress.setStatus("上传成功");
progress.toggleCancel(false);
} catch (ex) {
this.debug(ex);
}
}
function uploadError(file, errorCode, message) {
try {
var progress = new FileProgress(file, this.customSettings.progressTarget);
progress.setError();
progress.toggleCancel(false);
switch (errorCode) {
case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
progress.setStatus("上传错误: " + message);
this.debug("错误代码: HTTP错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
progress.setStatus("上传失败");
this.debug("错误代码: 上传失败, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.IO_ERROR:
progress.setStatus("服务器 (IO) 错误");
this.debug("错误代码: IO 错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
progress.setStatus("安全错误");
this.debug("错误代码: 安全错误, 文件名: " + file.name + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
progress.setStatus("超出上传限制.");
this.debug("错误代码: 超出上传限制, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED:
progress.setStatus("无法验证. 跳过上传.");
this.debug("错误代码: 文件验证失败, 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
// If there aren't any files left (they were all cancelled) disable the cancel button
if (this.getStats().files_queued === 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = true;
}
progress.setStatus("取消");
progress.setCancelled();
break;
case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
progress.setStatus("停止");
break;
default:
progress.setStatus("未处理的错误: " + errorCode);
this.debug("错误代码: " + errorCode + ", 文件名: " + file.name + ", 文件尺寸: " + file.size + ", 信息: " + message);
break;
}
} catch (ex) {
this.debug(ex);
}
}
function uploadComplete(file) {
if (this.getStats().files_queued === 0) {
document.getElementById(this.customSettings.cancelButtonId).disabled = true;
}
}
// This event comes from the Queue Plugin
function queueComplete(numFilesUploaded) {
var status = document.getElementById("divStatus");
status.innerHTML = numFilesUploaded + " 个文件" + (numFilesUploaded === 1 ? "" : "s") + "已上传.";
}
/*
* SWFUpload jQuery Plugin v1.0.0
*
* Copyright (c) 2009 Adam Royle
* Licensed under the MIT license.
*
*/
(function($){
var defaultHandlers = ['swfupload_loaded_handler','file_queued_handler','file_queue_error_handler','file_dialog_start_handler','file_dialog_complete_handler','upload_start_handler','upload_progress_handler','upload_error_handler','upload_success_handler','upload_complete_handler','queue_complete_handler'];
var additionalHandlers = [];
$.fn.swfupload = function(){
var args = $.makeArray(arguments);
return this.each(function(){
var swfu;
if (args.length == 1 && typeof(args[0]) == 'object') {
swfu = $(this).data('__swfu');
if (!swfu) {
var settings = args[0];
var $magicUploadControl = $(this);
var handlers = [];
$.merge(handlers, defaultHandlers);
$.merge(handlers, additionalHandlers);
$.each(handlers, function(i, v){
var eventName = v.replace(/_handler$/, '').replace(/_([a-z])/g, function(){ return arguments[1].toUpperCase(); });
settings[v] = function() {
var event = $.Event(eventName);
$magicUploadControl.trigger(event, $.makeArray(arguments));
return !event.isDefaultPrevented();
};
});
$(this).data('__swfu', new SWFUpload(settings));
}
} else if (args.length > 0 && typeof(args[0]) == 'string') {
var methodName = args.shift();
swfu = $(this).data('__swfu');
if (swfu && swfu[methodName]) {
swfu[methodName].apply(swfu, args);
}
}
});
};
$.swfupload = {
additionalHandlers: function() {
if (arguments.length === 0) {
return additionalHandlers.slice();
} else {
$(arguments).each(function(i, v){
$.merge(additionalHandlers, $.makeArray(v));
});
}
},
defaultHandlers: function() {
return defaultHandlers.slice();
},
getInstance: function(el) {
return $(el).data('__swfu');
}
};
})(jQuery);
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment