/****************************************************************************************************** jQuery.NobleCount Author Jeremy Horn Version 1.0 Date: 3/21/2010 Copyright (c) 2010 Jeremy Horn- jeremydhorn(at)gmail(dot)c0m | http://tpgblog.com Dual licensed under MIT and GPL. DESCRIPTION NobleCount... for a more 'proper' count of the characters remaining. NobleCount is a customizable jQuery plugin for a more the improved counting of the remaining characters, and resulting behaviors, of a text entry object, e.g. input textfield, textarea. As text is entered into the target text area an object for the purposes of tracking the total number of characters remaining, defined as the maximum number of characters minus the current total number of characters within the text entry object, and storing that information visually and/or within the DOM as an HTML 5 compliant data-* attribute. Events and CSS Class alterations, if defined, are triggered based on current user interaction with the target text entry object as well as the current state (positive or negative) of the character remaining value. NobleCount supports pre-existing text within the text object. NobleCount supports jQuery chaining. Within NobleCount context... NEGATIVE is defined as Integers < 0 POSITIVE is defined as Integers >= 0 [on_positive will fire when char_rem == 0] BY DEFAULT - maximum characters EQUAL 140 characters - no events defined - no class changes defined - no DOM attributes are created/altered - user permitted to type past the maximum number of characters limit, resulting in negative number of characters remaining IMPLEMENTATION $('#textarea1').NobleCount('#characters_remaining1'); $('#textfield2').NobleCount('#characters_remaining2', { / * OPTIONS * / }); COMPATIBILITY Tested in FF3.5, IE7 With jQuery 1.3.x, 1.4.x METHOD(S) To properly intialize, both the text entry object and the object that will store the total number of characters remaining must exist and be passed to NobleCount. $(TEXT_ENTRY_OBJECT).NobleCount(CHARACTERS_REMAINING_OBJECT); Any callback functions assigned to any of the availale events are passed the following parameters: t_obj, char_area, c_settings, char_rem t_obj text entry object char_area selection of the characters remaining object c_settings result of the options passed into NobleCount at time of initialization merged with the default options ** this is a GREAT way to pass in and remember other state information that will be needed upon the triggering of NobleCount events ** char_rem integer representation of the total number of characters remaining resulting from the calculated difference between the target maximum number of characters and the current number of characters currently within t_obj Both TEXT_ENTRY_OBJECT and CHARACTERS_REMAINING_OBJECT must be specified and valid. Upon successful initialization, all appropriate events and classes are applied to the CHARACTERS_REMAINING_OBJECT, including the storage (if not disabled) visually or only in the DOM (if enabled) of the integer representing the number of characters remaining. The target maximum number of characters (max_chars) are determined by the following precedence rules.... if max_chars passed via constructor max_chars = max_chars passed else if number exists within characters_remaining object and number > 0 max_chars = number within the text() of characters_remaining object else use the NobleCount's default max_chars CUSTOMIZATION NobleCount(c_obj, ) e.g. $(t_obj).NobleCount(c_obj, {max_chars:100px}); on_negative class (STRING) or FUNCTION that is applied/called when characters remaining is negative IF DEFINED on_positive class (STRING) or FUNCTION that is applied/called when characters remaining is positive IF DEFINED on_update FUNCTION that is called when characters remaining changes max_chars target maximum number of characters block_negative if TRUE, then all attempts are made to block entering more than max_characters; not effective against user pasting in blocks of text that exceed the max_chars value otherwise, text area will let individual entering the text to exceed max_chars limit (characters remaining becomes negative) cloak: false, if TRUE, then no visual updates of characters remaining object (c_obj) will occur; this does not have any effect on the char_rem value returned via any event callbacks otherwise, the text within c_obj is constantly updated to represent the total number of characters remaining until the max_chars limit has been reached in_dom: false if TRUE and cloak is ALSO TRUE, then the number of characters remaining are stored as the attribute of c_obj named 'data-noblecount' !NOTE: if enabled, due to constant updating of a DOM element attribute user experience can appear sluggish while the individual is modifying the text entry object (t_obj) EXAMPLE OPTIONS = { on_negative: 'go_red', on_positive: 'go_green', max_chars: 25, on_update: function(t_obj, char_area, c_settings, char_rem){ if ((char_rem % 10) == 0) { char_area.css('font-weight', 'bold'); char_area.css('font-size', '300%'); } else { char_area.css('font-weight', 'normal'); char_area.css('font-size', '100%'); } } }; MORE For more details about NobleCount, its implementation, usage, and examples, go to: http://tpgblog.com/noblecount/ ******************************************************************************************************/ (function($) { /********************************************************************************** FUNCTION NobleCount DESCRIPTION NobleCount method constructor allows for customization of maximum length and related update/length behaviors e.g. $(text_obj).NobleCount(characters_remaining_obj); REQUIRED: c_obj OPTIONAL: options **********************************************************************************/ $.fn.NobleCount = function(c_obj, options) { var c_settings; var mc_passed = false; // if c_obj is not specified, then nothing to do here if (typeof c_obj == 'string') { // check for new & valid options c_settings = $.extend({}, $.fn.NobleCount.settings, options); // was max_chars passed via options parameter? if (typeof options != 'undefined') { mc_passed = ((typeof options.max_chars == 'number') ? true : false); } // process all provided objects return this.each(function(){ var $this = $(this); // attach events to c_obj attach_nobility($this, c_obj, c_settings, mc_passed); }); } return this; }; /********************************************************************************** FUNCTION NobleCount.settings DESCRIPTION publically accessible data stucture containing the max_chars and event handling specifications for NobleCount can be directly accessed by '$.fn.NobleCount.settings = ... ;' **********************************************************************************/ $.fn.NobleCount.settings = { on_negative: null, // class (STRING) or FUNCTION that is applied/called // when characters remaining is negative on_positive: null, // class (STRING) or FUNCTION that is applied/called // when characters remaining is positive on_update: null, // FUNCTION that is called when characters remaining // changes max_chars: 140, // maximum number of characters block_negative: false, // if true, then all attempts are made to block entering // more than max_characters cloak: false, // if true, then no visual updates of characters // remaining (c_obj) occur in_dom: false // if true and cloak == true, then number of characters // remaining are stored as the attribute // 'data-noblecount' of c_obj }; ////////////////////////////////////////////////////////////////////////////////// // private functions and settings /********************************************************************************** FUNCTION attach_nobility DESCRIPTION performs all initialization routines and display initiation assigns both the keyup and keydown events to the target text entry object; both keyup and keydown are used to provide the smoothest user experience if max_chars_passed via constructor max_chars = max_chars_passed else if number exists within counting_object (and number > 0) max_chars = counting_object.number else use default max_chars PRE t_obj and c_obj EXIST c_settings and mc_passed initialized POST maximum number of characters for t_obj calculated and stored in max_char key events attached to t_obj **********************************************************************************/ function attach_nobility(t_obj, c_obj, c_settings, mc_passed){ var max_char = c_settings.max_chars; var char_area = $(c_obj); // first determine if max_char needs adjustment if (!mc_passed) { var tmp_num = char_area.text(); var isPosNumber = (/^[1-9]\d*$/).test(tmp_num); if (isPosNumber) { max_char = tmp_num; } } // initialize display of characters remaining // * note: initializing should not trigger on_update event_internals(t_obj, char_area, c_settings, max_char, true); // then attach the events -- seem to work better than keypress $(t_obj).keydown(function(e) { event_internals(t_obj, char_area, c_settings, max_char, false); // to block text entry, return false if (check_block_negative(e, t_obj, c_settings, max_char) == false) { return false; } }); $(t_obj).keyup(function(e) { event_internals(t_obj, char_area, c_settings, max_char, false); // to block text entry, return false if (check_block_negative(e, t_obj, c_settings, max_char) == false) { return false; } }); } /********************************************************************************** FUNCTION check_block_negative DESCRIPTION determines whether or not text entry within t_obj should be prevented PRE e EXISTS t_obj VALID c_settings and max_char initialized / calculated POST if t_obj text entry should be prevented FALSE is returned otherwise TRUE returned TODO improve selection detection and permissible behaviors experience ALSO doesnt CURRENTLY block from the pasting of large chunks of text that exceed max_char **********************************************************************************/ function check_block_negative(e, t_obj, c_settings, max_char){ if (c_settings.block_negative) { var char_code = e.which; var selected; // goofy handling required to work in both IE and FF if (typeof document.selection != 'undefined') { selected = (document.selection.createRange().text.length > 0); } else { selected = (t_obj[0].selectionStart != t_obj[0].selectionEnd); } //return false if can't write more if ((!((find_remaining(t_obj, max_char) < 1) && (char_code > 47 || char_code == 32 || char_code == 0 || char_code == 13) && !e.ctrlKey && !e.altKey && !selected)) == false) { // block text entry return false; } } // allow text entry return true; } /********************************************************************************** FUNCTION find_remaining DESCRIPTION determines of the number of characters permitted (max_char), the number of characters remaining until that limit has been reached PRE t_obj and max_char EXIST and are VALID POST returns integer of the difference between max_char and total number of characters within the text entry object (t_obj) **********************************************************************************/ function find_remaining(t_obj, max_char){ return max_char - ($(t_obj).val()).length; } /********************************************************************************** FUNCTION event_internals DESCRIPTION primarily used for the calculation of appropriate behavior resulting from any event attached to the text entry object (t_obj) whenever the char_rem and related display and/or DOM information needs updating this function is called if cloaking is being used, then no visual representation of the characters remaining, nor attempt by this plugin to change any of its visual characteristics will occur if cloaking and in_dom are both TRUE, then the number of characters remaining are stored within the HTML 5 compliant attribute of the character count remaining object (c_obj) labeled 'data-noblecount' PRE c_settings, init_disp initialized POST performs all updates to the DOM visual and otherwise required performs all relevant function calls **********************************************************************************/ function event_internals(t_obj, char_area, c_settings, max_char, init_disp) { var char_rem = find_remaining(t_obj, max_char); // is chararacters remaining positive or negative if (char_rem < 0) { toggle_states(c_settings.on_negative, c_settings.on_positive, t_obj, char_area, c_settings, char_rem); } else { toggle_states(c_settings.on_positive, c_settings.on_negative, t_obj, char_area, c_settings, char_rem); } // determine whether or not to update the text of the char_area (or c_obj) if (c_settings.cloak) { // this slows stuff down quite a bit; TODO: implement better method of publically accessible data storage if (c_settings.in_dom) { char_area.attr('data-noblecount', char_rem); } } else { // show the numbers of characters remaining char_area.text(char_rem); } // if event_internals isn't being called for initialization purposes and // on_update is a properly defined function then call it on this update if (!init_disp && jQuery.isFunction(c_settings.on_update)) { c_settings.on_update(t_obj, char_area, c_settings, char_rem); } } /********************************************************************************** FUNCTION toggle_states DESCRIPTION performs the toggling operations between the watched positive and negative characteristics first, enables/triggers/executes the toggle_on behavior/class second, disables the trigger_off class PRE toggle_on, toggle_off IF DEFINED, must be a string representation of a VALID class OR must be a VALID function POST toggle_on objects have been applied/executed toggle_off class has been removed (if it is a class) **********************************************************************************/ function toggle_states(toggle_on, toggle_off, t_obj, char_area, c_settings, char_rem){ if (toggle_on != null) { if (typeof toggle_on == 'string') { char_area.addClass(toggle_on); } else if (jQuery.isFunction(toggle_on)) { toggle_on(t_obj, char_area, c_settings, char_rem); } } if (toggle_off != null) { if (typeof toggle_off == 'string') { char_area.removeClass(toggle_off); } } } })(jQuery);/* http://keith-wood.name/datepick.html Date picker for jQuery v4.1.0. Written by Keith Wood (kbwood{at}iinet.com.au) February 2010. Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. Please attribute the author if you use it. */ (function($) { // Hide scope, no $ conflict /* Datepicker manager. */ function Datepicker() { this._defaults = { pickerClass: '', // CSS class to add to this instance of the datepicker showOnFocus: true, // True for popup on focus, false for not showTrigger: null, // Element to be cloned for a trigger, null for none showAnim: 'show', // Name of jQuery animation for popup, '' for no animation showOptions: {}, // Options for enhanced animations showSpeed: 'normal', // Duration of display/closure popupContainer: null, // The element to which a popup calendar is added, null for body alignment: 'bottom', // Alignment of popup - with nominated corner of input: // 'top' or 'bottom' aligns depending on language direction, // 'topLeft', 'topRight', 'bottomLeft', 'bottomRight' fixedWeeks: false, // True to always show 6 weeks, false to only show as many as are needed firstDay: 0, // First day of the week, 0 = Sunday, 1 = Monday, ... calculateWeek: this.iso8601Week, // Calculate week of the year from a date, null for ISO8601 monthsToShow: 1, // How many months to show, cols or [rows, cols] monthsOffset: 0, // How many months to offset the primary month by; // may be a function that takes the date and returns the offset monthsToStep: 1, // How many months to move when prev/next clicked monthsToJump: 12, // How many months to move when large prev/next clicked useMouseWheel: true, // True to use mousewheel if available, false to never use it changeMonth: true, // True to change month/year via drop-down, false for navigation only yearRange: 'c-10:c+10', // Range of years to show in drop-down: 'any' for direct text entry // or 'start:end', where start/end are '+-nn' for relative to today // or 'c+-nn' for relative to the currently selected date // or 'nnnn' for an absolute year shortYearCutoff: '+10', // Cutoff for two-digit year in the current century showOtherMonths: false, // True to show dates from other months, false to not show them selectOtherMonths: false, // True to allow selection of dates from other months too defaultDate: null, // Date to show if no other selected selectDefaultDate: false, // True to pre-select the default date if no other is chosen minDate: null, // The minimum selectable date maxDate: null, // The maximum selectable date dateFormat: 'mm/dd/yyyy', // Format for dates autoSize: false, // True to size the input field according to the date format rangeSelect: false, // Allows for selecting a date range on one date picker rangeSeparator: ' - ', // Text between two dates in a range multiSelect: 0, // Maximum number of selectable dates, zero for single select multiSeparator: ',', // Text between multiple dates onDate: null, // Callback as a date is added to the datepicker onShow: null, // Callback just before a datepicker is shown onChangeMonthYear: null, // Callback when a new month/year is selected onSelect: null, // Callback when a date is selected onClose: null, // Callback when a datepicker is closed altField: null, // Alternate field to update in synch with the datepicker altFormat: null, // Date format for alternate field, defaults to dateFormat constrainInput: true, // True to constrain typed input to dateFormat allowed characters commandsAsDateFormat: false, // True to apply formatDate to the command texts commands: this.commands // Command actions that may be added to a layout by name }; this.regional = []; this.regional[''] = { // US/English monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], dateFormat: 'mm/dd/yyyy', // See options on formatDate firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... renderer: this.defaultRenderer, // The rendering templates prevText: '<Prev', // Text for the previous month command prevStatus: 'Show the previous month', // Status text for the previous month command prevJumpText: '<<', // Text for the previous year command prevJumpStatus: 'Show the previous year', // Status text for the previous year command nextText: 'Next>', // Text for the next month command nextStatus: 'Show the next month', // Status text for the next month command nextJumpText: '>>', // Text for the next year command nextJumpStatus: 'Show the next year', // Status text for the next year command currentText: 'Current', // Text for the current month command currentStatus: 'Show the current month', // Status text for the current month command todayText: 'Today', // Text for the today's month command todayStatus: 'Show today\'s month', // Status text for the today's month command clearText: 'Clear', // Text for the clear command clearStatus: 'Clear all the dates', // Status text for the clear command closeText: 'Close', // Text for the close command closeStatus: 'Close the datepicker', // Status text for the close command yearStatus: 'Change the year', // Status text for year selection monthStatus: 'Change the month', // Status text for month selection weekText: 'Wk', // Text for week of the year column header weekStatus: 'Week of the year', // Status text for week of the year column header dayStatus: 'Select DD, M d, yyyy', // Status text for selectable days defaultStatus: 'Select a date', // Status text shown by default isRTL: false // True if language is right-to-left }; $.extend(this._defaults, this.regional['']); this._disabled = []; } $.extend(Datepicker.prototype, { /* Class name added to elements to indicate already configured with datepicker. */ markerClassName: 'hasDatepick', /* Name of the data property for instance settings. */ propertyName: 'datepick', _popupClass: 'datepick-popup', // Marker for popup division _triggerClass: 'datepick-trigger', // Marker for trigger element _disableClass: 'datepick-disable', // Marker for disabled element _monthYearClass: 'datepick-month-year', // Marker for month/year inputs _curMonthClass: 'datepick-month-', // Marker for current month/year _anyYearClass: 'datepick-any-year', // Marker for year direct input _curDoWClass: 'datepick-dow-', // Marker for day of week commands: { // Command actions that may be added to a layout by name // name: { // The command name, use '{button:name}' or '{link:name}' in layouts // text: '', // The field in the regional settings for the displayed text // status: '', // The field in the regional settings for the status text // // The keystroke to trigger the action // keystroke: {keyCode: nn, ctrlKey: boolean, altKey: boolean, shiftKey: boolean}, // enabled: fn, // The function that indicates the command is enabled // date: fn, // The function to get the date associated with this action // action: fn} // The function that implements the action prev: {text: 'prevText', status: 'prevStatus', // Previous month keystroke: {keyCode: 33}, // Page up enabled: function(inst) { var minDate = inst.curMinDate(); return (!minDate || plugin.add(plugin.day( plugin._applyMonthsOffset(plugin.add(plugin.newDate(inst.drawDate), 1 - inst.options.monthsToStep, 'm'), inst), 1), -1, 'd'). getTime() >= minDate.getTime()); }, date: function(inst) { return plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), -inst.options.monthsToStep, 'm'), inst), 1); }, action: function(inst) { plugin._changeMonthPlugin(this, -inst.options.monthsToStep); } }, prevJump: {text: 'prevJumpText', status: 'prevJumpStatus', // Previous year keystroke: {keyCode: 33, ctrlKey: true}, // Ctrl + Page up enabled: function(inst) { var minDate = inst.curMinDate(); return (!minDate || plugin.add(plugin.day( plugin._applyMonthsOffset(plugin.add(plugin.newDate(inst.drawDate), 1 - inst.options.monthsToJump, 'm'), inst), 1), -1, 'd'). getTime() >= minDate.getTime()); }, date: function(inst) { return plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), -inst.options.monthsToJump, 'm'), inst), 1); }, action: function(inst) { plugin._changeMonthPlugin(this, -inst.options.monthsToJump); } }, next: {text: 'nextText', status: 'nextStatus', // Next month keystroke: {keyCode: 34}, // Page down enabled: function(inst) { var maxDate = inst.get('maxDate'); return (!maxDate || plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), inst.options.monthsToStep, 'm'), inst), 1). getTime() <= maxDate.getTime()); }, date: function(inst) { return plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), inst.options.monthsToStep, 'm'), inst), 1); }, action: function(inst) { plugin._changeMonthPlugin(this, inst.options.monthsToStep); } }, nextJump: {text: 'nextJumpText', status: 'nextJumpStatus', // Next year keystroke: {keyCode: 34, ctrlKey: true}, // Ctrl + Page down enabled: function(inst) { var maxDate = inst.get('maxDate'); return (!maxDate || plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), inst.options.monthsToJump, 'm'), inst), 1). getTime() <= maxDate.getTime()); }, date: function(inst) { return plugin.day(plugin._applyMonthsOffset(plugin.add( plugin.newDate(inst.drawDate), inst.options.monthsToJump, 'm'), inst), 1); }, action: function(inst) { plugin._changeMonthPlugin(this, inst.options.monthsToJump); } }, current: {text: 'currentText', status: 'currentStatus', // Current month keystroke: {keyCode: 36, ctrlKey: true}, // Ctrl + Home enabled: function(inst) { var minDate = inst.curMinDate(); var maxDate = inst.get('maxDate'); var curDate = inst.selectedDates[0] || plugin.today(); return (!minDate || curDate.getTime() >= minDate.getTime()) && (!maxDate || curDate.getTime() <= maxDate.getTime()); }, date: function(inst) { return inst.selectedDates[0] || plugin.today(); }, action: function(inst) { var curDate = inst.selectedDates[0] || plugin.today(); plugin._showMonthPlugin(this, curDate.getFullYear(), curDate.getMonth() + 1); } }, today: {text: 'todayText', status: 'todayStatus', // Today's month keystroke: {keyCode: 36, ctrlKey: true}, // Ctrl + Home enabled: function(inst) { var minDate = inst.curMinDate(); var maxDate = inst.get('maxDate'); return (!minDate || plugin.today().getTime() >= minDate.getTime()) && (!maxDate || plugin.today().getTime() <= maxDate.getTime()); }, date: function(inst) { return plugin.today(); }, action: function(inst) { plugin._showMonthPlugin(this); } }, clear: {text: 'clearText', status: 'clearStatus', // Clear the datepicker keystroke: {keyCode: 35, ctrlKey: true}, // Ctrl + End enabled: function(inst) { return true; }, date: function(inst) { return null; }, action: function(inst) { plugin._clearPlugin(this); } }, close: {text: 'closeText', status: 'closeStatus', // Close the datepicker keystroke: {keyCode: 27}, // Escape enabled: function(inst) { return true; }, date: function(inst) { return null; }, action: function(inst) { plugin._hidePlugin(this); } }, prevWeek: {text: 'prevWeekText', status: 'prevWeekStatus', // Previous week keystroke: {keyCode: 38, ctrlKey: true}, // Ctrl + Up enabled: function(inst) { var minDate = inst.curMinDate(); return (!minDate || plugin.add(plugin.newDate(inst.drawDate), -7, 'd'). getTime() >= minDate.getTime()); }, date: function(inst) { return plugin.add(plugin.newDate(inst.drawDate), -7, 'd'); }, action: function(inst) { plugin._changeDayPlugin(this, -7); } }, prevDay: {text: 'prevDayText', status: 'prevDayStatus', // Previous day keystroke: {keyCode: 37, ctrlKey: true}, // Ctrl + Left enabled: function(inst) { var minDate = inst.curMinDate(); return (!minDate || plugin.add(plugin.newDate(inst.drawDate), -1, 'd'). getTime() >= minDate.getTime()); }, date: function(inst) { return plugin.add(plugin.newDate(inst.drawDate), -1, 'd'); }, action: function(inst) { plugin._changeDayPlugin(this, -1); } }, nextDay: {text: 'nextDayText', status: 'nextDayStatus', // Next day keystroke: {keyCode: 39, ctrlKey: true}, // Ctrl + Right enabled: function(inst) { var maxDate = inst.get('maxDate'); return (!maxDate || plugin.add(plugin.newDate(inst.drawDate), 1, 'd'). getTime() <= maxDate.getTime()); }, date: function(inst) { return plugin.add(plugin.newDate(inst.drawDate), 1, 'd'); }, action: function(inst) { plugin._changeDayPlugin(this, 1); } }, nextWeek: {text: 'nextWeekText', status: 'nextWeekStatus', // Next week keystroke: {keyCode: 40, ctrlKey: true}, // Ctrl + Down enabled: function(inst) { var maxDate = inst.get('maxDate'); return (!maxDate || plugin.add(plugin.newDate(inst.drawDate), 7, 'd'). getTime() <= maxDate.getTime()); }, date: function(inst) { return plugin.add(plugin.newDate(inst.drawDate), 7, 'd'); }, action: function(inst) { plugin._changeDayPlugin(this, 7); } } }, /* Default template for generating a datepicker. */ defaultRenderer: { // Anywhere: '{l10n:name}' to insert localised value for name, // '{link:name}' to insert a link trigger for command name, // '{button:name}' to insert a button trigger for command name, // '{popup:start}...{popup:end}' to mark a section for inclusion in a popup datepicker only, // '{inline:start}...{inline:end}' to mark a section for inclusion in an inline datepicker only // Overall structure: '{months}' to insert calendar months picker: '
' + '
{link:prev}{link:today}{link:next}
{months}' + '{popup:start}
{link:clear}{link:close}
{popup:end}' + '
', // One row of months: '{months}' to insert calendar months monthRow: '
{months}
', // A single month: '{monthHeader:dateFormat}' to insert the month header - // dateFormat is optional and defaults to 'MM yyyy', // '{weekHeader}' to insert a week header, '{weeks}' to insert the month's weeks month: '
{monthHeader}
' + '{weekHeader}{weeks}
', // A week header: '{days}' to insert individual day names weekHeader: '{days}', // Individual day header: '{day}' to insert day name dayHeader: '{day}', // One week of the month: '{days}' to insert the week's days, '{weekOfYear}' to insert week of year week: '{days}', // An individual day: '{day}' to insert day value day: '{day}', // jQuery selector, relative to picker, for a single month monthSelector: '.datepick-month', // jQuery selector, relative to picker, for individual days daySelector: 'td', // Class for right-to-left (RTL) languages rtlClass: 'datepick-rtl', // Class for multi-month datepickers multiClass: 'datepick-multi', // Class for selectable dates defaultClass: '', // Class for currently selected dates selectedClass: 'datepick-selected', // Class for highlighted dates highlightedClass: 'datepick-highlight', // Class for today todayClass: 'datepick-today', // Class for days from other months otherMonthClass: 'datepick-other-month', // Class for days on weekends weekendClass: 'datepick-weekend', // Class prefix for commands commandClass: 'datepick-cmd', // Extra class(es) for commands that are buttons commandButtonClass: '', // Extra class(es) for commands that are links commandLinkClass: '', // Class for disabled commands disabledClass: 'datepick-disabled' }, /* Override the default settings for all datepicker instances. @param options (object) the new settings to use as defaults @return (Datepicker) this object */ setDefaults: function(options) { $.extend(this._defaults, options || {}); return this; }, _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), _msPerDay: 24 * 60 * 60 * 1000, ATOM: 'yyyy-mm-dd', // RFC 3339/ISO 8601 COOKIE: 'D, dd M yyyy', FULL: 'DD, MM d, yyyy', ISO_8601: 'yyyy-mm-dd', JULIAN: 'J', RFC_822: 'D, d M yy', RFC_850: 'DD, dd-M-yy', RFC_1036: 'D, d M yy', RFC_1123: 'D, d M yyyy', RFC_2822: 'D, d M yyyy', RSS: 'D, d M yy', // RFC 822 TICKS: '!', TIMESTAMP: '@', W3C: 'yyyy-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 w - week of year (no leading zero) ww - week of year (two digit) m - month of year (no leading zero) mm - month of year (two digit) M - month name short MM - month name long yy - year (two digit) yyyy - year (four digit) @ - Unix timestamp (s since 01/01/1970) ! - Windows ticks (100ns since 01/01/0001) '...' - literal text '' - single quote @param format (string) the desired format of the date (optional, default datepicker format) @param date (Date) the date value to format @param settings (object) attributes include: dayNamesShort (string[]) abbreviated names of the days from Sunday (optional) dayNames (string[]) names of the days from Sunday (optional) monthNamesShort (string[]) abbreviated names of the months (optional) monthNames (string[]) names of the months (optional) calculateWeek (function) function that determines week of the year (optional) @return (string) the date in the above format */ formatDate: function(format, date, settings) { if (typeof format != 'string') { settings = date; date = format; format = ''; } if (!date) { return ''; } format = format || this._defaults.dateFormat; settings = settings || {}; var dayNamesShort = settings.dayNamesShort || this._defaults.dayNamesShort; var dayNames = settings.dayNames || this._defaults.dayNames; var monthNamesShort = settings.monthNamesShort || this._defaults.monthNamesShort; var monthNames = settings.monthNames || this._defaults.monthNames; var calculateWeek = settings.calculateWeek || this._defaults.calculateWeek; // Check whether a format character is doubled var doubled = function(match, step) { var matches = 1; while (iFormat + matches < format.length && format.charAt(iFormat + matches) == match) { matches++; } iFormat += matches - 1; return Math.floor(matches / (step || 1)) > 1; }; // Format a number, with leading zeroes if necessary var formatNumber = function(match, value, len, step) { var num = '' + value; if (doubled(match, step)) { 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 (doubled(match) ? longNames[value] : shortNames[value]); }; var output = ''; var literal = false; for (var iFormat = 0; iFormat < format.length; iFormat++) { if (literal) { if (format.charAt(iFormat) == "'" && !doubled("'")) { 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': output += formatNumber('o', this.dayOfYear(date), 3); break; case 'w': output += formatNumber('w', calculateWeek(date), 2); break; case 'm': output += formatNumber('m', date.getMonth() + 1, 2); break; case 'M': output += formatName('M', date.getMonth(), monthNamesShort, monthNames); break; case 'y': output += (doubled('y', 2) ? date.getFullYear() : (date.getFullYear() % 100 < 10 ? '0' : '') + date.getFullYear() % 100); break; case '@': output += Math.floor(date.getTime() / 1000); break; case '!': output += date.getTime() * 10000 + this._ticksTo1970; break; case "'": if (doubled("'")) { output += "'"; } else { literal = true; } break; default: output += format.charAt(iFormat); } } } return output; }, /* Parse a string value into a date object. See formatDate for the possible formats, plus: * - ignore rest of string @param format (string) the expected format of the date ('' for default datepicker format) @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[]) abbreviated names of the days from Sunday (optional) dayNames (string[]) names of the days from Sunday (optional) monthNamesShort (string[]) abbreviated names of the months (optional) monthNames (string[]) names of the months (optional) @return (Date) the extracted date value or null if value is blank @throws errors if the format and/or value are missing, if the value doesn't match the format, or if the date is invalid */ parseDate: function(format, value, settings) { if (value == null) { throw 'Invalid arguments'; } value = (typeof value == 'object' ? value.toString() : value + ''); if (value == '') { return null; } format = format || this._defaults.dateFormat; settings = settings || {}; var shortYearCutoff = settings.shortYearCutoff || this._defaults.shortYearCutoff; shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : this.today().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); var dayNamesShort = settings.dayNamesShort || this._defaults.dayNamesShort; var dayNames = settings.dayNames || this._defaults.dayNames; var monthNamesShort = settings.monthNamesShort || this._defaults.monthNamesShort; var monthNames = settings.monthNames || this._defaults.monthNames; var year = -1; var month = -1; var day = -1; var doy = -1; var shortYear = false; var literal = false; // Check whether a format character is doubled var doubled = function(match, step) { var matches = 1; while (iFormat + matches < format.length && format.charAt(iFormat + matches) == match) { matches++; } iFormat += matches - 1; return Math.floor(matches / (step || 1)) > 1; }; // Extract a number from the string value var getNumber = function(match, step) { var isDoubled = doubled(match, step); var size = [2, 3, isDoubled ? 4 : 2, 11, 20]['oy@!'.indexOf(match) + 1]; var digits = new RegExp('^-?\\d{1,' + size + '}'); var num = value.substring(iValue).match(digits); if (!num) { throw 'Missing number at position {0}'.replace(/\{0\}/, iValue); } iValue += num[0].length; return parseInt(num[0], 10); }; // Extract a name from the string value and convert to an index var getName = function(match, shortNames, longNames, step) { var names = (doubled(match, step) ? longNames : shortNames); for (var i = 0; i < names.length; i++) { if (value.substr(iValue, names[i].length).toLowerCase() == names[i].toLowerCase()) { iValue += names[i].length; return i + 1; } } throw 'Unknown name at position {0}'.replace(/\{0\}/, iValue); }; // Confirm that a literal character matches the string value var checkLiteral = function() { if (value.charAt(iValue) != format.charAt(iFormat)) { throw 'Unexpected literal at position {0}'.replace(/\{0\}/, iValue); } iValue++; }; var iValue = 0; for (var iFormat = 0; iFormat < format.length; iFormat++) { if (literal) { if (format.charAt(iFormat) == "'" && !doubled("'")) { 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 'w': getNumber('w'); break; case 'm': month = getNumber('m'); break; case 'M': month = getName('M', monthNamesShort, monthNames); break; case 'y': var iSave = iFormat; shortYear = !doubled('y', 2); iFormat = iSave; year = getNumber('y', 2); break; case '@': var date = this._normaliseDate(new Date(getNumber('@') * 1000)); year = date.getFullYear(); month = date.getMonth() + 1; day = date.getDate(); break; case '!': var date = this._normaliseDate( new Date((getNumber('!') - this._ticksTo1970) / 10000)); year = date.getFullYear(); month = date.getMonth() + 1; day = date.getDate(); break; case '*': iValue = value.length; break; case "'": if (doubled("'")) { checkLiteral(); } else { literal = true; } break; default: checkLiteral(); } } } if (iValue < value.length) { throw 'Additional text found at end'; } if (year == -1) { year = this.today().getFullYear(); } else if (year < 100 && shortYear) { year += (shortYearCutoff == -1 ? 1900 : this.today().getFullYear() - this.today().getFullYear() % 100 - (year <= shortYearCutoff ? 0 : 100)); } if (doy > -1) { month = 1; day = doy; for (var dim = this.daysInMonth(year, month); day > dim; dim = this.daysInMonth(year, month)) { month++; day -= dim; } } var date = this.newDate(year, month, day); if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) { throw 'Invalid date'; } return date; }, /* A date may be specified as an exact value or a relative one. @param dateSpec (Date or number or string) the date as an object or string in the given format or an offset - numeric days from today, or string amounts and periods, e.g. '+1m +2w' @param defaultDate (Date) the date to use if no other supplied, may be null @param currentDate (Date) the current date as a possible basis for relative dates, if null today is used (optional) @param dateFormat (string) the expected date format - see formatDate above (optional) @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 decoded date */ determineDate: function(dateSpec, defaultDate, currentDate, dateFormat, settings) { if (currentDate && typeof currentDate != 'object') { settings = dateFormat; dateFormat = currentDate; currentDate = null; } if (typeof dateFormat != 'string') { settings = dateFormat; dateFormat = ''; } var offsetString = function(offset) { try { return plugin.parseDate(dateFormat, offset, settings); } catch (e) { // Ignore } offset = offset.toLowerCase(); var date = (offset.match(/^c/) && currentDate ? plugin.newDate(currentDate) : null) || plugin.today(); var pattern = /([+-]?[0-9]+)\s*(d|w|m|y)?/g; var matches = null; while (matches = pattern.exec(offset)) { date = plugin.add(date, parseInt(matches[1], 10), matches[2] || 'd'); } return date; }; defaultDate = (defaultDate ? plugin.newDate(defaultDate) : null); dateSpec = (dateSpec == null ? defaultDate : (typeof dateSpec == 'string' ? offsetString(dateSpec) : (typeof dateSpec == 'number' ? (isNaN(dateSpec) || dateSpec == Infinity || dateSpec == -Infinity ? defaultDate : plugin.add(plugin.today(), dateSpec, 'd')) : plugin.newDate(dateSpec)))); return dateSpec; }, /* Find the number of days in a given month. @param year (Date) the date to get days for or (number) the full year @param month (number) the month (1 to 12) @return (number) the number of days in this month */ daysInMonth: function(year, month) { month = (year.getFullYear ? year.getMonth() + 1 : month); year = (year.getFullYear ? year.getFullYear() : year); return this.newDate(year, month + 1, 0).getDate(); }, /* Calculate the day of the year for a date. @param year (Date) the date to get the day-of-year for or (number) the full year @param month (number) the month (1-12) @param day (number) the day @return (number) the day of the year */ dayOfYear: function(year, month, day) { var date = (year.getFullYear ? year : this.newDate(year, month, day)); var newYear = this.newDate(date.getFullYear(), 1, 1); return Math.floor((date.getTime() - newYear.getTime()) / this._msPerDay) + 1; }, /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. @param year (Date) the date to get the week for or (number) the full year @param month (number) the month (1-12) @param day (number) the day @return (number) the number of the week within the year that contains this date */ iso8601Week: function(year, month, day) { var checkDate = (year.getFullYear ? new Date(year.getTime()) : this.newDate(year, month, day)); // Find Thursday of this week starting on Monday checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); var time = checkDate.getTime(); checkDate.setMonth(0, 1); // Compare with Jan 1 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; }, /* Return today's date. @return (Date) today */ today: function() { return this._normaliseDate(new Date()); }, /* Return a new date. @param year (Date) the date to clone or (number) the year @param month (number) the month (1-12) @param day (number) the day @return (Date) the date */ newDate: function(year, month, day) { return (!year ? null : (year.getFullYear ? this._normaliseDate(new Date(year.getTime())) : new Date(year, month - 1, day, 12))); }, /* Standardise a date into a common format - time portion is 12 noon. @param date (Date) the date to standardise @return (Date) the normalised date */ _normaliseDate: function(date) { if (date) { date.setHours(12, 0, 0, 0); } return date; }, /* Set the year for a date. @param date (Date) the original date @param year (number) the new year @return the updated date */ year: function(date, year) { date.setFullYear(year); return this._normaliseDate(date); }, /* Set the month for a date. @param date (Date) the original date @param month (number) the new month (1-12) @return the updated date */ month: function(date, month) { date.setMonth(month - 1); return this._normaliseDate(date); }, /* Set the day for a date. @param date (Date) the original date @param day (number) the new day of the month @return the updated date */ day: function(date, day) { date.setDate(day); return this._normaliseDate(date); }, /* Add a number of periods to a date. @param date (Date) the original date @param amount (number) the number of periods @param period (string) the type of period d/w/m/y @return the updated date */ add: function(date, amount, period) { if (period == 'd' || period == 'w') { this._normaliseDate(date); date.setDate(date.getDate() + amount * (period == 'w' ? 7 : 1)); } else { var year = date.getFullYear() + (period == 'y' ? amount : 0); var month = date.getMonth() + (period == 'm' ? amount : 0); date.setTime(plugin.newDate(year, month + 1, Math.min(date.getDate(), this.daysInMonth(year, month + 1))).getTime()); } return date; }, /* Apply the months offset value to a date. @param date (Date) the original date @param inst (object) the current instance settings @return (Date) the updated date */ _applyMonthsOffset: function(date, inst) { var monthsOffset = inst.options.monthsOffset; if ($.isFunction(monthsOffset)) { monthsOffset = monthsOffset.apply(inst.target[0], [date]); } return plugin.add(date, -monthsOffset, 'm'); }, /* Attach the datepicker functionality to an input field. @param target (element) the control to affect @param options (object) the custom options for this instance */ _attachPlugin: function(target, options) { target = $(target); if (target.hasClass(this.markerClassName)) { return; } var inlineSettings = ($.fn.metadata ? target.metadata() : {}); var inst = {options: $.extend({}, this._defaults, inlineSettings, options), target: target, selectedDates: [], drawDate: null, pickingRange: false, inline: ($.inArray(target[0].nodeName.toLowerCase(), ['div', 'span']) > -1), get: function(name) { // Get a setting value, computing if necessary if ($.inArray(name, ['defaultDate', 'minDate', 'maxDate']) > -1) { // Decode date settings return plugin.determineDate(this.options[name], null, this.selectedDates[0], this.options.dateFormat, inst.getConfig()); } return this.options[name]; }, curMinDate: function() { return (this.pickingRange ? this.selectedDates[0] : this.get('minDate')); }, getConfig: function() { return {dayNamesShort: this.options.dayNamesShort, dayNames: this.options.dayNames, monthNamesShort: this.options.monthNamesShort, monthNames: this.options.monthNames, calculateWeek: this.options.calculateWeek, shortYearCutoff: this.options.shortYearCutoff}; } }; target.addClass(this.markerClassName).data(this.propertyName, inst); if (inst.inline) { inst.drawDate = plugin._checkMinMax(plugin.newDate(inst.selectedDates[0] || inst.get('defaultDate') || plugin.today()), inst); inst.prevDate = plugin.newDate(inst.drawDate); this._update(target[0]); if ($.fn.mousewheel) { target.mousewheel(this._doMouseWheel); } } else { this._attachments(target, inst); target.bind('keydown.' + this.propertyName, this._keyDown). bind('keypress.' + this.propertyName, this._keyPress). bind('keyup.' + this.propertyName, this._keyUp); if (target.attr('disabled')) { this._disablePlugin(target[0]); } } }, /* Retrieve or reconfigure the settings for a control. @param target (element) the control to affect @param options (object) the new options for this instance or (string) an individual property name @param value (any) the individual property value (omit if options is an object or to retrieve the value of a setting) @return (any) if retrieving a value */ _optionPlugin: function(target, options, value) { target = $(target); var inst = target.data(this.propertyName); if (!options || (typeof options == 'string' && value == null)) { // Get option var name = options; options = (inst || {}).options; return (options && name ? options[name] : options); } if (!target.hasClass(this.markerClassName)) { return; } options = options || {}; if (typeof options == 'string') { var name = options; options = {}; options[name] = value; } if (options.calendar && options.calendar != inst.options.calendar) { var discardDate = function(name) { return (typeof inst.options[name] == 'object' ? null : inst.options[name]); }; options = $.extend({defaultDate: discardDate('defaultDate'), minDate: discardDate('minDate'), maxDate: discardDate('maxDate')}, options); inst.selectedDates = []; inst.drawDate = null; } var dates = inst.selectedDates; $.extend(inst.options, options); this._setDatePlugin(target[0], dates, null, false, true); inst.pickingRange = false; inst.drawDate = plugin.newDate(this._checkMinMax( (inst.options.defaultDate ? inst.get('defaultDate') : inst.drawDate) || inst.get('defaultDate') || plugin.today(), inst)); if (!inst.inline) { this._attachments(target, inst); } if (inst.inline || inst.div) { this._update(target[0]); } }, /* Attach events and trigger, if necessary. @param target (jQuery) the control to affect @param inst (object) the current instance settings */ _attachments: function(target, inst) { target.unbind('focus.' + this.propertyName); if (inst.options.showOnFocus) { target.bind('focus.' + this.propertyName, this._showPlugin); } if (inst.trigger) { inst.trigger.remove(); } var trigger = inst.options.showTrigger; inst.trigger = (!trigger ? $([]) : $(trigger).clone().removeAttr('id').addClass(this._triggerClass) [inst.options.isRTL ? 'insertBefore' : 'insertAfter'](target). click(function() { if (!plugin._isDisabledPlugin(target[0])) { plugin[plugin.curInst == inst ? '_hidePlugin' : '_showPlugin'](target[0]); } })); this._autoSize(target, inst); var dates = this._extractDates(inst, target.val()); if (dates) { this._setDatePlugin(target[0], dates, null, true); } var defaultDate = inst.get('defaultDate'); if (inst.options.selectDefaultDate && defaultDate && inst.selectedDates.length == 0) { this._setDatePlugin(target[0], plugin.newDate(defaultDate || plugin.today())); } }, /* Apply the maximum length for the date format. @param inst (object) the current instance settings */ _autoSize: function(target, inst) { if (inst.options.autoSize && !inst.inline) { var date = plugin.newDate(2009, 10, 20); // Ensure double digits var dateFormat = inst.options.dateFormat; if (dateFormat.match(/[DM]/)) { var findMax = function(names) { var max = 0; var maxI = 0; for (var i = 0; i < names.length; i++) { if (names[i].length > max) { max = names[i].length; maxI = i; } } return maxI; }; date.setMonth(findMax(inst.options[dateFormat.match(/MM/) ? // Longest month 'monthNames' : 'monthNamesShort'])); date.setDate(findMax(inst.options[dateFormat.match(/DD/) ? // Longest day 'dayNames' : 'dayNamesShort']) + 20 - date.getDay()); } inst.target.attr('size', plugin.formatDate(dateFormat, date, inst.getConfig()).length); } }, /* Remove the datepicker functionality from a control. @param target (element) the control to affect */ _destroyPlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var inst = target.data(this.propertyName); if (inst.trigger) { inst.trigger.remove(); } target.removeClass(this.markerClassName).removeData(this.propertyName). empty().unbind('.' + this.propertyName); if (inst.inline && $.fn.mousewheel) { target.unmousewheel(); } if (!inst.inline && inst.options.autoSize) { target.removeAttr('size'); } }, /* Apply multiple event functions. Usage, for example: onShow: multipleEvents(fn1, fn2, ...) @param fns (function...) the functions to apply */ multipleEvents: function(fns) { var funcs = arguments; return function(args) { for (var i = 0; i < funcs.length; i++) { funcs[i].apply(this, arguments); } }; }, /* Enable the control. @param target (element) the control to affect */ _enablePlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var inst = target.data(this.propertyName); if (inst.inline) { target.children('.' + this._disableClass).remove().end(). find('button,select').removeAttr('disabled').end(). find('a').attr('href', 'javascript:void(0)'); } else { target.prop('disabled', false); inst.trigger.filter('button.' + this._triggerClass). removeAttr('disabled').end(). filter('img.' + this._triggerClass). css({opacity: '1.0', cursor: ''}); } this._disabled = $.map(this._disabled, function(value) { return (value == target[0] ? null : value); }); // Delete entry }, /* Disable the control. @param target (element) the control to affect */ _disablePlugin: function(target) { target = $(target); if (!target.hasClass(this.markerClassName)) { return; } var inst = target.data(this.propertyName); if (inst.inline) { var inline = target.children(':last'); var offset = inline.offset(); var relOffset = {left: 0, top: 0}; inline.parents().each(function() { if ($(this).css('position') == 'relative') { relOffset = $(this).offset(); return false; } }); var zIndex = target.css('zIndex'); zIndex = (zIndex == 'auto' ? 0 : parseInt(zIndex, 10)) + 1; target.prepend('
'). find('button,select').attr('disabled', 'disabled').end(). find('a').removeAttr('href'); } else { target.prop('disabled', true); inst.trigger.filter('button.' + this._triggerClass). attr('disabled', 'disabled').end(). filter('img.' + this._triggerClass). css({opacity: '0.5', cursor: 'default'}); } this._disabled = $.map(this._disabled, function(value) { return (value == target[0] ? null : value); }); // Delete entry this._disabled.push(target[0]); }, /* Is the first field in a jQuery collection disabled as a datepicker? @param target (element) the control to examine @return (boolean) true if disabled, false if enabled */ _isDisabledPlugin: function(target) { return (target && $.inArray(target, this._disabled) > -1); }, /* Show a popup datepicker. @param target (event) a focus event or (element) the control to use */ _showPlugin: function(target) { target = $(target.target || target); var inst = target.data(plugin.propertyName); if (plugin.curInst == inst) { return; } if (plugin.curInst) { plugin._hidePlugin(plugin.curInst, true); } if (inst) { // Retrieve existing date(s) inst.lastVal = null; inst.selectedDates = plugin._extractDates(inst, target.val()); inst.pickingRange = false; inst.drawDate = plugin._checkMinMax(plugin.newDate(inst.selectedDates[0] || inst.get('defaultDate') || plugin.today()), inst); inst.prevDate = plugin.newDate(inst.drawDate); plugin.curInst = inst; // Generate content plugin._update(target[0], true); // Adjust position before showing var offset = plugin._checkOffset(inst); inst.div.css({left: offset.left, top: offset.top}); // And display var showAnim = inst.options.showAnim; var showSpeed = inst.options.showSpeed; showSpeed = (showSpeed == 'normal' && $.ui && $.ui.version >= '1.8' ? '_default' : showSpeed); if ($.effects && $.effects[showAnim]) { var data = inst.div.data(); // Update old effects data for (var key in data) { if (key.match(/^ec\.storage\./)) { data[key] = inst._mainDiv.css(key.replace(/ec\.storage\./, '')); } } inst.div.data(data).show(showAnim, inst.options.showOptions, showSpeed); } else { inst.div[showAnim || 'show']((showAnim ? showSpeed : '')); } } }, /* Extract possible dates from a string. @param inst (object) the current instance settings @param text (string) the text to extract from @return (CDate[]) the extracted dates */ _extractDates: function(inst, datesText) { if (datesText == inst.lastVal) { return; } inst.lastVal = datesText; datesText = datesText.split(inst.options.multiSelect ? inst.options.multiSeparator : (inst.options.rangeSelect ? inst.options.rangeSeparator : '\x00')); var dates = []; for (var i = 0; i < datesText.length; i++) { try { var date = plugin.parseDate(inst.options.dateFormat, datesText[i], inst.getConfig()); if (date) { var found = false; for (var j = 0; j < dates.length; j++) { if (dates[j].getTime() == date.getTime()) { found = true; break; } } if (!found) { dates.push(date); } } } catch (e) { // Ignore } } dates.splice(inst.options.multiSelect || (inst.options.rangeSelect ? 2 : 1), dates.length); if (inst.options.rangeSelect && dates.length == 1) { dates[1] = dates[0]; } return dates; }, /* Update the datepicker display. @param target (event) a focus event or (element) the control to use @param hidden (boolean) true to initially hide the datepicker */ _update: function(target, hidden) { target = $(target.target || target); var inst = target.data(plugin.propertyName); if (inst) { if (inst.inline || plugin.curInst == inst) { if ($.isFunction(inst.options.onChangeMonthYear) && (!inst.prevDate || inst.prevDate.getFullYear() != inst.drawDate.getFullYear() || inst.prevDate.getMonth() != inst.drawDate.getMonth())) { inst.options.onChangeMonthYear.apply(target[0], [inst.drawDate.getFullYear(), inst.drawDate.getMonth() + 1]); } } if (inst.inline) { target.html(this._generateContent(target[0], inst)); } else if (plugin.curInst == inst) { if (!inst.div) { inst.div = $('
').addClass(this._popupClass). css({display: (hidden ? 'none' : 'static'), position: 'absolute', left: target.offset().left, top: target.offset().top + target.outerHeight()}). appendTo($(inst.options.popupContainer || 'body')); if ($.fn.mousewheel) { inst.div.mousewheel(this._doMouseWheel); } } inst.div.html(this._generateContent(target[0], inst)); target.focus(); } } }, /* Update the input field and any alternate field with the current dates. @param target (element) the control to use @param keyUp (boolean, internal) true if coming from keyUp processing */ _updateInput: function(target, keyUp) { var inst = $.data(target, this.propertyName); if (inst) { var value = ''; var altValue = ''; var sep = (inst.options.multiSelect ? inst.options.multiSeparator : inst.options.rangeSeparator); var altFormat = inst.options.altFormat || inst.options.dateFormat; for (var i = 0; i < inst.selectedDates.length; i++) { value += (keyUp ? '' : (i > 0 ? sep : '') + plugin.formatDate( inst.options.dateFormat, inst.selectedDates[i], inst.getConfig())); altValue += (i > 0 ? sep : '') + plugin.formatDate( altFormat, inst.selectedDates[i], inst.getConfig()); } if (!inst.inline && !keyUp) { $(target).val(value); } $(inst.options.altField).val(altValue); if ($.isFunction(inst.options.onSelect) && !keyUp && !inst.inSelect) { inst.inSelect = true; // Prevent endless loops inst.options.onSelect.apply(target, [inst.selectedDates]); inst.inSelect = false; } } }, /* Retrieve the size of left and top borders for an element. @param elem (jQuery) the element of interest @return (number[2]) the left and top borders */ _getBorders: function(elem) { var convert = function(value) { return {thin: 1, medium: 3, thick: 5}[value] || value; }; return [parseFloat(convert(elem.css('border-left-width'))), parseFloat(convert(elem.css('border-top-width')))]; }, /* Check positioning to remain on the screen. @param inst (object) the current instance settings @return (object) the updated offset for the datepicker */ _checkOffset: function(inst) { var base = (inst.target.is(':hidden') && inst.trigger ? inst.trigger : inst.target); var offset = base.offset(); var browserWidth = $(window).width(); var browserHeight = $(window).height(); if (browserWidth == 0) { return offset; } var isFixed = false; $(inst.target).parents().each(function() { isFixed |= $(this).css('position') == 'fixed'; return !isFixed; }); var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollY = document.documentElement.scrollTop || document.body.scrollTop; var above = offset.top - (isFixed ? scrollY : 0) - inst.div.outerHeight(); var below = offset.top - (isFixed ? scrollY : 0) + base.outerHeight(); var alignL = offset.left - (isFixed ? scrollX : 0); var alignR = offset.left - (isFixed ? scrollX : 0) + base.outerWidth() - inst.div.outerWidth(); var tooWide = (offset.left - scrollX + inst.div.outerWidth()) > browserWidth; var tooHigh = (offset.top - scrollY + inst.target.outerHeight() + inst.div.outerHeight()) > browserHeight; inst.div.css('position', isFixed ? 'fixed' : 'absolute'); var alignment = inst.options.alignment; if (alignment == 'topLeft') { offset = {left: alignL, top: above}; } else if (alignment == 'topRight') { offset = {left: alignR, top: above}; } else if (alignment == 'bottomLeft') { offset = {left: alignL, top: below}; } else if (alignment == 'bottomRight') { offset = {left: alignR, top: below}; } else if (alignment == 'top') { offset = {left: (inst.options.isRTL || tooWide ? alignR : alignL), top: above}; } else { // bottom offset = {left: (inst.options.isRTL || tooWide ? alignR : alignL), top: (tooHigh ? above : below)}; } offset.left = Math.max((isFixed ? 0 : scrollX), offset.left); offset.top = Math.max((isFixed ? 0 : scrollY), offset.top); return offset; }, /* Close date picker if clicked elsewhere. @param event (MouseEvent) the mouse click to check */ _checkExternalClick: function(event) { if (!plugin.curInst) { return; } var target = $(event.target); if (!target.parents().andSelf().hasClass(plugin._popupClass) && !target.hasClass(plugin.markerClassName) && !target.parents().andSelf().hasClass(plugin._triggerClass)) { plugin._hidePlugin(plugin.curInst); } }, /* Hide a popup datepicker. @param target (element) the control to use or (object) the current instance settings @param immediate (boolean) true to close immediately without animation */ _hidePlugin: function(target, immediate) { if (!target) { return; } var inst = $.data(target, this.propertyName) || target; if (inst && inst == plugin.curInst) { var showAnim = (immediate ? '' : inst.options.showAnim); var showSpeed = inst.options.showSpeed; showSpeed = (showSpeed == 'normal' && $.ui && $.ui.version >= '1.8' ? '_default' : showSpeed); var postProcess = function() { if (!inst.div) { return; } inst.div.remove(); inst.div = null; plugin.curInst = null; if ($.isFunction(inst.options.onClose)) { inst.options.onClose.apply(target, [inst.selectedDates]); } }; inst.div.stop(); if ($.effects && $.effects[showAnim]) { inst.div.hide(showAnim, inst.options.showOptions, showSpeed, postProcess); } else { var hideAnim = (showAnim == 'slideDown' ? 'slideUp' : (showAnim == 'fadeIn' ? 'fadeOut' : 'hide')); inst.div[hideAnim]((showAnim ? showSpeed : ''), postProcess); } if (!showAnim) { postProcess(); } } }, /* Handle keystrokes in the datepicker. @param event (KeyEvent) the keystroke @return (boolean) true if not handled, false if handled */ _keyDown: function(event) { var target = event.target; var inst = $.data(target, plugin.propertyName); var handled = false; if (inst.div) { if (event.keyCode == 9) { // Tab - close plugin._hidePlugin(target); } else if (event.keyCode == 13) { // Enter - select plugin._selectDatePlugin(target, $('a.' + inst.options.renderer.highlightedClass, inst.div)[0]); handled = true; } else { // Command keystrokes var commands = inst.options.commands; for (var name in commands) { var command = commands[name]; if (command.keystroke.keyCode == event.keyCode && !!command.keystroke.ctrlKey == !!(event.ctrlKey || event.metaKey) && !!command.keystroke.altKey == event.altKey && !!command.keystroke.shiftKey == event.shiftKey) { plugin._performActionPlugin(target, name); handled = true; break; } } } } else { // Show on 'current' keystroke var command = inst.options.commands.current; if (command.keystroke.keyCode == event.keyCode && !!command.keystroke.ctrlKey == !!(event.ctrlKey || event.metaKey) && !!command.keystroke.altKey == event.altKey && !!command.keystroke.shiftKey == event.shiftKey) { plugin._showPlugin(target); handled = true; } } inst.ctrlKey = ((event.keyCode < 48 && event.keyCode != 32) || event.ctrlKey || event.metaKey); if (handled) { event.preventDefault(); event.stopPropagation(); } return !handled; }, /* Filter keystrokes in the datepicker. @param event (KeyEvent) the keystroke @return (boolean) true if allowed, false if not allowed */ _keyPress: function(event) { var inst = $.data(event.target, plugin.propertyName); if (inst && inst.options.constrainInput) { var ch = String.fromCharCode(event.keyCode || event.charCode); var allowedChars = plugin._allowedChars(inst); return (event.metaKey || inst.ctrlKey || ch < ' ' || !allowedChars || allowedChars.indexOf(ch) > -1); } return true; }, /* Determine the set of characters allowed by the date format. @param inst (object) the current instance settings @return (string) the set of allowed characters, or null if anything allowed */ _allowedChars: function(inst) { var allowedChars = (inst.options.multiSelect ? inst.options.multiSeparator : (inst.options.rangeSelect ? inst.options.rangeSeparator : '')); var literal = false; var hasNum = false; var dateFormat = inst.options.dateFormat; for (var i = 0; i < dateFormat.length; i++) { var ch = dateFormat.charAt(i); if (literal) { if (ch == "'" && dateFormat.charAt(i + 1) != "'") { literal = false; } else { allowedChars += ch; } } else { switch (ch) { case 'd': case 'm': case 'o': case 'w': allowedChars += (hasNum ? '' : '0123456789'); hasNum = true; break; case 'y': case '@': case '!': allowedChars += (hasNum ? '' : '0123456789') + '-'; hasNum = true; break; case 'J': allowedChars += (hasNum ? '' : '0123456789') + '-.'; hasNum = true; break; case 'D': case 'M': case 'Y': return null; // Accept anything case "'": if (dateFormat.charAt(i + 1) == "'") { allowedChars += "'"; } else { literal = true; } break; default: allowedChars += ch; } } } return allowedChars; }, /* Synchronise datepicker with the field. @param event (KeyEvent) the keystroke @return (boolean) true if allowed, false if not allowed */ _keyUp: function(event) { var target = event.target; var inst = $.data(target, plugin.propertyName); if (inst && !inst.ctrlKey && inst.lastVal != inst.target.val()) { try { var dates = plugin._extractDates(inst, inst.target.val()); if (dates.length > 0) { plugin._setDatePlugin(target, dates, null, true); } } catch (event) { // Ignore } } return true; }, /* Increment/decrement month/year on mouse wheel activity. @param event (event) the mouse wheel event @param delta (number) the amount of change */ _doMouseWheel: function(event, delta) { var target = (plugin.curInst && plugin.curInst.target[0]) || $(event.target).closest('.' + plugin.markerClassName)[0]; if (plugin._isDisabledPlugin(target)) { return; } var inst = $.data(target, plugin.propertyName); if (inst.options.useMouseWheel) { delta = (delta < 0 ? -1 : +1); plugin._changeMonthPlugin(target, -inst.options[event.ctrlKey ? 'monthsToJump' : 'monthsToStep'] * delta); } event.preventDefault(); }, /* Clear an input and close a popup datepicker. @param target (element) the control to use */ _clearPlugin: function(target) { var inst = $.data(target, this.propertyName); if (inst) { inst.selectedDates = []; this._hidePlugin(target); var defaultDate = inst.get('defaultDate'); if (inst.options.selectDefaultDate && defaultDate) { this._setDatePlugin(target, plugin.newDate(defaultDate || plugin.today())); } else { this._updateInput(target); } } }, /* Retrieve the selected date(s) for a datepicker. @param target (element) the control to examine @return (CDate[]) the selected date(s) */ _getDatePlugin: function(target) { var inst = $.data(target, this.propertyName); return (inst ? inst.selectedDates : []); }, /* Set the selected date(s) for a datepicker. @param target (element) the control to examine @param dates (CDate or number or string or [] of these) the selected date(s) @param endDate (CDate or number or string) the ending date for a range (optional) @param keyUp (boolean, internal) true if coming from keyUp processing @param setOpt (boolean, internal) true if coming from option processing */ _setDatePlugin: function(target, dates, endDate, keyUp, setOpt) { var inst = $.data(target, this.propertyName); if (inst) { if (!$.isArray(dates)) { dates = [dates]; if (endDate) { dates.push(endDate); } } var minDate = inst.get('minDate'); var maxDate = inst.get('maxDate'); var curDate = inst.selectedDates[0]; inst.selectedDates = []; for (var i = 0; i < dates.length; i++) { var date = plugin.determineDate( dates[i], null, curDate, inst.options.dateFormat, inst.getConfig()); if (date) { if ((!minDate || date.getTime() >= minDate.getTime()) && (!maxDate || date.getTime() <= maxDate.getTime())) { var found = false; for (var j = 0; j < inst.selectedDates.length; j++) { if (inst.selectedDates[j].getTime() == date.getTime()) { found = true; break; } } if (!found) { inst.selectedDates.push(date); } } } } inst.selectedDates.splice(inst.options.multiSelect || (inst.options.rangeSelect ? 2 : 1), inst.selectedDates.length); if (inst.options.rangeSelect) { switch (inst.selectedDates.length) { case 1: inst.selectedDates[1] = inst.selectedDates[0]; break; case 2: inst.selectedDates[1] = (inst.selectedDates[0].getTime() > inst.selectedDates[1].getTime() ? inst.selectedDates[0] : inst.selectedDates[1]); break; } inst.pickingRange = false; } inst.prevDate = (inst.drawDate ? plugin.newDate(inst.drawDate) : null); inst.drawDate = this._checkMinMax(plugin.newDate(inst.selectedDates[0] || inst.get('defaultDate') || plugin.today()), inst); if (!setOpt) { this._update(target); this._updateInput(target, keyUp); } } }, /* Determine whether a date is selectable for this datepicker. @param target (element) the control to check @param date (Date or string or number) the date to check @return (boolean) true if selectable, false if not */ _isSelectablePlugin: function(target, date) { var inst = $.data(target, this.propertyName); if (!inst) { return false; } date = plugin.determineDate(date, inst.selectedDates[0] || this.today(), null, inst.options.dateFormat, inst.getConfig()); return this._isSelectable(target, date, inst.options.onDate, inst.get('minDate'), inst.get('maxDate')); }, /* Internally determine whether a date is selectable for this datepicker. @param target (element) the control to check @param date (Date) the date to check @param onDate (function or boolean) any onDate callback or callback.selectable @param mindate (Date) the minimum allowed date @param maxdate (Date) the maximum allowed date @return (boolean) true if selectable, false if not */ _isSelectable: function(target, date, onDate, minDate, maxDate) { var dateInfo = (typeof onDate == 'boolean' ? {selectable: onDate} : (!$.isFunction(onDate) ? {} : onDate.apply(target, [date, true]))); return (dateInfo.selectable != false) && (!minDate || date.getTime() >= minDate.getTime()) && (!maxDate || date.getTime() <= maxDate.getTime()); }, /* Perform a named action for a datepicker. @param target (element) the control to affect @param action (string) the name of the action */ _performActionPlugin: function(target, action) { var inst = $.data(target, this.propertyName); if (inst && !this._isDisabledPlugin(target)) { var commands = inst.options.commands; if (commands[action] && commands[action].enabled.apply(target, [inst])) { commands[action].action.apply(target, [inst]); } } }, /* Set the currently shown month, defaulting to today's. @param target (element) the control to affect @param year (number) the year to show (optional) @param month (number) the month to show (1-12) (optional) @param day (number) the day to show (optional) */ _showMonthPlugin: function(target, year, month, day) { var inst = $.data(target, this.propertyName); if (inst && (day != null || (inst.drawDate.getFullYear() != year || inst.drawDate.getMonth() + 1 != month))) { inst.prevDate = plugin.newDate(inst.drawDate); var show = this._checkMinMax((year != null ? plugin.newDate(year, month, 1) : plugin.today()), inst); inst.drawDate = plugin.newDate(show.getFullYear(), show.getMonth() + 1, (day != null ? day : Math.min(inst.drawDate.getDate(), plugin.daysInMonth(show.getFullYear(), show.getMonth() + 1)))); this._update(target); } }, /* Adjust the currently shown month. @param target (element) the control to affect @param offset (number) the number of months to change by */ _changeMonthPlugin: function(target, offset) { var inst = $.data(target, this.propertyName); if (inst) { var date = plugin.add(plugin.newDate(inst.drawDate), offset, 'm'); this._showMonthPlugin(target, date.getFullYear(), date.getMonth() + 1); } }, /* Adjust the currently shown day. @param target (element) the control to affect @param offset (number) the number of days to change by */ _changeDayPlugin: function(target, offset) { var inst = $.data(target, this.propertyName); if (inst) { var date = plugin.add(plugin.newDate(inst.drawDate), offset, 'd'); this._showMonthPlugin(target, date.getFullYear(), date.getMonth() + 1, date.getDate()); } }, /* Restrict a date to the minimum/maximum specified. @param date (CDate) the date to check @param inst (object) the current instance settings */ _checkMinMax: function(date, inst) { var minDate = inst.get('minDate'); var maxDate = inst.get('maxDate'); date = (minDate && date.getTime() < minDate.getTime() ? plugin.newDate(minDate) : date); date = (maxDate && date.getTime() > maxDate.getTime() ? plugin.newDate(maxDate) : date); return date; }, /* Retrieve the date associated with an entry in the datepicker. @param target (element) the control to examine @param elem (element) the selected datepicker element @return (CDate) the corresponding date, or null */ _retrieveDatePlugin: function(target, elem) { var inst = $.data(target, this.propertyName); return (!inst ? null : this._normaliseDate( new Date(parseInt(elem.className.replace(/^.*dp(-?\d+).*$/, '$1'), 10)))); }, /* Select a date for this datepicker. @param target (element) the control to examine @param elem (element) the selected datepicker element */ _selectDatePlugin: function(target, elem) { var inst = $.data(target, this.propertyName); if (inst && !this._isDisabledPlugin(target)) { var date = this._retrieveDatePlugin(target, elem); if (inst.options.multiSelect) { var found = false; for (var i = 0; i < inst.selectedDates.length; i++) { if (date.getTime() == inst.selectedDates[i].getTime()) { inst.selectedDates.splice(i, 1); found = true; break; } } if (!found && inst.selectedDates.length < inst.options.multiSelect) { inst.selectedDates.push(date); } } else if (inst.options.rangeSelect) { if (inst.pickingRange) { inst.selectedDates[1] = date; } else { inst.selectedDates = [date, date]; } inst.pickingRange = !inst.pickingRange; } else { inst.selectedDates = [date]; } inst.prevDate = plugin.newDate(date); this._updateInput(target); if (inst.inline || inst.pickingRange || inst.selectedDates.length < (inst.options.multiSelect || (inst.options.rangeSelect ? 2 : 1))) { this._update(target); } else { this._hidePlugin(target); } } }, /* Generate the datepicker content for this control. @param target (element) the control to affect @param inst (object) the current instance settings @return (jQuery) the datepicker content */ _generateContent: function(target, inst) { var monthsToShow = inst.options.monthsToShow; monthsToShow = ($.isArray(monthsToShow) ? monthsToShow : [1, monthsToShow]); inst.drawDate = this._checkMinMax( inst.drawDate || inst.get('defaultDate') || plugin.today(), inst); var drawDate = plugin._applyMonthsOffset(plugin.newDate(inst.drawDate), inst); // Generate months var monthRows = ''; for (var row = 0; row < monthsToShow[0]; row++) { var months = ''; for (var col = 0; col < monthsToShow[1]; col++) { months += this._generateMonth(target, inst, drawDate.getFullYear(), drawDate.getMonth() + 1, inst.options.renderer, (row == 0 && col == 0)); plugin.add(drawDate, 1, 'm'); } monthRows += this._prepare(inst.options.renderer.monthRow, inst).replace(/\{months\}/, months); } var picker = this._prepare(inst.options.renderer.picker, inst).replace(/\{months\}/, monthRows). replace(/\{weekHeader\}/g, this._generateDayHeaders(inst, inst.options.renderer)); // Add commands var addCommand = function(type, open, close, name, classes) { if (picker.indexOf('{' + type + ':' + name + '}') == -1) { return; } var command = inst.options.commands[name]; var date = (inst.options.commandsAsDateFormat ? command.date.apply(target, [inst]) : null); picker = picker.replace(new RegExp('\\{' + type + ':' + name + '\\}', 'g'), '<' + open + (command.status ? ' title="' + inst.options[command.status] + '"' : '') + ' class="' + inst.options.renderer.commandClass + ' ' + inst.options.renderer.commandClass + '-' + name + ' ' + classes + (command.enabled(inst) ? '' : ' ' + inst.options.renderer.disabledClass) + '">' + (date ? plugin.formatDate(inst.options[command.text], date, inst.getConfig()) : inst.options[command.text]) + ''); }; for (var name in inst.options.commands) { addCommand('button', 'button type="button"', 'button', name, inst.options.renderer.commandButtonClass); addCommand('link', 'a href="javascript:void(0)"', 'a', name, inst.options.renderer.commandLinkClass); } picker = $(picker); if (monthsToShow[1] > 1) { var count = 0; $(inst.options.renderer.monthSelector, picker).each(function() { var nth = ++count % monthsToShow[1]; $(this).addClass(nth == 1 ? 'first' : (nth == 0 ? 'last' : '')); }); } // Add datepicker behaviour var self = this; picker.find(inst.options.renderer.daySelector + ' a').hover( function() { $(this).addClass(inst.options.renderer.highlightedClass); }, function() { (inst.inline ? $(this).parents('.' + self.markerClassName) : inst.div). find(inst.options.renderer.daySelector + ' a'). removeClass(inst.options.renderer.highlightedClass); }). click(function() { self._selectDatePlugin(target, this); }).end(). find('select.' + this._monthYearClass + ':not(.' + this._anyYearClass + ')'). change(function() { var monthYear = $(this).val().split('/'); self._showMonthPlugin(target, parseInt(monthYear[1], 10), parseInt(monthYear[0], 10)); }).end(). find('select.' + this._anyYearClass).click(function() { $(this).css('visibility', 'hidden'). next('input').css({left: this.offsetLeft, top: this.offsetTop, width: this.offsetWidth, height: this.offsetHeight}).show().focus(); }).end(). find('input.' + self._monthYearClass).change(function() { try { var year = parseInt($(this).val(), 10); year = (isNaN(year) ? inst.drawDate.getFullYear() : year); self._showMonthPlugin(target, year, inst.drawDate.getMonth() + 1, inst.drawDate.getDate()); } catch (e) { alert(e); } }).keydown(function(event) { if (event.keyCode == 13) { // Enter $(event.target).change(); } else if (event.keyCode == 27) { // Escape $(event.target).hide().prev('select').css('visibility', 'visible'); inst.target.focus(); } }); // Add command behaviour picker.find('.' + inst.options.renderer.commandClass).click(function() { if (!$(this).hasClass(inst.options.renderer.disabledClass)) { var action = this.className.replace( new RegExp('^.*' + inst.options.renderer.commandClass + '-([^ ]+).*$'), '$1'); plugin._performActionPlugin(target, action); } }); // Add classes if (inst.options.isRTL) { picker.addClass(inst.options.renderer.rtlClass); } if (monthsToShow[0] * monthsToShow[1] > 1) { picker.addClass(inst.options.renderer.multiClass); } if (inst.options.pickerClass) { picker.addClass(inst.options.pickerClass); } // Resize $('body').append(picker); var width = 0; picker.find(inst.options.renderer.monthSelector).each(function() { width += $(this).outerWidth(); }); picker.width(width / monthsToShow[0]); // Pre-show customisation if ($.isFunction(inst.options.onShow)) { inst.options.onShow.apply(target, [picker, inst]); } return picker; }, /* Generate the content for a single month. @param target (element) the control to affect @param inst (object) the current instance settings @param year (number) the year to generate @param month (number) the month to generate @param renderer (object) the rendering templates @param first (boolean) true if first of multiple months @return (string) the month content */ _generateMonth: function(target, inst, year, month, renderer, first) { var daysInMonth = plugin.daysInMonth(year, month); var monthsToShow = inst.options.monthsToShow; monthsToShow = ($.isArray(monthsToShow) ? monthsToShow : [1, monthsToShow]); var fixedWeeks = inst.options.fixedWeeks || (monthsToShow[0] * monthsToShow[1] > 1); var firstDay = inst.options.firstDay; var leadDays = (plugin.newDate(year, month, 1).getDay() - firstDay + 7) % 7; var numWeeks = (fixedWeeks ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); var selectOtherMonths = inst.options.selectOtherMonths && inst.options.showOtherMonths; var minDate = (inst.pickingRange ? inst.selectedDates[0] : inst.get('minDate')); var maxDate = inst.get('maxDate'); var showWeeks = renderer.week.indexOf('{weekOfYear}') > -1; var today = plugin.today(); var drawDate = plugin.newDate(year, month, 1); plugin.add(drawDate, -leadDays - (fixedWeeks && (drawDate.getDay() == firstDay) ? 7 : 0), 'd'); var ts = drawDate.getTime(); // Generate weeks var weeks = ''; for (var week = 0; week < numWeeks; week++) { var weekOfYear = (!showWeeks ? '' : '' + ($.isFunction(inst.options.calculateWeek) ? inst.options.calculateWeek(drawDate) : 0) + ''); var days = ''; for (var day = 0; day < 7; day++) { var selected = false; if (inst.options.rangeSelect && inst.selectedDates.length > 0) { selected = (drawDate.getTime() >= inst.selectedDates[0] && drawDate.getTime() <= inst.selectedDates[1]); } else { for (var i = 0; i < inst.selectedDates.length; i++) { if (inst.selectedDates[i].getTime() == drawDate.getTime()) { selected = true; break; } } } var dateInfo = (!$.isFunction(inst.options.onDate) ? {} : inst.options.onDate.apply(target, [drawDate, drawDate.getMonth() + 1 == month])); var selectable = (selectOtherMonths || drawDate.getMonth() + 1 == month) && this._isSelectable(target, drawDate, dateInfo.selectable, minDate, maxDate); days += this._prepare(renderer.day, inst).replace(/\{day\}/g, (selectable ? '' + (inst.options.showOtherMonths || (drawDate.getMonth() + 1) == month ? dateInfo.content || drawDate.getDate() : ' ') + (selectable ? '' : '')); plugin.add(drawDate, 1, 'd'); ts = drawDate.getTime(); } weeks += this._prepare(renderer.week, inst).replace(/\{days\}/g, days). replace(/\{weekOfYear\}/g, weekOfYear); } var monthHeader = this._prepare(renderer.month, inst).match(/\{monthHeader(:[^\}]+)?\}/); monthHeader = (monthHeader[0].length <= 13 ? 'MM yyyy' : monthHeader[0].substring(13, monthHeader[0].length - 1)); monthHeader = (first ? this._generateMonthSelection( inst, year, month, minDate, maxDate, monthHeader, renderer) : plugin.formatDate(monthHeader, plugin.newDate(year, month, 1), inst.getConfig())); var weekHeader = this._prepare(renderer.weekHeader, inst). replace(/\{days\}/g, this._generateDayHeaders(inst, renderer)); return this._prepare(renderer.month, inst).replace(/\{monthHeader(:[^\}]+)?\}/g, monthHeader). replace(/\{weekHeader\}/g, weekHeader).replace(/\{weeks\}/g, weeks); }, /* Generate the HTML for the day headers. @param inst (object) the current instance settings @param renderer (object) the rendering templates @return (string) a week's worth of day headers */ _generateDayHeaders: function(inst, renderer) { var header = ''; for (var day = 0; day < 7; day++) { var dow = (day + inst.options.firstDay) % 7; header += this._prepare(renderer.dayHeader, inst).replace(/\{day\}/g, '' + inst.options.dayNamesMin[dow] + ''); } return header; }, /* Generate selection controls for month. @param inst (object) the current instance settings @param year (number) the year to generate @param month (number) the month to generate @param minDate (CDate) the minimum date allowed @param maxDate (CDate) the maximum date allowed @param monthHeader (string) the month/year format @return (string) the month selection content */ _generateMonthSelection: function(inst, year, month, minDate, maxDate, monthHeader) { if (!inst.options.changeMonth) { return plugin.formatDate( monthHeader, plugin.newDate(year, month, 1), inst.getConfig()); } // Months var monthNames = inst.options['monthNames' + (monthHeader.match(/mm/i) ? '' : 'Short')]; var html = monthHeader.replace(/m+/i, '\\x2E').replace(/y+/i, '\\x2F'); var selector = ''; html = html.replace(/\\x2E/, selector); // Years var yearRange = inst.options.yearRange; if (yearRange == 'any') { selector = '' + ''; } else { yearRange = yearRange.split(':'); var todayYear = plugin.today().getFullYear(); var start = (yearRange[0].match('c[+-].*') ? year + parseInt(yearRange[0].substring(1), 10) : ((yearRange[0].match('[+-].*') ? todayYear : 0) + parseInt(yearRange[0], 10))); var end = (yearRange[1].match('c[+-].*') ? year + parseInt(yearRange[1].substring(1), 10) : ((yearRange[1].match('[+-].*') ? todayYear : 0) + parseInt(yearRange[1], 10))); selector = ''; } html = html.replace(/\\x2F/, selector); return html; }, /* Prepare a render template for use. Exclude popup/inline sections that are not applicable. Localise text of the form: {l10n:name}. @param text (string) the text to localise @param inst (object) the current instance settings @return (string) the localised text */ _prepare: function(text, inst) { var replaceSection = function(type, retain) { while (true) { var start = text.indexOf('{' + type + ':start}'); if (start == -1) { return; } var end = text.substring(start).indexOf('{' + type + ':end}'); if (end > -1) { text = text.substring(0, start) + (retain ? text.substr(start + type.length + 8, end - type.length - 8) : '') + text.substring(start + end + type.length + 6); } } }; replaceSection('inline', inst.inline); replaceSection('popup', !inst.inline); var pattern = /\{l10n:([^\}]+)\}/; var matches = null; while (matches = pattern.exec(text)) { text = text.replace(matches[0], inst.options[matches[1]]); } return text; } }); // The list of commands that return values and don't permit chaining var getters = ['getDate', 'isDisabled', 'isSelectable', 'retrieveDate']; /* Determine whether a command is a getter and doesn't permit chaining. @param command (string, optional) the command to run @param otherArgs ([], optional) any other arguments for the command @return true if the command is a getter, false if not */ function isNotChained(command, otherArgs) { if (command == 'option' && (otherArgs.length == 0 || (otherArgs.length == 1 && typeof otherArgs[0] == 'string'))) { return true; } return $.inArray(command, getters) > -1; } /* Attach the datepicker functionality to a jQuery selection. @param options (object) the new settings to use for these instances (optional) or (string) the command to run (optional) @return (jQuery) for chaining further calls or (any) getter value */ $.fn.datepick = function(options) { var otherArgs = Array.prototype.slice.call(arguments, 1); if (isNotChained(options, otherArgs)) { return plugin['_' + options + 'Plugin'].apply(plugin, [this[0]].concat(otherArgs)); } return this.each(function() { if (typeof options == 'string') { if (!plugin['_' + options + 'Plugin']) { throw 'Unknown command: ' + options; } plugin['_' + options + 'Plugin'].apply(plugin, [this].concat(otherArgs)); } else { plugin._attachPlugin(this, options || {}); } }); }; /* Initialise the datepicker functionality. */ var plugin = $.datepick = new Datepicker(); // Singleton instance $(function() { $(document).mousedown(plugin._checkExternalClick). resize(function() { plugin._hidePlugin(plugin.curInst); }); }); })(jQuery); /*! jQuery UI - v1.10.3 - 2013-12-17 * http://jqueryui.com * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.sortable.js, jquery.ui.slider.js * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ (function(e,t){function i(t,i){var s,n,r,o=t.nodeName.toLowerCase();return"area"===o?(s=t.parentNode,n=s.name,t.href&&n&&"map"===s.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&a(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&a(t)}function a(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var s=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,a){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),a&&a.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var a,s,n=e(this[0]);n.length&&n[0]!==document;){if(a=n.css("position"),("absolute"===a||"relative"===a||"fixed"===a)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++s)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,a){return!!e.data(t,a[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var a=e.attr(t,"tabindex"),s=isNaN(a);return(s||a>=0)&&i(t,!s)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(i,a){function s(t,i,a,s){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,a&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===a?["Left","Right"]:["Top","Bottom"],r=a.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+a]=function(i){return i===t?o["inner"+a].call(this):this.each(function(){e(this).css(r,s(this,i)+"px")})},e.fn["outer"+a]=function(t,i){return"number"!=typeof t?o["outer"+a].call(this,t):this.each(function(){e(this).css(r,s(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,a){var s,n=e.ui[t].prototype;for(s in a)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([i,a[s]])},call:function(e,t,i){var a,s=e.plugins[t];if(s&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(a=0;s.length>a;a++)e.options[s[a][0]]&&s[a][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var a=i&&"left"===i?"scrollLeft":"scrollTop",s=!1;return t[a]>0?!0:(t[a]=1,s=t[a]>0,t[a]=0,s)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,a=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(n){}a(t)},e.widget=function(i,s,a){var n,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],n=u+"-"+i,a||(a=s,s=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:a.version,_proto:e.extend({},a),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(a,function(i,a){return e.isFunction(a)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,n=this._superApply;return this._super=e,this._superApply=t,i=a.apply(this,arguments),this._super=s,this._superApply=n,i}}(),t):(l[i]=a,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:n}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var a,n,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(a in r[o])n=r[o][a],r[o].hasOwnProperty(a)&&n!==t&&(i[a]=e.isPlainObject(n)?e.isPlainObject(i[a])?e.widget.extend({},i[a],n):e.widget.extend({},n):n);return i},e.widget.bridge=function(i,a){var n=a.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,a=e.data(this,n);return a?e.isFunction(a[r])&&"_"!==r.charAt(0)?(s=a[r].apply(a,h),s!==a&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,n);t?t.option(r||{})._init():e.data(this,n,new a(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var a,n,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},a=i.split("."),i=a.shift(),a.length){for(n=o[i]=e.widget.extend({},this.options[i]),r=0;a.length-1>r;r++)n[a[r]]=n[a[r]]||{},n=n[a[r]];if(i=a.pop(),s===t)return n[i]===t?null:n[i];n[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,a){var n,r=this;"boolean"!=typeof i&&(a=s,s=i,i=!1),a?(s=n=e(s),this.bindings=this.bindings.add(s)):(a=s,s=this.element,n=this.widget()),e.each(a,function(a,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=a.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?n.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var a,n,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],n=i.originalEvent)for(a in n)a in i||(i[a]=n[a]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,a,n){"string"==typeof a&&(a={effect:a});var r,o=a?a===!0||"number"==typeof a?i:a.effect||i:t;a=a||{},"number"==typeof a&&(a={duration:a}),r=!e.isEmptyObject(a),a.complete=n,a.delay&&s.delay(a.delay),r&&e.effects&&e.effects.effect[o]?s[t](a):o!==t&&s[o]?s[o](a.duration,a.easing,n):s.queue(function(i){e(this)[t](),n&&n.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.3",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,a=1===i.which,n="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return a&&!n&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(e,t){function i(e,t,i){return[parseFloat(e[0])*(p.test(e[0])?t/100:1),parseFloat(e[1])*(p.test(e[1])?i/100:1)]}function s(t,i){return parseInt(e.css(t,i),10)||0}function a(t){var i=t[0];return 9===i.nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:e.isWindow(i)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()}}e.ui=e.ui||{};var n,r=Math.max,o=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,c=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=e.fn.position;e.position={scrollbarWidth:function(){if(n!==t)return n;var i,s,a=e("
"),r=a.children()[0];return e("body").append(a),i=r.offsetWidth,a.css("overflow","scroll"),s=r.offsetWidth,i===s&&(s=a[0].clientWidth),a.remove(),n=i-s},getScrollInfo:function(t){var i=t.isWindow?"":t.element.css("overflow-x"),s=t.isWindow?"":t.element.css("overflow-y"),a="scroll"===i||"auto"===i&&t.widths?"left":i>0?"right":"center",vertical:0>n?"top":a>0?"bottom":"middle"};c>p&&p>o(i+s)&&(h.horizontal="center"),d>m&&m>o(a+n)&&(h.vertical="middle"),h.important=r(o(i),o(s))>r(o(a),o(n))?"horizontal":"vertical",t.using.call(this,e,h)}),u.offset(e.extend(M,{using:l}))})},e.ui.position={fit:{left:function(e,t){var i,s=t.within,a=s.isWindow?s.scrollLeft:s.offset.left,n=s.width,o=e.left-t.collisionPosition.marginLeft,h=a-o,l=o+t.collisionWidth-n-a;t.collisionWidth>n?h>0&&0>=l?(i=e.left+h+t.collisionWidth-n-a,e.left+=h-i):e.left=l>0&&0>=h?a:h>l?a+n-t.collisionWidth:a:h>0?e.left+=h:l>0?e.left-=l:e.left=r(e.left-o,e.left)},top:function(e,t){var i,s=t.within,a=s.isWindow?s.scrollTop:s.offset.top,n=t.within.height,o=e.top-t.collisionPosition.marginTop,h=a-o,l=o+t.collisionHeight-n-a;t.collisionHeight>n?h>0&&0>=l?(i=e.top+h+t.collisionHeight-n-a,e.top+=h-i):e.top=l>0&&0>=h?a:h>l?a+n-t.collisionHeight:a:h>0?e.top+=h:l>0?e.top-=l:e.top=r(e.top-o,e.top)}},flip:{left:function(e,t){var i,s,a=t.within,n=a.offset.left+a.scrollLeft,r=a.width,h=a.isWindow?a.scrollLeft:a.offset.left,l=e.left-t.collisionPosition.marginLeft,u=l-h,c=l+t.collisionWidth-r-h,d="left"===t.my[0]?-t.elemWidth:"right"===t.my[0]?t.elemWidth:0,p="left"===t.at[0]?t.targetWidth:"right"===t.at[0]?-t.targetWidth:0,f=-2*t.offset[0];0>u?(i=e.left+d+p+f+t.collisionWidth-r-n,(0>i||o(u)>i)&&(e.left+=d+p+f)):c>0&&(s=e.left-t.collisionPosition.marginLeft+d+p+f-h,(s>0||c>o(s))&&(e.left+=d+p+f))},top:function(e,t){var i,s,a=t.within,n=a.offset.top+a.scrollTop,r=a.height,h=a.isWindow?a.scrollTop:a.offset.top,l=e.top-t.collisionPosition.marginTop,u=l-h,c=l+t.collisionHeight-r-h,d="top"===t.my[1],p=d?-t.elemHeight:"bottom"===t.my[1]?t.elemHeight:0,f="top"===t.at[1]?t.targetHeight:"bottom"===t.at[1]?-t.targetHeight:0,m=-2*t.offset[1];0>u?(s=e.top+p+f+m+t.collisionHeight-r-n,e.top+p+f+m>u&&(0>s||o(u)>s)&&(e.top+=p+f+m)):c>0&&(i=e.top-t.collisionPosition.marginTop+p+f+m-h,e.top+p+f+m>c&&(i>0||c>o(i))&&(e.top+=p+f+m))}},flipfit:{left:function(){e.ui.position.flip.left.apply(this,arguments),e.ui.position.fit.left.apply(this,arguments)},top:function(){e.ui.position.flip.top.apply(this,arguments),e.ui.position.fit.top.apply(this,arguments)}}},function(){var t,i,s,a,n,r=document.getElementsByTagName("body")[0],o=document.createElement("div");t=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&e.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(n in s)t.style[n]=s[n];t.appendChild(o),i=r||document.documentElement,i.insertBefore(t,i.firstChild),o.style.cssText="position: absolute; left: 10.7432222px;",a=e(o).offset().left,e.support.offsetFractions=a>10&&11>a,t.innerHTML="",i.removeChild(t)}()})(jQuery);(function(e){function t(e,t,i){return e>t&&t+i>e}function i(e){return/left|right/.test(e.css("float"))||/inline|table-cell/.test(e.css("display"))}e.widget("ui.sortable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===e.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,i){"disabled"===t?(this.options[t]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,i){var s=null,a=!1,n=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(t),e(t.target).parents().each(function(){return e.data(this,n.widgetName+"-item")===n?(s=e(this),!1):undefined}),e.data(t.target,n.widgetName+"-item")===n&&(s=e(t.target)),s?!this.options.handle||i||(e(this.options.handle,s).find("*").addBack().each(function(){this===t.target&&(a=!0)}),a)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(t,i,s){var a,n,r=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,r.cursorAt&&this._adjustOffsetFromHelper(r.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),r.containment&&this._setContainment(),r.cursor&&"auto"!==r.cursor&&(n=this.document.find("body"),this.storedCursor=n.css("cursor"),n.css("cursor",r.cursor),this.storedStylesheet=e("").appendTo(n)),r.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",r.opacity)),r.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",r.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(a=this.containers.length-1;a>=0;a--)this.containers[a]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!r.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){var i,s,a,n,r=this.options,o=!1;for(this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--)if(s=this.items[i],a=s.item[0],n=this._intersectsWithPointer(s),n&&s.instance===this.currentContainer&&a!==this.currentItem[0]&&this.placeholder[1===n?"next":"prev"]()[0]!==a&&!e.contains(this.placeholder[0],a)&&("semi-dynamic"===this.options.type?!e.contains(this.element[0],a):!0)){if(this.direction=1===n?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,i){if(t){if(e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t),this.options.revert){var s=this,a=this.placeholder.offset(),n=this.options.axis,r={};n&&"x"!==n||(r.left=a.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),n&&"y"!==n||(r.top=a.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,e(this.helper).animate(r,parseInt(this.options.revert,10)||500,function(){s._clear(t)})}else this._clear(t,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},e(i).each(function(){var i=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[\-=_](.+)/);i&&s.push((t.key||i[1]+"[]")+"="+(t.key&&t.expression?i[1]:i[2]))}),!s.length&&t.key&&s.push(t.key+"="),s.join("&")},toArray:function(t){var i=this._getItemsAsjQuery(t&&t.connected),s=[];return t=t||{},i.each(function(){s.push(e(t.item||this).attr(t.attribute||"id")||"")}),s},_intersectsWith:function(e){var t=this.positionAbs.left,i=t+this.helperProportions.width,s=this.positionAbs.top,a=s+this.helperProportions.height,n=e.left,r=n+e.width,o=e.top,h=o+e.height,l=this.offset.click.top,u=this.offset.click.left,c="x"===this.options.axis||s+l>o&&h>s+l,d="y"===this.options.axis||t+u>n&&r>t+u,p=c&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>e[this.floating?"width":"height"]?p:t+this.helperProportions.width/2>n&&r>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>o&&h>a-this.helperProportions.height/2},_intersectsWithPointer:function(e){var i="x"===this.options.axis||t(this.positionAbs.top+this.offset.click.top,e.top,e.height),s="y"===this.options.axis||t(this.positionAbs.left+this.offset.click.left,e.left,e.width),a=i&&s,n=this._getDragVerticalDirection(),r=this._getDragHorizontalDirection();return a?this.floating?r&&"right"===r||"down"===n?2:1:n&&("down"===n?2:1):!1},_intersectsWithSides:function(e){var i=t(this.positionAbs.top+this.offset.click.top,e.top+e.height/2,e.height),s=t(this.positionAbs.left+this.offset.click.left,e.left+e.width/2,e.width),a=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&s||"left"===n&&!s:a&&("down"===a&&i||"up"===a&&!i)},_getDragVerticalDirection:function(){var e=this.positionAbs.top-this.lastPositionAbs.top;return 0!==e&&(e>0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return 0!==e&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor===String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var i,s,a,n,r=[],o=[],h=this._connectWith();if(h&&t)for(i=h.length-1;i>=0;i--)for(a=e(h[i]),s=a.length-1;s>=0;s--)n=e.data(a[s],this.widgetFullName),n&&n!==this&&!n.options.disabled&&o.push([e.isFunction(n.options.items)?n.options.items.call(n.element):e(n.options.items,n.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),n]);for(o.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=o.length-1;i>=0;i--)o[i][0].each(function(){r.push(this)});return e(r)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var i=0;t.length>i;i++)if(t[i]===e.item[0])return!1;return!0})},_refreshItems:function(t){this.items=[],this.containers=[this];var i,s,a,n,r,o,h,l,u=this.items,c=[[e.isFunction(this.options.items)?this.options.items.call(this.element[0],t,{item:this.currentItem}):e(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(a=e(d[i]),s=a.length-1;s>=0;s--)n=e.data(a[s],this.widgetFullName),n&&n!==this&&!n.options.disabled&&(c.push([e.isFunction(n.options.items)?n.options.items.call(n.element[0],t,{item:this.currentItem}):e(n.options.items,n.element),n]),this.containers.push(n));for(i=c.length-1;i>=0;i--)for(r=c[i][1],o=c[i][0],s=0,l=o.length;l>s;s++)h=e(o[s]),h.data(this.widgetName+"-item",r),u.push({item:h,instance:r,width:0,height:0,left:0,top:0})},refreshPositions:function(t){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,a,n;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(a=this.options.toleranceElement?e(this.options.toleranceElement,s.item):s.item,t||(s.width=a.outerWidth(),s.height=a.outerHeight()),n=a.offset(),s.left=n.left,s.top=n.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)n=this.containers[i].element.offset(),this.containers[i].containerCache.left=n.left,this.containers[i].containerCache.top=n.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(t){t=t||this;var i,s=t.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=t.currentItem[0].nodeName.toLowerCase(),a=e("<"+s+">",t.document[0]).addClass(i||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?t.currentItem.children().each(function(){e(" ",t.document[0]).attr("colspan",e(this).attr("colspan")||1).appendTo(a)}):"img"===s&&a.attr("src",t.currentItem.attr("src")),i||a.css("visibility","hidden"),a},update:function(e,a){(!i||s.forcePlaceholderSize)&&(a.height()||a.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),a.width()||a.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10)))}}),t.placeholder=e(s.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),s.placeholder.update(t,t.placeholder)},_contactContainers:function(s){var a,n,r,o,h,l,u,c,d,p,f=null,m=null;for(a=this.containers.length-1;a>=0;a--)if(!e.contains(this.currentItem[0],this.containers[a].element[0]))if(this._intersectsWith(this.containers[a].containerCache)){if(f&&e.contains(this.containers[a].element[0],f.element[0]))continue;f=this.containers[a],m=a}else this.containers[a].containerCache.over&&(this.containers[a]._trigger("out",s,this._uiHash(this)),this.containers[a].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[m].containerCache.over||(this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1);else{for(r=1e4,o=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",u=this.positionAbs[h]+this.offset.click[h],n=this.items.length-1;n>=0;n--)e.contains(this.containers[m].element[0],this.items[n].item[0])&&this.items[n].item[0]!==this.currentItem[0]&&(!p||t(this.positionAbs.top+this.offset.click.top,this.items[n].top,this.items[n].height))&&(c=this.items[n].item.offset()[h],d=!1,Math.abs(c-u)>Math.abs(c+this.items[n][l]-u)&&(d=!0,c+=this.items[n][l]),r>Math.abs(c-u)&&(r=Math.abs(c-u),o=this.items[n],this.direction=d?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[m])return;o?this._rearrange(s,o,null,!0):this._rearrange(s,null,this.containers[m].element,!0),this._trigger("change",s,this._uiHash()),this.containers[m]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[m],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1}},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||e("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.currentItem.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,a=this.options;"parent"===a.containment&&(a.containment=this.helper[0].parentNode),("document"===a.containment||"window"===a.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,e("document"===a.containment?document:window).width()-this.helperProportions.width-this.margins.left,(e("document"===a.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(a.containment)||(t=e(a.containment)[0],i=e(a.containment).offset(),s="hidden"!==e(t).css("overflow"),this.containment=[i.left+(parseInt(e(t).css("borderLeftWidth"),10)||0)+(parseInt(e(t).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(e(t).css("borderTopWidth"),10)||0)+(parseInt(e(t).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(t.scrollWidth,t.offsetWidth):t.offsetWidth)-(parseInt(e(t).css("borderLeftWidth"),10)||0)-(parseInt(e(t).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(t.scrollHeight,t.offsetHeight):t.offsetHeight)-(parseInt(e(t).css("borderTopWidth"),10)||0)-(parseInt(e(t).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,a="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,n=/(html|body)/i.test(a[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():n?0:a.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():n?0:a.scrollLeft())*s}},_generatePosition:function(t){var i,s,a=this.options,n=t.pageX,r=t.pageY,o="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(o[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(t.pageX-this.offset.click.leftthis.containment[2]&&(n=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(r=this.containment[3]+this.offset.click.top)),a.grid&&(i=this.originalPageY+Math.round((r-this.originalPageY)/a.grid[1])*a.grid[1],r=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-a.grid[1]:i+a.grid[1]:i,s=this.originalPageX+Math.round((n-this.originalPageX)/a.grid[0])*a.grid[0],n=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-a.grid[0]:s+a.grid[0]:s)),{top:r-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:o.scrollTop()),left:n-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:o.scrollLeft())}},_rearrange:function(e,t,i,s){i?i[0].appendChild(this.placeholder[0]):t.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?t.item[0]:t.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var a=this.counter;this._delay(function(){a===this.counter&&this.refreshPositions(!s)})},_clear:function(e,t){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!t&&s.push(function(e){this._trigger("receive",e,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||t||s.push(function(e){this._trigger("update",e,this._uiHash())}),this!==this.currentContainer&&(t||(s.push(function(e){this._trigger("remove",e,this._uiHash())}),s.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)t||s.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!t){for(this._trigger("beforeStop",e,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!1}if(t||this._trigger("beforeStop",e,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!t){for(i=0;s.length>i;i++)s[i].call(this,e);this._trigger("stop",e,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){e.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(t){var i=t||this;return{helper:i.helper,placeholder:i.placeholder||e([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:t?t.element:null}}})})(jQuery);(function(e){var t=5;e.widget("ui.slider",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var t,i,s=this.options,a=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),n="
",r=[];for(i=s.values&&s.values.length||1,a.length>i&&(a.slice(i).remove(),a=a.slice(0,i)),t=a.length;i>t;t++)r.push(n);this.handles=a.add(e(r.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(t){e(this).data("ui-slider-handle-index",t)})},_createRange:function(){var t=this.options,i="";t.range?(t.range===!0&&(t.values?t.values.length&&2!==t.values.length?t.values=[t.values[0],t.values[0]]:e.isArray(t.values)&&(t.values=t.values.slice(0)):t.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=e("
").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===t.range||"max"===t.range?" ui-slider-range-"+t.range:""))):this.range=e([])},_setupEvents:function(){var e=this.handles.add(this.range).filter("a");this._off(e),this._on(e,this._handleEvents),this._hoverable(e),this._focusable(e)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(t){var i,s,a,n,r,o,h,l,u=this,c=this.options;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:t.pageX,y:t.pageY},s=this._normValueFromMouse(i),a=this._valueMax()-this._valueMin()+1,this.handles.each(function(t){var i=Math.abs(s-u.values(t));(a>i||a===i&&(t===u._lastChangedValue||u.values(t)===c.min))&&(a=i,n=e(this),r=t)}),o=this._start(t,r),o===!1?!1:(this._mouseSliding=!0,this._handleIndex=r,n.addClass("ui-state-active").focus(),h=n.offset(),l=!e(t.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:t.pageX-h.left-n.width()/2,top:t.pageY-h.top-n.height()/2-(parseInt(n.css("borderTopWidth"),10)||0)-(parseInt(n.css("borderBottomWidth"),10)||0)+(parseInt(n.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,r,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},i=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,i),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,i,s,a,n;return"horizontal"===this.orientation?(t=this.elementSize.width,i=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,i=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/t,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),a=this._valueMax()-this._valueMin(),n=this._valueMin()+s*a,this._trimAlignValue(n)},_start:function(e,t){var i={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("start",e,i)},_slide:function(e,t,i){var s,a,n;this.options.values&&this.options.values.length?(s=this.values(t?0:1),2===this.options.values.length&&this.options.range===!0&&(0===t&&i>s||1===t&&s>i)&&(i=s),i!==this.values(t)&&(a=this.values(),a[t]=i,n=this._trigger("slide",e,{handle:this.handles[t],value:i,values:a}),s=this.values(t?0:1),n!==!1&&this.values(t,i,!0))):i!==this.value()&&(n=this._trigger("slide",e,{handle:this.handles[t],value:i}),n!==!1&&this.value(i))},_stop:function(e,t){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._trigger("stop",e,i)},_change:function(e,t){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[t],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(t),i.values=this.values()),this._lastChangedValue=t,this._trigger("change",e,i)}},value:function(e){return arguments.length?(this.options.value=this._trimAlignValue(e),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(t,i){var s,a,n;if(arguments.length>1)return this.options.values[t]=this._trimAlignValue(i),this._refreshValue(),this._change(null,t),undefined;if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();for(s=this.options.values,a=arguments[0],n=0;s.length>n;n+=1)s[n]=this._trimAlignValue(a[n]),this._change(null,n);this._refreshValue()},_setOption:function(t,i){var s,a=0;switch("range"===t&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),e.isArray(this.options.values)&&(a=this.options.values.length),e.Widget.prototype._setOption.apply(this,arguments),t){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;a>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var e=this.options.value;return e=this._trimAlignValue(e)},_values:function(e){var t,i,s;if(arguments.length)return t=this.options.values[e],t=this._trimAlignValue(t);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(e){if(this._valueMin()>=e)return this._valueMin();if(e>=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,i=(e-this._valueMin())%t,s=e-i;return 2*Math.abs(i)>=t&&(s+=i>0?t:-t),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,i,s,a,n,r=this.options.range,o=this.options,h=this,l=this._animateOff?!1:o.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",e(this).stop(1,1)[l?"animate":"css"](u,o.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},o.animate),1===s&&h.range[l?"animate":"css"]({width:i-t+"%"},{queue:!1,duration:o.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},o.animate),1===s&&h.range[l?"animate":"css"]({height:i-t+"%"},{queue:!1,duration:o.animate}))),t=i}):(s=this.value(),a=this._valueMin(),n=this._valueMax(),i=n!==a?100*((s-a)/(n-a)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,o.animate),"min"===r&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},o.animate),"max"===r&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:o.animate}),"min"===r&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},o.animate),"max"===r&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:o.animate}))},_handleEvents:{keydown:function(i){var s,a,n,r,o=e(i.target).data("ui-slider-handle-index");switch(i.keyCode){case e.ui.keyCode.HOME:case e.ui.keyCode.END:case e.ui.keyCode.PAGE_UP:case e.ui.keyCode.PAGE_DOWN:case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,e(i.target).addClass("ui-state-active"),s=this._start(i,o),s===!1))return}switch(r=this.options.step,a=n=this.options.values&&this.options.values.length?this.values(o):this.value(),i.keyCode){case e.ui.keyCode.HOME:n=this._valueMin();break;case e.ui.keyCode.END:n=this._valueMax();break;case e.ui.keyCode.PAGE_UP:n=this._trimAlignValue(a+(this._valueMax()-this._valueMin())/t);break;case e.ui.keyCode.PAGE_DOWN:n=this._trimAlignValue(a-(this._valueMax()-this._valueMin())/t);break;case e.ui.keyCode.UP:case e.ui.keyCode.RIGHT:if(a===this._valueMax())return;n=this._trimAlignValue(a+r);break;case e.ui.keyCode.DOWN:case e.ui.keyCode.LEFT:if(a===this._valueMin())return;n=this._trimAlignValue(a-r)}this._slide(i,o,n)},click:function(e){e.preventDefault()},keyup:function(t){var i=e(t.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(t,i),this._change(t,i),e(t.target).removeClass("ui-state-active"))}}})})(jQuery); urlArray = window.location.href.split("/"); var SERVER = ""; if(urlArray[3] == "sandbox") { SERVER = "/sandbox"; } function baseLoad() { $(function() { $( "select[id^='slider_']" ).each(function() { var select = $(this); var selectName = $(this).attr("name"); var slider = $("
").insertAfter(select).slider({ min:0, max:100, step:10, range:"min", value: select.val(), slide: function( event, ui ) { select.val(ui.value); $("div#cv_" + $(this).attr("id")).empty().append(select.val() + "%"); }, change: function() { perc(select); } }); select.css("display","none"); // $("select[name=" + selectName + "]").on("change",perc); $("select[name='" + selectName + "']").change(function() { slider.slider( "value", select.val()); perc(select); }); }); }); $("form[name='taskForm'] select[name='dueText']").on("change",dueText); $("[name^='showBox']").on("click",showBox); $("a[name^='toggle_']").on("click",toggleCheckBoxes); $("form select[rel='selector']").on("change",selector); $("[id^='Finline']").on("click",Finline); $("div[id^='note']").on("mouseover",showNoteTrash); $("div[id^='note']").on("mouseout",hideNoteTrash); $("[rel='formconfirm']").on("click",formconfirm); $("form input[name='company']").on("keyup",company); $("form input[name='contact']").on("keyup",contact); $("form input[name='project']").on("keyup",project); // $("form input[name='service']").on("keyup",service); $("form input[name^='BCP|']").on("click",BCP); $("a[name='flyoutDisplay']").on("click",flyoutDisplay); $("form select[rel='ps']").on("change",ps); $("form select[rel^='oc_']").on("change",oc); $("ul[id^='psortable']").sortable({ connectWith: ".connectedSortable", stop: function(event, ui) { $('.connectedSortable').each(function() { url = SERVER + "/_includes/js/ajax/sort.php"; $.ajax({ url: url, data: "items=" + $(this).attr("title") + "&newlist=" + $(this).sortable("toArray"), // url: SERVER + "/_includes/js/ajax/sort.php?newlist=" + $(this).sortable("toArray"), error: function () { return true; } }); }); } }); $("#sortable1").sortable({ connectWith: ".connectedSortable", stop: function(event, ui) { $('.connectedSortable').each(function() { url = SERVER + "/_includes/js/ajax/sort.php"; $.ajax({ url: url, data: "items=" + $(this).attr("title") + "&newlist=" + $(this).sortable("toArray"), // url: SERVER + "/_includes/js/ajax/sort.php?newlist=" + $(this).sortable("toArray"), error: function () { return true; } }); }); } }); $(".sortable2").sortable({ connectWith: ".sortable2", update: function(event, ui) { if (this === ui.item.parent()[0]) { newPartTypeID = $(this).attr("id"); originalInfo = ui.item.attr('id'); url = SERVER + "/_includes/js/ajax/partsTypeControl.php?p=" + originalInfo + "&newPartTypeID=" + newPartTypeID; // alert(url); $.ajax({ url: url, error: function () { //alert('WTF'); }, success: function (jsonOBJ) { if(jsonOBJ.success) { //alert(jsonOBJ.success); } } }); } } }); $(".sortable").sortable({ connectWith: ".sortable", stop: function(event, ui) { $('.sortable').each(function() { url = SERVER + "/_includes/js/ajax/salesTracking.php"; $.ajax({ url: url, data: "data=" + JSON.stringify($('.sortable').salesTracking()), error: function () { //alert('WTF'); }, success: function (jsonOBJ) { if(jsonOBJ.success) { //alert(jsonOBJ.success); } } }); }); } }); $("input[rel='popupDatepicker']").datepick({dateFormat: 'mm-dd-yyyy',yearRange: '-100:+5'}); $("input[rel='popupDatepickerT']").datepick({dateFormat: 'mm-dd-yyyy',minDate: 0}); $("input[rel^='popupDatepickerSD']").datepick({dateFormat: 'M d, yyyy', onSelect: function(dateText){ target = $(this).attr("name").split("_"); field = target[0]; pid = target[1]; newDate = $(this).val(); url = SERVER + "/_includes/js/ajax/projectDate.php?pid=" + pid + "&field=" + field + "&newDate=" + newDate; $.ajax({ url: url, error: function () { return true; }, success: function (jsonOBJ) { if(jsonOBJ.success === true) { // alert(jsonOBJ.newDate); location.reload(); } } }); return false; } }); $(".edit").editable(SERVER + "/_includes/js/ajax/inlineProcess.php", { type : "text", loadurl : SERVER + "/_includes/js/ajax/inlineDisplay.php", onblur : "submit", loadtext : "", placeholder : "", tooltip: "", event : "mouseover", width : "auto", style : "display:inline", callback : function(value, settings) { var retval = value.replace(/['"]+/g, ''); if(retval == "") { retval = "not set"; } else { retval.replace(/['"]+/g, ''); } $(this).html(retval); } }); jQuery.editable.addInputType('datepicker', { element: function(settings, original) { var input = jQuery(''); // Catch the blur event on month change settings.onblur = function(e) { }; input.datepicker({ dateFormat: 'mm-dd-yy', onSelect: function(dateText, inst) { jQuery(this).parents("form").submit(); }, onClose: function(dateText, inst) { jQuery(this).parents("form").submit(); } }); input.datepicker('option', 'showAnim', 'slide'); jQuery(this).append(input); return (input); } }); $(".editabledatepicker").editable(SERVER + "/_includes/js/ajax/inlineProcess.php", { type: 'datepicker', loadurl : SERVER + "/_includes/js/ajax/inlineDisplay.php", onblur: 'submit', loadtext : "", placeholder : "", tooltip: "", style : "display:inline", event : "mouseover", callback : function(value, settings) { var retval = value.replace(/['"]+/g, ''); $(this).html(retval); } }); $.editable.addInputType('autogrow', { element : function(settings, original) { var textarea = $('