Fixes #2715 - Adding Microsoft Edge UA string support to Browser.
[mootools.git] / Source / Fx / Fx.CSS.js
blob60f98d7e82b2d265d0a55aed2200f89cd2c14567
1 /*
2 ---
4 name: Fx.CSS
6 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
8 license: MIT-style license.
10 requires: [Fx, Element.Style]
12 provides: Fx.CSS
14 ...
17 Fx.CSS = new Class({
19         Extends: Fx,
21         //prepares the base from/to object
23         prepare: function(element, property, values){
24                 values = Array.from(values);
25                 var from = values[0], to = values[1];
26                 if (to == null){
27                         to = from;
28                         from = element.getStyle(property);
29                         var unit = this.options.unit;
30                         // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
31                         if (unit && from && typeof from == 'string' && from.slice(-unit.length) != unit && parseFloat(from) != 0){
32                                 element.setStyle(property, to + unit);
33                                 var value = element.getComputedStyle(property);
34                                 // IE and Opera support pixelLeft or pixelWidth
35                                 if (!(/px$/.test(value))){
36                                         value = element.style[('pixel-' + property).camelCase()];
37                                         if (value == null){
38                                                 // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
39                                                 var left = element.style.left;
40                                                 element.style.left = to + unit;
41                                                 value = element.style.pixelLeft;
42                                                 element.style.left = left;
43                                         }
44                                 }
45                                 from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
46                                 element.setStyle(property, from + unit);
47                         }
48                 }
49                 return {from: this.parse(from), to: this.parse(to)};
50         },
52         //parses a value into an array
54         parse: function(value){
55                 value = Function.from(value)();
56                 value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
57                 return value.map(function(val){
58                         val = String(val);
59                         var found = false;
60                         Object.each(Fx.CSS.Parsers, function(parser, key){
61                                 if (found) return;
62                                 var parsed = parser.parse(val);
63                                 if (parsed || parsed === 0) found = {value: parsed, parser: parser};
64                         });
65                         found = found || {value: val, parser: Fx.CSS.Parsers.String};
66                         return found;
67                 });
68         },
70         //computes by a from and to prepared objects, using their parsers.
72         compute: function(from, to, delta){
73                 var computed = [];
74                 (Math.min(from.length, to.length)).times(function(i){
75                         computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
76                 });
77                 computed.$family = Function.from('fx:css:value');
78                 return computed;
79         },
81         //serves the value as settable
83         serve: function(value, unit){
84                 if (typeOf(value) != 'fx:css:value') value = this.parse(value);
85                 var returned = [];
86                 value.each(function(bit){
87                         returned = returned.concat(bit.parser.serve(bit.value, unit));
88                 });
89                 return returned;
90         },
92         //renders the change to an element
94         render: function(element, property, value, unit){
95                 element.setStyle(property, this.serve(value, unit));
96         },
98         //searches inside the page css to find the values for a selector
100         search: function(selector){
101                 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
102                 var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
104                 var searchStyles = function(rules){
105                         Array.each(rules, function(rule, i){
106                                 if (rule.media){
107                                         searchStyles(rule.rules || rule.cssRules);
108                                         return;
109                                 }
110                                 if (!rule.style) return;
111                                 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
112                                         return m.toLowerCase();
113                                 }) : null;
114                                 if (!selectorText || !selectorTest.test(selectorText)) return;
115                                 Object.each(Element.Styles, function(value, style){
116                                         if (!rule.style[style] || Element.ShortStyles[style]) return;
117                                         value = String(rule.style[style]);
118                                         to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
119                                 });
120                         });
121                 };
123                 Array.each(document.styleSheets, function(sheet, j){
124                         var href = sheet.href;
125                         if (href && href.indexOf('://') > -1 && href.indexOf(document.domain) == -1) return;
126                         var rules = sheet.rules || sheet.cssRules;
127                         searchStyles(rules);
128                 });
129                 return Fx.CSS.Cache[selector] = to;
130         }
134 Fx.CSS.Cache = {};
136 Fx.CSS.Parsers = {
138         Color: {
139                 parse: function(value){
140                         if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
141                         return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
142                 },
143                 compute: function(from, to, delta){
144                         return from.map(function(value, i){
145                                 return Math.round(Fx.compute(from[i], to[i], delta));
146                         });
147                 },
148                 serve: function(value){
149                         return value.map(Number);
150                 }
151         },
153         Number: {
154                 parse: parseFloat,
155                 compute: Fx.compute,
156                 serve: function(value, unit){
157                         return (unit) ? value + unit : value;
158                 }
159         },
161         String: {
162                 parse: Function.from(false),
163                 compute: function(zero, one){
164                         return one;
165                 },
166                 serve: function(zero){
167                         return zero;
168                 }
169         }
173 //<1.2compat>
175 Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers);
177 //</1.2compat>