[jQuery] Cross-browser inline style injection in DOM
Hello all jQuery people.
This is my first post in this list but I hope I can make sense with my
question.
Currently I'm developing some web applications for internal use,
porting some old ones.
I'd love the jQuery-way to do asynchronous requests, so I developed a
plugin similar to Pimentech jFrame. Basicly, it "automagically"
catches all clicks on links, sends an AJAH request and loads the
response inside a container.
The problem came when the response contains STYLE or LINK tags. Using
Firefox and Opera all was perfect, but no style was applied with IE6,
IE7, Chrome or Safari. I was thinking that was my plugin's fault, but
when I test the use case without it, the problem remains. No style
applied.
Check this simplified case without even jQuery:
<body>
<p id="test">This is a test and should have a border around and 1ex
padding!
<script type="text/javascript">
var div = document.createElement('div');
// <br/> added to avoid a bug in IE
div.innerHTML = '<br /><style>#test { border:2px solid #000; padding:
1ex; }</style>';
var span = div.getElementsByTagName('span')[0];
document.body.appendChild(div);
</script>
</body>
I thought that jQuery have workarounds to this, but I found none, so I
created a plugin to do the work.
In case I missed some jQuery functionality, please tell me. I prefer
the jQuery way.
This plugin relies on detecting whether inlined styles are processed
or not. If not, modify $.fn.html to move all style's and link's to
document.head, mark them with a 'data-style-loader' attribute and
adding a dummy link to the target. When te dummy link is removed (with
the same $.fn.html function), it removes all related style's and
link's from head.
Well, that's the code:
$(function($) {
// Checks for some supported features
(function() {
var div = document.createElement('div');
div.id = 'jquery-support-styled';
document.body.appendChild(div);
// Checks whether inlined styles applies automaticly (Firefox and
Opera returns true)
div.innerHTML = '<style>#'+div.id+' span { display:block; width:
3px; }</style><span />';
var span = div.getElementsByTagName('span')[0];
$.support.inlineStyleApplies = $(span).width() == 3;
// Checks whether inlined styles applies if they are inside 'br'
context (for IE)
$.support.mustPrependBrToInlineStyles = !
$.support.inlineStyleApplies && (function(){
div.innerHTML = '<br /><style>#'+div.id+' span { display:block;
width:5px; }</style><span />';
var span = div.getElementsByTagName('span')[0];
return ($.support.inlineStyleApplies = $(span).width() == 5);
})();
document.body.removeChild(div);
})();
// Saves old $().html function
var old_html = $.fn.html;
if($.support.mustPrependBrToInlineStyles) {
// Modify old $().html to add br before styles and links
$.fn.html = function(_value) {
if(typeof _value !== 'string') {
_value = _value.replace(/<style|<link/gi, function(_text) {
return '<br style="display:none"/>'+_text
})
}
return old_html.call(this, _value);
}
} else if(!$.support.inlineStyleApplies) {
// Change old $().html to move link´s and style´s to the head
$.fn.html = function(_text) {
// Remove css-pointers and their pointees
var $styles = this.find('link[data-style-loader]');
if($styles.length) { clean_css($styles); }
// Calls old $().html
old_html.call(this, _text);
// Promote new links and styles to document.head
$styles = this.find('style,link[rel*=stylesheet]');
if($styles.length) { add_styles.call(this, $styles) }
return this;
}
// Remove css-pointers and their pointees
function clean_css(_$styles) {
// Get pointees id
var st = [];
for(var i = 0; i < _$styles.length; ++i) {
st[st.length] = '[data-style-loader='+$(_$styles[i]).attr('data-
style-loader')+']'
}
// Remove all links pointed
$('head').find(st.join(', ')).remove();
}
// Promote new links and styles to document.head
function add_styles(_$styles) {
// Selects a pointer id
var tm = (new Date).getTime();
// Move to head and add attribute with pointer id
_$styles.attr('data-style-loader', tm).appendTo('head')
// Create a pointer (link inside target) that points to the new
links and styles
this.append('<link data-style-loader='+tm+' />')
}
}
})
I have tested the plugin with these cases:
1) Default, no style
2) <style type="text/css">#test { color:red; }</style>
3) <link rel="stylesheet" href="remote.css" /> and remote.css #test
{ color:red; }
4) <style type="text/css">@import url("remote.css")</style>
5) <link rel="stylesheet" href="import.css" /> and import.css @import
url("remote.css")
The plugin works ok with some exceptions.
In IE6 and IE7, case 4 fails silently. Surprisingly, 5 is no problem.
In Safari and Chrome, the style isn't removed when loading 1) after 3)
or 5). After 2) or 4) it works ok.
So, any suggestions? I hope that jQuery has something on those lines.
Thanks all for reading, and sorry for the long post.
And thanks to the jQuery Team for such a marvelous tool!
Best regards!