PrototypeJS 事件注册表问题
PrototypeJS Event Registry Issues
1.7.3
更新后原型事件注册表似乎有问题,我在元素存储上使用 prototype_event_registry
来访问点击事件,以便我可以重播它们。
这样我就可以停止事件并根据回调选择恢复它们,一切正常,但在查看 1.7.0
和 1.7.3
的差异后,它似乎已被删除?
我知道这是内部机制,我可能一开始就不应该使用它。无论如何,回到我的问题:
我已经更新了我的代码以与 1.7.3
一起使用,但对我来说这似乎非常 hacky,有更好的方法吗?
/**
* 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;
}
在 运行 上面的代码 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;
}
1.7.3
更新后原型事件注册表似乎有问题,我在元素存储上使用 prototype_event_registry
来访问点击事件,以便我可以重播它们。
这样我就可以停止事件并根据回调选择恢复它们,一切正常,但在查看 1.7.0
和 1.7.3
的差异后,它似乎已被删除?
我知道这是内部机制,我可能一开始就不应该使用它。无论如何,回到我的问题:
我已经更新了我的代码以与 1.7.3
一起使用,但对我来说这似乎非常 hacky,有更好的方法吗?
/**
* 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;
}
在 运行 上面的代码 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;
}