1/** 2 * ELIXON THEATRE 3 * Project Homepage: http://www.webdevelopers.eu/jquery/theatre 4 * 5 * LICENSE 6 * http://www.webdevelopers.eu/jquery/theatre/license 7 * Commons Attribution-NonCommercial 3.0 8 * 9 * Get a commercial license at 10 * http://www.webdevelopers.eu/jquery/theatre/buy 11 * 12 * DEMO 13 * http://www.webdevelopers.eu/jquery/theatre/demo 14 * 15 * DOCUMENTATION 16 * http://www.webdevelopers.eu/jquery/theatre/documentation 17 * 18 * CHANGELOG 19 * - fires event $stage.trigger('theatreMove', function(idx, actor, theatre)) upon move to allow custom external onMove handlers 20 * - $stage.theatre('jump', where [, speed]); 21 * - added support for swipeup, swipedown, swipeleft and swiperight events (e.g.https://github.com/stephband/jquery.event.swipe ) 22 * - honors Actor with .theatre-actor-active pre-created class as first actor automatically. 23 * 24 * @project Elixon CMS, http://www.webdevelopers.eu/ 25 * @package JQuery 26 * @subpackage Theatre 27 * @author Daniel Sevcik <[email protected]> 28 * @version 2.6 29 * @copyright 2010 Daniel Sevcik 30 * @since 2010-11-11T22:10:07+0100 31 * @revision $Revision: 5839 $ 32 * @access public 33 */ 34(function($) { 35 var effects={}; 36 var methods={}; 37 var urlBase; 38 39 $.fn.theatre=function() { 40 var currArguments=arguments; 41 this.css({"visibility": "visible", "display": "block"}); /* if the initial settings are to hide loading images... */ 42 (this.length ? this : $(document)).each(function() { 43 methods.initAll.apply($(this), currArguments); 44 }); 45 return this; 46 }; 47 48 // Examples: 49 // $.fn.theatre.cssSupport("transform"); 50 // $.fn.theatre.cssSupport("display", "inline-block"); 51 $.fn.theatre.cssSupport=function(propName, propValue) { 52 var i; 53 var ret=false; 54 55 // test Property Name 56 var elStyle=(document.body || document.documentElement).style; 57 var propNameUC=propName.substr(0, 1).toUpperCase()+propName.substr(1); 58 var test=[propName, 'Moz'+propNameUC, 'Webkit'+propNameUC, 'ms'+propNameUC, 'O'+propNameUC]; 59 60 for (i=0; i < test.length; i++) { 61 if (elStyle[test[i]] !== undefined) { 62 ret=true; 63 break; 64 } 65 } 66 67 // Test Property Value 68 if (propValue && ret) { 69 var $dummy=$("<div class='theatreCSSCompatDummy' style='width:1px; height: 1px; position: absolute; bottom: 0px; opacity: 0;'></div>").appendTo('body'); 70 var cssTest; 71 var ret2=false; 72 elStyle=$dummy.get(0).style; 73 74 for (i=0; i < test.length; i++) { 75 if (elStyle[test[i]] === undefined) { 76 continue; 77 } 78 cssTest={}; 79 cssTest[test[i]]=propValue; 80 $dummy.css(cssTest); 81 if (elStyle[test[i]] == propValue) { 82 ret2=true; 83 break; 84 } 85 } 86 $dummy.remove(); 87 ret=ret && ret2; 88 } 89 90 return ret; 91 }; 92 93 // name:string - 'FILE:EFFECT' or 'EFFECT', one file may register EFFECT or multiple effect prefixed by FILE string 94 methods.loadEffect=function(name) { 95 if (!urlBase) { // Find the locations 96 $('script[src*="jquery.theatre.js"], script[src*="jquery.theatre.min.js"], link[href*="theatre.css"]').first().each(function() { 97 urlBase=(this.href || this.src).replace(/\/[^\/]*(#.*)?$/, ''); 98 }); 99 } 100 var url=urlBase+'/effect.'+name.split(':')[0]+'.js'; 101 $('head').append('<script type="text/javascript" src="'+url+'"></script>'); 102 //$.getScript(url); 103 return effects[name]; 104 }; 105 106 // Clean actors removed on-the-fly 107 methods.buryDead=function(actors) { 108 return actors.filter(function() {return $(this).get(0).parentNode;}); 109 }; 110 111 methods.initAll=function(method) { 112 // Init theatre 113 if (typeof method == 'object' || !method || method == 'init') { 114 return this.is(document) || methods.init.apply(this, arguments); // don't init when this is document @see $.fn.theatre() 115 } 116 117 // Register Effect 118 if (method == 'effect') { 119 // Register new effect 120 if (typeof arguments[2] == 'function') { 121 return effects[arguments[1]]=arguments[2]; 122 } else { 123 $.error("Elixon Theatre cannot register effect object unless it is a Function."); 124 } 125 } else if (this.is(document)) { 126 return false; // do nothing, document context only for 'effect' function 127 } 128 129 var theatre=this.data('theatre'); 130 if (!theatre) return false; // not initialized yet 131 132 var jumpTo=arguments[1]; 133 var noStop=false;
134 switch(method) { 135 case 'iterate': 136 noStop=true; 137 method=theatre.settings.playDir; 138 case 'next': 139 case 'prev': 140 case 'redraw': 141 jumpTo=method; 142 // continue with next 'case' 143 case 'jump': 144 var forceRun=0; 145 switch(jumpTo) { 146 case 'redraw': jumpTo=theatre.index; forceRun=1; break; 147 case 'first': jumpTo=0; break; 148 case 'last': jumpTo=theatre.actors.length - 1; break; 149 case 'next': jumpTo=(theatre.index + theatre.actors.length + 1) % theatre.actors.length; break; 150 case 'prev': jumpTo=(theatre.index + theatre.actors.length - 1) % theatre.actors.length; break; 151 default: 152 jumpTo=(parseInt(arguments[1]) - 1) % theatre.actors.length; 153 jumpTo=(Math.abs(Math.floor(jumpTo / theatre.actors.length) * theatre.actors.length) + jumpTo) % theatre.actors.length; //normalize 154 } 155 if (!forceRun && jumpTo == theatre.index) break; // already there 156 if (typeof arguments[2] != 'undefined') { 157 if (typeof theatre.settings.speedOrig == 'undefined') theatre.settings.speedOrig=theatre.settings.speed; 158 theatre.settings.speed=arguments[2]; 159 } 160 var lastPos=theatre.index; 161 if (!noStop) this.theatre('stop'); // stop previous animation/play if any 162 while(forceRun || theatre.index != jumpTo) { 163 forceRun=0; 164 jumpTo=methods.onMove.apply(this, [jumpTo]); 165 if (jumpTo == -1) break; // cancelled by user callback 166 167 // console.log('Jumping to ' + jumpTo, this, theatre); 168 if (theatre.effect.jump) { 169 theatre.index=jumpTo; 170 theatre.effect.jump.apply(theatre.effect, [lastPos]); 171 } else { 172 // Which direction is closest to cycle ther using next/prev? 173 if (theatre.index < jumpTo) { 174 var dirNext=jumpTo - theatre.index; 175 var dirPrev=(theatre.index + theatre.actors.length) - jumpTo; 176 } else { 177 var dirPrev=theatre.index - jumpTo; 178 var dirNext=(theatre.actors.length + jumpTo) - theatre.index; 179 } 180 var origIndex=theatre.index; 181 theatre.index=(theatre.index + (dirNext < dirPrev ? 1 : -1) + theatre.actors.length) % theatre.actors.length; 182 var direction=dirNext < dirPrev || origIndex + 1 == theatre.index ? 'next' : 'prev'; 183 theatre.effect[direction].apply(theatre.effect, [lastPos]); 184 } 185 if (theatre.index == lastPos) break; // movement failed? cancelled by onMove() ? Avoid infinite loop. 186 lastPos=theatre.index; 187 methods.updatePaging.apply(this); 188 } 189 if (typeof theatre.settings.speedOrig != 'undefined') theatre.settings.speed=theatre.settings.speedOrig; 190 this 191 .attr('actors-count', theatre.actors.length) 192 .attr('position-ord', theatre.index + 1) 193 .attr('position', theatre.index + 1 == theatre.actors.length ? 'last' : (theatre.index || 'first')) 194 ; 195 break; 196 case 'play': 197 case 'destroy': 198 case 'stop': 199 methods[method].apply(this); 200 break; 201 default: // Unsupported 202 $.error('Elixon Theatre method "'+method+'" does not exist on jQuery.theatre!'); 203 } 204 }; 205 206 methods.init=function(options) { 207 methods.destroy.apply(this); // Reset old if any 208 209 // Default settings 210 var settings={ 211 selector: '> *:not(.theatre-control)', 212 effect: 'horizontal', // 'horizontal'|'vertical'|'fade'|'show'|'slide'|'3d'|CUSTOM EFFECT NAME|OBJECT with constructor implementing the init,next,prev methods 213 speed: 1000, // Transition speed 214 still: 3000, // Time between transitions 215 autoplay: true, 216 playDir: 'next', // or 'prev' 217 controls: 'horizontal', // display control buttons 'horizontal' or 'vertical' or 'none' 218 itemWidth: false, // width of the item or 'max' or false. 219 itemHeight: false, // height of the item or 'max' or false. 220 width: false, // set the height of the container. By default honors the already set size using CSS 221 height: false, // set the height of the container. By default honors the already set size using CSS 222 onMove: false, // function(index) {}, execution context is the Stage 223 onAfterMove: function() {}, // function(index) {}, execution context is the Stage 224 random: false // random order? 225 }; 226 if (options) { 227 $.extend(settings, options); 228 } 229 230 // Random 231 if (settings.random) { 232 var children=$('> *', this).get(); 233 while(children.length) { 234 var idx=Math.floor(Math.random() * children.length); 235 var child=children[idx]; 236 children.splice(idx, 1); 237 child.parentNode.appendChild(child); 238 } 239 } 240
241 var actors=$(settings.selector, this); 242 var theatre={ 243 paging: settings.paging && $(settings.paging), 244 actors: actors, 245 effect: false, 246 settings: settings, 247 interval: false, 248 index: 0, 249 methods: methods 250 }; 251 252 // Init effect object 253 var fxAll; 254 switch (typeof settings.effect) { 255 case "string": 256 fxAll=settings.effect.split(/\s+/); 257 break; 258 case "function": 259 fxAll=[settings.effect]; 260 break; 261 } 262 263 // Try fx + fallbacks 264 var effect; 265 for (var i=0; i < fxAll.length && !theatre.effect; i++) { 266 settings.effect=fxAll[i]; 267 if (typeof settings.effect == 'function') { 268 effect=settings.effect; 269 } else if (effects[settings.effect]) { 270 effect=effects[settings.effect]; 271 } else { 272 effect=methods.loadEffect(settings.effect); 273 } 274 275 if (!effect) $.error('Elixon Theatre does not support effect "'+settings.effect+'"!'); 276 theatre.effect=new effects[settings.effect](this, actors, settings, theatre); 277 278 // Capabilities 279 if (typeof theatre.effect.capable == 'function') { 280 var answer=theatre.effect.capable(); 281 if (answer !== true) { 282 if (typeof theatre.effect.destroy == 'function') theatre.effect.destroy(); 283 theatre.effect=null; 284 $(this).addClass('theatre-failover'); 285 if (fxAll.length == 1) { // allow only one automatic fallback otherwise honor only explicitly set fallbacks 286 fxAll.push(answer || settings.effect); 287 } 288 } 289 } 290 } 291 292 // Stage 293 this.addClass('theatre').data('theatre', theatre); 294 this.addClass('theatre-'+settings.effect.replace(/[^a-z0-9]+/ig, '-')); 295 if (settings.width) this.css('width', settings.width); 296 if (settings.height) this.css('height', settings.height); 297 298 // Actors - calculate orig width/height 299 var idx=0; 300 actors.each(function(){ 301 var $this=$(this); 302 var currIdx=idx++; 303 var getSettings=function() { return {width: $this.width(), height: $this.height(), index: currIdx};}; 304 if ($this.is('.theatre-actor-active')) { // preselect first actor 305 theatre.index=currIdx; 306 } 307 if (!$this.data('theatre')) {$this.data('theatre', getSettings());} 308 $this.load(function() {$this.data('theatre', getSettings());}); // slow image load problem 309 }); 310 if (settings.itemWidth || settings.itemHeight) { 311 var thisObj=this; 312 actors.each(function() { 313 var $this=$(this); 314 if (settings.itemWidth) { 315 $this.css('width', settings.itemWidth == 'max' ? (thisObj.width() - $this.outerWidth() + $this.width())+'px' : settings.itemWidth); 316 } 317 if (settings.itemHeight) { 318 $this.css('height', settings.itemHeight == 'max' ? (thisObj.height() - $this.outerHeight() + $this.height())+'px' : settings.itemHeight); 319 } 320 }); 321 } 322 323 this 324 .attr('actors-count', theatre.actors.length) 325 .attr('position-ord', 1) 326 .attr('position', 'first'); 327 actors.addClass('theatre-actor').stop(true, true); 328 actors.first().addClass('theatre-actor-first'); 329 actors.last().addClass('theatre-actor-last'); 330 theatre.effect.init(); 331 332 if (settings.autoplay) { 333 methods.play.apply(this, [true]); 334 } 335 336 // Controls 337 methods.appendControls.apply(this); 338 methods.generatePaging.apply(this); 339 methods.onMove.apply(this, [theatre.index]); 340 methods.onAfterMove.apply(this); 341 342 // Swipe gestures 343 methods.swipeSupport.apply(this); 344 345 // Causes problems with validated forms - interferes with background validation 346 // Focus the actor if it is outside of the Stage 347 // Good for multi-page FORM's TAB movement 348 // var $this=$(this); 349 // var mvForward=function() { 350 // var $actor=$(this) 351 // .closest('.theatre-actor') 352 // .add('.theatre-actor', this) 353 // .add(this) 354 // .filter('.theatre-actor') 355 // .first(); 356 // var actor=$actor.data('theatre'); 357 // if (actor && actor.index != theatre.index) { 358 // // Is visible actor? 359 // var point=$actor.offset(); 360 // point.left+=$actor.width()/2; 361 // point.top+=$actor.height()/2; 362 // var sOffset=$this.offset(); 363 // var inStage; 364 // inStage=sOffset.left < point.left && point.left < sOffset.left + $this.width(); 365 // inStage=inStage && sOffset.top < point.top && point.top < sOffset.top + $this.height(); 366 // if (!inStage) $this.theatre('jump', actor.index + 1); 367 // } 368 // }; 369 // //.click(mvForward); - onclick="...jump('next')" was reversed by this 370 // // setTimeout is needed because on focus on next invisible page on horizontal/vertical 371 // // browser scrolls automatically so at that moment it is always visible 372 // $('a, *:input, .theatre-actor', $this)
373 // .focus(function() {var thisObj=this; setTimeout(function() {mvForward.apply(thisObj);}, 100);}); 374 }; 375 376 methods.onMove=function(nextIdx) { 377 if (isNaN(nextIdx)) return -1; 378 var theatre=this.data('theatre'); 379 if (typeof theatre.settings.onMove != 'function') return nextIdx; 380 381 // Set active actor class 382 theatre.actors.not(theatre.actors[nextIdx]).removeClass('theatre-actor-active'); 383 $(theatre.actors[nextIdx]).addClass('theatre-actor-active'); 384 385 var retVal=theatre.settings.onMove.apply(this, [nextIdx, theatre.actors[nextIdx], theatre]); 386 387 // Ret val is false 388 if (typeof retVal == 'number') { 389 retVal=retVal % theatre.actors.length; 390 } else if (retVal === false) { 391 retVal=-1; 392 } else { 393 retVal=nextIdx; 394 } 395 if (retVal >= 0) this.trigger('theatreMove', [retVal, theatre.actors[retVal], theatre]); 396 397 return retVal; 398 }; 399 400 methods.onAfterMove=function() { 401 var theatre=this.data('theatre'); 402 if (typeof theatre.settings.onAfterMove != 'function') return false; 403 theatre.settings.onAfterMove.apply(this, [theatre.index, theatre.actors[theatre.index], theatre]); 404 return true; 405 }; 406 407 methods.generatePaging=function() { 408 var stage=this; 409 var theatre=this.data('theatre'); 410 if (!theatre.paging) return; 411 412 theatre.paging.each(function() { 413 var $this=$(this); 414 415 var templateHTML=$this.data('theatrePagingTemplate'); 416 if (!templateHTML) { 417 $this.data('theatrePagingTemplate', $this.html()); 418 } else { // regenerating the paging - restore template 419 $this.html(templateHTML); 420 } 421 422 var jumpers=[]; 423 $('> *', $this).each(function() {jumpers.push($('<div></div>').append(this).html());}); 424 var template=jumpers[jumpers.length - 1]; 425 426 // Re-generate 427 for(var i=0; i < theatre.actors.length; i++) { 428 var jumpHTML=jumpers.length < i + 1 ? template : jumpers[i]; 429 (function (pos) { 430 $this.append(jumpHTML.replace('{#}', pos)); // no "\n" it kills design, designer can always use padding or add space inside element 431 $this 432 .children() 433 .last() 434 .off(".theatre") 435 .on("click.theatre", function() {stage.theatre('jump', pos);}) 436 437 // for compatibility reason we need " " between elements and also give designers a way to hide wbr using CSS... 438 // many designs has alerady design for nested <span> so we use <nobr> that should be quite compatible. 439 .after(i < theatre.actors.length - 1 ? "<nobr class=\"theatre-spacer\"> </nobr>" : '') 440 ; 441 })(i+1); 442 } 443 }); 444 methods.updatePaging.apply(this); 445 }; 446 447 methods.updatePaging=function() { 448 var theatre=this.data('theatre'); 449 // console.log('Updating paging to ' + theatre.index, this, theatre.paging); 450 if (!theatre.paging) return; 451 452 theatre.paging.each(function() { 453 var $this=$(this); 454 $('> *:not(.theatre-spacer)', $this).removeClass('active').eq(theatre.index).addClass('active'); 455 }); 456 }; 457 458 methods.swipeSupport=function() { 459 var thisObj=this; 460 this 461 .on("swipeleft swipeup", function() {thisObj.theatre('next');}) 462 .on("swiperight swipedown", function() {thisObj.theatre('prev');}) 463 ; 464 }; 465 466 methods.appendControls=function() { 467 settings=this.data('theatre').settings; 468 // Controls 469 if (settings.controls == 'horizontal' || settings.controls == 'vertical') { 470 var thisObj=this; 471 this.append('<a class="theatre-control theatre-control-'+settings.controls+'-next theatre-next"><span></span></a>'); 472 this.append('<a class="theatre-control theatre-control-'+sett
472ings.controls+'-prev theatre-prev"><span></span></a>'); 473 this.append('<a class="theatre-control theatre-control-'+settings.controls+'-play theatre-play"><span></span></a>'); 474 this.append('<a class="theatre-control theatre-control-'+settings.controls+'-stop theatre-stop"><span></span></a>'); 475 $('.theatre-next', this).click(function() {thisObj.theatre('next');}); 476 $('.theatre-prev', this).click(function() {thisObj.theatre('prev');}); 477 $('.theatre-play', this).click(function() {thisObj.theatre('play');}); 478 $('.theatre-stop', this).click(function() {thisObj.theatre('stop');}); 479 this.mouseenter(function() {$('.theatre-control', thisObj).fadeIn();}); 480 this.mouseleave(function() {$('.theatre-control', thisObj).fadeOut();}); 481 $('.theatre-control', this).fadeOut(0); 482 } 483 484 this.append('<a class="theatre-control theatre-sign" rel="copyright license" style="position: absolute !important; display: none !important;" href="http://www.webdevelopers.eu/jquery/theatre" title="jQuery carousel plugin"><span style="display: none !important;">Elixon Theatre jQuery Plugin</span></a>'); 485 }; 486 487 methods.destroy=function() { 488 var theatre=this.data('theatre'); 489 if (theatre) { 490 clearInterval(theatre.interval); 491 try { // On the fly Actor's removal problem 492 // this.theatre('jump', 0, 0); 493 } catch (x) { 494 } 495 if (typeof theatre.effect.destroy == 'function') theatre.effect.destroy(); 496 this.removeClass('theatre-'+theatre.settings.effect.replace(/[^a-z0-9]+/ig, '-')); 497 theatre.actors.each(function(){ // Restore original sizes 498 var $this=$(this); 499 var theatre=$this.data('theatre'); 500 try { // @patch try-catch by Yotam Hamiel to solve problem with images added/removed on-the-fly to runnin Theatre 501 $this.width(theatre.width); 502 $this.height(theatre.height); 503 } catch (x) {} 504 }); 505 } 506 $('.theatre-control', this).remove(); 507 }; 508 509 methods.play=function(initDelay) { 510 var theatre=this.data('theatre'); 511 var stage=this; 512 //methods.stop.apply(this); 513 //stage.theatre('next'); 514 stage.theatre('stop'); 515 !initDelay && stage.theatre('iterate'); 516 theatre.interval=setInterval(function() { 517 stage.theatre('iterate'); 518 }, theatre.settings.speed + theatre.settings.still); 519 }; 520 521 methods.stop=function() { 522 var theatre=this.data('theatre'); 523 clearInterval(theatre.interval); 524 theatre.interval=false; 525 }; 526 527 effects['fade']= 528 effects['slide']= 529 effects['show']=function(stage, actors, settings, theatre) { 530 var onAfterMove=function() {methods.onAfterMove.apply(stage);}; 531 var x={ 532 fade: {show: 'fadeIn', hide: 'fadeOut', initStyle: {margin: 0, top: 0, left: 0, position: 'absolute', display: 'none'}}, 533 slide: {show: 'slideDown', hide: 'slideUp', initStyle: {}}, 534 show: {show: 'show', hide:'hide', initStyle: {}} 535 }[settings.effect]; 536 537 this.init=function() { 538 actors[x.hide](0).css(x.initStyle).eq(theatre.index)[x.show](0); // actors.fadeOut(0) - does not hide it if stage has height=0 - assigning 'display:none' 539 }; 540 this.next=function() { 541 actors.stop(true, true).css('z-index', 0)[x.hide](settings.speed) 542 .eq(theatre.index).css('z-index', 10)[x.show](settings.speed, onAfterMove); 543 }; 544 this.prev=function() { 545 actors.stop(true, true).css('z-index', 0)[x.hide](settings.speed) 546 .eq(theatre.index).css('z-index', 10)[x.show](settings.speed, onAfterMove); 547 }; 548 this.destroy=function() { 549 actors=methods.buryDead(actors); 550 actors.stop(true, true).css({zIndex: '', top: '', left: '', position: '', margin: ''})[x.show](0); 551 }; 552 }; 553 554 effects['vertical']= 555 effects['horizontal']=function(stage, actors, settings, theatre) { 556 var onAfterMove=function() {methods.onAfterMove.apply(stage);}; 557 var x={ 558 horizontal: {'size': 'outerWidth', 'direction': 'left'}, 559 vertical: {'size': 'outerHeight', 'direction': 'top'} 560 }[settings.effect]; 561 562 this.init=function() { 563 stage.scroll(function() {stage.scrollTop(0).scrollLeft(0);}); // TAB in forms causes automatic scroll 564 actors.fadeOut(0); 565 this.align(0, 0); 566 actors.fadeIn(); 567 }; 568 this.prev=function() { 569 var curr=$(settings.selector, stage).last(); 570 var blk=curr.parentsUntil('.theatre'); 571 (blk.length ? blk : curr).last().prependTo(stage); 572 curr.stop(true, true).css(x.direction, -curr[x.size](true)); 573 this.align(0); 574 }; 575 this.next=function() { 576 var curr=$(settings.selector, stage).first(); 577 var offset=this.align(-curr[x.size](true)); 578 var blk=curr.parentsUntil('.theatre'); 579 blk=(blk.length ? blk : curr).last(); 580 blk.appendTo(stage); 581 }; 582 this.destroy=function() { 583 actors=methods.buryDead(actors); 584 actors.stop(true, true).css(x.direction, '').css({opacity: '', left: '', top: ''}); 585 actors.each(function() {$(this).appendTo(stage);}); // restore order 586 }; 587 this.align=function(offset, speed) { 588 stage.scrollLeft(0).scrollTop(0); // with forms the TAB adds scroll 589 $(settings.selector, stage).each(function(idx) { 590 var $this=$(this); 591 var usrCallBack=theatre.index == $this.data('theatre').index ? onAfterMove : function() {}; 592 var callBack=usrCallBack; 593 if (offset < 0) { 594 callBack=function() {$this.css(x.direction, offset); usrCallBack();}; 595 } 596 var props={}; 597 props[x.direction]=offset; 598 $this.stop(true, true).animate(props, isNaN(speed) ? settings.speed : speed, callBack); 599 offset+=$this[x.size](true); 600 }); 601 return offset; 602 }; 603 }; 604 605 effects['3d']=function(stage, actors, settings, theatre) { 606 // Override custom/default settings 607 var onAfterMove=function() {methods.onAfterMove.apply(stage);}; 608 609 settings.resize=false; 610 611 var pivots=[]; 612 var maxWidth; 613 var maxHeight; 614 var styleBak={}; 615 616 this.init=function() { 617 var thisObj=this; 618 619 styleBak.overflow=stage.css('overflow'); 620 stage.css('overflow', 'visible'); 621 622 maxWidth=stage.width() * 0.5; 623 maxHeight=stage.height() * 0.8; 624 actors.each(function(pos) { 625 var rad=(2 * Math.PI * (-pos) / actors.length) + Math.PI / 2; 626 var x=Math.cos(rad); 627 var y=Math.sin(rad); 628 629 /* Bias */ 630 y=1 - Math.sqrt((1 - y) / 2) * 2; 631 632 var margin=10; 633 var sizeMin=0.2; 634 var size=(y + 1) / 2 * (1 - sizeMin) + sizeMin; 635 var x2=x * (stage.width() - margin) / 2 + stage.width() / 2; 636 var y2=y * (stage.height() - margin) / 2 + stage.height() / 2; 637 638 pivots.push({left: x2, top: y2, x: x, y: y, size: size, rad: rad}); 639 }); 640 this.animate(); 641 }; 642 this.next=function() { 643 this.animate(); 644 }; 645 this.prev=function() { 646 this.animate(); 647 }; 648 this.destroy=function() { 649 actors.stop(true, true).css({'z-index': '', opacity: '', left: '', top: ''}); 650 stage.css('overflow', styleBak.overflow); 651 }; 652 this.animate=function() { 653 var thisObj=this; 654 actors.stop(); 655 actors.each(function(pos) { 656 try { 657 var pivot=pivots[(pos - theatre.index + actors.length) % actors.length]; 658 var dim=thisObj.calcDim($(this), maxWidth, maxHeight, pivot.size); 659 var left=Math.round(pivot.left - pivot.x * dim[0] / 2 - dim[0] / 2); 660 var top=Math.round(pivot.top - pivot.y * dim[1] / 2 - dim[1] / 2); 661 // use transitions where applicable for skew() or scale() http://www.alistapart.com/articles/understanding-css3-transitions/ 662 // https://github.com/brandonaaron/jquery-cssHooks/blob/master/boxreflect.js for JQuery 1.4.3 663 $(this).css({'z-index': Math.round(pivot.size * 1000)}).animate({opacity: pivot.size, left: left, top: top, width: dim[0], height: dim[1]}, settings.speed, pos == theatre.index ? onAfterMove : null); 664 } catch (x) { 665 // Exceptions when adding/removing items on the fly 666 } 667 668 }); 669 }; 670 this.calcDim=function(obj, maxWidth, maxHeight, size) { 671 var dim=obj.data('theatre'); 672 var w=maxWidth; 673 var h=dim.height / dim.width * w; 674 if (h > maxHeight) { 675 w=maxWidth * (maxHeight / h); 676 h=maxHeight; 677 } 678 return [Math.round(w * size), Math.round(h * size)]; 679 }; 680 }; 681 682 // Trial notification 683 var sn="WX-XXXXXX-XXXXXX"; 684 if (sn.match(/^W3/)) { 685 var snMsg='%45%6C%69%78%6F%6E%20%54%68%65%61%74%72%65%20%74%72%69%61%6C%20%76%65%72%73%69%6F%6E%20%68%61%73%20%65%78%70%69%72%65%64%21%20%43%6C%69%63%6B%20%4F%4B%20%74%6F%20%6F%62%74%61%69%6E%20%74%68%65%20%66%75%6C%6C%20%76%65%72%73%69%6F%6E%2E'; 686 var expDate=new Date(sn.replace(/^W(\d)-(\d{2})(\d{2})(\d{2})-(\d{2})(\d{2})(\d{2})$/, "20$2-$3-$4T$5:$6:$7Z")); 687 var expMethod=["co", "nfi", "rm"]; 688 expDate.setTime(expDate.getTime() + 30 * 24 * 3600 * 1000); 689 if (expDate.getTime() && expDate.getTime() < (new Date).getTime()) { 690 if (window[expMethod.join('')](unescape(snMsg))) { 691 window.location="http://www.webdevelopers.eu/jquery/theatre/buy?trial=expired"; 692 } 693 } 694 } 695 696})(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.