github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/themes/wind/static/libs/flat-ui/js/flat-ui.js (about) 1 /*! 2 * Flat UI Free v2.2.2 (http://designmodo.github.io/Flat-UI/) 3 * Copyright 2013-2014 Designmodo, Inc. 4 */ 5 /*! 6 * jQuery UI Core 1.10.4 7 * http://jqueryui.com 8 * 9 * Copyright 2014 jQuery Foundation and other contributors 10 * Released under the MIT license. 11 * http://jquery.org/license 12 * 13 * http://api.jqueryui.com/category/ui-core/ 14 */ 15 (function( $, undefined ) { 16 17 var uuid = 0, 18 runiqueId = /^ui-id-\d+$/; 19 20 // $.ui might exist from components with no dependencies, e.g., $.ui.position 21 $.ui = $.ui || {}; 22 23 $.extend( $.ui, { 24 version: "1.10.4", 25 26 keyCode: { 27 BACKSPACE: 8, 28 COMMA: 188, 29 DELETE: 46, 30 DOWN: 40, 31 END: 35, 32 ENTER: 13, 33 ESCAPE: 27, 34 HOME: 36, 35 LEFT: 37, 36 NUMPAD_ADD: 107, 37 NUMPAD_DECIMAL: 110, 38 NUMPAD_DIVIDE: 111, 39 NUMPAD_ENTER: 108, 40 NUMPAD_MULTIPLY: 106, 41 NUMPAD_SUBTRACT: 109, 42 PAGE_DOWN: 34, 43 PAGE_UP: 33, 44 PERIOD: 190, 45 RIGHT: 39, 46 SPACE: 32, 47 TAB: 9, 48 UP: 38 49 } 50 }); 51 52 // plugins 53 $.fn.extend({ 54 focus: (function( orig ) { 55 return function( delay, fn ) { 56 return typeof delay === "number" ? 57 this.each(function() { 58 var elem = this; 59 setTimeout(function() { 60 $( elem ).focus(); 61 if ( fn ) { 62 fn.call( elem ); 63 } 64 }, delay ); 65 }) : 66 orig.apply( this, arguments ); 67 }; 68 })( $.fn.focus ), 69 70 scrollParent: function() { 71 var scrollParent; 72 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { 73 scrollParent = this.parents().filter(function() { 74 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); 75 }).eq(0); 76 } else { 77 scrollParent = this.parents().filter(function() { 78 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); 79 }).eq(0); 80 } 81 82 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; 83 }, 84 85 zIndex: function( zIndex ) { 86 if ( zIndex !== undefined ) { 87 return this.css( "zIndex", zIndex ); 88 } 89 90 if ( this.length ) { 91 var elem = $( this[ 0 ] ), position, value; 92 while ( elem.length && elem[ 0 ] !== document ) { 93 // Ignore z-index if position is set to a value where z-index is ignored by the browser 94 // This makes behavior of this function consistent across browsers 95 // WebKit always returns auto if the element is positioned 96 position = elem.css( "position" ); 97 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 98 // IE returns 0 when zIndex is not specified 99 // other browsers return a string 100 // we ignore the case of nested elements with an explicit value of 0 101 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 102 value = parseInt( elem.css( "zIndex" ), 10 ); 103 if ( !isNaN( value ) && value !== 0 ) { 104 return value; 105 } 106 } 107 elem = elem.parent(); 108 } 109 } 110 111 return 0; 112 }, 113 114 uniqueId: function() { 115 return this.each(function() { 116 if ( !this.id ) { 117 this.id = "ui-id-" + (++uuid); 118 } 119 }); 120 }, 121 122 removeUniqueId: function() { 123 return this.each(function() { 124 if ( runiqueId.test( this.id ) ) { 125 $( this ).removeAttr( "id" ); 126 } 127 }); 128 } 129 }); 130 131 // selectors 132 function focusable( element, isTabIndexNotNaN ) { 133 var map, mapName, img, 134 nodeName = element.nodeName.toLowerCase(); 135 if ( "area" === nodeName ) { 136 map = element.parentNode; 137 mapName = map.name; 138 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 139 return false; 140 } 141 img = $( "img[usemap=#" + mapName + "]" )[0]; 142 return !!img && visible( img ); 143 } 144 return ( /input|select|textarea|button|object/.test( nodeName ) ? 145 !element.disabled : 146 "a" === nodeName ? 147 element.href || isTabIndexNotNaN : 148 isTabIndexNotNaN) && 149 // the element and all of its ancestors must be visible 150 visible( element ); 151 } 152 153 function visible( element ) { 154 return $.expr.filters.visible( element ) && 155 !$( element ).parents().addBack().filter(function() { 156 return $.css( this, "visibility" ) === "hidden"; 157 }).length; 158 } 159 160 $.extend( $.expr[ ":" ], { 161 data: $.expr.createPseudo ? 162 $.expr.createPseudo(function( dataName ) { 163 return function( elem ) { 164 return !!$.data( elem, dataName ); 165 }; 166 }) : 167 // support: jQuery <1.8 168 function( elem, i, match ) { 169 return !!$.data( elem, match[ 3 ] ); 170 }, 171 172 focusable: function( element ) { 173 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); 174 }, 175 176 tabbable: function( element ) { 177 var tabIndex = $.attr( element, "tabindex" ), 178 isTabIndexNaN = isNaN( tabIndex ); 179 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); 180 } 181 }); 182 183 // support: jQuery <1.8 184 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { 185 $.each( [ "Width", "Height" ], function( i, name ) { 186 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], 187 type = name.toLowerCase(), 188 orig = { 189 innerWidth: $.fn.innerWidth, 190 innerHeight: $.fn.innerHeight, 191 outerWidth: $.fn.outerWidth, 192 outerHeight: $.fn.outerHeight 193 }; 194 195 function reduce( elem, size, border, margin ) { 196 $.each( side, function() { 197 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; 198 if ( border ) { 199 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; 200 } 201 if ( margin ) { 202 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; 203 } 204 }); 205 return size; 206 } 207 208 $.fn[ "inner" + name ] = function( size ) { 209 if ( size === undefined ) { 210 return orig[ "inner" + name ].call( this ); 211 } 212 213 return this.each(function() { 214 $( this ).css( type, reduce( this, size ) + "px" ); 215 }); 216 }; 217 218 $.fn[ "outer" + name] = function( size, margin ) { 219 if ( typeof size !== "number" ) { 220 return orig[ "outer" + name ].call( this, size ); 221 } 222 223 return this.each(function() { 224 $( this).css( type, reduce( this, size, true, margin ) + "px" ); 225 }); 226 }; 227 }); 228 } 229 230 // support: jQuery <1.8 231 if ( !$.fn.addBack ) { 232 $.fn.addBack = function( selector ) { 233 return this.add( selector == null ? 234 this.prevObject : this.prevObject.filter( selector ) 235 ); 236 }; 237 } 238 239 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) 240 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { 241 $.fn.removeData = (function( removeData ) { 242 return function( key ) { 243 if ( arguments.length ) { 244 return removeData.call( this, $.camelCase( key ) ); 245 } else { 246 return removeData.call( this ); 247 } 248 }; 249 })( $.fn.removeData ); 250 } 251 252 253 254 255 256 // deprecated 257 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 258 259 $.support.selectstart = "onselectstart" in document.createElement( "div" ); 260 $.fn.extend({ 261 disableSelection: function() { 262 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + 263 ".ui-disableSelection", function( event ) { 264 event.preventDefault(); 265 }); 266 }, 267 268 enableSelection: function() { 269 return this.unbind( ".ui-disableSelection" ); 270 } 271 }); 272 273 $.extend( $.ui, { 274 // $.ui.plugin is deprecated. Use $.widget() extensions instead. 275 plugin: { 276 add: function( module, option, set ) { 277 var i, 278 proto = $.ui[ module ].prototype; 279 for ( i in set ) { 280 proto.plugins[ i ] = proto.plugins[ i ] || []; 281 proto.plugins[ i ].push( [ option, set[ i ] ] ); 282 } 283 }, 284 call: function( instance, name, args ) { 285 var i, 286 set = instance.plugins[ name ]; 287 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { 288 return; 289 } 290 291 for ( i = 0; i < set.length; i++ ) { 292 if ( instance.options[ set[ i ][ 0 ] ] ) { 293 set[ i ][ 1 ].apply( instance.element, args ); 294 } 295 } 296 } 297 }, 298 299 // only used by resizable 300 hasScroll: function( el, a ) { 301 302 //If overflow is hidden, the element might have extra content, but the user wants to hide it 303 if ( $( el ).css( "overflow" ) === "hidden") { 304 return false; 305 } 306 307 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 308 has = false; 309 310 if ( el[ scroll ] > 0 ) { 311 return true; 312 } 313 314 // TODO: determine which cases actually cause this to happen 315 // if the element doesn't have the scroll set, see if it's possible to 316 // set the scroll 317 el[ scroll ] = 1; 318 has = ( el[ scroll ] > 0 ); 319 el[ scroll ] = 0; 320 return has; 321 } 322 }); 323 324 })( jQuery ); 325 326 /*! 327 * jQuery UI Widget 1.10.4 328 * http://jqueryui.com 329 * 330 * Copyright 2014 jQuery Foundation and other contributors 331 * Released under the MIT license. 332 * http://jquery.org/license 333 * 334 * http://api.jqueryui.com/jQuery.widget/ 335 */ 336 (function( $, undefined ) { 337 338 var uuid = 0, 339 slice = Array.prototype.slice, 340 _cleanData = $.cleanData; 341 $.cleanData = function( elems ) { 342 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { 343 try { 344 $( elem ).triggerHandler( "remove" ); 345 // http://bugs.jquery.com/ticket/8235 346 } catch( e ) {} 347 } 348 _cleanData( elems ); 349 }; 350 351 $.widget = function( name, base, prototype ) { 352 var fullName, existingConstructor, constructor, basePrototype, 353 // proxiedPrototype allows the provided prototype to remain unmodified 354 // so that it can be used as a mixin for multiple widgets (#8876) 355 proxiedPrototype = {}, 356 namespace = name.split( "." )[ 0 ]; 357 358 name = name.split( "." )[ 1 ]; 359 fullName = namespace + "-" + name; 360 361 if ( !prototype ) { 362 prototype = base; 363 base = $.Widget; 364 } 365 366 // create selector for plugin 367 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 368 return !!$.data( elem, fullName ); 369 }; 370 371 $[ namespace ] = $[ namespace ] || {}; 372 existingConstructor = $[ namespace ][ name ]; 373 constructor = $[ namespace ][ name ] = function( options, element ) { 374 // allow instantiation without "new" keyword 375 if ( !this._createWidget ) { 376 return new constructor( options, element ); 377 } 378 379 // allow instantiation without initializing for simple inheritance 380 // must use "new" keyword (the code above always passes args) 381 if ( arguments.length ) { 382 this._createWidget( options, element ); 383 } 384 }; 385 // extend with the existing constructor to carry over any static properties 386 $.extend( constructor, existingConstructor, { 387 version: prototype.version, 388 // copy the object used to create the prototype in case we need to 389 // redefine the widget later 390 _proto: $.extend( {}, prototype ), 391 // track widgets that inherit from this widget in case this widget is 392 // redefined after a widget inherits from it 393 _childConstructors: [] 394 }); 395 396 basePrototype = new base(); 397 // we need to make the options hash a property directly on the new instance 398 // otherwise we'll modify the options hash on the prototype that we're 399 // inheriting from 400 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 401 $.each( prototype, function( prop, value ) { 402 if ( !$.isFunction( value ) ) { 403 proxiedPrototype[ prop ] = value; 404 return; 405 } 406 proxiedPrototype[ prop ] = (function() { 407 var _super = function() { 408 return base.prototype[ prop ].apply( this, arguments ); 409 }, 410 _superApply = function( args ) { 411 return base.prototype[ prop ].apply( this, args ); 412 }; 413 return function() { 414 var __super = this._super, 415 __superApply = this._superApply, 416 returnValue; 417 418 this._super = _super; 419 this._superApply = _superApply; 420 421 returnValue = value.apply( this, arguments ); 422 423 this._super = __super; 424 this._superApply = __superApply; 425 426 return returnValue; 427 }; 428 })(); 429 }); 430 constructor.prototype = $.widget.extend( basePrototype, { 431 // TODO: remove support for widgetEventPrefix 432 // always use the name + a colon as the prefix, e.g., draggable:start 433 // don't prefix for widgets that aren't DOM-based 434 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name 435 }, proxiedPrototype, { 436 constructor: constructor, 437 namespace: namespace, 438 widgetName: name, 439 widgetFullName: fullName 440 }); 441 442 // If this widget is being redefined then we need to find all widgets that 443 // are inheriting from it and redefine all of them so that they inherit from 444 // the new version of this widget. We're essentially trying to replace one 445 // level in the prototype chain. 446 if ( existingConstructor ) { 447 $.each( existingConstructor._childConstructors, function( i, child ) { 448 var childPrototype = child.prototype; 449 450 // redefine the child widget using the same prototype that was 451 // originally used, but inherit from the new version of the base 452 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); 453 }); 454 // remove the list of existing child constructors from the old constructor 455 // so the old child constructors can be garbage collected 456 delete existingConstructor._childConstructors; 457 } else { 458 base._childConstructors.push( constructor ); 459 } 460 461 $.widget.bridge( name, constructor ); 462 }; 463 464 $.widget.extend = function( target ) { 465 var input = slice.call( arguments, 1 ), 466 inputIndex = 0, 467 inputLength = input.length, 468 key, 469 value; 470 for ( ; inputIndex < inputLength; inputIndex++ ) { 471 for ( key in input[ inputIndex ] ) { 472 value = input[ inputIndex ][ key ]; 473 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 474 // Clone objects 475 if ( $.isPlainObject( value ) ) { 476 target[ key ] = $.isPlainObject( target[ key ] ) ? 477 $.widget.extend( {}, target[ key ], value ) : 478 // Don't extend strings, arrays, etc. with objects 479 $.widget.extend( {}, value ); 480 // Copy everything else by reference 481 } else { 482 target[ key ] = value; 483 } 484 } 485 } 486 } 487 return target; 488 }; 489 490 $.widget.bridge = function( name, object ) { 491 var fullName = object.prototype.widgetFullName || name; 492 $.fn[ name ] = function( options ) { 493 var isMethodCall = typeof options === "string", 494 args = slice.call( arguments, 1 ), 495 returnValue = this; 496 497 // allow multiple hashes to be passed on init 498 options = !isMethodCall && args.length ? 499 $.widget.extend.apply( null, [ options ].concat(args) ) : 500 options; 501 502 if ( isMethodCall ) { 503 this.each(function() { 504 var methodValue, 505 instance = $.data( this, fullName ); 506 if ( !instance ) { 507 return $.error( "cannot call methods on " + name + " prior to initialization; " + 508 "attempted to call method '" + options + "'" ); 509 } 510 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 511 return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 512 } 513 methodValue = instance[ options ].apply( instance, args ); 514 if ( methodValue !== instance && methodValue !== undefined ) { 515 returnValue = methodValue && methodValue.jquery ? 516 returnValue.pushStack( methodValue.get() ) : 517 methodValue; 518 return false; 519 } 520 }); 521 } else { 522 this.each(function() { 523 var instance = $.data( this, fullName ); 524 if ( instance ) { 525 instance.option( options || {} )._init(); 526 } else { 527 $.data( this, fullName, new object( options, this ) ); 528 } 529 }); 530 } 531 532 return returnValue; 533 }; 534 }; 535 536 $.Widget = function( /* options, element */ ) {}; 537 $.Widget._childConstructors = []; 538 539 $.Widget.prototype = { 540 widgetName: "widget", 541 widgetEventPrefix: "", 542 defaultElement: "<div>", 543 options: { 544 disabled: false, 545 546 // callbacks 547 create: null 548 }, 549 _createWidget: function( options, element ) { 550 element = $( element || this.defaultElement || this )[ 0 ]; 551 this.element = $( element ); 552 this.uuid = uuid++; 553 this.eventNamespace = "." + this.widgetName + this.uuid; 554 this.options = $.widget.extend( {}, 555 this.options, 556 this._getCreateOptions(), 557 options ); 558 559 this.bindings = $(); 560 this.hoverable = $(); 561 this.focusable = $(); 562 563 if ( element !== this ) { 564 $.data( element, this.widgetFullName, this ); 565 this._on( true, this.element, { 566 remove: function( event ) { 567 if ( event.target === element ) { 568 this.destroy(); 569 } 570 } 571 }); 572 this.document = $( element.style ? 573 // element within the document 574 element.ownerDocument : 575 // element is window or document 576 element.document || element ); 577 this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 578 } 579 580 this._create(); 581 this._trigger( "create", null, this._getCreateEventData() ); 582 this._init(); 583 }, 584 _getCreateOptions: $.noop, 585 _getCreateEventData: $.noop, 586 _create: $.noop, 587 _init: $.noop, 588 589 destroy: function() { 590 this._destroy(); 591 // we can probably remove the unbind calls in 2.0 592 // all event bindings should go through this._on() 593 this.element 594 .unbind( this.eventNamespace ) 595 // 1.9 BC for #7810 596 // TODO remove dual storage 597 .removeData( this.widgetName ) 598 .removeData( this.widgetFullName ) 599 // support: jquery <1.6.3 600 // http://bugs.jquery.com/ticket/9413 601 .removeData( $.camelCase( this.widgetFullName ) ); 602 this.widget() 603 .unbind( this.eventNamespace ) 604 .removeAttr( "aria-disabled" ) 605 .removeClass( 606 this.widgetFullName + "-disabled " + 607 "ui-state-disabled" ); 608 609 // clean up events and states 610 this.bindings.unbind( this.eventNamespace ); 611 this.hoverable.removeClass( "ui-state-hover" ); 612 this.focusable.removeClass( "ui-state-focus" ); 613 }, 614 _destroy: $.noop, 615 616 widget: function() { 617 return this.element; 618 }, 619 620 option: function( key, value ) { 621 var options = key, 622 parts, 623 curOption, 624 i; 625 626 if ( arguments.length === 0 ) { 627 // don't return a reference to the internal hash 628 return $.widget.extend( {}, this.options ); 629 } 630 631 if ( typeof key === "string" ) { 632 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 633 options = {}; 634 parts = key.split( "." ); 635 key = parts.shift(); 636 if ( parts.length ) { 637 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 638 for ( i = 0; i < parts.length - 1; i++ ) { 639 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 640 curOption = curOption[ parts[ i ] ]; 641 } 642 key = parts.pop(); 643 if ( arguments.length === 1 ) { 644 return curOption[ key ] === undefined ? null : curOption[ key ]; 645 } 646 curOption[ key ] = value; 647 } else { 648 if ( arguments.length === 1 ) { 649 return this.options[ key ] === undefined ? null : this.options[ key ]; 650 } 651 options[ key ] = value; 652 } 653 } 654 655 this._setOptions( options ); 656 657 return this; 658 }, 659 _setOptions: function( options ) { 660 var key; 661 662 for ( key in options ) { 663 this._setOption( key, options[ key ] ); 664 } 665 666 return this; 667 }, 668 _setOption: function( key, value ) { 669 this.options[ key ] = value; 670 671 if ( key === "disabled" ) { 672 this.widget() 673 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) 674 .attr( "aria-disabled", value ); 675 this.hoverable.removeClass( "ui-state-hover" ); 676 this.focusable.removeClass( "ui-state-focus" ); 677 } 678 679 return this; 680 }, 681 682 enable: function() { 683 return this._setOption( "disabled", false ); 684 }, 685 disable: function() { 686 return this._setOption( "disabled", true ); 687 }, 688 689 _on: function( suppressDisabledCheck, element, handlers ) { 690 var delegateElement, 691 instance = this; 692 693 // no suppressDisabledCheck flag, shuffle arguments 694 if ( typeof suppressDisabledCheck !== "boolean" ) { 695 handlers = element; 696 element = suppressDisabledCheck; 697 suppressDisabledCheck = false; 698 } 699 700 // no element argument, shuffle and use this.element 701 if ( !handlers ) { 702 handlers = element; 703 element = this.element; 704 delegateElement = this.widget(); 705 } else { 706 // accept selectors, DOM elements 707 element = delegateElement = $( element ); 708 this.bindings = this.bindings.add( element ); 709 } 710 711 $.each( handlers, function( event, handler ) { 712 function handlerProxy() { 713 // allow widgets to customize the disabled handling 714 // - disabled as an array instead of boolean 715 // - disabled class as method for disabling individual parts 716 if ( !suppressDisabledCheck && 717 ( instance.options.disabled === true || 718 $( this ).hasClass( "ui-state-disabled" ) ) ) { 719 return; 720 } 721 return ( typeof handler === "string" ? instance[ handler ] : handler ) 722 .apply( instance, arguments ); 723 } 724 725 // copy the guid so direct unbinding works 726 if ( typeof handler !== "string" ) { 727 handlerProxy.guid = handler.guid = 728 handler.guid || handlerProxy.guid || $.guid++; 729 } 730 731 var match = event.match( /^(\w+)\s*(.*)$/ ), 732 eventName = match[1] + instance.eventNamespace, 733 selector = match[2]; 734 if ( selector ) { 735 delegateElement.delegate( selector, eventName, handlerProxy ); 736 } else { 737 element.bind( eventName, handlerProxy ); 738 } 739 }); 740 }, 741 742 _off: function( element, eventName ) { 743 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; 744 element.unbind( eventName ).undelegate( eventName ); 745 }, 746 747 _delay: function( handler, delay ) { 748 function handlerProxy() { 749 return ( typeof handler === "string" ? instance[ handler ] : handler ) 750 .apply( instance, arguments ); 751 } 752 var instance = this; 753 return setTimeout( handlerProxy, delay || 0 ); 754 }, 755 756 _hoverable: function( element ) { 757 this.hoverable = this.hoverable.add( element ); 758 this._on( element, { 759 mouseenter: function( event ) { 760 $( event.currentTarget ).addClass( "ui-state-hover" ); 761 }, 762 mouseleave: function( event ) { 763 $( event.currentTarget ).removeClass( "ui-state-hover" ); 764 } 765 }); 766 }, 767 768 _focusable: function( element ) { 769 this.focusable = this.focusable.add( element ); 770 this._on( element, { 771 focusin: function( event ) { 772 $( event.currentTarget ).addClass( "ui-state-focus" ); 773 }, 774 focusout: function( event ) { 775 $( event.currentTarget ).removeClass( "ui-state-focus" ); 776 } 777 }); 778 }, 779 780 _trigger: function( type, event, data ) { 781 var prop, orig, 782 callback = this.options[ type ]; 783 784 data = data || {}; 785 event = $.Event( event ); 786 event.type = ( type === this.widgetEventPrefix ? 787 type : 788 this.widgetEventPrefix + type ).toLowerCase(); 789 // the original event may come from any element 790 // so we need to reset the target on the new event 791 event.target = this.element[ 0 ]; 792 793 // copy original event properties over to the new event 794 orig = event.originalEvent; 795 if ( orig ) { 796 for ( prop in orig ) { 797 if ( !( prop in event ) ) { 798 event[ prop ] = orig[ prop ]; 799 } 800 } 801 } 802 803 this.element.trigger( event, data ); 804 return !( $.isFunction( callback ) && 805 callback.apply( this.element[0], [ event ].concat( data ) ) === false || 806 event.isDefaultPrevented() ); 807 } 808 }; 809 810 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 811 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 812 if ( typeof options === "string" ) { 813 options = { effect: options }; 814 } 815 var hasOptions, 816 effectName = !options ? 817 method : 818 options === true || typeof options === "number" ? 819 defaultEffect : 820 options.effect || defaultEffect; 821 options = options || {}; 822 if ( typeof options === "number" ) { 823 options = { duration: options }; 824 } 825 hasOptions = !$.isEmptyObject( options ); 826 options.complete = callback; 827 if ( options.delay ) { 828 element.delay( options.delay ); 829 } 830 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 831 element[ method ]( options ); 832 } else if ( effectName !== method && element[ effectName ] ) { 833 element[ effectName ]( options.duration, options.easing, callback ); 834 } else { 835 element.queue(function( next ) { 836 $( this )[ method ](); 837 if ( callback ) { 838 callback.call( element[ 0 ] ); 839 } 840 next(); 841 }); 842 } 843 }; 844 }); 845 846 })( jQuery ); 847 848 /*! 849 * jQuery UI Mouse 1.10.4 850 * http://jqueryui.com 851 * 852 * Copyright 2014 jQuery Foundation and other contributors 853 * Released under the MIT license. 854 * http://jquery.org/license 855 * 856 * http://api.jqueryui.com/mouse/ 857 * 858 * Depends: 859 * jquery.ui.widget.js 860 */ 861 (function( $, undefined ) { 862 863 var mouseHandled = false; 864 $( document ).mouseup( function() { 865 mouseHandled = false; 866 }); 867 868 $.widget("ui.mouse", { 869 version: "1.10.4", 870 options: { 871 cancel: "input,textarea,button,select,option", 872 distance: 1, 873 delay: 0 874 }, 875 _mouseInit: function() { 876 var that = this; 877 878 this.element 879 .bind("mousedown."+this.widgetName, function(event) { 880 return that._mouseDown(event); 881 }) 882 .bind("click."+this.widgetName, function(event) { 883 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { 884 $.removeData(event.target, that.widgetName + ".preventClickEvent"); 885 event.stopImmediatePropagation(); 886 return false; 887 } 888 }); 889 890 this.started = false; 891 }, 892 893 // TODO: make sure destroying one instance of mouse doesn't mess with 894 // other instances of mouse 895 _mouseDestroy: function() { 896 this.element.unbind("."+this.widgetName); 897 if ( this._mouseMoveDelegate ) { 898 $(document) 899 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) 900 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); 901 } 902 }, 903 904 _mouseDown: function(event) { 905 // don't let more than one widget handle mouseStart 906 if( mouseHandled ) { return; } 907 908 // we may have missed mouseup (out of window) 909 (this._mouseStarted && this._mouseUp(event)); 910 911 this._mouseDownEvent = event; 912 913 var that = this, 914 btnIsLeft = (event.which === 1), 915 // event.target.nodeName works around a bug in IE 8 with 916 // disabled inputs (#7620) 917 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); 918 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { 919 return true; 920 } 921 922 this.mouseDelayMet = !this.options.delay; 923 if (!this.mouseDelayMet) { 924 this._mouseDelayTimer = setTimeout(function() { 925 that.mouseDelayMet = true; 926 }, this.options.delay); 927 } 928 929 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 930 this._mouseStarted = (this._mouseStart(event) !== false); 931 if (!this._mouseStarted) { 932 event.preventDefault(); 933 return true; 934 } 935 } 936 937 // Click event may never have fired (Gecko & Opera) 938 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { 939 $.removeData(event.target, this.widgetName + ".preventClickEvent"); 940 } 941 942 // these delegates are required to keep context 943 this._mouseMoveDelegate = function(event) { 944 return that._mouseMove(event); 945 }; 946 this._mouseUpDelegate = function(event) { 947 return that._mouseUp(event); 948 }; 949 $(document) 950 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) 951 .bind("mouseup."+this.widgetName, this._mouseUpDelegate); 952 953 event.preventDefault(); 954 955 mouseHandled = true; 956 return true; 957 }, 958 959 _mouseMove: function(event) { 960 // IE mouseup check - mouseup happened when mouse was out of window 961 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { 962 return this._mouseUp(event); 963 } 964 965 if (this._mouseStarted) { 966 this._mouseDrag(event); 967 return event.preventDefault(); 968 } 969 970 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 971 this._mouseStarted = 972 (this._mouseStart(this._mouseDownEvent, event) !== false); 973 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); 974 } 975 976 return !this._mouseStarted; 977 }, 978 979 _mouseUp: function(event) { 980 $(document) 981 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) 982 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); 983 984 if (this._mouseStarted) { 985 this._mouseStarted = false; 986 987 if (event.target === this._mouseDownEvent.target) { 988 $.data(event.target, this.widgetName + ".preventClickEvent", true); 989 } 990 991 this._mouseStop(event); 992 } 993 994 return false; 995 }, 996 997 _mouseDistanceMet: function(event) { 998 return (Math.max( 999 Math.abs(this._mouseDownEvent.pageX - event.pageX), 1000 Math.abs(this._mouseDownEvent.pageY - event.pageY) 1001 ) >= this.options.distance 1002 ); 1003 }, 1004 1005 _mouseDelayMet: function(/* event */) { 1006 return this.mouseDelayMet; 1007 }, 1008 1009 // These are placeholder methods, to be overriden by extending plugin 1010 _mouseStart: function(/* event */) {}, 1011 _mouseDrag: function(/* event */) {}, 1012 _mouseStop: function(/* event */) {}, 1013 _mouseCapture: function(/* event */) { return true; } 1014 }); 1015 1016 })(jQuery); 1017 1018 /*! 1019 * jQuery UI Position 1.10.4 1020 * http://jqueryui.com 1021 * 1022 * Copyright 2014 jQuery Foundation and other contributors 1023 * Released under the MIT license. 1024 * http://jquery.org/license 1025 * 1026 * http://api.jqueryui.com/position/ 1027 */ 1028 (function( $, undefined ) { 1029 1030 $.ui = $.ui || {}; 1031 1032 var cachedScrollbarWidth, 1033 max = Math.max, 1034 abs = Math.abs, 1035 round = Math.round, 1036 rhorizontal = /left|center|right/, 1037 rvertical = /top|center|bottom/, 1038 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 1039 rposition = /^\w+/, 1040 rpercent = /%$/, 1041 _position = $.fn.position; 1042 1043 function getOffsets( offsets, width, height ) { 1044 return [ 1045 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 1046 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 1047 ]; 1048 } 1049 1050 function parseCss( element, property ) { 1051 return parseInt( $.css( element, property ), 10 ) || 0; 1052 } 1053 1054 function getDimensions( elem ) { 1055 var raw = elem[0]; 1056 if ( raw.nodeType === 9 ) { 1057 return { 1058 width: elem.width(), 1059 height: elem.height(), 1060 offset: { top: 0, left: 0 } 1061 }; 1062 } 1063 if ( $.isWindow( raw ) ) { 1064 return { 1065 width: elem.width(), 1066 height: elem.height(), 1067 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 1068 }; 1069 } 1070 if ( raw.preventDefault ) { 1071 return { 1072 width: 0, 1073 height: 0, 1074 offset: { top: raw.pageY, left: raw.pageX } 1075 }; 1076 } 1077 return { 1078 width: elem.outerWidth(), 1079 height: elem.outerHeight(), 1080 offset: elem.offset() 1081 }; 1082 } 1083 1084 $.position = { 1085 scrollbarWidth: function() { 1086 if ( cachedScrollbarWidth !== undefined ) { 1087 return cachedScrollbarWidth; 1088 } 1089 var w1, w2, 1090 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), 1091 innerDiv = div.children()[0]; 1092 1093 $( "body" ).append( div ); 1094 w1 = innerDiv.offsetWidth; 1095 div.css( "overflow", "scroll" ); 1096 1097 w2 = innerDiv.offsetWidth; 1098 1099 if ( w1 === w2 ) { 1100 w2 = div[0].clientWidth; 1101 } 1102 1103 div.remove(); 1104 1105 return (cachedScrollbarWidth = w1 - w2); 1106 }, 1107 getScrollInfo: function( within ) { 1108 var overflowX = within.isWindow || within.isDocument ? "" : 1109 within.element.css( "overflow-x" ), 1110 overflowY = within.isWindow || within.isDocument ? "" : 1111 within.element.css( "overflow-y" ), 1112 hasOverflowX = overflowX === "scroll" || 1113 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), 1114 hasOverflowY = overflowY === "scroll" || 1115 ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); 1116 return { 1117 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 1118 height: hasOverflowX ? $.position.scrollbarWidth() : 0 1119 }; 1120 }, 1121 getWithinInfo: function( element ) { 1122 var withinElement = $( element || window ), 1123 isWindow = $.isWindow( withinElement[0] ), 1124 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; 1125 return { 1126 element: withinElement, 1127 isWindow: isWindow, 1128 isDocument: isDocument, 1129 offset: withinElement.offset() || { left: 0, top: 0 }, 1130 scrollLeft: withinElement.scrollLeft(), 1131 scrollTop: withinElement.scrollTop(), 1132 width: isWindow ? withinElement.width() : withinElement.outerWidth(), 1133 height: isWindow ? withinElement.height() : withinElement.outerHeight() 1134 }; 1135 } 1136 }; 1137 1138 $.fn.position = function( options ) { 1139 if ( !options || !options.of ) { 1140 return _position.apply( this, arguments ); 1141 } 1142 1143 // make a copy, we don't want to modify arguments 1144 options = $.extend( {}, options ); 1145 1146 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 1147 target = $( options.of ), 1148 within = $.position.getWithinInfo( options.within ), 1149 scrollInfo = $.position.getScrollInfo( within ), 1150 collision = ( options.collision || "flip" ).split( " " ), 1151 offsets = {}; 1152 1153 dimensions = getDimensions( target ); 1154 if ( target[0].preventDefault ) { 1155 // force left top to allow flipping 1156 options.at = "left top"; 1157 } 1158 targetWidth = dimensions.width; 1159 targetHeight = dimensions.height; 1160 targetOffset = dimensions.offset; 1161 // clone to reuse original targetOffset later 1162 basePosition = $.extend( {}, targetOffset ); 1163 1164 // force my and at to have valid horizontal and vertical positions 1165 // if a value is missing or invalid, it will be converted to center 1166 $.each( [ "my", "at" ], function() { 1167 var pos = ( options[ this ] || "" ).split( " " ), 1168 horizontalOffset, 1169 verticalOffset; 1170 1171 if ( pos.length === 1) { 1172 pos = rhorizontal.test( pos[ 0 ] ) ? 1173 pos.concat( [ "center" ] ) : 1174 rvertical.test( pos[ 0 ] ) ? 1175 [ "center" ].concat( pos ) : 1176 [ "center", "center" ]; 1177 } 1178 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 1179 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 1180 1181 // calculate offsets 1182 horizontalOffset = roffset.exec( pos[ 0 ] ); 1183 verticalOffset = roffset.exec( pos[ 1 ] ); 1184 offsets[ this ] = [ 1185 horizontalOffset ? horizontalOffset[ 0 ] : 0, 1186 verticalOffset ? verticalOffset[ 0 ] : 0 1187 ]; 1188 1189 // reduce to just the positions without the offsets 1190 options[ this ] = [ 1191 rposition.exec( pos[ 0 ] )[ 0 ], 1192 rposition.exec( pos[ 1 ] )[ 0 ] 1193 ]; 1194 }); 1195 1196 // normalize collision option 1197 if ( collision.length === 1 ) { 1198 collision[ 1 ] = collision[ 0 ]; 1199 } 1200 1201 if ( options.at[ 0 ] === "right" ) { 1202 basePosition.left += targetWidth; 1203 } else if ( options.at[ 0 ] === "center" ) { 1204 basePosition.left += targetWidth / 2; 1205 } 1206 1207 if ( options.at[ 1 ] === "bottom" ) { 1208 basePosition.top += targetHeight; 1209 } else if ( options.at[ 1 ] === "center" ) { 1210 basePosition.top += targetHeight / 2; 1211 } 1212 1213 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 1214 basePosition.left += atOffset[ 0 ]; 1215 basePosition.top += atOffset[ 1 ]; 1216 1217 return this.each(function() { 1218 var collisionPosition, using, 1219 elem = $( this ), 1220 elemWidth = elem.outerWidth(), 1221 elemHeight = elem.outerHeight(), 1222 marginLeft = parseCss( this, "marginLeft" ), 1223 marginTop = parseCss( this, "marginTop" ), 1224 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, 1225 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, 1226 position = $.extend( {}, basePosition ), 1227 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 1228 1229 if ( options.my[ 0 ] === "right" ) { 1230 position.left -= elemWidth; 1231 } else if ( options.my[ 0 ] === "center" ) { 1232 position.left -= elemWidth / 2; 1233 } 1234 1235 if ( options.my[ 1 ] === "bottom" ) { 1236 position.top -= elemHeight; 1237 } else if ( options.my[ 1 ] === "center" ) { 1238 position.top -= elemHeight / 2; 1239 } 1240 1241 position.left += myOffset[ 0 ]; 1242 position.top += myOffset[ 1 ]; 1243 1244 // if the browser doesn't support fractions, then round for consistent results 1245 if ( !$.support.offsetFractions ) { 1246 position.left = round( position.left ); 1247 position.top = round( position.top ); 1248 } 1249 1250 collisionPosition = { 1251 marginLeft: marginLeft, 1252 marginTop: marginTop 1253 }; 1254 1255 $.each( [ "left", "top" ], function( i, dir ) { 1256 if ( $.ui.position[ collision[ i ] ] ) { 1257 $.ui.position[ collision[ i ] ][ dir ]( position, { 1258 targetWidth: targetWidth, 1259 targetHeight: targetHeight, 1260 elemWidth: elemWidth, 1261 elemHeight: elemHeight, 1262 collisionPosition: collisionPosition, 1263 collisionWidth: collisionWidth, 1264 collisionHeight: collisionHeight, 1265 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 1266 my: options.my, 1267 at: options.at, 1268 within: within, 1269 elem : elem 1270 }); 1271 } 1272 }); 1273 1274 if ( options.using ) { 1275 // adds feedback as second argument to using callback, if present 1276 using = function( props ) { 1277 var left = targetOffset.left - position.left, 1278 right = left + targetWidth - elemWidth, 1279 top = targetOffset.top - position.top, 1280 bottom = top + targetHeight - elemHeight, 1281 feedback = { 1282 target: { 1283 element: target, 1284 left: targetOffset.left, 1285 top: targetOffset.top, 1286 width: targetWidth, 1287 height: targetHeight 1288 }, 1289 element: { 1290 element: elem, 1291 left: position.left, 1292 top: position.top, 1293 width: elemWidth, 1294 height: elemHeight 1295 }, 1296 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 1297 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 1298 }; 1299 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 1300 feedback.horizontal = "center"; 1301 } 1302 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 1303 feedback.vertical = "middle"; 1304 } 1305 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 1306 feedback.important = "horizontal"; 1307 } else { 1308 feedback.important = "vertical"; 1309 } 1310 options.using.call( this, props, feedback ); 1311 }; 1312 } 1313 1314 elem.offset( $.extend( position, { using: using } ) ); 1315 }); 1316 }; 1317 1318 $.ui.position = { 1319 fit: { 1320 left: function( position, data ) { 1321 var within = data.within, 1322 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 1323 outerWidth = within.width, 1324 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1325 overLeft = withinOffset - collisionPosLeft, 1326 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 1327 newOverRight; 1328 1329 // element is wider than within 1330 if ( data.collisionWidth > outerWidth ) { 1331 // element is initially over the left side of within 1332 if ( overLeft > 0 && overRight <= 0 ) { 1333 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; 1334 position.left += overLeft - newOverRight; 1335 // element is initially over right side of within 1336 } else if ( overRight > 0 && overLeft <= 0 ) { 1337 position.left = withinOffset; 1338 // element is initially over both left and right sides of within 1339 } else { 1340 if ( overLeft > overRight ) { 1341 position.left = withinOffset + outerWidth - data.collisionWidth; 1342 } else { 1343 position.left = withinOffset; 1344 } 1345 } 1346 // too far left -> align with left edge 1347 } else if ( overLeft > 0 ) { 1348 position.left += overLeft; 1349 // too far right -> align with right edge 1350 } else if ( overRight > 0 ) { 1351 position.left -= overRight; 1352 // adjust based on position and margin 1353 } else { 1354 position.left = max( position.left - collisionPosLeft, position.left ); 1355 } 1356 }, 1357 top: function( position, data ) { 1358 var within = data.within, 1359 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 1360 outerHeight = data.within.height, 1361 collisionPosTop = position.top - data.collisionPosition.marginTop, 1362 overTop = withinOffset - collisionPosTop, 1363 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 1364 newOverBottom; 1365 1366 // element is taller than within 1367 if ( data.collisionHeight > outerHeight ) { 1368 // element is initially over the top of within 1369 if ( overTop > 0 && overBottom <= 0 ) { 1370 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; 1371 position.top += overTop - newOverBottom; 1372 // element is initially over bottom of within 1373 } else if ( overBottom > 0 && overTop <= 0 ) { 1374 position.top = withinOffset; 1375 // element is initially over both top and bottom of within 1376 } else { 1377 if ( overTop > overBottom ) { 1378 position.top = withinOffset + outerHeight - data.collisionHeight; 1379 } else { 1380 position.top = withinOffset; 1381 } 1382 } 1383 // too far up -> align with top 1384 } else if ( overTop > 0 ) { 1385 position.top += overTop; 1386 // too far down -> align with bottom edge 1387 } else if ( overBottom > 0 ) { 1388 position.top -= overBottom; 1389 // adjust based on position and margin 1390 } else { 1391 position.top = max( position.top - collisionPosTop, position.top ); 1392 } 1393 } 1394 }, 1395 flip: { 1396 left: function( position, data ) { 1397 var within = data.within, 1398 withinOffset = within.offset.left + within.scrollLeft, 1399 outerWidth = within.width, 1400 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 1401 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1402 overLeft = collisionPosLeft - offsetLeft, 1403 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 1404 myOffset = data.my[ 0 ] === "left" ? 1405 -data.elemWidth : 1406 data.my[ 0 ] === "right" ? 1407 data.elemWidth : 1408 0, 1409 atOffset = data.at[ 0 ] === "left" ? 1410 data.targetWidth : 1411 data.at[ 0 ] === "right" ? 1412 -data.targetWidth : 1413 0, 1414 offset = -2 * data.offset[ 0 ], 1415 newOverRight, 1416 newOverLeft; 1417 1418 if ( overLeft < 0 ) { 1419 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; 1420 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 1421 position.left += myOffset + atOffset + offset; 1422 } 1423 } 1424 else if ( overRight > 0 ) { 1425 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; 1426 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 1427 position.left += myOffset + atOffset + offset; 1428 } 1429 } 1430 }, 1431 top: function( position, data ) { 1432 var within = data.within, 1433 withinOffset = within.offset.top + within.scrollTop, 1434 outerHeight = within.height, 1435 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 1436 collisionPosTop = position.top - data.collisionPosition.marginTop, 1437 overTop = collisionPosTop - offsetTop, 1438 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 1439 top = data.my[ 1 ] === "top", 1440 myOffset = top ? 1441 -data.elemHeight : 1442 data.my[ 1 ] === "bottom" ? 1443 data.elemHeight : 1444 0, 1445 atOffset = data.at[ 1 ] === "top" ? 1446 data.targetHeight : 1447 data.at[ 1 ] === "bottom" ? 1448 -data.targetHeight : 1449 0, 1450 offset = -2 * data.offset[ 1 ], 1451 newOverTop, 1452 newOverBottom; 1453 if ( overTop < 0 ) { 1454 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; 1455 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { 1456 position.top += myOffset + atOffset + offset; 1457 } 1458 } 1459 else if ( overBottom > 0 ) { 1460 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; 1461 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { 1462 position.top += myOffset + atOffset + offset; 1463 } 1464 } 1465 } 1466 }, 1467 flipfit: { 1468 left: function() { 1469 $.ui.position.flip.left.apply( this, arguments ); 1470 $.ui.position.fit.left.apply( this, arguments ); 1471 }, 1472 top: function() { 1473 $.ui.position.flip.top.apply( this, arguments ); 1474 $.ui.position.fit.top.apply( this, arguments ); 1475 } 1476 } 1477 }; 1478 1479 // fraction support test 1480 (function () { 1481 var testElement, testElementParent, testElementStyle, offsetLeft, i, 1482 body = document.getElementsByTagName( "body" )[ 0 ], 1483 div = document.createElement( "div" ); 1484 1485 //Create a "fake body" for testing based on method used in jQuery.support 1486 testElement = document.createElement( body ? "div" : "body" ); 1487 testElementStyle = { 1488 visibility: "hidden", 1489 width: 0, 1490 height: 0, 1491 border: 0, 1492 margin: 0, 1493 background: "none" 1494 }; 1495 if ( body ) { 1496 $.extend( testElementStyle, { 1497 position: "absolute", 1498 left: "-1000px", 1499 top: "-1000px" 1500 }); 1501 } 1502 for ( i in testElementStyle ) { 1503 testElement.style[ i ] = testElementStyle[ i ]; 1504 } 1505 testElement.appendChild( div ); 1506 testElementParent = body || document.documentElement; 1507 testElementParent.insertBefore( testElement, testElementParent.firstChild ); 1508 1509 div.style.cssText = "position: absolute; left: 10.7432222px;"; 1510 1511 offsetLeft = $( div ).offset().left; 1512 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; 1513 1514 testElement.innerHTML = ""; 1515 testElementParent.removeChild( testElement ); 1516 })(); 1517 1518 }( jQuery ) ); 1519 1520 /*! 1521 * jQuery UI Button 1.10.4 1522 * http://jqueryui.com 1523 * 1524 * Copyright 2014 jQuery Foundation and other contributors 1525 * Released under the MIT license. 1526 * http://jquery.org/license 1527 * 1528 * http://api.jqueryui.com/button/ 1529 * 1530 * Depends: 1531 * jquery.ui.core.js 1532 * jquery.ui.widget.js 1533 */ 1534 (function( $, undefined ) { 1535 1536 var lastActive, 1537 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", 1538 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", 1539 formResetHandler = function() { 1540 var form = $( this ); 1541 setTimeout(function() { 1542 form.find( ":ui-button" ).button( "refresh" ); 1543 }, 1 ); 1544 }, 1545 radioGroup = function( radio ) { 1546 var name = radio.name, 1547 form = radio.form, 1548 radios = $( [] ); 1549 if ( name ) { 1550 name = name.replace( /'/g, "\\'" ); 1551 if ( form ) { 1552 radios = $( form ).find( "[name='" + name + "']" ); 1553 } else { 1554 radios = $( "[name='" + name + "']", radio.ownerDocument ) 1555 .filter(function() { 1556 return !this.form; 1557 }); 1558 } 1559 } 1560 return radios; 1561 }; 1562 1563 $.widget( "ui.button", { 1564 version: "1.10.4", 1565 defaultElement: "<button>", 1566 options: { 1567 disabled: null, 1568 text: true, 1569 label: null, 1570 icons: { 1571 primary: null, 1572 secondary: null 1573 } 1574 }, 1575 _create: function() { 1576 this.element.closest( "form" ) 1577 .unbind( "reset" + this.eventNamespace ) 1578 .bind( "reset" + this.eventNamespace, formResetHandler ); 1579 1580 if ( typeof this.options.disabled !== "boolean" ) { 1581 this.options.disabled = !!this.element.prop( "disabled" ); 1582 } else { 1583 this.element.prop( "disabled", this.options.disabled ); 1584 } 1585 1586 this._determineButtonType(); 1587 this.hasTitle = !!this.buttonElement.attr( "title" ); 1588 1589 var that = this, 1590 options = this.options, 1591 toggleButton = this.type === "checkbox" || this.type === "radio", 1592 activeClass = !toggleButton ? "ui-state-active" : ""; 1593 1594 if ( options.label === null ) { 1595 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); 1596 } 1597 1598 this._hoverable( this.buttonElement ); 1599 1600 this.buttonElement 1601 .addClass( baseClasses ) 1602 .attr( "role", "button" ) 1603 .bind( "mouseenter" + this.eventNamespace, function() { 1604 if ( options.disabled ) { 1605 return; 1606 } 1607 if ( this === lastActive ) { 1608 $( this ).addClass( "ui-state-active" ); 1609 } 1610 }) 1611 .bind( "mouseleave" + this.eventNamespace, function() { 1612 if ( options.disabled ) { 1613 return; 1614 } 1615 $( this ).removeClass( activeClass ); 1616 }) 1617 .bind( "click" + this.eventNamespace, function( event ) { 1618 if ( options.disabled ) { 1619 event.preventDefault(); 1620 event.stopImmediatePropagation(); 1621 } 1622 }); 1623 1624 // Can't use _focusable() because the element that receives focus 1625 // and the element that gets the ui-state-focus class are different 1626 this._on({ 1627 focus: function() { 1628 this.buttonElement.addClass( "ui-state-focus" ); 1629 }, 1630 blur: function() { 1631 this.buttonElement.removeClass( "ui-state-focus" ); 1632 } 1633 }); 1634 1635 if ( toggleButton ) { 1636 this.element.bind( "change" + this.eventNamespace, function() { 1637 that.refresh(); 1638 }); 1639 } 1640 1641 if ( this.type === "checkbox" ) { 1642 this.buttonElement.bind( "click" + this.eventNamespace, function() { 1643 if ( options.disabled ) { 1644 return false; 1645 } 1646 }); 1647 } else if ( this.type === "radio" ) { 1648 this.buttonElement.bind( "click" + this.eventNamespace, function() { 1649 if ( options.disabled ) { 1650 return false; 1651 } 1652 $( this ).addClass( "ui-state-active" ); 1653 that.buttonElement.attr( "aria-pressed", "true" ); 1654 1655 var radio = that.element[ 0 ]; 1656 radioGroup( radio ) 1657 .not( radio ) 1658 .map(function() { 1659 return $( this ).button( "widget" )[ 0 ]; 1660 }) 1661 .removeClass( "ui-state-active" ) 1662 .attr( "aria-pressed", "false" ); 1663 }); 1664 } else { 1665 this.buttonElement 1666 .bind( "mousedown" + this.eventNamespace, function() { 1667 if ( options.disabled ) { 1668 return false; 1669 } 1670 $( this ).addClass( "ui-state-active" ); 1671 lastActive = this; 1672 that.document.one( "mouseup", function() { 1673 lastActive = null; 1674 }); 1675 }) 1676 .bind( "mouseup" + this.eventNamespace, function() { 1677 if ( options.disabled ) { 1678 return false; 1679 } 1680 $( this ).removeClass( "ui-state-active" ); 1681 }) 1682 .bind( "keydown" + this.eventNamespace, function(event) { 1683 if ( options.disabled ) { 1684 return false; 1685 } 1686 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { 1687 $( this ).addClass( "ui-state-active" ); 1688 } 1689 }) 1690 // see #8559, we bind to blur here in case the button element loses 1691 // focus between keydown and keyup, it would be left in an "active" state 1692 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { 1693 $( this ).removeClass( "ui-state-active" ); 1694 }); 1695 1696 if ( this.buttonElement.is("a") ) { 1697 this.buttonElement.keyup(function(event) { 1698 if ( event.keyCode === $.ui.keyCode.SPACE ) { 1699 // TODO pass through original event correctly (just as 2nd argument doesn't work) 1700 $( this ).click(); 1701 } 1702 }); 1703 } 1704 } 1705 1706 // TODO: pull out $.Widget's handling for the disabled option into 1707 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can 1708 // be overridden by individual plugins 1709 this._setOption( "disabled", options.disabled ); 1710 this._resetButton(); 1711 }, 1712 1713 _determineButtonType: function() { 1714 var ancestor, labelSelector, checked; 1715 1716 if ( this.element.is("[type=checkbox]") ) { 1717 this.type = "checkbox"; 1718 } else if ( this.element.is("[type=radio]") ) { 1719 this.type = "radio"; 1720 } else if ( this.element.is("input") ) { 1721 this.type = "input"; 1722 } else { 1723 this.type = "button"; 1724 } 1725 1726 if ( this.type === "checkbox" || this.type === "radio" ) { 1727 // we don't search against the document in case the element 1728 // is disconnected from the DOM 1729 ancestor = this.element.parents().last(); 1730 labelSelector = "label[for='" + this.element.attr("id") + "']"; 1731 this.buttonElement = ancestor.find( labelSelector ); 1732 if ( !this.buttonElement.length ) { 1733 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); 1734 this.buttonElement = ancestor.filter( labelSelector ); 1735 if ( !this.buttonElement.length ) { 1736 this.buttonElement = ancestor.find( labelSelector ); 1737 } 1738 } 1739 this.element.addClass( "ui-helper-hidden-accessible" ); 1740 1741 checked = this.element.is( ":checked" ); 1742 if ( checked ) { 1743 this.buttonElement.addClass( "ui-state-active" ); 1744 } 1745 this.buttonElement.prop( "aria-pressed", checked ); 1746 } else { 1747 this.buttonElement = this.element; 1748 } 1749 }, 1750 1751 widget: function() { 1752 return this.buttonElement; 1753 }, 1754 1755 _destroy: function() { 1756 this.element 1757 .removeClass( "ui-helper-hidden-accessible" ); 1758 this.buttonElement 1759 .removeClass( baseClasses + " ui-state-active " + typeClasses ) 1760 .removeAttr( "role" ) 1761 .removeAttr( "aria-pressed" ) 1762 .html( this.buttonElement.find(".ui-button-text").html() ); 1763 1764 if ( !this.hasTitle ) { 1765 this.buttonElement.removeAttr( "title" ); 1766 } 1767 }, 1768 1769 _setOption: function( key, value ) { 1770 this._super( key, value ); 1771 if ( key === "disabled" ) { 1772 this.element.prop( "disabled", !!value ); 1773 if ( value ) { 1774 this.buttonElement.removeClass( "ui-state-focus" ); 1775 } 1776 return; 1777 } 1778 this._resetButton(); 1779 }, 1780 1781 refresh: function() { 1782 //See #8237 & #8828 1783 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); 1784 1785 if ( isDisabled !== this.options.disabled ) { 1786 this._setOption( "disabled", isDisabled ); 1787 } 1788 if ( this.type === "radio" ) { 1789 radioGroup( this.element[0] ).each(function() { 1790 if ( $( this ).is( ":checked" ) ) { 1791 $( this ).button( "widget" ) 1792 .addClass( "ui-state-active" ) 1793 .attr( "aria-pressed", "true" ); 1794 } else { 1795 $( this ).button( "widget" ) 1796 .removeClass( "ui-state-active" ) 1797 .attr( "aria-pressed", "false" ); 1798 } 1799 }); 1800 } else if ( this.type === "checkbox" ) { 1801 if ( this.element.is( ":checked" ) ) { 1802 this.buttonElement 1803 .addClass( "ui-state-active" ) 1804 .attr( "aria-pressed", "true" ); 1805 } else { 1806 this.buttonElement 1807 .removeClass( "ui-state-active" ) 1808 .attr( "aria-pressed", "false" ); 1809 } 1810 } 1811 }, 1812 1813 _resetButton: function() { 1814 if ( this.type === "input" ) { 1815 if ( this.options.label ) { 1816 this.element.val( this.options.label ); 1817 } 1818 return; 1819 } 1820 var buttonElement = this.buttonElement.removeClass( typeClasses ), 1821 buttonText = $( "<span></span>", this.document[0] ) 1822 .addClass( "ui-button-text" ) 1823 .html( this.options.label ) 1824 .appendTo( buttonElement.empty() ) 1825 .text(), 1826 icons = this.options.icons, 1827 multipleIcons = icons.primary && icons.secondary, 1828 buttonClasses = []; 1829 1830 if ( icons.primary || icons.secondary ) { 1831 if ( this.options.text ) { 1832 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); 1833 } 1834 1835 if ( icons.primary ) { 1836 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); 1837 } 1838 1839 if ( icons.secondary ) { 1840 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); 1841 } 1842 1843 if ( !this.options.text ) { 1844 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); 1845 1846 if ( !this.hasTitle ) { 1847 buttonElement.attr( "title", $.trim( buttonText ) ); 1848 } 1849 } 1850 } else { 1851 buttonClasses.push( "ui-button-text-only" ); 1852 } 1853 buttonElement.addClass( buttonClasses.join( " " ) ); 1854 } 1855 }); 1856 1857 $.widget( "ui.buttonset", { 1858 version: "1.10.4", 1859 options: { 1860 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" 1861 }, 1862 1863 _create: function() { 1864 this.element.addClass( "ui-buttonset" ); 1865 }, 1866 1867 _init: function() { 1868 this.refresh(); 1869 }, 1870 1871 _setOption: function( key, value ) { 1872 if ( key === "disabled" ) { 1873 this.buttons.button( "option", key, value ); 1874 } 1875 1876 this._super( key, value ); 1877 }, 1878 1879 refresh: function() { 1880 var rtl = this.element.css( "direction" ) === "rtl"; 1881 1882 this.buttons = this.element.find( this.options.items ) 1883 .filter( ":ui-button" ) 1884 .button( "refresh" ) 1885 .end() 1886 .not( ":ui-button" ) 1887 .button() 1888 .end() 1889 .map(function() { 1890 return $( this ).button( "widget" )[ 0 ]; 1891 }) 1892 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) 1893 .filter( ":first" ) 1894 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) 1895 .end() 1896 .filter( ":last" ) 1897 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) 1898 .end() 1899 .end(); 1900 }, 1901 1902 _destroy: function() { 1903 this.element.removeClass( "ui-buttonset" ); 1904 this.buttons 1905 .map(function() { 1906 return $( this ).button( "widget" )[ 0 ]; 1907 }) 1908 .removeClass( "ui-corner-left ui-corner-right" ) 1909 .end() 1910 .button( "destroy" ); 1911 } 1912 }); 1913 1914 }( jQuery ) ); 1915 1916 /*! 1917 * jQuery UI Slider 1.10.4 1918 * http://jqueryui.com 1919 * 1920 * Copyright 2014 jQuery Foundation and other contributors 1921 * Released under the MIT license. 1922 * http://jquery.org/license 1923 * 1924 * http://api.jqueryui.com/slider/ 1925 * 1926 * Depends: 1927 * jquery.ui.core.js 1928 * jquery.ui.mouse.js 1929 * jquery.ui.widget.js 1930 */ 1931 (function( $, undefined ) { 1932 1933 // number of pages in a slider 1934 // (how many times can you page up/down to go through the whole range) 1935 var numPages = 5; 1936 1937 $.widget( "ui.slider", $.ui.mouse, { 1938 version: "1.10.4", 1939 widgetEventPrefix: "slide", 1940 1941 options: { 1942 animate: false, 1943 distance: 0, 1944 max: 100, 1945 min: 0, 1946 orientation: "horizontal", 1947 range: false, 1948 step: 1, 1949 value: 0, 1950 values: null, 1951 1952 // callbacks 1953 change: null, 1954 slide: null, 1955 start: null, 1956 stop: null 1957 }, 1958 1959 _create: function() { 1960 this._keySliding = false; 1961 this._mouseSliding = false; 1962 this._animateOff = true; 1963 this._handleIndex = null; 1964 this._detectOrientation(); 1965 this._mouseInit(); 1966 1967 this.element 1968 .addClass( "ui-slider" + 1969 " ui-slider-" + this.orientation + 1970 " ui-widget" + 1971 " ui-widget-content" + 1972 " ui-corner-all"); 1973 1974 this._refresh(); 1975 this._setOption( "disabled", this.options.disabled ); 1976 1977 this._animateOff = false; 1978 }, 1979 1980 _refresh: function() { 1981 this._createRange(); 1982 this._createHandles(); 1983 this._setupEvents(); 1984 this._refreshValue(); 1985 }, 1986 1987 _createHandles: function() { 1988 var i, handleCount, 1989 options = this.options, 1990 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), 1991 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>", 1992 handles = []; 1993 1994 handleCount = ( options.values && options.values.length ) || 1; 1995 1996 if ( existingHandles.length > handleCount ) { 1997 existingHandles.slice( handleCount ).remove(); 1998 existingHandles = existingHandles.slice( 0, handleCount ); 1999 } 2000 2001 for ( i = existingHandles.length; i < handleCount; i++ ) { 2002 handles.push( handle ); 2003 } 2004 2005 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 2006 2007 this.handle = this.handles.eq( 0 ); 2008 2009 this.handles.each(function( i ) { 2010 $( this ).data( "ui-slider-handle-index", i ); 2011 }); 2012 }, 2013 2014 _createRange: function() { 2015 var options = this.options, 2016 classes = ""; 2017 2018 if ( options.range ) { 2019 if ( options.range === true ) { 2020 if ( !options.values ) { 2021 options.values = [ this._valueMin(), this._valueMin() ]; 2022 } else if ( options.values.length && options.values.length !== 2 ) { 2023 options.values = [ options.values[0], options.values[0] ]; 2024 } else if ( $.isArray( options.values ) ) { 2025 options.values = options.values.slice(0); 2026 } 2027 } 2028 2029 if ( !this.range || !this.range.length ) { 2030 this.range = $( "<div></div>" ) 2031 .appendTo( this.element ); 2032 2033 classes = "ui-slider-range" + 2034 // note: this isn't the most fittingly semantic framework class for this element, 2035 // but worked best visually with a variety of themes 2036 " ui-widget-header ui-corner-all"; 2037 } else { 2038 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) 2039 // Handle range switching from true to min/max 2040 .css({ 2041 "left": "", 2042 "bottom": "" 2043 }); 2044 } 2045 2046 this.range.addClass( classes + 2047 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); 2048 } else { 2049 if ( this.range ) { 2050 this.range.remove(); 2051 } 2052 this.range = null; 2053 } 2054 }, 2055 2056 _setupEvents: function() { 2057 var elements = this.handles.add( this.range ).filter( "a" ); 2058 this._off( elements ); 2059 this._on( elements, this._handleEvents ); 2060 this._hoverable( elements ); 2061 this._focusable( elements ); 2062 }, 2063 2064 _destroy: function() { 2065 this.handles.remove(); 2066 if ( this.range ) { 2067 this.range.remove(); 2068 } 2069 2070 this.element 2071 .removeClass( "ui-slider" + 2072 " ui-slider-horizontal" + 2073 " ui-slider-vertical" + 2074 " ui-widget" + 2075 " ui-widget-content" + 2076 " ui-corner-all" ); 2077 2078 this._mouseDestroy(); 2079 }, 2080 2081 _mouseCapture: function( event ) { 2082 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 2083 that = this, 2084 o = this.options; 2085 2086 if ( o.disabled ) { 2087 return false; 2088 } 2089 2090 this.elementSize = { 2091 width: this.element.outerWidth(), 2092 height: this.element.outerHeight() 2093 }; 2094 this.elementOffset = this.element.offset(); 2095 2096 position = { x: event.pageX, y: event.pageY }; 2097 normValue = this._normValueFromMouse( position ); 2098 distance = this._valueMax() - this._valueMin() + 1; 2099 this.handles.each(function( i ) { 2100 var thisDistance = Math.abs( normValue - that.values(i) ); 2101 if (( distance > thisDistance ) || 2102 ( distance === thisDistance && 2103 (i === that._lastChangedValue || that.values(i) === o.min ))) { 2104 distance = thisDistance; 2105 closestHandle = $( this ); 2106 index = i; 2107 } 2108 }); 2109 2110 allowed = this._start( event, index ); 2111 if ( allowed === false ) { 2112 return false; 2113 } 2114 this._mouseSliding = true; 2115 2116 this._handleIndex = index; 2117 2118 closestHandle 2119 .addClass( "ui-state-active" ) 2120 .focus(); 2121 2122 offset = closestHandle.offset(); 2123 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 2124 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 2125 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 2126 top: event.pageY - offset.top - 2127 ( closestHandle.height() / 2 ) - 2128 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - 2129 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + 2130 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) 2131 }; 2132 2133 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 2134 this._slide( event, index, normValue ); 2135 } 2136 this._animateOff = true; 2137 return true; 2138 }, 2139 2140 _mouseStart: function() { 2141 return true; 2142 }, 2143 2144 _mouseDrag: function( event ) { 2145 var position = { x: event.pageX, y: event.pageY }, 2146 normValue = this._normValueFromMouse( position ); 2147 2148 this._slide( event, this._handleIndex, normValue ); 2149 2150 return false; 2151 }, 2152 2153 _mouseStop: function( event ) { 2154 this.handles.removeClass( "ui-state-active" ); 2155 this._mouseSliding = false; 2156 2157 this._stop( event, this._handleIndex ); 2158 this._change( event, this._handleIndex ); 2159 2160 this._handleIndex = null; 2161 this._clickOffset = null; 2162 this._animateOff = false; 2163 2164 return false; 2165 }, 2166 2167 _detectOrientation: function() { 2168 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 2169 }, 2170 2171 _normValueFromMouse: function( position ) { 2172 var pixelTotal, 2173 pixelMouse, 2174 percentMouse, 2175 valueTotal, 2176 valueMouse; 2177 2178 if ( this.orientation === "horizontal" ) { 2179 pixelTotal = this.elementSize.width; 2180 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); 2181 } else { 2182 pixelTotal = this.elementSize.height; 2183 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); 2184 } 2185 2186 percentMouse = ( pixelMouse / pixelTotal ); 2187 if ( percentMouse > 1 ) { 2188 percentMouse = 1; 2189 } 2190 if ( percentMouse < 0 ) { 2191 percentMouse = 0; 2192 } 2193 if ( this.orientation === "vertical" ) { 2194 percentMouse = 1 - percentMouse; 2195 } 2196 2197 valueTotal = this._valueMax() - this._valueMin(); 2198 valueMouse = this._valueMin() + percentMouse * valueTotal; 2199 2200 return this._trimAlignValue( valueMouse ); 2201 }, 2202 2203 _start: function( event, index ) { 2204 var uiHash = { 2205 handle: this.handles[ index ], 2206 value: this.value() 2207 }; 2208 if ( this.options.values && this.options.values.length ) { 2209 uiHash.value = this.values( index ); 2210 uiHash.values = this.values(); 2211 } 2212 return this._trigger( "start", event, uiHash ); 2213 }, 2214 2215 _slide: function( event, index, newVal ) { 2216 var otherVal, 2217 newValues, 2218 allowed; 2219 2220 if ( this.options.values && this.options.values.length ) { 2221 otherVal = this.values( index ? 0 : 1 ); 2222 2223 if ( ( this.options.values.length === 2 && this.options.range === true ) && 2224 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) 2225 ) { 2226 newVal = otherVal; 2227 } 2228 2229 if ( newVal !== this.values( index ) ) { 2230 newValues = this.values(); 2231 newValues[ index ] = newVal; 2232 // A slide can be canceled by returning false from the slide callback 2233 allowed = this._trigger( "slide", event, { 2234 handle: this.handles[ index ], 2235 value: newVal, 2236 values: newValues 2237 } ); 2238 otherVal = this.values( index ? 0 : 1 ); 2239 if ( allowed !== false ) { 2240 this.values( index, newVal ); 2241 } 2242 } 2243 } else { 2244 if ( newVal !== this.value() ) { 2245 // A slide can be canceled by returning false from the slide callback 2246 allowed = this._trigger( "slide", event, { 2247 handle: this.handles[ index ], 2248 value: newVal 2249 } ); 2250 if ( allowed !== false ) { 2251 this.value( newVal ); 2252 } 2253 } 2254 } 2255 }, 2256 2257 _stop: function( event, index ) { 2258 var uiHash = { 2259 handle: this.handles[ index ], 2260 value: this.value() 2261 }; 2262 if ( this.options.values && this.options.values.length ) { 2263 uiHash.value = this.values( index ); 2264 uiHash.values = this.values(); 2265 } 2266 2267 this._trigger( "stop", event, uiHash ); 2268 }, 2269 2270 _change: function( event, index ) { 2271 if ( !this._keySliding && !this._mouseSliding ) { 2272 var uiHash = { 2273 handle: this.handles[ index ], 2274 value: this.value() 2275 }; 2276 if ( this.options.values && this.options.values.length ) { 2277 uiHash.value = this.values( index ); 2278 uiHash.values = this.values(); 2279 } 2280 2281 //store the last changed value index for reference when handles overlap 2282 this._lastChangedValue = index; 2283 2284 this._trigger( "change", event, uiHash ); 2285 } 2286 }, 2287 2288 value: function( newValue ) { 2289 if ( arguments.length ) { 2290 this.options.value = this._trimAlignValue( newValue ); 2291 this._refreshValue(); 2292 this._change( null, 0 ); 2293 return; 2294 } 2295 2296 return this._value(); 2297 }, 2298 2299 values: function( index, newValue ) { 2300 var vals, 2301 newValues, 2302 i; 2303 2304 if ( arguments.length > 1 ) { 2305 this.options.values[ index ] = this._trimAlignValue( newValue ); 2306 this._refreshValue(); 2307 this._change( null, index ); 2308 return; 2309 } 2310 2311 if ( arguments.length ) { 2312 if ( $.isArray( arguments[ 0 ] ) ) { 2313 vals = this.options.values; 2314 newValues = arguments[ 0 ]; 2315 for ( i = 0; i < vals.length; i += 1 ) { 2316 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 2317 this._change( null, i ); 2318 } 2319 this._refreshValue(); 2320 } else { 2321 if ( this.options.values && this.options.values.length ) { 2322 return this._values( index ); 2323 } else { 2324 return this.value(); 2325 } 2326 } 2327 } else { 2328 return this._values(); 2329 } 2330 }, 2331 2332 _setOption: function( key, value ) { 2333 var i, 2334 valsLength = 0; 2335 2336 if ( key === "range" && this.options.range === true ) { 2337 if ( value === "min" ) { 2338 this.options.value = this._values( 0 ); 2339 this.options.values = null; 2340 } else if ( value === "max" ) { 2341 this.options.value = this._values( this.options.values.length-1 ); 2342 this.options.values = null; 2343 } 2344 } 2345 2346 if ( $.isArray( this.options.values ) ) { 2347 valsLength = this.options.values.length; 2348 } 2349 2350 $.Widget.prototype._setOption.apply( this, arguments ); 2351 2352 switch ( key ) { 2353 case "orientation": 2354 this._detectOrientation(); 2355 this.element 2356 .removeClass( "ui-slider-horizontal ui-slider-vertical" ) 2357 .addClass( "ui-slider-" + this.orientation ); 2358 this._refreshValue(); 2359 break; 2360 case "value": 2361 this._animateOff = true; 2362 this._refreshValue(); 2363 this._change( null, 0 ); 2364 this._animateOff = false; 2365 break; 2366 case "values": 2367 this._animateOff = true; 2368 this._refreshValue(); 2369 for ( i = 0; i < valsLength; i += 1 ) { 2370 this._change( null, i ); 2371 } 2372 this._animateOff = false; 2373 break; 2374 case "min": 2375 case "max": 2376 this._animateOff = true; 2377 this._refreshValue(); 2378 this._animateOff = false; 2379 break; 2380 case "range": 2381 this._animateOff = true; 2382 this._refresh(); 2383 this._animateOff = false; 2384 break; 2385 } 2386 }, 2387 2388 //internal value getter 2389 // _value() returns value trimmed by min and max, aligned by step 2390 _value: function() { 2391 var val = this.options.value; 2392 val = this._trimAlignValue( val ); 2393 2394 return val; 2395 }, 2396 2397 //internal values getter 2398 // _values() returns array of values trimmed by min and max, aligned by step 2399 // _values( index ) returns single value trimmed by min and max, aligned by step 2400 _values: function( index ) { 2401 var val, 2402 vals, 2403 i; 2404 2405 if ( arguments.length ) { 2406 val = this.options.values[ index ]; 2407 val = this._trimAlignValue( val ); 2408 2409 return val; 2410 } else if ( this.options.values && this.options.values.length ) { 2411 // .slice() creates a copy of the array 2412 // this copy gets trimmed by min and max and then returned 2413 vals = this.options.values.slice(); 2414 for ( i = 0; i < vals.length; i+= 1) { 2415 vals[ i ] = this._trimAlignValue( vals[ i ] ); 2416 } 2417 2418 return vals; 2419 } else { 2420 return []; 2421 } 2422 }, 2423 2424 // returns the step-aligned value that val is closest to, between (inclusive) min and max 2425 _trimAlignValue: function( val ) { 2426 if ( val <= this._valueMin() ) { 2427 return this._valueMin(); 2428 } 2429 if ( val >= this._valueMax() ) { 2430 return this._valueMax(); 2431 } 2432 var step = ( this.options.step > 0 ) ? this.options.step : 1, 2433 valModStep = (val - this._valueMin()) % step, 2434 alignValue = val - valModStep; 2435 2436 if ( Math.abs(valModStep) * 2 >= step ) { 2437 alignValue += ( valModStep > 0 ) ? step : ( -step ); 2438 } 2439 2440 // Since JavaScript has problems with large floats, round 2441 // the final value to 5 digits after the decimal point (see #4124) 2442 return parseFloat( alignValue.toFixed(5) ); 2443 }, 2444 2445 _valueMin: function() { 2446 return this.options.min; 2447 }, 2448 2449 _valueMax: function() { 2450 return this.options.max; 2451 }, 2452 2453 _refreshValue: function() { 2454 var lastValPercent, valPercent, value, valueMin, valueMax, 2455 oRange = this.options.range, 2456 o = this.options, 2457 that = this, 2458 animate = ( !this._animateOff ) ? o.animate : false, 2459 _set = {}; 2460 2461 if ( this.options.values && this.options.values.length ) { 2462 this.handles.each(function( i ) { 2463 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; 2464 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 2465 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 2466 if ( that.options.range === true ) { 2467 if ( that.orientation === "horizontal" ) { 2468 if ( i === 0 ) { 2469 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); 2470 } 2471 if ( i === 1 ) { 2472 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 2473 } 2474 } else { 2475 if ( i === 0 ) { 2476 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); 2477 } 2478 if ( i === 1 ) { 2479 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 2480 } 2481 } 2482 } 2483 lastValPercent = valPercent; 2484 }); 2485 } else { 2486 value = this.value(); 2487 valueMin = this._valueMin(); 2488 valueMax = this._valueMax(); 2489 valPercent = ( valueMax !== valueMin ) ? 2490 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 2491 0; 2492 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 2493 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 2494 2495 if ( oRange === "min" && this.orientation === "horizontal" ) { 2496 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); 2497 } 2498 if ( oRange === "max" && this.orientation === "horizontal" ) { 2499 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 2500 } 2501 if ( oRange === "min" && this.orientation === "vertical" ) { 2502 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); 2503 } 2504 if ( oRange === "max" && this.orientation === "vertical" ) { 2505 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 2506 } 2507 } 2508 }, 2509 2510 _handleEvents: { 2511 keydown: function( event ) { 2512 var allowed, curVal, newVal, step, 2513 index = $( event.target ).data( "ui-slider-handle-index" ); 2514 2515 switch ( event.keyCode ) { 2516 case $.ui.keyCode.HOME: 2517 case $.ui.keyCode.END: 2518 case $.ui.keyCode.PAGE_UP: 2519 case $.ui.keyCode.PAGE_DOWN: 2520 case $.ui.keyCode.UP: 2521 case $.ui.keyCode.RIGHT: 2522 case $.ui.keyCode.DOWN: 2523 case $.ui.keyCode.LEFT: 2524 event.preventDefault(); 2525 if ( !this._keySliding ) { 2526 this._keySliding = true; 2527 $( event.target ).addClass( "ui-state-active" ); 2528 allowed = this._start( event, index ); 2529 if ( allowed === false ) { 2530 return; 2531 } 2532 } 2533 break; 2534 } 2535 2536 step = this.options.step; 2537 if ( this.options.values && this.options.values.length ) { 2538 curVal = newVal = this.values( index ); 2539 } else { 2540 curVal = newVal = this.value(); 2541 } 2542 2543 switch ( event.keyCode ) { 2544 case $.ui.keyCode.HOME: 2545 newVal = this._valueMin(); 2546 break; 2547 case $.ui.keyCode.END: 2548 newVal = this._valueMax(); 2549 break; 2550 case $.ui.keyCode.PAGE_UP: 2551 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) ); 2552 break; 2553 case $.ui.keyCode.PAGE_DOWN: 2554 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) ); 2555 break; 2556 case $.ui.keyCode.UP: 2557 case $.ui.keyCode.RIGHT: 2558 if ( curVal === this._valueMax() ) { 2559 return; 2560 } 2561 newVal = this._trimAlignValue( curVal + step ); 2562 break; 2563 case $.ui.keyCode.DOWN: 2564 case $.ui.keyCode.LEFT: 2565 if ( curVal === this._valueMin() ) { 2566 return; 2567 } 2568 newVal = this._trimAlignValue( curVal - step ); 2569 break; 2570 } 2571 2572 this._slide( event, index, newVal ); 2573 }, 2574 click: function( event ) { 2575 event.preventDefault(); 2576 }, 2577 keyup: function( event ) { 2578 var index = $( event.target ).data( "ui-slider-handle-index" ); 2579 2580 if ( this._keySliding ) { 2581 this._keySliding = false; 2582 this._stop( event, index ); 2583 this._change( event, index ); 2584 $( event.target ).removeClass( "ui-state-active" ); 2585 } 2586 } 2587 } 2588 2589 }); 2590 2591 }(jQuery)); 2592 2593 /*! 2594 * jQuery UI Effects 1.10.4 2595 * http://jqueryui.com 2596 * 2597 * Copyright 2014 jQuery Foundation and other contributors 2598 * Released under the MIT license. 2599 * http://jquery.org/license 2600 * 2601 * http://api.jqueryui.com/category/effects-core/ 2602 */ 2603 (function($, undefined) { 2604 2605 var dataSpace = "ui-effects-"; 2606 2607 $.effects = { 2608 effect: {} 2609 }; 2610 2611 /*! 2612 * jQuery Color Animations v2.1.2 2613 * https://github.com/jquery/jquery-color 2614 * 2615 * Copyright 2013 jQuery Foundation and other contributors 2616 * Released under the MIT license. 2617 * http://jquery.org/license 2618 * 2619 * Date: Wed Jan 16 08:47:09 2013 -0600 2620 */ 2621 (function( jQuery, undefined ) { 2622 2623 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", 2624 2625 // plusequals test for += 100 -= 100 2626 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 2627 // a set of RE's that can match strings and generate color tuples. 2628 stringParsers = [{ 2629 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 2630 parse: function( execResult ) { 2631 return [ 2632 execResult[ 1 ], 2633 execResult[ 2 ], 2634 execResult[ 3 ], 2635 execResult[ 4 ] 2636 ]; 2637 } 2638 }, { 2639 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 2640 parse: function( execResult ) { 2641 return [ 2642 execResult[ 1 ] * 2.55, 2643 execResult[ 2 ] * 2.55, 2644 execResult[ 3 ] * 2.55, 2645 execResult[ 4 ] 2646 ]; 2647 } 2648 }, { 2649 // this regex ignores A-F because it's compared against an already lowercased string 2650 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, 2651 parse: function( execResult ) { 2652 return [ 2653 parseInt( execResult[ 1 ], 16 ), 2654 parseInt( execResult[ 2 ], 16 ), 2655 parseInt( execResult[ 3 ], 16 ) 2656 ]; 2657 } 2658 }, { 2659 // this regex ignores A-F because it's compared against an already lowercased string 2660 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, 2661 parse: function( execResult ) { 2662 return [ 2663 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 2664 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 2665 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 2666 ]; 2667 } 2668 }, { 2669 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 2670 space: "hsla", 2671 parse: function( execResult ) { 2672 return [ 2673 execResult[ 1 ], 2674 execResult[ 2 ] / 100, 2675 execResult[ 3 ] / 100, 2676 execResult[ 4 ] 2677 ]; 2678 } 2679 }], 2680 2681 // jQuery.Color( ) 2682 color = jQuery.Color = function( color, green, blue, alpha ) { 2683 return new jQuery.Color.fn.parse( color, green, blue, alpha ); 2684 }, 2685 spaces = { 2686 rgba: { 2687 props: { 2688 red: { 2689 idx: 0, 2690 type: "byte" 2691 }, 2692 green: { 2693 idx: 1, 2694 type: "byte" 2695 }, 2696 blue: { 2697 idx: 2, 2698 type: "byte" 2699 } 2700 } 2701 }, 2702 2703 hsla: { 2704 props: { 2705 hue: { 2706 idx: 0, 2707 type: "degrees" 2708 }, 2709 saturation: { 2710 idx: 1, 2711 type: "percent" 2712 }, 2713 lightness: { 2714 idx: 2, 2715 type: "percent" 2716 } 2717 } 2718 } 2719 }, 2720 propTypes = { 2721 "byte": { 2722 floor: true, 2723 max: 255 2724 }, 2725 "percent": { 2726 max: 1 2727 }, 2728 "degrees": { 2729 mod: 360, 2730 floor: true 2731 } 2732 }, 2733 support = color.support = {}, 2734 2735 // element for support tests 2736 supportElem = jQuery( "<p>" )[ 0 ], 2737 2738 // colors = jQuery.Color.names 2739 colors, 2740 2741 // local aliases of functions called often 2742 each = jQuery.each; 2743 2744 // determine rgba support immediately 2745 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; 2746 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; 2747 2748 // define cache name and alpha properties 2749 // for rgba and hsla spaces 2750 each( spaces, function( spaceName, space ) { 2751 space.cache = "_" + spaceName; 2752 space.props.alpha = { 2753 idx: 3, 2754 type: "percent", 2755 def: 1 2756 }; 2757 }); 2758 2759 function clamp( value, prop, allowEmpty ) { 2760 var type = propTypes[ prop.type ] || {}; 2761 2762 if ( value == null ) { 2763 return (allowEmpty || !prop.def) ? null : prop.def; 2764 } 2765 2766 // ~~ is an short way of doing floor for positive numbers 2767 value = type.floor ? ~~value : parseFloat( value ); 2768 2769 // IE will pass in empty strings as value for alpha, 2770 // which will hit this case 2771 if ( isNaN( value ) ) { 2772 return prop.def; 2773 } 2774 2775 if ( type.mod ) { 2776 // we add mod before modding to make sure that negatives values 2777 // get converted properly: -10 -> 350 2778 return (value + type.mod) % type.mod; 2779 } 2780 2781 // for now all property types without mod have min and max 2782 return 0 > value ? 0 : type.max < value ? type.max : value; 2783 } 2784 2785 function stringParse( string ) { 2786 var inst = color(), 2787 rgba = inst._rgba = []; 2788 2789 string = string.toLowerCase(); 2790 2791 each( stringParsers, function( i, parser ) { 2792 var parsed, 2793 match = parser.re.exec( string ), 2794 values = match && parser.parse( match ), 2795 spaceName = parser.space || "rgba"; 2796 2797 if ( values ) { 2798 parsed = inst[ spaceName ]( values ); 2799 2800 // if this was an rgba parse the assignment might happen twice 2801 // oh well.... 2802 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; 2803 rgba = inst._rgba = parsed._rgba; 2804 2805 // exit each( stringParsers ) here because we matched 2806 return false; 2807 } 2808 }); 2809 2810 // Found a stringParser that handled it 2811 if ( rgba.length ) { 2812 2813 // if this came from a parsed string, force "transparent" when alpha is 0 2814 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 2815 if ( rgba.join() === "0,0,0,0" ) { 2816 jQuery.extend( rgba, colors.transparent ); 2817 } 2818 return inst; 2819 } 2820 2821 // named colors 2822 return colors[ string ]; 2823 } 2824 2825 color.fn = jQuery.extend( color.prototype, { 2826 parse: function( red, green, blue, alpha ) { 2827 if ( red === undefined ) { 2828 this._rgba = [ null, null, null, null ]; 2829 return this; 2830 } 2831 if ( red.jquery || red.nodeType ) { 2832 red = jQuery( red ).css( green ); 2833 green = undefined; 2834 } 2835 2836 var inst = this, 2837 type = jQuery.type( red ), 2838 rgba = this._rgba = []; 2839 2840 // more than 1 argument specified - assume ( red, green, blue, alpha ) 2841 if ( green !== undefined ) { 2842 red = [ red, green, blue, alpha ]; 2843 type = "array"; 2844 } 2845 2846 if ( type === "string" ) { 2847 return this.parse( stringParse( red ) || colors._default ); 2848 } 2849 2850 if ( type === "array" ) { 2851 each( spaces.rgba.props, function( key, prop ) { 2852 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 2853 }); 2854 return this; 2855 } 2856 2857 if ( type === "object" ) { 2858 if ( red instanceof color ) { 2859 each( spaces, function( spaceName, space ) { 2860 if ( red[ space.cache ] ) { 2861 inst[ space.cache ] = red[ space.cache ].slice(); 2862 } 2863 }); 2864 } else { 2865 each( spaces, function( spaceName, space ) { 2866 var cache = space.cache; 2867 each( space.props, function( key, prop ) { 2868 2869 // if the cache doesn't exist, and we know how to convert 2870 if ( !inst[ cache ] && space.to ) { 2871 2872 // if the value was null, we don't need to copy it 2873 // if the key was alpha, we don't need to copy it either 2874 if ( key === "alpha" || red[ key ] == null ) { 2875 return; 2876 } 2877 inst[ cache ] = space.to( inst._rgba ); 2878 } 2879 2880 // this is the only case where we allow nulls for ALL properties. 2881 // call clamp with alwaysAllowEmpty 2882 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 2883 }); 2884 2885 // everything defined but alpha? 2886 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { 2887 // use the default of 1 2888 inst[ cache ][ 3 ] = 1; 2889 if ( space.from ) { 2890 inst._rgba = space.from( inst[ cache ] ); 2891 } 2892 } 2893 }); 2894 } 2895 return this; 2896 } 2897 }, 2898 is: function( compare ) { 2899 var is = color( compare ), 2900 same = true, 2901 inst = this; 2902 2903 each( spaces, function( _, space ) { 2904 var localCache, 2905 isCache = is[ space.cache ]; 2906 if (isCache) { 2907 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; 2908 each( space.props, function( _, prop ) { 2909 if ( isCache[ prop.idx ] != null ) { 2910 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 2911 return same; 2912 } 2913 }); 2914 } 2915 return same; 2916 }); 2917 return same; 2918 }, 2919 _space: function() { 2920 var used = [], 2921 inst = this; 2922 each( spaces, function( spaceName, space ) { 2923 if ( inst[ space.cache ] ) { 2924 used.push( spaceName ); 2925 } 2926 }); 2927 return used.pop(); 2928 }, 2929 transition: function( other, distance ) { 2930 var end = color( other ), 2931 spaceName = end._space(), 2932 space = spaces[ spaceName ], 2933 startColor = this.alpha() === 0 ? color( "transparent" ) : this, 2934 start = startColor[ space.cache ] || space.to( startColor._rgba ), 2935 result = start.slice(); 2936 2937 end = end[ space.cache ]; 2938 each( space.props, function( key, prop ) { 2939 var index = prop.idx, 2940 startValue = start[ index ], 2941 endValue = end[ index ], 2942 type = propTypes[ prop.type ] || {}; 2943 2944 // if null, don't override start value 2945 if ( endValue === null ) { 2946 return; 2947 } 2948 // if null - use end 2949 if ( startValue === null ) { 2950 result[ index ] = endValue; 2951 } else { 2952 if ( type.mod ) { 2953 if ( endValue - startValue > type.mod / 2 ) { 2954 startValue += type.mod; 2955 } else if ( startValue - endValue > type.mod / 2 ) { 2956 startValue -= type.mod; 2957 } 2958 } 2959 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 2960 } 2961 }); 2962 return this[ spaceName ]( result ); 2963 }, 2964 blend: function( opaque ) { 2965 // if we are already opaque - return ourself 2966 if ( this._rgba[ 3 ] === 1 ) { 2967 return this; 2968 } 2969 2970 var rgb = this._rgba.slice(), 2971 a = rgb.pop(), 2972 blend = color( opaque )._rgba; 2973 2974 return color( jQuery.map( rgb, function( v, i ) { 2975 return ( 1 - a ) * blend[ i ] + a * v; 2976 })); 2977 }, 2978 toRgbaString: function() { 2979 var prefix = "rgba(", 2980 rgba = jQuery.map( this._rgba, function( v, i ) { 2981 return v == null ? ( i > 2 ? 1 : 0 ) : v; 2982 }); 2983 2984 if ( rgba[ 3 ] === 1 ) { 2985 rgba.pop(); 2986 prefix = "rgb("; 2987 } 2988 2989 return prefix + rgba.join() + ")"; 2990 }, 2991 toHslaString: function() { 2992 var prefix = "hsla(", 2993 hsla = jQuery.map( this.hsla(), function( v, i ) { 2994 if ( v == null ) { 2995 v = i > 2 ? 1 : 0; 2996 } 2997 2998 // catch 1 and 2 2999 if ( i && i < 3 ) { 3000 v = Math.round( v * 100 ) + "%"; 3001 } 3002 return v; 3003 }); 3004 3005 if ( hsla[ 3 ] === 1 ) { 3006 hsla.pop(); 3007 prefix = "hsl("; 3008 } 3009 return prefix + hsla.join() + ")"; 3010 }, 3011 toHexString: function( includeAlpha ) { 3012 var rgba = this._rgba.slice(), 3013 alpha = rgba.pop(); 3014 3015 if ( includeAlpha ) { 3016 rgba.push( ~~( alpha * 255 ) ); 3017 } 3018 3019 return "#" + jQuery.map( rgba, function( v ) { 3020 3021 // default to 0 when nulls exist 3022 v = ( v || 0 ).toString( 16 ); 3023 return v.length === 1 ? "0" + v : v; 3024 }).join(""); 3025 }, 3026 toString: function() { 3027 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); 3028 } 3029 }); 3030 color.fn.parse.prototype = color.fn; 3031 3032 // hsla conversions adapted from: 3033 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 3034 3035 function hue2rgb( p, q, h ) { 3036 h = ( h + 1 ) % 1; 3037 if ( h * 6 < 1 ) { 3038 return p + (q - p) * h * 6; 3039 } 3040 if ( h * 2 < 1) { 3041 return q; 3042 } 3043 if ( h * 3 < 2 ) { 3044 return p + (q - p) * ((2/3) - h) * 6; 3045 } 3046 return p; 3047 } 3048 3049 spaces.hsla.to = function ( rgba ) { 3050 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 3051 return [ null, null, null, rgba[ 3 ] ]; 3052 } 3053 var r = rgba[ 0 ] / 255, 3054 g = rgba[ 1 ] / 255, 3055 b = rgba[ 2 ] / 255, 3056 a = rgba[ 3 ], 3057 max = Math.max( r, g, b ), 3058 min = Math.min( r, g, b ), 3059 diff = max - min, 3060 add = max + min, 3061 l = add * 0.5, 3062 h, s; 3063 3064 if ( min === max ) { 3065 h = 0; 3066 } else if ( r === max ) { 3067 h = ( 60 * ( g - b ) / diff ) + 360; 3068 } else if ( g === max ) { 3069 h = ( 60 * ( b - r ) / diff ) + 120; 3070 } else { 3071 h = ( 60 * ( r - g ) / diff ) + 240; 3072 } 3073 3074 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% 3075 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) 3076 if ( diff === 0 ) { 3077 s = 0; 3078 } else if ( l <= 0.5 ) { 3079 s = diff / add; 3080 } else { 3081 s = diff / ( 2 - add ); 3082 } 3083 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; 3084 }; 3085 3086 spaces.hsla.from = function ( hsla ) { 3087 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 3088 return [ null, null, null, hsla[ 3 ] ]; 3089 } 3090 var h = hsla[ 0 ] / 360, 3091 s = hsla[ 1 ], 3092 l = hsla[ 2 ], 3093 a = hsla[ 3 ], 3094 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 3095 p = 2 * l - q; 3096 3097 return [ 3098 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 3099 Math.round( hue2rgb( p, q, h ) * 255 ), 3100 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 3101 a 3102 ]; 3103 }; 3104 3105 3106 each( spaces, function( spaceName, space ) { 3107 var props = space.props, 3108 cache = space.cache, 3109 to = space.to, 3110 from = space.from; 3111 3112 // makes rgba() and hsla() 3113 color.fn[ spaceName ] = function( value ) { 3114 3115 // generate a cache for this space if it doesn't exist 3116 if ( to && !this[ cache ] ) { 3117 this[ cache ] = to( this._rgba ); 3118 } 3119 if ( value === undefined ) { 3120 return this[ cache ].slice(); 3121 } 3122 3123 var ret, 3124 type = jQuery.type( value ), 3125 arr = ( type === "array" || type === "object" ) ? value : arguments, 3126 local = this[ cache ].slice(); 3127 3128 each( props, function( key, prop ) { 3129 var val = arr[ type === "object" ? key : prop.idx ]; 3130 if ( val == null ) { 3131 val = local[ prop.idx ]; 3132 } 3133 local[ prop.idx ] = clamp( val, prop ); 3134 }); 3135 3136 if ( from ) { 3137 ret = color( from( local ) ); 3138 ret[ cache ] = local; 3139 return ret; 3140 } else { 3141 return color( local ); 3142 } 3143 }; 3144 3145 // makes red() green() blue() alpha() hue() saturation() lightness() 3146 each( props, function( key, prop ) { 3147 // alpha is included in more than one space 3148 if ( color.fn[ key ] ) { 3149 return; 3150 } 3151 color.fn[ key ] = function( value ) { 3152 var vtype = jQuery.type( value ), 3153 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), 3154 local = this[ fn ](), 3155 cur = local[ prop.idx ], 3156 match; 3157 3158 if ( vtype === "undefined" ) { 3159 return cur; 3160 } 3161 3162 if ( vtype === "function" ) { 3163 value = value.call( this, cur ); 3164 vtype = jQuery.type( value ); 3165 } 3166 if ( value == null && prop.empty ) { 3167 return this; 3168 } 3169 if ( vtype === "string" ) { 3170 match = rplusequals.exec( value ); 3171 if ( match ) { 3172 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 3173 } 3174 } 3175 local[ prop.idx ] = value; 3176 return this[ fn ]( local ); 3177 }; 3178 }); 3179 }); 3180 3181 // add cssHook and .fx.step function for each named hook. 3182 // accept a space separated string of properties 3183 color.hook = function( hook ) { 3184 var hooks = hook.split( " " ); 3185 each( hooks, function( i, hook ) { 3186 jQuery.cssHooks[ hook ] = { 3187 set: function( elem, value ) { 3188 var parsed, curElem, 3189 backgroundColor = ""; 3190 3191 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { 3192 value = color( parsed || value ); 3193 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { 3194 curElem = hook === "backgroundColor" ? elem.parentNode : elem; 3195 while ( 3196 (backgroundColor === "" || backgroundColor === "transparent") && 3197 curElem && curElem.style 3198 ) { 3199 try { 3200 backgroundColor = jQuery.css( curElem, "backgroundColor" ); 3201 curElem = curElem.parentNode; 3202 } catch ( e ) { 3203 } 3204 } 3205 3206 value = value.blend( backgroundColor && backgroundColor !== "transparent" ? 3207 backgroundColor : 3208 "_default" ); 3209 } 3210 3211 value = value.toRgbaString(); 3212 } 3213 try { 3214 elem.style[ hook ] = value; 3215 } catch( e ) { 3216 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' 3217 } 3218 } 3219 }; 3220 jQuery.fx.step[ hook ] = function( fx ) { 3221 if ( !fx.colorInit ) { 3222 fx.start = color( fx.elem, hook ); 3223 fx.end = color( fx.end ); 3224 fx.colorInit = true; 3225 } 3226 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 3227 }; 3228 }); 3229 3230 }; 3231 3232 color.hook( stepHooks ); 3233 3234 jQuery.cssHooks.borderColor = { 3235 expand: function( value ) { 3236 var expanded = {}; 3237 3238 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { 3239 expanded[ "border" + part + "Color" ] = value; 3240 }); 3241 return expanded; 3242 } 3243 }; 3244 3245 // Basic color names only. 3246 // Usage of any of the other color names requires adding yourself or including 3247 // jquery.color.svg-names.js. 3248 colors = jQuery.Color.names = { 3249 // 4.1. Basic color keywords 3250 aqua: "#00ffff", 3251 black: "#000000", 3252 blue: "#0000ff", 3253 fuchsia: "#ff00ff", 3254 gray: "#808080", 3255 green: "#008000", 3256 lime: "#00ff00", 3257 maroon: "#800000", 3258 navy: "#000080", 3259 olive: "#808000", 3260 purple: "#800080", 3261 red: "#ff0000", 3262 silver: "#c0c0c0", 3263 teal: "#008080", 3264 white: "#ffffff", 3265 yellow: "#ffff00", 3266 3267 // 4.2.3. "transparent" color keyword 3268 transparent: [ null, null, null, 0 ], 3269 3270 _default: "#ffffff" 3271 }; 3272 3273 })( jQuery ); 3274 3275 3276 /******************************************************************************/ 3277 /****************************** CLASS ANIMATIONS ******************************/ 3278 /******************************************************************************/ 3279 (function() { 3280 3281 var classAnimationActions = [ "add", "remove", "toggle" ], 3282 shorthandStyles = { 3283 border: 1, 3284 borderBottom: 1, 3285 borderColor: 1, 3286 borderLeft: 1, 3287 borderRight: 1, 3288 borderTop: 1, 3289 borderWidth: 1, 3290 margin: 1, 3291 padding: 1 3292 }; 3293 3294 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { 3295 $.fx.step[ prop ] = function( fx ) { 3296 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { 3297 jQuery.style( fx.elem, prop, fx.end ); 3298 fx.setAttr = true; 3299 } 3300 }; 3301 }); 3302 3303 function getElementStyles( elem ) { 3304 var key, len, 3305 style = elem.ownerDocument.defaultView ? 3306 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : 3307 elem.currentStyle, 3308 styles = {}; 3309 3310 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { 3311 len = style.length; 3312 while ( len-- ) { 3313 key = style[ len ]; 3314 if ( typeof style[ key ] === "string" ) { 3315 styles[ $.camelCase( key ) ] = style[ key ]; 3316 } 3317 } 3318 // support: Opera, IE <9 3319 } else { 3320 for ( key in style ) { 3321 if ( typeof style[ key ] === "string" ) { 3322 styles[ key ] = style[ key ]; 3323 } 3324 } 3325 } 3326 3327 return styles; 3328 } 3329 3330 3331 function styleDifference( oldStyle, newStyle ) { 3332 var diff = {}, 3333 name, value; 3334 3335 for ( name in newStyle ) { 3336 value = newStyle[ name ]; 3337 if ( oldStyle[ name ] !== value ) { 3338 if ( !shorthandStyles[ name ] ) { 3339 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { 3340 diff[ name ] = value; 3341 } 3342 } 3343 } 3344 } 3345 3346 return diff; 3347 } 3348 3349 // support: jQuery <1.8 3350 if ( !$.fn.addBack ) { 3351 $.fn.addBack = function( selector ) { 3352 return this.add( selector == null ? 3353 this.prevObject : this.prevObject.filter( selector ) 3354 ); 3355 }; 3356 } 3357 3358 $.effects.animateClass = function( value, duration, easing, callback ) { 3359 var o = $.speed( duration, easing, callback ); 3360 3361 return this.queue( function() { 3362 var animated = $( this ), 3363 baseClass = animated.attr( "class" ) || "", 3364 applyClassChange, 3365 allAnimations = o.children ? animated.find( "*" ).addBack() : animated; 3366 3367 // map the animated objects to store the original styles. 3368 allAnimations = allAnimations.map(function() { 3369 var el = $( this ); 3370 return { 3371 el: el, 3372 start: getElementStyles( this ) 3373 }; 3374 }); 3375 3376 // apply class change 3377 applyClassChange = function() { 3378 $.each( classAnimationActions, function(i, action) { 3379 if ( value[ action ] ) { 3380 animated[ action + "Class" ]( value[ action ] ); 3381 } 3382 }); 3383 }; 3384 applyClassChange(); 3385 3386 // map all animated objects again - calculate new styles and diff 3387 allAnimations = allAnimations.map(function() { 3388 this.end = getElementStyles( this.el[ 0 ] ); 3389 this.diff = styleDifference( this.start, this.end ); 3390 return this; 3391 }); 3392 3393 // apply original class 3394 animated.attr( "class", baseClass ); 3395 3396 // map all animated objects again - this time collecting a promise 3397 allAnimations = allAnimations.map(function() { 3398 var styleInfo = this, 3399 dfd = $.Deferred(), 3400 opts = $.extend({}, o, { 3401 queue: false, 3402 complete: function() { 3403 dfd.resolve( styleInfo ); 3404 } 3405 }); 3406 3407 this.el.animate( this.diff, opts ); 3408 return dfd.promise(); 3409 }); 3410 3411 // once all animations have completed: 3412 $.when.apply( $, allAnimations.get() ).done(function() { 3413 3414 // set the final class 3415 applyClassChange(); 3416 3417 // for each animated element, 3418 // clear all css properties that were animated 3419 $.each( arguments, function() { 3420 var el = this.el; 3421 $.each( this.diff, function(key) { 3422 el.css( key, "" ); 3423 }); 3424 }); 3425 3426 // this is guarnteed to be there if you use jQuery.speed() 3427 // it also handles dequeuing the next anim... 3428 o.complete.call( animated[ 0 ] ); 3429 }); 3430 }); 3431 }; 3432 3433 $.fn.extend({ 3434 addClass: (function( orig ) { 3435 return function( classNames, speed, easing, callback ) { 3436 return speed ? 3437 $.effects.animateClass.call( this, 3438 { add: classNames }, speed, easing, callback ) : 3439 orig.apply( this, arguments ); 3440 }; 3441 })( $.fn.addClass ), 3442 3443 removeClass: (function( orig ) { 3444 return function( classNames, speed, easing, callback ) { 3445 return arguments.length > 1 ? 3446 $.effects.animateClass.call( this, 3447 { remove: classNames }, speed, easing, callback ) : 3448 orig.apply( this, arguments ); 3449 }; 3450 })( $.fn.removeClass ), 3451 3452 toggleClass: (function( orig ) { 3453 return function( classNames, force, speed, easing, callback ) { 3454 if ( typeof force === "boolean" || force === undefined ) { 3455 if ( !speed ) { 3456 // without speed parameter 3457 return orig.apply( this, arguments ); 3458 } else { 3459 return $.effects.animateClass.call( this, 3460 (force ? { add: classNames } : { remove: classNames }), 3461 speed, easing, callback ); 3462 } 3463 } else { 3464 // without force parameter 3465 return $.effects.animateClass.call( this, 3466 { toggle: classNames }, force, speed, easing ); 3467 } 3468 }; 3469 })( $.fn.toggleClass ), 3470 3471 switchClass: function( remove, add, speed, easing, callback) { 3472 return $.effects.animateClass.call( this, { 3473 add: add, 3474 remove: remove 3475 }, speed, easing, callback ); 3476 } 3477 }); 3478 3479 })(); 3480 3481 /******************************************************************************/ 3482 /*********************************** EFFECTS **********************************/ 3483 /******************************************************************************/ 3484 3485 (function() { 3486 3487 $.extend( $.effects, { 3488 version: "1.10.4", 3489 3490 // Saves a set of properties in a data storage 3491 save: function( element, set ) { 3492 for( var i=0; i < set.length; i++ ) { 3493 if ( set[ i ] !== null ) { 3494 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); 3495 } 3496 } 3497 }, 3498 3499 // Restores a set of previously saved properties from a data storage 3500 restore: function( element, set ) { 3501 var val, i; 3502 for( i=0; i < set.length; i++ ) { 3503 if ( set[ i ] !== null ) { 3504 val = element.data( dataSpace + set[ i ] ); 3505 // support: jQuery 1.6.2 3506 // http://bugs.jquery.com/ticket/9917 3507 // jQuery 1.6.2 incorrectly returns undefined for any falsy value. 3508 // We can't differentiate between "" and 0 here, so we just assume 3509 // empty string since it's likely to be a more common value... 3510 if ( val === undefined ) { 3511 val = ""; 3512 } 3513 element.css( set[ i ], val ); 3514 } 3515 } 3516 }, 3517 3518 setMode: function( el, mode ) { 3519 if (mode === "toggle") { 3520 mode = el.is( ":hidden" ) ? "show" : "hide"; 3521 } 3522 return mode; 3523 }, 3524 3525 // Translates a [top,left] array into a baseline value 3526 // this should be a little more flexible in the future to handle a string & hash 3527 getBaseline: function( origin, original ) { 3528 var y, x; 3529 switch ( origin[ 0 ] ) { 3530 case "top": y = 0; break; 3531 case "middle": y = 0.5; break; 3532 case "bottom": y = 1; break; 3533 default: y = origin[ 0 ] / original.height; 3534 } 3535 switch ( origin[ 1 ] ) { 3536 case "left": x = 0; break; 3537 case "center": x = 0.5; break; 3538 case "right": x = 1; break; 3539 default: x = origin[ 1 ] / original.width; 3540 } 3541 return { 3542 x: x, 3543 y: y 3544 }; 3545 }, 3546 3547 // Wraps the element around a wrapper that copies position properties 3548 createWrapper: function( element ) { 3549 3550 // if the element is already wrapped, return it 3551 if ( element.parent().is( ".ui-effects-wrapper" )) { 3552 return element.parent(); 3553 } 3554 3555 // wrap the element 3556 var props = { 3557 width: element.outerWidth(true), 3558 height: element.outerHeight(true), 3559 "float": element.css( "float" ) 3560 }, 3561 wrapper = $( "<div></div>" ) 3562 .addClass( "ui-effects-wrapper" ) 3563 .css({ 3564 fontSize: "100%", 3565 background: "transparent", 3566 border: "none", 3567 margin: 0, 3568 padding: 0 3569 }), 3570 // Store the size in case width/height are defined in % - Fixes #5245 3571 size = { 3572 width: element.width(), 3573 height: element.height() 3574 }, 3575 active = document.activeElement; 3576 3577 // support: Firefox 3578 // Firefox incorrectly exposes anonymous content 3579 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 3580 try { 3581 active.id; 3582 } catch( e ) { 3583 active = document.body; 3584 } 3585 3586 element.wrap( wrapper ); 3587 3588 // Fixes #7595 - Elements lose focus when wrapped. 3589 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 3590 $( active ).focus(); 3591 } 3592 3593 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element 3594 3595 // transfer positioning properties to the wrapper 3596 if ( element.css( "position" ) === "static" ) { 3597 wrapper.css({ position: "relative" }); 3598 element.css({ position: "relative" }); 3599 } else { 3600 $.extend( props, { 3601 position: element.css( "position" ), 3602 zIndex: element.css( "z-index" ) 3603 }); 3604 $.each([ "top", "left", "bottom", "right" ], function(i, pos) { 3605 props[ pos ] = element.css( pos ); 3606 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { 3607 props[ pos ] = "auto"; 3608 } 3609 }); 3610 element.css({ 3611 position: "relative", 3612 top: 0, 3613 left: 0, 3614 right: "auto", 3615 bottom: "auto" 3616 }); 3617 } 3618 element.css(size); 3619 3620 return wrapper.css( props ).show(); 3621 }, 3622 3623 removeWrapper: function( element ) { 3624 var active = document.activeElement; 3625 3626 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 3627 element.parent().replaceWith( element ); 3628 3629 // Fixes #7595 - Elements lose focus when wrapped. 3630 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 3631 $( active ).focus(); 3632 } 3633 } 3634 3635 3636 return element; 3637 }, 3638 3639 setTransition: function( element, list, factor, value ) { 3640 value = value || {}; 3641 $.each( list, function( i, x ) { 3642 var unit = element.cssUnit( x ); 3643 if ( unit[ 0 ] > 0 ) { 3644 value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; 3645 } 3646 }); 3647 return value; 3648 } 3649 }); 3650 3651 // return an effect options object for the given parameters: 3652 function _normalizeArguments( effect, options, speed, callback ) { 3653 3654 // allow passing all options as the first parameter 3655 if ( $.isPlainObject( effect ) ) { 3656 options = effect; 3657 effect = effect.effect; 3658 } 3659 3660 // convert to an object 3661 effect = { effect: effect }; 3662 3663 // catch (effect, null, ...) 3664 if ( options == null ) { 3665 options = {}; 3666 } 3667 3668 // catch (effect, callback) 3669 if ( $.isFunction( options ) ) { 3670 callback = options; 3671 speed = null; 3672 options = {}; 3673 } 3674 3675 // catch (effect, speed, ?) 3676 if ( typeof options === "number" || $.fx.speeds[ options ] ) { 3677 callback = speed; 3678 speed = options; 3679 options = {}; 3680 } 3681 3682 // catch (effect, options, callback) 3683 if ( $.isFunction( speed ) ) { 3684 callback = speed; 3685 speed = null; 3686 } 3687 3688 // add options to effect 3689 if ( options ) { 3690 $.extend( effect, options ); 3691 } 3692 3693 speed = speed || options.duration; 3694 effect.duration = $.fx.off ? 0 : 3695 typeof speed === "number" ? speed : 3696 speed in $.fx.speeds ? $.fx.speeds[ speed ] : 3697 $.fx.speeds._default; 3698 3699 effect.complete = callback || options.complete; 3700 3701 return effect; 3702 } 3703 3704 function standardAnimationOption( option ) { 3705 // Valid standard speeds (nothing, number, named speed) 3706 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { 3707 return true; 3708 } 3709 3710 // Invalid strings - treat as "normal" speed 3711 if ( typeof option === "string" && !$.effects.effect[ option ] ) { 3712 return true; 3713 } 3714 3715 // Complete callback 3716 if ( $.isFunction( option ) ) { 3717 return true; 3718 } 3719 3720 // Options hash (but not naming an effect) 3721 if ( typeof option === "object" && !option.effect ) { 3722 return true; 3723 } 3724 3725 // Didn't match any standard API 3726 return false; 3727 } 3728 3729 $.fn.extend({ 3730 effect: function( /* effect, options, speed, callback */ ) { 3731 var args = _normalizeArguments.apply( this, arguments ), 3732 mode = args.mode, 3733 queue = args.queue, 3734 effectMethod = $.effects.effect[ args.effect ]; 3735 3736 if ( $.fx.off || !effectMethod ) { 3737 // delegate to the original method (e.g., .show()) if possible 3738 if ( mode ) { 3739 return this[ mode ]( args.duration, args.complete ); 3740 } else { 3741 return this.each( function() { 3742 if ( args.complete ) { 3743 args.complete.call( this ); 3744 } 3745 }); 3746 } 3747 } 3748 3749 function run( next ) { 3750 var elem = $( this ), 3751 complete = args.complete, 3752 mode = args.mode; 3753 3754 function done() { 3755 if ( $.isFunction( complete ) ) { 3756 complete.call( elem[0] ); 3757 } 3758 if ( $.isFunction( next ) ) { 3759 next(); 3760 } 3761 } 3762 3763 // If the element already has the correct final state, delegate to 3764 // the core methods so the internal tracking of "olddisplay" works. 3765 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { 3766 elem[ mode ](); 3767 done(); 3768 } else { 3769 effectMethod.call( elem[0], args, done ); 3770 } 3771 } 3772 3773 return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); 3774 }, 3775 3776 show: (function( orig ) { 3777 return function( option ) { 3778 if ( standardAnimationOption( option ) ) { 3779 return orig.apply( this, arguments ); 3780 } else { 3781 var args = _normalizeArguments.apply( this, arguments ); 3782 args.mode = "show"; 3783 return this.effect.call( this, args ); 3784 } 3785 }; 3786 })( $.fn.show ), 3787 3788 hide: (function( orig ) { 3789 return function( option ) { 3790 if ( standardAnimationOption( option ) ) { 3791 return orig.apply( this, arguments ); 3792 } else { 3793 var args = _normalizeArguments.apply( this, arguments ); 3794 args.mode = "hide"; 3795 return this.effect.call( this, args ); 3796 } 3797 }; 3798 })( $.fn.hide ), 3799 3800 toggle: (function( orig ) { 3801 return function( option ) { 3802 if ( standardAnimationOption( option ) || typeof option === "boolean" ) { 3803 return orig.apply( this, arguments ); 3804 } else { 3805 var args = _normalizeArguments.apply( this, arguments ); 3806 args.mode = "toggle"; 3807 return this.effect.call( this, args ); 3808 } 3809 }; 3810 })( $.fn.toggle ), 3811 3812 // helper functions 3813 cssUnit: function(key) { 3814 var style = this.css( key ), 3815 val = []; 3816 3817 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { 3818 if ( style.indexOf( unit ) > 0 ) { 3819 val = [ parseFloat( style ), unit ]; 3820 } 3821 }); 3822 return val; 3823 } 3824 }); 3825 3826 })(); 3827 3828 /******************************************************************************/ 3829 /*********************************** EASING ***********************************/ 3830 /******************************************************************************/ 3831 3832 (function() { 3833 3834 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing) 3835 3836 var baseEasings = {}; 3837 3838 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 3839 baseEasings[ name ] = function( p ) { 3840 return Math.pow( p, i + 2 ); 3841 }; 3842 }); 3843 3844 $.extend( baseEasings, { 3845 Sine: function ( p ) { 3846 return 1 - Math.cos( p * Math.PI / 2 ); 3847 }, 3848 Circ: function ( p ) { 3849 return 1 - Math.sqrt( 1 - p * p ); 3850 }, 3851 Elastic: function( p ) { 3852 return p === 0 || p === 1 ? p : 3853 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); 3854 }, 3855 Back: function( p ) { 3856 return p * p * ( 3 * p - 2 ); 3857 }, 3858 Bounce: function ( p ) { 3859 var pow2, 3860 bounce = 4; 3861 3862 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 3863 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 3864 } 3865 }); 3866 3867 $.each( baseEasings, function( name, easeIn ) { 3868 $.easing[ "easeIn" + name ] = easeIn; 3869 $.easing[ "easeOut" + name ] = function( p ) { 3870 return 1 - easeIn( 1 - p ); 3871 }; 3872 $.easing[ "easeInOut" + name ] = function( p ) { 3873 return p < 0.5 ? 3874 easeIn( p * 2 ) / 2 : 3875 1 - easeIn( p * -2 + 2 ) / 2; 3876 }; 3877 }); 3878 3879 })(); 3880 3881 })(jQuery); 3882 3883 /*! 3884 * jQuery UI Touch Punch 0.2.2 3885 * 3886 * Copyright 2011, Dave Furfero 3887 * Dual licensed under the MIT or GPL Version 2 licenses. 3888 * 3889 * Depends: 3890 * jquery.ui.widget.js 3891 * jquery.ui.mouse.js 3892 */ 3893 (function ($) { 3894 3895 // Detect touch support 3896 $.support.touch = 'ontouchend' in document; 3897 3898 // Ignore browsers without touch support 3899 if (!$.support.touch) { 3900 return; 3901 } 3902 3903 var mouseProto = $.ui.mouse.prototype, 3904 _mouseInit = mouseProto._mouseInit, 3905 touchHandled; 3906 3907 /** 3908 * Simulate a mouse event based on a corresponding touch event 3909 * @param {Object} event A touch event 3910 * @param {String} simulatedType The corresponding mouse event 3911 */ 3912 function simulateMouseEvent (event, simulatedType) { 3913 3914 // Ignore multi-touch events 3915 if (event.originalEvent.touches.length > 1) { 3916 return; 3917 } 3918 3919 event.preventDefault(); 3920 3921 var touch = event.originalEvent.changedTouches[0], 3922 simulatedEvent = document.createEvent('MouseEvents'); 3923 3924 // Initialize the simulated mouse event using the touch event's coordinates 3925 simulatedEvent.initMouseEvent( 3926 simulatedType, // type 3927 true, // bubbles 3928 true, // cancelable 3929 window, // view 3930 1, // detail 3931 touch.screenX, // screenX 3932 touch.screenY, // screenY 3933 touch.clientX, // clientX 3934 touch.clientY, // clientY 3935 false, // ctrlKey 3936 false, // altKey 3937 false, // shiftKey 3938 false, // metaKey 3939 0, // button 3940 null // relatedTarget 3941 ); 3942 3943 // Dispatch the simulated event to the target element 3944 event.target.dispatchEvent(simulatedEvent); 3945 } 3946 3947 /** 3948 * Handle the jQuery UI widget's touchstart events 3949 * @param {Object} event The widget element's touchstart event 3950 */ 3951 mouseProto._touchStart = function (event) { 3952 3953 var self = this; 3954 3955 // Ignore the event if another widget is already being handled 3956 if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) { 3957 return; 3958 } 3959 3960 // Set the flag to prevent other widgets from inheriting the touch event 3961 touchHandled = true; 3962 3963 // Track movement to determine if interaction was a click 3964 self._touchMoved = false; 3965 3966 // Simulate the mouseover event 3967 simulateMouseEvent(event, 'mouseover'); 3968 3969 // Simulate the mousemove event 3970 simulateMouseEvent(event, 'mousemove'); 3971 3972 // Simulate the mousedown event 3973 simulateMouseEvent(event, 'mousedown'); 3974 }; 3975 3976 /** 3977 * Handle the jQuery UI widget's touchmove events 3978 * @param {Object} event The document's touchmove event 3979 */ 3980 mouseProto._touchMove = function (event) { 3981 3982 // Ignore event if not handled 3983 if (!touchHandled) { 3984 return; 3985 } 3986 3987 // Interaction was not a click 3988 this._touchMoved = true; 3989 3990 // Simulate the mousemove event 3991 simulateMouseEvent(event, 'mousemove'); 3992 }; 3993 3994 /** 3995 * Handle the jQuery UI widget's touchend events 3996 * @param {Object} event The document's touchend event 3997 */ 3998 mouseProto._touchEnd = function (event) { 3999 4000 // Ignore event if not handled 4001 if (!touchHandled) { 4002 return; 4003 } 4004 4005 // Simulate the mouseup event 4006 simulateMouseEvent(event, 'mouseup'); 4007 4008 // Simulate the mouseout event 4009 simulateMouseEvent(event, 'mouseout'); 4010 4011 // If the touch interaction did not move, it should trigger a click 4012 if (!this._touchMoved) { 4013 4014 // Simulate the click event 4015 simulateMouseEvent(event, 'click'); 4016 } 4017 4018 // Unset the flag to allow other widgets to inherit the touch event 4019 touchHandled = false; 4020 }; 4021 4022 /** 4023 * A duck punch of the $.ui.mouse _mouseInit method to support touch events. 4024 * This method extends the widget with bound touch event handlers that 4025 * translate touch events to mouse events and pass them to the widget's 4026 * original mouse event handling methods. 4027 */ 4028 mouseProto._mouseInit = function () { 4029 4030 var self = this; 4031 4032 // Delegate the touch handlers to the widget's element 4033 self.element 4034 .bind('touchstart', $.proxy(self, '_touchStart')) 4035 .bind('touchmove', $.proxy(self, '_touchMove')) 4036 .bind('touchend', $.proxy(self, '_touchEnd')); 4037 4038 // Call the original $.ui.mouse init method 4039 _mouseInit.call(self); 4040 }; 4041 4042 })(jQuery); 4043 /*! 4044 * Bootstrap v3.2.0 (http://getbootstrap.com) 4045 * Copyright 2011-2014 Twitter, Inc. 4046 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4047 */ 4048 4049 if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } 4050 4051 /* ======================================================================== 4052 * Bootstrap: transition.js v3.2.0 4053 * http://getbootstrap.com/javascript/#transitions 4054 * ======================================================================== 4055 * Copyright 2011-2014 Twitter, Inc. 4056 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4057 * ======================================================================== */ 4058 4059 4060 +function ($) { 4061 'use strict'; 4062 4063 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 4064 // ============================================================ 4065 4066 function transitionEnd() { 4067 var el = document.createElement('bootstrap') 4068 4069 var transEndEventNames = { 4070 WebkitTransition : 'webkitTransitionEnd', 4071 MozTransition : 'transitionend', 4072 OTransition : 'oTransitionEnd otransitionend', 4073 transition : 'transitionend' 4074 } 4075 4076 for (var name in transEndEventNames) { 4077 if (el.style[name] !== undefined) { 4078 return { end: transEndEventNames[name] } 4079 } 4080 } 4081 4082 return false // explicit for ie8 ( ._.) 4083 } 4084 4085 // http://blog.alexmaccaw.com/css-transitions 4086 $.fn.emulateTransitionEnd = function (duration) { 4087 var called = false 4088 var $el = this 4089 $(this).one('bsTransitionEnd', function () { called = true }) 4090 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 4091 setTimeout(callback, duration) 4092 return this 4093 } 4094 4095 $(function () { 4096 $.support.transition = transitionEnd() 4097 4098 if (!$.support.transition) return 4099 4100 $.event.special.bsTransitionEnd = { 4101 bindType: $.support.transition.end, 4102 delegateType: $.support.transition.end, 4103 handle: function (e) { 4104 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 4105 } 4106 } 4107 }) 4108 4109 }(jQuery); 4110 4111 /* ======================================================================== 4112 * Bootstrap: alert.js v3.2.0 4113 * http://getbootstrap.com/javascript/#alerts 4114 * ======================================================================== 4115 * Copyright 2011-2014 Twitter, Inc. 4116 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4117 * ======================================================================== */ 4118 4119 4120 +function ($) { 4121 'use strict'; 4122 4123 // ALERT CLASS DEFINITION 4124 // ====================== 4125 4126 var dismiss = '[data-dismiss="alert"]' 4127 var Alert = function (el) { 4128 $(el).on('click', dismiss, this.close) 4129 } 4130 4131 Alert.VERSION = '3.2.0' 4132 4133 Alert.prototype.close = function (e) { 4134 var $this = $(this) 4135 var selector = $this.attr('data-target') 4136 4137 if (!selector) { 4138 selector = $this.attr('href') 4139 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 4140 } 4141 4142 var $parent = $(selector) 4143 4144 if (e) e.preventDefault() 4145 4146 if (!$parent.length) { 4147 $parent = $this.hasClass('alert') ? $this : $this.parent() 4148 } 4149 4150 $parent.trigger(e = $.Event('close.bs.alert')) 4151 4152 if (e.isDefaultPrevented()) return 4153 4154 $parent.removeClass('in') 4155 4156 function removeElement() { 4157 // detach from parent, fire event then clean up data 4158 $parent.detach().trigger('closed.bs.alert').remove() 4159 } 4160 4161 $.support.transition && $parent.hasClass('fade') ? 4162 $parent 4163 .one('bsTransitionEnd', removeElement) 4164 .emulateTransitionEnd(150) : 4165 removeElement() 4166 } 4167 4168 4169 // ALERT PLUGIN DEFINITION 4170 // ======================= 4171 4172 function Plugin(option) { 4173 return this.each(function () { 4174 var $this = $(this) 4175 var data = $this.data('bs.alert') 4176 4177 if (!data) $this.data('bs.alert', (data = new Alert(this))) 4178 if (typeof option == 'string') data[option].call($this) 4179 }) 4180 } 4181 4182 var old = $.fn.alert 4183 4184 $.fn.alert = Plugin 4185 $.fn.alert.Constructor = Alert 4186 4187 4188 // ALERT NO CONFLICT 4189 // ================= 4190 4191 $.fn.alert.noConflict = function () { 4192 $.fn.alert = old 4193 return this 4194 } 4195 4196 4197 // ALERT DATA-API 4198 // ============== 4199 4200 $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 4201 4202 }(jQuery); 4203 4204 /* ======================================================================== 4205 * Bootstrap: button.js v3.2.0 4206 * http://getbootstrap.com/javascript/#buttons 4207 * ======================================================================== 4208 * Copyright 2011-2014 Twitter, Inc. 4209 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4210 * ======================================================================== */ 4211 4212 4213 +function ($) { 4214 'use strict'; 4215 4216 // BUTTON PUBLIC CLASS DEFINITION 4217 // ============================== 4218 4219 var Button = function (element, options) { 4220 this.$element = $(element) 4221 this.options = $.extend({}, Button.DEFAULTS, options) 4222 this.isLoading = false 4223 } 4224 4225 Button.VERSION = '3.2.0' 4226 4227 Button.DEFAULTS = { 4228 loadingText: 'loading...' 4229 } 4230 4231 Button.prototype.setState = function (state) { 4232 var d = 'disabled' 4233 var $el = this.$element 4234 var val = $el.is('input') ? 'val' : 'html' 4235 var data = $el.data() 4236 4237 state = state + 'Text' 4238 4239 if (data.resetText == null) $el.data('resetText', $el[val]()) 4240 4241 $el[val](data[state] == null ? this.options[state] : data[state]) 4242 4243 // push to event loop to allow forms to submit 4244 setTimeout($.proxy(function () { 4245 if (state == 'loadingText') { 4246 this.isLoading = true 4247 $el.addClass(d).attr(d, d) 4248 } else if (this.isLoading) { 4249 this.isLoading = false 4250 $el.removeClass(d).removeAttr(d) 4251 } 4252 }, this), 0) 4253 } 4254 4255 Button.prototype.toggle = function () { 4256 var changed = true 4257 var $parent = this.$element.closest('[data-toggle="buttons"]') 4258 4259 if ($parent.length) { 4260 var $input = this.$element.find('input') 4261 if ($input.prop('type') == 'radio') { 4262 if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 4263 else $parent.find('.active').removeClass('active') 4264 } 4265 if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 4266 } 4267 4268 if (changed) this.$element.toggleClass('active') 4269 } 4270 4271 4272 // BUTTON PLUGIN DEFINITION 4273 // ======================== 4274 4275 function Plugin(option) { 4276 return this.each(function () { 4277 var $this = $(this) 4278 var data = $this.data('bs.button') 4279 var options = typeof option == 'object' && option 4280 4281 if (!data) $this.data('bs.button', (data = new Button(this, options))) 4282 4283 if (option == 'toggle') data.toggle() 4284 else if (option) data.setState(option) 4285 }) 4286 } 4287 4288 var old = $.fn.button 4289 4290 $.fn.button = Plugin 4291 $.fn.button.Constructor = Button 4292 4293 4294 // BUTTON NO CONFLICT 4295 // ================== 4296 4297 $.fn.button.noConflict = function () { 4298 $.fn.button = old 4299 return this 4300 } 4301 4302 4303 // BUTTON DATA-API 4304 // =============== 4305 4306 $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 4307 var $btn = $(e.target) 4308 if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 4309 Plugin.call($btn, 'toggle') 4310 e.preventDefault() 4311 }) 4312 4313 }(jQuery); 4314 4315 /* ======================================================================== 4316 * Bootstrap: carousel.js v3.2.0 4317 * http://getbootstrap.com/javascript/#carousel 4318 * ======================================================================== 4319 * Copyright 2011-2014 Twitter, Inc. 4320 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4321 * ======================================================================== */ 4322 4323 4324 +function ($) { 4325 'use strict'; 4326 4327 // CAROUSEL CLASS DEFINITION 4328 // ========================= 4329 4330 var Carousel = function (element, options) { 4331 this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this)) 4332 this.$indicators = this.$element.find('.carousel-indicators') 4333 this.options = options 4334 this.paused = 4335 this.sliding = 4336 this.interval = 4337 this.$active = 4338 this.$items = null 4339 4340 this.options.pause == 'hover' && this.$element 4341 .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 4342 .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 4343 } 4344 4345 Carousel.VERSION = '3.2.0' 4346 4347 Carousel.DEFAULTS = { 4348 interval: 5000, 4349 pause: 'hover', 4350 wrap: true 4351 } 4352 4353 Carousel.prototype.keydown = function (e) { 4354 switch (e.which) { 4355 case 37: this.prev(); break 4356 case 39: this.next(); break 4357 default: return 4358 } 4359 4360 e.preventDefault() 4361 } 4362 4363 Carousel.prototype.cycle = function (e) { 4364 e || (this.paused = false) 4365 4366 this.interval && clearInterval(this.interval) 4367 4368 this.options.interval 4369 && !this.paused 4370 && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 4371 4372 return this 4373 } 4374 4375 Carousel.prototype.getItemIndex = function (item) { 4376 this.$items = item.parent().children('.item') 4377 return this.$items.index(item || this.$active) 4378 } 4379 4380 Carousel.prototype.to = function (pos) { 4381 var that = this 4382 var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 4383 4384 if (pos > (this.$items.length - 1) || pos < 0) return 4385 4386 if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 4387 if (activeIndex == pos) return this.pause().cycle() 4388 4389 return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 4390 } 4391 4392 Carousel.prototype.pause = function (e) { 4393 e || (this.paused = true) 4394 4395 if (this.$element.find('.next, .prev').length && $.support.transition) { 4396 this.$element.trigger($.support.transition.end) 4397 this.cycle(true) 4398 } 4399 4400 this.interval = clearInterval(this.interval) 4401 4402 return this 4403 } 4404 4405 Carousel.prototype.next = function () { 4406 if (this.sliding) return 4407 return this.slide('next') 4408 } 4409 4410 Carousel.prototype.prev = function () { 4411 if (this.sliding) return 4412 return this.slide('prev') 4413 } 4414 4415 Carousel.prototype.slide = function (type, next) { 4416 var $active = this.$element.find('.item.active') 4417 var $next = next || $active[type]() 4418 var isCycling = this.interval 4419 var direction = type == 'next' ? 'left' : 'right' 4420 var fallback = type == 'next' ? 'first' : 'last' 4421 var that = this 4422 4423 if (!$next.length) { 4424 if (!this.options.wrap) return 4425 $next = this.$element.find('.item')[fallback]() 4426 } 4427 4428 if ($next.hasClass('active')) return (this.sliding = false) 4429 4430 var relatedTarget = $next[0] 4431 var slideEvent = $.Event('slide.bs.carousel', { 4432 relatedTarget: relatedTarget, 4433 direction: direction 4434 }) 4435 this.$element.trigger(slideEvent) 4436 if (slideEvent.isDefaultPrevented()) return 4437 4438 this.sliding = true 4439 4440 isCycling && this.pause() 4441 4442 if (this.$indicators.length) { 4443 this.$indicators.find('.active').removeClass('active') 4444 var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 4445 $nextIndicator && $nextIndicator.addClass('active') 4446 } 4447 4448 var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 4449 if ($.support.transition && this.$element.hasClass('slide')) { 4450 $next.addClass(type) 4451 $next[0].offsetWidth // force reflow 4452 $active.addClass(direction) 4453 $next.addClass(direction) 4454 $active 4455 .one('bsTransitionEnd', function () { 4456 $next.removeClass([type, direction].join(' ')).addClass('active') 4457 $active.removeClass(['active', direction].join(' ')) 4458 that.sliding = false 4459 setTimeout(function () { 4460 that.$element.trigger(slidEvent) 4461 }, 0) 4462 }) 4463 .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) 4464 } else { 4465 $active.removeClass('active') 4466 $next.addClass('active') 4467 this.sliding = false 4468 this.$element.trigger(slidEvent) 4469 } 4470 4471 isCycling && this.cycle() 4472 4473 return this 4474 } 4475 4476 4477 // CAROUSEL PLUGIN DEFINITION 4478 // ========================== 4479 4480 function Plugin(option) { 4481 return this.each(function () { 4482 var $this = $(this) 4483 var data = $this.data('bs.carousel') 4484 var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 4485 var action = typeof option == 'string' ? option : options.slide 4486 4487 if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 4488 if (typeof option == 'number') data.to(option) 4489 else if (action) data[action]() 4490 else if (options.interval) data.pause().cycle() 4491 }) 4492 } 4493 4494 var old = $.fn.carousel 4495 4496 $.fn.carousel = Plugin 4497 $.fn.carousel.Constructor = Carousel 4498 4499 4500 // CAROUSEL NO CONFLICT 4501 // ==================== 4502 4503 $.fn.carousel.noConflict = function () { 4504 $.fn.carousel = old 4505 return this 4506 } 4507 4508 4509 // CAROUSEL DATA-API 4510 // ================= 4511 4512 $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 4513 var href 4514 var $this = $(this) 4515 var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 4516 if (!$target.hasClass('carousel')) return 4517 var options = $.extend({}, $target.data(), $this.data()) 4518 var slideIndex = $this.attr('data-slide-to') 4519 if (slideIndex) options.interval = false 4520 4521 Plugin.call($target, options) 4522 4523 if (slideIndex) { 4524 $target.data('bs.carousel').to(slideIndex) 4525 } 4526 4527 e.preventDefault() 4528 }) 4529 4530 $(window).on('load', function () { 4531 $('[data-ride="carousel"]').each(function () { 4532 var $carousel = $(this) 4533 Plugin.call($carousel, $carousel.data()) 4534 }) 4535 }) 4536 4537 }(jQuery); 4538 4539 /* ======================================================================== 4540 * Bootstrap: collapse.js v3.2.0 4541 * http://getbootstrap.com/javascript/#collapse 4542 * ======================================================================== 4543 * Copyright 2011-2014 Twitter, Inc. 4544 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4545 * ======================================================================== */ 4546 4547 4548 +function ($) { 4549 'use strict'; 4550 4551 // COLLAPSE PUBLIC CLASS DEFINITION 4552 // ================================ 4553 4554 var Collapse = function (element, options) { 4555 this.$element = $(element) 4556 this.options = $.extend({}, Collapse.DEFAULTS, options) 4557 this.transitioning = null 4558 4559 if (this.options.parent) this.$parent = $(this.options.parent) 4560 if (this.options.toggle) this.toggle() 4561 } 4562 4563 Collapse.VERSION = '3.2.0' 4564 4565 Collapse.DEFAULTS = { 4566 toggle: true 4567 } 4568 4569 Collapse.prototype.dimension = function () { 4570 var hasWidth = this.$element.hasClass('width') 4571 return hasWidth ? 'width' : 'height' 4572 } 4573 4574 Collapse.prototype.show = function () { 4575 if (this.transitioning || this.$element.hasClass('in')) return 4576 4577 var startEvent = $.Event('show.bs.collapse') 4578 this.$element.trigger(startEvent) 4579 if (startEvent.isDefaultPrevented()) return 4580 4581 var actives = this.$parent && this.$parent.find('> .panel > .in') 4582 4583 if (actives && actives.length) { 4584 var hasData = actives.data('bs.collapse') 4585 if (hasData && hasData.transitioning) return 4586 Plugin.call(actives, 'hide') 4587 hasData || actives.data('bs.collapse', null) 4588 } 4589 4590 var dimension = this.dimension() 4591 4592 this.$element 4593 .removeClass('collapse') 4594 .addClass('collapsing')[dimension](0) 4595 4596 this.transitioning = 1 4597 4598 var complete = function () { 4599 this.$element 4600 .removeClass('collapsing') 4601 .addClass('collapse in')[dimension]('') 4602 this.transitioning = 0 4603 this.$element 4604 .trigger('shown.bs.collapse') 4605 } 4606 4607 if (!$.support.transition) return complete.call(this) 4608 4609 var scrollSize = $.camelCase(['scroll', dimension].join('-')) 4610 4611 this.$element 4612 .one('bsTransitionEnd', $.proxy(complete, this)) 4613 .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize]) 4614 } 4615 4616 Collapse.prototype.hide = function () { 4617 if (this.transitioning || !this.$element.hasClass('in')) return 4618 4619 var startEvent = $.Event('hide.bs.collapse') 4620 this.$element.trigger(startEvent) 4621 if (startEvent.isDefaultPrevented()) return 4622 4623 var dimension = this.dimension() 4624 4625 this.$element[dimension](this.$element[dimension]())[0].offsetHeight 4626 4627 this.$element 4628 .addClass('collapsing') 4629 .removeClass('collapse') 4630 .removeClass('in') 4631 4632 this.transitioning = 1 4633 4634 var complete = function () { 4635 this.transitioning = 0 4636 this.$element 4637 .trigger('hidden.bs.collapse') 4638 .removeClass('collapsing') 4639 .addClass('collapse') 4640 } 4641 4642 if (!$.support.transition) return complete.call(this) 4643 4644 this.$element 4645 [dimension](0) 4646 .one('bsTransitionEnd', $.proxy(complete, this)) 4647 .emulateTransitionEnd(350) 4648 } 4649 4650 Collapse.prototype.toggle = function () { 4651 this[this.$element.hasClass('in') ? 'hide' : 'show']() 4652 } 4653 4654 4655 // COLLAPSE PLUGIN DEFINITION 4656 // ========================== 4657 4658 function Plugin(option) { 4659 return this.each(function () { 4660 var $this = $(this) 4661 var data = $this.data('bs.collapse') 4662 var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 4663 4664 if (!data && options.toggle && option == 'show') option = !option 4665 if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 4666 if (typeof option == 'string') data[option]() 4667 }) 4668 } 4669 4670 var old = $.fn.collapse 4671 4672 $.fn.collapse = Plugin 4673 $.fn.collapse.Constructor = Collapse 4674 4675 4676 // COLLAPSE NO CONFLICT 4677 // ==================== 4678 4679 $.fn.collapse.noConflict = function () { 4680 $.fn.collapse = old 4681 return this 4682 } 4683 4684 4685 // COLLAPSE DATA-API 4686 // ================= 4687 4688 $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 4689 var href 4690 var $this = $(this) 4691 var target = $this.attr('data-target') 4692 || e.preventDefault() 4693 || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 4694 var $target = $(target) 4695 var data = $target.data('bs.collapse') 4696 var option = data ? 'toggle' : $this.data() 4697 var parent = $this.attr('data-parent') 4698 var $parent = parent && $(parent) 4699 4700 if (!data || !data.transitioning) { 4701 if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed') 4702 $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 4703 } 4704 4705 Plugin.call($target, option) 4706 }) 4707 4708 }(jQuery); 4709 4710 /* ======================================================================== 4711 * Bootstrap: dropdown.js v3.2.0 4712 * http://getbootstrap.com/javascript/#dropdowns 4713 * ======================================================================== 4714 * Copyright 2011-2014 Twitter, Inc. 4715 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4716 * ======================================================================== */ 4717 4718 4719 +function ($) { 4720 'use strict'; 4721 4722 // DROPDOWN CLASS DEFINITION 4723 // ========================= 4724 4725 var backdrop = '.dropdown-backdrop' 4726 var toggle = '[data-toggle="dropdown"]' 4727 var Dropdown = function (element) { 4728 $(element).on('click.bs.dropdown', this.toggle) 4729 } 4730 4731 Dropdown.VERSION = '3.2.0' 4732 4733 Dropdown.prototype.toggle = function (e) { 4734 var $this = $(this) 4735 4736 if ($this.is('.disabled, :disabled')) return 4737 4738 var $parent = getParent($this) 4739 var isActive = $parent.hasClass('open') 4740 4741 clearMenus() 4742 4743 if (!isActive) { 4744 if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 4745 // if mobile we use a backdrop because click events don't delegate 4746 $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus) 4747 } 4748 4749 var relatedTarget = { relatedTarget: this } 4750 $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)) 4751 4752 if (e.isDefaultPrevented()) return 4753 4754 $this.trigger('focus') 4755 4756 $parent 4757 .toggleClass('open') 4758 .trigger('shown.bs.dropdown', relatedTarget) 4759 } 4760 4761 return false 4762 } 4763 4764 Dropdown.prototype.keydown = function (e) { 4765 if (!/(38|40|27)/.test(e.keyCode)) return 4766 4767 var $this = $(this) 4768 4769 e.preventDefault() 4770 e.stopPropagation() 4771 4772 if ($this.is('.disabled, :disabled')) return 4773 4774 var $parent = getParent($this) 4775 var isActive = $parent.hasClass('open') 4776 4777 if (!isActive || (isActive && e.keyCode == 27)) { 4778 if (e.which == 27) $parent.find(toggle).trigger('focus') 4779 return $this.trigger('click') 4780 } 4781 4782 var desc = ' li:not(.divider):visible a' 4783 var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc) 4784 4785 if (!$items.length) return 4786 4787 var index = $items.index($items.filter(':focus')) 4788 4789 if (e.keyCode == 38 && index > 0) index-- // up 4790 if (e.keyCode == 40 && index < $items.length - 1) index++ // down 4791 if (!~index) index = 0 4792 4793 $items.eq(index).trigger('focus') 4794 } 4795 4796 function clearMenus(e) { 4797 if (e && e.which === 3) return 4798 $(backdrop).remove() 4799 $(toggle).each(function () { 4800 var $parent = getParent($(this)) 4801 var relatedTarget = { relatedTarget: this } 4802 if (!$parent.hasClass('open')) return 4803 $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)) 4804 if (e.isDefaultPrevented()) return 4805 $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget) 4806 }) 4807 } 4808 4809 function getParent($this) { 4810 var selector = $this.attr('data-target') 4811 4812 if (!selector) { 4813 selector = $this.attr('href') 4814 selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 4815 } 4816 4817 var $parent = selector && $(selector) 4818 4819 return $parent && $parent.length ? $parent : $this.parent() 4820 } 4821 4822 4823 // DROPDOWN PLUGIN DEFINITION 4824 // ========================== 4825 4826 function Plugin(option) { 4827 return this.each(function () { 4828 var $this = $(this) 4829 var data = $this.data('bs.dropdown') 4830 4831 if (!data) $this.data('bs.dropdown', (data = new Dropdown(this))) 4832 if (typeof option == 'string') data[option].call($this) 4833 }) 4834 } 4835 4836 var old = $.fn.dropdown 4837 4838 $.fn.dropdown = Plugin 4839 $.fn.dropdown.Constructor = Dropdown 4840 4841 4842 // DROPDOWN NO CONFLICT 4843 // ==================== 4844 4845 $.fn.dropdown.noConflict = function () { 4846 $.fn.dropdown = old 4847 return this 4848 } 4849 4850 4851 // APPLY TO STANDARD DROPDOWN ELEMENTS 4852 // =================================== 4853 4854 $(document) 4855 .on('click.bs.dropdown.data-api', clearMenus) 4856 .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) 4857 .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) 4858 .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown) 4859 4860 }(jQuery); 4861 4862 /* ======================================================================== 4863 * Bootstrap: modal.js v3.2.0 4864 * http://getbootstrap.com/javascript/#modals 4865 * ======================================================================== 4866 * Copyright 2011-2014 Twitter, Inc. 4867 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4868 * ======================================================================== */ 4869 4870 4871 +function ($) { 4872 'use strict'; 4873 4874 // MODAL CLASS DEFINITION 4875 // ====================== 4876 4877 var Modal = function (element, options) { 4878 this.options = options 4879 this.$body = $(document.body) 4880 this.$element = $(element) 4881 this.$backdrop = 4882 this.isShown = null 4883 this.scrollbarWidth = 0 4884 4885 if (this.options.remote) { 4886 this.$element 4887 .find('.modal-content') 4888 .load(this.options.remote, $.proxy(function () { 4889 this.$element.trigger('loaded.bs.modal') 4890 }, this)) 4891 } 4892 } 4893 4894 Modal.VERSION = '3.2.0' 4895 4896 Modal.DEFAULTS = { 4897 backdrop: true, 4898 keyboard: true, 4899 show: true 4900 } 4901 4902 Modal.prototype.toggle = function (_relatedTarget) { 4903 return this.isShown ? this.hide() : this.show(_relatedTarget) 4904 } 4905 4906 Modal.prototype.show = function (_relatedTarget) { 4907 var that = this 4908 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 4909 4910 this.$element.trigger(e) 4911 4912 if (this.isShown || e.isDefaultPrevented()) return 4913 4914 this.isShown = true 4915 4916 this.checkScrollbar() 4917 this.$body.addClass('modal-open') 4918 4919 this.setScrollbar() 4920 this.escape() 4921 4922 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 4923 4924 this.backdrop(function () { 4925 var transition = $.support.transition && that.$element.hasClass('fade') 4926 4927 if (!that.$element.parent().length) { 4928 that.$element.appendTo(that.$body) // don't move modals dom position 4929 } 4930 4931 that.$element 4932 .show() 4933 .scrollTop(0) 4934 4935 if (transition) { 4936 that.$element[0].offsetWidth // force reflow 4937 } 4938 4939 that.$element 4940 .addClass('in') 4941 .attr('aria-hidden', false) 4942 4943 that.enforceFocus() 4944 4945 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 4946 4947 transition ? 4948 that.$element.find('.modal-dialog') // wait for modal to slide in 4949 .one('bsTransitionEnd', function () { 4950 that.$element.trigger('focus').trigger(e) 4951 }) 4952 .emulateTransitionEnd(300) : 4953 that.$element.trigger('focus').trigger(e) 4954 }) 4955 } 4956 4957 Modal.prototype.hide = function (e) { 4958 if (e) e.preventDefault() 4959 4960 e = $.Event('hide.bs.modal') 4961 4962 this.$element.trigger(e) 4963 4964 if (!this.isShown || e.isDefaultPrevented()) return 4965 4966 this.isShown = false 4967 4968 this.$body.removeClass('modal-open') 4969 4970 this.resetScrollbar() 4971 this.escape() 4972 4973 $(document).off('focusin.bs.modal') 4974 4975 this.$element 4976 .removeClass('in') 4977 .attr('aria-hidden', true) 4978 .off('click.dismiss.bs.modal') 4979 4980 $.support.transition && this.$element.hasClass('fade') ? 4981 this.$element 4982 .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 4983 .emulateTransitionEnd(300) : 4984 this.hideModal() 4985 } 4986 4987 Modal.prototype.enforceFocus = function () { 4988 $(document) 4989 .off('focusin.bs.modal') // guard against infinite focus loop 4990 .on('focusin.bs.modal', $.proxy(function (e) { 4991 if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 4992 this.$element.trigger('focus') 4993 } 4994 }, this)) 4995 } 4996 4997 Modal.prototype.escape = function () { 4998 if (this.isShown && this.options.keyboard) { 4999 this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { 5000 e.which == 27 && this.hide() 5001 }, this)) 5002 } else if (!this.isShown) { 5003 this.$element.off('keyup.dismiss.bs.modal') 5004 } 5005 } 5006 5007 Modal.prototype.hideModal = function () { 5008 var that = this 5009 this.$element.hide() 5010 this.backdrop(function () { 5011 that.$element.trigger('hidden.bs.modal') 5012 }) 5013 } 5014 5015 Modal.prototype.removeBackdrop = function () { 5016 this.$backdrop && this.$backdrop.remove() 5017 this.$backdrop = null 5018 } 5019 5020 Modal.prototype.backdrop = function (callback) { 5021 var that = this 5022 var animate = this.$element.hasClass('fade') ? 'fade' : '' 5023 5024 if (this.isShown && this.options.backdrop) { 5025 var doAnimate = $.support.transition && animate 5026 5027 this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') 5028 .appendTo(this.$body) 5029 5030 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 5031 if (e.target !== e.currentTarget) return 5032 this.options.backdrop == 'static' 5033 ? this.$element[0].focus.call(this.$element[0]) 5034 : this.hide.call(this) 5035 }, this)) 5036 5037 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 5038 5039 this.$backdrop.addClass('in') 5040 5041 if (!callback) return 5042 5043 doAnimate ? 5044 this.$backdrop 5045 .one('bsTransitionEnd', callback) 5046 .emulateTransitionEnd(150) : 5047 callback() 5048 5049 } else if (!this.isShown && this.$backdrop) { 5050 this.$backdrop.removeClass('in') 5051 5052 var callbackRemove = function () { 5053 that.removeBackdrop() 5054 callback && callback() 5055 } 5056 $.support.transition && this.$element.hasClass('fade') ? 5057 this.$backdrop 5058 .one('bsTransitionEnd', callbackRemove) 5059 .emulateTransitionEnd(150) : 5060 callbackRemove() 5061 5062 } else if (callback) { 5063 callback() 5064 } 5065 } 5066 5067 Modal.prototype.checkScrollbar = function () { 5068 if (document.body.clientWidth >= window.innerWidth) return 5069 this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar() 5070 } 5071 5072 Modal.prototype.setScrollbar = function () { 5073 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 5074 if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 5075 } 5076 5077 Modal.prototype.resetScrollbar = function () { 5078 this.$body.css('padding-right', '') 5079 } 5080 5081 Modal.prototype.measureScrollbar = function () { // thx walsh 5082 var scrollDiv = document.createElement('div') 5083 scrollDiv.className = 'modal-scrollbar-measure' 5084 this.$body.append(scrollDiv) 5085 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 5086 this.$body[0].removeChild(scrollDiv) 5087 return scrollbarWidth 5088 } 5089 5090 5091 // MODAL PLUGIN DEFINITION 5092 // ======================= 5093 5094 function Plugin(option, _relatedTarget) { 5095 return this.each(function () { 5096 var $this = $(this) 5097 var data = $this.data('bs.modal') 5098 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 5099 5100 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 5101 if (typeof option == 'string') data[option](_relatedTarget) 5102 else if (options.show) data.show(_relatedTarget) 5103 }) 5104 } 5105 5106 var old = $.fn.modal 5107 5108 $.fn.modal = Plugin 5109 $.fn.modal.Constructor = Modal 5110 5111 5112 // MODAL NO CONFLICT 5113 // ================= 5114 5115 $.fn.modal.noConflict = function () { 5116 $.fn.modal = old 5117 return this 5118 } 5119 5120 5121 // MODAL DATA-API 5122 // ============== 5123 5124 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 5125 var $this = $(this) 5126 var href = $this.attr('href') 5127 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 5128 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 5129 5130 if ($this.is('a')) e.preventDefault() 5131 5132 $target.one('show.bs.modal', function (showEvent) { 5133 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 5134 $target.one('hidden.bs.modal', function () { 5135 $this.is(':visible') && $this.trigger('focus') 5136 }) 5137 }) 5138 Plugin.call($target, option, this) 5139 }) 5140 5141 }(jQuery); 5142 5143 /* ======================================================================== 5144 * Bootstrap: tooltip.js v3.2.0 5145 * http://getbootstrap.com/javascript/#tooltip 5146 * Inspired by the original jQuery.tipsy by Jason Frame 5147 * ======================================================================== 5148 * Copyright 2011-2014 Twitter, Inc. 5149 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5150 * ======================================================================== */ 5151 5152 5153 +function ($) { 5154 'use strict'; 5155 5156 // TOOLTIP PUBLIC CLASS DEFINITION 5157 // =============================== 5158 5159 var Tooltip = function (element, options) { 5160 this.type = 5161 this.options = 5162 this.enabled = 5163 this.timeout = 5164 this.hoverState = 5165 this.$element = null 5166 5167 this.init('tooltip', element, options) 5168 } 5169 5170 Tooltip.VERSION = '3.2.0' 5171 5172 Tooltip.DEFAULTS = { 5173 animation: true, 5174 placement: 'top', 5175 selector: false, 5176 template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', 5177 trigger: 'hover focus', 5178 title: '', 5179 delay: 0, 5180 html: false, 5181 container: false, 5182 viewport: { 5183 selector: 'body', 5184 padding: 0 5185 } 5186 } 5187 5188 Tooltip.prototype.init = function (type, element, options) { 5189 this.enabled = true 5190 this.type = type 5191 this.$element = $(element) 5192 this.options = this.getOptions(options) 5193 this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport) 5194 5195 var triggers = this.options.trigger.split(' ') 5196 5197 for (var i = triggers.length; i--;) { 5198 var trigger = triggers[i] 5199 5200 if (trigger == 'click') { 5201 this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) 5202 } else if (trigger != 'manual') { 5203 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin' 5204 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' 5205 5206 this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) 5207 this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) 5208 } 5209 } 5210 5211 this.options.selector ? 5212 (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : 5213 this.fixTitle() 5214 } 5215 5216 Tooltip.prototype.getDefaults = function () { 5217 return Tooltip.DEFAULTS 5218 } 5219 5220 Tooltip.prototype.getOptions = function (options) { 5221 options = $.extend({}, this.getDefaults(), this.$element.data(), options) 5222 5223 if (options.delay && typeof options.delay == 'number') { 5224 options.delay = { 5225 show: options.delay, 5226 hide: options.delay 5227 } 5228 } 5229 5230 return options 5231 } 5232 5233 Tooltip.prototype.getDelegateOptions = function () { 5234 var options = {} 5235 var defaults = this.getDefaults() 5236 5237 this._options && $.each(this._options, function (key, value) { 5238 if (defaults[key] != value) options[key] = value 5239 }) 5240 5241 return options 5242 } 5243 5244 Tooltip.prototype.enter = function (obj) { 5245 var self = obj instanceof this.constructor ? 5246 obj : $(obj.currentTarget).data('bs.' + this.type) 5247 5248 if (!self) { 5249 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 5250 $(obj.currentTarget).data('bs.' + this.type, self) 5251 } 5252 5253 clearTimeout(self.timeout) 5254 5255 self.hoverState = 'in' 5256 5257 if (!self.options.delay || !self.options.delay.show) return self.show() 5258 5259 self.timeout = setTimeout(function () { 5260 if (self.hoverState == 'in') self.show() 5261 }, self.options.delay.show) 5262 } 5263 5264 Tooltip.prototype.leave = function (obj) { 5265 var self = obj instanceof this.constructor ? 5266 obj : $(obj.currentTarget).data('bs.' + this.type) 5267 5268 if (!self) { 5269 self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) 5270 $(obj.currentTarget).data('bs.' + this.type, self) 5271 } 5272 5273 clearTimeout(self.timeout) 5274 5275 self.hoverState = 'out' 5276 5277 if (!self.options.delay || !self.options.delay.hide) return self.hide() 5278 5279 self.timeout = setTimeout(function () { 5280 if (self.hoverState == 'out') self.hide() 5281 }, self.options.delay.hide) 5282 } 5283 5284 Tooltip.prototype.show = function () { 5285 var e = $.Event('show.bs.' + this.type) 5286 5287 if (this.hasContent() && this.enabled) { 5288 this.$element.trigger(e) 5289 5290 var inDom = $.contains(document.documentElement, this.$element[0]) 5291 if (e.isDefaultPrevented() || !inDom) return 5292 var that = this 5293 5294 var $tip = this.tip() 5295 5296 var tipId = this.getUID(this.type) 5297 5298 this.setContent() 5299 $tip.attr('id', tipId) 5300 this.$element.attr('aria-describedby', tipId) 5301 5302 if (this.options.animation) $tip.addClass('fade') 5303 5304 var placement = typeof this.options.placement == 'function' ? 5305 this.options.placement.call(this, $tip[0], this.$element[0]) : 5306 this.options.placement 5307 5308 var autoToken = /\s?auto?\s?/i 5309 var autoPlace = autoToken.test(placement) 5310 if (autoPlace) placement = placement.replace(autoToken, '') || 'top' 5311 5312 $tip 5313 .detach() 5314 .css({ top: 0, left: 0, display: 'block' }) 5315 .addClass(placement) 5316 .data('bs.' + this.type, this) 5317 5318 this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) 5319 5320 var pos = this.getPosition() 5321 var actualWidth = $tip[0].offsetWidth 5322 var actualHeight = $tip[0].offsetHeight 5323 5324 if (autoPlace) { 5325 var orgPlacement = placement 5326 var $parent = this.$element.parent() 5327 var parentDim = this.getPosition($parent) 5328 5329 placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' : 5330 placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' : 5331 placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' : 5332 placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' : 5333 placement 5334 5335 $tip 5336 .removeClass(orgPlacement) 5337 .addClass(placement) 5338 } 5339 5340 var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) 5341 5342 this.applyPlacement(calculatedOffset, placement) 5343 5344 var complete = function () { 5345 that.$element.trigger('shown.bs.' + that.type) 5346 that.hoverState = null 5347 } 5348 5349 $.support.transition && this.$tip.hasClass('fade') ? 5350 $tip 5351 .one('bsTransitionEnd', complete) 5352 .emulateTransitionEnd(150) : 5353 complete() 5354 } 5355 } 5356 5357 Tooltip.prototype.applyPlacement = function (offset, placement) { 5358 var $tip = this.tip() 5359 var width = $tip[0].offsetWidth 5360 var height = $tip[0].offsetHeight 5361 5362 // manually read margins because getBoundingClientRect includes difference 5363 var marginTop = parseInt($tip.css('margin-top'), 10) 5364 var marginLeft = parseInt($tip.css('margin-left'), 10) 5365 5366 // we must check for NaN for ie 8/9 5367 if (isNaN(marginTop)) marginTop = 0 5368 if (isNaN(marginLeft)) marginLeft = 0 5369 5370 offset.top = offset.top + marginTop 5371 offset.left = offset.left + marginLeft 5372 5373 // $.fn.offset doesn't round pixel values 5374 // so we use setOffset directly with our own function B-0 5375 $.offset.setOffset($tip[0], $.extend({ 5376 using: function (props) { 5377 $tip.css({ 5378 top: Math.round(props.top), 5379 left: Math.round(props.left) 5380 }) 5381 } 5382 }, offset), 0) 5383 5384 $tip.addClass('in') 5385 5386 // check to see if placing tip in new offset caused the tip to resize itself 5387 var actualWidth = $tip[0].offsetWidth 5388 var actualHeight = $tip[0].offsetHeight 5389 5390 if (placement == 'top' && actualHeight != height) { 5391 offset.top = offset.top + height - actualHeight 5392 } 5393 5394 var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) 5395 5396 if (delta.left) offset.left += delta.left 5397 else offset.top += delta.top 5398 5399 var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight 5400 var arrowPosition = delta.left ? 'left' : 'top' 5401 var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight' 5402 5403 $tip.offset(offset) 5404 this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition) 5405 } 5406 5407 Tooltip.prototype.replaceArrow = function (delta, dimension, position) { 5408 this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '') 5409 } 5410 5411 Tooltip.prototype.setContent = function () { 5412 var $tip = this.tip() 5413 var title = this.getTitle() 5414 5415 $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title) 5416 $tip.removeClass('fade in top bottom left right') 5417 } 5418 5419 Tooltip.prototype.hide = function () { 5420 var that = this 5421 var $tip = this.tip() 5422 var e = $.Event('hide.bs.' + this.type) 5423 5424 this.$element.removeAttr('aria-describedby') 5425 5426 function complete() { 5427 if (that.hoverState != 'in') $tip.detach() 5428 that.$element.trigger('hidden.bs.' + that.type) 5429 } 5430 5431 this.$element.trigger(e) 5432 5433 if (e.isDefaultPrevented()) return 5434 5435 $tip.removeClass('in') 5436 5437 $.support.transition && this.$tip.hasClass('fade') ? 5438 $tip 5439 .one('bsTransitionEnd', complete) 5440 .emulateTransitionEnd(150) : 5441 complete() 5442 5443 this.hoverState = null 5444 5445 return this 5446 } 5447 5448 Tooltip.prototype.fixTitle = function () { 5449 var $e = this.$element 5450 if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') { 5451 $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') 5452 } 5453 } 5454 5455 Tooltip.prototype.hasContent = function () { 5456 return this.getTitle() 5457 } 5458 5459 Tooltip.prototype.getPosition = function ($element) { 5460 $element = $element || this.$element 5461 var el = $element[0] 5462 var isBody = el.tagName == 'BODY' 5463 return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, { 5464 scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(), 5465 width: isBody ? $(window).width() : $element.outerWidth(), 5466 height: isBody ? $(window).height() : $element.outerHeight() 5467 }, isBody ? { top: 0, left: 0 } : $element.offset()) 5468 } 5469 5470 Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { 5471 return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } : 5472 placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : 5473 placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : 5474 /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } 5475 5476 } 5477 5478 Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { 5479 var delta = { top: 0, left: 0 } 5480 if (!this.$viewport) return delta 5481 5482 var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 5483 var viewportDimensions = this.getPosition(this.$viewport) 5484 5485 if (/right|left/.test(placement)) { 5486 var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll 5487 var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight 5488 if (topEdgeOffset < viewportDimensions.top) { // top overflow 5489 delta.top = viewportDimensions.top - topEdgeOffset 5490 } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow 5491 delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset 5492 } 5493 } else { 5494 var leftEdgeOffset = pos.left - viewportPadding 5495 var rightEdgeOffset = pos.left + viewportPadding + actualWidth 5496 if (leftEdgeOffset < viewportDimensions.left) { // left overflow 5497 delta.left = viewportDimensions.left - leftEdgeOffset 5498 } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow 5499 delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset 5500 } 5501 } 5502 5503 return delta 5504 } 5505 5506 Tooltip.prototype.getTitle = function () { 5507 var title 5508 var $e = this.$element 5509 var o = this.options 5510 5511 title = $e.attr('data-original-title') 5512 || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title) 5513 5514 return title 5515 } 5516 5517 Tooltip.prototype.getUID = function (prefix) { 5518 do prefix += ~~(Math.random() * 1000000) 5519 while (document.getElementById(prefix)) 5520 return prefix 5521 } 5522 5523 Tooltip.prototype.tip = function () { 5524 return (this.$tip = this.$tip || $(this.options.template)) 5525 } 5526 5527 Tooltip.prototype.arrow = function () { 5528 return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) 5529 } 5530 5531 Tooltip.prototype.validate = function () { 5532 if (!this.$element[0].parentNode) { 5533 this.hide() 5534 this.$element = null 5535 this.options = null 5536 } 5537 } 5538 5539 Tooltip.prototype.enable = function () { 5540 this.enabled = true 5541 } 5542 5543 Tooltip.prototype.disable = function () { 5544 this.enabled = false 5545 } 5546 5547 Tooltip.prototype.toggleEnabled = function () { 5548 this.enabled = !this.enabled 5549 } 5550 5551 Tooltip.prototype.toggle = function (e) { 5552 var self = this 5553 if (e) { 5554 self = $(e.currentTarget).data('bs.' + this.type) 5555 if (!self) { 5556 self = new this.constructor(e.currentTarget, this.getDelegateOptions()) 5557 $(e.currentTarget).data('bs.' + this.type, self) 5558 } 5559 } 5560 5561 self.tip().hasClass('in') ? self.leave(self) : self.enter(self) 5562 } 5563 5564 Tooltip.prototype.destroy = function () { 5565 clearTimeout(this.timeout) 5566 this.hide().$element.off('.' + this.type).removeData('bs.' + this.type) 5567 } 5568 5569 5570 // TOOLTIP PLUGIN DEFINITION 5571 // ========================= 5572 5573 function Plugin(option) { 5574 return this.each(function () { 5575 var $this = $(this) 5576 var data = $this.data('bs.tooltip') 5577 var options = typeof option == 'object' && option 5578 5579 if (!data && option == 'destroy') return 5580 if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) 5581 if (typeof option == 'string') data[option]() 5582 }) 5583 } 5584 5585 var old = $.fn.tooltip 5586 5587 $.fn.tooltip = Plugin 5588 $.fn.tooltip.Constructor = Tooltip 5589 5590 5591 // TOOLTIP NO CONFLICT 5592 // =================== 5593 5594 $.fn.tooltip.noConflict = function () { 5595 $.fn.tooltip = old 5596 return this 5597 } 5598 5599 }(jQuery); 5600 5601 /* ======================================================================== 5602 * Bootstrap: popover.js v3.2.0 5603 * http://getbootstrap.com/javascript/#popovers 5604 * ======================================================================== 5605 * Copyright 2011-2014 Twitter, Inc. 5606 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5607 * ======================================================================== */ 5608 5609 5610 +function ($) { 5611 'use strict'; 5612 5613 // POPOVER PUBLIC CLASS DEFINITION 5614 // =============================== 5615 5616 var Popover = function (element, options) { 5617 this.init('popover', element, options) 5618 } 5619 5620 if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') 5621 5622 Popover.VERSION = '3.2.0' 5623 5624 Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { 5625 placement: 'right', 5626 trigger: 'click', 5627 content: '', 5628 template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' 5629 }) 5630 5631 5632 // NOTE: POPOVER EXTENDS tooltip.js 5633 // ================================ 5634 5635 Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) 5636 5637 Popover.prototype.constructor = Popover 5638 5639 Popover.prototype.getDefaults = function () { 5640 return Popover.DEFAULTS 5641 } 5642 5643 Popover.prototype.setContent = function () { 5644 var $tip = this.tip() 5645 var title = this.getTitle() 5646 var content = this.getContent() 5647 5648 $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) 5649 $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events 5650 this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text' 5651 ](content) 5652 5653 $tip.removeClass('fade top bottom left right in') 5654 5655 // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do 5656 // this manually by checking the contents. 5657 if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() 5658 } 5659 5660 Popover.prototype.hasContent = function () { 5661 return this.getTitle() || this.getContent() 5662 } 5663 5664 Popover.prototype.getContent = function () { 5665 var $e = this.$element 5666 var o = this.options 5667 5668 return $e.attr('data-content') 5669 || (typeof o.content == 'function' ? 5670 o.content.call($e[0]) : 5671 o.content) 5672 } 5673 5674 Popover.prototype.arrow = function () { 5675 return (this.$arrow = this.$arrow || this.tip().find('.arrow')) 5676 } 5677 5678 Popover.prototype.tip = function () { 5679 if (!this.$tip) this.$tip = $(this.options.template) 5680 return this.$tip 5681 } 5682 5683 5684 // POPOVER PLUGIN DEFINITION 5685 // ========================= 5686 5687 function Plugin(option) { 5688 return this.each(function () { 5689 var $this = $(this) 5690 var data = $this.data('bs.popover') 5691 var options = typeof option == 'object' && option 5692 5693 if (!data && option == 'destroy') return 5694 if (!data) $this.data('bs.popover', (data = new Popover(this, options))) 5695 if (typeof option == 'string') data[option]() 5696 }) 5697 } 5698 5699 var old = $.fn.popover 5700 5701 $.fn.popover = Plugin 5702 $.fn.popover.Constructor = Popover 5703 5704 5705 // POPOVER NO CONFLICT 5706 // =================== 5707 5708 $.fn.popover.noConflict = function () { 5709 $.fn.popover = old 5710 return this 5711 } 5712 5713 }(jQuery); 5714 5715 /* ======================================================================== 5716 * Bootstrap: scrollspy.js v3.2.0 5717 * http://getbootstrap.com/javascript/#scrollspy 5718 * ======================================================================== 5719 * Copyright 2011-2014 Twitter, Inc. 5720 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5721 * ======================================================================== */ 5722 5723 5724 +function ($) { 5725 'use strict'; 5726 5727 // SCROLLSPY CLASS DEFINITION 5728 // ========================== 5729 5730 function ScrollSpy(element, options) { 5731 var process = $.proxy(this.process, this) 5732 5733 this.$body = $('body') 5734 this.$scrollElement = $(element).is('body') ? $(window) : $(element) 5735 this.options = $.extend({}, ScrollSpy.DEFAULTS, options) 5736 this.selector = (this.options.target || '') + ' .nav li > a' 5737 this.offsets = [] 5738 this.targets = [] 5739 this.activeTarget = null 5740 this.scrollHeight = 0 5741 5742 this.$scrollElement.on('scroll.bs.scrollspy', process) 5743 this.refresh() 5744 this.process() 5745 } 5746 5747 ScrollSpy.VERSION = '3.2.0' 5748 5749 ScrollSpy.DEFAULTS = { 5750 offset: 10 5751 } 5752 5753 ScrollSpy.prototype.getScrollHeight = function () { 5754 return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) 5755 } 5756 5757 ScrollSpy.prototype.refresh = function () { 5758 var offsetMethod = 'offset' 5759 var offsetBase = 0 5760 5761 if (!$.isWindow(this.$scrollElement[0])) { 5762 offsetMethod = 'position' 5763 offsetBase = this.$scrollElement.scrollTop() 5764 } 5765 5766 this.offsets = [] 5767 this.targets = [] 5768 this.scrollHeight = this.getScrollHeight() 5769 5770 var self = this 5771 5772 this.$body 5773 .find(this.selector) 5774 .map(function () { 5775 var $el = $(this) 5776 var href = $el.data('target') || $el.attr('href') 5777 var $href = /^#./.test(href) && $(href) 5778 5779 return ($href 5780 && $href.length 5781 && $href.is(':visible') 5782 && [[$href[offsetMethod]().top + offsetBase, href]]) || null 5783 }) 5784 .sort(function (a, b) { return a[0] - b[0] }) 5785 .each(function () { 5786 self.offsets.push(this[0]) 5787 self.targets.push(this[1]) 5788 }) 5789 } 5790 5791 ScrollSpy.prototype.process = function () { 5792 var scrollTop = this.$scrollElement.scrollTop() + this.options.offset 5793 var scrollHeight = this.getScrollHeight() 5794 var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() 5795 var offsets = this.offsets 5796 var targets = this.targets 5797 var activeTarget = this.activeTarget 5798 var i 5799 5800 if (this.scrollHeight != scrollHeight) { 5801 this.refresh() 5802 } 5803 5804 if (scrollTop >= maxScroll) { 5805 return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) 5806 } 5807 5808 if (activeTarget && scrollTop <= offsets[0]) { 5809 return activeTarget != (i = targets[0]) && this.activate(i) 5810 } 5811 5812 for (i = offsets.length; i--;) { 5813 activeTarget != targets[i] 5814 && scrollTop >= offsets[i] 5815 && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) 5816 && this.activate(targets[i]) 5817 } 5818 } 5819 5820 ScrollSpy.prototype.activate = function (target) { 5821 this.activeTarget = target 5822 5823 $(this.selector) 5824 .parentsUntil(this.options.target, '.active') 5825 .removeClass('active') 5826 5827 var selector = this.selector + 5828 '[data-target="' + target + '"],' + 5829 this.selector + '[href="' + target + '"]' 5830 5831 var active = $(selector) 5832 .parents('li') 5833 .addClass('active') 5834 5835 if (active.parent('.dropdown-menu').length) { 5836 active = active 5837 .closest('li.dropdown') 5838 .addClass('active') 5839 } 5840 5841 active.trigger('activate.bs.scrollspy') 5842 } 5843 5844 5845 // SCROLLSPY PLUGIN DEFINITION 5846 // =========================== 5847 5848 function Plugin(option) { 5849 return this.each(function () { 5850 var $this = $(this) 5851 var data = $this.data('bs.scrollspy') 5852 var options = typeof option == 'object' && option 5853 5854 if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) 5855 if (typeof option == 'string') data[option]() 5856 }) 5857 } 5858 5859 var old = $.fn.scrollspy 5860 5861 $.fn.scrollspy = Plugin 5862 $.fn.scrollspy.Constructor = ScrollSpy 5863 5864 5865 // SCROLLSPY NO CONFLICT 5866 // ===================== 5867 5868 $.fn.scrollspy.noConflict = function () { 5869 $.fn.scrollspy = old 5870 return this 5871 } 5872 5873 5874 // SCROLLSPY DATA-API 5875 // ================== 5876 5877 $(window).on('load.bs.scrollspy.data-api', function () { 5878 $('[data-spy="scroll"]').each(function () { 5879 var $spy = $(this) 5880 Plugin.call($spy, $spy.data()) 5881 }) 5882 }) 5883 5884 }(jQuery); 5885 5886 /* ======================================================================== 5887 * Bootstrap: tab.js v3.2.0 5888 * http://getbootstrap.com/javascript/#tabs 5889 * ======================================================================== 5890 * Copyright 2011-2014 Twitter, Inc. 5891 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5892 * ======================================================================== */ 5893 5894 5895 +function ($) { 5896 'use strict'; 5897 5898 // TAB CLASS DEFINITION 5899 // ==================== 5900 5901 var Tab = function (element) { 5902 this.element = $(element) 5903 } 5904 5905 Tab.VERSION = '3.2.0' 5906 5907 Tab.prototype.show = function () { 5908 var $this = this.element 5909 var $ul = $this.closest('ul:not(.dropdown-menu)') 5910 var selector = $this.data('target') 5911 5912 if (!selector) { 5913 selector = $this.attr('href') 5914 selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 5915 } 5916 5917 if ($this.parent('li').hasClass('active')) return 5918 5919 var previous = $ul.find('.active:last a')[0] 5920 var e = $.Event('show.bs.tab', { 5921 relatedTarget: previous 5922 }) 5923 5924 $this.trigger(e) 5925 5926 if (e.isDefaultPrevented()) return 5927 5928 var $target = $(selector) 5929 5930 this.activate($this.closest('li'), $ul) 5931 this.activate($target, $target.parent(), function () { 5932 $this.trigger({ 5933 type: 'shown.bs.tab', 5934 relatedTarget: previous 5935 }) 5936 }) 5937 } 5938 5939 Tab.prototype.activate = function (element, container, callback) { 5940 var $active = container.find('> .active') 5941 var transition = callback 5942 && $.support.transition 5943 && $active.hasClass('fade') 5944 5945 function next() { 5946 $active 5947 .removeClass('active') 5948 .find('> .dropdown-menu > .active') 5949 .removeClass('active') 5950 5951 element.addClass('active') 5952 5953 if (transition) { 5954 element[0].offsetWidth // reflow for transition 5955 element.addClass('in') 5956 } else { 5957 element.removeClass('fade') 5958 } 5959 5960 if (element.parent('.dropdown-menu')) { 5961 element.closest('li.dropdown').addClass('active') 5962 } 5963 5964 callback && callback() 5965 } 5966 5967 transition ? 5968 $active 5969 .one('bsTransitionEnd', next) 5970 .emulateTransitionEnd(150) : 5971 next() 5972 5973 $active.removeClass('in') 5974 } 5975 5976 5977 // TAB PLUGIN DEFINITION 5978 // ===================== 5979 5980 function Plugin(option) { 5981 return this.each(function () { 5982 var $this = $(this) 5983 var data = $this.data('bs.tab') 5984 5985 if (!data) $this.data('bs.tab', (data = new Tab(this))) 5986 if (typeof option == 'string') data[option]() 5987 }) 5988 } 5989 5990 var old = $.fn.tab 5991 5992 $.fn.tab = Plugin 5993 $.fn.tab.Constructor = Tab 5994 5995 5996 // TAB NO CONFLICT 5997 // =============== 5998 5999 $.fn.tab.noConflict = function () { 6000 $.fn.tab = old 6001 return this 6002 } 6003 6004 6005 // TAB DATA-API 6006 // ============ 6007 6008 $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { 6009 e.preventDefault() 6010 Plugin.call($(this), 'show') 6011 }) 6012 6013 }(jQuery); 6014 6015 /* ======================================================================== 6016 * Bootstrap: affix.js v3.2.0 6017 * http://getbootstrap.com/javascript/#affix 6018 * ======================================================================== 6019 * Copyright 2011-2014 Twitter, Inc. 6020 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6021 * ======================================================================== */ 6022 6023 6024 +function ($) { 6025 'use strict'; 6026 6027 // AFFIX CLASS DEFINITION 6028 // ====================== 6029 6030 var Affix = function (element, options) { 6031 this.options = $.extend({}, Affix.DEFAULTS, options) 6032 6033 this.$target = $(this.options.target) 6034 .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) 6035 .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) 6036 6037 this.$element = $(element) 6038 this.affixed = 6039 this.unpin = 6040 this.pinnedOffset = null 6041 6042 this.checkPosition() 6043 } 6044 6045 Affix.VERSION = '3.2.0' 6046 6047 Affix.RESET = 'affix affix-top affix-bottom' 6048 6049 Affix.DEFAULTS = { 6050 offset: 0, 6051 target: window 6052 } 6053 6054 Affix.prototype.getPinnedOffset = function () { 6055 if (this.pinnedOffset) return this.pinnedOffset 6056 this.$element.removeClass(Affix.RESET).addClass('affix') 6057 var scrollTop = this.$target.scrollTop() 6058 var position = this.$element.offset() 6059 return (this.pinnedOffset = position.top - scrollTop) 6060 } 6061 6062 Affix.prototype.checkPositionWithEventLoop = function () { 6063 setTimeout($.proxy(this.checkPosition, this), 1) 6064 } 6065 6066 Affix.prototype.checkPosition = function () { 6067 if (!this.$element.is(':visible')) return 6068 6069 var scrollHeight = $(document).height() 6070 var scrollTop = this.$target.scrollTop() 6071 var position = this.$element.offset() 6072 var offset = this.options.offset 6073 var offsetTop = offset.top 6074 var offsetBottom = offset.bottom 6075 6076 if (typeof offset != 'object') offsetBottom = offsetTop = offset 6077 if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) 6078 if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) 6079 6080 var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : 6081 offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : 6082 offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false 6083 6084 if (this.affixed === affix) return 6085 if (this.unpin != null) this.$element.css('top', '') 6086 6087 var affixType = 'affix' + (affix ? '-' + affix : '') 6088 var e = $.Event(affixType + '.bs.affix') 6089 6090 this.$element.trigger(e) 6091 6092 if (e.isDefaultPrevented()) return 6093 6094 this.affixed = affix 6095 this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null 6096 6097 this.$element 6098 .removeClass(Affix.RESET) 6099 .addClass(affixType) 6100 .trigger($.Event(affixType.replace('affix', 'affixed'))) 6101 6102 if (affix == 'bottom') { 6103 this.$element.offset({ 6104 top: scrollHeight - this.$element.height() - offsetBottom 6105 }) 6106 } 6107 } 6108 6109 6110 // AFFIX PLUGIN DEFINITION 6111 // ======================= 6112 6113 function Plugin(option) { 6114 return this.each(function () { 6115 var $this = $(this) 6116 var data = $this.data('bs.affix') 6117 var options = typeof option == 'object' && option 6118 6119 if (!data) $this.data('bs.affix', (data = new Affix(this, options))) 6120 if (typeof option == 'string') data[option]() 6121 }) 6122 } 6123 6124 var old = $.fn.affix 6125 6126 $.fn.affix = Plugin 6127 $.fn.affix.Constructor = Affix 6128 6129 6130 // AFFIX NO CONFLICT 6131 // ================= 6132 6133 $.fn.affix.noConflict = function () { 6134 $.fn.affix = old 6135 return this 6136 } 6137 6138 6139 // AFFIX DATA-API 6140 // ============== 6141 6142 $(window).on('load', function () { 6143 $('[data-spy="affix"]').each(function () { 6144 var $spy = $(this) 6145 var data = $spy.data() 6146 6147 data.offset = data.offset || {} 6148 6149 if (data.offsetBottom) data.offset.bottom = data.offsetBottom 6150 if (data.offsetTop) data.offset.top = data.offsetTop 6151 6152 Plugin.call($spy, data) 6153 }) 6154 }) 6155 6156 }(jQuery); 6157 6158 /* ======================================================================== 6159 * bootstrap-switch - v3.0.2 6160 * http://www.bootstrap-switch.org 6161 * ======================================================================== 6162 * Copyright 2012-2013 Mattia Larentis 6163 * 6164 * ======================================================================== 6165 * Licensed under the Apache License, Version 2.0 (the "License"); 6166 * you may not use this file except in compliance with the License. 6167 * You may obtain a copy of the License at 6168 * 6169 * http://www.apache.org/licenses/LICENSE-2.0 6170 * 6171 * Unless required by applicable law or agreed to in writing, software 6172 * distributed under the License is distributed on an "AS IS" BASIS, 6173 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6174 * See the License for the specific language governing permissions and 6175 * limitations under the License. 6176 * ======================================================================== 6177 */ 6178 6179 (function() { 6180 var __slice = [].slice; 6181 6182 (function($, window) { 6183 "use strict"; 6184 var BootstrapSwitch; 6185 BootstrapSwitch = (function() { 6186 function BootstrapSwitch(element, options) { 6187 if (options == null) { 6188 options = {}; 6189 } 6190 this.$element = $(element); 6191 this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, { 6192 state: this.$element.is(":checked"), 6193 size: this.$element.data("size"), 6194 animate: this.$element.data("animate"), 6195 disabled: this.$element.is(":disabled"), 6196 readonly: this.$element.is("[readonly]"), 6197 indeterminate: this.$element.data("indeterminate"), 6198 onColor: this.$element.data("on-color"), 6199 offColor: this.$element.data("off-color"), 6200 onText: this.$element.data("on-text"), 6201 offText: this.$element.data("off-text"), 6202 labelText: this.$element.data("label-text"), 6203 baseClass: this.$element.data("base-class"), 6204 wrapperClass: this.$element.data("wrapper-class"), 6205 radioAllOff: this.$element.data("radio-all-off") 6206 }, options); 6207 this.$wrapper = $("<div>", { 6208 "class": (function(_this) { 6209 return function() { 6210 var classes; 6211 classes = ["" + _this.options.baseClass].concat(_this._getClasses(_this.options.wrapperClass)); 6212 classes.push(_this.options.state ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off"); 6213 if (_this.options.size != null) { 6214 classes.push("" + _this.options.baseClass + "-" + _this.options.size); 6215 } 6216 if (_this.options.animate) { 6217 classes.push("" + _this.options.baseClass + "-animate"); 6218 } 6219 if (_this.options.disabled) { 6220 classes.push("" + _this.options.baseClass + "-disabled"); 6221 } 6222 if (_this.options.readonly) { 6223 classes.push("" + _this.options.baseClass + "-readonly"); 6224 } 6225 if (_this.options.indeterminate) { 6226 classes.push("" + _this.options.baseClass + "-indeterminate"); 6227 } 6228 if (_this.$element.attr("id")) { 6229 classes.push("" + _this.options.baseClass + "-id-" + (_this.$element.attr("id"))); 6230 } 6231 return classes.join(" "); 6232 }; 6233 })(this)() 6234 }); 6235 this.$container = $("<div>", { 6236 "class": "" + this.options.baseClass + "-container" 6237 }); 6238 this.$on = $("<span>", { 6239 html: this.options.onText, 6240 "class": "" + this.options.baseClass + "-handle-on " + this.options.baseClass + "-" + this.options.onColor 6241 }); 6242 this.$off = $("<span>", { 6243 html: this.options.offText, 6244 "class": "" + this.options.baseClass + "-handle-off " + this.options.baseClass + "-" + this.options.offColor 6245 }); 6246 this.$label = $("<label>", { 6247 html: this.options.labelText, 6248 "class": "" + this.options.baseClass + "-label" 6249 }); 6250 if (this.options.indeterminate) { 6251 this.$element.prop("indeterminate", true); 6252 } 6253 this.$element.on("init.bootstrapSwitch", (function(_this) { 6254 return function() { 6255 return _this.options.onInit.apply(element, arguments); 6256 }; 6257 })(this)); 6258 this.$element.on("switchChange.bootstrapSwitch", (function(_this) { 6259 return function() { 6260 return _this.options.onSwitchChange.apply(element, arguments); 6261 }; 6262 })(this)); 6263 this.$container = this.$element.wrap(this.$container).parent(); 6264 this.$wrapper = this.$container.wrap(this.$wrapper).parent(); 6265 this.$element.before(this.$on).before(this.$label).before(this.$off).trigger("init.bootstrapSwitch"); 6266 this._elementHandlers(); 6267 this._handleHandlers(); 6268 this._labelHandlers(); 6269 this._formHandler(); 6270 } 6271 6272 BootstrapSwitch.prototype._constructor = BootstrapSwitch; 6273 6274 BootstrapSwitch.prototype.state = function(value, skip) { 6275 if (typeof value === "undefined") { 6276 return this.options.state; 6277 } 6278 if (this.options.disabled || this.options.readonly || this.options.indeterminate) { 6279 return this.$element; 6280 } 6281 if (this.options.state && !this.options.radioAllOff && this.$element.is(':radio')) { 6282 return this.$element; 6283 } 6284 value = !!value; 6285 this.$element.prop("checked", value).trigger("change.bootstrapSwitch", skip); 6286 return this.$element; 6287 }; 6288 6289 BootstrapSwitch.prototype.toggleState = function(skip) { 6290 if (this.options.disabled || this.options.readonly || this.options.indeterminate) { 6291 return this.$element; 6292 } 6293 return this.$element.prop("checked", !this.options.state).trigger("change.bootstrapSwitch", skip); 6294 }; 6295 6296 BootstrapSwitch.prototype.size = function(value) { 6297 if (typeof value === "undefined") { 6298 return this.options.size; 6299 } 6300 if (this.options.size != null) { 6301 this.$wrapper.removeClass("" + this.options.baseClass + "-" + this.options.size); 6302 } 6303 if (value) { 6304 this.$wrapper.addClass("" + this.options.baseClass + "-" + value); 6305 } 6306 this.options.size = value; 6307 return this.$element; 6308 }; 6309 6310 BootstrapSwitch.prototype.animate = function(value) { 6311 if (typeof value === "undefined") { 6312 return this.options.animate; 6313 } 6314 value = !!value; 6315 this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-animate"); 6316 this.options.animate = value; 6317 return this.$element; 6318 }; 6319 6320 BootstrapSwitch.prototype.disabled = function(value) { 6321 if (typeof value === "undefined") { 6322 return this.options.disabled; 6323 } 6324 value = !!value; 6325 this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-disabled"); 6326 this.$element.prop("disabled", value); 6327 this.options.disabled = value; 6328 return this.$element; 6329 }; 6330 6331 BootstrapSwitch.prototype.toggleDisabled = function() { 6332 this.$element.prop("disabled", !this.options.disabled); 6333 this.$wrapper.toggleClass("" + this.options.baseClass + "-disabled"); 6334 this.options.disabled = !this.options.disabled; 6335 return this.$element; 6336 }; 6337 6338 BootstrapSwitch.prototype.readonly = function(value) { 6339 if (typeof value === "undefined") { 6340 return this.options.readonly; 6341 } 6342 value = !!value; 6343 this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-readonly"); 6344 this.$element.prop("readonly", value); 6345 this.options.readonly = value; 6346 return this.$element; 6347 }; 6348 6349 BootstrapSwitch.prototype.toggleReadonly = function() { 6350 this.$element.prop("readonly", !this.options.readonly); 6351 this.$wrapper.toggleClass("" + this.options.baseClass + "-readonly"); 6352 this.options.readonly = !this.options.readonly; 6353 return this.$element; 6354 }; 6355 6356 BootstrapSwitch.prototype.indeterminate = function(value) { 6357 if (typeof value === "undefined") { 6358 return this.options.indeterminate; 6359 } 6360 value = !!value; 6361 this.$wrapper[value ? "addClass" : "removeClass"]("" + this.options.baseClass + "-indeterminate"); 6362 this.$element.prop("indeterminate", value); 6363 this.options.indeterminate = value; 6364 return this.$element; 6365 }; 6366 6367 BootstrapSwitch.prototype.toggleIndeterminate = function() { 6368 this.$element.prop("indeterminate", !this.options.indeterminate); 6369 this.$wrapper.toggleClass("" + this.options.baseClass + "-indeterminate"); 6370 this.options.indeterminate = !this.options.indeterminate; 6371 return this.$element; 6372 }; 6373 6374 BootstrapSwitch.prototype.onColor = function(value) { 6375 var color; 6376 color = this.options.onColor; 6377 if (typeof value === "undefined") { 6378 return color; 6379 } 6380 if (color != null) { 6381 this.$on.removeClass("" + this.options.baseClass + "-" + color); 6382 } 6383 this.$on.addClass("" + this.options.baseClass + "-" + value); 6384 this.options.onColor = value; 6385 return this.$element; 6386 }; 6387 6388 BootstrapSwitch.prototype.offColor = function(value) { 6389 var color; 6390 color = this.options.offColor; 6391 if (typeof value === "undefined") { 6392 return color; 6393 } 6394 if (color != null) { 6395 this.$off.removeClass("" + this.options.baseClass + "-" + color); 6396 } 6397 this.$off.addClass("" + this.options.baseClass + "-" + value); 6398 this.options.offColor = value; 6399 return this.$element; 6400 }; 6401 6402 BootstrapSwitch.prototype.onText = function(value) { 6403 if (typeof value === "undefined") { 6404 return this.options.onText; 6405 } 6406 this.$on.html(value); 6407 this.options.onText = value; 6408 return this.$element; 6409 }; 6410 6411 BootstrapSwitch.prototype.offText = function(value) { 6412 if (typeof value === "undefined") { 6413 return this.options.offText; 6414 } 6415 this.$off.html(value); 6416 this.options.offText = value; 6417 return this.$element; 6418 }; 6419 6420 BootstrapSwitch.prototype.labelText = function(value) { 6421 if (typeof value === "undefined") { 6422 return this.options.labelText; 6423 } 6424 this.$label.html(value); 6425 this.options.labelText = value; 6426 return this.$element; 6427 }; 6428 6429 BootstrapSwitch.prototype.baseClass = function(value) { 6430 return this.options.baseClass; 6431 }; 6432 6433 BootstrapSwitch.prototype.wrapperClass = function(value) { 6434 if (typeof value === "undefined") { 6435 return this.options.wrapperClass; 6436 } 6437 if (!value) { 6438 value = $.fn.bootstrapSwitch.defaults.wrapperClass; 6439 } 6440 this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(" ")); 6441 this.$wrapper.addClass(this._getClasses(value).join(" ")); 6442 this.options.wrapperClass = value; 6443 return this.$element; 6444 }; 6445 6446 BootstrapSwitch.prototype.radioAllOff = function(value) { 6447 if (typeof value === "undefined") { 6448 return this.options.radioAllOff; 6449 } 6450 this.options.radioAllOff = value; 6451 return this.$element; 6452 }; 6453 6454 BootstrapSwitch.prototype.onInit = function(value) { 6455 if (typeof value === "undefined") { 6456 return this.options.onInit; 6457 } 6458 if (!value) { 6459 value = $.fn.bootstrapSwitch.defaults.onInit; 6460 } 6461 this.options.onInit = value; 6462 return this.$element; 6463 }; 6464 6465 BootstrapSwitch.prototype.onSwitchChange = function(value) { 6466 if (typeof value === "undefined") { 6467 return this.options.onSwitchChange; 6468 } 6469 if (!value) { 6470 value = $.fn.bootstrapSwitch.defaults.onSwitchChange; 6471 } 6472 this.options.onSwitchChange = value; 6473 return this.$element; 6474 }; 6475 6476 BootstrapSwitch.prototype.destroy = function() { 6477 var $form; 6478 $form = this.$element.closest("form"); 6479 if ($form.length) { 6480 $form.off("reset.bootstrapSwitch").removeData("bootstrap-switch"); 6481 } 6482 this.$container.children().not(this.$element).remove(); 6483 this.$element.unwrap().unwrap().off(".bootstrapSwitch").removeData("bootstrap-switch"); 6484 return this.$element; 6485 }; 6486 6487 BootstrapSwitch.prototype._elementHandlers = function() { 6488 return this.$element.on({ 6489 "change.bootstrapSwitch": (function(_this) { 6490 return function(e, skip) { 6491 var checked; 6492 e.preventDefault(); 6493 e.stopImmediatePropagation(); 6494 checked = _this.$element.is(":checked"); 6495 if (checked === _this.options.state) { 6496 return; 6497 } 6498 _this.options.state = checked; 6499 _this.$wrapper.removeClass(checked ? "" + _this.options.baseClass + "-off" : "" + _this.options.baseClass + "-on").addClass(checked ? "" + _this.options.baseClass + "-on" : "" + _this.options.baseClass + "-off"); 6500 if (!skip) { 6501 if (_this.$element.is(":radio")) { 6502 $("[name='" + (_this.$element.attr('name')) + "']").not(_this.$element).prop("checked", false).trigger("change.bootstrapSwitch", true); 6503 } 6504 return _this.$element.trigger("switchChange.bootstrapSwitch", [checked]); 6505 } 6506 }; 6507 })(this), 6508 "focus.bootstrapSwitch": (function(_this) { 6509 return function(e) { 6510 e.preventDefault(); 6511 return _this.$wrapper.addClass("" + _this.options.baseClass + "-focused"); 6512 }; 6513 })(this), 6514 "blur.bootstrapSwitch": (function(_this) { 6515 return function(e) { 6516 e.preventDefault(); 6517 return _this.$wrapper.removeClass("" + _this.options.baseClass + "-focused"); 6518 }; 6519 })(this), 6520 "keydown.bootstrapSwitch": (function(_this) { 6521 return function(e) { 6522 if (!e.which || _this.options.disabled || _this.options.readonly || _this.options.indeterminate) { 6523 return; 6524 } 6525 switch (e.which) { 6526 case 37: 6527 e.preventDefault(); 6528 e.stopImmediatePropagation(); 6529 return _this.state(false); 6530 case 39: 6531 e.preventDefault(); 6532 e.stopImmediatePropagation(); 6533 return _this.state(true); 6534 } 6535 }; 6536 })(this) 6537 }); 6538 }; 6539 6540 BootstrapSwitch.prototype._handleHandlers = function() { 6541 this.$on.on("click.bootstrapSwitch", (function(_this) { 6542 return function(e) { 6543 _this.state(false); 6544 return _this.$element.trigger("focus.bootstrapSwitch"); 6545 }; 6546 })(this)); 6547 return this.$off.on("click.bootstrapSwitch", (function(_this) { 6548 return function(e) { 6549 _this.state(true); 6550 return _this.$element.trigger("focus.bootstrapSwitch"); 6551 }; 6552 })(this)); 6553 }; 6554 6555 BootstrapSwitch.prototype._labelHandlers = function() { 6556 return this.$label.on({ 6557 "mousemove.bootstrapSwitch touchmove.bootstrapSwitch": (function(_this) { 6558 return function(e) { 6559 var left, pageX, percent, right; 6560 if (!_this.isLabelDragging) { 6561 return; 6562 } 6563 e.preventDefault(); 6564 _this.isLabelDragged = true; 6565 pageX = e.pageX || e.originalEvent.touches[0].pageX; 6566 percent = ((pageX - _this.$wrapper.offset().left) / _this.$wrapper.width()) * 100; 6567 left = 25; 6568 right = 75; 6569 if (_this.options.animate) { 6570 _this.$wrapper.removeClass("" + _this.options.baseClass + "-animate"); 6571 } 6572 if (percent < left) { 6573 percent = left; 6574 } else if (percent > right) { 6575 percent = right; 6576 } 6577 _this.$container.css("margin-left", "" + (percent - right) + "%"); 6578 return _this.$element.trigger("focus.bootstrapSwitch"); 6579 }; 6580 })(this), 6581 "mousedown.bootstrapSwitch touchstart.bootstrapSwitch": (function(_this) { 6582 return function(e) { 6583 if (_this.isLabelDragging || _this.options.disabled || _this.options.readonly || _this.options.indeterminate) { 6584 return; 6585 } 6586 e.preventDefault(); 6587 _this.isLabelDragging = true; 6588 return _this.$element.trigger("focus.bootstrapSwitch"); 6589 }; 6590 })(this), 6591 "mouseup.bootstrapSwitch touchend.bootstrapSwitch": (function(_this) { 6592 return function(e) { 6593 if (!_this.isLabelDragging) { 6594 return; 6595 } 6596 e.preventDefault(); 6597 if (_this.isLabelDragged) { 6598 _this.isLabelDragged = false; 6599 _this.state(parseInt(_this.$container.css("margin-left"), 10) > -(_this.$container.width() / 6)); 6600 if (_this.options.animate) { 6601 _this.$wrapper.addClass("" + _this.options.baseClass + "-animate"); 6602 } 6603 _this.$container.css("margin-left", ""); 6604 } else { 6605 _this.state(!_this.options.state); 6606 } 6607 return _this.isLabelDragging = false; 6608 }; 6609 })(this), 6610 "mouseleave.bootstrapSwitch": (function(_this) { 6611 return function(e) { 6612 return _this.$label.trigger("mouseup.bootstrapSwitch"); 6613 }; 6614 })(this) 6615 }); 6616 }; 6617 6618 BootstrapSwitch.prototype._formHandler = function() { 6619 var $form; 6620 $form = this.$element.closest("form"); 6621 if ($form.data("bootstrap-switch")) { 6622 return; 6623 } 6624 return $form.on("reset.bootstrapSwitch", function() { 6625 return window.setTimeout(function() { 6626 return $form.find("input").filter(function() { 6627 return $(this).data("bootstrap-switch"); 6628 }).each(function() { 6629 return $(this).bootstrapSwitch("state", this.checked); 6630 }); 6631 }, 1); 6632 }).data("bootstrap-switch", true); 6633 }; 6634 6635 BootstrapSwitch.prototype._getClasses = function(classes) { 6636 var c, cls, _i, _len; 6637 if (!$.isArray(classes)) { 6638 return ["" + this.options.baseClass + "-" + classes]; 6639 } 6640 cls = []; 6641 for (_i = 0, _len = classes.length; _i < _len; _i++) { 6642 c = classes[_i]; 6643 cls.push("" + this.options.baseClass + "-" + c); 6644 } 6645 return cls; 6646 }; 6647 6648 return BootstrapSwitch; 6649 6650 })(); 6651 $.fn.bootstrapSwitch = function() { 6652 var args, option, ret; 6653 option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 6654 ret = this; 6655 this.each(function() { 6656 var $this, data; 6657 $this = $(this); 6658 data = $this.data("bootstrap-switch"); 6659 if (!data) { 6660 $this.data("bootstrap-switch", data = new BootstrapSwitch(this, option)); 6661 } 6662 if (typeof option === "string") { 6663 return ret = data[option].apply(data, args); 6664 } 6665 }); 6666 return ret; 6667 }; 6668 $.fn.bootstrapSwitch.Constructor = BootstrapSwitch; 6669 return $.fn.bootstrapSwitch.defaults = { 6670 state: true, 6671 size: null, 6672 animate: true, 6673 disabled: false, 6674 readonly: false, 6675 indeterminate: false, 6676 onColor: "primary", 6677 offColor: "default", 6678 onText: "ON", 6679 offText: "OFF", 6680 labelText: " ", 6681 baseClass: "bootstrap-switch", 6682 wrapperClass: "wrapper", 6683 radioAllOff: false, 6684 onInit: function() {}, 6685 onSwitchChange: function() {} 6686 }; 6687 })(window.jQuery, window); 6688 6689 }).call(this); 6690 6691 (function ($) { 6692 "use strict"; 6693 6694 var defaultOptions = { 6695 tagClass: function(item) { 6696 return 'label label-info'; 6697 }, 6698 itemValue: function(item) { 6699 return item ? item.toString() : item; 6700 }, 6701 itemText: function(item) { 6702 return this.itemValue(item); 6703 }, 6704 freeInput: true, 6705 addOnBlur: true, 6706 maxTags: undefined, 6707 maxChars: undefined, 6708 confirmKeys: [13, 44], 6709 onTagExists: function(item, $tag) { 6710 $tag.hide().fadeIn(); 6711 }, 6712 trimValue: false, 6713 allowDuplicates: false 6714 }; 6715 6716 /** 6717 * Constructor function 6718 */ 6719 function TagsInput(element, options) { 6720 this.itemsArray = []; 6721 6722 this.$element = $(element); 6723 this.$element.hide(); 6724 6725 this.isSelect = (element.tagName === 'SELECT'); 6726 this.multiple = (this.isSelect && element.hasAttribute('multiple')); 6727 this.objectItems = options && options.itemValue; 6728 this.placeholderText = element.hasAttribute('placeholder') ? this.$element.attr('placeholder') : ''; 6729 this.inputSize = Math.max(1, this.placeholderText.length); 6730 6731 this.$container = $('<div class="bootstrap-tagsinput"></div>'); 6732 this.$input = $('<input type="text" placeholder="' + this.placeholderText + '"/>').appendTo(this.$container); 6733 6734 this.$element.after(this.$container); 6735 6736 var inputWidth = (this.inputSize < 3 ? 3 : this.inputSize) + "em"; 6737 this.$input.get(0).style.cssText = "width: " + inputWidth + " !important;"; 6738 this.build(options); 6739 } 6740 6741 TagsInput.prototype = { 6742 constructor: TagsInput, 6743 6744 /** 6745 * Adds the given item as a new tag. Pass true to dontPushVal to prevent 6746 * updating the elements val() 6747 */ 6748 add: function(item, dontPushVal) { 6749 var self = this; 6750 6751 if (self.options.maxTags && self.itemsArray.length >= self.options.maxTags) 6752 return; 6753 6754 // Ignore falsey values, except false 6755 if (item !== false && !item) 6756 return; 6757 6758 // Trim value 6759 if (typeof item === "string" && self.options.trimValue) { 6760 item = $.trim(item); 6761 } 6762 6763 // Throw an error when trying to add an object while the itemValue option was not set 6764 if (typeof item === "object" && !self.objectItems) 6765 throw("Can't add objects when itemValue option is not set"); 6766 6767 // Ignore strings only containg whitespace 6768 if (item.toString().match(/^\s*$/)) 6769 return; 6770 6771 // If SELECT but not multiple, remove current tag 6772 if (self.isSelect && !self.multiple && self.itemsArray.length > 0) 6773 self.remove(self.itemsArray[0]); 6774 6775 if (typeof item === "string" && this.$element[0].tagName === 'INPUT') { 6776 var items = item.split(','); 6777 if (items.length > 1) { 6778 for (var i = 0; i < items.length; i++) { 6779 this.add(items[i], true); 6780 } 6781 6782 if (!dontPushVal) 6783 self.pushVal(); 6784 return; 6785 } 6786 } 6787 6788 var itemValue = self.options.itemValue(item), 6789 itemText = self.options.itemText(item), 6790 tagClass = self.options.tagClass(item); 6791 6792 // Ignore items allready added 6793 var existing = $.grep(self.itemsArray, function(item) { return self.options.itemValue(item) === itemValue; } )[0]; 6794 if (existing && !self.options.allowDuplicates) { 6795 // Invoke onTagExists 6796 if (self.options.onTagExists) { 6797 var $existingTag = $(".tag", self.$container).filter(function() { return $(this).data("item") === existing; }); 6798 self.options.onTagExists(item, $existingTag); 6799 } 6800 return; 6801 } 6802 6803 // if length greater than limit 6804 if (self.items().toString().length + item.length + 1 > self.options.maxInputLength) 6805 return; 6806 6807 // raise beforeItemAdd arg 6808 var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false }); 6809 self.$element.trigger(beforeItemAddEvent); 6810 if (beforeItemAddEvent.cancel) 6811 return; 6812 6813 // register item in internal array and map 6814 self.itemsArray.push(item); 6815 6816 // add a tag element 6817 var $tag = $('<span class="tag ' + htmlEncode(tagClass) + '">' + htmlEncode(itemText) + '<span data-role="remove"></span></span>'); 6818 $tag.data('item', item); 6819 self.findInputWrapper().before($tag); 6820 $tag.after(' '); 6821 6822 // add <option /> if item represents a value not present in one of the <select />'s options 6823 if (self.isSelect && !$('option[value="' + encodeURIComponent(itemValue) + '"]',self.$element)[0]) { 6824 var $option = $('<option selected>' + htmlEncode(itemText) + '</option>'); 6825 $option.data('item', item); 6826 $option.attr('value', itemValue); 6827 self.$element.append($option); 6828 } 6829 6830 if (!dontPushVal) 6831 self.pushVal(); 6832 6833 // Add class when reached maxTags 6834 if (self.options.maxTags === self.itemsArray.length || self.items().toString().length === self.options.maxInputLength) 6835 self.$container.addClass('bootstrap-tagsinput-max'); 6836 6837 self.$element.trigger($.Event('itemAdded', { item: item })); 6838 }, 6839 6840 /** 6841 * Removes the given item. Pass true to dontPushVal to prevent updating the 6842 * elements val() 6843 */ 6844 remove: function(item, dontPushVal) { 6845 var self = this; 6846 6847 if (self.objectItems) { 6848 if (typeof item === "object") 6849 item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == self.options.itemValue(item); } ); 6850 else 6851 item = $.grep(self.itemsArray, function(other) { return self.options.itemValue(other) == item; } ); 6852 6853 item = item[item.length-1]; 6854 } 6855 6856 if (item) { 6857 var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false }); 6858 self.$element.trigger(beforeItemRemoveEvent); 6859 if (beforeItemRemoveEvent.cancel) 6860 return; 6861 6862 $('.tag', self.$container).filter(function() { return $(this).data('item') === item; }).remove(); 6863 $('option', self.$element).filter(function() { return $(this).data('item') === item; }).remove(); 6864 if($.inArray(item, self.itemsArray) !== -1) 6865 self.itemsArray.splice($.inArray(item, self.itemsArray), 1); 6866 } 6867 6868 if (!dontPushVal) 6869 self.pushVal(); 6870 6871 // Remove class when reached maxTags 6872 if (self.options.maxTags > self.itemsArray.length) 6873 self.$container.removeClass('bootstrap-tagsinput-max'); 6874 6875 self.$element.trigger($.Event('itemRemoved', { item: item })); 6876 }, 6877 6878 /** 6879 * Removes all items 6880 */ 6881 removeAll: function() { 6882 var self = this; 6883 6884 $('.tag', self.$container).remove(); 6885 $('option', self.$element).remove(); 6886 6887 while(self.itemsArray.length > 0) 6888 self.itemsArray.pop(); 6889 6890 self.pushVal(); 6891 }, 6892 6893 /** 6894 * Refreshes the tags so they match the text/value of their corresponding 6895 * item. 6896 */ 6897 refresh: function() { 6898 var self = this; 6899 $('.tag', self.$container).each(function() { 6900 var $tag = $(this), 6901 item = $tag.data('item'), 6902 itemValue = self.options.itemValue(item), 6903 itemText = self.options.itemText(item), 6904 tagClass = self.options.tagClass(item); 6905 6906 // Update tag's class and inner text 6907 $tag.attr('class', null); 6908 $tag.addClass('tag ' + htmlEncode(tagClass)); 6909 $tag.contents().filter(function() { 6910 return this.nodeType == 3; 6911 })[0].nodeValue = htmlEncode(itemText); 6912 6913 if (self.isSelect) { 6914 var option = $('option', self.$element).filter(function() { return $(this).data('item') === item; }); 6915 option.attr('value', itemValue); 6916 } 6917 }); 6918 }, 6919 6920 /** 6921 * Returns the items added as tags 6922 */ 6923 items: function() { 6924 return this.itemsArray; 6925 }, 6926 6927 /** 6928 * Assembly value by retrieving the value of each item, and set it on the 6929 * element. 6930 */ 6931 pushVal: function() { 6932 var self = this, 6933 val = $.map(self.items(), function(item) { 6934 return self.options.itemValue(item).toString(); 6935 }); 6936 6937 self.$element.val(val, true).trigger('change'); 6938 }, 6939 6940 /** 6941 * Initializes the tags input behaviour on the element 6942 */ 6943 build: function(options) { 6944 var self = this; 6945 6946 self.options = $.extend({}, defaultOptions, options); 6947 // When itemValue is set, freeInput should always be false 6948 if (self.objectItems) 6949 self.options.freeInput = false; 6950 6951 makeOptionItemFunction(self.options, 'itemValue'); 6952 makeOptionItemFunction(self.options, 'itemText'); 6953 makeOptionFunction(self.options, 'tagClass'); 6954 6955 // Typeahead Bootstrap version 2.3.2 6956 if (self.options.typeahead) { 6957 var typeahead = self.options.typeahead || {}; 6958 6959 makeOptionFunction(typeahead, 'source'); 6960 6961 self.$input.typeahead($.extend({}, typeahead, { 6962 source: function (query, process) { 6963 function processItems(items) { 6964 var texts = []; 6965 6966 for (var i = 0; i < items.length; i++) { 6967 var text = self.options.itemText(items[i]); 6968 map[text] = items[i]; 6969 texts.push(text); 6970 } 6971 process(texts); 6972 } 6973 6974 this.map = {}; 6975 var map = this.map, 6976 data = typeahead.source(query); 6977 6978 if ($.isFunction(data.success)) { 6979 // support for Angular callbacks 6980 data.success(processItems); 6981 } else if ($.isFunction(data.then)) { 6982 // support for Angular promises 6983 data.then(processItems); 6984 } else { 6985 // support for functions and jquery promises 6986 $.when(data) 6987 .then(processItems); 6988 } 6989 }, 6990 updater: function (text) { 6991 self.add(this.map[text]); 6992 }, 6993 matcher: function (text) { 6994 return (text.toLowerCase().indexOf(this.query.trim().toLowerCase()) !== -1); 6995 }, 6996 sorter: function (texts) { 6997 return texts.sort(); 6998 }, 6999 highlighter: function (text) { 7000 var regex = new RegExp( '(' + this.query + ')', 'gi' ); 7001 return text.replace( regex, "<strong>$1</strong>" ); 7002 } 7003 })); 7004 } 7005 7006 // typeahead.js 7007 if (self.options.typeaheadjs) { 7008 var typeaheadjs = self.options.typeaheadjs || {}; 7009 7010 self.$input.typeahead(null, typeaheadjs).on('typeahead:selected', $.proxy(function (obj, datum) { 7011 if (typeaheadjs.valueKey) 7012 self.add(datum[typeaheadjs.valueKey]); 7013 else 7014 self.add(datum); 7015 self.$input.typeahead('val', ''); 7016 }, self)); 7017 } 7018 7019 self.$container.on('click', $.proxy(function(event) { 7020 if (! self.$element.attr('disabled')) { 7021 self.$input.removeAttr('disabled'); 7022 } 7023 self.$input.focus(); 7024 }, self)); 7025 7026 if (self.options.addOnBlur && self.options.freeInput) { 7027 self.$input.on('focusout', $.proxy(function(event) { 7028 // HACK: only process on focusout when no typeahead opened, to 7029 // avoid adding the typeahead text as tag 7030 if ($('.typeahead, .twitter-typeahead', self.$container).length === 0) { 7031 self.add(self.$input.val()); 7032 self.$input.val(''); 7033 } 7034 }, self)); 7035 } 7036 7037 7038 self.$container.on('keydown', 'input', $.proxy(function(event) { 7039 var $input = $(event.target), 7040 $inputWrapper = self.findInputWrapper(); 7041 7042 if (self.$element.attr('disabled')) { 7043 self.$input.attr('disabled', 'disabled'); 7044 return; 7045 } 7046 7047 switch (event.which) { 7048 // BACKSPACE 7049 case 8: 7050 if (doGetCaretPosition($input[0]) === 0) { 7051 var prev = $inputWrapper.prev(); 7052 if (prev) { 7053 self.remove(prev.data('item')); 7054 } 7055 } 7056 break; 7057 7058 // DELETE 7059 case 46: 7060 if (doGetCaretPosition($input[0]) === 0) { 7061 var next = $inputWrapper.next(); 7062 if (next) { 7063 self.remove(next.data('item')); 7064 } 7065 } 7066 break; 7067 7068 // LEFT ARROW 7069 case 37: 7070 // Try to move the input before the previous tag 7071 var $prevTag = $inputWrapper.prev(); 7072 if ($input.val().length === 0 && $prevTag[0]) { 7073 $prevTag.before($inputWrapper); 7074 $input.focus(); 7075 } 7076 break; 7077 // RIGHT ARROW 7078 case 39: 7079 // Try to move the input after the next tag 7080 var $nextTag = $inputWrapper.next(); 7081 if ($input.val().length === 0 && $nextTag[0]) { 7082 $nextTag.after($inputWrapper); 7083 $input.focus(); 7084 } 7085 break; 7086 default: 7087 // ignore 7088 } 7089 7090 // Reset internal input's size 7091 var textLength = $input.val().length, 7092 wordSpace = Math.ceil(textLength / 5), 7093 size = textLength + wordSpace + 1; 7094 $input.attr('size', Math.max(this.inputSize, $input.val().length)); 7095 }, self)); 7096 7097 self.$container.on('keypress', 'input', $.proxy(function(event) { 7098 var $input = $(event.target); 7099 7100 if (self.$element.attr('disabled')) { 7101 self.$input.attr('disabled', 'disabled'); 7102 return; 7103 } 7104 7105 var text = $input.val(), 7106 maxLengthReached = self.options.maxChars && text.length >= self.options.maxChars; 7107 if (self.options.freeInput && (keyCombinationInList(event, self.options.confirmKeys) || maxLengthReached)) { 7108 self.add(maxLengthReached ? text.substr(0, self.options.maxChars) : text); 7109 $input.val(''); 7110 event.preventDefault(); 7111 } 7112 7113 // Reset internal input's size 7114 var textLength = $input.val().length, 7115 wordSpace = Math.ceil(textLength / 5), 7116 size = textLength + wordSpace + 1; 7117 $input.attr('size', Math.max(this.inputSize, $input.val().length)); 7118 }, self)); 7119 7120 // Remove icon clicked 7121 self.$container.on('click', '[data-role=remove]', $.proxy(function(event) { 7122 if (self.$element.attr('disabled')) { 7123 return; 7124 } 7125 self.remove($(event.target).closest('.tag').data('item')); 7126 }, self)); 7127 7128 // Only add existing value as tags when using strings as tags 7129 if (self.options.itemValue === defaultOptions.itemValue) { 7130 if (self.$element[0].tagName === 'INPUT') { 7131 self.add(self.$element.val()); 7132 } else { 7133 $('option', self.$element).each(function() { 7134 self.add($(this).attr('value'), true); 7135 }); 7136 } 7137 } 7138 }, 7139 7140 /** 7141 * Removes all tagsinput behaviour and unregsiter all event handlers 7142 */ 7143 destroy: function() { 7144 var self = this; 7145 7146 // Unbind events 7147 self.$container.off('keypress', 'input'); 7148 self.$container.off('click', '[role=remove]'); 7149 7150 self.$container.remove(); 7151 self.$element.removeData('tagsinput'); 7152 self.$element.show(); 7153 }, 7154 7155 /** 7156 * Sets focus on the tagsinput 7157 */ 7158 focus: function() { 7159 this.$input.focus(); 7160 }, 7161 7162 /** 7163 * Returns the internal input element 7164 */ 7165 input: function() { 7166 return this.$input; 7167 }, 7168 7169 /** 7170 * Returns the element which is wrapped around the internal input. This 7171 * is normally the $container, but typeahead.js moves the $input element. 7172 */ 7173 findInputWrapper: function() { 7174 var elt = this.$input[0], 7175 container = this.$container[0]; 7176 while(elt && elt.parentNode !== container) 7177 elt = elt.parentNode; 7178 7179 return $(elt); 7180 } 7181 }; 7182 7183 /** 7184 * Register JQuery plugin 7185 */ 7186 $.fn.tagsinput = function(arg1, arg2) { 7187 var results = []; 7188 7189 this.each(function() { 7190 var tagsinput = $(this).data('tagsinput'); 7191 // Initialize a new tags input 7192 if (!tagsinput) { 7193 tagsinput = new TagsInput(this, arg1); 7194 $(this).data('tagsinput', tagsinput); 7195 results.push(tagsinput); 7196 7197 if (this.tagName === 'SELECT') { 7198 $('option', $(this)).attr('selected', 'selected'); 7199 } 7200 7201 // Init tags from $(this).val() 7202 $(this).val($(this).val()); 7203 } else if (!arg1 && !arg2) { 7204 // tagsinput already exists 7205 // no function, trying to init 7206 results.push(tagsinput); 7207 } else if(tagsinput[arg1] !== undefined) { 7208 // Invoke function on existing tags input 7209 var retVal = tagsinput[arg1](arg2); 7210 if (retVal !== undefined) 7211 results.push(retVal); 7212 } 7213 }); 7214 7215 if ( typeof arg1 == 'string') { 7216 // Return the results from the invoked function calls 7217 return results.length > 1 ? results : results[0]; 7218 } else { 7219 return results; 7220 } 7221 }; 7222 7223 $.fn.tagsinput.Constructor = TagsInput; 7224 7225 /** 7226 * Most options support both a string or number as well as a function as 7227 * option value. This function makes sure that the option with the given 7228 * key in the given options is wrapped in a function 7229 */ 7230 function makeOptionItemFunction(options, key) { 7231 if (typeof options[key] !== 'function') { 7232 var propertyName = options[key]; 7233 options[key] = function(item) { return item[propertyName]; }; 7234 } 7235 } 7236 function makeOptionFunction(options, key) { 7237 if (typeof options[key] !== 'function') { 7238 var value = options[key]; 7239 options[key] = function() { return value; }; 7240 } 7241 } 7242 /** 7243 * HtmlEncodes the given value 7244 */ 7245 var htmlEncodeContainer = $('<div />'); 7246 function htmlEncode(value) { 7247 if (value) { 7248 return htmlEncodeContainer.text(value).html(); 7249 } else { 7250 return ''; 7251 } 7252 } 7253 7254 /** 7255 * Returns the position of the caret in the given input field 7256 * http://flightschool.acylt.com/devnotes/caret-position-woes/ 7257 */ 7258 function doGetCaretPosition(oField) { 7259 var iCaretPos = 0; 7260 if (document.selection) { 7261 oField.focus (); 7262 var oSel = document.selection.createRange(); 7263 oSel.moveStart ('character', -oField.value.length); 7264 iCaretPos = oSel.text.length; 7265 } else if (oField.selectionStart || oField.selectionStart == '0') { 7266 iCaretPos = oField.selectionStart; 7267 } 7268 return (iCaretPos); 7269 } 7270 7271 /** 7272 * Returns boolean indicates whether user has pressed an expected key combination. 7273 * @param object keyPressEvent: JavaScript event object, refer 7274 * http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 7275 * @param object lookupList: expected key combinations, as in: 7276 * [13, {which: 188, shiftKey: true}] 7277 */ 7278 function keyCombinationInList(keyPressEvent, lookupList) { 7279 var found = false; 7280 $.each(lookupList, function (index, keyCombination) { 7281 if (typeof (keyCombination) === 'number' && keyPressEvent.which === keyCombination) { 7282 found = true; 7283 return false; 7284 } 7285 7286 if (keyPressEvent.which === keyCombination.which) { 7287 var alt = !keyCombination.hasOwnProperty('altKey') || keyPressEvent.altKey === keyCombination.altKey, 7288 shift = !keyCombination.hasOwnProperty('shiftKey') || keyPressEvent.shiftKey === keyCombination.shiftKey, 7289 ctrl = !keyCombination.hasOwnProperty('ctrlKey') || keyPressEvent.ctrlKey === keyCombination.ctrlKey; 7290 if (alt && shift && ctrl) { 7291 found = true; 7292 return false; 7293 } 7294 } 7295 }); 7296 7297 return found; 7298 } 7299 7300 /** 7301 * Initialize tagsinput behaviour on inputs and selects which have 7302 * data-role=tagsinput 7303 */ 7304 $(function() { 7305 $("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput(); 7306 }); 7307 })(window.jQuery); 7308 7309 /*! 7310 7311 Holder - client side image placeholders 7312 Version 2.4.0+bxlim 7313 © 2014 Ivan Malopinsky - http://imsky.co 7314 7315 Site: http://imsky.github.io/holder 7316 Issues: https://github.com/imsky/holder/issues 7317 License: http://opensource.org/licenses/MIT 7318 7319 */ 7320 !function(e,t,r){t[e]=r}("onDomReady",this,function(e){"use strict";function t(e){if(!b){if(!a.body)return i(t);for(b=!0;e=S.shift();)i(e)}}function r(e){(y||e.type===s||a[c]===u)&&(n(),t())}function n(){y?(a[x](m,r,d),e[x](s,r,d)):(a[g](v,r),e[g](h,r))}function i(e,t){setTimeout(e,+t>=0?t:1)}function o(e){b?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function E(){document.removeEventListener("DOMContentLoaded",E,!1),document.readyState="complete"},!1),document.readyState="loading");var a=e.document,l=a.documentElement,s="load",d=!1,h="on"+s,u="complete",c="readyState",f="attachEvent",g="detachEvent",p="addEventListener",m="DOMContentLoaded",v="onreadystatechange",x="removeEventListener",y=p in a,w=d,b=d,S=[];if(a[c]===u)i(t);else if(y)a[p](m,r,d),e[p](s,r,d);else{a[f](v,r),e[f](h,r);try{w=null==e.frameElement&&l}catch(C){}w&&w.doScroll&&!function k(){if(!b){try{w.doScroll("left")}catch(e){return i(k,50)}n(),t()}}()}return o.version="1.4.0",o.isReady=function(){return b},o}(this)),document.querySelectorAll||(document.querySelectorAll=function(e){var t,r=document.createElement("style"),n=[];for(document.documentElement.firstChild.appendChild(r),document._qsa=[],r.styleSheet.cssText=e+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",window.scrollBy(0,0),r.parentNode.removeChild(r);document._qsa.length;)t=document._qsa.shift(),t.style.removeAttribute("x-qsa"),n.push(t);return document._qsa=null,n}),document.querySelector||(document.querySelector=function(e){var t=document.querySelectorAll(e);return t.length?t[0]:null}),document.getElementsByClassName||(document.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),document.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,r=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&r.push(t);return r}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var r,n=0,i=[],o=0,a=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;n<e.length;)r=t.indexOf(e.charAt(n)),o=o<<6|r,a+=6,24===a&&(i.push(String.fromCharCode(o>>16&255)),i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o)),a=0,o=0),n+=1;return 12===a?(o>>=4,i.push(String.fromCharCode(255&o))):18===a&&(o>>=2,i.push(String.fromCharCode(o>>8&255)),i.push(String.fromCharCode(255&o))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var r,n,i,o,a,l,s,d=0,h=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;d<e.length;)r=e.charCodeAt(d++),n=e.charCodeAt(d++),i=e.charCodeAt(d++),o=r>>2,a=(3&r)<<4|n>>4,l=(15&n)<<2|i>>6,s=63&i,d===e.length+2?(l=64,s=64):d===e.length+1&&(s=64),h.push(t.charAt(o),t.charAt(a),t.charAt(l),t.charAt(s));return h.join("")}}(this),function(){function e(t,r,n){t.document;var i,o=t.currentStyle[r].match(/([\d\.]+)(%|cm|em|in|mm|pc|pt|)/)||[0,0,""],a=o[1],l=o[2];return n=n?/%|em/.test(l)&&t.parentElement?e(t.parentElement,"fontSize",null):16:n,i="fontSize"==r?n:/width/i.test(r)?t.clientWidth:t.clientHeight,"%"==l?a/100*i:"cm"==l?.3937*a*96:"em"==l?a*n:"in"==l?96*a:"mm"==l?.3937*a*96/10:"pc"==l?12*a*96/72:"pt"==l?96*a/72:a}function t(e,t){var r="border"==t?"Width":"",n=t+"Top"+r,i=t+"Right"+r,o=t+"Bottom"+r,a=t+"Left"+r;e[t]=(e[n]==e[i]&&e[n]==e[o]&&e[n]==e[a]?[e[n]]:e[n]==e[o]&&e[a]==e[i]?[e[n],e[i]]:e[a]==e[i]?[e[n],e[i],e[o]]:[e[n],e[i],e[o],e[a]]).join(" ")}function r(r){var n,i=this,o=r.currentStyle,a=e(r,"fontSize"),l=function(e){return"-"+e.toLowerCase()};for(n in o)if(Array.prototype.push.call(i,"styleFloat"==n?"float":n.replace(/[A-Z]/,l)),"width"==n)i[n]=r.offsetWidth+"px";else if("height"==n)i[n]=r.offsetHeight+"px";else if("styleFloat"==n)i.float=o[n];else if(/margin.|padding.|border.+W/.test(n)&&"auto"!=i[n])i[n]=Math.round(e(r,n,a))+"px";else if(/^outline/.test(n))try{i[n]=o[n]}catch(s){i.outlineColor=o.color,i.outlineStyle=i.outlineStyle||"none",i.outlineWidth=i.outlineWidth||"0px",i.outline=[i.outlineColor,i.outlineWidth,i.outlineStyle].join(" ")}else i[n]=o[n];t(i,"margin"),t(i,"padding"),t(i,"border"),i.fontSize=Math.round(a)+"px"}window.getComputedStyle||(r.prototype={constructor:r,getPropertyPriority:function(){throw new Error("NotSupportedError: DOM Exception 9")},getPropertyValue:function(e){return this[e.replace(/-\w/g,function(e){return e[1].toUpperCase()})]},item:function(e){return this[e]},removeProperty:function(){throw new Error("NoModificationAllowedError: DOM Exception 7")},setProperty:function(){throw new Error("NoModificationAllowedError: DOM Exception 7")},getPropertyCSSValue:function(){throw new Error("NotSupportedError: DOM Exception 9")}},window.getComputedStyle=Window.prototype.getComputedStyle=function(e){return new r(e)})}(),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(e,t){e.augment=t()}(this,function(){"use strict";var e=function(){},t=Array.prototype.slice,r=function(r,n){var i=e.prototype="function"==typeof r?r.prototype:r,o=new e,a=n.apply(o,t.call(arguments,2).concat(i));if("object"==typeof a)for(var l in a)o[l]=a[l];if(!o.hasOwnProperty("constructor"))return o;var s=o.constructor;return s.prototype=o,s};return r.defclass=function(e){var t=e.constructor;return t.prototype=e,t},r.extend=function(e,t){return r(e,function(e){return this.uber=e,t})},r}),function(e,t){function r(e,t,r,o){var a=n(r.substr(r.lastIndexOf(e.domain)),e);a&&i(null,o,a,t)}function n(e,t){for(var r={theme:p(A.settings.themes.gray,null),stylesheets:t.stylesheets,holderURL:[]},n=!1,i=String.fromCharCode(11),o=e.replace(/([^\\])\//g,"$1"+i).split(i),a=/%[0-9a-f]{2}/gi,l=o.length,s=0;l>s;s++){var d=o[s];if(d.match(a))try{d=decodeURIComponent(d)}catch(h){d=o[s]}var u=!1;if(A.flags.dimensions.match(d))n=!0,r.dimensions=A.flags.dimensions.output(d),u=!0;else if(A.flags.fluid.match(d))n=!0,r.dimensions=A.flags.fluid.output(d),r.fluid=!0,u=!0;else if(A.flags.textmode.match(d))r.textmode=A.flags.textmode.output(d),u=!0;else if(A.flags.colors.match(d)){var c=A.flags.colors.output(d);r.theme=p(r.theme,c),u=!0}else if(t.themes[d])t.themes.hasOwnProperty(d)&&(r.theme=p(t.themes[d],null)),u=!0;else if(A.flags.font.match(d))r.font=A.flags.font.output(d),u=!0;else if(A.flags.auto.match(d))r.auto=!0,u=!0;else if(A.flags.text.match(d))r.text=A.flags.text.output(d),u=!0;else if(A.flags.random.match(d)){null==A.vars.cache.themeKeys&&(A.vars.cache.themeKeys=Object.keys(t.themes));var f=A.vars.cache.themeKeys[0|Math.random()*A.vars.cache.themeKeys.length];r.theme=p(t.themes[f],null),u=!0}u&&r.holderURL.push(d)}return r.holderURL.unshift(t.domain),r.holderURL=r.holderURL.join("/"),n?r:!1}function i(e,t,r,n){var i=r.dimensions,a=r.theme,l=i.width+"x"+i.height;if(e=null==e?r.fluid?"fluid":"image":e,null!=r.text&&(a.text=r.text,"object"===t.nodeName.toLowerCase())){for(var d=a.text.split("\\n"),u=0;u<d.length;u++)d[u]=b(d[u]);a.text=d.join("\\n")}var f=r.holderURL,g=p(n,null);r.font&&(a.font=r.font,!g.noFontFallback&&"img"===t.nodeName.toLowerCase()&&A.setup.supportsCanvas&&"svg"===g.renderer&&(g=p(g,{renderer:"canvas"}))),r.font&&"canvas"==g.renderer&&(g.reRender=!0),"background"==e?null==t.getAttribute("data-background-src")&&c(t,{"data-background-src":f}):c(t,{"data-src":f}),r.theme=a,t.holderData={flags:r,renderSettings:g},("image"==e||"fluid"==e)&&c(t,{alt:a.text?(a.text.length>16?a.text.substring(0,16)+"…":a.text)+" ["+l+"]":l}),"image"==e?("html"!=g.renderer&&r.auto||(t.style.width=i.width+"px",t.style.height=i.height+"px"),"html"==g.renderer?t.style.backgroundColor=a.background:(o(e,{dimensions:i,theme:a,flags:r},t,g),r.textmode&&"exact"==r.textmode&&(A.vars.resizableImages.push(t),s(t)))):"background"==e&&"html"!=g.renderer?o(e,{dimensions:i,theme:a,flags:r},t,g):"fluid"==e&&("%"==i.height.slice(-1)?t.style.height=i.height:null!=r.auto&&r.auto||(t.style.height=i.height+"px"),"%"==i.width.slice(-1)?t.style.width=i.width:null!=r.auto&&r.auto||(t.style.width=i.width+"px"),("inline"==t.style.display||""===t.style.display||"none"==t.style.display)&&(t.style.display="block"),h(t),"html"==g.renderer?t.style.backgroundColor=a.background:(A.vars.resizableImages.push(t),s(t)))}function o(e,t,r,n){function i(){var e=null;switch(n.renderer){case"canvas":e=L(s);break;case"svg":e=O(s,n);break;default:throw"Holder: invalid renderer: "+n.renderer}return e}var o=null;switch(n.renderer){case"svg":if(!A.setup.supportsSVG)return;break;case"canvas":if(!A.setup.supportsCanvas)return;break;default:return}{var l={width:t.dimensions.width,height:t.dimensions.height,theme:t.theme,flags:t.flags},s=a(l);({text:l.text,width:l.width,height:l.height,textHeight:l.font.size,font:l.font.family,fontWeight:l.font.weight,template:l.theme})}if(o=i(),null==o)throw"Holder: couldn't render placeholder";"background"==e?(r.style.backgroundImage="url("+o+")",r.style.backgroundSize=l.width+"px "+l.height+"px"):("img"===r.nodeName.toLowerCase()?c(r,{src:o}):"object"===r.nodeName.toLowerCase()&&(c(r,{data:o}),c(r,{type:"image/svg+xml"})),n.reRender&&setTimeout(function(){var e=i();if(null==e)throw"Holder: couldn't render placeholder";"img"===r.nodeName.toLowerCase()?c(r,{src:e}):"object"===r.nodeName.toLowerCase()&&(c(r,{data:e}),c(r,{type:"image/svg+xml"}))},100)),c(r,{"data-holder-rendered":!0})}function a(e){function t(e,t,r,n){t.width=r,t.height=n,e.width=Math.max(e.width,t.width),e.height+=t.height,e.add(t)}switch(e.font={family:e.theme.font?e.theme.font:"Arial, Helvetica, Open Sans, sans-serif",size:l(e.width,e.height,e.theme.size?e.theme.size:12),weight:e.theme.fontweight?e.theme.fontweight:"bold"},e.text=e.theme.text?e.theme.text:Math.floor(e.width)+"x"+Math.floor(e.height),e.flags.textmode){case"literal":e.text=e.flags.dimensions.width+"x"+e.flags.dimensions.height;break;case"exact":if(!e.flags.exactDimensions)break;e.text=Math.floor(e.flags.exactDimensions.width)+"x"+Math.floor(e.flags.exactDimensions.height)}var r=new F({width:e.width,height:e.height}),n=r.Shape,i=new n.Rect("holderBg",{fill:e.theme.background});i.resize(e.width,e.height),r.root.add(i);var o=new n.Group("holderTextGroup",{text:e.text,align:"center",font:e.font,fill:e.theme.foreground});o.moveTo(null,null,1),r.root.add(o);var a=o.textPositionData=T(r);if(!a)throw"Holder: staging fallback not supported yet.";o.properties.leading=a.boundingBox.height;var s=null,d=null;if(a.lineCount>1){var h=0,u=0,c=e.width*A.setup.lineWrapRatio,f=0;d=new n.Group("line"+f);for(var g=0;g<a.words.length;g++){var p=a.words[g];s=new n.Text(p.text);var m="\\n"==p.text;(h+p.width>=c||m===!0)&&(t(o,d,h,o.properties.leading),h=0,u+=o.properties.leading,f+=1,d=new n.Group("line"+f),d.y=u),m!==!0&&(s.moveTo(h,0),h+=a.spaceWidth+p.width,d.add(s))}t(o,d,h,o.properties.leading);for(var v in o.children)d=o.children[v],d.moveTo((o.width-d.width)/2,null,null);o.moveTo((e.width-o.width)/2,(e.height-o.height)/2,null),(e.height-o.height)/2<0&&o.moveTo(null,0,null)}else s=new n.Text(e.text),d=new n.Group("line0"),d.add(s),o.add(d),o.moveTo((e.width-a.boundingBox.width)/2,(e.height-a.boundingBox.height)/2,null);return r}function l(e,t,r){t=parseInt(t,10),e=parseInt(e,10);var n=Math.max(t,e),i=Math.min(t,e),o=1/12,a=Math.min(.75*i,.75*n*o);return Math.round(Math.max(r,a))}function s(e){var t;t=null==e||null==e.nodeType?A.vars.resizableImages:[e];for(var r in t)if(t.hasOwnProperty(r)){var n=t[r];if(n.holderData){var i=n.holderData.flags,a=d(n,k.invisibleErrorFn(s));if(a){if(i.fluid&&i.auto){var l=n.holderData.fluidConfig;switch(l.mode){case"width":a.height=a.width/l.ratio;break;case"height":a.width=a.height*l.ratio}}var h={dimensions:a,theme:i.theme,flags:i};i.textmode&&"exact"==i.textmode&&(i.exactDimensions=a,h.dimensions=i.dimensions),o("image",h,n,n.holderData.renderSettings)}}}}function d(e,t){var r={height:e.clientHeight,width:e.clientWidth};return r.height||r.width?(e.removeAttribute("data-holder-invisible"),r):(c(e,{"data-holder-invisible":!0}),void t.call(this,e))}function h(e){if(e.holderData){var t=d(e,k.invisibleErrorFn(h));if(t){var r=e.holderData.flags,n={fluidHeight:"%"==r.dimensions.height.slice(-1),fluidWidth:"%"==r.dimensions.width.slice(-1),mode:null,initialDimensions:t};n.fluidWidth&&!n.fluidHeight?(n.mode="width",n.ratio=n.initialDimensions.width/parseFloat(r.dimensions.height)):!n.fluidWidth&&n.fluidHeight&&(n.mode="height",n.ratio=parseFloat(r.dimensions.width)/n.initialDimensions.height),e.holderData.fluidConfig=n}}}function u(e,t){return null==t?E.createElement(e):E.createElementNS(t,e)}function c(e,t){for(var r in t)e.setAttribute(r,t[r])}function f(e,t,r){if(null==e){e=u("svg",C);var n=u("defs",C);e.appendChild(n)}return e.webkitMatchesSelector&&e.setAttribute("xmlns",C),c(e,{width:t,height:r,viewBox:"0 0 "+t+" "+r,preserveAspectRatio:"none"}),e}function g(e,r){if(t.XMLSerializer){{var n=new XMLSerializer,i="",o=r.stylesheets;e.querySelector("defs")}if(r.svgXMLStylesheet){for(var a=(new DOMParser).parseFromString("<xml />","application/xml"),l=o.length-1;l>=0;l--){var s=a.createProcessingInstruction("xml-stylesheet",'href="'+o[l]+'" rel="stylesheet"');a.insertBefore(s,a.firstChild)}var d=a.createProcessingInstruction("xml",'version="1.0" encoding="UTF-8" standalone="yes"');a.insertBefore(d,a.firstChild),a.removeChild(a.documentElement),i=n.serializeToString(a)}var h=n.serializeToString(e);return h=h.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),i+h}}function p(e,t){var r={};for(var n in e)e.hasOwnProperty(n)&&(r[n]=e[n]);if(null!=t)for(var i in t)t.hasOwnProperty(i)&&(r[i]=t[i]);return r}function m(e){var t=[];for(var r in e)e.hasOwnProperty(r)&&t.push(r+":"+e[r]);return t.join(";")}function v(e){A.vars.debounceTimer||e.call(this),A.vars.debounceTimer&&clearTimeout(A.vars.debounceTimer),A.vars.debounceTimer=setTimeout(function(){A.vars.debounceTimer=null,e.call(this)},A.setup.debounce)}function x(){v(function(){s(null)})}function y(e){var r=null;return"string"==typeof e?r=E.querySelectorAll(e):t.NodeList&&e instanceof t.NodeList?r=e:t.Node&&e instanceof t.Node?r=[e]:t.HTMLCollection&&e instanceof t.HTMLCollection?r=e:null===e&&(r=[]),r}function w(e,t){var r=new Image;r.onerror=function(){t.call(this,!1,e)},r.onload=function(){t.call(this,!0,e)},r.src=e.src}function b(e){for(var t=[],r=0,n=e.length-1;n>=0;n--)r=e[n].charCodeAt(),t.unshift(r>128?["&#",r,";"].join(""):e[n]);return t.join("")}function S(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})}var C="http://www.w3.org/2000/svg",E=t.document,k={addTheme:function(e,t){return null!=e&&null!=t&&(A.settings.themes[e]=t),delete A.vars.cache.themeKeys,this},addImage:function(e,t){var r=E.querySelectorAll(t);if(r.length)for(var n=0,i=r.length;i>n;n++){var o=u("img");c(o,{"data-src":e}),r[n].appendChild(o)}return this},run:function(e){e=e||{};var o={};A.vars.preempted=!0;var a=p(A.settings,e);o.renderer=a.renderer?a.renderer:A.setup.renderer,-1===A.setup.renderers.join(",").indexOf(o.renderer)&&(o.renderer=A.setup.supportsSVG?"svg":A.setup.supportsCanvas?"canvas":"html"),a.use_canvas?o.renderer="canvas":a.use_svg&&(o.renderer="svg");var l=y(a.images),s=y(a.bgnodes),d=y(a.stylenodes),h=y(a.objects);o.stylesheets=[],o.svgXMLStylesheet=!0,o.noFontFallback=a.noFontFallback?a.noFontFallback:!1;for(var c=0;c<d.length;c++){var f=d[c];if(f.attributes.rel&&f.attributes.href&&"stylesheet"==f.attributes.rel.value){var g=f.attributes.href.value,m=u("a");m.href=g;var v=m.protocol+"//"+m.host+m.pathname+m.search;o.stylesheets.push(v)}}for(c=0;c<s.length;c++){var x=t.getComputedStyle(s[c],null).getPropertyValue("background-image"),b=s[c].getAttribute("data-background-src"),S=null;S=null==b?x:b;var C=null,E="?"+a.domain+"/";if(0===S.indexOf(E))C=S.slice(1);else if(-1!=S.indexOf(E)){var k=S.substr(S.indexOf(E)).slice(1),T=k.match(/([^\"]*)"?\)/);null!=T&&(C=T[1])}if(null!=C){var L=n(C,a);L&&i("background",s[c],L,o)}}for(c=0;c<h.length;c++){var O=h[c],F={};try{F.data=O.getAttribute("data"),F.dataSrc=O.getAttribute("data-src")}catch(z){}var M=null!=F.data&&0===F.data.indexOf(a.domain),D=null!=F.dataSrc&&0===F.dataSrc.indexOf(a.domain);M?r(a,o,F.data,O):D&&r(a,o,F.dataSrc,O)}for(c=0;c<l.length;c++){var R=l[c],j={};try{j.src=R.getAttribute("src"),j.dataSrc=R.getAttribute("data-src"),j.rendered=R.getAttribute("data-holder-rendered")}catch(z){}var B=null!=j.src,P=null!=j.dataSrc&&0===j.dataSrc.indexOf(a.domain),N=null!=j.rendered&&"true"==j.rendered;B?0===j.src.indexOf(a.domain)?r(a,o,j.src,R):P&&(N?r(a,o,j.dataSrc,R):w({src:j.src,options:a,renderSettings:o,dataSrc:j.dataSrc,image:R},function(e,t){e||r(t.options,t.renderSettings,t.dataSrc,t.image)})):P&&r(a,o,j.dataSrc,R)}return this},invisibleErrorFn:function(){return function(e){if(e.hasAttribute("data-holder-invisible"))throw"Holder: invisible placeholder"}}};k.add_theme=k.addTheme,k.add_image=k.addImage,k.invisible_error_fn=k.invisibleErrorFn;var A={settings:{domain:"holder.js",images:"img",objects:"object",bgnodes:"body .holderjs",stylenodes:"head link.holderjs",stylesheets:[],themes:{gray:{background:"#EEEEEE",foreground:"#AAAAAA"},social:{background:"#3a5a97",foreground:"#FFFFFF"},industrial:{background:"#434A52",foreground:"#C2F200"},sky:{background:"#0D8FDB",foreground:"#FFFFFF"},vine:{background:"#39DBAC",foreground:"#1E292C"},lava:{background:"#F8591A",foreground:"#1C2846",size:12}}},flags:{dimensions:{regex:/^(\d+)x(\d+)$/,output:function(e){var t=this.regex.exec(e);return{width:+t[1],height:+t[2]}}},fluid:{regex:/^([0-9]+%?)x([0-9]+%?)$/,output:function(e){var t=this.regex.exec(e);return{width:t[1],height:t[2]}}},colors:{regex:/(?:#|\^)([0-9a-f]{3,})\:(?:#|\^)([0-9a-f]{3,})/i,output:function(e){var t=this.regex.exec(e);return{foreground:"#"+t[2],background:"#"+t[1]}}},text:{regex:/text\:(.*)/,output:function(e){return this.regex.exec(e)[1].replace("\\/","/")}},font:{regex:/font\:(.*)/,output:function(e){return this.regex.exec(e)[1]}},auto:{regex:/^auto$/},textmode:{regex:/textmode\:(.*)/,output:function(e){return this.regex.exec(e)[1]}},random:{regex:/^random$/}}},T=function(){var e=null,t=null,r=null;return function(n){var i=n.root;if(A.setup.supportsSVG){var o=!1,a=function(e){return E.createTextNode(e)};null==e&&(o=!0),e=f(e,i.properties.width,i.properties.height),o&&(t=u("text",C),r=a(null),c(t,{x:0}),t.appendChild(r),e.appendChild(t),E.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var l=i.children.holderTextGroup,s=l.properties;c(t,{y:s.font.size,style:m({"font-weight":s.font.weight,"font-size":s.font.size+"px","font-family":s.font.family,"dominant-baseline":"middle"})}),r.nodeValue=s.text;var d=t.getBBox(),h=Math.ceil(d.width/(i.properties.width*A.setup.lineWrapRatio)),g=s.text.split(" "),p=s.text.match(/\\n/g);h+=null==p?0:p.length,r.nodeValue=s.text.replace(/[ ]+/g,"");var v=t.getComputedTextLength(),x=d.width-v,y=Math.round(x/Math.max(1,g.length-1)),w=[];if(h>1){r.nodeValue="";for(var b=0;b<g.length;b++)if(0!==g[b].length){r.nodeValue=S(g[b]);var k=t.getBBox();w.push({text:g[b],width:k.width})}}return{spaceWidth:y,lineCount:h,boundingBox:d,words:w}}return!1}}(),L=function(){var e=u("canvas"),t=null;return function(r){null==t&&(t=e.getContext("2d"));var n=r.root;e.width=A.dpr(n.properties.width),e.height=A.dpr(n.properties.height),t.textBaseline="middle",t.fillStyle=n.children.holderBg.properties.fill,t.fillRect(0,0,A.dpr(n.children.holderBg.width),A.dpr(n.children.holderBg.height));{var i=n.children.holderTextGroup;i.properties}t.font=i.properties.font.weight+" "+A.dpr(i.properties.font.size)+"px "+i.properties.font.family+", monospace",t.fillStyle=i.properties.fill;for(var o in i.children){var a=i.children[o];for(var l in a.children){var s=a.children[l],d=A.dpr(i.x+a.x+s.x),h=A.dpr(i.y+a.y+s.y+i.properties.leading/2);t.fillText(s.properties.text,d,h)}}return e.toDataURL("image/png")}}(),O=function(){if(t.XMLSerializer){var e=f(null,0,0),r=u("rect",C);return e.appendChild(r),function(t,n){var i=t.root;f(e,i.properties.width,i.properties.height);for(var o=e.querySelectorAll("g"),a=0;a<o.length;a++)o[a].parentNode.removeChild(o[a]);c(r,{width:i.children.holderBg.width,height:i.children.holderBg.height,fill:i.children.holderBg.properties.fill});var l=i.children.holderTextGroup,s=l.properties,d=u("g",C);e.appendChild(d);for(var h in l.children){var p=l.children[h];for(var v in p.children){var x=p.children[v],y=l.x+p.x+x.x,w=l.y+p.y+x.y+l.properties.leading/2,b=u("text",C),S=E.createTextNode(null);c(b,{x:y,y:w,style:m({fill:s.fill,"font-weight":s.font.weight,"font-family":s.font.family+", monospace","font-size":s.font.size+"px","dominant-baseline":"central"})}),S.nodeValue=x.properties.text,b.appendChild(S),d.appendChild(b)}}var k="data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(g(e,n))));return k}}}(),F=function(e){function t(e,t){for(var r in t)e[r]=t[r];return e}var r=1,n=augment.defclass({constructor:function(e){r++,this.parent=null,this.children={},this.id=r,this.name="n"+r,null!=e&&(this.name=e),this.x=0,this.y=0,this.z=0,this.width=0,this.height=0},resize:function(e,t){null!=e&&(this.width=e),null!=t&&(this.height=t)},moveTo:function(e,t,r){this.x=null!=e?e:this.x,this.y=null!=t?t:this.y,this.z=null!=r?r:this.z},add:function(e){var t=e.name;if(null!=this.children[t])throw"SceneGraph: child with that name already exists: "+t;this.children[t]=e,e.parent=this}}),i=augment(n,function(t){this.constructor=function(){t.constructor.call(this,"root"),this.properties=e}}),o=augment(n,function(e){function r(r,n){if(e.constructor.call(this,r),this.properties={fill:"#000"},null!=n)t(this.properties,n);else if(null!=r&&"string"!=typeof r)throw"SceneGraph: invalid node name"}this.Group=augment.extend(this,{constructor:r,type:"group"}),this.Rect=augment.extend(this,{constructor:r,type:"rect"}),this.Text=augment.extend(this,{constructor:function(e){r.call(this),this.properties.text=e},type:"text"})}),a=new i;return this.Shape=o,this.root=a,this};for(var z in A.flags)A.flags.hasOwnProperty(z)&&(A.flags[z].match=function(e){return e.match(this.regex)});A.setup={renderer:"html",debounce:100,ratio:1,supportsCanvas:!1,supportsSVG:!1,lineWrapRatio:.9,renderers:["html","canvas","svg"]},A.dpr=function(e){return e*A.setup.ratio},A.vars={preempted:!1,resizableImages:[],debounceTimer:null,cache:{}},function(){var e=1,r=1,n=u("canvas"),i=null;n.getContext&&-1!=n.toDataURL("image/png").indexOf("data:image/png")&&(A.setup.renderer="canvas",i=n.getContext("2d"),A.setup.supportsCanvas=!0),A.setup.supportsCanvas&&(e=t.devicePixelRatio||1,r=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1),A.setup.ratio=e/r,E.createElementNS&&E.createElementNS(C,"svg").createSVGRect&&(A.setup.renderer="svg",A.setup.supportsSVG=!0)}(),e(k,"Holder",t),t.onDomReady&&t.onDomReady(function(){A.vars.preempted||k.run(),t.addEventListener?(t.addEventListener("resize",x,!1),t.addEventListener("orientationchange",x,!1)):t.attachEvent("onresize",x),"object"==typeof t.Turbolinks&&t.document.addEventListener("page:change",function(){k.run()})})}(function(e,t,r){var n="function"==typeof define&&define.amd;n?define(e):r[t]=e},this); 7321 /*! 7322 * typeahead.js 0.10.5 7323 * https://github.com/twitter/typeahead.js 7324 * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT 7325 */ 7326 7327 (function($) { 7328 var _ = function() { 7329 "use strict"; 7330 return { 7331 isMsie: function() { 7332 return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; 7333 }, 7334 isBlankString: function(str) { 7335 return !str || /^\s*$/.test(str); 7336 }, 7337 escapeRegExChars: function(str) { 7338 return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 7339 }, 7340 isString: function(obj) { 7341 return typeof obj === "string"; 7342 }, 7343 isNumber: function(obj) { 7344 return typeof obj === "number"; 7345 }, 7346 isArray: $.isArray, 7347 isFunction: $.isFunction, 7348 isObject: $.isPlainObject, 7349 isUndefined: function(obj) { 7350 return typeof obj === "undefined"; 7351 }, 7352 toStr: function toStr(s) { 7353 return _.isUndefined(s) || s === null ? "" : s + ""; 7354 }, 7355 bind: $.proxy, 7356 each: function(collection, cb) { 7357 $.each(collection, reverseArgs); 7358 function reverseArgs(index, value) { 7359 return cb(value, index); 7360 } 7361 }, 7362 map: $.map, 7363 filter: $.grep, 7364 every: function(obj, test) { 7365 var result = true; 7366 if (!obj) { 7367 return result; 7368 } 7369 $.each(obj, function(key, val) { 7370 if (!(result = test.call(null, val, key, obj))) { 7371 return false; 7372 } 7373 }); 7374 return !!result; 7375 }, 7376 some: function(obj, test) { 7377 var result = false; 7378 if (!obj) { 7379 return result; 7380 } 7381 $.each(obj, function(key, val) { 7382 if (result = test.call(null, val, key, obj)) { 7383 return false; 7384 } 7385 }); 7386 return !!result; 7387 }, 7388 mixin: $.extend, 7389 getUniqueId: function() { 7390 var counter = 0; 7391 return function() { 7392 return counter++; 7393 }; 7394 }(), 7395 templatify: function templatify(obj) { 7396 return $.isFunction(obj) ? obj : template; 7397 function template() { 7398 return String(obj); 7399 } 7400 }, 7401 defer: function(fn) { 7402 setTimeout(fn, 0); 7403 }, 7404 debounce: function(func, wait, immediate) { 7405 var timeout, result; 7406 return function() { 7407 var context = this, args = arguments, later, callNow; 7408 later = function() { 7409 timeout = null; 7410 if (!immediate) { 7411 result = func.apply(context, args); 7412 } 7413 }; 7414 callNow = immediate && !timeout; 7415 clearTimeout(timeout); 7416 timeout = setTimeout(later, wait); 7417 if (callNow) { 7418 result = func.apply(context, args); 7419 } 7420 return result; 7421 }; 7422 }, 7423 throttle: function(func, wait) { 7424 var context, args, timeout, result, previous, later; 7425 previous = 0; 7426 later = function() { 7427 previous = new Date(); 7428 timeout = null; 7429 result = func.apply(context, args); 7430 }; 7431 return function() { 7432 var now = new Date(), remaining = wait - (now - previous); 7433 context = this; 7434 args = arguments; 7435 if (remaining <= 0) { 7436 clearTimeout(timeout); 7437 timeout = null; 7438 previous = now; 7439 result = func.apply(context, args); 7440 } else if (!timeout) { 7441 timeout = setTimeout(later, remaining); 7442 } 7443 return result; 7444 }; 7445 }, 7446 noop: function() {} 7447 }; 7448 }(); 7449 var VERSION = "0.10.5"; 7450 var tokenizers = function() { 7451 "use strict"; 7452 return { 7453 nonword: nonword, 7454 whitespace: whitespace, 7455 obj: { 7456 nonword: getObjTokenizer(nonword), 7457 whitespace: getObjTokenizer(whitespace) 7458 } 7459 }; 7460 function whitespace(str) { 7461 str = _.toStr(str); 7462 return str ? str.split(/\s+/) : []; 7463 } 7464 function nonword(str) { 7465 str = _.toStr(str); 7466 return str ? str.split(/\W+/) : []; 7467 } 7468 function getObjTokenizer(tokenizer) { 7469 return function setKey() { 7470 var args = [].slice.call(arguments, 0); 7471 return function tokenize(o) { 7472 var tokens = []; 7473 _.each(args, function(k) { 7474 tokens = tokens.concat(tokenizer(_.toStr(o[k]))); 7475 }); 7476 return tokens; 7477 }; 7478 }; 7479 } 7480 }(); 7481 var LruCache = function() { 7482 "use strict"; 7483 function LruCache(maxSize) { 7484 this.maxSize = _.isNumber(maxSize) ? maxSize : 100; 7485 this.reset(); 7486 if (this.maxSize <= 0) { 7487 this.set = this.get = $.noop; 7488 } 7489 } 7490 _.mixin(LruCache.prototype, { 7491 set: function set(key, val) { 7492 var tailItem = this.list.tail, node; 7493 if (this.size >= this.maxSize) { 7494 this.list.remove(tailItem); 7495 delete this.hash[tailItem.key]; 7496 } 7497 if (node = this.hash[key]) { 7498 node.val = val; 7499 this.list.moveToFront(node); 7500 } else { 7501 node = new Node(key, val); 7502 this.list.add(node); 7503 this.hash[key] = node; 7504 this.size++; 7505 } 7506 }, 7507 get: function get(key) { 7508 var node = this.hash[key]; 7509 if (node) { 7510 this.list.moveToFront(node); 7511 return node.val; 7512 } 7513 }, 7514 reset: function reset() { 7515 this.size = 0; 7516 this.hash = {}; 7517 this.list = new List(); 7518 } 7519 }); 7520 function List() { 7521 this.head = this.tail = null; 7522 } 7523 _.mixin(List.prototype, { 7524 add: function add(node) { 7525 if (this.head) { 7526 node.next = this.head; 7527 this.head.prev = node; 7528 } 7529 this.head = node; 7530 this.tail = this.tail || node; 7531 }, 7532 remove: function remove(node) { 7533 node.prev ? node.prev.next = node.next : this.head = node.next; 7534 node.next ? node.next.prev = node.prev : this.tail = node.prev; 7535 }, 7536 moveToFront: function(node) { 7537 this.remove(node); 7538 this.add(node); 7539 } 7540 }); 7541 function Node(key, val) { 7542 this.key = key; 7543 this.val = val; 7544 this.prev = this.next = null; 7545 } 7546 return LruCache; 7547 }(); 7548 var PersistentStorage = function() { 7549 "use strict"; 7550 var ls, methods; 7551 try { 7552 ls = window.localStorage; 7553 ls.setItem("~~~", "!"); 7554 ls.removeItem("~~~"); 7555 } catch (err) { 7556 ls = null; 7557 } 7558 function PersistentStorage(namespace) { 7559 this.prefix = [ "__", namespace, "__" ].join(""); 7560 this.ttlKey = "__ttl__"; 7561 this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix)); 7562 } 7563 if (ls && window.JSON) { 7564 methods = { 7565 _prefix: function(key) { 7566 return this.prefix + key; 7567 }, 7568 _ttlKey: function(key) { 7569 return this._prefix(key) + this.ttlKey; 7570 }, 7571 get: function(key) { 7572 if (this.isExpired(key)) { 7573 this.remove(key); 7574 } 7575 return decode(ls.getItem(this._prefix(key))); 7576 }, 7577 set: function(key, val, ttl) { 7578 if (_.isNumber(ttl)) { 7579 ls.setItem(this._ttlKey(key), encode(now() + ttl)); 7580 } else { 7581 ls.removeItem(this._ttlKey(key)); 7582 } 7583 return ls.setItem(this._prefix(key), encode(val)); 7584 }, 7585 remove: function(key) { 7586 ls.removeItem(this._ttlKey(key)); 7587 ls.removeItem(this._prefix(key)); 7588 return this; 7589 }, 7590 clear: function() { 7591 var i, key, keys = [], len = ls.length; 7592 for (i = 0; i < len; i++) { 7593 if ((key = ls.key(i)).match(this.keyMatcher)) { 7594 keys.push(key.replace(this.keyMatcher, "")); 7595 } 7596 } 7597 for (i = keys.length; i--; ) { 7598 this.remove(keys[i]); 7599 } 7600 return this; 7601 }, 7602 isExpired: function(key) { 7603 var ttl = decode(ls.getItem(this._ttlKey(key))); 7604 return _.isNumber(ttl) && now() > ttl ? true : false; 7605 } 7606 }; 7607 } else { 7608 methods = { 7609 get: _.noop, 7610 set: _.noop, 7611 remove: _.noop, 7612 clear: _.noop, 7613 isExpired: _.noop 7614 }; 7615 } 7616 _.mixin(PersistentStorage.prototype, methods); 7617 return PersistentStorage; 7618 function now() { 7619 return new Date().getTime(); 7620 } 7621 function encode(val) { 7622 return JSON.stringify(_.isUndefined(val) ? null : val); 7623 } 7624 function decode(val) { 7625 return JSON.parse(val); 7626 } 7627 }(); 7628 var Transport = function() { 7629 "use strict"; 7630 var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10); 7631 function Transport(o) { 7632 o = o || {}; 7633 this.cancelled = false; 7634 this.lastUrl = null; 7635 this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax; 7636 this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get; 7637 this._cache = o.cache === false ? new LruCache(0) : sharedCache; 7638 } 7639 Transport.setMaxPendingRequests = function setMaxPendingRequests(num) { 7640 maxPendingRequests = num; 7641 }; 7642 Transport.resetCache = function resetCache() { 7643 sharedCache.reset(); 7644 }; 7645 _.mixin(Transport.prototype, { 7646 _get: function(url, o, cb) { 7647 var that = this, jqXhr; 7648 if (this.cancelled || url !== this.lastUrl) { 7649 return; 7650 } 7651 if (jqXhr = pendingRequests[url]) { 7652 jqXhr.done(done).fail(fail); 7653 } else if (pendingRequestsCount < maxPendingRequests) { 7654 pendingRequestsCount++; 7655 pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always); 7656 } else { 7657 this.onDeckRequestArgs = [].slice.call(arguments, 0); 7658 } 7659 function done(resp) { 7660 cb && cb(null, resp); 7661 that._cache.set(url, resp); 7662 } 7663 function fail() { 7664 cb && cb(true); 7665 } 7666 function always() { 7667 pendingRequestsCount--; 7668 delete pendingRequests[url]; 7669 if (that.onDeckRequestArgs) { 7670 that._get.apply(that, that.onDeckRequestArgs); 7671 that.onDeckRequestArgs = null; 7672 } 7673 } 7674 }, 7675 get: function(url, o, cb) { 7676 var resp; 7677 if (_.isFunction(o)) { 7678 cb = o; 7679 o = {}; 7680 } 7681 this.cancelled = false; 7682 this.lastUrl = url; 7683 if (resp = this._cache.get(url)) { 7684 _.defer(function() { 7685 cb && cb(null, resp); 7686 }); 7687 } else { 7688 this._get(url, o, cb); 7689 } 7690 return !!resp; 7691 }, 7692 cancel: function() { 7693 this.cancelled = true; 7694 } 7695 }); 7696 return Transport; 7697 function callbackToDeferred(fn) { 7698 return function customSendWrapper(url, o) { 7699 var deferred = $.Deferred(); 7700 fn(url, o, onSuccess, onError); 7701 return deferred; 7702 function onSuccess(resp) { 7703 _.defer(function() { 7704 deferred.resolve(resp); 7705 }); 7706 } 7707 function onError(err) { 7708 _.defer(function() { 7709 deferred.reject(err); 7710 }); 7711 } 7712 }; 7713 } 7714 }(); 7715 var SearchIndex = function() { 7716 "use strict"; 7717 function SearchIndex(o) { 7718 o = o || {}; 7719 if (!o.datumTokenizer || !o.queryTokenizer) { 7720 $.error("datumTokenizer and queryTokenizer are both required"); 7721 } 7722 this.datumTokenizer = o.datumTokenizer; 7723 this.queryTokenizer = o.queryTokenizer; 7724 this.reset(); 7725 } 7726 _.mixin(SearchIndex.prototype, { 7727 bootstrap: function bootstrap(o) { 7728 this.datums = o.datums; 7729 this.trie = o.trie; 7730 }, 7731 add: function(data) { 7732 var that = this; 7733 data = _.isArray(data) ? data : [ data ]; 7734 _.each(data, function(datum) { 7735 var id, tokens; 7736 id = that.datums.push(datum) - 1; 7737 tokens = normalizeTokens(that.datumTokenizer(datum)); 7738 _.each(tokens, function(token) { 7739 var node, chars, ch; 7740 node = that.trie; 7741 chars = token.split(""); 7742 while (ch = chars.shift()) { 7743 node = node.children[ch] || (node.children[ch] = newNode()); 7744 node.ids.push(id); 7745 } 7746 }); 7747 }); 7748 }, 7749 get: function get(query) { 7750 var that = this, tokens, matches; 7751 tokens = normalizeTokens(this.queryTokenizer(query)); 7752 _.each(tokens, function(token) { 7753 var node, chars, ch, ids; 7754 if (matches && matches.length === 0) { 7755 return false; 7756 } 7757 node = that.trie; 7758 chars = token.split(""); 7759 while (node && (ch = chars.shift())) { 7760 node = node.children[ch]; 7761 } 7762 if (node && chars.length === 0) { 7763 ids = node.ids.slice(0); 7764 matches = matches ? getIntersection(matches, ids) : ids; 7765 } else { 7766 matches = []; 7767 return false; 7768 } 7769 }); 7770 return matches ? _.map(unique(matches), function(id) { 7771 return that.datums[id]; 7772 }) : []; 7773 }, 7774 reset: function reset() { 7775 this.datums = []; 7776 this.trie = newNode(); 7777 }, 7778 serialize: function serialize() { 7779 return { 7780 datums: this.datums, 7781 trie: this.trie 7782 }; 7783 } 7784 }); 7785 return SearchIndex; 7786 function normalizeTokens(tokens) { 7787 tokens = _.filter(tokens, function(token) { 7788 return !!token; 7789 }); 7790 tokens = _.map(tokens, function(token) { 7791 return token.toLowerCase(); 7792 }); 7793 return tokens; 7794 } 7795 function newNode() { 7796 return { 7797 ids: [], 7798 children: {} 7799 }; 7800 } 7801 function unique(array) { 7802 var seen = {}, uniques = []; 7803 for (var i = 0, len = array.length; i < len; i++) { 7804 if (!seen[array[i]]) { 7805 seen[array[i]] = true; 7806 uniques.push(array[i]); 7807 } 7808 } 7809 return uniques; 7810 } 7811 function getIntersection(arrayA, arrayB) { 7812 var ai = 0, bi = 0, intersection = []; 7813 arrayA = arrayA.sort(compare); 7814 arrayB = arrayB.sort(compare); 7815 var lenArrayA = arrayA.length, lenArrayB = arrayB.length; 7816 while (ai < lenArrayA && bi < lenArrayB) { 7817 if (arrayA[ai] < arrayB[bi]) { 7818 ai++; 7819 } else if (arrayA[ai] > arrayB[bi]) { 7820 bi++; 7821 } else { 7822 intersection.push(arrayA[ai]); 7823 ai++; 7824 bi++; 7825 } 7826 } 7827 return intersection; 7828 function compare(a, b) { 7829 return a - b; 7830 } 7831 } 7832 }(); 7833 var oParser = function() { 7834 "use strict"; 7835 return { 7836 local: getLocal, 7837 prefetch: getPrefetch, 7838 remote: getRemote 7839 }; 7840 function getLocal(o) { 7841 return o.local || null; 7842 } 7843 function getPrefetch(o) { 7844 var prefetch, defaults; 7845 defaults = { 7846 url: null, 7847 thumbprint: "", 7848 ttl: 24 * 60 * 60 * 1e3, 7849 filter: null, 7850 ajax: {} 7851 }; 7852 if (prefetch = o.prefetch || null) { 7853 prefetch = _.isString(prefetch) ? { 7854 url: prefetch 7855 } : prefetch; 7856 prefetch = _.mixin(defaults, prefetch); 7857 prefetch.thumbprint = VERSION + prefetch.thumbprint; 7858 prefetch.ajax.type = prefetch.ajax.type || "GET"; 7859 prefetch.ajax.dataType = prefetch.ajax.dataType || "json"; 7860 !prefetch.url && $.error("prefetch requires url to be set"); 7861 } 7862 return prefetch; 7863 } 7864 function getRemote(o) { 7865 var remote, defaults; 7866 defaults = { 7867 url: null, 7868 cache: true, 7869 wildcard: "%QUERY", 7870 replace: null, 7871 rateLimitBy: "debounce", 7872 rateLimitWait: 300, 7873 send: null, 7874 filter: null, 7875 ajax: {} 7876 }; 7877 if (remote = o.remote || null) { 7878 remote = _.isString(remote) ? { 7879 url: remote 7880 } : remote; 7881 remote = _.mixin(defaults, remote); 7882 remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait); 7883 remote.ajax.type = remote.ajax.type || "GET"; 7884 remote.ajax.dataType = remote.ajax.dataType || "json"; 7885 delete remote.rateLimitBy; 7886 delete remote.rateLimitWait; 7887 !remote.url && $.error("remote requires url to be set"); 7888 } 7889 return remote; 7890 function byDebounce(wait) { 7891 return function(fn) { 7892 return _.debounce(fn, wait); 7893 }; 7894 } 7895 function byThrottle(wait) { 7896 return function(fn) { 7897 return _.throttle(fn, wait); 7898 }; 7899 } 7900 } 7901 }(); 7902 (function(root) { 7903 "use strict"; 7904 var old, keys; 7905 old = root.Bloodhound; 7906 keys = { 7907 data: "data", 7908 protocol: "protocol", 7909 thumbprint: "thumbprint" 7910 }; 7911 root.Bloodhound = Bloodhound; 7912 function Bloodhound(o) { 7913 if (!o || !o.local && !o.prefetch && !o.remote) { 7914 $.error("one of local, prefetch, or remote is required"); 7915 } 7916 this.limit = o.limit || 5; 7917 this.sorter = getSorter(o.sorter); 7918 this.dupDetector = o.dupDetector || ignoreDuplicates; 7919 this.local = oParser.local(o); 7920 this.prefetch = oParser.prefetch(o); 7921 this.remote = oParser.remote(o); 7922 this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null; 7923 this.index = new SearchIndex({ 7924 datumTokenizer: o.datumTokenizer, 7925 queryTokenizer: o.queryTokenizer 7926 }); 7927 this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null; 7928 } 7929 Bloodhound.noConflict = function noConflict() { 7930 root.Bloodhound = old; 7931 return Bloodhound; 7932 }; 7933 Bloodhound.tokenizers = tokenizers; 7934 _.mixin(Bloodhound.prototype, { 7935 _loadPrefetch: function loadPrefetch(o) { 7936 var that = this, serialized, deferred; 7937 if (serialized = this._readFromStorage(o.thumbprint)) { 7938 this.index.bootstrap(serialized); 7939 deferred = $.Deferred().resolve(); 7940 } else { 7941 deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse); 7942 } 7943 return deferred; 7944 function handlePrefetchResponse(resp) { 7945 that.clear(); 7946 that.add(o.filter ? o.filter(resp) : resp); 7947 that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl); 7948 } 7949 }, 7950 _getFromRemote: function getFromRemote(query, cb) { 7951 var that = this, url, uriEncodedQuery; 7952 if (!this.transport) { 7953 return; 7954 } 7955 query = query || ""; 7956 uriEncodedQuery = encodeURIComponent(query); 7957 url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery); 7958 return this.transport.get(url, this.remote.ajax, handleRemoteResponse); 7959 function handleRemoteResponse(err, resp) { 7960 err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp); 7961 } 7962 }, 7963 _cancelLastRemoteRequest: function cancelLastRemoteRequest() { 7964 this.transport && this.transport.cancel(); 7965 }, 7966 _saveToStorage: function saveToStorage(data, thumbprint, ttl) { 7967 if (this.storage) { 7968 this.storage.set(keys.data, data, ttl); 7969 this.storage.set(keys.protocol, location.protocol, ttl); 7970 this.storage.set(keys.thumbprint, thumbprint, ttl); 7971 } 7972 }, 7973 _readFromStorage: function readFromStorage(thumbprint) { 7974 var stored = {}, isExpired; 7975 if (this.storage) { 7976 stored.data = this.storage.get(keys.data); 7977 stored.protocol = this.storage.get(keys.protocol); 7978 stored.thumbprint = this.storage.get(keys.thumbprint); 7979 } 7980 isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol; 7981 return stored.data && !isExpired ? stored.data : null; 7982 }, 7983 _initialize: function initialize() { 7984 var that = this, local = this.local, deferred; 7985 deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve(); 7986 local && deferred.done(addLocalToIndex); 7987 this.transport = this.remote ? new Transport(this.remote) : null; 7988 return this.initPromise = deferred.promise(); 7989 function addLocalToIndex() { 7990 that.add(_.isFunction(local) ? local() : local); 7991 } 7992 }, 7993 initialize: function initialize(force) { 7994 return !this.initPromise || force ? this._initialize() : this.initPromise; 7995 }, 7996 add: function add(data) { 7997 this.index.add(data); 7998 }, 7999 get: function get(query, cb) { 8000 var that = this, matches = [], cacheHit = false; 8001 matches = this.index.get(query); 8002 matches = this.sorter(matches).slice(0, this.limit); 8003 matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest(); 8004 if (!cacheHit) { 8005 (matches.length > 0 || !this.transport) && cb && cb(matches); 8006 } 8007 function returnRemoteMatches(remoteMatches) { 8008 var matchesWithBackfill = matches.slice(0); 8009 _.each(remoteMatches, function(remoteMatch) { 8010 var isDuplicate; 8011 isDuplicate = _.some(matchesWithBackfill, function(match) { 8012 return that.dupDetector(remoteMatch, match); 8013 }); 8014 !isDuplicate && matchesWithBackfill.push(remoteMatch); 8015 return matchesWithBackfill.length < that.limit; 8016 }); 8017 cb && cb(that.sorter(matchesWithBackfill)); 8018 } 8019 }, 8020 clear: function clear() { 8021 this.index.reset(); 8022 }, 8023 clearPrefetchCache: function clearPrefetchCache() { 8024 this.storage && this.storage.clear(); 8025 }, 8026 clearRemoteCache: function clearRemoteCache() { 8027 this.transport && Transport.resetCache(); 8028 }, 8029 ttAdapter: function ttAdapter() { 8030 return _.bind(this.get, this); 8031 } 8032 }); 8033 return Bloodhound; 8034 function getSorter(sortFn) { 8035 return _.isFunction(sortFn) ? sort : noSort; 8036 function sort(array) { 8037 return array.sort(sortFn); 8038 } 8039 function noSort(array) { 8040 return array; 8041 } 8042 } 8043 function ignoreDuplicates() { 8044 return false; 8045 } 8046 })(this); 8047 var html = function() { 8048 return { 8049 wrapper: '<span class="twitter-typeahead"></span>', 8050 dropdown: '<span class="tt-dropdown-menu"></span>', 8051 dataset: '<div class="tt-dataset-%CLASS%"></div>', 8052 suggestions: '<span class="tt-suggestions"></span>', 8053 suggestion: '<div class="tt-suggestion"></div>' 8054 }; 8055 }(); 8056 var css = function() { 8057 "use strict"; 8058 var css = { 8059 wrapper: { 8060 position: "relative", 8061 display: "inline-block" 8062 }, 8063 hint: { 8064 position: "absolute", 8065 top: "0", 8066 left: "0", 8067 borderColor: "transparent", 8068 boxShadow: "none", 8069 opacity: "1" 8070 }, 8071 input: { 8072 position: "relative", 8073 verticalAlign: "top", 8074 backgroundColor: "transparent" 8075 }, 8076 inputWithNoHint: { 8077 position: "relative", 8078 verticalAlign: "top" 8079 }, 8080 dropdown: { 8081 position: "absolute", 8082 top: "100%", 8083 left: "0", 8084 zIndex: "100", 8085 display: "none" 8086 }, 8087 suggestions: { 8088 display: "block" 8089 }, 8090 suggestion: { 8091 whiteSpace: "nowrap", 8092 cursor: "pointer" 8093 }, 8094 suggestionChild: { 8095 whiteSpace: "normal" 8096 }, 8097 ltr: { 8098 left: "0", 8099 right: "auto" 8100 }, 8101 rtl: { 8102 left: "auto", 8103 right: " 0" 8104 } 8105 }; 8106 if (_.isMsie()) { 8107 _.mixin(css.input, { 8108 backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" 8109 }); 8110 } 8111 if (_.isMsie() && _.isMsie() <= 7) { 8112 _.mixin(css.input, { 8113 marginTop: "-1px" 8114 }); 8115 } 8116 return css; 8117 }(); 8118 var EventBus = function() { 8119 "use strict"; 8120 var namespace = "typeahead:"; 8121 function EventBus(o) { 8122 if (!o || !o.el) { 8123 $.error("EventBus initialized without el"); 8124 } 8125 this.$el = $(o.el); 8126 } 8127 _.mixin(EventBus.prototype, { 8128 trigger: function(type) { 8129 var args = [].slice.call(arguments, 1); 8130 this.$el.trigger(namespace + type, args); 8131 } 8132 }); 8133 return EventBus; 8134 }(); 8135 var EventEmitter = function() { 8136 "use strict"; 8137 var splitter = /\s+/, nextTick = getNextTick(); 8138 return { 8139 onSync: onSync, 8140 onAsync: onAsync, 8141 off: off, 8142 trigger: trigger 8143 }; 8144 function on(method, types, cb, context) { 8145 var type; 8146 if (!cb) { 8147 return this; 8148 } 8149 types = types.split(splitter); 8150 cb = context ? bindContext(cb, context) : cb; 8151 this._callbacks = this._callbacks || {}; 8152 while (type = types.shift()) { 8153 this._callbacks[type] = this._callbacks[type] || { 8154 sync: [], 8155 async: [] 8156 }; 8157 this._callbacks[type][method].push(cb); 8158 } 8159 return this; 8160 } 8161 function onAsync(types, cb, context) { 8162 return on.call(this, "async", types, cb, context); 8163 } 8164 function onSync(types, cb, context) { 8165 return on.call(this, "sync", types, cb, context); 8166 } 8167 function off(types) { 8168 var type; 8169 if (!this._callbacks) { 8170 return this; 8171 } 8172 types = types.split(splitter); 8173 while (type = types.shift()) { 8174 delete this._callbacks[type]; 8175 } 8176 return this; 8177 } 8178 function trigger(types) { 8179 var type, callbacks, args, syncFlush, asyncFlush; 8180 if (!this._callbacks) { 8181 return this; 8182 } 8183 types = types.split(splitter); 8184 args = [].slice.call(arguments, 1); 8185 while ((type = types.shift()) && (callbacks = this._callbacks[type])) { 8186 syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); 8187 asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); 8188 syncFlush() && nextTick(asyncFlush); 8189 } 8190 return this; 8191 } 8192 function getFlush(callbacks, context, args) { 8193 return flush; 8194 function flush() { 8195 var cancelled; 8196 for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { 8197 cancelled = callbacks[i].apply(context, args) === false; 8198 } 8199 return !cancelled; 8200 } 8201 } 8202 function getNextTick() { 8203 var nextTickFn; 8204 if (window.setImmediate) { 8205 nextTickFn = function nextTickSetImmediate(fn) { 8206 setImmediate(function() { 8207 fn(); 8208 }); 8209 }; 8210 } else { 8211 nextTickFn = function nextTickSetTimeout(fn) { 8212 setTimeout(function() { 8213 fn(); 8214 }, 0); 8215 }; 8216 } 8217 return nextTickFn; 8218 } 8219 function bindContext(fn, context) { 8220 return fn.bind ? fn.bind(context) : function() { 8221 fn.apply(context, [].slice.call(arguments, 0)); 8222 }; 8223 } 8224 }(); 8225 var highlight = function(doc) { 8226 "use strict"; 8227 var defaults = { 8228 node: null, 8229 pattern: null, 8230 tagName: "strong", 8231 className: null, 8232 wordsOnly: false, 8233 caseSensitive: false 8234 }; 8235 return function hightlight(o) { 8236 var regex; 8237 o = _.mixin({}, defaults, o); 8238 if (!o.node || !o.pattern) { 8239 return; 8240 } 8241 o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; 8242 regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); 8243 traverse(o.node, hightlightTextNode); 8244 function hightlightTextNode(textNode) { 8245 var match, patternNode, wrapperNode; 8246 if (match = regex.exec(textNode.data)) { 8247 wrapperNode = doc.createElement(o.tagName); 8248 o.className && (wrapperNode.className = o.className); 8249 patternNode = textNode.splitText(match.index); 8250 patternNode.splitText(match[0].length); 8251 wrapperNode.appendChild(patternNode.cloneNode(true)); 8252 textNode.parentNode.replaceChild(wrapperNode, patternNode); 8253 } 8254 return !!match; 8255 } 8256 function traverse(el, hightlightTextNode) { 8257 var childNode, TEXT_NODE_TYPE = 3; 8258 for (var i = 0; i < el.childNodes.length; i++) { 8259 childNode = el.childNodes[i]; 8260 if (childNode.nodeType === TEXT_NODE_TYPE) { 8261 i += hightlightTextNode(childNode) ? 1 : 0; 8262 } else { 8263 traverse(childNode, hightlightTextNode); 8264 } 8265 } 8266 } 8267 }; 8268 function getRegex(patterns, caseSensitive, wordsOnly) { 8269 var escapedPatterns = [], regexStr; 8270 for (var i = 0, len = patterns.length; i < len; i++) { 8271 escapedPatterns.push(_.escapeRegExChars(patterns[i])); 8272 } 8273 regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; 8274 return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); 8275 } 8276 }(window.document); 8277 var Input = function() { 8278 "use strict"; 8279 var specialKeyCodeMap; 8280 specialKeyCodeMap = { 8281 9: "tab", 8282 27: "esc", 8283 37: "left", 8284 39: "right", 8285 13: "enter", 8286 38: "up", 8287 40: "down" 8288 }; 8289 function Input(o) { 8290 var that = this, onBlur, onFocus, onKeydown, onInput; 8291 o = o || {}; 8292 if (!o.input) { 8293 $.error("input is missing"); 8294 } 8295 onBlur = _.bind(this._onBlur, this); 8296 onFocus = _.bind(this._onFocus, this); 8297 onKeydown = _.bind(this._onKeydown, this); 8298 onInput = _.bind(this._onInput, this); 8299 this.$hint = $(o.hint); 8300 this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); 8301 if (this.$hint.length === 0) { 8302 this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; 8303 } 8304 if (!_.isMsie()) { 8305 this.$input.on("input.tt", onInput); 8306 } else { 8307 this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { 8308 if (specialKeyCodeMap[$e.which || $e.keyCode]) { 8309 return; 8310 } 8311 _.defer(_.bind(that._onInput, that, $e)); 8312 }); 8313 } 8314 this.query = this.$input.val(); 8315 this.$overflowHelper = buildOverflowHelper(this.$input); 8316 } 8317 Input.normalizeQuery = function(str) { 8318 return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " "); 8319 }; 8320 _.mixin(Input.prototype, EventEmitter, { 8321 _onBlur: function onBlur() { 8322 this.resetInputValue(); 8323 this.trigger("blurred"); 8324 }, 8325 _onFocus: function onFocus() { 8326 this.trigger("focused"); 8327 }, 8328 _onKeydown: function onKeydown($e) { 8329 var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; 8330 this._managePreventDefault(keyName, $e); 8331 if (keyName && this._shouldTrigger(keyName, $e)) { 8332 this.trigger(keyName + "Keyed", $e); 8333 } 8334 }, 8335 _onInput: function onInput() { 8336 this._checkInputValue(); 8337 }, 8338 _managePreventDefault: function managePreventDefault(keyName, $e) { 8339 var preventDefault, hintValue, inputValue; 8340 switch (keyName) { 8341 case "tab": 8342 hintValue = this.getHint(); 8343 inputValue = this.getInputValue(); 8344 preventDefault = hintValue && hintValue !== inputValue && !withModifier($e); 8345 break; 8346 8347 case "up": 8348 case "down": 8349 preventDefault = !withModifier($e); 8350 break; 8351 8352 default: 8353 preventDefault = false; 8354 } 8355 preventDefault && $e.preventDefault(); 8356 }, 8357 _shouldTrigger: function shouldTrigger(keyName, $e) { 8358 var trigger; 8359 switch (keyName) { 8360 case "tab": 8361 trigger = !withModifier($e); 8362 break; 8363 8364 default: 8365 trigger = true; 8366 } 8367 return trigger; 8368 }, 8369 _checkInputValue: function checkInputValue() { 8370 var inputValue, areEquivalent, hasDifferentWhitespace; 8371 inputValue = this.getInputValue(); 8372 areEquivalent = areQueriesEquivalent(inputValue, this.query); 8373 hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false; 8374 this.query = inputValue; 8375 if (!areEquivalent) { 8376 this.trigger("queryChanged", this.query); 8377 } else if (hasDifferentWhitespace) { 8378 this.trigger("whitespaceChanged", this.query); 8379 } 8380 }, 8381 focus: function focus() { 8382 this.$input.focus(); 8383 }, 8384 blur: function blur() { 8385 this.$input.blur(); 8386 }, 8387 getQuery: function getQuery() { 8388 return this.query; 8389 }, 8390 setQuery: function setQuery(query) { 8391 this.query = query; 8392 }, 8393 getInputValue: function getInputValue() { 8394 return this.$input.val(); 8395 }, 8396 setInputValue: function setInputValue(value, silent) { 8397 this.$input.val(value); 8398 silent ? this.clearHint() : this._checkInputValue(); 8399 }, 8400 resetInputValue: function resetInputValue() { 8401 this.setInputValue(this.query, true); 8402 }, 8403 getHint: function getHint() { 8404 return this.$hint.val(); 8405 }, 8406 setHint: function setHint(value) { 8407 this.$hint.val(value); 8408 }, 8409 clearHint: function clearHint() { 8410 this.setHint(""); 8411 }, 8412 clearHintIfInvalid: function clearHintIfInvalid() { 8413 var val, hint, valIsPrefixOfHint, isValid; 8414 val = this.getInputValue(); 8415 hint = this.getHint(); 8416 valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; 8417 isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); 8418 !isValid && this.clearHint(); 8419 }, 8420 getLanguageDirection: function getLanguageDirection() { 8421 return (this.$input.css("direction") || "ltr").toLowerCase(); 8422 }, 8423 hasOverflow: function hasOverflow() { 8424 var constraint = this.$input.width() - 2; 8425 this.$overflowHelper.text(this.getInputValue()); 8426 return this.$overflowHelper.width() >= constraint; 8427 }, 8428 isCursorAtEnd: function() { 8429 var valueLength, selectionStart, range; 8430 valueLength = this.$input.val().length; 8431 selectionStart = this.$input[0].selectionStart; 8432 if (_.isNumber(selectionStart)) { 8433 return selectionStart === valueLength; 8434 } else if (document.selection) { 8435 range = document.selection.createRange(); 8436 range.moveStart("character", -valueLength); 8437 return valueLength === range.text.length; 8438 } 8439 return true; 8440 }, 8441 destroy: function destroy() { 8442 this.$hint.off(".tt"); 8443 this.$input.off(".tt"); 8444 this.$hint = this.$input = this.$overflowHelper = null; 8445 } 8446 }); 8447 return Input; 8448 function buildOverflowHelper($input) { 8449 return $('<pre aria-hidden="true"></pre>').css({ 8450 position: "absolute", 8451 visibility: "hidden", 8452 whiteSpace: "pre", 8453 fontFamily: $input.css("font-family"), 8454 fontSize: $input.css("font-size"), 8455 fontStyle: $input.css("font-style"), 8456 fontVariant: $input.css("font-variant"), 8457 fontWeight: $input.css("font-weight"), 8458 wordSpacing: $input.css("word-spacing"), 8459 letterSpacing: $input.css("letter-spacing"), 8460 textIndent: $input.css("text-indent"), 8461 textRendering: $input.css("text-rendering"), 8462 textTransform: $input.css("text-transform") 8463 }).insertAfter($input); 8464 } 8465 function areQueriesEquivalent(a, b) { 8466 return Input.normalizeQuery(a) === Input.normalizeQuery(b); 8467 } 8468 function withModifier($e) { 8469 return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; 8470 } 8471 }(); 8472 var Dataset = function() { 8473 "use strict"; 8474 var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum"; 8475 function Dataset(o) { 8476 o = o || {}; 8477 o.templates = o.templates || {}; 8478 if (!o.source) { 8479 $.error("missing source"); 8480 } 8481 if (o.name && !isValidName(o.name)) { 8482 $.error("invalid dataset name: " + o.name); 8483 } 8484 this.query = null; 8485 this.highlight = !!o.highlight; 8486 this.name = o.name || _.getUniqueId(); 8487 this.source = o.source; 8488 this.displayFn = getDisplayFn(o.display || o.displayKey); 8489 this.templates = getTemplates(o.templates, this.displayFn); 8490 this.$el = $(html.dataset.replace("%CLASS%", this.name)); 8491 } 8492 Dataset.extractDatasetName = function extractDatasetName(el) { 8493 return $(el).data(datasetKey); 8494 }; 8495 Dataset.extractValue = function extractDatum(el) { 8496 return $(el).data(valueKey); 8497 }; 8498 Dataset.extractDatum = function extractDatum(el) { 8499 return $(el).data(datumKey); 8500 }; 8501 _.mixin(Dataset.prototype, EventEmitter, { 8502 _render: function render(query, suggestions) { 8503 if (!this.$el) { 8504 return; 8505 } 8506 var that = this, hasSuggestions; 8507 this.$el.empty(); 8508 hasSuggestions = suggestions && suggestions.length; 8509 if (!hasSuggestions && this.templates.empty) { 8510 this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null); 8511 } else if (hasSuggestions) { 8512 this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null); 8513 } 8514 this.trigger("rendered"); 8515 function getEmptyHtml() { 8516 return that.templates.empty({ 8517 query: query, 8518 isEmpty: true 8519 }); 8520 } 8521 function getSuggestionsHtml() { 8522 var $suggestions, nodes; 8523 $suggestions = $(html.suggestions).css(css.suggestions); 8524 nodes = _.map(suggestions, getSuggestionNode); 8525 $suggestions.append.apply($suggestions, nodes); 8526 that.highlight && highlight({ 8527 className: "tt-highlight", 8528 node: $suggestions[0], 8529 pattern: query 8530 }); 8531 return $suggestions; 8532 function getSuggestionNode(suggestion) { 8533 var $el; 8534 $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion); 8535 $el.children().each(function() { 8536 $(this).css(css.suggestionChild); 8537 }); 8538 return $el; 8539 } 8540 } 8541 function getHeaderHtml() { 8542 return that.templates.header({ 8543 query: query, 8544 isEmpty: !hasSuggestions 8545 }); 8546 } 8547 function getFooterHtml() { 8548 return that.templates.footer({ 8549 query: query, 8550 isEmpty: !hasSuggestions 8551 }); 8552 } 8553 }, 8554 getRoot: function getRoot() { 8555 return this.$el; 8556 }, 8557 update: function update(query) { 8558 var that = this; 8559 this.query = query; 8560 this.canceled = false; 8561 this.source(query, render); 8562 function render(suggestions) { 8563 if (!that.canceled && query === that.query) { 8564 that._render(query, suggestions); 8565 } 8566 } 8567 }, 8568 cancel: function cancel() { 8569 this.canceled = true; 8570 }, 8571 clear: function clear() { 8572 this.cancel(); 8573 this.$el.empty(); 8574 this.trigger("rendered"); 8575 }, 8576 isEmpty: function isEmpty() { 8577 return this.$el.is(":empty"); 8578 }, 8579 destroy: function destroy() { 8580 this.$el = null; 8581 } 8582 }); 8583 return Dataset; 8584 function getDisplayFn(display) { 8585 display = display || "value"; 8586 return _.isFunction(display) ? display : displayFn; 8587 function displayFn(obj) { 8588 return obj[display]; 8589 } 8590 } 8591 function getTemplates(templates, displayFn) { 8592 return { 8593 empty: templates.empty && _.templatify(templates.empty), 8594 header: templates.header && _.templatify(templates.header), 8595 footer: templates.footer && _.templatify(templates.footer), 8596 suggestion: templates.suggestion || suggestionTemplate 8597 }; 8598 function suggestionTemplate(context) { 8599 return "<p>" + displayFn(context) + "</p>"; 8600 } 8601 } 8602 function isValidName(str) { 8603 return /^[_a-zA-Z0-9-]+$/.test(str); 8604 } 8605 }(); 8606 var Dropdown = function() { 8607 "use strict"; 8608 function Dropdown(o) { 8609 var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave; 8610 o = o || {}; 8611 if (!o.menu) { 8612 $.error("menu is required"); 8613 } 8614 this.isOpen = false; 8615 this.isEmpty = true; 8616 this.datasets = _.map(o.datasets, initializeDataset); 8617 onSuggestionClick = _.bind(this._onSuggestionClick, this); 8618 onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this); 8619 onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this); 8620 this.$menu = $(o.menu).on("click.tt", ".tt-suggestion", onSuggestionClick).on("mouseenter.tt", ".tt-suggestion", onSuggestionMouseEnter).on("mouseleave.tt", ".tt-suggestion", onSuggestionMouseLeave); 8621 _.each(this.datasets, function(dataset) { 8622 that.$menu.append(dataset.getRoot()); 8623 dataset.onSync("rendered", that._onRendered, that); 8624 }); 8625 } 8626 _.mixin(Dropdown.prototype, EventEmitter, { 8627 _onSuggestionClick: function onSuggestionClick($e) { 8628 this.trigger("suggestionClicked", $($e.currentTarget)); 8629 }, 8630 _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) { 8631 this._removeCursor(); 8632 this._setCursor($($e.currentTarget), true); 8633 }, 8634 _onSuggestionMouseLeave: function onSuggestionMouseLeave() { 8635 this._removeCursor(); 8636 }, 8637 _onRendered: function onRendered() { 8638 this.isEmpty = _.every(this.datasets, isDatasetEmpty); 8639 this.isEmpty ? this._hide() : this.isOpen && this._show(); 8640 this.trigger("datasetRendered"); 8641 function isDatasetEmpty(dataset) { 8642 return dataset.isEmpty(); 8643 } 8644 }, 8645 _hide: function() { 8646 this.$menu.hide(); 8647 }, 8648 _show: function() { 8649 this.$menu.css("display", "block"); 8650 }, 8651 _getSuggestions: function getSuggestions() { 8652 return this.$menu.find(".tt-suggestion"); 8653 }, 8654 _getCursor: function getCursor() { 8655 return this.$menu.find(".tt-cursor").first(); 8656 }, 8657 _setCursor: function setCursor($el, silent) { 8658 $el.first().addClass("tt-cursor"); 8659 !silent && this.trigger("cursorMoved"); 8660 }, 8661 _removeCursor: function removeCursor() { 8662 this._getCursor().removeClass("tt-cursor"); 8663 }, 8664 _moveCursor: function moveCursor(increment) { 8665 var $suggestions, $oldCursor, newCursorIndex, $newCursor; 8666 if (!this.isOpen) { 8667 return; 8668 } 8669 $oldCursor = this._getCursor(); 8670 $suggestions = this._getSuggestions(); 8671 this._removeCursor(); 8672 newCursorIndex = $suggestions.index($oldCursor) + increment; 8673 newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1; 8674 if (newCursorIndex === -1) { 8675 this.trigger("cursorRemoved"); 8676 return; 8677 } else if (newCursorIndex < -1) { 8678 newCursorIndex = $suggestions.length - 1; 8679 } 8680 this._setCursor($newCursor = $suggestions.eq(newCursorIndex)); 8681 this._ensureVisible($newCursor); 8682 }, 8683 _ensureVisible: function ensureVisible($el) { 8684 var elTop, elBottom, menuScrollTop, menuHeight; 8685 elTop = $el.position().top; 8686 elBottom = elTop + $el.outerHeight(true); 8687 menuScrollTop = this.$menu.scrollTop(); 8688 menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10); 8689 if (elTop < 0) { 8690 this.$menu.scrollTop(menuScrollTop + elTop); 8691 } else if (menuHeight < elBottom) { 8692 this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight)); 8693 } 8694 }, 8695 close: function close() { 8696 if (this.isOpen) { 8697 this.isOpen = false; 8698 this._removeCursor(); 8699 this._hide(); 8700 this.trigger("closed"); 8701 } 8702 }, 8703 open: function open() { 8704 if (!this.isOpen) { 8705 this.isOpen = true; 8706 !this.isEmpty && this._show(); 8707 this.trigger("opened"); 8708 } 8709 }, 8710 setLanguageDirection: function setLanguageDirection(dir) { 8711 this.$menu.css(dir === "ltr" ? css.ltr : css.rtl); 8712 }, 8713 moveCursorUp: function moveCursorUp() { 8714 this._moveCursor(-1); 8715 }, 8716 moveCursorDown: function moveCursorDown() { 8717 this._moveCursor(+1); 8718 }, 8719 getDatumForSuggestion: function getDatumForSuggestion($el) { 8720 var datum = null; 8721 if ($el.length) { 8722 datum = { 8723 raw: Dataset.extractDatum($el), 8724 value: Dataset.extractValue($el), 8725 datasetName: Dataset.extractDatasetName($el) 8726 }; 8727 } 8728 return datum; 8729 }, 8730 getDatumForCursor: function getDatumForCursor() { 8731 return this.getDatumForSuggestion(this._getCursor().first()); 8732 }, 8733 getDatumForTopSuggestion: function getDatumForTopSuggestion() { 8734 return this.getDatumForSuggestion(this._getSuggestions().first()); 8735 }, 8736 update: function update(query) { 8737 _.each(this.datasets, updateDataset); 8738 function updateDataset(dataset) { 8739 dataset.update(query); 8740 } 8741 }, 8742 empty: function empty() { 8743 _.each(this.datasets, clearDataset); 8744 this.isEmpty = true; 8745 function clearDataset(dataset) { 8746 dataset.clear(); 8747 } 8748 }, 8749 isVisible: function isVisible() { 8750 return this.isOpen && !this.isEmpty; 8751 }, 8752 destroy: function destroy() { 8753 this.$menu.off(".tt"); 8754 this.$menu = null; 8755 _.each(this.datasets, destroyDataset); 8756 function destroyDataset(dataset) { 8757 dataset.destroy(); 8758 } 8759 } 8760 }); 8761 return Dropdown; 8762 function initializeDataset(oDataset) { 8763 return new Dataset(oDataset); 8764 } 8765 }(); 8766 var Typeahead = function() { 8767 "use strict"; 8768 var attrsKey = "ttAttrs"; 8769 function Typeahead(o) { 8770 var $menu, $input, $hint; 8771 o = o || {}; 8772 if (!o.input) { 8773 $.error("missing input"); 8774 } 8775 this.isActivated = false; 8776 this.autoselect = !!o.autoselect; 8777 this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; 8778 this.$node = buildDom(o.input, o.withHint); 8779 $menu = this.$node.find(".tt-dropdown-menu"); 8780 $input = this.$node.find(".tt-input"); 8781 $hint = this.$node.find(".tt-hint"); 8782 $input.on("blur.tt", function($e) { 8783 var active, isActive, hasActive; 8784 active = document.activeElement; 8785 isActive = $menu.is(active); 8786 hasActive = $menu.has(active).length > 0; 8787 if (_.isMsie() && (isActive || hasActive)) { 8788 $e.preventDefault(); 8789 $e.stopImmediatePropagation(); 8790 _.defer(function() { 8791 $input.focus(); 8792 }); 8793 } 8794 }); 8795 $menu.on("mousedown.tt", function($e) { 8796 $e.preventDefault(); 8797 }); 8798 this.eventBus = o.eventBus || new EventBus({ 8799 el: $input 8800 }); 8801 this.dropdown = new Dropdown({ 8802 menu: $menu, 8803 datasets: o.datasets 8804 }).onSync("suggestionClicked", this._onSuggestionClicked, this).onSync("cursorMoved", this._onCursorMoved, this).onSync("cursorRemoved", this._onCursorRemoved, this).onSync("opened", this._onOpened, this).onSync("closed", this._onClosed, this).onAsync("datasetRendered", this._onDatasetRendered, this); 8805 this.input = new Input({ 8806 input: $input, 8807 hint: $hint 8808 }).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this); 8809 this._setLanguageDirection(); 8810 } 8811 _.mixin(Typeahead.prototype, { 8812 _onSuggestionClicked: function onSuggestionClicked(type, $el) { 8813 var datum; 8814 if (datum = this.dropdown.getDatumForSuggestion($el)) { 8815 this._select(datum); 8816 } 8817 }, 8818 _onCursorMoved: function onCursorMoved() { 8819 var datum = this.dropdown.getDatumForCursor(); 8820 this.input.setInputValue(datum.value, true); 8821 this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName); 8822 }, 8823 _onCursorRemoved: function onCursorRemoved() { 8824 this.input.resetInputValue(); 8825 this._updateHint(); 8826 }, 8827 _onDatasetRendered: function onDatasetRendered() { 8828 this._updateHint(); 8829 }, 8830 _onOpened: function onOpened() { 8831 this._updateHint(); 8832 this.eventBus.trigger("opened"); 8833 }, 8834 _onClosed: function onClosed() { 8835 this.input.clearHint(); 8836 this.eventBus.trigger("closed"); 8837 }, 8838 _onFocused: function onFocused() { 8839 this.isActivated = true; 8840 this.dropdown.open(); 8841 }, 8842 _onBlurred: function onBlurred() { 8843 this.isActivated = false; 8844 this.dropdown.empty(); 8845 this.dropdown.close(); 8846 }, 8847 _onEnterKeyed: function onEnterKeyed(type, $e) { 8848 var cursorDatum, topSuggestionDatum; 8849 cursorDatum = this.dropdown.getDatumForCursor(); 8850 topSuggestionDatum = this.dropdown.getDatumForTopSuggestion(); 8851 if (cursorDatum) { 8852 this._select(cursorDatum); 8853 $e.preventDefault(); 8854 } else if (this.autoselect && topSuggestionDatum) { 8855 this._select(topSuggestionDatum); 8856 $e.preventDefault(); 8857 } 8858 }, 8859 _onTabKeyed: function onTabKeyed(type, $e) { 8860 var datum; 8861 if (datum = this.dropdown.getDatumForCursor()) { 8862 this._select(datum); 8863 $e.preventDefault(); 8864 } else { 8865 this._autocomplete(true); 8866 } 8867 }, 8868 _onEscKeyed: function onEscKeyed() { 8869 this.dropdown.close(); 8870 this.input.resetInputValue(); 8871 }, 8872 _onUpKeyed: function onUpKeyed() { 8873 var query = this.input.getQuery(); 8874 this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp(); 8875 this.dropdown.open(); 8876 }, 8877 _onDownKeyed: function onDownKeyed() { 8878 var query = this.input.getQuery(); 8879 this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown(); 8880 this.dropdown.open(); 8881 }, 8882 _onLeftKeyed: function onLeftKeyed() { 8883 this.dir === "rtl" && this._autocomplete(); 8884 }, 8885 _onRightKeyed: function onRightKeyed() { 8886 this.dir === "ltr" && this._autocomplete(); 8887 }, 8888 _onQueryChanged: function onQueryChanged(e, query) { 8889 this.input.clearHintIfInvalid(); 8890 query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty(); 8891 this.dropdown.open(); 8892 this._setLanguageDirection(); 8893 }, 8894 _onWhitespaceChanged: function onWhitespaceChanged() { 8895 this._updateHint(); 8896 this.dropdown.open(); 8897 }, 8898 _setLanguageDirection: function setLanguageDirection() { 8899 var dir; 8900 if (this.dir !== (dir = this.input.getLanguageDirection())) { 8901 this.dir = dir; 8902 this.$node.css("direction", dir); 8903 this.dropdown.setLanguageDirection(dir); 8904 } 8905 }, 8906 _updateHint: function updateHint() { 8907 var datum, val, query, escapedQuery, frontMatchRegEx, match; 8908 datum = this.dropdown.getDatumForTopSuggestion(); 8909 if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) { 8910 val = this.input.getInputValue(); 8911 query = Input.normalizeQuery(val); 8912 escapedQuery = _.escapeRegExChars(query); 8913 frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); 8914 match = frontMatchRegEx.exec(datum.value); 8915 match ? this.input.setHint(val + match[1]) : this.input.clearHint(); 8916 } else { 8917 this.input.clearHint(); 8918 } 8919 }, 8920 _autocomplete: function autocomplete(laxCursor) { 8921 var hint, query, isCursorAtEnd, datum; 8922 hint = this.input.getHint(); 8923 query = this.input.getQuery(); 8924 isCursorAtEnd = laxCursor || this.input.isCursorAtEnd(); 8925 if (hint && query !== hint && isCursorAtEnd) { 8926 datum = this.dropdown.getDatumForTopSuggestion(); 8927 datum && this.input.setInputValue(datum.value); 8928 this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName); 8929 } 8930 }, 8931 _select: function select(datum) { 8932 this.input.setQuery(datum.value); 8933 this.input.setInputValue(datum.value, true); 8934 this._setLanguageDirection(); 8935 this.eventBus.trigger("selected", datum.raw, datum.datasetName); 8936 this.dropdown.close(); 8937 _.defer(_.bind(this.dropdown.empty, this.dropdown)); 8938 }, 8939 open: function open() { 8940 this.dropdown.open(); 8941 }, 8942 close: function close() { 8943 this.dropdown.close(); 8944 }, 8945 setVal: function setVal(val) { 8946 val = _.toStr(val); 8947 if (this.isActivated) { 8948 this.input.setInputValue(val); 8949 } else { 8950 this.input.setQuery(val); 8951 this.input.setInputValue(val, true); 8952 } 8953 this._setLanguageDirection(); 8954 }, 8955 getVal: function getVal() { 8956 return this.input.getQuery(); 8957 }, 8958 destroy: function destroy() { 8959 this.input.destroy(); 8960 this.dropdown.destroy(); 8961 destroyDomStructure(this.$node); 8962 this.$node = null; 8963 } 8964 }); 8965 return Typeahead; 8966 function buildDom(input, withHint) { 8967 var $input, $wrapper, $dropdown, $hint; 8968 $input = $(input); 8969 $wrapper = $(html.wrapper).css(css.wrapper); 8970 $dropdown = $(html.dropdown).css(css.dropdown); 8971 $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input)); 8972 $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly", true).attr({ 8973 autocomplete: "off", 8974 spellcheck: "false", 8975 tabindex: -1 8976 }); 8977 $input.data(attrsKey, { 8978 dir: $input.attr("dir"), 8979 autocomplete: $input.attr("autocomplete"), 8980 spellcheck: $input.attr("spellcheck"), 8981 style: $input.attr("style") 8982 }); 8983 $input.addClass("tt-input").attr({ 8984 autocomplete: "off", 8985 spellcheck: false 8986 }).css(withHint ? css.input : css.inputWithNoHint); 8987 try { 8988 !$input.attr("dir") && $input.attr("dir", "auto"); 8989 } catch (e) {} 8990 return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown); 8991 } 8992 function getBackgroundStyles($el) { 8993 return { 8994 backgroundAttachment: $el.css("background-attachment"), 8995 backgroundClip: $el.css("background-clip"), 8996 backgroundColor: $el.css("background-color"), 8997 backgroundImage: $el.css("background-image"), 8998 backgroundOrigin: $el.css("background-origin"), 8999 backgroundPosition: $el.css("background-position"), 9000 backgroundRepeat: $el.css("background-repeat"), 9001 backgroundSize: $el.css("background-size") 9002 }; 9003 } 9004 function destroyDomStructure($node) { 9005 var $input = $node.find(".tt-input"); 9006 _.each($input.data(attrsKey), function(val, key) { 9007 _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); 9008 }); 9009 $input.detach().removeData(attrsKey).removeClass("tt-input").insertAfter($node); 9010 $node.remove(); 9011 } 9012 }(); 9013 (function() { 9014 "use strict"; 9015 var old, typeaheadKey, methods; 9016 old = $.fn.typeahead; 9017 typeaheadKey = "ttTypeahead"; 9018 methods = { 9019 initialize: function initialize(o, datasets) { 9020 datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); 9021 o = o || {}; 9022 return this.each(attach); 9023 function attach() { 9024 var $input = $(this), eventBus, typeahead; 9025 _.each(datasets, function(d) { 9026 d.highlight = !!o.highlight; 9027 }); 9028 typeahead = new Typeahead({ 9029 input: $input, 9030 eventBus: eventBus = new EventBus({ 9031 el: $input 9032 }), 9033 withHint: _.isUndefined(o.hint) ? true : !!o.hint, 9034 minLength: o.minLength, 9035 autoselect: o.autoselect, 9036 datasets: datasets 9037 }); 9038 $input.data(typeaheadKey, typeahead); 9039 } 9040 }, 9041 open: function open() { 9042 return this.each(openTypeahead); 9043 function openTypeahead() { 9044 var $input = $(this), typeahead; 9045 if (typeahead = $input.data(typeaheadKey)) { 9046 typeahead.open(); 9047 } 9048 } 9049 }, 9050 close: function close() { 9051 return this.each(closeTypeahead); 9052 function closeTypeahead() { 9053 var $input = $(this), typeahead; 9054 if (typeahead = $input.data(typeaheadKey)) { 9055 typeahead.close(); 9056 } 9057 } 9058 }, 9059 val: function val(newVal) { 9060 return !arguments.length ? getVal(this.first()) : this.each(setVal); 9061 function setVal() { 9062 var $input = $(this), typeahead; 9063 if (typeahead = $input.data(typeaheadKey)) { 9064 typeahead.setVal(newVal); 9065 } 9066 } 9067 function getVal($input) { 9068 var typeahead, query; 9069 if (typeahead = $input.data(typeaheadKey)) { 9070 query = typeahead.getVal(); 9071 } 9072 return query; 9073 } 9074 }, 9075 destroy: function destroy() { 9076 return this.each(unattach); 9077 function unattach() { 9078 var $input = $(this), typeahead; 9079 if (typeahead = $input.data(typeaheadKey)) { 9080 typeahead.destroy(); 9081 $input.removeData(typeaheadKey); 9082 } 9083 } 9084 } 9085 }; 9086 $.fn.typeahead = function(method) { 9087 var tts; 9088 if (methods[method] && method !== "initialize") { 9089 tts = this.filter(function() { 9090 return !!$(this).data(typeaheadKey); 9091 }); 9092 return methods[method].apply(tts, [].slice.call(arguments, 1)); 9093 } else { 9094 return methods.initialize.apply(this, arguments); 9095 } 9096 }; 9097 $.fn.typeahead.noConflict = function noConflict() { 9098 $.fn.typeahead = old; 9099 return this; 9100 }; 9101 })(); 9102 })(window.jQuery); 9103 /* 9104 Copyright 2012 Igor Vaynberg 9105 9106 Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 9107 9108 This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU 9109 General Public License version 2 (the "GPL License"). You may choose either license to govern your 9110 use of this software only upon the condition that you accept all of the terms of either the Apache 9111 License or the GPL License. 9112 9113 You may obtain a copy of the Apache License and the GPL License at: 9114 9115 http://www.apache.org/licenses/LICENSE-2.0 9116 http://www.gnu.org/licenses/gpl-2.0.html 9117 9118 Unless required by applicable law or agreed to in writing, software distributed under the 9119 Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9120 CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for 9121 the specific language governing permissions and limitations under the Apache License and the GPL License. 9122 */ 9123 (function ($) { 9124 if(typeof $.fn.each2 == "undefined") { 9125 $.extend($.fn, { 9126 /* 9127 * 4-10 times faster .each replacement 9128 * use it carefully, as it overrides jQuery context of element on each iteration 9129 */ 9130 each2 : function (c) { 9131 var j = $([0]), i = -1, l = this.length; 9132 while ( 9133 ++i < l 9134 && (j.context = j[0] = this[i]) 9135 && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object 9136 ); 9137 return this; 9138 } 9139 }); 9140 } 9141 })(jQuery); 9142 9143 (function ($, undefined) { 9144 "use strict"; 9145 /*global document, window, jQuery, console */ 9146 9147 if (window.Select2 !== undefined) { 9148 return; 9149 } 9150 9151 var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, 9152 lastMousePosition={x:0,y:0}, $document, scrollBarDimensions, 9153 9154 KEY = { 9155 TAB: 9, 9156 ENTER: 13, 9157 ESC: 27, 9158 SPACE: 32, 9159 LEFT: 37, 9160 UP: 38, 9161 RIGHT: 39, 9162 DOWN: 40, 9163 SHIFT: 16, 9164 CTRL: 17, 9165 ALT: 18, 9166 PAGE_UP: 33, 9167 PAGE_DOWN: 34, 9168 HOME: 36, 9169 END: 35, 9170 BACKSPACE: 8, 9171 DELETE: 46, 9172 isArrow: function (k) { 9173 k = k.which ? k.which : k; 9174 switch (k) { 9175 case KEY.LEFT: 9176 case KEY.RIGHT: 9177 case KEY.UP: 9178 case KEY.DOWN: 9179 return true; 9180 } 9181 return false; 9182 }, 9183 isControl: function (e) { 9184 var k = e.which; 9185 switch (k) { 9186 case KEY.SHIFT: 9187 case KEY.CTRL: 9188 case KEY.ALT: 9189 return true; 9190 } 9191 9192 if (e.metaKey) return true; 9193 9194 return false; 9195 }, 9196 isFunctionKey: function (k) { 9197 k = k.which ? k.which : k; 9198 return k >= 112 && k <= 123; 9199 } 9200 }, 9201 MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>", 9202 9203 DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18":"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC5":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z","\u0386":"\u0391","\u0388":"\u0395","\u0389":"\u0397","\u038A":"\u0399","\u03AA":"\u0399","\u038C":"\u039F","\u038E":"\u03A5","\u03AB":"\u03A5","\u038F":"\u03A9","\u03AC":"\u03B1","\u03AD":"\u03B5","\u03AE":"\u03B7","\u03AF":"\u03B9","\u03CA":"\u03B9","\u0390":"\u03B9","\u03CC":"\u03BF","\u03CD":"\u03C5","\u03CB":"\u03C5","\u03B0":"\u03C5","\u03C9":"\u03C9","\u03C2":"\u03C3"}; 9204 9205 $document = $(document); 9206 9207 nextUid=(function() { var counter=1; return function() { return counter++; }; }()); 9208 9209 9210 function reinsertElement(element) { 9211 var placeholder = $(document.createTextNode('')); 9212 9213 element.before(placeholder); 9214 placeholder.before(element); 9215 placeholder.remove(); 9216 } 9217 9218 function stripDiacritics(str) { 9219 // Used 'uni range + named function' from http://jsperf.com/diacritics/18 9220 function match(a) { 9221 return DIACRITICS[a] || a; 9222 } 9223 9224 return str.replace(/[^\u0000-\u007E]/g, match); 9225 } 9226 9227 function indexOf(value, array) { 9228 var i = 0, l = array.length; 9229 for (; i < l; i = i + 1) { 9230 if (equal(value, array[i])) return i; 9231 } 9232 return -1; 9233 } 9234 9235 function measureScrollbar () { 9236 var $template = $( MEASURE_SCROLLBAR_TEMPLATE ); 9237 $template.appendTo('body'); 9238 9239 var dim = { 9240 width: $template.width() - $template[0].clientWidth, 9241 height: $template.height() - $template[0].clientHeight 9242 }; 9243 $template.remove(); 9244 9245 return dim; 9246 } 9247 9248 /** 9249 * Compares equality of a and b 9250 * @param a 9251 * @param b 9252 */ 9253 function equal(a, b) { 9254 if (a === b) return true; 9255 if (a === undefined || b === undefined) return false; 9256 if (a === null || b === null) return false; 9257 // Check whether 'a' or 'b' is a string (primitive or object). 9258 // The concatenation of an empty string (+'') converts its argument to a string's primitive. 9259 if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object 9260 if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object 9261 return false; 9262 } 9263 9264 /** 9265 * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty 9266 * strings 9267 * @param string 9268 * @param separator 9269 */ 9270 function splitVal(string, separator) { 9271 var val, i, l; 9272 if (string === null || string.length < 1) return []; 9273 val = string.split(separator); 9274 for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]); 9275 return val; 9276 } 9277 9278 function getSideBorderPadding(element) { 9279 return element.outerWidth(false) - element.width(); 9280 } 9281 9282 function installKeyUpChangeEvent(element) { 9283 var key="keyup-change-value"; 9284 element.on("keydown", function () { 9285 if ($.data(element, key) === undefined) { 9286 $.data(element, key, element.val()); 9287 } 9288 }); 9289 element.on("keyup", function () { 9290 var val= $.data(element, key); 9291 if (val !== undefined && element.val() !== val) { 9292 $.removeData(element, key); 9293 element.trigger("keyup-change"); 9294 } 9295 }); 9296 } 9297 9298 9299 /** 9300 * filters mouse events so an event is fired only if the mouse moved. 9301 * 9302 * filters out mouse events that occur when mouse is stationary but 9303 * the elements under the pointer are scrolled. 9304 */ 9305 function installFilteredMouseMove(element) { 9306 element.on("mousemove", function (e) { 9307 var lastpos = lastMousePosition; 9308 if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { 9309 $(e.target).trigger("mousemove-filtered", e); 9310 } 9311 }); 9312 } 9313 9314 /** 9315 * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made 9316 * within the last quietMillis milliseconds. 9317 * 9318 * @param quietMillis number of milliseconds to wait before invoking fn 9319 * @param fn function to be debounced 9320 * @param ctx object to be used as this reference within fn 9321 * @return debounced version of fn 9322 */ 9323 function debounce(quietMillis, fn, ctx) { 9324 ctx = ctx || undefined; 9325 var timeout; 9326 return function () { 9327 var args = arguments; 9328 window.clearTimeout(timeout); 9329 timeout = window.setTimeout(function() { 9330 fn.apply(ctx, args); 9331 }, quietMillis); 9332 }; 9333 } 9334 9335 function installDebouncedScroll(threshold, element) { 9336 var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); 9337 element.on("scroll", function (e) { 9338 if (indexOf(e.target, element.get()) >= 0) notify(e); 9339 }); 9340 } 9341 9342 function focus($el) { 9343 if ($el[0] === document.activeElement) return; 9344 9345 /* set the focus in a 0 timeout - that way the focus is set after the processing 9346 of the current event has finished - which seems like the only reliable way 9347 to set focus */ 9348 window.setTimeout(function() { 9349 var el=$el[0], pos=$el.val().length, range; 9350 9351 $el.focus(); 9352 9353 /* make sure el received focus so we do not error out when trying to manipulate the caret. 9354 sometimes modals or others listeners may steal it after its set */ 9355 var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0); 9356 if (isVisible && el === document.activeElement) { 9357 9358 /* after the focus is set move the caret to the end, necessary when we val() 9359 just before setting focus */ 9360 if(el.setSelectionRange) 9361 { 9362 el.setSelectionRange(pos, pos); 9363 } 9364 else if (el.createTextRange) { 9365 range = el.createTextRange(); 9366 range.collapse(false); 9367 range.select(); 9368 } 9369 } 9370 }, 0); 9371 } 9372 9373 function getCursorInfo(el) { 9374 el = $(el)[0]; 9375 var offset = 0; 9376 var length = 0; 9377 if ('selectionStart' in el) { 9378 offset = el.selectionStart; 9379 length = el.selectionEnd - offset; 9380 } else if ('selection' in document) { 9381 el.focus(); 9382 var sel = document.selection.createRange(); 9383 length = document.selection.createRange().text.length; 9384 sel.moveStart('character', -el.value.length); 9385 offset = sel.text.length - length; 9386 } 9387 return { offset: offset, length: length }; 9388 } 9389 9390 function killEvent(event) { 9391 event.preventDefault(); 9392 event.stopPropagation(); 9393 } 9394 function killEventImmediately(event) { 9395 event.preventDefault(); 9396 event.stopImmediatePropagation(); 9397 } 9398 9399 function measureTextWidth(e) { 9400 if (!sizer){ 9401 var style = e[0].currentStyle || window.getComputedStyle(e[0], null); 9402 sizer = $(document.createElement("div")).css({ 9403 position: "absolute", 9404 left: "-10000px", 9405 top: "-10000px", 9406 display: "none", 9407 fontSize: style.fontSize, 9408 fontFamily: style.fontFamily, 9409 fontStyle: style.fontStyle, 9410 fontWeight: style.fontWeight, 9411 letterSpacing: style.letterSpacing, 9412 textTransform: style.textTransform, 9413 whiteSpace: "nowrap" 9414 }); 9415 sizer.attr("class","select2-sizer"); 9416 $("body").append(sizer); 9417 } 9418 sizer.text(e.val()); 9419 return sizer.width(); 9420 } 9421 9422 function syncCssClasses(dest, src, adapter) { 9423 var classes, replacements = [], adapted; 9424 9425 classes = $.trim(dest.attr("class")); 9426 9427 if (classes) { 9428 classes = '' + classes; // for IE which returns object 9429 9430 $(classes.split(/\s+/)).each2(function() { 9431 if (this.indexOf("select2-") === 0) { 9432 replacements.push(this); 9433 } 9434 }); 9435 } 9436 9437 classes = $.trim(src.attr("class")); 9438 9439 if (classes) { 9440 classes = '' + classes; // for IE which returns object 9441 9442 $(classes.split(/\s+/)).each2(function() { 9443 if (this.indexOf("select2-") !== 0) { 9444 adapted = adapter(this); 9445 9446 if (adapted) { 9447 replacements.push(adapted); 9448 } 9449 } 9450 }); 9451 } 9452 9453 dest.attr("class", replacements.join(" ")); 9454 } 9455 9456 9457 function markMatch(text, term, markup, escapeMarkup) { 9458 var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())), 9459 tl=term.length; 9460 9461 if (match<0) { 9462 markup.push(escapeMarkup(text)); 9463 return; 9464 } 9465 9466 markup.push(escapeMarkup(text.substring(0, match))); 9467 markup.push("<span class='select2-match'>"); 9468 markup.push(escapeMarkup(text.substring(match, match + tl))); 9469 markup.push("</span>"); 9470 markup.push(escapeMarkup(text.substring(match + tl, text.length))); 9471 } 9472 9473 function defaultEscapeMarkup(markup) { 9474 var replace_map = { 9475 '\\': '\', 9476 '&': '&', 9477 '<': '<', 9478 '>': '>', 9479 '"': '"', 9480 "'": ''', 9481 "/": '/' 9482 }; 9483 9484 return String(markup).replace(/[&<>"'\/\\]/g, function (match) { 9485 return replace_map[match]; 9486 }); 9487 } 9488 9489 /** 9490 * Produces an ajax-based query function 9491 * 9492 * @param options object containing configuration parameters 9493 * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax 9494 * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax 9495 * @param options.url url for the data 9496 * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. 9497 * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified 9498 * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often 9499 * @param options.results a function(remoteData, pageNumber, query) that converts data returned form the remote request to the format expected by Select2. 9500 * The expected format is an object containing the following keys: 9501 * results array of objects that will be used as choices 9502 * more (optional) boolean indicating whether there are more results available 9503 * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true} 9504 */ 9505 function ajax(options) { 9506 var timeout, // current scheduled but not yet executed request 9507 handler = null, 9508 quietMillis = options.quietMillis || 100, 9509 ajaxUrl = options.url, 9510 self = this; 9511 9512 return function (query) { 9513 window.clearTimeout(timeout); 9514 timeout = window.setTimeout(function () { 9515 var data = options.data, // ajax data function 9516 url = ajaxUrl, // ajax url string or function 9517 transport = options.transport || $.fn.select2.ajaxDefaults.transport, 9518 // deprecated - to be removed in 4.0 - use params instead 9519 deprecated = { 9520 type: options.type || 'GET', // set type of request (GET or POST) 9521 cache: options.cache || false, 9522 jsonpCallback: options.jsonpCallback||undefined, 9523 dataType: options.dataType||"json" 9524 }, 9525 params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated); 9526 9527 data = data ? data.call(self, query.term, query.page, query.context) : null; 9528 url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url; 9529 9530 if (handler && typeof handler.abort === "function") { handler.abort(); } 9531 9532 if (options.params) { 9533 if ($.isFunction(options.params)) { 9534 $.extend(params, options.params.call(self)); 9535 } else { 9536 $.extend(params, options.params); 9537 } 9538 } 9539 9540 $.extend(params, { 9541 url: url, 9542 dataType: options.dataType, 9543 data: data, 9544 success: function (data) { 9545 // TODO - replace query.page with query so users have access to term, page, etc. 9546 // added query as third paramter to keep backwards compatibility 9547 var results = options.results(data, query.page, query); 9548 query.callback(results); 9549 }, 9550 error: function(jqXHR, textStatus, errorThrown){ 9551 var results = { 9552 hasError: true, 9553 jqXHR: jqXHR, 9554 textStatus: textStatus, 9555 errorThrown: errorThrown, 9556 }; 9557 9558 query.callback(results); 9559 } 9560 }); 9561 handler = transport.call(self, params); 9562 }, quietMillis); 9563 }; 9564 } 9565 9566 /** 9567 * Produces a query function that works with a local array 9568 * 9569 * @param options object containing configuration parameters. The options parameter can either be an array or an 9570 * object. 9571 * 9572 * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys. 9573 * 9574 * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain 9575 * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text' 9576 * key can either be a String in which case it is expected that each element in the 'data' array has a key with the 9577 * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract 9578 * the text. 9579 */ 9580 function local(options) { 9581 var data = options, // data elements 9582 dataText, 9583 tmp, 9584 text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search 9585 9586 if ($.isArray(data)) { 9587 tmp = data; 9588 data = { results: tmp }; 9589 } 9590 9591 if ($.isFunction(data) === false) { 9592 tmp = data; 9593 data = function() { return tmp; }; 9594 } 9595 9596 var dataItem = data(); 9597 if (dataItem.text) { 9598 text = dataItem.text; 9599 // if text is not a function we assume it to be a key name 9600 if (!$.isFunction(text)) { 9601 dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available 9602 text = function (item) { return item[dataText]; }; 9603 } 9604 } 9605 9606 return function (query) { 9607 var t = query.term, filtered = { results: [] }, process; 9608 if (t === "") { 9609 query.callback(data()); 9610 return; 9611 } 9612 9613 process = function(datum, collection) { 9614 var group, attr; 9615 datum = datum[0]; 9616 if (datum.children) { 9617 group = {}; 9618 for (attr in datum) { 9619 if (datum.hasOwnProperty(attr)) group[attr]=datum[attr]; 9620 } 9621 group.children=[]; 9622 $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); 9623 if (group.children.length || query.matcher(t, text(group), datum)) { 9624 collection.push(group); 9625 } 9626 } else { 9627 if (query.matcher(t, text(datum), datum)) { 9628 collection.push(datum); 9629 } 9630 } 9631 }; 9632 9633 $(data().results).each2(function(i, datum) { process(datum, filtered.results); }); 9634 query.callback(filtered); 9635 }; 9636 } 9637 9638 // TODO javadoc 9639 function tags(data) { 9640 var isFunc = $.isFunction(data); 9641 return function (query) { 9642 var t = query.term, filtered = {results: []}; 9643 var result = isFunc ? data(query) : data; 9644 if ($.isArray(result)) { 9645 $(result).each(function () { 9646 var isObject = this.text !== undefined, 9647 text = isObject ? this.text : this; 9648 if (t === "" || query.matcher(t, text)) { 9649 filtered.results.push(isObject ? this : {id: this, text: this}); 9650 } 9651 }); 9652 query.callback(filtered); 9653 } 9654 }; 9655 } 9656 9657 /** 9658 * Checks if the formatter function should be used. 9659 * 9660 * Throws an error if it is not a function. Returns true if it should be used, 9661 * false if no formatting should be performed. 9662 * 9663 * @param formatter 9664 */ 9665 function checkFormatter(formatter, formatterName) { 9666 if ($.isFunction(formatter)) return true; 9667 if (!formatter) return false; 9668 if (typeof(formatter) === 'string') return true; 9669 throw new Error(formatterName +" must be a string, function, or falsy value"); 9670 } 9671 9672 /** 9673 * Returns a given value 9674 * If given a function, returns its output 9675 * 9676 * @param val string|function 9677 * @param context value of "this" to be passed to function 9678 * @returns {*} 9679 */ 9680 function evaluate(val, context) { 9681 if ($.isFunction(val)) { 9682 var args = Array.prototype.slice.call(arguments, 2); 9683 return val.apply(context, args); 9684 } 9685 return val; 9686 } 9687 9688 function countResults(results) { 9689 var count = 0; 9690 $.each(results, function(i, item) { 9691 if (item.children) { 9692 count += countResults(item.children); 9693 } else { 9694 count++; 9695 } 9696 }); 9697 return count; 9698 } 9699 9700 /** 9701 * Default tokenizer. This function uses breaks the input on substring match of any string from the 9702 * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those 9703 * two options have to be defined in order for the tokenizer to work. 9704 * 9705 * @param input text user has typed so far or pasted into the search field 9706 * @param selection currently selected choices 9707 * @param selectCallback function(choice) callback tho add the choice to selection 9708 * @param opts select2's opts 9709 * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value 9710 */ 9711 function defaultTokenizer(input, selection, selectCallback, opts) { 9712 var original = input, // store the original so we can compare and know if we need to tell the search to update its text 9713 dupe = false, // check for whether a token we extracted represents a duplicate selected choice 9714 token, // token 9715 index, // position at which the separator was found 9716 i, l, // looping variables 9717 separator; // the matched separator 9718 9719 if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined; 9720 9721 while (true) { 9722 index = -1; 9723 9724 for (i = 0, l = opts.tokenSeparators.length; i < l; i++) { 9725 separator = opts.tokenSeparators[i]; 9726 index = input.indexOf(separator); 9727 if (index >= 0) break; 9728 } 9729 9730 if (index < 0) break; // did not find any token separator in the input string, bail 9731 9732 token = input.substring(0, index); 9733 input = input.substring(index + separator.length); 9734 9735 if (token.length > 0) { 9736 token = opts.createSearchChoice.call(this, token, selection); 9737 if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) { 9738 dupe = false; 9739 for (i = 0, l = selection.length; i < l; i++) { 9740 if (equal(opts.id(token), opts.id(selection[i]))) { 9741 dupe = true; break; 9742 } 9743 } 9744 9745 if (!dupe) selectCallback(token); 9746 } 9747 } 9748 } 9749 9750 if (original!==input) return input; 9751 } 9752 9753 function cleanupJQueryElements() { 9754 var self = this; 9755 9756 $.each(arguments, function (i, element) { 9757 self[element].remove(); 9758 self[element] = null; 9759 }); 9760 } 9761 9762 /** 9763 * Creates a new class 9764 * 9765 * @param superClass 9766 * @param methods 9767 */ 9768 function clazz(SuperClass, methods) { 9769 var constructor = function () {}; 9770 constructor.prototype = new SuperClass; 9771 constructor.prototype.constructor = constructor; 9772 constructor.prototype.parent = SuperClass.prototype; 9773 constructor.prototype = $.extend(constructor.prototype, methods); 9774 return constructor; 9775 } 9776 9777 AbstractSelect2 = clazz(Object, { 9778 9779 // abstract 9780 bind: function (func) { 9781 var self = this; 9782 return function () { 9783 func.apply(self, arguments); 9784 }; 9785 }, 9786 9787 // abstract 9788 init: function (opts) { 9789 var results, search, resultsSelector = ".select2-results"; 9790 9791 // prepare options 9792 this.opts = opts = this.prepareOpts(opts); 9793 9794 this.id=opts.id; 9795 9796 // destroy if called on an existing component 9797 if (opts.element.data("select2") !== undefined && 9798 opts.element.data("select2") !== null) { 9799 opts.element.data("select2").destroy(); 9800 } 9801 9802 this.container = this.createContainer(); 9803 9804 this.liveRegion = $("<span>", { 9805 role: "status", 9806 "aria-live": "polite" 9807 }) 9808 .addClass("select2-hidden-accessible") 9809 .appendTo(document.body); 9810 9811 this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()); 9812 this.containerEventName= this.containerId 9813 .replace(/([.])/g, '_') 9814 .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); 9815 this.container.attr("id", this.containerId); 9816 9817 this.container.attr("title", opts.element.attr("title")); 9818 9819 this.body = $("body"); 9820 9821 syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); 9822 9823 this.container.attr("style", opts.element.attr("style")); 9824 this.container.css(evaluate(opts.containerCss, this.opts.element)); 9825 this.container.addClass(evaluate(opts.containerCssClass, this.opts.element)); 9826 9827 this.elementTabIndex = this.opts.element.attr("tabindex"); 9828 9829 // swap container for the element 9830 this.opts.element 9831 .data("select2", this) 9832 .attr("tabindex", "-1") 9833 .before(this.container) 9834 .on("click.select2", killEvent); // do not leak click events 9835 9836 this.container.data("select2", this); 9837 9838 this.dropdown = this.container.find(".select2-drop"); 9839 9840 syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); 9841 9842 this.dropdown.addClass(evaluate(opts.dropdownCssClass, this.opts.element)); 9843 this.dropdown.data("select2", this); 9844 this.dropdown.on("click", killEvent); 9845 9846 this.results = results = this.container.find(resultsSelector); 9847 this.search = search = this.container.find("input.select2-input"); 9848 9849 this.queryCount = 0; 9850 this.resultsPage = 0; 9851 this.context = null; 9852 9853 // initialize the container 9854 this.initContainer(); 9855 9856 this.container.on("click", killEvent); 9857 9858 installFilteredMouseMove(this.results); 9859 9860 this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent)); 9861 this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) { 9862 this._touchEvent = true; 9863 this.highlightUnderEvent(event); 9864 })); 9865 this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved)); 9866 this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved)); 9867 9868 // Waiting for a click event on touch devices to select option and hide dropdown 9869 // otherwise click will be triggered on an underlying element 9870 this.dropdown.on('click', this.bind(function (event) { 9871 if (this._touchEvent) { 9872 this._touchEvent = false; 9873 this.selectHighlighted(); 9874 } 9875 })); 9876 9877 installDebouncedScroll(80, this.results); 9878 this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded)); 9879 9880 // do not propagate change event from the search field out of the component 9881 $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();}); 9882 $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();}); 9883 9884 // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel 9885 if ($.fn.mousewheel) { 9886 results.mousewheel(function (e, delta, deltaX, deltaY) { 9887 var top = results.scrollTop(); 9888 if (deltaY > 0 && top - deltaY <= 0) { 9889 results.scrollTop(0); 9890 killEvent(e); 9891 } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { 9892 results.scrollTop(results.get(0).scrollHeight - results.height()); 9893 killEvent(e); 9894 } 9895 }); 9896 } 9897 9898 installKeyUpChangeEvent(search); 9899 search.on("keyup-change input paste", this.bind(this.updateResults)); 9900 search.on("focus", function () { search.addClass("select2-focused"); }); 9901 search.on("blur", function () { search.removeClass("select2-focused");}); 9902 9903 this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) { 9904 if ($(e.target).closest(".select2-result-selectable").length > 0) { 9905 this.highlightUnderEvent(e); 9906 this.selectHighlighted(e); 9907 } 9908 })); 9909 9910 // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening 9911 // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's 9912 // dom it will trigger the popup close, which is not what we want 9913 // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal. 9914 this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); }); 9915 9916 this.nextSearchTerm = undefined; 9917 9918 if ($.isFunction(this.opts.initSelection)) { 9919 // initialize selection based on the current value of the source element 9920 this.initSelection(); 9921 9922 // if the user has provided a function that can set selection based on the value of the source element 9923 // we monitor the change event on the element and trigger it, allowing for two way synchronization 9924 this.monitorSource(); 9925 } 9926 9927 if (opts.maximumInputLength !== null) { 9928 this.search.attr("maxlength", opts.maximumInputLength); 9929 } 9930 9931 var disabled = opts.element.prop("disabled"); 9932 if (disabled === undefined) disabled = false; 9933 this.enable(!disabled); 9934 9935 var readonly = opts.element.prop("readonly"); 9936 if (readonly === undefined) readonly = false; 9937 this.readonly(readonly); 9938 9939 // Calculate size of scrollbar 9940 scrollBarDimensions = scrollBarDimensions || measureScrollbar(); 9941 9942 this.autofocus = opts.element.prop("autofocus"); 9943 opts.element.prop("autofocus", false); 9944 if (this.autofocus) this.focus(); 9945 9946 this.search.attr("placeholder", opts.searchInputPlaceholder); 9947 }, 9948 9949 // abstract 9950 destroy: function () { 9951 var element=this.opts.element, select2 = element.data("select2"), self = this; 9952 9953 this.close(); 9954 9955 if (element.length && element[0].detachEvent) { 9956 element.each(function () { 9957 this.detachEvent("onpropertychange", self._sync); 9958 }); 9959 } 9960 if (this.propertyObserver) { 9961 this.propertyObserver.disconnect(); 9962 this.propertyObserver = null; 9963 } 9964 this._sync = null; 9965 9966 if (select2 !== undefined) { 9967 select2.container.remove(); 9968 select2.liveRegion.remove(); 9969 select2.dropdown.remove(); 9970 element 9971 .removeClass("select2-offscreen") 9972 .removeData("select2") 9973 .off(".select2") 9974 .prop("autofocus", this.autofocus || false); 9975 if (this.elementTabIndex) { 9976 element.attr({tabindex: this.elementTabIndex}); 9977 } else { 9978 element.removeAttr("tabindex"); 9979 } 9980 element.show(); 9981 } 9982 9983 cleanupJQueryElements.call(this, 9984 "container", 9985 "liveRegion", 9986 "dropdown", 9987 "results", 9988 "search" 9989 ); 9990 }, 9991 9992 // abstract 9993 optionToData: function(element) { 9994 if (element.is("option")) { 9995 return { 9996 id:element.prop("value"), 9997 text:element.text(), 9998 element: element.get(), 9999 css: element.attr("class"), 10000 disabled: element.prop("disabled"), 10001 locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true) 10002 }; 10003 } else if (element.is("optgroup")) { 10004 return { 10005 text:element.attr("label"), 10006 children:[], 10007 element: element.get(), 10008 css: element.attr("class") 10009 }; 10010 } 10011 }, 10012 10013 // abstract 10014 prepareOpts: function (opts) { 10015 var element, select, idKey, ajaxUrl, self = this; 10016 10017 element = opts.element; 10018 10019 if (element.get(0).tagName.toLowerCase() === "select") { 10020 this.select = select = opts.element; 10021 } 10022 10023 if (select) { 10024 // these options are not allowed when attached to a select because they are picked up off the element itself 10025 $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () { 10026 if (this in opts) { 10027 throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element."); 10028 } 10029 }); 10030 } 10031 10032 opts = $.extend({}, { 10033 populateResults: function(container, results, query) { 10034 var populate, id=this.opts.id, liveRegion=this.liveRegion; 10035 10036 populate=function(results, container, depth) { 10037 10038 var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted; 10039 10040 results = opts.sortResults(results, container, query); 10041 10042 // collect the created nodes for bulk append 10043 var nodes = []; 10044 for (i = 0, l = results.length; i < l; i = i + 1) { 10045 10046 result=results[i]; 10047 10048 disabled = (result.disabled === true); 10049 selectable = (!disabled) && (id(result) !== undefined); 10050 10051 compound=result.children && result.children.length > 0; 10052 10053 node=$("<li></li>"); 10054 node.addClass("select2-results-dept-"+depth); 10055 node.addClass("select2-result"); 10056 node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable"); 10057 if (disabled) { node.addClass("select2-disabled"); } 10058 if (compound) { node.addClass("select2-result-with-children"); } 10059 node.addClass(self.opts.formatResultCssClass(result)); 10060 node.attr("role", "presentation"); 10061 10062 label=$(document.createElement("div")); 10063 label.addClass("select2-result-label"); 10064 label.attr("id", "select2-result-label-" + nextUid()); 10065 label.attr("role", "option"); 10066 10067 formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup); 10068 if (formatted!==undefined) { 10069 label.html(formatted); 10070 node.append(label); 10071 } 10072 10073 10074 if (compound) { 10075 10076 innerContainer=$("<ul></ul>"); 10077 innerContainer.addClass("select2-result-sub"); 10078 populate(result.children, innerContainer, depth+1); 10079 node.append(innerContainer); 10080 } 10081 10082 node.data("select2-data", result); 10083 nodes.push(node[0]); 10084 } 10085 10086 // bulk append the created nodes 10087 container.append(nodes); 10088 liveRegion.text(opts.formatMatches(results.length)); 10089 }; 10090 10091 populate(results, container, 0); 10092 } 10093 }, $.fn.select2.defaults, opts); 10094 10095 if (typeof(opts.id) !== "function") { 10096 idKey = opts.id; 10097 opts.id = function (e) { return e[idKey]; }; 10098 } 10099 10100 if ($.isArray(opts.element.data("select2Tags"))) { 10101 if ("tags" in opts) { 10102 throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id"); 10103 } 10104 opts.tags=opts.element.data("select2Tags"); 10105 } 10106 10107 if (select) { 10108 opts.query = this.bind(function (query) { 10109 var data = { results: [], more: false }, 10110 term = query.term, 10111 children, placeholderOption, process; 10112 10113 process=function(element, collection) { 10114 var group; 10115 if (element.is("option")) { 10116 if (query.matcher(term, element.text(), element)) { 10117 collection.push(self.optionToData(element)); 10118 } 10119 } else if (element.is("optgroup")) { 10120 group=self.optionToData(element); 10121 element.children().each2(function(i, elm) { process(elm, group.children); }); 10122 if (group.children.length>0) { 10123 collection.push(group); 10124 } 10125 } 10126 }; 10127 10128 children=element.children(); 10129 10130 // ignore the placeholder option if there is one 10131 if (this.getPlaceholder() !== undefined && children.length > 0) { 10132 placeholderOption = this.getPlaceholderOption(); 10133 if (placeholderOption) { 10134 children=children.not(placeholderOption); 10135 } 10136 } 10137 10138 children.each2(function(i, elm) { process(elm, data.results); }); 10139 10140 query.callback(data); 10141 }); 10142 // this is needed because inside val() we construct choices from options and their id is hardcoded 10143 opts.id=function(e) { return e.id; }; 10144 } else { 10145 if (!("query" in opts)) { 10146 10147 if ("ajax" in opts) { 10148 ajaxUrl = opts.element.data("ajax-url"); 10149 if (ajaxUrl && ajaxUrl.length > 0) { 10150 opts.ajax.url = ajaxUrl; 10151 } 10152 opts.query = ajax.call(opts.element, opts.ajax); 10153 } else if ("data" in opts) { 10154 opts.query = local(opts.data); 10155 } else if ("tags" in opts) { 10156 opts.query = tags(opts.tags); 10157 if (opts.createSearchChoice === undefined) { 10158 opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; }; 10159 } 10160 if (opts.initSelection === undefined) { 10161 opts.initSelection = function (element, callback) { 10162 var data = []; 10163 $(splitVal(element.val(), opts.separator)).each(function () { 10164 var obj = { id: this, text: this }, 10165 tags = opts.tags; 10166 if ($.isFunction(tags)) tags=tags(); 10167 $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } }); 10168 data.push(obj); 10169 }); 10170 10171 callback(data); 10172 }; 10173 } 10174 } 10175 } 10176 } 10177 if (typeof(opts.query) !== "function") { 10178 throw "query function not defined for Select2 " + opts.element.attr("id"); 10179 } 10180 10181 if (opts.createSearchChoicePosition === 'top') { 10182 opts.createSearchChoicePosition = function(list, item) { list.unshift(item); }; 10183 } 10184 else if (opts.createSearchChoicePosition === 'bottom') { 10185 opts.createSearchChoicePosition = function(list, item) { list.push(item); }; 10186 } 10187 else if (typeof(opts.createSearchChoicePosition) !== "function") { 10188 throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function"; 10189 } 10190 10191 return opts; 10192 }, 10193 10194 /** 10195 * Monitor the original element for changes and update select2 accordingly 10196 */ 10197 // abstract 10198 monitorSource: function () { 10199 var el = this.opts.element, observer, self = this; 10200 10201 el.on("change.select2", this.bind(function (e) { 10202 if (this.opts.element.data("select2-change-triggered") !== true) { 10203 this.initSelection(); 10204 } 10205 })); 10206 10207 this._sync = this.bind(function () { 10208 10209 // sync enabled state 10210 var disabled = el.prop("disabled"); 10211 if (disabled === undefined) disabled = false; 10212 this.enable(!disabled); 10213 10214 var readonly = el.prop("readonly"); 10215 if (readonly === undefined) readonly = false; 10216 this.readonly(readonly); 10217 10218 syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); 10219 this.container.addClass(evaluate(this.opts.containerCssClass, this.opts.element)); 10220 10221 syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass); 10222 this.dropdown.addClass(evaluate(this.opts.dropdownCssClass, this.opts.element)); 10223 10224 }); 10225 10226 // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener) 10227 if (el.length && el[0].attachEvent) { 10228 el.each(function() { 10229 this.attachEvent("onpropertychange", self._sync); 10230 }); 10231 } 10232 10233 // safari, chrome, firefox, IE11 10234 observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver; 10235 if (observer !== undefined) { 10236 if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } 10237 this.propertyObserver = new observer(function (mutations) { 10238 $.each(mutations, self._sync); 10239 }); 10240 this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false }); 10241 } 10242 }, 10243 10244 // abstract 10245 triggerSelect: function(data) { 10246 var evt = $.Event("select2-selecting", { val: this.id(data), object: data, choice: data }); 10247 this.opts.element.trigger(evt); 10248 return !evt.isDefaultPrevented(); 10249 }, 10250 10251 /** 10252 * Triggers the change event on the source element 10253 */ 10254 // abstract 10255 triggerChange: function (details) { 10256 10257 details = details || {}; 10258 details= $.extend({}, details, { type: "change", val: this.val() }); 10259 // prevents recursive triggering 10260 this.opts.element.data("select2-change-triggered", true); 10261 this.opts.element.trigger(details); 10262 this.opts.element.data("select2-change-triggered", false); 10263 10264 // some validation frameworks ignore the change event and listen instead to keyup, click for selects 10265 // so here we trigger the click event manually 10266 this.opts.element.click(); 10267 10268 // ValidationEngine ignores the change event and listens instead to blur 10269 // so here we trigger the blur event manually if so desired 10270 if (this.opts.blurOnChange) 10271 this.opts.element.blur(); 10272 }, 10273 10274 //abstract 10275 isInterfaceEnabled: function() 10276 { 10277 return this.enabledInterface === true; 10278 }, 10279 10280 // abstract 10281 enableInterface: function() { 10282 var enabled = this._enabled && !this._readonly, 10283 disabled = !enabled; 10284 10285 if (enabled === this.enabledInterface) return false; 10286 10287 this.container.toggleClass("select2-container-disabled", disabled); 10288 this.close(); 10289 this.enabledInterface = enabled; 10290 10291 return true; 10292 }, 10293 10294 // abstract 10295 enable: function(enabled) { 10296 if (enabled === undefined) enabled = true; 10297 if (this._enabled === enabled) return; 10298 this._enabled = enabled; 10299 10300 this.opts.element.prop("disabled", !enabled); 10301 this.enableInterface(); 10302 }, 10303 10304 // abstract 10305 disable: function() { 10306 this.enable(false); 10307 }, 10308 10309 // abstract 10310 readonly: function(enabled) { 10311 if (enabled === undefined) enabled = false; 10312 if (this._readonly === enabled) return; 10313 this._readonly = enabled; 10314 10315 this.opts.element.prop("readonly", enabled); 10316 this.enableInterface(); 10317 }, 10318 10319 // abstract 10320 opened: function () { 10321 return (this.container) ? this.container.hasClass("select2-dropdown-open") : false; 10322 }, 10323 10324 // abstract 10325 positionDropdown: function() { 10326 var $dropdown = this.dropdown, 10327 offset = this.container.offset(), 10328 height = this.container.outerHeight(false), 10329 width = this.container.outerWidth(false), 10330 dropHeight = $dropdown.outerHeight(false), 10331 $window = $(window), 10332 windowWidth = $window.width(), 10333 windowHeight = $window.height(), 10334 viewPortRight = $window.scrollLeft() + windowWidth, 10335 viewportBottom = $window.scrollTop() + windowHeight, 10336 dropTop = offset.top + height, 10337 dropLeft = offset.left, 10338 enoughRoomBelow = dropTop + dropHeight <= viewportBottom, 10339 enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(), 10340 dropWidth = $dropdown.outerWidth(false), 10341 enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight, 10342 aboveNow = $dropdown.hasClass("select2-drop-above"), 10343 bodyOffset, 10344 above, 10345 changeDirection, 10346 css, 10347 resultsListNode; 10348 10349 // always prefer the current above/below alignment, unless there is not enough room 10350 if (aboveNow) { 10351 above = true; 10352 if (!enoughRoomAbove && enoughRoomBelow) { 10353 changeDirection = true; 10354 above = false; 10355 } 10356 } else { 10357 above = false; 10358 if (!enoughRoomBelow && enoughRoomAbove) { 10359 changeDirection = true; 10360 above = true; 10361 } 10362 } 10363 10364 //if we are changing direction we need to get positions when dropdown is hidden; 10365 if (changeDirection) { 10366 $dropdown.hide(); 10367 offset = this.container.offset(); 10368 height = this.container.outerHeight(false); 10369 width = this.container.outerWidth(false); 10370 dropHeight = $dropdown.outerHeight(false); 10371 viewPortRight = $window.scrollLeft() + windowWidth; 10372 viewportBottom = $window.scrollTop() + windowHeight; 10373 dropTop = offset.top + height; 10374 dropLeft = offset.left; 10375 dropWidth = $dropdown.outerWidth(false); 10376 enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight; 10377 $dropdown.show(); 10378 10379 // fix so the cursor does not move to the left within the search-textbox in IE 10380 this.focusSearch(); 10381 } 10382 10383 if (this.opts.dropdownAutoWidth) { 10384 resultsListNode = $('.select2-results', $dropdown)[0]; 10385 $dropdown.addClass('select2-drop-auto-width'); 10386 $dropdown.css('width', ''); 10387 // Add scrollbar width to dropdown if vertical scrollbar is present 10388 dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width); 10389 dropWidth > width ? width = dropWidth : dropWidth = width; 10390 dropHeight = $dropdown.outerHeight(false); 10391 enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight; 10392 } 10393 else { 10394 this.container.removeClass('select2-drop-auto-width'); 10395 } 10396 10397 //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); 10398 //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove); 10399 10400 // fix positioning when body has an offset and is not position: static 10401 if (this.body.css('position') !== 'static') { 10402 bodyOffset = this.body.offset(); 10403 dropTop -= bodyOffset.top; 10404 dropLeft -= bodyOffset.left; 10405 } 10406 10407 if (!enoughRoomOnRight) { 10408 dropLeft = offset.left + this.container.outerWidth(false) - dropWidth; 10409 } 10410 10411 css = { 10412 left: dropLeft, 10413 width: width 10414 }; 10415 10416 if (above) { 10417 css.top = offset.top - dropHeight; 10418 css.bottom = 'auto'; 10419 this.container.addClass("select2-drop-above"); 10420 $dropdown.addClass("select2-drop-above"); 10421 } 10422 else { 10423 css.top = dropTop; 10424 css.bottom = 'auto'; 10425 this.container.removeClass("select2-drop-above"); 10426 $dropdown.removeClass("select2-drop-above"); 10427 } 10428 css = $.extend(css, evaluate(this.opts.dropdownCss, this.opts.element)); 10429 10430 $dropdown.css(css); 10431 }, 10432 10433 // abstract 10434 shouldOpen: function() { 10435 var event; 10436 10437 if (this.opened()) return false; 10438 10439 if (this._enabled === false || this._readonly === true) return false; 10440 10441 event = $.Event("select2-opening"); 10442 this.opts.element.trigger(event); 10443 return !event.isDefaultPrevented(); 10444 }, 10445 10446 // abstract 10447 clearDropdownAlignmentPreference: function() { 10448 // clear the classes used to figure out the preference of where the dropdown should be opened 10449 this.container.removeClass("select2-drop-above"); 10450 this.dropdown.removeClass("select2-drop-above"); 10451 }, 10452 10453 /** 10454 * Opens the dropdown 10455 * 10456 * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example, 10457 * the dropdown is already open, or if the 'open' event listener on the element called preventDefault(). 10458 */ 10459 // abstract 10460 open: function () { 10461 10462 if (!this.shouldOpen()) return false; 10463 10464 this.opening(); 10465 10466 // Only bind the document mousemove when the dropdown is visible 10467 $document.on("mousemove.select2Event", function (e) { 10468 lastMousePosition.x = e.pageX; 10469 lastMousePosition.y = e.pageY; 10470 }); 10471 10472 return true; 10473 }, 10474 10475 /** 10476 * Performs the opening of the dropdown 10477 */ 10478 // abstract 10479 opening: function() { 10480 var cid = this.containerEventName, 10481 scroll = "scroll." + cid, 10482 resize = "resize."+cid, 10483 orient = "orientationchange."+cid, 10484 mask; 10485 10486 this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); 10487 10488 this.clearDropdownAlignmentPreference(); 10489 10490 if(this.dropdown[0] !== this.body.children().last()[0]) { 10491 this.dropdown.detach().appendTo(this.body); 10492 } 10493 10494 // create the dropdown mask if doesn't already exist 10495 mask = $("#select2-drop-mask"); 10496 if (mask.length == 0) { 10497 mask = $(document.createElement("div")); 10498 mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask"); 10499 mask.hide(); 10500 mask.appendTo(this.body); 10501 mask.on("mousedown touchstart click", function (e) { 10502 // Prevent IE from generating a click event on the body 10503 reinsertElement(mask); 10504 10505 var dropdown = $("#select2-drop"), self; 10506 if (dropdown.length > 0) { 10507 self=dropdown.data("select2"); 10508 if (self.opts.selectOnBlur) { 10509 self.selectHighlighted({noFocus: true}); 10510 } 10511 self.close(); 10512 e.preventDefault(); 10513 e.stopPropagation(); 10514 } 10515 }); 10516 } 10517 10518 // ensure the mask is always right before the dropdown 10519 if (this.dropdown.prev()[0] !== mask[0]) { 10520 this.dropdown.before(mask); 10521 } 10522 10523 // move the global id to the correct dropdown 10524 $("#select2-drop").removeAttr("id"); 10525 this.dropdown.attr("id", "select2-drop"); 10526 10527 // show the elements 10528 mask.show(); 10529 10530 this.positionDropdown(); 10531 this.dropdown.show(); 10532 this.positionDropdown(); 10533 10534 this.dropdown.addClass("select2-drop-active"); 10535 10536 // attach listeners to events that can change the position of the container and thus require 10537 // the position of the dropdown to be updated as well so it does not come unglued from the container 10538 var that = this; 10539 this.container.parents().add(window).each(function () { 10540 $(this).on(resize+" "+scroll+" "+orient, function (e) { 10541 if (that.opened()) that.positionDropdown(); 10542 }); 10543 }); 10544 10545 10546 }, 10547 10548 // abstract 10549 close: function () { 10550 if (!this.opened()) return; 10551 10552 var cid = this.containerEventName, 10553 scroll = "scroll." + cid, 10554 resize = "resize."+cid, 10555 orient = "orientationchange."+cid; 10556 10557 // unbind event listeners 10558 this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); }); 10559 10560 this.clearDropdownAlignmentPreference(); 10561 10562 $("#select2-drop-mask").hide(); 10563 this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id 10564 this.dropdown.hide(); 10565 this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); 10566 this.results.empty(); 10567 10568 // Now that the dropdown is closed, unbind the global document mousemove event 10569 $document.off("mousemove.select2Event"); 10570 10571 this.clearSearch(); 10572 this.search.removeClass("select2-active"); 10573 this.opts.element.trigger($.Event("select2-close")); 10574 }, 10575 10576 /** 10577 * Opens control, sets input value, and updates results. 10578 */ 10579 // abstract 10580 externalSearch: function (term) { 10581 this.open(); 10582 this.search.val(term); 10583 this.updateResults(false); 10584 }, 10585 10586 // abstract 10587 clearSearch: function () { 10588 10589 }, 10590 10591 //abstract 10592 getMaximumSelectionSize: function() { 10593 return evaluate(this.opts.maximumSelectionSize, this.opts.element); 10594 }, 10595 10596 // abstract 10597 ensureHighlightVisible: function () { 10598 var results = this.results, children, index, child, hb, rb, y, more, topOffset; 10599 10600 index = this.highlight(); 10601 10602 if (index < 0) return; 10603 10604 if (index == 0) { 10605 10606 // if the first element is highlighted scroll all the way to the top, 10607 // that way any unselectable headers above it will also be scrolled 10608 // into view 10609 10610 results.scrollTop(0); 10611 return; 10612 } 10613 10614 children = this.findHighlightableChoices().find('.select2-result-label'); 10615 10616 child = $(children[index]); 10617 10618 topOffset = (child.offset() || {}).top || 0; 10619 10620 hb = topOffset + child.outerHeight(true); 10621 10622 // if this is the last child lets also make sure select2-more-results is visible 10623 if (index === children.length - 1) { 10624 more = results.find("li.select2-more-results"); 10625 if (more.length > 0) { 10626 hb = more.offset().top + more.outerHeight(true); 10627 } 10628 } 10629 10630 rb = results.offset().top + results.outerHeight(true); 10631 if (hb > rb) { 10632 results.scrollTop(results.scrollTop() + (hb - rb)); 10633 } 10634 y = topOffset - results.offset().top; 10635 10636 // make sure the top of the element is visible 10637 if (y < 0 && child.css('display') != 'none' ) { 10638 results.scrollTop(results.scrollTop() + y); // y is negative 10639 } 10640 }, 10641 10642 // abstract 10643 findHighlightableChoices: function() { 10644 return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)"); 10645 }, 10646 10647 // abstract 10648 moveHighlight: function (delta) { 10649 var choices = this.findHighlightableChoices(), 10650 index = this.highlight(); 10651 10652 while (index > -1 && index < choices.length) { 10653 index += delta; 10654 var choice = $(choices[index]); 10655 if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) { 10656 this.highlight(index); 10657 break; 10658 } 10659 } 10660 }, 10661 10662 // abstract 10663 highlight: function (index) { 10664 var choices = this.findHighlightableChoices(), 10665 choice, 10666 data; 10667 10668 if (arguments.length === 0) { 10669 return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); 10670 } 10671 10672 if (index >= choices.length) index = choices.length - 1; 10673 if (index < 0) index = 0; 10674 10675 this.removeHighlight(); 10676 10677 choice = $(choices[index]); 10678 choice.addClass("select2-highlighted"); 10679 10680 // ensure assistive technology can determine the active choice 10681 this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id")); 10682 10683 this.ensureHighlightVisible(); 10684 10685 this.liveRegion.text(choice.text()); 10686 10687 data = choice.data("select2-data"); 10688 if (data) { 10689 this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data }); 10690 } 10691 }, 10692 10693 removeHighlight: function() { 10694 this.results.find(".select2-highlighted").removeClass("select2-highlighted"); 10695 }, 10696 10697 touchMoved: function() { 10698 this._touchMoved = true; 10699 }, 10700 10701 clearTouchMoved: function() { 10702 this._touchMoved = false; 10703 }, 10704 10705 // abstract 10706 countSelectableResults: function() { 10707 return this.findHighlightableChoices().length; 10708 }, 10709 10710 // abstract 10711 highlightUnderEvent: function (event) { 10712 var el = $(event.target).closest(".select2-result-selectable"); 10713 if (el.length > 0 && !el.is(".select2-highlighted")) { 10714 var choices = this.findHighlightableChoices(); 10715 this.highlight(choices.index(el)); 10716 } else if (el.length == 0) { 10717 // if we are over an unselectable item remove all highlights 10718 this.removeHighlight(); 10719 } 10720 }, 10721 10722 // abstract 10723 loadMoreIfNeeded: function () { 10724 var results = this.results, 10725 more = results.find("li.select2-more-results"), 10726 below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible 10727 page = this.resultsPage + 1, 10728 self=this, 10729 term=this.search.val(), 10730 context=this.context; 10731 10732 if (more.length === 0) return; 10733 below = more.offset().top - results.offset().top - results.height(); 10734 10735 if (below <= this.opts.loadMorePadding) { 10736 more.addClass("select2-active"); 10737 this.opts.query({ 10738 element: this.opts.element, 10739 term: term, 10740 page: page, 10741 context: context, 10742 matcher: this.opts.matcher, 10743 callback: this.bind(function (data) { 10744 10745 // ignore a response if the select2 has been closed before it was received 10746 if (!self.opened()) return; 10747 10748 10749 self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context}); 10750 self.postprocessResults(data, false, false); 10751 10752 if (data.more===true) { 10753 more.detach().appendTo(results).text(evaluate(self.opts.formatLoadMore, self.opts.element, page+1)); 10754 window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); 10755 } else { 10756 more.remove(); 10757 } 10758 self.positionDropdown(); 10759 self.resultsPage = page; 10760 self.context = data.context; 10761 this.opts.element.trigger({ type: "select2-loaded", items: data }); 10762 })}); 10763 } 10764 }, 10765 10766 /** 10767 * Default tokenizer function which does nothing 10768 */ 10769 tokenize: function() { 10770 10771 }, 10772 10773 /** 10774 * @param initial whether or not this is the call to this method right after the dropdown has been opened 10775 */ 10776 // abstract 10777 updateResults: function (initial) { 10778 var search = this.search, 10779 results = this.results, 10780 opts = this.opts, 10781 data, 10782 self = this, 10783 input, 10784 term = search.val(), 10785 lastTerm = $.data(this.container, "select2-last-term"), 10786 // sequence number used to drop out-of-order responses 10787 queryNumber; 10788 10789 // prevent duplicate queries against the same term 10790 if (initial !== true && lastTerm && equal(term, lastTerm)) return; 10791 10792 $.data(this.container, "select2-last-term", term); 10793 10794 // if the search is currently hidden we do not alter the results 10795 if (initial !== true && (this.showSearchInput === false || !this.opened())) { 10796 return; 10797 } 10798 10799 function postRender() { 10800 search.removeClass("select2-active"); 10801 self.positionDropdown(); 10802 if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) { 10803 self.liveRegion.text(results.text()); 10804 } 10805 else { 10806 self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable').length)); 10807 } 10808 } 10809 10810 function render(html) { 10811 results.html(html); 10812 postRender(); 10813 } 10814 10815 queryNumber = ++this.queryCount; 10816 10817 var maxSelSize = this.getMaximumSelectionSize(); 10818 if (maxSelSize >=1) { 10819 data = this.data(); 10820 if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { 10821 render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, opts.element, maxSelSize) + "</li>"); 10822 return; 10823 } 10824 } 10825 10826 if (search.val().length < opts.minimumInputLength) { 10827 if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) { 10828 render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, opts.element, search.val(), opts.minimumInputLength) + "</li>"); 10829 } else { 10830 render(""); 10831 } 10832 if (initial && this.showSearch) this.showSearch(true); 10833 return; 10834 } 10835 10836 if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) { 10837 if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) { 10838 render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, opts.element, search.val(), opts.maximumInputLength) + "</li>"); 10839 } else { 10840 render(""); 10841 } 10842 return; 10843 } 10844 10845 if (opts.formatSearching && this.findHighlightableChoices().length === 0) { 10846 render("<li class='select2-searching'>" + evaluate(opts.formatSearching, opts.element) + "</li>"); 10847 } 10848 10849 search.addClass("select2-active"); 10850 10851 this.removeHighlight(); 10852 10853 // give the tokenizer a chance to pre-process the input 10854 input = this.tokenize(); 10855 if (input != undefined && input != null) { 10856 search.val(input); 10857 } 10858 10859 this.resultsPage = 1; 10860 10861 opts.query({ 10862 element: opts.element, 10863 term: search.val(), 10864 page: this.resultsPage, 10865 context: null, 10866 matcher: opts.matcher, 10867 callback: this.bind(function (data) { 10868 var def; // default choice 10869 10870 // ignore old responses 10871 if (queryNumber != this.queryCount) { 10872 return; 10873 } 10874 10875 // ignore a response if the select2 has been closed before it was received 10876 if (!this.opened()) { 10877 this.search.removeClass("select2-active"); 10878 return; 10879 } 10880 10881 // handle ajax error 10882 if(data.hasError !== undefined && checkFormatter(opts.formatAjaxError, "formatAjaxError")) { 10883 render("<li class='select2-ajax-error'>" + evaluate(opts.formatAjaxError, opts.element, data.jqXHR, data.textStatus, data.errorThrown) + "</li>"); 10884 return; 10885 } 10886 10887 // save context, if any 10888 this.context = (data.context===undefined) ? null : data.context; 10889 // create a default choice and prepend it to the list 10890 if (this.opts.createSearchChoice && search.val() !== "") { 10891 def = this.opts.createSearchChoice.call(self, search.val(), data.results); 10892 if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) { 10893 if ($(data.results).filter( 10894 function () { 10895 return equal(self.id(this), self.id(def)); 10896 }).length === 0) { 10897 this.opts.createSearchChoicePosition(data.results, def); 10898 } 10899 } 10900 } 10901 10902 if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) { 10903 render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, opts.element, search.val()) + "</li>"); 10904 return; 10905 } 10906 10907 results.empty(); 10908 self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null}); 10909 10910 if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) { 10911 results.append("<li class='select2-more-results'>" + opts.escapeMarkup(evaluate(opts.formatLoadMore, opts.element, this.resultsPage)) + "</li>"); 10912 window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); 10913 } 10914 10915 this.postprocessResults(data, initial); 10916 10917 postRender(); 10918 10919 this.opts.element.trigger({ type: "select2-loaded", items: data }); 10920 })}); 10921 }, 10922 10923 // abstract 10924 cancel: function () { 10925 this.close(); 10926 }, 10927 10928 // abstract 10929 blur: function () { 10930 // if selectOnBlur == true, select the currently highlighted option 10931 if (this.opts.selectOnBlur) 10932 this.selectHighlighted({noFocus: true}); 10933 10934 this.close(); 10935 this.container.removeClass("select2-container-active"); 10936 // synonymous to .is(':focus'), which is available in jquery >= 1.6 10937 if (this.search[0] === document.activeElement) { this.search.blur(); } 10938 this.clearSearch(); 10939 this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); 10940 }, 10941 10942 // abstract 10943 focusSearch: function () { 10944 focus(this.search); 10945 }, 10946 10947 // abstract 10948 selectHighlighted: function (options) { 10949 if (this._touchMoved) { 10950 this.clearTouchMoved(); 10951 return; 10952 } 10953 var index=this.highlight(), 10954 highlighted=this.results.find(".select2-highlighted"), 10955 data = highlighted.closest('.select2-result').data("select2-data"); 10956 10957 if (data) { 10958 this.highlight(index); 10959 this.onSelect(data, options); 10960 } else if (options && options.noFocus) { 10961 this.close(); 10962 } 10963 }, 10964 10965 // abstract 10966 getPlaceholder: function () { 10967 var placeholderOption; 10968 return this.opts.element.attr("placeholder") || 10969 this.opts.element.attr("data-placeholder") || // jquery 1.4 compat 10970 this.opts.element.data("placeholder") || 10971 this.opts.placeholder || 10972 ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined); 10973 }, 10974 10975 // abstract 10976 getPlaceholderOption: function() { 10977 if (this.select) { 10978 var firstOption = this.select.children('option').first(); 10979 if (this.opts.placeholderOption !== undefined ) { 10980 //Determine the placeholder option based on the specified placeholderOption setting 10981 return (this.opts.placeholderOption === "first" && firstOption) || 10982 (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select)); 10983 } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") { 10984 //No explicit placeholder option specified, use the first if it's blank 10985 return firstOption; 10986 } 10987 } 10988 }, 10989 10990 /** 10991 * Get the desired width for the container element. This is 10992 * derived first from option `width` passed to select2, then 10993 * the inline 'style' on the original element, and finally 10994 * falls back to the jQuery calculated element width. 10995 */ 10996 // abstract 10997 initContainerWidth: function () { 10998 function resolveContainerWidth() { 10999 var style, attrs, matches, i, l, attr; 11000 11001 if (this.opts.width === "off") { 11002 return null; 11003 } else if (this.opts.width === "element"){ 11004 return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'; 11005 } else if (this.opts.width === "copy" || this.opts.width === "resolve") { 11006 // check if there is inline style on the element that contains width 11007 style = this.opts.element.attr('style'); 11008 if (style !== undefined) { 11009 attrs = style.split(';'); 11010 for (i = 0, l = attrs.length; i < l; i = i + 1) { 11011 attr = attrs[i].replace(/\s/g, ''); 11012 matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i); 11013 if (matches !== null && matches.length >= 1) 11014 return matches[1]; 11015 } 11016 } 11017 11018 if (this.opts.width === "resolve") { 11019 // next check if css('width') can resolve a width that is percent based, this is sometimes possible 11020 // when attached to input type=hidden or elements hidden via css 11021 style = this.opts.element.css('width'); 11022 if (style.indexOf("%") > 0) return style; 11023 11024 // finally, fallback on the calculated width of the element 11025 return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px'); 11026 } 11027 11028 return null; 11029 } else if ($.isFunction(this.opts.width)) { 11030 return this.opts.width(); 11031 } else { 11032 return this.opts.width; 11033 } 11034 }; 11035 11036 var width = resolveContainerWidth.call(this); 11037 if (width !== null) { 11038 this.container.css("width", width); 11039 } 11040 } 11041 }); 11042 11043 SingleSelect2 = clazz(AbstractSelect2, { 11044 11045 // single 11046 11047 createContainer: function () { 11048 var container = $(document.createElement("div")).attr({ 11049 "class": "select2-container" 11050 }).html([ 11051 "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>", 11052 " <span class='select2-chosen'> </span><abbr class='select2-search-choice-close'></abbr>", 11053 " <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>", 11054 "</a>", 11055 "<label for='' class='select2-offscreen'></label>", 11056 "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />", 11057 "<div class='select2-drop select2-display-none'>", 11058 " <div class='select2-search'>", 11059 " <label for='' class='select2-offscreen'></label>", 11060 " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'", 11061 " aria-autocomplete='list' />", 11062 " </div>", 11063 " <ul class='select2-results' role='listbox'>", 11064 " </ul>", 11065 "</div>"].join("")); 11066 return container; 11067 }, 11068 11069 // single 11070 enableInterface: function() { 11071 if (this.parent.enableInterface.apply(this, arguments)) { 11072 this.focusser.prop("disabled", !this.isInterfaceEnabled()); 11073 } 11074 }, 11075 11076 // single 11077 opening: function () { 11078 var el, range, len; 11079 11080 if (this.opts.minimumResultsForSearch >= 0) { 11081 this.showSearch(true); 11082 } 11083 11084 this.parent.opening.apply(this, arguments); 11085 11086 if (this.showSearchInput !== false) { 11087 // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range 11088 // all other browsers handle this just fine 11089 11090 this.search.val(this.focusser.val()); 11091 } 11092 if (this.opts.shouldFocusInput(this)) { 11093 this.search.focus(); 11094 // move the cursor to the end after focussing, otherwise it will be at the beginning and 11095 // new text will appear *before* focusser.val() 11096 el = this.search.get(0); 11097 if (el.createTextRange) { 11098 range = el.createTextRange(); 11099 range.collapse(false); 11100 range.select(); 11101 } else if (el.setSelectionRange) { 11102 len = this.search.val().length; 11103 el.setSelectionRange(len, len); 11104 } 11105 } 11106 11107 // initializes search's value with nextSearchTerm (if defined by user) 11108 // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter 11109 if(this.search.val() === "") { 11110 if(this.nextSearchTerm != undefined){ 11111 this.search.val(this.nextSearchTerm); 11112 this.search.select(); 11113 } 11114 } 11115 11116 this.focusser.prop("disabled", true).val(""); 11117 this.updateResults(true); 11118 this.opts.element.trigger($.Event("select2-open")); 11119 }, 11120 11121 // single 11122 close: function () { 11123 if (!this.opened()) return; 11124 this.parent.close.apply(this, arguments); 11125 11126 this.focusser.prop("disabled", false); 11127 11128 if (this.opts.shouldFocusInput(this)) { 11129 this.focusser.focus(); 11130 } 11131 }, 11132 11133 // single 11134 focus: function () { 11135 if (this.opened()) { 11136 this.close(); 11137 } else { 11138 this.focusser.prop("disabled", false); 11139 if (this.opts.shouldFocusInput(this)) { 11140 this.focusser.focus(); 11141 } 11142 } 11143 }, 11144 11145 // single 11146 isFocused: function () { 11147 return this.container.hasClass("select2-container-active"); 11148 }, 11149 11150 // single 11151 cancel: function () { 11152 this.parent.cancel.apply(this, arguments); 11153 this.focusser.prop("disabled", false); 11154 11155 if (this.opts.shouldFocusInput(this)) { 11156 this.focusser.focus(); 11157 } 11158 }, 11159 11160 // single 11161 destroy: function() { 11162 $("label[for='" + this.focusser.attr('id') + "']") 11163 .attr('for', this.opts.element.attr("id")); 11164 this.parent.destroy.apply(this, arguments); 11165 11166 cleanupJQueryElements.call(this, 11167 "selection", 11168 "focusser" 11169 ); 11170 }, 11171 11172 // single 11173 initContainer: function () { 11174 11175 var selection, 11176 container = this.container, 11177 dropdown = this.dropdown, 11178 idSuffix = nextUid(), 11179 elementLabel; 11180 11181 if (this.opts.minimumResultsForSearch < 0) { 11182 this.showSearch(false); 11183 } else { 11184 this.showSearch(true); 11185 } 11186 11187 this.selection = selection = container.find(".select2-choice"); 11188 11189 this.focusser = container.find(".select2-focusser"); 11190 11191 // add aria associations 11192 selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix); 11193 this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix); 11194 this.results.attr("id", "select2-results-"+idSuffix); 11195 this.search.attr("aria-owns", "select2-results-"+idSuffix); 11196 11197 // rewrite labels from original element to focusser 11198 this.focusser.attr("id", "s2id_autogen"+idSuffix); 11199 11200 elementLabel = $("label[for='" + this.opts.element.attr("id") + "']"); 11201 11202 this.focusser.prev() 11203 .text(elementLabel.text()) 11204 .attr('for', this.focusser.attr('id')); 11205 11206 // Ensure the original element retains an accessible name 11207 var originalTitle = this.opts.element.attr("title"); 11208 this.opts.element.attr("title", (originalTitle || elementLabel.text())); 11209 11210 this.focusser.attr("tabindex", this.elementTabIndex); 11211 11212 // write label for search field using the label from the focusser element 11213 this.search.attr("id", this.focusser.attr('id') + '_search'); 11214 11215 this.search.prev() 11216 .text($("label[for='" + this.focusser.attr('id') + "']").text()) 11217 .attr('for', this.search.attr('id')); 11218 11219 this.search.on("keydown", this.bind(function (e) { 11220 if (!this.isInterfaceEnabled()) return; 11221 11222 // filter 229 keyCodes (input method editor is processing key input) 11223 if (229 == e.keyCode) return; 11224 11225 if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { 11226 // prevent the page from scrolling 11227 killEvent(e); 11228 return; 11229 } 11230 11231 switch (e.which) { 11232 case KEY.UP: 11233 case KEY.DOWN: 11234 this.moveHighlight((e.which === KEY.UP) ? -1 : 1); 11235 killEvent(e); 11236 return; 11237 case KEY.ENTER: 11238 this.selectHighlighted(); 11239 killEvent(e); 11240 return; 11241 case KEY.TAB: 11242 this.selectHighlighted({noFocus: true}); 11243 return; 11244 case KEY.ESC: 11245 this.cancel(e); 11246 killEvent(e); 11247 return; 11248 } 11249 })); 11250 11251 this.search.on("blur", this.bind(function(e) { 11252 // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown. 11253 // without this the search field loses focus which is annoying 11254 if (document.activeElement === this.body.get(0)) { 11255 window.setTimeout(this.bind(function() { 11256 if (this.opened()) { 11257 this.search.focus(); 11258 } 11259 }), 0); 11260 } 11261 })); 11262 11263 this.focusser.on("keydown", this.bind(function (e) { 11264 if (!this.isInterfaceEnabled()) return; 11265 11266 if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { 11267 return; 11268 } 11269 11270 if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { 11271 killEvent(e); 11272 return; 11273 } 11274 11275 if (e.which == KEY.DOWN || e.which == KEY.UP 11276 || (e.which == KEY.ENTER && this.opts.openOnEnter)) { 11277 11278 if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return; 11279 11280 this.open(); 11281 killEvent(e); 11282 return; 11283 } 11284 11285 if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { 11286 if (this.opts.allowClear) { 11287 this.clear(); 11288 } 11289 killEvent(e); 11290 return; 11291 } 11292 })); 11293 11294 11295 installKeyUpChangeEvent(this.focusser); 11296 this.focusser.on("keyup-change input", this.bind(function(e) { 11297 if (this.opts.minimumResultsForSearch >= 0) { 11298 e.stopPropagation(); 11299 if (this.opened()) return; 11300 this.open(); 11301 } 11302 })); 11303 11304 selection.on("mousedown touchstart", "abbr", this.bind(function (e) { 11305 if (!this.isInterfaceEnabled()) return; 11306 this.clear(); 11307 killEventImmediately(e); 11308 this.close(); 11309 this.selection.focus(); 11310 })); 11311 11312 selection.on("mousedown touchstart", this.bind(function (e) { 11313 // Prevent IE from generating a click event on the body 11314 reinsertElement(selection); 11315 11316 if (!this.container.hasClass("select2-container-active")) { 11317 this.opts.element.trigger($.Event("select2-focus")); 11318 } 11319 11320 if (this.opened()) { 11321 this.close(); 11322 } else if (this.isInterfaceEnabled()) { 11323 this.open(); 11324 } 11325 11326 killEvent(e); 11327 })); 11328 11329 dropdown.on("mousedown touchstart", this.bind(function() { 11330 if (this.opts.shouldFocusInput(this)) { 11331 this.search.focus(); 11332 } 11333 })); 11334 11335 selection.on("focus", this.bind(function(e) { 11336 killEvent(e); 11337 })); 11338 11339 this.focusser.on("focus", this.bind(function(){ 11340 if (!this.container.hasClass("select2-container-active")) { 11341 this.opts.element.trigger($.Event("select2-focus")); 11342 } 11343 this.container.addClass("select2-container-active"); 11344 })).on("blur", this.bind(function() { 11345 if (!this.opened()) { 11346 this.container.removeClass("select2-container-active"); 11347 this.opts.element.trigger($.Event("select2-blur")); 11348 } 11349 })); 11350 this.search.on("focus", this.bind(function(){ 11351 if (!this.container.hasClass("select2-container-active")) { 11352 this.opts.element.trigger($.Event("select2-focus")); 11353 } 11354 this.container.addClass("select2-container-active"); 11355 })); 11356 11357 this.initContainerWidth(); 11358 this.opts.element.addClass("select2-offscreen"); 11359 this.setPlaceholder(); 11360 11361 }, 11362 11363 // single 11364 clear: function(triggerChange) { 11365 var data=this.selection.data("select2-data"); 11366 if (data) { // guard against queued quick consecutive clicks 11367 var evt = $.Event("select2-clearing"); 11368 this.opts.element.trigger(evt); 11369 if (evt.isDefaultPrevented()) { 11370 return; 11371 } 11372 var placeholderOption = this.getPlaceholderOption(); 11373 this.opts.element.val(placeholderOption ? placeholderOption.val() : ""); 11374 this.selection.find(".select2-chosen").empty(); 11375 this.selection.removeData("select2-data"); 11376 this.setPlaceholder(); 11377 11378 if (triggerChange !== false){ 11379 this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); 11380 this.triggerChange({removed:data}); 11381 } 11382 } 11383 }, 11384 11385 /** 11386 * Sets selection based on source element's value 11387 */ 11388 // single 11389 initSelection: function () { 11390 var selected; 11391 if (this.isPlaceholderOptionSelected()) { 11392 this.updateSelection(null); 11393 this.close(); 11394 this.setPlaceholder(); 11395 } else { 11396 var self = this; 11397 this.opts.initSelection.call(null, this.opts.element, function(selected){ 11398 if (selected !== undefined && selected !== null) { 11399 self.updateSelection(selected); 11400 self.close(); 11401 self.setPlaceholder(); 11402 self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val()); 11403 } 11404 }); 11405 } 11406 }, 11407 11408 isPlaceholderOptionSelected: function() { 11409 var placeholderOption; 11410 if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered 11411 return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected")) 11412 || (this.opts.element.val() === "") 11413 || (this.opts.element.val() === undefined) 11414 || (this.opts.element.val() === null); 11415 }, 11416 11417 // single 11418 prepareOpts: function () { 11419 var opts = this.parent.prepareOpts.apply(this, arguments), 11420 self=this; 11421 11422 if (opts.element.get(0).tagName.toLowerCase() === "select") { 11423 // install the selection initializer 11424 opts.initSelection = function (element, callback) { 11425 var selected = element.find("option").filter(function() { return this.selected && !this.disabled }); 11426 // a single select box always has a value, no need to null check 'selected' 11427 callback(self.optionToData(selected)); 11428 }; 11429 } else if ("data" in opts) { 11430 // install default initSelection when applied to hidden input and data is local 11431 opts.initSelection = opts.initSelection || function (element, callback) { 11432 var id = element.val(); 11433 //search in data by id, storing the actual matching item 11434 var match = null; 11435 opts.query({ 11436 matcher: function(term, text, el){ 11437 var is_match = equal(id, opts.id(el)); 11438 if (is_match) { 11439 match = el; 11440 } 11441 return is_match; 11442 }, 11443 callback: !$.isFunction(callback) ? $.noop : function() { 11444 callback(match); 11445 } 11446 }); 11447 }; 11448 } 11449 11450 return opts; 11451 }, 11452 11453 // single 11454 getPlaceholder: function() { 11455 // if a placeholder is specified on a single select without a valid placeholder option ignore it 11456 if (this.select) { 11457 if (this.getPlaceholderOption() === undefined) { 11458 return undefined; 11459 } 11460 } 11461 11462 return this.parent.getPlaceholder.apply(this, arguments); 11463 }, 11464 11465 // single 11466 setPlaceholder: function () { 11467 var placeholder = this.getPlaceholder(); 11468 11469 if (this.isPlaceholderOptionSelected() && placeholder !== undefined) { 11470 11471 // check for a placeholder option if attached to a select 11472 if (this.select && this.getPlaceholderOption() === undefined) return; 11473 11474 this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder)); 11475 11476 this.selection.addClass("select2-default"); 11477 11478 this.container.removeClass("select2-allowclear"); 11479 } 11480 }, 11481 11482 // single 11483 postprocessResults: function (data, initial, noHighlightUpdate) { 11484 var selected = 0, self = this, showSearchInput = true; 11485 11486 // find the selected element in the result list 11487 11488 this.findHighlightableChoices().each2(function (i, elm) { 11489 if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { 11490 selected = i; 11491 return false; 11492 } 11493 }); 11494 11495 // and highlight it 11496 if (noHighlightUpdate !== false) { 11497 if (initial === true && selected >= 0) { 11498 this.highlight(selected); 11499 } else { 11500 this.highlight(0); 11501 } 11502 } 11503 11504 // hide the search box if this is the first we got the results and there are enough of them for search 11505 11506 if (initial === true) { 11507 var min = this.opts.minimumResultsForSearch; 11508 if (min >= 0) { 11509 this.showSearch(countResults(data.results) >= min); 11510 } 11511 } 11512 }, 11513 11514 // single 11515 showSearch: function(showSearchInput) { 11516 if (this.showSearchInput === showSearchInput) return; 11517 11518 this.showSearchInput = showSearchInput; 11519 11520 this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput); 11521 this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput); 11522 //add "select2-with-searchbox" to the container if search box is shown 11523 $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput); 11524 }, 11525 11526 // single 11527 onSelect: function (data, options) { 11528 11529 if (!this.triggerSelect(data)) { return; } 11530 11531 var old = this.opts.element.val(), 11532 oldData = this.data(); 11533 11534 this.opts.element.val(this.id(data)); 11535 this.updateSelection(data); 11536 11537 this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data }); 11538 11539 this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val()); 11540 this.close(); 11541 11542 if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) { 11543 this.focusser.focus(); 11544 } 11545 11546 if (!equal(old, this.id(data))) { 11547 this.triggerChange({ added: data, removed: oldData }); 11548 } 11549 }, 11550 11551 // single 11552 updateSelection: function (data) { 11553 11554 var container=this.selection.find(".select2-chosen"), formatted, cssClass; 11555 11556 this.selection.data("select2-data", data); 11557 11558 container.empty(); 11559 if (data !== null) { 11560 formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup); 11561 } 11562 if (formatted !== undefined) { 11563 container.append(formatted); 11564 } 11565 cssClass=this.opts.formatSelectionCssClass(data, container); 11566 if (cssClass !== undefined) { 11567 container.addClass(cssClass); 11568 } 11569 11570 this.selection.removeClass("select2-default"); 11571 11572 if (this.opts.allowClear && this.getPlaceholder() !== undefined) { 11573 this.container.addClass("select2-allowclear"); 11574 } 11575 }, 11576 11577 // single 11578 val: function () { 11579 var val, 11580 triggerChange = false, 11581 data = null, 11582 self = this, 11583 oldData = this.data(); 11584 11585 if (arguments.length === 0) { 11586 return this.opts.element.val(); 11587 } 11588 11589 val = arguments[0]; 11590 11591 if (arguments.length > 1) { 11592 triggerChange = arguments[1]; 11593 } 11594 11595 if (this.select) { 11596 this.select 11597 .val(val) 11598 .find("option").filter(function() { return this.selected }).each2(function (i, elm) { 11599 data = self.optionToData(elm); 11600 return false; 11601 }); 11602 this.updateSelection(data); 11603 this.setPlaceholder(); 11604 if (triggerChange) { 11605 this.triggerChange({added: data, removed:oldData}); 11606 } 11607 } else { 11608 // val is an id. !val is true for [undefined,null,'',0] - 0 is legal 11609 if (!val && val !== 0) { 11610 this.clear(triggerChange); 11611 return; 11612 } 11613 if (this.opts.initSelection === undefined) { 11614 throw new Error("cannot call val() if initSelection() is not defined"); 11615 } 11616 this.opts.element.val(val); 11617 this.opts.initSelection(this.opts.element, function(data){ 11618 self.opts.element.val(!data ? "" : self.id(data)); 11619 self.updateSelection(data); 11620 self.setPlaceholder(); 11621 if (triggerChange) { 11622 self.triggerChange({added: data, removed:oldData}); 11623 } 11624 }); 11625 } 11626 }, 11627 11628 // single 11629 clearSearch: function () { 11630 this.search.val(""); 11631 this.focusser.val(""); 11632 }, 11633 11634 // single 11635 data: function(value) { 11636 var data, 11637 triggerChange = false; 11638 11639 if (arguments.length === 0) { 11640 data = this.selection.data("select2-data"); 11641 if (data == undefined) data = null; 11642 return data; 11643 } else { 11644 if (arguments.length > 1) { 11645 triggerChange = arguments[1]; 11646 } 11647 if (!value) { 11648 this.clear(triggerChange); 11649 } else { 11650 data = this.data(); 11651 this.opts.element.val(!value ? "" : this.id(value)); 11652 this.updateSelection(value); 11653 if (triggerChange) { 11654 this.triggerChange({added: value, removed:data}); 11655 } 11656 } 11657 } 11658 } 11659 }); 11660 11661 MultiSelect2 = clazz(AbstractSelect2, { 11662 11663 // multi 11664 createContainer: function () { 11665 var container = $(document.createElement("div")).attr({ 11666 "class": "select2-container select2-container-multi" 11667 }).html([ 11668 "<ul class='select2-choices'>", 11669 " <li class='select2-search-field'>", 11670 " <label for='' class='select2-offscreen'></label>", 11671 " <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>", 11672 " </li>", 11673 "</ul>", 11674 "<div class='select2-drop select2-drop-multi select2-display-none'>", 11675 " <ul class='select2-results'>", 11676 " </ul>", 11677 "</div>"].join("")); 11678 return container; 11679 }, 11680 11681 // multi 11682 prepareOpts: function () { 11683 var opts = this.parent.prepareOpts.apply(this, arguments), 11684 self=this; 11685 11686 // TODO validate placeholder is a string if specified 11687 11688 if (opts.element.get(0).tagName.toLowerCase() === "select") { 11689 // install the selection initializer 11690 opts.initSelection = function (element, callback) { 11691 11692 var data = []; 11693 11694 element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) { 11695 data.push(self.optionToData(elm)); 11696 }); 11697 callback(data); 11698 }; 11699 } else if ("data" in opts) { 11700 // install default initSelection when applied to hidden input and data is local 11701 opts.initSelection = opts.initSelection || function (element, callback) { 11702 var ids = splitVal(element.val(), opts.separator); 11703 //search in data by array of ids, storing matching items in a list 11704 var matches = []; 11705 opts.query({ 11706 matcher: function(term, text, el){ 11707 var is_match = $.grep(ids, function(id) { 11708 return equal(id, opts.id(el)); 11709 }).length; 11710 if (is_match) { 11711 matches.push(el); 11712 } 11713 return is_match; 11714 }, 11715 callback: !$.isFunction(callback) ? $.noop : function() { 11716 // reorder matches based on the order they appear in the ids array because right now 11717 // they are in the order in which they appear in data array 11718 var ordered = []; 11719 for (var i = 0; i < ids.length; i++) { 11720 var id = ids[i]; 11721 for (var j = 0; j < matches.length; j++) { 11722 var match = matches[j]; 11723 if (equal(id, opts.id(match))) { 11724 ordered.push(match); 11725 matches.splice(j, 1); 11726 break; 11727 } 11728 } 11729 } 11730 callback(ordered); 11731 } 11732 }); 11733 }; 11734 } 11735 11736 return opts; 11737 }, 11738 11739 // multi 11740 selectChoice: function (choice) { 11741 11742 var selected = this.container.find(".select2-search-choice-focus"); 11743 if (selected.length && choice && choice[0] == selected[0]) { 11744 11745 } else { 11746 if (selected.length) { 11747 this.opts.element.trigger("choice-deselected", selected); 11748 } 11749 selected.removeClass("select2-search-choice-focus"); 11750 if (choice && choice.length) { 11751 this.close(); 11752 choice.addClass("select2-search-choice-focus"); 11753 this.opts.element.trigger("choice-selected", choice); 11754 } 11755 } 11756 }, 11757 11758 // multi 11759 destroy: function() { 11760 $("label[for='" + this.search.attr('id') + "']") 11761 .attr('for', this.opts.element.attr("id")); 11762 this.parent.destroy.apply(this, arguments); 11763 11764 cleanupJQueryElements.call(this, 11765 "searchContainer", 11766 "selection" 11767 ); 11768 }, 11769 11770 // multi 11771 initContainer: function () { 11772 11773 var selector = ".select2-choices", selection; 11774 11775 this.searchContainer = this.container.find(".select2-search-field"); 11776 this.selection = selection = this.container.find(selector); 11777 11778 var _this = this; 11779 this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) { 11780 //killEvent(e); 11781 _this.search[0].focus(); 11782 _this.selectChoice($(this)); 11783 }); 11784 11785 // rewrite labels from original element to focusser 11786 this.search.attr("id", "s2id_autogen"+nextUid()); 11787 11788 this.search.prev() 11789 .text($("label[for='" + this.opts.element.attr("id") + "']").text()) 11790 .attr('for', this.search.attr('id')); 11791 11792 this.search.on("input paste", this.bind(function() { 11793 if (this.search.attr('placeholder') && this.search.val().length == 0) return; 11794 if (!this.isInterfaceEnabled()) return; 11795 if (!this.opened()) { 11796 this.open(); 11797 } 11798 })); 11799 11800 this.search.attr("tabindex", this.elementTabIndex); 11801 11802 this.keydowns = 0; 11803 this.search.on("keydown", this.bind(function (e) { 11804 if (!this.isInterfaceEnabled()) return; 11805 11806 ++this.keydowns; 11807 var selected = selection.find(".select2-search-choice-focus"); 11808 var prev = selected.prev(".select2-search-choice:not(.select2-locked)"); 11809 var next = selected.next(".select2-search-choice:not(.select2-locked)"); 11810 var pos = getCursorInfo(this.search); 11811 11812 if (selected.length && 11813 (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) { 11814 var selectedChoice = selected; 11815 if (e.which == KEY.LEFT && prev.length) { 11816 selectedChoice = prev; 11817 } 11818 else if (e.which == KEY.RIGHT) { 11819 selectedChoice = next.length ? next : null; 11820 } 11821 else if (e.which === KEY.BACKSPACE) { 11822 if (this.unselect(selected.first())) { 11823 this.search.width(10); 11824 selectedChoice = prev.length ? prev : next; 11825 } 11826 } else if (e.which == KEY.DELETE) { 11827 if (this.unselect(selected.first())) { 11828 this.search.width(10); 11829 selectedChoice = next.length ? next : null; 11830 } 11831 } else if (e.which == KEY.ENTER) { 11832 selectedChoice = null; 11833 } 11834 11835 this.selectChoice(selectedChoice); 11836 killEvent(e); 11837 if (!selectedChoice || !selectedChoice.length) { 11838 this.open(); 11839 } 11840 return; 11841 } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1) 11842 || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) { 11843 11844 this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last()); 11845 killEvent(e); 11846 return; 11847 } else { 11848 this.selectChoice(null); 11849 } 11850 11851 if (this.opened()) { 11852 switch (e.which) { 11853 case KEY.UP: 11854 case KEY.DOWN: 11855 this.moveHighlight((e.which === KEY.UP) ? -1 : 1); 11856 killEvent(e); 11857 return; 11858 case KEY.ENTER: 11859 this.selectHighlighted(); 11860 killEvent(e); 11861 return; 11862 case KEY.TAB: 11863 this.selectHighlighted({noFocus:true}); 11864 this.close(); 11865 return; 11866 case KEY.ESC: 11867 this.cancel(e); 11868 killEvent(e); 11869 return; 11870 } 11871 } 11872 11873 if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) 11874 || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { 11875 return; 11876 } 11877 11878 if (e.which === KEY.ENTER) { 11879 if (this.opts.openOnEnter === false) { 11880 return; 11881 } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { 11882 return; 11883 } 11884 } 11885 11886 this.open(); 11887 11888 if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { 11889 // prevent the page from scrolling 11890 killEvent(e); 11891 } 11892 11893 if (e.which === KEY.ENTER) { 11894 // prevent form from being submitted 11895 killEvent(e); 11896 } 11897 11898 })); 11899 11900 this.search.on("keyup", this.bind(function (e) { 11901 this.keydowns = 0; 11902 this.resizeSearch(); 11903 }) 11904 ); 11905 11906 this.search.on("blur", this.bind(function(e) { 11907 this.container.removeClass("select2-container-active"); 11908 this.search.removeClass("select2-focused"); 11909 this.selectChoice(null); 11910 if (!this.opened()) this.clearSearch(); 11911 e.stopImmediatePropagation(); 11912 this.opts.element.trigger($.Event("select2-blur")); 11913 })); 11914 11915 this.container.on("click", selector, this.bind(function (e) { 11916 if (!this.isInterfaceEnabled()) return; 11917 if ($(e.target).closest(".select2-search-choice").length > 0) { 11918 // clicked inside a select2 search choice, do not open 11919 return; 11920 } 11921 this.selectChoice(null); 11922 this.clearPlaceholder(); 11923 if (!this.container.hasClass("select2-container-active")) { 11924 this.opts.element.trigger($.Event("select2-focus")); 11925 } 11926 this.open(); 11927 this.focusSearch(); 11928 e.preventDefault(); 11929 })); 11930 11931 this.container.on("focus", selector, this.bind(function () { 11932 if (!this.isInterfaceEnabled()) return; 11933 if (!this.container.hasClass("select2-container-active")) { 11934 this.opts.element.trigger($.Event("select2-focus")); 11935 } 11936 this.container.addClass("select2-container-active"); 11937 this.dropdown.addClass("select2-drop-active"); 11938 this.clearPlaceholder(); 11939 })); 11940 11941 this.initContainerWidth(); 11942 this.opts.element.addClass("select2-offscreen"); 11943 11944 // set the placeholder if necessary 11945 this.clearSearch(); 11946 }, 11947 11948 // multi 11949 enableInterface: function() { 11950 if (this.parent.enableInterface.apply(this, arguments)) { 11951 this.search.prop("disabled", !this.isInterfaceEnabled()); 11952 } 11953 }, 11954 11955 // multi 11956 initSelection: function () { 11957 var data; 11958 if (this.opts.element.val() === "" && this.opts.element.text() === "") { 11959 this.updateSelection([]); 11960 this.close(); 11961 // set the placeholder if necessary 11962 this.clearSearch(); 11963 } 11964 if (this.select || this.opts.element.val() !== "") { 11965 var self = this; 11966 this.opts.initSelection.call(null, this.opts.element, function(data){ 11967 if (data !== undefined && data !== null) { 11968 self.updateSelection(data); 11969 self.close(); 11970 // set the placeholder if necessary 11971 self.clearSearch(); 11972 } 11973 }); 11974 } 11975 }, 11976 11977 // multi 11978 clearSearch: function () { 11979 var placeholder = this.getPlaceholder(), 11980 maxWidth = this.getMaxSearchWidth(); 11981 11982 if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { 11983 this.search.val(placeholder).addClass("select2-default"); 11984 // stretch the search box to full width of the container so as much of the placeholder is visible as possible 11985 // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944 11986 this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width")); 11987 } else { 11988 this.search.val("").width(10); 11989 } 11990 }, 11991 11992 // multi 11993 clearPlaceholder: function () { 11994 if (this.search.hasClass("select2-default")) { 11995 this.search.val("").removeClass("select2-default"); 11996 } 11997 }, 11998 11999 // multi 12000 opening: function () { 12001 this.clearPlaceholder(); // should be done before super so placeholder is not used to search 12002 this.resizeSearch(); 12003 12004 this.parent.opening.apply(this, arguments); 12005 12006 this.focusSearch(); 12007 12008 // initializes search's value with nextSearchTerm (if defined by user) 12009 // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter 12010 if(this.search.val() === "") { 12011 if(this.nextSearchTerm != undefined){ 12012 this.search.val(this.nextSearchTerm); 12013 this.search.select(); 12014 } 12015 } 12016 12017 this.updateResults(true); 12018 if (this.opts.shouldFocusInput(this)) { 12019 this.search.focus(); 12020 } 12021 this.opts.element.trigger($.Event("select2-open")); 12022 }, 12023 12024 // multi 12025 close: function () { 12026 if (!this.opened()) return; 12027 this.parent.close.apply(this, arguments); 12028 }, 12029 12030 // multi 12031 focus: function () { 12032 this.close(); 12033 this.search.focus(); 12034 }, 12035 12036 // multi 12037 isFocused: function () { 12038 return this.search.hasClass("select2-focused"); 12039 }, 12040 12041 // multi 12042 updateSelection: function (data) { 12043 var ids = [], filtered = [], self = this; 12044 12045 // filter out duplicates 12046 $(data).each(function () { 12047 if (indexOf(self.id(this), ids) < 0) { 12048 ids.push(self.id(this)); 12049 filtered.push(this); 12050 } 12051 }); 12052 data = filtered; 12053 12054 this.selection.find(".select2-search-choice").remove(); 12055 $(data).each(function () { 12056 self.addSelectedChoice(this); 12057 }); 12058 self.postprocessResults(); 12059 }, 12060 12061 // multi 12062 tokenize: function() { 12063 var input = this.search.val(); 12064 input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts); 12065 if (input != null && input != undefined) { 12066 this.search.val(input); 12067 if (input.length > 0) { 12068 this.open(); 12069 } 12070 } 12071 12072 }, 12073 12074 // multi 12075 onSelect: function (data, options) { 12076 12077 if (!this.triggerSelect(data) || data.text === "") { return; } 12078 12079 this.addSelectedChoice(data); 12080 12081 this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); 12082 12083 // keep track of the search's value before it gets cleared 12084 this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val()); 12085 12086 this.clearSearch(); 12087 this.updateResults(); 12088 12089 if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true); 12090 12091 if (this.opts.closeOnSelect) { 12092 this.close(); 12093 this.search.width(10); 12094 } else { 12095 if (this.countSelectableResults()>0) { 12096 this.search.width(10); 12097 this.resizeSearch(); 12098 if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) { 12099 // if we reached max selection size repaint the results so choices 12100 // are replaced with the max selection reached message 12101 this.updateResults(true); 12102 } else { 12103 // initializes search's value with nextSearchTerm and update search result 12104 if(this.nextSearchTerm != undefined){ 12105 this.search.val(this.nextSearchTerm); 12106 this.updateResults(); 12107 this.search.select(); 12108 } 12109 } 12110 this.positionDropdown(); 12111 } else { 12112 // if nothing left to select close 12113 this.close(); 12114 this.search.width(10); 12115 } 12116 } 12117 12118 // since its not possible to select an element that has already been 12119 // added we do not need to check if this is a new element before firing change 12120 this.triggerChange({ added: data }); 12121 12122 if (!options || !options.noFocus) 12123 this.focusSearch(); 12124 }, 12125 12126 // multi 12127 cancel: function () { 12128 this.close(); 12129 this.focusSearch(); 12130 }, 12131 12132 addSelectedChoice: function (data) { 12133 var enableChoice = !data.locked, 12134 enabledItem = $( 12135 "<li class='select2-search-choice'>" + 12136 " <div></div>" + 12137 " <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" + 12138 "</li>"), 12139 disabledItem = $( 12140 "<li class='select2-search-choice select2-locked'>" + 12141 "<div></div>" + 12142 "</li>"); 12143 var choice = enableChoice ? enabledItem : disabledItem, 12144 id = this.id(data), 12145 val = this.getVal(), 12146 formatted, 12147 cssClass; 12148 12149 formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup); 12150 if (formatted != undefined) { 12151 choice.find("div").replaceWith("<div>"+formatted+"</div>"); 12152 } 12153 cssClass=this.opts.formatSelectionCssClass(data, choice.find("div")); 12154 if (cssClass != undefined) { 12155 choice.addClass(cssClass); 12156 } 12157 12158 if(enableChoice){ 12159 choice.find(".select2-search-choice-close") 12160 .on("mousedown", killEvent) 12161 .on("click dblclick", this.bind(function (e) { 12162 if (!this.isInterfaceEnabled()) return; 12163 12164 this.unselect($(e.target)); 12165 this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); 12166 killEvent(e); 12167 this.close(); 12168 this.focusSearch(); 12169 })).on("focus", this.bind(function () { 12170 if (!this.isInterfaceEnabled()) return; 12171 this.container.addClass("select2-container-active"); 12172 this.dropdown.addClass("select2-drop-active"); 12173 })); 12174 } 12175 12176 choice.data("select2-data", data); 12177 choice.insertBefore(this.searchContainer); 12178 12179 val.push(id); 12180 this.setVal(val); 12181 }, 12182 12183 // multi 12184 unselect: function (selected) { 12185 var val = this.getVal(), 12186 data, 12187 index; 12188 selected = selected.closest(".select2-search-choice"); 12189 12190 if (selected.length === 0) { 12191 throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; 12192 } 12193 12194 data = selected.data("select2-data"); 12195 12196 if (!data) { 12197 // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued 12198 // and invoked on an element already removed 12199 return; 12200 } 12201 12202 var evt = $.Event("select2-removing"); 12203 evt.val = this.id(data); 12204 evt.choice = data; 12205 this.opts.element.trigger(evt); 12206 12207 if (evt.isDefaultPrevented()) { 12208 return false; 12209 } 12210 12211 while((index = indexOf(this.id(data), val)) >= 0) { 12212 val.splice(index, 1); 12213 this.setVal(val); 12214 if (this.select) this.postprocessResults(); 12215 } 12216 12217 selected.remove(); 12218 12219 this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); 12220 this.triggerChange({ removed: data }); 12221 12222 return true; 12223 }, 12224 12225 // multi 12226 postprocessResults: function (data, initial, noHighlightUpdate) { 12227 var val = this.getVal(), 12228 choices = this.results.find(".select2-result"), 12229 compound = this.results.find(".select2-result-with-children"), 12230 self = this; 12231 12232 choices.each2(function (i, choice) { 12233 var id = self.id(choice.data("select2-data")); 12234 if (indexOf(id, val) >= 0) { 12235 choice.addClass("select2-selected"); 12236 // mark all children of the selected parent as selected 12237 choice.find(".select2-result-selectable").addClass("select2-selected"); 12238 } 12239 }); 12240 12241 compound.each2(function(i, choice) { 12242 // hide an optgroup if it doesn't have any selectable children 12243 if (!choice.is('.select2-result-selectable') 12244 && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) { 12245 choice.addClass("select2-selected"); 12246 } 12247 }); 12248 12249 if (this.highlight() == -1 && noHighlightUpdate !== false){ 12250 self.highlight(0); 12251 } 12252 12253 //If all results are chosen render formatNoMatches 12254 if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){ 12255 if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) { 12256 if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) { 12257 this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.opts.element, self.search.val()) + "</li>"); 12258 } 12259 } 12260 } 12261 12262 }, 12263 12264 // multi 12265 getMaxSearchWidth: function() { 12266 return this.selection.width() - getSideBorderPadding(this.search); 12267 }, 12268 12269 // multi 12270 resizeSearch: function () { 12271 var minimumWidth, left, maxWidth, containerLeft, searchWidth, 12272 sideBorderPadding = getSideBorderPadding(this.search); 12273 12274 minimumWidth = measureTextWidth(this.search) + 10; 12275 12276 left = this.search.offset().left; 12277 12278 maxWidth = this.selection.width(); 12279 containerLeft = this.selection.offset().left; 12280 12281 searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; 12282 12283 if (searchWidth < minimumWidth) { 12284 searchWidth = maxWidth - sideBorderPadding; 12285 } 12286 12287 if (searchWidth < 40) { 12288 searchWidth = maxWidth - sideBorderPadding; 12289 } 12290 12291 if (searchWidth <= 0) { 12292 searchWidth = minimumWidth; 12293 } 12294 12295 this.search.width(Math.floor(searchWidth)); 12296 }, 12297 12298 // multi 12299 getVal: function () { 12300 var val; 12301 if (this.select) { 12302 val = this.select.val(); 12303 return val === null ? [] : val; 12304 } else { 12305 val = this.opts.element.val(); 12306 return splitVal(val, this.opts.separator); 12307 } 12308 }, 12309 12310 // multi 12311 setVal: function (val) { 12312 var unique; 12313 if (this.select) { 12314 this.select.val(val); 12315 } else { 12316 unique = []; 12317 // filter out duplicates 12318 $(val).each(function () { 12319 if (indexOf(this, unique) < 0) unique.push(this); 12320 }); 12321 this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); 12322 } 12323 }, 12324 12325 // multi 12326 buildChangeDetails: function (old, current) { 12327 var current = current.slice(0), 12328 old = old.slice(0); 12329 12330 // remove intersection from each array 12331 for (var i = 0; i < current.length; i++) { 12332 for (var j = 0; j < old.length; j++) { 12333 if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) { 12334 current.splice(i, 1); 12335 if(i>0){ 12336 i--; 12337 } 12338 old.splice(j, 1); 12339 j--; 12340 } 12341 } 12342 } 12343 12344 return {added: current, removed: old}; 12345 }, 12346 12347 12348 // multi 12349 val: function (val, triggerChange) { 12350 var oldData, self=this; 12351 12352 if (arguments.length === 0) { 12353 return this.getVal(); 12354 } 12355 12356 oldData=this.data(); 12357 if (!oldData.length) oldData=[]; 12358 12359 // val is an id. !val is true for [undefined,null,'',0] - 0 is legal 12360 if (!val && val !== 0) { 12361 this.opts.element.val(""); 12362 this.updateSelection([]); 12363 this.clearSearch(); 12364 if (triggerChange) { 12365 this.triggerChange({added: this.data(), removed: oldData}); 12366 } 12367 return; 12368 } 12369 12370 // val is a list of ids 12371 this.setVal(val); 12372 12373 if (this.select) { 12374 this.opts.initSelection(this.select, this.bind(this.updateSelection)); 12375 if (triggerChange) { 12376 this.triggerChange(this.buildChangeDetails(oldData, this.data())); 12377 } 12378 } else { 12379 if (this.opts.initSelection === undefined) { 12380 throw new Error("val() cannot be called if initSelection() is not defined"); 12381 } 12382 12383 this.opts.initSelection(this.opts.element, function(data){ 12384 var ids=$.map(data, self.id); 12385 self.setVal(ids); 12386 self.updateSelection(data); 12387 self.clearSearch(); 12388 if (triggerChange) { 12389 self.triggerChange(self.buildChangeDetails(oldData, self.data())); 12390 } 12391 }); 12392 } 12393 this.clearSearch(); 12394 }, 12395 12396 // multi 12397 onSortStart: function() { 12398 if (this.select) { 12399 throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead."); 12400 } 12401 12402 // collapse search field into 0 width so its container can be collapsed as well 12403 this.search.width(0); 12404 // hide the container 12405 this.searchContainer.hide(); 12406 }, 12407 12408 // multi 12409 onSortEnd:function() { 12410 12411 var val=[], self=this; 12412 12413 // show search and move it to the end of the list 12414 this.searchContainer.show(); 12415 // make sure the search container is the last item in the list 12416 this.searchContainer.appendTo(this.searchContainer.parent()); 12417 // since we collapsed the width in dragStarted, we resize it here 12418 this.resizeSearch(); 12419 12420 // update selection 12421 this.selection.find(".select2-search-choice").each(function() { 12422 val.push(self.opts.id($(this).data("select2-data"))); 12423 }); 12424 this.setVal(val); 12425 this.triggerChange(); 12426 }, 12427 12428 // multi 12429 data: function(values, triggerChange) { 12430 var self=this, ids, old; 12431 if (arguments.length === 0) { 12432 return this.selection 12433 .children(".select2-search-choice") 12434 .map(function() { return $(this).data("select2-data"); }) 12435 .get(); 12436 } else { 12437 old = this.data(); 12438 if (!values) { values = []; } 12439 ids = $.map(values, function(e) { return self.opts.id(e); }); 12440 this.setVal(ids); 12441 this.updateSelection(values); 12442 this.clearSearch(); 12443 if (triggerChange) { 12444 this.triggerChange(this.buildChangeDetails(old, this.data())); 12445 } 12446 } 12447 } 12448 }); 12449 12450 $.fn.select2 = function () { 12451 12452 var args = Array.prototype.slice.call(arguments, 0), 12453 opts, 12454 select2, 12455 method, value, multiple, 12456 allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"], 12457 valueMethods = ["opened", "isFocused", "container", "dropdown"], 12458 propertyMethods = ["val", "data"], 12459 methodsMap = { search: "externalSearch" }; 12460 12461 this.each(function () { 12462 if (args.length === 0 || typeof(args[0]) === "object") { 12463 opts = args.length === 0 ? {} : $.extend({}, args[0]); 12464 opts.element = $(this); 12465 12466 if (opts.element.get(0).tagName.toLowerCase() === "select") { 12467 multiple = opts.element.prop("multiple"); 12468 } else { 12469 multiple = opts.multiple || false; 12470 if ("tags" in opts) {opts.multiple = multiple = true;} 12471 } 12472 12473 select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single(); 12474 select2.init(opts); 12475 } else if (typeof(args[0]) === "string") { 12476 12477 if (indexOf(args[0], allowedMethods) < 0) { 12478 throw "Unknown method: " + args[0]; 12479 } 12480 12481 value = undefined; 12482 select2 = $(this).data("select2"); 12483 if (select2 === undefined) return; 12484 12485 method=args[0]; 12486 12487 if (method === "container") { 12488 value = select2.container; 12489 } else if (method === "dropdown") { 12490 value = select2.dropdown; 12491 } else { 12492 if (methodsMap[method]) method = methodsMap[method]; 12493 12494 value = select2[method].apply(select2, args.slice(1)); 12495 } 12496 if (indexOf(args[0], valueMethods) >= 0 12497 || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) { 12498 return false; // abort the iteration, ready to return first matched value 12499 } 12500 } else { 12501 throw "Invalid arguments to select2 plugin: " + args; 12502 } 12503 }); 12504 return (value === undefined) ? this : value; 12505 }; 12506 12507 // plugin defaults, accessible to users 12508 $.fn.select2.defaults = { 12509 width: "copy", 12510 loadMorePadding: 0, 12511 closeOnSelect: true, 12512 openOnEnter: true, 12513 containerCss: {}, 12514 dropdownCss: {}, 12515 containerCssClass: "", 12516 dropdownCssClass: "", 12517 formatResult: function(result, container, query, escapeMarkup) { 12518 var markup=[]; 12519 markMatch(result.text, query.term, markup, escapeMarkup); 12520 return markup.join(""); 12521 }, 12522 formatSelection: function (data, container, escapeMarkup) { 12523 return data ? escapeMarkup(data.text) : undefined; 12524 }, 12525 sortResults: function (results, container, query) { 12526 return results; 12527 }, 12528 formatResultCssClass: function(data) {return data.css;}, 12529 formatSelectionCssClass: function(data, container) {return undefined;}, 12530 minimumResultsForSearch: 0, 12531 minimumInputLength: 0, 12532 maximumInputLength: null, 12533 maximumSelectionSize: 0, 12534 id: function (e) { return e == undefined ? null : e.id; }, 12535 matcher: function(term, text) { 12536 return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0; 12537 }, 12538 separator: ",", 12539 tokenSeparators: [], 12540 tokenizer: defaultTokenizer, 12541 escapeMarkup: defaultEscapeMarkup, 12542 blurOnChange: false, 12543 selectOnBlur: false, 12544 adaptContainerCssClass: function(c) { return c; }, 12545 adaptDropdownCssClass: function(c) { return null; }, 12546 nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; }, 12547 searchInputPlaceholder: '', 12548 createSearchChoicePosition: 'top', 12549 shouldFocusInput: function (instance) { 12550 // Attempt to detect touch devices 12551 var supportsTouchEvents = (('ontouchstart' in window) || 12552 (navigator.msMaxTouchPoints > 0)); 12553 12554 // Only devices which support touch events should be special cased 12555 if (!supportsTouchEvents) { 12556 return true; 12557 } 12558 12559 // Never focus the input if search is disabled 12560 if (instance.opts.minimumResultsForSearch < 0) { 12561 return false; 12562 } 12563 12564 return true; 12565 } 12566 }; 12567 12568 $.fn.select2.locales = []; 12569 12570 $.fn.select2.locales['en'] = { 12571 formatMatches: function (matches) { if (matches === 1) { return "One result is available, press enter to select it."; } return matches + " results are available, use up and down arrow keys to navigate."; }, 12572 formatNoMatches: function () { return "No matches found"; }, 12573 formatAjaxError: function (jqXHR, textStatus, errorThrown) { return "Loading failed"; }, 12574 formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1 ? "" : "s"); }, 12575 formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1 ? "" : "s"); }, 12576 formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, 12577 formatLoadMore: function (pageNumber) { return "Loading more results…"; }, 12578 formatSearching: function () { return "Searching…"; }, 12579 }; 12580 12581 $.extend($.fn.select2.defaults, $.fn.select2.locales['en']); 12582 12583 $.fn.select2.ajaxDefaults = { 12584 transport: $.ajax, 12585 params: { 12586 type: "GET", 12587 cache: false, 12588 dataType: "json" 12589 } 12590 }; 12591 12592 // exports 12593 window.Select2 = { 12594 query: { 12595 ajax: ajax, 12596 local: local, 12597 tags: tags 12598 }, util: { 12599 debounce: debounce, 12600 markMatch: markMatch, 12601 escapeMarkup: defaultEscapeMarkup, 12602 stripDiacritics: stripDiacritics 12603 }, "class": { 12604 "abstract": AbstractSelect2, 12605 "single": SingleSelect2, 12606 "multi": MultiSelect2 12607 } 12608 }; 12609 12610 }(jQuery)); 12611 12612 /* ============================================================ 12613 * flatui-radiocheck v0.1.0 12614 * ============================================================ */ 12615 12616 +function (global, $) { 12617 'use strict'; 12618 12619 var Radiocheck = function (element, options) { 12620 this.init('radiocheck', element, options); 12621 }; 12622 12623 Radiocheck.DEFAULTS = { 12624 checkboxClass: 'custom-checkbox', 12625 radioClass: 'custom-radio', 12626 checkboxTemplate: '<span class="icons"><span class="icon-unchecked"></span><span class="icon-checked"></span></span>', 12627 radioTemplate: '<span class="icons"><span class="icon-unchecked"></span><span class="icon-checked"></span></span>' 12628 }; 12629 12630 Radiocheck.prototype.init = function (type, element, options) { 12631 this.$element = $(element); 12632 this.options = $.extend({}, Radiocheck.DEFAULTS, this.$element.data(), options); 12633 if (this.$element.attr('type') == 'checkbox') { 12634 this.$element.addClass(this.options.checkboxClass); 12635 this.$element.after(this.options.checkboxTemplate); 12636 } else if (this.$element.attr('type') == 'radio') { 12637 this.$element.addClass(this.options.radioClass); 12638 this.$element.after(this.options.radioTemplate); 12639 } 12640 }; 12641 12642 Radiocheck.prototype.check = function () { 12643 this.$element.prop('checked', true); 12644 this.$element.trigger('change.radiocheck').trigger('checked.radiocheck'); 12645 }, 12646 12647 Radiocheck.prototype.uncheck = function () { 12648 this.$element.prop('checked', false); 12649 this.$element.trigger('change.radiocheck').trigger('unchecked.radiocheck'); 12650 }, 12651 12652 Radiocheck.prototype.toggle = function () { 12653 this.$element.prop('checked', function (i, value) { 12654 return !value; 12655 }); 12656 this.$element.trigger('change.radiocheck').trigger('toggled.radiocheck'); 12657 }, 12658 12659 Radiocheck.prototype.indeterminate = function () { 12660 this.$element.prop('indeterminate', true); 12661 this.$element.trigger('change.radiocheck').trigger('indeterminated.radiocheck'); 12662 }, 12663 12664 Radiocheck.prototype.determinate = function () { 12665 this.$element.prop('indeterminate', false); 12666 this.$element.trigger('change.radiocheck').trigger('determinated.radiocheck'); 12667 }, 12668 12669 Radiocheck.prototype.disable = function () { 12670 this.$element.prop('disabled', true); 12671 this.$element.trigger('change.radiocheck').trigger('disabled.radiocheck'); 12672 }, 12673 12674 Radiocheck.prototype.enable = function () { 12675 this.$element.prop('disabled', false); 12676 this.$element.trigger('change.radiocheck').trigger('enabled.radiocheck'); 12677 }, 12678 12679 Radiocheck.prototype.destroy = function () { 12680 this.$element.removeData().removeClass(this.options.checkboxClass + ' ' + this.options.radioClass).next('.icons').remove(); 12681 this.$element.trigger('destroyed.radiocheck'); 12682 }; 12683 12684 // RADIOCHECK PLUGIN DEFINITION 12685 // ============================ 12686 12687 function Plugin(option) { 12688 return this.each(function () { 12689 var $this = $(this); 12690 var data = $this.data('radiocheck'); 12691 var options = typeof option == 'object' && option; 12692 12693 if (!data && option == 'destroy') { return; } 12694 if (!data) { 12695 $this.data('radiocheck', (data = new Radiocheck(this, options))); 12696 } 12697 if (typeof option == 'string') { 12698 data[option](); 12699 } 12700 12701 // Adding 'nohover' class for mobile devices 12702 12703 var mobile = /mobile|tablet|phone|ip(ad|od)|android|silk|webos/i.test(global.navigator.userAgent); 12704 12705 if (mobile === true) { 12706 $this.parent().hover(function () { 12707 $this.addClass('nohover'); 12708 }, function () { 12709 $this.removeClass('nohover'); 12710 }); 12711 } 12712 }); 12713 } 12714 12715 var old = $.fn.radiocheck; 12716 12717 $.fn.radiocheck = Plugin; 12718 $.fn.radiocheck.Constructor = Radiocheck; 12719 12720 // RADIOCHECK NO CONFLICT 12721 // ====================== 12722 12723 $.fn.radiocheck.noConflict = function () { 12724 $.fn.radiocheck = old; 12725 return this; 12726 }; 12727 12728 }(this, jQuery);