Модераторы: Sardar, Aliance
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Небольшая либа для работы с событиями 
V
    Опции темы
vasac
Дата 11.4.2007, 20:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Здравствуйте!
Решил для упрощения жизни при работе с несложными страничками упростить себе жизнь и написал библиотечку. Поиспользовал — понравилось smile
Дописал комментариев и выложил здесь. Может еще кому понравится smile

Код

/**
 * Работа с обработчиками событий
 *
 * @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 &mdash; тест</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 &mdash; тест</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>Группа &laquo;litest&raquo; (&laquo;Два.Один&raquo; и &laquo;Три&raquo;)</td>
                <td><input type="checkbox" value="1" onchange="this.checked ? Events.groupEnable( &quot;litest&quot; ) : Events.groupDisable( &quot;litest&quot; );" checked="checked" /></td>
                <td>&mdash; снимите галочку, чтобы отключить</td>
            </tr>
            <tr>
                <td>Группа по умолчанию (все остальные)</td>
                <td><input type="checkbox" value="1" onchange="this.checked ? Events.groupEnable( &quot;0&quot; ) : Events.groupDisable( &quot;0&quot; );" checked="checked" /></td>
                <td>&nbsp;</td>
            </tr>
        </table>
        
        <p>Отменить дальнейшее распространение для &laquo;Два.Два&raquo;:
           <input type="checkbox" value="1" id="ilitesttwo" />
           &mdash; установите галочку и событие не дойдет до пункта &laquo;Два&raquo;.
        </p>
        
        <p><input type="submit" value="Убить группу litest" onclick="if (confirm(&quot;Все обработчики группы litest будут удалены навсегда&quot;)) {this.style.display=&quot;none&quot;;Events.groupRemove(&quot;litest&quot;);}" /></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> отменяет действие по умолчанию.
           Поставьте здесь галочку, чтобы он этого не делал &mdash;
           <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
PM WWW   Вверх
coyl
Дата 24.7.2007, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 13.6.2006

Репутация: нет
Всего: 1



перечисли совместимые браузеры плз
PM MAIL   Вверх
vasac
Дата 25.7.2007, 07:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



ie, ff, opera, safari с тех версий, в которых поддерживаются addEventListenet/attachEvent
PM WWW   Вверх
egao
Дата 13.9.2007, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 6.8.2007

Репутация: нет
Всего: нет



чёта уж слишком многа букав.  smile 

по поводу утечек - ты их своими глазами наблюдал?
PM MAIL   Вверх
vasac
Дата 14.9.2007, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Цитата

чёта уж слишком многа букав.

Здесь уж ничем помочь не могу smile

Цитата

по поводу утечек - ты их своими глазами наблюдал? 

Наблюдал. Как и бесчисленное множество других программистов. Которые описали это в бесчисленном множестве статей )
PM WWW   Вверх
egao
Дата 14.9.2007, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 109
Регистрация: 6.8.2007

Репутация: нет
Всего: нет



в бесчисленном множестве статей речь идёт о замыканиях, а не о событиях.
мой вопрос остаётся в силе: наблюдал ли ты утечки именно по вине событий, а не замыканий?
PM MAIL   Вверх
vasac
Дата 14.9.2007, 12:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Речь там идет не о замыканиях, как таковых, а о навешивании в качестве обработчика события анонимной функции, которая сама по себе является замыканием. 
Как я понимаю в IE просто забыли о том, что ссылка на функцию может хранится в DOM, при этом отсутствия в JS-контекстах (т.к. анонимная) и не сделали нормальной очистки.
PM WWW   Вверх
cruelangel
Дата 18.9.2007, 01:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 319
Регистрация: 12.9.2007

Репутация: 1
Всего: 8



http://darkodemon.blogspot.com/2007/09/javascript.html

специально проверил - утечек не происходит.
PM MAIL   Вверх
vasac
Дата 18.9.2007, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Вот сведения об утечке:
http://support.microsoft.com/kb/929874/

Недавно для всех js-программистов был величайший праздник, т.к. MS таки пофиксили эту вещь:
http://support.microsoft.com/kb/933566/

Видимо, у вас стоит обновление (или вообще не XP + IE6). Другое дело, остается множество людей, не обновляющих Win.
PM WWW   Вверх
cruelangel
Дата 18.9.2007, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 319
Регистрация: 12.9.2007

Репутация: 1
Всего: 8



неа, не стоит smile
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Здесь публикуют скрипты, которые уже проверены в обсуждениях других тем (при этом полезно поставить ссылки на все смежные обсуждения) или переносятся кем-либо из модераторов по просьбе участников, если видно, что в результате обсуждения темы был написан полезный или интересный скрипт. Третий возможный вариант - участник форума публикует скрипт, заведомо известный как полезный и эффективный, для, возможно, небольшой доработки и обсуждения.
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | JavaScript: Наши скрипты | Следующая тема »


 




[ Время генерации скрипта: 0.0588 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.