1/*! Backstretch - v2.0.4 - 2013-06-19 2* http://srobbin.com/jquery-plugins/backstretch/ 3* Copyright (c) 2013 Scott Robbin; Licensed MIT */ 4(function(a,d,p){a.fn.backstretch=function(c,b){(c===p||0===c.length)&&a.error("No images were supplied for Backstretch");0===a(d).scrollTop()&&d.scrollTo(0,0);return this.each(function(){var d=a(this),g=d.data("backstretch");if(g){if("string"==typeof c&&"function"==typeof g[c]){g[c](b);return}b=a.extend(g.options,b);g.destroy(!0)}g=new q(this,c,b);d.data("backstretch",g)})};a.backstretch=function(c,b){return a("body").backstretch(c,b).data("backstretch")};a.expr[":"].backstretch=function(c){return a(c).data("backstretch")!==p};a.fn.backstretch.defaults={centeredX:!0,centeredY:!0,duration:5E3,fade:0};var r={left:0,top:0,overflow:"hidden",margin:0,padding:0,height:"100%",width:"100%",zIndex:-999999},s={position:"absolute",display:"none",margin:0,padding:0,border:"none",width:"auto",height:"auto",maxHeight:"none",maxWidth:"none",zIndex:-999999},q=function(c,b,e){this.options=a.extend({},a.fn.backstretch.defaults,e||{});this.images=a.isArray(b)?b:[b];a.each(this.images,function(){a("<img />")[0].src=this});this.isBody=c===document.body;this.$container=a(c);this.$root=this.isBody?l?a(d):a(document):this.$container;c=this.$container.children(".backstretch").first();this.$wrap=c.length?c:a('<div class="backstretch"></div>').css(r).appendTo(this.$container);this.isBody||(c=this.$container.css("position"),b=this.$container.css("zIndex"),this.$container.css({position:"static"===c?"relative":c,zIndex:"auto"===b?0:b,background:"none"}),this.$wrap.css({zIndex:-999998}));this.$wrap.css({position:this.isBody&&l?"fixed":"absolute"});this.index=0;this.show(this.index);a(d).on("resize.backstretch",a.proxy(this.resize,this)).on("orientationchange.backstretch",a.proxy(function(){this.isBody&&0===d.pageYOffset&&(d.scrollTo(0,1),this.resize())},this))};q.prototype={resize:function(){try{var a={left:0,top:0},b=this.isBody?this.$root.width():this.$root.innerWidth(),e=b,g=this.isBody?d.innerHeight?d.innerHeight:this.$root.height():this.$root.innerHeight(),j=e/this.$img.data("ratio"),f;j>=g?(f=(j-g)/2,this.options.centeredY&&(a.top="-"+f+"px")):(j=g,e=j*this.$img.data("ratio"),f=(e-b)/2,this.options.centeredX&&(a.left="-"+f+"px"));this.$wrap.css({width:b,height:g}).find("img:not(.deleteable)").css({width:e,height:j}).css(a)}catch(h){}return this},show:function(c){if(!(Math.abs(c)>this.images.length-1)){var b=this,e=b.$wrap.find("img").addClass("deleteable"),d={relatedTarget:b.$container[0]};b.$container.trigger(a.Event("backstretch.before",d),[b,c]);this.index=c;clearInterval(b.interval);b.$img=a("<img />").css(s).bind("load",function(f){var h=this.width||a(f.target).width();f=this.height||a(f.target).height();a(this).data("ratio",h/f);a(this).fadeIn(b.options.speed||b.options.fade,function(){e.remove();b.paused||b.cycle();a(["after","show"]).each(function(){b.$container.trigger(a.Event("backstretch."+this,d),[b,c])})});b.resize()}).appendTo(b.$wrap);b.$img.attr("src",b.images[c]);return b}},next:function(){return this.show(this.index<this.images.length-1?this.index+1:0)},prev:function(){return this.show(0===this.index?this.images.length-1:this.index-1)},pause:function(){this.paused=!0;return this},resume:function(){this.paused=!1;this.next();return this},cycle:function(){1<this.images.length&&(clearInterval(this.interval),this.interval=setInterval(a.proxy(function(){this.paused||this.next()},this),this.options.duration));return this},destroy:function(c){a(d).off("resize.backstretch orientationchange.backstretch");clearInterval(this.interval);c||this.$wrap.remove();this.$container.removeData("backstretch")}};var l,f=navigator.userAgent,m=navigator.platform,e=f.match(/AppleWebKit\/([0-9]+)/),e=!!e&&e[1],h=f.match(/Fennec\/([0-9]+)/),h=!!h&&h[1],n=f.match(/Opera Mobi\/([0-9]+)/),t=!!n&&n[1],k=f.match(/MSIE ([0-9]+)/),k=!!k&&k[1];l=!((-1<m.indexOf("iPhone")||-1<m.indexOf("iPad")||-1<m.indexOf("iPod"))&&e&&534>e||d.operamini&&"[object OperaMini]"==={}.toString.call(d.operamini)||n&&7458>t||-1<f.indexOf("Android")&&e&&533>e||h&&6>h||"palmGetResource"in d&&e&&534>e||-1<f.indexOf("MeeGo")&&-1<f.indexOf("NokiaBrowser/8.5.0")||k&&6>=k)})(jQuery,window); 5 6/** 7 * Arctext.js 8 * A jQuery plugin for curved text 9 * http://www.codrops.com 10 * 11 * Copyright 2011, Pedro Botelho / Codrops 12 * Free to use under the MIT license. 13 * 14 * Date: Mon Jan 23 2012 15 */ 16 17(function( $, undefined ) { 18 19 /*! 20 * FitText.js 1.0 21 * 22 * Copyright 2011, Dave Rupert http://daverupert.com 23 * Released under the WTFPL license 24 * http://sam.zoy.org/wtfpl/ 25 * 26 * Date: Thu May 05 14:23:00 2011 -0600 27 */ 28 $.fn.fitText = function( kompressor, options ) { 29 30 var settings = { 31 'minFontSize' : Number.NEGATIVE_INFINITY, 32 'maxFontSize' : Number.POSITIVE_INFINITY 33 }; 34 35 return this.each(function() { 36 var $this = $(this); // store the object 37 var compressor = kompressor || 1; // set the compressor 38 39 if ( options ) { 40 $.extend( settings, options ); 41 } 42 43 // Resizer() resizes items based on the object width divided by the compressor * 10 44 var resizer = function () { 45 $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize))); 46 }; 47 48 // Call once to set. 49 resizer(); 50 51 // Call on resize. Opera debounces their resize by default. 52 $(window).resize(resizer); 53 }); 54 55 }; 56 57 /* 58 * Lettering plugin 59 * 60 * changed injector function: 61 * add for empty chars. 62 */ 63 function injector(t, splitter, klass, after) { 64 var a = t.text().split(splitter), inject = '', emptyclass; 65 if (a.length) { 66 $(a).each(function(i, item) { 67 emptyclass = ''; 68 if(item === ' ') { 69 emptyclass = ' empty'; 70 item=' '; 71 } 72 inject += '<span class="'+klass+(i+1)+emptyclass+'">'+item+'</span>'+after; 73 }); 74 t.empty().append(inject); 75 } 76 } 77 78 var methods = { 79 init : function() { 80 81 return this.each(function() { 82 injector($(this), '', 'char', ''); 83 }); 84 85 }, 86 87 words : function() { 88 89 return this.each(function() { 90 injector($(this), ' ', 'word', ' '); 91 }); 92 93 }, 94 95 lines : function() { 96 97 return this.each(function() { 98 var r = "eefec303079ad17405c889e092e105b0"; 99 // Because it's hard to split a <br/> tag consistently across browsers, 100 // (*ahem* IE *ahem*), we replaces all <br/> instances with an md5 hash 101 // (of the word "split"). If you're trying to use this plugin on that 102 // md5 hash string, it will fail because you're being ridiculous. 103 injector($(this).children("br").replaceWith(r).end(), r, 'line', ''); 104 }); 105 106 } 107 }; 108 109 $.fn.lettering = function( method ) { 110 // Method calling logic 111 if ( method && methods[method] ) { 112 return methods[ method ].apply( this, [].slice.call( arguments, 1 ));
113 } else if ( method === 'letters' || ! method ) { 114 return methods.init.apply( this, [].slice.call( arguments, 0 ) ); // always pass an array 115 } 116 $.error( 'Method ' + method + ' does not exist on jQuery.lettering' ); 117 return this; 118 }; 119 120 /* 121 * Arctext object. 122 */ 123 $.Arctext = function( options, element ) { 124 125 this.$el = $( element ); 126 this._init( options ); 127 128 }; 129 130 $.Arctext.defaults = { 131 radius : 0, // the minimum value allowed is half of the word length. if set to -1, the word will be straight. 132 dir : 1, // 1: curve is down, -1: curve is up. 133 rotate : true, // if true each letter will be rotated. 134 fitText : false // if you wanna try out the fitText plugin (http://fittextjs.com/) set this to true. Don't forget the wrapper should be fluid. 135 }; 136 137 $.Arctext.prototype = { 138 _init : function( options ) { 139 140 this.options = $.extend( true, {}, $.Arctext.defaults, options ); 141 142 // apply the lettering plugin. 143 this._applyLettering(); 144 145 this.$el.data( 'arctext', true ); 146 147 // calculate values 148 this._calc(); 149 150 // apply transformation. 151 this._rotateWord(); 152 153 // load the events 154 this._loadEvents(); 155 156 }, 157 _applyLettering : function() { 158 159 this.$el.lettering(); 160 161 if( this.options.fitText ) 162 this.$el.fitText(); 163 164 this.$letters = this.$el.find('span').css('display', 'inline-block'); 165 166 }, 167 _calc : function() { 168 169 if( this.options.radius === -1 ) 170 return false; 171 172 // calculate word / arc sizes & distances. 173 this._calcBase(); 174 175 // get final values for each letter. 176 this._calcLetters(); 177 178 }, 179 _calcBase : function() { 180 181 // total word width (sum of letters widths) 182 this.dtWord = 0; 183 184 var _self = this; 185 186 this.$letters.each( function(i) { 187 188 var $letter = $(this), 189 letterWidth = $letter.outerWidth( true ); 190 191 _self.dtWord += letterWidth; 192 193 // save the center point of each letter: 194 $letter.data( 'center', _self.dtWord - letterWidth / 2 ); 195 196 }); 197 198 // the middle point of the word. 199 var centerWord = this.dtWord / 2; 200 201 // check radius : the minimum value allowed is half of the word length. 202 if( this.options.radius < centerWord ) 203 this.options.radius = centerWord; 204 205 // total arc segment length, where the letters will be placed. 206 this.dtArcBase = this.dtWord; 207 208 // calculate the arc (length) that goes from the beginning of the first letter (x=0) to the end of the last letter (x=this.dtWord). 209 // first lets calculate the angle for the triangle with base = this.dtArcBase and the other two sides = radius. 210 var angle = 2 * Math.asin( this.dtArcBase / ( 2 * this.options.radius ) ); 211 212 // given the formula: L(ength) = R(adius) x A(ngle), we calculate our arc length. 213 this.dtArc = this.options.radius * angle; 214 215 }, 216 _calcLetters : function() { 217 218 var _self = this, 219 iteratorX = 0; 220 221 this.$letters.each( function(i) { 222 223 var $letter = $(this), 224 // calculate each letter's semi arc given the percentage of each letter on the original word. 225 dtArcLetter = ( $letter.outerWidth( true ) / _self.dtWord ) * _self.dtArc, 226 // angle for the dtArcLetter given our radius. 227 beta = dtArcLetter / _self.options.radius, 228 // distance from the middle point of the semi arc's chord to the center of the circle. 229 // this is going to be the place where the letter will be positioned. 230 h = _self.options.radius * ( Math.cos( beta / 2 ) ), 231 // angle formed by the x-axis and the left most point of the chord. 232 alpha = Math.acos( ( _self.dtWord / 2 - iteratorX ) / _self.options.radius ), 233 // angle formed by the x-axis and the right most point of the chord. 234 theta = alpha + beta / 2, 235 // distances of the sides of the triangle formed by h and the orthogonal to the x-axis. 236 x = Math.cos( theta ) * h, 237 y = Math.sin( theta ) * h, 238 // the value for the coordinate x of the middle point of the chord. 239 xpos = iteratorX + Math.abs( _self.dtWord / 2 - x - iteratorX ), 240 // finally, calculate how much to translate each letter, given its center point. 241 // also calculate the angle to rotate the letter accordingly. 242 xval = 0| xpos - $letter.data( 'center' ), 243 yval = 0| _self.options.radius - y, 244 angle = ( _self.options.rotate ) ? 0| -Math.asin( x / _self.options.radius ) * ( 180 / Math.PI ) : 0; 245 246 // the iteratorX will be positioned on the second point of each semi arc 247 iteratorX = 2 * xpos - iteratorX; 248 249 // save these values 250 $letter.data({ 251 x : xval, 252 y : ( _self.options.dir === 1 ) ? yval : -yval, 253 a : ( _self.options.dir === 1 ) ? angle : -angle 254 }); 255 256 }); 257 258 }, 259 _rotateWord : function( animation ) { 260 261 if( !this.$el.data('arctext') ) return false; 262 263 var _self = this; 264 265 this.$letters.each( function(i) { 266 267 var $letter = $(this), 268 transformation = ( _self.options.radius === -1 ) ? 'none' : 'translateX(' + $letter.data('x') + 'px) translateY(' + $letter.data('y') + 'px) rotate(' + $letter.data('a') + 'deg)', 269 transition = ( animation ) ? 'all ' + ( animation.speed || 0 ) + 'ms ' + ( animation.easing || 'linear' ) : 'none'; 270 271 $letter.css({ 272 '-webkit-transition' : transition, 273 '-moz-transition' : transition, 274 '-o-transition' : transition, 275 '-ms-transition' : transition, 276 'transition' : transition 277 }) 278 .css({ 279 '-webkit-transform' : transformation, 280 '-moz-transform' : transformation, 281 '-o-transform' : transformation, 282 '-ms-transform' : transformation, 283 'transform' : transformation 284 }); 285 286 }); 287 288 }, 289 _loadEvents : function() { 290 291 if( this.options.fitText ) { 292 293 var _self = this; 294 295 $(window).on( 'resize.arctext', function() { 296 297 _self._calc(); 298 299 // apply transformation. 300 _self._rotateWord(); 301 302 }); 303 304 } 305 306 }, 307 set : function( opts ) { 308 309 if( !opts.radius && 310 !opts.dir && 311 opts.rotate === 'undefined' ) { 312 return false; 313 } 314 315 this.options.radius = opts.radius || this.options.radius; 316 this.options.dir = opts.dir || this.options.dir; 317 318 if( opts.rotate !== undefined ) { 319 this.options.rotate = opts.rotate; 320 } 321 322 this._calc(); 323 324 this._rotateWord( opts.animation ); 325 326 }, 327 destroy : function() { 328 329 this.options.radius = -1; 330 this._rotateWord(); 331 this.$letters.removeData('x y a center'); 332 this.$el.removeData('arctext'); 333 $(window).off('.arctext'); 334 335 } 336 }; 337 338 var logError = function( message ) { 339 if ( this.console ) { 340 console.error( message ); 341 } 342 }; 343 344 $.fn.arctext = function( options ) { 345 346 if ( typeof options === 'string' ) { 347 348 var args = Array.prototype.slice.call( arguments, 1 ); 349 350 this.each(function() { 351 352 var instance = $.data( this, 'arctext' ); 353 354 if ( !instance ) { 355 logError( "cannot call methods on arctext prior to initialization; " + 356 "attempted to call method '" + options + "'" ); 357 return; 358 } 359 360 if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) { 361 logError( "no such method '" + options + "' for arctext instance" ); 362 return; 363 } 364 365 instance[ options ].apply( instance, args ); 366 367 }); 368 369 } 370 else { 371 372 this.each(function() { 373 374 var instance = $.data( this, 'arctext' ); 375 if ( !instance ) { 376 $.data( this, 'arctext', new $.Arctext( options, this ) ); 377 } 378 }); 379 380 } 381 382 return this; 383 384 }; 385 386})( jQuery ); 387 388 389 390/*!
391 * pickadate.js v3.5.3, 2014/07/12 392 * By Amsul, http://amsul.ca 393 * Hosted on http://amsul.github.io/pickadate.js 394 * Licensed under MIT 395 */ 396 397(function ( factory ) { 398 399 // AMD. 400 if ( typeof define == 'function' && define.amd ) 401 define( 'picker', ['jquery'], factory ) 402 403 // Node.js/browserify. 404 else if ( typeof exports == 'object' ) 405 module.exports = factory( require('jquery') ) 406 407 // Browser globals. 408 else this.Picker = factory( jQuery ) 409 410}(function( $ ) { 411 412var $window = $( window ) 413var $document = $( document ) 414var $html = $( document.documentElement ) 415 416 417/** 418 * The picker constructor that creates a blank picker. 419 */ 420function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { 421 422 // If thereâs no element, return the picker constructor. 423 if ( !ELEMENT ) return PickerConstructor 424 425 426 var 427 IS_DEFAULT_THEME = false, 428 429 430 // The state of the picker. 431 STATE = { 432 id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) 433 }, 434 435 436 // Merge the defaults and options passed. 437 SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {}, 438 439 440 // Merge the default classes with the settings classes. 441 CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ), 442 443 444 // The element node wrapper into a jQuery object. 445 $ELEMENT = $( ELEMENT ), 446 447 448 // Pseudo picker constructor. 449 PickerInstance = function() { 450 return this.start() 451 }, 452 453 454 // The picker prototype. 455 P = PickerInstance.prototype = { 456 457 constructor: PickerInstance, 458 459 $node: $ELEMENT, 460 461 462 /** 463 * Initialize everything 464 */ 465 start: function() { 466 467 // If itâs already started, do nothing. 468 if ( STATE && STATE.start ) return P 469 470 471 // Update the picker states. 472 STATE.methods = {} 473 STATE.start = true 474 STATE.open = false 475 STATE.type = ELEMENT.type 476 477 478 // Confirm focus state, convert into text input to remove UA stylings, 479 // and set as readonly to prevent keyboard popup. 480 ELEMENT.autofocus = ELEMENT == document.activeElement 481 ELEMENT.readOnly = !SETTINGS.editable 482 ELEMENT.id = ELEMENT.id || STATE.id 483 if ( ELEMENT.type != 'text' ) { 484 ELEMENT.type = 'text' 485 } 486 487 488 // Create a new picker component with the settings. 489 P.component = new COMPONENT(P, SETTINGS) 490 491 492 // Create the picker root with a holder and then prepare it. 493 P.$root = $( PickerConstructor._.node('div', createWrappedComponent(), CLASSES.picker, 'id="' + ELEMENT.id + '_root"') ) 494 prepareElementRoot() 495 496 497 // If thereâs a format for the hidden input element, create the element. 498 if ( SETTINGS.formatSubmit ) { 499 prepareElementHidden() 500 } 501 502 503 // Prepare the input element. 504 prepareElement() 505 506 507 // Insert the root as specified in the settings. 508 if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) 509 else $ELEMENT.after( P.$root ) 510 511 512 // Bind the default component and settings events. 513 P.on({ 514 start: P.component.onStart, 515 render: P.component.onRender, 516 stop: P.component.onStop, 517 open: P.component.onOpen, 518 close: P.component.onClose, 519 set: P.component.onSet 520 }).on({ 521 start: SETTINGS.onStart, 522 render: SETTINGS.onRender, 523 stop: SETTINGS.onStop, 524 open: SETTINGS.onOpen, 525 close: SETTINGS.onClose, 526 set: SETTINGS.onSet 527 }) 528 529 530 // Once weâre all set, check the theme in use. 531 IS_DEFAULT_THEME = isUsingDefaultTheme( P.$root.children()[ 0 ] ) 532 533 534 // If the element has autofocus, open the picker. 535 if ( ELEMENT.autofocus ) { 536 P.open() 537 } 538 539 540 // Trigger queued the âstartâ? and ârenderâ? events. 541 return P.trigger( 'start' ).trigger( 'render' ) 542 }, //start 543 544 545 /**
546 * Render a new picker 547 */ 548 render: function( entireComponent ) { 549 550 // Insert a new component holder in the root or box. 551 if ( entireComponent ) P.$root.html( createWrappedComponent() ) 552 else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) 553 554 // Trigger the queued ârenderâ? events. 555 return P.trigger( 'render' ) 556 }, //render 557 558 559 /** 560 * Destroy everything 561 */ 562 stop: function() { 563 564 // If itâs already stopped, do nothing. 565 if ( !STATE.start ) return P 566 567 // Then close the picker. 568 P.close() 569 570 // Remove the hidden field. 571 if ( P._hidden ) { 572 P._hidden.parentNode.removeChild( P._hidden ) 573 } 574 575 // Remove the root. 576 P.$root.remove() 577 578 // Remove the input class, remove the stored data, and unbind 579 // the events (after a tick for IE - see `P.close`). 580 $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) 581 setTimeout( function() { 582 $ELEMENT.off( '.' + STATE.id ) 583 }, 0) 584 585 // Restore the element state 586 ELEMENT.type = STATE.type 587 ELEMENT.readOnly = false 588 589 // Trigger the queued âstopâ? events. 590 P.trigger( 'stop' ) 591 592 // Reset the picker states. 593 STATE.methods = {} 594 STATE.start = false 595 596 return P 597 }, //stop 598 599 600 /** 601 * Open up the picker 602 */ 603 open: function( dontGiveFocus ) { 604 605 // If itâs already open, do nothing. 606 if ( STATE.open ) return P 607 608 // Add the âactiveâ? class. 609 $ELEMENT.addClass( CLASSES.active ) 610 aria( ELEMENT, 'expanded', true ) 611 612 // * A Firefox bug, when `html` has `overflow:hidden`, results in 613 // killing transitions :(. So add the âopenedâ? state on the next tick. 614 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 615 setTimeout( function() { 616 617 // Add the âopenedâ? class to the picker root. 618 P.$root.addClass( CLASSES.opened ) 619 aria( P.$root[0], 'hidden', false ) 620 621 }, 0 ) 622 623 // If we have to give focus, bind the element and doc events. 624 if ( dontGiveFocus !== false ) { 625 626 // Set it as open. 627 STATE.open = true 628 629 // Prevent the page from scrolling. 630 if ( IS_DEFAULT_THEME ) { 631 $html. 632 css( 'overflow', 'hidden' ). 633 css( 'padding-right', '+=' + getScrollbarWidth() ) 634 } 635 636 // Pass focus to the elementâs jQuery object. 637 $ELEMENT.trigger( 'focus' ) 638 639 // Bind the document events. 640 $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { 641 642 var target = event.target 643 644 // If the target of the event is not the element, close the picker picker. 645 // * Donât worry about clicks or focusins on the root because those donât bubble up. 646 // Also, for Firefox, a click on an `option` element bubbles up directly 647 // to the doc. So make sure the target wasn't the doc. 648 // * In Firefox stopPropagation() doesnât prevent right-click events from bubbling, 649 // which causes the picker to unexpectedly close when right-clicking it. So make 650 // sure the event wasnât a right-click. 651 if ( target != ELEMENT && target != document && event.which != 3 ) { 652 653 // If the target was the holder that c
653overs the screen, 654 // keep the element focused to maintain tabindex. 655 P.close( target === P.$root.children()[0] ) 656 } 657 658 }).on( 'keydown.' + STATE.id, function( event ) { 659 660 var 661 // Get the keycode. 662 keycode = event.keyCode, 663 664 // Translate that to a selection change. 665 keycodeToMove = P.component.key[ keycode ], 666 667 // Grab the target. 668 target = event.target 669 670 671 // On escape, close the picker and give focus. 672 if ( keycode == 27 ) { 673 P.close( true ) 674 } 675 676 677 // Check if there is a key movement or âenterâ? keypress on the element. 678 else if ( target == ELEMENT && ( keycodeToMove || keycode == 13 ) ) { 679 680 // Prevent the default action to stop page movement. 681 event.preventDefault() 682 683 // Trigger the key movement action. 684 if ( keycodeToMove ) { 685 PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] ) 686 } 687 688 // On âenterâ?, if the highlighted item isnât disabled, set the value and close. 689 else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) { 690 P.set( 'select', P.component.item.highlight ).close() 691 } 692 } 693 694 695 // If the target is within the root and âenterâ? is pressed, 696 // prevent the default action and trigger a click on the target instead. 697 else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { 698 event.preventDefault() 699 target.click() 700 } 701 }) 702 } 703 704 // Trigger the queued âopenâ? events. 705 return P.trigger( 'open' ) 706 }, //open 707 708 709 /** 710 * Close the picker 711 */ 712 close: function( giveFocus ) { 713 714 // If we need to give focus, do it before changing states. 715 if ( giveFocus ) { 716 // ....ah yes! It wouldâve been incomplete without a crazy workaround for IE :| 717 // The focus is triggered *after* the close has completed - causing it 718 // to open again. So unbind and rebind the event at the next tick. 719 $ELEMENT.off( 'focus.' + STATE.id ).trigger( 'focus' ) 720 setTimeout( function() { 721 $ELEMENT.on( 'focus.' + STATE.id, focusToOpen ) 722 }, 0 ) 723 } 724 725 // Remove the âactiveâ? class. 726 $ELEMENT.removeClass( CLASSES.active ) 727 aria( ELEMENT, 'expanded', false ) 728 729 // * A Firefox bug, when `html` has `overflow:hidden`, results in 730 // killing transitions :(. So remove the âopenedâ? state on the next tick. 731 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 732 setTimeout( function() { 733 734 // Remove the âopenedâ? and âfocusedâ? class from the picker root. 735 P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) 736 aria( P.$root[0], 'hidden', true ) 737 738 }, 0 ) 739 740 // If itâs already closed, do nothing more. 741 if ( !STATE.open ) return P 742 743 // Set it as closed. 744 STATE.open = false 745 746 // Allow the page to scroll. 747 if ( IS_DEFAULT_THEME ) { 748 $html. 749 css( 'overflow', '' ). 750 css( 'padding-right', '-=' + getScrollbarWidth() ) 751 } 752 753 // Unbind the document events. 754 $document.off( '.' + STATE.id ) 755 756 // Trigger the queued âcloseâ? events. 757 return P.trigger( 'close' ) 758 }, //close 759 760 761 /** 762 * Clear the values 763 */ 764 clear: function( options ) { 765 return P.set( 'clear', null, options ) 766 }, //clear 767 768 769 /** 770 * Set something 771 */ 772 set: function( thing, value, options ) { 773 774 var thingItem, thingValue, 775 thingIsObject = $.isPlainObject( thing ), 776 thingObject = thingIsObject ? thing : {} 777 778 // Make sure we have usable options. 779 options = thingIsObject && $.isPlainObject( value ) ? value : options || {} 780 781 if ( thing ) { 782 783 // If the thing isnât an object, make it one. 784 if ( !thingIsObject ) { 785 thingObject[ thing ] = value 786 } 787 788 // Go through the things of items to set. 789 for ( thingItem in thingObject ) { 790 791 // Grab the value of the thing. 792 thingValue = thingObject[ thingItem ] 793 794 // First, if the item exists and thereâs a value, set it. 795 if ( thingItem in P.component.item ) { 796 if ( thingValue === undefined ) thingValue = null 797 P.component.set( thingItem, thingValue, options ) 798 } 799 800 // Then, check to update the element value and broadcast a change. 801 if ( thingItem == 'select' || thingItem == 'clear' ) { 802 $ELEMENT. 803 val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ). 804 trigger( 'change' ) 805 } 806 } 807 808 // Render a new picker. 809 P.render() 810 } 811 812 // When the method isnât muted, trigger queued âsetâ? events and pass the `thingObject`. 813 return options.muted ? P : P.trigger( 'set', thingObject ) 814 }, //set 815 816 817 /** 818 * Get something 819 */ 820 get: function( thing, format ) { 821 822 // Make sure thereâs something to get. 823 thing = thing || 'value' 824 825 // If a picker state exists, return that. 826 if ( STATE[ thing ] != null ) { 827 return STATE[ thing ] 828 } 829 830 // Return the value, if that. 831 if ( thing == 'value' ) { 832 return ELEMENT.value 833 } 834 835 // Check if a component item exists, return that. 836 if ( thing in P.component.item ) { 837 if ( typeof format == 'string' ) { 838 var thingValue = P.component.get( thing ) 839 return thingValue ? 840 PickerConstructor._.trigger( 841 P.component.formats.toString, 842 P.component, 843 [ format, thingValue ] 844 ) : '' 845 } 846 return P.component.get( thing ) 847 } 848 }, //get 849 850 851 852 /** 853 * Bind events on the things. 854 */ 855 on: function( thing, method, internal ) { 856 857 var thingName, thingMethod, 858 thingIsObject = $.isPlainObject( thing ), 859 thingObject = thingIsObject ? thing : {} 860 861 if ( thing ) { 862 863 // If the thing isnât an object, make it one. 864 if ( !thingIsObject ) { 865 thingObject[ thing ] = method 866 } 867 868 // Go through the things to bind to. 869 for ( thingName in thingObject ) { 870 871 // Grab the method of the thing. 872 thingMethod = thingObject[ thingName ] 873 874 // If it was an internal binding, prefix it. 875 if ( internal ) { 876 thingName = '_' + thingName 877 } 878 879 // Make sure the thing methods collection exists. 880 STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] 881 882 // Add the method to the relative method collection. 883 STATE.methods[ thingName ].push( thingMethod ) 884 } 885 } 886 887 return P 888 }, //on 889 890 891 892 /** 893 * Unbind events on the things. 894 */ 895 off: function() { 896 var i, thingName, 897 names = arguments; 898 for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { 899 thingName = names[i] 900 if ( thingName in STATE.methods ) { 901 delete STATE.methods[thingName] 902 } 903 } 904 return P 905 }, 906 907 908 /** 909 * Fire off method events. 910 */ 911 trigger: function( name, data ) { 912 var _trigger = function( name ) { 913 var methodList = STATE.methods[ name ] 914 if ( methodList ) { 915 methodList.map( function( method ) { 916 PickerConstructor._.trigger( method, P, [ data ] ) 917 }) 918 } 919 } 920 _trigger( '_' + name ) 921 _trigger( name ) 922 return P 923 }
923 //trigger 924 } //PickerInstance.prototype 925 926 927 /** 928 * Wrap the picker holder components together. 929 */ 930 function createWrappedComponent() { 931 932 // Create a picker wrapper holder 933 return PickerConstructor._.node( 'div', 934 935 // Create a picker wrapper node 936 PickerConstructor._.node( 'div', 937 938 // Create a picker frame 939 PickerConstructor._.node( 'div', 940 941 // Create a picker box node 942 PickerConstructor._.node( 'div', 943 944 // Create the components nodes. 945 P.component.nodes( STATE.open ), 946 947 // The picker box class 948 CLASSES.box 949 ), 950 951 // Picker wrap class 952 CLASSES.wrap 953 ), 954 955 // Picker frame class 956 CLASSES.frame 957 ), 958 959 // Picker holder class 960 CLASSES.holder 961 ) //endreturn 962 } //createWrappedComponent 963 964 965 966 /** 967 * Prepare the input element with all bindings. 968 */ 969 function prepareElement() { 970 971 $ELEMENT. 972 973 // Store the picker data by component name. 974 data(NAME, P). 975 976 // Add the âinputâ? class name. 977 addClass(CLASSES.input). 978 979 // If thereâs a `data-value`, update the value of the element. 980 val( $ELEMENT.data('value') ? 981 P.get('select', SETTINGS.format) : 982 ELEMENT.value 983 ). 984 985 // On focus/click, open the picker and adjust the root âfocusedâ? state. 986 on('focus.' + STATE.id + ' click.' + STATE.id, focusToOpen) 987 988 989 // Only bind keydown events if the element isnât editable. 990 if ( !SETTINGS.editable ) { 991 992 // Handle keyboard event based on the picker being opened or not. 993 $ELEMENT.on('keydown.' + STATE.id, function(event) { 994 995 var keycode = event.keyCode,
996 997 // Check if one of the delete keys was pressed. 998 isKeycodeDelete = /^(8|46)$/.test(keycode) 999 1000 // For some reason IE clears the input value on âescapeâ?. 1001 if ( keycode == 27 ) { 1002 P.close() 1003 return false 1004 } 1005 1006 // Check if `space` or `delete` was pressed or the picker is closed with a key movement. 1007 if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { 1008 1009 // Prevent it from moving the page and bubbling to doc. 1010 event.preventDefault() 1011 event.stopPropagation() 1012 1013 // If `delete` was pressed, clear the values and close the picker. 1014 // Otherwise open the picker. 1015 if ( isKeycodeDelete ) { P.clear().close() } 1016 else { P.open() } 1017 } 1018 }) 1019 } 1020 1021 1022 // Update the aria attributes. 1023 aria(ELEMENT, { 1024 haspopup: true, 1025 expanded: false, 1026 readonly: false, 1027 owns: ELEMENT.id + '_root' + (P._hidden ? ' ' + P._hidden.id : '') 1028 }) 1029 } 1030 1031 1032 /** 1033 * Prepare the root picker element with all bindings. 1034 */ 1035 function prepareElementRoot() { 1036 1037 P.$root. 1038 1039 on({ 1040 1041 // When something within the root is focused, stop from bubbling 1042 // to the doc and remove the âfocusedâ? state from the root. 1043 focusin: function( event ) { 1044 P.$root.removeClass( CLASSES.focused ) 1045 event.stopPropagation() 1046 }, 1047 1048 // When something within the root holder is clicked, stop it 1049 // from bubbling to the doc. 1050 'mousedown click': function( event ) { 1051 1052 var target = event.target 1053 1054 // Make sure the target isnât the root holder so it can bubble up. 1055 if ( target != P.$root.children()[ 0 ] ) { 1056 1057 event.stopPropagation() 1058 1059 // * For mousedown events, cancel the default action in order to 1060 // prevent cases where focus is shifted onto external elements 1061 // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). 1062 // Also, for Firefox, donât prevent action on the `option` element. 1063 if ( event.type == 'mousedown' && !$( target ).is( ':input' ) && target.nodeName != 'OPTION' ) { 1064 1065 event.preventDefault() 1066 1067 // Re-focus onto the element so that users can click away 1068 // from elements focused within the picker. 1069 ELEMENT.focus() 1070 } 1071 } 1072 } 1073 }). 1074 1075 // If thereâs a click on an actionable element, carry out the actions. 1076 on( 'click', '[data-pick], [data-nav], [data-clear]', function() { 1077 1078 var $target = $( this ), 1079 targetData = $target.data(), 1080 targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ), 1081 1082 // * For IE, non-focusable elements can be active elements as well 1083 // (http://stackoverflow.com/a/2684561). 1084 activeElement = document.activeElement 1085 activeElement = activeElement && ( activeElement.type || activeElement.href ) && activeElement 1086 1087 // If itâs disabled or nothing inside is actively focused, re-focus the element. 1088 if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { 1089 ELEMENT.focus() 1090 } 1091 1092 // If something is superficially changed, update the `highlight` based on the `nav`. 1093 if ( targetData.nav && !targetDisabled ) { 1094 P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } ) 1095 } 1096 1097 // If something is picked, set `select` then close with focus. 1098 else if ( PickerConstructor._.isInteger( targetData.pick ) && !targetDisabled ) { 1099 P.set( 'select', targetData.pick ).close( true ) 1100 } 1101 1102 // If a âclearâ? button is pressed, empty the values and close with focus. 1103 else if ( targetData.clear ) { 1104 P.clear().close( true ) 1105 } 1106 }) 1107 .on('click', '[data-close]', function () { 1108 P.close(true); 1109 }) //P.$root 1110 1111 aria( P.$root[0], 'hidden', true ) 1112 } 1113 1114 1115 /** 1116 * Prepare the hidden input element along with all bindings. 1117 */ 1118 function prepareElementHidden() { 1119 1120 var name 1121 1122 if ( SETTINGS.hiddenName === true ) { 1123 name = ELEMENT.name 1124 ELEMENT.name = '' 1125 } 1126 else { 1127 name = [ 1128 typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', 1129 typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' 1130 ] 1131 name = name[0] + ELEMENT.name + name[1] 1132 } 1133 1134 P._hidden = $( 1135 '<input ' + 1136 'type=hidden ' + 1137 1138 // Create the name using the original inputâs with a prefix and suffix. 1139 'name="' + name + '"' + 1140 1141 // Create the ID using the original inputâs; only if it has one. 1142 (ELEMENT.id ? 'id="' + ELEMENT.id + '_hidden"' : '') + 1143 1144 // If the element has a value, set the hidden value as well. 1145 ( 1146 $ELEMENT.data('value') || ELEMENT.value ? 1147 ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' : 1148 '' 1149 ) + 1150 '>' 1151 )[0] 1152 1153 $ELEMENT. 1154 1155 // If the value changes, update the hidden input with the correct format. 1156 on('change.' + STATE.id, function() { 1157 P._hidden.value = ELEMENT.value ? 1158 P.get('select', SETTINGS.formatSubmit) : 1159 '' 1160 }). 1161 1162 // Insert the hidden input after the element. 1163 after(P._hidden) 1164 } 1165 1166 1167 // Separated for IE 1168 function focusToOpen( event ) { 1169 1170 // Stop the event from propagating to the doc. 1171 event.stopPropagation() 1172 1173 // If itâs a focus event, add the âfocusedâ? class to the root. 1174 if ( event.type == 'focus' ) { 1175 P.$root.addClass( CLASSES.focused ) 1176 } 1177 1178 // And then finally open the picker. 1179 P.open() 1180 } 1181 1182 1183 // Return a new picker instance. 1184 return new PickerInstance() 1185} //PickerConstructor 1186 1187 1188 1189/** 1190 * The default classes and prefix to use for the HTML classes. 1191 */ 1192PickerConstructor.klasses = function( prefix ) { 1193 prefix = prefix || 'picker' 1194 return { 1195 1196 picker: prefix, 1197 opened: prefix + '--opened', 1198 focused: prefix + '--focused', 1199 1200 input: prefix + '__input', 1201 active: prefix + '__input--active', 1202 1203 holder: prefix + '__holder', 1204 1205 frame: prefix + '__frame', 1206 wrap: prefix + '__wrap', 1207 1208 box: prefix + '__box' 1209 } 1210} //PickerConstructor.klasses 1211 1212 1213 1214/** 1215 * Check if the default theme is being used. 1216 */ 1217function isUsingDefaultTheme( element ) { 1218 1219 var theme, 1220 prop = 'position' 1221 1222 // For IE. 1223 if ( element.currentStyle ) { 1224 theme = element.currentStyle[prop] 1225 } 1226 1227 // For normal browsers. 1228 else if ( window.getComputedStyle ) { 1229 theme = getComputedStyle( element )[prop] 1230 } 1231 1232 return theme == 'fixed' 1233} 1234 1235 1236 1237/** 1238 * Get the width of the browserâs scrollbar. 1239 * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js 1240 */ 1241function getScrollbarWidth() { 1242 1243 if ( $html.height() <= $window.height() ) { 1244 return 0 1245 } 1246 1247 var $outer = $( '<div style="visibility:hidden;width:100px" />' ). 1248 appendTo( 'body' ) 1249 1250 // Get the width without scrollbars. 1251 var widthWithoutScroll = $outer[0].offsetWidth 1252 1253 // Force adding scrollbars. 1254 $outer.css( 'overflow', 'scroll' ) 1255 1256 // Add the inner div. 1257 var $inner = $( '<div style="width:100%" />' ).appendTo( $outer ) 1258 1259 // Get the width with scrollbars. 1260 var widthWithScroll = $inner[0].offsetWidth 1261 1262 // Remove the divs. 1263 $outer.remove() 1264 1265 // Return the difference between the widths. 1266 return widthWithoutScroll - widthWithScroll 1267} 1268 1269 1270 1271/** 1272 * PickerConstructor helper methods. 1273 */ 1274PickerConstructor._ = { 1275 1276 /** 1277 * Create a group of nodes. Expects: 1278 * ` 1279 { 1280 min: {Integer}, 1281 max: {Integer}, 1282 i: {Integer}, 1283 node: {String}, 1284 item: {Function} 1285 } 1286 * ` 1287 */ 1288 group: function( groupObject ) { 1289 1290 var 1291 // Scope for the looped object 1292 loopObjectScope, 1293 1294 // Create the nodes list 1295 nodesList = '', 1296 1297 // The counter starts from the `min` 1298 counter = PickerConstructor._.trigger( groupObject.min, groupObject ) 1299 1300 1301 // Loop from the `min` to `max`, incrementing by `i` 1302 for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { 1303 1304 // Trigger the `item` function within scope of the object 1305 loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) 1306 1307 // Splice the subgroup and create nodes out of the sub nodes 1308 nodesList += PickerConstructor._.node( 1309 groupObject.node, 1310 loopObjectScope[ 0 ], // the node 1311 loopObjectScope[ 1 ], // the classes 1312 loopObjectScope[ 2 ] // the attributes 1313 ) 1314 } 1315 1316 // Return the list of nodes 1317 return nodesList 1318 }, //group 1319 1320 1321 /** 1322 * Create a dom node string 1323 */ 1324 node: function( wrapper, item, klass, attribute ) { 1325 1326 // If the item is false-y, just return an empty string 1327 if ( !item ) return '' 1328 1329 // If the item is an array, do a join 1330 item = $.isArray( item ) ? item.join( '' ) : item 1331 1332 // Check for the class 1333 klass = klass ? ' class="' + klass + '"' : '' 1334 1335 // Check for any attributes 1336 attribute = attribute ? ' ' + attribute : '' 1337 1338 // Return the wrapped item 1339 return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>' 1340 }, //node 1341 1342 1343 /** 1344 * Lead numbers below 10 with a zero. 1345 */ 1346 lead: function( number ) { 1347 return ( number < 10 ? '0': '' ) + number 1348 }, 1349 1350 1351 /** 1352 * Trigger a function otherwise return the value. 1353 */ 1354 trigger: function( callback, scope, args ) { 1355 return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback 1356 }, 1357 1358 1359 /** 1360 * If the second character is a digit, length is 2 otherwise 1. 1361 */ 1362 digits: function( string ) { 1363 return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 1364 }, 1365 1366 1367 /** 1368 * Tell if something is a date object. 1369 */ 1370 isDate: function( value ) { 1371 return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) 1372 }, 1373 1374 1375 /** 1376 * Tell if something is an integer. 1377 */ 1378 isInteger: function( value ) { 1379 return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 1380 }, 1381 1382 1383 /** 1384 * Create ARIA attribute strings. 1385 */ 1386 ariaAttr: ariaAttr 1387} //PickerConstructor._ 1388 1389 1390 1391/** 1392 * Extend the picker with a component and defaults. 1393 */ 1394PickerConstructor.extend = function( name, Component ) { 1395 1396 // Extend jQuery. 1397 $.fn[ name ] = function( options, action ) { 1398 1399 // Grab the component data. 1400 var componentData = this.data( name ) 1401 1402 // If the picker is requested, return the data object. 1403 if ( options == 'picker' ) { 1404 return componentData 1405 } 1406 1407 // If the component data exists and `options` is a string, carry out the action. 1408 if ( componentData && typeof options == 'string' ) { 1409 return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) 1410 } 1411 1412 // Otherwise go through each matched element and if the component 1413 // doesnât exist, create a new picker using `this` element 1414 // and merging the defaults and options with a deep copy. 1415 return this.each( function() { 1416 var $this = $( this ) 1417 if ( !$this.data( name ) ) { 1418 new PickerConstructor( this, name, Component, options ) 1419 } 1420 }) 1421 } 1422 1423 // Set the defaults. 1424 $.fn[ name ].defaults = Component.defaults 1425} //PickerConstructor.extend 1426 1427 1428 1429function aria(element, attribute, value) { 1430 if ( $.isPlainObject(attribute) ) { 1431 for ( var key in attribute ) { 1432 ariaSet(element, key, attribute[key]) 1433 } 1434 } 1435 else { 1436 ariaSet(element, attribute, value) 1437 } 1438} 1439function ariaSet(element, attribute, value) { 1440 element.setAttribute( 1441 (attribute == 'role' ? '' : 'aria-') + attribute, 1442 value 1443 ) 1444} 1445function ariaAttr(attribute, data) { 1446 if ( !$.isPlainObject(attribute) ) { 1447 attribute = { attribute: data } 1448 } 1449 data = '' 1450 for ( var key in attribute ) { 1451 var attr = (key == 'role' ? '' : 'aria-') + key, 1452 attrVal = attribute[key] 1453 data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' 1454 } 1455 return data 1456} 1457 1458 1459 1460// Expose the picker constructor. 1461return PickerConstructor 1462 1463 1464})); 1465 1466 1467 1468 1469 1470 1471/*! 1472 * Date picker for pickadate.js v3.5.3 1473 * http://amsul.github.io/pickadate.js/date.htm 1474 */ 1475 1476(function ( factory ) { 1477 1478 // AMD. 1479 if ( typeof define == 'function' && define.amd ) 1480 define( ['picker','jquery'], factory ) 1481 1482 // Node.js/browserify. 1483 else if ( typeof exports == 'object' ) 1484 module.exports = factory( require('./picker.js'), require('jquery') ) 1485 1486 // Browser globals. 1487 else factory( Picker, jQuery ) 1488 1489}(function( Picker, $ ) { 1490 1491 1492/** 1493 * Globals and constants 1494 */ 1495var DAYS_IN_WEEK = 7, 1496 WEEKS_IN_CALENDAR = 6, 1497 _ = Picker._ 1498 1499 1500 1501/** 1502 * The date picker constructor 1503 */ 1504function DatePicker( picker, settings ) { 1505 1506 var calendar = this, 1507 element = picker.$node[ 0 ], 1508 elementValue = element.value, 1509 elementDataValue = picker.$node.data( 'value' ), 1510 valueString = elementDataValue || elementValue, 1511 formatString = elementDataValue ? settings.formatSubmit : settings.format, 1512 isRTL = function() { 1513 1514 return element.currentStyle ? 1515 1516 // For IE. 1517 element.currentStyle.direction == 'rtl' : 1518 1519 // For normal browsers. 1520 getComputedStyle( picker.$root[0] ).direction == 'rtl'
1521 } 1522 1523 calendar.settings = settings 1524 calendar.$node = picker.$node 1525 1526 // The queue of methods that will be used to build item objects. 1527 calendar.queue = { 1528 min: 'measure create', 1529 max: 'measure create', 1530 now: 'now create', 1531 select: 'parse create validate', 1532 highlight: 'parse navigate create validate', 1533 view: 'parse create validate viewset', 1534 disable: 'deactivate', 1535 enable: 'activate' 1536 } 1537 1538 // The component's item object. 1539 calendar.item = {} 1540 1541 calendar.item.clear = null 1542 calendar.item.disable = ( settings.disable || [] ).slice( 0 ) 1543 calendar.item.enable = -(function( collectionDisabled ) { 1544 return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 1545 })( calendar.item.disable ) 1546 1547 calendar. 1548 set( 'min', settings.min ). 1549 set( 'max', settings.max ). 1550 set( 'now' ) 1551 1552 // When thereâs a value, set the `select`, which in turn 1553 // also sets the `highlight` and `view`. 1554 if ( valueString ) { 1555 calendar.set( 'select', valueString, { format: formatString }) 1556 } 1557 1558 // If thereâs no value, default to highlighting âtodayâ?. 1559 else { 1560 calendar. 1561 set( 'select', null ). 1562 set( 'highlight', calendar.item.now ) 1563 } 1564 1565 1566 // The keycode to movement mapping. 1567 calendar.key = { 1568 40: 7, // Down 1569 38: -7, // Up 1570 39: function() { return isRTL() ? -1 : 1 }, // Right 1571 37: function() { return isRTL() ? 1 : -1 }, // Left 1572 go: function( timeChange ) { 1573 var highlightedObject = calendar.item.highlight, 1574 targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) 1575 calendar.set( 1576 'highlight', 1577 [ targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate() ], 1578 { interval: timeChange } 1579 ) 1580 this.render() 1581 } 1582 } 1583 1584 1585 // Bind some picker events. 1586 picker. 1587 on( 'render', function() { 1588 picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { 1589 var value = this.value 1590 if ( value ) { 1591 picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) 1592 picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) 1593 } 1594 }) 1595 picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { 1596 var value = this.value 1597 if ( value ) { 1598 picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) 1599 picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) 1600 } 1601 }) 1602 }, 1 ). 1603 on( 'open', function() { 1604 var includeToday = '' 1605 if ( calendar.disabled( calendar.get('now') ) ) { 1606 includeToday = ':not(.' + settings.klass.buttonToday + ')' 1607 } 1608 picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false ) 1609 }, 1 ). 1610 on( 'close', function() { 1611 picker.$root.find( 'button, select' ).attr( 'disabled', true ) 1612 }, 1 ) 1613 1614} //DatePicker 1615 1616 1617/** 1618 * Set a datepicker item object. 1619 */ 1620DatePicker.prototype.set = function( type, value, options ) { 1621 1622 var calendar = this, 1623 calendarItem = calendar.item 1624 1625 // If the value is `null` just set it immediately. 1626 if ( value === null ) { 1627 if ( type == 'clear' ) type = 'select' 1628 calendarItem[ type ] = value 1629 return calendar 1630 } 1631 1632 // Otherwise go through the queue of methods, and invoke the functions. 1633 // Update this as the time unit, and set the final value as this item. 1634 // * In the case of `enable`, keep the queue but set `disable` instead. 1635 // And in the case of `flip`, keep the queue but set `enable` instead. 1636 calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { 1637 value = calendar[ method ]( type, value, options ) 1638 return value 1639 }).pop() 1640 1641 // Check if we need to cascade through more updates. 1642 if ( type == 'select' ) { 1643 calendar.set( 'highlight', calendarItem.select, options ) 1644 } 1645 else if ( type == 'highlight' ) { 1646 calendar.set( 'view', calendarItem.highlight, options ) 1647 } 1648 else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { 1649 if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) { 1650 calendar.set( 'select', calendarItem.select, options ) 1651 } 1652 if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) { 1653 calendar.set( 'highlight', calendarItem.highlight, options ) 1654 } 1655 } 1656 1657 return calendar 1658} //DatePicker.prototype.set 1659 1660 1661/** 1662 * Get a datepicker item object. 1663 */ 1664DatePicker.prototype.get = function( type ) { 1665 return this.item[ type ] 1666} //DatePicker.prototype.get 1667 1668 1669/** 1670 * Create a picker date object. 1671 */ 1672DatePicker.prototype.create = function( type, value, options ) { 1673 1674 var isInfiniteValue, 1675 calendar = this 1676 1677 // If thereâs no value, use the type as the value. 1678 value = value === undefined ? type : value 1679 1680 1681 // If itâs infinity, update the value. 1682 if ( value == -Infinity || value == Infinity ) { 1683 isInfiniteValue = value 1684 } 1685 1686 // If itâs an object, use the native date object. 1687 else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 1688 value = value.obj 1689 } 1690 1691 // If itâs an array, convert it into a date and make sure 1692 // that itâs a valid date â otherwise default to today. 1693 else if ( $.isArray( value ) ) { 1694 value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) 1695 value = _.isDate( value ) ? value : calendar.create().obj 1696 } 1697 1698 // If itâs a number or date object, make a normalized date. 1699 else if ( _.isInteger( value ) || _.isDate( value ) ) { 1700 value = calendar.normalize( new Date( value ), options ) 1701 } 1702 1703 // If itâs a literal true or any other case, set it to now. 1704 else /*if ( value === true )*/ { 1705 value = calendar.now( type, value, options ) 1706 } 1707 1708 // Return the compiled object. 1709 return { 1710 year: isInfiniteValue || value.getFullYear(), 1711 month: isInfiniteValue || value.getMonth(), 1712 date: isInfiniteValue || value.getDate(), 1713 day: isInfiniteValue || value.getDay(), 1714 obj: isInfiniteValue || value, 1715 pick: isInfiniteValue || value.getTime() 1716 } 1717} //DatePicker.prototype.create 1718 1719 1720/** 1721 * Create a range limit object using an array, date object, 1722 * literal âtrueâ?, or integer relative to another time. 1723 */ 1724DatePicker.prototype.createRange = function( from, to ) { 1725 1726 var calendar = this, 1727 createDate = function( date ) { 1728 if ( date === true || $.isArray( date ) || _.isDate( date ) ) { 1729 return calendar.create( date ) 1730 } 1731 return date 1732 } 1733 1734 // Create objects if possible. 1735 if ( !_.isInteger( from ) ) { 1736 from = createDate( from ) 1737 } 1738 if ( !_.isInteger( to ) ) { 1739 to = createDate( to ) 1740 } 1741 1742 // Create relative dates. 1743 if ( _.isInteger( from ) && $.isPlainObject( to ) ) { 1744 from = [ to.year, to.month, to.date + from ]; 1745 } 1746 else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { 1747 to = [ from.year, from.month, from.date + to ]; 1748 } 1749 1750 return { 1751 from: createDate( from ), 1752 to: createDate( to ) 1753 } 1754} //DatePicker.prototype.createRange 1755 1756 1757/** 1758 * Check if a date unit falls within a date range object. 1759 */ 1760DatePicker.prototype.withinRange = function( range, dateUnit ) { 1761 range = this.createRange(range.from, range.to) 1762 return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick 1763} 1764 1765 1766/** 1767 * Check if two date range objects overlap. 1768 */ 1769DatePicker.prototype.overlapRanges = function( one, two ) { 1770 1771 var calendar = this 1772 1773 // Convert the ranges into comparable dates. 1774 one = calendar.createRange( one.from, one.to ) 1775 two = calendar.createRange( two.from, two.to ) 1776 1777 return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || 1778 calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) 1779} 1780 1781 1782/** 1783 * Get the date today. 1784 */ 1785DatePicker.prototype.now = function( type, value, options ) { 1786 value = new Date() 1787 if ( options && options.rel ) { 1788 value.setDate( value.getDate() + options.rel ) 1789 } 1790 return this.normalize( value, options ) 1791} 1792 1793 1794/** 1795 * Navigate to next/prev month. 1796 */ 1797DatePicker.prototype.navigate = function( type, value, options ) { 1798 1799 var targetDateObject, 1800 targetYear, 1801 targetMonth, 1802 targetDate, 1803 isTargetArray = $.isArray( value ), 1804 isTargetObject = $.isPlainObject( value ), 1805 viewsetObject = this.item.view/*, 1806 safety = 100*/ 1807 1808 1809 if ( isTargetArray || isTargetObject ) { 1810 1811 if ( isTargetObject ) { 1812 targetYear = value.year 1813 targetMonth = value.month 1814 targetDate = value.date 1815 } 1816 else { 1817 targetYear = +value[0] 1818 targetMonth = +value[1] 1819 targetDate = +value[2] 1820 } 1821 1822 // If weâre navigating months but the view is in a different 1823 // month, navigate to the viewâs year and month. 1824 if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { 1825 targetYear = viewsetObject.year 1826 targetMonth = viewsetObject.month 1827 } 1828 1829 // Figure out the expected target year and month. 1830 targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) 1831 targetYear = targetDateObject.getFullYear() 1832 targetMonth = targetDateObject.getMonth() 1833 1834 // If the month weâre going to doesnât have enough days, 1835 // keep decreasing the date until we reach the monthâs last date. 1836 while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) { 1837 targetDate -= 1 1838 /*safety -= 1 1839 if ( !safety ) { 1840 throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.' 1841 }*/ 1842 } 1843 1844 value = [ targetYear, targetMonth, targetDate ] 1845 } 1846 1847 return value 1848} //DatePicker.prototype.navigate 1849 1850 1851/** 1852 * Normalize a date by setting the hours to midnight. 1853 */ 1854DatePicker.prototype.normalize = function( value/*, options*/ ) { 1855 value.setHours( 0, 0, 0, 0 ) 1856 return value 1857} 1858 1859 1860/** 1861 * Measure the range of dates. 1862 */ 1863DatePicker.prototype.measure = function( type, value/*, options*/ ) { 1864 1865 var calendar = this 1866 1867 // If itâs anything false-y, remove the limits. 1868 if ( !value ) { 1869 value = type == 'min' ? -Infinity : Infinity 1870 } 1871 1872 // If itâs a string, parse it. 1873 else if ( typeof value == 'string' ) { 1874 value = calendar.parse( type, value ) 1875 } 1876 1877 // If it's an integer, get a date relative to today. 1878 else if ( _.isInteger( value ) ) { 1879 value = calendar.now( type, value, { rel: value } ) 1880 } 1881 1882 return value 1883} ///DatePicker.prototype.measure 1884 1885 1886/** 1887 * Create a viewset object based on navigation. 1888 */ 1889DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { 1890 return this.create([ dateObject.year, dateObject.month, 1 ]) 1891} 1892 1893 1894/** 1895 * Validate a date as enabled and shift if needed. 1896 */ 1897DatePicker.prototype.validate = function( type, dateObject, options ) { 1898 1899 var calendar = this, 1900 1901 // Keep a reference to the original date. 1902 originalDateObject = dateObject, 1903 1904 // Make sure we have an interval. 1905 interval = options && options.interval ? options.interval : 1, 1906 1907 // Check if the calendar enabled dates are inverted. 1908 isFlippedBase = calendar.item.enable === -1, 1909 1910 // Check if we have any enabled dates after/before now. 1911 hasEnabledBeforeTarget, hasEnabledAfterTarget, 1912 1913 // The min & max limits. 1914 minLimitObject = calendar.item.min, 1915 maxLimitObject = calendar.item.max, 1916 1917 // Check if weâve reached the limit during shifting. 1918 reachedMin, reachedMax, 1919 1920 // Check if the calendar is inverted and at least one weekday is enabled. 1921 hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) { 1922 1923 // If thereâs a date, check where it is relative to the target. 1924 if ( $.isArray( value ) ) { 1925 var dateTime = calendar.create( value ).pick 1926 if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true 1927 else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true 1928 } 1929 1930 // Return only integers for enabled weekdays. 1931 return _.isInteger( value ) 1932 }).length/*, 1933 1934 safety = 100*/ 1935 1936 1937 1938 // Cases to validate for: 1939 // [1] Not inverted and date disabled. 1940 // [2] Inverted and some dates enabled. 1941 // [3] Not inverted and out of range. 1942 // 1943 // Cases to **not** validate for: 1944 // ⢠Navigating months. 1945 // ⢠Not inverted and date enabled. 1946 // ⢠Inverted and all dates disabled. 1947 // ⢠..and anything else. 1948 if ( !options || !options.nav ) if ( 1949 /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) || 1950 /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) || 1951 /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) ) 1952 ) { 1953 1954 1955 // When inverted, flip the direction if there arenât any enabled weekdays 1956 // and there are no enabled dates in the direction of the interval. 1957 if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) { 1958 interval *= -1 1959 } 1960 1961 1962 // Keep looping until we reach an enabled date. 1963 while ( /*safety &&*/ calendar.disabled( dateObject ) ) { 1964 1965 /*safety -= 1 1966 if ( !safety ) { 1967 throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.' 1968 }*/ 1969 1970 1971 // If weâve looped into the next/prev month with a large interval, return to the original date and flatten the interval. 1972 if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { 1973 dateObject = originalDateObject 1974 interval = interval > 0 ? 1 : -1 1975 } 1976 1977 1978 // If weâve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. 1979 if ( dateObject.pick <= minLimitObject.pick ) { 1980 reachedMin = true 1981 interval = 1 1982 dateObject = calendar.create([ 1983 minLimitObject.year, 1984 minLimitObject.month, 1985 minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1) 1986 ]) 1987 } 1988 else if ( dateObject.pick >= maxLimitObject.pick ) { 1989 reachedMax = true 1990 interval = -1 1991 dateObject = calendar.create([ 1992 maxLimitObject.year, 1993 maxLimitObject.month, 1994 maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1) 1995 ]) 1996 } 1997 1998 1999 // If weâve reached both limits, just break out of the loop. 2000 if (
2000 reachedMin && reachedMax ) { 2001 break 2002 } 2003 2004 2005 // Finally, create the shifted date using the interval and keep looping. 2006 dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ]) 2007 } 2008 2009 } //endif 2010 2011 2012 // Return the date object settled on. 2013 return dateObject 2014} //DatePicker.prototype.validate 2015 2016 2017/** 2018 * Check if a date is disabled. 2019 */ 2020DatePicker.prototype.disabled = function( dateToVerify ) { 2021 2022 var 2023 calendar = this, 2024 2025 // Filter through the disabled dates to check if this is one. 2026 isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) { 2027 2028 // If the date is a number, match the weekday with 0index and `firstDay` check. 2029 if ( _.isInteger( dateToDisable ) ) { 2030 return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7 2031 } 2032 2033 // If itâs an array or a native JS date, create and match the exact date. 2034 if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) { 2035 return dateToVerify.pick === calendar.create( dateToDisable ).pick 2036 } 2037 2038 // If itâs an object, match a date within the âfromâ? and âtoâ? range. 2039 if ( $.isPlainObject( dateToDisable ) ) { 2040 return calendar.withinRange( dateToDisable, dateToVerify ) 2041 } 2042 }) 2043 2044 // If this date matches a disabled date, confirm itâs not inverted. 2045 isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { 2046 return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || 2047 $.isPlainObject( dateToDisable ) && dateToDisable.inverted 2048 }).length 2049 2050 // Check the calendar âenabledâ? flag and respectively flip the 2051 // disabled state. Then also check if itâs beyond the min/max limits. 2052 return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || 2053 dateToVerify.pick < calendar.item.min.pick || 2054 dateToVerify.pick > calendar.item.max.pick 2055 2056} //DatePicker.prototype.disabled 2057 2058 2059/** 2060 * Parse a string into a usable type. 2061 */ 2062DatePicker.prototype.parse = function( type, value, options ) { 2063 2064 var calendar = this, 2065 parsingObject = {} 2066 2067 // If itâs already parsed, weâre good. 2068 if ( !value || typeof value != 'string' ) { 2069 return value 2070 } 2071 2072 // We need a `.format` to parse the value with. 2073 if ( !( options && options.format ) ) { 2074 options = options || {} 2075 options.format = calendar.settings.format 2076 } 2077 2078 // Convert the format into an array and then map through it. 2079 calendar.formats.toArray( options.format ).map( function( label ) { 2080 2081 var 2082 // Grab the formatting label. 2083 formattingLabel = calendar.formats[ label ], 2084 2085 // The format length is from the formatting label function or the 2086 // label length without the escaping exclamation (!) mark. 2087 formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length 2088 2089 // If there's a format label, split the value up to the format length. 2090 // Then add it to the parsing object with appropriate label. 2091 if ( formattingLabel ) { 2092 parsingObject[ label ] = value.substr( 0, formatLength ) 2093 } 2094 2095 // Update the value as the substring from format length to end. 2096 value = value.substr( formatLength ) 2097 }) 2098 2099 // Compensate for month 0index. 2100 return [ 2101 parsingObject.yyyy || parsingObject.yy, 2102 +( parsingObject.mm || parsingObject.m ) - 1, 2103 parsingObject.dd || parsingObject.d 2104 ] 2105} //DatePicker.prototype.parse 2106 2107 2108/** 2109 * Various formats to display the object in. 2110 */ 2111DatePicker.prototype.formats = (function() { 2112 2113 // Return the length of the first word in a collection. 2114 function getWordLengthFromCollection( string, collection, dateObject ) { 2115 2116 // Grab the first word from the string. 2117 var word = string.match( /\w+/ )[ 0 ] 2118 2119 // If there's no month index, add it to the date object 2120 if ( !dateObject.mm && !dateObject.m ) { 2121 dateObject.m = collection.indexOf( word ) + 1 2122 } 2123 2124 // Return the length of the word. 2125 return word.length 2126 } 2127 2128 // Get the length of the first word in a string. 2129 function getFirstWordLength( string ) { 2130 return string.match( /\w+/ )[ 0 ].length 2131 } 2132 2133 return { 2134 2135 d: function( string, dateObject ) { 2136 2137 // If there's string, then get the digits length. 2138 // Otherwise return the selected date. 2139 return string ? _.digits( string ) : dateObject.date 2140 }, 2141 dd: function( string, dateObject ) { 2142 2143 // If there's a string, then the length is always 2. 2144 // Otherwise return the selected date with a leading zero. 2145 return string ? 2 : _.lead( dateObject.date ) 2146 }, 2147 ddd: function( string, dateObject ) { 2148 2149 // If there's a string, then get the length of the first word. 2150 // Otherwise return the short selected weekday. 2151 return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ] 2152 }, 2153 dddd: function( string, dateObject ) { 2154 2155 // If there's a string, then get the length of the first word. 2156 // Otherwise return the full selected weekday. 2157 return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ] 2158 }, 2159 m: function( string, dateObject ) { 2160 2161 // If there's a string, then get the length of the digits 2162 // Otherwise return the selected month with 0index compensation. 2163 return string ? _.digits( string ) : dateObject.month + 1 2164 }, 2165 mm: function( string, dateObject ) { 2166 2167 // If there's a string, then the length is always 2. 2168 // Otherwise return the selected month with 0index and leading zero. 2169 return string ? 2 : _.lead( dateObject.month + 1 ) 2170 }, 2171 mmm: function( string, dateObject ) { 2172 2173 var collection = this.settings.monthsShort 2174 2175 // If there's a string, get length of the relevant month from the short 2176 // months collection. Otherwise return the selected month from that c
2176ollection. 2177 return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] 2178 }, 2179 mmmm: function( string, dateObject ) { 2180 2181 var collection = this.settings.monthsFull 2182 2183 // If there's a string, get length of the relevant month from the full 2184 // months collection. Otherwise return the selected month from that collection. 2185 return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] 2186 }, 2187 yy: function( string, dateObject ) { 2188 2189 // If there's a string, then the length is always 2. 2190 // Otherwise return the selected year by slicing out the first 2 digits. 2191 return string ? 2 : ( '' + dateObject.year ).slice( 2 ) 2192 }, 2193 yyyy: function( string, dateObject ) { 2194 2195 // If there's a string, then the length is always 4. 2196 // Otherwise return the selected year. 2197 return string ? 4 : dateObject.year 2198 }, 2199 2200 // Create an array by splitting the formatting string passed. 2201 toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) }, 2202 2203 // Format an object into a string using the formatting options. 2204 toString: function ( formatString, itemObject ) { 2205 var calendar = this 2206 return calendar.formats.toArray( formatString ).map( function( label ) { 2207 return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) 2208 }).join( '' ) 2209 } 2210 } 2211})() //DatePicker.prototype.formats 2212 2213 2214 2215 2216/** 2217 * Check if two date units are the exact. 2218 */ 2219DatePicker.prototype.isDateExact = function( one, two ) { 2220 2221 var calendar = this 2222 2223 // When weâre working with weekdays, do a direct comparison. 2224 if ( 2225 ( _.isInteger( one ) && _.isInteger( two ) ) || 2226 ( typeof one == 'boolean' && typeof two == 'boolean' ) 2227 ) { 2228 return one === two 2229 } 2230 2231 // When weâre working with date representations, compare the âpickâ? value. 2232 if ( 2233 ( _.isDate( one ) || $.isArray( one ) ) && 2234 ( _.isDate( two ) || $.isArray( two ) ) 2235 ) { 2236 return calendar.create( one ).pick === calendar.create( two ).pick 2237 } 2238 2239 // When weâre working with range objects, compare the âfromâ? and âtoâ?. 2240 if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 2241 return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to ) 2242 } 2243 2244 return false 2245} 2246 2247 2248/** 2249 * Check if two date units overlap. 2250 */ 2251DatePicker.prototype.isDateOverlap = function( one, two ) { 2252 2253 var calendar = this, 2254 firstDay = calendar.settings.firstDay ? 1 : 0 2255 2256 // When weâre working with a weekday index, compare the days. 2257 if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { 2258 one = one % 7 + firstDay 2259 return one === calendar.create( two ).day + 1 2260 } 2261 if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { 2262 two = two % 7 + firstDay 2263 return two === calendar.create( one ).day + 1 2264 } 2265 2266 // When weâre working with range objects, check if the ranges overlap. 2267 if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 2268 return calendar.overlapRanges( one, two ) 2269 } 2270 2271 return false 2272} 2273 2274 2275/** 2276 * Flip the âenabledâ? state. 2277 */ 2278DatePicker.prototype.flipEnable = function(val) { 2279 var itemObject = this.item 2280 itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) 2281} 2282 2283 2284/** 2285 * Mark a collection of dates as âdisabledâ?. 2286 */ 2287DatePicker.prototype.deactivate = function( type, datesToDisable ) { 2288 2289 var calendar = this, 2290 disabledItems = calendar.item.disable.slice(0) 2291 2292 2293 // If weâre flipping, thatâs all we need to do. 2294 if ( datesToDisable == 'flip' ) { 2295 calendar.flipEnable() 2296 } 2297 2298 else if ( datesToDisable === false ) { 2299 calendar.flipEnable(1) 2300 disabledItems = [] 2301 } 2302 2303 else if ( datesToDisable === true ) { 2304 calendar.flipEnable(-1) 2305 disabledItems = [] 2306 } 2307 2308 // Otherwise go through the dates to disable. 2309 else { 2310 2311 datesToDisable.map(function( unitToDisable ) { 2312 2313 var matchFound 2314 2315 // When we have disabled items, check for matches. 2316 // If something is matched, immediately break out. 2317 for ( var index = 0; index < disabledItems.length; index += 1 ) { 2318 if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { 2319 matchFound = true 2320 break 2321 } 2322 } 2323 2324 // If nothing was found, add the validated unit to the collection. 2325 if ( !matchFound ) { 2326 if ( 2327 _.isInteger( unitToDisable ) || 2328 _.isDate( unitToDisable ) || 2329 $.isArray( unitToDisable ) || 2330 ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) 2331 ) { 2332 disabledItems.push( unitToDisable ) 2333 } 2334 } 2335 }) 2336 } 2337 2338 // Return the updated collection. 2339 return disabledItems 2340} //DatePicker.prototype.deactivate 2341 2342 2343/** 2344 * Mark a collection of dates as âenabledâ?. 2345 */ 2346DatePicker.prototype.activate = function( type, datesToEnable ) { 2347 2348 var calendar = this, 2349 disabledItems = calendar.item.disable, 2350 disabledItemsCount = disabledItems.length 2351 2352 // If weâre flipping, thatâs all we need to do. 2353 if ( datesToEnable == 'flip' ) { 2354 calendar.flipEnable() 2355 } 2356 2357 else if ( datesToEnable === true ) { 2358 calendar.flipEnable(1) 2359 disabledItems = [] 2360 } 2361 2362 else if ( datesToEnable === false ) { 2363 calendar.flipEnable(-1) 2364 disabledItems = [] 2365 } 2366 2367 // Otherwise go through the disabled dates. 2368 else { 2369 2370 datesToEnable.map(function( unitToEnable ) { 2371 2372 var matchFound, 2373 disabledUnit, 2374 index, 2375 isExactRange 2376 2377 // Go through the disabled items and try to find a match. 2378 for ( index = 0; index < disabledItemsCount; index += 1 ) { 2379 2380 disabledUnit = disabledItems[index] 2381 2382 // When an exact match is found, remove it from the collection. 2383 if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { 2384 matchFound = disabledItems[index] = null 2385 isExactRange = true 2386 break 2387 } 2388 2389 // When an overlapped match is found, add the âinvertedâ? state to it. 2390 else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { 2391 if ( $.isPlainObject( unitToEnable ) ) { 2392 unitToEnable.inverted = true 2393 matchFound = unitToEnable 2394 } 2395 else if ( $.isArray( unitToEnable ) ) { 2396 matchFound = unitToEnable 2397 if ( !matchFound[3] ) matchFound.push( '
2397inverted' ) 2398 } 2399 else if ( _.isDate( unitToEnable ) ) { 2400 matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] 2401 } 2402 break 2403 } 2404 } 2405 2406 // If a match was found, remove a previous duplicate entry. 2407 if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 2408 if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { 2409 disabledItems[index] = null 2410 break 2411 } 2412 } 2413 2414 // In the event that weâre dealing with an exact range of dates, 2415 // make sure there are no âinvertedâ? dates because of it. 2416 if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 2417 if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { 2418 disabledItems[index] = null 2419 break 2420 } 2421 } 2422 2423 // If something is still matched, add it into the collection. 2424 if ( matchFound ) { 2425 disabledItems.push( matchFound ) 2426 } 2427 }) 2428 } 2429 2430 // Return the updated collection. 2431 return disabledItems.filter(function( val ) { return val != null }) 2432} //DatePicker.prototype.activate 2433 2434 2435/** 2436 * Create a string for the nodes in the picker. 2437 */ 2438DatePicker.prototype.nodes = function( isOpen ) { 2439 2440 var 2441 calendar = this, 2442 settings = calendar.settings, 2443 calendarItem = calendar.item, 2444 nowObject = calendarItem.now, 2445 selectedObject = calendarItem.select, 2446 highlightedObject = calendarItem.highlight, 2447 viewsetObject = calendarItem.view, 2448 disabledCollection = calendarItem.disable, 2449 minLimitObject = calendarItem.min, 2450 maxLimitObject = calendarItem.max, 2451 2452 2453 // Create the calendar table head using a copy of weekday labels collection. 2454 // * We do a copy so we don't mutate the original array. 2455 tableHead = (function( collection, fullCollection ) { 2456 2457 // If the first day should be Monday, move Sunday to the end. 2458 if ( settings.firstDay ) { 2459 collection.push( collection.shift() ) 2460 fullCollection.push( fullCollection.shift() ) 2461 } 2462 2463 // Create and return the table head group. 2464 return _.node( 2465 'thead', 2466 _.node( 2467 'tr', 2468 _.group({ 2469 min: 0, 2470 max: DAYS_IN_WEEK - 1, 2471 i: 1, 2472 node: 'th', 2473 item: function( counter ) { 2474 return [ 2475 collection[ counter ], 2476 settings.klass.weekdays, 2477 'scope=col title="' + fullCollection[ counter ] + '"' 2478 ] 2479 } 2480 }) 2481 ) 2482 ) //endreturn 2483 })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysShort ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead 2484 2485 2486 // Create the nav for next/prev month. 2487 createMonthNav = function( next ) { 2488 2489 // Otherwise, return the created month tag. 2490 return _.node( 2491 'div', 2492 ' ', 2493 settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + ( 2494 2495 // If the focused month is outside the range, disabled the button. 2496 ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) || 2497 ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ? 2498 ' ' + settings.klass.navDisabled : '' 2499 ), 2500 'data-nav=' + ( next || -1 ) + ' ' + 2501 _.ariaAttr({ 2502 role: 'button', 2503 controls: calendar.$node[0].id + '_table' 2504 }) + ' ' + 2505 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"' 2506 ) //endreturn 2507 }, //createMonthNav 2508 2509 2510 // Create the month label. 2511 createMonthLabel = function() { 2512 2513 var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull 2514 2515 // If there are months to select, add a dropdown menu. 2516 if ( settings.selectMonths ) { 2517
2518 return _.node( 'select', 2519 _.group({ 2520 min: 0, 2521 max: 11, 2522 i: 1, 2523 node: 'option', 2524 item: function( loopedMonth ) { 2525 2526 return [ 2527 2528 // The looped month and no classes. 2529 monthsCollection[ loopedMonth ], 0, 2530 2531 // Set the value and selected index. 2532 'value=' + loopedMonth + 2533 ( viewsetObject.month == loopedMonth ? ' selected' : '' ) + 2534 ( 2535 ( 2536 ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) || 2537 ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month ) 2538 ) ? 2539 ' disabled' : '' 2540 ) 2541 ] 2542 } 2543 }), 2544 settings.klass.selectMonth, 2545 ( isOpen ? '' : 'disabled' ) + ' ' + 2546 _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + 2547 'title="' + settings.labelMonthSelect + '"' 2548 ) 2549 } 2550 2551 // If there's a need for a month selector 2552 return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month ) 2553 }, //createMonthLabel 2554 2555 2556 // Create the year label. 2557 createYearLabel = function() { 2558 2559 var focusedYear = viewsetObject.year, 2560 2561 // If years selector is set to a literal "true", set it to 5. Otherwise 2562 // divide in half to get half before and half after focused year. 2563 numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) 2564 2565 // If there are years to select, add a dropdown menu. 2566 if ( numberYears ) { 2567 2568 var 2569 minYear = minLimitObject.year, 2570 maxYear = maxLimitObject.year, 2571 lowestYear = focusedYear - numberYears, 2572 highestYear = focusedYear + numberYears 2573 2574 // If the min year is greater than the lowest year, increase the highest year 2575 // by the difference and set the lowest year to the min year. 2576 if ( minYear > lowestYear ) { 2577 highestYear += minYear - lowestYear 2578 lowestYear = minYear 2579 } 2580 2581 // If the max year is less than the highest year, decrease the lowest year 2582 // by the lower of the two: available and needed years. Then set the 2583 // highest year to the max year. 2584 if ( maxYear < highestYear ) { 2585 2586 var availableYears = lowestYear - minYear, 2587 neededYears = highestYear - maxYear 2588 2589 lowestYear -= availableYears > neededYears ? neededYears : availableYears 2590 highestYear = maxYear 2591 } 2592 2593 return _.node( 'select', 2594 _.group({ 2595 min: lowestYear, 2596 max: highestYear, 2597 i: 1, 2598 node: 'option', 2599 item: function( loopedYear ) { 2600 return [ 2601 2602 // The looped year and no classes. 2603 loopedYear, 0, 2604 2605 // Set the value and selected index. 2606 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' ) 2607 ] 2608 } 2609 }), 2610 settings.klass.selectYear, 2611 ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + 2612 'title="' + settings.labelYearSelect + '"' 2613 ) 2614 } 2615 2616 // Otherwise just return the year focused
2617 return _.node( 'div', focusedYear, settings.klass.year ) 2618 } //createYearLabel 2619 2620 2621 // Create and return the entire calendar. 2622 return _.node( 2623 'div', 2624 ( settings.selectYears ? createYearLabel() + createMonthLabel() : createMonthLabel() + createYearLabel() ) + 2625 createMonthNav() + createMonthNav( 1 ), 2626 settings.klass.header 2627 ) + _.node( 2628 'table', 2629 tableHead + 2630 _.node( 2631 'tbody', 2632 _.group({ 2633 min: 0, 2634 max: WEEKS_IN_CALENDAR - 1, 2635 i: 1, 2636 node: 'tr', 2637 item: function( rowCounter ) { 2638 2639 // If Monday is the first day and the month starts on Sunday, shift the date back a week. 2640 var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 2641 2642 return [ 2643 _.group({ 2644 min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index 2645 max: function() { 2646 return this.min + DAYS_IN_WEEK - 1 2647 }, 2648 i: 1, 2649 node: 'td', 2650 item: function( targetDate ) { 2651 2652 // Convert the time date from a relative date to a target date. 2653 targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) 2654 2655 var isSelected = selectedObject && selectedObject.pick == targetDate.pick, 2656 isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, 2657 isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick 2658 2659 return [ 2660 _.node( 2661 'div', 2662 targetDate.date, 2663 (function( klasses ) { 2664 2665 // Add the `infocus` or `outfocus` classes based on month in view. 2666 klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) 2667 2668 // Add the `today` class if needed. 2669 if ( nowObject.pick == targetDate.pick ) { 2670 klasses.push( settings.klass.now ) 2671 } 2672 2673 // Add the `selected` class if something's selected and the time matches. 2674 if ( isSelected ) { 2675 klasses.push( settings.klass.selected ) 2676 } 2677 2678 // Add the `highlighted` class if something's highlighted and the time matches. 2679 if ( isHighlighted ) { 2680 klasses.push( settings.klass.highlighted ) 2681 } 2682 2683 // Add the `disabled` class if something's disabled and the object matches. 2684 if ( isDisabled ) { 2685 klasses.push( settings.klass.disabled ) 2686 } 2687 2688 return klasses.join( ' ' ) 2689 })([ settings.klass.day ]), 2690 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({ 2691 role: 'gridcell', 2692 selected: isSelected && calendar.$node.val() === _.trigger( 2693 calendar.formats.toString, 2694 calendar, 2695 [ settings.format, targetDate ] 2696 ) ? true : null, 2697 activedescendant: isHighlighted ? true : null, 2698 disabled: isDisabled ? true : null 2699 }) 2700 ), 2701 '', 2702 _.ariaAttr({ role: 'presentation' }) 2703 ] //endreturn 2704 } 2705 }) 2706 ] //endreturn 2707 } 2708 }) 2709 ), 2710 settings.klass.table, 2711 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({ 2712 role: 'grid', 2713 controls: calendar.$node[0].id, 2714 readonly: true 2715 }) 2716 ) + 2717 2718 // * For Firefox forms to submit, make sure to set the buttonsâ `type` attributes as âbuttonâ?. 2719 _.node( 2720 'div', 2721 _.node( 'button', settings.today, settings.klass.buttonToday,
2722 'type=button data-pick=' + nowObject.pick + 2723 ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' + 2724 _.ariaAttr({ controls: calendar.$node[0].id }) ) + 2725 _.node( 'button', settings.clear, settings.klass.buttonClear, 2726 'type=button data-clear=1' + 2727 ( isOpen ? '' : ' disabled' ) + ' ' + 2728 _.ariaAttr({ controls: calendar.$node[0].id }) ) + 2729 _.node('button', settings.close, settings.klass.buttonClose, 2730 'type=button data-close=true ' + 2731 ( isOpen ? '' : ' disabled' ) + ' ' + 2732 _.ariaAttr({ controls: calendar.$node[0].id }) ), 2733 settings.klass.footer 2734 ) //endreturn 2735} //DatePicker.prototype.nodes 2736 2737 2738 2739 2740/** 2741 * The date picker defaults. 2742 */ 2743DatePicker.defaults = (function( prefix ) { 2744 2745 return { 2746 2747 // The title label to use for the month nav buttons 2748 labelMonthNext: 'Next month', 2749 labelMonthPrev: 'Previous month', 2750 2751 // The title label to use for the dropdown selectors 2752 labelMonthSelect: 'Select a month', 2753 labelYearSelect: 'Select a year', 2754 2755 // Months and weekdays 2756 monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], 2757 monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], 2758 weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], 2759 weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], 2760 2761 // Today and clear 2762 today: 'Today', 2763 clear: 'Clear', 2764 close: 'Close', 2765 2766 // The format to show on the `input` element 2767 format: 'd mmmm, yyyy', 2768 2769 // Classes 2770 klass: { 2771 2772 table: prefix + 'table', 2773 2774 header: prefix + 'header', 2775 2776 navPrev: prefix + 'nav--prev', 2777 navNext: prefix + 'nav--next', 2778 navDisabled: prefix + 'nav--disabled', 2779 2780 month: prefix + 'month', 2781 year: prefix + 'year', 2782 2783 selectMonth: prefix + 'select--month', 2784 selectYear: prefix + 'select--year', 2785 2786 weekdays: prefix + 'weekday', 2787 2788 day: prefix + 'day', 2789 disabled: prefix + 'day--disabled', 2790 selected: prefix + 'day--selected', 2791 highlighted: prefix + 'day--highlighted', 2792 now: prefix + 'day--today', 2793 infocus: prefix + 'day--infocus', 2794 outfocus: prefix + 'day--outfocus', 2795 2796 footer: prefix + 'footer', 2797 2798 buttonClear: prefix + 'button--clear', 2799 buttonToday: prefix + 'button--today', 2800 buttonClose: prefix + 'button--close' 2801 } 2802 } 2803})( Picker.klasses().picker + '__' ) 2804 2805 2806 2807 2808 2809/** 2810 * Extend the picker to add the date picker. 2811 */ 2812Picker.extend( 'pickadate', DatePicker ) 2813 2814 2815})); 2816 2817 2818 2819 2820/*! 2821 * Time picker for pickadate.js v3.5.3 2822 * http://amsul.github.io/pickadate.js/time.htm 2823 */ 2824 2825(function ( factory ) { 2826 2827 // AMD. 2828 if ( typeof define == 'function' && define.amd ) 2829 define( ['picker','jquery'], factory ) 2830 2831 // Node.js/browserify. 2832 else if ( typeof exports == 'object' ) 2833 module.exports = factory( require('./picker.js'), require('jquery') ) 2834 2835 // Browser globals. 2836 else factory( Picker, jQuery ) 2837 2838}(function( Picker, $ ) { 2839 2840 2841/** 2842 * Globals and constants 2843 */ 2844var HOURS_IN_DAY = 24, 2845 MINUTES_IN_HOUR = 60, 2846 HOURS_TO_NOON = 12, 2847 MINUTES_IN_DAY = HOURS_IN_DAY * MINUTES_IN_HOUR, 2848 _ = Picker._ 2849 2850 2851 2852/** 2853 * The time picker constructor 2854 */ 2855function TimePicker( picker, settings ) { 2856 2857 var clock = this, 2858 elementValue = picker.$node[ 0 ].value, 2859 elementDataValue = picker.$node.data( 'value' ), 2860 valueString = elementDataValue || elementValue, 2861 formatString = elementDataValue ? settings.formatSubmit : settings.format 2862 2863 clock.settings = settings 2864 clock.$node = picker.$node 2865 2866 // The queue of methods that will be used to build item objects. 2867 clock.queue = { 2868 interval: 'i', 2869 min: 'measure create', 2870 max: 'measure create', 2871 now: 'now create', 2872 select: 'parse create validate', 2873 highlight: 'parse create validate', 2874 view: 'parse create validate', 2875 disable: 'deactivate',
2876 enable: 'activate' 2877 } 2878 2879 // The component's item object. 2880 clock.item = {} 2881 2882 clock.item.clear = null 2883 clock.item.interval = settings.interval || 30 2884 clock.item.disable = ( settings.disable || [] ).slice( 0 ) 2885 clock.item.enable = -(function( collectionDisabled ) { 2886 return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 2887 })( clock.item.disable ) 2888 2889 clock. 2890 set( 'min', settings.min ). 2891 set( 'max', settings.max ). 2892 set( 'now' ) 2893 2894 // When thereâs a value, set the `select`, which in turn 2895 // also sets the `highlight` and `view`. 2896 if ( valueString ) { 2897 clock.set( 'select', valueString, { 2898 format: formatString, 2899 fromValue: !!elementValue 2900 }) 2901 } 2902 2903 // If thereâs no value, default to highlighting âtodayâ?. 2904 else { 2905 clock. 2906 set( 'select', null ). 2907 set( 'highlight', clock.item.now ) 2908 } 2909 2910 // The keycode to movement mapping. 2911 clock.key = { 2912 40: 1, // Down 2913 38: -1, // Up 2914 39: 1, // Right 2915 37: -1, // Left 2916 go: function( timeChange ) { 2917 clock.set( 2918 'highlight', 2919 clock.item.highlight.pick + timeChange * clock.item.interval, 2920 { interval: timeChange * clock.item.interval } 2921 ) 2922 this.render() 2923 } 2924 } 2925 2926 2927 // Bind some picker events. 2928 picker. 2929 on( 'render', function() { 2930 var $pickerHolder = picker.$root.children(), 2931 $viewset = $pickerHolder.find( '.' + settings.klass.viewset ), 2932 vendors = function( prop ) { 2933 return ['webkit', 'moz', 'ms', 'o', ''].map(function( vendor ) { 2934 return ( vendor ? '-' + vendor + '-' : '' ) + prop 2935 }) 2936 }, 2937 animations = function( $el, state ) { 2938 vendors( 'transform' ).map(function( prop ) { 2939 $el.css( prop, state ) 2940 }) 2941 vendors( 'transition' ).map(function( prop ) { 2942 $el.css( prop, state ) 2943 }) 2944 } 2945 if ( $viewset.length ) { 2946 animations( $pickerHolder, 'none' ) 2947 $pickerHolder[ 0 ].scrollTop = ~~$viewset.position().top - ( $viewset[ 0 ].clientHeight * 2 ) 2948 animations( $pickerHolder, '' ) 2949 } 2950 }, 1 ). 2951 on( 'open', function() { 2952 picker.$root.find( 'button' ).attr( 'disabled', false ) 2953 }, 1 ). 2954 on( 'close', function() { 2955 picker.$root.find( 'button' ).attr( 'disabled', true ) 2956 }, 1 ) 2957 2958} //TimePicker 2959 2960 2961/** 2962 * Set a timepicker item object. 2963 */ 2964TimePicker.prototype.set = function( type, value, options ) { 2965 2966 var clock = this, 2967 clockItem = clock.item 2968 2969 // If the value is `null` just set it immediately. 2970 if ( value === null ) { 2971 if ( type == 'clear' ) type = 'select' 2972 clockItem[ type ] = value 2973 return clock 2974 } 2975 2976 // Otherwise go through the queue of methods, and invoke the functions. 2977 // Update this as the time unit, and set the final value as this item. 2978 // * In the case of `enable`, keep the queue but set `disable` instead. 2979 // And in the case of `flip`, keep the queue but set `enable` instead. 2980 clockItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = clock.queue[ type ].split( ' ' ).map( function( method ) { 2981 value = clock[ method ]( type, value, options ) 2982 return value 2983 }).pop() 2984 2985 // Check if we need to cascade through more updates. 2986 if ( type == 'select' ) { 2987 clock.set( 'highlight', clockItem.select, options ) 2988 } 2989 else if ( type == 'highlight' ) { 2990 clock.set( 'view', clockItem.highlight, options ) 2991 } 2992 else if ( type == 'interval' ) { 2993 clock. 2994 set( 'min', clockItem.min, options ). 2995 set( 'max', clockItem.max, options ) 2996 } 2997 else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { 2998 if ( type == 'min' ) { 2999 clock.set( 'max', clockItem.max, options ) 3000 } 3001 if ( clockItem.select && clock.disabled( clockItem.select ) ) { 3002 clock.set( 'select', clockItem.select, options ) 3003 } 3004 if ( clockItem.highlight && clock.disabled( clockItem.highlight ) ) { 3005 clock.set( 'highlight', clockItem.highlight, options ) 3006 } 3007 } 3008 3009 return clock 3010} //TimePicker.prototype.set 3011 3012 3013/** 3014 * Get a timepicker item object. 3015 */ 3016TimePicker.prototype.get = function( type ) { 3017 return this.item[ type ] 3018} //TimePicker.prototype.get 3019 3020 3021/** 3022 * Create a picker time object. 3023 */ 3024TimePicker.prototype.create = function( type, value, options ) { 3025 3026 var clock = this 3027 3028 // If thereâs no value, use the type as the value. 3029 value = value === undefined ? type : value 3030 3031 // If itâs a date object, convert it into an array. 3032 if ( _.isDate( value ) ) { 3033 value = [ value.getHours(), value.getMinutes() ] 3034 } 3035 3036 // If itâs an object, use the âpickâ? value. 3037 if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 3038 value = value.pick 3039 } 3040 3041 // If itâs an array, convert it into minutes. 3042 else if ( $.isArray( value ) ) { 3043 value = +value[ 0 ] * MINUTES_IN_HOUR + (+value[ 1 ]) 3044 } 3045 3046 // If no valid value is passed, set it to ânowâ?. 3047 else if ( !_.isInteger( value ) ) { 3048 value = clock.now( type, value, options ) 3049 } 3050 3051 // If weâre setting the max, make sure itâs greater than the min. 3052 if ( type == 'max' && value < clock.item.min.pick ) { 3053 value += MINUTES_IN_DAY 3054 } 3055 3056 // If the value doesnât fall directly on the interval, 3057 // add one interval to indicate it as âpassedâ?. 3058 if ( type != 'min' && type != 'max' && (value - clock.item.min.pick) % clock.item.interval !== 0 ) { 3059 value += clock.item.interval 3060 } 3061 3062 // Normalize it into a âreachableâ? interval. 3063 value = clock.normalize( type, value, options ) 3064 3065 // Return the compiled object. 3066 return { 3067 3068 // Divide to get hours from minutes. 3069 hour: ~~( HOURS_IN_DAY + value / MINUTES_IN_HOUR ) % HOURS_IN_DAY, 3070 3071 // The remainder is the minutes. 3072 mins: ( MINUTES_IN_HOUR + value % MINUTES_IN_HOUR ) % MINUTES_IN_HOUR, 3073 3074 // The time in total minutes. 3075 time: ( MINUTES_IN_DAY + value ) % MINUTES_IN_DAY, 3076 3077 // Reference to the ârelativeâ? value to pick. 3078 pick: value 3079 } 3080} //TimePicker.prototype.create 3081 3082 3083/** 3084 * Create a range limit object using an array, date object, 3085 * literal âtrueâ?, or integer relative to another time. 3086 */ 3087TimePicker.prototype.createRange = function( from, to ) { 3088 3089 var clock = this, 3090 createTime = function( time ) { 3091 if ( time === true || $.isArray( time ) || _.isDate( time ) ) { 3092 return clock.create( time ) 3093 } 3094 return time 3095 } 3096 3097 // Create objects if possible. 3098 if ( !_.isInteger( from ) ) { 3099 from = createTime( from ) 3100 } 3101 if ( !_.isInteger( to ) ) { 3102 to = createTime( to ) 3103 } 3104 3105 // Create relative times. 3106 if ( _.isInteger( from ) && $.isPlainObject( to ) ) { 3107 from = [ to.hour, to.mins + ( from * clock.settings.interval ) ]; 3108 } 3109 else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { 3110 to = [ from.hour, from.mins + ( to * clock.settings.interval ) ]; 3111 } 3112 3113 return { 3114 from: createTime( from ), 3115 to: createTime( to ) 3116 } 3117} //TimePicker.prototype.createRange 3118 3119 3120/** 3121 * Check if a time unit falls within a time range object. 3122 */ 3123TimePicker.prototype.withinRange = function( range, timeUnit ) { 3124 range = this.createRange(range.from, range.to) 3125 return timeUnit.pick >= range.from.pick && timeUnit.pick <= range.to.pick 3126} 3127 3128 3129/** 3130 * Check if two time range objects overlap. 3131 */ 3132TimePicker.prototype.overlapRanges = function( one, two ) { 3133 3134 var clock = this 3135 3136 // Convert the ranges into comparable times. 3137 one = clock.createRange( one.from, one.to ) 3138 two = clock.createRange( two.from, two.to ) 3139 3140 return clock.withinRange( one, two.from ) || clock.withinRange( one, two.to ) || 3141 clock.withinRange( two, one.from ) || clock.withinRange( two, one.to ) 3142} 3143 3144 3145/** 3146 * Get the time relative to now. 3147 */ 3148TimePicker.prototype.now = function( type, value/*, options*/ ) { 3149 3150 var interval = this.item.interval, 3151 date = new Date(), 3152 nowMinutes = date.getHours() * MINUTES_IN_HOUR + date.getMinutes(), 3153 isValueInteger = _.isInteger( value ), 3154 isBelowInterval 3155 3156 // Make sure ânowâ? falls within the interval range. 3157 nowMinutes -= nowMinutes % interval 3158 3159 // Check if the difference is less than the interval itself. 3160 isBelowInterval = value < 0 && interval * value + nowMinutes <= -interval 3161 3162 // Add an interval because the time has âpassedâ?. 3163 nowMinutes += type == 'min' && isBelowInterval ? 0 : interval 3164 3165 // If the value is a number, adjust by that many intervals. 3166 if ( isValueInteger ) { 3167 nowMinutes += interval * ( 3168 isBelowInterval && type != 'max' ? 3169 value + 1 : 3170 value 3171 ) 3172 } 3173 3174 // Return the final calculation. 3175 return nowMinutes 3176} //TimePicker.prototype.now 3177 3178 3179/** 3180 * Normalize minutes to be âreachableâ? based on the min and interval. 3181 */ 3182TimePicker.prototype.normalize = function( type, value/*, options*/ ) { 3183 3184 var interval = this.item.interval, 3185 minTime = this.item.min && this.item.min.pick || 0 3186 3187 // If setting min time, donât shift anything. 3188 // Otherwise get the value and min difference and then 3189 // normalize the difference with the interval. 3190 value -= type == 'min' ? 0 : ( value - minTime ) % interval 3191 3192 // Return the adjusted value. 3193 return value 3194} //TimePicker.prototype.normalize 3195 3196 3197/** 3198 * Measure the range of minutes. 3199 */ 3200TimePicker.prototype.measure = function( type, value, options ) { 3201 3202 var clock = this 3203 3204 // If itâs anything false-y, set it to the default. 3205 if ( !value ) { 3206 value = type == 'min' ? [ 0, 0 ] : [ HOURS_IN_DAY - 1, MINUTES_IN_HOUR - 1 ] 3207 } 3208 3209 // If itâs a string, parse it. 3210 if ( typeof value == 'string' ) { 3211 value = clock.parse( type, value ) 3212 } 3213 3214 // If itâs a literal true, or an integer, make it relative to now. 3215 else if ( value === true || _.isInteger( value ) ) { 3216 value = clock.now( type, value, options ) 3217 } 3218 3219 // If itâs an object already, just normalize it. 3220 else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 3221 value = clock.normalize( type, value.pick, options ) 3222 } 3223 3224 return value 3225} ///TimePicker.prototype.measure 3226 3227 3228/** 3229 * Validate an object as enabled. 3230 */ 3231TimePicker.prototype.validate = function( type, timeObject, options ) { 3232 3233 var clock = this, 3234 interval = options && options.interval ? options.interval : clock.item.interval 3235 3236 // Check if the object is disabled. 3237 if ( clock.disabled( timeObject ) ) { 3238 3239 // Shift with the interval until we reach an enabled time. 3240 timeObject = clock.shift( timeObject, interval ) 3241 } 3242 3243 // Scope the object into range. 3244 timeObject = clock.scope( timeObject ) 3245 3246 // Do a second check to see if we landed on a disabled min/max. 3247 // In that case, shift using the opposite interval as before. 3248 if ( clock.disabled( timeObject ) ) { 3249 timeObject = clock.shift( timeObject, interval * -1 ) 3250 } 3251 3252 // Return the final object. 3253 return timeObject 3254} //TimePicker.prototype.validate 3255 3256 3257/** 3258 * Check if an object is disabled. 3259 */ 3260TimePicker.prototype.disabled = function( timeToVerify ) { 3261 3262 var clock = this, 3263 3264 // Filter through the disabled times to check if this is one. 3265 isDisabledMatch = clock.item.disable.filter( function( timeToDisable ) { 3266 3267 // If the time is a number, match the hours. 3268 if ( _.isInteger( timeToDisable ) ) { 3269 return timeToVerify.hour == timeToDisable 3270 } 3271 3272 // If itâs an array, create the object and match the times. 3273 if ( $.isArray( timeToDisable ) || _.isDate( timeToDisable ) ) { 3274 return timeToVerify.pick == clock.create( timeToDisable ).pick 3275 } 3276 3277 // If itâs an object, match a time within the âfromâ? and âtoâ? range. 3278 if ( $.isPlainObject( timeToDisable ) ) { 3279 return clock.withinRange( timeToDisable, timeToVerify ) 3280 } 3281 }) 3282 3283 // If this time matches a disabled time, confirm itâs not inverted. 3284 isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( timeToDisable ) { 3285 return $.isArray( timeToDisable ) && timeToDisable[2] == 'inverted' || 3286 $.isPlainObject( timeToDisable ) && timeToDisable.inverted 3287 }).length 3288 3289 // If the clock is "enabled" flag is flipped, flip the condition. 3290 return clock.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || 3291 timeToVerify.pick < clock.item.min.pick || 3292 timeToVerify.pick > clock.item.max.pick 3293} //TimePicker.prototype.disabled 3294 3295 3296/** 3297 * Shift an object by an interval until we reach an enabled object. 3298 */ 3299TimePicker.prototype.shift = function( timeObject, interval ) { 3300 3301 var clock = this, 3302 minLimit = clock.item.min.pick, 3303 maxLimit = clock.item.max.pick/*, 3304 safety = 1000*/ 3305 3306 interval = interval || clock.item.interval 3307 3308 // Keep looping as long as the time is disabled. 3309 while ( /*safety &&*/ clock.disabled( timeObject ) ) { 3310 3311 /*safety -= 1 3312 if ( !safety ) { 3313 throw 'Fell into an infinite loop while shifting to ' + timeObject.hour + ':' + timeObject.mins + '.' 3314 }*/ 3315 3316 // Increase/decrease the time by the interval and keep looping. 3317 timeObject = clock.create( timeObject.pick += interval ) 3318 3319 // If we've looped beyond the limits, break out of the loop. 3320 if ( timeObject.pick <= minLimit || timeObject.pick >= maxLimit ) { 3321 break 3322 } 3323 } 3324 3325 // Return the final object. 3326 return timeObject 3327} //TimePicker.prototype.shift 3328 3329 3330/** 3331 * Scope an object to be within range of min and max. 3332 */ 3333TimePicker.prototype.scope = function( timeObject ) { 3334 var minLimit = this.item.min.pick, 3335 maxLimit = this.item.max.pick 3336 return this.create( timeObject.pick > maxLimit ? maxLimit : timeObject.pick < minLimit ? minLimit : timeObject ) 3337} //TimePicker.prototype.scope 3338 3339 3340/** 3341 * Parse a string into a usable type. 3342 */ 3343TimePicker.prototype.parse = function( type, value, options ) { 3344 3345 var hour, minutes, isPM, item, parseValue, 3346 clock = this, 3347 parsingObject = {} 3348 3349 // If itâs already parsed, weâre good. 3350 if ( !value || typeof value != 'string' ) { 3351 return value 3352 } 3353 3354 // We need a `.format` to parse the value with. 3355 if ( !( options && options.format ) ) { 3356 options = options || {} 3357 options.format = clock.settings.format 3358 } 3359 3360 // Convert the format into an array and then map through it. 3361 clock.formats.toArray( options.format ).map( function( label ) { 3362 3363 var 3364 substring, 3365 3366 // Grab the formatting label. 3367 formattingLabel = clock.formats[ label ], 3368 3369 // The format length is from the formatting label function or the 3370 // label length without the escaping exclamation (!) mark. 3371 formatLength = formattingLabel ? 3372 _.trigger( formattingLabel, clock, [ value, parsingObject ] ) : 3373 label.replace( /^!/, '' ).length 3374 3375 // If there's a format label, split the value up to the format length. 3376 // Then add it to the parsing object with appropriate label. 3377 if ( formattingLabel ) { 3378 substring = v
3378alue.substr( 0, formatLength ) 3379 parsingObject[ label ] = substring.match(/^\d+$/) ? +substring : substring 3380 } 3381 3382 // Update the time value as the substring from format length to end. 3383 value = value.substr( formatLength ) 3384 }) 3385 3386 // Grab the hour and minutes from the parsing object. 3387 for ( item in parsingObject ) { 3388 parseValue = parsingObject[item] 3389 if ( _.isInteger(parseValue) ) { 3390 if ( item.match(/^(h|hh)$/i) ) { 3391 hour = parseValue 3392 if ( item == 'h' || item == 'hh' ) { 3393 hour %= 12 3394 } 3395 } 3396 else if ( item == 'i' ) { 3397 minutes = parseValue 3398 } 3399 } 3400 else if ( item.match(/^a$/i) && parseValue.match(/^p/i) && ('h' in parsingObject || 'hh' in parsingObject) ) { 3401 isPM = true 3402 } 3403 } 3404 3405 // Calculate it in minutes and return. 3406 return (isPM ? hour + 12 : hour) * MINUTES_IN_HOUR + minutes 3407} //TimePicker.prototype.parse 3408 3409 3410/** 3411 * Various formats to display the object in. 3412 */ 3413TimePicker.prototype.formats = { 3414 3415 h: function( string, timeObject ) { 3416 3417 // If there's string, then get the digits length. 3418 // Otherwise return the selected hour in "standard" format. 3419 return string ? _.digits( string ) : timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON 3420 }, 3421 hh: function( string, timeObject ) { 3422 3423 // If there's a string, then the length is always 2. 3424 // Otherwise return the selected hour in "standard" format with a leading zero. 3425 return string ? 2 : _.lead( timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON ) 3426 }, 3427 H: function( string, timeObject ) { 3428 3429 // If there's string, then get the digits length. 3430 // Otherwise return the selected hour in "military" format as a string. 3431 return string ? _.digits( string ) : '' + ( timeObject.hour % 24 ) 3432 }, 3433 HH: function( string, timeObject ) { 3434 3435 // If there's string, then get the digits length. 3436 // Otherwise return the selected hour in "military" format with a leading zero. 3437 return string ? _.digits( string ) : _.lead( timeObject.hour % 24 ) 3438 }, 3439 i: function( string, timeObject ) { 3440 3441 // If there's a string, then the length is always 2. 3442 // Otherwise return the selected minutes. 3443 return string ? 2 : _.lead( timeObject.mins ) 3444 }, 3445 a: function( string, timeObject ) { 3446 3447 // If there's a string, then the length is always 4. 3448 // Otherwise check if it's more than "noon" and return either am/pm. 3449 return string ? 4 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'a.m.' : 'p.m.' 3450 }, 3451 A: function( string, timeObject ) { 3452 3453 // If there's a string, then the length is always 2. 3454 // Otherwise check if it's more than "noon" and return either am/pm. 3455 return string ? 2 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'AM' : 'PM' 3456 }, 3457 3458 // Create an array by splitting the formatting string passed. 3459 toArray: function( formatString ) { return formatString.split( /(h{1,2}|H{1,2}|i|a|A|!.)/g ) }, 3460 3461 // Format an object into a string using the formatting options. 3462 toString: function ( formatString, itemObject ) { 3463 var clock = this 3464 return clock.formats.toArray( formatString ).map( function( label ) { 3465 return _.trigger( clock.formats[ label ], clock, [ 0, itemObject ] ) || label.replace( /^!/, '' ) 3466 }).join( '' ) 3467 } 3468} //TimePicker.prototype.formats 3469 3470 3471 3472 3473/** 3474 * Check if two time units are the exact. 3475 */ 3476TimePicker.prototype.isTimeExact = function( one, two ) { 3477 3478 var clock = this 3479 3480 // When weâre working with minutes, do a direct comparison. 3481 if ( 3482 ( _.isInteger( one ) && _.isInteger( two ) ) || 3483 ( typeof one == 'boolean' && typeof two == 'boolean' ) 3484 ) { 3485 return one === two 3486 } 3487 3488 // When weâre working with time representations, compare the âpickâ? value. 3489 if ( 3490 ( _.isDate( one ) || $.isArray( one ) ) && 3491 ( _.isDate( two ) || $.isArray( two ) ) 3492 ) { 3493 return clock.create( one ).pick === clock.create( two ).pick 3494 } 3495 3496 // When weâre working with range objects, compare the âfromâ? and âtoâ?. 3497 if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 3498 return clock.isTimeExact( one.from, two.from ) && clock.isTimeExact( one.to, two.to ) 3499 } 3500 3501 return false 3502} 3503 3504 3505/** 3506 * Check if two time units overlap. 3507 */ 3508TimePicker.prototype.isTimeOverlap = function( one, two ) { 3509 3510 var clock = this 3511 3512 // When weâre working with an integer, compare the hours. 3513 if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { 3514 return one === clock.create( two ).hour 3515 } 3516 if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { 3517 return two === clock.create( one ).hour 3518 } 3519 3520 // When weâre working with range objects, check if the ranges overlap. 3521 if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 3522 return clock.overlapRanges( one, two ) 3523 } 3524 3525 return false 3526} 3527 3528 3529/** 3530 * Flip the âenabledâ? state. 3531 */ 3532TimePicker.prototype.flipEnable = function(val) { 3533 var itemObject = this.item 3534 itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) 3535} 3536 3537 3538/** 3539 * Mark a collection of times as âdisabledâ?. 3540 */ 3541TimePicker.prototype.deactivate = function( type, timesToDisable ) { 3542 3543 var clock = this, 3544 disabledItems = clock.item.disable.slice(0) 3545 3546 3547 // If weâre flipping, thatâs all we need to do. 3548 if ( timesToDisable == 'flip' ) { 3549 clock.flipEnable() 3550 } 3551 3552 else if ( timesToDisable === false ) { 3553 clock.flipEnable(1) 3554 disabledItems = [] 3555 } 3556 3557 else if ( timesToDisable === true ) { 3558 clock.flipEnable(-1) 3559 disabledItems = [] 3560 } 3561 3562 // Otherwise go through the times to disable. 3563 else { 3564 3565 timesToDisable.map(function( unitToDisable ) { 3566 3567 var matchFound 3568 3569 // When we have disabled items, check for matches. 3570 // If something is matched, immediately break out. 3571 for ( var index = 0; index < disabledItems.length; index += 1 ) { 3572 if ( clock.isTimeExact( unitToDisable, disabledItems[index] ) ) { 3573 matchFound = true 3574 break 3575 } 3576 } 3577 3578 // If nothing was found, add the validated unit to the collection. 3579 if ( !matchFound ) { 3580 if ( 3581 _.isInteger( unitToDisable ) || 3582 _.isDate( unitToDisable ) || 3583 $.isArray( unitToDisable ) || 3584 ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) 3585 ) { 3586 disabledItems.push( unitToDisable ) 3587 } 3588 } 3589 }) 3590 } 3591 3592 // Return the updated collection. 3593 return disabledItems 3594} //TimePicker.prototype.deactivate 3595 3596 3597/** 3598 * Mark a collection of times as âenabledâ?. 3599 */ 3600TimePicker.prototype.activate = function( type, timesToEnable ) { 3601 3602 var clock = this, 3603 disabledItems = clock.item.disable, 3604 disabledItemsCount = disabledItems.length 3605 3606 // If weâre flipping, thatâs all we need to do. 3607 if ( timesToEnable == 'flip' ) { 3608 clock.flipEnable() 3609 } 3610 3611 else if ( timesToEnable === true ) { 3612 clock.flipEnable(1) 3613 disabledItems = [] 3614 } 3615 3616 else if ( timesToEnable === false ) { 3617 clock.flipEnable(-1) 3618 disabledItems = [] 3619 } 3620 3621 // Otherwise go through the disabled times. 3622 else { 3623 3624 timesToEnable.map(function( unitToEnable ) { 3625 3626 var matchFound, 3627 disabledUnit, 3628 index, 3629 isRangeMatched 3630 3631 // Go through the disabled items and try to find a match. 3632 for ( index = 0; index < disabledItemsCount; index += 1 ) { 3633 3634 disabledUnit = disabledItems[index] 3635 3636 // When an exact match is found, remove it from the collection. 3637 if ( clock.isTimeExact( disabledUnit, unitToEnable ) ) { 3638 matchFound = disabledItems[index] = null 3639 isRangeMatched = true 3640 break 3641 } 3642 3643 // When an overlapped match is found, add the âinvertedâ? state to it. 3644 else if ( clock.isTimeOverlap( disabledUnit, unitToEnable ) ) { 3645 if ( $.isPlainObject( unitToEnable ) ) { 3646 unitToEnable.inverted = true 3647 matchFound = unitToEnable 3648 } 3649 else if ( $.isArray( unitToEnable ) ) { 3650 matchFound = unitToEnable 3651 if ( !matchFound[2] ) matchFound.push( '
3651inverted' ) 3652 } 3653 else if ( _.isDate( unitToEnable ) ) { 3654 matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] 3655 } 3656 break 3657 } 3658 } 3659 3660 // If a match was found, remove a previous duplicate entry. 3661 if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 3662 if ( clock.isTimeExact( disabledItems[index], unitToEnable ) ) { 3663 disabledItems[index] = null 3664 break 3665 } 3666 } 3667 3668 // In the event that weâre dealing with an overlap of range times, 3669 // make sure there are no âinvertedâ? times because of it. 3670 if ( isRangeMatched ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 3671 if ( clock.isTimeOverlap( disabledItems[index], unitToEnable ) ) { 3672 disabledItems[index] = null 3673 break 3674 } 3675 } 3676 3677 // If something is still matched, add it into the collection. 3678 if ( matchFound ) { 3679 disabledItems.push( matchFound ) 3680 } 3681 }) 3682 } 3683 3684 // Return the updated collection. 3685 return disabledItems.filter(function( val ) { return val != null }) 3686} //TimePicker.prototype.activate 3687 3688 3689/** 3690 * The division to use for the range intervals. 3691 */ 3692TimePicker.prototype.i = function( type, value/*, options*/ ) { 3693 return _.isInteger( value ) && value > 0 ? value : this.item.interval 3694} 3695 3696 3697/** 3698 * Create a string for the nodes in the picker. 3699 */ 3700TimePicker.prototype.nodes = function( isOpen ) { 3701 3702 var 3703 clock = this, 3704 settings = clock.settings, 3705 selectedObject = clock.item.select, 3706 highlightedObject = clock.item.highlight, 3707 viewsetObject = clock.item.view, 3708 disabledCollection = clock.item.disable 3709 3710 return _.node( 3711 'ul', 3712 _.group({ 3713 min: clock.item.min.pick, 3714 max: clock.item.max.pick, 3715 i: clock.item.interval, 3716 node: 'li', 3717 item: function( loopedTime ) { 3718 loopedTime = clock.create( loopedTime ) 3719 var timeMinutes = loopedTime.pick, 3720 isSelected = selectedObject && selectedObject.pick == timeMinutes, 3721 isHighlighted = highlightedObject && highlightedObject.pick == timeMinutes, 3722 isDisabled = disabledCollection && clock.disabled( loopedTime ) 3723 return [ 3724 _.trigger( clock.formats.toString, clock, [ _.trigger( settings.formatLabel, clock, [ loopedTime ] ) || settings.format, loopedTime ] ), 3725 (function( klasses ) { 3726 3727 if ( isSelected ) { 3728 klasses.push( settings.klass.selected ) 3729 } 3730 3731 if ( isHighlighted ) { 3732 klasses.push( settings.klass.highlighted ) 3733 } 3734 3735 if ( viewsetObject && viewsetObject.pick == timeMinutes ) { 3736 klasses.push( settings.klass.viewset ) 3737 } 3738 3739 if ( isDisabled ) { 3740 klasses.push( settings.klass.disabled ) 3741 } 3742 3743 return klasses.join( ' ' ) 3744 })( [ settings.klass.listItem ] ), 3745 'data-pick=' + loopedTime.pick + ' ' + _.ariaAttr({ 3746 role: 'option', 3747 selected: isSelected && clock.$node.val() === _.trigger( 3748 clock.formats.toString, 3749 clock, 3750 [ settings.format, loopedTime ] 3751 ) ? true : null, 3752 activedescendant: isHighlighted ? true : null, 3753 disabled: isDisabled ? true : null 3754 }) 3755 ] 3756 } 3757 }) + 3758 3759 // * For Firefox forms to submit, make sure to set the buttonâs `type` attribute as âbuttonâ?. 3760 _.node( 3761 'li', 3762 _.node( 3763 'button', 3764 settings.clear, 3765 settings.klass.buttonClear, 3766 'type=button data-clear=1' + ( isOpen ? '' : ' disabled' ) + ' ' + 3767 _.ariaAttr({ controls: clock.$node[0].id }) 3768 ), 3769 '', _.ariaAttr({ role: 'presentation' }) 3770 ), 3771 settings.klass.list, 3772 _.ariaAttr({ role: 'listbox', controls: clock.$node[0].id }) 3773 ) 3774} //TimePicker.prototype.nodes 3775 3776 3777 3778 3779 3780 3781 3782/* ========================================================================== 3783 Extend the picker to add the component with the defaults. 3784 ========================================================================== */ 3785 3786TimePicker.defaults = (function( prefix ) { 3787 3788 return { 3789 3790 // Clear 3791 clear: 'Clear', 3792 3793 // The format to show on the `input` element 3794 format: 'h:i A', 3795 3796 // The interval between each time 3797 interval: 30, 3798 3799 // Classes 3800 klass: { 3801 3802 picker: prefix + ' ' + prefix + '--time', 3803 holder: prefix + '__holder', 3804 3805 list: prefix + '__list', 3806 listItem: prefix + '__list-item', 3807 3808 disabled: prefix + '__list-item--disabled', 3809 selected: prefix + '__list-item--selected', 3810 highlighted: prefix + '__list-item--highlighted', 3811 viewset: prefix + '__list-item--viewset', 3812 now: prefix + '__list-item--now', 3813 3814 buttonClear: prefix + '__button--clear' 3815 } 3816 } 3817})( Picker.klasses().picker ) 3818 3819 3820 3821 3822 3823/** 3824 * Extend the picker to add the time picker. 3825 */ 3826Picker.extend( 'pickatime', TimePicker ) 3827 3828 3829})); 3830 3831 3832/* Chosen v1.1.0 | (c) 2011-2013 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */
vendor: 29,308 bytes, lines 3833-3933
3833!function(){var a,AbstractChosen,Chosen,SelectParser,b,c={}.hasOwnProperty,d=function(a,b){function d(){this.constructor=a}for(var e in b)c.call(b,e)&&(a[e]=b[e]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};SelectParser=function(){function SelectParser(){this.options_index=0,this.parsed=[]}return SelectParser.prototype.add_node=function(a){return"OPTGROUP"===a.nodeName.toUpperCase()?this.add_group(a):this.add_option(a)},SelectParser.prototype.add_group=function(a){var b,c,d,e,f,g;for(b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:this.escapeExpression(a.label),children:0,disabled:a.disabled}),f=a.childNodes,g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(this.add_option(c,b,a.disabled));return g},SelectParser.prototype.add_option=function(a,b,c){return"OPTION"===a.nodeName.toUpperCase()?(""!==a.text?(null!=b&&(this.parsed[b].children+=1),this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:a.value,text:a.text,html:a.innerHTML,selected:a.selected,disabled:c===!0?c:a.disabled,group_array_index:b,classes:a.className,style:a.style.cssText})):this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:!0}),this.options_index+=1):void 0},SelectParser.prototype.escapeExpression=function(a){var b,c;return null==a||a===!1?"":/[\&\<\>\"\'\`]/.test(a)?(b={"<":"<",">":">",'"':""","'":"'","`":"`"},c=/&(?!\w+;)|[\<\>\"\'\`]/g,a.replace(c,function(a){return b[a]||"&"})):a},SelectParser}(),SelectParser.select_to_array=function(a){var b,c,d,e,f;for(c=new SelectParser,f=a.childNodes,d=0,e=f.length;e>d;d++)b=f[d],c.add_node(b);return c.parsed},AbstractChosen=function(){function AbstractChosen(a,b){this.form_field=a,this.options=null!=b?b:{},AbstractChosen.browser_is_supported()&&(this.is_multiple=this.form_field.multiple,this.set_default_text(),this.set_default_values(),this.setup(),this.set_up_html(),this.register_observers())}return AbstractChosen.prototype.set_default_values=function(){var a=this;return this.click_test_action=function(b){return a.test_active_click(b)},this.activate_action=function(b){return a.activate_field(b)},this.active_field=!1,this.mouse_on_container=!1,this.results_showing=!1,this.result_highlighted=null,this.allow_single_deselect=null!=this.options.allow_single_deselect&&null!=this.form_field.options[0]&&""===this.form_field.options[0].text?this.options.allow_single_deselect:!1,this.disable_search_threshold=this.options.disable_search_threshold||0,this.disable_search=this.options.disable_search||!1,this.enable_split_word_search=null!=this.options.enable_split_word_search?this.options.enable_split_word_search:!0,this.group_search=null!=this.options.group_search?this.options.group_search:!0,this.search_contains=this.options.search_contains||!1,this.single_backstroke_delete=null!=this.options.single_backstroke_delete?this.options.single_backstroke_delete:!0,this.max_selected_options=this.options.max_selected_options||1/0,this.inherit_select_classes=this.options.inherit_select_classes||!1,this.display_selected_options=null!=this.options.display_selected_options?this.options.display_selected_options:!0,this.display_disabled_options=null!=this.options.display_disabled_options?this.options.display_disabled_options:!0},AbstractChosen.prototype.set_default_text=function(){return this.default_text=this.form_field.getAttribute("data-placeholder")?this.form_field.getAttribute("data-placeholder"):this.is_multiple?this.options.placeholder_text_multiple||this.options.placeholder_text||AbstractChosen.default_multiple_text:this.options.placeholder_text_single||this.options.placeholder_text||AbstractChosen.default_single_text,this.results_none_found=this.form_field.getAttribute("data-no_results_text")||this.options.no_results_text||AbstractChosen.default_no_result_text},AbstractChosen.prototype.mouse_enter=function(){return this.mouse_on_container=!0},AbstractChosen.prototype.mouse_leave=function(){return this.mouse_on_container=!1},AbstractChosen.prototype.input_focus=function(){var a=this;if(this.is_multiple){if(!this.active_field)return setTimeout(function(){return a.container_mousedown()},50)}else if(!this.active_field)return this.activate_field()},AbstractChosen.prototype.input_blur=function(){var a=this;return this.mouse_on_container?void 0:(this.active_field=!1,setTimeout(function(){return a.blur_test()},100))},AbstractChosen.prototype.results_option_build=function(a){var b,c,d,e,f;for(b="",f=this.results_data,d=0,e=f.length;e>d;d++)c=f[d],b+=c.group?this.result_add_group(c):this.result_add_option(c),(null!=a?a.first:void 0)&&(c.selected&&this.is_multiple?this.choice_build(c):c.selected&&!this.is_multiple&&this.single_set_selected_text(c.text));return b},AbstractChosen.prototype.result_add_option=function(a){var b,c;return a.search_match?this.include_option_in_results(a)?(b=[],a.disabled||a.selected&&this.is_multiple||b.push("active-result"),!a.disabled||a.selected&&this.is_multiple||b.push("disabled-result"),a.selected&&b.push("result-selected"),null!=a.group_array_index&&b.push("group-option"),""!==a.classes&&b.push(a.classes),c=document.createElement("li"),c.className=b.join(" "),c.style.cssText=a.style,c.setAttribute("data-option-array-index",a.array_index),c.innerHTML=a.search_text,this.outerHTML(c)):"":""},AbstractChosen.prototype.result_add_group=function(a){var b;return a.search_match||a.group_match?a.active_options>0?(b=document.createElement("li"),b.className="group-result",b.innerHTML=a.search_text,this.outerHTML(b)):"":""},AbstractChosen.prototype.results_update_field=function(){return this.set_default_text(),this.is_multiple||this.results_reset_cleanup(),this.result_clear_highlight(),this.results_build(),this.results_showing?this.winnow_results():void 0},AbstractChosen.prototype.reset_single_select_options=function(){var a,b,c,d,e;for(d=this.results_data,e=[],b=0,c=d.length;c>b;b++)a=d[b],a.selected?e.push(a.selected=!1):e.push(void 0);return e},AbstractChosen.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},AbstractChosen.prototype.results_search=function(){return this.results_showing?this.winnow_results():this.results_show()},AbstractChosen.prototype.winnow_results=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m;for(this.no_results_clear(),e=0,g=this.get_search_text(),a=g.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),d=this.search_contains?"":"^",c=new RegExp(d+a,"i"),j=new RegExp(a,"i"),m=this.results_data,k=0,l=m.length;l>k;k++)b=m[k],b.search_match=!1,f=null,this.include_option_in_results(b)&&(b.group&&(b.group_match=!1,b.active_options=0),null!=b.group_array_index&&this.results_data[b.group_array_index]&&(f=this.results_data[b.group_array_index],0===f.active_options&&f.search_match&&(e+=1),f.active_options+=1),(!b.group||this.group_search)&&(b.search_text=b.group?b.label:b.html,b.search_match=this.search_string_match(b.search_text,c),b.search_match&&!b.group&&(e+=1),b.search_match?(g.length&&(h=b.search_text.search(j),i=b.search_text.substr(0,h+g.length)+"</em>"+b.search_text.substr(h+g.length),b.search_text=i.substr(0,h)+"<em>"+i.substr(h)),null!=f&&(f.group_match=!0)):null!=b.group_array_index&&this.results_data[b.group_array_index].search_match&&(b.search_match=!0)));return this.result_clear_highlight(),1>e&&g.length?(this.update_results_content(""),this.no_results(g)):(this.update_results_content(this.results_option_build()),this.winnow_results_set_highlight())},AbstractChosen.prototype.search_string_match=function(a,b){var c,d,e,f;if(b.test(a))return!0;if(this.enable_split_word_search&&(a.indexOf(" ")>=0||0===a.indexOf("["))&&(d=a.replace(/\[|\]/g,"").split(" "),d.length))for(e=0,f=d.length;f>e;e++)if(c=d[e],b.test(c))return!0},AbstractChosen.prototype.choices_count=function(){var a,b,c,d;if(null!=this.selected_option_count)return this.selected_option_count;for(this.selected_option_count=0,d=this.form_field.options,b=0,c=d.length;c>b;b++)a=d[b],a.selected&&(this.selected_option_count+=1);return this.selected_option_count},AbstractChosen.prototype.choices_click=function(a){return a.preventDefault(),this.results_showing||this.is_disabled?void 0:this.results_show()},AbstractChosen.prototype.keyup_checker=function(a){var b,c;switch(b=null!=(c=a.which)?c:a.keyCode,this.search_field_scale(),b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices_count()>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:if(a.preventDefault(),this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},AbstractChosen.prototype.clipboard_event_checker=function(){var a=this;return setTimeout(function(){return a.results_search()},50)},AbstractChosen.prototype.container_width=function(){return null!=this.options.width?this.options.width:""+this.form_field.offsetWidth+"px"},AbstractChosen.prototype.include_option_in_results=function(a){return this.is_multiple&&!this.display_selected_options&&a.selected?!1:!this.display_disabled_options&&a.disabled?!1:a.empty?!1:!0},AbstractChosen.prototype.search_results_touchstart=function(a){return this.touch_started=!0,this.search_results_mouseover(a)},AbstractChosen.prototype.search_results_touchmove=function(a){return this.touch_started=!1,this.search_results_mouseout(a)},AbstractChosen.prototype.search_results_touchend=function(a){return this.touch_started?this.search_results_mouseup(a):void 0},AbstractChosen.prototype.outerHTML=function(a){var b;return a.outerHTML?a.outerHTML:(b=document.createElement("div"),b.appendChild(a),b.innerHTML)},AbstractChosen.browser_is_supported=function(){return"Microsoft Internet Explorer"===window.navigator.appName?document.documentMode>=8:/iP(od|hone)/i.test(window.navigator.userAgent)?!1:/Android/i.test(window.navigator.userAgent)&&/Mobile/i.test(window.navigator.userAgent)?!1:!0},AbstractChosen.default_multiple_text="Select Some Options",AbstractChosen.default_single_text="Select an Option",AbstractChosen.default_no_result_text="No results match",AbstractChosen}(),a=jQuery,a.fn.extend({chosen:function(b){return AbstractChosen.browser_is_supported()?this.each(function(){var c,d;c=a(this),d=c.data("chosen"),"destroy"===b&&d?d.destroy():d||c.data("chosen",new Chosen(this,b))}):this}}),Chosen=function(c){function Chosen(){return b=Chosen.__super__.constructor.apply(this,arguments)}return d(Chosen,c),Chosen.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.current_selectedIndex=this.form_field.selectedIndex,this.is_rtl=this.form_field_jq.hasClass("chosen-rtl")},Chosen.prototype.set_up_html=function(){var b,c;return b=["chosen-container"],b.push("chosen-container-"+(this.is_multiple?"multi":"single")),this.inherit_select_classes&&this.form_field.className&&b.push(this.form_field.className),this.is_rtl&&b.push("chosen-rtl"),c={"class":b.join(" "),style:"width: "+this.container_width()+";",title:this.form_field.title},this.form_field.id.length&&(c.id=this.form_field.id.replace(/[^\w]/g,"_")+"_chosen"),this.container=a("<div />",c),this.is_multiple?this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="'+this.default_text+'" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>'):this.container.html('<a class="chosen-single chosen-default" tabindex="-1"><span>'+this.default_text+'</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>'),this.form_field_jq.hide().after(this.container),this.dropdown=this.container.find("div.chosen-drop").first(),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chosen-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chosen-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chosen-search").first(),this.selected_item=this.container.find(".chosen-single").first()),this.results_build(),this.set_tab_index(),this.set_label_behavior(),this.form_field_jq.trigger("chosen:ready",{chosen:this})},Chosen.prototype.register_observers=function(){var a=this;return this.container.bind("mousedown.chosen",function(b){a.container_mousedown(b)}),this.container.bind("mouseup.chosen",function(b){a.container_mouseup(b)}),this.container.bind("mouseenter.chosen",function(b){a.mouse_enter(b)}),this.container.bind("mouseleave.chosen",function(b){a.mouse_leave(b)}),this.search_results.bind("mouseup.chosen",function(b){a.search_results_mouseup(b)}),this.search_results.bind("mouseover.chosen",function(b){a.search_results_mouseover(b)}),this.search_results.bind("mouseout.chosen",function(b){a.search_results_mouseout(b)}),this.search_results.bind("mousewheel.chosen DOMMouseScroll.chosen",function(b){a.search_results_mousewheel(b)}),this.search_results.bind("touchstart.chosen",function(b){a.search_results_touchstart(b)}),this.search_results.bind("touchmove.chosen",function(b){a.search_results_touchmove(b)}),this.search_results.bind("touchend.chosen",function(b){a.search_results_touchend(b)}),this.form_field_jq.bind("chosen:updated.chosen",function(b){a.results_update_field(b)}),this.form_field_jq.bind("chosen:activate.chosen",function(b){a.activate_field(b)}),this.form_field_jq.bind("chosen:open.chosen",function(b){a.container_mousedown(b)}),this.form_field_jq.bind("chosen:close.chosen",function(b){a.input_blur(b)}),this.search_field.bind("blur.chosen",function(b){a.input_blur(b)}),this.search_field.bind("keyup.chosen",function(b){a.keyup_checker(b)}),this.search_field.bind("keydown.chosen",function(b){a.keydown_checker(b)}),this.search_field.bind("focus.chosen",function(b){a.input_focus(b)}),this.search_field.bind("cut.chosen",function(b){a.clipboard_event_checker(b)}),this.search_field.bind("paste.chosen",function(b){a.clipboard_event_checker(b)}),this.is_multiple?this.search_choices.bind("click.chosen",function(b){a.choices_click(b)}):this.container.bind("click.chosen",function(a){a.preventDefault()})},Chosen.prototype.destroy=function(){return a(this.container[0].ownerDocument).unbind("click.chosen",this.click_test_action),this.search_field[0].tabIndex&&(this.form_field_jq[0].tabIndex=this.search_field[0].tabIndex),this.container.remove(),this.form_field_jq.removeData("chosen"),this.form_field_jq.show()},Chosen.prototype.search_field_disabled=function(){return this.is_disabled=this.form_field_jq[0].disabled,this.is_disabled?(this.container.addClass("chosen-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus.chosen",this.activate_action),this.close_field()):(this.container.removeClass("chosen-disabled"),this.search_field[0].disabled=!1,this.is_multiple?void 0:this.selected_item.bind("focus.chosen",this.activate_action))},Chosen.prototype.container_mousedown=function(b){return this.is_disabled||(b&&"mousedown"===b.type&&!this.results_showing&&b.preventDefault(),null!=b&&a(b.target).hasClass("search-choice-close"))?void 0:(this.active_field?this.is_multiple||!b||a(b.target)[0]!==this.selected_item[0]&&!a(b.target).parents("a.chosen-single").length||(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(this.container[0].ownerDocument).bind("click.chosen",this.click_test_action),this.results_show()),this.activate_field())},Chosen.prototype.container_mouseup=function(a){return"ABBR"!==a.target.nodeName||this.is_disabled?void 0:this.results_reset(a)},Chosen.prototype.search_results_mousewheel=function(a){var b;return a.originalEvent&&(b=-a.originalEvent.wheelDelta||a.originalEvent.detail),null!=b?(a.preventDefault(),"DOMMouseScroll"===a.type&&(b=40*b),this.search_results.scrollTop(b+this.search_results.scrollTop())):void 0},Chosen.prototype.blur_test=function(){return!this.active_field&&this.container.hasClass("chosen-container-active")?this.close_field():void 0},Chosen.prototype.close_field=function(){return a(this.container[0].ownerDocument).unbind("click.chosen",this.click_test_action),this.active_field=!1,this.results_hide(),this.container.removeClass("chosen-container-active"),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},Chosen.prototype.activate_field=function(){return this.container.addClass("chosen-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},Chosen.prototype.test_active_click=function(b){var c;return c=a(b.target).closest(".chosen-container"),c.length&&this.container[0]===c[0]?this.active_field=!0:this.close_field()},Chosen.prototype.results_build=function(){return this.parsing=!0,this.selected_option_count=null,this.results_data=SelectParser.select_to_array(this.form_field),this.is_multiple?this.search_choices.find("li.search-choice").remove():this.is_multiple||(this.single_set_selected_text(),this.disable_search||this.form_field.options.length<=this.disable_search_threshold?(this.search_field[0].readOnly=!0,this.container.addClass("chosen-container-single-nosearch")):(this.search_field[0].readOnly=!1,this.container.removeClass("chosen-container-single-nosearch"))),this.update_results_content(this.results_option_build({first:!0})),this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.parsing=!1},Chosen.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){if(this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight(),b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(f>c)return this.search_results.scrollTop(c)}},Chosen.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClass("highlighted"),this.result_highlight=null},Chosen.prototype.results_show=function(){return this.is_multiple&&this.max_selected_options<=this.choices_count()?(this.form_field_jq.trigger("chosen:maxselected",{chosen:this}),!1):(this.container.addClass("chosen-with-drop"),this.results_showing=!0,this.search_field.focus(),this.search_field.val(this.search_field.val()),this.winnow_results(),this.form_field_jq.trigger("chosen:showing_dropdown",{chosen:this}))},Chosen.prototype.update_results_content=function(a){return this.search_results.html(a)},Chosen.prototype.results_hide=function(){return this.results_showing&&(this.result_clear_highlight(),this.container.removeClass("chosen-with-drop"),this.form_field_jq.trigger("chosen:hiding_dropdown",{chosen:this})),this.results_showing=!1},Chosen.prototype.set_tab_index=function(){var a;return this.form_field.tabIndex?(a=this.form_field.tabIndex,this.form_field.tabIndex=-1,this.search_field[0].tabIndex=a):void 0},Chosen.prototype.set_label_behavior=function(){var b=this;return this.form_field_label=this.form_field_jq.parents("label"),!this.form_field_label.length&&this.form_field.id.length&&(this.form_field_label=a("label[for='"+this.form_field.id+"']")),this.form_field_label.length>0?this.form_field_label.bind("click.chosen",function(a){return b.is_multiple?b.container_mousedown(a):b.activate_field()}):void 0},Chosen.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices_count()<1&&!this.active_field?(this.search_field.val(this.default_text),this.search_field.addClass("default")):(this.search_field.val(""),this.search_field.removeClass("default"))},Chosen.prototype.search_results_mouseup=function(b){var c;return c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first(),c.length?(this.result_highlight=c,this.result_select(b),this.search_field.focus()):void 0},Chosen.prototype.search_results_mouseover=function(b){var c;return c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first(),c?this.result_do_highlight(c):void 0},Chosen.prototype.search_results_mouseout=function(b){return a(b.target).hasClass("active-result")?this.result_clear_highlight():void 0},Chosen.prototype.choice_build=function(b){var c,d,e=this;return c=a("<li />",{"class":"search-choice"}).html("<span>"+b.html+"</span>"),b.disabled?c.addClass("search-choice-disabled"):(d=a("<a />",{"class":"search-choice-close","data-option-array-index":b.array_index}),d.bind("click.chosen",function(a){return e.choice_destroy_link_click(a)}),c.append(d)),this.search_container.before(c)},Chosen.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),b.stopPropagation(),this.is_disabled?void 0:this.choice_destroy(a(b.target))},Chosen.prototype.choice_destroy=function(a){return this.result_deselect(a[0].getAttribute("data-option-array-index"))?(this.show_search_field_default(),this.is_multiple&&this.choices_count()>0&&this.search_field.val().length<1&&this.results_hide(),a.parents("li").first().remove(),this.search_field_scale()):void 0},Chosen.prototype.results_reset=function(){return this.reset_single_select_options(),this.form_field.options[0].selected=!0,this.single_set_selected_text(),this.show_search_field_default(),this.results_reset_cleanup(),this.form_field_jq.trigger("change"),this.active_field?this.results_hide():void 0},Chosen.prototype.results_reset_cleanup=function(){return this.current_selectedIndex=this.form_field.selectedIndex,this.selected_item.find("abbr").remove()},Chosen.prototype.result_select=function(a){var b,c;return this.result_highlight?(b=this.result_highlight,this.result_clear_highlight(),this.is_multiple&&this.max_selected_options<=this.choices_count()?(this.form_field_jq.trigger("chosen:maxselected",{chosen:this}),!1):(this.is_multiple?b.removeClass("active-result"):this.reset_single_select_options(),c=this.results_data[b[0].getAttribute("data-option-array-index")],c.selected=!0,this.form_field.options[c.options_index].selected=!0,this.selected_option_count=null,this.is_multiple?this.choice_build(c):this.single_set_selected_text(c.text),(a.metaKey||a.ctrlKey)&&this.is_multiple||this.results_hide(),this.search_field.val(""),(this.is_multiple||this.form_field.selectedIndex!==this.current_selectedIndex)&&this.form_field_jq.trigger("change",{selected:this.form_field.options[c.options_index].value}),this.current_selectedIndex=this.form_field.selectedIndex,this.search_field_scale())):void 0},Chosen.prototype.single_set_selected_text=function(a){return null==a&&(a=this.default_text),a===this.default_text?this.selected_item.addClass("chosen-default"):(this.single_deselect_control_build(),this.selected_item.removeClass("chosen-default")),this.selected_item.find("span").text(a)},Chosen.prototype.result_deselect=function(a){var b;return b=this.results_data[a],this.form_field.options[b.options_index].disabled?!1:(b.selected=!1,this.form_field.options[b.options_index].selected=!1,this.selected_option_count=null,this.result_clear_highlight(),this.results_showing&&this.winnow_results(),this.form_field_jq.trigger("change",{deselected:this.form_field.options[b.options_index].value}),this.search_field_scale(),!0)},Chosen.prototype.single_deselect_control_build=function(){return this.allow_single_deselect?(this.selected_item.find("abbr").length||this.selected_item.find("span").first().after('<abbr class="search-choice-close"></abbr>'),this.selected_item.addClass("chosen-single-with-deselect")):void 0},Chosen.prototype.get_search_text=function(){return this.search_field.val()===this.default_text?"":a("<div/>").text(a.trim(this.search_field.val())).html()},Chosen.prototype.winnow_results_set_highlight=function(){var a,b;return b=this.is_multiple?[]:this.search_results.find(".result-selected.active-result"),a=b.length?b.first():this.search_results.find(".active-result").first(),null!=a?this.result_do_highlight(a):void 0},Chosen.prototype.no_results=function(b){var c;return c=a('<li class="no-results">'+this.results_none_found+' "<span></span>"</li>'),c.find("span").first().html(b),this.search_results.append(c),this.form_field_jq.trigger("chosen:no_results",{chosen:this})},Chosen.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},Chosen.prototype.keydown_arrow=function(){var a;return this.results_showing&&this.result_highlight?(a=this.result_highlight.nextAll("li.active-result").first())?this.result_do_highlight(a):void 0:this.results_show()},Chosen.prototype.keyup_arrow=function(){var a;return this.results_showing||this.is_multiple?this.result_highlight?(a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices_count()>0&&this.results_hide(),this.result_clear_highlight())):void 0:this.results_show()},Chosen.prototype.keydown_backstroke=function(){var a;return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(a=this.search_container.siblings("li.search-choice").last(),a.length&&!a.hasClass("search-choice-disabled")?(this.pending_backstroke=a,this.single_backstroke_delete?this.keydown_backstroke():this.pending_backstroke.addClass("search-choice-focus")):void 0)},Chosen.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},Chosen.prototype.keydown_checker=function(a){var b,c;switch(b=null!=(c=a.which)?c:a.keyCode,this.search_field_scale(),8!==b&&this.pending_backstroke&&this.clear_backstroke(),b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:a.preventDefault(),this.keydown_arrow()}},Chosen.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){for(d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"],i=0,j=g.length;j>i;i++)e=g[i],f+=e+":"+this.search_field.css(e)+";";return b=a("<div />",{style:f}),b.text(this.search_field.val()),a("body").append(b),h=b.width()+25,b.remove(),c=this.container.outerWidth(),h>c-10&&(h=c-10),this.search_field.css({width:h+"px"})}},Chosen}(AbstractChosen)}.call(this); 3834 3835/* 3836 * jQuery One Page Nav Plugin 3837 * http://github.com/davist11/jQuery-One-Page-Nav 3838 * 3839 * Copyright (c) 2010 Trevor Davis (http://trevordavis.net) 3840 * Dual licensed under the MIT and GPL licenses. 3841 * Uses the same license as jQuery, see: 3842 * http://jquery.org/license 3843 * 3844 * @version 3.0.0 3845 * 3846 * Example usage: 3847 * $('#nav').onePageNav({ 3848 * currentClass: 'current', 3849 * changeHash: false, 3850 * scrollSpeed: 750 3851 * }); 3852 */ 3853 3854;(function($, window, document, undefined){ 3855 3856 // our plugin constructor 3857 var OnePageNav = function(elem, options){ 3858 this.elem = elem; 3859 this.$elem = $(elem); 3860 this.options = options; 3861 this.metadata = this.$elem.data('plugin-options'); 3862 this.$win = $(window); 3863 this.sections = {}; 3864 this.didScroll = false; 3865 this.$doc = $(document); 3866 this.docHeight = this.$doc.height(); 3867 }; 3868 3869 // the plugin prototype 3870 OnePageNav.prototype = { 3871 defaults: { 3872 navItems: 'a', 3873 currentClass: 'current', 3874 changeHash: false, 3875 easing: 'swing', 3876 filter: '', 3877 scrollSpeed: 750, 3878 scrollThreshold: 0.5, 3879 begin: false, 3880 end: false, 3881 scrollChange: false 3882 }, 3883 3884 init: function() { 3885 // Introduce defaults that can be extended either 3886 // globally or using an object literal. 3887 this.config = $.extend({}, this.defaults, this.options, this.metadata); 3888 3889 this.$nav = this.$elem.find(this.config.navItems); 3890 3891 //Filter any links out of the nav 3892 if(this.config.filter !== '') { 3893 this.$nav = this.$nav.filter(this.config.filter); 3894 } 3895 3896 //Handle clicks on the nav 3897 this.$nav.on('click.onePageNav', $.proxy(this.handleClick, this)); 3898 3899 //Get the section positions 3900 this.getPositions(); 3901 3902 //Handle scroll changes 3903 this.bindInterval(); 3904 3905 //Update the positions on resize too 3906 this.$win.on('resize.onePageNav', $.proxy(this.getPositions, this)); 3907 3908 return this; 3909 }, 3910 3911 adjustNav: function(self, $parent) { 3912 self.$elem.find('.' + self.config.currentClass).removeClass(self.config.currentClass); 3913 $parent.addClass(self.config.currentClass); 3914 }, 3915 3916 bindInterval: function() { 3917 var self = this; 3918 var docHeight; 3919 3920 self.$win.on('scroll.onePageNav', function() { 3921 self.didScroll = true; 3922 }); 3923 3924 self.t = setInterval(function() { 3925 docHeight = self.$doc.height(); 3926 3927 //If it was scrolled 3928 if(self.didScroll) { 3929 self.didScroll = false; 3930 self.scrollChange(); 3931 } 3932 3933 //If the document height changes
3934 if(docHeight !== self.docHeight) { 3935 self.docHeight = docHeight; 3936 self.getPositions(); 3937 } 3938 }, 250); 3939 }, 3940 3941 getHash: function($link) { 3942 return $link.attr('href').split('#')[1]; 3943 }, 3944 3945 getPositions: function() { 3946 var self = this; 3947 var linkHref; 3948 var topPos; 3949 var $target; 3950 3951 self.$nav.each(function() { 3952 linkHref = self.getHash($(this)); 3953 $target = $('#' + linkHref); 3954 3955 if($target.length) { 3956 topPos = $target.offset().top; 3957 self.sections[linkHref] = Math.round(topPos); 3958 } 3959 }); 3960 }, 3961 3962 getSection: function(windowPos) { 3963 var returnValue = null; 3964 var windowHeight = Math.round(this.$win.height() * this.config.scrollThreshold); 3965 3966 for(var section in this.sections) { 3967 if((this.sections[section] - windowHeight) < windowPos) { 3968 returnValue = section; 3969 } 3970 } 3971 3972 return returnValue; 3973 }, 3974 3975 handleClick: function(e) { 3976 var self = this; 3977 var $link = $(e.currentTarget); 3978 var $parent = $link.parent(); 3979 var newLoc = '#' + self.getHash($link); 3980 3981 if(!$parent.hasClass(self.config.currentClass)) { 3982 //Start callback 3983 if(self.config.begin) { 3984 self.config.begin(); 3985 } 3986 3987 //Change the highlighted nav item 3988 self.adjustNav(self, $parent); 3989 3990 //Removing the auto-adjust on scroll 3991 self.unbindInterval(); 3992 3993 //Scroll to the correct position 3994 self.scrollTo(newLoc, function() { 3995 //Do we need to change the hash? 3996 if(self.config.changeHash) { 3997 window.location.hash = newLoc; 3998 } 3999 4000 //Add the auto-adjust on scroll back in 4001 self.bindInterval(); 4002 4003 //End callback 4004 if(self.config.end) { 4005 self.config.end(); 4006 } 4007 }); 4008 } 4009 4010 e.preventDefault(); 4011 }, 4012 4013 scrollChange: function() { 4014 var windowTop = this.$win.scrollTop(); 4015 var position = this.getSection(windowTop); 4016 var $parent; 4017 4018 //If the position is set 4019 if(position !== null) { 4020 $parent = this.$elem.find('a[href$="#' + position + '"]').parent(); 4021 4022 //If it's not already the current section 4023 if(!$parent.hasClass(this.config.currentClass)) { 4024 //Change the highlighted nav item 4025 this.adjustNav(this, $parent); 4026 4027 //If there is a scrollChange callback 4028 if(this.config.scrollChange) { 4029 this.config.scrollChange($parent); 4030 } 4031 } 4032 } 4033 }, 4034 4035 scrollTo: function(target, callback) { 4036 var offset = $(target).offset().top; 4037 4038 $('html, body').animate({ 4039 scrollTop: offset 4040 }, this.config.scrollSpeed, this.config.easing, callback); 4041 }, 4042 4043 unbindInterval: function() { 4044 clearInterval(this.t); 4045 this.$win.unbind('scroll.onePageNav'); 4046 } 4047 }; 4048 4049 OnePageNav.defaults = OnePageNav.prototype.defaults; 4050 4051 $.fn.onePageNav = function(options) { 4052 return this.each(function() { 4053 new OnePageNav(this, options).init(); 4054 }); 4055 }; 4056 4057})( jQuery, window , document ); 4058 4059 4060/*! 4061 * Bootstrap v3.2.0 (http://getbootstrap.com) 4062 * Copyright 2011-2014 Twitter, Inc. 4063 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4064 */ 4065 4066/*! 4067 * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=6dbe887f58ce5549314a) 4068 * Config saved to config.json and https://gist.github.com/6dbe887f58ce5549314a 4069 */ 4070if (typeof jQuery === "undefined") { throw new Error("Bootstrap's JavaScript requires jQuery") } 4071 4072/* ======================================================================== 4073 * Bootstrap: modal.js v3.2.0 4074 * http://getbootstrap.com/javascript/#modals 4075 * ======================================================================== 4076 * Copyright 2011-2014 Twitter, Inc. 4077 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4078 * ======================================================================== */ 4079 4080 4081+function ($) { 4082 'use strict'; 4083 4084 // MODAL CLASS DEFINITION 4085 // ====================== 4086 4087 var Modal = function (element, options) { 4088 this.options = options 4089 this.$body = $(document.body) 4090 this.$element = $(element) 4091 this.$backdrop = 4092 this.isShown = null 4093 this.scrollbarWidth = 0 4094 4095 if (this.options.remote) { 4096 this.$element
vendor: 7,867 bytes, lines 4097-4364
4097 .find('.modal-content') 4098 .load(this.options.remote, $.proxy(function () { 4099 this.$element.trigger('loaded.bs.modal') 4100 }, this)) 4101 } 4102 } 4103 4104 Modal.VERSION = '3.2.0' 4105 4106 Modal.DEFAULTS = { 4107 backdrop: true, 4108 keyboard: true, 4109 show: true 4110 } 4111 4112 Modal.prototype.toggle = function (_relatedTarget) { 4113 return this.isShown ? this.hide() : this.show(_relatedTarget) 4114 } 4115 4116 Modal.prototype.show = function (_relatedTarget) { 4117 var that = this 4118 var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget }) 4119 4120 this.$element.trigger(e) 4121 4122 if (this.isShown || e.isDefaultPrevented()) return 4123 4124 this.isShown = true 4125 4126 this.checkScrollbar() 4127 this.$body.addClass('modal-open') 4128 4129 this.setScrollbar() 4130 this.escape() 4131 4132 this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this)) 4133 4134 this.backdrop(function () { 4135 var transition = $.support.transition && that.$element.hasClass('fade') 4136 4137 if (!that.$element.parent().length) { 4138 that.$element.appendTo(that.$body) // don't move modals dom position 4139 } 4140 4141 that.$element 4142 .show() 4143 .scrollTop(0) 4144 4145 if (transition) { 4146 that.$element[0].offsetWidth // force reflow 4147 } 4148 4149 that.$element 4150 .addClass('in') 4151 .attr('aria-hidden', false) 4152 4153 that.enforceFocus() 4154 4155 var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }) 4156 4157 transition ? 4158 that.$element.find('.modal-dialog') // wait for modal to slide in 4159 .one('bsTransitionEnd', function () { 4160 that.$element.trigger('focus').trigger(e) 4161 }) 4162 .emulateTransitionEnd(300) : 4163 that.$element.trigger('focus').trigger(e) 4164 }) 4165 } 4166 4167 Modal.prototype.hide = function (e) { 4168 if (e) e.preventDefault() 4169 4170 e = $.Event('hide.bs.modal') 4171 4172 this.$element.trigger(e) 4173 4174 if (!this.isShown || e.isDefaultPrevented()) return 4175 4176 this.isShown = false 4177 4178 this.$body.removeClass('modal-open') 4179 4180 this.resetScrollbar() 4181 this.escape() 4182 4183 $(document).off('focusin.bs.modal') 4184 4185 this.$element 4186 .removeClass('in') 4187 .attr('aria-hidden', true) 4188 .off('click.dismiss.bs.modal') 4189 4190 $.support.transition && this.$element.hasClass('fade') ? 4191 this.$element 4192 .one('bsTransitionEnd', $.proxy(this.hideModal, this)) 4193 .emulateTransitionEnd(300) : 4194 this.hideModal() 4195 } 4196 4197 Modal.prototype.enforceFocus = function () { 4198 $(document) 4199 .off('focusin.bs.modal') // guard against infinite focus loop 4200 .on('focusin.bs.modal', $.proxy(function (e) { 4201 if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { 4202 this.$element.trigger('focus') 4203 } 4204 }, this)) 4205 } 4206 4207 Modal.prototype.escape = function () { 4208 if (this.isShown && this.options.keyboard) { 4209 this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { 4210 e.which == 27 && this.hide() 4211 }, this)) 4212 } else if (!this.isShown) { 4213 this.$element.off('keyup.dismiss.bs.modal') 4214 } 4215 } 4216 4217 Modal.prototype.hideModal = function () { 4218 var that = this 4219 this.$element.hide() 4220 this.backdrop(function () { 4221 that.$element.trigger('hidden.bs.modal') 4222 }) 4223 } 4224 4225 Modal.prototype.removeBackdrop = function () { 4226 this.$backdrop && this.$backdrop.remove() 4227 this.$backdrop = null 4228 } 4229 4230 Modal.prototype.backdrop = function (callback) { 4231 var that = this 4232 var animate = this.$element.hasClass('fade') ? 'fade' : '' 4233 4234 if (this.isShown && this.options.backdrop) { 4235 var doAnimate = $.support.transition && animate 4236 4237 this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') 4238 .appendTo(this.$body) 4239 4240 this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { 4241 if (e.target !== e.currentTarget) return 4242 this.options.backdrop == 'static' 4243 ? this.$element[0].focus.call(this.$element[0]) 4244 : this.hide.call(this) 4245 }, this)) 4246 4247 if (doAnimate) this.$backdrop[0].offsetWidth // force reflow 4248 4249 this.$backdrop.addClass('in') 4250 4251 if (!callback) return 4252 4253 doAnimate ? 4254 this.$backdrop 4255 .one('bsTransitionEnd', callback) 4256 .emulateTransitionEnd(150) : 4257 callback() 4258 4259 } else if (!this.isShown && this.$backdrop) { 4260 this.$backdrop.removeClass('in') 4261 4262 var callbackRemove = function () { 4263 that.removeBackdrop() 4264 callback && callback() 4265 } 4266 $.support.transition && this.$element.hasClass('fade') ? 4267 this.$backdrop 4268 .one('bsTransitionEnd', callbackRemove) 4269 .emulateTransitionEnd(150) : 4270 callbackRemove() 4271 4272 } else if (callback) { 4273 callback() 4274 } 4275 } 4276 4277 Modal.prototype.checkScrollbar = function () { 4278 if (document.body.clientWidth >= window.innerWidth) return 4279 this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar() 4280 } 4281 4282 Modal.prototype.setScrollbar = function () { 4283 var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10) 4284 if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth) 4285 } 4286 4287 Modal.prototype.resetScrollbar = function () { 4288 this.$body.css('padding-right', '') 4289 } 4290 4291 Modal.prototype.measureScrollbar = function () { // thx walsh 4292 var scrollDiv = document.createElement('div') 4293 scrollDiv.className = 'modal-scrollbar-measure' 4294 this.$body.append(scrollDiv) 4295 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth 4296 this.$body[0].removeChild(scrollDiv) 4297 return scrollbarWidth 4298 } 4299 4300 4301 // MODAL PLUGIN DEFINITION 4302 // ======================= 4303 4304 function Plugin(option, _relatedTarget) { 4305 return this.each(function () { 4306 var $this = $(this) 4307 var data = $this.data('bs.modal') 4308 var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option) 4309 4310 if (!data) $this.data('bs.modal', (data = new Modal(this, options))) 4311 if (typeof option == 'string') data[option](_relatedTarget) 4312 else if (options.show) data.show(_relatedTarget) 4313 }) 4314 } 4315 4316 var old = $.fn.modal 4317 4318 $.fn.modal = Plugin 4319 $.fn.modal.Constructor = Modal 4320 4321 4322 // MODAL NO CONFLICT 4323 // ================= 4324 4325 $.fn.modal.noConflict = function () { 4326 $.fn.modal = old 4327 return this 4328 } 4329 4330 4331 // MODAL DATA-API 4332 // ============== 4333 4334 $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) { 4335 var $this = $(this) 4336 var href = $this.attr('href') 4337 var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7 4338 var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) 4339 4340 if ($this.is('a')) e.preventDefault() 4341 4342 $target.one('show.bs.modal', function (showEvent) { 4343 if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown 4344 $target.one('hidden.bs.modal', function () { 4345 $this.is(':visible') && $this.trigger('focus') 4346 }) 4347 }) 4348 Plugin.call($target, option, this) 4349 }) 4350 4351}(jQuery); 4352 4353/* ======================================================================== 4354 * Bootstrap: transition.js v3.2.0 4355 * http://getbootstrap.com/javascript/#transitions 4356 * ======================================================================== 4357 * Copyright 2011-2014 Twitter, Inc. 4358 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 4359 * ======================================================================== */ 4360 4361 4362+function ($) { 4363 'use strict'; 4364
4365 // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 4366 // ============================================================ 4367 4368 function transitionEnd() { 4369 var el = document.createElement('bootstrap') 4370 4371 var transEndEventNames = { 4372 WebkitTransition : 'webkitTransitionEnd', 4373 MozTransition : 'transitionend', 4374 OTransition : 'oTransitionEnd otransitionend', 4375 transition : 'transitionend' 4376 } 4377 4378 for (var name in transEndEventNames) { 4379 if (el.style[name] !== undefined) { 4380 return { end: transEndEventNames[name] } 4381 } 4382 } 4383 4384 return false // explicit for ie8 ( ._.) 4385 } 4386 4387 // http://blog.alexmaccaw.com/css-transitions 4388 $.fn.emulateTransitionEnd = function (duration) { 4389 var called = false 4390 var $el = this 4391 $(this).one('bsTransitionEnd', function () { called = true }) 4392 var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 4393 setTimeout(callback, duration) 4394 return this 4395 } 4396 4397 $(function () { 4398 $.support.transition = transitionEnd() 4399 4400 if (!$.support.transition) return 4401 4402 $.event.special.bsTransitionEnd = { 4403 bindType: $.support.transition.end, 4404 delegateType: $.support.transition.end, 4405 handle: function (e) { 4406 if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 4407 } 4408 } 4409 }) 4410 4411}(jQuery); 4412 4413/*! 4414 * jQuery Cookie Plugin v1.4.1 4415 * https://github.com/carhartl/jquery-cookie 4416 * 4417 * Copyright 2006, 2014 Klaus Hartl 4418 * Released under the MIT license 4419 */ 4420(function (factory) { 4421 if (typeof define === 'function' && define.amd) { 4422 // AMD (Register as an anonymous module) 4423 define(['jquery'], factory); 4424 } else if (typeof exports === 'object') { 4425 // Node/CommonJS 4426 module.exports = factory(require('jquery')); 4427 } else { 4428 // Browser globals 4429 factory(jQuery); 4430 } 4431}(function ($) { 4432 4433 var pluses = /\+/g; 4434 4435 function encode(s) { 4436 return config.raw ? s : encodeURIComponent(s); 4437 } 4438 4439 function decode(s) { 4440 return config.raw ? s : decodeURIComponent(s); 4441 } 4442 4443 function stringifyCookieValue(value) { 4444 return encode(config.json ? JSON.stringify(value) : String(value)); 4445 } 4446 4447 function parseCookieValue(s) { 4448 if (s.indexOf('"') === 0) { 4449 // This is a quoted cookie as according to RFC2068, unescape... 4450 s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 4451 } 4452 4453 try { 4454 // Replace server-side written pluses with spaces. 4455 // If we can't decode the cookie, ignore it, it's unusable. 4456 // If we can't parse the cookie, ignore it, it's unusable. 4457 s = decodeURIComponent(s.replace(pluses, ' ')); 4458 return config.json ? JSON.parse(s) : s; 4459 } catch(e) {} 4460 } 4461 4462 function read(s, converter) { 4463 var value = config.raw ? s : parseCookieValue(s); 4464 return $.isFunction(converter) ? converter(value) : value; 4465 } 4466 4467 var config = $.cookie = function (key, value, options) { 4468 4469 // Write 4470 4471 if (arguments.length > 1 && !$.isFunction(value)) { 4472 options = $.extend({}, config.defaults, options); 4473 4474 if (typeof options.expires === 'number') { 4475 var days = options.expires, t = options.expires = new Date(); 4476 t.setMilliseconds(t.getMilliseconds() + days * 864e+5); 4477 } 4478 4479 return (document.cookie = [ 4480 encode(key), '=', stringifyCookieValue(value), 4481 options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 4482 options.path ? '; path=' + options.path : '', 4483 options.domain ? '; domain=' + options.domain : '', 4484 options.secure ? '; secure' : '' 4485 ].join('')); 4486 } 4487 4488 // Read 4489 4490 var result = key ? undefined : {}, 4491 // To prevent the for loop in the first place assign an empty array 4492 // in case there are no cookies at all. Also prevents odd result when 4493 // calling $.cookie(). 4494 cookies = document.cookie ? document.cookie.split('; ') : [], 4495 i = 0, 4496 l = cookies.length; 4497 4498 for (; i < l; i++) { 4499 var parts = cookies[i].split('='), 4500 name = decode(parts.shift()), 4501 cookie = parts.join('='); 4502 4503 if (key === name) { 4504 // If second argument (value) is a function it's a converter... 4505 result = read(cookie, value); 4506 break; 4507 } 4508 4509 // Prevent storing a cookie that we couldn't decode. 4510 if (!key && (cookie = read(cookie)) !== undefined) { 4511 result[name] = cookie; 4512 } 4513 } 4514 4515 return result; 4516 }; 4517 4518 config.defaults = {}; 4519 4520 $.removeCookie = function (key, options) {
vendor: 7,539 bytes, lines 4521-4807
4521 // Must not alter options, thus extending a fresh object... 4522 $.cookie(key, '', $.extend({}, options, { expires: -1 })); 4523 return !$.cookie(key); 4524 }; 4525 4526})); 4527 4528/*! 4529 * fancyBox - jQuery Plugin 4530 * version: 2.1.5 (Fri, 14 Jun 2013) 4531 * @requires jQuery v1.6 or later 4532 * 4533 * Examples at http://fancyapps.com/fancybox/ 4534 * License: www.fancyapps.com/fancybox/#license 4535 * 4536 * Copyright 2012 Janis Skarnelis - [email protected] 4537 * 4538 */ 4539 4540(function (window, document, $, undefined) { 4541 "use strict"; 4542 4543 var H = $("html"), 4544 W = $(window), 4545 D = $(document), 4546 F = $.fancybox = function () { 4547 F.open.apply( this, arguments ); 4548 }, 4549 IE = navigator.userAgent.match(/msie/i), 4550 didUpdate = null, 4551 isTouch = document.createTouch !== undefined, 4552 4553 isQuery = function(obj) { 4554 return obj && obj.hasOwnProperty && obj instanceof $; 4555 }, 4556 isString = function(str) { 4557 return str && $.type(str) === "string"; 4558 }, 4559 isPercentage = function(str) { 4560 return isString(str) && str.indexOf('%') > 0; 4561 }, 4562 isScrollable = function(el) { 4563 return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight))); 4564 }, 4565 getScalar = function(orig, dim) { 4566 var value = parseInt(orig, 10) || 0; 4567 4568 if (dim && isPercentage(orig)) { 4569 value = F.getViewport()[ dim ] / 100 * value; 4570 } 4571 4572 return Math.ceil(value); 4573 }, 4574 getValue = function(value, dim) { 4575 return getScalar(value, dim) + 'px'; 4576 }; 4577 4578 $.extend(F, { 4579 // The current version of fancyBox 4580 version: '2.1.5', 4581 4582 defaults: { 4583 padding : 15, 4584 margin : 20, 4585 4586 width : 800, 4587 height : 600, 4588 minWidth : 100, 4589 minHeight : 100, 4590 maxWidth : 9999, 4591 maxHeight : 9999, 4592 pixelRatio: 1, // Set to 2 for retina display support 4593 4594 autoSize : true, 4595 autoHeight : false, 4596 autoWidth : false, 4597 4598 autoResize : true, 4599 autoCenter : !isTouch, 4600 fitToView : true, 4601 aspectRatio : false, 4602 topRatio : 0.5, 4603 leftRatio : 0.5, 4604 4605 scrolling : 'auto', // 'auto', 'yes' or 'no' 4606 wrapCSS : '', 4607 4608 arrows : true, 4609 closeBtn : true, 4610 closeClick : false, 4611 nextClick : false, 4612 mouseWheel : true, 4613 autoPlay : false, 4614 playSpeed : 3000, 4615 preload : 3, 4616 modal : false, 4617 loop : true, 4618 4619 ajax : { 4620 dataType : 'html', 4621 headers : { 'X-fancyBox': true } 4622 }, 4623 iframe : { 4624 scrolling : 'auto', 4625 preload : true 4626 }, 4627 swf : { 4628 wmode: 'transparent', 4629 allowfullscreen : 'true', 4630 allowscriptaccess : 'always' 4631 }, 4632 4633 keys : { 4634 next : { 4635 13 : 'left', // enter 4636 34 : 'up', // page down 4637 39 : 'left', // right arrow 4638 40 : 'up' // down arrow 4639 }, 4640 prev : { 4641 8 : 'right', // backspace 4642 33 : 'down', // page up 4643 37 : 'right', // left arrow 4644 38 : 'down' // up arrow 4645 }, 4646 close : [27], // escape key 4647 play : [32], // space - start/stop slideshow 4648 toggle : [70] // letter "f" - toggle fullscreen 4649 }, 4650 4651 direction : { 4652 next : 'left', 4653 prev : 'right' 4654 }, 4655 4656 scrollOutside : true, 4657 4658 // Override some properties 4659 index : 0, 4660 type : null, 4661 href : null, 4662 content : null, 4663 title : null, 4664 4665 // HTML templates 4666 tpl: { 4667 wrap : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>', 4668 image : '<img class="fancybox-image" src="{href}" alt="" />', 4669 iframe : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>', 4670 error : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>', 4671 closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>', 4672 next : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>', 4673 prev : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>' 4674 }, 4675 4676 // Properties for each animation type 4677 // Opening fancyBox 4678 openEffect : 'fade', // 'elastic', 'fade' or 'none' 4679 openSpeed : 250, 4680 openEasing : 'swing', 4681 openOpacity : true, 4682 openMethod : 'zoomIn', 4683 4684 // Closing fancyBox 4685 closeEffect : 'fade', // 'elastic', 'fade' or 'none' 4686 closeSpeed : 250, 4687 closeEasing : 'swing', 4688 closeOpacity : true, 4689 closeMethod : 'zoomOut', 4690 4691 // Changing next gallery item 4692 nextEffect : 'elastic', // 'elastic', 'fade' or 'none' 4693 nextSpeed : 250, 4694 nextEasing : 'swing', 4695 nextMethod : 'changeIn', 4696 4697 // Changing previous gallery item 4698 prevEffect : 'elastic', // 'elastic', 'fade' or 'none' 4699 prevSpeed : 250, 4700 prevEasing : 'swing', 4701 prevMethod : 'changeOut', 4702 4703 // Enable default helpers 4704 helpers : { 4705 overlay : true, 4706 title : true 4707 }, 4708 4709 // Callbacks 4710 onCancel : $.noop, // If canceling 4711 beforeLoad : $.noop, // Before loading 4712 afterLoad : $.noop, // After loading 4713 beforeShow : $.noop, // Before changing in current item 4714 afterShow : $.noop, // After opening 4715 beforeChange : $.noop, // Before changing gallery item 4716 beforeClose : $.noop, // Before closing 4717 afterClose : $.noop // After closing 4718 }, 4719 4720 //Current state 4721 group : {}, // Selected group 4722 opts : {}, // Group options 4723 previous : null, // Previous element 4724 coming : null, // Element being loaded 4725 current : null, // Currently loaded element 4726 isActive : false, // Is activated 4727 isOpen : false, // Is currently open 4728 isOpened : false, // Have been fully opened at least once 4729 4730 wrap : null, 4731 skin : null, 4732 outer : null, 4733 inner : null, 4734 4735 player : { 4736 timer : null, 4737 isActive : false 4738 }, 4739 4740 // Loaders 4741 ajaxLoad : null, 4742 imgPreload : null, 4743 4744 // Some collections 4745 transitions : {}, 4746 helpers : {}, 4747 4748 /* 4749 * Static methods 4750 */ 4751 4752 open: function (group, opts) { 4753 if (!group) { 4754 return; 4755 } 4756 4757 if (!$.isPlainObject(opts)) { 4758 opts = {}; 4759 } 4760 4761 // Close if already active 4762 if (false === F.close(true)) { 4763 return; 4764 } 4765 4766 // Normalize group 4767 if (!$.isArray(group)) { 4768 group = isQuery(group) ? $(group).get() : [group]; 4769 } 4770 4771 // Recheck if the type of each element is `object` and set content type (image, ajax, etc) 4772 $.each(group, function(i, element) { 4773 var obj = {}, 4774 href, 4775 title, 4776 content, 4777 type, 4778 rez, 4779 hrefParts, 4780 selector; 4781 4782 if ($.type(element) === "object") { 4783 // Check if is DOM element 4784 if (element.nodeType) { 4785 element = $(element); 4786 } 4787 4788 if (isQuery(element)) { 4789 obj = { 4790 href : element.data('fancybox-href') || element.attr('href'), 4791 title : element.data('fancybox-title') || element.attr('title'), 4792 isDom : true, 4793 element : element 4794 }; 4795 4796 if ($.metadata) { 4797 $.extend(true, obj, element.metadata()); 4798 } 4799 4800 } else { 4801 obj = element; 4802 } 4803 } 4804 4805 href = opts.href || obj.href || (isString(element) ? element : null); 4806 title = opts.title !== undefined ? opts.title : obj.title || ''; 4807
vendor: 40,030 bytes, lines 4808-6419
4808 content = opts.content || obj.content; 4809 type = content ? 'html' : (opts.type || obj.type); 4810 4811 if (!type && obj.isDom) { 4812 type = element.data('fancybox-type'); 4813 4814 if (!type) { 4815 rez = element.prop('class').match(/fancybox\.(\w+)/); 4816 type = rez ? rez[1] : null; 4817 } 4818 } 4819 4820 if (isString(href)) { 4821 // Try to guess the content type 4822 if (!type) { 4823 if (F.isImage(href)) { 4824 type = 'image'; 4825 4826 } else if (F.isSWF(href)) { 4827 type = 'swf'; 4828 4829 } else if (href.charAt(0) === '#') { 4830 type = 'inline'; 4831 4832 } else if (isString(element)) { 4833 type = 'html'; 4834 content = element; 4835 } 4836 } 4837 4838 // Split url into two pieces with source url and content selector, e.g, 4839 // "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id" 4840 if (type === 'ajax') { 4841 hrefParts = href.split(/\s+/, 2); 4842 href = hrefParts.shift(); 4843 selector = hrefParts.shift(); 4844 } 4845 } 4846 4847 if (!content) { 4848 if (type === 'inline') { 4849 if (href) { 4850 content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7 4851 4852 } else if (obj.isDom) { 4853 content = element; 4854 } 4855 4856 } else if (type === 'html') { 4857 content = href; 4858 4859 } else if (!type && !href && obj.isDom) { 4860 type = 'inline'; 4861 content = element; 4862 } 4863 } 4864 4865 $.extend(obj, { 4866 href : href, 4867 type : type, 4868 content : content, 4869 title : title, 4870 selector : selector 4871 }); 4872 4873 group[ i ] = obj; 4874 }); 4875 4876 // Extend the defaults 4877 F.opts = $.extend(true, {}, F.defaults, opts); 4878 4879 // All options are merged recursive except keys 4880 if (opts.keys !== undefined) { 4881 F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; 4882 } 4883 4884 F.group = group; 4885 4886 return F._start(F.opts.index); 4887 }, 4888 4889 // Cancel image loading or abort ajax request 4890 cancel: function () { 4891 var coming = F.coming; 4892 4893 if (!coming || false === F.trigger('onCancel')) { 4894 return; 4895 } 4896 4897 F.hideLoading(); 4898 4899 if (F.ajaxLoad) { 4900 F.ajaxLoad.abort(); 4901 } 4902 4903 F.ajaxLoad = null; 4904 4905 if (F.imgPreload) { 4906 F.imgPreload.onload = F.imgPreload.onerror = null; 4907 } 4908 4909 if (coming.wrap) { 4910 coming.wrap.stop(true, true).trigger('onReset').remove(); 4911 } 4912 4913 F.coming = null; 4914 4915 // If the first item has been canceled, then clear everything 4916 if (!F.current) { 4917 F._afterZoomOut( coming ); 4918 } 4919 }, 4920 4921 // Start closing animation if is open; remove immediately if opening/closing 4922 close: function (event) { 4923 F.cancel(); 4924 4925 if (false === F.trigger('beforeClose')) { 4926 return; 4927 } 4928 4929 F.unbindEvents(); 4930 4931 if (!F.isActive) { 4932 return; 4933 } 4934 4935 if (!F.isOpen || event === true) { 4936 $('.fancybox-wrap').stop(true).trigger('onReset').remove(); 4937 4938 F._afterZoomOut(); 4939 4940 } else { 4941 F.isOpen = F.isOpened = false; 4942 F.isClosing = true; 4943 4944 $('.fancybox-item, .fancybox-nav').remove(); 4945 4946 F.wrap.stop(true, true).removeClass('fancybox-opened'); 4947 4948 F.transitions[ F.current.closeMethod ](); 4949 } 4950 }, 4951 4952 // Manage slideshow: 4953 // $.fancybox.play(); - toggle slideshow 4954 // $.fancybox.play( true ); - start 4955 // $.fancybox.play( false ); - stop 4956 play: function ( action ) { 4957 var clear = function () { 4958 clearTimeout(F.player.timer); 4959 }, 4960 set = function () { 4961 clear(); 4962 4963 if (F.current && F.player.isActive) { 4964 F.player.timer = setTimeout(F.next, F.current.playSpeed); 4965 } 4966 }, 4967 stop = function () { 4968 clear(); 4969 4970 D.unbind('.player'); 4971 4972 F.player.isActive = false; 4973 4974 F.trigger('onPlayEnd'); 4975 }, 4976 start = function () { 4977 if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { 4978 F.player.isActive = true; 4979 4980 D.bind({ 4981 'onCancel.player beforeClose.player' : stop, 4982 'onUpdate.player' : set, 4983 'beforeLoad.player' : clear 4984 }); 4985 4986 set(); 4987 4988 F.trigger('onPlayStart'); 4989 } 4990 }; 4991 4992 if (action === true || (!F.player.isActive && action !== false)) { 4993 start(); 4994 } else { 4995 stop(); 4996 } 4997 }, 4998 4999 // Navigate to next gallery item 5000 next: function ( direction ) { 5001 var current = F.current; 5002 5003 if (current) { 5004 if (!isString(direction)) { 5005 direction = current.direction.next; 5006 } 5007 5008 F.jumpto(current.index + 1, direction, 'next'); 5009 } 5010 }, 5011 5012 // Navigate to previous gallery item 5013 prev: function ( direction ) { 5014 var current = F.current; 5015 5016 if (current) { 5017 if (!isString(direction)) { 5018 direction = current.direction.prev; 5019 } 5020 5021 F.jumpto(current.index - 1, direction, 'prev'); 5022 } 5023 }, 5024 5025 // Navigate to gallery item by index 5026 jumpto: function ( index, direction, router ) { 5027 var current = F.current; 5028 5029 if (!current) { 5030 return; 5031 } 5032 5033 index = getScalar(index); 5034 5035 F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ]; 5036 F.router = router || 'jumpto'; 5037 5038 if (current.loop) { 5039 if (index < 0) { 5040 index = current.group.length + (index % current.group.length); 5041 } 5042 5043 index = index % current.group.length; 5044 } 5045 5046 if (current.group[ index ] !== undefined) { 5047 F.cancel(); 5048 5049 F._start(index); 5050 } 5051 }, 5052 5053 // Center inside viewport and toggle position type to fixed or absolute if needed 5054 reposition: function (e, onlyAbsolute) { 5055 var current = F.current, 5056 wrap = current ? current.wrap : null, 5057 pos; 5058 5059 if (wrap) { 5060 pos = F._getPosition(onlyAbsolute); 5061 5062 if (e && e.type === 'scroll') { 5063 delete pos.position; 5064 5065 wrap.stop(true, true).animate(pos, 200); 5066 5067 } else { 5068 wrap.css(pos); 5069 5070 current.pos = $.extend({}, current.dim, pos); 5071 } 5072 } 5073 }, 5074 5075 update: function (e) { 5076 var type = (e && e.type), 5077 anyway = !type || type === 'orientationchange'; 5078 5079 if (anyway) { 5080 clearTimeout(didUpdate); 5081 5082 didUpdate = null; 5083 } 5084 5085 if (!F.isOpen || didUpdate) { 5086 return; 5087 } 5088 5089 didUpdate = setTimeout(function() { 5090 var current = F.current; 5091 5092 if (!current || F.isClosing) { 5093 return; 5094 } 5095 5096 F.wrap.removeClass('fancybox-tmp'); 5097 5098 if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) { 5099 F._setDimension(); 5100 } 5101 5102 if (!(type === 'scroll' && current.canShrink)) { 5103 F.reposition(e); 5104 } 5105 5106 F.trigger('onUpdate'); 5107 5108 didUpdate = null; 5109 5110 }, (anyway && !isTouch ? 0 : 300)); 5111 }, 5112 5113 // Shrink content to fit inside viewport or restore if resized 5114 toggle: function ( action ) { 5115 if (F.isOpen) { 5116 F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView; 5117 5118 // Help browser to restore document dimensions 5119 if (isTouch) { 5120 F.wrap.removeAttr('style').addClass('fancybox-tmp'); 5121 5122 F.trigger('onUpdate'); 5123 } 5124 5125 F.update(); 5126 } 5127 }, 5128 5129 hideLoading: function () { 5130 D.unbind('.loading'); 5131 5132 $('#fancybox-loading').remove(); 5133 }, 5134 5135 showLoading: function () { 5136 var el, viewport; 5137 5138 F.hideLoading(); 5139 5140 el = $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body'); 5141 5142 // If user will press the escape-button, the request will be canceled 5143 D.bind('keydown.loading', function(e) { 5144 if ((e.which || e.keyCode) === 27) { 5145 e.preventDefault(); 5146 5147 F.cancel(); 5148 } 5149 }); 5150 5151 if (!F.defaults.fixed) { 5152 viewport = F.getViewport(); 5153 5154 el.css({ 5155 position : 'absolute', 5156 top : (viewport.h * 0.5) + viewport.y, 5157 left : (viewport.w * 0.5) + viewport.x 5158 }); 5159 } 5160 }, 5161 5162 getViewport: function () { 5163 var locked = (F.current && F.current.locked) || false, 5164 rez = { 5165 x: W.scrollLeft(), 5166 y: W.scrollTop() 5167 }; 5168 5169 if (locked) { 5170 rez.w = locked[0].clientWidth; 5171 rez.h = locked[0].clientHeight; 5172 5173 } else { 5174 // See http://bugs.jquery.com/ticket/6724 5175 rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width(); 5176 rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height(); 5177 } 5178 5179 return rez; 5180 }, 5181 5182 // Unbind the keyboard / clicking actions 5183 unbindEvents: function () { 5184 if (F.wrap && isQuery(F.wrap)) { 5185 F.wrap.unbind('.fb'); 5186 } 5187 5188 D.unbind('.fb'); 5189 W.unbind('.fb'); 5190 }, 5191 5192 bindEvents: function () { 5193 var current = F.current, 5194 keys; 5195 5196 if (!current) { 5197 return; 5198 } 5199 5200 // Changing document height on iOS devices triggers a 'resize' event, 5201 // that can change document height... repeating infinitely 5202 W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update); 5203 5204 keys = current.keys; 5205 5206 if (keys) { 5207 D.bind('keydown.fb', function (e) { 5208 var code = e.which || e.keyCode, 5209 target = e.target || e.srcElement; 5210 5211 // Skip esc key if loading, because showLoading will cancel preloading 5212 if (code === 27 && F.coming) { 5213 return false; 5214 } 5215 5216 // Ignore key combinations and key events within form elements 5217 if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { 5218 $.each(keys, function(i, val) { 5219 if (current.group.length > 1 && val[ code ] !== undefined) { 5220 F[ i ]( val[ code ] ); 5221 5222 e.preventDefault(); 5223 return false; 5224 } 5225 5226 if ($.inArray(code, val) > -1) { 5227 F[ i ] (); 5228 5229 e.preventDefault(); 5230 return false; 5231 } 5232 }); 5233 } 5234 }); 5235 } 5236 5237 if ($.fn.mousewheel && current.mouseWheel) { 5238 F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) { 5239 var target = e.target || null, 5240 parent = $(target), 5241 canScroll = false; 5242 5243 while (parent.length) { 5244 if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) { 5245 break; 5246 } 5247 5248 canScroll = isScrollable( parent[0] ); 5249 parent = $(parent).parent(); 5250 } 5251 5252 if (delta !== 0 && !canScroll) { 5253 if (F.group.length > 1 && !current.canShrink) { 5254 if (deltaY > 0 || deltaX > 0) { 5255 F.prev( deltaY > 0 ? 'down' : 'left' ); 5256 5257 } else if (deltaY < 0 || deltaX < 0) { 5258 F.next( deltaY < 0 ? 'up' : 'right' ); 5259 } 5260 5261 e.preventDefault(); 5262 } 5263 } 5264 }); 5265 } 5266 }, 5267 5268 trigger: function (event, o) { 5269 var ret, obj = o || F.coming || F.current; 5270 5271 if (!obj) { 5272 return; 5273 } 5274 5275 if ($.isFunction( obj[event] )) { 5276 ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); 5277 } 5278 5279 if (ret === false) { 5280 return false; 5281 } 5282 5283 if (obj.helpers) { 5284 $.each(obj.helpers, function (helper, opts) { 5285 if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) { 5286 F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj); 5287 } 5288 }); 5289 } 5290 5291 D.trigger(event); 5292 }, 5293 5294 isImage: function (str) { 5295 return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); 5296 }, 5297 5298 isSWF: function (str) { 5299 return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); 5300 }, 5301 5302 _start: function (index) { 5303 var coming = {}, 5304 obj, 5305 href, 5306 type, 5307 margin, 5308 padding; 5309 5310 index = getScalar( index ); 5311 obj = F.group[ index ] || null; 5312 5313 if (!obj) { 5314 return false; 5315 } 5316 5317 coming = $.extend(true, {}, F.opts, obj); 5318 5319 // Convert margin and padding properties to array - top, right, bottom, left 5320 margin = coming.margin; 5321 padding = coming.padding; 5322 5323 if ($.type(margin) === 'number') { 5324 coming.margin = [margin, margin, margin, margin]; 5325 } 5326 5327 if ($.type(padding) === 'number') { 5328 coming.padding = [padding, padding, padding, padding]; 5329 } 5330 5331 // 'modal' propery is just a shortcut 5332 if (coming.modal) { 5333 $.extend(true, coming, { 5334 closeBtn : false, 5335 closeClick : false, 5336 nextClick : false, 5337 arrows : false, 5338 mouseWheel : false, 5339 keys : null, 5340 helpers: { 5341 overlay : { 5342 closeClick : false 5343 } 5344 } 5345 }); 5346 } 5347 5348 // 'autoSize' property is a shortcut, too 5349 if (coming.autoSize) { 5350 coming.autoWidth = coming.autoHeight = true; 5351 } 5352 5353 if (coming.width === 'auto') { 5354 coming.autoWidth = true; 5355 } 5356 5357 if (coming.height === 'auto') { 5358 coming.autoHeight = true; 5359 } 5360 5361 /* 5362 * Add reference to the group, so it`s possible to access from callbacks, example: 5363 * afterLoad : function() { 5364 * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); 5365 * } 5366 */ 5367 5368 coming.group = F.group; 5369 coming.index = index; 5370 5371 // Give a chance for callback or helpers to update coming item (type, title, etc) 5372 F.coming = coming; 5373 5374 if (false === F.trigger('beforeLoad')) { 5375 F.coming = null; 5376 5377 return; 5378 } 5379 5380 type = coming.type; 5381 href = coming.href; 5382 5383 if (!type) { 5384 F.coming = null; 5385 5386 //If we can not determine content type then drop silently or display next/prev item if looping through gallery 5387 if (F.current && F.router && F.router !== 'jumpto') { 5388 F.current.index = index; 5389 5390 return F[ F.router ]( F.direction ); 5391 } 5392 5393 return false; 5394 } 5395 5396 F.isActive = true; 5397 5398 if (type === 'image' || type === 'swf') { 5399 coming.autoHeight = coming.autoWidth = false; 5400 coming.scrolling = 'visible'; 5401 } 5402 5403 if (type === 'image') { 5404 coming.aspectRatio = true; 5405 } 5406 5407 if (type === 'iframe' && isTouch) { 5408 coming.scrolling = 'scroll'; 5409 } 5410 5411 // Build the neccessary markup 5412 coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' ); 5413 5414 $.extend(coming, { 5415 skin : $('.fancybox-skin', coming.wrap), 5416 outer : $('.fancybox-outer', coming.wrap), 5417 inner : $('.fancybox-inner', coming.wrap) 5418 }); 5419 5420 $.each(["Top", "Right", "Bottom", "Left"], function(i, v) { 5421 coming.skin.css('padding' + v, getValue(coming.padding[ i ])); 5422 }); 5423 5424 F.trigger('onReady'); 5425 5426 // Check before try to load; 'inline' and 'html' types need content, others - href 5427 if (type === 'inline' || type === 'html') { 5428 if (!coming.content || !coming.content.length) { 5429 return F._error( 'content' ); 5430 } 5431 5432 } else if (!href) { 5433 return F._error( 'href' ); 5434 } 5435 5436 if (type === 'image') { 5437 F._loadImage(); 5438 5439 } else if (type === 'ajax') { 5440 F._loadAjax(); 5441 5442 } else if (type === 'iframe') { 5443 F._loadIframe(); 5444 5445 } else { 5446 F._afterLoad(); 5447 } 5448 }, 5449 5450 _error: function ( type ) { 5451 $.extend(F.coming, { 5452 type : 'html', 5453 autoWidth : true, 5454 autoHeight : true, 5455 minWidth : 0, 5456 minHeight : 0, 5457 scrolling : 'no', 5458 hasError : type, 5459 content : F.coming.tpl.error 5460 }); 5461 5462 F._afterLoad(); 5463 }, 5464 5465 _loadImage: function () { 5466 // Reset preload image so it is later possible to check "complete" property 5467 var img = F.imgPreload = new Image(); 5468 5469 img.onload = function () { 5470 this.onload = this.onerror = null; 5471 5472 F.coming.width = this.width / F.opts.pixelRatio; 5473 F.coming.height = this.height / F.opts.pixelRatio; 5474 5475 F._afterLoad(); 5476 }; 5477 5478 img.onerror = function () { 5479 this.onload = this.onerror = null; 5480 5481 F._error( 'image' ); 5482 }; 5483 5484 img.src = F.coming.href; 5485 5486 if (img.complete !== true) { 5487 F.showLoading(); 5488 } 5489 }, 5490 5491 _loadAjax: function () { 5492 var coming = F.coming; 5493 5494 F.showLoading(); 5495 5496 F.ajaxLoad = $.ajax($.extend({}, coming.ajax, { 5497 url: coming.href, 5498 error: function (jqXHR, textStatus) { 5499 if (F.coming && textStatus !== 'abort') { 5500 F._error( 'ajax', jqXHR ); 5501 5502 } else { 5503 F.hideLoading(); 5504 } 5505 }, 5506 success: function (data, textStatus) { 5507 if (textStatus === 'success') { 5508 coming.content = data; 5509 5510 F._afterLoad(); 5511 } 5512 } 5513 })); 5514 }, 5515 5516 _loadIframe: function() { 5517 var coming = F.coming, 5518 iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime())) 5519 .attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling) 5520 .attr('src', coming.href); 5521 5522 // This helps IE 5523 $(coming.wrap).bind('onReset', function () { 5524 try { 5525 $(this).find('iframe').hide().attr('src', '//about:blank').end().empty(); 5526 } catch (e) {} 5527 }); 5528 5529 if (coming.iframe.preload) { 5530 F.showLoading(); 5531 5532 iframe.one('load', function() { 5533 $(this).data('ready', 1); 5534 5535 // iOS will lose scrolling if we resize 5536 if (!isTouch) { 5537 $(this).bind('load.fb', F.update); 5538 } 5539 5540 // Without this trick: 5541 // - iframe won't scroll on iOS devices 5542 // - IE7 sometimes displays empty iframe 5543 $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show(); 5544 5545 F._afterLoad(); 5546 }); 5547 } 5548 5549 coming.content = iframe.appendTo( coming.inner ); 5550 5551 if (!coming.iframe.preload) { 5552 F._afterLoad(); 5553 } 5554 }, 5555 5556 _preloadImages: function() { 5557 var group = F.group, 5558 current = F.current, 5559 len = group.length, 5560 cnt = current.preload ? Math.min(current.preload, len - 1) : 0, 5561 item, 5562 i; 5563 5564 for (i = 1; i <= cnt; i += 1) { 5565 item = group[ (current.index + i ) % len ]; 5566 5567 if (item.type === 'image' && item.href) { 5568 new Image().src = item.href; 5569 } 5570 } 5571 }, 5572 5573 _afterLoad: function () { 5574 var coming = F.coming, 5575 previous = F.current, 5576 placeholder = 'fancybox-placeholder', 5577 current, 5578 content, 5579 type, 5580 scrolling, 5581 href, 5582 embed; 5583 5584 F.hideLoading(); 5585 5586 if (!coming || F.isActive === false) { 5587 return; 5588 } 5589 5590 if (false === F.trigger('afterLoad', coming, previous)) { 5591 coming.wrap.stop(true).trigger('onReset').remove(); 5592 5593 F.coming = null; 5594 5595 return; 5596 } 5597 5598 if (previous) { 5599 F.trigger('beforeChange', previous); 5600 5601 previous.wrap.stop(true).removeClass('fancybox-opened') 5602 .find('.fancybox-item, .fancybox-nav') 5603 .remove(); 5604 } 5605 5606 F.unbindEvents(); 5607 5608 current = coming; 5609 content = coming.content; 5610 type = coming.type; 5611 scrolling = coming.scrolling; 5612 5613 $.extend(F, { 5614 wrap : current.wrap, 5615 skin : current.skin, 5616 outer : current.outer, 5617 inner : current.inner, 5618 current : current, 5619 previous : previous 5620 }); 5621 5622 href = current.href; 5623 5624 switch (type) { 5625 case 'inline': 5626 case 'ajax': 5627 case 'html': 5628 if (current.selector) { 5629 content = $('<div>').html(content).find(current.selector); 5630 5631 } else if (isQuery(content)) { 5632 if (!content.data(placeholder)) { 5633 content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() ); 5634 } 5635 5636 content = content.show().detach(); 5637 5638 current.wrap.bind('onReset', function () { 5639 if ($(this).find(content).length) { 5640 content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false); 5641 } 5642 }); 5643 } 5644 break; 5645 5646 case 'image': 5647 content = current.tpl.image.replace('{href}', href); 5648 break; 5649 5650 case 'swf': 5651 content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>'; 5652 embed = ''; 5653 5654 $.each(current.swf, function(name, val) { 5655 content += '<param name="' + name + '" value="' + val + '"></param>'; 5656 embed += ' ' + name + '="' + val + '"'; 5657 }); 5658 5659 content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>'; 5660 break; 5661 } 5662 5663 if (!(isQuery(content) && content.parent().is(current.inner))) { 5664 current.inner.append( content ); 5665 } 5666 5667 // Give a chance for helpers or callbacks to update elements 5668 F.trigger('beforeShow'); 5669 5670 // Set scrolling before calculating dimensions 5671 current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling)); 5672 5673 // Set initial dimensions and start position 5674 F._setDimension(); 5675 5676 F.reposition(); 5677 5678 F.isOpen = false; 5679 F.coming = null; 5680 5681 F.bindEvents(); 5682 5683 if (!F.isOpened) { 5684 $('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove(); 5685 5686 } else if (previous.prevMethod) { 5687 F.transitions[ previous.prevMethod ](); 5688 } 5689 5690 F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ](); 5691 5692 F._preloadImages(); 5693 }, 5694 5695 _setDimension: function () { 5696 var viewport = F.getViewport(), 5697 steps = 0, 5698 canShrink = false, 5699 canExpand = false, 5700 wrap = F.wrap, 5701 skin = F.skin, 5702 inner = F.inner, 5703 current = F.current, 5704 width = current.width, 5705 height = current.height, 5706 minWidth = current.minWidth, 5707 minHeight = current.minHeight, 5708 maxWidth = current.maxWidth, 5709 maxHeight = current.maxHeight, 5710 scrolling = current.scrolling, 5711 scrollOut = current.scrollOutside ? current.scrollbarWidth : 0, 5712 margin = current.margin, 5713 wMargin = getScalar(margin[1] + margin[3]), 5714 hMargin = getScalar(margin[0] + margin[2]), 5715 wPadding, 5716 hPadding, 5717 wSpace, 5718 hSpace, 5719 origWidth, 5720 origHeight, 5721 origMaxWidth, 5722 origMaxHeight, 5723 ratio, 5724 width_, 5725 height_, 5726 maxWidth_, 5727 maxHeight_, 5728 iframe, 5729 body; 5730 5731 // Reset dimensions so we could re-check actual size 5732 wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp'); 5733 5734 wPadding = getScalar(skin.outerWidth(true) - skin.width()); 5735 hPadding = getScalar(skin.outerHeight(true) - skin.height()); 5736 5737 // Any space between content and viewport (margin, padding, border, title) 5738 wSpace = wMargin + wPadding; 5739 hSpace = hMargin + hPadding; 5740 5741 origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width; 5742 origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height; 5743 5744 if (current.type === 'iframe') { 5745 iframe = current.content; 5746 5747 if (current.autoHeight && iframe.data('ready') === 1) { 5748 try { 5749 if (iframe[0].contentWindow.document.location) { 5750 inner.width( origWidth ).height(9999); 5751 5752 body = iframe.contents().find('body'); 5753 5754 if (scrollOut) { 5755 body.css('overflow-x', 'hidden'); 5756 } 5757 5758 origHeight = body.outerHeight(true); 5759 } 5760 5761 } catch (e) {} 5762 } 5763 5764 } else if (current.autoWidth || current.autoHeight) { 5765 inner.addClass( 'fancybox-tmp' ); 5766 5767 // Set width or height in case we need to calculate only one dimension 5768 if (!current.autoWidth) { 5769 inner.width( origWidth ); 5770 } 5771 5772 if (!current.autoHeight) { 5773 inner.height( origHeight ); 5774 } 5775 5776 if (current.autoWidth) { 5777 origWidth = inner.width(); 5778 } 5779 5780 if (current.autoHeight) { 5781 origHeight = inner.height(); 5782 } 5783 5784 inner.removeClass( 'fancybox-tmp' ); 5785 } 5786 5787 width = getScalar( origWidth ); 5788 height = getScalar( origHeight ); 5789 5790 ratio = origWidth / origHeight; 5791 5792 // Calculations for the content 5793 minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth); 5794 maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth); 5795 5796 minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight); 5797 maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight); 5798 5799 // These will be used to determine if wrap can fit in the viewport 5800 origMaxWidth = maxWidth; 5801 origMaxHeight = maxHeight; 5802 5803 if (current.fitToView) { 5804 maxWidth = Math.min(viewport.w - wSpace, maxWidth); 5805 maxHeight = Math.min(viewport.h - hSpace, maxHeight); 5806 } 5807 5808 maxWidth_ = viewport.w - wMargin; 5809 maxHeight_ = viewport.h - hMargin; 5810 5811 if (current.aspectRatio) { 5812 if (width > maxWidth) { 5813 width = maxWidth; 5814 height = getScalar(width / ratio); 5815 } 5816 5817 if (height > maxHeight) { 5818 height = maxHeight; 5819 width = getScalar(height * ratio); 5820 } 5821 5822 if (width < minWidth) { 5823 width = minWidth; 5824 height = getScalar(width / ratio); 5825 } 5826 5827 if (height < minHeight) { 5828 height = minHeight; 5829 width = getScalar(height * ratio); 5830 } 5831 5832 } else { 5833 width = Math.max(minWidth, Math.min(width, maxWidth)); 5834 5835 if (current.autoHeight && current.type !== 'iframe') { 5836 inner.width( width ); 5837 5838 height = inner.height(); 5839 } 5840 5841 height = Math.max(minHeight, Math.min(height, maxHeight)); 5842 } 5843 5844 // Try to fit inside viewport (including the title) 5845 if (current.fitToView) { 5846 inner.width( width ).height( height ); 5847 5848 wrap.width( width + wPadding ); 5849 5850 // Real wrap dimensions 5851 width_ = wrap.width(); 5852 height_ = wrap.height(); 5853 5854 if (current.aspectRatio) { 5855 while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) { 5856 if (steps++ > 19) { 5857 break; 5858 } 5859 5860 height = Math.max(minHeight, Math.min(maxHeight, height - 10)); 5861 width = getScalar(height * ratio); 5862 5863 if (width < minWidth) { 5864 width = minWidth; 5865 height = getScalar(width / ratio); 5866 } 5867 5868 if (width > maxWidth) { 5869 width = maxWidth; 5870 height = getScalar(width / ratio); 5871 } 5872 5873 inner.width( width ).height( height ); 5874 5875 wrap.width( width + wPadding ); 5876 5877 width_ = wrap.width(); 5878 height_ = wrap.height(); 5879 } 5880 5881 } else { 5882 width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_))); 5883 height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_))); 5884 } 5885 } 5886 5887 if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) { 5888 width += scrollOut; 5889 } 5890 5891 inner.width( width ).height( height ); 5892 5893 wrap.width( width + wPadding ); 5894 5895 width_ = wrap.width(); 5896 height_ = wrap.height(); 5897 5898 canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight; 5899 canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight)); 5900 5901 $.extend(current, { 5902 dim : { 5903 width : getValue( width_ ), 5904 height : getValue( height_ ) 5905 }, 5906 origWidth : origWidth, 5907 origHeight : origHeight, 5908 canShrink : canShrink, 5909 canExpand : canExpand, 5910 wPadding : wPadding, 5911 hPadding : hPadding, 5912 wrapSpace : height_ - skin.outerHeight(true), 5913 skinSpace : skin.height() - height 5914 }); 5915 5916 if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) { 5917 inner.height('auto'); 5918 } 5919 }, 5920 5921 _getPosition: function (onlyAbsolute) { 5922 var current = F.current, 5923 viewport = F.getViewport(), 5924 margin = current.margin, 5925 width = F.wrap.width() + margin[1] + margin[3], 5926 height = F.wrap.height() + margin[0] + margin[2], 5927 rez = { 5928 position: 'absolute', 5929 top : margin[0], 5930 left : margin[3] 5931 }; 5932 5933 if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { 5934 rez.position = 'fixed'; 5935 5936 } else if (!current.locked) { 5937 rez.top += viewport.y; 5938 rez.left += viewport.x; 5939 } 5940 5941 rez.top = getValue(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))); 5942 rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width) * current.leftRatio))); 5943 5944 return rez; 5945 }, 5946 5947 _afterZoomIn: function () { 5948 var current = F.current; 5949 5950 if (!current) { 5951 return; 5952 } 5953 5954 F.isOpen = F.isOpened = true; 5955 5956 F.wrap.css('overflow', 'visible').addClass('fancybox-opened'); 5957 5958 F.update(); 5959 5960 // Assign a click event 5961 if ( current.closeClick || (current.nextClick && F.group.length > 1) ) { 5962 F.inner.css('cursor', 'pointer').bind('click.fb', function(e) { 5963 if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { 5964 e.preventDefault(); 5965 5966 F[ current.closeClick ? 'close' : 'next' ](); 5967 } 5968 }); 5969 } 5970 5971 // Create a close button 5972 if (current.closeBtn) { 5973 $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) { 5974 e.preventDefault(); 5975 5976 F.close(); 5977 }); 5978 } 5979 5980 // Create navigation arrows 5981 if (current.arrows && F.group.length > 1) { 5982 if (current.loop || current.index > 0) { 5983 $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); 5984 } 5985 5986 if (current.loop || current.index < F.group.length - 1) { 5987 $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); 5988 } 5989 } 5990 5991 F.trigger('afterShow'); 5992 5993 // Stop the slideshow if this is the last item 5994 if (!current.loop && current.index === current.group.length - 1) { 5995 F.play( false ); 5996 5997 } else if (F.opts.autoPlay && !F.player.isActive) { 5998 F.opts.autoPlay = false; 5999 6000 F.play(); 6001 } 6002 }, 6003 6004 _afterZoomOut: function ( obj ) { 6005 obj = obj || F.current; 6006 6007 $('.fancybox-wrap').trigger('onReset').remove(); 6008 6009 $.extend(F, { 6010 group : {}, 6011 opts : {}, 6012 router : false, 6013 current : null, 6014 isActive : false, 6015 isOpened : false, 6016 isOpen : false, 6017 isClosing : false, 6018 wrap : null, 6019 skin : null, 6020 outer : null, 6021 inner : null 6022 }); 6023 6024 F.trigger('afterClose', obj); 6025 } 6026 }); 6027 6028 /* 6029 * Default transitions 6030 */ 6031 6032 F.transitions = { 6033 getOrigPosition: function () { 6034 var current = F.current, 6035 element = current.element, 6036 orig = current.orig, 6037 pos = {}, 6038 width = 50, 6039 height = 50, 6040 hPadding = current.hPadding, 6041 wPadding = current.wPadding, 6042 viewport = F.getViewport(); 6043 6044 if (!orig && current.isDom && element.is(':visible')) { 6045 orig = element.find('img:first'); 6046 6047 if (!orig.length) { 6048 orig = element; 6049 } 6050 } 6051 6052 if (isQuery(orig)) { 6053 pos = orig.offset(); 6054 6055 if (orig.is('img')) { 6056 width = orig.outerWidth(); 6057 height = orig.outerHeight(); 6058 } 6059 6060 } else { 6061 pos.top = viewport.y + (viewport.h - height) * current.topRatio; 6062 pos.left = viewport.x + (viewport.w - width) * current.leftRatio; 6063 } 6064 6065 if (F.wrap.css('position') === 'fixed' || current.locked) { 6066 pos.top -= viewport.y; 6067 pos.left -= viewport.x; 6068 } 6069 6070 pos = { 6071 top : getValue(pos.top - hPadding * current.topRatio), 6072 left : getValue(pos.left - wPadding * current.leftRatio), 6073 width : getValue(width + wPadding), 6074 height : getValue(height + hPadding) 6075 }; 6076 6077 return pos; 6078 }, 6079 6080 step: function (now, fx) { 6081 var ratio, 6082 padding, 6083 value, 6084 prop = fx.prop, 6085 current = F.current, 6086 wrapSpace = current.wrapSpace, 6087 skinSpace = current.skinSpace; 6088 6089 if (prop === 'width' || prop === 'height') { 6090 ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start); 6091 6092 if (F.isClosing) { 6093 ratio = 1 - ratio; 6094 } 6095 6096 padding = prop === 'width' ? current.wPadding : current.hPadding; 6097 value = now - padding; 6098 6099 F.skin[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) ) ); 6100 F.inner[ prop ]( getScalar( prop === 'width' ? value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) ); 6101 } 6102 }, 6103 6104 zoomIn: function () { 6105 var current = F.current, 6106 startPos = current.pos, 6107 effect = current.openEffect, 6108 elastic = effect === 'elastic', 6109 endPos = $.extend({opacity : 1}, startPos); 6110 6111 // Remove "position" property that breaks older IE 6112 delete endPos.position; 6113 6114 if (elastic) { 6115 startPos = this.getOrigPosition(); 6116 6117 if (current.openOpacity) { 6118 startPos.opacity = 0.1; 6119 } 6120 6121 } else if (effect === 'fade') { 6122 startPos.opacity = 0.1; 6123 } 6124 6125 F.wrap.css(startPos).animate(endPos, { 6126 duration : effect === 'none' ? 0 : current.openSpeed, 6127 easing : current.openEasing, 6128 step : elastic ? this.step : null, 6129 complete : F._afterZoomIn 6130 }); 6131 }, 6132 6133 zoomOut: function () { 6134 var current = F.current, 6135 effect = current.closeEffect, 6136 elastic = effect === 'elastic', 6137 endPos = {opacity : 0.1}; 6138 6139 if (elastic) { 6140 endPos = this.getOrigPosition(); 6141 6142 if (current.closeOpacity) { 6143 endPos.opacity = 0.1; 6144 } 6145 } 6146 6147 F.wrap.animate(endPos, { 6148 duration : effect === 'none' ? 0 : current.closeSpeed, 6149 easing : current.closeEasing, 6150 step : elastic ? this.step : null, 6151 complete : F._afterZoomOut 6152 }); 6153 }, 6154 6155 changeIn: function () { 6156 var current = F.current, 6157 effect = current.nextEffect, 6158 startPos = current.pos, 6159 endPos = { opacity : 1 }, 6160 direction = F.direction, 6161 distance = 200, 6162 field; 6163 6164 startPos.opacity = 0.1; 6165 6166 if (effect === 'elastic') { 6167 field = direction === 'down' || direction === 'up' ? 'top' : 'left'; 6168 6169 if (direction === 'down' || direction === 'right') { 6170 startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance); 6171 endPos[ field ] = '+=' + distance + 'px'; 6172 6173 } else { 6174 startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance); 6175 endPos[ field ] = '-=' + distance + 'px'; 6176 } 6177 } 6178 6179 // Workaround for http://bugs.jquery.com/ticket/12273 6180 if (effect === 'none') { 6181 F._afterZoomIn(); 6182 6183 } else { 6184 F.wrap.css(startPos).animate(endPos, { 6185 duration : current.nextSpeed, 6186 easing : current.nextEasing, 6187 complete : F._afterZoomIn 6188 }); 6189 } 6190 }, 6191 6192 changeOut: function () { 6193 var previous = F.previous, 6194 effect = previous.prevEffect, 6195 endPos = { opacity : 0.1 }, 6196 direction = F.direction, 6197 distance = 200; 6198 6199 if (effect === 'elastic') { 6200 endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px'; 6201 } 6202 6203 previous.wrap.animate(endPos, { 6204 duration : effect === 'none' ? 0 : previous.prevSpeed, 6205 easing : previous.prevEasing, 6206 complete : function () { 6207 $(this).trigger('onReset').remove(); 6208 } 6209 }); 6210 } 6211 }; 6212 6213 /* 6214 * Overlay helper 6215 */ 6216 6217 F.helpers.overlay = { 6218 defaults : { 6219 closeClick : true, // if true, fancyBox will be closed when user clicks on the overlay 6220 speedOut : 200, // duration of fadeOut animation 6221 showEarly : true, // indicates if should be opened immediately or wait until the content is ready 6222 css : {}, // custom CSS properties 6223 locked : !isTouch, // if true, the content will be locked into overlay 6224 fixed : true // if false, the overlay CSS position property will not be set to "fixed" 6225 }, 6226 6227 overlay : null, // current handle 6228 fixed : false, // indicates if the overlay has position "fixed" 6229 el : $('html'), // element that contains "the lock" 6230 6231 // Public methods 6232 create : function(opts) { 6233 opts = $.extend({}, this.defaults, opts); 6234 6235 if (this.overlay) { 6236 this.close(); 6237 } 6238 6239 this.overlay = $('<div class="fancybox-overlay"></div>').appendTo('body'); 6240 this.fixed = false; 6241 6242 if (opts.fixed && F.defaults.fixed) { 6243 this.overlay.addClass('fancybox-overlay-fixed'); 6244 6245 this.fixed = true; 6246 } 6247 }, 6248 6249 open : function(opts) { 6250 var that = this; 6251 6252 opts = $.extend({}, this.defaults, opts); 6253 6254 if (this.overlay) { 6255 this.overlay.unbind('.overlay').width('auto').height('auto'); 6256 6257 } else { 6258 this.create(opts); 6259 } 6260 6261 if (!this.fixed) { 6262 W.bind('resize.overlay', $.proxy( this.update, this) ); 6263 6264 this.update(); 6265 } 6266 6267 if (opts.closeClick) { 6268 this.overlay.bind('click.overlay', function(e) { 6269 if ($(e.target).hasClass('fancybox-overlay')) { 6270 if (F.isActive) { 6271 F.close(); 6272 } else { 6273 that.close(); 6274 } 6275 6276 return false; 6277 } 6278 }); 6279 } 6280 6281 this.overlay.css( opts.css ).show(); 6282 }, 6283 6284 close : function() { 6285 var scrollV, scrollH; 6286 6287 W.unbind('resize.overlay'); 6288 6289 if (this.el.hasClass('fancybox-lock')) { 6290 $('.fancybox-margin').removeClass('fancybox-margin'); 6291 6292 scrollV = W.scrollTop(); 6293 scrollH = W.scrollLeft(); 6294 6295 this.el.removeClass('fancybox-lock'); 6296 6297 W.scrollTop( scrollV ).scrollLeft( scrollH ); 6298 } 6299 6300 $('.fancybox-overlay').remove().hide(); 6301 6302 $.extend(this, { 6303 overlay : null, 6304 fixed : false 6305 }); 6306 }, 6307 6308 // Private, callbacks 6309 6310 update : function () { 6311 var width = '100%', offsetWidth; 6312 6313 // Reset width/height so it will not mess 6314 this.overlay.width(width).height('100%'); 6315 6316 // jQuery does not return reliable result for IE 6317 if (IE) { 6318 offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); 6319 6320 if (D.width() > offsetWidth) { 6321 width = D.width(); 6322 } 6323 6324 } else if (D.width() > W.width()) { 6325 width = D.width(); 6326 } 6327 6328 this.overlay.width(width).height(D.height()); 6329 }, 6330 6331 // This is where we can manipulate DOM, because later it would cause iframes to reload 6332 onReady : function (opts, obj) { 6333 var overlay = this.overlay; 6334 6335 $('.fancybox-overlay').stop(true, true); 6336 6337 if (!overlay) { 6338 this.create(opts); 6339 } 6340 6341 if (opts.locked && this.fixed && obj.fixed) { 6342 if (!overlay) { 6343 this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false; 6344 } 6345 6346 obj.locked = this.overlay.append( obj.wrap ); 6347 obj.fixed = false; 6348 } 6349 6350 if (opts.showEarly === true) { 6351 this.beforeShow.apply(this, arguments); 6352 } 6353 }, 6354 6355 beforeShow : function(opts, obj) { 6356 var scrollV, scrollH; 6357 6358 if (obj.locked) { 6359 if (this.margin !== false) { 6360 $('*').filter(function(){ 6361 return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") ); 6362 }).addClass('fancybox-margin'); 6363 6364 this.el.addClass('fancybox-margin'); 6365 } 6366 6367 scrollV = W.scrollTop(); 6368 scrollH = W.scrollLeft(); 6369 6370 this.el.addClass('fancybox-lock'); 6371 6372 W.scrollTop( scrollV ).scrollLeft( scrollH ); 6373 } 6374 6375 this.open(opts); 6376 }, 6377 6378 onUpdate : function() { 6379 if (!this.fixed) { 6380 this.update(); 6381 } 6382 }, 6383 6384 afterClose: function (opts) { 6385 // Remove overlay if exists and fancyBox is not opening 6386 // (e.g., it is not being open using afterClose callback) 6387 //if (this.overlay && !F.isActive) { 6388 if (this.overlay && !F.coming) { 6389 this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this )); 6390 } 6391 } 6392 }; 6393 6394 /* 6395 * Title helper 6396 */ 6397 6398 F.helpers.title = { 6399 defaults : { 6400 type : 'float', // 'float', 'inside', 'outside' or 'over', 6401 position : 'bottom' // 'top' or 'bottom' 6402 }, 6403 6404 beforeShow: function (opts) { 6405 var current = F.current, 6406 text = current.title, 6407 type = opts.type, 6408 title, 6409 target; 6410 6411 if ($.isFunction(text)) { 6412 text = text.call(current.element, current); 6413 } 6414 6415 if (!isString(text) || $.trim(text) === '') { 6416 return; 6417 } 6418 6419 title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">
vendor: 3,295 bytes, lines 6419-6547
6419' + text + '</div>'); 6420 6421 switch (type) { 6422 case 'inside': 6423 target = F.skin; 6424 break; 6425 6426 case 'outside': 6427 target = F.wrap; 6428 break; 6429 6430 case 'over': 6431 target = F.inner; 6432 break; 6433 6434 default: // 'float' 6435 target = F.skin; 6436 6437 title.appendTo('body'); 6438 6439 if (IE) { 6440 title.width( title.width() ); 6441 } 6442 6443 title.wrapInner('<span class="child"></span>'); 6444 6445 //Increase bottom margin so this title will also fit into viewport 6446 F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) ); 6447 break; 6448 } 6449 6450 title[ (opts.position === 'top' ? 'prependTo' : 'appendTo') ](target); 6451 } 6452 }; 6453 6454 // jQuery plugin initialization 6455 $.fn.fancybox = function (options) { 6456 var index, 6457 that = $(this), 6458 selector = this.selector || '', 6459 run = function(e) { 6460 var what = $(this).blur(), idx = index, relType, relVal; 6461 6462 if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) { 6463 relType = options.groupAttr || 'data-fancybox-group'; 6464 relVal = what.attr(relType); 6465 6466 if (!relVal) { 6467 relType = 'rel'; 6468 relVal = what.get(0)[ relType ]; 6469 } 6470 6471 if (relVal && relVal !== '' && relVal !== 'nofollow') { 6472 what = selector.length ? $(selector) : that; 6473 what = what.filter('[' + relType + '="' + relVal + '"]'); 6474 idx = what.index(this); 6475 } 6476 6477 options.index = idx; 6478 6479 // Stop an event from bubbling if everything is fine 6480 if (F.open(what, options) !== false) { 6481 e.preventDefault(); 6482 } 6483 } 6484 }; 6485 6486 options = options || {}; 6487 index = options.index || 0; 6488 6489 if (!selector || options.live === false) { 6490 that.unbind('click.fb-start').bind('click.fb-start', run); 6491 6492 } else { 6493 D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run); 6494 } 6495 6496 this.filter('[data-fancybox-start=1]').trigger('click'); 6497 6498 return this; 6499 }; 6500 6501 // Tests that need a body at doc ready 6502 D.ready(function() { 6503 var w1, w2; 6504 6505 if ( $.scrollbarWidth === undefined ) { 6506 // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth 6507 $.scrollbarWidth = function() { 6508 var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'), 6509 child = parent.children(), 6510 width = child.innerWidth() - child.height( 99 ).innerWidth(); 6511 6512 parent.remove(); 6513 6514 return width; 6515 }; 6516 } 6517 6518 if ( $.support.fixedPosition === undefined ) { 6519 $.support.fixedPosition = (function() { 6520 var elem = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'), 6521 fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 ); 6522 6523 elem.remove(); 6524 6525 return fixed; 6526 }()); 6527 } 6528 6529 $.extend(F.defaults, { 6530 scrollbarWidth : $.scrollbarWidth(), 6531 fixed : $.support.fixedPosition, 6532 parent : $('body') 6533 }); 6534 6535 //Get real width of page scroll-bar 6536 w1 = $(window).width(); 6537 6538 H.addClass('fancybox-lock-test'); 6539 6540 w2 = $(window).width(); 6541 6542 H.removeClass('fancybox-lock-test'); 6543 6544 $("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head"); 6545 }); 6546 6547}(window, document, jQuery));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.