1 /* 2 * JBoss, Home of Professional Open Source 3 * Copyright 2013, Red Hat, Inc. and individual contributors 4 * by the @authors tag. See the copyright.txt in the distribution for a 5 * full listing of individual contributors. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this software; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 */ 22 23 /** 24 * @author Pavel Yaschenko 25 */ 26 27 // TODO: add support to bind multiple events using type param as an object with eventType,function pairs // see bindById method 28 // TODO: update js docs 29 30 window.RichFaces = window.RichFaces || {}; 31 RichFaces.jQuery = RichFaces.jQuery || window.jQuery; 32 33 (function($, rf) { 34 35 /** 36 * RichFaces Event API container 37 * @class 38 * @memberOf RichFaces 39 * @static 40 * @name Event 41 * */ 42 rf.Event = rf.Event || {}; 43 44 var getEventElement = function (selector) { 45 if (!selector) { 46 throw "RichFaces.Event: empty selector"; 47 } 48 var element; 49 if (rf.BaseComponent && selector instanceof rf.BaseComponent) { 50 element = $(rf.getDomElement(selector.getEventElement())); 51 } else { 52 element = $(selector); 53 } 54 55 return element; 56 } 57 58 var getHandlerWrapper = function (component, fn) { 59 return function (e, d) { 60 if (!e[rf.RICH_CONTAINER]) { 61 e[rf.RICH_CONTAINER] = {data: d}; 62 } 63 return fn.call(component || this, e, this, d); 64 }; 65 } 66 67 var getMultipleHandlerWrapper = function (object, component) { 68 var result = {}; 69 for (var type in object) { 70 result[type] = getHandlerWrapper(component, object[type]); 71 } 72 return result; 73 } 74 75 $.extend(rf.Event, { 76 /** 77 * @constant 78 * @name RichFaces.Event.RICH_NAMESPACE 79 * @type string 80 * */ 81 RICH_NAMESPACE : "RICH", 82 83 /** 84 * @constant 85 * @name RichFaces.Event.EVENT_NAMESPACE_SEPARATOR 86 * @type string 87 * */ 88 EVENT_NAMESPACE_SEPARATOR : ".", 89 90 MESSAGE_EVENT_TYPE: "onmessage", 91 92 /** 93 * Attach an event handler to execute when the DOM is fully loaded. 94 * 95 * @function 96 * @name RichFaces.Event.ready 97 * @param {function} fn - event handler 98 * @return {jQuery} document element wrapped by jQuery 99 * */ 100 ready : function(fn) { 101 // TODO: not completed yet 102 return $(document).ready(fn); 103 /* 104 function callback(jQueryReference) { 105 this; // document 106 } 107 */ 108 }, 109 110 /** 111 * Attach a handler to an event for the elements. 112 * @function 113 * @name RichFaces.Event.bind 114 * 115 * @param {string|DOMElement|jQuery} selector - jQuery elements selector 116 * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names 117 * @param {function} fn - event handler 118 * @param {Object} [data] - component or object with additional data 119 * It is a context for an event handler 120 * @return {function} function that binded to the element's event 121 * */ 122 bind : function(selector, eventType, fn, component, data) { 123 // eventType: namespace can be used, like onclick.rf.conponentName 124 if (typeof eventType == "object") { 125 // in this case fn == component object 126 getEventElement(selector).bind(getMultipleHandlerWrapper(eventType, fn), data); 127 } else { 128 var f = getHandlerWrapper(component, fn); 129 getEventElement(selector).bind(eventType, data, f); 130 return f; 131 } 132 }, 133 134 /** 135 * Attach a handler to an event for the element by element id. 136 * @function 137 * @name RichFaces.Event.bindById 138 * 139 * @param {string} id - DOM element id 140 * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names 141 * @param {function} fn - event handler 142 * @param {Object} [data] - component or object with additional data 143 * It is a context for an event handler 144 * @return {function} function that binded to the element's event 145 * */ 146 bindById : function(id, eventType, fn, component, data) { 147 // eventType: namespace can be used, like onclick.rf.conponentName 148 if (typeof eventType == "object") { 149 // in this case fn == component object 150 $(document.getElementById(id)).bind(getMultipleHandlerWrapper(eventType, fn), data); 151 } else { 152 var f = getHandlerWrapper(component, fn); 153 $(document.getElementById(id)).bind(eventType, data, f); 154 } 155 return f; 156 }, 157 158 /** 159 * Attach a handler to an event for the elements. 160 * The handler will be called only once when event happened. 161 * @function 162 * @name RichFaces.Event.bindOne 163 * 164 * @param {string|DOMElement|jQuery} selector - jQuery elements selector 165 * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names 166 * @param {function} fn - event handler 167 * @param {Object} [data] - component or object with additional data 168 * It is a context for an event handler 169 * @return {function} function that binded to the element's event 170 * */ 171 bindOne: function(selector, eventType, fn, component, data) { 172 // eventType: namespace can be used, like onclick.rf.conponentName 173 var f = getHandlerWrapper(component, fn); 174 getEventElement(selector).one(eventType, data, f); 175 return f; 176 }, 177 178 /** 179 * Attach a handler to an event for the element by element id. 180 * The handler will be called only once when event happened. 181 * @function 182 * @name RichFaces.Event.bindOneById 183 * 184 * @param {string} id - DOM element id 185 * @param {string} eventType - one or more JavaScript event types, such as "click" or "submit," or custom event names 186 * @param {function} fn - event handler 187 * @param {Object} [data] - component or object with additional data 188 * It is a context for an event handler 189 * @return {function} function that binded to the element's event 190 * */ 191 bindOneById: function(id, eventType, fn, component, data) { 192 // eventType: namespace can be used, like onclick.rf.conponentName 193 var f = getHandlerWrapper(component, fn); 194 $(document.getElementById(id)).one(eventType, data, f); 195 return f; 196 }, 197 198 /** 199 * Remove a previously-attached event handler from the elements. 200 * @function 201 * @name RichFaces.Event.unbind 202 * 203 * @param {string|DOMElement|jQuery} selector - jQuery elements selector 204 * @param {string} [eventType] - one or more JavaScript event types, such as "click" or "submit," or custom event names 205 * @param {function} [fn] - event handler 206 * @return {jQuery} element wrapped by jQuery 207 * */ 208 unbind : function(selector, eventType, fn) { 209 // eventType: namespace can be used, like onclick.rf.conponentName 210 return getEventElement(selector).unbind(eventType, fn); 211 }, 212 213 /** 214 * Remove a previously-attached event handler from the elements by element id. 215 * The handler will be called only once when event happened. 216 * @function 217 * @name RichFaces.Event.unbindById 218 * 219 * @param {string} id - DOM element id 220 * @param {string} [eventType] - one or more JavaScript event types, such as "click" or "submit," or custom event names 221 * @param {function} [fn] - event handler 222 * @return {jQuery} element wrapped by jQuery 223 * */ 224 unbindById : function(id, eventType, fn) { 225 // eventType: namespace can be used, like onclick.rf.conponentName 226 return $(document.getElementById(id)).unbind(eventType, fn); 227 }, 228 229 // TODO add jsdocs and qunits 230 bindScrollEventHandlers: function(element, handler, component) { 231 var elements = []; 232 element = rf.getDomElement(element).parentNode; 233 while (element && element != window.document.body) { 234 if (element.offsetWidth != element.scrollWidth || element.offsetHeight != element.scrollHeight) { 235 elements.push(element); 236 rf.Event.bind(element, "scroll" + component.getNamespace(), handler, component); 237 } 238 element = element.parentNode; 239 } 240 return elements; 241 }, 242 unbindScrollEventHandlers: function(elements, component) { 243 rf.Event.unbind(elements, "scroll" + component.getNamespace()); 244 }, 245 246 /** 247 * Execute all handlers and behaviors attached to the matched elements for the given event type. 248 * @function 249 * @name RichFaces.Event.fire 250 * 251 * @param {string|DOMElement|jQuery} selector - jQuery elements selector 252 * @param {string} eventType - event type 253 * @param {Object} [data] - a object of additional parameters to pass to the event handler 254 * @return {jQuery} element wrapped by jQuery 255 * */ 256 fire : function(selector, eventType, data) { 257 var event = $.Event(eventType); 258 getEventElement(selector).trigger(event, [data]); 259 return !event.isDefaultPrevented(); 260 }, 261 262 /** 263 * The same as the fire method, but selects element by id. 264 * @function 265 * @name RichFaces.Event.fireById 266 * 267 * @param {string} id - DOM element id 268 * @param {string} eventType - event type 269 * @param {Object} [data] - a object of additional parameters to pass to the event handler 270 * @return {jQuery} element wrapped by jQuery 271 * */ 272 fireById : function(id, eventType, data) { 273 var event = $.Event(eventType); 274 $(document.getElementById(id)).trigger(event, [data]); 275 return !event.isDefaultPrevented(); 276 }, 277 278 /** 279 * The same as the fire method, but: 280 * - does not cause the default behavior of an event to occur 281 * - does not bubble up event 282 * - call handler only for the first founded element 283 * - returns whatever value that was returned by the handler 284 * @function 285 * @name RichFaces.Event.callHandler 286 * 287 * @param {string|DOMElement|jQuery} selector - jQuery elements selector 288 * @param {string} eventType - event type 289 * @param {Object} [data] - a object of additional parameters to pass to the event handler 290 * @return value that was returned by the handler 291 * */ 292 callHandler : function(selector, eventType, data) { 293 return getEventElement(selector).triggerHandler(eventType, [data]); 294 }, 295 296 /** 297 * The same as the callHandler method, but selects element by id. 298 * @function 299 * @name RichFaces.Event.callHandlerById 300 * 301 * @param {string} id - DOM element id 302 * @param {string} eventType - event type 303 * @param {Object} [data] - a object of additional parameters to pass to the event handler 304 * @return value that was returned by the handler 305 * */ 306 callHandlerById : function(id, eventType, data) { 307 return $(document.getElementById(id)).triggerHandler(eventType, [data]); 308 }, 309 310 /** 311 * Create an event namespace for the components. 312 * @function 313 * @name RichFaces.Event.createNamespace 314 * 315 * @param {string} [componentName] - component name 316 * @param {string} [id] - element id 317 * @param {string} [prefix=RichFaces.Event.RICH_NAMESPACE] - namespace prefix 318 * @return {string} namespace string 319 * */ 320 // TODO: rename argument names 321 createNamespace : function(componentName, id, prefix) { 322 var a = []; 323 a.push(prefix || rf.Event.RICH_NAMESPACE); 324 if (componentName) { 325 a.push(componentName); 326 } 327 if (id) { 328 a.push(id); 329 } 330 return a.join(rf.Event.EVENT_NAMESPACE_SEPARATOR); 331 } 332 }); 333 334 })(RichFaces.jQuery, RichFaces); 335 336 /* 337 fn : function (eventObject, element) { 338 this; // object passed as data to bind function or dom element if no data 339 element; // dom element 340 341 } 342 */ 343 344 // API usage example: 345 // RichFaces.Event.bind(selector, type, fn, data); 346