Существуют определенные преимущества централизованной, однотипной организации небольших JS-разработок и заплаток в одном файле:
В настоящей статье предлагается к использованию простой, легковесный метод организации на основе библиотеки libhack.js.
Библиотека libhack.js предоставляет функцию execFunctionsByTable()
, принимающую в качестве аргумента объект следующего формата:
{ 'где запускать':[ function(){ что выполнять } ], 'где запускать2':[ function(){ что выполнять2 } ] }
Например:
{ '.*':[ function(){ allPageAction(); allPageAction2(); } ], '[/]sitename.ru[/][\w]*$':[ function(){ mainPageAction(); mainPageAction2(); }, function(){ mainPageAction3(); } ], '[/]blogs[/]':[ function(){ blogsAction(); blogsAction2(); } ] }
где строки '.*'
, '[/]sitename.ru[/][\w]*$'
и '[/]blogs[/]'
содержат регулярные выражения, при совпадении которых с текущим адресом страницы (а именно с document.URL
) срабатывают соответствующие блоки кода. В приведенном примере настроены три блока кода: один срабатывает на всех страницах (и содержит allPageAction();...
), другой — только на главной (содержит mainPageAction();...
), третий — только на страницах модуля blogs (содержит blogsAction();...
).
Внутри каждого блока функции выполняются в том порядке, в котором они приведены в файле. Функции выполняются сразу после загрузки HTML-страницы до полной загрузки дополнительных материалов (CSS, картинок, шрифтов и т.п.). Каждое регулярное выражение проверяется на соответствие текущему адресу, и соответствующий блок кода выполняется или не выполняется.
Пары 'выражение':[блок кода]
и отдельные функции разделяются запятыми. После последнего блока кода/функции запятая не ставится.
Содержимое каждой анонимной функции function(){}
выполняется в отдельном try..catch
и ошибки в нем (кроме синтаксических) не влияют на выполнение других таких функций. Обнаруженные ошибки вместе с номером строки выводятся в консоль функцией debugLog()
внутри библиотеки если установлена глобальная переменная DEBUG
. Функция debugLog()
также доступна пользователю.
Для использования библиотеки libhack.js необходимо включить ее в шаблоны страниц после основных скриптов Ксевиана:
Библиотека libhack.js зависит от библиотеки prototype.js и должна загружаться после нее.
С целью упрощения понимания мелких скриптов другими разработчиками предлагается следующая организация кода с примерами использования некоторых функций libhack.js:
/* * Локальный JS, версия 0.1 * Зависимости: prototype.js, libhack.js */ (function(){ /* Список действий */ var toDo = { // На всех страницах '.*':[ // настроить вывод ошибок function(){ DEBUG = 1; noConsoleNoErrors(); interceptErrors('behaviour.js'); }, // определить возможности браузера function(){ detectFeatures(); }, // привязать действие к кнопкам Назад function(){ var elements = $$('.backButton'); elements.each(function(e,i){ e.onclick = function(){ history.back(); return false; }; }); } ], // На страницах нескольких модулей '[/](products|articles|blogs)[/]':[ // заменить по таблице function(){ var replacementTable = [ {target:'.listing > h1', search:'замени_меня', replacement:'замени_мной'}, {target:'.message', search:'удали_меня|и_меня', replacement:''}, {target:'.more', search:'^0 Ответов', replacement:'Ответить'}, {target:'.more', search:'(([^1]|^)1) Ответов', replacement:'$1 Ответ'}, {target:'.more', search:'(([^1]|^)[234]) Ответов', replacement:'$1 Ответа'} ]; replaceDomByTable(replacementTable); } ], // На страницах одного модуля '[/]forum[/]':[ // настроить JS-табы без AJAX с поддержкой хэш-ссылок function(){ handleStaticTabs(); } ], // В личном кабинете '[/]profile[/]':[ // добавить возможность автоматической AJAX-навигации в личный кабинет // например /profile/?add=products или /profile/?list=products function(){ var navTable = { add:'/index.php?app=front&xml=content&structure=items&show=form&mod=', list:'index.php?app=front&xml=content&structure=items&show=listing&mod=' } postNavigation(navTable); } ], // На конечных страницах нескольких модулей '[/](news|companies)[/].+[/]':[ // для пар типа
// удалить все dt, после которых стоят пустые dd function(){ var elements = $$('dd:empty'); elements.each(function(e,i){ e.previous('dt').remove(); e.remove(); }); }, // сделать что-то function(){ doSomething(); deleteSomething(); }, // (1) настроить переключение видимости по щелчку function(){ var elements = $$('a.toggle'); elements.each(function(e,i){ e.observe('click', (function(E){ // (2) собственно полезная функция return function() { E.next('.togglable').toggle(); } })(e)); }); } ] } /* Локальные функции */ // сделать что-то function doSomething(){ console.log('something done'); } // удалить что-то function deleteSomething(){ var element = $$('article ul')[0]; element.remove(); console.log('something removed'); } /* Начало работы */ execFunctionsByTable(toDo); })();
(function(){})();
отделяет ее пространство имен переменных и функций от глобального, минимизируя возможные проблемы в этой области (т.н. модульный паттерн). Объявленные внутри этой конструкции функции недоступны вне скрипта.element
(elem
если уже занято; e
, E
локально), elements
(elems
), container
, form
, box
, url
и т.п.(1)
в листинге] позволяет ставить в соответствие одному элементу произвольное количество событий одного типа и делать это для любого количества элементов. При этом создается столько копий возвращаемой функции [(2)
в листинге], сколько найдено элементов на странице, и для каждого переменные внутри функции задаются в момент привязки независимо. В результате копии функций элементов не зависят друг от друга и от действий других скриптов.Любые часто используемые функции предлагается оформлять в достаточно общей форме и добавлять в библиотеку libhack.js.