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

Powered by POEM™ Engine Copyright © 2002-2005