I have a pretty specific scenario where I would like to select all elements with jQuery, make a CSS change, save the elements, then reverse the change I made.
The Goal
I created a jQuery plugin called jQuery.sendFeedback. This plugin allows the user to highlight areas of the screen, as shown in this demo. When they submit their feedback the plugin grabs all the HTML on the page and dumps it into a callback function. Like so:
$('*').each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
var feedbackInformation = {
subject: $feedbackSubject.val(),
details: $feedbackDetails.val(),
html: '<html>' + $('html').html() + '</html>'
};
if (settings.feedbackSent)
settings.feedbackSent(feedbackInformation);
The callback function accepts this feedback information and makes an AJAX call to store the page HTML on the server (this HTML includes the red box highlights the user drew on the screen). When someone from tech support needs to view the user’s “screen shot” they navigate to a page that serves up the stored HTML so the developer can see where the user drew their highlights on the screen.
My original problem was that different screen resolutions made the elements different sizes and the red highlights would highlight the wrong areas as the screen changed. This was fixed pretty easily by selecting all elements on the page and manually setting their height and width to their current height and width when the user takes the snap shot. This makes all the element sizes static, which is perfect.
$('*').each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
The Problem
The issue with this is that when the plugin is done transmitting this HTML the page currently being viewed now has static heights and widths on every element. This prevents dropdown menus and some other things from operating as they should. I cannot think of an easy way to reverse the change I made to the DOM without refreshing the page (which may very well end up being my only option). I’d prefer not to refresh the page.
Attempted Solution
What I need is a way to manipulate the HTML that I’m sending to the server, but not the DOM. I tried to change the above code to pull out the HTML first, then do the operation on the string containing the HTML (thus not affecting the DOM), but I’m not quite sure what I’m doing here.
var html = '<html>' + $('html').html() + '</html>';
$('*', html).each(function ()
{
$(this).width($(this).width());
$(this).height($(this).height());
});
This did not work. So either I need to be able to manipulate the string of HTML or I need to be able to manipulate the DOM and undo the manipulation afterward. I’m not quite sure what to do here.
Update
I employed the solution that I posted below it is working beautifully now. Now I am wondering if there is a way to statically write all the css for each element to the element, eliminating the need for style sheets to be referenced.
After much pain and suffering I figured a crude but effective method for reverting my modifications to the DOM. Though I hadn’t gotten around to trying @fdfrye’s suggestion of cloning, I will be trying that next to see if there is a mroe elegant solution. In the meantime, here is the new code in case anyone else can benefit from it:
When I’m looping through every element and modifying the css, I log the original value onto the element as data. After I assign the DOM HTML to a variable I then loop through all elements again and restore the style attribute to its original value. If there was no style attribute then I log ‘none’ to the element data and then remove the style attribute entirely when looping through again.
This is more performance heavy than I wish it was since it loops through all elements twice; it takes a few seconds to finish. Not horrible but it seems like a little much for such a small task. Anyway, it works. I get a string with fixed-sized HTML elements and the DOM goes back to normal as if the plugin never touched it.