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 не клонируется - что за чертовщина??

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);
  }
 

Вывод: Если вам нужна идеальная копия содержимого, создайте ее заново в обход клонирования базируясь на оригинале. Я бы поступил именно так. К сожалению это медленный метод. Ну либо как это делают остальные - копировать аттрибуты.

Вобщем всем спасибо за помощь, в конце концов сделал как посоветовал "ootync" через картинку))


С JQuery работать вобще не умею