Как записать XHTML через innerHTML в Opera

Oct 13, 2009 17:13


Давеча я рассказывал, как Opera обламывает jQuery-разработчика при попытке использовать XHTML своей некорректной работой с innerHTML. А теперь расскажу, как можно попытаться это дело исправить.

Итак, пишем для Opera такую функцию:

function appendXHTML(node, xhtml){ var doc = (new DOMParser()).parseFromString( '' + xhtml + '', "application/xhtml+xml" ).documentElement; var frag=document.createDocumentFragment(); var elem=doc.firstChild; while(elem){ frag.appendChild(elem.cloneNode(true)); elem=elem.nextSibling; }; node.appendChild(frag); };
Она запишет в документ правильный XHTML-фрагмент. Вопрос в том, как её задействовать. Ныне Opera поддерживает изначально Mozilla’вские методы __defineGetter__ и __defineSetter__, позволяющие определить свои обработчики для чтения и присвоения некоторого свойства объекта. К сожалению, переопределить с их помощью уже имеющееся свойство innerHTML мне не удалось (может, чего-то не понял?), получилось только определить новое свойство:

if("HTMLElement" in window){ HTMLElement.prototype.__defineSetter__( "innerXHTML", function(val){ if("opera" in window && window.opera){ while(this.firstChild) this.removeChild(this.firstChild); appendXHTML(this, val); } else this.innerHTML=val; } ); }
Памятуя, что разработка идёт с использованием jQuery, функцию-сеттер лучше переписать так:

function(val){ if($.browser.opera){ $(this).empty(); appendXHTML(this, val); } else this.innerHTML=val; }
Теперь можно попытаться позаменять в собственном коде jQuery все обращения к innerHTML на обращения к innerXHTML (да, автозамена - это не очень хорошо, но что ж поделаешь?). Только тогда нам ещё понадобится функция-геттер (на случай, когда свойство будет использоваться для чтения). Она тривиальна (пишем её рядышком, внутрь проверки существования HTMLElement):

HTMLElement.prototype.__defineGetter__( "innerXHTML", function(){ return this.innerHTML; } );
Недовольным останется только Internet Explorer и на сей раз даже вполне оправданно, ибо он реализует (пусть и не в полном объёме) не проприетарные придумки, а метод defineProperty из стандарта ECMAScript 5. Специально для него пишем:

if("defineProperty" in Object) Object.defineProperty( Element.prototype, "innerXHTML", { get: function(){ return this.innerHTML; }, set: function(val){ this.innerHTML=val; } } );
Разумеется, после этого IE продолжит писать XHTML код по-своему, как и раньше, ну, да он всё равно XHTML так пока и не понимает и, что ценно, в отличие от Opera не притворяется перед jQuery, что это не так.

Вот и всё. На примерах работает в IE 8 (в IE 7 не работает, что на нынешний момент можно ещё, наверное, считать серьёзным ограничением; и ещё, очень важно - никакого Quirks Mode, корректный DOCTYPE должен быть указан!), Firefox 2.0 и 3.5, Opera 9.6 (в Opera 9.0 не работает), а также в Chrome 3.0 и Safari 4.0. На большом проекте метод пока не испытывал.

innerhtml, jquery, Web-программирование, javascript, стандарты, opera, xhtml, ie

Previous post Next post
Up