[Import jquery ui clinton@unknownlamer.org**20081216080040] addfile ./static/js/jquery/ui/ui.datepicker.js hunk ./static/js/jquery/ui/ui.datepicker.js 1 +/* + * jQuery UI Datepicker @VERSION + * + * Copyright (c) 2006, 2007, 2008 Marc Grabanski + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * ui.core.js + * + * Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au). + */ + +(function($) { // hide the namespace + +var PROP_NAME = 'datepicker'; + +/* Date picker manager. + Use the singleton instance of this class, $.datepicker, to interact with the date picker. + Settings for (groups of) date pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Datepicker() { + this.debug = false; // Change this to true to start debugging + this._curInst = null; // The current instance in use + this._disabledInputs = []; // List of date picker inputs that have been disabled + this._datepickerShowing = false; // True if the popup picker is showing , false if not + this._inDialog = false; // True if showing within a "dialog", false if not + this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division + this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class + this._appendClass = 'ui-datepicker-append'; // The name of the append marker class + this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class + this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class + this._promptClass = 'ui-datepicker-prompt'; // The name of the dialog prompt marker class + this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class + this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class + this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + clearText: 'Clear', // Display text for clear link + clearStatus: 'Erase the current date', // Status text for clear link + closeText: 'Close', // Display text for close link + closeStatus: 'Close without change', // Status text for close link + prevText: '<Prev', // Display text for previous month link + prevStatus: 'Show the previous month', // Status text for previous month link + prevBigText: '<<', // Display text for previous year link + prevBigStatus: 'Show the previous year', // Status text for previous year link + nextText: 'Next>', // Display text for next month link + nextStatus: 'Show the next month', // Status text for next month link + nextBigText: '>>', // Display text for next year link + nextBigStatus: 'Show the next year', // Status text for next year link + currentText: 'Today', // Display text for current month link + currentStatus: 'Show the current month', // Status text for current month link + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], // Names of months for drop-down and formatting + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting + monthStatus: 'Show a different month', // Status text for selecting a month + yearStatus: 'Show a different year', // Status text for selecting a year + weekHeader: 'Wk', // Header for the week of the year column + weekStatus: 'Week of the year', // Status text for the week of the year column + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday + dayStatus: 'Set DD as first week day', // Status text for the day of the week selection + dateStatus: 'Select DD, M d', // Status text for the date selection + dateFormat: 'mm/dd/yy', // See format options on parseDate + firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... + initStatus: 'Select a date', // Initial Status text on opening + isRTL: false // True if right-to-left language, false if left-to-right + }; + this._defaults = { // Global defaults for all the date picker instances + showOn: 'focus', // 'focus' for popup on focus, + // 'button' for trigger button, or 'both' for either + showAnim: 'show', // Name of jQuery animation for popup + showOptions: {}, // Options for enhanced animations + defaultDate: null, // Used when field is blank: actual date, + // +/-number for offset from today, null for today + appendText: '', // Display text following the input box, e.g. showing the format + buttonText: '...', // Text for trigger button + buttonImage: '', // URL for trigger button image + buttonImageOnly: false, // True if the image appears alone, false if it appears on a button + closeAtTop: true, // True to have the clear/close at the top, + // false to have them at the bottom + mandatory: false, // True to hide the Clear link, false to include it + hideIfNoPrevNext: false, // True to hide next/previous month links + // if not applicable, false to just disable them + navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links + showBigPrevNext: false, // True to show big prev/next links + gotoCurrent: false, // True if today link goes back to current selection instead + changeMonth: true, // True if month can be selected directly, false if only prev/next + changeYear: true, // True if year can be selected directly, false if only prev/next + showMonthAfterYear: false, // True if the year select precedes month, false for month then year + yearRange: '-10:+10', // Range of years to display in drop-down, + // either relative to current year (-nn:+nn) or absolute (nnnn:nnnn) + changeFirstDay: true, // True to click on day name to change, false to remain as set + highlightWeek: false, // True to highlight the selected week + showOtherMonths: false, // True to show dates in other months, false to leave blank + showWeeks: false, // True to show week of the year, false to omit + calculateWeek: this.iso8601Week, // How to calculate the week of the year, + // takes a Date and returns the number of the week for it + shortYearCutoff: '+10', // Short year values < this are in the current century, + // > this are in the previous century, + // string value starting with '+' for current year + value + showStatus: false, // True to show status bar at bottom, false to not show it + statusForDate: this.dateStatus, // Function to provide status text for a date - + // takes date and instance as parameters, returns display text + minDate: null, // The earliest selectable date, or null for no limit + maxDate: null, // The latest selectable date, or null for no limit + duration: 'normal', // Duration of display/closure + beforeShowDay: null, // Function that takes a date and returns an array with + // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', + // [2] = cell title (optional), e.g. $.datepicker.noWeekends + beforeShow: null, // Function that takes an input field and + // returns a set of custom settings for the date picker + onSelect: null, // Define a callback function when a date is selected + onChangeMonthYear: null, // Define a callback function when the month or year is changed + onClose: null, // Define a callback function when the datepicker is closed + numberOfMonths: 1, // Number of months to show at a time + showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) + stepMonths: 1, // Number of months to step back/forward + stepBigMonths: 12, // Number of months to step back/forward for the big links + rangeSelect: false, // Allows for selecting a date range on one date picker + rangeSeparator: ' - ', // Text between two dates in a range + altField: '', // Selector for an alternate field to store selected dates into + altFormat: '' // The date format to use for the alternate field + }; + $.extend(this._defaults, this.regional['']); + this.dpDiv = $(''); +} + +$.extend(Datepicker.prototype, { + /* Class name added to elements to indicate already configured with a date picker. */ + markerClassName: 'hasDatepicker', + + /* Debug logging (if enabled). */ + log: function () { + if (this.debug) + console.log.apply('', arguments); + }, + + /* Override the default settings for all instances of the date picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + /* Attach the date picker to a jQuery selection. + @param target element - the target input field or division or span + @param settings object - the new settings to use for this date picker instance (anonymous) */ + _attachDatepicker: function(target, settings) { + // check for settings on the control itself - in namespace 'date:' + var inlineSettings = null; + for (attrName in this._defaults) { + var attrValue = target.getAttribute('date:' + attrName); + if (attrValue) { + inlineSettings = inlineSettings || {}; + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + var nodeName = target.nodeName.toLowerCase(); + var inline = (nodeName == 'div' || nodeName == 'span'); + if (!target.id) + target.id = 'dp' + (++this.uuid); + var inst = this._newInst($(target), inline); + inst.settings = $.extend({}, settings || {}, inlineSettings || {}); + if (nodeName == 'input') { + this._connectDatepicker(target, inst); + } else if (inline) { + this._inlineDatepicker(target, inst); + } + }, + + /* Create a new instance object. */ + _newInst: function(target, inline) { + var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars + return {id: id, input: target, // associated target + selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection + drawMonth: 0, drawYear: 0, // month being drawn + inline: inline, // is datepicker inline or not + dpDiv: (!inline ? this.dpDiv : // presentation div + $('
'))}; + }, + + /* Attach the date picker to an input field. */ + _connectDatepicker: function(target, inst) { + var input = $(target); + if (input.hasClass(this.markerClassName)) + return; + var appendText = this._get(inst, 'appendText'); + var isRTL = this._get(inst, 'isRTL'); + if (appendText) + input[isRTL ? 'before' : 'after']('' + appendText + ''); + var showOn = this._get(inst, 'showOn'); + if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field + input.focus(this._showDatepicker); + if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked + var buttonText = this._get(inst, 'buttonText'); + var buttonImage = this._get(inst, 'buttonImage'); + var trigger = $(this._get(inst, 'buttonImageOnly') ? + $('').addClass(this._triggerClass). + attr({ src: buttonImage, alt: buttonText, title: buttonText }) : + $('').addClass(this._triggerClass). + html(buttonImage == '' ? buttonText : $('').attr( + { src:buttonImage, alt:buttonText, title:buttonText }))); + input[isRTL ? 'before' : 'after'](trigger); + trigger.click(function() { + if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target) + $.datepicker._hideDatepicker(); + else + $.datepicker._showDatepicker(target); + return false; + }); + } + input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress). + bind("setData.datepicker", function(event, key, value) { + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key) { + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + }, + + /* Attach an inline date picker to a div. */ + _inlineDatepicker: function(target, inst) { + var divSpan = $(target); + if (divSpan.hasClass(this.markerClassName)) + return; + divSpan.addClass(this.markerClassName).append(inst.dpDiv). + bind("setData.datepicker", function(event, key, value){ + inst.settings[key] = value; + }).bind("getData.datepicker", function(event, key){ + return this._get(inst, key); + }); + $.data(target, PROP_NAME, inst); + this._setDate(inst, this._getDefaultDate(inst)); + this._updateDatepicker(inst); + }, + + /* Tidy up after displaying the date picker. */ + _inlineShow: function(inst) { + var numMonths = this._getNumberOfMonths(inst); // fix width for dynamic number of date pickers + inst.dpDiv.width(numMonths[1] * $('.ui-datepicker', inst.dpDiv[0]).width()); + }, + + /* Pop-up the date picker in a "dialog" box. + @param input element - ignored + @param dateText string - the initial date to display (in the current format) + @param onSelect function - the function(dateText) to call when a date is selected + @param settings object - update the dialog date picker instance's settings (anonymous object) + @param pos int[2] - coordinates for the dialog's position within the screen or + event - with x/y coordinates or + leave empty for default (screen centre) + @return the manager object */ + _dialogDatepicker: function(input, dateText, onSelect, settings, pos) { + var inst = this._dialogInst; // internal instance + if (!inst) { + var id = 'dp' + (++this.uuid); + this._dialogInput = $(''); + this._dialogInput.keydown(this._doKeyDown); + $('body').append(this._dialogInput); + inst = this._dialogInst = this._newInst(this._dialogInput, false); + inst.settings = {}; + $.data(this._dialogInput[0], PROP_NAME, inst); + } + extendRemove(inst.settings, settings || {}); + this._dialogInput.val(dateText); + + this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); + if (!this._pos) { + var browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; + var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + this._pos = // should use actual width/height below + [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; + } + + // move input on screen for focus, but hidden behind dialog + this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px'); + inst.settings.onSelect = onSelect; + this._inDialog = true; + this.dpDiv.addClass(this._dialogClass); + this._showDatepicker(this._dialogInput[0]); + if ($.blockUI) + $.blockUI(this.dpDiv); + $.data(this._dialogInput[0], PROP_NAME, inst); + return this; + }, + + /* Detach a datepicker from its control. + @param target element - the target input field or division or span */ + _destroyDatepicker: function(target) { + var $target = $(target); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + $.removeData(target, PROP_NAME); + if (nodeName == 'input') { + $target.siblings('.' + this._appendClass).remove().end(). + siblings('.' + this._triggerClass).remove().end(). + removeClass(this.markerClassName). + unbind('focus', this._showDatepicker). + unbind('keydown', this._doKeyDown). + unbind('keypress', this._doKeyPress); + } else if (nodeName == 'div' || nodeName == 'span') + $target.removeClass(this.markerClassName).empty(); + }, + + /* Enable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _enableDatepicker: function(target) { + var $target = $(target); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = false; + $target.siblings('button.' + this._triggerClass). + each(function() { this.disabled = false; }).end(). + siblings('img.' + this._triggerClass). + css({opacity: '1.0', cursor: ''}); + } + else if (nodeName == 'div' || nodeName == 'span') { + $target.children('.' + this._disableClass).remove(); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + }, + + /* Disable the date picker to a jQuery selection. + @param target element - the target input field or division or span */ + _disableDatepicker: function(target) { + var $target = $(target); + if (!$target.hasClass(this.markerClassName)) { + return; + } + var nodeName = target.nodeName.toLowerCase(); + if (nodeName == 'input') { + target.disabled = true; + $target.siblings('button.' + this._triggerClass). + each(function() { this.disabled = true; }).end(). + siblings('img.' + this._triggerClass). + css({opacity: '0.5', cursor: 'default'}); + } + else if (nodeName == 'div' || nodeName == 'span') { + var inline = $target.children('.' + this._inlineClass); + var offset = inline.offset(); + var relOffset = {left: 0, top: 0}; + inline.parents().each(function() { + if ($(this).css('position') == 'relative') { + relOffset = $(this).offset(); + return false; + } + }); + $target.prepend('
'); + } + this._disabledInputs = $.map(this._disabledInputs, + function(value) { return (value == target ? null : value); }); // delete entry + this._disabledInputs[this._disabledInputs.length] = target; + }, + + /* Is the first field in a jQuery collection disabled as a datepicker? + @param target element - the target input field or division or span + @return boolean - true if disabled, false if enabled */ + _isDisabledDatepicker: function(target) { + if (!target) + return false; + for (var i = 0; i < this._disabledInputs.length; i++) { + if (this._disabledInputs[i] == target) + return true; + } + return false; + }, + + /* Retrieve the instance data for the target control. + @param target element - the target input field or division or span + @return object - the associated instance data + @throws error if a jQuery problem getting data */ + _getInst: function(target) { + try { + return $.data(target, PROP_NAME); + } + catch (err) { + throw 'Missing instance data for this datepicker'; + } + }, + + /* Update the settings for a date picker attached to an input field or division. + @param target element - the target input field or division or span + @param name object - the new settings to update or + string - the name of the setting to change or + @param value any - the new value for the setting (omit if above is an object) */ + _changeDatepicker: function(target, name, value) { + var settings = name || {}; + if (typeof name == 'string') { + settings = {}; + settings[name] = value; + } + var inst = this._getInst(target); + if (inst) { + if (this._curInst == inst) { + this._hideDatepicker(null); + } + extendRemove(inst.settings, settings); + var date = new Date(); + extendRemove(inst, {rangeStart: null, // start of range + endDay: null, endMonth: null, endYear: null, // end of range + selectedDay: date.getDate(), selectedMonth: date.getMonth(), + selectedYear: date.getFullYear(), // starting point + currentDay: date.getDate(), currentMonth: date.getMonth(), + currentYear: date.getFullYear(), // current selection + drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn + this._updateDatepicker(inst); + } + }, + + /* Redraw the date picker attached to an input field or division. + @param target element - the target input field or division or span */ + _refreshDatepicker: function(target) { + var inst = this._getInst(target); + if (inst) { + this._updateDatepicker(inst); + } + }, + + /* Set the dates for a jQuery selection. + @param target element - the target input field or division or span + @param date Date - the new date + @param endDate Date - the new end date for a range (optional) */ + _setDateDatepicker: function(target, date, endDate) { + var inst = this._getInst(target); + if (inst) { + this._setDate(inst, date, endDate); + this._updateDatepicker(inst); + this._updateAlternate(inst); + } + }, + + /* Get the date(s) for the first entry in a jQuery selection. + @param target element - the target input field or division or span + @return Date - the current date or + Date[2] - the current dates for a range */ + _getDateDatepicker: function(target) { + var inst = this._getInst(target); + if (inst && !inst.inline) + this._setDateFromField(inst); + return (inst ? this._getDate(inst) : null); + }, + + /* Handle keystrokes. */ + _doKeyDown: function(e) { + var inst = $.datepicker._getInst(e.target); + var handled = true; + if ($.datepicker._datepickerShowing) + switch (e.keyCode) { + case 9: $.datepicker._hideDatepicker(null, ''); + break; // hide on tab out + case 13: $.datepicker._selectDay(e.target, inst.selectedMonth, inst.selectedYear, + $('td.ui-datepicker-days-cell-over', inst.dpDiv)[0]); + return false; // don't submit the form + break; // select the value on enter + case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration')); + break; // hide on escape + case 33: $.datepicker._adjustDate(e.target, (e.ctrlKey ? + -$.datepicker._get(inst, 'stepBigMonths') : + -$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // previous month/year on page up/+ ctrl + case 34: $.datepicker._adjustDate(e.target, (e.ctrlKey ? + +$.datepicker._get(inst, 'stepBigMonths') : + +$.datepicker._get(inst, 'stepMonths')), 'M'); + break; // next month/year on page down/+ ctrl + case 35: if (e.ctrlKey) $.datepicker._clearDate(e.target); + handled = e.ctrlKey; + break; // clear on ctrl+end + case 36: if (e.ctrlKey) $.datepicker._gotoToday(e.target); + handled = e.ctrlKey; + break; // current on ctrl+home + case 37: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -1, 'D'); + handled = e.ctrlKey; + break; // -1 day on ctrl+left + case 38: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -7, 'D'); + handled = e.ctrlKey; + break; // -1 week on ctrl+up + case 39: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +1, 'D'); + handled = e.ctrlKey; + break; // +1 day on ctrl+right + case 40: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +7, 'D'); + handled = e.ctrlKey; + break; // +1 week on ctrl+down + default: handled = false; + } + else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home + $.datepicker._showDatepicker(this); + else + handled = false; + if (handled) { + e.preventDefault(); + e.stopPropagation(); + } + }, + + /* Filter entered characters - based on date format. */ + _doKeyPress: function(e) { + var inst = $.datepicker._getInst(e.target); + var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); + var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode); + return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); + }, + + /* Pop-up the date picker for a given input field. + @param input element - the input field attached to the date picker or + event - if triggered by focus */ + _showDatepicker: function(input) { + input = input.target || input; + if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger + input = $('input', input.parentNode)[0]; + if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here + return; + var inst = $.datepicker._getInst(input); + var beforeShow = $.datepicker._get(inst, 'beforeShow'); + extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {})); + $.datepicker._hideDatepicker(null, ''); + $.datepicker._lastInput = input; + $.datepicker._setDateFromField(inst); + if ($.datepicker._inDialog) // hide cursor + input.value = ''; + if (!$.datepicker._pos) { // position below input + $.datepicker._pos = $.datepicker._findPos(input); + $.datepicker._pos[1] += input.offsetHeight; // add the height + } + var isFixed = false; + $(input).parents().each(function() { + isFixed |= $(this).css('position') == 'fixed'; + return !isFixed; + }); + if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled + $.datepicker._pos[0] -= document.documentElement.scrollLeft; + $.datepicker._pos[1] -= document.documentElement.scrollTop; + } + var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; + $.datepicker._pos = null; + inst.rangeStart = null; + // determine sizing offscreen + inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); + $.datepicker._updateDatepicker(inst); + // fix width for dynamic number of date pickers + inst.dpDiv.width($.datepicker._getNumberOfMonths(inst)[1] * + $('.ui-datepicker', inst.dpDiv[0])[0].offsetWidth); + // and adjust position before showing + offset = $.datepicker._checkOffset(inst, offset, isFixed); + inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? + 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', + left: offset.left + 'px', top: offset.top + 'px'}); + if (!inst.inline) { + var showAnim = $.datepicker._get(inst, 'showAnim') || 'show'; + var duration = $.datepicker._get(inst, 'duration'); + var postProcess = function() { + $.datepicker._datepickerShowing = true; + if ($.browser.msie && parseInt($.browser.version,10) < 7) // fix IE < 7 select problems + $('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}); + }; + if ($.effects && $.effects[showAnim]) + inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); + else + inst.dpDiv[showAnim](duration, postProcess); + if (duration == '') + postProcess(); + if (inst.input[0].type != 'hidden') + inst.input[0].focus(); + $.datepicker._curInst = inst; + } + }, + + /* Generate the date picker content. */ + _updateDatepicker: function(inst) { + var dims = {width: inst.dpDiv.width() + 4, + height: inst.dpDiv.height() + 4}; + inst.dpDiv.empty().append(this._generateHTML(inst)). + find('iframe.ui-datepicker-cover'). + css({width: dims.width, height: dims.height}); + var numMonths = this._getNumberOfMonths(inst); + inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + + 'Class']('ui-datepicker-multi'); + inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + + 'Class']('ui-datepicker-rtl'); + if (inst.input && inst.input[0].type != 'hidden') + $(inst.input[0]).focus(); + }, + + /* Check positioning to remain on screen. */ + _checkOffset: function(inst, offset, isFixed) { + var pos = inst.input ? this._findPos(inst.input[0]) : null; + var browserWidth = window.innerWidth || document.documentElement.clientWidth; + var browserHeight = window.innerHeight || document.documentElement.clientHeight; + var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; + var scrollY = document.documentElement.scrollTop || document.body.scrollTop; + // reposition date picker horizontally if outside the browser window + if (this._get(inst, 'isRTL') || (offset.left + inst.dpDiv.width() - scrollX) > browserWidth) + offset.left = Math.max((isFixed ? 0 : scrollX), + pos[0] + (inst.input ? inst.input.width() : 0) - (isFixed ? scrollX : 0) - inst.dpDiv.width() - + (isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0)); + else + offset.left -= (isFixed ? scrollX : 0); + // reposition date picker vertically if outside the browser window + if ((offset.top + inst.dpDiv.height() - scrollY) > browserHeight) + offset.top = Math.max((isFixed ? 0 : scrollY), + pos[1] - (isFixed ? scrollY : 0) - (this._inDialog ? 0 : inst.dpDiv.height()) - + (isFixed && $.browser.opera ? document.documentElement.scrollTop : 0)); + else + offset.top -= (isFixed ? scrollY : 0); + return offset; + }, + + /* Find an object's position on the screen. */ + _findPos: function(obj) { + while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) { + obj = obj.nextSibling; + } + var position = $(obj).offset(); + return [position.left, position.top]; + }, + + /* Hide the date picker from view. + @param input element - the input field attached to the date picker + @param duration string - the duration over which to close the date picker */ + _hideDatepicker: function(input, duration) { + var inst = this._curInst; + if (!inst || (input && inst != $.data(input, PROP_NAME))) + return; + var rangeSelect = this._get(inst, 'rangeSelect'); + if (rangeSelect && inst.stayOpen) + this._selectDate('#' + inst.id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + inst.stayOpen = false; + if (this._datepickerShowing) { + duration = (duration != null ? duration : this._get(inst, 'duration')); + var showAnim = this._get(inst, 'showAnim'); + var postProcess = function() { + $.datepicker._tidyDialog(inst); + }; + if (duration != '' && $.effects && $.effects[showAnim]) + inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), + duration, postProcess); + else + inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' : + (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess); + if (duration == '') + this._tidyDialog(inst); + var onClose = this._get(inst, 'onClose'); + if (onClose) + onClose.apply((inst.input ? inst.input[0] : null), + [(inst.input ? inst.input.val() : ''), inst]); // trigger custom callback + this._datepickerShowing = false; + this._lastInput = null; + inst.settings.prompt = null; + if (this._inDialog) { + this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); + if ($.blockUI) { + $.unblockUI(); + $('body').append(this.dpDiv); + } + } + this._inDialog = false; + } + this._curInst = null; + }, + + /* Tidy up after a dialog display. */ + _tidyDialog: function(inst) { + inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker'); + $('.' + this._promptClass, inst.dpDiv).remove(); + }, + + /* Close date picker if clicked elsewhere. */ + _checkExternalClick: function(event) { + if (!$.datepicker._curInst) + return; + var $target = $(event.target); + if (($target.parents('#' + $.datepicker._mainDivId).length == 0) && + !$target.hasClass($.datepicker.markerClassName) && + !$target.hasClass($.datepicker._triggerClass) && + $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI)) + $.datepicker._hideDatepicker(null, ''); + }, + + /* Adjust one of the date sub-fields. */ + _adjustDate: function(id, offset, period) { + var target = $(id); + var inst = this._getInst(target[0]); + this._adjustInstDate(inst, offset, period); + this._updateDatepicker(inst); + }, + + /* Action for current link. */ + _gotoToday: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'gotoCurrent') && inst.currentDay) { + inst.selectedDay = inst.currentDay; + inst.drawMonth = inst.selectedMonth = inst.currentMonth; + inst.drawYear = inst.selectedYear = inst.currentYear; + } + else { + var date = new Date(); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + } + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Action for selecting a new month/year. */ + _selectMonthYear: function(id, select, period) { + var target = $(id); + var inst = this._getInst(target[0]); + inst._selectingMonthYear = false; + inst['selected' + (period == 'M' ? 'Month' : 'Year')] = + inst['draw' + (period == 'M' ? 'Month' : 'Year')] = + parseInt(select.options[select.selectedIndex].value,10); + this._notifyChange(inst); + this._adjustDate(target); + }, + + /* Restore input focus after not changing month/year. */ + _clickMonthYear: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (inst.input && inst._selectingMonthYear && !$.browser.msie) + inst.input[0].focus(); + inst._selectingMonthYear = !inst._selectingMonthYear; + }, + + /* Action for changing the first week day. */ + _changeFirstDay: function(id, day) { + var target = $(id); + var inst = this._getInst(target[0]); + inst.settings.firstDay = day; + this._updateDatepicker(inst); + }, + + /* Action for selecting a day. */ + _selectDay: function(id, month, year, td) { + if ($(td).hasClass(this._unselectableClass)) + return; + var target = $(id); + var inst = this._getInst(target[0]); + var rangeSelect = this._get(inst, 'rangeSelect'); + if (rangeSelect) { + inst.stayOpen = !inst.stayOpen; + if (inst.stayOpen) { + $('.ui-datepicker td', inst.dpDiv).removeClass(this._currentClass); + $(td).addClass(this._currentClass); + } + } + inst.selectedDay = inst.currentDay = $('a', td).html(); + inst.selectedMonth = inst.currentMonth = month; + inst.selectedYear = inst.currentYear = year; + if (inst.stayOpen) { + inst.endDay = inst.endMonth = inst.endYear = null; + } + else if (rangeSelect) { + inst.endDay = inst.currentDay; + inst.endMonth = inst.currentMonth; + inst.endYear = inst.currentYear; + } + this._selectDate(id, this._formatDate(inst, + inst.currentDay, inst.currentMonth, inst.currentYear)); + if (inst.stayOpen) { + inst.rangeStart = new Date(inst.currentYear, inst.currentMonth, inst.currentDay); + this._updateDatepicker(inst); + } + else if (rangeSelect) { + inst.selectedDay = inst.currentDay = inst.rangeStart.getDate(); + inst.selectedMonth = inst.currentMonth = inst.rangeStart.getMonth(); + inst.selectedYear = inst.currentYear = inst.rangeStart.getFullYear(); + inst.rangeStart = null; + if (inst.inline) + this._updateDatepicker(inst); + } + }, + + /* Erase the input field and hide the date picker. */ + _clearDate: function(id) { + var target = $(id); + var inst = this._getInst(target[0]); + if (this._get(inst, 'mandatory')) + return; + inst.stayOpen = false; + inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null; + this._selectDate(target, ''); + }, + + /* Update the input field with the selected date. */ + _selectDate: function(id, dateStr) { + var target = $(id); + var inst = this._getInst(target[0]); + dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); + if (this._get(inst, 'rangeSelect') && dateStr) + dateStr = (inst.rangeStart ? this._formatDate(inst, inst.rangeStart) : + dateStr) + this._get(inst, 'rangeSeparator') + dateStr; + if (inst.input) + inst.input.val(dateStr); + this._updateAlternate(inst); + var onSelect = this._get(inst, 'onSelect'); + if (onSelect) + onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback + else if (inst.input) + inst.input.trigger('change'); // fire the change event + if (inst.inline) + this._updateDatepicker(inst); + else if (!inst.stayOpen) { + this._hideDatepicker(null, this._get(inst, 'duration')); + this._lastInput = inst.input[0]; + if (typeof(inst.input[0]) != 'object') + inst.input[0].focus(); // restore focus + this._lastInput = null; + } + }, + + /* Update any alternate field to synchronise with the main field. */ + _updateAlternate: function(inst) { + var altField = this._get(inst, 'altField'); + if (altField) { // update alternate field too + var altFormat = this._get(inst, 'altFormat'); + var date = this._getDate(inst); + dateStr = (isArray(date) ? (!date[0] && !date[1] ? '' : + this.formatDate(altFormat, date[0], this._getFormatConfig(inst)) + + this._get(inst, 'rangeSeparator') + this.formatDate( + altFormat, date[1] || date[0], this._getFormatConfig(inst))) : + this.formatDate(altFormat, date, this._getFormatConfig(inst))); + $(altField).each(function() { $(this).val(dateStr); }); + } + }, + + /* Set as beforeShowDay function to prevent selection of weekends. + @param date Date - the date to customise + @return [boolean, string] - is this date selectable?, what is its CSS class? */ + noWeekends: function(date) { + var day = date.getDay(); + return [(day > 0 && day < 6), '']; + }, + + /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. + @param date Date - the date to get the week for + @return number - the number of the week within the year that contains this date */ + iso8601Week: function(date) { + var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), + (date.getTimezoneOffset() / -60)); + var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan + var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7 + firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday + if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary + checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year + return $.datepicker.iso8601Week(checkDate); + } else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year + firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7; + if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary + return 1; + } + } + return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date + }, + + /* Provide status text for a particular date. + @param date the date to get the status for + @param inst the current datepicker instance + @return the status display text for this date */ + dateStatus: function(date, inst) { + return $.datepicker.formatDate($.datepicker._get(inst, 'dateStatus'), + date, $.datepicker._getFormatConfig(inst)); + }, + + /* Parse a string value into a date object. + See formatDate below for the possible formats. + + @param format string - the expected format of the date + @param value string - the date in the above format + @param settings Object - attributes include: + shortYearCutoff number - the cutoff year for determining the century (optional) + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return Date - the extracted date value or null if value is blank */ + parseDate: function (format, value, settings) { + if (format == null || value == null) + throw 'Invalid arguments'; + value = (typeof value == 'object' ? value.toString() : value + ''); + if (value == '') + return null; + var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + var year = -1; + var month = -1; + var day = -1; + var doy = -1; + var literal = false; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Extract a number from the string value + var getNumber = function(match) { + lookAhead(match); + var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2))); + var size = origSize; + var num = 0; + while (size > 0 && iValue < value.length && + value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') { + num = num * 10 + parseInt(value.charAt(iValue++),10); + size--; + } + if (size == origSize) + throw 'Missing number at position ' + iValue; + return num; + }; + // Extract a name from the string value and convert to an index + var getName = function(match, shortNames, longNames) { + var names = (lookAhead(match) ? longNames : shortNames); + var size = 0; + for (var j = 0; j < names.length; j++) + size = Math.max(size, names[j].length); + var name = ''; + var iInit = iValue; + while (size > 0 && iValue < value.length) { + name += value.charAt(iValue++); + for (var i = 0; i < names.length; i++) + if (name == names[i]) + return i + 1; + size--; + } + throw 'Unknown name at position ' + iInit; + }; + // Confirm that a literal character matches the string value + var checkLiteral = function() { + if (value.charAt(iValue) != format.charAt(iFormat)) + throw 'Unexpected literal at position ' + iValue; + iValue++; + }; + var iValue = 0; + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + checkLiteral(); + else + switch (format.charAt(iFormat)) { + case 'd': + day = getNumber('d'); + break; + case 'D': + getName('D', dayNamesShort, dayNames); + break; + case 'o': + doy = getNumber('o'); + break; + case 'm': + month = getNumber('m'); + break; + case 'M': + month = getName('M', monthNamesShort, monthNames); + break; + case 'y': + year = getNumber('y'); + break; + case '@': + var date = new Date(getNumber('@')); + year = date.getFullYear(); + month = date.getMonth() + 1; + day = date.getDate(); + break; + case "'": + if (lookAhead("'")) + checkLiteral(); + else + literal = true; + break; + default: + checkLiteral(); + } + } + if (year < 100) + year += new Date().getFullYear() - new Date().getFullYear() % 100 + + (year <= shortYearCutoff ? 0 : -100); + if (doy > -1) { + month = 1; + day = doy; + do { + var dim = this._getDaysInMonth(year, month - 1); + if (day <= dim) + break; + month++; + day -= dim; + } while (true); + } + var date = new Date(year, month - 1, day); + if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) + throw 'Invalid date'; // E.g. 31/02/* + return date; + }, + + /* Standard date formats. */ + ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) + COOKIE: 'D, dd M yy', + ISO_8601: 'yy-mm-dd', + RFC_822: 'D, d M y', + RFC_850: 'DD, dd-M-y', + RFC_1036: 'D, d M y', + RFC_1123: 'D, d M yy', + RFC_2822: 'D, d M yy', + RSS: 'D, d M y', // RFC 822 + TIMESTAMP: '@', + W3C: 'yy-mm-dd', // ISO 8601 + + /* Format a date object into a string value. + The format can be combinations of the following: + d - day of month (no leading zero) + dd - day of month (two digit) + o - day of year (no leading zeros) + oo - day of year (three digit) + D - day name short + DD - day name long + m - month of year (no leading zero) + mm - month of year (two digit) + M - month name short + MM - month name long + y - year (two digit) + yy - year (four digit) + @ - Unix timestamp (ms since 01/01/1970) + '...' - literal text + '' - single quote + + @param format string - the desired format of the date + @param date Date - the date value to format + @param settings Object - attributes include: + dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) + dayNames string[7] - names of the days from Sunday (optional) + monthNamesShort string[12] - abbreviated names of the months (optional) + monthNames string[12] - names of the months (optional) + @return string - the date in the above format */ + formatDate: function (format, date, settings) { + if (!date) + return ''; + var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; + var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; + var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; + var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; + // Check whether a format character is doubled + var lookAhead = function(match) { + var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); + if (matches) + iFormat++; + return matches; + }; + // Format a number, with leading zero if necessary + var formatNumber = function(match, value, len) { + var num = '' + value; + if (lookAhead(match)) + while (num.length < len) + num = '0' + num; + return num; + }; + // Format a name, short or long as requested + var formatName = function(match, value, shortNames, longNames) { + return (lookAhead(match) ? longNames[value] : shortNames[value]); + }; + var output = ''; + var literal = false; + if (date) + for (var iFormat = 0; iFormat < format.length; iFormat++) { + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + output += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': + output += formatNumber('d', date.getDate(), 2); + break; + case 'D': + output += formatName('D', date.getDay(), dayNamesShort, dayNames); + break; + case 'o': + var doy = date.getDate(); + for (var m = date.getMonth() - 1; m >= 0; m--) + doy += this._getDaysInMonth(date.getFullYear(), m); + output += formatNumber('o', doy, 3); + break; + case 'm': + output += formatNumber('m', date.getMonth() + 1, 2); + break; + case 'M': + output += formatName('M', date.getMonth(), monthNamesShort, monthNames); + break; + case 'y': + output += (lookAhead('y') ? date.getFullYear() : + (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); + break; + case '@': + output += date.getTime(); + break; + case "'": + if (lookAhead("'")) + output += "'"; + else + literal = true; + break; + default: + output += format.charAt(iFormat); + } + } + return output; + }, + + /* Extract all possible characters from the date format. */ + _possibleChars: function (format) { + var chars = ''; + var literal = false; + for (var iFormat = 0; iFormat < format.length; iFormat++) + if (literal) + if (format.charAt(iFormat) == "'" && !lookAhead("'")) + literal = false; + else + chars += format.charAt(iFormat); + else + switch (format.charAt(iFormat)) { + case 'd': case 'm': case 'y': case '@': + chars += '0123456789'; + break; + case 'D': case 'M': + return null; // Accept anything + case "'": + if (lookAhead("'")) + chars += "'"; + else + literal = true; + break; + default: + chars += format.charAt(iFormat); + } + return chars; + }, + + /* Get a setting value, defaulting if necessary. */ + _get: function(inst, name) { + return inst.settings[name] !== undefined ? + inst.settings[name] : this._defaults[name]; + }, + + /* Parse existing date and initialise date picker. */ + _setDateFromField: function(inst) { + var dateFormat = this._get(inst, 'dateFormat'); + var dates = inst.input ? inst.input.val().split(this._get(inst, 'rangeSeparator')) : null; + inst.endDay = inst.endMonth = inst.endYear = null; + var date = defaultDate = this._getDefaultDate(inst); + if (dates.length > 0) { + var settings = this._getFormatConfig(inst); + if (dates.length > 1) { + date = this.parseDate(dateFormat, dates[1], settings) || defaultDate; + inst.endDay = date.getDate(); + inst.endMonth = date.getMonth(); + inst.endYear = date.getFullYear(); + } + try { + date = this.parseDate(dateFormat, dates[0], settings) || defaultDate; + } catch (e) { + this.log(e); + date = defaultDate; + } + } + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + inst.currentDay = (dates[0] ? date.getDate() : 0); + inst.currentMonth = (dates[0] ? date.getMonth() : 0); + inst.currentYear = (dates[0] ? date.getFullYear() : 0); + this._adjustInstDate(inst); + }, + + /* Retrieve the default date shown on opening. */ + _getDefaultDate: function(inst) { + var date = this._determineDate(this._get(inst, 'defaultDate'), new Date()); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + return date; + }, + + /* A date may be specified as an exact value or a relative one. */ + _determineDate: function(date, defaultDate) { + var offsetNumeric = function(offset) { + var date = new Date(); + date.setUTCDate(date.getUTCDate() + offset); + return date; + }; + var offsetString = function(offset, getDaysInMonth) { + var date = new Date(); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; + var matches = pattern.exec(offset); + while (matches) { + switch (matches[2] || 'd') { + case 'd' : case 'D' : + day += parseInt(matches[1],10); break; + case 'w' : case 'W' : + day += parseInt(matches[1],10) * 7; break; + case 'm' : case 'M' : + month += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + case 'y': case 'Y' : + year += parseInt(matches[1],10); + day = Math.min(day, getDaysInMonth(year, month)); + break; + } + matches = pattern.exec(offset); + } + return new Date(year, month, day); + }; + date = (date == null ? defaultDate : + (typeof date == 'string' ? offsetString(date, this._getDaysInMonth) : + (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : date))); + return (date && date.toString() == 'Invalid Date' ? defaultDate : date); + }, + + /* Set the date(s) directly. */ + _setDate: function(inst, date, endDate) { + var clear = !(date); + var origMonth = inst.selectedMonth; + var origYear = inst.selectedYear; + date = this._determineDate(date, new Date()); + inst.selectedDay = inst.currentDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear(); + if (this._get(inst, 'rangeSelect')) { + if (endDate) { + endDate = this._determineDate(endDate, null); + inst.endDay = endDate.getDate(); + inst.endMonth = endDate.getMonth(); + inst.endYear = endDate.getFullYear(); + } else { + inst.endDay = inst.currentDay; + inst.endMonth = inst.currentMonth; + inst.endYear = inst.currentYear; + } + } + if (origMonth != inst.selectedMonth || origYear != inst.selectedYear) + this._notifyChange(inst); + this._adjustInstDate(inst); + if (inst.input) + inst.input.val(clear ? '' : this._formatDate(inst) + + (!this._get(inst, 'rangeSelect') ? '' : this._get(inst, 'rangeSeparator') + + this._formatDate(inst, inst.endDay, inst.endMonth, inst.endYear))); + }, + + /* Retrieve the date(s) directly. */ + _getDate: function(inst) { + var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay)); + if (this._get(inst, 'rangeSelect')) { + return [inst.rangeStart || startDate, + (!inst.endYear ? inst.rangeStart || startDate : + new Date(inst.endYear, inst.endMonth, inst.endDay))]; + } else + return startDate; + }, + + /* Generate the HTML for the current state of the date picker. */ + _generateHTML: function(inst) { + var today = new Date(); + today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time + var showStatus = this._get(inst, 'showStatus'); + var initStatus = this._get(inst, 'initStatus') || ' '; + var isRTL = this._get(inst, 'isRTL'); + // build the date picker HTML + var clear = (this._get(inst, 'mandatory') ? '' : + '
' + + this._get(inst, 'clearText') + '
'); + var controls = '
' + (isRTL ? '' : clear) + + '
' + + this._get(inst, 'closeText') + '
' + (isRTL ? clear : '') + '
'; + var prompt = this._get(inst, 'prompt'); + var closeAtTop = this._get(inst, 'closeAtTop'); + var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); + var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); + var showBigPrevNext = this._get(inst, 'showBigPrevNext'); + var numMonths = this._getNumberOfMonths(inst); + var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); + var stepMonths = this._get(inst, 'stepMonths'); + var stepBigMonths = this._get(inst, 'stepBigMonths'); + var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); + var currentDate = (!inst.currentDay ? new Date(9999, 9, 9) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay)); + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + var drawMonth = inst.drawMonth - showCurrentAtPos; + var drawYear = inst.drawYear; + if (drawMonth < 0) { + drawMonth += 12; + drawYear--; + } + if (maxDate) { + var maxDraw = new Date(maxDate.getFullYear(), + maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate()); + maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); + while (new Date(drawYear, drawMonth, 1) > maxDraw) { + drawMonth--; + if (drawMonth < 0) { + drawMonth = 11; + drawYear--; + } + } + } + // controls and links + var prevText = this._get(inst, 'prevText'); + prevText = (!navigationAsDateFormat ? prevText : this.formatDate( + prevText, new Date(drawYear, drawMonth - stepMonths, 1), this._getFormatConfig(inst))); + var prevBigText = (showBigPrevNext ? this._get(inst, 'prevBigText') : ''); + prevBigText = (!navigationAsDateFormat ? prevBigText : this.formatDate( + prevBigText, new Date(drawYear, drawMonth - stepBigMonths, 1), this._getFormatConfig(inst))); + var prev = '
' + (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? + (showBigPrevNext ? '' + prevBigText + '' : '') + + '' + prevText + '' : + (hideIfNoPrevNext ? '' : '')) + '
'; + var nextText = this._get(inst, 'nextText'); + nextText = (!navigationAsDateFormat ? nextText : this.formatDate( + nextText, new Date(drawYear, drawMonth + stepMonths, 1), this._getFormatConfig(inst))); + var nextBigText = (showBigPrevNext ? this._get(inst, 'nextBigText') : ''); + nextBigText = (!navigationAsDateFormat ? nextBigText : this.formatDate( + nextBigText, new Date(drawYear, drawMonth + stepBigMonths, 1), this._getFormatConfig(inst))); + var next = '
' + (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? + '' + nextText + '' + + (showBigPrevNext ? '' + nextBigText + '' : '') : + (hideIfNoPrevNext ? '' : '')) + '
'; + var currentText = this._get(inst, 'currentText'); + var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); + currentText = (!navigationAsDateFormat ? currentText : + this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); + var html = (prompt ? '
' + prompt + '
' : '') + + (closeAtTop && !inst.inline ? controls : '') + + ''; + var firstDay = this._get(inst, 'firstDay'); + var changeFirstDay = this._get(inst, 'changeFirstDay'); + var dayNames = this._get(inst, 'dayNames'); + var dayNamesShort = this._get(inst, 'dayNamesShort'); + var dayNamesMin = this._get(inst, 'dayNamesMin'); + var monthNames = this._get(inst, 'monthNames'); + var beforeShowDay = this._get(inst, 'beforeShowDay'); + var highlightWeek = this._get(inst, 'highlightWeek'); + var showOtherMonths = this._get(inst, 'showOtherMonths'); + var showWeeks = this._get(inst, 'showWeeks'); + var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; + var weekStatus = this._get(inst, 'weekStatus'); + var status = (showStatus ? this._get(inst, 'dayStatus') || initStatus : ''); + var dateStatus = this._get(inst, 'statusForDate') || this.dateStatus; + var endDate = inst.endDay ? new Date(inst.endYear, inst.endMonth, inst.endDay) : currentDate; + for (var row = 0; row < numMonths[0]; row++) + for (var col = 0; col < numMonths[1]; col++) { + var selectedDate = new Date(drawYear, drawMonth, inst.selectedDay); + html += '
' + + this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, row > 0 || col > 0, showStatus, initStatus, monthNames) + // draw month headers + '' + + '' + + (showWeeks ? '' + + this._get(inst, 'weekHeader') + '' : ''); + for (var dow = 0; dow < 7; dow++) { // days of the week + var day = (dow + firstDay) % 7; + var dayStatus = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) : + status.replace(/D/, dayNamesShort[day])); + html += '= 5 ? ' class="ui-datepicker-week-end-cell"' : '') + '>' + + (!changeFirstDay ? '' + + dayNamesMin[day] + (changeFirstDay ? '' : '') + ''; + } + html += ''; + var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + var tzDate = new Date(drawYear, drawMonth, 1 - leadDays); + var utcDate = new Date(drawYear, drawMonth, 1 - leadDays); + var printDate = utcDate; + var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate + for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows + html += '' + + (showWeeks ? '' : ''); + for (var dow = 0; dow < 7; dow++) { // create date picker days + var daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); + var otherMonth = (printDate.getMonth() != drawMonth); + var unselectable = otherMonth || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + html += ''; // display for this month + tzDate.setDate(tzDate.getDate() + 1); + utcDate.setUTCDate(utcDate.getUTCDate() + 1); + printDate = (tzDate > utcDate ? tzDate : utcDate); + } + html += ''; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + html += '
' + + calculateWeek(printDate) + '' + // actions + (otherMonth ? (showOtherMonths ? printDate.getDate() : ' ') : // display for other months + (unselectable ? printDate.getDate() : '' + printDate.getDate() + '')) + '
'; + } + html += (showStatus ? '
' + initStatus + '
' : '') + + (!closeAtTop && !inst.inline ? controls : '') + + '
' + + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? + '' : ''); + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + selectedDate, secondary, showStatus, initStatus, monthNames) { + minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate); + var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); + var html = '
'; + var monthHtml = ''; + // month selection + if (secondary || !this._get(inst, 'changeMonth')) + monthHtml += monthNames[drawMonth] + ' '; + else { + var inMinYear = (minDate && minDate.getFullYear() == drawYear); + var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); + monthHtml += ''; + } + if (!showMonthAfterYear) + html += monthHtml; + // year selection + if (secondary || !this._get(inst, 'changeYear')) + html += drawYear; + else { + // determine range of years to display + var years = this._get(inst, 'yearRange').split(':'); + var year = 0; + var endYear = 0; + if (years.length != 2) { + year = drawYear - 10; + endYear = drawYear + 10; + } else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') { + year = endYear = new Date().getFullYear(); + year += parseInt(years[0], 10); + endYear += parseInt(years[1], 10); + } else { + year = parseInt(years[0], 10); + endYear = parseInt(years[1], 10); + } + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + html += ''; + } + if (showMonthAfterYear) + html += monthHtml; + html += '
'; // Close datepicker_header + return html; + }, + + /* Provide code to set and clear the status panel. */ + _addStatus: function(showStatus, id, text, initStatus) { + return (showStatus ? ' onmouseover="jQuery(\'#ui-datepicker-status-' + id + + '\').html(\'' + (text || initStatus) + '\');" ' + + 'onmouseout="jQuery(\'#ui-datepicker-status-' + id + + '\').html(\'' + initStatus + '\');"' : ''); + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period == 'Y' ? offset : 0); + var month = inst.drawMonth + (period == 'M' ? offset : 0); + var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + + (period == 'D' ? offset : 0); + var date = new Date(year, month, day); + // ensure it is within the bounds set + var minDate = this._getMinMaxDate(inst, 'min', true); + var maxDate = this._getMinMaxDate(inst, 'max'); + date = (minDate && date < minDate ? minDate : date); + date = (maxDate && date > maxDate ? maxDate : date); + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period == 'M' || period == 'Y') + this._notifyChange(inst); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, 'onChangeMonthYear'); + if (onChange) + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, 'numberOfMonths'); + return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */ + _getMinMaxDate: function(inst, minMax, checkRange) { + var date = this._determineDate(this._get(inst, minMax + 'Date'), null); + if (date) { + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + } + return (!checkRange || !inst.rangeStart ? date : + (!date || inst.rangeStart > date ? inst.rangeStart : date)); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - new Date(year, month, 32).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst); + var date = new Date(curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1); + if (offset < 0) + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + // during range selection, use minimum of selected date and range start + var newMinDate = (!inst.rangeStart ? null : + new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay)); + newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate); + var minDate = newMinDate || this._getMinMaxDate(inst, 'min'); + var maxDate = this._getMinMaxDate(inst, 'max'); + return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, 'shortYearCutoff'); + shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), + monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day == 'object' ? day : new Date(year, month, day)) : + new Date(inst.currentYear, inst.currentMonth, inst.currentDay)); + return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); + } +}); + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) + if (props[name] == null || props[name] == undefined) + target[name] = props[name]; + return target; +}; + +/* Determine whether an object is an array. */ +function isArray(a) { + return (a && (($.browser.safari && typeof a == 'object' && a.length) || + (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); +}; + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document.body).append($.datepicker.dpDiv). + mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate')) + return $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this[0]].concat(otherArgs)); + return this.each(function() { + typeof options == 'string' ? + $.datepicker['_' + options + 'Datepicker']. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); + +})(jQuery); addfile ./static/js/jquery/ui/ui.dialog.js hunk ./static/js/jquery/ui/ui.dialog.js 1 +/* + * jQuery UI Dialog @VERSION + * + * Copyright (c) 2008 Richard D. Worth (rdworth.org) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Dialog + * + * Depends: + * ui.core.js + * ui.draggable.js + * ui.resizable.js + */ +(function($) { + +var setDataSwitch = { + dragStart: "start.draggable", + drag: "drag.draggable", + dragStop: "stop.draggable", + maxHeight: "maxHeight.resizable", + minHeight: "minHeight.resizable", + maxWidth: "maxWidth.resizable", + minWidth: "minWidth.resizable", + resizeStart: "start.resizable", + resize: "drag.resizable", + resizeStop: "stop.resizable" +}; + +$.widget("ui.dialog", { + _init: function() { + this.originalTitle = this.element.attr('title'); + this.options.title = this.options.title || this.originalTitle; + + var self = this, + options = this.options, + + uiDialogContent = this.element + .removeAttr('title') + .addClass('ui-dialog-content') + .wrap('
') + .wrap('
'), + + uiDialogContainer = (this.uiDialogContainer = uiDialogContent.parent()) + .addClass('ui-dialog-container') + .css({ + position: 'relative', + width: '100%', + height: '100%' + }), + + uiDialogTitlebar = (this.uiDialogTitlebar = $('
')) + .addClass('ui-dialog-titlebar') + .append('X') + .prependTo(uiDialogContainer), + + title = options.title || ' ', + titleId = $.ui.dialog.getTitleId(this.element), + uiDialogTitle = $('') + .addClass('ui-dialog-title') + .attr('id', titleId) + .html(title) + .prependTo(uiDialogTitlebar), + + uiDialog = (this.uiDialog = uiDialogContainer.parent()) + .appendTo(document.body) + .hide() + .addClass('ui-dialog') + .addClass(options.dialogClass) + // add content classes to dialog + // to inherit theme at top level of element + .addClass(uiDialogContent.attr('className')) + .removeClass('ui-dialog-content') + .css({ + position: 'absolute', + width: options.width, + height: options.height, + overflow: 'hidden', + zIndex: options.zIndex + }) + // setting tabIndex makes the div focusable + // setting outline to 0 prevents a border on focus in Mozilla + .attr('tabIndex', -1).css('outline', 0).keydown(function(ev) { + (options.closeOnEscape && ev.keyCode + && ev.keyCode == $.keyCode.ESCAPE && self.close()); + }) + .mousedown(function() { + self._moveToTop(); + }), + + uiDialogButtonPane = (this.uiDialogButtonPane = $('
')) + .addClass('ui-dialog-buttonpane') + .css({ + position: 'absolute', + bottom: 0 + }) + .appendTo(uiDialog); + + this.uiDialogTitlebarClose = $('.ui-dialog-titlebar-close', uiDialogTitlebar) + .hover( + function() { + $(this).addClass('ui-dialog-titlebar-close-hover'); + }, + function() { + $(this).removeClass('ui-dialog-titlebar-close-hover'); + } + ) + .mousedown(function(ev) { + ev.stopPropagation(); + }) + .click(function() { + self.close(); + return false; + }); + + uiDialogTitlebar.find("*").add(uiDialogTitlebar).each(function() { + $.ui.disableSelection(this); + }); + + (options.draggable && $.fn.draggable && this._makeDraggable()); + (options.resizable && $.fn.resizable && this._makeResizable()); + + this._createButtons(options.buttons); + this._isOpen = false; + + (options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe()); + (options.autoOpen && this.open()); + }, + + destroy: function() { + (this.overlay && this.overlay.destroy()); + this.uiDialog.hide(); + this.element + .unbind('.dialog') + .removeData('dialog') + .removeClass('ui-dialog-content') + .hide().appendTo('body'); + this.uiDialog.remove(); + + (this.originalTitle && this.element.attr('title', this.originalTitle)); + }, + + close: function() { + if (false === this._trigger('beforeclose', null, { options: this.options })) { + return; + } + + (this.overlay && this.overlay.destroy()); + this.uiDialog + .hide(this.options.hide) + .unbind('keypress.ui-dialog'); + + this._trigger('close', null, { options: this.options }); + $.ui.dialog.overlay.resize(); + + this._isOpen = false; + }, + + isOpen: function() { + return this._isOpen; + }, + + open: function() { + if (this._isOpen) { return; } + + this.overlay = this.options.modal ? new $.ui.dialog.overlay(this) : null; + (this.uiDialog.next().length && this.uiDialog.appendTo('body')); + this._position(this.options.position); + this.uiDialog.show(this.options.show); + (this.options.autoResize && this._size()); + this._moveToTop(true); + + // prevent tabbing out of modal dialogs + (this.options.modal && this.uiDialog.bind('keypress.ui-dialog', function(e) { + if (e.keyCode != $.keyCode.TAB) { + return; + } + + var tabbables = $(':tabbable', this), + first = tabbables.filter(':first')[0], + last = tabbables.filter(':last')[0]; + + if (e.target == last && !e.shiftKey) { + setTimeout(function() { + first.focus(); + }, 1); + } else if (e.target == first && e.shiftKey) { + setTimeout(function() { + last.focus(); + }, 1); + } + })); + + this.uiDialog.find(':tabbable:first').focus(); + this._trigger('open', null, { options: this.options }); + this._isOpen = true; + }, + + _createButtons: function(buttons) { + var self = this, + hasButtons = false, + uiDialogButtonPane = this.uiDialogButtonPane; + + // remove any existing buttons + uiDialogButtonPane.empty().hide(); + + $.each(buttons, function() { return !(hasButtons = true); }); + if (hasButtons) { + uiDialogButtonPane.show(); + $.each(buttons, function(name, fn) { + $('') + .text(name) + .click(function() { fn.apply(self.element[0], arguments); }) + .appendTo(uiDialogButtonPane); + }); + } + }, + + _makeDraggable: function() { + var self = this, + options = this.options; + + this.uiDialog.draggable({ + cancel: '.ui-dialog-content', + helper: options.dragHelper, + handle: '.ui-dialog-titlebar', + start: function() { + self._moveToTop(); + (options.dragStart && options.dragStart.apply(self.element[0], arguments)); + }, + drag: function() { + (options.drag && options.drag.apply(self.element[0], arguments)); + }, + stop: function() { + (options.dragStop && options.dragStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }); + }, + + _makeResizable: function(handles) { + handles = (handles === undefined ? this.options.resizable : handles); + var self = this, + options = this.options, + resizeHandles = typeof handles == 'string' + ? handles + : 'n,e,s,w,se,sw,ne,nw'; + + this.uiDialog.resizable({ + cancel: '.ui-dialog-content', + helper: options.resizeHelper, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: options.minHeight, + start: function() { + (options.resizeStart && options.resizeStart.apply(self.element[0], arguments)); + }, + resize: function() { + (options.autoResize && self._size.apply(self)); + (options.resize && options.resize.apply(self.element[0], arguments)); + }, + handles: resizeHandles, + stop: function() { + (options.autoResize && self._size.apply(self)); + (options.resizeStop && options.resizeStop.apply(self.element[0], arguments)); + $.ui.dialog.overlay.resize(); + } + }); + }, + + // the force parameter allows us to move modal dialogs to their correct + // position on open + _moveToTop: function(force) { + + if ((this.options.modal && !force) + || (!this.options.stack && !this.options.modal)) { + return this._trigger('focus', null, { options: this.options }); + } + + var maxZ = this.options.zIndex, options = this.options; + $('.ui-dialog:visible').each(function() { + maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex); + }); + (this.overlay && this.overlay.$el.css('z-index', ++maxZ)); + this.uiDialog.css('z-index', ++maxZ); + + this._trigger('focus', null, { options: this.options }); + }, + + _position: function(pos) { + var wnd = $(window), doc = $(document), + pTop = doc.scrollTop(), pLeft = doc.scrollLeft(), + minTop = pTop; + + if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) { + pos = [ + pos == 'right' || pos == 'left' ? pos : 'center', + pos == 'top' || pos == 'bottom' ? pos : 'middle' + ]; + } + if (pos.constructor != Array) { + pos = ['center', 'middle']; + } + if (pos[0].constructor == Number) { + pLeft += pos[0]; + } else { + switch (pos[0]) { + case 'left': + pLeft += 0; + break; + case 'right': + pLeft += wnd.width() - this.uiDialog.width(); + break; + default: + case 'center': + pLeft += (wnd.width() - this.uiDialog.width()) / 2; + } + } + if (pos[1].constructor == Number) { + pTop += pos[1]; + } else { + switch (pos[1]) { + case 'top': + pTop += 0; + break; + case 'bottom': + pTop += wnd.height() - this.uiDialog.height(); + break; + default: + case 'middle': + pTop += (wnd.height() - this.uiDialog.height()) / 2; + } + } + + // prevent the dialog from being too high (make sure the titlebar + // is accessible) + pTop = Math.max(pTop, minTop); + this.uiDialog.css({top: pTop, left: pLeft}); + }, + + _setData: function(key, value){ + (setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value)); + switch (key) { + case "buttons": + this._createButtons(value); + break; + case "draggable": + (value + ? this._makeDraggable() + : this.uiDialog.draggable('destroy')); + break; + case "height": + this.uiDialog.height(value); + break; + case "position": + this._position(value); + break; + case "resizable": + var uiDialog = this.uiDialog, + isResizable = this.uiDialog.is(':data(resizable)'); + + // currently resizable, becoming non-resizable + (isResizable && !value && uiDialog.resizable('destroy')); + + // currently resizable, changing handles + (isResizable && typeof value == 'string' && + uiDialog.resizable('option', 'handles', value)); + + // currently non-resizable, becoming resizable + (isResizable || this._makeResizable(value)); + + break; + case "title": + $(".ui-dialog-title", this.uiDialogTitlebar).html(value || ' '); + break; + case "width": + this.uiDialog.width(value); + break; + } + + $.widget.prototype._setData.apply(this, arguments); + }, + + _size: function() { + var container = this.uiDialogContainer, + titlebar = this.uiDialogTitlebar, + content = this.element, + tbMargin = (parseInt(content.css('margin-top'), 10) || 0) + + (parseInt(content.css('margin-bottom'), 10) || 0), + lrMargin = (parseInt(content.css('margin-left'), 10) || 0) + + (parseInt(content.css('margin-right'), 10) || 0); + content.height(container.height() - titlebar.outerHeight() - tbMargin); + content.width(container.width() - lrMargin); + } +}); + +$.extend($.ui.dialog, { + defaults: { + autoOpen: true, + autoResize: true, + bgiframe: false, + buttons: {}, + closeOnEscape: true, + draggable: true, + height: 200, + minHeight: 100, + minWidth: 150, + modal: false, + overlay: {}, + position: 'center', + resizable: true, + stack: true, + width: 300, + zIndex: 1000 + }, + + getter: 'isOpen', + + uuid: 0, + getTitleId: function($el) { + return 'ui-dialog-title-' + ($el.attr('id') || ++this.uuid); + }, + + overlay: function(dialog) { + this.$el = $.ui.dialog.overlay.create(dialog); + } +}); + +$.extend($.ui.dialog.overlay, { + instances: [], + events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), + function(e) { return e + '.dialog-overlay'; }).join(' '), + create: function(dialog) { + if (this.instances.length === 0) { + // prevent use of anchors and inputs + // we use a setTimeout in case the overlay is created from an + // event that we're going to be cancelling (see #2804) + setTimeout(function() { + $('a, :input').bind($.ui.dialog.overlay.events, function() { + // allow use of the element if inside a dialog and + // - there are no modal dialogs + // - there are modal dialogs, but we are in front of the topmost modal + var allow = false; + var $dialog = $(this).parents('.ui-dialog'); + if ($dialog.length) { + var $overlays = $('.ui-dialog-overlay'); + if ($overlays.length) { + var maxZ = parseInt($overlays.css('z-index'), 10); + $overlays.each(function() { + maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10)); + }); + allow = parseInt($dialog.css('z-index'), 10) > maxZ; + } else { + allow = true; + } + } + return allow; + }); + }, 1); + + // allow closing by pressing the escape key + $(document).bind('keydown.dialog-overlay', function(e) { + (dialog.options.closeOnEscape && e.keyCode + && e.keyCode == $.keyCode.ESCAPE && dialog.close()); + }); + + // handle window resize + $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); + } + + var $el = $('
').appendTo(document.body) + .addClass('ui-dialog-overlay').css($.extend({ + borderWidth: 0, margin: 0, padding: 0, + position: 'absolute', top: 0, left: 0, + width: this.width(), + height: this.height() + }, dialog.options.overlay)); + + (dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe()); + + this.instances.push($el); + return $el; + }, + + destroy: function($el) { + this.instances.splice($.inArray(this.instances, $el), 1); + + if (this.instances.length === 0) { + $('a, :input').add([document, window]).unbind('.dialog-overlay'); + } + + $el.remove(); + }, + + height: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollHeight = Math.max( + document.documentElement.scrollHeight, + document.body.scrollHeight + ); + var offsetHeight = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight + ); + + if (scrollHeight < offsetHeight) { + return $(window).height() + 'px'; + } else { + return scrollHeight + 'px'; + } + // handle Opera + } else if ($.browser.opera) { + return Math.max( + window.innerHeight, + $(document).height() + ) + 'px'; + // handle "good" browsers + } else { + return $(document).height() + 'px'; + } + }, + + width: function() { + // handle IE 6 + if ($.browser.msie && $.browser.version < 7) { + var scrollWidth = Math.max( + document.documentElement.scrollWidth, + document.body.scrollWidth + ); + var offsetWidth = Math.max( + document.documentElement.offsetWidth, + document.body.offsetWidth + ); + + if (scrollWidth < offsetWidth) { + return $(window).width() + 'px'; + } else { + return scrollWidth + 'px'; + } + // handle Opera + } else if ($.browser.opera) { + return Math.max( + window.innerWidth, + $(document).width() + ) + 'px'; + // handle "good" browsers + } else { + return $(document).width() + 'px'; + } + }, + + resize: function() { + /* If the dialog is draggable and the user drags it past the + * right edge of the window, the document becomes wider so we + * need to stretch the overlay. If the user then drags the + * dialog back to the left, the document will become narrower, + * so we need to shrink the overlay to the appropriate size. + * This is handled by shrinking the overlay before setting it + * to the full document size. + */ + var $overlays = $([]); + $.each($.ui.dialog.overlay.instances, function() { + $overlays = $overlays.add(this); + }); + + $overlays.css({ + width: 0, + height: 0 + }).css({ + width: $.ui.dialog.overlay.width(), + height: $.ui.dialog.overlay.height() + }); + } +}); + +$.extend($.ui.dialog.overlay.prototype, { + destroy: function() { + $.ui.dialog.overlay.destroy(this.$el); + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.draggable.js hunk ./static/js/jquery/ui/ui.draggable.js 1 +/* + * jQuery UI Draggable @VERSION + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Draggables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.draggable", $.extend({}, $.ui.mouse, { + + getHandle: function(e) { + + var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; + $(this.options.handle, this.element) + .find("*") + .andSelf() + .each(function() { + if(this == e.target) handle = true; + }); + + return handle; + + }, + + createHelper: function() { + + var o = this.options; + var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [e])) : (o.helper == 'clone' ? this.element.clone() : this.element); + + if(!helper.parents('body').length) + helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); + + if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) + helper.css("position", "absolute"); + + return helper; + + }, + + + _init: function() { + + if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position"))) + this.element[0].style.position = 'relative'; + + (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-draggable")); + (this.options.disabled && this.element.addClass('ui-draggable-disabled')); + + this._mouseInit(); + + }, + + _mouseCapture: function(e) { + + var o = this.options; + + if (this.helper || o.disabled || $(e.target).is('.ui-resizable-handle')) + return false; + + //Quit if we're not on a valid handle + this.handle = this.getHandle(e); + if (!this.handle) + return false; + + return true; + + }, + + _mouseStart: function(e) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this.createHelper(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + this.margins = { //Cache the margins + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0) + }; + + this.cssPosition = this.helper.css("position"); //Store the helper's css position + this.offset = this.element.offset(); //The element's absolute position on the page + this.offset = { //Substract the margins from the element's absolute offset + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + this.offset.click = { //Where the click happened, relative to the element + left: e.pageX - this.offset.left, + top: e.pageY - this.offset.top + }; + + //Calling this method cached the next parents that have scrollTop / scrollLeft attached + this.cacheScrollParents(); + + + this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); //Get the offsetParent and cache its position + if(this.offsetParent[0] == document.body && $.browser.mozilla) po = { top: 0, left: 0 }; //Ugly FF3 fix + this.offset.parent = { //Store its position plus border + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + if(this.cssPosition == "relative") { + var p = this.element.position(); + this.offset.relative = { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollTopParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollLeftParent.scrollLeft() + }; + } else { + this.offset.relative = { top: 0, left: 0 }; + } + + //Generate the original position + this.originalPosition = this._generatePosition(e); + + //Cache the helper size + this.cacheHelperProportions(); + + //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied + if(o.cursorAt) + this.adjustOffsetFromHelper(o.cursorAt); + + //Cache later used stuff + $.extend(this, { + PAGEY_INCLUDES_SCROLL: (this.cssPosition == "absolute" && (!this.scrollTopParent[0].tagName || (/(html|body)/i).test(this.scrollTopParent[0].tagName))), + PAGEX_INCLUDES_SCROLL: (this.cssPosition == "absolute" && (!this.scrollLeftParent[0].tagName || (/(html|body)/i).test(this.scrollLeftParent[0].tagName))), + OFFSET_PARENT_NOT_SCROLL_PARENT_Y: this.scrollTopParent[0] != this.offsetParent[0] && !(this.scrollTopParent[0] == document && (/(body|html)/i).test(this.offsetParent[0].tagName)), + OFFSET_PARENT_NOT_SCROLL_PARENT_X: this.scrollLeftParent[0] != this.offsetParent[0] && !(this.scrollLeftParent[0] == document && (/(body|html)/i).test(this.offsetParent[0].tagName)) + }); + + if(o.containment) + this.setContainment(); + + + //Call plugins and callbacks + this._propagate("start", e); + + //Recache the helper size + this.cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, e); + + this.helper.addClass("ui-draggable-dragging"); + this._mouseDrag(e); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + }, + + cacheScrollParents: function() { + + this.scrollTopParent = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this.helper); + this.scrollLeftParent = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this.helper); + + }, + + adjustOffsetFromHelper: function(obj) { + if(obj.left != undefined) this.offset.click.left = obj.left + this.margins.left; + if(obj.right != undefined) this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + if(obj.top != undefined) this.offset.click.top = obj.top + this.margins.top; + if(obj.bottom != undefined) this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + }, + + cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + setContainment: function() { + + var o = this.options; + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0), + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0) + ]; + + if(!(/^(document|window|parent)$/).test(o.containment)) { + var ce = $(o.containment)[0]; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.relative.left - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0), + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.relative.top - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0) + ]; + } + + }, + + + _convertPositionTo: function(d, pos) { + + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + + return { + top: ( + pos.top // the calculated relative position + + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - (this.cssPosition == "fixed" || this.PAGEY_INCLUDES_SCROLL || this.OFFSET_PARENT_NOT_SCROLL_PARENT_Y ? 0 : this.scrollTopParent.scrollTop()) * mod // The offsetParent's scroll position, not if the element is fixed + + (this.cssPosition == "fixed" ? $(document).scrollTop() : 0) * mod + + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods) + ), + left: ( + pos.left // the calculated relative position + + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - (this.cssPosition == "fixed" || this.PAGEX_INCLUDES_SCROLL || this.OFFSET_PARENT_NOT_SCROLL_PARENT_X ? 0 : this.scrollLeftParent.scrollLeft()) * mod // The offsetParent's scroll position, not if the element is fixed + + (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0) * mod + + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods) + ) + }; + }, + _generatePosition: function(e) { + + var o = this.options; + var position = { + top: ( + e.pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + (this.cssPosition == "fixed" || this.PAGEY_INCLUDES_SCROLL || this.OFFSET_PARENT_NOT_SCROLL_PARENT_Y ? 0 : this.scrollTopParent.scrollTop()) // The offsetParent's scroll position, not if the element is fixed + - (this.cssPosition == "fixed" ? $(document).scrollTop() : 0) + ), + left: ( + e.pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + (this.cssPosition == "fixed" || this.PAGEX_INCLUDES_SCROLL || this.OFFSET_PARENT_NOT_SCROLL_PARENT_X ? 0 : this.scrollLeftParent.scrollLeft()) // The offsetParent's scroll position, not if the element is fixed + - (this.cssPosition == "fixed" ? $(document).scrollLeft() : 0) + ) + }; + + if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + if(this.containment) { + if(position.left < this.containment[0]) position.left = this.containment[0]; + if(position.top < this.containment[1]) position.top = this.containment[1]; + if(position.left > this.containment[2]) position.left = this.containment[2]; + if(position.top > this.containment[3]) position.top = this.containment[3]; + } + + if(o.grid) { + var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1]; + position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0]; + position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + return position; + }, + _mouseDrag: function(e) { + + //Compute the helpers position + this.position = this._generatePosition(e); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + this.position = this._propagate("drag", e) || this.position; + + if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; + if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; + if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); + + return false; + }, + _mouseStop: function(e) { + + //If we are using droppables, inform the manager about the drop + var dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) + var dropped = $.ui.ddmanager.drop(this, e); + + if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + var self = this; + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10) || 500, function() { + self._propagate("stop", e); + self._clear(); + }); + } else { + this._propagate("stop", e); + this._clear(); + } + + return false; + }, + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.options.helper != 'original' && !this.cancelHelperRemoval) this.helper.remove(); + //if($.ui.ddmanager) $.ui.ddmanager.current = null; + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + plugins: {}, + uiHash: function(e) { + return { + helper: this.helper, + position: this.position, + absolutePosition: this.positionAbs, + options: this.options + }; + }, + _propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.uiHash()]); + if(n == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins + return this.element.triggerHandler(n == "drag" ? n : "drag"+n, [e, this.uiHash()], this.options[n]); + }, + destroy: function() { + if(!this.element.data('draggable')) return; + this.element.removeData("draggable").unbind(".draggable").removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled'); + this._mouseDestroy(); + } +})); + +$.extend($.ui.draggable, { + defaults: { + appendTo: "parent", + axis: false, + cancel: ":input", + delay: 0, + distance: 1, + helper: "original", + scope: "default", + cssNamespace: "ui" + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function(e, ui) { + var t = $('body'); + if (t.css("cursor")) ui.options._cursor = t.css("cursor"); + t.css("cursor", ui.options.cursor); + }, + stop: function(e, ui) { + if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(e, ui) { + var t = $(ui.helper); + if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); + t.css('zIndex', ui.options.zIndex); + }, + stop: function(e, ui) { + if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(e, ui) { + var t = $(ui.helper); + if(t.css("opacity")) ui.options._opacity = t.css("opacity"); + t.css('opacity', ui.options.opacity); + }, + stop: function(e, ui) { + if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); + } +}); + +$.ui.plugin.add("draggable", "iframeFix", { + start: function(e, ui) { + $(ui.options.iframeFix === true ? "iframe" : ui.options.iframeFix).each(function() { + $('
') + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + }, + stop: function(e, ui) { + $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //Remove frame helpers + } +}); + + + +$.ui.plugin.add("draggable", "scroll", { + start: function(e, ui) { + var o = ui.options; + var i = $(this).data("draggable"); + o.scrollSensitivity = o.scrollSensitivity || 20; + o.scrollSpeed = o.scrollSpeed || 20; + + i.overflowY = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + i.overflowX = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(this); + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') i.overflowYOffset = i.overflowY.offset(); + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') i.overflowXOffset = i.overflowX.offset(); + + }, + drag: function(e, ui) { + + var o = ui.options, scrolled = false; + var i = $(this).data("draggable"); + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { + if((i.overflowYOffset.top + i.overflowY[0].offsetHeight) - e.pageY < o.scrollSensitivity) + i.overflowY[0].scrollTop = scrolled = i.overflowY[0].scrollTop + o.scrollSpeed; + if(e.pageY - i.overflowYOffset.top < o.scrollSensitivity) + i.overflowY[0].scrollTop = scrolled = i.overflowY[0].scrollTop - o.scrollSpeed; + + } else { + if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { + if((i.overflowXOffset.left + i.overflowX[0].offsetWidth) - e.pageX < o.scrollSensitivity) + i.overflowX[0].scrollLeft = scrolled = i.overflowX[0].scrollLeft + o.scrollSpeed; + if(e.pageX - i.overflowXOffset.left < o.scrollSensitivity) + i.overflowX[0].scrollLeft = scrolled = i.overflowX[0].scrollLeft - o.scrollSpeed; + } else { + if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + if(scrolled !== false) + $.ui.ddmanager.prepareOffsets(i, e); + + } +}); + + +$.ui.plugin.add("draggable", "snap", { + start: function(e, ui) { + + var inst = $(this).data("draggable"); + inst.snapElements = []; + + $(ui.options.snap.constructor != String ? ( ui.options.snap.items || ':data(draggable)' ) : ui.options.snap).each(function() { + var $t = $(this); var $o = $t.offset(); + if(this != inst.element[0]) inst.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + }); + + }, + drag: function(e, ui) { + + var inst = $(this).data("draggable"); + var d = ui.options.snapTolerance || 20; + + var x1 = ui.absolutePosition.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.absolutePosition.top, y2 = y1 + inst.helperProportions.height; + + for (var i = inst.snapElements.length - 1; i >= 0; i--){ + + var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, + t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, null, $.extend(inst.uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = false; + continue; + } + + if(ui.options.snapMode != 'inner') { + var ts = Math.abs(t - y2) <= d; + var bs = Math.abs(b - y1) <= d; + var ls = Math.abs(l - x2) <= d; + var rs = Math.abs(r - x1) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left; + } + + var first = (ts || bs || ls || rs); + + if(ui.options.snapMode != 'outer') { + var ts = Math.abs(t - y1) <= d; + var bs = Math.abs(b - y2) <= d; + var ls = Math.abs(l - x1) <= d; + var rs = Math.abs(r - x2) <= d; + if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top; + if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; + if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left; + if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, null, $.extend(inst.uiHash(), { snapItem: inst.snapElements[i].item }))); + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + }; + + } +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(e,ui) { + + var inst = $(this).data("draggable"); + inst.sortables = []; + $(ui.options.connectToSortable).each(function() { + if($.data(this, 'sortable')) { + var sortable = $.data(this, 'sortable'); + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache + sortable._propagate("activate", e, inst); + } + }); + + }, + stop: function(e,ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("draggable"); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + this.instance.isOver = 0; + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + if(this.shouldRevert) this.instance.options.revert = true; //revert here + this.instance._mouseStop(e); + + //Also propagate receive event, since the sortable is actually receiving a element + this.instance.element.triggerHandler("sortreceive", [e, $.extend(this.instance.ui(), { sender: inst.element })], this.instance.options["receive"]); + + this.instance.options.helper = this.instance.options._helper; + } else { + this.instance._propagate("deactivate", e, inst); + } + + }); + + }, + drag: function(e,ui) { + + var inst = $(this).data("draggable"), self = this; + + var checkPos = function(o) { + + var l = o.left, r = l + o.width, + t = o.top, b = t + o.height; + + return (l < (this.positionAbs.left + this.offset.click.left) && (this.positionAbs.left + this.offset.click.left) < r + && t < (this.positionAbs.top + this.offset.click.top) && (this.positionAbs.top + this.offset.click.top) < b); + }; + + $.each(inst.sortables, function(i) { + + if(checkPos.call(inst, this.instance.containerCache)) { + + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + this.instance.isOver = 1; + + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(self).clone().appendTo(this.instance.element).data("sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + e.target = this.instance.currentItem[0]; + this.instance._mouseCapture(e, true); + this.instance._mouseStart(e, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._propagate("toSortable", e); + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) this.instance._mouseDrag(e); + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + this.instance.options.revert = false; //No revert here + this.instance._mouseStop(e, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) this.instance.placeholder.remove(); + + inst._propagate("fromSortable", e); + } + + }; + + }); + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function(e,ui) { + var group = $.makeArray($(ui.options.stack.group)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || ui.options.stack.min) - (parseInt($(b).css("zIndex"),10) || ui.options.stack.min); + }); + + $(group).each(function(i) { + this.style.zIndex = ui.options.stack.min + i; + }); + + this[0].style.zIndex = ui.options.stack.min + group.length; + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.droppable.js hunk ./static/js/jquery/ui/ui.droppable.js 1 +/* + * jQuery UI Droppable @VERSION + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Droppables + * + * Depends: + * ui.core.js + * ui.draggable.js + */ +(function($) { + +$.widget("ui.droppable", { + + _setData: function(key, value) { + + if(key == 'accept') { + this.options.accept = value && $.isFunction(value) ? value : function(d) { + return d.is(accept); + }; + } else { + $.widget.prototype._setData.apply(this, arguments); + } + + }, + + _init: function() { + + var o = this.options, accept = o.accept; + this.isover = 0; this.isout = 1; + + this.options.accept = this.options.accept && $.isFunction(this.options.accept) ? this.options.accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[this.options.scope] = $.ui.ddmanager.droppables[this.options.scope] || []; + $.ui.ddmanager.droppables[this.options.scope].push(this); + + (this.options.cssNamespace && this.element.addClass(this.options.cssNamespace+"-droppable")); + + }, + plugins: {}, + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + absolutePosition: c.positionAbs, + options: this.options, + element: this.element + }; + }, + destroy: function() { + var drop = $.ui.ddmanager.droppables[this.options.scope]; + for ( var i = 0; i < drop.length; i++ ) + if ( drop[i] == this ) + drop.splice(i, 1); + + this.element + .removeClass("ui-droppable-disabled") + .removeData("droppable") + .unbind(".droppable"); + }, + _over: function(e) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'over', [e, this.ui(draggable)]); + this.element.triggerHandler("dropover", [e, this.ui(draggable)], this.options.over); + } + + }, + _out: function(e) { + + var draggable = $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element + + if (this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'out', [e, this.ui(draggable)]); + this.element.triggerHandler("dropout", [e, this.ui(draggable)], this.options.out); + } + + }, + _drop: function(e,custom) { + + var draggable = custom || $.ui.ddmanager.current; + if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element + + var childrenIntersection = false; + this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, 'droppable'); + if(inst.options.greedy && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)) { + childrenIntersection = true; return false; + } + }); + if(childrenIntersection) return false; + + if(this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + $.ui.plugin.call(this, 'drop', [e, this.ui(draggable)]); + this.element.triggerHandler("drop", [e, this.ui(draggable)], this.options.drop); + return this.element; + } + + return false; + + }, + _activate: function(e) { + + var draggable = $.ui.ddmanager.current; + $.ui.plugin.call(this, 'activate', [e, this.ui(draggable)]); + if(draggable) this.element.triggerHandler("dropactivate", [e, this.ui(draggable)], this.options.activate); + + }, + _deactivate: function(e) { + + var draggable = $.ui.ddmanager.current; + $.ui.plugin.call(this, 'deactivate', [e, this.ui(draggable)]); + if(draggable) this.element.triggerHandler("dropdeactivate", [e, this.ui(draggable)], this.options.deactivate); + + } +}); + +$.extend($.ui.droppable, { + defaults: { + disabled: false, + tolerance: 'intersect', + scope: 'default', + cssNamespace: 'ui' + } +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) return false; + + var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height; + var l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case 'fit': + return (l < x1 && x2 < r + && t < y1 && y2 < b); + break; + case 'intersect': + return (l < x1 + (draggable.helperProportions.width / 2) // Right Half + && x2 - (draggable.helperProportions.width / 2) < r // Left Half + && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half + && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + break; + case 'pointer': + return (l < ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left) && ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left) < r + && t < ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top) && ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top) < b); + break; + case 'touch': + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + break; + default: + return false; + break; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { 'default': [] }, + prepareOffsets: function(t, e) { + + var m = $.ui.ddmanager.droppables[t.options.scope]; + var type = e ? e.type : null; // workaround for #2317 + var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); + + droppablesLoop: for (var i = 0; i < m.length; i++) { + + if(m[i].options.disabled || (t && !m[i].options.accept.call(m[i].element,(t.currentItem || t.element)))) continue; //No disabled and non-accepted + for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item + m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + if(type == "dragstart" || type == "sortactivate") m[i]._activate.call(m[i], e); //Activate the droppable if used directly from draggables + + } + + }, + drop: function(draggable, e) { + + var dropped = false; + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(!this.options) return; + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) + dropped = this._drop.call(this, e); + + if (!this.options.disabled && this.visible && this.options.accept.call(this.element,(draggable.currentItem || draggable.element))) { + this.isout = 1; this.isover = 0; + this._deactivate.call(this, e); + } + + }); + return dropped; + + }, + drag: function(draggable, e) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, e); + + //Run through all droppables and check their positions based on specific tolerance options + + $.each($.ui.ddmanager.droppables[draggable.options.scope], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) return; + var intersects = $.ui.intersect(draggable, this, this.options.tolerance); + + var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); + if(!c) return; + + var parentInstance; + if (this.options.greedy) { + var parent = this.element.parents(':data(droppable):eq(0)'); + if (parent.length) { + parentInstance = $.data(parent[0], 'droppable'); + parentInstance.greedyChild = (c == 'isover' ? 1 : 0); + } + } + + // we just moved into a greedy child + if (parentInstance && c == 'isover') { + parentInstance['isover'] = 0; + parentInstance['isout'] = 1; + parentInstance._out.call(parentInstance, e); + } + + this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; + this[c == "isover" ? "_over" : "_out"].call(this, e); + + // we just moved out of a greedy child + if (parentInstance && c == 'isout') { + parentInstance['isout'] = 0; + parentInstance['isover'] = 1; + parentInstance._over.call(parentInstance, e); + } + }); + + } +}; + +/* + * Droppable Extensions + */ + +$.ui.plugin.add("droppable", "activeClass", { + activate: function(e, ui) { + $(this).addClass(ui.options.activeClass); + }, + deactivate: function(e, ui) { + $(this).removeClass(ui.options.activeClass); + }, + drop: function(e, ui) { + $(this).removeClass(ui.options.activeClass); + } +}); + +$.ui.plugin.add("droppable", "hoverClass", { + over: function(e, ui) { + $(this).addClass(ui.options.hoverClass); + }, + out: function(e, ui) { + $(this).removeClass(ui.options.hoverClass); + }, + drop: function(e, ui) { + $(this).removeClass(ui.options.hoverClass); + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.magnifier.js hunk ./static/js/jquery/ui/ui.magnifier.js 1 +/* + * jQuery UI Magnifier @VERSION + * + * Copyright (c) 2008 jQuery + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Magnifier + * + * Depends: + * ui.core.js + */ +(function($) { + +var counter = 0; + +$.widget("ui.magnifier", { + _init: function() { + var self = this, + o = this.options; + + this.element + .addClass("ui-magnifier") + .bind('click.magnifier', function(e) { + (!self.disabled && o.click && o.click.apply(this, [e, { + options: self.options, + current: self.current[0], + currentOffset: self.current[1] + }])); + }); + + // the element must have relative or absolute positioning + if (!(/^(r|a)/).test(this.element.css("position"))) { + this.element.css("position", "relative"); + } + + this.items = []; + this.element.find(o.items).each(function() { + var $this = $(this); + // TODO: use a hash so references to this data is readable + self.items.push([ + this, + $this.offset(), + [$this.width(),$this.height()], + (o.overlap ? $this.position() : null) + ]); + + (o.opacity && $this.css('opacity', o.opacity.min)); + }); + + // absolutize + (o.overlap && $.each(this.items, function() { + $(this[0]).css({ + position: "absolute", + top: this[3].top, + left: this[3].left + }); + })); + + this.identifier = ++counter; + $(document).bind("mousemove.magnifier"+this.identifier, function(e) { + (self.disabled || self._magnify.apply(self, [e])); + }); + + this.pp = this.element.offset(); + }, + + destroy: function() { + this.reset(); + this.element + .removeClass("ui-magnifier ui-magnifier-disabled") + .unbind(".magnifier"); + $(document).unbind("mousemove.magnifier"+this.identifier); + }, + + disable: function() { + this.reset(); + $.widget.prototype.disable.apply(this, arguments); + }, + + reset: function(e) { + var o = this.options; + + $.each(this.items, function() { + var item = this; + $(item[0]).css({ + width: item[2][0], + height: item[2][1], + top: (item[3] ? item[3].top : 0), + left: (item[3] ? item[3].left : 0) + }); + + (o.opacity && $(item[0]).css('opacity', o.opacity.min)); + (o.zIndex && $(item[0]).css("z-index", "")); + }); + }, + + _magnify: function(e) { + var p = [e.pageX,e.pageY], o = this.options, c, distance = 1; + this.current = this.items[0]; + + // Compute the parent's distance + // we don't need to fire anything if we are not near the parent + var overlap = ((p[0] > this.pp.left-o.distance) && + (p[0] < this.pp.left + this.element[0].offsetWidth + o.distance) && + (p[1] > this.pp.top-o.distance) && + (p[1] < this.pp.top + this.element[0].offsetHeight + o.distance)); + if (!overlap) { return false; } + + for (var i=0; i *" + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.progressbar.js hunk ./static/js/jquery/ui/ui.progressbar.js 1 - +/* + * jQuery UI ProgressBar @VERSION + * + * Copyright (c) 2008 Eduardo Lundgren + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/ProgressBar + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.progressbar", { + _init: function() { + + this._interval = this.options.interval; + + var self = this, + options = this.options, + id = (new Date()).getTime()+Math.random(), + text = options.text || '0%'; + + this.element.addClass("ui-progressbar").width(options.width); + + $.extend(this, { + active: false, + pixelState: 0, + percentState: 0, + identifier: id, + bar: $('
').css({ + width: '0px', overflow: 'hidden', zIndex: 100 + }), + textElement: $('
').html(text).css({ + width: '0px', overflow: 'hidden' + }), + textBg: $('
').html(text).css({ + width: this.element.width() + }), + wrapper: $('
') + }); + + this.wrapper + .append(this.bar.append(this.textElement.addClass(options.textClass)), this.textBg) + .appendTo(this.element); + }, + + plugins: {}, + ui: function(e) { + return { + instance: this, + identifier: this.identifier, + options: this.options, + element: this.bar, + textElement: this.textElement, + pixelState: this.pixelState, + percentState: this.percentState + }; + }, + + _propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.ui()]); + this.element.triggerHandler(n == "progressbar" ? n : ["progressbar", n].join(""), [e, this.ui()], this.options[n]); + }, + + destroy: function() { + this.stop(); + + this.element + .removeClass("ui-progressbar ui-progressbar-disabled") + .removeData("progressbar").unbind(".progressbar") + .find('.ui-progressbar-wrap').remove(); + + delete jQuery.easing[this.identifier]; + }, + + enable: function() { + this.element.removeClass("ui-progressbar-disabled"); + this.disabled = false; + }, + + disable: function() { + this.element.addClass("ui-progressbar-disabled"); + this.disabled = true; + }, + + start: function() { + var self = this, options = this.options; + + if (this.disabled) { + return; + } + + jQuery.easing[this.identifier] = function (x, t, b, c, d) { + var inc = options.increment, + width = options.width, + step = ((inc > width ? width : inc)/width), + state = Math.round(x/step)*step; + return state > 1 ? 1 : state; + }; + + self.active = true; + + setTimeout( + function() { + self.active = false; + }, + options.duration + ); + + this._animate(); + + this._propagate('start', this.ui()); + return false; + }, + + _animate: function() { + var self = this, + options = this.options, + interval = options.interval; + + this.bar.animate( + { + width: options.width + }, + { + duration: interval, + easing: this.identifier, + step: function(step, b) { + self.progress((step/options.width)*100); + var timestamp = new Date().getTime(), elapsedTime = (timestamp - b.startTime); + options.interval = interval - elapsedTime; + }, + complete: function() { + delete jQuery.easing[self.identifier]; + self.pause(); + + if (self.active) { + /*TODO*/ + } + } + } + ); + }, + + pause: function() { + if (this.disabled) return; + this.bar.stop(); + this._propagate('pause', this.ui()); + }, + + stop: function() { + this.bar.stop(); + this.bar.width(0); + this.textElement.width(0); + this.bar.addClass('ui-hidden'); + this.options.interval = this._interval; + this._propagate('stop', this.ui()); + }, + + text: function(text){ + this.textElement.html(text); + this.textBg.html(text); + }, + + progress: function(percentState) { + if (this.bar.is('.ui-hidden')) { + this.bar.removeClass('ui-hidden'); + } + + this.percentState = percentState > 100 ? 100 : percentState; + this.pixelState = (this.percentState/100)*this.options.width; + this.bar.width(this.pixelState); + this.textElement.width(this.pixelState); + + if (this.options.range && !this.options.text) { + this.textElement.html(Math.round(this.percentState) + '%'); + } + this._propagate('progress', this.ui()); + } +}); + +$.ui.progressbar.defaults = { + width: 300, + duration: 3000, + interval: 200, + increment: 1, + range: true, + text: '', + addClass: '', + textClass: '' +}; + +})(jQuery); addfile ./static/js/jquery/ui/ui.resizable.js hunk ./static/js/jquery/ui/ui.resizable.js 1 +/* + * jQuery UI Resizable @VERSION + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Resizables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.resizable", $.extend({}, $.ui.mouse, { + _init: function() { + + var self = this, o = this.options; + + var elpos = this.element.css('position'); + + this.originalElement = this.element; + + // simulate .ui-resizable { position: relative; } + this.element.addClass("ui-resizable").css({ position: /static/.test(elpos) ? 'relative' : elpos }); + + $.extend(o, { + _aspectRatio: !!(o.aspectRatio), + helper: o.helper || o.ghost || o.animate ? o.helper || 'proxy' : null, + knobHandles: o.knobHandles === true ? 'ui-resizable-knob-handle' : o.knobHandles + }); + + //Default Theme + var aBorder = '1px solid #DEDEDE'; + + o.defaultTheme = { + 'ui-resizable': { display: 'block' }, + 'ui-resizable-handle': { position: 'absolute', background: '#F2F2F2', fontSize: '0.1px' }, + 'ui-resizable-n': { cursor: 'n-resize', height: '4px', left: '0px', right: '0px', borderTop: aBorder }, + 'ui-resizable-s': { cursor: 's-resize', height: '4px', left: '0px', right: '0px', borderBottom: aBorder }, + 'ui-resizable-e': { cursor: 'e-resize', width: '4px', top: '0px', bottom: '0px', borderRight: aBorder }, + 'ui-resizable-w': { cursor: 'w-resize', width: '4px', top: '0px', bottom: '0px', borderLeft: aBorder }, + 'ui-resizable-se': { cursor: 'se-resize', width: '4px', height: '4px', borderRight: aBorder, borderBottom: aBorder }, + 'ui-resizable-sw': { cursor: 'sw-resize', width: '4px', height: '4px', borderBottom: aBorder, borderLeft: aBorder }, + 'ui-resizable-ne': { cursor: 'ne-resize', width: '4px', height: '4px', borderRight: aBorder, borderTop: aBorder }, + 'ui-resizable-nw': { cursor: 'nw-resize', width: '4px', height: '4px', borderLeft: aBorder, borderTop: aBorder } + }; + + o.knobTheme = { + 'ui-resizable-handle': { background: '#F2F2F2', border: '1px solid #808080', height: '8px', width: '8px' }, + 'ui-resizable-n': { cursor: 'n-resize', top: '0px', left: '45%' }, + 'ui-resizable-s': { cursor: 's-resize', bottom: '0px', left: '45%' }, + 'ui-resizable-e': { cursor: 'e-resize', right: '0px', top: '45%' }, + 'ui-resizable-w': { cursor: 'w-resize', left: '0px', top: '45%' }, + 'ui-resizable-se': { cursor: 'se-resize', right: '0px', bottom: '0px' }, + 'ui-resizable-sw': { cursor: 'sw-resize', left: '0px', bottom: '0px' }, + 'ui-resizable-nw': { cursor: 'nw-resize', left: '0px', top: '0px' }, + 'ui-resizable-ne': { cursor: 'ne-resize', right: '0px', top: '0px' } + }; + + o._nodeName = this.element[0].nodeName; + + //Wrap the element if it cannot hold child nodes + if(o._nodeName.match(/canvas|textarea|input|select|button|img/i)) { + var el = this.element; + + //Opera fixing relative position + if (/relative/.test(el.css('position')) && $.browser.opera) + el.css({ position: 'relative', top: 'auto', left: 'auto' }); + + //Create a wrapper element and set the wrapper to the new current internal element + el.wrap( + $('
').css( { + position: el.css('position'), + width: el.outerWidth(), + height: el.outerHeight(), + top: el.css('top'), + left: el.css('left') + }) + ); + + var oel = this.element; this.element = this.element.parent(); + + // store instance on wrapper + this.element.data('resizable', this); + + //Move margins to the wrapper + this.element.css({ marginLeft: oel.css("marginLeft"), marginTop: oel.css("marginTop"), + marginRight: oel.css("marginRight"), marginBottom: oel.css("marginBottom") + }); + + oel.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + if ($.browser.safari && o.preventDefault) oel.css('resize', 'none'); + + o.proportionallyResize = oel.css({ position: 'static', zoom: 1, display: 'block' }); + + // avoid IE jump + this.element.css({ margin: oel.css('margin') }); + + // fix handlers offset + this._proportionallyResize(); + } + + if(!o.handles) o.handles = !$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }; + if(o.handles.constructor == String) { + + o.zIndex = o.zIndex || 1000; + + if(o.handles == 'all') o.handles = 'n,e,s,w,se,sw,ne,nw'; + + var n = o.handles.split(","); o.handles = {}; + + // insertions are applied when don't have theme loaded + var insertionsDefault = { + handle: 'position: absolute; display: none; overflow:hidden;', + n: 'top: 0pt; width:100%;', + e: 'right: 0pt; height:100%;', + s: 'bottom: 0pt; width:100%;', + w: 'left: 0pt; height:100%;', + se: 'bottom: 0pt; right: 0px;', + sw: 'bottom: 0pt; left: 0px;', + ne: 'top: 0pt; right: 0px;', + nw: 'top: 0pt; left: 0px;' + }; + + for(var i = 0; i < n.length; i++) { + var handle = $.trim(n[i]), dt = o.defaultTheme, hname = 'ui-resizable-'+handle, loadDefault = !$.ui.css(hname) && !o.knobHandles, userKnobClass = $.ui.css('ui-resizable-knob-handle'), + allDefTheme = $.extend(dt[hname], dt['ui-resizable-handle']), allKnobTheme = $.extend(o.knobTheme[hname], !userKnobClass ? o.knobTheme['ui-resizable-handle'] : {}); + + // increase zIndex of sw, se, ne, nw axis + var applyZIndex = /sw|se|ne|nw/.test(handle) ? { zIndex: ++o.zIndex } : {}; + + var defCss = (loadDefault ? insertionsDefault[handle] : ''), + axis = $(['
'].join('')).css( applyZIndex ); + o.handles[handle] = '.ui-resizable-'+handle; + + this.element.append( + //Theme detection, if not loaded, load o.defaultTheme + axis.css( loadDefault ? allDefTheme : {} ) + // Load the knobHandle css, fix width, height, top, left... + .css( o.knobHandles ? allKnobTheme : {} ).addClass(o.knobHandles ? 'ui-resizable-knob-handle' : '').addClass(o.knobHandles) + ); + } + + if (o.knobHandles) this.element.addClass('ui-resizable-knob').css( !$.ui.css('ui-resizable-knob') ? { /*border: '1px #fff dashed'*/ } : {} ); + } + + this._renderAxis = function(target) { + target = target || this.element; + + for(var i in o.handles) { + if(o.handles[i].constructor == String) + o.handles[i] = $(o.handles[i], this.element).show(); + + if (o.transparent) + o.handles[i].css({opacity:0}); + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.element.is('.ui-wrapper') && + o._nodeName.match(/textarea|input|select|button/i)) { + + var axis = $(o.handles[i], this.element), padWrapper = 0; + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + var padPos = [ 'padding', + /ne|nw|n/.test(i) ? 'Top' : + /se|sw|s/.test(i) ? 'Bottom' : + /^e$/.test(i) ? 'Right' : 'Left' ].join(""); + + if (!o.transparent) + target.css(padPos, padWrapper); + + this._proportionallyResize(); + } + if(!$(o.handles[i]).length) continue; + } + }; + + this._renderAxis(this.element); + o._handles = $('.ui-resizable-handle', self.element); + + if (o.disableSelection) + o._handles.each(function(i, e) { $.ui.disableSelection(e); }); + + //Matching axis name + o._handles.mouseover(function() { + if (!o.resizing) { + if (this.className) + var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + //Axis, default = se + self.axis = o.axis = axis && axis[1] ? axis[1] : 'se'; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + o._handles.hide(); + $(self.element).addClass("ui-resizable-autohide").hover(function() { + $(this).removeClass("ui-resizable-autohide"); + o._handles.show(); + }, + function(){ + if (!o.resizing) { + $(this).addClass("ui-resizable-autohide"); + o._handles.hide(); + } + }); + } + + this._mouseInit(); + }, + plugins: {}, + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + options: this.options, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + }, + _propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.ui()]); + if (n != "resize") this.element.triggerHandler(["resize", n].join(""), [e, this.ui()], this.options[n]); + }, + destroy: function() { + var el = this.element, wrapped = el.children(".ui-resizable").get(0); + + this._mouseDestroy(); + + var _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled") + .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); + }; + + _destroy(el); + + if (el.is('.ui-wrapper') && wrapped) { + el.parent().append( + $(wrapped).css({ + position: el.css('position'), + width: el.outerWidth(), + height: el.outerHeight(), + top: el.css('top'), + left: el.css('left') + }) + ).end().remove(); + + _destroy(wrapped); + } + }, + + _mouseCapture: function(e) { + + if(this.options.disabled) return false; + + var handle = false; + for(var i in this.options.handles) { + if($(this.options.handles[i])[0] == e.target) handle = true; + } + if (!handle) return false; + + return true; + + }, + + _mouseStart: function(e) { + + var o = this.options, iniPos = this.element.position(), el = this.element, + num = function(v) { return parseInt(v, 10) || 0; }, ie6 = $.browser.msie && $.browser.version < 7; + o.resizing = true; + o.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; + + // bugfix #1749 + if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { + + // sOffset decides if document scrollOffset will be added to the top/left of the resizable element + var sOffset = $.browser.msie && !o.containment && (/absolute/).test(el.css('position')) && !(/relative/).test(el.parent().css('position')); + var dscrollt = sOffset ? o.documentScroll.top : 0, dscrolll = sOffset ? o.documentScroll.left : 0; + + el.css({ position: 'absolute', top: (iniPos.top + dscrollt), left: (iniPos.left + dscrolll) }); + } + + //Opera fixing relative position + if ($.browser.opera && /relative/.test(el.css('position'))) + el.css({ position: 'relative', top: 'auto', left: 'auto' }); + + this._renderProxy(); + + var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); + + if (o.containment) { + curleft += $(o.containment).scrollLeft()||0; + curtop += $(o.containment).scrollTop()||0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = o.helper || ie6 ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: e.pageX, top: e.pageY }; + + //Aspect Ratio + o.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height)||1); + + if (o.preserveCursor) + $('body').css('cursor', this.axis + '-resize'); + + this._propagate("start", e); + return true; + }, + _mouseDrag: function(e) { + + //Increase performance, avoid regex + var el = this.helper, o = this.options, props = {}, + self = this, smp = this.originalMousePosition, a = this.axis; + + var dx = (e.pageX-smp.left)||0, dy = (e.pageY-smp.top)||0; + var trigger = this._change[a]; + if (!trigger) return false; + + // Calculate the attrs that will be change + var data = trigger.apply(this, [e, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; + + if (o._aspectRatio || e.shiftKey) + data = this._updateRatio(data, e); + + data = this._respectSize(data, e); + + // plugins callbacks need to be called first + this._propagate("resize", e); + + el.css({ + top: this.position.top + "px", left: this.position.left + "px", + width: this.size.width + "px", height: this.size.height + "px" + }); + + if (!o.helper && o.proportionallyResize) + this._proportionallyResize(); + + this._updateCache(data); + + // calling the user callback at the end + this.element.triggerHandler("resize", [e, this.ui()], this.options["resize"]); + + return false; + }, + _mouseStop: function(e) { + + this.options.resizing = false; + var o = this.options, num = function(v) { return parseInt(v, 10) || 0; }, self = this; + + if(o.helper) { + var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName), + soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var s = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + if (!o.animate) + this.element.css($.extend(s, { top: top, left: left })); + + if (o.helper && !o.animate) this._proportionallyResize(); + } + + if (o.preserveCursor) + $('body').css('cursor', 'auto'); + + this._propagate("stop", e); + + if (o.helper) this.helper.remove(); + + return false; + }, + _updateCache: function(data) { + var o = this.options; + this.offset = this.helper.offset(); + if (data.left) this.position.left = data.left; + if (data.top) this.position.top = data.top; + if (data.height) this.size.height = data.height; + if (data.width) this.size.width = data.width; + }, + _updateRatio: function(data, e) { + + var o = this.options, cpos = this.position, csize = this.size, a = this.axis; + + if (data.height) data.width = (csize.height * o.aspectRatio); + else if (data.width) data.height = (csize.width / o.aspectRatio); + + if (a == 'sw') { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a == 'nw') { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + _respectSize: function(data, e) { + + var el = this.helper, o = this.options, pRatio = o._aspectRatio || e.shiftKey, a = this.axis, + ismaxw = data.width && o.maxWidth && o.maxWidth < data.width, ismaxh = data.height && o.maxHeight && o.maxHeight < data.height, + isminw = data.width && o.minWidth && o.minWidth > data.width, isminh = data.height && o.minHeight && o.minHeight > data.height; + + if (isminw) data.width = o.minWidth; + if (isminh) data.height = o.minHeight; + if (ismaxw) data.width = o.maxWidth; + if (ismaxh) data.height = o.maxHeight; + + var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; + var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + + if (isminw && cw) data.left = dw - o.minWidth; + if (ismaxw && cw) data.left = dw - o.maxWidth; + if (isminh && ch) data.top = dh - o.minHeight; + if (ismaxh && ch) data.top = dh - o.maxHeight; + + // fixing jump error on top/left - bug #2330 + var isNotwh = !data.width && !data.height; + if (isNotwh && !data.left && data.top) data.top = null; + else if (isNotwh && !data.top && data.left) data.left = null; + + return data; + }, + _proportionallyResize: function() { + var o = this.options; + if (!o.proportionallyResize) return; + var prel = o.proportionallyResize, el = this.helper || this.element; + + if (!o.borderDif) { + var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], + p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; + + o.borderDif = $.map(b, function(v, i) { + var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; + return border + padding; + }); + } + prel.css({ + height: (el.height() - o.borderDif[0] - o.borderDif[2]) + "px", + width: (el.width() - o.borderDif[1] - o.borderDif[3]) + "px" + }); + }, + _renderProxy: function() { + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(o.helper) { + this.helper = this.helper || $('
'); + + // fix ie6 offset + var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), + pxyoffset = ( ie6 ? 2 : -1 ); + + this.helper.addClass(o.helper).css({ + width: el.outerWidth() + pxyoffset, + height: el.outerHeight() + pxyoffset, + position: 'absolute', + left: this.elementOffset.left - ie6offset +'px', + top: this.elementOffset.top - ie6offset +'px', + zIndex: ++o.zIndex + }); + + this.helper.appendTo("body"); + + if (o.disableSelection) + $.ui.disableSelection(this.helper.get(0)); + + } else { + this.helper = el; + } + }, + _change: { + e: function(e, dx, dy) { + return { width: this.originalSize.width + dx }; + }, + w: function(e, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(e, dx, dy) { + var o = this.options, cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(e, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(e, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [e, dx, dy])); + }, + sw: function(e, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [e, dx, dy])); + }, + ne: function(e, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [e, dx, dy])); + }, + nw: function(e, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [e, dx, dy])); + } + } +})); + +$.extend($.ui.resizable, { + defaults: { + cancel: ":input", + distance: 1, + delay: 0, + preventDefault: true, + transparent: false, + minWidth: 10, + minHeight: 10, + aspectRatio: false, + disableSelection: true, + preserveCursor: true, + autoHide: false, + knobHandles: false + } +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "containment", { + + start: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"), el = self.element; + var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + if (!ce) return; + + self.containerElement = $(ce); + + if (/document/.test(oc) || oc == document) { + self.containerOffset = { left: 0, top: 0 }; + self.containerPosition = { left: 0, top: 0 }; + + self.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + + // i'm a node, so compute top, left, right, bottom + else{ + self.containerOffset = $(ce).offset(); + self.containerPosition = $(ce).position(); + self.containerSize = { height: $(ce).innerHeight(), width: $(ce).innerWidth() }; + + var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + self.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"), + ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, + pRatio = o._aspectRatio || e.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; + + if (ce[0] != document && /static/.test(ce.css('position'))) + cop = self.containerPosition; + + if (cp.left < (o.helper ? co.left : cop.left)) { + self.size.width = self.size.width + (o.helper ? (self.position.left - co.left) : (self.position.left - cop.left)); + if (pRatio) self.size.height = self.size.width / o.aspectRatio; + self.position.left = o.helper ? co.left : cop.left; + } + + if (cp.top < (o.helper ? co.top : 0)) { + self.size.height = self.size.height + (o.helper ? (self.position.top - co.top) : self.position.top); + if (pRatio) self.size.width = self.size.height * o.aspectRatio; + self.position.top = o.helper ? co.top : 0; + } + + var woset = (o.helper ? self.offset.left - co.left : (self.position.left - cop.left)) + self.sizeDiff.width, + hoset = (o.helper ? self.offset.top - co.top : self.position.top) + self.sizeDiff.height; + + if (woset + self.size.width >= self.parentData.width) { + self.size.width = self.parentData.width - woset; + if (pRatio) self.size.height = self.size.width / o.aspectRatio; + } + + if (hoset + self.size.height >= self.parentData.height) { + self.size.height = self.parentData.height - hoset; + if (pRatio) self.size.width = self.size.height * o.aspectRatio; + } + }, + + stop: function(e, ui){ + var o = ui.options, self = $(this).data("resizable"), cp = self.position, + co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; + + var helper = $(self.helper), ho = helper.offset(), w = helper.innerWidth(), h = helper.innerHeight(); + + + if (o.helper && !o.animate && /relative/.test(ce.css('position'))) + $(this).css({ left: (ho.left - co.left), top: (ho.top - co.top), width: w, height: h }); + + if (o.helper && !o.animate && /static/.test(ce.css('position'))) + $(this).css({ left: cop.left + (ho.left - co.left), top: cop.top + (ho.top - co.top), width: w, height: h }); + + } +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"), cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || e.shiftKey; + o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; + var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); + + if (/^(se|s|e)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + } + else if (/^(ne)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + } + else if (/^(sw)$/.test(a)) { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.left = op.left - ox; + } + else { + self.size.width = os.width + ox; + self.size.height = os.height + oy; + self.position.top = op.top - oy; + self.position.left = op.left - ox; + } + } + +}); + +$.ui.plugin.add("resizable", "animate", { + + stop: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"); + + var pr = o.proportionallyResize, ista = pr && (/textarea/i).test(pr.get(0).nodeName), + soffseth = ista && $.ui.hasScroll(pr.get(0), 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, + soffsetw = ista ? 0 : self.sizeDiff.width; + + var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, + left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, + top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; + + self.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration || "slow", easing: o.animateEasing || "swing", + step: function() { + + var data = { + width: parseInt(self.element.css('width'), 10), + height: parseInt(self.element.css('height'), 10), + top: parseInt(self.element.css('top'), 10), + left: parseInt(self.element.css('left'), 10) + }; + + if (pr) pr.css({ width: data.width, height: data.height }); + + // propagating resize, and updating values for each animation step + self._updateCache(data); + self._propagate("animate", e); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize, cs = self.size; + + if (!pr) self.ghost = self.element.clone(); + else self.ghost = pr.clone(); + + self.ghost.css( + { opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 } + ) + .addClass('ui-resizable-ghost').addClass(typeof o.ghost == 'string' ? o.ghost : ''); + + self.ghost.appendTo(self.helper); + + }, + + resize: function(e, ui){ + var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize; + + if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); + + }, + + stop: function(e, ui){ + var o = ui.options, self = $(this).data("resizable"), pr = o.proportionallyResize; + if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); + } + +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function(e, ui) { + var o = ui.options, self = $(this).data("resizable"), + + _store = function(exp) { + $(exp).each(function() { + $(this).data("resizable-alsoresize", { + width: parseInt($(this).width(), 10), height: parseInt($(this).height(), 10), + left: parseInt($(this).css('left'), 10), top: parseInt($(this).css('top'), 10) + }); + }); + }; + + if (typeof(o.alsoResize) == 'object') { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function(exp, c) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function(e, ui){ + var o = ui.options, self = $(this).data("resizable"), os = self.originalSize, op = self.originalPosition; + + var delta = { + height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, + top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 + }, + + _alsoResize = function(exp, c) { + $(exp).each(function() { + var start = $(this).data("resizable-alsoresize"), style = {}, css = c && c.length ? c : ['width', 'height', 'top', 'left']; + + $.each(css || ['width', 'height', 'top', 'left'], function(i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) + style[prop] = sum || null; + }); + $(this).css(style); + }); + }; + + if (typeof(o.alsoResize) == 'object') { + $.each(o.alsoResize, function(exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function(e, ui){ + $(this).removeData("resizable-alsoresize-start"); + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.selectable.js hunk ./static/js/jquery/ui/ui.selectable.js 1 +/* + * jQuery UI Selectable @VERSION + * + * Copyright (c) 2008 Richard D. Worth (rdworth.org) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Selectables + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.selectable", $.extend({}, $.ui.mouse, { + _init: function() { + var self = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + var selectees; + this.refresh = function() { + selectees = $(self.options.filter, self.element[0]); + selectees.each(function() { + var $this = $(this); + var pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.width(), + bottom: pos.top + $this.height(), + startselected: false, + selected: $this.hasClass('ui-selected'), + selecting: $this.hasClass('ui-selecting'), + unselecting: $this.hasClass('ui-unselecting') + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $(document.createElement('div')) + .css({border:'1px dotted black'}) + .addClass("ui-selectable-helper"); + }, + toggle: function() { + if(this.options.disabled){ + this.enable(); + } else { + this.disable(); + } + }, + destroy: function() { + this.element + .removeClass("ui-selectable ui-selectable-disabled") + .removeData("selectable") + .unbind(".selectable"); + this._mouseDestroy(); + }, + _mouseStart: function(e) { + var self = this; + + this.opos = [e.pageX, e.pageY]; + + if (this.options.disabled) + return; + + var options = this.options; + + this.selectees = $(options.filter, this.element[0]); + + // selectable START callback + this.element.triggerHandler("selectablestart", [e, { + "selectable": this.element[0], + "options": options + }], options.start); + + $('body').append(this.helper); + // position helper (lasso) + this.helper.css({ + "z-index": 100, + "position": "absolute", + "left": e.clientX, + "top": e.clientY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter('.ui-selected').each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!e.metaKey) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self.element.triggerHandler("selectableunselecting", [e, { + selectable: self.element[0], + unselecting: selectee.element, + options: options + }], options.unselecting); + } + }); + + var isSelectee = false; + $(e.target).parents().andSelf().each(function() { + if($.data(this, "selectable-item")) isSelectee = true; + }); + return this.options.keyboard ? !isSelectee : true; + }, + _mouseDrag: function(e) { + var self = this; + this.dragged = true; + + if (this.options.disabled) + return; + + var options = this.options; + + var x1 = this.opos[0], y1 = this.opos[1], x2 = e.pageX, y2 = e.pageY; + if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"); + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element == self.element[0]) + return; + var hit = false; + if (options.tolerance == 'touch') { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance == 'fit') { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass('ui-selecting'); + selectee.selecting = true; + // selectable SELECTING callback + self.element.triggerHandler("selectableselecting", [e, { + selectable: self.element[0], + selecting: selectee.element, + options: options + }], options.selecting); + } + } else { + // UNSELECT + if (selectee.selecting) { + if (e.metaKey && selectee.startselected) { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + selectee.$element.addClass('ui-selected'); + selectee.selected = true; + } else { + selectee.$element.removeClass('ui-selecting'); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + self.element.triggerHandler("selectableunselecting", [e, { + selectable: self.element[0], + unselecting: selectee.element, + options: options + }], options.unselecting); + } + } + if (selectee.selected) { + if (!e.metaKey && !selectee.startselected) { + selectee.$element.removeClass('ui-selected'); + selectee.selected = false; + + selectee.$element.addClass('ui-unselecting'); + selectee.unselecting = true; + // selectable UNSELECTING callback + self.element.triggerHandler("selectableunselecting", [e, { + selectable: self.element[0], + unselecting: selectee.element, + options: options + }], options.unselecting); + } + } + } + }); + + return false; + }, + _mouseStop: function(e) { + var self = this; + + this.dragged = false; + + var options = this.options; + + $('.ui-unselecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-unselecting'); + selectee.unselecting = false; + selectee.startselected = false; + self.element.triggerHandler("selectableunselected", [e, { + selectable: self.element[0], + unselected: selectee.element, + options: options + }], options.unselected); + }); + $('.ui-selecting', this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + self.element.triggerHandler("selectableselected", [e, { + selectable: self.element[0], + selected: selectee.element, + options: options + }], options.selected); + }); + this.element.triggerHandler("selectablestop", [e, { + selectable: self.element[0], + options: this.options + }], this.options.stop); + + this.helper.remove(); + + return false; + } +})); + +$.extend($.ui.selectable, { + defaults: { + distance: 1, + delay: 0, + cancel: ":input", + appendTo: 'body', + autoRefresh: true, + filter: '*', + tolerance: 'touch' + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.slider.js hunk ./static/js/jquery/ui/ui.slider.js 1 +/* + * jQuery UI Slider @VERSION + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Slider + * + * Depends: + * ui.core.js + */ +(function($) { + +$.fn.unwrap = $.fn.unwrap || function(expr) { + return this.each(function(){ + $(this).parents(expr).eq(0).after(this).remove(); + }); +}; + +$.widget("ui.slider", { + plugins: {}, + ui: function(e) { + return { + options: this.options, + handle: this.currentHandle, + value: this.options.axis != "both" || !this.options.axis ? Math.round(this.value(null,this.options.axis == "vertical" ? "y" : "x")) : { + x: Math.round(this.value(null,"x")), + y: Math.round(this.value(null,"y")) + }, + range: this._getRange() + }; + }, + _propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.ui()]); + this.element.triggerHandler(n == "slide" ? n : "slide"+n, [e, this.ui()], this.options[n]); + }, + destroy: function() { + + this.element + .removeClass("ui-slider ui-slider-disabled") + .removeData("slider") + .unbind(".slider"); + + if(this.handle && this.handle.length) { + this.handle + .unwrap("a"); + this.handle.each(function() { + $(this).data("mouse")._mouseDestroy(); + }); + } + + this.generated && this.generated.remove(); + + }, + _setData: function(key, value) { + $.widget.prototype._setData.apply(this, arguments); + if (/min|max|steps/.test(key)) { + this._initBoundaries(); + } + + if(key == "range") { + value ? this.handle.length == 2 && this._createRange() : this._removeRange(); + } + + }, + + _init: function() { + + var self = this; + this.element.addClass("ui-slider"); + this._initBoundaries(); + + // Initialize mouse and key events for interaction + this.handle = $(this.options.handle, this.element); + if (!this.handle.length) { + self.handle = self.generated = $(self.options.handles || [0]).map(function() { + var handle = $("
").addClass("ui-slider-handle").appendTo(self.element); + if (this.id) + handle.attr("id", this.id); + return handle[0]; + }); + } + + + var handleclass = function(el) { + this.element = $(el); + this.element.data("mouse", this); + this.options = self.options; + + this.element.bind("mousedown", function() { + if(self.currentHandle) this.blur(self.currentHandle); + self._focus(this, true); + }); + + this._mouseInit(); + }; + + $.extend(handleclass.prototype, $.ui.mouse, { + _mouseStart: function(e) { return self._start.call(self, e, this.element[0]); }, + _mouseStop: function(e) { return self._stop.call(self, e, this.element[0]); }, + _mouseDrag: function(e) { return self._drag.call(self, e, this.element[0]); }, + _mouseCapture: function() { return true; }, + trigger: function(e) { this._mouseDown(e); } + }); + + + $(this.handle) + .each(function() { + new handleclass(this); + }) + .wrap('') + .parent() + .bind('click', function() { return false; }) + .bind('focus', function(e) { self._focus(this.firstChild); }) + .bind('blur', function(e) { self._blur(this.firstChild); }) + .bind('keydown', function(e) { if(!self.options.noKeyboard) return self._keydown(e.keyCode, this.firstChild); }) + ; + + // Bind the click to the slider itself + this.element.bind('mousedown.slider', function(e) { + self._click.apply(self, [e]); + self.currentHandle.data("mouse").trigger(e); + self.firstValue = self.firstValue + 1; //This is for always triggering the change event + }); + + // Move the first handle to the startValue + $.each(this.options.handles || [], function(index, handle) { + self.moveTo(handle.start, index, true); + }); + if (!isNaN(this.options.startValue)) + this.moveTo(this.options.startValue, 0, true); + + this.previousHandle = $(this.handle[0]); //set the previous handle to the first to allow clicking before selecting the handle + if(this.handle.length == 2 && this.options.range) this._createRange(); + }, + _initBoundaries: function() { + + var element = this.element[0], o = this.options; + this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() }; + + $.extend(o, { + axis: o.axis || (element.offsetWidth < element.offsetHeight ? 'vertical' : 'horizontal'), + max: !isNaN(parseInt(o.max,10)) ? { x: parseInt(o.max, 10), y: parseInt(o.max, 10) } : ({ x: o.max && o.max.x || 100, y: o.max && o.max.y || 100 }), + min: !isNaN(parseInt(o.min,10)) ? { x: parseInt(o.min, 10), y: parseInt(o.min, 10) } : ({ x: o.min && o.min.x || 0, y: o.min && o.min.y || 0 }) + }); + //Prepare the real maxValue + o.realMax = { + x: o.max.x - o.min.x, + y: o.max.y - o.min.y + }; + //Calculate stepping based on steps + o.stepping = { + x: o.stepping && o.stepping.x || parseInt(o.stepping, 10) || (o.steps ? o.realMax.x/(o.steps.x || parseInt(o.steps, 10) || o.realMax.x) : 0), + y: o.stepping && o.stepping.y || parseInt(o.stepping, 10) || (o.steps ? o.realMax.y/(o.steps.y || parseInt(o.steps, 10) || o.realMax.y) : 0) + }; + }, + + + _keydown: function(keyCode, handle) { + var k = keyCode; + if(/(33|34|35|36|37|38|39|40)/.test(k)) { + var o = this.options, xpos, ypos; + if (/(35|36)/.test(k)) { + xpos = (k == 35) ? o.max.x : o.min.x; + ypos = (k == 35) ? o.max.y : o.min.y; + } else { + var oper = /(34|37|40)/.test(k) ? "-=" : "+="; + var step = /(37|38|39|40)/.test(k) ? "_oneStep" : "_pageStep"; + xpos = oper + this[step]("x"); + ypos = oper + this[step]("y"); + } + this.moveTo({ + x: xpos, + y: ypos + }, handle); + return false; + } + return true; + }, + _focus: function(handle,hard) { + this.currentHandle = $(handle).addClass('ui-slider-handle-active'); + if (hard) + this.currentHandle.parent()[0].focus(); + }, + _blur: function(handle) { + $(handle).removeClass('ui-slider-handle-active'); + if(this.currentHandle && this.currentHandle[0] == handle) { this.previousHandle = this.currentHandle; this.currentHandle = null; }; + }, + _click: function(e) { + // This method is only used if: + // - The user didn't click a handle + // - The Slider is not disabled + // - There is a current, or previous selected handle (otherwise we wouldn't know which one to move) + + var pointer = [e.pageX,e.pageY]; + + var clickedHandle = false; + this.handle.each(function() { + if(this == e.target) + clickedHandle = true; + }); + if (clickedHandle || this.options.disabled || !(this.currentHandle || this.previousHandle)) + return; + + // If a previous handle was focussed, focus it again + if (!this.currentHandle && this.previousHandle) + this._focus(this.previousHandle, true); + + // propagate only for distance > 0, otherwise propagation is done my drag + this.offset = this.element.offset(); + + this.moveTo({ + y: this._convertValue(e.pageY - this.offset.top - this.currentHandle[0].offsetHeight/2, "y"), + x: this._convertValue(e.pageX - this.offset.left - this.currentHandle[0].offsetWidth/2, "x") + }, null, !this.options.distance); + }, + + + + _createRange: function() { + if(this.rangeElement) return; + this.rangeElement = $('
') + .addClass('ui-slider-range') + .css({ position: 'absolute' }) + .appendTo(this.element); + this._updateRange(); + }, + _removeRange: function() { + this.rangeElement.remove(); + this.rangeElement = null; + }, + _updateRange: function() { + var prop = this.options.axis == "vertical" ? "top" : "left"; + var size = this.options.axis == "vertical" ? "height" : "width"; + this.rangeElement.css(prop, (parseInt($(this.handle[0]).css(prop),10) || 0) + this._handleSize(0, this.options.axis == "vertical" ? "y" : "x")/2); + this.rangeElement.css(size, (parseInt($(this.handle[1]).css(prop),10) || 0) - (parseInt($(this.handle[0]).css(prop),10) || 0)); + }, + _getRange: function() { + return this.rangeElement ? this._convertValue(parseInt(this.rangeElement.css(this.options.axis == "vertical" ? "height" : "width"),10), this.options.axis == "vertical" ? "y" : "x") : null; + }, + + _handleIndex: function() { + return this.handle.index(this.currentHandle[0]); + }, + value: function(handle, axis) { + if(this.handle.length == 1) this.currentHandle = this.handle; + if(!axis) axis = this.options.axis == "vertical" ? "y" : "x"; + + var curHandle = $(handle != undefined && handle !== null ? this.handle[handle] || handle : this.currentHandle); + + if(curHandle.data("mouse").sliderValue) { + return parseInt(curHandle.data("mouse").sliderValue[axis],10); + } else { + return parseInt(((parseInt(curHandle.css(axis == "x" ? "left" : "top"),10) / (this.actualSize[axis == "x" ? "width" : "height"] - this._handleSize(handle,axis))) * this.options.realMax[axis]) + this.options.min[axis],10); + } + + }, + _convertValue: function(value,axis) { + return this.options.min[axis] + (value / (this.actualSize[axis == "x" ? "width" : "height"] - this._handleSize(null,axis))) * this.options.realMax[axis]; + }, + + _translateValue: function(value,axis) { + return ((value - this.options.min[axis]) / this.options.realMax[axis]) * (this.actualSize[axis == "x" ? "width" : "height"] - this._handleSize(null,axis)); + }, + _translateRange: function(value,axis) { + if (this.rangeElement) { + if (this.currentHandle[0] == this.handle[0] && value >= this._translateValue(this.value(1),axis)) + value = this._translateValue(this.value(1,axis) - this._oneStep(axis), axis); + if (this.currentHandle[0] == this.handle[1] && value <= this._translateValue(this.value(0),axis)) + value = this._translateValue(this.value(0,axis) + this._oneStep(axis), axis); + } + if (this.options.handles) { + var handle = this.options.handles[this._handleIndex()]; + if (value < this._translateValue(handle.min,axis)) { + value = this._translateValue(handle.min,axis); + } else if (value > this._translateValue(handle.max,axis)) { + value = this._translateValue(handle.max,axis); + } + } + return value; + }, + _translateLimits: function(value,axis) { + if (value >= this.actualSize[axis == "x" ? "width" : "height"] - this._handleSize(null,axis)) + value = this.actualSize[axis == "x" ? "width" : "height"] - this._handleSize(null,axis); + if (value <= 0) + value = 0; + return value; + }, + _handleSize: function(handle,axis) { + return $(handle != undefined && handle !== null ? this.handle[handle] : this.currentHandle)[0]["offset"+(axis == "x" ? "Width" : "Height")]; + }, + _oneStep: function(axis) { + return this.options.stepping[axis] || 1; + }, + _pageStep: function(axis) { + return /* this.options.paging[axis] ||*/ 10; + }, + + + _start: function(e, handle) { + + var o = this.options; + if(o.disabled) return false; + + // Prepare the outer size + this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() }; + + // This is a especially ugly fix for strange blur events happening on mousemove events + if (!this.currentHandle) + this._focus(this.previousHandle, true); + + this.offset = this.element.offset(); + + this.handleOffset = this.currentHandle.offset(); + this.clickOffset = { top: e.pageY - this.handleOffset.top, left: e.pageX - this.handleOffset.left }; + + this.firstValue = this.value(); + + this._propagate('start', e); + this._drag(e, handle); + return true; + + }, + _stop: function(e) { + this._propagate('stop', e); + if (this.firstValue != this.value()) + this._propagate('change', e); + // This is a especially ugly fix for strange blur events happening on mousemove events + this._focus(this.currentHandle, true); + return false; + }, + _drag: function(e, handle) { + + var o = this.options; + var position = { top: e.pageY - this.offset.top - this.clickOffset.top, left: e.pageX - this.offset.left - this.clickOffset.left}; + if(!this.currentHandle) this._focus(this.previousHandle, true); //This is a especially ugly fix for strange blur events happening on mousemove events + + position.left = this._translateLimits(position.left, "x"); + position.top = this._translateLimits(position.top, "y"); + + if (o.stepping.x) { + var value = this._convertValue(position.left, "x"); + value = Math.round(value / o.stepping.x) * o.stepping.x; + position.left = this._translateValue(value, "x"); + } + if (o.stepping.y) { + var value = this._convertValue(position.top, "y"); + value = Math.round(value / o.stepping.y) * o.stepping.y; + position.top = this._translateValue(value, "y"); + } + + position.left = this._translateRange(position.left, "x"); + position.top = this._translateRange(position.top, "y"); + + if(o.axis != "vertical") this.currentHandle.css({ left: position.left }); + if(o.axis != "horizontal") this.currentHandle.css({ top: position.top }); + + //Store the slider's value + this.currentHandle.data("mouse").sliderValue = { + x: Math.round(this._convertValue(position.left, "x")) || 0, + y: Math.round(this._convertValue(position.top, "y")) || 0 + }; + + if (this.rangeElement) + this._updateRange(); + this._propagate('slide', e); + return false; + }, + + moveTo: function(value, handle, noPropagation) { + + var o = this.options; + + // Prepare the outer size + this.actualSize = { width: this.element.outerWidth() , height: this.element.outerHeight() }; + + //If no handle has been passed, no current handle is available and we have multiple handles, return false + if (handle == undefined && !this.currentHandle && this.handle.length != 1) + return false; + + //If only one handle is available, use it + if (handle == undefined && !this.currentHandle) + handle = 0; + + if (handle != undefined) + this.currentHandle = this.previousHandle = $(this.handle[handle] || handle); + + + if(value.x !== undefined && value.y !== undefined) { + var x = value.x, y = value.y; + } else { + var x = value, y = value; + } + + if(x !== undefined && x.constructor != Number) { + var me = /^\-\=/.test(x), pe = /^\+\=/.test(x); + if(me || pe) { + x = this.value(null, "x") + parseInt(x.replace(me ? '=' : '+=', ''), 10); + } else { + x = isNaN(parseInt(x, 10)) ? undefined : parseInt(x, 10); + } + } + + if(y !== undefined && y.constructor != Number) { + var me = /^\-\=/.test(y), pe = /^\+\=/.test(y); + if(me || pe) { + y = this.value(null, "y") + parseInt(y.replace(me ? '=' : '+=', ''), 10); + } else { + y = isNaN(parseInt(y, 10)) ? undefined : parseInt(y, 10); + } + } + + if(o.axis != "vertical" && x !== undefined) { + if(o.stepping.x) x = Math.round(x / o.stepping.x) * o.stepping.x; + x = this._translateValue(x, "x"); + x = this._translateLimits(x, "x"); + x = this._translateRange(x, "x"); + + o.animate ? this.currentHandle.stop().animate({ left: x }, (Math.abs(parseInt(this.currentHandle.css("left")) - x)) * (!isNaN(parseInt(o.animate)) ? o.animate : 5)) : this.currentHandle.css({ left: x }); + } + + if(o.axis != "horizontal" && y !== undefined) { + if(o.stepping.y) y = Math.round(y / o.stepping.y) * o.stepping.y; + y = this._translateValue(y, "y"); + y = this._translateLimits(y, "y"); + y = this._translateRange(y, "y"); + o.animate ? this.currentHandle.stop().animate({ top: y }, (Math.abs(parseInt(this.currentHandle.css("top")) - y)) * (!isNaN(parseInt(o.animate)) ? o.animate : 5)) : this.currentHandle.css({ top: y }); + } + + if (this.rangeElement) + this._updateRange(); + + //Store the slider's value + this.currentHandle.data("mouse").sliderValue = { + x: Math.round(this._convertValue(x, "x")) || 0, + y: Math.round(this._convertValue(y, "y")) || 0 + }; + + if (!noPropagation) { + this._propagate('start', null); + this._propagate('stop', null); + this._propagate('change', null); + this._propagate("slide", null); + } + } +}); + +$.ui.slider.getter = "value"; + +$.ui.slider.defaults = { + handle: ".ui-slider-handle", + distance: 1, + animate: false +}; + +})(jQuery); addfile ./static/js/jquery/ui/ui.sortable.js hunk ./static/js/jquery/ui/ui.sortable.js 1 +/* + * jQuery UI Sortable @VERSION + * + * Copyright (c) 2008 Paul Bakaus + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Sortables + * + * Depends: + * ui.core.js + */ +(function($) { + +function contains(a, b) { + var safari2 = $.browser.safari && $.browser.version < 522; + if (a.contains && !safari2) { + return a.contains(b); + } + if (a.compareDocumentPosition) + return !!(a.compareDocumentPosition(b) & 16); + while (b = b.parentNode) + if (b == a) return true; + return false; +}; + +$.widget("ui.sortable", $.extend({}, $.ui.mouse, { + _init: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are floating + this.floating = this.items.length ? (/left|right/).test(this.items[0].item.css('float')) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + }, + plugins: {}, + ui: function(inst) { + return { + helper: (inst || this)["helper"], + placeholder: (inst || this)["placeholder"] || $([]), + position: (inst || this)["position"], + absolutePosition: (inst || this)["positionAbs"], + options: this.options, + element: this.element, + item: (inst || this)["currentItem"], + sender: inst ? inst.element : null + }; + }, + + _propagate: function(n,e,inst, noPropagation) { + $.ui.plugin.call(this, n, [e, this.ui(inst)]); + if(!noPropagation) this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]); + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var str = []; o = o || {}; + + $(items).each(function() { + var res = ($(this.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); + if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); + }); + + return str.join('&'); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected); + var ret = []; + + items.each(function() { ret.push($(this).attr(o.attr || 'id')); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height; + var l = item.left, r = l + item.width, + t = item.top, b = t + item.height; + + var dyClick = this.offset.click.top, dxClick = this.offset.click.left; + var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if(this.options.tolerance == "pointer" || this.options.forcePointerForContainers || (this.options.tolerance == "guess" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithEdge: function(item) { + var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height; + + var l = item.left, r = l + item.width, + t = item.top, b = t + item.height; + + var dyClick = this.offset.click.top, dxClick = this.offset.click.left; + var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if(this.options.tolerance == "pointer" || (this.options.tolerance == "guess" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])) { + if(!isOverElement) return false; + + if(this.floating) { + if ((x1 + dxClick) > l && (x1 + dxClick) < l + item.width/2) return 2; + if ((x1 + dxClick) > l + item.width/2 && (x1 + dxClick) < r) return 1; + } else { + var height = item.height; + var direction = y1 - this.updateOriginalPosition.top < 0 ? 2 : 1; // 2 = up + + if (direction == 1 && (y1 + dyClick) < t + height/2) { return 2; } // up + else if (direction == 2 && (y1 + dyClick) > t + height/2) { return 1; } // down + } + + } else { + if (!(l < x1 + (this.helperProportions.width / 2) // Right Half + && x2 - (this.helperProportions.width / 2) < r // Left Half + && t < y1 + (this.helperProportions.height / 2) // Bottom Half + && y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half + + if(this.floating) { + if(x2 > l && x1 < l) return 2; //Crosses left edge + if(x1 < r && x2 > r) return 1; //Crosses right edge + } else { + if(y2 > t && y1 < t) return 1; //Crosses top edge + if(y1 < b && y2 > b) return 2; //Crosses bottom edge + } + } + + return false; + + }, + + refresh: function() { + this._refreshItems(); + this.refreshPositions(); + }, + + _getItemsAsjQuery: function(connected) { + + var self = this; + var items = []; + var queries = []; + + if(this.options.connectWith && connected) { + for (var i = this.options.connectWith.length - 1; i >= 0; i--){ + var cur = $(this.options.connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper"), inst]); + } + }; + }; + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper"), this]); + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + }; + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(sortable-item)"); + + for (var i=0; i < this.items.length; i++) { + + for (var j=0; j < list.length; j++) { + if(list[j] == this.items[i].item[0]) + this.items.splice(i,1); + }; + + }; + + }, + + _refreshItems: function() { + + this.items = []; + this.containers = [this]; + var items = this.items; + var self = this; + var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element), this]]; + + if(this.options.connectWith) { + for (var i = this.options.connectWith.length - 1; i >= 0; i--){ + var cur = $(this.options.connectWith[i]); + for (var j = cur.length - 1; j >= 0; j--){ + var inst = $.data(cur[j], 'sortable'); + if(inst && inst != this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + }; + }; + } + + for (var i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + $.data(this, 'sortable-item', queries[i][1]); // Data for target checking (mouse manager) + items.push({ + item: $(this), + instance: queries[i][1], + width: 0, height: 0, + left: 0, top: 0 + }); + }); + }; + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent) { + var po = this.offsetParent.offset(); + this.offset.parent = { top: po.top + this.offsetParentBorders.top, left: po.left + this.offsetParentBorders.left }; + } + + for (var i = this.items.length - 1; i >= 0; i--){ + + //We ignore calculating positions of all connected containers when we're not over them + if(this.items[i].instance != this.currentContainer && this.currentContainer && this.items[i].item[0] != this.currentItem[0]) + continue; + + var t = this.options.toleranceElement ? $(this.options.toleranceElement, this.items[i].item) : this.items[i].item; + + if(!fast) { + this.items[i].width = t[0].offsetWidth; + this.items[i].height = t[0].offsetHeight; + } + + var p = t.offset(); + this.items[i].left = p.left; + this.items[i].top = p.top; + + }; + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (var i = this.containers.length - 1; i >= 0; i--){ + var p =this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + }; + } + + }, + + destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled") + .removeData("sortable") + .unbind(".sortable"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) + this.items[i].item.removeData("sortable-item"); + }, + + _createPlaceholder: function(that) { + + var self = that || this, o = self.options; + + if(!o.placeholder || o.placeholder.constructor == String) { + var className = o.placeholder; + o.placeholder = { + element: function() { + var el = $(document.createElement(self.currentItem[0].nodeName)).addClass(className || "ui-sortable-placeholder")[0]; + + if(!className) { + el.style.visibility = "hidden"; + document.body.appendChild(el); + el.innerHTML = self.currentItem[0].innerHTML; + document.body.removeChild(el); + }; + + return el; + }, + update: function(container, p) { + if(className && !o.forcePlaceholderSize) return; + if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; + if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; + } + }; + } + + self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)) + self.currentItem.parent()[0].appendChild(self.placeholder[0]); + self.placeholder[0].parentNode.insertBefore(self.placeholder[0], self.currentItem[0]); + o.placeholder.update(self, self.placeholder); + }, + + _contactContainers: function(e) { + for (var i = this.containers.length - 1; i >= 0; i--){ + + if(this._intersectsWith(this.containers[i].containerCache)) { + if(!this.containers[i].containerCache.over) { + + + if(this.currentContainer != this.containers[i]) { + + //When entering a new container, we will find the item with the least distance and append our item near it + var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[i].floating ? 'left' : 'top']; + for (var j = this.items.length - 1; j >= 0; j--) { + if(!contains(this.containers[i].element[0], this.items[j].item[0])) continue; + var cur = this.items[j][this.containers[i].floating ? 'left' : 'top']; + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + } + } + + if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled + continue; + + this.currentContainer = this.containers[i]; + itemWithLeastDistance ? this.options.sortIndicator.call(this, e, itemWithLeastDistance, null, true) : this.options.sortIndicator.call(this, e, null, this.containers[i].element, true); + this._propagate("change", e); //Call plugins and callbacks + this.containers[i]._propagate("change", e, this); //Call plugins and callbacks + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + } + + this.containers[i]._propagate("over", e, this); + this.containers[i].containerCache.over = 1; + } + } else { + if(this.containers[i].containerCache.over) { + this.containers[i]._propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + }; + }, + + _mouseCapture: function(e, overrideHandle) { + + if(this.options.disabled || this.options.type == 'static') return false; + + //We have to refresh the items data once first + this._refreshItems(); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + var currentItem = null, self = this, nodes = $(e.target).parents().each(function() { + if($.data(this, 'sortable-item') == self) { + currentItem = $(this); + return false; + } + }); + if($.data(e.target, 'sortable-item') == self) currentItem = $(e.target); + + if(!currentItem) return false; + if(this.options.handle && !overrideHandle) { + var validHandle = false; + + $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == e.target) validHandle = true; }); + if(!validHandle) return false; + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + createHelper: function(e) { + + var o = this.options; + var helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : (o.helper == "original" ? this.currentItem : this.currentItem.clone()); + + if (!helper.parents('body').length) + $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); //Add the helper to the DOM if that didn't happen already + + return helper; + + }, + + _mouseStart: function(e, overrideHandle, noActivation) { + + var o = this.options; + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this.createHelper(e); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + this.margins = { //Cache the margins + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + + this.offset = this.currentItem.offset(); //The element's absolute position on the page + this.offset = { //Substract the margins from the element's absolute offset + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + this.offset.click = { //Where the click happened, relative to the element + left: e.pageX - this.offset.left, + top: e.pageY - this.offset.top + }; + + this.offsetParent = this.helper.offsetParent(); //Get the offsetParent and cache its position + var po = this.offsetParent.offset(); + + this.offsetParentBorders = { + top: (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + this.offset.parent = { //Store its position plus border + top: po.top + this.offsetParentBorders.top, + left: po.left + this.offsetParentBorders.left + }; + + this.updateOriginalPosition = this.originalPosition = this._generatePosition(e); //Generate the original position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; //Cache the former DOM position + + //If o.placeholder is used, create a new element at the given position with the class + this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() };//Cache the helper size + + + if(o.helper == "original") { + this._storedCSS = { position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left"), clear: this.currentItem.css("clear") }; + } else { + this.currentItem.hide(); //Hide the original, won't cause anything bad this way + } + + //Position it absolutely and add a helper class + this.helper + .css({ position: 'absolute', clear: 'both' }) + .addClass('ui-sortable-helper'); + + //Create the placeholder + this._createPlaceholder(); + + //Call plugins and callbacks + this._propagate("start", e); + + //Recache the helper size + if(!this._preserveHelperProportions) + this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; + + if(o.cursorAt) { + if(o.cursorAt.left != undefined) this.offset.click.left = o.cursorAt.left; + if(o.cursorAt.right != undefined) this.offset.click.left = this.helperProportions.width - o.cursorAt.right; + if(o.cursorAt.top != undefined) this.offset.click.top = o.cursorAt.top; + if(o.cursorAt.bottom != undefined) this.offset.click.top = this.helperProportions.height - o.cursorAt.bottom; + } + + /* + * - Position constraining - + * Here we prepare position constraining like grid and containment. + */ + + if(o.containment) { + if(o.containment == 'parent') o.containment = this.helper[0].parentNode; + if(o.containment == 'document' || o.containment == 'window') this.containment = [ + 0 - this.offset.parent.left, + 0 - this.offset.parent.top, + $(o.containment == 'document' ? document : window).width() - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.element.css("marginRight"),10) || 0), + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.element.css("marginBottom"),10) || 0) + ]; + + if(!(/^(document|window|parent)$/).test(o.containment)) { + var ce = $(o.containment)[0]; + var co = $(o.containment).offset(); + var over = ($(ce).css("overflow") != 'hidden'); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.parent.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.parent.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - this.offset.parent.left - this.helperProportions.width - this.margins.left - (parseInt(this.currentItem.css("marginRight"),10) || 0), + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - this.offset.parent.top - this.helperProportions.height - this.margins.top - (parseInt(this.currentItem.css("marginBottom"),10) || 0) + ]; + } + } + + //Post 'activate' events to possible containers + if(!noActivation) { + for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._propagate("activate", e, this); } + } + + //Prepare possible droppables + if($.ui.ddmanager) + $.ui.ddmanager.current = this; + + if ($.ui.ddmanager && !o.dropBehaviour) + $.ui.ddmanager.prepareOffsets(this, e); + + this.dragging = true; + + this._mouseDrag(e); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + + }, + + _convertPositionTo: function(d, pos) { + if(!pos) pos = this.position; + var mod = d == "absolute" ? 1 : -1; + return { + top: ( + pos.top // the calculated relative position + + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) + - (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) * mod // The offsetParent's scroll position + + this.margins.top * mod //Add the margin (you don't want the margin counting in intersection methods) + ), + left: ( + pos.left // the calculated relative position + + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) + - (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft) * mod // The offsetParent's scroll position + + this.margins.left * mod //Add the margin (you don't want the margin counting in intersection methods) + ) + }; + }, + + _generatePosition: function(e) { + + var o = this.options; + var position = { + top: ( + e.pageY // The absolute mouse position + - this.offset.click.top // Click offset (relative to the element) + - this.offset.parent.top // The offsetParent's offset without borders (offset + border) + + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) // The offsetParent's scroll position, not if the element is fixed + ), + left: ( + e.pageX // The absolute mouse position + - this.offset.click.left // Click offset (relative to the element) + - this.offset.parent.left // The offsetParent's offset without borders (offset + border) + + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft) // The offsetParent's scroll position, not if the element is fixed + ) + }; + + if(!this.originalPosition) return position; //If we are not dragging yet, we won't check for options + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + if(this.containment) { + if(position.left < this.containment[0]) position.left = this.containment[0]; + if(position.top < this.containment[1]) position.top = this.containment[1]; + if(position.left > this.containment[2]) position.left = this.containment[2]; + if(position.top > this.containment[3]) position.top = this.containment[3]; + } + + if(o.grid) { + var top = this.originalPosition.top + Math.round((position.top - this.originalPosition.top) / o.grid[1]) * o.grid[1]; + position.top = this.containment ? (!(top < this.containment[1] || top > this.containment[3]) ? top : (!(top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + var left = this.originalPosition.left + Math.round((position.left - this.originalPosition.left) / o.grid[0]) * o.grid[0]; + position.left = this.containment ? (!(left < this.containment[0] || left > this.containment[2]) ? left : (!(left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + return position; + }, + + _mouseDrag: function(e) { + + //Compute the helpers position + this.position = this._generatePosition(e); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call the internal plugins + $.ui.plugin.call(this, "sort", [e, this.ui()]); + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper's position + this.helper[0].style.left = this.position.left+'px'; + this.helper[0].style.top = this.position.top+'px'; + + //Rearrange + for (var i = this.items.length - 1; i >= 0; i--) { + var intersection = this._intersectsWithEdge(this.items[i]); + if(!intersection) continue; + + if(this.items[i].item[0] != this.currentItem[0] //cannot intersect with itself + && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != this.items[i].item[0] //no useless actions that have been done before + && !contains(this.placeholder[0], this.items[i].item[0]) //no action if the item moved is the parent of the item checked + && (this.options.type == 'semi-dynamic' ? !contains(this.element[0], this.items[i].item[0]) : true) + ) { + + this.updateOriginalPosition = this._generatePosition(e); + + this.direction = intersection == 1 ? "down" : "up"; + this.options.sortIndicator.call(this, e, this.items[i]); + this._propagate("change", e); //Call plugins and callbacks + break; + } + } + + //Post events to containers + this._contactContainers(e); + + //Interconnect with droppables + if($.ui.ddmanager) $.ui.ddmanager.drag(this, e); + + //Call callbacks + this.element.triggerHandler("sort", [e, this.ui()], this.options["sort"]); + + return false; + + }, + + _rearrange: function(e, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var self = this, counter = this.counter; + + window.setTimeout(function() { + if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + },0); + + }, + + _mouseStop: function(e, noPropagation) { + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) + $.ui.ddmanager.drop(this, e); + + if(this.options.revert) { + var self = this; + var cur = self.placeholder.offset(); + + $(this.helper).animate({ + left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), + top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) + }, parseInt(this.options.revert, 10) || 500, function() { + self._clear(e); + }); + } else { + this._clear(e, noPropagation); + } + + return false; + + }, + + _clear: function(e, noPropagation) { + + //We first have to update the dom position of the actual currentItem + if(!this._noFinalSort) this.placeholder.before(this.currentItem); + this._noFinalSort = null; + + if(this.options.helper == "original") + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + else + this.currentItem.show(); + + if(this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) this._propagate("update", e, null, noPropagation); //Trigger update callback if the DOM position has changed + if(!contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element + this._propagate("remove", e, null, noPropagation); + for (var i = this.containers.length - 1; i >= 0; i--){ + if(contains(this.containers[i].element[0], this.currentItem[0])) { + this.containers[i]._propagate("update", e, this, noPropagation); + this.containers[i]._propagate("receive", e, this, noPropagation); + } + }; + }; + + //Post events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._propagate("deactivate", e, this, noPropagation); + if(this.containers[i].containerCache.over) { + this.containers[i]._propagate("out", e, this); + this.containers[i].containerCache.over = 0; + } + } + + this.dragging = false; + if(this.cancelHelperRemoval) { + this._propagate("beforeStop", e, null, noPropagation); + this._propagate("stop", e, null, noPropagation); + return false; + } + + this._propagate("beforeStop", e, null, noPropagation); + + this.placeholder.remove(); + if(this.options.helper != "original") this.helper.remove(); this.helper = null; + this._propagate("stop", e, null, noPropagation); + + return true; + + } +})); + +$.extend($.ui.sortable, { + getter: "serialize toArray", + defaults: { + helper: "original", + tolerance: "guess", + distance: 1, + delay: 0, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + cancel: ":input", + items: '> *', + zIndex: 1000, + dropOnEmpty: true, + appendTo: "parent", + sortIndicator: $.ui.sortable.prototype._rearrange, + scope: "default", + forcePlaceholderSize: false + } +}); + +/* + * Sortable Extensions + */ + +$.ui.plugin.add("sortable", "cursor", { + start: function(e, ui) { + var t = $('body'); + if (t.css("cursor")) ui.options._cursor = t.css("cursor"); + t.css("cursor", ui.options.cursor); + }, + beforeStop: function(e, ui) { + if (ui.options._cursor) $('body').css("cursor", ui.options._cursor); + } +}); + +$.ui.plugin.add("sortable", "zIndex", { + start: function(e, ui) { + var t = ui.helper; + if(t.css("zIndex")) ui.options._zIndex = t.css("zIndex"); + t.css('zIndex', ui.options.zIndex); + }, + beforeStop: function(e, ui) { + if(ui.options._zIndex) $(ui.helper).css('zIndex', ui.options._zIndex); + } +}); + +$.ui.plugin.add("sortable", "opacity", { + start: function(e, ui) { + var t = ui.helper; + if(t.css("opacity")) ui.options._opacity = t.css("opacity"); + t.css('opacity', ui.options.opacity); + }, + beforeStop: function(e, ui) { + if(ui.options._opacity) $(ui.helper).css('opacity', ui.options._opacity); + } +}); + +$.ui.plugin.add("sortable", "scroll", { + start: function(e, ui) { + var o = ui.options; + var i = $(this).data("sortable"); + + i.overflowY = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-y'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(i.currentItem); + i.overflowX = function(el) { + do { if(/auto|scroll/.test(el.css('overflow')) || (/auto|scroll/).test(el.css('overflow-x'))) return el; el = el.parent(); } while (el[0].parentNode); + return $(document); + }(i.currentItem); + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') i.overflowYOffset = i.overflowY.offset(); + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') i.overflowXOffset = i.overflowX.offset(); + + }, + sort: function(e, ui) { + + var o = ui.options; + var i = $(this).data("sortable"); + + if(i.overflowY[0] != document && i.overflowY[0].tagName != 'HTML') { + if((i.overflowYOffset.top + i.overflowY[0].offsetHeight) - e.pageY < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop + o.scrollSpeed; + if(e.pageY - i.overflowYOffset.top < o.scrollSensitivity) + i.overflowY[0].scrollTop = i.overflowY[0].scrollTop - o.scrollSpeed; + } else { + if(e.pageY - $(document).scrollTop() < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + if($(window).height() - (e.pageY - $(document).scrollTop()) < o.scrollSensitivity) + $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(i.overflowX[0] != document && i.overflowX[0].tagName != 'HTML') { + if((i.overflowXOffset.left + i.overflowX[0].offsetWidth) - e.pageX < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft + o.scrollSpeed; + if(e.pageX - i.overflowXOffset.left < o.scrollSensitivity) + i.overflowX[0].scrollLeft = i.overflowX[0].scrollLeft - o.scrollSpeed; + } else { + if(e.pageX - $(document).scrollLeft() < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + if($(window).width() - (e.pageX - $(document).scrollLeft()) < o.scrollSensitivity) + $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } +}); + +$.ui.plugin.add("sortable", "axis", { + sort: function(e, ui) { + + var i = $(this).data("sortable"); + + if(ui.options.axis == "y") i.position.left = i.originalPosition.left; + if(ui.options.axis == "x") i.position.top = i.originalPosition.top; + + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.spinner.js hunk ./static/js/jquery/ui/ui.spinner.js 1 +/* + * jQuery UI Spinner @VERSION + * + * Copyright (c) 2008 jQuery + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Spinner + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget('ui.spinner', { + _init: function() { + // terminate initialization if spinner already applied to current element + if($.data(this.element[0], 'spinner')) return; + + // check for onInit callback + if (this.options.init) { + this.options.init(this.ui(null)); + } + + // check for decimals in steppinng and set _decimals as internal (needs cleaning up) + this._decimals = 0; + if (this.options.stepping.toString().indexOf('.') != -1) { + var s = this.options.stepping.toString(); + this._decimals = s.slice(s.indexOf('.')+1, s.length).length; + } + + //Initialize needed constants + var self = this; + this.element + .addClass('ui-spinner-box') + .attr('autocomplete', 'off'); // switch off autocomplete in opera + + this._setValue( isNaN(this._getValue()) ? this.options.start : this._getValue() ); + + this.element + .wrap('
') + .parent() + .addClass('ui-spinner') + .append('') + .find('.ui-spinner-up') + .bind('mousedown', function(e) { + $(this).addClass('ui-spinner-pressed'); + if(!self.counter) self.counter = 1; + self._mousedown(100, '_up', e); + }) + .bind('mouseup', function(e) { + $(this).removeClass('ui-spinner-pressed'); + if(self.counter == 1) self._up(e); + self._mouseup(e); + }) + .bind('mouseout', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self._mouseup(e); + }) + // mousedown/mouseup capture first click, now handle second click + .bind('dblclick', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self._up(e); + }) + .bind('keydown.spinner', function(e) { + var KEYS = $.keyCode; + if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) { + $(this).addClass('ui-spinner-pressed'); + if(!self.counter) self.counter = 1; + self._up.call(self, e); + } else if (e.keyCode == KEYS.DOWN || e.keyCode == KEYS.RIGHT) { + self.element.siblings('.ui-spinner-down').focus(); + } else if (e.keyCode == KEYS.LEFT) { + self.element.focus(); + } + }) + .bind('keyup.spinner', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self.counter = 0; + self._propagate('change', e); + }) + .end() + .append('') + .find('.ui-spinner-down') + .bind('mousedown', function(e) { + $(this).addClass('ui-spinner-pressed'); + if(!self.counter) self.counter = 1; + self._mousedown(100, '_down', e); + }) + .bind('mouseup', function(e) { + $(this).removeClass('ui-spinner-pressed'); + if(self.counter == 1) self._down(); + self._mouseup(e); + }) + .bind('mouseout', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self._mouseup(e); + }) + // mousedown/mouseup capture first click, now handle second click + .bind('dblclick', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self._down(e); + }) + .bind('keydown.spinner', function(e) { + var KEYS = $.keyCode; + if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.ENTER) { + $(this).addClass('ui-spinner-pressed'); + if(!self.counter) self.counter = 1; + self._down.call(self, e); + } else if (e.keyCode == KEYS.UP || e.keyCode == KEYS.LEFT) { + self.element.siblings('.ui-spinner-up').focus(); + } + }) + .bind('keyup.spinner', function(e) { + $(this).removeClass('ui-spinner-pressed'); + self.counter = 0; + self._propagate('change', e); + }) + .end(); + + + // DataList: Set contraints for object length and step size. + // Manipulate height of spinner. + this._items = this.element.children().length; + if (this._items > 1) { + this.element + .addClass('ui-spinner-list') + .css('height', this.element.outerHeight()/this._items) + .children() + .addClass('ui-spinner-listitem') + .end() + .parent() + .css('height', this.element.outerHeight()) + .end(); + this.options.stepping = 1; + this.options.min = 0; + this.options.max = this._items-1; + } + + this.element + .bind('keydown.spinner', function(e) { + if(!self.counter) self.counter = 1; + return self._keydown.call(self, e); + }) + .bind('keyup.spinner', function(e) { + self.counter = 0; + self._propagate('change', e); + }) + .bind('blur.spinner', function(e) { + self._cleanUp(); + }); + + if ($.fn.mousewheel) { + this.element.mousewheel(function(e, delta) { + self._mousewheel(e, delta); + }); + } + }, + + + _constrain: function() { + if(this.options.min != undefined && this._getValue() < this.options.min) this._setValue(this.options.min); + if(this.options.max != undefined && this._getValue() > this.options.max) this._setValue(this.options.max); + }, + _cleanUp: function() { + this._setValue(this._getValue()); + this._constrain(); + }, + _spin: function(d, e) { + if (this.disabled) return; + + if(isNaN(this._getValue())) this._setValue(this.options.start); + this._setValue(this._getValue() + (d == 'up' ? 1:-1) * (this.options.incremental && this.counter > 100 ? (this.counter > 200 ? 100 : 10) : 1) * this.options.stepping); + this._animate(d); + this._constrain(); + if(this.counter) this.counter++; + this._propagate('spin', e); + }, + _down: function(e) { + this._spin('down', e); + this._propagate('down', e); + }, + _up: function(e) { + this._spin('up', e); + this._propagate('up', e); + }, + _mousedown: function(i, d, e) { + var self = this; + i = i || 100; + if(this.timer) window.clearInterval(this.timer); + this.timer = window.setInterval(function() { + self[d](e); + if(self.counter > 20) self._mousedown(20, d, e); + }, i); + }, + _mouseup: function(e) { + this.counter = 0; + if(this.timer) window.clearInterval(this.timer); + this.element[0].focus(); + this._propagate('change', e); + }, + _keydown: function(e) { + var KEYS = $.keyCode; + + if(e.keyCode == KEYS.UP) this._up(e); + if(e.keyCode == KEYS.DOWN) this._down(e); + if(e.keyCode == KEYS.HOME) this._setValue(this.options.min || this.options.start); //Home key goes to min, if defined, else to start + if(e.keyCode == KEYS.END && this.options.max != undefined) this._setValue(this.options.max); //End key goes to maximum + return (e.keyCode == KEYS.TAB || e.keyCode == KEYS.BACKSPACE || + e.keyCode == KEYS.LEFT || e.keyCode == KEYS.RIGHT || e.keyCode == KEYS.PERIOD || + e.keyCode == KEYS.NUMPAD_DECIMAL || e.keyCode == KEYS.NUMPAD_SUBTRACT || + (e.keyCode >= 96 && e.keyCode <= 105) || // add support for numeric keypad 0-9 + (/[0-9\-\.]/).test(String.fromCharCode(e.keyCode))) ? true : false; + }, + _mousewheel: function(e, delta) { + delta = ($.browser.opera ? -delta / Math.abs(delta) : delta); + delta > 0 ? this._up(e) : this._down(e); + e.preventDefault(); + }, + _getValue: function() { + return parseFloat(this.element.val().replace(/[^0-9\-\.]/g, '')); + }, + _setValue: function(newVal) { + if(isNaN(newVal)) newVal = this.options.start; + this.element.val( + this.options.currency ? + $.ui.spinner.format.currency(newVal, this.options.currency) : + $.ui.spinner.format.number(newVal, this._decimals) + ); + }, + _animate: function(d) { + if (this.element.hasClass('ui-spinner-list') && ((d == 'up' && this._getValue() <= this.options.max) || (d == 'down' && this._getValue() >= this.options.min)) ) { + this.element.animate({marginTop: '-' + this._getValue() * this.element.outerHeight() }, { + duration: 'fast', + queue: false + }); + } + }, + _addItem: function(html) { + if (!this.element.is('input')) { + var wrapper = 'div'; + if (this.element.is('ol') || this.element.is('ul')) { + wrapper = 'li'; + } + this.element.append('<'+ wrapper +' class="ui-spinner-dyn">'+ html + ''); + } + }, + + + plugins: {}, + ui: function(e) { + return { + options: this.options, + element: this.element, + value: this._getValue(), + add: this._addItem + }; + }, + _propagate: function(n,e) { + $.ui.plugin.call(this, n, [e, this.ui()]); + return this.element.triggerHandler(n == 'spin' ? n : 'spin'+n, [e, this.ui()], this.options[n]); + }, + destroy: function() { + if(!$.data(this.element[0], 'spinner')) return; + if ($.fn.mousewheel) { + this.element.unmousewheel(); + } + this.element + .removeClass('ui-spinner-box ui-spinner-list') + .removeAttr('disabled') + .removeAttr('autocomplete') + .removeData('spinner') + .unbind('.spinner') + .siblings() + .remove() + .end() + .children() + .removeClass('ui-spinner-listitem') + .remove('.ui-spinner-dyn') + .end() + .parent() + .removeClass('ui-spinner ui-spinner-disabled') + .before(this.element.clone()) + .remove() + .end(); + }, + enable: function() { + this.element + .removeAttr('disabled') + .siblings() + .removeAttr('disabled') + .parent() + .removeClass('ui-spinner-disabled'); + this.disabled = false; + }, + disable: function() { + this.element + .attr('disabled', true) + .siblings() + .attr('disabled', true) + .parent() + .addClass('ui-spinner-disabled'); + this.disabled = true; + } +}); + +$.extend($.ui.spinner, { + defaults: { + stepping: 1, + start: 0, + incremental: true, + currency: false + }, + format: { + number: function(num, dec) { + return this.round(num, dec); + }, + currency: function(num, sym) { + return (num !== Math.abs(num) ? '-' : '') + sym + this.round(Math.abs(num), 2); + }, + round: function(num, dec) { + var s = Math.round(parseFloat(num)*Math.pow(10, dec)) / Math.pow(10, dec); // round off weird decimals + if (dec > 0) { + s = s + ((s.toString().indexOf('.') == -1) ? '.' : '') + '0000000001'; + s = s.substr(0, s.indexOf('.')+1+dec); + } else { + s = Math.round(s); + } + return s; + } + } +}); + +})(jQuery); addfile ./static/js/jquery/ui/ui.tabs.js hunk ./static/js/jquery/ui/ui.tabs.js 1 +/* + * jQuery UI Tabs @VERSION + * + * Copyright (c) 2007, 2008 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * http://docs.jquery.com/UI/Tabs + * + * Depends: + * ui.core.js + */ +(function($) { + +$.widget("ui.tabs", { + _init: function() { + this.options.event += '.tabs'; // namespace event + + // create tabs + this._tabify(true); + }, + _setData: function(key, value) { + if ((/^selected/).test(key)) + this.select(value); + else { + this.options[key] = value; + this._tabify(); + } + }, + length: function() { + return this.$tabs.length; + }, + _tabId: function(a) { + return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '') + || this.options.idPrefix + $.data(a); + }, + ui: function(tab, panel) { + return { + options: this.options, + tab: tab, + panel: panel, + index: this.$tabs.index(tab) + }; + }, + _tabify: function(init) { + + this.$lis = $('li:has(a[href])', this.element); + this.$tabs = this.$lis.map(function() { return $('a', this)[0]; }); + this.$panels = $([]); + + var self = this, o = this.options; + + this.$tabs.each(function(i, a) { + // inline tab + if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash + self.$panels = self.$panels.add(a.hash); + // remote tab + else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#" + $.data(a, 'href.tabs', a.href); // required for restore on destroy + $.data(a, 'load.tabs', a.href); // mutable + var id = self._tabId(a); + a.href = '#' + id; + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass) + .insertAfter( self.$panels[i - 1] || self.element ); + $panel.data('destroy.tabs', true); + } + self.$panels = self.$panels.add( $panel ); + } + // invalid tab href + else + o.disabled.push(i + 1); + }); + + // initialization from scratch + if (init) { + + // attach necessary classes for styling if not present + this.element.addClass(o.navClass); + this.$panels.each(function() { + var $this = $(this); + $this.addClass(o.panelClass); + }); + + // Selected tab + // use "selected" option or try to retrieve: + // 1. from fragment identifier in url + // 2. from cookie + // 3. from selected class attribute on
  • + if (o.selected === undefined) { + if (location.hash) { + this.$tabs.each(function(i, a) { + if (a.hash == location.hash) { + o.selected = i; + // prevent page scroll to fragment + if ($.browser.msie || $.browser.opera) { // && !o.remote + var $toShow = $(location.hash), toShowId = $toShow.attr('id'); + $toShow.attr('id', ''); + setTimeout(function() { + $toShow.attr('id', toShowId); // restore id + }, 500); + } + scrollTo(0, 0); + return false; // break + } + }); + } + else if (o.cookie) { + var index = parseInt($.cookie('ui-tabs-' + $.data(self.element[0])), 10); + if (index && self.$tabs[index]) + o.selected = index; + } + else if (self.$lis.filter('.' + o.selectedClass).length) + o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] ); + } + o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + // A selected tab cannot become disabled. + o.disabled = $.unique(o.disabled.concat( + $.map(this.$lis.filter('.' + o.disabledClass), + function(n, i) { return self.$lis.index(n); } ) + )).sort(); + if ($.inArray(o.selected, o.disabled) != -1) + o.disabled.splice($.inArray(o.selected, o.disabled), 1); + + // highlight selected tab + this.$panels.addClass(o.hideClass); + this.$lis.removeClass(o.selectedClass); + if (o.selected !== null) { + this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before + this.$lis.eq(o.selected).addClass(o.selectedClass); + + // seems to be expected behavior that the show callback is fired + var onShow = function() { + self._trigger('show', null, + self.ui(self.$tabs[o.selected], self.$panels[o.selected])); + }; + + // load if remote tab + if ($.data(this.$tabs[o.selected], 'load.tabs')) + this.load(o.selected, onShow); + // just trigger show event + else + onShow(); + } + + // clean up to avoid memory leaks in certain versions of IE 6 + $(window).bind('unload', function() { + self.$tabs.unbind('.tabs'); + self.$lis = self.$tabs = self.$panels = null; + }); + + } + // update selected after add/remove + else + o.selected = this.$lis.index( this.$lis.filter('.' + o.selectedClass)[0] ); + + // set or update cookie after init and add/remove respectively + if (o.cookie) + $.cookie('ui-tabs-' + $.data(self.element[0]), o.selected, o.cookie); + + // disable tabs + for (var i = 0, li; li = this.$lis[i]; i++) + $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass); + + // reset cache if switching from cached to not cached + if (o.cache === false) + this.$tabs.removeData('cache.tabs'); + + // set up animations + var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal'; + if (o.fx && o.fx.constructor == Array) + hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx; + else + hideFx = showFx = o.fx || baseFx; + + // reset some styles to maintain print style sheets etc. + var resetCSS = { display: '', overflow: '', height: '' }; + if (!$.browser.msie) // not in IE to prevent ClearType font issue + resetCSS.opacity = ''; + + // Hide a tab, animation prevents browser scrolling to fragment, + // $show is optional. + function hideTab(clicked, $hide, $show) { + $hide.animate(hideFx, hideFx.duration || baseDuration, function() { // + $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. + if ($.browser.msie && hideFx.opacity) + $hide[0].style.filter = ''; + if ($show) + showTab(clicked, $show, $hide); + }); + } + + // Show a tab, animation prevents browser scrolling to fragment, + // $hide is optional. + function showTab(clicked, $show, $hide) { + if (showFx === baseFx) + $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels + $show.animate(showFx, showFx.duration || baseDuration, function() { + $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc. + if ($.browser.msie && showFx.opacity) + $show[0].style.filter = ''; + + // callback + self._trigger('show', null, self.ui(clicked, $show[0])); + }); + } + + // switch a tab + function switchTab(clicked, $li, $hide, $show) { + /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click + $.ajaxHistory.update(clicked.hash); + }*/ + $li.addClass(o.selectedClass) + .siblings().removeClass(o.selectedClass); + hideTab(clicked, $hide, $show); + } + + // attach tab event handler, unbind to avoid duplicates from former tabifying... + this.$tabs.unbind('.tabs').bind(o.event, function() { + + //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click + var $li = $(this).parents('li:eq(0)'), + $hide = self.$panels.filter(':visible'), + $show = $(this.hash); + + // If tab is already selected and not unselectable or tab disabled or + // or is already loading or click callback returns false stop here. + // Check if click handler returns false last so that it is not executed + // for a disabled or loading tab! + if (($li.hasClass(o.selectedClass) && !o.unselect) + || $li.hasClass(o.disabledClass) + || $(this).hasClass(o.loadingClass) + || self._trigger('select', null, self.ui(this, $show[0])) === false + ) { + this.blur(); + return false; + } + + self.options.selected = self.$tabs.index(this); + + // if tab may be closed + if (o.unselect) { + if ($li.hasClass(o.selectedClass)) { + self.options.selected = null; + $li.removeClass(o.selectedClass); + self.$panels.stop(); + hideTab(this, $hide); + this.blur(); + return false; + } else if (!$hide.length) { + self.$panels.stop(); + var a = this; + self.load(self.$tabs.index(this), function() { + $li.addClass(o.selectedClass).addClass(o.unselectClass); + showTab(a, $show); + }); + this.blur(); + return false; + } + } + + if (o.cookie) + $.cookie('ui-tabs-' + $.data(self.element[0]), self.options.selected, o.cookie); + + // stop possibly running animations + self.$panels.stop(); + + // show new tab + if ($show.length) { + + // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled + /*if ($.browser.msie && o.bookmarkable) { + var showId = this.hash.replace('#', ''); + $show.attr('id', ''); + setTimeout(function() { + $show.attr('id', showId); // restore id + }, 0); + }*/ + + var a = this; + self.load(self.$tabs.index(this), $hide.length ? + function() { + switchTab(a, $li, $hide, $show); + } : + function() { + $li.addClass(o.selectedClass); + showTab(a, $show); + } + ); + + // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash + /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0; + var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0; + setTimeout(function() { + scrollTo(scrollX, scrollY); + }, 0);*/ + + } else + throw 'jQuery UI Tabs: Mismatching fragment identifier.'; + + // Prevent IE from keeping other link focussed when using the back button + // and remove dotted border from clicked link. This is controlled in modern + // browsers via CSS, also blur removes focus from address bar in Firefox + // which can become a usability and annoying problem with tabsRotate. + if ($.browser.msie) + this.blur(); + + //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE + return false; + + }); + + // disable click if event is configured to something else + if (!(/^click/).test(o.event)) + this.$tabs.bind('click.tabs', function() { return false; }); + + }, + add: function(url, label, index) { + if (index == undefined) + index = this.$tabs.length; // append by default + + var o = this.options; + var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label)); + $li.data('destroy.tabs', true); + + var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] ); + + // try to find an existing element before creating a new one + var $panel = $('#' + id); + if (!$panel.length) { + $panel = $(o.panelTemplate).attr('id', id) + .addClass(o.hideClass) + .data('destroy.tabs', true); + } + $panel.addClass(o.panelClass); + if (index >= this.$lis.length) { + $li.appendTo(this.element); + $panel.appendTo(this.element[0].parentNode); + } else { + $li.insertBefore(this.$lis[index]); + $panel.insertBefore(this.$panels[index]); + } + + o.disabled = $.map(o.disabled, + function(n, i) { return n >= index ? ++n : n }); + + this._tabify(); + + if (this.$tabs.length == 1) { + $li.addClass(o.selectedClass); + $panel.removeClass(o.hideClass); + var href = $.data(this.$tabs[0], 'load.tabs'); + if (href) + this.load(index, href); + } + + // callback + this._trigger('add', null, this.ui(this.$tabs[index], this.$panels[index])); + }, + remove: function(index) { + var o = this.options, $li = this.$lis.eq(index).remove(), + $panel = this.$panels.eq(index).remove(); + + // If selected tab was removed focus tab to the right or + // in case the last tab was removed the tab to the left. + if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1) + this.select(index + (index + 1 < this.$tabs.length ? 1 : -1)); + + o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }), + function(n, i) { return n >= index ? --n : n }); + + this._tabify(); + + // callback + this._trigger('remove', null, this.ui($li.find('a')[0], $panel[0])); + }, + enable: function(index) { + var o = this.options; + if ($.inArray(index, o.disabled) == -1) + return; + + var $li = this.$lis.eq(index).removeClass(o.disabledClass); + if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2... + $li.css('display', 'inline-block'); + setTimeout(function() { + $li.css('display', 'block'); + }, 0); + } + + o.disabled = $.grep(o.disabled, function(n, i) { return n != index; }); + + // callback + this._trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index])); + }, + disable: function(index) { + var self = this, o = this.options; + if (index != o.selected) { // cannot disable already selected tab + this.$lis.eq(index).addClass(o.disabledClass); + + o.disabled.push(index); + o.disabled.sort(); + + // callback + this._trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index])); + } + }, + select: function(index) { + if (typeof index == 'string') + index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] ); + this.$tabs.eq(index).trigger(this.options.event); + }, + load: function(index, callback) { // callback is for internal usage only + + var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0], + bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs'); + + callback = callback || function() {}; + + // no remote or from cache - just finish with callback + if (!url || !bypassCache && $.data(a, 'cache.tabs')) { + callback(); + return; + } + + // load remote from here on + + var inner = function(parent) { + var $parent = $(parent), $inner = $parent.find('*:last'); + return $inner.length && $inner.is(':not(img)') && $inner || $parent; + }; + var cleanup = function() { + self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass) + .each(function() { + if (o.spinner) + inner(this).parent().html(inner(this).data('label.tabs')); + }); + self.xhr = null; + }; + + if (o.spinner) { + var label = inner(a).html(); + inner(a).wrapInner('') + .find('em').data('label.tabs', label).html(o.spinner); + } + + var ajaxOptions = $.extend({}, o.ajaxOptions, { + url: url, + success: function(r, s) { + $(a.hash).html(r); + cleanup(); + + if (o.cache) + $.data(a, 'cache.tabs', true); // if loaded once do not load them again + + // callbacks + self._trigger('load', null, self.ui(self.$tabs[index], self.$panels[index])); + o.ajaxOptions.success && o.ajaxOptions.success(r, s); + + // This callback is required because the switch has to take + // place after loading has completed. Call last in order to + // fire load before show callback... + callback(); + } + }); + if (this.xhr) { + // terminate pending requests from other tabs and restore tab label + this.xhr.abort(); + cleanup(); + } + $a.addClass(o.loadingClass); + setTimeout(function() { // timeout is again required in IE, "wait" for id being restored + self.xhr = $.ajax(ajaxOptions); + }, 0); + + }, + url: function(index, url) { + this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url); + }, + destroy: function() { + var o = this.options; + this.element.unbind('.tabs') + .removeClass(o.navClass).removeData('tabs'); + this.$tabs.each(function() { + var href = $.data(this, 'href.tabs'); + if (href) + this.href = href; + var $this = $(this).unbind('.tabs'); + $.each(['href', 'load', 'cache'], function(i, prefix) { + $this.removeData(prefix + '.tabs'); + }); + }); + this.$lis.add(this.$panels).each(function() { + if ($.data(this, 'destroy.tabs')) + $(this).remove(); + else + $(this).removeClass([o.selectedClass, o.unselectClass, + o.disabledClass, o.panelClass, o.hideClass].join(' ')); + }); + } +}); + +$.ui.tabs.defaults = { + // basic setup + unselect: false, + event: 'click', + disabled: [], + cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } + // TODO history: false, + + // Ajax + spinner: 'Loading…', + cache: false, + idPrefix: 'ui-tabs-', + ajaxOptions: {}, + + // animations + fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } + + // templates + tabTemplate: '
  • #{label}
  • ', + panelTemplate: '
    ', + + // CSS classes + navClass: 'ui-tabs-nav', + selectedClass: 'ui-tabs-selected', + unselectClass: 'ui-tabs-unselect', + disabledClass: 'ui-tabs-disabled', + panelClass: 'ui-tabs-panel', + hideClass: 'ui-tabs-hide', + loadingClass: 'ui-tabs-loading' +}; + +$.ui.tabs.getter = "length"; + +/* + * Tabs Extensions + */ + +/* + * Rotate + */ +$.extend($.ui.tabs.prototype, { + rotation: null, + rotate: function(ms, continuing) { + + continuing = continuing || false; + + var self = this, t = this.options.selected; + + function start() { + self.rotation = setInterval(function() { + t = ++t < self.$tabs.length ? t : 0; + self.select(t); + }, ms); + } + + function stop(e) { + if (!e || e.clientX) { // only in case of a true click + clearInterval(self.rotation); + } + } + + // start interval + if (ms) { + start(); + if (!continuing) + this.$tabs.bind(this.options.event, stop); + else + this.$tabs.bind(this.options.event, function() { + stop(); + t = self.options.selected; + start(); + }); + } + // stop interval + else { + stop(); + this.$tabs.unbind(this.options.event, stop); + } + } +}); + +})(jQuery); addfile ./static/js/jquery/version.txt hunk ./static/js/jquery/version.txt 1 - +1.6rc2