From c9a2d1a6e031cfd0143d19767e4daa37495732ef Mon Sep 17 00:00:00 2001 From: Sebastien Grosjean Date: Fri, 17 Dec 2010 01:35:10 +0100 Subject: [PATCH 1/2] Fixed Element.Absolutize & Element.Relativize and add Element.undoAbsolutize & Element.undoRelativize. Tested and documented. --- src/prototype/dom/layout.js | 74 ++++++++++++++++++++++++++++++++----- test/unit/dom_test.js | 63 +++++++++++++++++++++++++++++-- test/unit/fixtures/dom.html | 6 +++ 3 files changed, 131 insertions(+), 12 deletions(-) diff --git a/src/prototype/dom/layout.js b/src/prototype/dom/layout.js index d55fd87fd..aa63e6c1e 100644 --- a/src/prototype/dom/layout.js +++ b/src/prototype/dom/layout.js @@ -1040,6 +1040,9 @@ * * Turns `element` into an absolutely-positioned element _without_ * changing its position in the page layout. + * + * To revert back to `element`'s original position, + * use [[Element.undoAbsolutize]]. **/ function absolutize(element) { element = $(element); @@ -1056,10 +1059,11 @@ var layout = element.getLayout(); element.store('prototype_absolutize_original_styles', { - left: element.getStyle('left'), - top: element.getStyle('top'), - width: element.getStyle('width'), - height: element.getStyle('height') + position: element.getStyle('position'), + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') }); element.setStyle({ @@ -1073,28 +1077,78 @@ return element; } + /** + * Element.undoAbsolutize(@element) -> Element + * + * Sets `element` back to the state it was in _before_ + * [[Element.absolutize]] was applied to it. + **/ + function undoAbsolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') !== 'absolute') { + return element; + } + + // Restore the original styles as captured by Element#absolutize. + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + element.store('prototype_absolutize_original_styles', undefined); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + /** * Element.relativize(@element) -> Element * * Turns `element` into a relatively-positioned element without changing * its position in the page layout. * - * Used to undo a call to [[Element.absolutize]]. + * To revert back to `element`'s original position, + * use [[Element.undoRelativize]]. **/ function relativize(element) { element = $(element); if (Element.getStyle(element, 'position') === 'relative') { return element; } + + element.store('prototype_relativize_original_styles', { + position: element.getStyle('position') + }); - // Restore the original styles as captured by Element#absolutize. + element.setStyle({ + position: 'relative' + }); + + return element; + } + + /** + * Element.undoRelativize(@element) -> Element + * + * Sets `element` back to the state it was in _before_ + * [[Element.relativize]] was applied to it. + **/ + function undoRelativize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') !== 'relative') { + return element; + } + + // Restore the original styles as captured by Element#relativize. var originalStyles = - element.retrieve('prototype_absolutize_original_styles'); + element.retrieve('prototype_relativize_original_styles'); + + element.store('prototype_relativize_original_styles', undefined); if (originalStyles) element.setStyle(originalStyles); return element; } - + if (Prototype.Browser.IE) { // IE doesn't report offsets correctly for static elements, so we change them // to "relative" to get the values, then change them back. @@ -1165,7 +1219,9 @@ cumulativeScrollOffset: cumulativeScrollOffset, viewportOffset: viewportOffset, absolutize: absolutize, - relativize: relativize + undoAbsolutize: undoAbsolutize, + relativize: relativize, + undoRelativize: undoRelativize }); function isBody(element) { diff --git a/test/unit/dom_test.js b/test/unit/dom_test.js index 1c67a5338..1bed7f9f2 100644 --- a/test/unit/dom_test.js +++ b/test/unit/dom_test.js @@ -1399,20 +1399,77 @@ new Test.Unit.Runner({ testAbsolutize: function() { $('notInlineAbsoluted', 'inlineAbsoluted').each(function(elt) { if ('_originalLeft' in elt) delete elt._originalLeft; + elt.absolutize(); + this.assertUndefined(elt._originalLeft, 'absolutize() did not detect absolute positioning'); }, this); + + // make sure it store original properties and set position as absolute + var element = $('absolute_fixed_undefined'); + + if (element.retrieve('prototype_absolutize_original_styles') !== undefined) + element.store('prototype_absolutize_original_styles', undefined); + + element.absolutize(); + + this.assertEqual('absolute', element.getStyle('position')); + + var originalStyles = element.retrieve('prototype_absolutize_original_styles'); + this.assertNotUndefined(originalStyles, 'absolutize() did not store original properties'); + ['position', 'top', 'left', 'width', 'height'].each(function(property) { + this.assertNotUndefined(originalStyles[property], + 'absolutize() did not store original ' + property + ' property'); + }, this); + // invoking on "absolute" positioned element should return element var element = $('absolute_fixed_undefined').setStyle({position: 'absolute'}); this.assertEqual(element, element.absolutize()); }, - + + testUndoAbsolutize: function() { + $('position-static', 'position-fixed', 'position-relative').each(function(elt) { + elt.absolutize(); + this.assertEqual(elt, elt.undoAbsolutize()); + this.assertEqual(elt.id.split('-').last(), elt.getStyle('position')); + this.assertUndefined(elt.retrieve('prototype_absolutize_original_styles')); + }, this); + // invoking on none "absolute" positioned element should return element + var element = $('position-untouched'); + this.assertEqual(element, element.undoAbsolutize()); + }, + testRelativize: function() { + var element = $('absolute_fixed_undefined'); + + if (element.retrieve('prototype_relativize_original_styles') !== undefined) + element.store('prototype_relativize_original_styles', undefined); + + element.relativize(); + + this.assertEqual('relative', element.getStyle('position')); + + var originalStyles = element.retrieve('prototype_relativize_original_styles'); + this.assertNotUndefined(originalStyles, 'relativize() did not store original properties'); + this.assertNotUndefined(originalStyles['position'], + 'relativize() did not store original position property'); + // invoking on "relative" positioned element should return element - var element = $('absolute_fixed_undefined').setStyle({position: 'relative'}); this.assertEqual(element, element.relativize()); }, - + + testUndoRelativize: function() { + $('position-static', 'position-fixed', 'position-absolute').each(function(elt) { + elt.relativize(); + this.assertEqual(elt, elt.undoRelativize()); + this.assertEqual(elt.id.split('-').last(), elt.getStyle('position')); + this.assertUndefined(elt.retrieve('prototype_relativize_original_styles')); + }, this); + // invoking on none "relative" positioned element should return element + var element = $('position-untouched'); + this.assertEqual(element, element.undoRelativize()); + }, + testViewportDimensions: function() { preservingBrowserDimensions(function() { window.resizeTo(800, 600); diff --git a/test/unit/fixtures/dom.html b/test/unit/fixtures/dom.html index 99395eeca..59def9ebc 100644 --- a/test/unit/fixtures/dom.html +++ b/test/unit/fixtures/dom.html @@ -265,6 +265,12 @@
+
+
+
+
+
+
From 0ae2caf56d44b6e2b7d1032c3d5d875f57551e9e Mon Sep 17 00:00:00 2001 From: Sebastien Grosjean Date: Fri, 17 Dec 2010 17:51:46 +0100 Subject: [PATCH 2/2] Maintain backward compatibility and fix misordered Element.undoAbsolutize & Element.undoRelativize calls. --- src/prototype/dom/layout.js | 11 +++++++++++ test/unit/dom_test.js | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/prototype/dom/layout.js b/src/prototype/dom/layout.js index aa63e6c1e..b7e251573 100644 --- a/src/prototype/dom/layout.js +++ b/src/prototype/dom/layout.js @@ -1041,12 +1041,17 @@ * Turns `element` into an absolutely-positioned element _without_ * changing its position in the page layout. * + * It also reverts back a previous [[Element.relativize]] call + * on this `element`. + * * To revert back to `element`'s original position, * use [[Element.undoAbsolutize]]. **/ function absolutize(element) { element = $(element); + element.undoRelativize(); + if (Element.getStyle(element, 'position') === 'absolute') { return element; } @@ -1106,11 +1111,17 @@ * Turns `element` into a relatively-positioned element without changing * its position in the page layout. * + * It also reverts back a previous [[Element.absolutize]] call + * on this `element`. + * * To revert back to `element`'s original position, * use [[Element.undoRelativize]]. **/ function relativize(element) { element = $(element); + + element.undoAbsolutize(); + if (Element.getStyle(element, 'position') === 'relative') { return element; } diff --git a/test/unit/dom_test.js b/test/unit/dom_test.js index 1bed7f9f2..67fbbc519 100644 --- a/test/unit/dom_test.js +++ b/test/unit/dom_test.js @@ -1469,6 +1469,24 @@ new Test.Unit.Runner({ var element = $('position-untouched'); this.assertEqual(element, element.undoRelativize()); }, + + testAbsolutizeThenRelativize: function() { + var element = $('position-static'); + element.absolutize(); + element.relativize(); + element.undoAbsolutize(); + element.undoRelativize(); + this.assertEqual('static', element.getStyle('position')); + }, + + testRelativizeThenAbsolutize: function() { + var element = $('position-static'); + element.relativize(); + element.absolutize(); + element.undoRelativize(); + element.undoAbsolutize(); + this.assertEqual('static', element.getStyle('position')); + }, testViewportDimensions: function() { preservingBrowserDimensions(function() {