[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('transition', function (Y, NAME) { 9 10 /** 11 * Provides the transition method for Node. 12 * Transition has no API of its own, but adds the transition method to Node. 13 * 14 * @module transition 15 * @requires node-style 16 */ 17 18 var CAMEL_VENDOR_PREFIX = '', 19 VENDOR_PREFIX = '', 20 DOCUMENT = Y.config.doc, 21 DOCUMENT_ELEMENT = 'documentElement', 22 DOCUMENT_STYLE = DOCUMENT[DOCUMENT_ELEMENT].style, 23 TRANSITION_CAMEL = 'transition', 24 TRANSITION_PROPERTY_CAMEL = 'transitionProperty', 25 TRANSITION_PROPERTY, 26 TRANSITION_DURATION, 27 TRANSITION_TIMING_FUNCTION, 28 TRANSITION_DELAY, 29 TRANSITION_END, 30 ON_TRANSITION_END, 31 32 EMPTY_OBJ = {}, 33 34 VENDORS = [ 35 'Webkit', 36 'Moz' 37 ], 38 39 VENDOR_TRANSITION_END = { 40 Webkit: 'webkitTransitionEnd' 41 }, 42 43 /** 44 * A class for constructing transition instances. 45 * Adds the "transition" method to Node. 46 * @class Transition 47 * @constructor 48 */ 49 50 Transition = function() { 51 this.init.apply(this, arguments); 52 }; 53 54 // One off handling of transform-prefixing. 55 Transition._TRANSFORM = 'transform'; 56 57 Transition._toCamel = function(property) { 58 property = property.replace(/-([a-z])/gi, function(m0, m1) { 59 return m1.toUpperCase(); 60 }); 61 62 return property; 63 }; 64 65 Transition._toHyphen = function(property) { 66 property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) { 67 var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2; 68 69 if (m3) { 70 str += '-' + m3.toLowerCase(); 71 } 72 73 return str; 74 }); 75 76 return property; 77 }; 78 79 Transition.SHOW_TRANSITION = 'fadeIn'; 80 Transition.HIDE_TRANSITION = 'fadeOut'; 81 82 Transition.useNative = false; 83 84 // Map transition properties to vendor-specific versions. 85 if ('transition' in DOCUMENT_STYLE 86 && 'transitionProperty' in DOCUMENT_STYLE 87 && 'transitionDuration' in DOCUMENT_STYLE 88 && 'transitionTimingFunction' in DOCUMENT_STYLE 89 && 'transitionDelay' in DOCUMENT_STYLE) { 90 Transition.useNative = true; 91 Transition.supported = true; // TODO: remove 92 } else { 93 Y.Array.each(VENDORS, function(val) { // then vendor specific 94 var property = val + 'Transition'; 95 if (property in DOCUMENT[DOCUMENT_ELEMENT].style) { 96 CAMEL_VENDOR_PREFIX = val; 97 VENDOR_PREFIX = Transition._toHyphen(val) + '-'; 98 99 Transition.useNative = true; 100 Transition.supported = true; // TODO: remove 101 Transition._VENDOR_PREFIX = val; 102 } 103 }); 104 } 105 106 // Map transform property to vendor-specific versions. 107 // One-off required for cssText injection. 108 if (typeof DOCUMENT_STYLE.transform === 'undefined') { 109 Y.Array.each(VENDORS, function(val) { // then vendor specific 110 var property = val + 'Transform'; 111 if (typeof DOCUMENT_STYLE[property] !== 'undefined') { 112 Transition._TRANSFORM = property; 113 } 114 }); 115 } 116 117 if (CAMEL_VENDOR_PREFIX) { 118 TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + 'Transition'; 119 TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty'; 120 } 121 122 TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property'; 123 TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration'; 124 TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function'; 125 TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay'; 126 127 TRANSITION_END = 'transitionend'; 128 ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend'; 129 TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END; 130 131 Transition.fx = {}; 132 Transition.toggles = {}; 133 134 Transition._hasEnd = {}; 135 136 Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i; 137 138 Y.Node.DOM_EVENTS[TRANSITION_END] = 1; 139 140 Transition.NAME = 'transition'; 141 142 Transition.DEFAULT_EASING = 'ease'; 143 Transition.DEFAULT_DURATION = 0.5; 144 Transition.DEFAULT_DELAY = 0; 145 146 Transition._nodeAttrs = {}; 147 148 Transition.prototype = { 149 constructor: Transition, 150 init: function(node, config) { 151 var anim = this; 152 anim._node = node; 153 if (!anim._running && config) { 154 anim._config = config; 155 node._transition = anim; // cache for reuse 156 157 anim._duration = ('duration' in config) ? 158 config.duration: anim.constructor.DEFAULT_DURATION; 159 160 anim._delay = ('delay' in config) ? 161 config.delay: anim.constructor.DEFAULT_DELAY; 162 163 anim._easing = config.easing || anim.constructor.DEFAULT_EASING; 164 anim._count = 0; // track number of animated properties 165 anim._running = false; 166 167 } 168 169 return anim; 170 }, 171 172 addProperty: function(prop, config) { 173 var anim = this, 174 node = this._node, 175 uid = Y.stamp(node), 176 nodeInstance = Y.one(node), 177 attrs = Transition._nodeAttrs[uid], 178 computed, 179 compareVal, 180 dur, 181 attr, 182 val; 183 184 if (!attrs) { 185 attrs = Transition._nodeAttrs[uid] = {}; 186 } 187 188 attr = attrs[prop]; 189 190 // might just be a value 191 if (config && config.value !== undefined) { 192 val = config.value; 193 } else if (config !== undefined) { 194 val = config; 195 config = EMPTY_OBJ; 196 } 197 198 if (typeof val === 'function') { 199 val = val.call(nodeInstance, nodeInstance); 200 } 201 202 if (attr && attr.transition) { 203 // take control if another transition owns this property 204 if (attr.transition !== anim) { 205 attr.transition._count--; // remapping attr to this transition 206 } 207 } 208 209 anim._count++; // properties per transition 210 211 // make 0 async and fire events 212 dur = ((typeof config.duration !== 'undefined') ? config.duration : 213 anim._duration) || 0.0001; 214 215 attrs[prop] = { 216 value: val, 217 duration: dur, 218 delay: (typeof config.delay !== 'undefined') ? config.delay : 219 anim._delay, 220 221 easing: config.easing || anim._easing, 222 223 transition: anim 224 }; 225 226 // native end event doesnt fire when setting to same value 227 // supplementing with timer 228 // val may be a string or number (height: 0, etc), but computedStyle is always string 229 computed = Y.DOM.getComputedStyle(node, prop); 230 compareVal = (typeof val === 'string') ? computed : parseFloat(computed); 231 232 if (Transition.useNative && compareVal === val) { 233 setTimeout(function() { 234 anim._onNativeEnd.call(node, { 235 propertyName: prop, 236 elapsedTime: dur 237 }); 238 }, dur * 1000); 239 } 240 }, 241 242 removeProperty: function(prop) { 243 var anim = this, 244 attrs = Transition._nodeAttrs[Y.stamp(anim._node)]; 245 246 if (attrs && attrs[prop]) { 247 delete attrs[prop]; 248 anim._count--; 249 } 250 251 }, 252 253 initAttrs: function(config) { 254 var attr, 255 node = this._node; 256 257 if (config.transform && !config[Transition._TRANSFORM]) { 258 config[Transition._TRANSFORM] = config.transform; 259 delete config.transform; // TODO: copy 260 } 261 262 for (attr in config) { 263 if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) { 264 this.addProperty(attr, config[attr]); 265 266 // when size is auto or % webkit starts from zero instead of computed 267 // (https://bugs.webkit.org/show_bug.cgi?id=16020) 268 // TODO: selective set 269 if (node.style[attr] === '') { 270 Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr)); 271 } 272 } 273 } 274 }, 275 276 /** 277 * Starts or an animation. 278 * @method run 279 * @chainable 280 * @private 281 */ 282 run: function(callback) { 283 var anim = this, 284 node = anim._node, 285 config = anim._config, 286 data = { 287 type: 'transition:start', 288 config: config 289 }; 290 291 292 if (!anim._running) { 293 anim._running = true; 294 295 if (config.on && config.on.start) { 296 config.on.start.call(Y.one(node), data); 297 } 298 299 anim.initAttrs(anim._config); 300 301 anim._callback = callback; 302 anim._start(); 303 } 304 305 306 return anim; 307 }, 308 309 _start: function() { 310 this._runNative(); 311 }, 312 313 _prepDur: function(dur) { 314 dur = parseFloat(dur) * 1000; 315 316 return dur + 'ms'; 317 }, 318 319 _runNative: function() { 320 var anim = this, 321 node = anim._node, 322 uid = Y.stamp(node), 323 style = node.style, 324 computed = node.ownerDocument.defaultView.getComputedStyle(node), 325 attrs = Transition._nodeAttrs[uid], 326 cssText = '', 327 cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)], 328 329 transitionText = TRANSITION_PROPERTY + ': ', 330 duration = TRANSITION_DURATION + ': ', 331 easing = TRANSITION_TIMING_FUNCTION + ': ', 332 delay = TRANSITION_DELAY + ': ', 333 hyphy, 334 attr, 335 name; 336 337 // preserve existing transitions 338 if (cssTransition !== 'all') { 339 transitionText += cssTransition + ','; 340 duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ','; 341 easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ','; 342 delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ','; 343 344 } 345 346 // run transitions mapped to this instance 347 for (name in attrs) { 348 hyphy = Transition._toHyphen(name); 349 attr = attrs[name]; 350 if ((attr = attrs[name]) && attr.transition === anim) { 351 if (name in node.style) { // only native styles allowed 352 duration += anim._prepDur(attr.duration) + ','; 353 delay += anim._prepDur(attr.delay) + ','; 354 easing += (attr.easing) + ','; 355 356 transitionText += hyphy + ','; 357 cssText += hyphy + ': ' + attr.value + '; '; 358 } else { 359 this.removeProperty(name); 360 } 361 } 362 } 363 364 transitionText = transitionText.replace(/,$/, ';'); 365 duration = duration.replace(/,$/, ';'); 366 easing = easing.replace(/,$/, ';'); 367 delay = delay.replace(/,$/, ';'); 368 369 // only one native end event per node 370 if (!Transition._hasEnd[uid]) { 371 node.addEventListener(TRANSITION_END, anim._onNativeEnd, ''); 372 Transition._hasEnd[uid] = true; 373 374 } 375 376 style.cssText += transitionText + duration + easing + delay + cssText; 377 378 }, 379 380 _end: function(elapsed) { 381 var anim = this, 382 node = anim._node, 383 callback = anim._callback, 384 config = anim._config, 385 data = { 386 type: 'transition:end', 387 config: config, 388 elapsedTime: elapsed 389 }, 390 391 nodeInstance = Y.one(node); 392 393 anim._running = false; 394 anim._callback = null; 395 396 if (node) { 397 if (config.on && config.on.end) { 398 setTimeout(function() { // IE: allow previous update to finish 399 config.on.end.call(nodeInstance, data); 400 401 // nested to ensure proper fire order 402 if (callback) { 403 callback.call(nodeInstance, data); 404 } 405 406 }, 1); 407 } else if (callback) { 408 setTimeout(function() { // IE: allow previous update to finish 409 callback.call(nodeInstance, data); 410 }, 1); 411 } 412 } 413 414 }, 415 416 _endNative: function(name) { 417 var node = this._node, 418 value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)]; 419 420 name = Transition._toHyphen(name); 421 if (typeof value === 'string') { 422 value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ','); 423 value = value.replace(/^,|,$/, ''); 424 node.style[TRANSITION_CAMEL] = value; 425 } 426 }, 427 428 _onNativeEnd: function(e) { 429 var node = this, 430 uid = Y.stamp(node), 431 event = e,//e._event, 432 name = Transition._toCamel(event.propertyName), 433 elapsed = event.elapsedTime, 434 attrs = Transition._nodeAttrs[uid], 435 attr = attrs[name], 436 anim = (attr) ? attr.transition : null, 437 data, 438 config; 439 440 if (anim) { 441 anim.removeProperty(name); 442 anim._endNative(name); 443 config = anim._config[name]; 444 445 data = { 446 type: 'propertyEnd', 447 propertyName: name, 448 elapsedTime: elapsed, 449 config: config 450 }; 451 452 if (config && config.on && config.on.end) { 453 config.on.end.call(Y.one(node), data); 454 } 455 456 if (anim._count <= 0) { // after propertyEnd fires 457 anim._end(elapsed); 458 node.style[TRANSITION_PROPERTY_CAMEL] = ''; // clean up style 459 } 460 } 461 }, 462 463 destroy: function() { 464 var anim = this, 465 node = anim._node; 466 467 if (node) { 468 node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false); 469 anim._node = null; 470 } 471 } 472 }; 473 474 Y.Transition = Transition; 475 Y.TransitionNative = Transition; // TODO: remove 476 477 /** 478 * Animate one or more css properties to a given value. Requires the "transition" module. 479 * <pre>example usage: 480 * Y.one('#demo').transition({ 481 * duration: 1, // in seconds, default is 0.5 482 * easing: 'ease-out', // default is 'ease' 483 * delay: '1', // delay start for 1 second, default is 0 484 * 485 * height: '10px', 486 * width: '10px', 487 * 488 * opacity: { // per property 489 * value: 0, 490 * duration: 2, 491 * delay: 2, 492 * easing: 'ease-in' 493 * } 494 * }); 495 * </pre> 496 * @for Node 497 * @method transition 498 * @param {Object} config An object containing one or more style properties, a duration and an easing. 499 * @param {Function} callback A function to run after the transition has completed. 500 * @chainable 501 */ 502 Y.Node.prototype.transition = function(name, config, callback) { 503 var 504 transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)], 505 anim = (transitionAttrs) ? transitionAttrs.transition || null : null, 506 fxConfig, 507 prop; 508 509 if (typeof name === 'string') { // named effect, pull config from registry 510 if (typeof config === 'function') { 511 callback = config; 512 config = null; 513 } 514 515 fxConfig = Transition.fx[name]; 516 517 if (config && typeof config === 'object') { 518 config = Y.clone(config); 519 520 for (prop in fxConfig) { 521 if (fxConfig.hasOwnProperty(prop)) { 522 if (! (prop in config)) { 523 config[prop] = fxConfig[prop]; 524 } 525 } 526 } 527 } else { 528 config = fxConfig; 529 } 530 531 } else { // name is a config, config is a callback or undefined 532 callback = config; 533 config = name; 534 } 535 536 if (anim && !anim._running) { 537 anim.init(this, config); 538 } else { 539 anim = new Transition(this._node, config); 540 } 541 542 anim.run(callback); 543 return this; 544 }; 545 546 Y.Node.prototype.show = function(name, config, callback) { 547 this._show(); // show prior to transition 548 if (name && Y.Transition) { 549 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default 550 if (typeof config === 'function') { 551 callback = config; 552 config = name; 553 } 554 name = Transition.SHOW_TRANSITION; 555 } 556 this.transition(name, config, callback); 557 } 558 else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); } 559 return this; 560 }; 561 562 Y.NodeList.prototype.show = function(name, config, callback) { 563 var nodes = this._nodes, 564 i = 0, 565 node; 566 567 while ((node = nodes[i++])) { 568 Y.one(node).show(name, config, callback); 569 } 570 571 return this; 572 }; 573 574 575 576 var _wrapCallBack = function(anim, fn, callback) { 577 return function() { 578 if (fn) { 579 fn.call(anim); 580 } 581 if (callback && typeof callback === 'function') { 582 callback.apply(anim._node, arguments); 583 } 584 }; 585 }; 586 587 Y.Node.prototype.hide = function(name, config, callback) { 588 if (name && Y.Transition) { 589 if (typeof config === 'function') { 590 callback = config; 591 config = null; 592 } 593 594 callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback 595 if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default 596 if (typeof config === 'function') { 597 callback = config; 598 config = name; 599 } 600 name = Transition.HIDE_TRANSITION; 601 } 602 this.transition(name, config, callback); 603 } else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node'); 604 } else { 605 this._hide(); 606 } 607 return this; 608 }; 609 610 Y.NodeList.prototype.hide = function(name, config, callback) { 611 var nodes = this._nodes, 612 i = 0, 613 node; 614 615 while ((node = nodes[i++])) { 616 Y.one(node).hide(name, config, callback); 617 } 618 619 return this; 620 }; 621 622 /** 623 * Animate one or more css properties to a given value. Requires the "transition" module. 624 * <pre>example usage: 625 * Y.all('.demo').transition({ 626 * duration: 1, // in seconds, default is 0.5 627 * easing: 'ease-out', // default is 'ease' 628 * delay: '1', // delay start for 1 second, default is 0 629 * 630 * height: '10px', 631 * width: '10px', 632 * 633 * opacity: { // per property 634 * value: 0, 635 * duration: 2, 636 * delay: 2, 637 * easing: 'ease-in' 638 * } 639 * }); 640 * </pre> 641 * @for NodeList 642 * @method transition 643 * @param {Object} config An object containing one or more style properties, a duration and an easing. 644 * @param {Function} callback A function to run after the transition has completed. The callback fires 645 * once per item in the NodeList. 646 * @param {Boolean} callbackOnce If true, the callback will be called only after the 647 * last transition has completed 648 * @chainable 649 */ 650 Y.NodeList.prototype.transition = function(config, callback, callbackOnce) { 651 var nodes = this._nodes, 652 size = this.size(), 653 i = 0, 654 callbackOnce = callbackOnce === true, 655 node; 656 657 while ((node = nodes[i++])) { 658 if (i < size && callbackOnce){ 659 Y.one(node).transition(config); 660 } else { 661 Y.one(node).transition(config, callback); 662 } 663 } 664 665 return this; 666 }; 667 668 Y.Node.prototype.toggleView = function(name, on, callback) { 669 this._toggles = this._toggles || []; 670 callback = arguments[arguments.length - 1]; 671 672 if (typeof name !== 'string') { // no transition, just toggle 673 on = name; 674 this._toggleView(on, callback); // call original _toggleView in Y.Node 675 return; 676 } 677 678 if (typeof on === 'function') { // Ignore "on" if used for callback argument. 679 on = undefined; 680 } 681 682 if (typeof on === 'undefined' && name in this._toggles) { // reverse current toggle 683 on = ! this._toggles[name]; 684 } 685 686 on = (on) ? 1 : 0; 687 if (on) { 688 this._show(); 689 } else { 690 callback = _wrapCallBack(this, this._hide, callback); 691 } 692 693 this._toggles[name] = on; 694 this.transition(Y.Transition.toggles[name][on], callback); 695 696 return this; 697 }; 698 699 Y.NodeList.prototype.toggleView = function(name, on, callback) { 700 var nodes = this._nodes, 701 i = 0, 702 node; 703 704 while ((node = nodes[i++])) { 705 node = Y.one(node); 706 node.toggleView.apply(node, arguments); 707 } 708 709 return this; 710 }; 711 712 Y.mix(Transition.fx, { 713 fadeOut: { 714 opacity: 0, 715 duration: 0.5, 716 easing: 'ease-out' 717 }, 718 719 fadeIn: { 720 opacity: 1, 721 duration: 0.5, 722 easing: 'ease-in' 723 }, 724 725 sizeOut: { 726 height: 0, 727 width: 0, 728 duration: 0.75, 729 easing: 'ease-out' 730 }, 731 732 sizeIn: { 733 height: function(node) { 734 return node.get('scrollHeight') + 'px'; 735 }, 736 width: function(node) { 737 return node.get('scrollWidth') + 'px'; 738 }, 739 duration: 0.5, 740 easing: 'ease-in', 741 742 on: { 743 start: function() { 744 var overflow = this.getStyle('overflow'); 745 if (overflow !== 'hidden') { // enable scrollHeight/Width 746 this.setStyle('overflow', 'hidden'); 747 this._transitionOverflow = overflow; 748 } 749 }, 750 751 end: function() { 752 if (this._transitionOverflow) { // revert overridden value 753 this.setStyle('overflow', this._transitionOverflow); 754 delete this._transitionOverflow; 755 } 756 } 757 } 758 } 759 }); 760 761 Y.mix(Transition.toggles, { 762 size: ['sizeOut', 'sizeIn'], 763 fade: ['fadeOut', 'fadeIn'] 764 }); 765 766 767 }, '3.17.2', {"requires": ["node-style"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |