Эксперт
  
Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006
Репутация: нет Всего: 36
|
Здравствуйте! Решил для упрощения жизни при работе с несложными страничками упростить себе жизнь и написал библиотечку. Поиспользовал — понравилось  Дописал комментариев и выложил здесь. Может еще кому понравится  | Код | /** * Работа с обработчиками событий * * @package Events * @version 1.0 * @author Григорьев О.С. aka vasa_c * @copyright © vasa_c, 2007 * @license LGPL (http://www.gnu.org/copyleft/lesser.html) * * ВОЗМОЖНОСТИ ЛИБЫ: * - Унификация для всех браузеров: * - установки/удаления обработчиков (без проверки addEventListener/attachEvent) * - доступа к целевому объекту и объекту event * - отмены действия по умолчанию и дальнейшего распространения * - Более гибкий вызов обработчика (см. ниже) * - Группы обработчиков (см.ниже) * - Централизованное удаление всех обработчиков в конце (для борьбы с утечками памяти) * - Возможность указания объектов, как непосредственно, так и через id * - Обращение к установленным обработчикам по идентификаторам * * Недостатки: * - Браузеры не поддерживающие последние модели событий идут лесом (ошибок не происходит, но обработчики не устанавливаются) * - Не поддерживается погружение событий * - Не поддерживается генерация событий * * * ФОРМАТ ОБРАБОТЧИКОВ * В качестве обработчиков можно передавать: * - function * - string - пропускается через eval() * - массив формата [function, объект, параметры, нестандартный вызов], обязателен только первый параметр * "объект" - объект в контексте которого вызывается функция. * не указан или false - window * true - целевой объект события * можно указывать строку, например "one.two.three", при вызове она будет * резволиться в объект (для тех случаев, когда объекта нет на стадии установки обработчиков) * "параметры" - массив параметров с которыми вызывается обработчик * "нестандартный вызов" - если указан, то обработчик считается нестандартным, не указан - стандартным (см. ниже) * * При "стандартном" вызове в обработчик передаются три параметра - node, event. Если был задан массив "параметры", * то они добавляются начиная с третьего. * node - целевой объект * event - объект Event * * При "нестандартном" эти три параметра не передаются. * Он используется для вызова существующих функций с определенным списком параметров. * Разруливание доступа к элементу и event ложится на плечи самого обработчика. * * * ГРУППЫ ОБРАБОТЧИКОВ * Работа приложения может состоять из набора устойчивых состояний и переходов между ними. * Каждое состояние может характеризоваться набором действующих в нем обработчиков. * При переходе из одного в другое, следует удалить все старые обработчики и установить новые. * В данной либе можно устанавливать обработчики один раз, при этом привязывая их к какой-либо * группе, а потом включать/отключать их синхронно. * Группа идентифицируется именем. Группа по умолчанию - "0". * * ФУНКЦИИ * add - установка обработчика * remove, groupRemove, enable, disable, groupEnable, groupDisable - * удаление, включение/выключение отдельных обработчиков и групп * preventDefault, stopPropagation - отмена дальнейшего распространения и действия по умолчанию * using - вывод в глобальное пространство имен * * * Тестировалось в IE6, FF2, Opera9 */ /** * @var object Events - пространство имен библиотеки */ var Events = new function() {
/********** PUBLIC **********/
/** * Установка обработчика * * @param mixed node - целевой элемент (или его id) * @param string event - имя события (без "on") * @param mixed handler - обработчик (формат описан в шапке файла) * @param string group - имя группы (по умолчанию "0") * @param bool enb - изначальный вкл/выкл обработчика (по умолчанию true) * * @return int - идентификатор обработчика */ this.add = ( function( node, event, handler, group, enb ) {
if ( typeof( node ) != "object" ) { node = document.getElementById( node ); } if ( arguments.length < 5 ) { enb = true; if ( arguments.length < 4 ) { group = "0"; } }
if ( ( typeof( handler ) ) == "object" ) { if ( !handler[ 1 ] ) { handler[ 1 ] = window; } else if ( handler[ 1 ] === true ) { handler[ 1 ] = node; } if ( !handler[ 2 ] ) { handler[ 2 ] = []; } } else if ( typeof( handler ) == "function" ) { handler = [ handler, window, [] ]; } var id = aHandlers.length; aHandlers[ id ] = { "node": node, "event": event, "handler": handler, "group": group, "enb": enb, "h": addE( id ) }; if ( !aGroups[ group ] ) { aGroups[ group ] = { "enb": true, "A": [ id ] }; } else { aGroups[ group ].A[ aGroups[ group ].A.length ] = id; } add( node, event, aHandlers[ id ].h ); return id; } ); // add(). /** * Удаление обработчика * * @param int id - его идентификатор */ this.remove = ( function( id ) { var h = aHandlers[ id ]; if ( !h ) { return false; } remove( h.node, h.event, h.h ); aHandlers[ id ] = false; return true; } ); /** * Включение обработчика * * @param int id - его идентификатор */ this.enable = ( function( id ) { if ( aHandlers[ id ] ) { aHandlers[ id ].enb = true; } return true; } ); /** * Выключение обработчика * * @param int id - его идентификатор */ this.disable = ( function( id ) { if ( aHandlers[ id ] ) { aHandlers[ id ].enb = false; } return true; } ); /** * Удаление группы * * @param string group - ее имя */ this.groupRemove = ( function( name ) { if ( !aGroups[ name ] ) { return false; } var g = aGroups[ name ].A; for ( var i = 0; i < g.length; i++ ) { _this.remove( g[ i ] ); } aGroups[ name ] = false; return true; } ); /** * Включение группы * * @param string group - ее имя */ this.groupEnable = ( function( name ) { if ( aGroups[ name ] ) { aGroups[ name ].enb = true; } return true; } ); /** * Выключение группы * * @param string group - ее имя */ this.groupDisable = ( function( name ) { if ( aGroups[ name ] ) { aGroups[ name ].enb = false; } return true; } ); /** * Вывод функций в глобальную область видимости * * @param string prefix - префикс имен функций (по умолчанию "events"). * * Функции либы выводятся в глобальное пространство имен. * При указании непустого префикса, он добавляется к имени функции, * которое приводится к криволинейной нотации. "add" --> "eventsAdd" */ this.using = ( function( prefix ) { if ( arguments.length == 0 ) { prefix = "events"; } for ( var name in this ) { if ( name == "using" ) { continue; } var pName = prefix.length ? prefix + name.charAt( 0 ).toUpperCase() + name.substr( 1, name.length - 1 ) : name; window[ pName ] = this[ name ]; } } ); // using().
/** * Остановка дальнейшего распространения события. * Вызывается внутри обработчика в виде Events.stopPropagation(). */ this.stopPropagation = ( function() { addE.stopPropagation = true; return true; } ); /** * Отмена действия по умолчанию * Вызывается внутри обработчика в виде Events.preventDefault(). */ this.preventDefault = ( function() { addE.preventDefault = true; return true; } );
/********** PRIVATE **********/
/** * @var array aHandlers - обработчики * @var object aGroups - группы */ var aHandlers = []; var aGroups = {};
/** * Получение настоящего обработчик для устанавливаемого обработчика :) * Возвращает функцию, которая будет установлена в качестве обработчика. * В ней разруливаются признаки вкл/выкл, объекты, отмена распространения и т.п. * и вызывается окончательный обработчик. * * @param int id - идентификатор обработчика * @return function - "настоящий" обработчик */ function addE( id ) { return ( function( e ) {
var h = aHandlers[ id ];
if ( !( ( h ) && ( h.enb ) && ( aGroups[ h.group ] ) && ( aGroups[ h.group ].enb ) ) ) { return; }
if ( typeof( h.handler ) != "object" ) { return eval( h.handler ); } var prm = []; if ( !h.handler[ 3 ] ) { prm[ 0 ] = h.node; e = window.event || e; prm[ 1 ] = e; for ( var i = 0; i < h.handler[ 2 ].length; i++ ) { prm[ i + 2 ] = h.handler[ 2 ][ i ]; } } else prm = h.handler[ 2 ];
var obj = h.handler[ 1 ]; if ( typeof( obj ) != "object" ) { obj = ( function( path ) { path = path.split( "." ); var o = window; for ( var i = 0; i < path.length; i++ ) { if ( !o[ path[ i ] ] ) { return window; } o = o[ path[ i ] ]; } return o; }( obj ) ); }
addE.stopPropagation = false; addE.preventDefault = false; var ret = h.handler[ 0 ].apply( obj, prm );
if ( addE.stopPropagation ) { if ( e.stopPropagation ) { e.stopPropagation(); } else { e.cancelBubble = true; } } if ( addE.preventDefault ) { if ( e.preventDefault ) { e.preventDefault(); } else { return false; } }
return ret; } ) }; // addE().
/** * Унификация установки/удаления обработчиков. */ if ( window.addEventListener ) { var add = ( function( el, event, handler ) { return el.addEventListener( event, handler, false ); } ); var remove = ( function( el, event, handler ) { return el.removeEventListener( event, handler, false ); } ); } else if ( window.attachEvent ) { var add = ( function( el, event, handler ) { return el.attachEvent( "on" + event, handler ); } ); var remove = ( function( el, event, handler ) { return el.detachEvent( "on" + event, handler ); } ); } else { var add = ( function() {} ); var remove = add; }
/** * @var object _this - алиас для this, на случай использования using(). */ var _this = this;
/** * Удаление обработчиков по унлоаду */ add( window, "unload", ( function() { for ( var name in aGroups ) { _this.groupRemove( name ); } return true; } ) );
}(); // Events.
|
Страничка для теста (файл библиотеки - events.js): | Код | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru"> <head profile="http://gmpg.org/xfn/11"> <title>Events.js — тест</title> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="./events.js"></script> </head> <body>
<h1>Events.js — тест</h1>
<h2>Установка обработчиков, включение/выключение групп</h2>
<ul> <li id="lione">Раз</li> <li id="litwo"> Два <ul> <li id="litwoone" style="font-weight:normal;color:black">Два.Один</li> <li id="litwotwo" style="font-weight:normal;color:black">Два.Два</li> </ul> </li> <li id="lithree">Три</li> </ul> <p>Жмите на пункты списка.</p> <table border="0"> <tr> <td>Группа «litest» («Два.Один» и «Три»)</td> <td><input type="checkbox" value="1" onchange="this.checked ? Events.groupEnable( "litest" ) : Events.groupDisable( "litest" );" checked="checked" /></td> <td>— снимите галочку, чтобы отключить</td> </tr> <tr> <td>Группа по умолчанию (все остальные)</td> <td><input type="checkbox" value="1" onchange="this.checked ? Events.groupEnable( "0" ) : Events.groupDisable( "0" );" checked="checked" /></td> <td> </td> </tr> </table> <p>Отменить дальнейшее распространение для «Два.Два»: <input type="checkbox" value="1" id="ilitesttwo" /> — установите галочку и событие не дойдет до пункта «Два». </p> <p><input type="submit" value="Убить группу litest" onclick="if (confirm("Все обработчики группы litest будут удалены навсегда")) {this.style.display="none";Events.groupRemove("litest");}" /></p> <script type="text/javascript"> function litest( node ) { node.style.color = "red"; node.style.fontWeight = "bold"; setTimeout( function() { node.style.color = "black"; node.style.fontWeight = "normal"; }, 1000 ); return true; } function litesttwo( node ) { litest( node ); if ( document.getElementById( "ilitesttwo" ).checked ) { Events.stopPropagation(); } return true; } Events.add( "lione", "click", litest ); Events.add( "litwo", "click", litest ); Events.add( "litwoone", "click", litest, "litest" ); Events.add( "litwotwo", "click", litesttwo ); Events.add( "lithree", "click", litest, "litest" ); </script>
<h2>Назначение обработчиков</h2> <p><a href="#" id="a2func">На эту ссылку обработчик установлен, как простая функция</a></p> <p><a href="#" id="a2stand">Обработчик этой ссылке выполняется в контексте объекта данной ссылки с доп.параметрами 1,2,3</a></p> <p><a href="#" id="a2nstand">Нестандартный обработчик с параметрами 1,2,3, в контексте объекта one.two.three</a></p>
<script type="text/javascript"> function func2() { Events.preventDefault(); var str = "Функция вызвана в контексте "; if ( this == window ) { str += "объекта window"; } else if ( this.tagName ) { str += "DOM-элемента \"" + this.tagName + '"'; } else { str += "пользовательского объекта" + ( this.name ? ( ' "' + this.name + '"' ) : "" ); } str += "\nВ нее переданы аргументы в количестве: " + arguments.length; for ( var i = 0; i < arguments.length; i++ ) { str += "\n" + ( i + 1 ) + ". " + arguments[ i ]; } alert( str ); return true; } Events.add( "a2func", "click", func2 ); Events.add( "a2stand", "click", [ func2, true, [ 1, 2, 3 ] ] ); Events.add( "a2nstand", "click", [ func2, "one.two.three", [ 1, 2, 3 ], true ] ); var one = { "two": { "three": { name: "one.two.three" } } }; </script> <h3 style="font-weight:bold">Обработчик в виде строки для eval():</h3>
<p>Повесить на следующию ссылку пользовательский код: <input type="text" value="alert(1)" id="ia2eval" /> <input type="submit" value="повесить" onclick="a2evalH()" /> (разработчик не несет ответственности за то, что вы здесь напишите) </p> <p><a href="#" id="a2eval">Ссылка с eval-обработчиком</a></p>
<script type="text/javascript"> function a2evalH() { if ( a2evalH.idHandler ) { Events.remove( a2evalH.idHandler ); } a2evalH.idHandler = Events.add( "a2eval", "click", document.getElementById( "ia2eval" ).value ); return true; } a2evalH(); Events.using( "" ); </script>
<h2>Отмена действия по умолчанию</h2> <p>Обработчик <a href="http://yandex.ru" id="aYa">данной ссылки</a> отменяет действие по умолчанию. Поставьте здесь галочку, чтобы он этого не делал — <input type="checkbox" value="1" id="iaYa" /> </p> <script type="text/javascript"> Events.add( "aYa", "click", ( function() { if ( !document.getElementById( "iaYa" ).checked ) { Events.preventDefault(); } return true; } ) ); </script> </body> </html> |
Присоединённый файл ( Кол-во скачиваний: 32 )
events.rar 6,03 Kb
|