Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > JavaScript: Общие вопросы > Своя реализация innerText для всех браузеров


Автор: Sardar 24.12.2004, 23:58
Иногда требуется достать текстовое содержимое ноды. В ИЕ и Опере есть не описанное в спецификации от W3C поле innerText через которое можно достать/установить текст из/в ноды(у). В Мозиллоподобных браузерах и просто экзотических такого поля нет. Согласно идее от W3C можно пробежатся по списку нод и самому собрать содержимое, что мы и сделаем:
HTML
<div id="test">This <span style="color:red">is</span>&nbsp;<span style="background-color: #7495f6; color: #0b451b; font-weight: bold">a <a href="#">Test</a></span></div>

Код
/**
* Функция достает текстовое содержимое любой ноды. Текстом будем считать
* текстовые ноды и элементы, которые опрашиваем рекурсивно.
*/
function innerText(node) {
//  return node.innerText; //хорошая вещь в ИЕ
//  return node.innerHTML; //из стадарта W3C, но не совсем то что нужно
 var ret = "";
 for(var i=0; i<node.childNodes.length; i++) {
    switch(node.childNodes[i].nodeType) {
   case 1: ret+=innerText(node.childNodes[i]); break; //если элемент
   case 3: ret+=node.childNodes[i].nodeValue; //если текстовая нода
 }
 }
 return ret;
}
alert(innerText(document.getElementById("test")));


Решение рабочее, можно использовать под любым браузером. Но можно пойти дальше, используя механизм getter/setter Мозиллоподобных можно определить свойства для нод:
Код

/*
* Ниже мы используем особый механизм геттеров/сеттеров берущих свои корни еще
* с нетскейповских времён.
*/
//избавляемся от глючной но поддерживающей innerText Оперы
//бродилка имеет Node, но не имеет Node.prototype - бред... =/
if(typeof(Node)!="undefined"&&typeof(Node.prototype)!="undefined"&&typeof(Node.prototype.__defineGetter__)=="function") {  Node.prototype.__defineGetter__("innerText", function()
 {
    var ret = "";
    for(var i=0; i<this.childNodes.length; i++) {
       switch(this.childNodes[i].nodeType) {
         case 1: ret+=this.childNodes[i].innerText; break; //если элемент
      case 3: ret+=this.childNodes[i].nodeValue; break; //если текст
    }
    } return ret;
 });
 
 Node.prototype.__defineSetter__("innerText", function(val)
 {
//и не пытайтесь использовать removeChild, Мозиллу глючит по чёрному
//уж лучше так... через innerHTML =/
   this.innerHTML=""; //очищяем содержимое
   this.appendChild(document.createTextNode(val));
 });
}

var a=document.getElementById("test");
alert(a.innerText);
a.innerText="Vingrad";

Заметим что кот будет работать хорошо только в Опере, ИЕ и Мозилле, так как первые два проигнорируют конструцию, а Мозилла получит новое свойство в интерфейс нод. Особые экзотические браузеры возможно работать не будут, но это не страшно, т.к. 95% народа мы удовлетворим smile

Автор: mix 30.12.2004, 20:48
В догонку:
в мозилле есть похожее на innerText свойство textContent

Автор: Sardar 30.12.2004, 21:05
mix полезное замечание, в Мозилле есть полный эквивалент innerText в IE - textContent, юзаем также как и в ИЕ.
Похоже что вопрос окончательно исчерпан, в моём коде нет нужды.

Автор: Се ля ви 2.1.2005, 15:35
Цитата(Sardar @ 30.12.2004, 21:05)
Мозилле есть полный эквивалент innerText в IE - textContent

Концептуальный вопрос - а в стандарте W3C это свойство есть?

Тогда изменим патчовый скрипт Sardar`а, что бы делать минимум изменений в коде:
Код
/*
* Ниже мы используем особый механизм геттеров/сеттеров берущих свои корни еще
* с нетскейповских времён.
*/

// Избавляемся от глючной но поддерживающей innerText Оперы - бродилка имеет Node, но не имеет Node.prototype - бред... =/
if ( typeof(Node) != "undefined" &&
    typeof(Node.prototype) != "undefined" &&
    typeof(Node.prototype.__defineGetter__) == "function" ) {
   
    Node.prototype.__defineGetter__(
         "innerText",
         function() { return this.textContent; }
    );
 
    Node.prototype.__defineSetter__(
         "innerText",
         function(val) {
              //И не пытайтесь использовать removeChild, Мозиллу глючит по чёрному, уж лучше так - через innerHTML =/
              this.textContent =""; //очищяем содержимое
              this.appendChild(document.createTextNode(val));
         }
    );
}

var a=document.getElementById("test");
alert(a.innerText);
a.innerText="Vingrad";


P.S. Очень странно, что Mozilla не принимает removeChild - это часть уже старого DOM level 1 - уж его-то она обязана поддерживать. Можешь отловить её ошибку через try..catch и прочитать сообщение?

Автор: Sardar 2.1.2005, 16:45
Се ля ви устанавливать текст через textContent тоже можно, так что можем ипользовать this.textContent=val;.

В стандартах этого свойства нет, т.к. оно составное, т.е. рекурсивно должно пробегать по всем нодам-потомкам. Для скриптов это очень актуально, т.к. много писать не хочется. Для какого нибудь АПИ для XML это не особо нужно, ибо с базовых возможностей можешь намутить что нибудь своё.

Цитата
P.S. Очень странно, что Mozilla не принимает removeChild - это часть уже старого DOM level 1 - уж его-то она обязана поддерживать. Можешь отловить её ошибку через try..catch и прочитать сообщение?

Нет, removeChild работает, просот в этом контексте почему то Мозилла проглючила... smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)