'use strict'; /* global KeyEvent, Promise */ (function(exports) { // |target| is an abstract key object, not a DOM element var DefaultTargetHandler = function(target, app) { this.target = target; this.app = app; this.ignoreCommitActions = false; }; DefaultTargetHandler.prototype.activate = function() { this.app.console.log('DefaultTargetHandler.activate()'); this.app.feedbackManager.triggerFeedback(this.target); this.app.visualHighlightManager.show(this.target); }; DefaultTargetHandler.prototype.longPress = function() { this.app.console.log('DefaultTargetHandler.longPress()'); // Does the key have an long press value? if (!('longPressValue' in this.target)) { return; } // Ignore any action when commit. this.ignoreCommitActions = true; var keyCode = this.target.longPressKeyCode; var promise = Promise.resolve(this.app.inputMethodManager.currentIMEngine.click(keyCode)); this.app.visualHighlightManager.hide(this.target); return promise; }; DefaultTargetHandler.prototype.moveOut = function() { this.app.console.log('DefaultTargetHandler.moveOut()'); this.app.visualHighlightManager.hide(this.target); }; DefaultTargetHandler.prototype.moveIn = function() { this.app.console.log('DefaultTargetHandler.moveIn()'); this.app.visualHighlightManager.show(this.target); }; DefaultTargetHandler.prototype.commit = function() { this.app.console.log('DefaultTargetHandler.commit()'); if (this.ignoreCommitActions) { this.app.console.log('DefaultTargetHandler.commit()::return early'); return; } var keyCode = this.target.keyCode; var keyCodeUpper = this.target.keyCodeUpper; var engine = this.app.inputMethodManager.currentIMEngine; /* * Return promise here, and rely on the action queue in TargetHandlerManager * to make sure the key code is sent with the right capitalization state. */ var code = this.app.upperCaseStateManager.isUpperCase ? keyCodeUpper : keyCode; this.app.console.log('DefaultTargetHandler.commit()::engine.click', code); var promise = Promise.resolve(engine.click(code)); this.app.visualHighlightManager.hide(this.target); return promise; }; DefaultTargetHandler.prototype.cancel = function() { this.app.console.log('DefaultTargetHandler.cancel()'); this.app.visualHighlightManager.hide(this.target); }; DefaultTargetHandler.prototype.doubleTap = function() { this.app.console.log('DefaultTargetHandler.doubleTap()'); return this.commit(); }; DefaultTargetHandler.prototype.newTargetActivate = function() { // According to UX requirement, the current target need to be committed when // there is a new press. We will have to commit ourselves here. this.commit(); // Ignore addition calls on commit(). this.ignoreCommitActions = true; }; DefaultTargetHandler.prototype.move = function() { }; var NullTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; NullTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); NullTargetHandler.prototype.activate = NullTargetHandler.prototype.moveIn = NullTargetHandler.prototype.moveOut = NullTargetHandler.prototype.commit = NullTargetHandler.prototype.cancel = NullTargetHandler.prototype.doubleTap = function() { }; var SpaceKeyTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; SpaceKeyTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); SpaceKeyTargetHandler.prototype.longPress = function() { this.app.targetHandlersManager.activeTargetsManager.clearAllTargets(); navigator.mozInputMethod.mgmt.hide(); this.app.visualHighlightManager.hide(this.target); }; var CandidateSelectionTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; CandidateSelectionTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); CandidateSelectionTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'CandidateSelectionTargetHandler.commit()::return early'); return; } this.app.candidatePanelManager.hideFullPanel(); // We use the target's data instead of target.text because the // text actually displayed to the user might have an ellipsis in it // to make it fit. var engine = this.app.inputMethodManager.currentIMEngine; if (typeof engine.select === 'function') { engine.select(this.target.text, this.target.data); } this.app.visualHighlightManager.hide(this.target); }; var BackspaceTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); this.deleteTimeout = undefined; this.deleteInterval = undefined; this.ignoreCommitActions = false; }; BackspaceTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); // Backspace repeat delay and repeat rate BackspaceTargetHandler.prototype.REPEAT_RATE = 50; BackspaceTargetHandler.prototype.REPEAT_TIMEOUT = 500; // Sends a delete code to remove last character // The argument specifies whether this is an auto repeat or not. BackspaceTargetHandler.prototype._sendDelete = function(isRepeat) { // Pass the isRepeat argument to the input method. It may not want // to compute suggestions, for example, if this is just one in a series // of repeating events. var engine = this.app.inputMethodManager.currentIMEngine; engine.click(KeyEvent.DOM_VK_BACK_SPACE, null, isRepeat); }; BackspaceTargetHandler.prototype.activate = function() { this.app.feedbackManager.triggerFeedback(this.target); this.app.visualHighlightManager.show(this.target); // First repetition, after a delay this.deleteTimeout = setTimeout(function() { this._sendDelete(true); // Second, after shorter delay this.deleteInterval = setInterval(function() { this._sendDelete(true); }.bind(this), this.REPEAT_RATE); }.bind(this), this.REPEAT_TIMEOUT); }; BackspaceTargetHandler.prototype.moveOut = function() { this.app.visualHighlightManager.hide(this.target); clearTimeout(this.deleteTimeout); clearInterval(this.deleteInterval); }; BackspaceTargetHandler.prototype.moveIn = function() { // Do nothing and make sure commit does nothing. this.ignoreCommitActions = true; }; BackspaceTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'BackspaceTargetHandler.commit()::return early'); return; } clearTimeout(this.deleteTimeout); clearInterval(this.deleteInterval); this._sendDelete(false); this.app.visualHighlightManager.hide(this.target); }; BackspaceTargetHandler.prototype.cancel = function() { clearTimeout(this.deleteTimeout); clearInterval(this.deleteInterval); this.app.visualHighlightManager.hide(this.target); }; var CompositeTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; CompositeTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); CompositeTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'CompositeTargetHandler.commit()::return early'); return; } // Keys with this attribute set send more than a single character // Like ".com" or "2nd" or (in Catalan) "l·l". var compositeString = this.target.compositeKey; var promise; var engine = this.app.inputMethodManager.currentIMEngine; if (engine.handleKey) { // Engine with the new method that could handle a key dict. promise = engine.handleKey({ key: compositeString, printable: true }); } else { promise = Promise.resolve(); // XXX: Split the key into characters and click() on it one by one. compositeString.split('').forEach(function(chr) { promise = promise .then(function() { return engine.click(chr.charCodeAt(0)); }, function(e) { console.error(e); return engine.click(chr.charCodeAt(0)); }); }); } this.app.visualHighlightManager.hide(this.target); return promise; }; var PageSwitchingTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; PageSwitchingTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); PageSwitchingTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'PageSwitchingTargetHandler.commit()::return early'); return; } var page = this.target.targetPage; this.app.setLayoutPage(page); this.app.visualHighlightManager.hide(this.target); // If needed, empty the candidate panel var currentIMEngine = this.app.inputMethodManager.currentIMEngine; if (typeof currentIMEngine.empty === 'function') { currentIMEngine.empty(); } }; var CapsLockTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); this.isPreviouslyUpperCase = undefined; }; CapsLockTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); CapsLockTargetHandler.prototype.isNewTargetActivated = false; CapsLockTargetHandler.prototype.activate = function() { this.isPreviouslyUpperCase = this.app.upperCaseStateManager.isUpperCase; // Switch to upperCaseLocked state so all combo presses will be upper caps this.app.upperCaseStateManager.switchUpperCaseState({ isUpperCaseLocked: true }); this.app.feedbackManager.triggerFeedback(this.target); this.app.visualHighlightManager.show(this.target); }; CapsLockTargetHandler.prototype.commit = function() { if (this.isNewTargetActivated) { // If the user have ever tap any other keys (i.e. combo keys), // we should go back to lower case regardless. this.app.upperCaseStateManager.switchUpperCaseState({ isUpperCase: false, isUpperCaseLocked: false }); } else { // Depend on the previous upper case state, single tap should allow user // switch between upper case and lower case. this.app.upperCaseStateManager.switchUpperCaseState({ isUpperCase: !this.isPreviouslyUpperCase, isUpperCaseLocked: false }); } this.app.visualHighlightManager.hide(this.target); }; CapsLockTargetHandler.prototype.doubleTap = function() { this.app.upperCaseStateManager.switchUpperCaseState({ isUpperCaseLocked: true }); this.app.visualHighlightManager.hide(this.target); }; CapsLockTargetHandler.prototype.newTargetActivate = function() { this.isNewTargetActivated = true; }; var SwitchKeyboardTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; SwitchKeyboardTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); SwitchKeyboardTargetHandler.prototype.longPress = function() { this.ignoreCommitActions = true; this.app.targetHandlersManager.activeTargetsManager.clearAllTargets(); navigator.mozInputMethod.mgmt.showAll(); this.app.visualHighlightManager.hide(this.target); }; SwitchKeyboardTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { return; } this.app.targetHandlersManager.activeTargetsManager.clearAllTargets(); navigator.mozInputMethod.mgmt.next(); this.app.visualHighlightManager.hide(this.target); }; var ToggleCandidatePanelTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; ToggleCandidatePanelTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); ToggleCandidatePanelTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'ToggleCandidatePanelTargetHandler.commit()::return early'); return; } this.app.candidatePanelManager.toggleFullPanel(); this.app.visualHighlightManager.hide(this.target); }; var DismissSuggestionsTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; DismissSuggestionsTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); DismissSuggestionsTargetHandler.prototype.commit = function() { if (this.ignoreCommitActions) { this.app.console.log( 'DismissSuggestionsTargetHandler.commit()::return early'); return; } var engine = this.app.inputMethodManager.currentIMEngine; if (typeof engine.dismissSuggestions === 'function') { engine.dismissSuggestions(); } this.app.visualHighlightManager.hide(this.target); }; var HandwritingPadTargetHandler = function(target, app) { DefaultTargetHandler.apply(this, arguments); }; HandwritingPadTargetHandler.prototype = Object.create(DefaultTargetHandler.prototype); HandwritingPadTargetHandler.prototype.activate = function(press) { this.app.handwritingPadsManager.handlePressStart(press); }; HandwritingPadTargetHandler.prototype.move = function(press) { this.app.handwritingPadsManager.handlePressMove(press); }; HandwritingPadTargetHandler.prototype.moveOut = function(press) { }; HandwritingPadTargetHandler.prototype.moveIn = function(press) { this.app.handwritingPadsManager.handlePressStart(press); }; HandwritingPadTargetHandler.prototype.commit = function() { this.app.handwritingPadsManager.handlePressEnd(); }; HandwritingPadTargetHandler.prototype.newTargetActivate = function() { }; exports.DefaultTargetHandler = DefaultTargetHandler; exports.NullTargetHandler = NullTargetHandler; exports.SpaceKeyTargetHandler = SpaceKeyTargetHandler; exports.CandidateSelectionTargetHandler = CandidateSelectionTargetHandler; exports.BackspaceTargetHandler = BackspaceTargetHandler; exports.CompositeTargetHandler = CompositeTargetHandler; exports.PageSwitchingTargetHandler = PageSwitchingTargetHandler; exports.CapsLockTargetHandler = CapsLockTargetHandler; exports.SwitchKeyboardTargetHandler = SwitchKeyboardTargetHandler; exports.ToggleCandidatePanelTargetHandler = ToggleCandidatePanelTargetHandler; exports.DismissSuggestionsTargetHandler = DismissSuggestionsTargetHandler; exports.HandwritingPadTargetHandler = HandwritingPadTargetHandler; })(window);