public
Fork of sstephenson/prototype
Description: Prototype JavaScript framework (forked for some disruptive changes)
Homepage: http://prototypejs.org/
Clone URL: git://github.com/savetheclocktower/prototype.git
Elements with hidden ancestors now report their dimensions correctly. 
(Nick Stackenburg, Andrew Dupont) [#9 state:resolved]
Sun Apr 20 17:38:39 -0700 2008
commit  f9a884f86753870d459a8b8c6d8458aaf7684bf9
tree    d5c3f2029a9beae6aa1bcb6852ae9bbd32eced55
parent  c752c942645072dfe252164aa60aa703a04b3848
...
18
19
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
22
23
...
25
26
27
28
 
29
 
30
31
32
 
33
34
35
36
37
38
39
40
41
 
42
43
44
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
47
48
...
69
70
71
72
 
73
74
75
...
79
80
81
82
 
83
84
85
...
106
107
108
109
 
 
 
 
110
111
112
...
122
123
124
125
 
126
127
128
...
244
245
246
247
 
248
249
250
...
279
280
281
282
 
 
283
284
285
...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
...
43
44
45
 
46
47
48
49
50
 
51
52
 
 
 
 
 
 
 
 
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
95
96
97
 
98
99
100
101
...
105
106
107
 
108
109
110
111
...
132
133
134
 
135
136
137
138
139
140
141
...
151
152
153
 
154
155
156
157
...
273
274
275
 
276
277
278
279
...
308
309
310
 
311
312
313
314
315
0
@@ -18,6 +18,24 @@ Element.Layout = Class.create({
0
     this.getLayout();
0
   },
0
   
0
+ _applyTemporaryStyles: function(element, styles) {
0
+ for (var property in styles) {
0
+ element['_original_' + property] = element.style[property];
0
+ }
0
+ element.setStyle(styles);
0
+ },
0
+
0
+ _removeTemporaryStyles: function(element) {
0
+ var prop, styles = {};
0
+ for (var property in element) {
0
+ if (!property.startsWith('_original_')) continue;
0
+ prop = property.replace(/^_original_/, '');
0
+ styles[prop] = element[property] || '';
0
+ element[property] = undefined;
0
+ }
0
+ element.setStyle(styles);
0
+ },
0
+
0
   getLayout: function() {
0
     var element = this.element,
0
         display = element.getStyle('display'),
0
@@ -25,24 +43,32 @@ Element.Layout = Class.create({
0
     
0
     // The style object is inaccessible in Safari <= 2.0 when the element
0
     // is hidden.
0
- var isNotShown = display === "none" || display === null;
0
+ var isNotShown = display === "none" || display === null || element.offsetHeight == 0;
0
     var isTable = element.tagName.toUpperCase() == 'TABLE';
0
+ var hasHiddenAncestor = false;
0
     
0
     // If the element is hidden, we show it for an instant
0
- // to grab its dimensions.
0
+ // to grab its dimensions.
0
     if (isNotShown) {
0
- var style = element.style;
0
- var originalStyle = {
0
- visibility: style.visibility,
0
- position: style.position,
0
- display: style.display
0
- };
0
-
0
- Object.extend(style, {
0
+ this._applyTemporaryStyles(element, {
0
         visibility: 'hidden',
0
         position: 'absolute',
0
         display: 'block'
0
       });
0
+
0
+ // If, after showing the element, it still has an offsetHeight of 0,
0
+ // we assume one of its ancestors is hidden.
0
+ hasHiddenAncestor = element.offsetHeight == 0;
0
+
0
+ if (hasHiddenAncestor) {
0
+ var ancestors = element.ancestors();
0
+ ancestors.each( function(ancestor) {
0
+ if (ancestor !== element && ancestor.visible()) return;
0
+ this._applyTemporaryStyles(ancestor, {
0
+ display: 'block', visibility: 'visible', position: 'absolute'
0
+ });
0
+ }, this);
0
+ }
0
     }
0
     
0
     if (this.options.dimensions === true) {
0
@@ -69,7 +95,7 @@ Element.Layout = Class.create({
0
       
0
       this.layout.paddingBox = paddingBox;
0
 
0
- var padding = this.getStyleValuesFor('padding', 'trbl');
0
+ var padding = this._getStyleValuesFor('padding', 'trbl');
0
       this.layout.padding = padding;
0
 
0
       var contentBox = {
0
@@ -79,7 +105,7 @@ Element.Layout = Class.create({
0
       
0
       this.layout.contentBox = contentBox;
0
 
0
- var border = this.getStyleValuesFor('border', 'trbl');
0
+ var border = this._getStyleValuesFor('border', 'trbl');
0
       this.layout.border = border;
0
 
0
       var borderBox = {
0
@@ -106,7 +132,10 @@ Element.Layout = Class.create({
0
     // If we altered the element's styles, return them to their
0
     // original values.
0
     if (isNotShown) {
0
- Object.extend(style, originalStyle);
0
+ this._removeTemporaryStyles(element);
0
+ if (hasHiddenAncestor) {
0
+ ancestors.each(this._removeTemporaryStyles, this);
0
+ }
0
     }
0
     
0
     return this.layout;
0
@@ -122,7 +151,7 @@ Element.Layout = Class.create({
0
   // sidesNeeded argument is a string.
0
   // "trbl" = top, right, bottom, left
0
   // "tb" = top, bottom
0
- getStyleValuesFor: function(property, sidesNeeded) {
0
+ _getStyleValuesFor: function(property, sidesNeeded) {
0
     var sides = $w('top bottom left right');
0
     var propertyNames = sides.map( function(s) {
0
       return property + s.capitalize();
0
@@ -244,7 +273,7 @@ Element.Layout = Class.create({
0
     // Then subtract cumulative scroll offsets
0
     element = this.element;
0
     do {
0
- if (!Prototype.Browser.Opera || element.tagName.toUpperCase() == 'BODY') {
0
+ if (!Prototype.Browser.Opera || element.tagName.toUpperCase() == 'HTML') {
0
         valueT -= element.scrollTop || 0;
0
         valueL -= element.scrollLeft || 0;
0
       }
0
@@ -279,7 +308,8 @@ Element.Layout = Class.create({
0
     if (element.offsetParent) return $(element.offsetParent);
0
     if (element == document.body) return $(element);
0
     
0
- while ((element = element.parentNode) && element !== document.body)
0
+ while ((element = element.parentNode) && element !== document.body
0
+ && element.nodeType !== 9)
0
       if (Element.getStyle(element, 'position') !== 'static')
0
         return element;
0
 
...
86
87
88
89
 
90
91
92
93
94
95
96
97
98
99
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
104
105
...
410
411
412
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
414
415
...
551
552
553
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
555
556
...
86
87
88
 
89
90
91
92
93
 
 
 
 
 
 
 
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
0
@@ -86,20 +86,64 @@
0
       left: 15px;
0
     }
0
     
0
- #dimensions-display-none, #imensions-display-none-pos-rel, #dimensions-display-none-pos-abs {
0
+ #dimensions-display-none, #dimensions-display-none-pos-rel, #dimensions-display-none-pos-abs {
0
         display: none;
0
     }
0
     
0
     #dimensions-table, #dimensions-tbody, #dimensions-tr, #dimensions-td {
0
- font-size: 10px;
0
- margin: 0;
0
- padding: 0;
0
- border: 0;
0
- border-spacing: 0;
0
- height: 10em;
0
- width: 20em;
0
+ font-size: 10px;
0
+ margin: 0;
0
+ padding: 0;
0
+ border: 0;
0
+ border-spacing: 0;
0
+ height: 10em;
0
+ width: 20em;
0
+ }
0
+
0
+ .getDimensionsBox {
0
+ float: left;
0
+ clear: both;
0
+ width: 200px;
0
+ height: 200px;
0
+ background: #1d8bcb;
0
+ }
0
+
0
+ .getDimensionsBox div { float: left; }
0
+
0
+ .getDimensionsBox .deep {
0
+ height: 150px;
0
+ width: 150px;
0
+ background: #21bacc;
0
     }
0
 
0
+ .getDimensionsBox .deeper {
0
+ height: 130px;
0
+ width: 130px;
0
+ background: #94dee6;
0
+ }
0
+
0
+ .getDimensionsBox .deepest {
0
+ height: 100px;
0
+ width: 100px;
0
+ background: #cbeff3;
0
+ }
0
+
0
+ #clonePositionSource,
0
+ #cloneDimensionsSource {
0
+ position: absolute;
0
+ top: 10px;
0
+ left: 560px;
0
+ height: 20px;
0
+ width: 30px;
0
+ background: red;
0
+ }
0
+
0
+ #clonePositionTarget,
0
+ #cloneDimensionsTarget {
0
+ position: absolute;
0
+ background: #21bacc;
0
+ }
0
+
0
     #notInlineAbsoluted { position: absolute; }
0
     
0
     #elementToViewportDimensions {
0
@@ -410,6 +454,44 @@
0
 
0
 <div id='elementToViewportDimensions' style='display: none'></div>
0
 
0
+<div class='getDimensionsBox' id='getDimensionsBox1'>
0
+ <div class='deep'>
0
+ <div class='deeper'>
0
+ <div class='deepest' style='display:none'></div>
0
+ </div>
0
+ </div>
0
+</div>
0
+
0
+<div class='getDimensionsBox' id='getDimensionsBox2'>
0
+ <div class='deep'>
0
+ <div class='deeper' style='display:none'>
0
+ <div class='deepest'></div>
0
+ </div>
0
+ </div>
0
+</div>
0
+
0
+<div class='getDimensionsBox' id='getDimensionsBox3'>
0
+ <div class='deep' style='display:none'>
0
+ <div class='deeper' style='display:none'>
0
+ <div class='deepest'></div>
0
+ </div>
0
+ </div>
0
+</div>
0
+
0
+<div class='getDimensionsBox' id='getDimensionsBox4' style='display:none'>
0
+ <div class='deep' style='display:none'>
0
+ <div class='deeper' style='display:none'>
0
+ <div class='deepest'></div>
0
+ </div>
0
+ </div>
0
+</div>
0
+
0
+<div id='clonePositionSource'></div>
0
+<div id='clonePositionTarget'></div>
0
+
0
+<div id='cloneDimensionsSource'></div>
0
+<div id='cloneDimensionsTarget'></div>
0
+
0
 <!-- Tests follow -->
0
 <script type="text/javascript" language="javascript" charset="utf-8">
0
 // <![CDATA[
0
@@ -551,6 +633,23 @@
0
       $('dimensions-table').hide();
0
       this.assertIdentical(100, $('dimensions-table').getDimensions().height);
0
       this.assertIdentical(200, $('dimensions-table').getDimensions().width);
0
+
0
+ Prototype.debug = true;
0
+
0
+ // display:none ancestors
0
+ $R(1, 4).each(function(num) {
0
+ var element = $('getDimensionsBox' + num);
0
+ this.assertIdentical(200, element.getDimensions().height);
0
+ this.assertIdentical(200, element.getDimensions().width);
0
+ this.assertIdentical(150, element.down('.deep').getDimensions().height);
0
+ this.assertIdentical(150, element.down('.deep').getDimensions().width);
0
+ this.assertIdentical(130, element.down('.deeper').getDimensions().height);
0
+ this.assertIdentical(130, element.down('.deeper').getDimensions().width);
0
+ this.assertIdentical(100, element.down('.deepest').getDimensions().height);
0
+ this.assertIdentical(100, element.down('.deepest').getDimensions().width);
0
+ }, this);
0
+
0
+ Prototype.debug = false;
0
     },
0
 
0
     testPositionedOffset: function() {

Comments

    No one has commented yet.