Source: components/modals/pin.js

define('application/components/modals/pin', [
    'application/components/modals/abstract',
    'rofl/lib/l10n',
    'rofl/lib/utils',
    'antie/runtimecontext',
    'application/managers/session',
    'rofl/widgets/container',
    'application/widgets/login/keyboard',
    'application/widgets/pin/input',
    'application/managers/api',
    'rofl/widgets/label',
    'rofl/events/keyevent',
    'antie/storageprovider',
    'application/widgets/detail/iconbutton',
    'rofl/widgets/verticallist'
], function (
    ModalComponent,
    L10N,
    Utils,
    RuntimeContext,
    SessionManager,
    Container,
    Keyboard,
    Input,
    ApiManager,
    Label,
    KeyEvent,
    StorageProvider,
    IconButton,
    VerticalList
) {
    'use strict';

    var l10n = L10N.getInstance(),
        inputConfig = {
            inputField: {
                opts: {
                    placeholder: l10n.get('pin.inputfield.placeholder'),
                    maxLength: 4,
                    validateLength: true,
                    maskCharacter: '*'
                }
            },
            errorMessage: l10n.get('parental.modalconfig.error')
        },
        api = ApiManager.getKPNAPI(),
        application = RuntimeContext.getCurrentApplication(),
        device = RuntimeContext.getDevice(),
        sessionManager = SessionManager.getInstance(),
        layout = application.getLayout().pin,
        storage;

    return ModalComponent.extend({

        /**
         * Initialises the component.
         */
        init: function init () {
            this._onTextValidatedBound = Utils.bind(this._onTextValidated, this);
            this._onTextChangeBound = Utils.bind(this._onTextChange, this);
            storage = device.getStorage(StorageProvider.STORAGE_TYPE_SESSION, 'storage');

            init.base.call(this, 'parental-pin-modal');
        },

        /**
         * Builds the input widget.
         *
         * @returns {Object} Input.
         * @private
         */
        _buildInput: function () {
            var input = new Input(inputConfig);

            return input;
        },

        /**
         * Creates modal component based on passed options with one button.
         */
        _createModal: function () {
            var view, title, text, overlay, verticalList, errorCode;

            this._viewList = new VerticalList();
            this.appendChildWidget(this._viewList);

            view = this._view = new Container();
            view.addClass('modal-view');

            overlay = this._overlay = new Container();
            overlay.addClass('overlay');

            verticalList = this._buttonsList = new VerticalList();
            verticalList.addClass('buttons-list');
            verticalList.focus();

            title = this._title = new Label({ text: '', classNames: 'title', enableHTML: true });

            text = this._text = new Label({ text: '', classNames: 'text', enableHTML: true });

            errorCode = this._errorCode = new Label({ text: '', classNames: ['error-code'] });

            view.appendChildWidget(title);
            view.appendChildWidget(text);
            view.appendChildWidget(errorCode);
            view.appendChildWidget(verticalList);

            this._viewList.appendChildWidget(overlay);
            this._viewList.appendChildWidget(view);
        },

        /**
         * Before show event.
         *
         * @param {Object} e - Event.
         */
        onBeforeShow: function (e) {
            var title = this._title = new Label({ text: l10n.get('parental.modalconfig.title') }),
                text = this._text = new Label({ text: e.args.description || l10n.get('parental.modalconfig.text'), enableHTML: true });

            this._successCallback = e.args.successCallback;
            this._escapeCallback = e.args.escapeCallback;
            this._errorCallback = e.args.errorCallback;
            this._callingPageKeyEvent = e.args.callingPageKeyEvent;
            this._closeOnError = e.args.closeOnError;
            this._keyEventCallback = this._callingPageKeyEvent && this._callingPageKeyEvent.keyEventCallback;
            this._callingPageKeyCodes = this._callingPageKeyEvent && this._callingPageKeyEvent.keyCodes;
            this._view.removeChildWidgets();
            this._input = this._buildInput();
            this._input.getInputField().showCursorBlink();

            title.addClass('title');
            text.addClass('text');

            this._view.appendChildWidget(title);
            this._view.appendChildWidget(text);
            this._view.appendChildWidget(this._input);

            this._input.getInputField().getCursor()
                .setStylesTo({
                    position: 'absolute',
                    left: layout.left + 'px'
                });
        },

        /**
         * After show event.
         */
        onAfterShow: function () {
            this._input.getKeyboard().focus();
        },

        /**
         * Before hide event.
         */
        onBeforeHide: function onBeforeHide () {
            onBeforeHide.base.call(this);
            this._input.getInputField().stopCursorBlink();
        },

        /**
         * On text validate bound.
         *
         */
        _onTextValidated: function () {
            var pin = this._input.getValue();

            this._onParentalPinCheck.call(this, pin);
        },

        /**
         * On text change bound. Hides error after every text change.
         */
        _onTextChange: function () {
            var text = this._input.getValue();

            if (text.length) {
                this._input.getInputField().getCursor()
                    .setStylesTo({
                        position: 'relative',
                        left: 'auto'
                    });
            } else {
                this._input.getInputField().getCursor()
                    .setStylesTo({
                        position: 'absolute',
                        left: layout.left + 'px'
                    });
            }

            this._input.hideError();
        },

        /**
         * OnKeyDownEvent.
         *
         * @param {Event} event - The event data.
         */
        _onKeyDown: function (event) {
            var keyboard = this._input.getKeyboard().getKeyboard(),
                currentText = keyboard.getText(),
                callingPageHandlesKey = false,
                character;

            // Check if the calling page should handle the keyevent.
            Utils.each(this._callingPageKeyCodes, function (keyCode) {
                if (keyCode === event.keyCode) {
                    callingPageHandlesKey = true;
                }
            });

            if (callingPageHandlesKey && Utils.isFunction(this._keyEventCallback)) {
                this.parentWidget.back();
                this._keyEventCallback(event);

                return;
            }

            switch (event.keyCode) {
                case KeyEvent.VK_0:
                case KeyEvent.VK_1:
                case KeyEvent.VK_2:
                case KeyEvent.VK_3:
                case KeyEvent.VK_4:
                case KeyEvent.VK_5:
                case KeyEvent.VK_6:
                case KeyEvent.VK_7:
                case KeyEvent.VK_8:
                case KeyEvent.VK_9:
                    character = event.keyChar;
                    currentText += character;
                    keyboard.setText(currentText);
                    break;
                case KeyEvent.VK_BACK:
                    this._onClose();
                    break;
                case KeyEvent.VK_LEFT:
                case KeyEvent.VK_RIGHT:
                    event.stopPropagation();
                    event.preventDefault();
                    break;
            }
        },

        /**
         * Checks user entered PIN against BE.
         *
         * @param {string} pin - PIN.
         * @private
         */
        _onParentalPinCheck: function (pin) {
            api.update('parental', {
                data: {
                    userPin: pin
                },
                withCredentials: true
            })
            .then(Utils.bind(function (result) {
                this.parentWidget.back();
                sessionManager.setUserPin(pin);
                storage.setItem('parental', false);
                this._successCallback(result);
            }, this))
            .catch(Utils.bind(function (result) {
                this._input.showError();
                this._input.clearInputField();

                this._input.getInputField().getCursor()
                    .setStylesTo({
                        position: 'absolute',
                        left: layout.left + 'px'
                    });

                // in case of 3 times wrong pin
                if (Utils.getNested(result, 'errorDescription') === '403-8117'
                    || Utils.getNested(result, 'resultObj', 'remainingAttempts') === 0) {
                    this.parentWidget.back();
                    application.route('modal', {
                        title: l10n.get('parental.limitation_modal.title'),
                        text: l10n.get('parental.limitation_modal.description'),
                        buttons: [
                            {
                                label: l10n.get('parental.limitation_modal.button'),
                                class: 'confirm_button',
                                button: 'confirmbutton',
                                labelname: 'confirmButtonLabel'
                            }
                        ],
                        callback: function () {
                            this._errorCallback(result);
                        }
                    });
                } else {
                    if (this._errorCallback) {
                        this._errorCallback(result);
                    }

                    if (this._closeOnError) {
                        this.parentWidget.back();
                    }
                }

            }, this));
        },

        getEscapeCallback: function () {
            return this._escapeCallback;
        },

        /**
         * Gets executed when the modal should close.
         *
         * @private
         */
        _onClose: function () {
            this.parentWidget.back();

            if (Utils.isFunction(this._escapeCallback)) {
                this._escapeCallback();
            }
        },

        /**
         * Global close function.
         *
         * @param {boolean} callEscape - True if escape function callback should execute.
         */
        close: function (callEscape) {
            this.parentWidget.back();

            if (callEscape && Utils.isFunction(this._escapeCallback)) {
                this._escapeCallback();
            }
        }
    });
});