2015-11-27 2 views
14

После обновления 1.7.3 возникла проблема с реестром событий прототипа, я использовал prototype_event_registry в хранилище элементов для доступа к событиям щелчка, чтобы я мог их воспроизвести.PrototypeJS Проблемы с регистрацией событий

Это значит, что я могу остановить события и, возможно, возобновить их на основе обратного вызова, все работает нормально, но, посмотрев разницы для 1.7.0 и 1.7.3, кажется, что их удалили?

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

Я обновил свой код для работы с 1.7.3, но мне кажется, что это очень хлопотно, есть ли лучший способ сделать это?

/** 
* creates a toggling handler for click events taking previous click events into account. 
* 
* w.r.t stopping of a click event, handles cases where the button is a submit or a normal button. 
* in the case of a submit, calling <tt>Event.stop()</tt> should be sufficient as there are no other listeners on the button. 
* however, if a normal button has a handler that calls <tt>save()</tt>, and another handler using client code and calling stop, 
* it will not affect stopping of the event, since <tt>Event.stop</tt> only stops propagation, not other handlers! 
* 
* note that this function will always execute the specified handler before any other defined events. 
* 
* @param {Element} element the element to use for this click event 
* @param {Function} handler the handler to use for this stopping click event, if this handler returns true, 
* all other actions for the click event will be prevented 
* @returns {Element} the element that was supplied as argument 
*/ 
function stoppingClickEvent(element, handler) { 
    if (!element) throw 'cannot use method, if element is undefined'; 

    // assign default handler if none was supplied 
    handler = handler || Prototype.emptyFunction; 

    if (element.type && element.type === 'submit') { 
     element.on('click', function(submitEvent) { 
      // call the supplied handler with the current element as context and the event as argument 
      // if it returns true, we should stop the event 
      var stopEvent = handler.call(element, submitEvent); 

      if (stopEvent) { 
       // since the element's default action will be to submit a form, we prevent it 
       submitEvent.stop(); 
      } 
     }); 
    } else { 
     // prototype 1.7.3 removed support for 'prototype_event_registry', so we need to do multiple hacks here 
     // first get the window of the element so we can access the prototype 
     // event cache from the correct context (frames) 
     var elementDoc = element.ownerDocument; 
     var elementWindow = elementDoc.defaultView || elementDoc.parentWindow; 

     if (!elementWindow) { 
      throw 'cannot access the window object for element ' + element.id; 
     } 

     // we are dealing with a normal element's click event, so we don't know how many click events have been set up. 
     // capture them all so we can decide to call them or not. 
     // FIXME: need a better way of doing this 
     var registry = elementWindow['Event'].cache[element._prototypeUID || element.uniqueID] || {}, 
      events = registry['click'] || []; 

     // now that we have a copy of the events, we can stop them all and add our new handler 
     element.stopObserving('click').on('click', function(clickEvent) { 
      // call the supplied handler with the current element as context and the event as argument 
      // if it returns true, we should stop the event 
      var stopEvent = handler.call(element, clickEvent); 

      if (!stopEvent) { 
       // the event should not be stopped, run all the original click events 
       events.each(function(wrapper) { 
        wrapper.handler.call(element, clickEvent); 
       }); 
      } 
     }); 
    } 

    return element; 
} 
+1

Похоже реестр событий была переписана в 1.7.1 - 'Event.cache' объект был настроен на предотвращение утечки памяти повышает производительность. Я уверен, что элемент. _prototypeUID' должен всегда существовать на любом расширенном элементе, но в противном случае это способ ссылаться на регистр событий для каждого элемента. –

+0

Не Event.stop (д) делать то, что он должен делать? Это должно остановить распространение событий, не так ли? –

+0

@kiran, он останавливает распространение, но не останавливает никаких дополнительных обработчиков кликов, указанных на кнопке, следовательно, эта функция :) – epoch

ответ

0

После выполнения вышеуказанного кода в течение 3-4 месяцев я, наконец, решил его вернуть. Кажется, что существует много проблем, особенно при работе с несколькими кадрами и обработчиками событий на одной странице.

Наиболее распространенным является один, Event.cache для конкретного элемента, являющегося undefined.

Это может быть связано с неправильной обработкой выше, но я очень подозреваю, что новый фреймворк Event был некорректным, так как возврат к 1.7.0 полностью устраняет все проблемы, которые я испытывал.

Просто для справки, это код, я сейчас, используя с 1.7.0:

/** 
* creates a toggling handler for click events taking previous click events into account. 
* 
* w.r.t stopping of a click event, handles cases where the button is a submit or a normal button. 
* in the case of a submit, calling <tt>Event.stop()</tt> should be sufficient as there are no other listeners on the button. 
* however, if a normal button has a handler that calls <tt>save()</tt>, and another handler using client code and calling stop, 
* it will not affect stopping of the event, since <tt>Event.stop</tt> only stops propagation, not other handlers! 
* 
* note that this function will always execute the specified handler before any other defined events. 
* 
* @param {Element} element the element to use for this click event 
* @param {Function} handler the handler to use for this stopping click event, if this handler returns true, 
* all other actions for the click event will be prevented 
* @returns {Element} the element that was supplied as argument 
*/ 
function stoppingClickEvent(element, handler) { 
    if (!element) throw 'cannot use method, if element is undefined'; 

    // assign default handler if none was supplied 
    handler = handler || Prototype.emptyFunction; 

    if (element.type && element.type === 'submit') { 
     element.on('click', function(submitEvent) { 
      // call the supplied handler with the current element as context and the event as argument 
      // if it returns true, we should stop the event 
      var stopEvent = handler.call(element, submitEvent); 

      if (stopEvent) { 
       // since the element's default action will be to submit a form, we prevent it 
       submitEvent.stop(); 
      } 
     }); 
    } else { 
     // we are dealing with a normal element's click event, so we don't know how many click events have been set up. 
     // capture them all so we can decide to call them or not. 
     var registry = element.getStorage().get('prototype_event_registry') || $H(), 
      events = registry.get('click') || []; 

     // now that we have a copy of the events, we can stop them all and add our new handler 
     element.stopObserving('click').on('click', function(clickEvent) { 
      // call the supplied handler with the current element as context and the event as argument 
      // if it returns true, we should stop the event 
      var stopEvent = handler.call(element, clickEvent); 

      if (!stopEvent) { 
       // the event should not be stopped, run all the original click events 
       events.each(function(func) { 
        func.call(element, clickEvent); 
       }); 
      } 
     }); 
    } 

    return element; 
}