// a cow makes moo, this script too. requires mootools 1.2b or compatible.
// MIT-style licence
var CssEffects = {
prefix: "%prefix%",
initialValues: {
duration: "%initialDuration%",
property: "%initialProperty%",
transition: "%initialTransition%"
},
timeUnit: "%timeUnit%"
};
CssEffects.deprecates = (Browser.Engine.trident4) ? true : false;
CssEffects.$regexps = {
parserA: new RegExp('(?:s)*([^{}]+?)s*{([^}]*' + CssEffects.prefix + "[^}]*)}", "gi"),
parserB: new RegExp(CssEffects.prefix + "(?:-?([a-z-]+))?s*:s*([^;]+?)s*(!important)?s*;", "gi"),
time: new RegExp('d+' + CssEffects.timeUnit)
};
CssEffects.Durations = new Hash();
CssEffects.Properties = new Hash();
CssEffects.Transitions = new Hash();
CssEffects.Element = new Class({
initialize: function(element){
this.element = element;
element.store('CssEffects', this);
this.previous = {};
this.dynamicPseudos = [];
this.rules = [];
this.styleAttribute = '';
this.saveStyleAttribute();
this.effect = new Fx.Morph(this.element,{
onCancel: function(){
this.previous = this.getStyles(this.dynamicPseudos);
}.bind(this),
onComplete: this.element.setStyles.bind(this.element, this.previous)
});
(function(){
this.previous = this.getStyles();
element.setStyles(this.previous);
}).delay(1, this);
CssEffects.DynamicPseudos.each(function(obj, pseudo){
['begin', "end"].each(function(when){
$splat(obj[when]).each(function(event){
element.addEvent(event, this.change.bind(this, [when, pseudo]));
}, this);
}, this);
}, this);
},
change: function(when, pseudo){
pseudo = pseudo || '';
(function(){
if (pseudo.length > 0){
if (when == "end" && !this.dynamicPseudos.contains(pseudo)) return;
this.dynamicPseudos[(when == "begin") ? "push" : "remove"](pseudo);
}
this.effect.cancel();
this.restoreStyleAttribute();
var now = this.getStyles(this.dynamicPseudos);
this.element.setStyles(this.previous);
var to = Hash.filter(now, function(v, p){
return (!$defined(this.previous[p]) || this.previous[p] != v);
}, this);
var duration = this.getOwnStyle('duration', this.dynamicPseudos);
var transition = this.getOwnStyle('transition', this.dynamicPseudos);
this.effect.options.duration = duration.match(CssEffects.$regexps.time) ? duration.toInt()
: CssEffects.Durations.get(duration);
this.effect.options.transition = CssEffects.Transitions.get(transition);
this.effect.start(to);
this.previous = now;
}).delay(1, this)
return this;
},
addRule: function(rule){
this.rules.include(rule);
return this;
},
hasRule: function(rule){
return this.rules.contains(rule);
},
removeRule: function(rule){
this.rules.erase(rule);
return this;
},
getOwnStyle: function(property, dynamicPseudos){
dynamicPseudos = dynamicPseudos || [];
var pseudoStr = dynamicPseudos.sort().join('$');
var rules = this.rules.filter(function(rule){
var rulePseudoStr = rule.dynamicPseudos.sort().join('$');
return (!rulePseudoStr || rule.values.has(property) && pseudoStr == rulePseudoStr);
});
var value = CssEffects.initialValues[property];
var importance = 0, specificity = 0;
rules.each(function(rule){
var mImportance = rule.importances.get(property);
if (mImportance > importance || (mImportance == importance && rule.specificity >= specificity)){
importance = mImportance;
specificity = rule.specificity;
value = rule.values.get(property);
}
});
return value;
},
getStyles: function (dynamicPseudos){
var property = this.getOwnStyle('property', dynamicPseudos);
if (property == "none") return {};
property = (property == "all") ? CssEffects.Properties : $splat(property);
return this.element.getStyles.apply(this.element, property);
},
saveStyleAttribute: function(){
this.styleAttribute = this.element.get('style') || '';
return this;
},
restoreStyleAttribute: function(){
return this.element.set('style', this.styleAttribute);
}
});
CssEffects.Element.getInstance = function(element){
return element.retrieve('CssEffects') || new CssEffects.Element(element);
};
CssEffects.Parser = {
addCss: function(text){
while (a = CssEffects.$regexps.parserA.exec(text)){
var selectors = a[1].split(/s*,s*/);
rules = selectors.map(function(selector){
return new CssEffects.Rule(selector);
});
while (b = CssEffects.$regexps.parserB.exec(a[2])){
var importance = (b[3] == "!important") ? 2 : 1;
rules.each(function(rule){
rule.addDeclaration(b[1], b[2], importance);
});
}
}
return this;
},
addStylesheet: function(element){
switch (element.get('tag')){
case "style":
this.addCss(element.get('html'));
break;
case "link":
new Request({
onSuccess: function(text){
this.addCss(text);
}.bind(this),
url: element.href,
method: "get"
}).send();
}
return this;
},
processDocument: function(){
$each(document.styleSheets, function(styleSheet){
var element = $(styleSheet[styleSheet.ownerNode ? "ownerNode" : "owningElement"]);
this.addStylesheet(element);
}, this);
return this;
}
};
CssEffects.Rule = new Class({
initialize: function(selector){
this.importances = new Hash();
this.values = new Hash();
this.selector = selector.replace(/:active|:focus|:hover/ig, '');
this.dynamicPseudos = selector.match(/(:active|:focus|:hover)/ig) || [];
this.specificity = (function(){
var str = selector.replace(/:(before|after|first-letter|first-line)/, '');
var a = str.match(/#/g); a = a ? a.length : 0;
var b = str.match(/[|:|./g); b = b ? b.length : 0;
var c = str.match(/( |+|>)[a-z]+/ig); c = c ? c.length : 0;
if (str.match(/^[a-z]+/i)) c++;
return 100 * a + 10 * b + c;
})();
this.use();
},
addDeclaration: function(property, value, importance){
if (!property) return this.addShortHand(value, importance);
if (!this.importances.has(property) || this.importances.get(property) <= importance) {
if (value.contains(',')) value = value.split(/s*,s*/);
this.values.set(property, value);
this.importances.set(property, importance);
}
return this;
},
addShortHand: function(shortHand, importance){
shortHand.match(/([^s,]+s*,s*)+[^s,]+|[^s,]+/gi).each(function(value){
var property = (value.match(CssEffects.$regexps.time) || CssEffects.Durations.has(value)) ? "duration"
: (CssEffects.Transitions.has(value)) ? "transition"
: "property";
this.addDeclaration(property, value, importance);
}, this);
return this;
},
use: function(){
$$(this.selector).each(function(element){
CssEffects.Element.getInstance(element).addRule(this);
}, this);
}
});
CssEffects.DynamicPseudos = new Hash({
":active": {
begin: "mousedown",
end: ['mouseup', "mouseout"]
},
":focus": {
begin: "focus",
end: "blur"
},
":hover": {
begin: "mouseenter",
end: "mouseleave"
}
});
// normal:
CssEffects.prefix = "-moofx";
initialValues: {
duration: "0ms",
property: "all",
transition: "sine-in-out"
},
aliases
};
CssEffects.Durations = new Hash({
"short": 250,
"normal": 500,
"long": 750
});
CssEffects.Properties = ['backgroundColor', "backgroundPosition", "borderBottomColor",
"borderBottomStyle", "borderBottomWidth", "borderLeftColor", "borderLeftStyle",
"borderLeftWidth", "borderRightColor", "borderRightStyle", "borderRightWidth",
"borderTopColor", "borderTopStyle", "borderTopWidth", "bottom",
"color", "fontSize", "fontWeight", "height", "left", "letterSpacing", "lineHeight",
"marginBottom", "marginLeft", "marginRight", "marginTop", "maxHeight", "maxWidth",
"opacity", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "right",
"textIndent", "top", "width", "zIndex", "zoom"];
CssEffects.DynamicPseudos = new Hash({
":active": {
begin: "mousedown",
end: ['mouseup', "mouseout"]
},
":focus": {
begin: "focus",
end: "blur"
},
":hover": {
begin: "mouseenter",
end: "mouseleave"
}
});
CssEffects.Transitions = new Hash({
linear: Fx.Transitions.linear
});
['Quad', "Cubic", "Quart", "Quint", "Expo", "Circ",
"Sine", "Back", "Bounce", "Elastic"].each(function (transition){
['In', "Out", "InOut"].each(function (ease){
var alias = transition.toLowerCase() + ease.hyphenate().toLowerCase();
CssEffects.Transitions.set(alias, Fx.Transitions[transition]['ease' + ease]);
});
});
window.addEvent('domready', CssEffects.Parser.processDocument.bind(CssEffects.Parser));
})();