Xpoint
   [напомнить пароль]

Полезные функции

Оглавление

Работа со строками

escape(), совместимый с русскими буквами

К сожалению, стандартное поведение функции escape() при работе с русскими буквами не соответствует тому, что обычно требуется для веб-приложений. Вызов escape('тест') вместо %F2%E5%F1%F2 (закодированные символы в кодировке windows-1251) возвращает бесполезную строку %u0442%u0435%u0441%u0442. Это можно поправить, если перед вызовом escape() перевести нужные символы из Unicode в windows-1251. Следующий код заменяет стандартную функцию и переводит буквы русского алфавита из Unicode в windows-1251 (таблицу перевода можно менять, как угодно):

// Инициализируем таблицу перевода
var trans = [];
for (var i = 0x410; i <= 0x44F; i++)
  trans[i] = i - 0x350; // А-Яа-я
trans[0x401] = 0xA8;    // Ё
trans[0x451] = 0xB8;    // ё

// Сохраняем стандартную функцию escape()
var escapeOrig = window.escape;

// Переопределяем функцию escape()
window.escape = function(str)
{
  var ret = [];
  // Составляем массив кодов символов, попутно переводим кириллицу
  for (var i = 0; i < str.length; i++)
  {
    var n = str.charCodeAt(i);
    if (typeof trans[n] != 'undefined')
      n = trans[n];
    if (n <= 0xFF)
      ret.push(n);
  }
  return escapeOrig(String.fromCharCode.apply(null, ret));
}

Требуется IE 5.5+, поскольку более старые версии не поддерживают Function.apply() и Array.push() (это можно обойти, но ухудшится эффективность кода). С другими браузерами проблем нет. Заметим, что любые непереведенные символы с кодом более 255 удаляются.

Более корректно было бы кодировать данные в UTF-8 с помощью функции encodeURIComponent(). Но в этом случае сервер должен либо поддерживать Unicode, либо перекодировать получаемые данные опять же в кодировку windows-1251.

В привилегированных скриптах для Gecko-браузеров проблему можно решить более элегантно:

window.escape = function(str)
{
    var converter = Components.classes['@mozilla.org/intl/texttosuburi;1']
                              .createInstance(Components.interfaces.nsITextToSubURI);

    return converter.ConvertAndEscape('windows-1251', str);
}

Интерфейс nsITextToSubURI используется и самим браузером для кодирования данных формуляров, когда их нужно отправить на сервер.

Перекодировка из Windows-1251 и КОИ-8

Хотя внутреннее представление строк в JS всегда юникодное, иногда во внешних данных скрипта могут появиться строки в другой кодировке (например, при анализе document.referer на предмет поисковых слов). Данная функция позволяет корректно (с сохранением, например, символов украинского алфавита) преобразовать строку из Windows-1251 в юникод.

function win2unicode(str) {
   var charmap   = unescape(
      "%u0402%u0403%u201A%u0453%u201E%u2026%u2020%u2021%u20AC%u2030%u0409%u2039%u040A%u040C%u040B%u040F"+
      "%u0452%u2018%u2019%u201C%u201D%u2022%u2013%u2014%u0000%u2122%u0459%u203A%u045A%u045C%u045B%u045F"+
      "%u00A0%u040E%u045E%u0408%u00A4%u0490%u00A6%u00A7%u0401%u00A9%u0404%u00AB%u00AC%u00AD%u00AE%u0407"+
      "%u00B0%u00B1%u0406%u0456%u0491%u00B5%u00B6%u00B7%u0451%u2116%u0454%u00BB%u0458%u0405%u0455%u0457")
   var code2char = function(code) {
               if(code >= 0xC0 && code <= 0xFF) return String.fromCharCode(code - 0xC0 + 0x0410)
               if(code >= 0x80 && code <= 0xBF) return charmap.charAt(code - 0x80)
               return String.fromCharCode(code)
            }
   var res = ""
   for(var i = 0; i < str.length; i++) res = res + code2char(str.charCodeAt(i))
   return res
}

Аналогичная функция для КОИ-8:

function koi2unicode(str) {
   var charmap   = unescape(
      "%u2500%u2502%u250C%u2510%u2514%u2518%u251C%u2524%u252C%u2534%u253C%u2580%u2584%u2588%u258C%u2590"+
      "%u2591%u2592%u2593%u2320%u25A0%u2219%u221A%u2248%u2264%u2265%u00A0%u2321%u00B0%u00B2%u00B7%u00F7"+
      "%u2550%u2551%u2552%u0451%u2553%u2554%u2555%u2556%u2557%u2558%u2559%u255A%u255B%u255C%u255D%u255E"+
      "%u255F%u2560%u2561%u0401%u2562%u2563%u2564%u2565%u2566%u2567%u2568%u2569%u256A%u256B%u256C%u00A9"+
      "%u044E%u0430%u0431%u0446%u0434%u0435%u0444%u0433%u0445%u0438%u0439%u043A%u043B%u043C%u043D%u043E"+
      "%u043F%u044F%u0440%u0441%u0442%u0443%u0436%u0432%u044C%u044B%u0437%u0448%u044D%u0449%u0447%u044A"+
      "%u042E%u0410%u0411%u0426%u0414%u0415%u0424%u0413%u0425%u0418%u0419%u041A%u041B%u041C%u041D%u041E"+
      "%u041F%u042F%u0420%u0421%u0422%u0423%u0416%u0412%u042C%u042B%u0417%u0428%u042D%u0429%u0427%u042A")
   var code2char = function(code) {
               if(code >= 0x80 && code <= 0xFF) return charmap.charAt(code - 0x80)
               return String.fromCharCode(code)
            }
   var res = ""
   for(var i = 0; i < str.length; i++) res = res + code2char(str.charCodeAt(i))
   return res
}

Удаление пробелов

Следующий код добавляет в класс String три метода для удаления пробелов. ltrim() обрезает пробелы, переводы строк и табуляцию с начала строки, rtrim() с конца, а trim() с обеих сторон.

if ('undefined' == typeof String.prototype.ltrim) {
  String.prototype.ltrim = function() {
    return this.replace(/^\s+/, '');
  }
}

if ('undefined' == typeof String.prototype.rtrim) {
  String.prototype.rtrim = function() {
    return this.replace(/\s+$/, '');
  }
}

if ('undefined' == typeof String.prototype.trim) {
  String.prototype.trim = function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  }
}

Пример использования:

var str = ' \n\t\r test \n\t\r ';
alert('!' + str.ltrim() + '!');
alert('!' + str.rtrim() + '!');
alert('!' + str.trim() + '!');

Обработка событий

Назначение нескольких обработчиков для одного события

Часто нужно устанавливать обработчик для какого-то события, причём не хочется проверять, не установила ли этот обработчик уже какая-нибудь другая часть программы. Стандарт DOM определяет метод addEventListener(), с помощью которого можно назначать любое количество обработчиков для одного события, и они не будут мешать друг другу. Этот метод поддерживают Gecko-браузеры, Safari и последние версии Opera. Internet Explorer, как обычно, реализует собственное решение: attachEvent(). Следует обратить внимание на то, что IE считает приставку on частью названия события, в то время как в DOM события называются load, click и т.п.

Следующие функции позволяют назначать несколько обработчиков для одного события одинаково в любом браузере.

function addHandler(object, event, handler)
{
  if (typeof object.addEventListener != 'undefined')
    object.addEventListener(event, handler, false);
  else if (typeof object.attachEvent != 'undefined')
    object.attachEvent('on' + event, handler);
  else
    throw "Incompatible browser";
}

function removeHandler(object, event, handler)
{
  if (typeof object.removeEventListener != 'undefined')
    object.removeEventListener(event, handler, false);
  else if (typeof object.detachEvent != 'undefined')
    object.detachEvent('on' + event, handler);
  else
    throw "Incompatible browser";
}

Функции addHandler() и removeHandler() вызывают тот метод для назначения обработчиков событий, который поддерживается браузером. В маловероятном случае, что браузер не поддерживает ни одного метода (таких браузеров уже практически не осталось), функции создают исключение.

Пример использования:

<div id="test" onclick="alert(1)">Click me!</div>

<script type="text/javascript">
function handler2(e)
{
  alert(2);
}
function handler3(e)
{
  alert(3);
}

addHandler(document.getElementById('test'), 'click', handler2);
addHandler(document.getElementById('test'), 'click', handler3);
removeHandler(document.getElementById('test'), 'click', handler2);
</script>

Здесь при клике на блоке все браузеры сначала покажут 1, а потом 3. Второй обработчик не сработает, его удалили из списка.

Если обработчик хочет предотвратить стандартную обработку события (к примеру, переход по ссылке при клике), не всегда достаточно вернуть false. Это будет работать правильно в Internet Explorer, но возвратное значение обработчиков, назначенных через addEventListener(), игнорируется. Для таких обработчиков в DOM существует метод preventDefault() объекта Event. Итого получаем:

function handler(e)
{
  e = e || window.event;

  // здесь что-то делаем

  if (typeof e.preventDefault != 'undefined')
    e.preventDefault();
  return false;
}

Установка обработчика события onload для страницы

В разных браузерах под «страницей» понимаются разные вещи — в некоторых обработчик onload следует привязывать к объекту window, в некоторых — к объекту document, да ещё и способы привязки могут отличаться (см. выше). Для облегчения этой задачи предлагается следующая функция:

function setGlobalOnLoad(f) {
   var root = window.addEventListener || window.attachEvent ? window : document.addEventListener ? document : null
   if (root){
      if(root.addEventListener) root.addEventListener("load", f, false)
      else if(root.attachEvent) root.attachEvent("onload", f)
   } else {
      if(typeof window.onload == 'function') {
         var existing = window.onload
         window.onload = function() {
            existing()
            f()
         }
      } else {
         window.onload = f
      }
   }
}

Фильтр ввода для текстового поля

Иногда требуется ограничить содержимое текстового поля лишь определенными символами. Следующий код позволит вводить в текстовое поле только символы латинского алфавита, цифры и знак подчеркивания:

<input type="text" onkeypress="return testKey(event)">

<script type="text/javascript">
function testKey(e)
{
  // Make sure to use event.charCode if available
  var key = (typeof e.charCode == 'undefined' ? e.keyCode : e.charCode);

  // Ignore special keys
  if (e.ctrlKey || e.altKey || key < 32)
    return true;

  key = String.fromCharCode(key);
  return /\w/.test(key);
}
</script>

Регулярное выражение для проверки символа разумеется можно и изменить. К примеру регулярное выражение /[\d\.]/ позволит только цифры и точку.

Заметим, что пользователь все еще может скопировать в текстовое поле строку, которая не удовлетворяет условиям. Поэтому следует дополнительно поставить проверку корректности содержимого поля на событие change самого поля или событие submit его формы.

Работа с CSS-классами

Перенесено: Изменение стилей элементов (Изменение класса элемента)

Работа с объектами и функциями

Задание параметра “this” для callback-функций

При динамическом назначении обработчиков событий (в DHTML или в асинхронных вызовах типа AJAX), очень часто требуется каким-то образом передать в callback-функцию дополнительные параметры. Как минимум, часто бывает желательно, чтобы внутри функции параметр this имел определённое значение. Каждый, кто пытался использовать this в таких функциях, знает, что он может указывать куда угодно, но только не на тот объект, что нужен. Эта проблема может быть решена следующим образом:

Function.prototype.bind = function(object) {
    var method = this
    return function() {
        return method.apply(object, arguments) 
    }
}

Используется этот метод например так:

addHandler(link, "click", function() { alert(this.href) }.bind(link))

В этом примере this внутри функции-обработчика будет указывать на link. Точно так же можно передать в callback указатель на любой другой нужный объект.

Работа с DOM-элементами

Определение координат элемента на странице

function getBounds(element)
{
  var left = element.offsetLeft;
  var top = element.offsetTop;
  for (var parent = element.offsetParent; parent; parent = parent.offsetParent)
  {
    left += parent.offsetLeft - parent.scrollLeft;
    top += parent.offsetTop - parent.scrollTop
  }
  return {left: left, top: top, width: element.offsetWidth, height: element.offsetHeight};
}

Эта функция возвращает объект со свойствами left, top, width и height, определяющими координаты элемента относительно верхнего угла страницы и его размер. Пример использования:

var element = document.getElementById('myElement');
var bounds = getBounds(element);
alert('Координаты элемента: ' +
      '(' + bounds.left + ',' + bounds.top + ') x ' +
      '(' + bounds.width + ',' + bounds.height + ')');

Удаление всех вложенных элементов

function cleanNode(dest)
{
  while (dest.firstChild)
    dest.removeChild(dest.firstChild);
}

Изменения типа (nodeName) элементов

Возможно, у Вас возникнет задача преобразовать одни элементы в другие "на лету". Для этого можно воспользоваться следующей функцией:

function element2span(obj) {
   var span = document.createElement('span');
   while (obj.firstChild) span.appendChild(obj.firstChild);
   obj.parentNode.replaceChild(span, obj);
}

Данная функция преобразует элемент, переданный в качестве параметра, в <span>, сохраняя в нем всех потомков.
Если нужно, копируйте значения атрибутов самостоятельно, например: span.className = obj.className

Комментарии

2005-04-02 23:42:59 [обр] Владимир Палант[досье]
Вызов thisFunc() равнозначен arguments.callee. Эта функция действительно представляет собой какую-то ценность?
спустя 17 дней [обр] Давид Мзареулян[досье]
«escape(), совместимый с русскими буквами» — считаю это очень вредным подходом. Гораздо правильнее и надёжнее нацчить сервер обрабатывать %uXXXX.
спустя 2 дня [обр] Владимир Палант[досье]
Apache выдает Bad Request на %uXXXX в имени файла, так что такое решение не универсально. Вообще ИМХО ни одна стандартная процедура разбора запроса на сервере это не понимает, поскольку это попросту неправильное кодирование в смысле стандарта HTTP. Кроме того, я использую вышеприведенный код для обращения к Google, который не умеет обрабатывать %uXXXX и никогда этому не научится, по понятным причинам. Если бы стандартный escape() выдавал UTF-8 — я бы согласился с вами на все 100%. Но не так.
спустя 1 минуту [обр] Владимир Палант[досье]
PS: Написать escape(), который кодировал бы данные в UTF-8 было бы лучше, это точно. Может как-нибудь будет время, чтобы это сделать.
спустя 4 дня [обр] Давид Мзареулян[досье]

Ну, правильное оно или нет, а во всех браузерах escape() работает совершенно одинаково. Предложенное же решение крайне неустойчиво («любые непереведенные символы с кодом более 255 по прежнему кодируются как %uNNNN» — а если у меня умляуты в тексте?).

escapeUTF8(), действительно, был бы более осмысленным.

спустя 1 час 35 минут [обр] Владимир Палант[досье]
Уже написал escapeUTF8(), когда понял, что эта функция делает то же самое, что и encodeURIComponent(), причём работает в тех же браузерах.
спустя 2 часа 36 минут [обр] Давид Мзареулян[досье]
А в каких браузерах не работает encodeURIComponent? Я так понимаю, и IE и Mozilla его умеют?
спустя 17 часов [обр] Владимир Палант[досье]
Из браузеров с существенной долей рынка проблема только с IE 5.0, наверное. Мой код в нём тоже не работает, не хотелось извращаться.
спустя 4 месяца 2 дня [обр] Дворнов Роман[досье]

Приятно наблюдать обновления в данной статье. Хотя мне кажется, что это должно быть разделом, или что-то вроде (что собственно говоря светит - вопрос времени :] ).
Хочу добавить пару замечаний/ремарок.
Функция из "Удаление пробелов", а именно trim(), правильней было бы записать из соображений re-use:

return this.ltrim().rtrim();

Понравилась ваша идея по поводу обертки для className. Была идея написать что-то подобное, но ваш подход показался самым удачным. Единственное что хромает, так это реализация методов. Понимания повторного использования кода не чувствуется, в итоге неуместные повторения. Осмелюсь предложить свой вариант (который сейчас активно использую) на рассмотрение, собственно всё отличие в реализации и паре методов. Так как нет желания выкладывать портянки здесь (и тем самым нарываться на уместный гнев модераторов), выложу в отдельной теме (или скажите куда положить), если это актуально.. актуально? :]

спустя 4 дня [обр] Иван Шумков[досье]
Помойму давно уже можно так:
Object.prototype.addEvent = function(event, handler) {
   if (typeof this.addEventListener != 'undefined')
      this.addEventListener(event, handler, false);
   else if (typeof this.attachEvent != 'undefined')
      this.attachEvent('on' + event, handler);
}

Object.prototype.remEvent = function(event, handler) {
   if (typeof this.removeEventListener != 'undefined')
      this.removeEventListener(event, handler, false);
   else if (typeof this.detachEvent != 'undefined')
      this.detachEvent('on' + event, handler);
}
спустя 28 минут [обр] Владимир Палант[досье]
В IE HTML-элементы не считаются объектами, поэтому Object.prototype на них никак не влияет. Кроме того, Opera поддерживает addEventListener только с версии 7.20, а версия 7.0 ещё играла роль, когда писался этот код.
спустя 57 минут [обр] Владимир Палант[досье]
PS: В браузерах, которые поддерживают наследование для HTML-элементов, можно использовать HTMLElement.prototype.
спустя 3 месяца 19 дней [обр] Rion[досье]

исправьте пожалуйста

function cleanNode(dest)
{
  while (var child = dest.firstChild)
    dest.removeChild(child);
}

на

function cleanNode(dest)
{
  var child;
  while (child = dest.firstChild)
    dest.removeChild(child);
}

а то FF ошибки выдает

спустя 27 дней [обр] TroT[досье]

ладна. падилюсь сваими функицими

RANDOM

//   Число
function rand(first, last) {
   var min = last && first || 0,
      max = last || first || 1
   return min + Math.round(Math.random()*(max - min))
}
//   Элемент массива
Array.prototype.rand = function(first, last) {
   return this[rand(last && first || 0, last || first || this.length - 1)]
}

//   Примеры
arr = ['строка 1', 'строка 2', 'строка 3']
document.write(
   'случайный бит (0 или 1):   <b>' + rand()      + '</b><br>' +
   'случайное число от 0 до 3:   <b>' + rand(3)   + '</b><br>' +
   'случайное число от 2 до 3:   <b>' + rand(2,3)   + '</b><br>' +
   'случайная фраза:         <b>' + arr.rand() + '</b>'
)
спустя 4 минуты [обр] TroT[досье]
ROLLOVER
function addRollover(obj, url) {
   (new Image).src = url
   obj.onmouseover = function () {
      var lastSrc = this.src
      this.src = url
      this.onmouseout = function() { this.src = lastSrc }
   }
}
<img src="img1.gif" rollover="img2.gif">
<script>
allImgs = document.getElementsByTagName('img')
for(i=allImgs.length-1; i>=0; i--) {
   value = allImgs[i].attributes.rollover ? allImgs[i].attributes.rollover.value : allImgs[i].rollover || 0
   if (value) addRollover(allImgs[i], value)
}
</script>
спустя 2 минуты [обр] TroT[досье]
писать исчо? или я это так: "сам с сабой адной рукой"?
спустя 42 минуты [обр] Владимир Палант[досье]
Не надо. Можете создать страницу "Бесполезные функции", если хотите.
спустя 4 дня [обр] Алексей В. Иванов[досье]
TroT[досье] они не только бесполезные, но и кривые.
Нужно объяснять, почему запись min + Math.round(Math.random()*(max - min)) ошибочна?
спустя 22 дня [обр] Ferra[досье]
Если не сложно, объясните, плиз. Ведь ее полИнета юзает...
спустя 18 часов [обр] Владимир Палант[досье]

Надеюсь, что "полИнета юзает" все-таки не это, а min + Math.random()*(max - min). Результатом будет дробное число из интервала [min,max[. И распределение тогда равномерное.

А вот Math.round(), видимо, должен гарантировать, что число получится целое — но при этом распределение искажается. Если взять min=0 и max=4, то получим 12.5% вероятности, что выпадет 0, те же 12.5% для 4, и 25% для всех чисел в промежутке (посчитайте, какие интервалы результата Math.random() выдают какие результаты). А правильно случайное целое число в интервале [min,max] считается так: min + parseInt(Math.random()*(max - min + 1)). Без округлений, с откидыванием дробной части.

спустя 2 дня 14 часов [обр] Алексей В. Иванов[досье]
Я бы вместо parseInt использовал Math.floor
спустя 8 минут [обр] Владимир Палант[досье]
Или так, это уже не принципиально.
спустя 3 месяца 29 дней [обр] AKS[досье]

Если позволите, то я хотел бы оставить парочку замечаний по-поводу полезных функций.

  1. Касательно раздела "Работа с CSS-классами" - указан не совсем удачный пример использования.
CssClasses(div).add('someClass')
CssClasses(div).remove('someClass')
CssClasses(div).flip('someClass')

При каждом вызове CssClasses(div) будет создан новый экземпляр объекта CssClassesHandler, а в этом, мягко говоря, нет никакой необходимости.

  1. В теме "Задание параметра “this” для callback-функций" создается расширение для функций bind, но пример использования показывает, что в нем нет никакой практической пользы:
addHandler(link, "click", function() { alert(this.href) }.bind(link))

Что мешает напрямую передать объект link в обработчик, ведь, используя анонимную функцию, это сделать очень просто, не так ли?

addHandler(link, "click", function() { alert(link.href) })
спустя 15 дней [обр] Роман Рахман[досье]

Очень тонко обойден глюк с назначением нескольких обработчиков одного события

addHandler(document.getElementById('test'), 'click', handler2);
addHandler(document.getElementById('test'), 'click', handler3);
removeHandler(document.getElementById('test'), 'click', handler2);
Здесь при клике на блоке все браузеры сначала покажут 1, а потом 3. Второй обработчик не сработает, его удалили из списка.

А теперь просто не удалять обработчик handler2. Что имеем:
Gecko (opera не смотрел) - 1, 2, 3
IE (6 по крайней мере) - 1, 3, 2

Дело в очередности FIFO для первого и LIFO для второго.

спустя 1 день 1 час [обр] Владимир Палант[досье]
Простите, глюк? Насколько я помню, очередность вызова обработчиков не определена, и рассчитывать на нее не стоит. Но даже если DOM и предписывает определенный порядок (лень сейчас проверять) — у IE собственный "стандарт", его это не касается. Так где же глюк?
спустя 2 дня 12 часов [обр] Роман Рахман[досье]
ну глюк-не-глюк, мелочь а неприятно. имхо любое разночтение в исполнении кода, какое здесь имеет место быть, заслуживает отметки в базе знаний. многим это разночтение в order of events мешает
спустя 15 дней [обр] Ярослав Федин[досье]
function getBounds(element)
{
  var left = element.offsetLeft;
  var top = element.offsetTop;
  for (var parent = element.offsetParent; parent; parent = parent.offsetParent)
  {
    left += parent.offsetLeft;
    top += parent.offsetTop;
  }
  return {left: left, top: top, width: element.offsetWidth, height: element.offsetHeight};
}

-->

function getBounds(element){
  var e = element;
  var left, top;
  do {
    left += e.offsetLeft || 0;
    top += e.offsetTop || 0;
  } while (e = e.offsetParent)
  return {left: left, top: top, width: element.offsetWidth, height: element.offsetHeight};
}

Читать легче, мне кажется, цикл do while чем for.

спустя 1 месяц 11 дней [обр] Дворнов Роман[досье]
Функцию getBounds вообще стоит выбросить на помойку (уж простите за грубость). Для точного и правильного опередения top/left элемента написанный код не годится. Он годится только для простых ситуаций. Добавьте margin, padding, border, overflow, position для некоторых родителей element'а, поскрольте, и увидите что ваша функция, мягко говоря, врет. Чтобы считать правильно координаты я в свое время потратил изрядное количество времени, и в итоге получил честное опеределение координат для IE (5-7), FireFox 1.0.7, Opera (8.5-9) - то есть то, что было "под рукой". Не указываю FF1.5, потому что что-то накрутили в ней и в ряде моих тестов FF1.5 почему-то врет 1-2 пиксела :(
У меня получилась "портянка" - зато считает правильно. Поверьте, в пару строк кода задача не решается :(
ЗЫ кто не верит - могу дать свои тесты.
спустя 9 часов [обр] Владимир Палант[досье]
Дворнов Роман[досье]
В Firefox 1.5 будет врать не на 1-2 пиксела — он совсем по другому работает с overflow, причем это баг, насколько я понял. Я тоже уже писал "точные" функции, монстры получаются. Данная функция предназначена как раз для простых случаев, которых — 99%.
спустя 20 дней [обр] skynet80[досье]
По поводу отправки русских слов и колдовства с escape.
Я поступаю проще.
При выводе создаю пустой див в котором в ид передаю русские слова с которыми буду оперировать.
<script type="text/javascript">
function getAttr(grp,n) {
   var rus = document.getElementsByName(grp);
   var out = new Array();
   ii=0;
    for(var i = 0 ; i < rus.length; i++) {
             out[ii] = rus[i].id.substring(n,rus[i].id.length);
             ii++;
       }
    }
    return out.toString();
}
</script>
<span onClick="ajax_send(getAttr('vasya_was',5))">Здесь был Вася Пупкин</span>
<?php
print '<div name="vasya_was" id="vasya'.urlencode('Здесь был Вася Пупкин').'"></div>';
?>
спустя 3 месяца 23 дня [обр] Голубчик Алексей[досье]
последние функции неэффективные если дочерних элементов много...
вот так будет лучше думается мне:
/**
 * Функция_удаляющая_все_дочерние_узлы_у_объекта. Хотя убей непаму накой она нужна
 * @param {HTMLElement} n - объект, в_котором_удаляем_все_дочерние_узлы.
 */
function cleanNode(n) {
   if (typeof n.innerHTML != 'undefined') {
      n.innerHTML = '';
      return
   }
   var r = document.createRange(); //создаем объект диапазона 
   r.selectNodeContents(n); //устанавливаем границы диапазона между содержиммым узла, 
   //в котором будем все далять
   r.deleteContents(); //удаляем все содержимое в диапазоне 
}

/**
 * Эмулятор_removeNode_метода_IE_в_других_браузерах.
 * @param {Boolean} b - если=true удаляет_все, 
 * иначе_удаляет_только_сам_объект_и_
 * дочерние_узлы_займут_его_место.
 */
if ( typeof HTMLElement != "undefined" && typeof HTMLElement.prototype.removeNode == "undefined") {
   HTMLElement.prototype.removeNode = function (b) {
      if (b) {
         return this.parentNode.removeChild(this)
      }
      var f, r = document.createRange();
      r.selectNodeContents(this);
      f = r.extractContents();
      return this.parentNode.replaceChild(f, this)
   }
}
/**
 * Функция_преобразует_заданный_элемент_в_SPAN, сохраняя_все_дочерние_узлы.
 * @param {HTMLElement} n - елемент, который_будем_менять_на_другой, оставляя_его_дочерние_узлы.
 */
function element2span(n) {
   var span = document.createElement('span');
   if (n.applyElement) {
      n.applyElement(span) //делаем объект span родителем, переданному элементу 
   } else {
      n.parentNode.insertBefore(span,n); //вставляем span перед элементом 
      span.appendChild(n) //перемещаем элемент внутрь span-а 
   }
   //удаляем элемент, оставляя его дочерние узлы 
   n.removeNode(false);
}
спустя 1 месяц 23 дня [обр] zwet[досье]
Дворнов Роман[досье], если вас не затруднит, выложите, пожалуйста, ваши тестовые странички и "портянку" getBounds, ежели, конечно, последняя не какая-нибудь секретная штука. Буду безмерно благодарен.
спустя 23 дня [обр] Алексей В. Иванов[досье]
Дворнов Роман[досье] попробуйте на своих тестах исправленную функцию.
спустя 56 минут [обр] Владимир Палант[досье]
Алексей, я не думаю, что эту функцию можно так просто исправить. Когда дело доходит то overflow:scroll, то даже разные версии Gecko ведут себя совершенно по разному — о разных браузерах я вообще молчу. Поэтому лучше оставить исходный код с пометкой, что он будет работать только в простых ситуациях. А со сложными придется ждать нормального общепризнанного стандарта, который скажет, как offsetLeft/offsetTop должен работать.
спустя 23 дня [обр] Алексей В. Иванов[досье]
Думаю, мы должны ориентироваться на новые браузеры, если не хотим усложнять код поддержкой старых.
Powered by POEM™ Engine Copyright © 2002-2005