Недавно, в моей практике, случилось мне писать небольшой сайтик... Писал я его на ASP.NET, но это не важно... т.к. проблемы начались, когда дело дошло до JavaScript...
Перво наперво, пришлось долго искать описание объектной модели документа, благо в MSDN она описана... Ух ты, как хорошо все написано... было подумал я... и быстренько набросал метод (еще и при дополнительной помощи моего знакомого), суть которого заключалась в следующем: есть табличка, в этой табличке есть строчки, в каждой строчке есть несколько столбцов, в одном из которых есть поле ввода textarea, а в другом есть checkbox... А надо сделать следующее: если в textarea набрали текст длинее 5 символов, то соответствующая строчка начинает подсвечиваться желтеньким цветом, а на checkbox ставится галочка, если меньше 5 символом, то подсвечивается другим цветом, и галочка на checkbox снимается...
В итоге получилось, что то вроде:
if (obj.innerText.length < 5)
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'AliceBlue';
obj.parentNode.parentNode.parentNode.
childNodes[2].childNodes[0].childNodes[0].chaecked = false;
}
else
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'LemonChiffon';
obj.parentNode.parentNode.parentNode.
childNodes[2].childNodes[0].childNodes[0].chaecked = true;
}
Где obj - это наш textarea, obj.parentNode.parentNode.parentNode - это наша строчка, ну а obj.parentNode.parentNode.parentNode. childNodes[2].childNodes[0].childNodes[0] - это наш checkbox..., который на самом деле находится просто в span, а до этого еще и во второй колонке. Запускаем, все работает, отлично! Запускаем в Firefox... не работает... На помощь приходит плагин firebug... Ставим, начинаем дебажить... Перво наперво, выясняется, что textarea в firefox java не содержит поля innerText, зато у него есть поле value, которого нет в IE... дык... надо найти что то общее... обращаем внимание на поле textLength, которое сразу же указывает нам на длину текста... есть ли оно в IE? Наверное нам это было уже не интересно, главное, что не value... Переправили, запускаем... работает, но не полностью, цвет меняет, а галочку не ставит... Почему?... дебажим...
obj.parentNode.parentNode.parentNode.childNodes[2] - колонка, так и должно быть... а obj.parentNode.parentNode.parentNode. childNodes[2].childNodes[0] это не span... странно... ага, индексы в firefox почему то другие... и их больше:) Ах, так она еще и переводы строки считает... Подгоняем индексы, что бы проверить - будет ли вообще это работать? Получаем:
obj.parentNode.parentNode.parentNode.
childNodes[3].childNodes[1].childNodes[0]
заместо
obj.parentNode.parentNode.parentNode.
childNodes[2].childNodes[0].childNodes[0]
самое плачевное... что где то индексы совпадают, а где то нет... Но! Русские не сдаются:)
Было решено писать супер пупер мега метод, который в потомках рекурсивно будет искать определенный объект, в нашем случае это input с типом checkbox, благо во всей строчке он такой один (почему именно этот путь? Ну что первое в голову пришло...)
В итоге получаем метод:
function GetCheck(Obj)
{
for (i=0;i < Obj.childNodes.length; i++)
{
if (Obj.childNodes[i].tagName == 'INPUT' &&
Obj.childNodes[i].type == 'checkbox')
return Obj.childNodes[i];
else
{
Res = GetCheck(Obj.childNodes[i]);
if (Res != null)
return Res;
}
}
}
Круто! Запускаем... зациклились... Рекурсия - смотри рекурсия... Почему это функция бегает все время по одним и тем же нодам... нам понять удалось не сразу... по всей видимости сказалось то, что перейти на javascript сразу после кода на C# не так легко... а ведь ошибка крылась в какой то переменой, коей оказалась i... Ну да... локальные, глобальные... в общем, она была одна на все рекурсивные функции... проблема была решена добавлением следующей строчки:
var i = 0;
Круто! Запускаем, работает... галку мы нашли... теперь осталось ее проставить или убрать, в итоге получаем следующий метод:
function TextChange(obj)
{
var SranaGalka;
function GetCheck(Obj)
{
var i = 0;
for (;i < Obj.childNodes.length; i++)
{
if (Obj.childNodes[i].tagName == 'INPUT' &&
Obj.childNodes[i].type == 'checkbox')
return Obj.childNodes[i];
else
{
Res = GetCheck(Obj.childNodes[i]);
if (Res != null)
return Res;
}
}
}
SranaGalka = GetCheck(obj.parentNode.parentNode.parentNode);
if (obj.textLength < 5)
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'AliceBlue';
SranaGalka.checked=false;
}
else
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'LemonChiffon';
SranaGalka.checked=true;
}
}
Который, кстати, работает в Firefox! Запускаем Opera... не работает, даже цвет не меняет... обидно... ладно, отдебажить в опере нечем, переходим к IE - запускаем... цвет меняется, галка ставится... но когда надо снять выделение... цвет не меняется, галка не ставится... неужели код, который в else не работает?? он же такой же... вроде как... дебажим, уже в студии (кстати, отдельная история)... obj.textLength - undefined... а как ни странно, но undefined > 5 равно истине... да... но зато мы знаем, что в IE точно работает obj.innerText.length, который не работает в firefox - как быть? Как, как... танцевать с бубном и придумывать следующую строчку:
Length = obj.textLength==null?
obj.innerText.length : obj.textLength;
и неужели эта строчка определяет, какой у вас браузер, и вызывает соответствующее свойство? Конечно, а вы как думали...
В итоге получаем:
function TextChange(obj)
{
var SranaGalka;
function GetCheck(Obj)
{
var i = 0;
for (;i < Obj.childNodes.length; i++)
{
if (Obj.childNodes[i].tagName == 'INPUT' &&
Obj.childNodes[i].type == 'checkbox')
return Obj.childNodes[i];
else
{
Res = GetCheck(Obj.childNodes[i]);
if (Res != null)
return Res;
}
}
}
SranaGalka = GetCheck(obj.parentNode.parentNode.parentNode);
Length = obj.textLength==null?
obj.innerText.length:obj.textLength;
if (Length < 5)
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'AliceBlue';
SranaGalka.checked=false;
}
else
{
obj.parentNode.parentNode.parentNode.
style.backgroundColor = 'LemonChiffon';
SranaGalka.checked=true;
}
}
Запускаем... IE - работает... Firefox - работает... осталось самое страшное - Opera, ведь в ней мы никак не сможем отдебажить... но... о чудо! и там работает:) По всей видимости, в Opera null не может сравниваться с числом, в связи с чем скрипт просто переставал выполняться.... Ну да ладно, самое главное, что все работает, и на все это ушло всего навсего часа 4 с небольшим... Зато какой супер пупер мега метод то получился, и никакая SranaGalka нам теперь не помеха:) И даже не напоминайте нам про Safari и что то другое;)
P.S. Да, быть может, можно легче... но уже проехали;)
P.S. Да, быть может, можно легче... но уже проехали;)