diff --git a/static/scripts/common.js b/static/scripts/common.js index 8862eaac9d..f755399f45 100644 --- a/static/scripts/common.js +++ b/static/scripts/common.js @@ -36,7 +36,7 @@ require.config({ 'jquery.magnific-popup': 'lib/jquery.magnific-popup', - simplemodal: 'lib/jquery.simplemodal.1.4.4.min', + simplemodal: 'lib/jquery.simplemodal', jstree: 'lib/jstree.1.0', select2: 'lib/select2-3.5.2', diff --git a/static/scripts/lib/jquery.simplemodal.1.4.4.min.js b/static/scripts/lib/jquery.simplemodal.1.4.4.min.js deleted file mode 100644 index 382c7367f5..0000000000 --- a/static/scripts/lib/jquery.simplemodal.1.4.4.min.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SimpleModal 1.4.4 - jQuery Plugin - * http://simplemodal.com/ - * Copyright (c) 2013 Eric Martin - * Licensed under MIT and GPL - * Date: Sun, Jan 20 2013 15:58:56 -0800 - */ -(function(b){"function"===typeof define&&define.amd?define(["jquery"],b):b(jQuery)})(function(b){var j=[],n=b(document),k=navigator.userAgent.toLowerCase(),l=b(window),g=[],o=null,p=/msie/.test(k)&&!/opera/.test(k),q=/opera/.test(k),m,r;m=p&&/msie 6./.test(k)&&"object"!==typeof window.XMLHttpRequest;r=p&&/msie 7.0/.test(k);b.modal=function(a,h){return b.modal.impl.init(a,h)};b.modal.close=function(){b.modal.impl.close()};b.modal.focus=function(a){b.modal.impl.focus(a)};b.modal.setContainerDimensions= -function(){b.modal.impl.setContainerDimensions()};b.modal.setPosition=function(){b.modal.impl.setPosition()};b.modal.update=function(a,h){b.modal.impl.update(a,h)};b.fn.modal=function(a){return b.modal.impl.init(this,a)};b.modal.defaults={appendTo:"body",focus:!0,opacity:50,overlayId:"simplemodal-overlay",overlayCss:{},containerId:"simplemodal-container",containerCss:{},dataId:"simplemodal-data",dataCss:{},minHeight:null,minWidth:null,maxHeight:null,maxWidth:null,autoResize:!1,autoPosition:!0,zIndex:1E3, -close:!0,closeHTML:'',closeClass:"simplemodal-close",escClose:!0,overlayClose:!1,fixed:!0,position:null,persist:!1,modal:!0,onOpen:null,onShow:null,onClose:null};b.modal.impl={d:{},init:function(a,h){if(this.d.data)return!1;o=p&&!b.support.boxModel;this.o=b.extend({},b.modal.defaults,h);this.zIndex=this.o.zIndex;this.occb=!1;if("object"===typeof a){if(a=a instanceof b?a:b(a),this.d.placeholder=!1,0").attr("id", -"simplemodal-placeholder").css({display:"none"})),this.d.placeholder=!0,this.display=a.css("display"),!this.o.persist))this.d.orig=a.clone(!0)}else if("string"===typeof a||"number"===typeof a)a=b("
").html(a);else return alert("SimpleModal Error: Unsupported data type: "+typeof a),this;this.create(a);this.open();b.isFunction(this.o.onShow)&&this.o.onShow.apply(this,[this.d]);return this},create:function(a){this.getDimensions();if(this.o.modal&&m)this.d.iframe=b('').css(b.extend(this.o.iframeCss, -{display:"none",opacity:0,position:"fixed",height:g[0],width:g[1],zIndex:this.o.zIndex,top:0,left:0})).appendTo(this.o.appendTo);this.d.overlay=b("
").attr("id",this.o.overlayId).addClass("simplemodal-overlay").css(b.extend(this.o.overlayCss,{display:"none",opacity:this.o.opacity/100,height:this.o.modal?j[0]:0,width:this.o.modal?j[1]:0,position:"fixed",left:0,top:0,zIndex:this.o.zIndex+1})).appendTo(this.o.appendTo);this.d.container=b("
").attr("id",this.o.containerId).addClass("simplemodal-container").css(b.extend({position:this.o.fixed? -"fixed":"absolute"},this.o.containerCss,{display:"none",zIndex:this.o.zIndex+2})).append(this.o.close&&this.o.closeHTML?b(this.o.closeHTML).addClass(this.o.closeClass):"").appendTo(this.o.appendTo);this.d.wrap=b("
").attr("tabIndex",-1).addClass("simplemodal-wrap").css({height:"100%",outline:0,width:"100%"}).appendTo(this.d.container);this.d.data=a.attr("id",a.attr("id")||this.o.dataId).addClass("simplemodal-data").css(b.extend(this.o.dataCss,{display:"none"})).appendTo("body");this.setContainerDimensions(); -this.d.data.appendTo(this.d.wrap);(m||o)&&this.fixIE()},bindEvents:function(){var a=this;b("."+a.o.closeClass).bind("click.simplemodal",function(b){b.preventDefault();a.close()});a.o.modal&&a.o.close&&a.o.overlayClose&&a.d.overlay.bind("click.simplemodal",function(b){b.preventDefault();a.close()});n.bind("keydown.simplemodal",function(b){a.o.modal&&9===b.keyCode?a.watchTab(b):a.o.close&&a.o.escClose&&27===b.keyCode&&(b.preventDefault(),a.close())});l.bind("resize.simplemodal orientationchange.simplemodal", -function(){a.getDimensions();a.o.autoResize?a.setContainerDimensions():a.o.autoPosition&&a.setPosition();m||o?a.fixIE():a.o.modal&&(a.d.iframe&&a.d.iframe.css({height:g[0],width:g[1]}),a.d.overlay.css({height:j[0],width:j[1]}))})},unbindEvents:function(){b("."+this.o.closeClass).unbind("click.simplemodal");n.unbind("keydown.simplemodal");l.unbind(".simplemodal");this.d.overlay.unbind("click.simplemodal")},fixIE:function(){var a=this.o.position;b.each([this.d.iframe||null,!this.o.modal?null:this.d.overlay, -"fixed"===this.d.container.css("position")?this.d.container:null],function(b,e){if(e){var f=e[0].style;f.position="absolute";if(2>b)f.removeExpression("height"),f.removeExpression("width"),f.setExpression("height",'document.body.scrollHeight > document.body.clientHeight ? document.body.scrollHeight : document.body.clientHeight + "px"'),f.setExpression("width",'document.body.scrollWidth > document.body.clientWidth ? document.body.scrollWidth : document.body.clientWidth + "px"');else{var c,d;a&&a.constructor=== -Array?(c=a[0]?"number"===typeof a[0]?a[0].toString():a[0].replace(/px/,""):e.css("top").replace(/px/,""),c=-1===c.indexOf("%")?c+' + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"':parseInt(c.replace(/%/,""))+' * ((document.documentElement.clientHeight || document.body.clientHeight) / 100) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"',a[1]&&(d="number"===typeof a[1]? -a[1].toString():a[1].replace(/px/,""),d=-1===d.indexOf("%")?d+' + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"':parseInt(d.replace(/%/,""))+' * ((document.documentElement.clientWidth || document.body.clientWidth) / 100) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"')):(c='(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (t = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"', -d='(document.documentElement.clientWidth || document.body.clientWidth) / 2 - (this.offsetWidth / 2) + (t = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + "px"');f.removeExpression("top");f.removeExpression("left");f.setExpression("top",c);f.setExpression("left",d)}}})},focus:function(a){var h=this,a=a&&-1!==b.inArray(a,["first","last"])?a:"first",e=b(":input:enabled:visible:"+a,h.d.wrap);setTimeout(function(){0c?c:bc?c:this.o.minHeight&&"auto"!==i&&ed?d:ad?d:this.o.minWidth&&"auto"!==c&&fb||f>a?"auto":"visible"});this.o.autoPosition&&this.setPosition()},setPosition:function(){var a,b;a=g[0]/2-this.d.container.outerHeight(!0)/2;b=g[1]/2-this.d.container.outerWidth(!0)/2;var e="fixed"!==this.d.container.css("position")?l.scrollTop():0;this.o.position&&"[object Array]"===Object.prototype.toString.call(this.o.position)?(a=e+(this.o.position[0]||a),b=this.o.position[1]||b): -a=e+a;this.d.container.css({left:b,top:a})},watchTab:function(a){if(0my data').modal({options}); + * @example $('#myDiv').modal({options}); + * @example jQueryObject.modal({options}); + * + * 2) As a stand-alone function, like $.modal(data). The data parameter + * is required and an optional options object can be passed as a second + * parameter. This method provides more flexibility in the types of data + * that are allowed. The data could be a DOM object, a jQuery object, HTML + * or a string. + * + * @example $.modal('
my data
', {options}); + * @example $.modal('my data', {options}); + * @example $.modal($('#myDiv'), {options}); + * @example $.modal(jQueryObject, {options}); + * @example $.modal(document.getElementById('myDiv'), {options}); + * + * A SimpleModal call can contain multiple elements, but only one modal + * dialog can be created at a time. Which means that all of the matched + * elements will be displayed within the modal container. + * + * SimpleModal internally sets the CSS needed to display the modal dialog + * properly in all browsers, yet provides the developer with the flexibility + * to easily control the look and feel. The styling for SimpleModal can be + * done through external stylesheets, or through SimpleModal, using the + * overlayCss, containerCss, and dataCss options. + * + * SimpleModal has been tested in the following browsers: + * - IE 6+ + * - Firefox 2+ + * - Opera 9+ + * - Safari 3+ + * - Chrome 1+ + * + * @name SimpleModal + * @type jQuery + * @requires jQuery v1.3 + * @cat Plugins/Windows and Overlays + * @author Eric Martin (http://ericmmartin.com) + * @version @VERSION + */ + +;(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else { + // Browser globals + factory(jQuery); + } +} +(function ($) { + var d = [], + doc = $(document), + ua = navigator.userAgent.toLowerCase(), + wndw = $(window), + w = []; + + var browser = { + ieQuirks: null, + msie: /msie/.test(ua) && !/opera/.test(ua), + opera: /opera/.test(ua) + }; + browser.ie6 = browser.msie && /msie 6./.test(ua) && typeof window['XMLHttpRequest'] !== 'object'; + browser.ie7 = browser.msie && /msie 7.0/.test(ua); + browser.boxModel = (document.compatMode === "CSS1Compat"); + + /* + * Create and display a modal dialog. + * + * @param {string, object} data A string, jQuery object or DOM object + * @param {object} [options] An optional object containing options overrides + */ + $.modal = function (data, options) { + return $.modal.impl.init(data, options); + }; + + /* + * Close the modal dialog. + */ + $.modal.close = function () { + $.modal.impl.close(); + }; + + /* + * Set focus on first or last visible input in the modal dialog. To focus on the last + * element, call $.modal.focus('last'). If no input elements are found, focus is placed + * on the data wrapper element. + */ + $.modal.focus = function (pos) { + $.modal.impl.focus(pos); + }; + + /* + * Determine and set the dimensions of the modal dialog container. + * setPosition() is called if the autoPosition option is true. + */ + $.modal.setContainerDimensions = function () { + $.modal.impl.setContainerDimensions(); + }; + + /* + * Re-position the modal dialog. + */ + $.modal.setPosition = function () { + $.modal.impl.setPosition(); + }; + + /* + * Update the modal dialog. If new dimensions are passed, they will be used to determine + * the dimensions of the container. + * + * setContainerDimensions() is called, which in turn calls setPosition(), if enabled. + * Lastly, focus() is called is the focus option is true. + */ + $.modal.update = function (height, width) { + $.modal.impl.update(height, width); + }; + + /* + * Chained function to create a modal dialog. + * + * @param {object} [options] An optional object containing options overrides + */ + $.fn.modal = function (options) { + return $.modal.impl.init(this, options); + }; + + /* + * SimpleModal default options + * + * appendTo: (String:'body') The jQuery selector to append the elements to. For .NET, use 'form'. + * focus: (Boolean:true) Focus in the first visible, enabled element? + * opacity: (Number:50) The opacity value for the overlay div, from 0 - 100 + * overlayId: (String:'simplemodal-overlay') The DOM element id for the overlay div + * overlayCss: (Object:{}) The CSS styling for the overlay div + * containerId: (String:'simplemodal-container') The DOM element id for the container div + * containerCss: (Object:{}) The CSS styling for the container div + * dataId: (String:'simplemodal-data') The DOM element id for the data div + * dataCss: (Object:{}) The CSS styling for the data div + * minHeight: (Number:null) The minimum height for the container + * minWidth: (Number:null) The minimum width for the container + * maxHeight: (Number:null) The maximum height for the container. If not specified, the window height is used. + * maxWidth: (Number:null) The maximum width for the container. If not specified, the window width is used. + * autoResize: (Boolean:false) Automatically resize the container if it exceeds the browser window dimensions? + * autoPosition: (Boolean:true) Automatically position the container upon creation and on window resize? + * zIndex: (Number: 1000) Starting z-index value + * close: (Boolean:true) If true, closeHTML, escClose and overClose will be used if set. + If false, none of them will be used. + * closeHTML: (String:'') The HTML for the default close link. + SimpleModal will automatically add the closeClass to this element. + * closeClass: (String:'simplemodal-close') The CSS class used to bind to the close event + * escClose: (Boolean:true) Allow Esc keypress to close the dialog? + * overlayClose: (Boolean:false) Allow click on overlay to close the dialog? + * fixed: (Boolean:true) If true, the container will use a fixed position. If false, it will use a + absolute position (the dialog will scroll with the page) + * position: (Array:null) Position of container [top, left]. Can be number of pixels or percentage + * persist: (Boolean:false) Persist the data across modal calls? Only used for existing + DOM elements. If true, the data will be maintained across modal calls, if false, + the data will be reverted to its original state. + * modal: (Boolean:true) User will be unable to interact with the page below the modal or tab away from the dialog. + If false, the overlay, iframe, and certain events will be disabled allowing the user to interact + with the page below the dialog. + * onOpen: (Function:null) The callback function used in place of SimpleModal's open + * onShow: (Function:null) The callback function used after the modal dialog has opened + * onClose: (Function:null) The callback function used in place of SimpleModal's close + */ + $.modal.defaults = { + appendTo: 'body', + focus: true, + opacity: 50, + overlayId: 'simplemodal-overlay', + overlayCss: {}, + containerId: 'simplemodal-container', + containerCss: {}, + dataId: 'simplemodal-data', + dataCss: {}, + minHeight: null, + minWidth: null, + maxHeight: null, + maxWidth: null, + autoResize: false, + autoPosition: true, + zIndex: 1000, + close: true, + closeHTML: '', + closeClass: 'simplemodal-close', + escClose: true, + overlayClose: false, + fixed: true, + position: null, + persist: false, + modal: true, + onOpen: null, + onShow: null, + onClose: null + }; + + /* + * Main modal object + * o = options + */ + $.modal.impl = { + /* + * Contains the modal dialog elements and is the object passed + * back to the callback (onOpen, onShow, onClose) functions + */ + d: {}, + /* + * Initialize the modal dialog + */ + init: function (data, options) { + var s = this; + + // don't allow multiple calls + if (s.d.data) { + return false; + } + + browser.ieQuirks = browser.msie && !browser.boxModel; + + // merge defaults and user options + s.o = $.extend({}, $.modal.defaults, options); + + // keep track of z-index + s.zIndex = s.o.zIndex; + + // set the onClose callback flag + s.occb = false; + + // determine how to handle the data based on its type + if (typeof data === 'object') { + // convert DOM object to a jQuery object + data = data instanceof $ ? data : $(data); + s.d.placeholder = false; + + // if the object came from the DOM, keep track of its parent + if (data.parent().parent().size() > 0) { + data.before($('') + .attr('id', 'simplemodal-placeholder') + .css({display: 'none'})); + + s.d.placeholder = true; + s.display = data.css('display'); + + // persist changes? if not, make a clone of the element + if (!s.o.persist) { + s.d.orig = data.clone(true); + } + } + } + else if (typeof data === 'string' || typeof data === 'number') { + // just insert the data as innerHTML + data = $('
').html(data); + } + else { + // unsupported data type! + alert('SimpleModal Error: Unsupported data type: ' + typeof data); + return s; + } + + // create the modal overlay, container and, if necessary, iframe + s.create(data); + data = null; + + // display the modal dialog + s.open(); + + // useful for adding events/manipulating data in the modal dialog + if ($.isFunction(s.o.onShow)) { + s.o.onShow.apply(s, [s.d]); + } + + // don't break the chain =) + return s; + }, + /* + * Create and add the modal overlay and container to the page + */ + create: function (data) { + var s = this; + + // get the window properties + s.getDimensions(); + + // add an iframe to prevent select options from bleeding through + if (s.o.modal && browser.ie6) { + s.d.iframe = $('') + .css($.extend(s.o.iframeCss, { + display: 'none', + opacity: 0, + position: 'fixed', + height: w[0], + width: w[1], + zIndex: s.o.zIndex, + top: 0, + left: 0 + })) + .appendTo(s.o.appendTo); + } + + // create the overlay + s.d.overlay = $('
') + .attr('id', s.o.overlayId) + .addClass('simplemodal-overlay') + .css($.extend(s.o.overlayCss, { + display: 'none', + opacity: s.o.opacity / 100, + height: s.o.modal ? d[0] : 0, + width: s.o.modal ? d[1] : 0, + position: 'fixed', + left: 0, + top: 0, + zIndex: s.o.zIndex + 1 + })) + .appendTo(s.o.appendTo); + + // create the container + s.d.container = $('
') + .attr('id', s.o.containerId) + .addClass('simplemodal-container') + .css($.extend( + {position: s.o.fixed ? 'fixed' : 'absolute'}, + s.o.containerCss, + {display: 'none', zIndex: s.o.zIndex + 2} + )) + .append(s.o.close && s.o.closeHTML + ? $(s.o.closeHTML).addClass(s.o.closeClass) + : '') + .appendTo(s.o.appendTo); + + s.d.wrap = $('
') + .attr('tabIndex', -1) + .addClass('simplemodal-wrap') + .css({height: '100%', outline: 0, width: '100%'}) + .appendTo(s.d.container); + + // add styling and attributes to the data + // append to body to get correct dimensions, then move to wrap + s.d.data = data + .attr('id', data.attr('id') || s.o.dataId) + .addClass('simplemodal-data') + .css($.extend(s.o.dataCss, { + display: 'none' + })) + .appendTo('body'); + data = null; + + s.setContainerDimensions(); + s.d.data.appendTo(s.d.wrap); + + // fix issues with IE + if (browser.ie6 || browser.ieQuirks) { + s.fixIE(); + } + }, + /* + * Bind events + */ + bindEvents: function () { + var s = this; + + // bind the close event to any element with the closeClass class + $('.' + s.o.closeClass).bind('click.simplemodal', function (e) { + e.preventDefault(); + s.close(); + }); + + // bind the overlay click to the close function, if enabled + if (s.o.modal && s.o.close && s.o.overlayClose) { + s.d.overlay.bind('click.simplemodal', function (e) { + e.preventDefault(); + s.close(); + }); + } + + // bind keydown events + doc.bind('keydown.simplemodal', function (e) { + if (s.o.modal && e.keyCode === 9) { // TAB + s.watchTab(e); + } + else if ((s.o.close && s.o.escClose) && e.keyCode === 27) { // ESC + e.preventDefault(); + s.close(); + } + }); + + // update window size + wndw.bind('resize.simplemodal orientationchange.simplemodal', function () { + // redetermine the window width/height + s.getDimensions(); + + // reposition the dialog + s.o.autoResize ? s.setContainerDimensions() : s.o.autoPosition && s.setPosition(); + + if (browser.ie6 || browser.ieQuirks) { + s.fixIE(); + } + else if (s.o.modal) { + // update the iframe & overlay + s.d.iframe && s.d.iframe.css({height: w[0], width: w[1]}); + s.d.overlay.css({height: d[0], width: d[1]}); + } + }); + }, + /* + * Unbind events + */ + unbindEvents: function () { + $('.' + this.o.closeClass).unbind('click.simplemodal'); + doc.unbind('keydown.simplemodal'); + wndw.unbind('.simplemodal'); + this.d.overlay.unbind('click.simplemodal'); + }, + /* + * Fix issues in IE6 and IE7 in quirks mode + */ + fixIE: function () { + var s = this, p = s.o.position; + + // simulate fixed position - adapted from BlockUI + $.each([s.d.iframe || null, !s.o.modal ? null : s.d.overlay, s.d.container.css('position') === 'fixed' ? s.d.container : null], function (i, el) { + if (el) { + var bch = 'document.body.clientHeight', bcw = 'document.body.clientWidth', + bsh = 'document.body.scrollHeight', bsl = 'document.body.scrollLeft', + bst = 'document.body.scrollTop', bsw = 'document.body.scrollWidth', + ch = 'document.documentElement.clientHeight', cw = 'document.documentElement.clientWidth', + sl = 'document.documentElement.scrollLeft', st = 'document.documentElement.scrollTop', + s = el[0].style; + + s.position = 'absolute'; + if (i < 2) { + s.removeExpression('height'); + s.removeExpression('width'); + s.setExpression('height','' + bsh + ' > ' + bch + ' ? ' + bsh + ' : ' + bch + ' + "px"'); + s.setExpression('width','' + bsw + ' > ' + bcw + ' ? ' + bsw + ' : ' + bcw + ' + "px"'); + } + else { + var te, le; + if (p && p.constructor === Array) { + var top = p[0] + ? typeof p[0] === 'number' ? p[0].toString() : p[0].replace(/px/, '') + : el.css('top').replace(/px/, ''); + te = top.indexOf('%') === -1 + ? top + ' + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"' + : parseInt(top.replace(/%/, '')) + ' * ((' + ch + ' || ' + bch + ') / 100) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'; + + if (p[1]) { + var left = typeof p[1] === 'number' ? p[1].toString() : p[1].replace(/px/, ''); + le = left.indexOf('%') === -1 + ? left + ' + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"' + : parseInt(left.replace(/%/, '')) + ' * ((' + cw + ' || ' + bcw + ') / 100) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'; + } + } + else { + te = '(' + ch + ' || ' + bch + ') / 2 - (this.offsetHeight / 2) + (t = ' + st + ' ? ' + st + ' : ' + bst + ') + "px"'; + le = '(' + cw + ' || ' + bcw + ') / 2 - (this.offsetWidth / 2) + (t = ' + sl + ' ? ' + sl + ' : ' + bsl + ') + "px"'; + } + s.removeExpression('top'); + s.removeExpression('left'); + s.setExpression('top', te); + s.setExpression('left', le); + } + } + }); + }, + /* + * Place focus on the first or last visible input + */ + focus: function (pos) { + var s = this, p = pos && $.inArray(pos, ['first', 'last']) !== -1 ? pos : 'first'; + + // focus on dialog or the first visible/enabled input element + var input = $(':input:enabled:visible:' + p, s.d.wrap); + setTimeout(function () { + input.length > 0 ? input.focus() : s.d.wrap.focus(); + }, 10); + }, + getDimensions: function () { + // fix a jQuery bug with determining the window height - use innerHeight if available + var s = this, + h = typeof window.innerHeight === 'undefined' ? wndw.height() : window.innerHeight; + + d = [doc.height(), doc.width()]; + w = [h, wndw.width()]; + }, + getVal: function (v, d) { + return v ? (typeof v === 'number' ? v + : v === 'auto' ? 0 + : v.indexOf('%') > 0 ? ((parseInt(v.replace(/%/, '')) / 100) * (d === 'h' ? w[0] : w[1])) + : parseInt(v.replace(/px/, ''))) + : null; + }, + /* + * Update the container. Set new dimensions, if provided. + * Focus, if enabled. Re-bind events. + */ + update: function (height, width) { + var s = this; + + // prevent update if dialog does not exist + if (!s.d.data) { + return false; + } + + // reset orig values + s.d.origHeight = s.getVal(height, 'h'); + s.d.origWidth = s.getVal(width, 'w'); + + // hide data to prevent screen flicker + s.d.data.hide(); + height && s.d.container.css('height', height); + width && s.d.container.css('width', width); + s.setContainerDimensions(); + s.d.data.show(); + s.o.focus && s.focus(); + + // rebind events + s.unbindEvents(); + s.bindEvents(); + }, + setContainerDimensions: function () { + var s = this, + badIE = browser.ie6 || browser.ie7; + + // get the dimensions for the container and data + var ch = s.d.origHeight ? s.d.origHeight : browser.opera ? s.d.container.height() : s.getVal(badIE ? s.d.container[0].currentStyle['height'] : s.d.container.css('height'), 'h'), + cw = s.d.origWidth ? s.d.origWidth : browser.opera ? s.d.container.width() : s.getVal(badIE ? s.d.container[0].currentStyle['width'] : s.d.container.css('width'), 'w'), + dh = s.d.data.outerHeight(true), dw = s.d.data.outerWidth(true); + + s.d.origHeight = s.d.origHeight || ch; + s.d.origWidth = s.d.origWidth || cw; + + // mxoh = max option height, mxow = max option width + var mxoh = s.o.maxHeight ? s.getVal(s.o.maxHeight, 'h') : null, + mxow = s.o.maxWidth ? s.getVal(s.o.maxWidth, 'w') : null, + mh = mxoh && mxoh < w[0] ? mxoh : w[0], + mw = mxow && mxow < w[1] ? mxow : w[1]; + + // moh = min option height + var moh = s.o.minHeight ? s.getVal(s.o.minHeight, 'h') : 'auto'; + if (!ch) { + if (!dh) {ch = moh;} + else { + if (dh > mh) {ch = mh;} + else if (s.o.minHeight && moh !== 'auto' && dh < moh) {ch = moh;} + else {ch = dh;} + } + } + else { + ch = s.o.autoResize && ch > mh ? mh : ch < moh ? moh : ch; + } + + // mow = min option width + var mow = s.o.minWidth ? s.getVal(s.o.minWidth, 'w') : 'auto'; + if (!cw) { + if (!dw) {cw = mow;} + else { + if (dw > mw) {cw = mw;} + else if (s.o.minWidth && mow !== 'auto' && dw < mow) {cw = mow;} + else {cw = dw;} + } + } + else { + cw = s.o.autoResize && cw > mw ? mw : cw < mow ? mow : cw; + } + + s.d.container.css({height: ch, width: cw}); + s.d.wrap.css({overflow: (dh > ch || dw > cw) ? 'auto' : 'visible'}); + s.o.autoPosition && s.setPosition(); + }, + setPosition: function () { + var s = this, top, left, + hc = (w[0]/2) - (s.d.container.outerHeight(true)/2), + vc = (w[1]/2) - (s.d.container.outerWidth(true)/2), + st = s.d.container.css('position') !== 'fixed' ? wndw.scrollTop() : 0; + + if (s.o.position && Object.prototype.toString.call(s.o.position) === '[object Array]') { + top = st + (s.o.position[0] || hc); + left = s.o.position[1] || vc; + } else { + top = st + hc; + left = vc; + } + s.d.container.css({left: left, top: top}); + }, + watchTab: function (e) { + var s = this; + + if ($(e.target).parents('.simplemodal-container').length > 0) { + // save the list of inputs + s.inputs = $(':input:enabled:visible:first, :input:enabled:visible:last', s.d.data[0]); + + // if it's the first or last tabbable element, refocus + if ((!e.shiftKey && e.target === s.inputs[s.inputs.length -1]) || + (e.shiftKey && e.target === s.inputs[0]) || + s.inputs.length === 0) { + e.preventDefault(); + var pos = e.shiftKey ? 'last' : 'first'; + s.focus(pos); + } + } + else { + // might be necessary when custom onShow callback is used + e.preventDefault(); + s.focus(); + } + }, + /* + * Open the modal dialog elements + * - Note: If you use the onOpen callback, you must "show" the + * overlay and container elements manually + * (the iframe will be handled by SimpleModal) + */ + open: function () { + var s = this; + // display the iframe + s.d.iframe && s.d.iframe.show(); + + if ($.isFunction(s.o.onOpen)) { + // execute the onOpen callback + s.o.onOpen.apply(s, [s.d]); + } + else { + // display the remaining elements + s.d.overlay.show(); + s.d.container.show(); + s.d.data.show(); + } + + s.o.focus && s.focus(); + + // bind default events + s.bindEvents(); + }, + /* + * Close the modal dialog + * - Note: If you use an onClose callback, you must remove the + * overlay, container and iframe elements manually + * + * @param {boolean} external Indicates whether the call to this + * function was internal or external. If it was external, the + * onClose callback will be ignored + */ + close: function () { + var s = this; + + // prevent close when dialog does not exist + if (!s.d.data) { + return false; + } + + // remove the default events + s.unbindEvents(); + + if ($.isFunction(s.o.onClose) && !s.occb) { + // set the onClose callback flag + s.occb = true; + + // execute the onClose callback + s.o.onClose.apply(s, [s.d]); + } + else { + // if the data came from the DOM, put it back + if (s.d.placeholder) { + var ph = $('#simplemodal-placeholder'); + // save changes to the data? + if (s.o.persist) { + // insert the (possibly) modified data back into the DOM + ph.replaceWith(s.d.data.removeClass('simplemodal-data').css('display', s.display)); + } + else { + // remove the current and insert the original, + // unmodified data back into the DOM + s.d.data.hide().remove(); + ph.replaceWith(s.d.orig); + } + } + else { + // otherwise, remove it + s.d.data.hide().remove(); + } + + // remove the remaining elements + s.d.container.hide().remove(); + s.d.overlay.hide(); + s.d.iframe && s.d.iframe.hide().remove(); + s.d.overlay.remove(); + + // reset the dialog object + s.d = {}; + } + } + }; +}));