1 goog.provide('lime.style'); 2 goog.provide('lime.style.Transform'); 3 4 goog.require('goog.dom'); 5 goog.require('goog.style'); 6 goog.require('lime.userAgent'); 7 8 (function() { 9 10 var prefix = goog.userAgent.WEBKIT ? 'Webkit' : 11 goog.userAgent.GECKO ? 'Moz' : 12 goog.userAgent.OPERA ? 'O' : 13 goog.userAgent.IE ? 'ms' : ''; 14 15 var testDivStyle = goog.dom.createDom('div').style; 16 17 lime.style.transformProperty = '-' + prefix.toLowerCase() + '-transform'; 18 19 /** 20 * Try if a CSS style property with given name exists 21 * @param {string} name Property name. 22 * @return {boolean|string} If property exists. 23 */ 24 lime.style.tryProperty = function(name) { 25 return testDivStyle[name] !== undefined ? name : false; 26 }; 27 28 /** 29 * Get the name of actual CSS property from general(unprefixed) name 30 * @param {string} name Unprefixed name. 31 * @return {string} Actual valid property name. 32 */ 33 lime.style.getCSSproperty = function(name) { 34 var name_lower = name.charAt(0).toLowerCase() + name.substr(1), 35 prefix_name = prefix + name; 36 return lime.style.tryProperty(name) ? 37 name : (lime.style.tryProperty(name_lower) ? 38 name_lower : lime.style.tryProperty(prefix_name) ? 39 prefix_name : undefined ); 40 }; 41 42 /** 43 * Set border radisu of a DOM element 44 * @param {Element} el Element to change. 45 * @param {Array.<number>} values Radius values. 46 * @param {Array.<number>=} opt_vertical Vertical radius values. 47 * @param {boolean=} opt_isPerc If values are given in percentages. 48 */ 49 lime.style.setBorderRadius = (function() { 50 var stylename = lime.style.getCSSproperty('BorderRadius'); 51 var out = function(values, unit) { 52 return (goog.isArray(values) ? values.join(unit + ' ') : values) + unit; 53 }; 54 return function(el, values, opt_vertical, opt_isPerc) { 55 var unit = opt_isPerc ? '%' : 'px'; 56 var vertical = goog.isDef(opt_vertical) ? opt_vertical : values; 57 var value = out(values, unit) + '/' + out(vertical, unit); 58 if (value != el.border_radius_cache_) { 59 el.style[stylename] = el.border_radius_cache_ = value; 60 } 61 }; 62 })(); 63 64 // There are classes like CSSMatrix in some browsers. 65 // Maybe this would make more sense. 66 67 (function(){ 68 69 /** 70 * Object representing CSS Transform. 71 * @constructor 72 * @param {number=} opt_precision Default precision. 73 */ 74 lime.style.Transform = function(opt_precision) { 75 this.values = []; 76 this.precision = 1; 77 if (this.opt_precision) { 78 this.setPrecision(/** @type {number} */ (opt_precision)); 79 } 80 }; 81 82 /** 83 * Scale current transform object 84 * @param {number} sx X-axis scale factor. 85 * @param {number} sy y-axis scale factor. 86 * @return {lime.style.Transform} obejct itself. 87 */ 88 lime.style.Transform.prototype.scale = function(sx, sy) { 89 //if(sx!=1 && sy!=1) 90 this.values.push('scale(' + sx + ',' + sy + ')'); 91 return this; 92 }; 93 94 /** 95 * Rotate current transform object 96 * @param {number} angle Angle to rotate. 97 * @param {string=} opt_unit Units. 98 * @return {lime.style.Transform} obejct itself. 99 */ 100 lime.style.Transform.prototype.rotate = function(angle, opt_unit) { 101 var rot_str = 'rotate(' + angle + (opt_unit ? opt_unit : 'deg') + ')'; 102 if (angle != 0) 103 this.values.push(rot_str); 104 105 return this; 106 }; 107 108 /** 109 * Translate(move) current transform object 110 * @param {number} tx Offset in x-axis. 111 * @param {number} ty Offset in y-axis. 112 * @param {number=} opt_tz Offset in z-axis. 113 * @return {lime.style.Transform} obejct itself. 114 */ 115 lime.style.Transform.prototype.translate = function(tx, ty, opt_tz) { 116 117 var p = 1 / this.precision; 118 var val = 'translate'; 119 if (lime.userAgent.IOS) val += '3d'; 120 val += '(' + (tx * p) + 'px,' + (ty * p) + 'px'; 121 if (lime.userAgent.IOS) val += ',' + ((opt_tz ? opt_tz : 0) * p) + 'px'; 122 this.values.push(val + ')'); 123 124 return this; 125 }; 126 127 /** 128 * Set the current precision of transform. This is handled as a 129 * state machine so its added when called not when done. 130 * @param {number} p Precision(Lowest value to make a difference). 131 * @return {lime.style.Transform} obejct itself. 132 */ 133 lime.style.Transform.prototype.setPrecision = function(p) { 134 if (this.precision != 1) { 135 var opposite = 1 / this.precision; 136 this.scale(opposite, opposite); 137 this.precision = 1; 138 } 139 if (p != 1) { 140 this.scale(p, p); 141 this.precision = p; 142 } 143 return this; 144 }; 145 146 /** 147 * Return CSS transform string from the obejct 148 * @return {string} CSS value string. 149 */ 150 lime.style.Transform.prototype.toString = function() { 151 if (this.precision != 1) { 152 this.setPrecision(1); 153 } 154 return this.values.join(' '); 155 }; 156 157 /** 158 * Set transform to a DOM element. 159 * @param {Element} el Element to change. 160 * @param {lime.style.Transform} transform Transform. 161 */ 162 lime.style.setTransform = (function() { 163 var stylename = lime.style.getCSSproperty('Transform'); 164 return function(el, transform) { 165 var value = transform.toString(); 166 167 if (value != el.transform_cache_) { 168 el.style[stylename] = el.transform_cache_ = value; 169 } 170 lime.transformSet_=1; 171 172 }; 173 })(); 174 175 })(); 176 177 /** 178 * Set transform origin point for a DOM element. 179 * @param {Element} el Element to change. 180 * @param {number} ox X Offset. 181 * @param {number} oy Y Offset. 182 * @param {boolean=} opt_isPerc If unit is percentage. 183 */ 184 lime.style.setTransformOrigin = (function() { 185 var stylename = lime.style.getCSSproperty('TransformOrigin'); 186 return function(el, ox, oy, opt_isPerc) { 187 var unit = opt_isPerc ? '%' : 'px'; 188 var value = ox + unit + ' ' + oy + unit; 189 if (value != el.transform_origin_cache_) { 190 el.style[stylename] = el.transform_origin_cache_ = value; 191 } 192 }; 193 })(); 194 195 196 var stylename = lime.style.getCSSproperty('Transition'); 197 lime.style.isTransitionsSupported = !!stylename && !goog.userAgent.OPERA; 198 // Opera's CSS3 transitions seem to be unstable atm. No shorthand plus 199 // doesn't work if the duration property has not been previously set inside 200 // CSS style sheet @tonis 201 202 var clearProp = function(str, prop) { 203 if (!str.length) return str; 204 var proplist = str.split('),'); 205 for (var i = 0; i < proplist.length - 1; i++) { 206 proplist[i] += ')'; 207 } 208 209 proplist = goog.array.filter(proplist, function(part) { 210 return part.indexOf(prop) == -1; 211 }); 212 return proplist.join(','); 213 }; 214 215 /** 216 * Activate transition rule for a property 217 * @param {Element} el Element to change. 218 * @param {string} property Transition property name. 219 * @param {number} time Transition duration. 220 * @param {lime.animation.EasingFunction} ease Easing function. 221 */ 222 lime.style.setTransition = function(el, property, time, ease) { 223 if (!stylename) return; 224 var curvalue = clearProp(el.style[stylename], property); 225 if (curvalue.length) curvalue += ', '; 226 //console.log(time+'s cubic-bezier('+ease[1]+', 227 //'+ease[2]+','+ease[3]+','+ease[4]+')'); 228 curvalue += property + ' ' + time + 's cubic-bezier(' + ease[1] + 229 ',' + ease[2] + ',' + ease[3] + ',' + ease[4] + ')'; 230 el.style[stylename] = curvalue; 231 }; 232 233 /** 234 * Clear previously set transition rule. 235 * @param {Element} el Element to change. 236 * @param {string} property Transition property name. 237 */ 238 lime.style.clearTransition = function(el, property) { 239 if (!stylename || !el) return; 240 el.style[stylename] = clearProp(el.style[stylename], property); 241 242 // console.log('clear',el.style[stylename],property); 243 }; 244 245 /** 246 * Change size of a DOM element. Has cache built in for speed boost. 247 * @param {Element} el Element to change. 248 * @param {number} w New width. 249 * @param {number} h New height. 250 */ 251 lime.style.setSize = function(el, w, h) { 252 if (el.width_cache_ != w || el.height_cache_ != h) { 253 el.width_cache_ = w; 254 el.height_cache_ = h; 255 return goog.style.setSize(el, w, h); 256 } 257 } 258 259 })(); 260