1/** 2 * UpSolution Element: Interactive Text 3 */ 4!function( $ ) { 5 "use strict"; 6 /** 7 * @class WItext 8 * @param {string|node} container 9 */ 10 $us.WItext = function( container ) { 11 // Variables 12 var defaultOptions = { 13 html_nbsp_char: true 14 }; 15 16 // Elements 17 this.$container = $( container ); 18 var $parts = this.$container.find( '.w-itext-part' ); 19 20 if ( $parts.length === 0 ) { 21 return; // No animated parts 22 } 23 24 // Get options 25 var options = $.extend( defaultOptions, this.$container[ 0 ].onclick() || {} ); 26 // Delete data everywhere except for the preview of the usbuilder, 27 // the data may be needed again to restore the elements. 28 if ( ! $us.usbPreview() ) this.$container.removeAttr( 'onclick' ); 29 30 // Set options 31 var type = this.$container.usMod( 'type' ); 32 this.animateChars = ( type.substring( type.length - 'chars'.length ).toLowerCase() === 'chars' ); 33 this.duration = parseInt( options.duration ) || 1000; 34 this.delay = parseInt( options.delay ) || 5000; 35 this.dynamicColor = ( options.dynamicColor || '' ); 36 this.disablePartAnimation = options.disablePartAnimation || false; 37 this.animateDurations = []; // Time of all animations 38 this.type = this.animateChars ? type.substring( 0, type.length - 'chars'.length ) : type; 39 this.nbsp_char = options.html_nbsp_char ? ' ' : ' '; 40 41 // Creating objects for all parts 42 this.parts = []; 43 $parts 44 .css( { transitionDuration: this.duration + 'ms' } ) 45 .each( function( index, part ) { 46 var part = { 47 $node: $( part ), 48 currentState: 0, 49 states: part.onclick() || [] 50 }; 51 // Delete data everywhere except for the preview of the usbilder, 52 // the data may be needed again to restore the elements 53 if ( ! $us.usbPreview() ) part.$node.removeAttr( 'onclick' ); 54 if ( this.dynamicColor ) { 55 part.$node.css( 'color', this.dynamicColor ); 56 } 57 this.parts[ index ] = part; 58 }.bind( this ) ); 59 60 // Start first animation 61 var timer = $ush.timeout( function() { 62 this.parts.map( function( part ) { 63 this._events.startAnimate.call( this, part ); 64 }.bind( this ) ); 65 $ush.clearTimeout( timer ); 66 }.bind( this ), this.delay ); 67 }; 68 // Export api 69 $us.WItext.prototype = { 70 _events: { 71 /** 72 * Starts the next animation step. 73 * 74 * @param {object} part 75 */ 76 startAnimate: function( part ) { 77 part.currentState = ( part.currentState === part.states.length - 1 ) ? 0 : ( part.currentState + 1 ); 78 this.render.call( this, part ); 79 }, 80 /** 81 * Animation restart. 82 * 83 * @param {object} part 84 */ 85 restartAnimate: function( part ) { 86 $ush.timeout( this._events.startAnimate.bind( this, part ), this.delay ); 87 }, 88 /** 89 * Clear unwanted items or data after animation. 90 * 91 * @param {object} part 92 */ 93 clearAnimation: function( part ) { 94 var text = $ush.toString( part.states[ part.currentState ] ).replace( ' ', this.nbsp_char ); 95 part.$node 96 .html( text ) 97 .css( 'width', '' ); 98 if ( this.type === 'typing' && text.trim() && text !== this.nbsp_char ) { 99 part.$node.append( '<i class="w-itext-cursor"></i>' ); 100 } 101 if ( part.curDuration === Math.max.apply( null, this.animateDurations ) ) { 102 this.animateDurations = []; 103 this.parts.map( function( _part ) { 104 this._events.restartAnimate.call( this, _part ); 105 }.bind( this ) ); 106 } 107 } 108 }, 109 /** 110 * Rendering animation elements. 111 * 112 * @param {object} part 113 */ 114 render: function( part ) { 115 var nextValue = part.states[ part.currentState ], 116 $curSpan = part.$node.wrapInner( '<span></span>' ).children( 'span' ), 117 $nextSpan = $( '<span class="measure"></span>' ).html( nextValue.replace( ' ', this.nbsp_char ) ).appendTo( part.$node ), 118 nextWidth = $nextSpan.width(), 119 outType = 'fadeOut', 120 startDelay = 0; 121 part.curDuration = this.duration; 122 // Remove typing chars 123 if ( this.type === 'typing' ) { 124 var oldValue = $curSpan.text().trim() + ' ', 125 removeDuration = Math.floor( part.curDuration / 3 ); 126 startDelay = Math.max.apply( null, [ startDelay, ( removeDuration * oldValue.length ) ] ); 127 for ( var i = 0; i < oldValue.length; i ++ ) {
128 $curSpan.text( oldValue ); 129 $ush.timeout( function() { 130 var text = $curSpan.text(); 131 $curSpan.text( text.substring( 0, text.length - 1 ) ); 132 }.bind( this ), removeDuration * i ); 133 } 134 } 135 // Start animation 136 $ush.timeout( function() { 137 part.$node.addClass( 'notransition' ); 138 if ( ! this.disablePartAnimation ) { 139 part.$node.css( 'width', part.$node.width() ); 140 } 141 $ush.timeout( function() { 142 part.$node.removeClass( 'notransition' ); 143 if ( ! this.disablePartAnimation ) { 144 part.$node.css( 'width', nextWidth ); 145 } 146 }.bind( this ), 25 ); 147 if ( this.type !== 'typing' ) { 148 $curSpan 149 .css({ 150 position: 'absolute', 151 top: 0, 152 left: 0, 153 width: ! this.disablePartAnimation ? nextWidth : '', 154 transitionDuration: ( this.duration / 5 ) + 'ms' 155 }) 156 .addClass( 'animated_' + outType ); 157 } 158 if ( ! this.disablePartAnimation ) { 159 $nextSpan.css( 'width', nextWidth ); 160 } 161 $nextSpan.removeClass( 'measure' ).prependTo( part.$node ); 162 if ( this.animateChars ) { 163 $nextSpan.empty(); 164 if ( this.type === 'typing' ) { 165 $nextSpan.append( '<span class="w-itext-part-nospan"></span>' ); 166 } 167 for ( var i = 0; i < nextValue.length; i ++ ) { 168 var $char = ( ( nextValue[ i ] !== ' ' ) ? nextValue[ i ] : this.nbsp_char ); 169 if ( this.type !== 'typing' ) { 170 $char = $( '<span>' + $char + '</span>' ); 171 $char 172 .css( 'transition-duration', part.curDuration + 'ms' ) 173 .appendTo( $nextSpan ); 174 $char.appendTo( $nextSpan ); 175 } 176 $ush.timeout( function( $char ) { 177 if ( this.type !== 'typing' ) { 178 $char.addClass( 'animated_' + this.type ); 179 } else { 180 var $text = $( '> span:first', $nextSpan ); 181 $text.html( $text.html() + $char ); 182 } 183 }.bind( this, $char ), part.curDuration * i ); 184 } 185 186 if ( this.type === 'typing' && $ush.toString( nextValue ).trim() && nextValue !== this.nbsp_char ) { 187 $nextSpan.append( '<i class="w-itext-cursor"></i>' ); 188 } 189 part.curDuration *= ( nextValue.length + 1 ); 190 } else { 191 $nextSpan.wrapInner( '<span></span>' ).children( 'span' ).css( { 192 'animation-duration': this.duration + 'ms' 193 } ).addClass( 'animated_' + this.type ); 194 } 195 this.animateDurations.push( part.curDuration ); 196 197 // Clear and next animation state 198 $ush.timeout( this._events.clearAnimation.bind( this, part ), part.curDuration + Math.floor( this.delay / 3 ) ); 199 }.bind( this ), startDelay ); 200 } 201 }; 202 203 $.fn.wItext = function( options ) { 204 return this.each( function() { 205 $( this ).data( 'wItext', new $us.WItext( this, options ) ); 206 } ); 207 }; 208 209 $( function() { 210 $( '.w-itext' ).wItext(); 211 } ); 212 213}( 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.