Source: widgets/search/multikbd.js

define('application/widgets/search/multikbd', [
    'rofl/widgets/keyboard/multi',
    'rofl/widgets/label',
    'rofl/lib/l10n',
    'application/widgets/button',
    'rofl/events/keyboard/swapkeyset',
    'rofl/lib/utils',
    'antie/runtimecontext',
    'rofl/events/keyevent'
], function (
    Parent,
    Label,
    L10N,
    Button,
    SwapKeysetEvent,
    Utils,
    RuntimeContext,
    KeyEvent
) {
    'use strict';

    var l10n = L10N.getInstance(),
        MultipleKeyboard;

    MultipleKeyboard = Parent.extend({

        /**
         * Initialises the component.
         */
        init: function init () {
            init.base.call(this, {
                keysets: [
                    {
                        keys: ['abcdef', 'ghijkl', 'mnopqr', 'stuvwx', 'yz____', '______'],
                        swap: l10n.get('search.input.multikbd.swapLetters'),
                        custom: [
                            {
                                columnIndex: 2,
                                rowIndex: 4,
                                character: l10n.get('search.input.multikbd.clearAll'),
                                key: l10n.get('search.input.multikbd.key.clearAll'),
                                callback: Utils.bind(function () {
                                    this.setText('');
                                }, this)
                            },

                            // Fill blank space bw clear all & del indexes.
                            {
                                columnIndex: 3,
                                rowIndex: 4,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 4,
                                rowIndex: 4,
                                character: l10n.get('search.input.multikbd.backspace'),
                                key: l10n.get('search.input.multikbd.key.backSpace'),
                                labelClass: ['buttonBackspaceLabel', 'icon', 'icon-backspace-v2'],
                                callback: Utils.bind(function () {
                                    var inputText = this.getText();

                                    this.setText(inputText.slice(0, inputText.length - 1));
                                }, this)
                            },

                            // Fill two blank spaces before space index.
                            {
                                columnIndex: 0,
                                rowIndex: 5,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 1,
                                rowIndex: 5,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 2,
                                rowIndex: 5,
                                character: l10n.get('search.input.multikbd.space'),
                                key: l10n.get('search.input.multikbd.key.space'),
                                callback: Utils.bind(function () {
                                    var inputText = this.getText();

                                    this.setText(inputText + ' ');
                                }, this)
                            },
                            {
                                columnIndex: 4,
                                rowIndex: 5,
                                character: l10n.get('search.input.multikbd.swapNumbers'),
                                key: l10n.get('search.input.multikbd.key.swapKey'),
                                callback: Utils.bind(function (keyEvent) {
                                    keyEvent.target.bubbleEvent(new SwapKeysetEvent(l10n.get('search.input.multikbd.swapNumbers')));
                                }, this)
                            }
                        ]
                    },
                    {

                        // Letter '-' has special meaning for TAL keyboard. Since we need
                        // to use it literally, we use custom definition.
                        keys: ['123456', '7890&,', '.’____', '______'], // here X is placeholder for the '-' key
                        swap: l10n.get('search.input.multikbd.swapNumbers'),
                        custom: [
                            {
                                columnIndex: 2,
                                rowIndex: 2,
                                character: l10n.get('search.input.multikbd.clearAll'),
                                key: l10n.get('search.input.multikbd.key.clearAll'),
                                callback: Utils.bind(function () {
                                    this.setText('');
                                }, this)
                            },

                            // Fill blank space bw clear all & del indexes.
                            {
                                columnIndex: 3,
                                rowIndex: 2,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 4,
                                rowIndex: 2,
                                character: l10n.get('search.input.multikbd.backspace'),
                                key: l10n.get('search.input.multikbd.key.backSpace'),
                                labelClass: ['buttonBackspaceLabel', 'icon', 'icon-backspace-v2'],
                                callback: Utils.bind(function () {
                                    var inputText = this.getText();

                                    this.setText(inputText.slice(0, inputText.length - 1));
                                }, this)
                            },

                            // Fill two blank spaces before space index.
                            {
                                columnIndex: 0,
                                rowIndex: 3,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 1,
                                rowIndex: 3,
                                character: '',
                                key: 'filler',
                                labelClass: 'filler'
                            },
                            {
                                columnIndex: 2,
                                rowIndex: 3,
                                character: l10n.get('search.input.multikbd.space'),
                                key: l10n.get('search.input.multikbd.key.space'),
                                callback: Utils.bind(function () {
                                    var inputText = this.getText();

                                    this.setText(inputText + ' ');
                                }, this)
                            },
                            {
                                columnIndex: 4,
                                rowIndex: 3,
                                character: l10n.get('search.input.multikbd.swapLetters'),
                                key: l10n.get('search.input.multikbd.key.swapKey'),
                                callback: Utils.bind(function (keyEvent) {
                                    keyEvent.target.bubbleEvent(new SwapKeysetEvent(l10n.get('search.input.multikbd.swapLetters')));
                                }, this)
                            }
                        ]
                    }
                ]
            });

            this._listeners = [];
            this.getKeyboard().setMaximumLength(50);
            this.getKeyboard().setContinuousListener(true);
            this.getSwapList().removeChildWidgets();
            this._build();
        },

        /**
         * Builds&initializes the MultipleKeyboard widget.
         *
         * @private
         */
        _build: function () {
            this.addClass('multikbd');
            this._registerListener('keydown', this._keyboard, this._onKeyDownHandler);
        },

        /**
         * Adds bound event listener to given target and makes sure, it is removed once widget
         * is disposed of.
         *
         * @param {string} eventType - Type of the event to handle (keydown, textchange, etc...).
         * @param {Object} target - Event target.
         * @param {Object} listener - Event listener.
         * @private
         */
        _registerListener: function (eventType, target, listener) {
            var boundListener = Utils.bind(listener, target);

            target.addEventListener(eventType, boundListener);
            this._listeners.push({
                target: target,
                eventType: eventType,
                listener: boundListener
            });
        },

        /**
         * Cleanup routine. Removes registered event listeners.
         */
        dispose: function () {
            var i, listener;

            for (i = 0; i < this._listeners.length; i++) {
                listener = this._listeners[i];
                listener.target.removeEventListener(listener.eventType, listener.listener);
            }
        },

        /**
         * Resets keyboard state.
         */
        reset: function () {
            this._keyboard.bubbleEvent(new SwapKeysetEvent('ABC'));
            this.setText('');
            this._keyboard.setActiveChildKey('a');
        },

        /**
         * Populate the base keyboard with the keys in the
         * keyset. Uses labelClass.
         *
         * @param {Object} keyset - The keyset to use.
         * @param {string} keyset.keys - The keys to set.
         * @param {Array} keyset.custom - The custom keys to place.
         * @private
         */
        _populateKeyboardWithKeyset: function (keyset) {
            var customKeys = keyset.custom,
                keyboard = this._keyboard,
                keys = keyset.keys,
                options = {
                    labelEnableHTML: true
                },
                cols = keys.length,
                rows = 1;

            /*
             * Make sure the keyboard has the proper col/row
             * values when passing in an array, this can be
             * used for things like keypads.
             */
            if (Utils.isArray(keys)) {
                cols = keys[0].length;
                rows = keys.length;
                keys = keys.join('');
            }

            keyboard.removeChildWidgets();
            keyboard.setCols(cols);
            keyboard.setRows(rows);
            keyboard.setKeyboardKeys(keys, options);

            if (customKeys) {
                Utils.each(customKeys, function (customKey) {
                    keyboard.addCustomKey(customKey.columnIndex, customKey.rowIndex || 0, {
                        labelEnableHTML: true,
                        label: customKey.character,
                        callback: customKey.callback,
                        key: customKey.key,
                        labelClass: customKey.labelClass
                    });
                });
            }

            keyboard.render(RuntimeContext.getDevice());
        },

        /**
         * Handles the key down event. Will handle the cases of large buttons.
         *
         * @param {KeyEvent} evt - Key event.
         * @private
         */
        _onKeyDownHandler: function _onKeyDownHandler (evt) {
            var keyCode = evt.keyCode,
                keyboard = this.parentWidget.parentWidget,
                isSpecialKeysetActive = keyboard.getActiveKeyset().swap !== 'ABC',
                activeChildIndex = this.getActiveChildWidgetIndex(),
                yLetterIndex = isSpecialKeysetActive ? 12 : 24,
                zLetterIndex = isSpecialKeysetActive ? 13 : 25,
                clearAllIndex = isSpecialKeysetActive ? 14 : 26,
                deleteButtonIndex = isSpecialKeysetActive ? 15 : 27,
                spaceButtonIndex = isSpecialKeysetActive ? 30 : 32,
                spaceButtonFill1 = isSpecialKeysetActive ? 18 : 30,
                spaceButtonFill2 = isSpecialKeysetActive ? 19 : 31;

            if (evt.keyCode === KeyEvent.VK_BACK && keyboard.getActiveKeyset().swap !== 'ABC') {
                evt.stopPropagation();
                keyboard.setActiveKeysetByIndex(0);
            }

            switch (activeChildIndex) {
                case clearAllIndex:

                    // CLEAR ALL button.
                if (keyCode === KeyEvent.VK_UP) {

                    // Set the previously active index before focusing the space button.
                    if (this._prevActiveIndex) {
                        this.setActiveChildKey(this.getChildWidgetByIndex(this._prevActiveIndex).getDataItem());
                    }
                }
                break;
                case deleteButtonIndex:

                    // DELETE button.
                    if (keyCode === KeyEvent.VK_RIGHT) {
                        this.setActiveChildKey('backspace');
                    } else if (keyCode === KeyEvent.VK_DOWN || keyCode === KeyEvent.VK_LEFT) {
                        this.setActiveChildKey('clearall');
                    }
                    break;
                case spaceButtonFill1:
                case spaceButtonFill2:

                    // SPACE button.
                    if (keyCode === KeyEvent.VK_DOWN) {
                        this._prevActiveIndex = activeChildIndex === spaceButtonFill1 ? yLetterIndex : zLetterIndex;
                        this.setActiveChildKey('space');
                    } else if (keyCode === KeyEvent.VK_RIGHT && activeChildIndex === spaceButtonFill2) {
                        this.setActiveChildKey('swap');
                    } else {
                        this.setActiveChildKey('space');
                    }
                    break;
                default:
                    if (activeChildIndex !== spaceButtonIndex) {
                        this._prevActiveIndex = null;
                    }

            }
        }
    });

    return MultipleKeyboard;
});