| 1 |
/* |
| 2 |
A simple jQuery modal (http://github.com/kylefox/jquery-modal) |
| 3 |
Version 0.8.2 |
| 4 |
*/ |
| 5 |
|
| 6 |
(function (factory) { |
| 7 |
// Making your jQuery plugin work better with npm tools |
| 8 |
// http://blog.npmjs.org/post/112712169830/making-your-jquery-plugin-work-better-with-npm |
| 9 |
if(typeof module === "object" && typeof module.exports === "object") { |
| 10 |
factory(require("jquery"), window, document); |
| 11 |
} |
| 12 |
else { |
| 13 |
factory(jQuery, window, document); |
| 14 |
} |
| 15 |
}(function($, window, document, undefined) { |
| 16 |
|
| 17 |
var modals = [], |
| 18 |
getCurrent = function() { |
| 19 |
return modals.length ? modals[modals.length - 1] : null; |
| 20 |
}, |
| 21 |
selectCurrent = function() { |
| 22 |
var i, |
| 23 |
selected = false; |
| 24 |
for (i=modals.length-1; i>=0; i--) { |
| 25 |
if (modals[i].$blocker) { |
| 26 |
modals[i].$blocker.toggleClass('current',!selected).toggleClass('behind',selected); |
| 27 |
selected = true; |
| 28 |
} |
| 29 |
} |
| 30 |
}; |
| 31 |
|
| 32 |
$.modal = function(el, options) { |
| 33 |
var remove, target; |
| 34 |
this.$body = $('body'); |
| 35 |
this.options = $.extend({}, $.modal.defaults, options); |
| 36 |
this.options.doFade = !isNaN(parseInt(this.options.fadeDuration, 10)); |
| 37 |
this.$blocker = null; |
| 38 |
if (this.options.closeExisting) |
| 39 |
while ($.modal.isActive()) |
| 40 |
$.modal.close(); // Close any open modals. |
| 41 |
modals.push(this); |
| 42 |
if (el.is('a')) { |
| 43 |
target = el.attr('href'); |
| 44 |
this.anchor = el; |
| 45 |
//Select element by id from href |
| 46 |
if (/^#/.test(target)) { |
| 47 |
this.$elm = $(target); |
| 48 |
if (this.$elm.length !== 1) return null; |
| 49 |
this.$body.append(this.$elm); |
| 50 |
this.open(); |
| 51 |
//AJAX |
| 52 |
} else { |
| 53 |
this.$elm = $('<div>'); |
| 54 |
this.$body.append(this.$elm); |
| 55 |
remove = function(event, modal) { modal.elm.remove(); }; |
| 56 |
this.showSpinner(); |
| 57 |
el.trigger($.modal.AJAX_SEND); |
| 58 |
$.get(target).done(function(html) { |
| 59 |
if (!$.modal.isActive()) return; |
| 60 |
el.trigger($.modal.AJAX_SUCCESS); |
| 61 |
var current = getCurrent(); |
| 62 |
current.$elm.empty().append(html).on($.modal.CLOSE, remove); |
| 63 |
current.hideSpinner(); |
| 64 |
current.open(); |
| 65 |
el.trigger($.modal.AJAX_COMPLETE); |
| 66 |
}).fail(function() { |
| 67 |
el.trigger($.modal.AJAX_FAIL); |
| 68 |
var current = getCurrent(); |
| 69 |
current.hideSpinner(); |
| 70 |
modals.pop(); // remove expected modal from the list |
| 71 |
el.trigger($.modal.AJAX_COMPLETE); |
| 72 |
}); |
| 73 |
} |
| 74 |
} else { |
| 75 |
this.$elm = el; |
| 76 |
this.$body.append(this.$elm); |
| 77 |
this.open(); |
| 78 |
} |
| 79 |
}; |
| 80 |
|
| 81 |
$.modal.prototype = { |
| 82 |
constructor: $.modal, |
| 83 |
|
| 84 |
open: function() { |
| 85 |
var m = this; |
| 86 |
this.block(); |
| 87 |
this.anchor.blur(); |
| 88 |
if(this.options.doFade) { |
| 89 |
setTimeout(function() { |
| 90 |
m.show(); |
| 91 |
}, this.options.fadeDuration * this.options.fadeDelay); |
| 92 |
} else { |
| 93 |
this.show(); |
| 94 |
} |
| 95 |
$(document).off('keydown.modal').on('keydown.modal', function(event) { |
| 96 |
var current = getCurrent(); |
| 97 |
if (event.which === 27 && current.options.escapeClose) current.close(); |
| 98 |
}); |
| 99 |
if (this.options.clickClose) |
| 100 |
this.$blocker.click(function(e) { |
| 101 |
if (e.target === this) |
| 102 |
$.modal.close(); |
| 103 |
}); |
| 104 |
}, |
| 105 |
|
| 106 |
close: function() { |
| 107 |
modals.pop(); |
| 108 |
this.unblock(); |
| 109 |
this.hide(); |
| 110 |
if (!$.modal.isActive()) |
| 111 |
$(document).off('keydown.modal'); |
| 112 |
}, |
| 113 |
|
| 114 |
block: function() { |
| 115 |
this.$elm.trigger($.modal.BEFORE_BLOCK, [this._ctx()]); |
| 116 |
this.$body.css('overflow','hidden'); |
| 117 |
this.$blocker = $('<div class="' + this.options.blockerClass + ' blocker current"></div>').appendTo(this.$body); |
| 118 |
selectCurrent(); |
| 119 |
if(this.options.doFade) { |
| 120 |
this.$blocker.css('opacity',0).animate({opacity: 1}, this.options.fadeDuration); |
| 121 |
} |
| 122 |
this.$elm.trigger($.modal.BLOCK, [this._ctx()]); |
| 123 |
}, |
| 124 |
|
| 125 |
unblock: function(now) { |
| 126 |
if (!now && this.options.doFade) |
| 127 |
this.$blocker.fadeOut(this.options.fadeDuration, this.unblock.bind(this,true)); |
| 128 |
else { |
| 129 |
this.$blocker.children().appendTo(this.$body); |
| 130 |
this.$blocker.remove(); |
| 131 |
this.$blocker = null; |
| 132 |
selectCurrent(); |
| 133 |
if (!$.modal.isActive()) |
| 134 |
this.$body.css('overflow',''); |
| 135 |
} |
| 136 |
}, |
| 137 |
|
| 138 |
show: function() { |
| 139 |
this.$elm.trigger($.modal.BEFORE_OPEN, [this._ctx()]); |
| 140 |
if (this.options.showClose) { |
| 141 |
this.closeButton = $('<a href="#close-modal" rel="modal:close" class="close-modal ' + this.options.closeClass + '">' + this.options.closeText + '</a>'); |
| 142 |
this.$elm.append(this.closeButton); |
| 143 |
} |
| 144 |
this.$elm.addClass(this.options.modalClass).appendTo(this.$blocker); |
| 145 |
if(this.options.doFade) { |
| 146 |
this.$elm.css('opacity',0).show().animate({opacity: 1}, this.options.fadeDuration); |
| 147 |
} else { |
| 148 |
this.$elm.show(); |
| 149 |
} |
| 150 |
this.$elm.trigger($.modal.OPEN, [this._ctx()]); |
| 151 |
}, |
| 152 |
|
| 153 |
hide: function() { |
| 154 |
this.$elm.trigger($.modal.BEFORE_CLOSE, [this._ctx()]); |
| 155 |
if (this.closeButton) this.closeButton.remove(); |
| 156 |
var _this = this; |
| 157 |
if(this.options.doFade) { |
| 158 |
this.$elm.fadeOut(this.options.fadeDuration, function () { |
| 159 |
_this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]); |
| 160 |
}); |
| 161 |
} else { |
| 162 |
this.$elm.hide(0, function () { |
| 163 |
_this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]); |
| 164 |
}); |
| 165 |
} |
| 166 |
this.$elm.trigger($.modal.CLOSE, [this._ctx()]); |
| 167 |
}, |
| 168 |
|
| 169 |
showSpinner: function() { |
| 170 |
if (!this.options.showSpinner) return; |
| 171 |
this.spinner = this.spinner || $('<div class="' + this.options.modalClass + '-spinner"></div>') |
| 172 |
.append(this.options.spinnerHtml); |
| 173 |
this.$body.append(this.spinner); |
| 174 |
this.spinner.show(); |
| 175 |
}, |
| 176 |
|
| 177 |
hideSpinner: function() { |
| 178 |
if (this.spinner) this.spinner.remove(); |
| 179 |
}, |
| 180 |
|
| 181 |
//Return context for custom events |
| 182 |
_ctx: function() { |
| 183 |
return { elm: this.$elm, $elm: this.$elm, $blocker: this.$blocker, options: this.options }; |
| 184 |
} |
| 185 |
}; |
| 186 |
|
| 187 |
$.modal.close = function(event) { |
| 188 |
if (!$.modal.isActive()) return; |
| 189 |
if (event) event.preventDefault(); |
| 190 |
var current = getCurrent(); |
| 191 |
current.close(); |
| 192 |
return current.$elm; |
| 193 |
}; |
| 194 |
|
| 195 |
// Returns if there currently is an active modal |
| 196 |
$.modal.isActive = function () { |
| 197 |
return modals.length > 0; |
| 198 |
}; |
| 199 |
|
| 200 |
$.modal.getCurrent = getCurrent; |
| 201 |
|
| 202 |
$.modal.defaults = { |
| 203 |
closeExisting: true, |
| 204 |
escapeClose: true, |
| 205 |
clickClose: true, |
| 206 |
closeText: 'Close', |
| 207 |
closeClass: '', |
| 208 |
modalClass: "modal", |
| 209 |
blockerClass: "jquery-modal", |
| 210 |
spinnerHtml: null, |
| 211 |
showSpinner: true, |
| 212 |
showClose: true, |
| 213 |
fadeDuration: null, // Number of milliseconds the fade animation takes. |
| 214 |
fadeDelay: 1.0 // Point during the overlay's fade-in that the modal begins to fade in (.5 = 50%, 1.5 = 150%, etc.) |
| 215 |
}; |
| 216 |
|
| 217 |
// Event constants |
| 218 |
$.modal.BEFORE_BLOCK = 'modal:before-block'; |
| 219 |
$.modal.BLOCK = 'modal:block'; |
| 220 |
$.modal.BEFORE_OPEN = 'modal:before-open'; |
| 221 |
$.modal.OPEN = 'modal:open'; |
| 222 |
$.modal.BEFORE_CLOSE = 'modal:before-close'; |
| 223 |
$.modal.CLOSE = 'modal:close'; |
| 224 |
$.modal.AFTER_CLOSE = 'modal:after-close'; |
| 225 |
$.modal.AJAX_SEND = 'modal:ajax:send'; |
| 226 |
$.modal.AJAX_SUCCESS = 'modal:ajax:success'; |
| 227 |
$.modal.AJAX_FAIL = 'modal:ajax:fail'; |
| 228 |
$.modal.AJAX_COMPLETE = 'modal:ajax:complete'; |
| 229 |
|
| 230 |
$.fn.modal = function(options){ |
| 231 |
if (this.length === 1) { |
| 232 |
new $.modal(this, options); |
| 233 |
} |
| 234 |
return this; |
| 235 |
}; |
| 236 |
|
| 237 |
// Automatically bind links with rel="modal:close" to, well, close the modal. |
| 238 |
$(document).on('click.modal', 'a[rel~="modal:close"]', $.modal.close); |
| 239 |
$(document).on('click.modal', 'a[rel~="modal:open"]', function(event) { |
| 240 |
event.preventDefault(); |
| 241 |
$(this).modal(); |
| 242 |
}); |
| 243 |
})); |
| 244 |
|