Ext.namespace('Zarafa.core'); /** * @class Zarafa.core.Events * Utility class for handling special events. * @singleton */ Zarafa.core.Events = { /** * The list of fields and the corresponding {@link Ext.util.Observable} * objects which are used to register the event handlers. Use * {@link #registerListener} and {@link #unregisterListener} to add/remove * {@Link Ext.util.Observable} instances. Use {@link #getListener} * to obtain a {@link Ext.util.Observable} instance. * @property * @type Object * @private */ listeners : {}, /** * Register a {@link Ext.util.Observable} instance for the given * {@link Ext.form.Field}/{@link Ext.Element} pair to the {@link #listeners} * object. * @param {Ext.form.Field} field The register for which the observable is added * @param {Ext.Element} el The element for which the the observable is added * @param {Ext.util.Observable} observable The observable to register * @private */ registerListener : function(field, el, observable) { var observables = Zarafa.core.Events.listeners[field.id]; if (observables) { observables.push(observable); } else { Zarafa.core.Events.listeners[field.id] = [ observable ]; } }, /** * Unregister a previously {@link #registerListener registered} * {@link Ext.util.Observable} from the {@link #listeners}. * @param {Ext.form.Field} field The register to which the observable belongs * @param {Ext.Element} el The element to which the observable belongs * @private */ unregisterListener : function(field, el) { var observables = Zarafa.core.Events.listeners[field.id]; if (observables) { for (var i = 0, len = observables.length; i < len; i++) { var observable = observables[i]; if (observable.el === el) { observables.splice(i, 1); if (observables.length === 0) { delete Zarafa.core.Events.listeners[field.id]; } } } } }, /** * Obtain a previously {@link #registerListener registered} * {@link Ext.util.Observable} from the {@link #listeners}. * @param {Ext.form.Field} field The register to which the observable belongs * @param {Ext.Element} el The element to which the observable belongs * @private */ getListener : function(field, el) { var observables = Zarafa.core.Events.listeners[field.id]; if (!observables) { return undefined; } for (var i = 0, len = observables.length; i < len; i++) { var observable = observables[i]; if (observable.el === el) { return observable; } } }, /** * Add a special event handler to the given field to catch * 'paste' events. There are multiple ways to paste text into * a textfield. * 1) contextmenu * 2) Ctrl-V (shortcut depending on OS) * 3) Drag & Drop text * * Support for catching these options depends severely on the browser, * and thus this special event handler will serve as compatibility * handler to handle the various cases correctly. * * @param {Ext.form.Field} field The field on which to listen for * paste events. * @param {Ext.Element} el The element on which the event should be registered * @param {Function} fn The callback function to be called when text * has been pasted. This function has no arguments (See {@link Ext.util.Observable#on}). * @param {Object} scope The scope in which the functon will be called (See {@link Ext.util.Observable#on}). * @param {Object} obj (optional) Additional options (See {@link Ext.util.Observable#on}). */ addPasteEventHandler : function(field, el, fn, scope, obj) { // Check if this field has already been used to register // an event handler for pasting. If that is not the case // we need to construct a new Ext.util.Observable object // for the field and add the event handlers. var observable = Zarafa.core.Events.getListener(field, el); if (!Ext.isDefined(observable)) { var noOn = !Ext.isFunction(el.on); observable = new Ext.util.Observable(); observable.field = field; observable.el = el; observable.hasFocus = field.hasFocus; observable.originalValue = field.getValue(); observable.addEvents('paste'); // Register the event handler for paste events. This will ensure // the input element will be resized when pasting. if (noOn) { el.addEventListener('paste', this.onPaste.createDelegate(observable)); } else { field.mon(el, 'paste', this.onPaste, observable); } // A special kind of pasting is dragging & dropping text into // the boxfield. There really isn't a true event handler for that, // as it isn't pasting, but neither is it typing. So use the mouse // to detect such changes. // // For some reason the 'mouseup' event is not being triggered when // the user drops the text into the input field. So we must use // the event which is fired a bit later. if (noOn) { el.addEventListener('mouseover', this.onPasteMouseOver.createDelegate(observable)); } else { field.mon(el, 'mouseover', this.onPasteMouseOver, observable); } field.on('blur', this.onPasteBlur, observable); Zarafa.core.Events.registerListener(field, el, observable); } observable.addListener('paste', fn, scope, obj); }, /** * Removes the event handler as registered by {@link #addPasteEventHandler}. * * @param {Ext.form.Field} field The field on which the event was registered * @param {Ext.Element} el The element on which the event should be registered * @param {Function} fn The function to unregister * @param {Object} scope The scope for the function. */ removePasteEventHandler : function(field, el, fn, scope) { var observable = Zarafa.core.Events.getListener(field, el); if (Ext.isDefined(observable)) { observable.removeListener('paste', fn, scope); // If this was the last event handler, delete // the Observable instance. if (!observable.hasListener('paste')) { Zarafa.core.Events.unregisterListener(field, el); } } }, /** * As Opera doesn't have the 'paste' browser event we are mimicking the behavior * here by having a global 'keyup' event handler. This event will simply check * if 'Ctrl-V has been pressed and will fire the event handler. * * This function is called in the scope of an {@link Ext.util.Observable}. * * @param {Number} key The key which was pressed * @param {Ext.EventObject} e The event object which fired the event * @private */ onPasteKeyUp : function(key, e) { // There are references online which indicate that Opera doesn't detect // the Ctrl key properly and the keyCode is 0. But Opera 11 seems to // behave correctly... if (key.ctrlKey === true && key.keyCode === Ext.EventObject.V) { this.fireEvent('paste'); } }, /** * Event handler for the 'paste' event on the {@link #el input element}. * This will start the {@link #onPastePoll} function to wait for the contents * to be pasted so it can fire the event handler. * * This function is called in the scope of an {@link Ext.util.Observable}. * * @private */ onPaste : function() { Zarafa.core.Events.onPastePoll.call(this, this.field, this.field.getValue(), 5); }, /** * The 'paste' event on an input element is fired before the text which must * be pasted is added into the input field. There is no cross-browser solution * to access the text before it is put into the input field, hence polling is used * to wait for the input field to be updated with the new text, so it can fire * the event handler. * * This function is called in the scope of an {@link Ext.util.Observable}. * * @param {Ext.form.Field} field The field to poll for the new value * @param {String} oldValue The original value of the input element * @param {Number} limit The number of polling tries left * @private */ onPastePoll : function(field, oldValue, limit) { if (limit === 0) { return; } else if (field.getValue() === oldValue) { Zarafa.core.Events.onPastePoll.defer(1, this, [field, oldValue, --limit]); return; } this.fireEvent('paste'); this.originalValue = this.field.getValue(); }, /** * Event handler which is fired when the Mouse is being moved over the * input field. This will check if the input field has been magically * changed without the user pressing any button. If that happens, then * the user has dragged text into the input element and we need to * fire the event handler. * * This function is called in the scope of an {@link Ext.util.Observable}. * * @private */ onPasteMouseOver : function() { if (this.hasFocus === false) { if (this.originalValue !== this.field.getValue()) { this.field.focus(); this.fireEvent('paste'); this.originalValue = this.field.getValue(); } this.hasFocus = true; } }, /** * Event handler which is fired when the registered field is being * {@link Ext.form.Field#blur blurred}. This will store the value * currently in the editor so during {@link #onPasteMouseOver} we can * check if text has been dropped into the editor. * @private */ onPasteBlur : function() { this.hasFocus = false; this.originalValue = this.field.getValue(); } };