Source: widgets/verticallist.js

/**
 * @fileOverview Requirejs module containing the antie.widgets.VerticalList class.
 * @preserve Copyright (c) 2013-present British Broadcasting Corporation. All rights reserved.
 * @license See https://github.com/fmtvp/tal/blob/master/LICENSE for full licence
 */

define(
    'antie/widgets/verticallist',
    [
        'antie/widgets/list',
        'antie/events/keyevent'
    ],
    function(List, KeyEvent) {
        'use strict';

        /**
         * The VerticalList widget is a container widget that supports spatial navigation between items using {@link KeyEvent.VK_UP} and {@link KeyEvent.VK_DOWN}.
         * @name antie.widgets.VerticalList
         * @class
         * @extends antie.widgets.List
         * @requires antie.events.KeyEvent
         * @param {String} [id] The unique ID of the widget. If excluded, a temporary internal ID will be used (but not included in any output).
         * @param {antie.Formatter} [itemFormatter] A formatter class used on each data item to generate the list item child widgets.
         * @param {antie.DataSource|Array} [dataSource] An array of data to be used to generate the list items, or an asynchronous data source.
         */
        return List.extend(/** @lends antie.widgets.VerticalList.prototype */ {
            /**
             * @constructor
             * @ignore
             */
            init: function init (id, itemFormatter, dataSource) {
                init.base.call(this, id, itemFormatter, dataSource);
                this.addClass('verticallist');

                var self = this;
                this.addEventListener('keydown', function(e) {
                    self._onKeyDown(e);
                });
            },
            /**
             * Key handler for vertical lists. Processes KeyEvent.VK_UP and KeyEvent.VK_DOWN keys and stops propagation
             * if the keypress is handled. Otherwise allows the event to be bubbled up to the parent widget to allow
             * spatial navigation out of the list.
             * @param {antie.events.KeyEvent} evt The key event.
             */
            _onKeyDown: function _onKeyDown (evt) {
                if(evt.keyCode !== KeyEvent.VK_UP && evt.keyCode !== KeyEvent.VK_DOWN) {
                    return;
                }

                var _newSelectedIndex = this._selectedIndex;
                var _newSelectedWidget = null;
                do {
                    if(evt.keyCode === KeyEvent.VK_UP) {
                        _newSelectedIndex--;
                    } else if(evt.keyCode === KeyEvent.VK_DOWN) {
                        _newSelectedIndex++;
                    }
                    if(_newSelectedIndex < 0 || _newSelectedIndex >= this._childWidgetOrder.length) {
                        break;
                    }
                    var _widget = this._childWidgetOrder[_newSelectedIndex];
                    if(_widget.isFocusable()) {
                        _newSelectedWidget = _widget;
                        break;
                    }
                } while(true);

                if(_newSelectedWidget) {
                    this.setActiveChildWidget(_newSelectedWidget);
                    evt.stopPropagation();

                }
            }
        });
    }
);