goog.provide('lime.style');
goog.provide('lime.style.Transform');
goog.require('goog.dom');
goog.require('goog.style');
goog.require('lime.userAgent');
(function() {
var prefix = goog.userAgent.WEBKIT ? 'Webkit' :
goog.userAgent.GECKO ? 'Moz' :
goog.userAgent.OPERA ? 'O' :
goog.userAgent.IE ? 'ms' : '';
var testDivStyle = goog.dom.createDom('div').style;
lime.style.transformProperty = '-' + prefix.toLowerCase() + '-transform';
/**
* Try if a CSS style property with given name exists
* @param {string} name Property name.
* @return {boolean|string} If property exists.
*/
lime.style.tryProperty = function(name) {
return testDivStyle[name] !== undefined ? name : false;
};
/**
* Get the name of actual CSS property from general(unprefixed) name
* @param {string} name Unprefixed name.
* @return {string} Actual valid property name.
*/
lime.style.getCSSproperty = function(name) {
var name_lower = name.charAt(0).toLowerCase() + name.substr(1),
prefix_name = prefix + name;
return lime.style.tryProperty(name) ?
name : (lime.style.tryProperty(name_lower) ?
name_lower : lime.style.tryProperty(prefix_name) ?
prefix_name : undefined);
};
})();
/**
* Set border radius of a DOM element
* @param {Element} el Element to change.
* @param {Array.<number>} values Radius values.
* @param {Array.<number>=} opt_vertical Vertical radius values.
* @param {boolean=} opt_isPerc If values are given in percentages.
*/
lime.style.setBorderRadius = (function() {
var stylename = lime.style.getCSSproperty('BorderRadius');
var out = function(values, unit) {
return (goog.isArray(values) ? values.join(unit + ' ') : values) + unit;
};
return function(el, values, opt_vertical, opt_isPerc) {
var unit = opt_isPerc ? '%' : 'px';
var vertical = goog.isDef(opt_vertical) ? opt_vertical : values;
var value = out(values, unit) + '/' + out(vertical, unit);
if (value != el.border_radius_cache_) {
el.style[stylename] = el.border_radius_cache_ = value;
}
};
})();
// There are classes like CSSMatrix in some browsers.
// Maybe this would make more sense.
/**
* Object representing CSS Transform.
* @constructor
* @param {number=} opt_precision Default precision.
*/
lime.style.Transform = function(opt_precision) {
this.values = [];
this.precision = 1;
this.enable3D_ = true;
if (this.opt_precision) {
this.setPrecision( /** @type {number} */ (opt_precision));
}
};
/**
* Sets 3D enabling flag for css hardware acceleration (on by default)
* @param {Boolean} value
* @return {lime.style.Transform} object itself.
*/
lime.style.Transform.prototype.set3DAllowed = function(value) {
this.enable3D_ = value;
return this;
};
/**
* Scale current transform object
* @param {number} sx X-axis scale factor.
* @param {number} sy y-axis scale factor.
* @return {lime.style.Transform} object itself.
*/
lime.style.Transform.prototype.scale = function(sx, sy) {
//if(sx!=1 && sy!=1)
this.values.push('scale(' + sx + ',' + sy + ')');
return this;
};
/**
* Rotate current transform object
* @param {number} angle Angle to rotate.
* @param {string=} opt_unit Units. Defaults to degrees.
* @return {lime.style.Transform} object itself.
*/
lime.style.Transform.prototype.rotate = function(angle, opt_unit) {
var rot_str;
if (this.enable3D_ && (lime.userAgent.IOS || lime.userAgent.PLAYBOOK)) {
rot_str = 'rotate3d(0, 0, 1, ' + angle + (opt_unit ? opt_unit : 'deg') + ')';
} else {
rot_str = 'rotate(' + angle + (opt_unit ? opt_unit : 'deg') + ')';
}
if (angle != 0)
this.values.push(rot_str);
return this;
};
/**
* Translate(move) current transform object
* @param {number} tx Offset in x-axis.
* @param {number} ty Offset in y-axis.
* @param {number=} opt_tz Offset in z-axis.
* @return {lime.style.Transform} object itself.
*/
lime.style.Transform.prototype.translate = function(tx, ty, opt_tz) {
var p = 1 / this.precision;
var val = 'translate';
if (this.enable3D_ && (lime.userAgent.CHROME || lime.userAgent.IOS || lime.userAgent.PLAYBOOK)) {
val += '3d';
}
val += '(' + (tx * p) + 'px,' + (ty * p) + 'px';
if (this.enable3D_ && (lime.userAgent.CHROME || lime.userAgent.IOS || lime.userAgent.PLAYBOOK)) {
val += ',' + ((opt_tz ? opt_tz : 0) * p) + 'px';
}
this.values.push(val + ')');
return this;
};
/**
* Set the current precision of transform. This is handled as a
* state machine so it's added when called not when done.
* @param {number} p Precision(Lowest value to make a difference).
* @return {lime.style.Transform} object itself.
*/
lime.style.Transform.prototype.setPrecision = function(p) {
if (this.precision != 1) {
var opposite = 1 / this.precision;
this.scale(opposite, opposite);
this.precision = 1;
}
if (p != 1) {
this.scale(p, p);
this.precision = p;
}
return this;
};
/**
* Return CSS transform string from the object
* @return {string} CSS value string.
*/
lime.style.Transform.prototype.toString = function() {
if (this.precision != 1) {
this.setPrecision(1);
}
return this.values.join(' ');
};
/**
* Set transform to a DOM element.
* @param {Element} el Element to change.
* @param {lime.style.Transform} transform Transform.
*/
lime.style.setTransform = (function() {
var stylename = lime.style.getCSSproperty('Transform');
return function(el, transform) {
var value = transform.toString();
if (value != el.transform_cache_) {
el.style[stylename] = el.transform_cache_ = value;
}
lime.transformSet_ = 1;
};
})();
/**
* Set transform origin point for a DOM element.
* @param {Element} el Element to change.
* @param {number} ox X Offset.
* @param {number} oy Y Offset.
* @param {boolean=} opt_isPerc If unit is percentage.
*/
lime.style.setTransformOrigin = (function() {
var stylename = lime.style.getCSSproperty('TransformOrigin');
return function(el, ox, oy, opt_isPerc) {
var unit = opt_isPerc ? '%' : 'px';
var value = ox + unit + ' ' + oy + unit;
if (value != el.transform_origin_cache_) {
el.style[stylename] = el.transform_origin_cache_ = value;
}
};
})();
(function() {
var stylename = lime.style.getCSSproperty('Transition');
lime.style.isTransitionsSupported = !! stylename && !goog.userAgent.OPERA;
// Opera's CSS3 transitions seem to be unstable atm. No shorthand plus
// doesn't work if the duration property has not been previously set inside
// CSS style sheet @tonis
var clearProp = function(str, prop) {
if (!str.length) return str;
var proplist = str.split('),');
for (var i = 0; i < proplist.length - 1; i++) {
proplist[i] += ')';
}
proplist = goog.array.filter(proplist, function(part) {
return part.indexOf(prop) == -1;
});
return proplist.join(',');
};
/**
* Activate transition rule for a property
* @param {Element} el Element to change.
* @param {string} property Transition property name.
* @param {number} time Transition duration.
* @param {lime.animation.EasingFunction} ease Easing function.
*/
lime.style.setTransition = function(el, property, time, ease) {
if (!stylename) return;
var curvalue = clearProp(el.style[stylename], property);
if (curvalue.length) curvalue += ', ';
//console.log(time+'s cubic-bezier('+ease[1]+',
//'+ease[2]+','+ease[3]+','+ease[4]+')');
curvalue += property + ' ' + time + 's cubic-bezier(' + ease[1] +
',' + ease[2] + ',' + ease[3] + ',' + ease[4] + ')';
el.style[stylename] = curvalue;
};
/**
* Clear previously set transition rule.
* @param {Element} el Element to change.
* @param {string} property Transition property name.
*/
lime.style.clearTransition = function(el, property) {
if (!stylename || !el) return;
el.style[stylename] = clearProp(el.style[stylename], property);
// console.log('clear',el.style[stylename],property);
};
/**
* Change size of a DOM element. Has cache built in for speed boost.
* @param {Element} el Element to change.
* @param {number} w New width.
* @param {number} h New height.
*/
lime.style.setSize = function(el, w, h) {
if (el.width_cache_ != w || el.height_cache_ != h) {
el.width_cache_ = w;
el.height_cache_ = h;
return goog.style.setSize(el, w, h);
}
return undefined;
};
})();