{"version":3,"sources":["garnish.js"],"names":["$","cancel","raf","erd","Base","extend","_instance","_static","prototype","_prototyping","proto","this","call","base","constructor","klass","_constructing","apply","arguments","ancestor","forEach","implement","toString","valueOf","type","init","source","value","length","test","method","previous","returnValue","toSource","hidden","i","key","desc","Object","getOwnPropertyDescriptor","defineProperty","version","object","block","context","undefined","String","Garnish","getErd","elementResizeDetectorMaker","callOnAdd","triggerResizeEvent","elem","trigger","$win","window","$doc","document","$bod","body","rtl","hasClass","ltr","$scrollContainer","DELETE_KEY","SHIFT_KEY","CTRL_KEY","ALT_KEY","RETURN_KEY","ESC_KEY","SPACE_KEY","LEFT_KEY","UP_KEY","RIGHT_KEY","DOWN_KEY","A_KEY","S_KEY","CMD_KEY","PRIMARY_CLICK","SECONDARY_CLICK","X_AXIS","Y_AXIS","FX_DURATION","TEXT_NODE","log","msg","console","_isMobileBrowser","_isMobileOrTabletBrowser","isMobileBrowser","detectTablets","a","navigator","userAgent","vendor","opera","RegExp","substr","isArray","val","Array","isJquery","jQuery","isString","hasAttr","attr","isTextNode","nodeType","getOffset","_offset","offset","top","scrollTop","left","scrollLeft","getDist","x1","y1","x2","y2","Math","sqrt","pow","hitTest","x","y","_$elem","_x1","_y1","_x2","outerWidth","_y2","outerHeight","isCursorOver","ev","pageX","pageY","copyTextStyles","target","$source","css","fontFamily","fontSize","fontWeight","letterSpacing","lineHeight","textAlign","textIndent","whiteSpace","wordSpacing","wordWrap","getBodyScrollTop","_scrollTop","_maxScrollTop","height","requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","fn","setTimeout","cancelAnimationFrame","mozCancelAnimationFrame","webkitCancelAnimationFrame","clearTimeout","id","scrollContainerToElement","container","$elem","$container","scrollParent","prop","elemScrollOffset","elemOffset","targetScrollTop","elemHeight","containerHeight","innerHeight","clientHeight","velocity","mobileHA","SHAKE_STEPS","SHAKE_STEP_DURATION","shake","startingPoint","parseInt","isNaN","_properties","getElement","makeArray","getInputBasename","name","replace","getInputPostVal","$input","findInputs","find","getPostData","inputName","postData","arrayInputCounters","$inputs","eq","inputVal","isArrayInput","croppedName","substring","j","copyInputValues","$sourceInputs","$targetInputs","isCtrlKeyPressed","platform","match","metaKey","ctrlKey","_eventHandlers","_normalizeEvents","events","split","on","data","handler","push","namespace","off","eventHandler","splice","settings","_namespace","_$listeners","_disabled","floor","random","_listeners","noop","setSettings","defaults","baseSettings","_ev","_splitEvents","trim","_formatEvents","slice","join","addListener","func","bind","proxy","inArray","removeListener","removeAllListeners","disable","enable","destroy","event","special","activate","setup","namespaces","eventHandle","mousedown.garnish-activate","e","preventDefault","click.garnish-activate","keydown.garnish-activate","keyCode","addClass","removeClass","removeAttr","teardown","textchange","handle","el","args","delay","handleObj","targetData","delayTimeout","resize","listenTo","each","BaseDrag","$items","dragging","mousedownX","mousedownY","realMouseX","realMouseY","mouseX","mouseY","mouseDistX","mouseDistY","mouseOffsetX","mouseOffsetY","$targetItem","scrollProperty","scrollAxis","scrollDist","scrollProxy","scrollFrame","_","items","isPlainObject","addItems","allowDragging","startDragging","onDragStart","drag","didMouseMove","_scrollProperty","axis","_winScrollTop","_minMouseScrollY","windowScrollTargetSize","_scrollAxis","_scrollDist","round","_maxMouseScrollY","_winScrollLeft","_minMouseScrollX","_maxMouseScrollX","width","_scrollWindow","_cancelWindowScroll","onDrag","stopDragging","onDragStop","item","removeItems","add","index","_deinitItem","removeAllItems","_handleMouseDown","which","$target","$handle","_getItemHandle","currentTarget","is","closest","ignoreHandleSelector","_handleMouseMove","_mouseDist","minMouseDist","_handleMouseUp","scrollPos","removeData","CheckboxSelect","$all","$options","$checkboxes","filter","not","onAllChange","isAllChecked","checked","disabled","ContextMenu","options","$menu","showingMenu","counter","buildMenu","menuClass","$ul","appendTo","hasOwnProperty","option","$li","$a","label","onClick","mousedown","hideMenu","showMenu","showing","show","hide","Drag","targetItemWidth","targetItemHeight","targetItemPositionInDraggee","$draggee","otherItems","totalOtherItems","helpers","helperTargets","helperPositions","helperLagIncrement","updateHelperPosProxy","updateHelperPosFrame","lastMouseX","lastMouseY","_returningHelpersToDraggees","draggeeDisplay","setDraggee","findDraggee","_updateHelperPos","helperLagIncrementDividend","concat","toArray","singleHelper","_createHelper","removeDraggee","collapseDraggees","appendDraggee","$newDraggee","oldLength","newLength","draggeeVirtualMidpointX","draggeeVirtualMidpointY","getHelperTargetX","getHelperTargetY","returnHelpersToDraggees","$helper","display","visibility","callback","draggeeOffset","_showDraggee","onReturnHelpersToDraggees","$draggeeHelper","clone","copyDraggeeInputValuesToHelper","ceil","margin","pointer-events","helper","append","helperPos","_getHelperTarget","position","zIndex","helperBaseZindex","opacity","helperOpacity","_i","_j","_lag","helperLagBase","helperSpacingX","helperSpacingY","remove","DragDrop","$dropTargets","$activeDropTarget","updateDropTargets","dropTargets","_activeDropTarget","_elem","activeDropTargetClass","onDropTargetChange","fadeOutHelpers","duration","complete","DragMove","DragSort","$heightedContainer","$insertion","insertionVisible","oldDraggeeIndexes","newDraggeeIndexes","closestItem","_midpointVersion","_$prevItem","createInsertion","insertion","magnetStrength","_draggeeOffsetX","_draggeeOffsetY","canInsertBefore","$item","canInsertAfter","_getDraggeeIndexes","moveTargetItemToFront","_getItemIndex","first","insertBefore","_placeInsertionWithDraggee","_clearMidpoints","parent","_removeInsertion","_getClosestItem","_updateInsertion","insertAfter","onSortChange","onInsertionPointChange","indexes","_closestItem","_testForClosestItem","_midpoint","_getItemMidpoint","_startXDist","_lastXDist","abs","_startYDist","_lastYDist","_$otherItem","prev","_xDist","_yDist","last","next","_repositionDraggee","get","_moveDraggeeToItem","_$item","prependTo","_mouseDistX","_mouseDistY","_closestItemMouseDistY","_closestItemMouseDistX","EscManager","handlers","escapeLatest","register","obj","unregister","pop","escManager","HUD","$trigger","$fixedTriggerParent","$hud","$tip","$body","$header","$footer","$mainContainer","$main","$shade","orientation","updatingSizeAndPosition","windowWidth","windowHeight","mainWidth","mainHeight","bodyContents","onShow","onHide","onSubmit","activeHUDs","class","shadeClass","hudClass","tipClass","bodyClass","mainContainerClass","mainClass","updateBody","$parent","offsetParent","hideOnShadeClick","closeBtn","html","headerClass","footerClass","stopPropagation","closeOtherHUDs","hudID","shortcutManager","addLayer","hideOnEsc","registerShortcut","updateRecords","updateSizeAndPosition","changed","force","updateSizeAndPositionInternal","triggerWidth","triggerHeight","triggerOffset","windowScrollLeft","windowScrollTop","scrollContainerTriggerOffset","scrollContainerScrollLeft","scrollContainerScrollTop","hudBodyWidth","hudBodyHeight","right","bottom","overflow-x","overflow-y","maxHudBodyWidth","maxHudBodyHeight","triggerCenter","clearances","orientations","relevantSize","windowSpacing","triggerSpacing","tipClasses","minBodyWidth","minBodyHeight","maxLeft","minLeft","tipLeft","tipWidth","maxTop","minTop","tipTop","removeLayer","toggle","submit","_handleSubmit","Menu","visible","$anchor","menuId","_windowWidth","_windowHeight","_windowScrollLeft","_windowScrollTop","_anchorOffset","_anchorWidth","_anchorHeight","_anchorOffsetRight","_anchorOffsetBottom","_menuWidth","_menuHeight","addOptions","$menuList","role","aria-hidden","attachToElement","anchor","nodeName","optionKey","tabindex","selectOption","setPositionRelativeToAnchor","topClearance","bottomClearance","maxHeight","min","align","_alignCenter","rightClearance","leftClearance","_alignRight","_alignLeft","detach","onOptionSelect","selectedOption","MenuBtn","$btn","menu","btn","menuAnchor","aria-controls","aria-haspopup","aria-expanded","onMenuHide","onBlur","contains","activeElement","onKeyDown","$option","$currentOption","click","focusOption","onMouseDown","MixedInput","elements","focussedElement","blurTimeout","getElementIndex","isText","onFocus","setFocus","setCarotPos","addTextElement","text","TextElement","addElement","focussedElementIndex","selectionStart","selectionEnd","preVal","postVal","newText","removeElement","$prevElem","$nextElem","prevElemVal","newVal","blurFocussedElement","focus","focusPreviousElement","$from","focusNextElement","pos","parentInput","$stage","focussed","interval","padding","setWidth","getIndex","buildStage","getTextWidth","stageWidth","setInterval","checkInput","NiceText","clearInterval","getVal","setVal","onChange","Modal","dragger","desiredWidth","desiredHeight","resizeDragger","resizeStartWidth","resizeStartHeight","setContainer","autoShow","instances","draggable","dragHandleSelector","resizable","$resizeDragHandle","_handleResizeStart","_handleResize","closeOtherModals","visibleModal","onFadeIn","quickShow","onFadeOut","quickHide","max","min-width","min-height","_width","getWidth","minGutter","_height","getHeight","_handleWindowResize","relativeElemPadding","$hint","$charsLeft","autoHeight","maxLength","showCharsLeft","showingHint","inputBoxSizing","minHeight","initialized","input","isVisible","initialize","getHeightForValue","updateHeight","hint","$hintContainer","charsLeftClass","updateCharsLeft","initializeIfVisible","showHint","hintFadeDuration","hideHint","onTextChange","border-top","border-right","border-bottom","border-left","padding-top","padding-right","padding-bottom","padding-left","-webkit-box-sizing","-moz-box-sizing","box-sizing","spaces","onHeightChange","updateHeightIfWidthChanged","_charsLeft","charsLeftHtml","negativeCharsLeftClass","charsLeft","Select","$selectedItems","$focusedItem","mousedownTarget","mouseUpTimeout","callbackFrame","$focusable","$first","$last","allowEmpty","checkboxMode","ignoreClick","deselectAll","getItemIndex","isSelected","selectItem","preventScroll","multi","setFocusableItem","focusItem","_selectItems","selectAll","selectRange","sliceFrom","sliceTo","deselectItem","_deselectItems","clearFirst","deselectOthers","toggleItem","_canDeselect","clearMouseUpTimeout","getFirstItem","getLastItem","isPreviousItem","isNextItem","getPreviousItem","getNextItem","getItemToTheLeft","horizontal","vertical","getClosestItem","getItemToTheRight","getItemAbove","getItemBelow","dir","step","axisProps","closestItemAxisProps","dirProps","closestItemDirectionProps","$thisItem","thisOffset","thisMidpoint","midpointOffset","midpointSizeFunc","otherRowPos","smallestMidpointDiff","$closestItem","$otherItem","otherOffset","isNextRow","rowOffset","otherMidpoint","midpointDiff","isWrongDirection","getFurthestItemToTheLeft","getFurthestItem","getFurthestItemToTheRight","getFurthestItemAbove","getFurthestItemBelow","$testItem","totalSelected","getTotalSelected","updateIndexes","itemsChanged","selectionChanged","selectedIndex","selectedClass","onSelectionChange","resetItemOrder","getSelectedItems","shiftKey","_actAsCheckbox","onMouseUp","<","b",">","SelectMenu","selected","build","_addSelectedOptionClass","select","dom","ul","className","setBtnText","$btnLabel","ulClass","ShortcutManager","shortcuts","layer","shortcut","_normalizeShortcut","JSON","stringify","unregisterShortcut","ctrl","shift","alt","triggerShortcut","altKey"],"mappings":"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","file":"garnish.js","sourcesContent":["/**\n * Garnish UI toolkit\n *\n * @copyright 2013 Pixel & Tonic, Inc.. All rights reserved.\n * @author    Brandon Kelly <brandon@pixelandtonic.com>\n * @version   0.1.45\n * @license   MIT\n */\n(function($){\n\n/*!\r\n\tBase.js, version 1.1a\r\n\tCopyright 2006-2010, Dean Edwards\r\n\tLicense: http://www.opensource.org/licenses/mit-license.php\r\n*/\r\n\r\nvar Base = function() {\r\n\t// dummy\r\n};\r\n\r\nBase.extend = function(_instance, _static) { // subclass\r\n\tvar extend = Base.prototype.extend;\r\n\r\n\t// build the prototype\r\n\tBase._prototyping = true;\r\n\tvar proto = new this;\r\n\textend.call(proto, _instance);\r\n\tproto.base = function() {\r\n\t\t// call this method from any other method to invoke that method's ancestor\r\n\t};\r\n\tdelete Base._prototyping;\r\n\r\n\t// create the wrapper for the constructor function\r\n\t//var constructor = proto.constructor.valueOf(); //-dean\r\n\tvar constructor = proto.constructor;\r\n\tvar klass = proto.constructor = function() {\r\n\t\tif (!Base._prototyping) {\r\n\t\t\tif (this._constructing || this.constructor == klass) { // instantiation\r\n\t\t\t\tthis._constructing = true;\r\n\t\t\t\tconstructor.apply(this, arguments);\r\n\t\t\t\tdelete this._constructing;\r\n\t\t\t} else if (arguments[0] != null) { // casting\r\n\t\t\t\treturn (arguments[0].extend || extend).call(arguments[0], proto);\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\t// build the class interface\r\n\tklass.ancestor = this;\r\n\tklass.extend = this.extend;\r\n\tklass.forEach = this.forEach;\r\n\tklass.implement = this.implement;\r\n\tklass.prototype = proto;\r\n\tklass.toString = this.toString;\r\n\tklass.valueOf = function(type) {\r\n\t\t//return (type == \"object\") ? klass : constructor; //-dean\r\n\t\treturn (type == \"object\") ? klass : constructor.valueOf();\r\n\t};\r\n\textend.call(klass, _static);\r\n\t// class initialisation\r\n\tif (typeof klass.init == \"function\") klass.init();\r\n\treturn klass;\r\n};\r\n\r\nBase.prototype = {\r\n\textend: function(source, value) {\r\n\t\tif (arguments.length > 1) { // extending with a name/value pair\r\n\t\t\tvar ancestor = this[source];\r\n\t\t\tif (ancestor && (typeof value == \"function\") && // overriding a method?\r\n\t\t\t\t// the valueOf() comparison is to avoid circular references\r\n\t\t\t\t(!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) &&\r\n\t\t\t\t/\\bbase\\b/.test(value)) {\r\n\t\t\t\t// get the underlying method\r\n\t\t\t\tvar method = value.valueOf();\r\n\t\t\t\t// override\r\n\t\t\t\tvalue = function() {\r\n\t\t\t\t\tvar previous = this.base || Base.prototype.base;\r\n\t\t\t\t\tthis.base = ancestor;\r\n\t\t\t\t\tvar returnValue = method.apply(this, arguments);\r\n\t\t\t\t\tthis.base = previous;\r\n\t\t\t\t\treturn returnValue;\r\n\t\t\t\t};\r\n\t\t\t\t// point to the underlying method\r\n\t\t\t\tvalue.valueOf = function(type) {\r\n\t\t\t\t\treturn (type == \"object\") ? value : method;\r\n\t\t\t\t};\r\n\t\t\t\tvalue.toString = Base.toString;\r\n\t\t\t}\r\n\t\t\tthis[source] = value;\r\n\t\t} else if (source) { // extending with an object literal\r\n\t\t\tvar extend = Base.prototype.extend;\r\n\t\t\t// if this object has a customised extend method then use it\r\n\t\t\tif (!Base._prototyping && typeof this != \"function\") {\r\n\t\t\t\textend = this.extend || extend;\r\n\t\t\t}\r\n\t\t\tvar proto = {toSource: null};\r\n\t\t\t// do the \"toString\" and other methods manually\r\n\t\t\tvar hidden = [\"constructor\", \"toString\", \"valueOf\"];\r\n\t\t\t// if we are prototyping then include the constructor\r\n\t\t\tvar i = Base._prototyping ? 0 : 1;\r\n\t\t\twhile (key = hidden[i++]) {\r\n\t\t\t\tif (source[key] != proto[key]) {\r\n\t\t\t\t\textend.call(this, key, source[key]);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// copy each of the source object's properties to this object\r\n\t\t\tfor (var key in source) {\r\n\t\t\t\tif (!proto[key]) {\r\n\t\t\t\t\tvar desc = Object.getOwnPropertyDescriptor(source, key);\r\n\t\t\t\t\tif (typeof desc.value != typeof undefined) {\r\n\t\t\t\t\t\t// set the value normally in case it's a function that needs to be overwritten\r\n\t\t\t\t\t\textend.call(this, key, desc.value);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\t// set it while maintaining the original descriptor settings\r\n\t\t\t\t\t\tObject.defineProperty(this, key, desc);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n};\r\n\r\n// initialise\r\nBase = Base.extend({\r\n\tconstructor: function() {\r\n\t\tthis.extend(arguments[0]);\r\n\t}\r\n}, {\r\n\tancestor: Object,\r\n\tversion: \"1.1\",\r\n\r\n\tforEach: function(object, block, context) {\r\n\t\tfor (var key in object) {\r\n\t\t\tif (this.prototype[key] === undefined) {\r\n\t\t\t\tblock.call(context, object[key], key, object);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\timplement: function() {\r\n\t\tfor (var i = 0; i < arguments.length; i++) {\r\n\t\t\tif (typeof arguments[i] == \"function\") {\r\n\t\t\t\t// if it's a function, call it\r\n\t\t\t\targuments[i](this.prototype);\r\n\t\t\t} else {\r\n\t\t\t\t// add the interface using the extend method\r\n\t\t\t\tthis.prototype.extend(arguments[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\ttoString: function() {\r\n\t\treturn String(this.valueOf());\r\n\t}\r\n});\r\n\n/**\n * @namespace Garnish\n */\n\n// Bail if Garnish is already defined\nif (typeof Garnish !== 'undefined') {\n    throw 'Garnish is already defined!';\n}\n\nGarnish = {\n\n    // jQuery objects for common elements\n    $win: $(window),\n    $doc: $(document),\n    $bod: $(document.body)\n\n};\n\nGarnish.rtl = Garnish.$bod.hasClass('rtl');\nGarnish.ltr = !Garnish.rtl;\n\nGarnish = $.extend(Garnish, {\n\n    $scrollContainer: Garnish.$win,\n\n    // Key code constants\n    DELETE_KEY: 8,\n    SHIFT_KEY: 16,\n    CTRL_KEY: 17,\n    ALT_KEY: 18,\n    RETURN_KEY: 13,\n    ESC_KEY: 27,\n    SPACE_KEY: 32,\n    LEFT_KEY: 37,\n    UP_KEY: 38,\n    RIGHT_KEY: 39,\n    DOWN_KEY: 40,\n    A_KEY: 65,\n    S_KEY: 83,\n    CMD_KEY: 91,\n\n    // Mouse button constants\n    PRIMARY_CLICK: 1,\n    SECONDARY_CLICK: 3,\n\n    // Axis constants\n    X_AXIS: 'x',\n    Y_AXIS: 'y',\n\n    FX_DURATION: 100,\n\n    // Node types\n    TEXT_NODE: 3,\n\n    /**\n     * Logs a message to the browser's console, if the browser has one.\n     *\n     * @param {string} msg\n     */\n    log: function(msg) {\n        if (typeof console !== 'undefined' && typeof console.log === 'function') {\n            console.log(msg);\n        }\n    },\n\n    _isMobileBrowser: null,\n    _isMobileOrTabletBrowser: null,\n\n    /**\n     * Returns whether this is a mobile browser.\n     * Detection script courtesy of http://detectmobilebrowsers.com\n     *\n     * Last updated: 2014-11-24\n     *\n     * @param {boolean} detectTablets\n     * @return {boolean}\n     */\n    isMobileBrowser: function(detectTablets) {\n        var key = detectTablets ? '_isMobileOrTabletBrowser' : '_isMobileBrowser';\n\n        if (Garnish[key] === null) {\n            var a = navigator.userAgent || navigator.vendor || window.opera;\n            Garnish[key] = ((new RegExp('(android|bb\\d+|meego).+mobile|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\\.(browser|link)|vodafone|wap|windows ce|xda|xiino' + (detectTablets ? '|android|ipad|playbook|silk' : ''), 'i')).test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\\-(n|u)|c55\\/|capi|ccwa|cdm\\-|cell|chtm|cldc|cmd\\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\\-s|devi|dica|dmob|do(c|p)o|ds(12|\\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\\-|_)|g1 u|g560|gene|gf\\-5|g\\-mo|go(\\.w|od)|gr(ad|un)|haie|hcit|hd\\-(m|p|t)|hei\\-|hi(pt|ta)|hp( i|ip)|hs\\-c|ht(c(\\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\\-(20|go|ma)|i230|iac( |\\-|\\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\\/)|klon|kpt |kwc\\-|kyo(c|k)|le(no|xi)|lg( g|\\/(k|l|u)|50|54|\\-[a-w])|libw|lynx|m1\\-w|m3ga|m50\\/|ma(te|ui|xo)|mc(01|21|ca)|m\\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\\-2|po(ck|rt|se)|prox|psio|pt\\-g|qa\\-a|qc(07|12|21|32|60|\\-[2-7]|i\\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\\-|oo|p\\-)|sdk\\/|se(c(\\-|0|1)|47|mc|nd|ri)|sgh\\-|shar|sie(\\-|m)|sk\\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\\-|v\\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\\-|tdg\\-|tel(i|m)|tim\\-|t\\-mo|to(pl|sh)|ts(70|m\\-|m3|m5)|tx\\-9|up(\\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\\-|your|zeto|zte\\-/i.test(a.substr(0, 4)));\n        }\n\n        return Garnish[key];\n    },\n\n    /**\n     * Returns whether a variable is an array.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isArray: function(val) {\n        return (val instanceof Array);\n    },\n\n    /**\n     * Returns whether a variable is a jQuery collection.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isJquery: function(val) {\n        return (val instanceof jQuery);\n    },\n\n    /**\n     * Returns whether a variable is a string.\n     *\n     * @param {object} val\n     * @return {boolean}\n     */\n    isString: function(val) {\n        return (typeof val === 'string');\n    },\n\n    /**\n     * Returns whether an element has an attribute.\n     *\n     * @see http://stackoverflow.com/questions/1318076/jquery-hasattr-checking-to-see-if-there-is-an-attribute-on-an-element/1318091#1318091\n     */\n    hasAttr: function(elem, attr) {\n        var val = $(elem).attr(attr);\n        return (typeof val !== 'undefined' && val !== false);\n    },\n\n    /**\n     * Returns whether something is a text node.\n     *\n     * @param {object} elem\n     * @return {boolean}\n     */\n    isTextNode: function(elem) {\n        return (elem.nodeType === Garnish.TEXT_NODE);\n    },\n\n    /**\n     * Returns the offset of an element within the scroll container, whether that's the window or something else\n     */\n    getOffset: function(elem) {\n        this.getOffset._offset = $(elem).offset();\n\n        if (Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n            this.getOffset._offset.top += Garnish.$scrollContainer.scrollTop();\n            this.getOffset._offset.left += Garnish.$scrollContainer.scrollLeft();\n        }\n\n        return this.getOffset._offset;\n    },\n\n    /**\n     * Returns the distance between two coordinates.\n     *\n     * @param {number} x1 The first coordinate's X position.\n     * @param {number} y1 The first coordinate's Y position.\n     * @param {number} x2 The second coordinate's X position.\n     * @param {number} y2 The second coordinate's Y position.\n     * @return {number}\n     */\n    getDist: function(x1, y1, x2, y2) {\n        return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));\n    },\n\n    /**\n     * Returns whether an element is touching an x/y coordinate.\n     *\n     * @param {number}    x    The coordinate's X position.\n     * @param {number}    y    The coordinate's Y position.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    hitTest: function(x, y, elem) {\n        Garnish.hitTest._$elem = $(elem);\n        Garnish.hitTest._offset = Garnish.hitTest._$elem.offset();\n        Garnish.hitTest._x1 = Garnish.hitTest._offset.left;\n        Garnish.hitTest._y1 = Garnish.hitTest._offset.top;\n        Garnish.hitTest._x2 = Garnish.hitTest._x1 + Garnish.hitTest._$elem.outerWidth();\n        Garnish.hitTest._y2 = Garnish.hitTest._y1 + Garnish.hitTest._$elem.outerHeight();\n\n        return (x >= Garnish.hitTest._x1 && x < Garnish.hitTest._x2 && y >= Garnish.hitTest._y1 && y < Garnish.hitTest._y2);\n    },\n\n    /**\n     * Returns whether the cursor is touching an element.\n     *\n     * @param {object} ev   The mouse event object containing pageX and pageY properties.\n     * @param {object} elem Either an actual element or a jQuery collection.\n     * @return {boolean}\n     */\n    isCursorOver: function(ev, elem) {\n        return Garnish.hitTest(ev.pageX, ev.pageY, elem);\n    },\n\n    /**\n     * Copies text styles from one element to another.\n     *\n     * @param {object} source The source element. Can be either an actual element or a jQuery collection.\n     * @param {object} target The target element. Can be either an actual element or a jQuery collection.\n     */\n    copyTextStyles: function(source, target) {\n        var $source = $(source),\n            $target = $(target);\n\n        $target.css({\n            fontFamily: $source.css('fontFamily'),\n            fontSize: $source.css('fontSize'),\n            fontWeight: $source.css('fontWeight'),\n            letterSpacing: $source.css('letterSpacing'),\n            lineHeight: $source.css('lineHeight'),\n            textAlign: $source.css('textAlign'),\n            textIndent: $source.css('textIndent'),\n            whiteSpace: $source.css('whiteSpace'),\n            wordSpacing: $source.css('wordSpacing'),\n            wordWrap: $source.css('wordWrap')\n        });\n    },\n\n    /**\n     * Returns the body's real scrollTop, discarding any window banding in Safari.\n     *\n     * @return {number}\n     */\n    getBodyScrollTop: function() {\n        Garnish.getBodyScrollTop._scrollTop = document.body.scrollTop;\n\n        if (Garnish.getBodyScrollTop._scrollTop < 0) {\n            Garnish.getBodyScrollTop._scrollTop = 0;\n        }\n        else {\n            Garnish.getBodyScrollTop._maxScrollTop = Garnish.$bod.outerHeight() - Garnish.$win.height();\n\n            if (Garnish.getBodyScrollTop._scrollTop > Garnish.getBodyScrollTop._maxScrollTop) {\n                Garnish.getBodyScrollTop._scrollTop = Garnish.getBodyScrollTop._maxScrollTop;\n            }\n        }\n\n        return Garnish.getBodyScrollTop._scrollTop;\n    },\n\n    requestAnimationFrame: (function() {\n            var raf = (\n                window.requestAnimationFrame ||\n                window.mozRequestAnimationFrame ||\n                window.webkitRequestAnimationFrame ||\n                function(fn) {\n                    return window.setTimeout(fn, 20);\n                }\n            );\n\n            return function(fn) {\n                return raf(fn);\n            };\n        })(),\n\n    cancelAnimationFrame: (function() {\n            var cancel = (\n                window.cancelAnimationFrame ||\n                window.mozCancelAnimationFrame ||\n                window.webkitCancelAnimationFrame ||\n                window.clearTimeout\n            );\n\n            return function(id) {\n                return cancel(id);\n            };\n        })(),\n\n    /**\n     * Scrolls a container element to an element within it.\n     *\n     * @param {object} container Either an actual element or a jQuery collection.\n     * @param {object} elem      Either an actual element or a jQuery collection.\n     */\n    scrollContainerToElement: function(container, elem) {\n        var $elem;\n\n        if (typeof elem === 'undefined') {\n            $elem = $(container);\n            $container = $elem.scrollParent();\n        }\n        else {\n            var $container = $(container);\n            $elem = $(elem);\n        }\n\n        if ($container.prop('nodeName') === 'HTML' || $container[0] === Garnish.$doc[0]) {\n            $container = Garnish.$win;\n        }\n\n        var scrollTop = $container.scrollTop(),\n            elemOffset = $elem.offset().top;\n\n        var elemScrollOffset;\n\n        if ($container[0] === window) {\n            elemScrollOffset = elemOffset - scrollTop;\n        }\n        else {\n            elemScrollOffset = elemOffset - $container.offset().top;\n        }\n\n        var targetScrollTop = false;\n\n        // Is the element above the fold?\n        if (elemScrollOffset < 0) {\n            targetScrollTop = scrollTop + elemScrollOffset - 10;\n        }\n        else {\n            var elemHeight = $elem.outerHeight(),\n                containerHeight = ($container[0] === window ? window.innerHeight : $container[0].clientHeight);\n\n            // Is it below the fold?\n            if (elemScrollOffset + elemHeight > containerHeight) {\n                targetScrollTop = scrollTop + (elemScrollOffset - (containerHeight - elemHeight)) + 10;\n            }\n        }\n\n        if (targetScrollTop !== false) {\n            // Velocity only allows you to scroll to an arbitrary position if you're scrolling the main window\n            if ($container[0] === window) {\n                $('html').velocity('scroll', {\n                    offset: targetScrollTop + 'px',\n                    mobileHA: false\n                });\n            }\n            else {\n                $container.scrollTop(targetScrollTop);\n            }\n        }\n    },\n\n    SHAKE_STEPS: 10,\n    SHAKE_STEP_DURATION: 25,\n\n    /**\n     * Shakes an element.\n     *\n     * @param {object}  elem Either an actual element or a jQuery collection.\n     * @param {string} prop The property that should be adjusted (default is 'margin-left').\n     */\n    shake: function(elem, prop) {\n        var $elem = $(elem);\n\n        if (!prop) {\n            prop = 'margin-left';\n        }\n\n        var startingPoint = parseInt($elem.css(prop));\n        if (isNaN(startingPoint)) {\n            startingPoint = 0;\n        }\n\n        for (var i = 0; i <= Garnish.SHAKE_STEPS; i++) {\n            (function(i) {\n                setTimeout(function() {\n                    Garnish.shake._properties = {};\n                    Garnish.shake._properties[prop] = startingPoint + (i % 2 ? -1 : 1) * (10 - i);\n                    $elem.velocity(Garnish.shake._properties, Garnish.SHAKE_STEP_DURATION);\n                }, (Garnish.SHAKE_STEP_DURATION * i));\n            })(i);\n        }\n    },\n\n    /**\n     * Returns the first element in an array or jQuery collection.\n     *\n     * @param {object} elem\n     * @return mixed\n     */\n    getElement: function(elem) {\n        return $.makeArray(elem)[0];\n    },\n\n    /**\n     * Returns the beginning of an input's name= attribute value with any [bracktes] stripped out.\n     *\n     * @param {object} elem\n     * @return string|null\n     */\n    getInputBasename: function(elem) {\n        var name = $(elem).attr('name');\n\n        if (name) {\n            return name.replace(/\\[.*/, '');\n        }\n        else {\n            return null;\n        }\n    },\n\n    /**\n     * Returns an input's value as it would be POSTed.\n     * So unchecked checkboxes and radio buttons return null,\n     * and multi-selects whose name don't end in \"[]\" only return the last selection\n     *\n     * @param {object} $input\n     * @return {(string|string[])}\n     */\n    getInputPostVal: function($input) {\n        var type = $input.attr('type'),\n            val = $input.val();\n\n        // Is this an unchecked checkbox or radio button?\n        if ((type === 'checkbox' || type === 'radio')) {\n            if ($input.prop('checked')) {\n                return val;\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Flatten any array values whose input name doesn't end in \"[]\"\n        //  - e.g. a multi-select\n        else if (Garnish.isArray(val) && $input.attr('name').substr(-2) !== '[]') {\n            if (val.length) {\n                return val[val.length - 1];\n            }\n            else {\n                return null;\n            }\n        }\n\n        // Just return the value\n        else {\n            return val;\n        }\n    },\n\n    /**\n     * Returns the inputs within a container\n     *\n     * @param {object} container The container element. Can be either an actual element or a jQuery collection.\n     * @return {object}\n     */\n    findInputs: function(container) {\n        return $(container).find('input,text,textarea,select,button');\n    },\n\n    /**\n     * Returns the post data within a container.\n     *\n     * @param {object} container\n     * @return {array}\n     */\n    getPostData: function(container) {\n        var postData = {},\n            arrayInputCounters = {},\n            $inputs = Garnish.findInputs(container);\n\n        var inputName;\n\n        for (var i = 0; i < $inputs.length; i++) {\n            var $input = $inputs.eq(i);\n\n            if ($input.prop('disabled')) {\n                continue;\n            }\n\n            inputName = $input.attr('name');\n            if (!inputName) {\n                continue;\n            }\n\n            var inputVal = Garnish.getInputPostVal($input);\n            if (inputVal === null) {\n                continue;\n            }\n\n            var isArrayInput = (inputName.substr(-2) === '[]');\n\n            if (isArrayInput) {\n                // Get the cropped input name\n                var croppedName = inputName.substring(0, inputName.length - 2);\n\n                // Prep the input counter\n                if (typeof arrayInputCounters[croppedName] === 'undefined') {\n                    arrayInputCounters[croppedName] = 0;\n                }\n            }\n\n            if (!Garnish.isArray(inputVal)) {\n                inputVal = [inputVal];\n            }\n\n            for (var j = 0; j < inputVal.length; j++) {\n                if (isArrayInput) {\n                    inputName = croppedName + '[' + arrayInputCounters[croppedName] + ']';\n                    arrayInputCounters[croppedName]++;\n                }\n\n                postData[inputName] = inputVal[j];\n            }\n        }\n\n        return postData;\n    },\n\n    copyInputValues: function(source, target) {\n        var $sourceInputs = Garnish.findInputs(source),\n            $targetInputs = Garnish.findInputs(target);\n\n        for (var i = 0; i < $sourceInputs.length; i++) {\n            if (typeof $targetInputs[i] === 'undefined') {\n                break;\n            }\n\n            $targetInputs.eq(i).val(\n                $sourceInputs.eq(i).val()\n            );\n        }\n    },\n\n    /**\n     * Returns whether the \"Ctrl\" key is pressed (or ⌘ if this is a Mac) for a given keyboard event\n     *\n     * @param ev The keyboard event\n     *\n     * @return {boolean} Whether the \"Ctrl\" key is pressed\n     */\n    isCtrlKeyPressed: function(ev) {\n        if (window.navigator.platform.match(/Mac/)) {\n            // metaKey maps to ⌘ on Macs\n            return ev.metaKey;\n        }\n        return ev.ctrlKey;\n    },\n\n    _eventHandlers: [],\n\n    _normalizeEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(' ');\n        }\n\n        for (var i = 0; i < events.length; i++) {\n            if (typeof events[i] === 'string') {\n                events[i] = events[i].split('.');\n            }\n        }\n\n        return events;\n    },\n\n    on: function(target, events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                target: target,\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(target, events, handler) {\n        events = this._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.target === target &&\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    }\n});\n\n\n/**\n * Garnish base class\n */\nGarnish.Base = Base.extend({\n\n    settings: null,\n\n    _eventHandlers: null,\n    _namespace: null,\n    _$listeners: null,\n    _disabled: false,\n\n    constructor: function() {\n        this._eventHandlers = [];\n        this._namespace = '.Garnish' + Math.floor(Math.random() * 1000000000);\n        this._listeners = [];\n        this.init.apply(this, arguments);\n    },\n\n    init: $.noop,\n\n    setSettings: function(settings, defaults) {\n        var baseSettings = (typeof this.settings === 'undefined' ? {} : this.settings);\n        this.settings = $.extend({}, baseSettings, defaults, settings);\n    },\n\n    on: function(events, data, handler) {\n        if (typeof data === 'function') {\n            handler = data;\n            data = {};\n        }\n\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n            this._eventHandlers.push({\n                type: ev[0],\n                namespace: ev[1],\n                data: data,\n                handler: handler\n            });\n        }\n    },\n\n    off: function(events, handler) {\n        events = Garnish._normalizeEvents(events);\n\n        for (var i = 0; i < events.length; i++) {\n            var ev = events[i];\n\n            for (var j = this._eventHandlers.length - 1; j >= 0; j--) {\n                var eventHandler = this._eventHandlers[j];\n\n                if (\n                    eventHandler.type === ev[0] &&\n                    (!ev[1] || eventHandler.namespace === ev[1]) &&\n                    eventHandler.handler === handler\n                ) {\n                    this._eventHandlers.splice(j, 1);\n                }\n            }\n        }\n    },\n\n    trigger: function(type, data) {\n        var ev = {\n            type: type,\n            target: this\n        };\n\n        // instance level event handlers\n        var i, handler, _ev;\n        for (i = 0; i < this._eventHandlers.length; i++) {\n            handler = this._eventHandlers[i];\n\n            if (handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n\n        // class level event handlers\n        for (i = 0; i < Garnish._eventHandlers.length; i++) {\n            handler = Garnish._eventHandlers[i];\n\n            if (this instanceof handler.target && handler.type === type) {\n                _ev = $.extend({data: handler.data}, data, ev);\n                handler.handler(_ev);\n            }\n        }\n    },\n\n    _splitEvents: function(events) {\n        if (typeof events === 'string') {\n            events = events.split(',');\n\n            for (var i = 0; i < events.length; i++) {\n                events[i] = $.trim(events[i]);\n            }\n        }\n\n        return events;\n    },\n\n    _formatEvents: function(events) {\n        events = this._splitEvents(events).slice(0);\n\n        for (var i = 0; i < events.length; i++) {\n            events[i] += this._namespace;\n        }\n\n        return events.join(' ');\n    },\n\n    addListener: function(elem, events, data, func) {\n        var $elem = $(elem);\n\n        // Ignore if there aren't any elements\n        if (!$elem.length) {\n            return;\n        }\n\n        events = this._splitEvents(events);\n\n        // Param mapping\n        if (typeof func === 'undefined' && typeof data !== 'object') {\n            // (elem, events, func)\n            func = data;\n            data = {};\n        }\n\n        if (typeof func === 'function') {\n            func = func.bind(this);\n        }\n        else {\n            func = this[func].bind(this);\n        }\n\n        $elem.on(this._formatEvents(events), data, $.proxy(function() {\n            if (!this._disabled) {\n                return func.apply(this, arguments);\n            }\n        }, this));\n\n        // Remember that we're listening to this element\n        if ($.inArray(elem, this._listeners) === -1) {\n            this._listeners.push(elem);\n        }\n    },\n\n    removeListener: function(elem, events) {\n        $(elem).off(this._formatEvents(events));\n    },\n\n    removeAllListeners: function(elem) {\n        $(elem).off(this._namespace);\n    },\n\n    disable: function() {\n        this._disabled = true;\n    },\n\n    enable: function() {\n        this._disabled = false;\n    },\n\n    destroy: function() {\n        this.trigger('destroy');\n        this.removeAllListeners(this._listeners);\n    }\n});\n\n// Custom events\n// -----------------------------------------------------------------------------\n\nvar erd;\n\nfunction getErd() {\n    if (typeof erd === 'undefined') {\n        erd = elementResizeDetectorMaker({\n            callOnAdd: false\n        });\n    }\n\n    return erd;\n}\n\nfunction triggerResizeEvent(elem) {\n    $(elem).trigger('resize');\n}\n\n// Work them into jQuery's event system\n$.extend(jQuery.event.special, {\n    activate: {\n        setup: function(data, namespaces, eventHandle) {\n            var activateNamespace = this._namespace + '-activate';\n            var $elem = $(this);\n\n            $elem.on({\n                'mousedown.garnish-activate': function(e) {\n                    // Prevent buttons from getting focus on click\n                    e.preventDefault();\n                },\n                'click.garnish-activate': function(e) {\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.trigger('activate');\n                    }\n                },\n                'keydown.garnish-activate': function(e) {\n                    // Ignore if the event was bubbled up, or if it wasn't the space key\n                    if (this !== $elem[0] || e.keyCode !== Garnish.SPACE_KEY) {\n                        return;\n                    }\n\n                    e.preventDefault();\n\n                    if (!$elem.hasClass('disabled')) {\n                        $elem.addClass('active');\n\n                        Garnish.$doc.on('keyup.garnish-activate', function(e) {\n                            $elem.removeClass('active');\n\n                            if (e.keyCode === Garnish.SPACE_KEY) {\n                                e.preventDefault();\n                                $elem.trigger('activate');\n                            }\n\n                            Garnish.$doc.off('keyup.garnish-activate');\n                        });\n                    }\n                }\n            });\n\n            if (!$elem.hasClass('disabled')) {\n                $elem.attr('tabindex', '0');\n            } else {\n                $elem.removeAttr('tabindex');\n            }\n        },\n        teardown: function() {\n            $(this).off('.garnish-activate');\n        }\n    },\n\n    textchange: {\n        setup: function(data, namespaces, eventHandle) {\n            var $elem = $(this);\n            $elem.data('garnish-textchange-value', $elem.val());\n            $elem.on('keypress.garnish-textchange keyup.garnish-textchange change.garnish-textchange blur.garnish-textchange', function(e) {\n                var val = $elem.val();\n                if (val !== $elem.data('garnish-textchange-value')) {\n                    $elem.data('garnish-textchange-value', val);\n                    $elem.trigger('textchange');\n                }\n            });\n        },\n        teardown: function() {\n            $(this).off('.garnish-textchange');\n        },\n        handle: function(ev, data) {\n            var el = this;\n            var args = arguments;\n            var delay = data && typeof data.delay !== 'undefined' ? data.delay : (ev.data && ev.data.delay !== undefined ? ev.data.delay : null);\n            var handleObj = ev.handleObj;\n            var targetData = $.data(ev.target);\n\n            // Was this event configured with a delay?\n            if (delay) {\n                if (targetData.delayTimeout) {\n                    clearTimeout(targetData.delayTimeout);\n                }\n\n                targetData.delayTimeout = setTimeout(function() {\n                    handleObj.handler.apply(el, args);\n                }, delay);\n            } else {\n                return handleObj.handler.apply(el, args);\n            }\n        }\n    },\n\n    resize: {\n        setup: function(data, namespaces, eventHandle) {\n            // window is the only element that natively supports a resize event\n            if (this === window) {\n                return false;\n            }\n\n            $('> :last-child', this).addClass('last');\n            getErd().listenTo(this, triggerResizeEvent)\n        },\n        teardown: function() {\n            if (this === window) {\n                return false;\n            }\n\n            getErd().removeListener(this, triggerResizeEvent);\n        }\n    }\n});\n\n// Give them their own element collection chaining methods\njQuery.each(['activate', 'textchange', 'resize'], function(i, name) {\n    jQuery.fn[name] = function(data, fn) {\n        return arguments.length > 0 ?\n            this.on(name, null, data, fn) :\n            this.trigger(name);\n    };\n});\n\n/** global: Garnish */\n/**\n * Base drag class\n *\n * Does all the grunt work for manipulating elements via click-and-drag,\n * while leaving the actual element manipulation up to a subclass.\n */\nGarnish.BaseDrag = Garnish.Base.extend(\n    {\n        $items: null,\n\n        dragging: false,\n\n        mousedownX: null,\n        mousedownY: null,\n        realMouseX: null,\n        realMouseY: null,\n        mouseX: null,\n        mouseY: null,\n        mouseDistX: null,\n        mouseDistY: null,\n        mouseOffsetX: null,\n        mouseOffsetY: null,\n\n        $targetItem: null,\n\n        scrollProperty: null,\n        scrollAxis: null,\n        scrollDist: null,\n        scrollProxy: null,\n        scrollFrame: null,\n\n        _: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            this.settings = $.extend({}, Garnish.BaseDrag.defaults, settings);\n\n            this.$items = $();\n            this._ = {};\n\n            if (items) {\n                this.addItems(items);\n            }\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            return true;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            this.dragging = true;\n            this.onDragStart();\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            if (didMouseMove) {\n                // Is the mouse up against one of the window edges?\n                this.drag._scrollProperty = null;\n\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    // Scrolling up?\n                    this.drag._winScrollTop = Garnish.$win.scrollTop();\n                    this.drag._minMouseScrollY = this.drag._winScrollTop + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseY < this.drag._minMouseScrollY) {\n                        this.drag._scrollProperty = 'scrollTop';\n                        this.drag._scrollAxis = 'Y';\n                        this.drag._scrollDist = Math.round((this.mouseY - this.drag._minMouseScrollY) / 2);\n                    }\n                    else {\n                        // Scrolling down?\n                        this.drag._maxMouseScrollY = this.drag._winScrollTop + Garnish.$win.height() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseY > this.drag._maxMouseScrollY) {\n                            this.drag._scrollProperty = 'scrollTop';\n                            this.drag._scrollAxis = 'Y';\n                            this.drag._scrollDist = Math.round((this.mouseY - this.drag._maxMouseScrollY) / 2);\n                        }\n                    }\n                }\n\n                if (!this.drag._scrollProperty && this.settings.axis !== Garnish.Y_AXIS) {\n                    // Scrolling left?\n                    this.drag._winScrollLeft = Garnish.$win.scrollLeft();\n                    this.drag._minMouseScrollX = this.drag._winScrollLeft + Garnish.BaseDrag.windowScrollTargetSize;\n\n                    if (this.mouseX < this.drag._minMouseScrollX) {\n                        this.drag._scrollProperty = 'scrollLeft';\n                        this.drag._scrollAxis = 'X';\n                        this.drag._scrollDist = Math.round((this.mouseX - this.drag._minMouseScrollX) / 2);\n                    }\n                    else {\n                        // Scrolling right?\n                        this.drag._maxMouseScrollX = this.drag._winScrollLeft + Garnish.$win.width() - Garnish.BaseDrag.windowScrollTargetSize;\n\n                        if (this.mouseX > this.drag._maxMouseScrollX) {\n                            this.drag._scrollProperty = 'scrollLeft';\n                            this.drag._scrollAxis = 'X';\n                            this.drag._scrollDist = Math.round((this.mouseX - this.drag._maxMouseScrollX) / 2);\n                        }\n                    }\n                }\n\n                if (this.drag._scrollProperty) {\n                    // Are we starting to scroll now?\n                    if (!this.scrollProperty) {\n                        if (!this.scrollProxy) {\n                            this.scrollProxy = this._scrollWindow.bind(this);\n                        }\n\n                        if (this.scrollFrame) {\n                            Garnish.cancelAnimationFrame(this.scrollFrame);\n                            this.scrollFrame = null;\n                        }\n\n                        this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n                    }\n\n                    this.scrollProperty = this.drag._scrollProperty;\n                    this.scrollAxis = this.drag._scrollAxis;\n                    this.scrollDist = this.drag._scrollDist;\n                }\n                else {\n                    this._cancelWindowScroll();\n                }\n            }\n\n            this.onDrag();\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            this.dragging = false;\n            this.onDragStop();\n\n            // Clear the scroll animation\n            this._cancelWindowScroll();\n        },\n\n        /**\n         * Add Items\n         *\n         * @param {object} items Elements that should be draggable.\n         */\n        addItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure this element doesn't belong to another dragger\n                if ($.data(item, 'drag')) {\n                    Garnish.log('Element was added to more than one dragger');\n                    $.data(item, 'drag').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'drag', this);\n\n                // Add the listener\n                this.addListener(item, 'mousedown', '_handleMouseDown');\n            }\n\n            this.$items = this.$items.add(items);\n        },\n\n        /**\n         * Remove Items\n         *\n         * @param {object} items Elements that should no longer be draggable.\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('dragStart');\n                this.settings.onDragStart();\n            }.bind(this));\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('drag');\n                this.settings.onDrag();\n            }.bind(this));\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('dragStop');\n                this.settings.onDragStop();\n            }.bind(this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Handle Mouse Down\n         */\n        _handleMouseDown: function(ev) {\n            // Ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Ignore if we already have a target\n            if (this.$targetItem) {\n                return;\n            }\n\n            // Ignore if they didn't actually click on the handle\n            var $target = $(ev.target),\n                $handle = this._getItemHandle(ev.currentTarget);\n\n            if (!$target.is($handle) && !$target.closest($handle).length) {\n                return;\n            }\n\n            // Make sure the target isn't a button (unless the button is the handle)\n            if (ev.currentTarget !== ev.target && this.settings.ignoreHandleSelector) {\n                if (\n                    $target.is(this.settings.ignoreHandleSelector) ||\n                    $target.closest(this.settings.ignoreHandleSelector).length\n                ) {\n                    return;\n                }\n            }\n\n            ev.preventDefault();\n\n            // Make sure that dragging is allowed right now\n            if (!this.allowDragging()) {\n                return;\n            }\n\n            // Capture the target\n            this.$targetItem = $(ev.currentTarget);\n\n            // Capture the current mouse position\n            this.mousedownX = this.mouseX = ev.pageX;\n            this.mousedownY = this.mouseY = ev.pageY;\n\n            // Capture the difference between the mouse position and the target item's offset\n            var offset = this.$targetItem.offset();\n            this.mouseOffsetX = ev.pageX - offset.left;\n            this.mouseOffsetY = ev.pageY - offset.top;\n\n            // Listen for mousemove, mouseup\n            this.addListener(Garnish.$doc, 'mousemove', '_handleMouseMove');\n            this.addListener(Garnish.$doc, 'mouseup', '_handleMouseUp');\n        },\n\n        _getItemHandle: function(item) {\n            if (this.settings.handle) {\n                if (typeof this.settings.handle === 'object') {\n                    return $(this.settings.handle);\n                }\n\n                if (typeof this.settings.handle === 'string') {\n                    return $(this.settings.handle, item);\n                }\n\n                if (typeof this.settings.handle === 'function') {\n                    return $(this.settings.handle(item));\n                }\n            }\n\n            return $(item);\n        },\n\n        /**\n         * Handle Mouse Move\n         */\n        _handleMouseMove: function(ev) {\n            ev.preventDefault();\n\n            this.realMouseX = ev.pageX;\n            this.realMouseY = ev.pageY;\n\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this.mouseX = ev.pageX;\n            }\n\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this.mouseY = ev.pageY;\n            }\n\n            this.mouseDistX = this.mouseX - this.mousedownX;\n            this.mouseDistY = this.mouseY - this.mousedownY;\n\n            if (!this.dragging) {\n                // Has the mouse moved far enough to initiate dragging yet?\n                this._handleMouseMove._mouseDist = Garnish.getDist(this.mousedownX, this.mousedownY, this.realMouseX, this.realMouseY);\n\n                if (this._handleMouseMove._mouseDist >= Garnish.BaseDrag.minMouseDist) {\n                    this.startDragging();\n                }\n            }\n\n            if (this.dragging) {\n                this.drag(true);\n            }\n        },\n\n        /**\n         * Handle Moues Up\n         */\n        _handleMouseUp: function(ev) {\n            // Unbind the document events\n            this.removeAllListeners(Garnish.$doc);\n\n            if (this.dragging) {\n                this.stopDragging();\n            }\n\n            this.$targetItem = null;\n        },\n\n        /**\n         * Scroll Window\n         */\n        _scrollWindow: function() {\n            this._.scrollPos = Garnish.$scrollContainer[this.scrollProperty]();\n            Garnish.$scrollContainer[this.scrollProperty](this._.scrollPos + this.scrollDist);\n\n            this['mouse' + this.scrollAxis] -= this._.scrollPos - Garnish.$scrollContainer[this.scrollProperty]();\n            this['realMouse' + this.scrollAxis] = this['mouse' + this.scrollAxis];\n\n            this.drag();\n\n            this.scrollFrame = Garnish.requestAnimationFrame(this.scrollProxy);\n        },\n\n        /**\n         * Cancel Window Scroll\n         */\n        _cancelWindowScroll: function() {\n            if (this.scrollFrame) {\n                Garnish.cancelAnimationFrame(this.scrollFrame);\n                this.scrollFrame = null;\n            }\n\n            this.scrollProperty = null;\n            this.scrollAxis = null;\n            this.scrollDist = null;\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            this.removeAllListeners(item);\n            $.removeData(item, 'drag');\n        }\n    },\n    {\n        minMouseDist: 1,\n        windowScrollTargetSize: 25,\n\n        defaults: {\n            handle: null,\n            axis: null,\n            ignoreHandleSelector: 'input, textarea, button, select, .btn',\n\n            onDragStart: $.noop,\n            onDrag: $.noop,\n            onDragStop: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Checkbox select class\n */\nGarnish.CheckboxSelect = Garnish.Base.extend(\n    {\n        $container: null,\n        $all: null,\n        $options: null,\n\n        init: function(container) {\n            this.$container = $(container);\n\n            // Is this already a checkbox select?\n            if (this.$container.data('checkboxSelect')) {\n                Garnish.log('Double-instantiating a checkbox select on an element');\n                this.$container.data('checkbox-select').destroy();\n            }\n\n            this.$container.data('checkboxSelect', this);\n\n            var $checkboxes = this.$container.find('input');\n            this.$all = $checkboxes.filter('.all:first');\n            this.$options = $checkboxes.not(this.$all);\n\n            this.addListener(this.$all, 'change', 'onAllChange');\n        },\n\n        onAllChange: function() {\n            var isAllChecked = this.$all.prop('checked');\n\n            this.$options.prop({\n                checked: isAllChecked,\n                disabled: isAllChecked\n            });\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('checkboxSelect');\n            this.base();\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Context Menu\n */\nGarnish.ContextMenu = Garnish.Base.extend(\n    {\n        $target: null,\n        options: null,\n        $menu: null,\n        showingMenu: false,\n\n        /**\n         * Constructor\n         */\n        init: function(target, options, settings) {\n            this.$target = $(target);\n\n            // Is this already a context menu target?\n            if (this.$target.data('contextmenu')) {\n                Garnish.log('Double-instantiating a context menu on an element');\n                this.$target.data('contextmenu').destroy();\n            }\n\n            this.$target.data('contextmenu', this);\n\n            this.options = options;\n            this.setSettings(settings, Garnish.ContextMenu.defaults);\n\n            Garnish.ContextMenu.counter++;\n\n            this.enable();\n        },\n\n        /**\n         * Build Menu\n         */\n        buildMenu: function() {\n            this.$menu = $('<div class=\"' + this.settings.menuClass + '\" style=\"display: none\" />');\n\n            var $ul = $('<ul/>').appendTo(this.$menu);\n\n            for (var i in this.options) {\n                if (!this.options.hasOwnProperty(i)) {\n                    continue;\n                }\n\n                var option = this.options[i];\n\n                if (option === '-') {\n                    // Create a new <ul>\n                    $('<hr/>').appendTo(this.$menu);\n                    $ul = $('<ul/>').appendTo(this.$menu);\n                }\n                else {\n                    var $li = $('<li></li>').appendTo($ul),\n                        $a = $('<a>' + option.label + '</a>').appendTo($li);\n\n                    if (typeof option.onClick === 'function') {\n                        // maintain the current $a and options.onClick variables\n                        (function($a, onClick) {\n                            setTimeout(function() {\n                                $a.mousedown(function(ev) {\n                                    this.hideMenu();\n                                    // call the onClick callback, with the scope set to the item,\n                                    // and pass it the event with currentTarget set to the item as well\n                                    onClick.call(this.currentTarget, $.extend(ev, {currentTarget: this.currentTarget}));\n                                }.bind(this));\n                            }.bind(this), 1);\n                        }).call(this, $a, option.onClick);\n                    }\n                }\n            }\n        },\n\n        /**\n         * Show Menu\n         */\n        showMenu: function(ev) {\n            // Ignore left mouse clicks\n            if (ev.type === 'mousedown' && ev.which !== Garnish.SECONDARY_CLICK) {\n                return;\n            }\n\n            if (ev.type === 'contextmenu') {\n                // Prevent the real context menu from showing\n                ev.preventDefault();\n            }\n\n            // Ignore if already showing\n            if (this.showing && ev.currentTarget === this.currentTarget) {\n                return;\n            }\n\n            this.currentTarget = ev.currentTarget;\n\n            if (!this.$menu) {\n                this.buildMenu();\n            }\n\n            this.$menu.appendTo(document.body);\n            this.$menu.show();\n            this.$menu.css({left: ev.pageX + 1, top: ev.pageY - 4});\n\n            this.showing = true;\n\n            setTimeout(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'hideMenu');\n            }.bind(this), 0);\n        },\n\n        /**\n         * Hide Menu\n         */\n        hideMenu: function() {\n            this.removeListener(Garnish.$doc, 'mousedown');\n            this.$menu.hide();\n            this.showing = false;\n        },\n\n        /**\n         * Enable\n         */\n        enable: function() {\n            this.addListener(this.$target, 'contextmenu,mousedown', 'showMenu');\n        },\n\n        /**\n         * Disable\n         */\n        disable: function() {\n            this.removeListener(this.$target, 'contextmenu,mousedown');\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$target.removeData('contextmenu');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuClass: 'menu'\n        },\n        counter: 0\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag class\n *\n * Builds on the BaseDrag class by \"picking up\" the selceted element(s),\n * without worrying about what to do when an element is being dragged.\n */\nGarnish.Drag = Garnish.BaseDrag.extend(\n    {\n        targetItemWidth: null,\n        targetItemHeight: null,\n        targetItemPositionInDraggee: null,\n\n        $draggee: null,\n\n        otherItems: null,\n        totalOtherItems: null,\n\n        helpers: null,\n        helperTargets: null,\n        helperPositions: null,\n        helperLagIncrement: null,\n        updateHelperPosProxy: null,\n        updateHelperPosFrame: null,\n\n        lastMouseX: null,\n        lastMouseY: null,\n\n        _returningHelpersToDraggees: false,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.Drag.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Returns whether dragging is allowed right now.\n         */\n        allowDragging: function() {\n            // Don't allow dragging if we're in the middle of animating the helpers back to the draggees\n            return !this._returningHelpersToDraggees;\n        },\n\n        /**\n         * Start Dragging\n         */\n        startDragging: function() {\n            // Reset some things\n            this.helpers = [];\n            this.helperTargets = [];\n            this.helperPositions = [];\n            this.lastMouseX = this.lastMouseY = null;\n\n            // Capture the target item's width/height\n            this.targetItemWidth = this.$targetItem.outerWidth();\n            this.targetItemHeight = this.$targetItem.outerHeight();\n\n            // Save the draggee's display style (block/table-row) so we can re-apply it later\n            this.draggeeDisplay = this.$targetItem.css('display');\n\n            // Set the $draggee\n            this.setDraggee(this.findDraggee());\n\n            // Create an array of all the other items\n            this.otherItems = [];\n\n            for (var i = 0; i < this.$items.length; i++) {\n                var item = this.$items[i];\n\n                if ($.inArray(item, this.$draggee) === -1) {\n                    this.otherItems.push(item);\n                }\n            }\n\n            this.totalOtherItems = this.otherItems.length;\n\n            // Keep the helpers following the cursor, with a little lag to smooth it out\n            if (!this.updateHelperPosProxy) {\n                this.updateHelperPosProxy = this._updateHelperPos.bind(this);\n            }\n\n            this.helperLagIncrement = this.helpers.length === 1 ? 0 : this.settings.helperLagIncrementDividend / (this.helpers.length - 1);\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n\n            this.base();\n        },\n\n        /**\n         * Sets the draggee.\n         */\n        setDraggee: function($draggee) {\n            // Record the target item's position in the draggee\n            this.targetItemPositionInDraggee = $.inArray(this.$targetItem[0], $draggee.add(this.$targetItem[0]));\n\n            // Keep the target item at the front of the list\n            this.$draggee = $([this.$targetItem[0]].concat($draggee.not(this.$targetItem).toArray()));\n\n            // Create the helper(s)\n            if (this.settings.singleHelper) {\n                this._createHelper(0);\n            }\n            else {\n                for (var i = 0; i < this.$draggee.length; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee) {\n                this.$draggee.hide();\n            }\n            else if (this.settings.collapseDraggees) {\n                this.$targetItem.css('visibility', 'hidden');\n                this.$draggee.not(this.$targetItem).hide();\n            }\n            else {\n                this.$draggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Appends additional items to the draggee.\n         */\n        appendDraggee: function($newDraggee) {\n            if (!$newDraggee.length) {\n                return;\n            }\n\n            if (!this.settings.collapseDraggees) {\n                var oldLength = this.$draggee.length;\n            }\n\n            this.$draggee = $(this.$draggee.toArray().concat($newDraggee.toArray()));\n\n            // Create new helpers?\n            if (!this.settings.collapseDraggees) {\n                var newLength = this.$draggee.length;\n\n                for (var i = oldLength; i < newLength; i++) {\n                    this._createHelper(i);\n                }\n            }\n\n            if (this.settings.removeDraggee || this.settings.collapseDraggees) {\n                $newDraggee.hide();\n            }\n            else {\n                $newDraggee.css('visibility', 'hidden');\n            }\n        },\n\n        /**\n         * Drag\n         */\n        drag: function(didMouseMove) {\n            // Update the draggee's virtual midpoint\n            this.draggeeVirtualMidpointX = this.mouseX - this.mouseOffsetX + (this.targetItemWidth / 2);\n            this.draggeeVirtualMidpointY = this.mouseY - this.mouseOffsetY + (this.targetItemHeight / 2);\n\n            this.base(didMouseMove);\n        },\n\n        /**\n         * Stop Dragging\n         */\n        stopDragging: function() {\n            // Clear the helper animation\n            Garnish.cancelAnimationFrame(this.updateHelperPosFrame);\n\n            this.base();\n        },\n\n        /**\n         * Identifies the item(s) that are being dragged.\n         */\n        findDraggee: function() {\n            switch (typeof this.settings.filter) {\n                case 'function': {\n                    return this.settings.filter();\n                }\n\n                case 'string': {\n                    return this.$items.filter(this.settings.filter);\n                }\n\n                default: {\n                    return this.$targetItem;\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            return this.mouseX - this.mouseOffsetX;\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            return this.mouseY - this.mouseOffsetY;\n        },\n\n        /**\n         * Return Helpers to Draggees\n         */\n        returnHelpersToDraggees: function() {\n            this._returningHelpersToDraggees = true;\n\n            for (var i = 0; i < this.helpers.length; i++) {\n                var $draggee = this.$draggee.eq(i),\n                    $helper = this.helpers[i];\n\n                $draggee.css({\n                    display: this.draggeeDisplay,\n                    visibility: 'hidden'\n                });\n\n                var draggeeOffset = $draggee.offset();\n                var callback;\n\n                if (i === 0) {\n                    callback = this._showDraggee.bind(this);\n                }\n                else {\n                    callback = null;\n                }\n\n                $helper.velocity({left: draggeeOffset.left, top: draggeeOffset.top}, Garnish.FX_DURATION, callback);\n            }\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        onReturnHelpersToDraggees: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('returnHelpersToDraggees');\n                this.settings.onReturnHelpersToDraggees();\n            }.bind(this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        /**\n         * Creates a helper.\n         */\n        _createHelper: function(i) {\n            var $draggee = this.$draggee.eq(i),\n                $draggeeHelper = $draggee.clone().addClass('draghelper');\n\n            if (this.settings.copyDraggeeInputValuesToHelper) {\n                Garnish.copyInputValues($draggee, $draggeeHelper);\n            }\n\n            // Remove any name= attributes so radio buttons don't lose their values\n            $draggeeHelper.find('[name]').attr('name', '');\n\n            $draggeeHelper\n                .outerWidth(Math.ceil($draggee.outerWidth()))\n                .outerHeight(Math.ceil($draggee.outerHeight()))\n                .css({margin: 0, 'pointer-events': 'none'});\n\n            if (this.settings.helper) {\n                if (typeof this.settings.helper === 'function') {\n                    $draggeeHelper = this.settings.helper($draggeeHelper);\n                }\n                else {\n                    $draggeeHelper = $(this.settings.helper).append($draggeeHelper);\n                }\n            }\n\n            $draggeeHelper.appendTo(Garnish.$bod);\n\n            var helperPos = this._getHelperTarget(i);\n\n            $draggeeHelper.css({\n                position: 'absolute',\n                top: helperPos.top,\n                left: helperPos.left,\n                zIndex: this.settings.helperBaseZindex + this.$draggee.length - i,\n                opacity: this.settings.helperOpacity\n            });\n\n            this.helperPositions[i] = {\n                top: helperPos.top,\n                left: helperPos.left\n            };\n\n            this.helpers.push($draggeeHelper);\n        },\n\n        /**\n         * Update Helper Position\n         */\n        _updateHelperPos: function() {\n            // Has the mouse moved?\n            if (this.mouseX !== this.lastMouseX || this.mouseY !== this.lastMouseY) {\n                // Get the new target helper positions\n                for (this._updateHelperPos._i = 0; this._updateHelperPos._i < this.helpers.length; this._updateHelperPos._i++) {\n                    this.helperTargets[this._updateHelperPos._i] = this._getHelperTarget(this._updateHelperPos._i);\n                }\n\n                this.lastMouseX = this.mouseX;\n                this.lastMouseY = this.mouseY;\n            }\n\n            // Gravitate helpers toward their target positions\n            for (this._updateHelperPos._j = 0; this._updateHelperPos._j < this.helpers.length; this._updateHelperPos._j++) {\n                this._updateHelperPos._lag = this.settings.helperLagBase + (this.helperLagIncrement * this._updateHelperPos._j);\n\n                this.helperPositions[this._updateHelperPos._j] = {\n                    left: this.helperPositions[this._updateHelperPos._j].left + ((this.helperTargets[this._updateHelperPos._j].left - this.helperPositions[this._updateHelperPos._j].left) / this._updateHelperPos._lag),\n                    top: this.helperPositions[this._updateHelperPos._j].top + ((this.helperTargets[this._updateHelperPos._j].top - this.helperPositions[this._updateHelperPos._j].top) / this._updateHelperPos._lag)\n                };\n\n                this.helpers[this._updateHelperPos._j].css(this.helperPositions[this._updateHelperPos._j]);\n            }\n\n            // Let's do this again on the next frame!\n            this.updateHelperPosFrame = Garnish.requestAnimationFrame(this.updateHelperPosProxy);\n        },\n\n        /**\n         * Get the helper position for a draggee helper\n         */\n        _getHelperTarget: function(i) {\n            return {\n                left: this.getHelperTargetX() + (this.settings.helperSpacingX * i),\n                top: this.getHelperTargetY() + (this.settings.helperSpacingY * i)\n            };\n        },\n\n        _showDraggee: function() {\n            // Remove the helpers\n            for (var i = 0; i < this.helpers.length; i++) {\n                this.helpers[i].remove();\n            }\n\n            this.helpers = null;\n\n            this.$draggee.show().css('visibility', 'inherit');\n\n            this.onReturnHelpersToDraggees();\n\n            this._returningHelpersToDraggees = false;\n        }\n    },\n    {\n        defaults: {\n            filter: null,\n            singleHelper: false,\n            collapseDraggees: false,\n            removeDraggee: false,\n            copyDraggeeInputValuesToHelper: false,\n            helperOpacity: 1,\n            helper: null,\n            helperBaseZindex: 1000,\n            helperLagBase: 1,\n            helperLagIncrementDividend: 1.5,\n            helperSpacingX: 5,\n            helperSpacingY: 5,\n            onReturnHelpersToDraggees: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag-and-drop class\n *\n * Builds on the Drag class by allowing you to set up \"drop targets\"\n * which the dragged elemements can be dropped onto.\n */\nGarnish.DragDrop = Garnish.Drag.extend({\n\n        $dropTargets: null,\n        $activeDropTarget: null,\n\n        /**\n         * Constructor\n         */\n        init: function(settings) {\n            settings = $.extend({}, Garnish.DragDrop.defaults, settings);\n            this.base(settings);\n        },\n\n        updateDropTargets: function() {\n            if (this.settings.dropTargets) {\n                if (typeof this.settings.dropTargets === 'function') {\n                    this.$dropTargets = $(this.settings.dropTargets());\n                }\n                else {\n                    this.$dropTargets = $(this.settings.dropTargets);\n                }\n\n                // Discard if it's an empty array\n                if (!this.$dropTargets.length) {\n                    this.$dropTargets = null;\n                }\n            }\n        },\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.updateDropTargets();\n            this.$activeDropTarget = null;\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            if (this.$dropTargets) {\n                this.onDrag._activeDropTarget = null;\n\n                // is the cursor over any of the drop target?\n                for (this.onDrag._i = 0; this.onDrag._i < this.$dropTargets.length; this.onDrag._i++) {\n                    this.onDrag._elem = this.$dropTargets[this.onDrag._i];\n\n                    if (Garnish.hitTest(this.mouseX, this.mouseY, this.onDrag._elem)) {\n                        this.onDrag._activeDropTarget = this.onDrag._elem;\n                        break;\n                    }\n                }\n\n                // has the drop target changed?\n                if (\n                    (this.$activeDropTarget && this.onDrag._activeDropTarget !== this.$activeDropTarget[0]) ||\n                    (!this.$activeDropTarget && this.onDrag._activeDropTarget !== null)\n                ) {\n                    // was there a previous one?\n                    if (this.$activeDropTarget) {\n                        this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n                    }\n\n                    // remember the new one\n                    if (this.onDrag._activeDropTarget) {\n                        this.$activeDropTarget = $(this.onDrag._activeDropTarget).addClass(this.settings.activeDropTargetClass);\n                    }\n                    else {\n                        this.$activeDropTarget = null;\n                    }\n\n                    this.settings.onDropTargetChange(this.$activeDropTarget);\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            if (this.$dropTargets && this.$activeDropTarget) {\n                this.$activeDropTarget.removeClass(this.settings.activeDropTargetClass);\n            }\n\n            this.base();\n        },\n\n        /**\n         * Fade Out Helpers\n         */\n        fadeOutHelpers: function() {\n            for (var i = 0; i < this.helpers.length; i++) {\n                (function($draggeeHelper) {\n                    $draggeeHelper.velocity('fadeOut', {\n                        duration: Garnish.FX_DURATION,\n                        complete: function() {\n                            $draggeeHelper.remove();\n                        }\n                    });\n                })(this.helpers[i]);\n            }\n        }\n    },\n    {\n        defaults: {\n            dropTargets: null,\n            onDropTargetChange: $.noop,\n            activeDropTargetClass: 'active'\n        }\n    });\n\n/** global: Garnish */\n/**\n * Drag-to-move clas\n *\n * Builds on the BaseDrag class by simply moving the dragged element(s) along with the mouse.\n */\nGarnish.DragMove = Garnish.BaseDrag.extend(\n    {\n        onDrag: function(items, settings) {\n            this.$targetItem.css({\n                left: this.mouseX - this.mouseOffsetX,\n                top: this.mouseY - this.mouseOffsetY\n            });\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Drag-to-sort class\n *\n * Builds on the Drag class by allowing you to sort the elements amongst themselves.\n */\nGarnish.DragSort = Garnish.Drag.extend(\n    {\n        $heightedContainer: null,\n        $insertion: null,\n        insertionVisible: false,\n        oldDraggeeIndexes: null,\n        newDraggeeIndexes: null,\n        closestItem: null,\n\n        _midpointVersion: 0,\n        _$prevItem: null,\n\n        /**\n         * Constructor\n         *\n         * @param {object} items    Elements that should be draggable right away. (Can be skipped.)\n         * @param {object} settings Any settings that should override the defaults.\n         */\n        init: function(items, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (settings)\n                settings = items;\n                items = null;\n            }\n\n            settings = $.extend({}, Garnish.DragSort.defaults, settings);\n            this.base(items, settings);\n        },\n\n        /**\n         * Creates the insertion element.\n         */\n        createInsertion: function() {\n            if (this.settings.insertion) {\n                if (typeof this.settings.insertion === 'function') {\n                    return $(this.settings.insertion(this.$draggee));\n                }\n                else {\n                    return $(this.settings.insertion);\n                }\n            }\n        },\n\n        /**\n         * Returns the helper’s target X position\n         */\n        getHelperTargetX: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetX._draggeeOffsetX = this.$draggee.offset().left;\n                return this.getHelperTargetX._draggeeOffsetX + ((this.mouseX - this.mouseOffsetX - this.getHelperTargetX._draggeeOffsetX) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns the helper’s target Y position\n         */\n        getHelperTargetY: function() {\n            if (this.settings.magnetStrength !== 1) {\n                this.getHelperTargetY._draggeeOffsetY = this.$draggee.offset().top;\n                return this.getHelperTargetY._draggeeOffsetY + ((this.mouseY - this.mouseOffsetY - this.getHelperTargetY._draggeeOffsetY) / this.settings.magnetStrength);\n            }\n            else {\n                return this.base();\n            }\n        },\n\n        /**\n         * Returns whether the draggee can be inserted before a given item.\n         */\n        canInsertBefore: function($item) {\n            return true;\n        },\n\n        /**\n         * Returns whether the draggee can be inserted after a given item.\n         */\n        canInsertAfter: function($item) {\n            return true;\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Drag Start\n         */\n        onDragStart: function() {\n            this.oldDraggeeIndexes = this._getDraggeeIndexes();\n\n            // Are we supposed to be moving the target item to the front, and is it not already there?\n            if (\n                this.settings.moveTargetItemToFront &&\n                this.$draggee.length > 1 &&\n                this._getItemIndex(this.$draggee[0]) > this._getItemIndex(this.$draggee[1])\n            ) {\n                // Reposition the target item before the other draggee items in the DOM\n                this.$draggee.first().insertBefore(this.$draggee[1]);\n            }\n\n            // Create the insertion\n            this.$insertion = this.createInsertion();\n            this._placeInsertionWithDraggee();\n\n            this.closestItem = null;\n            this._clearMidpoints();\n\n            //  Get the closest container that has a height\n            if (this.settings.container) {\n                this.$heightedContainer = $(this.settings.container);\n\n                while (!this.$heightedContainer.height()) {\n                    this.$heightedContainer = this.$heightedContainer.parent();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag\n         */\n        onDrag: function() {\n            // If there's a container set, make sure that we're hovering over it\n            if (this.$heightedContainer && !Garnish.hitTest(this.mouseX, this.mouseY, this.$heightedContainer)) {\n                if (this.closestItem) {\n                    this.closestItem = null;\n                    this._removeInsertion();\n                }\n            }\n            else {\n                // Is there a new closest item?\n                if (\n                    this.closestItem !== (this.closestItem = this._getClosestItem()) &&\n                    this.closestItem !== null\n                ) {\n                    this._updateInsertion();\n                }\n            }\n\n            this.base();\n        },\n\n        /**\n         * On Drag Stop\n         */\n        onDragStop: function() {\n            this._removeInsertion();\n\n            // Should we keep the target item where it was?\n            if (!this.settings.moveTargetItemToFront && this.targetItemPositionInDraggee !== 0) {\n                this.$targetItem.insertAfter(this.$draggee.eq(this.targetItemPositionInDraggee));\n            }\n\n            // Return the helpers to the draggees\n            this.returnHelpersToDraggees();\n\n            this.base();\n\n            // Has the item actually moved?\n            this.$items = $().add(this.$items);\n            this.newDraggeeIndexes = this._getDraggeeIndexes();\n\n            if (this.newDraggeeIndexes.join(',') !== this.oldDraggeeIndexes.join(',')) {\n                this.onSortChange();\n            }\n        },\n\n        /**\n         * On Insertion Point Change event\n         */\n        onInsertionPointChange: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('insertionPointChange');\n                this.settings.onInsertionPointChange();\n            }.bind(this));\n        },\n\n        /**\n         * On Sort Change event\n         */\n        onSortChange: function() {\n            Garnish.requestAnimationFrame(function() {\n                this.trigger('sortChange');\n                this.settings.onSortChange();\n            }.bind(this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _getItemIndex: function(item) {\n            return $.inArray(item, this.$items);\n        },\n\n        _getDraggeeIndexes: function() {\n            var indexes = [];\n\n            for (var i = 0; i < this.$draggee.length; i++) {\n                indexes.push(this._getItemIndex(this.$draggee[i]))\n            }\n\n            return indexes;\n        },\n\n        /**\n         * Returns the closest item to the cursor.\n         */\n        _getClosestItem: function() {\n            this._getClosestItem._closestItem = null;\n\n            // Start by checking the draggee/insertion, if either are visible\n            if (!this.settings.removeDraggee) {\n                this._testForClosestItem(this.$draggee[0]);\n            }\n            else if (this.insertionVisible) {\n                this._testForClosestItem(this.$insertion[0]);\n            }\n\n            // Check items before the draggee\n            if (this._getClosestItem._closestItem) {\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._closestItem)\n            }\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._startXDist = this._getClosestItem._lastXDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX) : null;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._startYDist = this._getClosestItem._lastYDist = this._getClosestItem._closestItem ? Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY) : null;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.first().prev();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertBefore(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.prev();\n            }\n\n            // Check items after the draggee\n            if (this.settings.axis !== Garnish.Y_AXIS) {\n                this._getClosestItem._lastXDist = this._getClosestItem._startXDist;\n            }\n            if (this.settings.axis !== Garnish.X_AXIS) {\n                this._getClosestItem._lastYDist = this._getClosestItem._startYDist;\n            }\n\n            this._getClosestItem._$otherItem = this.$draggee.last().next();\n\n            while (this._getClosestItem._$otherItem.length) {\n                // See if we're just getting further away\n                this._getClosestItem._midpoint = this._getItemMidpoint(this._getClosestItem._$otherItem[0]);\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._xDist = Math.abs(this._getClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._yDist = Math.abs(this._getClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n                }\n\n                if (\n                    (this.settings.axis === Garnish.Y_AXIS || (this._getClosestItem._lastXDist !== null && this._getClosestItem._xDist > this._getClosestItem._lastXDist)) &&\n                    (this.settings.axis === Garnish.X_AXIS || (this._getClosestItem._lastYDist !== null && this._getClosestItem._yDist > this._getClosestItem._lastYDist))\n                ) {\n                    break;\n                }\n\n                if (this.settings.axis !== Garnish.Y_AXIS) {\n                    this._getClosestItem._lastXDist = this._getClosestItem._xDist;\n                }\n                if (this.settings.axis !== Garnish.X_AXIS) {\n                    this._getClosestItem._lastYDist = this._getClosestItem._yDist;\n                }\n\n                // Give the extending class a chance to allow/disallow this item\n                if (this.canInsertAfter(this._getClosestItem._$otherItem)) {\n                    this._testForClosestItem(this._getClosestItem._$otherItem[0]);\n                }\n\n                // Prep the next item\n                this._getClosestItem._$otherItem = this._getClosestItem._$otherItem.next();\n            }\n\n            // Return the result\n\n            // Ignore if it's the draggee or insertion\n            if (\n                this._getClosestItem._closestItem !== this.$draggee[0] &&\n                (!this.insertionVisible || this._getClosestItem._closestItem !== this.$insertion[0])\n            ) {\n                return this._getClosestItem._closestItem;\n            }\n            else {\n                return null;\n            }\n        },\n\n        _clearMidpoints: function() {\n            this._midpointVersion++;\n            this._$prevItem = null;\n        },\n\n        _getItemMidpoint: function(item) {\n            if ($.data(item, 'midpointVersion') !== this._midpointVersion) {\n                // If this isn't the draggee, temporarily move the draggee to this item\n                this._getItemMidpoint._repositionDraggee = (\n                    !this.settings.axis &&\n                    (!this.settings.removeDraggee || this.insertionVisible) &&\n                    item !== this.$draggee[0] &&\n                    (!this.$insertion || item !== this.$insertion.get(0))\n                );\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Is this the first time we've had to temporarily reposition the draggee since the last midpoint clearing?\n                    if (!this._$prevItem) {\n                        this._$prevItem = (this.insertionVisible ? this.$insertion : this.$draggee).first().prev();\n                    }\n\n                    this._moveDraggeeToItem(item);\n\n                    // Now figure out which element we're actually getting the midpoint of\n                    if (!this.settings.removeDraggee) {\n                        this._getItemMidpoint._$item = this.$draggee;\n                    }\n                    else {\n                        this._getItemMidpoint._$item = this.$insertion;\n                    }\n                }\n                else {\n                    // We're actually getting the midpoint of this item\n                    this._getItemMidpoint._$item = $(item);\n                }\n\n                this._getItemMidpoint._offset = this._getItemMidpoint._$item.offset();\n\n                $.data(item, 'midpoint', {\n                    x: this._getItemMidpoint._offset.left + this._getItemMidpoint._$item.outerWidth() / 2,\n                    y: this._getItemMidpoint._offset.top + this._getItemMidpoint._$item.outerHeight() / 2\n                });\n\n                $.data(item, 'midpointVersion', this._midpointVersion);\n\n                delete this._getItemMidpoint._$item;\n                delete this._getItemMidpoint._offset;\n\n                if (this._getItemMidpoint._repositionDraggee) {\n                    // Move the draggee back\n                    if (this._$prevItem.length) {\n                        this.$draggee.insertAfter(this._$prevItem);\n                    }\n                    else {\n                        this.$draggee.prependTo(this.$draggee.parent());\n                    }\n\n                    this._placeInsertionWithDraggee();\n                }\n            }\n\n            return $.data(item, 'midpoint');\n        },\n\n        _testForClosestItem: function(item) {\n            this._testForClosestItem._midpoint = this._getItemMidpoint(item);\n            this._testForClosestItem._mouseDistX = Math.abs(this._testForClosestItem._midpoint.x - this.draggeeVirtualMidpointX);\n            this._testForClosestItem._mouseDistY = Math.abs(this._testForClosestItem._midpoint.y - this.draggeeVirtualMidpointY);\n\n            // Don't even consider items that are further away on the Y axis\n            if (\n                this._getClosestItem._closestItem === null ||\n                this._testForClosestItem._mouseDistY < this._getClosestItem._closestItemMouseDistY ||\n                (\n                    this._testForClosestItem._mouseDistY === this._getClosestItem._closestItemMouseDistY &&\n                    this._testForClosestItem._mouseDistX <= this._getClosestItem._closestItemMouseDistX\n                )\n            ) {\n                this._getClosestItem._closestItem = item;\n                this._getClosestItem._closestItemMouseDistX = this._testForClosestItem._mouseDistX;\n                this._getClosestItem._closestItemMouseDistY = this._testForClosestItem._mouseDistY;\n            }\n        },\n\n        /**\n         * Updates the position of the insertion point.\n         */\n        _updateInsertion: function() {\n            if (this.closestItem) {\n                this._moveDraggeeToItem(this.closestItem);\n            }\n\n            // Now that things have shifted around, invalidate the midpoints\n            this._clearMidpoints();\n\n            this.onInsertionPointChange();\n        },\n\n        _moveDraggeeToItem: function(item) {\n            // Going down?\n            if (this.$draggee.index() < $(item).index()) {\n                this.$draggee.insertAfter(item);\n            }\n            else {\n                this.$draggee.insertBefore(item);\n            }\n\n            this._placeInsertionWithDraggee();\n        },\n\n        _placeInsertionWithDraggee: function() {\n            if (this.$insertion) {\n                this.$insertion.insertBefore(this.$draggee.first());\n                this.insertionVisible = true;\n            }\n        },\n\n        /**\n         * Removes the insertion, if it's visible.\n         */\n        _removeInsertion: function() {\n            if (this.insertionVisible) {\n                this.$insertion.remove();\n                this.insertionVisible = false;\n            }\n        }\n    },\n    {\n        defaults: {\n            container: null,\n            insertion: null,\n            moveTargetItemToFront: false,\n            magnetStrength: 1,\n            onInsertionPointChange: $.noop,\n            onSortChange: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * ESC key manager class\n * @deprecated Use Garnish.ShortcutManager instead\n */\nGarnish.EscManager = Garnish.Base.extend(\n    {\n        handlers: null,\n\n        init: function() {\n            this.handlers = [];\n\n            this.addListener(Garnish.$bod, 'keyup', function(ev) {\n                if (ev.keyCode === Garnish.ESC_KEY) {\n                    this.escapeLatest(ev);\n                }\n            });\n        },\n\n        register: function(obj, func) {\n            this.handlers.push({\n                obj: obj,\n                func: func\n            });\n        },\n\n        unregister: function(obj) {\n            for (var i = this.handlers.length - 1; i >= 0; i--) {\n                if (this.handlers[i].obj === obj) {\n                    this.handlers.splice(i, 1);\n                }\n            }\n        },\n\n        escapeLatest: function(ev) {\n            if (this.handlers.length) {\n                var handler = this.handlers.pop();\n\n                var func;\n\n                if (typeof handler.func === 'function') {\n                    func = handler.func;\n                }\n                else {\n                    func = handler.obj[handler.func];\n                }\n\n                func.call(handler.obj, ev);\n\n                if (typeof handler.obj.trigger === 'function') {\n                    handler.obj.trigger('escape');\n                }\n            }\n        }\n    }\n);\n\nGarnish.escManager = new Garnish.EscManager();\n\n/** global: Garnish */\n/**\n * HUD\n */\nGarnish.HUD = Garnish.Base.extend(\n    {\n        $trigger: null,\n        $fixedTriggerParent: null,\n        $hud: null,\n        $tip: null,\n        $body: null,\n        $header: null,\n        $footer: null,\n        $mainContainer: null,\n        $main: null,\n        $shade: null,\n\n        showing: false,\n        orientation: null,\n\n        updatingSizeAndPosition: false,\n        windowWidth: null,\n        windowHeight: null,\n        scrollTop: null,\n        scrollLeft: null,\n        mainWidth: null,\n        mainHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(trigger, bodyContents, settings) {\n\n            this.$trigger = $(trigger);\n\n            this.setSettings(settings, Garnish.HUD.defaults);\n            this.on('show', this.settings.onShow);\n            this.on('hide', this.settings.onHide);\n            this.on('submit', this.settings.onSubmit);\n\n            if (typeof Garnish.HUD.activeHUDs === 'undefined') {\n                Garnish.HUD.activeHUDs = {};\n            }\n\n            this.$shade = $('<div/>', {'class': this.settings.shadeClass});\n            this.$hud = $('<div/>', {'class': this.settings.hudClass}).data('hud', this);\n            this.$tip = $('<div/>', {'class': this.settings.tipClass}).appendTo(this.$hud);\n            this.$body = $('<form/>', {'class': this.settings.bodyClass}).appendTo(this.$hud);\n            this.$mainContainer = $('<div/>', {'class': this.settings.mainContainerClass}).appendTo(this.$body);\n            this.$main = $('<div/>', {'class': this.settings.mainClass}).appendTo(this.$mainContainer);\n\n            this.updateBody(bodyContents);\n\n            // See if the trigger is fixed\n            var $parent = this.$trigger;\n\n            do {\n                if ($parent.css('position') === 'fixed') {\n                    this.$fixedTriggerParent = $parent;\n                    break;\n                }\n\n                $parent = $parent.offsetParent();\n            }\n            while ($parent.length && $parent.prop('nodeName') !== 'HTML');\n\n            if (this.$fixedTriggerParent) {\n                this.$hud.css('position', 'fixed');\n            }\n            else {\n                this.$hud.css('position', 'absolute');\n            }\n\n            // Hide the HUD until it gets positioned\n\t\t\tthis.$hud.css('opacity', 0);\n            this.show();\n            this.$hud.css('opacity', 1);\n\n            this.addListener(this.$body, 'submit', '_handleSubmit');\n\n            if (this.settings.hideOnShadeClick) {\n                this.addListener(this.$shade, 'tap,click', 'hide');\n            }\n\n            if (this.settings.closeBtn) {\n                this.addListener(this.settings.closeBtn, 'activate', 'hide');\n            }\n\n            this.addListener(Garnish.$win, 'resize', 'updateSizeAndPosition');\n            this.addListener(this.$main, 'resize', 'updateSizeAndPosition');\n            if (!this.$fixedTriggerParent && Garnish.$scrollContainer[0] !== Garnish.$win[0]) {\n                this.addListener(Garnish.$scrollContainer, 'scroll', 'updateSizeAndPosition');\n            }\n        },\n\n        /**\n         * Update the body contents\n         */\n        updateBody: function(bodyContents) {\n            // Cleanup\n            this.$main.html('');\n\n            if (this.$header) {\n                this.$hud.removeClass('has-header');\n                this.$header.remove();\n                this.$header = null;\n            }\n\n            if (this.$footer) {\n                this.$hud.removeClass('has-footer');\n                this.$footer.remove();\n                this.$footer = null;\n            }\n\n            // Append the new body contents\n            this.$main.append(bodyContents);\n\n            // Look for a header and footer\n            var $header = this.$main.find('.' + this.settings.headerClass + ':first'),\n                $footer = this.$main.find('.' + this.settings.footerClass + ':first');\n\n            if ($header.length) {\n                this.$header = $header.insertBefore(this.$mainContainer);\n                this.$hud.addClass('has-header');\n            }\n\n            if ($footer.length) {\n                this.$footer = $footer.insertAfter(this.$mainContainer);\n                this.$hud.addClass('has-footer');\n            }\n        },\n\n        /**\n         * Show\n         */\n        show: function(ev) {\n            if (ev && ev.stopPropagation) {\n                ev.stopPropagation();\n            }\n\n            if (this.showing) {\n                return;\n            }\n\n            if (this.settings.closeOtherHUDs) {\n                for (var hudID in Garnish.HUD.activeHUDs) {\n                    if (!Garnish.HUD.activeHUDs.hasOwnProperty(hudID)) {\n                        continue;\n                    }\n                    Garnish.HUD.activeHUDs[hudID].hide();\n                }\n            }\n\n            // Move it to the end of <body> so it gets the highest sub-z-index\n            this.$shade.appendTo(Garnish.$bod);\n            this.$hud.appendTo(Garnish.$bod);\n\n            this.$hud.show();\n            this.$shade.show();\n            this.showing = true;\n            Garnish.HUD.activeHUDs[this._namespace] = this;\n\n            Garnish.shortcutManager.addLayer();\n\n            if (this.settings.hideOnEsc) {\n                Garnish.shortcutManager.registerShortcut(Garnish.ESC_KEY, this.hide.bind(this));\n            }\n\n            this.onShow();\n            this.enable();\n\n            if (this.updateRecords()) {\n                // Prevent the browser from jumping\n                this.$hud.css('top', Garnish.$scrollContainer.scrollTop());\n\n                this.updateSizeAndPosition(true);\n            }\n        },\n\n        onShow: function() {\n            this.trigger('show');\n        },\n\n        updateRecords: function() {\n            var changed = false;\n            changed = (this.windowWidth !== (this.windowWidth = Garnish.$win.width())) || changed;\n            changed = (this.windowHeight !== (this.windowHeight = Garnish.$win.height())) || changed;\n            changed = (this.scrollTop !== (this.scrollTop = Garnish.$scrollContainer.scrollTop())) || changed;\n            changed = (this.scrollLeft !== (this.scrollLeft = Garnish.$scrollContainer.scrollLeft())) || changed;\n            changed = (this.mainWidth !== (this.mainWidth = this.$main.outerWidth())) || changed;\n            changed = (this.mainHeight !== (this.mainHeight = this.$main.outerHeight())) || changed;\n            return changed;\n        },\n\n        updateSizeAndPosition: function(force) {\n            if (force === true || (this.updateRecords() && !this.updatingSizeAndPosition)) {\n                this.updatingSizeAndPosition = true;\n                Garnish.requestAnimationFrame(this.updateSizeAndPositionInternal.bind(this));\n            }\n        },\n\n        updateSizeAndPositionInternal: function() {\n            var triggerWidth,\n                triggerHeight,\n                triggerOffset,\n                windowScrollLeft,\n                windowScrollTop,\n                scrollContainerTriggerOffset,\n                scrollContainerScrollLeft,\n                scrollContainerScrollTop,\n                hudBodyWidth,\n                hudBodyHeight;\n\n            // Get the window sizes and trigger offset\n\n            windowScrollLeft = Garnish.$win.scrollLeft();\n            windowScrollTop = Garnish.$win.scrollTop();\n\n            // Get the trigger's dimensions\n            triggerWidth = this.$trigger.outerWidth();\n            triggerHeight = this.$trigger.outerHeight();\n\n            // Get the offsets for each side of the trigger element\n            triggerOffset = this.$trigger.offset();\n\n            if (this.$fixedTriggerParent) {\n                triggerOffset.left -= windowScrollLeft;\n                triggerOffset.top -= windowScrollTop;\n\n                scrollContainerTriggerOffset = triggerOffset;\n\n                windowScrollLeft = 0;\n                windowScrollTop = 0;\n                scrollContainerScrollLeft = 0;\n                scrollContainerScrollTop = 0;\n            }\n            else {\n                scrollContainerTriggerOffset = Garnish.getOffset(this.$trigger);\n\n                scrollContainerScrollLeft = Garnish.$scrollContainer.scrollLeft();\n                scrollContainerScrollTop = Garnish.$scrollContainer.scrollTop();\n            }\n\n            triggerOffset.right = triggerOffset.left + triggerWidth;\n            triggerOffset.bottom = triggerOffset.top + triggerHeight;\n\n            scrollContainerTriggerOffset.right = scrollContainerTriggerOffset.left + triggerWidth;\n            scrollContainerTriggerOffset.bottom = scrollContainerTriggerOffset.top + triggerHeight;\n\n            // Get the HUD dimensions\n            this.$hud.css({\n                width: ''\n            });\n\n            this.$mainContainer.css({\n                height: '',\n                'overflow-x': '',\n                'overflow-y': ''\n            });\n\n            hudBodyWidth = this.$body.width();\n            hudBodyHeight = this.$body.height();\n\n            // Determine the best orientation for the HUD\n\n            // Find the actual available top/right/bottom/left clearances\n            var clearances = {\n                bottom: this.windowHeight + scrollContainerScrollTop - scrollContainerTriggerOffset.bottom,\n                top: scrollContainerTriggerOffset.top - scrollContainerScrollTop,\n                right: this.windowWidth + scrollContainerScrollLeft - scrollContainerTriggerOffset.right,\n                left: scrollContainerTriggerOffset.left - scrollContainerScrollLeft\n            };\n\n            // Find the first position that has enough room\n            this.orientation = null;\n\n            for (var i = 0; i < this.settings.orientations.length; i++) {\n                var orientation = this.settings.orientations[i],\n                    relevantSize = (orientation === 'top' || orientation === 'bottom' ? hudBodyHeight : hudBodyWidth);\n\n                if (clearances[orientation] - (this.settings.windowSpacing + this.settings.triggerSpacing) >= relevantSize) {\n                    // This is the first orientation that has enough room in order of preference, so we'll go with this\n                    this.orientation = orientation;\n                    break;\n                }\n\n                if (!this.orientation || clearances[orientation] > clearances[this.orientation]) {\n                    // Use this as a fallback as it's the orientation with the most clearance so far\n                    this.orientation = orientation;\n                }\n            }\n\n            // Just in case...\n            if (!this.orientation || $.inArray(this.orientation, ['bottom', 'top', 'right', 'left']) === -1) {\n                this.orientation = 'bottom'\n            }\n\n            // Update the tip class\n            if (this.tipClass) {\n                this.$tip.removeClass(this.tipClass);\n            }\n\n            this.tipClass = this.settings.tipClass + '-' + Garnish.HUD.tipClasses[this.orientation];\n            this.$tip.addClass(this.tipClass);\n\n            // Make sure the HUD body is within the allowed size\n\n            var maxHudBodyWidth,\n                maxHudBodyHeight;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                maxHudBodyWidth = this.windowWidth - this.settings.windowSpacing * 2;\n                maxHudBodyHeight = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n            }\n            else {\n                maxHudBodyWidth = clearances[this.orientation] - this.settings.windowSpacing - this.settings.triggerSpacing;\n                maxHudBodyHeight = this.windowHeight - this.settings.windowSpacing * 2;\n            }\n\n            if (maxHudBodyWidth < this.settings.minBodyWidth) {\n                maxHudBodyWidth = this.settings.minBodyWidth;\n            }\n\n            if (maxHudBodyHeight < this.settings.minBodyHeight) {\n                maxHudBodyHeight = this.settings.minBodyHeight;\n            }\n\n            if (hudBodyWidth > maxHudBodyWidth || hudBodyWidth < this.settings.minBodyWidth) {\n                if (hudBodyWidth > maxHudBodyWidth) {\n                    hudBodyWidth = maxHudBodyWidth;\n                }\n                else {\n                    hudBodyWidth = this.settings.minBodyWidth;\n                }\n\n                this.$hud.width(hudBodyWidth);\n\n                // Is there any overflow now?\n                if (this.mainWidth > maxHudBodyWidth) {\n                    this.$mainContainer.css('overflow-x', 'scroll');\n                }\n\n                // The height may have just changed\n                hudBodyHeight = this.$body.height();\n            }\n\n            if (hudBodyHeight > maxHudBodyHeight || hudBodyHeight < this.settings.minBodyHeight) {\n                if (hudBodyHeight > maxHudBodyHeight) {\n                    hudBodyHeight = maxHudBodyHeight;\n                }\n                else {\n                    hudBodyHeight = this.settings.minBodyHeight;\n                }\n\n                var mainHeight = hudBodyHeight;\n\n                if (this.$header) {\n                    mainHeight -= this.$header.outerHeight();\n                }\n\n                if (this.$footer) {\n                    mainHeight -= this.$footer.outerHeight();\n                }\n\n                this.$mainContainer.height(mainHeight);\n\n                // Is there any overflow now?\n                if (this.mainHeight > mainHeight) {\n                    this.$mainContainer.css('overflow-y', 'scroll');\n                }\n            }\n\n            // Set the HUD/tip positions\n            var triggerCenter, left, top;\n\n            if (this.orientation === 'top' || this.orientation === 'bottom') {\n                // Center the HUD horizontally\n                var maxLeft = (this.windowWidth + windowScrollLeft) - (hudBodyWidth + this.settings.windowSpacing);\n                var minLeft = (windowScrollLeft + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.left + Math.round(triggerWidth / 2);\n                left = triggerCenter - Math.round(hudBodyWidth / 2);\n\n                if (left > maxLeft) {\n                    left = maxLeft;\n                }\n                if (left < minLeft) {\n                    left = minLeft;\n                }\n\n                this.$hud.css('left', left);\n\n                var tipLeft = (triggerCenter - left) - (this.settings.tipWidth / 2);\n                this.$tip.css({left: tipLeft, top: ''});\n\n                if (this.orientation === 'top') {\n                    top = triggerOffset.top - (hudBodyHeight + this.settings.triggerSpacing);\n                    this.$hud.css('top', top);\n                }\n                else {\n                    top = triggerOffset.bottom + this.settings.triggerSpacing;\n                    this.$hud.css('top', top);\n                }\n            }\n            else {\n                // Center the HUD vertically\n                var maxTop = (this.windowHeight + windowScrollTop) - (hudBodyHeight + this.settings.windowSpacing);\n                var minTop = (windowScrollTop + this.settings.windowSpacing);\n                triggerCenter = triggerOffset.top + Math.round(triggerHeight / 2);\n                top = triggerCenter - Math.round(hudBodyHeight / 2);\n\n                if (top > maxTop) {\n                    top = maxTop;\n                }\n                if (top < minTop) {\n                    top = minTop;\n                }\n\n                this.$hud.css('top', top);\n\n                var tipTop = (triggerCenter - top) - (this.settings.tipWidth / 2);\n                this.$tip.css({top: tipTop, left: ''});\n\n\n                if (this.orientation === 'left') {\n                    left = triggerOffset.left - (hudBodyWidth + this.settings.triggerSpacing);\n                    this.$hud.css('left', left);\n                }\n                else {\n                    left = triggerOffset.right + this.settings.triggerSpacing;\n                    this.$hud.css('left', left);\n                }\n            }\n\n            this.updatingSizeAndPosition = false;\n            this.trigger('updateSizeAndPosition');\n        },\n\n        /**\n         * Hide\n         */\n        hide: function() {\n            if (!this.showing) {\n                return;\n            }\n\n            this.disable();\n\n            this.$hud.hide();\n            this.$shade.hide();\n\n            this.showing = false;\n            delete Garnish.HUD.activeHUDs[this._namespace];\n            Garnish.shortcutManager.removeLayer();\n            this.onHide();\n        },\n\n        onHide: function() {\n            this.trigger('hide');\n        },\n\n        toggle: function() {\n            if (this.showing) {\n                this.hide();\n            }\n            else {\n                this.show();\n            }\n        },\n\n        submit: function() {\n            this.onSubmit();\n        },\n\n        onSubmit: function() {\n            this.trigger('submit');\n        },\n\n        _handleSubmit: function(ev) {\n            ev.preventDefault();\n            this.submit();\n        }\n    },\n    {\n        tipClasses: {bottom: 'top', top: 'bottom', right: 'left', left: 'right'},\n\n        defaults: {\n            shadeClass: 'hud-shade',\n            hudClass: 'hud',\n            tipClass: 'tip',\n            bodyClass: 'body',\n            headerClass: 'hud-header',\n            footerClass: 'hud-footer',\n            mainContainerClass: 'main-container',\n            mainClass: 'main',\n            orientations: ['bottom', 'top', 'right', 'left'],\n            triggerSpacing: 10,\n            windowSpacing: 10,\n            tipWidth: 30,\n            minBodyWidth: 200,\n            minBodyHeight: 0,\n            onShow: $.noop,\n            onHide: $.noop,\n            onSubmit: $.noop,\n            closeBtn: null,\n            closeOtherHUDs: true,\n            hideOnEsc: true,\n            hideOnShadeClick: true,\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Menu\n */\nGarnish.Menu = Garnish.Base.extend(\n    {\n        settings: null,\n        visible: false,\n\n        $container: null,\n        $options: null,\n        $anchor: null,\n\n        menuId: null,\n\n        _windowWidth: null,\n        _windowHeight: null,\n        _windowScrollLeft: null,\n        _windowScrollTop: null,\n\n        _anchorOffset: null,\n        _anchorWidth: null,\n        _anchorHeight: null,\n        _anchorOffsetRight: null,\n        _anchorOffsetBottom: null,\n\n        _menuWidth: null,\n        _menuHeight: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, settings) {\n            this.setSettings(settings, Garnish.Menu.defaults);\n\n            this.$container = $(container);\n\n            this.$options = $();\n            this.addOptions(this.$container.find('a'));\n\n            // Menu List\n            this.menuId = 'menu' + this._namespace;\n            this.$menuList = $('ul', this.$container);\n            this.$menuList.attr({\n                'role': 'listbox',\n                'id': this.menuId,\n                'aria-hidden': 'true'\n            });\n\n            // Deprecated\n            if (this.settings.attachToElement) {\n                this.settings.anchor = this.settings.attachToElement;\n                Garnish.log('The \\'attachToElement\\' setting is deprecated. Use \\'anchor\\' instead.');\n            }\n\n            if (this.settings.anchor) {\n                this.$anchor = $(this.settings.anchor);\n            }\n\n            // Prevent clicking on the container from hiding the menu\n            this.addListener(this.$container, 'mousedown', function(ev) {\n                ev.stopPropagation();\n\n                if (ev.target.nodeName !== 'INPUT') {\n                    // Prevent this from causing the menu button to blur\n                    ev.preventDefault();\n                }\n            });\n        },\n\n        addOptions: function($options) {\n            this.$options = this.$options.add($options);\n            $options.data('menu', this);\n\n            $options.each(function(optionKey, option) {\n                $(option).attr({\n                    'role': 'option',\n                    'tabindex': '-1',\n                    'id': this.menuId + '-option-' + optionKey\n                });\n            }.bind(this));\n\n            this.removeAllListeners($options);\n            this.addListener($options, 'click', function(ev) {\n                this.selectOption(ev.currentTarget);\n            });\n        },\n\n        setPositionRelativeToAnchor: function() {\n            this._windowWidth = Garnish.$win.width();\n            this._windowHeight = Garnish.$win.height();\n            this._windowScrollLeft = Garnish.$win.scrollLeft();\n            this._windowScrollTop = Garnish.$win.scrollTop();\n\n            this._anchorOffset = this.$anchor.offset();\n            this._anchorWidth = this.$anchor.outerWidth();\n            this._anchorHeight = this.$anchor.outerHeight();\n            this._anchorOffsetRight = this._anchorOffset.left + this._anchorHeight;\n            this._anchorOffsetBottom = this._anchorOffset.top + this._anchorHeight;\n\n            this.$container.css('minWidth', 0);\n            this.$container.css('minWidth', this._anchorWidth - (this.$container.outerWidth() - this.$container.width()));\n\n            this._menuWidth = this.$container.outerWidth();\n            this._menuHeight = this.$container.outerHeight();\n\n            // Is there room for the menu below the anchor?\n            var topClearance = this._anchorOffset.top - this._windowScrollTop,\n                bottomClearance = this._windowHeight + this._windowScrollTop - this._anchorOffsetBottom;\n\n            if (bottomClearance >= this._menuHeight || (topClearance < this._menuHeight && bottomClearance >= topClearance)) {\n                this.$container.css({\n                    top: this._anchorOffsetBottom,\n                    maxHeight: bottomClearance - this.settings.windowSpacing\n                });\n            } else {\n                this.$container.css({\n                    top: this._anchorOffset.top - Math.min(this._menuHeight, topClearance - this.settings.windowSpacing),\n                    maxHeight: topClearance - this.settings.windowSpacing\n                });\n            }\n\n            // Figure out how we're aliging it\n            var align = this.$container.data('align');\n\n            if (align !== 'left' && align !== 'center' && align !== 'right') {\n                align = 'left';\n            }\n\n            if (align === 'center') {\n                this._alignCenter();\n            }\n            else {\n                // Figure out which options are actually possible\n                var rightClearance = this._windowWidth + this._windowScrollLeft - (this._anchorOffset.left + this._menuWidth),\n                    leftClearance = this._anchorOffsetRight - this._menuWidth;\n\n                if (align === 'right' && leftClearance >= 0 || rightClearance < 0) {\n                    this._alignRight();\n                }\n                else {\n                    this._alignLeft();\n                }\n            }\n\n            delete this._windowWidth;\n            delete this._windowHeight;\n            delete this._windowScrollLeft;\n            delete this._windowScrollTop;\n            delete this._anchorOffset;\n            delete this._anchorWidth;\n            delete this._anchorHeight;\n            delete this._anchorOffsetRight;\n            delete this._anchorOffsetBottom;\n            delete this._menuWidth;\n            delete this._menuHeight;\n        },\n\n        show: function() {\n            if (this.visible) {\n                return;\n            }\n\n            // Move the menu to the end of the DOM\n            this.$container.appendTo(Garnish.$bod);\n\n            if (this.$anchor) {\n                this.setPositionRelativeToAnchor();\n            }\n\n            this.$container.velocity('stop');\n            this.$container.css({\n                opacity: 1,\n                display: 'block'\n            });\n\n            this.$menuList.attr('aria-hidden', 'false');\n\n            Garnish.shortcutManager\n                .addLayer()\n                .registerShortcut(Garnish.ESC_KEY, this.hide.bind(this));\n\n            this.addListener(Garnish.$scrollContainer, 'scroll', 'setPositionRelativeToAnchor');\n\n            this.visible = true;\n            this.trigger('show');\n        },\n\n        hide: function() {\n            if (!this.visible) {\n                return;\n            }\n\n            this.$menuList.attr('aria-hidden', 'true');\n\n            this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION}, function() {\n                this.$container.detach();\n            }.bind(this));\n\n            Garnish.shortcutManager.removeLayer();\n            this.removeListener(Garnish.$scrollContainer, 'scroll');\n            this.visible = false;\n            this.trigger('hide');\n        },\n\n        selectOption: function(option) {\n            this.settings.onOptionSelect(option);\n            this.trigger('optionselect', {selectedOption: option});\n            this.hide();\n        },\n\n        _alignLeft: function() {\n            this.$container.css({\n                left: this._anchorOffset.left,\n                right: 'auto'\n            });\n        },\n\n        _alignRight: function() {\n            this.$container.css({\n                right: this._windowWidth - (this._anchorOffset.left + this._anchorWidth),\n                left: 'auto'\n            });\n        },\n\n        _alignCenter: function() {\n            var left = Math.round((this._anchorOffset.left + this._anchorWidth / 2) - (this._menuWidth / 2));\n\n            if (left < 0) {\n                left = 0;\n            }\n\n            this.$container.css('left', left);\n        }\n\n    },\n    {\n        defaults: {\n            anchor: null,\n            windowSpacing: 5,\n            onOptionSelect: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Menu Button\n */\nGarnish.MenuBtn = Garnish.Base.extend(\n    {\n        $btn: null,\n        menu: null,\n        showingMenu: false,\n        disabled: true,\n\n        /**\n         * Constructor\n         */\n        init: function(btn, menu, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(menu)) {\n                // (btn, settings)\n                settings = menu;\n                menu = null;\n            }\n\n            this.$btn = $(btn);\n            var $menu;\n\n            // Is this already a menu button?\n            if (this.$btn.data('menubtn')) {\n                // Grab the old MenuBtn's menu container\n                if (!menu) {\n                    $menu = this.$btn.data('menubtn').menu.$container;\n                }\n\n                Garnish.log('Double-instantiating a menu button on an element');\n                this.$btn.data('menubtn').destroy();\n            }\n            else if (!menu) {\n                $menu = this.$btn.next('.menu').detach();\n            }\n\n            this.$btn.data('menubtn', this);\n\n            this.setSettings(settings, Garnish.MenuBtn.defaults);\n\n            this.menu = menu || new Garnish.Menu($menu);\n            this.menu.$anchor = $(this.settings.menuAnchor || this.$btn);\n            this.menu.on('optionselect', function(ev) {\n                this.onOptionSelect(ev.selectedOption);\n            }.bind(this));\n\n            this.$btn.attr({\n                'tabindex': 0,\n                'aria-controls': this.menu.menuId,\n                'aria-haspopup': 'listbox',\n                'aria-expanded': 'false'\n            });\n\n            this.menu.on('hide', this.onMenuHide.bind(this));\n            this.addListener(this.$btn, 'mousedown', 'onMouseDown');\n            this.addListener(this.$btn, 'keydown', 'onKeyDown');\n            this.addListener(this.$btn, 'blur', 'onBlur');\n            this.enable();\n        },\n\n        onBlur: function() {\n            if (this.showingMenu) {\n                Garnish.requestAnimationFrame(function() {\n                    if (!$.contains(this.menu.$container.get(0), document.activeElement)) {\n                        this.hideMenu();\n                    }\n                }.bind(this));\n            }\n        },\n\n        onKeyDown: function(ev) {\n            var $option;\n\n            switch (ev.keyCode) {\n                case Garnish.RETURN_KEY: {\n                    ev.preventDefault();\n\n                    const $currentOption = this.menu.$options.filter('.hover');\n                    if ($currentOption.length > 0) {\n                        $currentOption.get(0).click();\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        const $currentOption = this.menu.$options.filter('.hover');\n                        if ($currentOption.length > 0) {\n                            $currentOption.get(0).click();\n                        }\n                    } else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n\n                        this.focusOption($option);\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index + 1) < this.menu.$options.length) {\n                                        $option = $(this.menu.$options[(index + 1)]);\n                                    }\n                                }\n                            }\n                        }.bind(this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[0]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.first();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    if (this.showingMenu) {\n                        $.each(this.menu.$options, function(index, value) {\n                            if (!$option) {\n                                if ($(value).hasClass('hover')) {\n                                    if ((index - 1) >= 0) {\n                                        $option = $(this.menu.$options[(index - 1)]);\n                                    }\n                                }\n                            }\n                        }.bind(this));\n\n                        if (!$option) {\n                            $option = $(this.menu.$options[(this.menu.$options.length - 1)]);\n                        }\n                    }\n                    else {\n                        this.showMenu();\n\n                        $option = this.menu.$options.filter('.sel:first');\n\n                        if ($option.length === 0) {\n                            $option = this.menu.$options.last();\n                        }\n                    }\n\n                    this.focusOption($option);\n\n                    break;\n                }\n            }\n        },\n\n        focusOption: function($option) {\n            this.menu.$options.removeClass('hover');\n\n            $option.addClass('hover');\n\n            this.menu.$menuList.attr('aria-activedescendant', $option.attr('id'));\n            this.$btn.attr('aria-activedescendant', $option.attr('id'));\n        },\n\n        onMouseDown: function(ev) {\n            if (ev.which !== Garnish.PRIMARY_CLICK || Garnish.isCtrlKeyPressed(ev) || ev.target.nodeName === 'INPUT') {\n                return;\n            }\n\n            ev.preventDefault();\n\n            if (this.showingMenu) {\n                this.hideMenu();\n            }\n            else {\n                this.showMenu();\n            }\n        },\n\n        showMenu: function() {\n            if (this.disabled) {\n                return;\n            }\n\n            this.menu.show();\n            this.$btn.addClass('active');\n            this.$btn.trigger('focus');\n            this.$btn.attr('aria-expanded', 'true');\n\n            this.showingMenu = true;\n\n            setTimeout(function() {\n                this.addListener(Garnish.$doc, 'mousedown', 'onMouseDown');\n            }.bind(this), 1);\n        },\n\n        hideMenu: function() {\n            this.menu.hide();\n            this.$btn.attr('aria-expanded', 'false');\n        },\n\n        onMenuHide: function() {\n            this.$btn.removeClass('active');\n            this.showingMenu = false;\n\n            this.removeListener(Garnish.$doc, 'mousedown');\n        },\n\n        onOptionSelect: function(option) {\n            this.settings.onOptionSelect(option);\n            this.trigger('optionSelect', {option: option});\n        },\n\n        enable: function() {\n            this.disabled = false;\n        },\n\n        disable: function() {\n            this.disabled = true;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$btn.removeData('menubtn');\n            this.base();\n        }\n    },\n    {\n        defaults: {\n            menuAnchor: null,\n            onOptionSelect: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Mixed input\n *\n * @todo RTL support, in the event that the input doesn't have dir=\"ltr\".\n */\nGarnish.MixedInput = Garnish.Base.extend(\n    {\n        $container: null,\n        elements: null,\n        focussedElement: null,\n        blurTimeout: null,\n\n        init: function(container, settings) {\n            this.$container = $(container);\n            this.setSettings(settings, Garnish.MixedInput.defaults);\n\n            this.elements = [];\n\n            // Allow the container to receive focus\n            this.$container.attr('tabindex', 0);\n            this.addListener(this.$container, 'focus', 'onFocus');\n        },\n\n        getElementIndex: function($elem) {\n            return $.inArray($elem, this.elements);\n        },\n\n        isText: function($elem) {\n            return ($elem.prop('nodeName') === 'INPUT');\n        },\n\n        onFocus: function() {\n            // Set focus to the first element\n            if (this.elements.length) {\n                var $elem = this.elements[0];\n                this.setFocus($elem);\n                this.setCarotPos($elem, 0);\n            }\n            else {\n                this.addTextElement();\n            }\n        },\n\n        addTextElement: function(index) {\n            var text = new TextElement(this);\n            this.addElement(text.$input, index);\n            return text;\n        },\n\n        addElement: function($elem, index) {\n            // Was a target index passed, and is it valid?\n            if (typeof index === 'undefined') {\n                if (this.focussedElement) {\n                    var focussedElement = this.focussedElement,\n                        focussedElementIndex = this.getElementIndex(focussedElement);\n\n                    // Is the focus on a text element?\n                    if (this.isText(focussedElement)) {\n                        var selectionStart = focussedElement.prop('selectionStart'),\n                            selectionEnd = focussedElement.prop('selectionEnd'),\n                            val = focussedElement.val(),\n                            preVal = val.substring(0, selectionStart),\n                            postVal = val.substr(selectionEnd);\n\n                        if (preVal && postVal) {\n                            // Split the input into two\n                            focussedElement.val(preVal).trigger('change');\n                            var newText = new TextElement(this);\n                            newText.$input.val(postVal).trigger('change');\n                            this.addElement(newText.$input, focussedElementIndex + 1);\n\n                            // Insert the new element in between them\n                            index = focussedElementIndex + 1;\n                        }\n                        else if (!preVal) {\n                            // Insert the new element before this one\n                            index = focussedElementIndex;\n                        }\n                        else {\n                            // Insert it after this one\n                            index = focussedElementIndex + 1;\n                        }\n                    }\n                    else {\n                        // Just insert the new one after this one\n                        index = focussedElementIndex + 1;\n                    }\n                }\n                else {\n                    // Insert the new element at the end\n                    index = this.elements.length;\n                }\n            }\n\n            // Add the element\n            if (typeof this.elements[index] !== 'undefined') {\n                $elem.insertBefore(this.elements[index]);\n                this.elements.splice(index, 0, $elem);\n            }\n            else {\n                // Just for safe measure, set the index to what it really will be\n                index = this.elements.length;\n\n                this.$container.append($elem);\n                this.elements.push($elem);\n            }\n\n            // Make sure that there are text elements surrounding all non-text elements\n            if (!this.isText($elem)) {\n                // Add a text element before?\n                if (index === 0 || !this.isText(this.elements[index - 1])) {\n                    this.addTextElement(index);\n                    index++;\n                }\n\n                // Add a text element after?\n                if (index === this.elements.length - 1 || !this.isText(this.elements[index + 1])) {\n                    this.addTextElement(index + 1);\n                }\n            }\n\n            // Add event listeners\n            this.addListener($elem, 'click', function() {\n                this.setFocus($elem);\n            });\n\n            // Set focus to the new element\n            setTimeout(function() {\n                this.setFocus($elem);\n            }.bind(this), 1);\n        },\n\n        removeElement: function($elem) {\n            var index = this.getElementIndex($elem);\n            if (index !== -1) {\n                this.elements.splice(index, 1);\n\n                if (!this.isText($elem)) {\n                    // Combine the two now-adjacent text elements\n                    var $prevElem = this.elements[index - 1],\n                        $nextElem = this.elements[index];\n\n                    if (this.isText($prevElem) && this.isText($nextElem)) {\n                        var prevElemVal = $prevElem.val(),\n                            newVal = prevElemVal + $nextElem.val();\n                        $prevElem.val(newVal).trigger('change');\n                        this.removeElement($nextElem);\n                        this.setFocus($prevElem);\n                        this.setCarotPos($prevElem, prevElemVal.length);\n                    }\n                }\n\n                $elem.remove();\n            }\n        },\n\n        setFocus: function($elem) {\n            this.$container.addClass('focus');\n\n            if (!this.focussedElement) {\n                // Prevent the container from receiving focus\n                // as long as one of its elements has focus\n                this.$container.attr('tabindex', '-1');\n            }\n            else {\n                // Blur the previously-focussed element\n                this.blurFocussedElement();\n            }\n\n            $elem.attr('tabindex', '0');\n            $elem.focus();\n            this.focussedElement = $elem;\n\n            this.addListener($elem, 'blur', function() {\n                this.blurTimeout = setTimeout(function() {\n                    if (this.focussedElement === $elem) {\n                        this.blurFocussedElement();\n                        this.focussedElement = null;\n                        this.$container.removeClass('focus');\n\n                        // Get ready for future focus\n                        this.$container.attr('tabindex', '0');\n                    }\n                }.bind(this), 1);\n            });\n        },\n\n        blurFocussedElement: function() {\n            this.removeListener(this.focussedElement, 'blur');\n            this.focussedElement.attr('tabindex', '-1');\n        },\n\n        focusPreviousElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index > 0) {\n                var $elem = this.elements[index - 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the end\n                if (this.isText($elem)) {\n                    var length = $elem.val().length;\n                    this.setCarotPos($elem, length);\n                }\n            }\n        },\n\n        focusNextElement: function($from) {\n            var index = this.getElementIndex($from);\n\n            if (index < this.elements.length - 1) {\n                var $elem = this.elements[index + 1];\n                this.setFocus($elem);\n\n                // If it's a text element, put the carot at the beginning\n                if (this.isText($elem)) {\n                    this.setCarotPos($elem, 0)\n                }\n            }\n        },\n\n        setCarotPos: function($elem, pos) {\n            $elem.prop('selectionStart', pos);\n            $elem.prop('selectionEnd', pos);\n        }\n\n    });\n\n\nvar TextElement = Garnish.Base.extend({\n\n        parentInput: null,\n        $input: null,\n        $stage: null,\n        val: null,\n        focussed: false,\n        interval: null,\n\n        init: function(parentInput) {\n            this.parentInput = parentInput;\n\n            this.$input = $('<input type=\"text\"/>').appendTo(this.parentInput.$container);\n            this.$input.css('margin-right', (2 - TextElement.padding) + 'px');\n\n            this.setWidth();\n\n            this.addListener(this.$input, 'focus', 'onFocus');\n            this.addListener(this.$input, 'blur', 'onBlur');\n            this.addListener(this.$input, 'keydown', 'onKeyDown');\n            this.addListener(this.$input, 'change', 'checkInput');\n        },\n\n        getIndex: function() {\n            return this.parentInput.getElementIndex(this.$input);\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                position: 'absolute',\n                top: -9999,\n                left: -9999,\n                wordWrap: 'nowrap'\n            });\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getTextWidth: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (val) {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Spaces\n                val = val.replace(/ /g, '&nbsp;');\n            }\n\n            this.$stage.html(val);\n            this.stageWidth = this.$stage.width();\n            return this.stageWidth;\n        },\n\n        onFocus: function() {\n            this.focussed = true;\n            this.interval = setInterval(this.checkInput.bind(this), Garnish.NiceText.interval);\n            this.checkInput();\n        },\n\n        onBlur: function() {\n            this.focussed = false;\n            clearInterval(this.interval);\n            this.checkInput();\n        },\n\n        onKeyDown: function(ev) {\n            setTimeout(this.checkInput.bind(this), 1);\n\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    if (this.$input.prop('selectionStart') === this.val.length && this.$input.prop('selectionEnd') === this.val.length) {\n                        // Set focus to the next element\n                        this.parentInput.focusNextElement(this.$input);\n                    }\n                    break;\n                }\n\n                case Garnish.DELETE_KEY: {\n                    if (this.$input.prop('selectionStart') === 0 && this.$input.prop('selectionEnd') === 0) {\n                        // Set focus to the previous element\n                        this.parentInput.focusPreviousElement(this.$input);\n                        ev.preventDefault();\n                    }\n                }\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        setVal: function(val) {\n            this.$input.val(val);\n            this.checkInput();\n        },\n\n        checkInput: function() {\n            // Has the value changed?\n            var changed = (this.val !== this.getVal());\n            if (changed) {\n                this.setWidth();\n                this.onChange();\n            }\n\n            return changed;\n        },\n\n        setWidth: function() {\n            // has the width changed?\n            if (this.stageWidth !== this.getTextWidth(this.val)) {\n                // update the textarea width\n                var width = this.stageWidth + TextElement.padding;\n                this.$input.width(width);\n            }\n        },\n\n        onChange: $.noop\n    },\n    {\n        padding: 20\n    }\n);\n\n/** global: Garnish */\n/**\n * Modal\n */\nGarnish.Modal = Garnish.Base.extend(\n    {\n        $container: null,\n        $shade: null,\n\n        visible: false,\n\n        dragger: null,\n\n        desiredWidth: null,\n        desiredHeight: null,\n        resizeDragger: null,\n        resizeStartWidth: null,\n        resizeStartHeight: null,\n\n        init: function(container, settings) {\n            // Param mapping\n            if (typeof settings === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n            }\n\n            this.setSettings(settings, Garnish.Modal.defaults);\n\n            // Create the shade\n            this.$shade = $('<div class=\"' + this.settings.shadeClass + '\"/>');\n\n            // If the container is already set, drop the shade below it.\n            if (container) {\n                this.$shade.insertBefore(container);\n            }\n            else {\n                this.$shade.appendTo(Garnish.$bod);\n            }\n\n            if (container) {\n                this.setContainer(container);\n\n                if (this.settings.autoShow) {\n                    this.show();\n                }\n            }\n\n            Garnish.Modal.instances.push(this);\n        },\n\n        setContainer: function(container) {\n            this.$container = $(container);\n\n            // Is this already a modal?\n            if (this.$container.data('modal')) {\n                Garnish.log('Double-instantiating a modal on an element');\n                this.$container.data('modal').destroy();\n            }\n\n            this.$container.data('modal', this);\n\n            if (this.settings.draggable) {\n                this.dragger = new Garnish.DragMove(this.$container, {\n                    handle: (this.settings.dragHandleSelector ? this.$container.find(this.settings.dragHandleSelector) : this.$container)\n                });\n            }\n\n            if (this.settings.resizable) {\n                var $resizeDragHandle = $('<div class=\"resizehandle\"/>').appendTo(this.$container);\n\n                this.resizeDragger = new Garnish.BaseDrag($resizeDragHandle, {\n                    onDragStart: this._handleResizeStart.bind(this),\n                    onDrag: this._handleResize.bind(this)\n                });\n            }\n\n            this.addListener(this.$container, 'click', function(ev) {\n                ev.stopPropagation();\n            });\n\n            // Show it if we're late to the party\n            if (this.visible) {\n                this.show();\n            }\n        },\n\n        show: function() {\n            // Close other modals as needed\n            if (this.settings.closeOtherModals && Garnish.Modal.visibleModal && Garnish.Modal.visibleModal !== this) {\n                Garnish.Modal.visibleModal.hide();\n            }\n\n            if (this.$container) {\n                // Move it to the end of <body> so it gets the highest sub-z-index\n                this.$shade.appendTo(Garnish.$bod);\n                this.$container.appendTo(Garnish.$bod);\n\n                this.$container.show();\n                this.updateSizeAndPosition();\n\n                this.$shade.velocity('fadeIn', {\n                    duration: 50,\n                    complete: function() {\n                        this.$container.velocity('fadeIn', {\n                            complete: function() {\n                                this.updateSizeAndPosition();\n                                this.onFadeIn();\n                            }.bind(this)\n                        });\n                    }.bind(this)\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.addListener(this.$shade, 'click', 'hide');\n                }\n\n                this.addListener(Garnish.$win, 'resize', '_handleWindowResize');\n            }\n\n            this.enable();\n\n            if (!this.visible) {\n                this.visible = true;\n                Garnish.Modal.visibleModal = this;\n\n                Garnish.shortcutManager.addLayer();\n\n                if (this.settings.hideOnEsc) {\n                    Garnish.shortcutManager.registerShortcut(Garnish.ESC_KEY, this.hide.bind(this));\n                }\n\n                this.trigger('show');\n                this.settings.onShow();\n            }\n        },\n\n        quickShow: function() {\n            this.show();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.show().css('opacity', 1);\n\n                this.$shade.velocity('stop');\n                this.$shade.show().css('opacity', 1);\n            }\n        },\n\n        hide: function(ev) {\n            if (!this.visible) {\n                return;\n            }\n\n            this.disable();\n\n            if (ev) {\n                ev.stopPropagation();\n            }\n\n            if (this.$container) {\n                this.$container.velocity('fadeOut', {duration: Garnish.FX_DURATION});\n                this.$shade.velocity('fadeOut', {\n                    duration: Garnish.FX_DURATION,\n                    complete: this.onFadeOut.bind(this)\n                });\n\n                if (this.settings.hideOnShadeClick) {\n                    this.removeListener(this.$shade, 'click');\n                }\n\n                this.removeListener(Garnish.$win, 'resize');\n            }\n\n            this.visible = false;\n            Garnish.Modal.visibleModal = null;\n            Garnish.shortcutManager.removeLayer();\n            this.trigger('hide');\n            this.settings.onHide();\n        },\n\n        quickHide: function() {\n            this.hide();\n\n            if (this.$container) {\n                this.$container.velocity('stop');\n                this.$container.css('opacity', 0).hide();\n\n                this.$shade.velocity('stop');\n                this.$shade.css('opacity', 0).hide();\n            }\n        },\n\n        updateSizeAndPosition: function() {\n            if (!this.$container) {\n                return;\n            }\n\n            this.$container.css({\n                'width': (this.desiredWidth ? Math.max(this.desiredWidth, 200) : ''),\n                'height': (this.desiredHeight ? Math.max(this.desiredHeight, 200) : ''),\n                'min-width': '',\n                'min-height': ''\n            });\n\n            // Set the width first so that the height can adjust for the width\n            this.updateSizeAndPosition._windowWidth = Garnish.$win.width();\n            this.updateSizeAndPosition._width = Math.min(this.getWidth(), this.updateSizeAndPosition._windowWidth - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'width': this.updateSizeAndPosition._width,\n                'min-width': this.updateSizeAndPosition._width,\n                'left': Math.round((this.updateSizeAndPosition._windowWidth - this.updateSizeAndPosition._width) / 2)\n            });\n\n            // Now set the height\n            this.updateSizeAndPosition._windowHeight = Garnish.$win.height();\n            this.updateSizeAndPosition._height = Math.min(this.getHeight(), this.updateSizeAndPosition._windowHeight - this.settings.minGutter * 2);\n\n            this.$container.css({\n                'height': this.updateSizeAndPosition._height,\n                'min-height': this.updateSizeAndPosition._height,\n                'top': Math.round((this.updateSizeAndPosition._windowHeight - this.updateSizeAndPosition._height) / 2)\n            });\n\n            this.trigger('updateSizeAndPosition');\n        },\n\n        onFadeIn: function() {\n            this.trigger('fadeIn');\n            this.settings.onFadeIn();\n        },\n\n        onFadeOut: function() {\n            this.trigger('fadeOut');\n            this.settings.onFadeOut();\n        },\n\n        getHeight: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the height of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            this.getHeight._height = this.$container.outerHeight();\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getHeight._height;\n        },\n\n        getWidth: function() {\n            if (!this.$container) {\n                throw 'Attempted to get the width of a modal whose container has not been set.';\n            }\n\n            if (!this.visible) {\n                this.$container.show();\n            }\n\n            // Chrome might be 1px shy here for some reason\n            this.getWidth._width = this.$container.outerWidth() + 1;\n\n            if (!this.visible) {\n                this.$container.hide();\n            }\n\n            return this.getWidth._width;\n        },\n\n        _handleWindowResize: function(ev) {\n            // ignore propagated resize events\n            if (ev.target === window) {\n                this.updateSizeAndPosition();\n            }\n        },\n\n        _handleResizeStart: function() {\n            this.resizeStartWidth = this.getWidth();\n            this.resizeStartHeight = this.getHeight();\n        },\n\n        _handleResize: function() {\n            if (Garnish.ltr) {\n                this.desiredWidth = this.resizeStartWidth + (this.resizeDragger.mouseDistX * 2);\n            }\n            else {\n                this.desiredWidth = this.resizeStartWidth - (this.resizeDragger.mouseDistX * 2);\n            }\n\n            this.desiredHeight = this.resizeStartHeight + (this.resizeDragger.mouseDistY * 2);\n\n            this.updateSizeAndPosition();\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            if (this.$container) {\n                this.$container.removeData('modal').remove();\n            }\n\n            if (this.dragger) {\n                this.dragger.destroy();\n            }\n\n            if (this.resizeDragger) {\n                this.resizeDragger.destroy();\n            }\n\n            this.base();\n        }\n    },\n    {\n        relativeElemPadding: 8,\n        defaults: {\n            autoShow: true,\n            draggable: false,\n            dragHandleSelector: null,\n            resizable: false,\n            minGutter: 10,\n            onShow: $.noop,\n            onHide: $.noop,\n            onFadeIn: $.noop,\n            onFadeOut: $.noop,\n            closeOtherModals: false,\n            hideOnEsc: true,\n            hideOnShadeClick: true,\n            shadeClass: 'modal-shade'\n        },\n        instances: [],\n        visibleModal: null\n    }\n);\n\n/** global: Garnish */\n/**\n * Nice Text\n */\nGarnish.NiceText = Garnish.Base.extend(\n    {\n        $input: null,\n        $hint: null,\n        $stage: null,\n        $charsLeft: null,\n        autoHeight: null,\n        maxLength: null,\n        showCharsLeft: false,\n        showingHint: false,\n        val: null,\n        inputBoxSizing: 'content-box',\n        width: null,\n        height: null,\n        minHeight: null,\n        initialized: false,\n\n        init: function(input, settings) {\n            this.$input = $(input);\n            this.settings = $.extend({}, Garnish.NiceText.defaults, settings);\n\n            if (this.isVisible()) {\n                this.initialize();\n            }\n            else {\n                this.addListener(Garnish.$win, 'resize', 'initializeIfVisible');\n            }\n        },\n\n        isVisible: function() {\n            return (this.$input.height() > 0);\n        },\n\n        initialize: function() {\n            if (this.initialized) {\n                return;\n            }\n\n            this.initialized = true;\n            this.removeListener(Garnish.$win, 'resize');\n\n            this.maxLength = this.$input.attr('maxlength');\n\n            if (this.maxLength) {\n                this.maxLength = parseInt(this.maxLength);\n            }\n\n            if (this.maxLength && (this.settings.showCharsLeft || Garnish.hasAttr(this.$input, 'data-show-chars-left'))) {\n                this.showCharsLeft = true;\n\n                // Remove the maxlength attribute\n                this.$input.removeAttr('maxlength');\n            }\n\n            // Is this already a transparent text input?\n            if (this.$input.data('nicetext')) {\n                Garnish.log('Double-instantiating a transparent text input on an element');\n                this.$input.data('nicetext').destroy();\n            }\n\n            this.$input.data('nicetext', this);\n\n            this.getVal();\n\n            this.autoHeight = (this.settings.autoHeight && this.$input.prop('nodeName') === 'TEXTAREA');\n\n            if (this.autoHeight) {\n                this.minHeight = this.getHeightForValue('');\n                this.updateHeight();\n\n                // Update height when the window resizes\n                this.width = this.$input.width();\n                this.addListener(Garnish.$win, 'resize', 'updateHeightIfWidthChanged');\n            }\n\n            if (this.settings.hint) {\n                this.$hintContainer = $('<div class=\"texthint-container\"/>').insertBefore(this.$input);\n                this.$hint = $('<div class=\"texthint\">' + this.settings.hint + '</div>').appendTo(this.$hintContainer);\n                this.$hint.css({\n                    top: (parseInt(this.$input.css('borderTopWidth')) + parseInt(this.$input.css('paddingTop'))),\n                    left: (parseInt(this.$input.css('borderLeftWidth')) + parseInt(this.$input.css('paddingLeft')) + 1)\n                });\n                Garnish.copyTextStyles(this.$input, this.$hint);\n\n                if (this.val) {\n                    this.$hint.hide();\n                }\n                else {\n                    this.showingHint = true;\n                }\n\n                // Focus the input when clicking on the hint\n                this.addListener(this.$hint, 'mousedown', function(ev) {\n                    ev.preventDefault();\n                    this.$input.focus();\n                });\n            }\n\n            if (this.showCharsLeft) {\n                this.$charsLeft = $('<div aria-live=\"polite\" class=\"' + this.settings.charsLeftClass + '\"/>').insertAfter(this.$input);\n                this.updateCharsLeft();\n            }\n\n            this.addListener(this.$input, 'textchange', 'onTextChange');\n        },\n\n        initializeIfVisible: function() {\n            if (this.isVisible()) {\n                this.initialize();\n            }\n        },\n\n        getVal: function() {\n            this.val = this.$input.val();\n            return this.val;\n        },\n\n        showHint: function() {\n            this.$hint.velocity('fadeIn', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = true;\n        },\n\n        hideHint: function() {\n            this.$hint.velocity('fadeOut', {\n                complete: Garnish.NiceText.hintFadeDuration\n            });\n\n            this.showingHint = false;\n        },\n\n        onTextChange: function() {\n            this.getVal();\n\n            if (this.$hint) {\n                if (this.showingHint && this.val) {\n                    this.hideHint();\n                }\n                else if (!this.showingHint && !this.val) {\n                    this.showHint();\n                }\n            }\n\n            if (this.autoHeight) {\n                this.updateHeight();\n            }\n\n            if (this.showCharsLeft) {\n                this.updateCharsLeft();\n            }\n        },\n\n        buildStage: function() {\n            this.$stage = $('<stage/>').appendTo(Garnish.$bod);\n\n            // replicate the textarea's text styles\n            this.$stage.css({\n                display: 'block',\n                position: 'absolute',\n                top: -9999,\n                left: -9999\n            });\n\n            this.inputBoxSizing = this.$input.css('box-sizing');\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css({\n                    'border-top': this.$input.css('border-top'),\n                    'border-right': this.$input.css('border-right'),\n                    'border-bottom': this.$input.css('border-bottom'),\n                    'border-left': this.$input.css('border-left'),\n                    'padding-top': this.$input.css('padding-top'),\n                    'padding-right': this.$input.css('padding-right'),\n                    'padding-bottom': this.$input.css('padding-bottom'),\n                    'padding-left': this.$input.css('padding-left'),\n                    '-webkit-box-sizing': this.inputBoxSizing,\n                    '-moz-box-sizing': this.inputBoxSizing,\n                    'box-sizing': this.inputBoxSizing\n                });\n            }\n\n            Garnish.copyTextStyles(this.$input, this.$stage);\n        },\n\n        getHeightForValue: function(val) {\n            if (!this.$stage) {\n                this.buildStage();\n            }\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.$stage.css('width', this.$input.outerWidth());\n            }\n            else {\n                this.$stage.css('width', this.$input.width());\n            }\n\n            if (!val) {\n                val = '&nbsp;';\n                for (var i = 1; i < this.$input.prop('rows'); i++) {\n                    val += '<br/>&nbsp;';\n                }\n            }\n            else {\n                // Ampersand entities\n                val = val.replace(/&/g, '&amp;');\n\n                // < and >\n                val = val.replace(/</g, '&lt;');\n                val = val.replace(/>/g, '&gt;');\n\n                // Multiple spaces\n                val = val.replace(/ {2,}/g, function(spaces) {\n                    // TODO: replace with String.repeat() when more broadly available?\n                    var replace = '';\n                    for (var i = 0; i < spaces.length - 1; i++) {\n                        replace += '&nbsp;';\n                    }\n                    return replace + ' ';\n                });\n\n                // Line breaks\n                val = val.replace(/[\\n\\r]$/g, '<br/>&nbsp;');\n                val = val.replace(/[\\n\\r]/g, '<br/>');\n            }\n\n            this.$stage.html(val);\n\n            if (this.inputBoxSizing === 'border-box') {\n                this.getHeightForValue._height = this.$stage.outerHeight();\n            }\n            else {\n                this.getHeightForValue._height = this.$stage.height();\n            }\n\n            if (this.minHeight && this.getHeightForValue._height < this.minHeight) {\n                this.getHeightForValue._height = this.minHeight;\n            }\n\n            return this.getHeightForValue._height;\n        },\n\n        updateHeight: function() {\n            // has the height changed?\n            if (this.height !== (this.height = this.getHeightForValue(this.val))) {\n                this.$input.css('min-height', this.height);\n\n                if (this.initialized) {\n                    this.onHeightChange();\n                }\n            }\n        },\n\n        updateHeightIfWidthChanged: function() {\n            if (this.isVisible() && this.width !== (this.width = this.$input.width()) && this.width) {\n                this.updateHeight();\n            }\n        },\n\n        onHeightChange: function() {\n            this.settings.onHeightChange();\n        },\n\n        updateCharsLeft: function() {\n            this.updateCharsLeft._charsLeft = this.maxLength - this.val.length;\n            this.$charsLeft.html(Garnish.NiceText.charsLeftHtml(this.updateCharsLeft._charsLeft));\n\n            if (this.updateCharsLeft._charsLeft >= 0) {\n                this.$charsLeft.removeClass(this.settings.negativeCharsLeftClass);\n            }\n            else {\n                this.$charsLeft.addClass(this.settings.negativeCharsLeftClass);\n            }\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$input.removeData('nicetext');\n\n            if (this.$hint) {\n                this.$hint.remove();\n            }\n\n            if (this.$stage) {\n                this.$stage.remove();\n            }\n\n            this.base();\n        }\n    },\n    {\n        interval: 100,\n        hintFadeDuration: 50,\n        charsLeftHtml: function(charsLeft) {\n            return charsLeft;\n        },\n        defaults: {\n            autoHeight: true,\n            showCharsLeft: false,\n            charsLeftClass: 'chars-left',\n            negativeCharsLeftClass: 'negative-chars-left',\n            onHeightChange: $.noop\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Select\n */\nGarnish.Select = Garnish.Base.extend(\n    {\n        $container: null,\n        $items: null,\n        $selectedItems: null,\n        $focusedItem: null,\n\n        mousedownTarget: null,\n        mouseUpTimeout: null,\n        callbackFrame: null,\n\n        $focusable: null,\n        $first: null,\n        first: null,\n        $last: null,\n        last: null,\n\n        /**\n         * Constructor\n         */\n        init: function(container, items, settings) {\n            this.$container = $(container);\n\n            // Param mapping\n            if (typeof items === 'undefined' && $.isPlainObject(container)) {\n                // (settings)\n                settings = container;\n                container = null;\n                items = null;\n            }\n            else if (typeof settings === 'undefined' && $.isPlainObject(items)) {\n                // (container, settings)\n                settings = items;\n                items = null;\n            }\n\n            // Is this already a select?\n            if (this.$container.data('select')) {\n                Garnish.log('Double-instantiating a select on an element');\n                this.$container.data('select').destroy();\n            }\n\n            this.$container.data('select', this);\n\n            this.setSettings(settings, Garnish.Select.defaults);\n\n            this.$items = $();\n            this.$selectedItems = $();\n\n            this.addItems(items);\n\n            // --------------------------------------------------------------------\n\n            if (this.settings.allowEmpty && !this.settings.checkboxMode) {\n                this.addListener(this.$container, 'click', function() {\n                    if (this.ignoreClick) {\n                        this.ignoreClick = false;\n                    }\n                    else {\n                        // Deselect all items on container click\n                        this.deselectAll(true);\n                    }\n                });\n            }\n        },\n\n        /**\n         * Get Item Index\n         */\n        getItemIndex: function($item) {\n            return this.$items.index($item[0]);\n        },\n\n        /**\n         * Is Selected?\n         */\n        isSelected: function(item) {\n            if (Garnish.isJquery(item)) {\n                if (!item[0]) {\n                    return false;\n                }\n\n                item = item[0];\n            }\n\n            return ($.inArray(item, this.$selectedItems) !== -1);\n        },\n\n        /**\n         * Select Item\n         */\n        selectItem: function($item, focus, preventScroll) {\n            if (!this.settings.multi) {\n                this.deselectAll();\n            }\n\n            this.$first = this.$last = $item;\n            this.first = this.last = this.getItemIndex($item);\n\n            if (focus) {\n                this.setFocusableItem($item);\n                this.focusItem($item, preventScroll);\n            }\n\n            this._selectItems($item);\n        },\n\n        selectAll: function() {\n            if (!this.settings.multi || !this.$items.length) {\n                return;\n            }\n\n            this.first = 0;\n            this.last = this.$items.length - 1;\n            this.$first = this.$items.eq(this.first);\n            this.$last = this.$items.eq(this.last);\n\n            this._selectItems(this.$items);\n        },\n\n        /**\n         * Select Range\n         */\n        selectRange: function($item, preventScroll) {\n            if (!this.settings.multi) {\n                return this.selectItem($item, true, true);\n            }\n\n            this.deselectAll();\n\n            this.$last = $item;\n            this.last = this.getItemIndex($item);\n\n            this.setFocusableItem($item);\n            this.focusItem($item, preventScroll);\n\n            // prepare params for $.slice()\n            var sliceFrom, sliceTo;\n\n            if (this.first < this.last) {\n                sliceFrom = this.first;\n                sliceTo = this.last + 1;\n            }\n            else {\n                sliceFrom = this.last;\n                sliceTo = this.first + 1;\n            }\n\n            this._selectItems(this.$items.slice(sliceFrom, sliceTo));\n        },\n\n        /**\n         * Deselect Item\n         */\n        deselectItem: function($item) {\n            var index = this.getItemIndex($item);\n            if (this.first === index) {\n                this.$first = this.first = null;\n            }\n            if (this.last === index) {\n                this.$last = this.last = null;\n            }\n\n            this._deselectItems($item);\n        },\n\n        /**\n         * Deselect All\n         */\n        deselectAll: function(clearFirst) {\n            if (clearFirst) {\n                this.$first = this.first = this.$last = this.last = null;\n            }\n\n            this._deselectItems(this.$items);\n        },\n\n        /**\n         * Deselect Others\n         */\n        deselectOthers: function($item) {\n            this.deselectAll();\n            this.selectItem($item, true, true);\n        },\n\n        /**\n         * Toggle Item\n         */\n        toggleItem: function($item, preventScroll) {\n            if (!this.isSelected($item)) {\n                this.selectItem($item, true, preventScroll);\n            }\n            else {\n                if (this._canDeselect($item)) {\n                    this.deselectItem($item, true);\n                }\n            }\n        },\n\n        clearMouseUpTimeout: function() {\n            clearTimeout(this.mouseUpTimeout);\n        },\n\n        getFirstItem: function() {\n            if (this.$items.length) {\n                return this.$items.first();\n            }\n        },\n\n        getLastItem: function() {\n            if (this.$items.length) {\n                return this.$items.last();\n            }\n        },\n\n        isPreviousItem: function(index) {\n            return (index > 0);\n        },\n\n        isNextItem: function(index) {\n            return (index < this.$items.length - 1);\n        },\n\n        getPreviousItem: function(index) {\n            if (this.isPreviousItem(index)) {\n                return this.$items.eq(index - 1);\n            }\n        },\n\n        getNextItem: function(index) {\n            if (this.isNextItem(index)) {\n                return this.$items.eq(index + 1);\n            }\n        },\n\n        getItemToTheLeft: function(index) {\n            var func = (Garnish.ltr ? 'Previous' : 'Next');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '<');\n                }\n            }\n        },\n\n        getItemToTheRight: function(index) {\n            var func = (Garnish.ltr ? 'Next' : 'Previous');\n\n            if (this['is' + func + 'Item'](index)) {\n                if (this.settings.horizontal) {\n                    return this['get' + func + 'Item'](index);\n                }\n                else if (!this.settings.vertical) {\n                    return this.getClosestItem(index, Garnish.X_AXIS, '>');\n                }\n            }\n        },\n\n        getItemAbove: function(index) {\n            if (this.isPreviousItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getPreviousItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '<');\n                }\n            }\n        },\n\n        getItemBelow: function(index) {\n            if (this.isNextItem(index)) {\n                if (this.settings.vertical) {\n                    return this.getNextItem(index);\n                }\n                else if (!this.settings.horizontal) {\n                    return this.getClosestItem(index, Garnish.Y_AXIS, '>');\n                }\n            }\n        },\n\n        getClosestItem: function(index, axis, dir) {\n            var axisProps = Garnish.Select.closestItemAxisProps[axis],\n                dirProps = Garnish.Select.closestItemDirectionProps[dir];\n\n            var $thisItem = this.$items.eq(index),\n                thisOffset = $thisItem.offset(),\n                thisMidpoint = thisOffset[axisProps.midpointOffset] + Math.round($thisItem[axisProps.midpointSizeFunc]() / 2),\n                otherRowPos = null,\n                smallestMidpointDiff = null,\n                $closestItem = null;\n\n            // Go the other way if this is the X axis and a RTL page\n            var step;\n\n            if (Garnish.rtl && axis === Garnish.X_AXIS) {\n                step = dirProps.step * -1;\n            }\n            else {\n                step = dirProps.step;\n            }\n\n            for (var i = index + step; (typeof this.$items[i] !== 'undefined'); i += step) {\n                var $otherItem = this.$items.eq(i),\n                    otherOffset = $otherItem.offset();\n\n                // Are we on the next row yet?\n                if (dirProps.isNextRow(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    // Is this the first time we've seen this row?\n                    if (otherRowPos === null) {\n                        otherRowPos = otherOffset[axisProps.rowOffset];\n                    }\n                    // Have we gone too far?\n                    else if (otherOffset[axisProps.rowOffset] !== otherRowPos) {\n                        break;\n                    }\n\n                    var otherMidpoint = otherOffset[axisProps.midpointOffset] + Math.round($otherItem[axisProps.midpointSizeFunc]() / 2),\n                        midpointDiff = Math.abs(thisMidpoint - otherMidpoint);\n\n                    // Are we getting warmer?\n                    if (smallestMidpointDiff === null || midpointDiff < smallestMidpointDiff) {\n                        smallestMidpointDiff = midpointDiff;\n                        $closestItem = $otherItem;\n                    }\n                    // Getting colder?\n                    else {\n                        break;\n                    }\n                }\n                // Getting colder?\n                else if (dirProps.isWrongDirection(otherOffset[axisProps.rowOffset], thisOffset[axisProps.rowOffset])) {\n                    break;\n                }\n            }\n\n            return $closestItem;\n        },\n\n        getFurthestItemToTheLeft: function(index) {\n            return this.getFurthestItem(index, 'ToTheLeft');\n        },\n\n        getFurthestItemToTheRight: function(index) {\n            return this.getFurthestItem(index, 'ToTheRight');\n        },\n\n        getFurthestItemAbove: function(index) {\n            return this.getFurthestItem(index, 'Above');\n        },\n\n        getFurthestItemBelow: function(index) {\n            return this.getFurthestItem(index, 'Below');\n        },\n\n        getFurthestItem: function(index, dir) {\n            var $item, $testItem;\n\n            while ($testItem = this['getItem' + dir](index)) {\n                $item = $testItem;\n                index = this.getItemIndex($item);\n            }\n\n            return $item;\n        },\n\n        /**\n         * totalSelected getter\n         */\n        get totalSelected() {\n            return this.getTotalSelected();\n        },\n\n        /**\n         * Get Total Selected\n         */\n        getTotalSelected: function() {\n            return this.$selectedItems.length;\n        },\n\n        /**\n         * Add Items\n         */\n        addItems: function(items) {\n            var $items = $(items);\n\n            for (var i = 0; i < $items.length; i++) {\n                var item = $items[i];\n\n                // Make sure this element doesn't belong to another selector\n                if ($.data(item, 'select')) {\n                    Garnish.log('Element was added to more than one selector');\n                    $.data(item, 'select').removeItems(item);\n                }\n\n                // Add the item\n                $.data(item, 'select', this);\n\n                // Get the handle\n                var $handle;\n\n                if (this.settings.handle) {\n                    if (typeof this.settings.handle === 'object') {\n                        $handle = $(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'string') {\n                        $handle = $(item).find(this.settings.handle);\n                    }\n                    else if (typeof this.settings.handle === 'function') {\n                        $handle = $(this.settings.handle(item));\n                    }\n                }\n                else {\n                    $handle = $(item);\n                }\n\n                $.data(item, 'select-handle', $handle);\n                $handle.data('select-item', item);\n\n                this.addListener($handle, 'mousedown', 'onMouseDown');\n                this.addListener($handle, 'mouseup', 'onMouseUp');\n                this.addListener($handle, 'click', function() {\n                    this.ignoreClick = true;\n                });\n\n                this.addListener(item, 'keydown', 'onKeyDown');\n            }\n\n            this.$items = this.$items.add($items);\n            this.updateIndexes();\n        },\n\n        /**\n         * Remove Items\n         */\n        removeItems: function(items) {\n            items = $.makeArray(items);\n\n            var itemsChanged = false,\n                selectionChanged = false;\n\n            for (var i = 0; i < items.length; i++) {\n                var item = items[i];\n\n                // Make sure we actually know about this item\n                var index = $.inArray(item, this.$items);\n                if (index !== -1) {\n                    this._deinitItem(item);\n                    this.$items.splice(index, 1);\n                    itemsChanged = true;\n\n                    var selectedIndex = $.inArray(item, this.$selectedItems);\n                    if (selectedIndex !== -1) {\n                        this.$selectedItems.splice(selectedIndex, 1);\n                        selectionChanged = true;\n                    }\n                }\n            }\n\n            if (itemsChanged) {\n                this.updateIndexes();\n\n                if (selectionChanged) {\n                    $(items).removeClass(this.settings.selectedClass);\n                    this.onSelectionChange();\n                }\n            }\n        },\n\n        /**\n         * Remove All Items\n         */\n        removeAllItems: function() {\n            for (var i = 0; i < this.$items.length; i++) {\n                this._deinitItem(this.$items[i]);\n            }\n\n            this.$items = $();\n            this.$selectedItems = $();\n            this.updateIndexes();\n        },\n\n        /**\n         * Update First/Last indexes\n         */\n        updateIndexes: function() {\n            if (this.first !== null) {\n                this.first = this.getItemIndex(this.$first);\n                this.setFocusableItem(this.$first);\n            }\n            else if (this.$items.length) {\n                this.setFocusableItem($(this.$items[0]));\n            }\n\n            if (this.$focusedItem) {\n                this.setFocusableItem(this.$focusedItem);\n                this.focusItem(this.$focusedItem, true);\n            }\n\n            if (this.last !== null) {\n                this.last = this.getItemIndex(this.$last);\n            }\n        },\n\n        /**\n         * Reset Item Order\n         */\n        resetItemOrder: function() {\n            this.$items = $().add(this.$items);\n            this.$selectedItems = $().add(this.$selectedItems);\n            this.updateIndexes();\n        },\n\n        /**\n         * Sets the focusable item.\n         *\n         * We only want to have one focusable item per selection list, so that the user\n         * doesn't have to tab through a million items.\n         *\n         * @param {object} $item\n         */\n        setFocusableItem: function($item) {\n            if (this.$focusable) {\n                this.$focusable.removeAttr('tabindex');\n            }\n\n            this.$focusable = $item.attr('tabindex', '0');\n        },\n\n        /**\n         * Sets the focus on an item.\n         */\n        focusItem: function($item, preventScroll) {\n            $item[0].focus({preventScroll: !!preventScroll});\n            this.$focusedItem = $item;\n            this.trigger('focusItem', {item: $item});\n        },\n\n        /**\n         * Get Selected Items\n         */\n        getSelectedItems: function() {\n            return this.$selectedItems;\n        },\n\n        /**\n         * Destroy\n         */\n        destroy: function() {\n            this.$container.removeData('select');\n            this.removeAllItems();\n            this.base();\n        },\n\n        // Events\n        // ---------------------------------------------------------------------\n\n        /**\n         * On Mouse Down\n         */\n        onMouseDown: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enforce the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            this.mousedownTarget = ev.currentTarget;\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            if (this.first !== null && ev.shiftKey) {\n                // Shift key is consistent for both selection modes\n                this.selectRange($item, true);\n            }\n            else if (this._actAsCheckbox(ev)) {\n                this.toggleItem($item, true);\n            }\n        },\n\n        /**\n         * On Mouse Up\n         */\n        onMouseUp: function(ev) {\n            // ignore right clicks\n            if (ev.which !== Garnish.PRIMARY_CLICK) {\n                return;\n            }\n\n            // Enfore the filter\n            if (this.settings.filter && !$(ev.target).is(this.settings.filter)) {\n                return;\n            }\n\n            var $item = $($.data(ev.currentTarget, 'select-item'));\n\n            // was this a click?\n            if (\n                !this._actAsCheckbox(ev) && !ev.shiftKey &&\n                ev.currentTarget === this.mousedownTarget\n            ) {\n                // If this is already selected, wait a moment to see if this is a double click before making any rash decisions\n                if (this.isSelected($item)) {\n                    this.clearMouseUpTimeout();\n\n                    this.mouseUpTimeout = setTimeout(function() {\n                        this.deselectOthers($item);\n                    }.bind(this), 300);\n                }\n                else {\n                    this.deselectAll();\n                    this.selectItem($item, true, true);\n                }\n            }\n        },\n\n        /**\n         * On Key Down\n         */\n        onKeyDown: function(ev) {\n            // Ignore if the focus isn't on one of our items\n            if (ev.target !== ev.currentTarget) {\n                return;\n            }\n\n            var ctrlKey = Garnish.isCtrlKeyPressed(ev);\n            var shiftKey = ev.shiftKey;\n\n            var anchor, $item;\n\n            if (!this.settings.checkboxMode || !this.$focusable.length) {\n                anchor = ev.shiftKey ? this.last : this.first;\n            }\n            else {\n                anchor = $.inArray(this.$focusable[0], this.$items);\n\n                if (anchor === -1) {\n                    anchor = 0;\n                }\n            }\n\n            // Ok, what are we doing here?\n            switch (ev.keyCode) {\n                case Garnish.LEFT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getLastItem();\n                        }\n                        else {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheLeft(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheLeft(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.RIGHT_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (Garnish.ltr) {\n                            $item = this.getFirstItem();\n                        }\n                        else {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemToTheRight(anchor);\n                        }\n                        else {\n                            $item = this.getItemToTheRight(anchor);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.UP_KEY: {\n                    ev.preventDefault();\n\n                    // Select the last item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.prev();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getLastItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemAbove(anchor);\n                        }\n                        else {\n                            $item = this.getItemAbove(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.DOWN_KEY: {\n                    ev.preventDefault();\n\n                    // Select the first item if none are selected\n                    if (this.first === null) {\n                        if (this.$focusable) {\n                            $item = this.$focusable.next();\n                        }\n\n                        if (!this.$focusable || !$item.length) {\n                            $item = this.getFirstItem();\n                        }\n                    }\n                    else {\n                        if (ctrlKey) {\n                            $item = this.getFurthestItemBelow(anchor);\n                        }\n                        else {\n                            $item = this.getItemBelow(anchor);\n                        }\n\n                        if (!$item) {\n                            $item = this.getLastItem();\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.SPACE_KEY: {\n                    if (!ctrlKey && !shiftKey) {\n                        ev.preventDefault();\n\n                        if (this.isSelected(this.$focusable)) {\n                            if (this._canDeselect(this.$focusable)) {\n                                this.deselectItem(this.$focusable);\n                            }\n                        }\n                        else {\n                            this.selectItem(this.$focusable, true, false);\n                        }\n                    }\n\n                    break;\n                }\n\n                case Garnish.A_KEY: {\n                    if (ctrlKey) {\n                        ev.preventDefault();\n                        this.selectAll();\n                    }\n\n                    break;\n                }\n            }\n\n            // Is there an item queued up for focus/selection?\n            if ($item && $item.length) {\n                if (!this.settings.checkboxMode) {\n                    // select it\n                    if (this.first !== null && ev.shiftKey) {\n                        this.selectRange($item, false);\n                    }\n                    else {\n                        this.deselectAll();\n                        this.selectItem($item, true, false);\n                    }\n                }\n                else {\n                    // just set the new item to be focusable\n                    this.setFocusableItem($item);\n                    $item.focus();\n                    this.$focusedItem = $item;\n                    this.trigger('focusItem', {item: $item});\n                }\n            }\n        },\n\n        /**\n         * Set Callback Timeout\n         */\n        onSelectionChange: function() {\n            if (this.callbackFrame) {\n                Garnish.cancelAnimationFrame(this.callbackFrame);\n                this.callbackFrame = null;\n            }\n\n            this.callbackFrame = Garnish.requestAnimationFrame(function() {\n                this.callbackFrame = null;\n                this.trigger('selectionChange');\n                this.settings.onSelectionChange();\n            }.bind(this));\n        },\n\n        // Private methods\n        // ---------------------------------------------------------------------\n\n        _actAsCheckbox: function(ev) {\n            if (Garnish.isCtrlKeyPressed(ev)) {\n                return !this.settings.checkboxMode;\n            }\n            else {\n                return this.settings.checkboxMode;\n            }\n        },\n\n        _canDeselect: function($items) {\n            return (this.settings.allowEmpty || this.totalSelected > $items.length);\n        },\n\n        _selectItems: function($items) {\n            $items.addClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.add($items);\n            this.onSelectionChange();\n        },\n\n        _deselectItems: function($items) {\n            $items.removeClass(this.settings.selectedClass);\n            this.$selectedItems = this.$selectedItems.not($items);\n            this.onSelectionChange();\n        },\n\n        /**\n         * Deinitialize an item.\n         */\n        _deinitItem: function(item) {\n            var $handle = $.data(item, 'select-handle');\n\n            if ($handle) {\n                $handle.removeData('select-item');\n                this.removeAllListeners($handle);\n            }\n\n            $.removeData(item, 'select');\n            $.removeData(item, 'select-handle');\n\n            if (this.$focusedItem && this.$focusedItem[0] === item) {\n                this.$focusedItem = null;\n            }\n        }\n    },\n    {\n        defaults: {\n            selectedClass: 'sel',\n            multi: false,\n            allowEmpty: true,\n            vertical: false,\n            horizontal: false,\n            handle: null,\n            filter: null,\n            checkboxMode: false,\n            onSelectionChange: $.noop\n        },\n\n        closestItemAxisProps: {\n            x: {\n                midpointOffset: 'top',\n                midpointSizeFunc: 'outerHeight',\n                rowOffset: 'left'\n            },\n            y: {\n                midpointOffset: 'left',\n                midpointSizeFunc: 'outerWidth',\n                rowOffset: 'top'\n            }\n        },\n\n        closestItemDirectionProps: {\n            '<': {\n                step: -1,\n                isNextRow: function(a, b) {\n                    return (a < b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a > b);\n                }\n            },\n            '>': {\n                step: 1,\n                isNextRow: function(a, b) {\n                    return (a > b);\n                },\n                isWrongDirection: function(a, b) {\n                    return (a < b);\n                }\n            }\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Select Menu\n */\nGarnish.SelectMenu = Garnish.Menu.extend(\n    {\n        /**\n         * Constructor\n         */\n        init: function(btn, options, settings, callback) {\n            // argument mapping\n            if (typeof settings === 'function') {\n                // (btn, options, callback)\n                callback = settings;\n                settings = {};\n            }\n\n            settings = $.extend({}, Garnish.SelectMenu.defaults, settings);\n\n            this.base(btn, options, settings, callback);\n\n            this.selected = -1;\n        },\n\n        /**\n         * Build\n         */\n        build: function() {\n            this.base();\n\n            if (this.selected !== -1) {\n                this._addSelectedOptionClass(this.selected);\n            }\n        },\n\n        /**\n         * Select\n         */\n        select: function(option) {\n            // ignore if it's already selected\n            if (option === this.selected) {\n                return;\n            }\n\n            if (this.dom.ul) {\n                if (this.selected !== -1) {\n                    this.dom.options[this.selected].className = '';\n                }\n\n                this._addSelectedOptionClass(option);\n            }\n\n            this.selected = option;\n\n            // set the button text to the selected option\n            this.setBtnText($(this.options[option].label).text());\n\n            this.base(option);\n        },\n\n        /**\n         * Add Selected Option Class\n         */\n        _addSelectedOptionClass: function(option) {\n            this.dom.options[option].className = 'sel';\n        },\n\n        /**\n         * Set Button Text\n         */\n        setBtnText: function(text) {\n            this.dom.$btnLabel.text(text);\n        }\n\n    },\n    {\n        defaults: {\n            ulClass: 'menu select'\n        }\n    }\n);\n\n/** global: Garnish */\n/**\n * Keyboard shortcut manager class\n *\n * This can be used to map keyboard events to the current UI \"layer\" (whether that's the base document,\n * a modal, an HUD, or a menu).\n */\nGarnish.ShortcutManager = Garnish.Base.extend(\n    {\n        shortcuts: null,\n        layer: 0,\n\n        init: function() {\n            this.shortcuts = [[]];\n            this.addListener(Garnish.$bod, 'keydown', 'triggerShortcut');\n        },\n\n        addLayer: function() {\n            this.layer++;\n            this.shortcuts.push([]);\n            return this;\n        },\n\n        removeLayer: function() {\n            if (this.layer === 0) {\n                throw 'Can’t remove the base layer.';\n            }\n            this.layer--;\n            this.shortcuts.pop();\n            return this;\n        },\n\n        registerShortcut: function(shortcut, callback, layer) {\n            shortcut = this._normalizeShortcut(shortcut);\n            if (typeof layer === 'undefined') {\n                layer = this.layer;\n            }\n            this.shortcuts[layer].push({\n                key: JSON.stringify(shortcut),\n                shortcut: shortcut,\n                callback: callback,\n            });\n            return this;\n        },\n\n        unregisterShortcut: function(shortcut, layer) {\n            shortcut = this._normalizeShortcut(shortcut);\n            var key = JSON.stringify(shortcut);\n            if (typeof layer === 'undefined') {\n                layer = this.layer;\n            }\n            for (var i = 0; i < this.shortcuts[layer].length; i++) {\n                if (this.shortcuts[layer][i].key === key) {\n                    this.shortcuts[layer].splice(i, 1);\n                    break;\n                }\n            }\n            return this;\n        },\n\n        _normalizeShortcut: function(shortcut) {\n            if (typeof shortcut === 'number') {\n                shortcut = {keyCode: shortcut};\n            }\n\n            if (typeof shortcut.keyCode !== 'number') {\n                throw 'Invalid shortcut';\n            }\n\n            return {\n                keyCode: shortcut.keyCode,\n                ctrl: !!shortcut.ctrl,\n                shift: !!shortcut.shift,\n                alt: !!shortcut.alt,\n            };\n        },\n\n        triggerShortcut: function(ev) {\n            var shortcut;\n            for (var i = 0; i < this.shortcuts[this.layer].length; i++) {\n                shortcut = this.shortcuts[this.layer][i].shortcut;\n                if (\n                    shortcut.keyCode === ev.keyCode &&\n                    shortcut.ctrl === Garnish.isCtrlKeyPressed(ev) &&\n                    shortcut.shift === ev.shiftKey &&\n                    shortcut.alt === ev.altKey\n                ) {\n                    ev.preventDefault();\n                    this.shortcuts[this.layer][i].callback(ev);\n                    break;\n                }\n            }\n        },\n    }\n);\n\nGarnish.shortcutManager = new Garnish.ShortcutManager();\n\n})(jQuery);\n"]}