Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed Element.Absolutize & Element.Relativize and add Element.undoAbsolutize & Element.undoRelativize. Tested and documented. #13

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 76 additions & 9 deletions src/prototype/dom/layout.js
Expand Up @@ -1040,10 +1040,18 @@
*
* 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;
}
Expand All @@ -1056,10 +1064,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({
Expand All @@ -1073,28 +1082,84 @@
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]].
* 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;
}

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.
Expand Down Expand Up @@ -1165,7 +1230,9 @@
cumulativeScrollOffset: cumulativeScrollOffset,
viewportOffset: viewportOffset,
absolutize: absolutize,
relativize: relativize
undoAbsolutize: undoAbsolutize,
relativize: relativize,
undoRelativize: undoRelativize
});

function isBody(element) {
Expand Down
79 changes: 77 additions & 2 deletions test/unit/dom_test.js
Expand Up @@ -1399,20 +1399,95 @@ 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());
},

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() {
window.resizeTo(800, 600);
Expand Down
6 changes: 6 additions & 0 deletions test/unit/fixtures/dom.html
Expand Up @@ -265,6 +265,12 @@
<div id="notInlineAbsoluted"></div>
<div id="inlineAbsoluted" style="position: absolute"></div>

<div id="position-static"></div>
<div id="position-fixed" style="position: fixed;"></div>
<div id="position-absolute" style="position: absolute;"></div>
<div id="position-relative" style="position: relative;"></div>
<div id="position-untouched"></div>

<div id="unextended"></div>
<div id="identification">
<div id="predefined_id"></div>
Expand Down