JavaScript « cloneNode в IE
Столкнулся с такой проблемой: есть фрейм, который представляет собой rich text editor. В боди фрейма содержится текст и элемент <object> с аттрибутом unselectable (здесь и везде - IE8). Выполняю следующий код (rte_frame - ссылка на этот фрейм):
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }
var node = rte_frame.contentWindow.document.body.cloneNode(true)
Ошибка происходит при попытке обратиться к аттрибуту innerHTML объекта node. Опытным путем удалось установить, что всему виной аттрибут unselectable. Т.е. если его удалить - все пройдет успешно. Также к ошибке приводят установленные name, data и др.
UPDATE Синтетический пример:
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }
<body>
<iframe src="iframecontent.html" id="myTestFrame" width="468" height="60" align="left">
</iframe>
<SCRIPT LANGUAGE="JavaScript">
document.onclick = function() {
var doc = document.getElementById('myTestFrame').contentWindow.document;
var obj = doc.createElement('object');
obj.id='object';
//obj.test = 'sdf';
doc.body.appendChild(obj);
}
document.onkeypress = function(){
var doc = document.getElementById('myTestFrame').contentDocument || document.getElementById('myTestFrame').contentWindow.document;
alert( doc.body.cloneNode(true).innerHTML);
}
</SCRIPT>
</body>
Если убрать комментарий для obj.test = 'sdf';, будет вылетать ошибка в IE. (В Firefox, например, просто нельзя установить такой аттрибут)
Как обойти эту проблему?
ЗЫ. Еще заметил, что внутренние тэги <param> при cloneNode не клонируется - что за чертовщина??
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }
var node = rte_frame.contentWindow.document.body.cloneNode(true)
Ошибка происходит при попытке обратиться к аттрибуту innerHTML объекта node. Опытным путем удалось установить, что всему виной аттрибут unselectable. Т.е. если его удалить - все пройдет успешно. Также к ошибке приводят установленные name, data и др.
UPDATE Синтетический пример:
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .javascript.geshi_code {font-family:monospace;} .javascript.geshi_code .imp {font-weight: bold; color: red;} .javascript.geshi_code .kw1 {color: #000066; font-weight: bold;} .javascript.geshi_code .kw2 {color: #003366; font-weight: bold;} .javascript.geshi_code .kw3 {color: #000066;} .javascript.geshi_code .co1 {color: #006600; font-style: italic;} .javascript.geshi_code .co2 {color: #009966; font-style: italic;} .javascript.geshi_code .coMULTI {color: #006600; font-style: italic;} .javascript.geshi_code .es0 {color: #000099; font-weight: bold;} .javascript.geshi_code .br0 {color: #009900;} .javascript.geshi_code .sy0 {color: #339933;} .javascript.geshi_code .st0 {color: #3366CC;} .javascript.geshi_code .nu0 {color: #CC0000;} .javascript.geshi_code .me1 {color: #660066;} .javascript.geshi_code span.xtra { display:block; }
<body>
<iframe src="iframecontent.html" id="myTestFrame" width="468" height="60" align="left">
</iframe>
<SCRIPT LANGUAGE="JavaScript">
document.onclick = function() {
var doc = document.getElementById('myTestFrame').contentWindow.document;
var obj = doc.createElement('object');
obj.id='object';
//obj.test = 'sdf';
doc.body.appendChild(obj);
}
document.onkeypress = function(){
var doc = document.getElementById('myTestFrame').contentDocument || document.getElementById('myTestFrame').contentWindow.document;
alert( doc.body.cloneNode(true).innerHTML);
}
</SCRIPT>
</body>
Если убрать комментарий для obj.test = 'sdf';, будет вылетать ошибка в IE. (В Firefox, например, просто нельзя установить такой аттрибут)
Как обойти эту проблему?
ЗЫ. Еще заметил, что внутренние тэги <param> при cloneNode не клонируется - что за чертовщина??
1 ответов
Я почти уверен что вы вызываете javascript код сразу же за iframe. В этом и ошибка, т.к фрейм еще не успевает загрузиться. Нужно отлавливать событие onload у iframe и там уже делать всю логику.
Чтобы не быть голословным привожу рабочий пример.
<HTML>
<HEAD>
<TITLE> Тест iframe cloneNode</TITLE>
</HEAD>
<BODY>
<iframe src="iframecontent.html" id="myTestFrame" width="468" height="60" align="left">
</iframe>
<SCRIPT LANGUAGE="JavaScript">
document.getElementById('myTestFrame').onload = function(){
var doc = document.getElementById('myTestFrame').contentDocument || document.getElementById('myTestFrame').contentWindow.document;
alert( doc.body.cloneNode(true).innerHTML);
}
</SCRIPT>
</BODY>
</HTML>
Ну естественно нужен файл iframecontent.html иначе будет не onload а onerror отлавливаться.
Народ подскажите как вот сюда
<td colspan="2"><input type="submit" name="login" value="Вход"</td>
вставить ссылку (Ну тоесть чтобы при нажатии на "ВХод" нас выбрасовало например на страницу http://123.ru/)
Буду очень благодарен
Я сделал через ява скрипт
<td colspan="2"><input type="hidden" />
<a href="http://123.ru" onclick="return true;"><input type="submit" name="login" class="mainoption" value="Вход"/></td>
Вопрос теперь в другом, как убрать подчеркивание кнопки. Только именной этой кнопки, а не подчеркивания на всей страничке
Все это довольно таки старая ошибка. SO так же не один раз упоминает об этом . Причем, на сколько я понял, каких-то определенных манипуляций не достаточно что бы решить ее. В большинстве случаев ее решают иными путями избегая клонирования в целом.
Вы пробовали рассматривать процесс клонирования в популярных фреймворках?
Так к примеру в jQuery:
Собственно их комментарий, в котором говорится, что клонирование в IE не пройдет гладко, и что некоторые аттрибуты будут просто проигнорированы:
// IE copies events bound via attachEvent when
// using cloneNode. Calling detachEvent on the
// clone will also remove the events from the orignal
// In order to get around this, we use innerHTML.
// Unfortunately, this means some modifications to
// attributes in IE that are actually only stored
// as properties will not be copied (such as the
// the name attribute on an input).
ps/ Сейчас обнаружил, что clone метод в версии jQuery 1.4 значительно изменился. Хотя суть сохранилась - Они пытаются клонировать элемент, затем копируют в клон все аттрибуты и свойства с событиями.
clone: function( events ) {
var ret = this.map(function() {
if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
var html = this.outerHTML, ownerDocument = this.ownerDocument;
if ( !html ) {
var div = ownerDocument.createElement("div");
div.appendChild( this.cloneNode(true) );
html = div.innerHTML;
}
return jQuery.clean([html.replace(rinlinejQuery, "")
.replace(rleadingWhitespace, "")], ownerDocument)[0];
} else {
return this.cloneNode(true);
}
});
// Copy the events from the original to the clone
if ( events === true ) {
cloneCopyEvent( this, ret );
cloneCopyEvent( this.find("*"), ret.find("*") );
}
return ret;
},
Тоже самое происходит в mooTools,
clone: function(contents, keepid){
contents = contents !== false;
var clone = this.cloneNode(contents);
var clean = function(node, element){
if (!keepid) node.removeAttribute('id');
if (Browser.Engine.trident){
node.clearAttributes();
node.mergeAttributes(element);
node.removeAttribute('uid');
if (node.options){
var no = node.options, eo = element.options;
for (var j = no.length; j--;) no[j].selected = eo[j].selected;
}
}
var prop = props[element.tagName.toLowerCase()];
if (prop && element[prop]) node[prop] = element[prop];
};
if (contents){
var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
for (var i = ce.length; i--;) clean(ce[i], te[i]);
}
clean(clone, this);
return document.id(clone);
}
Да и в prototype.js:
clone: function(element, deep) {
if (!(element = $(element))) return;
var clone = element.cloneNode(deep);
clone._prototypeUID = void 0;
if (deep) {
var descendants = Element.select(clone, '*'),
i = descendants.length;
while (i--) {
descendants[i]._prototypeUID = void 0;
}
}
return Element.extend(clone);
}
Вывод: Если вам нужна идеальная копия содержимого, создайте ее заново в обход клонирования базируясь на оригинале. Я бы поступил именно так. К сожалению это медленный метод. Ну либо как это делают остальные - копировать аттрибуты.