From b546c463bf78c2db4030251081d1bdf08fea0e4c Mon Sep 17 00:00:00 2001 From: Ben McMahen Date: Mon, 14 Oct 2013 19:36:07 -0600 Subject: [PATCH] first commit --- .gitignore | 3 + History.md | 0 Makefile | 11 + Readme.md | 53 ++ component.json | 27 + example/example.html | 37 ++ index.js | 94 +++ modal.css | 52 ++ standalone/modal.css | 80 +++ standalone/modal.js | 1483 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1840 insertions(+) create mode 100644 .gitignore create mode 100644 History.md create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 component.json create mode 100644 example/example.html create mode 100644 index.js create mode 100644 modal.css create mode 100644 standalone/modal.css create mode 100644 standalone/modal.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6032462 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +components +build +.DS_Store \ No newline at end of file diff --git a/History.md b/History.md new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7659e93 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ + +build: components index.js modal.css + @component build --dev + +components: component.json + @component install --dev + +clean: + rm -fr build components template.js + +.PHONY: clean diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..89c3185 --- /dev/null +++ b/Readme.md @@ -0,0 +1,53 @@ + +# modal + + A simple, bootstrap-like modal dialog written in pure Javascript. + +## Installation + + $ component install bmcmahen/modal + + or use the standalone version in the `standalone` directory, and attach the script and css to your HTML page. + +## Use + +You can use the `data-attribute` api, much like Bootstrap. The `data-modal-id` attribute directs us to the id of the modal dialog markup. You can use `data-show-overlay` to enable an overlay, and `data-modal-close` on a button within the modal to close it. + +```html + +show modal + + + +``` + +Or you can use the Javascript API. + +```javascript +var modal = require('modal'); +var myModal = modal(document.querySelector('#myModal')); + +myModal.overlay(); // enable the overlay +myModal.show(); // show the modal +myModal.hide(); // hide the modal + +myModal.on('showing', function(){ + console.log('modal is in the process of showing..'); +}); +``` + +## Events + +### showing(fn) +### shown(fn) +### hiding(fn) +### hidden(fn) + +## License + + MIT diff --git a/component.json b/component.json new file mode 100644 index 0000000..c403b59 --- /dev/null +++ b/component.json @@ -0,0 +1,27 @@ +{ + "name": "modal", + "repo": "bmcmahen/modal", + "description": "a simple modal written in vanilla javscript", + "version": "0.0.2", + "keywords": [], + "dependencies": { + "component/emitter": "*", + "bmcmahen/overlay": "*", + "component/classes": "*", + "anthonyshort/after-transition": "*", + "component/events": "*", + "component/delegate": "*", + "component/domify": "*", + "javve/get-attribute": "*", + "bmcmahen/target": "*", + "yields/prevent": "*" + }, + "development": {}, + "license": "MIT", + "scripts": [ + "index.js" + ], + "styles": [ + "modal.css" + ] +} \ No newline at end of file diff --git a/example/example.html b/example/example.html new file mode 100644 index 0000000..cd89879 --- /dev/null +++ b/example/example.html @@ -0,0 +1,37 @@ + + + + + + + + + + + show modal + + + + + + + + + \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..51b3d52 --- /dev/null +++ b/index.js @@ -0,0 +1,94 @@ +var Emitter = require('emitter'); +var overlay = require('overlay'); +var classes = require('classes'); +var afterTransition = require('after-transition'); +var events = require('events'); +var delegate = require('delegate'); +var prevent = require('prevent'); +var target = require('target'); +var attr = require('get-attribute'); +var domify = require('domify'); + +/** + * Bind any links with [data-modal-id]. _id should direct + * us to the id of the modal dialog. + */ + +var modalTrigger = delegate.bind(document, '[data-modal-id]', 'click', function(e){ + prevent(e); + var el = target(e); + var _id = attr(el, 'data-modal-id'); + var newModal = new Modal(document.getElementById(_id)); + if (attr(el, 'data-show-overlay')) newModal.overlay(); + newModal.show(); +}); + +/** + * API + * @param {Element} el + * @return {Modal} + */ + +module.exports = function(el){ + delegate.unbind(document, 'click', modalTrigger, false); + return new Modal(el); +}; + +/** + * Modal Constructor + * @param {Element} el + */ + +function Modal(el){ + this.el = el; + this.isShown = false; + this.bind(); +} + +Emitter(Modal.prototype); + +Modal.prototype.toggle = function(){ + if (this.isShown) this.hide(); + else this.show(); + return this; +}; + +Modal.prototype.bind = function(){ + this.events = events(this.el, this); + this.events.bind('click [data-modal-close]', 'hide'); +}; + +Modal.prototype.overlay = function(className){ + this._overlay = overlay(className || 'modal-dialogue'); + return this; +}; + +Modal.prototype.show = function(){ + if (this.isShown) return this; + this.previouslyFocused = document.activeElement; + this.isShown = true; + this.emit('showing'); + if (this._overlay) this._overlay.show(); + classes(this.el).add('modal-show'); + var self = this; + afterTransition(this.el, function(){ + self.emit('shown'); + }); + this.el.focus(); + return this; +}; + +Modal.prototype.hide = function(e){ + if (e) prevent(e); + if (!this.isShown) return this; + this.emit('hiding'); + if (this._overlay) this._overlay.hide(); + classes(this.el).remove('modal-show'); + this.previouslyFocused.focus(); + this.isShown = false; + var self = this; + afterTransition(this.el, function(){ + self.emit('hidden'); + }); + return this; +}; diff --git a/modal.css b/modal.css new file mode 100644 index 0000000..8c270fb --- /dev/null +++ b/modal.css @@ -0,0 +1,52 @@ +.modal-dialog { + position: fixed; + top: 50%; + left: 50%; + width: 50%; + max-width: 630px; + min-width: 320px; + height: auto; + z-index: 2000; + visibility: hidden; + -webkit-transform-style: preserve-3d; + -webkit-transform: translateX(-50%) translateY(-50%); + -moz-transform: translateX(-50%) translateY(-50%); + -o-transform: translateX(-50%) translateY(-50%); + -ms-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); +} + +.modal-show { + visibility: visible; +} + +.modal-dialog-wrapper { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + opacity: 0; + + -webkit-transform: scale(0.3); + -moz-transform: scale(0.3); + -o-transform: scale(0.3); + -ms-transform: scale(0.3); + transform: scale(0.3); + background: white; +} + +.modal-show .modal-dialog-wrapper { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + opacity: 1; +} + + diff --git a/standalone/modal.css b/standalone/modal.css new file mode 100644 index 0000000..7a55e5b --- /dev/null +++ b/standalone/modal.css @@ -0,0 +1,80 @@ +#overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,.85); + transition: opacity 300ms; + -webkit-transition: opacity 300ms; + -moz-transition: opacity 300ms; + -ms-transition: opacity 300ms; + -o-transition: opacity 300ms; + z-index: 500; + pointer-events: none; + opacity: 0; +} + +#overlay.show { + opacity: 1; +} + + + + + + + + + +.modal-dialog { + position: fixed; + top: 50%; + left: 50%; + width: 50%; + max-width: 630px; + min-width: 320px; + height: auto; + z-index: 2000; + visibility: hidden; + -webkit-backface-visibility: hidden; + -webkit-transform-style: preserve-3d; + -webkit-transform: translateX(-50%) translateY(-50%); + -moz-transform: translateX(-50%) translateY(-50%); + -o-transform: translateX(-50%) translateY(-50%); + -ms-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); +} + +.modal-show { + visibility: visible; +} + +.modal-dialog-wrapper { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + opacity: 0; + + -webkit-transform: scale(0.3); + -moz-transform: scale(0.3); + -o-transform: scale(0.3); + -ms-transform: scale(0.3); + transform: scale(0.3); + background: white; +} + +.modal-show .modal-dialog-wrapper { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; + filter: alpha(opacity=100); + opacity: 1; +} \ No newline at end of file diff --git a/standalone/modal.js b/standalone/modal.js new file mode 100644 index 0000000..6243167 --- /dev/null +++ b/standalone/modal.js @@ -0,0 +1,1483 @@ +;(function(){ + +/** + * Require the given path. + * + * @param {String} path + * @return {Object} exports + * @api public + */ + +function require(path, parent, orig) { + var resolved = require.resolve(path); + + // lookup failed + if (null == resolved) { + orig = orig || path; + parent = parent || 'root'; + var err = new Error('Failed to require "' + orig + '" from "' + parent + '"'); + err.path = orig; + err.parent = parent; + err.require = true; + throw err; + } + + var module = require.modules[resolved]; + + // perform real require() + // by invoking the module's + // registered function + if (!module._resolving && !module.exports) { + var mod = {}; + mod.exports = {}; + mod.client = mod.component = true; + module._resolving = true; + module.call(this, mod.exports, require.relative(resolved), mod); + delete module._resolving; + module.exports = mod.exports; + } + + return module.exports; +} + +/** + * Registered modules. + */ + +require.modules = {}; + +/** + * Registered aliases. + */ + +require.aliases = {}; + +/** + * Resolve `path`. + * + * Lookup: + * + * - PATH/index.js + * - PATH.js + * - PATH + * + * @param {String} path + * @return {String} path or null + * @api private + */ + +require.resolve = function(path) { + if (path.charAt(0) === '/') path = path.slice(1); + + var paths = [ + path, + path + '.js', + path + '.json', + path + '/index.js', + path + '/index.json' + ]; + + for (var i = 0; i < paths.length; i++) { + var path = paths[i]; + if (require.modules.hasOwnProperty(path)) return path; + if (require.aliases.hasOwnProperty(path)) return require.aliases[path]; + } +}; + +/** + * Normalize `path` relative to the current path. + * + * @param {String} curr + * @param {String} path + * @return {String} + * @api private + */ + +require.normalize = function(curr, path) { + var segs = []; + + if ('.' != path.charAt(0)) return path; + + curr = curr.split('/'); + path = path.split('/'); + + for (var i = 0; i < path.length; ++i) { + if ('..' == path[i]) { + curr.pop(); + } else if ('.' != path[i] && '' != path[i]) { + segs.push(path[i]); + } + } + + return curr.concat(segs).join('/'); +}; + +/** + * Register module at `path` with callback `definition`. + * + * @param {String} path + * @param {Function} definition + * @api private + */ + +require.register = function(path, definition) { + require.modules[path] = definition; +}; + +/** + * Alias a module definition. + * + * @param {String} from + * @param {String} to + * @api private + */ + +require.alias = function(from, to) { + if (!require.modules.hasOwnProperty(from)) { + throw new Error('Failed to alias "' + from + '", it does not exist'); + } + require.aliases[to] = from; +}; + +/** + * Return a require function relative to the `parent` path. + * + * @param {String} parent + * @return {Function} + * @api private + */ + +require.relative = function(parent) { + var p = require.normalize(parent, '..'); + + /** + * lastIndexOf helper. + */ + + function lastIndexOf(arr, obj) { + var i = arr.length; + while (i--) { + if (arr[i] === obj) return i; + } + return -1; + } + + /** + * The relative require() itself. + */ + + function localRequire(path) { + var resolved = localRequire.resolve(path); + return require(resolved, parent, path); + } + + /** + * Resolve relative to the parent. + */ + + localRequire.resolve = function(path) { + var c = path.charAt(0); + if ('/' == c) return path.slice(1); + if ('.' == c) return require.normalize(p, path); + + // resolve deps by returning + // the dep in the nearest "deps" + // directory + var segs = parent.split('/'); + var i = lastIndexOf(segs, 'deps') + 1; + if (!i) i = 0; + path = segs.slice(0, i + 1).join('/') + '/deps/' + path; + return path; + }; + + /** + * Check if module is defined at `path`. + */ + + localRequire.exists = function(path) { + return require.modules.hasOwnProperty(localRequire.resolve(path)); + }; + + return localRequire; +}; +require.register("component-indexof/index.js", function(exports, require, module){ + +var indexOf = [].indexOf; + +module.exports = function(arr, obj){ + if (indexOf) return arr.indexOf(obj); + for (var i = 0; i < arr.length; ++i) { + if (arr[i] === obj) return i; + } + return -1; +}; +}); +require.register("component-emitter/index.js", function(exports, require, module){ + +/** + * Module dependencies. + */ + +var index = require('indexof'); + +/** + * Expose `Emitter`. + */ + +module.exports = Emitter; + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks[event] = this._callbacks[event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + var self = this; + this._callbacks = this._callbacks || {}; + + function on() { + self.off(event, on); + fn.apply(this, arguments); + } + + fn._off = on; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks[event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks[event]; + return this; + } + + // remove specific handler + var i = index(callbacks, fn._off || fn); + if (~i) callbacks.splice(i, 1); + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks[event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks[event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + +}); +require.register("ianstormtaylor-redraw/index.js", function(exports, require, module){ + +/** + * Expose `redraw`. + */ + +module.exports = redraw; + + +/** + * Force a redraw on an `el`. + * + * @param {Element} el + */ + +function redraw (el) { + el.offsetHeight; +} +}); +require.register("bmcmahen-overlay/index.js", function(exports, require, module){ + +/** + * Module dependencies. + */ + +var Emitter = require('emitter'); +var classes = require('classes'); +var redraw = require('redraw'); +var afterTransition = require('after-transition'); + +/** + * Expose `Overlay`. + */ + +module.exports = Overlay; + +/** + * Initialize a new `Overlay`. + * + * @param {Object} options + * @api public + */ + +function Overlay(className) { + if (!(this instanceof Overlay)) return new Overlay(); + this.el = document.createElement('div'); + if (className) classes(this.el).add(className); + this.el.id = 'overlay'; +} + +/** + * Mixin 'Emitter' + */ + +Emitter(Overlay.prototype); + +/** + * Show the overlay. + * + * Emits "show" event. + * + * @return {Overlay} + * @api public + */ + +Overlay.prototype.show = function(){ + document.getElementsByTagName('body')[0].appendChild(this.el); + this.emit('show'); + redraw(this.el); + var self = this; + afterTransition.once(this.el, function(){ + self.emit('shown'); + }); + classes(this.el).add('show'); + return this; +}; + +/** + * Hide the overlay. + * + * Emits "hide" event, and "hidden" when finished. + * + * @return {Overlay} + * @api public + */ + +Overlay.prototype.hide = function(){ + if (!this.el) return; + this.emit('hide'); + var self = this; + afterTransition.once(this.el, function(){ + self.emit('hidden'); + self.el.parentNode.removeChild(self.el); + }); + classes(this.el).remove('show'); + return this; +}; + + + +}); +require.register("component-classes/index.js", function(exports, require, module){ + +/** + * Module dependencies. + */ + +var index = require('indexof'); + +/** + * Whitespace regexp. + */ + +var re = /\s+/; + +/** + * toString reference. + */ + +var toString = Object.prototype.toString; + +/** + * Wrap `el` in a `ClassList`. + * + * @param {Element} el + * @return {ClassList} + * @api public + */ + +module.exports = function(el){ + return new ClassList(el); +}; + +/** + * Initialize a new ClassList for `el`. + * + * @param {Element} el + * @api private + */ + +function ClassList(el) { + this.el = el; + this.list = el.classList; +} + +/** + * Add class `name` if not already present. + * + * @param {String} name + * @return {ClassList} + * @api public + */ + +ClassList.prototype.add = function(name){ + // classList + if (this.list) { + this.list.add(name); + return this; + } + + // fallback + var arr = this.array(); + var i = index(arr, name); + if (!~i) arr.push(name); + this.el.className = arr.join(' '); + return this; +}; + +/** + * Remove class `name` when present, or + * pass a regular expression to remove + * any which match. + * + * @param {String|RegExp} name + * @return {ClassList} + * @api public + */ + +ClassList.prototype.remove = function(name){ + if ('[object RegExp]' == toString.call(name)) { + return this.removeMatching(name); + } + + // classList + if (this.list) { + this.list.remove(name); + return this; + } + + // fallback + var arr = this.array(); + var i = index(arr, name); + if (~i) arr.splice(i, 1); + this.el.className = arr.join(' '); + return this; +}; + +/** + * Remove all classes matching `re`. + * + * @param {RegExp} re + * @return {ClassList} + * @api private + */ + +ClassList.prototype.removeMatching = function(re){ + var arr = this.array(); + for (var i = 0; i < arr.length; i++) { + if (re.test(arr[i])) { + this.remove(arr[i]); + } + } + return this; +}; + +/** + * Toggle class `name`. + * + * @param {String} name + * @return {ClassList} + * @api public + */ + +ClassList.prototype.toggle = function(name){ + // classList + if (this.list) { + this.list.toggle(name); + return this; + } + + // fallback + if (this.has(name)) { + this.remove(name); + } else { + this.add(name); + } + return this; +}; + +/** + * Return an array of classes. + * + * @return {Array} + * @api public + */ + +ClassList.prototype.array = function(){ + var arr = this.el.className.split(re); + if ('' === arr[0]) arr.pop(); + return arr; +}; + +/** + * Check if class `name` is present. + * + * @param {String} name + * @return {ClassList} + * @api public + */ + +ClassList.prototype.has = +ClassList.prototype.contains = function(name){ + return this.list + ? this.list.contains(name) + : !! ~index(this.array(), name); +}; + +}); +require.register("anthonyshort-has-transitions/index.js", function(exports, require, module){ +/** + * This will store the property that the current + * browser uses for transitionDuration + */ +var property; + +/** + * The properties we'll check on an element + * to determine if it actually has transitions + * We use duration as this is the only property + * needed to technically have transitions + * @type {Array} + */ +var types = [ + "transitionDuration", + "MozTransitionDuration", + "webkitTransitionDuration" +]; + +/** + * Determine the correct property for this browser + * just once so we done need to check every time + */ +while(types.length) { + var type = types.shift(); + if(type in document.body.style) { + property = type; + } +} + +/** + * Determine if the browser supports transitions or + * if an element has transitions at all. + * @param {Element} el Optional. Returns browser support if not included + * @return {Boolean} + */ +function hasTransitions(el){ + if(!property) { + return false; // No browser support for transitions + } + if(!el) { + return property != null; // We just want to know if browsers support it + } + var duration = getComputedStyle(el)[property]; + return duration !== "" && parseFloat(duration) !== 0; // Does this element have transitions? +} + +module.exports = hasTransitions; +}); +require.register("component-event/index.js", function(exports, require, module){ + +/** + * Bind `el` event `type` to `fn`. + * + * @param {Element} el + * @param {String} type + * @param {Function} fn + * @param {Boolean} capture + * @return {Function} + * @api public + */ + +exports.bind = function(el, type, fn, capture){ + if (el.addEventListener) { + el.addEventListener(type, fn, capture || false); + } else { + el.attachEvent('on' + type, fn); + } + return fn; +}; + +/** + * Unbind `el` event `type`'s callback `fn`. + * + * @param {Element} el + * @param {String} type + * @param {Function} fn + * @param {Boolean} capture + * @return {Function} + * @api public + */ + +exports.unbind = function(el, type, fn, capture){ + if (el.removeEventListener) { + el.removeEventListener(type, fn, capture || false); + } else { + el.detachEvent('on' + type, fn); + } + return fn; +}; + +}); +require.register("anthonyshort-css-emitter/index.js", function(exports, require, module){ +/** + * Module Dependencies + */ + +var events = require('event'); + +// CSS events + +var watch = [ + 'transitionend' +, 'webkitTransitionEnd' +, 'oTransitionEnd' +, 'MSTransitionEnd' +, 'animationend' +, 'webkitAnimationEnd' +, 'oAnimationEnd' +, 'MSAnimationEnd' +]; + +/** + * Expose `CSSnext` + */ + +module.exports = CssEmitter; + +/** + * Initialize a new `CssEmitter` + * + */ + +function CssEmitter(element){ + if (!(this instanceof CssEmitter)) return new CssEmitter(element); + this.el = element; +} + +/** + * Bind CSS events. + * + * @api public + */ + +CssEmitter.prototype.bind = function(fn){ + for (var i=0; i < watch.length; i++) { + events.bind(this.el, watch[i], fn); + } + return this; +}; + +/** + * Unbind CSS events + * + * @api public + */ + +CssEmitter.prototype.unbind = function(fn){ + for (var i=0; i < watch.length; i++) { + events.unbind(this.el, watch[i], fn); + } + return this; +}; + +/** + * Fire callback only once + * + * @api public + */ + +CssEmitter.prototype.once = function(fn){ + var self = this; + function on(){ + self.unbind(on); + fn.apply(self.el, arguments); + } + self.bind(on); + return this; +}; + + +}); +require.register("anthonyshort-after-transition/index.js", function(exports, require, module){ +var hasTransitions = require('has-transitions'); +var emitter = require('css-emitter'); + +function afterTransition(el, callback) { + if(hasTransitions(el)) { + return emitter(el).bind(callback); + } + return callback.apply(el); +}; + +afterTransition.once = function(el, callback) { + afterTransition(el, function fn(){ + callback.apply(el); + emitter(el).unbind(fn); + }); +}; + +module.exports = afterTransition; +}); +require.register("component-events/index.js", function(exports, require, module){ + +/** + * Module dependencies. + */ + +var events = require('event'); +var delegate = require('delegate'); + +/** + * Expose `Events`. + */ + +module.exports = Events; + +/** + * Initialize an `Events` with the given + * `el` object which events will be bound to, + * and the `obj` which will receive method calls. + * + * @param {Object} el + * @param {Object} obj + * @api public + */ + +function Events(el, obj) { + if (!(this instanceof Events)) return new Events(el, obj); + if (!el) throw new Error('element required'); + if (!obj) throw new Error('object required'); + this.el = el; + this.obj = obj; + this._events = {}; +} + +/** + * Subscription helper. + */ + +Events.prototype.sub = function(event, method, cb){ + this._events[event] = this._events[event] || {}; + this._events[event][method] = cb; +}; + +/** + * Bind to `event` with optional `method` name. + * When `method` is undefined it becomes `event` + * with the "on" prefix. + * + * Examples: + * + * Direct event handling: + * + * events.bind('click') // implies "onclick" + * events.bind('click', 'remove') + * events.bind('click', 'sort', 'asc') + * + * Delegated event handling: + * + * events.bind('click li > a') + * events.bind('click li > a', 'remove') + * events.bind('click a.sort-ascending', 'sort', 'asc') + * events.bind('click a.sort-descending', 'sort', 'desc') + * + * @param {String} event + * @param {String|function} [method] + * @return {Function} callback + * @api public + */ + +Events.prototype.bind = function(event, method){ + var e = parse(event); + var el = this.el; + var obj = this.obj; + var name = e.name; + var method = method || 'on' + name; + var args = [].slice.call(arguments, 2); + + // callback + function cb(){ + var a = [].slice.call(arguments).concat(args); + obj[method].apply(obj, a); + } + + // bind + if (e.selector) { + cb = delegate.bind(el, e.selector, name, cb); + } else { + events.bind(el, name, cb); + } + + // subscription for unbinding + this.sub(name, method, cb); + + return cb; +}; + +/** + * Unbind a single binding, all bindings for `event`, + * or all bindings within the manager. + * + * Examples: + * + * Unbind direct handlers: + * + * events.unbind('click', 'remove') + * events.unbind('click') + * events.unbind() + * + * Unbind delegate handlers: + * + * events.unbind('click', 'remove') + * events.unbind('click') + * events.unbind() + * + * @param {String|Function} [event] + * @param {String|Function} [method] + * @api public + */ + +Events.prototype.unbind = function(event, method){ + if (0 == arguments.length) return this.unbindAll(); + if (1 == arguments.length) return this.unbindAllOf(event); + + // no bindings for this event + var bindings = this._events[event]; + if (!bindings) return; + + // no bindings for this method + var cb = bindings[method]; + if (!cb) return; + + events.unbind(this.el, event, cb); +}; + +/** + * Unbind all events. + * + * @api private + */ + +Events.prototype.unbindAll = function(){ + for (var event in this._events) { + this.unbindAllOf(event); + } +}; + +/** + * Unbind all events for `event`. + * + * @param {String} event + * @api private + */ + +Events.prototype.unbindAllOf = function(event){ + var bindings = this._events[event]; + if (!bindings) return; + + for (var method in bindings) { + this.unbind(event, method); + } +}; + +/** + * Parse `event`. + * + * @param {String} event + * @return {Object} + * @api private + */ + +function parse(event) { + var parts = event.split(/ +/); + return { + name: parts.shift(), + selector: parts.join(' ') + } +} + +}); +require.register("component-query/index.js", function(exports, require, module){ + +function one(selector, el) { + return el.querySelector(selector); +} + +exports = module.exports = function(selector, el){ + el = el || document; + return one(selector, el); +}; + +exports.all = function(selector, el){ + el = el || document; + return el.querySelectorAll(selector); +}; + +exports.engine = function(obj){ + if (!obj.one) throw new Error('.one callback required'); + if (!obj.all) throw new Error('.all callback required'); + one = obj.one; + exports.all = obj.all; +}; + +}); +require.register("component-matches-selector/index.js", function(exports, require, module){ +/** + * Module dependencies. + */ + +var query = require('query'); + +/** + * Element prototype. + */ + +var proto = Element.prototype; + +/** + * Vendor function. + */ + +var vendor = proto.matches + || proto.webkitMatchesSelector + || proto.mozMatchesSelector + || proto.msMatchesSelector + || proto.oMatchesSelector; + +/** + * Expose `match()`. + */ + +module.exports = match; + +/** + * Match `el` to `selector`. + * + * @param {Element} el + * @param {String} selector + * @return {Boolean} + * @api public + */ + +function match(el, selector) { + if (vendor) return vendor.call(el, selector); + var nodes = query.all(selector, el.parentNode); + for (var i = 0; i < nodes.length; ++i) { + if (nodes[i] == el) return true; + } + return false; +} + +}); +require.register("discore-closest/index.js", function(exports, require, module){ +var matches = require('matches-selector') + +module.exports = function (element, selector, checkYoSelf, root) { + element = checkYoSelf ? element : element.parentNode + root = root || document + + do { + if (matches(element, selector)) + return element + // After `matches` on the edge case that + // the selector matches the root + // (when the root is not the document) + if (element === root) + return + // Make sure `element !== document` + // otherwise we get an illegal invocation + } while ((element = element.parentNode) && element !== document) +} +}); +require.register("component-delegate/index.js", function(exports, require, module){ +/** + * Module dependencies. + */ + +var closest = require('closest') + , event = require('event'); + +/** + * Delegate event `type` to `selector` + * and invoke `fn(e)`. A callback function + * is returned which may be passed to `.unbind()`. + * + * @param {Element} el + * @param {String} selector + * @param {String} type + * @param {Function} fn + * @param {Boolean} capture + * @return {Function} + * @api public + */ + +exports.bind = function(el, selector, type, fn, capture){ + return event.bind(el, type, function(e){ + var target = e.target || e.srcElement; + e.delegateTarget = closest(target, selector, true, el); + if (e.delegateTarget) fn.call(el, e); + }, capture); +}; + +/** + * Unbind event `type`'s callback `fn`. + * + * @param {Element} el + * @param {String} type + * @param {Function} fn + * @param {Boolean} capture + * @api public + */ + +exports.unbind = function(el, type, fn, capture){ + event.unbind(el, type, fn, capture); +}; + +}); +require.register("component-domify/index.js", function(exports, require, module){ + +/** + * Expose `parse`. + */ + +module.exports = parse; + +/** + * Wrap map from jquery. + */ + +var map = { + option: [1, ''], + optgroup: [1, ''], + legend: [1, '
', '
'], + thead: [1, '', '
'], + tbody: [1, '', '
'], + tfoot: [1, '', '
'], + colgroup: [1, '', '
'], + caption: [1, '', '
'], + tr: [2, '', '
'], + td: [3, '', '
'], + th: [3, '', '
'], + col: [2, '', '
'], + _default: [0, '', ''] +}; + +/** + * Parse `html` and return the children. + * + * @param {String} html + * @return {Array} + * @api private + */ + +function parse(html) { + if ('string' != typeof html) throw new TypeError('String expected'); + + html = html.replace(/^\s+|\s+$/g, ''); // Remove leading/trailing whitespace + + // tag name + var m = /<([\w:]+)/.exec(html); + if (!m) throw new Error('No elements were generated.'); + var tag = m[1]; + + // body support + if (tag == 'body') { + var el = document.createElement('html'); + el.innerHTML = html; + return el.removeChild(el.lastChild); + } + + // wrap map + var wrap = map[tag] || map._default; + var depth = wrap[0]; + var prefix = wrap[1]; + var suffix = wrap[2]; + var el = document.createElement('div'); + el.innerHTML = prefix + html + suffix; + while (depth--) el = el.lastChild; + + var els = el.children; + if (1 == els.length) { + return el.removeChild(els[0]); + } + + var fragment = document.createDocumentFragment(); + while (els.length) { + fragment.appendChild(el.removeChild(els[0])); + } + + return fragment; +} + +}); +require.register("javve-get-attribute/index.js", function(exports, require, module){ +/** + * Return the value for `attr` at `element`. + * + * @param {Element} el + * @param {String} attr + * @api public + */ + +module.exports = function(el, attr) { + var result = (el.getAttribute && el.getAttribute(attr)) || null; + if( !result ) { + var attrs = el.attributes; + var length = attrs.length; + for(var i = 0; i < length; i++) { + if (attr[i] !== undefined) { + if(attr[i].nodeName === attr) { + result = attr[i].nodeValue; + } + } + } + } + return result; +} +}); +require.register("bmcmahen-target/index.js", function(exports, require, module){ +module.exports = function(e){ + e = e || window.event; + return e.target || e.srcElement; +}; +}); +require.register("yields-prevent/index.js", function(exports, require, module){ + +/** + * prevent default on the given `e`. + * + * examples: + * + * anchor.onclick = prevent; + * anchor.onclick = function(e){ + * if (something) return prevent(e); + * }; + * + * @param {Event} e + */ + +module.exports = function(e){ + e = e || window.event + return e.preventDefault + ? e.preventDefault() + : e.returnValue = false; +}; + +}); +require.register("modal/index.js", function(exports, require, module){ +var Emitter = require('emitter'); +var overlay = require('overlay'); +var classes = require('classes'); +var afterTransition = require('after-transition'); +var events = require('events'); +var delegate = require('delegate'); +var template = require('./template'); +var prevent = require('prevent'); +var target = require('target'); +var attr = require('get-attribute'); +var domify = require('domify'); + +/** + * Bind any links with [data-modal-id]. _id should direct + * us to the id of the modal dialog. + */ + +var modalTrigger = delegate.bind(document, '[data-modal-id]', 'click', function(e){ + prevent(e); + var el = target(e); + var _id = attr(el, 'data-modal-id'); + var newModal = new Modal(document.getElementById(_id)); + if (attr(el, 'data-show-overlay')) newModal.overlay(); + newModal.show(); +}); + +/** + * API + * @param {Element} el + * @return {Modal} + */ + +module.exports = function(el){ + delegate.unbind(document, 'click', modalTrigger, false); + return new Modal(el); +}; + +/** + * Modal Constructor + * @param {Element} el + */ + +function Modal(el){ + this.el = el; + this.isShown = false; + this.bind(); +} + +Emitter(Modal.prototype); + +Modal.prototype.toggle = function(){ + if (this.isShown) this.hide(); + else this.show(); + return this; +}; + +Modal.prototype.bind = function(){ + this.events = events(this.el, this); + this.events.bind('click [data-modal-close]', 'hide'); +}; + +Modal.prototype.overlay = function(className){ + this._overlay = overlay(className || 'modal-dialogue'); + return this; +}; + +Modal.prototype.show = function(){ + if (this.isShown) return this; + this.previouslyFocused = document.activeElement; + this.isShown = true; + this.emit('showing'); + if (this._overlay) this._overlay.show(); + classes(this.el).add('modal-show'); + var self = this; + afterTransition(this.el, function(){ + self.emit('shown'); + }); + this.el.focus(); + return this; +}; + +Modal.prototype.hide = function(e){ + if (e) prevent(e); + if (!this.isShown) return this; + this.emit('hiding'); + if (this._overlay) this._overlay.hide(); + classes(this.el).remove('modal-show'); + this.previouslyFocused.focus(); + this.isShown = false; + var self = this; + afterTransition(this.el, function(){ + self.emit('hidden'); + }); + return this; +}; + +}); +require.register("modal/template.js", function(exports, require, module){ +module.exports = '
\n
\n
\n
\n
'; +}); + + + + + + + + + + + +require.alias("component-emitter/index.js", "modal/deps/emitter/index.js"); +require.alias("component-emitter/index.js", "emitter/index.js"); +require.alias("component-indexof/index.js", "component-emitter/deps/indexof/index.js"); + +require.alias("bmcmahen-overlay/index.js", "modal/deps/overlay/index.js"); +require.alias("bmcmahen-overlay/index.js", "overlay/index.js"); +require.alias("component-classes/index.js", "bmcmahen-overlay/deps/classes/index.js"); +require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js"); + +require.alias("component-emitter/index.js", "bmcmahen-overlay/deps/emitter/index.js"); +require.alias("component-indexof/index.js", "component-emitter/deps/indexof/index.js"); + +require.alias("anthonyshort-after-transition/index.js", "bmcmahen-overlay/deps/after-transition/index.js"); +require.alias("anthonyshort-after-transition/index.js", "bmcmahen-overlay/deps/after-transition/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-after-transition/deps/has-transitions/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-after-transition/deps/has-transitions/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-has-transitions/index.js"); +require.alias("anthonyshort-css-emitter/index.js", "anthonyshort-after-transition/deps/css-emitter/index.js"); +require.alias("component-emitter/index.js", "anthonyshort-css-emitter/deps/emitter/index.js"); +require.alias("component-indexof/index.js", "component-emitter/deps/indexof/index.js"); + +require.alias("component-event/index.js", "anthonyshort-css-emitter/deps/event/index.js"); + +require.alias("anthonyshort-after-transition/index.js", "anthonyshort-after-transition/index.js"); +require.alias("ianstormtaylor-redraw/index.js", "bmcmahen-overlay/deps/redraw/index.js"); + +require.alias("component-classes/index.js", "modal/deps/classes/index.js"); +require.alias("component-classes/index.js", "classes/index.js"); +require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js"); + +require.alias("anthonyshort-after-transition/index.js", "modal/deps/after-transition/index.js"); +require.alias("anthonyshort-after-transition/index.js", "modal/deps/after-transition/index.js"); +require.alias("anthonyshort-after-transition/index.js", "after-transition/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-after-transition/deps/has-transitions/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-after-transition/deps/has-transitions/index.js"); +require.alias("anthonyshort-has-transitions/index.js", "anthonyshort-has-transitions/index.js"); +require.alias("anthonyshort-css-emitter/index.js", "anthonyshort-after-transition/deps/css-emitter/index.js"); +require.alias("component-emitter/index.js", "anthonyshort-css-emitter/deps/emitter/index.js"); +require.alias("component-indexof/index.js", "component-emitter/deps/indexof/index.js"); + +require.alias("component-event/index.js", "anthonyshort-css-emitter/deps/event/index.js"); + +require.alias("anthonyshort-after-transition/index.js", "anthonyshort-after-transition/index.js"); +require.alias("component-events/index.js", "modal/deps/events/index.js"); +require.alias("component-events/index.js", "events/index.js"); +require.alias("component-event/index.js", "component-events/deps/event/index.js"); + +require.alias("component-delegate/index.js", "component-events/deps/delegate/index.js"); +require.alias("discore-closest/index.js", "component-delegate/deps/closest/index.js"); +require.alias("discore-closest/index.js", "component-delegate/deps/closest/index.js"); +require.alias("component-matches-selector/index.js", "discore-closest/deps/matches-selector/index.js"); +require.alias("component-query/index.js", "component-matches-selector/deps/query/index.js"); + +require.alias("discore-closest/index.js", "discore-closest/index.js"); +require.alias("component-event/index.js", "component-delegate/deps/event/index.js"); + +require.alias("component-delegate/index.js", "modal/deps/delegate/index.js"); +require.alias("component-delegate/index.js", "delegate/index.js"); +require.alias("discore-closest/index.js", "component-delegate/deps/closest/index.js"); +require.alias("discore-closest/index.js", "component-delegate/deps/closest/index.js"); +require.alias("component-matches-selector/index.js", "discore-closest/deps/matches-selector/index.js"); +require.alias("component-query/index.js", "component-matches-selector/deps/query/index.js"); + +require.alias("discore-closest/index.js", "discore-closest/index.js"); +require.alias("component-event/index.js", "component-delegate/deps/event/index.js"); + +require.alias("component-domify/index.js", "modal/deps/domify/index.js"); +require.alias("component-domify/index.js", "domify/index.js"); + +require.alias("javve-get-attribute/index.js", "modal/deps/get-attribute/index.js"); +require.alias("javve-get-attribute/index.js", "get-attribute/index.js"); + +require.alias("bmcmahen-target/index.js", "modal/deps/target/index.js"); +require.alias("bmcmahen-target/index.js", "modal/deps/target/index.js"); +require.alias("bmcmahen-target/index.js", "target/index.js"); +require.alias("bmcmahen-target/index.js", "bmcmahen-target/index.js"); +require.alias("yields-prevent/index.js", "modal/deps/prevent/index.js"); +require.alias("yields-prevent/index.js", "prevent/index.js"); +if (typeof exports == "object") { + module.exports = require("modal"); +} else if (typeof define == "function" && define.amd) { + define(function(){ return require("modal"); }); +} else { + this["modal"] = require("modal"); +}})(); \ No newline at end of file