/** * @author Pavel Yaschenko */ // TODO: add support to bind multiple events using type param as an object with eventType,function pairs // see bindById method // TODO: update js docs (function($, richfaces) { /** * RichFaces Event API container * @class * @memberOf RichFaces * @static * @name Event * */ richfaces.Event = richfaces.Event || {}; var getEventElement = function (selector) { if (!selector) { throw "RichFaces.Event: empty selector"; } var element; if (RichFaces.BaseComponent && selector instanceof RichFaces.BaseComponent) { element = $(richfaces.getDomElement(selector.getEventElement())); } else { element = $(selector); } return element; } var getHandlerWrapper = function (component, fn) { return function (e, d) { if (!e[richfaces.RICH_CONTAINER]) { e[richfaces.RICH_CONTAINER] = {data: d}; } return fn.call(component || this, e, this, d); }; } var getMultipleHandlerWrapper = function (object, component) { var result = {}; for (var type in object) { result[type] = getHandlerWrapper(component, object[type]); } return result; } $.extend(richfaces.Event, { /** * @constant * @name RichFaces.Event.RICH_NAMESPACE * @type string * */ RICH_NAMESPACE : "RICH", /** * @constant * @name RichFaces.Event.EVENT_NAMESPACE_SEPARATOR * @type string * */ EVENT_NAMESPACE_SEPARATOR : ".", MESSAGE_EVENT_TYPE: "onmessage", /** * Attach an event handler to execute when the DOM is fully loaded. * * @function * @name RichFaces.Event.ready * @param {function} fn - event handler * @return {jQuery} document element wrapped by jQuery * */ ready : function(fn) { // TODO: not completed yet return $(document).ready(fn); /* function callback(jQueryReference) { this; // document } */ }, /** * Attach a handler to an event for the elements. * @function * @name RichFaces.Event.bind * * @param {string|DOMElement|jQuery} selector - jQuery elements selector * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} fn - event handler * @param {Object} [data] - component or object with additional data * It is a context for an event handler * @return {function} function that binded to the element's event * */ bind : function(selector, eventType, fn, component, data) { // eventType: namespace can be used, like onclick.rf.conponentName if (typeof eventType == "object") { // in this case fn == component object getEventElement(selector).bind(getMultipleHandlerWrapper(eventType, fn), data); } else { var f = getHandlerWrapper(component, fn); getEventElement(selector).bind(eventType, data, f); return f; } }, /** * Attach a handler to an event for the element by element id. * @function * @name RichFaces.Event.bindById * * @param {string} id - DOM element id * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} fn - event handler * @param {Object} [data] - component or object with additional data * It is a context for an event handler * @return {function} function that binded to the element's event * */ bindById : function(id, eventType, fn, component, data) { // eventType: namespace can be used, like onclick.rf.conponentName if (typeof eventType == "object") { // in this case fn == component object $(document.getElementById(id)).bind(getMultipleHandlerWrapper(eventType, fn), data); } else { var f = getHandlerWrapper(component, fn); $(document.getElementById(id)).bind(eventType, data, f); } return f; }, /** * Attach a handler to an event for the elements. * The handler will be called only once when event happened. * @function * @name RichFaces.Event.bindOne * * @param {string|DOMElement|jQuery} selector - jQuery elements selector * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} fn - event handler * @param {Object} [data] - component or object with additional data * It is a context for an event handler * @return {function} function that binded to the element's event * */ bindOne: function(selector, eventType, fn, component, data) { // eventType: namespace can be used, like onclick.rf.conponentName var f = getHandlerWrapper(component, fn); getEventElement(selector).one(eventType, data, f); return f; }, /** * Attach a handler to an event for the element by element id. * The handler will be called only once when event happened. * @function * @name RichFaces.Event.bindOneById * * @param {string} id - DOM element id * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} fn - event handler * @param {Object} [data] - component or object with additional data * It is a context for an event handler * @return {function} function that binded to the element's event * */ bindOneById: function(id, eventType, fn, component, data) { // eventType: namespace can be used, like onclick.rf.conponentName var f = getHandlerWrapper(component, fn); $(document.getElementById(id)).one(eventType, data, f); return f; }, /** * Remove a previously-attached event handler from the elements. * @function * @name RichFaces.Event.unbind * * @param {string|DOMElement|jQuery} selector - jQuery elements selector * @param {string} [eventType] - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} [fn] - event handler * @return {jQuery} element wrapped by jQuery * */ unbind : function(selector, eventType, fn) { // eventType: namespace can be used, like onclick.rf.conponentName return getEventElement(selector).unbind(eventType, fn); }, /** * Remove a previously-attached event handler from the elements by element id. * The handler will be called only once when event happened. * @function * @name RichFaces.Event.unbindById * * @param {string} id - DOM element id * @param {string} [eventType] - one or more JavaScript event types, such as "click" or "submit," or custom event names * @param {function} [fn] - event handler * @return {jQuery} element wrapped by jQuery * */ unbindById : function(id, eventType, fn) { // eventType: namespace can be used, like onclick.rf.conponentName return $(document.getElementById(id)).unbind(eventType, fn); }, // TODO add jsdocs and qunits bindScrollEventHandlers: function(element, handler, component) { var elements = []; element = richfaces.getDomElement(element).parentNode; while (element && element != window.document.body) { if (element.offsetWidth != element.scrollWidth || element.offsetHeight != element.scrollHeight) { elements.push(element); richfaces.Event.bind(element, "scroll" + component.getNamespace(), handler, component); } element = element.parentNode; } return elements; }, unbindScrollEventHandlers: function(elements, component) { richfaces.Event.unbind(elements, "scroll" + component.getNamespace()); }, /** * Execute all handlers and behaviors attached to the matched elements for the given event type. * @function * @name RichFaces.Event.fire * * @param {string|DOMElement|jQuery} selector - jQuery elements selector * @param {string} eventType - event type * @param {Object} [data] - a object of additional parameters to pass to the event handler * @return {jQuery} element wrapped by jQuery * */ fire : function(selector, eventType, data) { var event = $.Event(eventType); getEventElement(selector).trigger(event, [data]); return !event.isDefaultPrevented(); }, /** * The same as the fire method, but selects element by id. * @function * @name RichFaces.Event.fireById * * @param {string} id - DOM element id * @param {string} eventType - event type * @param {Object} [data] - a object of additional parameters to pass to the event handler * @return {jQuery} element wrapped by jQuery * */ fireById : function(id, eventType, data) { var event = $.Event(eventType); $(document.getElementById(id)).trigger(event, [data]); return !event.isDefaultPrevented(); }, /** * The same as the fire method, but: * - does not cause the default behavior of an event to occur * - does not bubble up event * - call handler only for the first founded element * - returns whatever value that was returned by the handler * @function * @name RichFaces.Event.callHandler * * @param {string|DOMElement|jQuery} selector - jQuery elements selector * @param {string} eventType - event type * @param {Object} [data] - a object of additional parameters to pass to the event handler * @return value that was returned by the handler * */ callHandler : function(selector, eventType, data) { return getEventElement(selector).triggerHandler(eventType, [data]); }, /** * The same as the callHandler method, but selects element by id. * @function * @name RichFaces.Event.callHandlerById * * @param {string} id - DOM element id * @param {string} eventType - event type * @param {Object} [data] - a object of additional parameters to pass to the event handler * @return value that was returned by the handler * */ callHandlerById : function(id, eventType, data) { return $(document.getElementById(id)).triggerHandler(eventType, [data]); }, /** * Create an event namespace for the components. * @function * @name RichFaces.Event.createNamespace * * @param {string} [componentName] - component name * @param {string} [id] - element id * @param {string} [prefix=RichFaces.Event.RICH_NAMESPACE] - namespace prefix * @return {string} namespace string * */ // TODO: rename argument names createNamespace : function(componentName, id, prefix) { var a = []; a.push(prefix || richfaces.Event.RICH_NAMESPACE); if (componentName) { a.push(componentName); } if (id) { a.push(id); } return a.join(richfaces.Event.EVENT_NAMESPACE_SEPARATOR); } }); })(jQuery, window.RichFaces || (window.RichFaces = {})); /* fn : function (eventObject, element) { this; // object passed as data to bind function or dom element if no data element; // dom element } */ // API usage example: // RichFaces.Event.bind(selector, type, fn, data);