1/* Another polyfill for CSS3 Transitions. 2 * This one parses a stylesheet looking for transitions happening on :hover and :focus and convert them to jQuery code. 3 * 4 * Limitations: 5 * - Use simple and coherent selectors (`#menu li` to declare the transition and `#menu li:hover` for the target style) 6 * - Detail the transition properties (`transition-property: padding-left, ...` instead of `transition: all`) 7 * 8 * Complete documentation and latest version available at https://github.com/louisremi/jquery.transition.js 9 * 10 * License: MIT or GPL 11 * 12 * Author: @louis_remi 13 */ 14(function($, window, document, undefined) { 15 16var div = document.createElement("div"), 17 divStyle = div.style, 18 propertyName = "transition", 19 // with leading upper-case 20 suffix = "Transition", 21 testProperties = [ 22 "O" + suffix, 23 // "ms", not "Ms" 24 "ms" + suffix, 25 "Webkit" + suffix, 26 "Moz" + suffix, 27 // prefix-less property 28 propertyName 29 ], 30 i = testProperties.length, 31 supportTransition, 32 self = this; 33 34// test different vendor prefixes of this property 35while ( i-- ) { 36 if ( testProperties[i] in divStyle ) { 37 supportTransition = testProperties[i]; 38 continue; 39 } 40} 41 42if ( !supportTransition ) { 43 $(function() { 44 var docSS = document.styleSheets, 45 i = docSS.length, 46 rules, j, curRule, curSelectorText, 47 duration, 48 transition, selectors, k, curSelector, 49 transitionSelector = {}, pseudoSelector = {}, 50 split, pseudo, 51 selector; 52 53 // Loop through all stylesheets 54 while ( i-- ) { 55 // if the stylesheet gives us security issues and is readOnly, exit here 56 //if ( docSS[i].readOnly ) { continue }; 57 rules = docSS[i].rules || docSS[i].cssRules; 58 j = rules.length; 59 60 // Loop through all rules 61 while ( j-- ) { 62 curRule = rules[j]; 63 curSelectorText = curRule.selectorText; 64 // Search for a transition property list 65 transition = curRule.style["transition-property"]; 66 // Turn a list of transition properties into a hash of properties 67 transition = transition ? 68 transition.replace(/(^|,)\s*([\w-]*)[^,]*/g, "$1$2").split(","): 69 0; 70 selectors = curSelectorText.split(","); 71 k = selectors.length; 72 73 if ( transition ) { 74 duration = curRule.style["transition-duration"]; 75 if ( duration ) { 76 duration = parseFloat( duration ) * ( ~duration.indexOf("ms") ? 1 : 1000 ); 77 } 78 } 79 80 // Loop through all the selectors of the current rule 81 while ( k-- ) { 82 curSelector = $.trim( selectors[k] ); 83 // If there is a transition in the current rule, add its selector to the transitionSelector list 84 if ( transition ) { 85 transitionSelector[curSelector] = { 86 properties: transition, 87 duration: duration 88 }; 89 } 90 // If there is a :hover, :focus or :target pseudo-class in the selector, add it to the listeners list 91 split = curSelector.split( pseudo = 92 ~curSelector.indexOf(":hover")? ":hover": 93 ~curSelector.indexOf(":focus")? ":focus": 94 ~curSelector.indexOf(":target")? ":target": "," 95 ); 96 if ( split.length > 1 ) { 97 // store selectors at the same place when they exist for both :hover and :focus 98 (pseudo == ":hover" || pseudo == ":focus") && pseudoSelector[split.join("")] ? 99 pseudoSelector[split.join("")].pseudo += " " + pseudo: 100 pseudoSelector[split.join("")] = { 101 pseudo: pseudo, 102 style: curRule.style, 103 selector: split[0], 104 animated: split[1], 105 id: [i, j] 106 } 107 } 108 } 109 } 110 } 111 112 // Match selectors of rules containing transitions, 113 // and selectors with :hover, :focus or :target pseudo-class. 114 // Only looking for exact match! 115 var listener, delegate, animated, style, 116 properties, temp, id, 117 props, 118 hfEvents; 119 for ( selector in pseudoSelector ) { 120 if ( ( transition = transitionSelector[selector] ) ) { 121 temp = pseudoSelector[selector]; 122 pseudo = temp.pseudo; 123 animated = temp.animated; 124 split = temp.selector; 125 id = temp.id; 126 127 properties = transition.properties; 128 duration = transition.duration; 129 props = {}; 130 i = properties.length; 131 while ( i-- ) { 132 props[properties[i]] = 133 // use camelCase property name 134 temp.style[properties[i].replace(/-([a-z])/g, function( all, letter ) { 135 return letter.toUpperCase(); 136 })]; 137 } 138 139 // remove the rule from the CSS to fix a race condition in IE9 140 docSS[id[0]].removeRule(id[1]); 141 142 hfEvents = [[], []]; 143 if ( ~pseudo.indexOf(":hover") && ( hfEvents[0].push("mouseenter"), hfEvents[1].push("mouseleave") ) 144 || ~pseudo.indexOf(":focus") && ( hfEvents[0].push("focus"), hfEvents[1].push("blur") ) 145 ) { 146 // If the selector _starts_ with an #id, we can bind the listener to it 147 listener = /^#[\w\-]* /.test(split) && ( split = split.split(" ") ) ? 148 split[0]: 149 // use the body otherwise 150 document.body; 151 delegate = typeof split != "string" ? split[1] : split; 152 153 // mouseenter and focus listeners 154 $(listener).delegate( delegate, hfEvents[0].join(" "), {a: animated, p: props, d: duration}, function( e ) { 155 var $animated = e.data.a ? $(this).find(e.data.a) : $(this), 156 prop, save = {}; 157 // exit immediatly if nothing is to be animated 158 if ( !$animated.length ) { 159 return; 160 } 161 // Save the initial style of the elements to be animated 162 if ( !$.data( this, "initStyle" ) ) { 163 for ( prop in e.data.p ) { 164 save[prop] = $.css( $animated[0], prop ); 165 } 166 $.data( this, "initStyle", save ); 167 } 168 $animated.stop(true).animate( props, e.data.d ); 169 170 // mouseleave and blur listeners 171 }).delegate( delegate, hfEvents[1].join(" "), {a: animated, d: duration}, function( e ) { 172 var self = this, 173 init = $.data( this, "initStyle" ), 174 $animated = e.data.a ? $(this).find(e.data.a) : $(this); 175 // exit immediatly if nothing is to be animated 176 if ( !$animated.length ) { 177 return; 178 } 179 if ( init ) { 180 $animated 181 .stop(true).animate( init, e.data.d ) 182 // Clear the saved style at the end of the animation 183 .queue(function() { 184 $.data( self, "initStyle", null ); 185 }); 186 } 187 }); 188 } 189 } 190 } 191 }); 192} 193 194})(jQuery, window, document);
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.