Skip to content
This repository

Enhancement refactor element.style #2414

Open
wants to merge 3 commits into from

3 participants

Olmo Maldonado Arian Stolwijk Gonzalo Rubio
Olmo Maldonado
Owner

Don't merge. It's no where near done. Just wanted to get some feedback.

A couple of things.

  1. I unrolled the Element.ShortStyles which significantly increased Element.Styles. I still think there's room to play with this. Keeping in mind, however, that we want to keep it simple. Let compilers and gzip do the hard work.

  2. Getter and setters are separated, but there may be collisions and a lot of repetition (element.getComputedStyle).

  3. There's also some normalization in setStyle and getStyle ... how are we going to handle this? Per getter/setter or against all results.

Olmo Maldonado
Owner

Oh and this is definitely untested.. :D ala 1.0.x style (a "kami commit")

Arian Stolwijk arian commented on the diff August 22, 2012
Source/Element/Element.Style.js
@@ -110,45 +122,29 @@ Element.implement({
110 122
 	},
111 123
 
112 124
 	getStyle: function(property){
113  
-		if (property == 'opacity') return getOpacity(this);
114  
-		property = (property == 'float' ? floatName : property).camelCase();
  125
+
  126
+		property = (property == 'float') ? floatName : property.camelCase();
  127
+
  128
+		var getter = getGetter(property);
2
Arian Stolwijk Owner
arian added a note August 22, 2012

there isn't a getGetter function yet.

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

hehe good call. Must have forgotten. I'll fix soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Arian Stolwijk arian commented on the diff August 22, 2012
Source/Element/Element.Style.js
@@ -213,23 +200,232 @@ Element.Styles = new Hash(Element.Styles);
213 200
 
214 201
 //</1.2compat>
215 202
 
216  
-Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
  203
+Element.Styles = {
  204
+	left: {map: '@px'},
4
Arian Stolwijk Owner
arian added a note August 22, 2012

why not keep left: '@px' by default, only for special cases use an object. Is smaller and probably better for backward compat.

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

We could reduce this by adding more logic to the getGetter, getMap, and getStyle, but I'm also trying to encourage a simple hook mechanism. See the following comment.

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

oh and there is a simple byte reduction I had thought of, but I'm not implementing yet. give me your 2c:

'left,top,bottom,right,width,height,letterSpacing,lineHeight,...'.split(',').forEach(function(property){
    Element.Styles[property] = {map: '@px'};
});
Olmo Maldonado Owner
ibolmo added a note August 22, 2012

Even further:

{
  '@px': 'left,top,bottom,right,width,height,letterSpacing,lineHeight,...',
  '@': 'zIndex',
  ...
}

And just have the initializer code once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Arian Stolwijk arian commented on the diff August 22, 2012
Source/Element/Element.Style.js
((10 lines not shown))
  208
+	width: {map: '@px'},
  209
+	height: {map: '@px'},
  210
+	letterSpacing: {map: '@px'},
  211
+	lineHeight: {map: '@px'},
  212
+	clip: {map: 'rect(@px @px @px @px)'},
  213
+	zIndex: {
  214
+		map: '@',
  215
+		get: function(element){
  216
+			return element.getComputedStyle('zIndex');
  217
+		}
  218
+	},
  219
+	'zoom': {map: '@'},
  220
+	textIndent: {map: '@px'},
  221
+	opacity: {
  222
+		map: '@',
  223
+		get: function(element){
2
Arian Stolwijk Owner
arian added a note August 22, 2012
get: getOpacity,
set: setOpacity

should be able to handle it..

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

actually I'm considering moving that logic inside the get and set. Just haven't gotten to it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Arian Stolwijk arian commented on the diff August 22, 2012
Source/Element/Element.Style.js
((11 lines not shown))
  209
+	height: {map: '@px'},
  210
+	letterSpacing: {map: '@px'},
  211
+	lineHeight: {map: '@px'},
  212
+	clip: {map: 'rect(@px @px @px @px)'},
  213
+	zIndex: {
  214
+		map: '@',
  215
+		get: function(element){
  216
+			return element.getComputedStyle('zIndex');
  217
+		}
  218
+	},
  219
+	'zoom': {map: '@'},
  220
+	textIndent: {map: '@px'},
  221
+	opacity: {
  222
+		map: '@',
  223
+		get: function(element){
  224
+			return getOpacity(this);
2
Arian Stolwijk Owner
arian added a note August 22, 2012

also you're using this here, instead of element.

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

right, forgot to update. nice catch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Arian Stolwijk arian commented on the diff August 22, 2012
Source/Element/Element.Style.js
((180 lines not shown))
  372
+		borderRightStyle: '@px',
  373
+		borderBottomStyle: '@px',
  374
+		borderLeftStyle: '@px'
  375
+	},
  376
+	borderColor: {
  377
+		borderTopColor: '@px',
  378
+		borderRightColor: '@px',
  379
+		borderBottomColor: '@px',
  380
+		borderLeftColor: '@px'
  381
+	}
  382
+};
  383
+
  384
+
  385
+// todo(ibolmo): collisions?
  386
+
  387
+if (hasBackgroundPositionXY){
2
Arian Stolwijk Owner
arian added a note August 22, 2012

maybe also move the feature detections here, closer where it's actually used.

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

agreed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Arian Stolwijk
Owner

Nice work, good start! :+1:

Gonzalo Rubio gonchuki commented on the diff August 22, 2012
Source/Element/Element.Style.js
((12 lines not shown))
115 131
 		var result = this.style[property];
116  
-		if (!result || property == 'zIndex'){
117  
-			if (Element.ShortStyles.hasOwnProperty(property)){
118  
-				result = [];
119  
-				for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
120  
-				return result.join(' ');
121  
-			}
  132
+
  133
+		if (!result && Element.ShortStyles.hasOwnProperty(property)){
  134
+			result = [];
  135
+			for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
  136
+			return result.join(' ');
  137
+		} else {
4
Gonzalo Rubio
gonchuki added a note August 22, 2012

code will wrongly enter here when result && !Element.ShortStyles.hasOwnProperty(property), you only need to run the getComputedStyle part if we got no result from the this.style[property]

Even better, I'm also not sure if doing: var result = this.style[property] || this.getComputedStyle(property); would break anything, current specs pass but that doesn't say much. Any reason to give ShortStyles precedence over trying to getComputedStyle on the element?

Olmo Maldonado Owner
ibolmo added a note August 22, 2012

You're right the change is not 1:1 with the previous logic. I'll modify soon.

Regards to your suggest change, again you're right. It's not clear why we can't default to getComputedStyle. If style getter doesn't work.

My other thought is, why can't we always use getComputedStyle? Was the original idea used to save CPU cycles?

Gonzalo Rubio
gonchuki added a note August 22, 2012

saving CPU cycles is a sure thing, remember than only IE has .currentStyle so other browsers will go though the longer function-call-heavy path. Considering that getStyle is used a lot on animations, we should always have the fastest possible path here to avoid jerkiness.

That being said, if it's safe to do style || getComputedStyle on this part of the code then we could integrate this default behavior right inside getComputedStyle if (this.style[property]) return this.style[property]; etc. as the rest of the uses of getComputedStyle are always as a default when the element.style cannot be retrieved (getOpacity, setFilter on #2411, etc)

Gonzalo Rubio
gonchuki added a note August 28, 2012

investigated this, it's not safe to just integrate the element style inside getComputedStyle. Several tests break on different browsers so it seems it is like that for a reason. Removing the element.style querying altogether is neither an option, once again several tests break. Keeping in line with the comment I left on #2417 I think this part of the code should stay with the same logic flow unless we get way more specs to cover all bases.

edit: also a small correction to my comment above: seems that Opera also has currentStyle and it has a serious bug on getComputedStyle where if you set something as a %, the getComputedStyle call rounds the result to the nearest pixel integer instead of returning the exact sub-pixel value as Firefox/IE9/IE10 does (this unit conversion from % to px was addressed on #2160, some browsers convert from % to px, others don't).

Take this as misc info to reinforce the fact that current logic flow is mostly ok, even though I would still like to have getComputedStyle used if available instead of currentStyle as that's the standard and I will probably get up a PR later with these changes. I still think that doing small incremental changes gets us in a position where we can ship code now without requiring a ton of new specs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Olmo Maldonado
Owner

The reason I unrolled the https://github.com/mootools/mootoolscore/blob/cb327bf3/Source/Element/Element.Style.js#L216-232 is simply that it wasn't easy to read.

My logic is that we're no longer in 2000 when JS compilers were non-existant and that most people didn't bother to gzip .. CDNs are prolific now.

Lastly, I'm not done with Element.ShortStyle and Element.Styles. I think there's a lot of room to explore. To explore, I thought let's see all properties unrolled.

I have some ideas with increased effort:

  1. Instead of defaulting to '@' we could default to '@px' in line: https://github.com/mootools/mootools-core/pull/2414/files#L0R86. That'll save a lot of bytes. I'm not sure, however, of the consequences. Need more test coverage.

  2. I was thinking we could do a BoxModel class that we can use to say contain this stuff. Especially rules about accepted input and margin**Top**-like (, borderTopWidth...) definitions that would be implicit to the model. Again, this is very vapor but I thought it might be interesting to see if it'll simplify development.

  3. Finally, if we decide that we don't need developers to understand the code we can save a lot of bytes by having a script that scrapes the w3 css definition and comes up with a literally mapping of the accepted input and the expected output. Notice that sometimes we map some outputs to px or convert rgba to rgb. That's really bad. or how we round floats ow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 260 additions and 64 deletions. Show diff stats Hide diff stats

  1. 324  Source/Element/Element.Style.js
324  Source/Element/Element.Style.js
... ...
@@ -1,3 +1,4 @@
  1
+
1 2
 /*
2 3
 ---
3 4
 
@@ -75,6 +76,16 @@ var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat',
75 76
 	namedPositions = {left: '0%', top: '0%', center: '50%', right: '100%', bottom: '100%'},
76 77
 	hasBackgroundPositionXY = (html.style.backgroundPositionX != null);
77 78
 
  79
+function getSetter(property){
  80
+	property = Element.Styles[property];
  81
+	return property && property.set;
  82
+}
  83
+
  84
+function getMap(property){
  85
+	property = Element.Styles[property];
  86
+	return property && property.map || '@';
  87
+}
  88
+
78 89
 Element.implement({
79 90
 
80 91
 	getComputedStyle: function(property){
@@ -85,14 +96,11 @@ Element.implement({
85 96
 	},
86 97
 
87 98
 	setStyle: function(property, value){
88  
-		if (property == 'opacity'){
89  
-			if (value != null) value = parseFloat(value);
90  
-			setOpacity(this, value);
91  
-			return this;
92  
-		}
93  
-		property = (property == 'float' ? floatName : property).camelCase();
  99
+
  100
+		property = (property == 'float') ? floatName : property.camelCase();
  101
+
94 102
 		if (typeOf(value) != 'string'){
95  
-			var map = (Element.Styles[property] || '@').split(' ');
  103
+			var map = getMap(property).split(' ');
96 104
 			value = Array.from(value).map(function(val, i){
97 105
 				if (!map[i]) return '';
98 106
 				return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
@@ -100,7 +108,11 @@ Element.implement({
100 108
 		} else if (value == String(Number(value))){
101 109
 			value = Math.round(value);
102 110
 		}
103  
-		this.style[property] = value;
  111
+
  112
+		var setter = getSetter(property);
  113
+		if (setter) setter(element, value);
  114
+		else this.style[property] = value;
  115
+
104 116
 		//<ltIE9>
105 117
 		if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
106 118
 			this.style.removeAttribute(property);
@@ -110,45 +122,29 @@ Element.implement({
110 122
 	},
111 123
 
112 124
 	getStyle: function(property){
113  
-		if (property == 'opacity') return getOpacity(this);
114  
-		property = (property == 'float' ? floatName : property).camelCase();
  125
+
  126
+		property = (property == 'float') ? floatName : property.camelCase();
  127
+
  128
+		var getter = getGetter(property);
  129
+		if (getter) return getter(property);
  130
+
115 131
 		var result = this.style[property];
116  
-		if (!result || property == 'zIndex'){
117  
-			if (Element.ShortStyles.hasOwnProperty(property)){
118  
-				result = [];
119  
-				for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
120  
-				return result.join(' ');
121  
-			}
  132
+
  133
+		if (!result && Element.ShortStyles.hasOwnProperty(property)){
  134
+			result = [];
  135
+			for (var s in Element.ShortStyles[property]) result.push(this.getStyle(s));
  136
+			return result.join(' ');
  137
+		} else {
122 138
 			result = this.getComputedStyle(property);
123 139
 		}
124  
-		if (hasBackgroundPositionXY && /^backgroundPosition[XY]?$/.test(property)){
125  
-			return result.replace(/(top|right|bottom|left)/g, function(position){
126  
-				return namedPositions[position];
127  
-			}) || '0px';
128  
-		}
129  
-		if (!result && property == 'backgroundPosition') return '0px 0px';
  140
+
  141
+		// todo(ibolmo): normalization is needed for which properties? and when
130 142
 		if (result){
131 143
 			result = String(result);
132 144
 			var color = result.match(/rgba?\([\d\s,]+\)/);
133 145
 			if (color) result = result.replace(color[0], color[0].rgbToHex());
134 146
 		}
135  
-		if (Browser.opera || Browser.ie){
136  
-			if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
137  
-				var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
138  
-				values.each(function(value){
139  
-					size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
140  
-				}, this);
141  
-				return this['offset' + property.capitalize()] - size + 'px';
142  
-			}
143  
-			if ((/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
144  
-				return '0px';
145  
-			}
146  
-			//<ltIE9>
147  
-			if (returnsBordersInWrongOrder && /^border(Top|Right|Bottom|Left)?$/.test(property) && /^#/.test(result)){
148  
-				return result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1');
149  
-			}
150  
-			//</ltIE9>
151  
-		}
  147
+
152 148
 		return result;
153 149
 	},
154 150
 
@@ -167,15 +163,6 @@ Element.implement({
167 163
 
168 164
 });
169 165
 
170  
-Element.Styles = {
171  
-	left: '@px', top: '@px', bottom: '@px', right: '@px',
172  
-	width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
173  
-	backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
174  
-	fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
175  
-	margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
176  
-	borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
177  
-	zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
178  
-};
179 166
 
180 167
 //<1.3compat>
181 168
 
@@ -213,23 +200,232 @@ Element.Styles = new Hash(Element.Styles);
213 200
 
214 201
 //</1.2compat>
215 202
 
216  
-Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
  203
+Element.Styles = {
  204
+	left: {map: '@px'},
  205
+	top: {map: '@px'},
  206
+	bottom: {map: '@px'},
  207
+	right: {map: '@px'},
  208
+	width: {map: '@px'},
  209
+	height: {map: '@px'},
  210
+	letterSpacing: {map: '@px'},
  211
+	lineHeight: {map: '@px'},
  212
+	clip: {map: 'rect(@px @px @px @px)'},
  213
+	zIndex: {
  214
+		map: '@',
  215
+		get: function(element){
  216
+			return element.getComputedStyle('zIndex');
  217
+		}
  218
+	},
  219
+	'zoom': {map: '@'},
  220
+	textIndent: {map: '@px'},
  221
+	opacity: {
  222
+		map: '@',
  223
+		get: function(element){
  224
+			return getOpacity(this);
  225
+		},
  226
+		set: function(element, value){
  227
+			if (value != null) value = parseFloat(value);
  228
+			setOpacity(this, value);
  229
+			return this;
  230
+		}
  231
+	},
  232
+	color: {map: 'rgb(@, @, @)'},
  233
+
  234
+	maxWidth: {map: '@px'},
  235
+	maxHeight: {map: '@px'},
217 236
 
218  
-['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
219  
-	var Short = Element.ShortStyles;
220  
-	var All = Element.Styles;
221  
-	['margin', 'padding'].each(function(style){
222  
-		var sd = style + direction;
223  
-		Short[style][sd] = All[sd] = '@px';
  237
+	minWidth: {map: '@px'},
  238
+	minHeight: {map: '@px'},
  239
+
  240
+	backgroundColor: {map: 'rgb(@, @, @)'},
  241
+	backgroundPosition: {
  242
+		map: '@px @px',
  243
+		get: function(element){
  244
+			return element.getComputedStyle('backgroundPosition') || '0px 0px';
  245
+		}
  246
+	},
  247
+
  248
+	fontWeight: {map: '@'},
  249
+	fontSize: {map: '@px'},
  250
+
  251
+	margin: {map: '@px @px @px @px'},
  252
+	marginTop: {map: '@px'},
  253
+	marginRight: {map: '@px'},
  254
+	marginBottom: {map: '@px'},
  255
+	marginLeft: {map: '@px'},
  256
+
  257
+	padding: {map: '@px @px @px @px'},
  258
+	paddingTop: {map: '@px'},
  259
+	paddingRight: {map: '@px'},
  260
+	paddingBottom: {map: '@px'},
  261
+	paddingLeft: {map: '@px'},
  262
+
  263
+	border: {map: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)'},
  264
+	borderWidth: {map: '@px @px @px @px'},
  265
+	borderStyle: {map: '@ @ @ @'},
  266
+	borderColor: {map: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)'},
  267
+
  268
+	borderTop: {map: '@px @ rgb(@, @, @)'},
  269
+	borderTopWidth: {map: '@px'},
  270
+	borderTopColor: {map: '@px'},
  271
+	borderTopStyle: {map: '@px'},
  272
+
  273
+	borderRight: {map: '@px @ rgb(@, @, @)'},
  274
+	borderRightWidth: {map: '@px'},
  275
+	borderRightStyle: {map: '@px'},
  276
+	borderRightColor: {map: '@px'},
  277
+
  278
+	borderBottom: {map: '@px @ rgb(@, @, @)'},
  279
+	borderBottomStyle: {map: '@px'},
  280
+	borderBottomColor: {map: '@px'},
  281
+	borderBottomWidth: {map: '@px'},
  282
+
  283
+	borderLeft: {map: '@px @ rgb(@, @, @)'},
  284
+	borderLeftWidth: {map: '@px'},
  285
+	borderLeftStyle: {map: '@px'},
  286
+	borderLeftColor: {map: '@px'}
  287
+};
  288
+
  289
+Element.ShortStyles = {
  290
+	margin: {
  291
+		marginTop: '@px',
  292
+		marginRight: '@px',
  293
+		marginBottom: '@px',
  294
+		marginLeft: '@px'
  295
+	},
  296
+	padding: {
  297
+		paddingTop: '@px',
  298
+		paddingRight: '@px',
  299
+		paddingBottom: '@px',
  300
+		paddingLeft: '@px'
  301
+	},
  302
+	border: {
  303
+		borderTop: '@px @ rgb(@, @, @)',
  304
+		borderRight: '@px @ rgb(@, @, @)',
  305
+		borderBottom: '@px @ rgb(@, @, @)',
  306
+		borderLeft: '@px @ rgb(@, @, @)'
  307
+	},
  308
+	borderTop: {
  309
+		borderTopWidth: '@px',
  310
+		borderTopColor: '@px',
  311
+		borderTopStyle: '@px',
  312
+		borderRightWidth: '@px',
  313
+		borderRightStyle: '@px',
  314
+		borderRightColor: '@px',
  315
+		borderBottomStyle: '@px',
  316
+		borderBottomColor: '@px',
  317
+		borderBottomWidth: '@px',
  318
+		borderLeftWidth: '@px',
  319
+		borderLeftStyle: '@px',
  320
+		borderLeftColor: '@px'
  321
+	},
  322
+	borderRight: {
  323
+		borderTopWidth: '@px',
  324
+		borderTopColor: '@px',
  325
+		borderTopStyle: '@px',
  326
+		borderRightWidth: '@px',
  327
+		borderRightStyle: '@px',
  328
+		borderRightColor: '@px',
  329
+		borderBottomStyle: '@px',
  330
+		borderBottomColor: '@px',
  331
+		borderBottomWidth: '@px',
  332
+		borderLeftWidth: '@px',
  333
+		borderLeftStyle: '@px',
  334
+		borderLeftColor: '@px'
  335
+	},
  336
+	borderBottom: {
  337
+		borderTopWidth: '@px',
  338
+		borderTopColor: '@px',
  339
+		borderTopStyle: '@px',
  340
+		borderRightWidth: '@px',
  341
+		borderRightStyle: '@px',
  342
+		borderRightColor: '@px',
  343
+		borderBottomStyle: '@px',
  344
+		borderBottomColor: '@px',
  345
+		borderBottomWidth: '@px',
  346
+		borderLeftWidth: '@px',
  347
+		borderLeftStyle: '@px',
  348
+		borderLeftColor: '@px'
  349
+	},
  350
+	borderLeft: {
  351
+		borderTopWidth: '@px',
  352
+		borderTopColor: '@px',
  353
+		borderTopStyle: '@px',
  354
+		borderRightWidth: '@px',
  355
+		borderRightStyle: '@px',
  356
+		borderRightColor: '@px',
  357
+		borderBottomStyle: '@px',
  358
+		borderBottomColor: '@px',
  359
+		borderBottomWidth: '@px',
  360
+		borderLeftWidth: '@px',
  361
+		borderLeftStyle: '@px',
  362
+		borderLeftColor: '@px'
  363
+	},
  364
+	borderWidth: {
  365
+		borderTopWidth: '@px',
  366
+		borderRightWidth: '@px',
  367
+		borderBottomWidth: '@px',
  368
+		borderLeftWidth: '@px'
  369
+	},
  370
+	borderStyle: {
  371
+		borderTopStyle: '@px', q
  372
+		borderRightStyle: '@px',
  373
+		borderBottomStyle: '@px',
  374
+		borderLeftStyle: '@px'
  375
+	},
  376
+	borderColor: {
  377
+		borderTopColor: '@px',
  378
+		borderRightColor: '@px',
  379
+		borderBottomColor: '@px',
  380
+		borderLeftColor: '@px'
  381
+	}
  382
+};
  383
+
  384
+
  385
+// todo(ibolmo): collisions?
  386
+
  387
+if (hasBackgroundPositionXY){
  388
+	['backgroundPositionX', 'backgroundPositionY'].forEach(function(property){
  389
+		Element.Styles[property] = {get: function(element){
  390
+			return element.getComputedStyle(property).replace(/(top|right|bottom|left)/g, function(position){
  391
+				return namedPosition[position];
  392
+			}) || '0px';
  393
+		}};
224 394
 	});
225  
-	var bd = 'border' + direction;
226  
-	Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
227  
-	var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
228  
-	Short[bd] = {};
229  
-	Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
230  
-	Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
231  
-	Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
232  
-});
  395
+	Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
  396
+}
  397
+
  398
+if (Browser.opera || Browser.ie){
  399
+	Object.each({
  400
+		width: ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'],
  401
+		height: ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight']
  402
+	}, function(styles, property){
  403
+		Element.Styles[property].get = function(element){
  404
+			var result = element.getComputedStyle(property), size = 0;
  405
+			if (result.substr(-2) == 'px') return result;
  406
+
  407
+			Object.forEach(element.getStyles(styles), function(value){ size += value; });
  408
+			return (element['offset' + property.capitalize()] - size) + 'px';
  409
+		};
  410
+	});
  411
+
  412
+	for (var property in Element.Styles) if (/^border(.+)Width|margin|padding/.test(property)){
  413
+		Element.Styles[property].get = function(element){
  414
+			var result = element.getComputedStyle(property);
  415
+			return isNaN(parseFloat(result)) ? '0px' : result;
  416
+		}
  417
+	}
  418
+}
  419
+
  420
+//<ltIE9>
  421
+if (returnsBordersInWrongOrder){
  422
+	for (var property in Element.Styles) if (/^border(Top|Right|Bottom|Left)?$/.test(property)){
  423
+		Element.Styles[property].get = function(element){
  424
+			var result = element.getComputedStyle(property);
  425
+			return /^#/.test(result) ? result.replace(/^(.+)\s(.+)\s(.+)$/, '$2 $3 $1') : result;
  426
+		};
  427
+	}
  428
+}
  429
+//</ltIE9>
233 430
 
234  
-if (hasBackgroundPositionXY) Element.ShortStyles.backgroundPosition = {backgroundPositionX: '@', backgroundPositionY: '@'};
235 431
 })();
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.