]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
WebTV: Code cosmetics
authorIan <ian@sproink.co.uk>
Sat, 18 Oct 2014 10:21:43 +0000 (11:21 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 20 Oct 2014 17:38:09 +0000 (19:38 +0200)
src/webui/static/tv.js

index 91694382c358c3bf0f3ff90cdd269db17d6bcd3d..1c610a2801dcbe518b8c8d4676e2957ef23d9e26 100644 (file)
@@ -1,4 +1,3 @@
-
 Ext.namespace('tv');
 Ext.namespace('tv.ui');
 
@@ -52,7 +51,6 @@ if (VK_PAGE_UP === undefined)
 if (VK_PAGE_DOWN === undefined)
     var VK_PAGE_DOWN = 0x22;
 
-
 tv.ui.VideoPlayer = Ext.extend(Ext.Panel, (function() {
 
     var profiles = {
@@ -88,225 +86,225 @@ tv.ui.VideoPlayer = Ext.extend(Ext.Panel, (function() {
     };
 
     return {
-    constructor: function(config) {
-        this.params = {};
-        tv.ui.VideoPlayer.superclass.constructor.call(this, config);
-
-        Ext.applyIf(this.params, {
-            profile   : '',        // stream profile
-            playlist  : false      // don't use m3u8 playlist
-        });
-    },
-
-    initComponent: function() {
-        Ext.apply(this, {
-        baseCls     : 'tv-video-player',
-        html        : '',
-        bufferLength: 3000, //ms
-
-        listeners: {
-            beforedestroy: {
-                fn: function(dv, items) {
-                    this.video = null;
-                }
-            },
-            bodyresize: {
-                fn: function(panel, width, height) {
-                    this.video.setSize(width, height);
+        constructor: function(config) {
+            this.params = {};
+            tv.ui.VideoPlayer.superclass.constructor.call(this, config);
+    
+            Ext.applyIf(this.params, {
+                profile   : '',        // stream profile
+                playlist  : false      // don't use m3u8 playlist
+            });
+        },
+    
+        initComponent: function() {
+            Ext.apply(this, {
+                baseCls     : 'tv-video-player',
+                html        : '',
+                bufferLength: 3000, //ms
+    
+                listeners: {
+                    beforedestroy: {
+                        fn: function(dv, items) {
+                            this.video = null;
+                        }
+                    },
+                    bodyresize: {
+                        fn: function(panel, width, height) {
+                            this.video.setSize(width, height);
+                        }
+                    },
+                    render: {
+                        fn: function() {
+                            this.message = this.body.createChild({
+                                tag : 'div',
+                                cls : 'tv-video-message',
+                                html: ''
+                            });
+                            this.message.setVisibilityMode(Ext.Element.DISPLAY);
+                            this.message.hide();
+    
+                            this.video = this.body.createChild({
+                                tag     : 'video',
+                                html    : "Your browser doesn't support html5 video"
+                            });
+    
+                            this.source = this.video.createChild({tag: 'source'});
+                            this.source.dom.addEventListener('error', this.error.bind(this));
+    
+                            this.stop();
+    
+                            var self = this;
+                            this.video.dom.addEventListener('error', this.error.bind(this));
+                            this.video.dom.addEventListener('loadeddata', function() {
+                                setTimeout(function() {
+                                    self.play();
+                                },
+                                self.bufferLength);
+                            });
+                        }
+                    }
                 }
-            },
-            render: {
-                fn: function() {
-                    this.message = this.body.createChild({
-                        tag : 'div',
-                        cls : 'tv-video-message',
-                        html: ''
-                    });
-                    this.message.setVisibilityMode(Ext.Element.DISPLAY);
-                    this.message.hide();
-
-                    this.video = this.body.createChild({
-                        tag     : 'video',
-                        html    : "Your browser doesn't support html5 video"
-                    });
-
-                    this.source = this.video.createChild({tag: 'source'});
-                    this.source.dom.addEventListener('error', this.error.bind(this));
-
-                    this.stop();
-
-                    var self = this;
-                    this.video.dom.addEventListener('error', this.error.bind(this));
-                    this.video.dom.addEventListener('loadeddata', function() {
-                        setTimeout(function() {
-                            self.play();
-                        },
-                        self.bufferLength);
-                    });
+            });
+            tv.ui.VideoPlayer.superclass.initComponent.apply(this, arguments);
+        },
+    
+        _getUrl: function(uuid, params) {
+            var url = '';
+    
+            if(params.playlist)
+                url += 'playlist/channel/'
+            else
+                url += 'stream/channel/'
+    
+            url += uuid;
+    
+            if (params.profile)
+                url += "?profile=" + params.profile;
+    
+            return url;
+        },
+    
+        _getProfile: function() {
+            var el = this.video.dom;
+    
+            // chrome can handle h264+aac within mkv, given that h264 codecs are available
+            if(Ext.isChrome &&
+              el.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') == 'probably')
+                return profiles['mkv'];
+    
+            for (var key in profiles)
+                if(el.canPlayType(profiles[key].mimetype) == 'probably')
+                    return profiles[key];
+    
+            for (var key in profiles)
+                if(el.canPlayType(profiles[key].mimetype) == 'maybe')
+                    return profiles[key];
+    
+            return {};
+        },
+    
+        error: function(e) {
+            var url = this.source.dom.src;
+    
+            if(url && url != document.location.href) {
+                this.body.removeClass('tv-video-loading');
+                this.body.removeClass('tv-video-idle');
+                this.body.addClass('tv-video-error');
+                this.video.hide();
+    
+                this.message.update('An unknown error occurred.');
+    
+                var err = e.target.error;
+    
+                if(err) {
+                    switch (err.code) {
+    
+                        case err.MEDIA_ERR_ABORTED:
+                            this.message.update('You aborted the video playback.');
+                            break;
+    
+                        case err.MEDIA_ERR_NETWORK:
+                            this.message.update('A network error caused the video ' +
+                                'download to fail part-way.');
+                            break;
+    
+                        case err.MEDIA_ERR_DECODE:
+                            this.message.update('The video playback was aborted due to ' +
+                                'a corruption problem or because the video ' +
+                                'used features your browser did not support.');
+                            break;
+    
+                        case err.MEDIA_ERR_SRC_NOT_SUPPORTED:
+                            this.message.update('The video could not be loaded, either because ' +
+                                'the server or network failed or because the ' +
+                                'format is not supported.');
+                            break;
+                    }
                 }
+                this.message.show();
             }
-        }
-        });
-        tv.ui.VideoPlayer.superclass.initComponent.apply(this, arguments);
-    },
-
-    _getUrl: function(uuid, params) {
-        var url = '';
-
-        if(params.playlist)
-            url += 'playlist/channel/'
-        else
-            url += 'stream/channel/'
-
-        url += uuid;
-
-        if (params.profile)
-            url += "?profile=" + params.profile;
-
-        return url;
-    },
-
-    _getProfile: function() {
-        var el = this.video.dom;
-
-        // chrome can handle h264+aac within mkv, given that h264 codecs are available
-        if(Ext.isChrome &&
-           el.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"') == 'probably')
-        return profiles['mkv'];
-
-        for (var key in profiles)
-            if(el.canPlayType(profiles[key].mimetype) == 'probably')
-                return profiles[key];
-
-        for (var key in profiles)
-            if(el.canPlayType(profiles[key].mimetype) == 'maybe')
-                return profiles[key];
-
-        return {};
-    },
-
-    error: function(e) {
-        var url = this.source.dom.src;
-
-        if(url && url != document.location.href) {
+        },
+    
+        stop: function() {
+            this.message.hide();
+            this.body.removeClass('tv-video-loading');
+            this.body.removeClass('tv-video-error');
+            this.body.addClass('tv-video-idle');
+            this.source.dom.src = '';
+            this.video.dom.load();
+        },
+    
+        pause: function() {
+            this.video.dom.pause();
+        },
+    
+        setVolume: function(vol) {
+            this.video.dom.volume = vol / 100.0;
+        },
+    
+        getVolume: function() {
+            return Math.round(100 * this.video.dom.volume);
+        },
+    
+        setDisplaySize: function(width, height) {
+            this.video.setSize(width, height);
+        },
+    
+        setProfile: function(pro) {
+            this.params.profile = pro;
+        },
+    
+        isIdle: function() {
+            return this.body.hasClass('tv-video-idle');
+        },
+    
+        fullscreen: function() {
+            var dom  = this.video.dom;
+    
+            if(typeof dom.requestFullScreen !== 'undefined')
+                dom.requestFullScreen();
+    
+            else if(typeof dom.mozRequestFullScreen !== 'undefined')
+                dom.mozRequestFullScreen();
+    
+            else if(typeof dom.webkitRequestFullScreen !== 'undefined')
+                dom.webkitEnterFullscreen();
+        },
+    
+        play: function() {
+            this.message.hide();
             this.body.removeClass('tv-video-loading');
             this.body.removeClass('tv-video-idle');
-            this.body.addClass('tv-video-error');
+            this.body.removeClass('tv-video-error');
+    
+            this.video.show();
+            this.video.dom.play();
+        },
+    
+        zapTo: function(uuid, config) {
+            var config = config || {}
+            var params = {}
+    
+            if (!this.params.profile)
+                Ext.apply(params, this._getProfile(), this.params);
+            else
+                Ext.apply(params, this.params);
+    
+            Ext.apply(params, config);
+    
             this.video.hide();
-
-            this.message.update('An unknown error occurred.');
-
-            var err = e.target.error;
-
-            if(err) {
-                switch (err.code) {
-
-                case err.MEDIA_ERR_ABORTED:
-                    this.message.update('You aborted the video playback.');
-                break;
-
-                case err.MEDIA_ERR_NETWORK:
-                    this.message.update('A network error caused the video ' +
-                         'download to fail part-way.');
-                break;
-
-                case err.MEDIA_ERR_DECODE:
-                    this.message.update('The video playback was aborted due to ' +
-                        'a corruption problem or because the video ' +
-                        'used features your browser did not support.');
-                break;
-
-                case err.MEDIA_ERR_SRC_NOT_SUPPORTED:
-                    this.message.update('The video could not be loaded, either because ' +
-                        'the server or network failed or because the ' +
-                        'format is not supported.');
-                break;
-                }
-            }
+            this.stop();
+    
+            this.message.update('Loading...');
             this.message.show();
+    
+            this.body.removeClass('tv-video-idle');
+            this.body.removeClass('tv-video-error');
+            this.body.addClass('tv-video-loading');
+    
+            this.source.dom.src = this._getUrl(uuid, params);
+            this.video.dom.load();
         }
-    },
-
-    stop: function() {
-        this.message.hide();
-        this.body.removeClass('tv-video-loading');
-        this.body.removeClass('tv-video-error');
-        this.body.addClass('tv-video-idle');
-        this.source.dom.src = '';
-        this.video.dom.load();
-    },
-
-    pause: function() {
-        this.video.dom.pause();
-    },
-
-    setVolume: function(vol) {
-        this.video.dom.volume = vol / 100.0;
-    },
-
-    getVolume: function() {
-        return Math.round(100 * this.video.dom.volume);
-    },
-
-    setDisplaySize: function(width, height) {
-        this.video.setSize(width, height);
-    },
-
-    setProfile: function(pro) {
-        this.params.profile = pro;
-    },
-
-    isIdle: function() {
-        return this.body.hasClass('tv-video-idle');
-    },
-
-    fullscreen: function() {
-        var dom  = this.video.dom;
-
-        if(typeof dom.requestFullScreen !== 'undefined')
-            dom.requestFullScreen();
-
-        else if(typeof dom.mozRequestFullScreen !== 'undefined')
-            dom.mozRequestFullScreen();
-
-        else if(typeof dom.webkitRequestFullScreen !== 'undefined')
-            dom.webkitEnterFullscreen();
-    },
-
-    play: function() {
-        this.message.hide();
-        this.body.removeClass('tv-video-loading');
-        this.body.removeClass('tv-video-idle');
-        this.body.removeClass('tv-video-error');
-
-        this.video.show();
-        this.video.dom.play();
-    },
-
-    zapTo: function(uuid, config) {
-        var config = config || {}
-        var params = {}
-
-        if (!this.params.profile)
-            Ext.apply(params, this._getProfile(), this.params);
-        else
-            Ext.apply(params, this.params);
-
-        Ext.apply(params, config);
-
-        this.video.hide();
-        this.stop();
-
-        this.message.update('Loading...');
-        this.message.show();
-
-        this.body.removeClass('tv-video-idle');
-        this.body.removeClass('tv-video-error');
-        this.body.addClass('tv-video-loading');
-
-        this.source.dom.src = this._getUrl(uuid, params);
-        this.video.dom.load();
-    }
     };
 }()));
 
@@ -314,49 +312,51 @@ tv.ui.VideoPlayer = Ext.extend(Ext.Panel, (function() {
 tv.ui.ChannelList = Ext.extend(Ext.DataView, {
 
     initComponent: function() {
-    Ext.apply(this, {
-        cls: 'tv-list',
-        overClass: 'tv-list-item-over',
-        selectedClass: 'tv-list-item-selected',
-        itemSelector:'div.tv-list-item',
-        singleSelect: true,
-        tpl: new Ext.XTemplate(
-        '<tpl for=".">',
-        '<div class="tv-list-item" id="{uuid}">',
-        '<img src="{icon_public_url}" title="{name}">{name}',
-        '</div>',
-        '</tpl>'),
-
-        listeners: {
-        selectionchange: {
-            fn: function(dv, items) {
-            if(items.length == 0)
-                return;
-
-            var node = this.getNode(items[0]);
-            node = Ext.get(node);
-            node.scrollIntoView(this.el);
-            }
-        },
-        dblclick: {
-            fn: function() {
-            this.fireEvent('naventer');
+        Ext.apply(this, {
+            cls: 'tv-list',
+            overClass: 'tv-list-item-over',
+            selectedClass: 'tv-list-item-selected',
+            itemSelector:'div.tv-list-item',
+            singleSelect: true,
+            tpl: new Ext.XTemplate(
+                '<tpl for=".">',
+                '<div class="tv-list-item" id="{uuid}">',
+                '<img src="{icon_public_url}" title="{name}">{name}',
+                '</div>',
+                '</tpl>'
+            ),
+    
+            listeners: {
+                selectionchange: {
+                    fn: function(dv, items) {
+                        if(items.length == 0)
+                            return;
+    
+                        var node = this.getNode(items[0]);
+                        node = Ext.get(node);
+                        node.scrollIntoView(this.el);
+                    }
+                },
+                dblclick: {
+                    fn: function() {
+                    this.fireEvent('naventer');
+                    }
+                }
             }
-        }
-        }
-    });
-
-    this.addEvents(
-        'navup',
-        'navdown',
-        'navleft',
-        'navright',
-        'navback',
-        'naventer',
-        'pageup',
-        'pagedown'
+        });
+    
+        this.addEvents(
+            'navup',
+            'navdown',
+            'navback',
+            'naventer',
+            'pageup',
+            'pagedown',
+            'pagefirst',
+            'pagelast'
         );
-    tv.ui.ChannelList.superclass.initComponent.apply(this, arguments);
+    
+        tv.ui.ChannelList.superclass.initComponent.apply(this, arguments);
     },
 
     visibleItems: function() {
@@ -371,221 +371,207 @@ tv.ui.ChannelList = Ext.extend(Ext.DataView, {
 
     onRender : function(ct, position) {
         tv.ui.ChannelList.superclass.onRender.call(this, ct, position);
-    Ext.dd.ScrollManager.register(this.el);
+        Ext.dd.ScrollManager.register(this.el);
 
-    this.getTemplateTarget().set({tabindex: Ext.id(undefined, '0')});
-    this.getTemplateTarget().on('keydown', function(e) {
+        this.getTemplateTarget().set({tabindex: Ext.id(undefined, '0')});
+        this.getTemplateTarget().on('keydown', function(e) {
 
 //IH
-    console.log('keypress:', e.getKey());
+            console.log('keypress:', e.getKey());
 //
-        switch(e.getKey()) {
-
-        case VK_LEFT:
-            this.fireEvent('navleft');
-            break;
-
-        case VK_RIGHT:
-            this.fireEvent('navright');
-        break;
-
-        case VK_UP:
-            this.fireEvent('navup', 1);
-        break;
-
-        case VK_DOWN:
-            this.fireEvent('navdown', 1);
-        break;
-
-        case VK_PAGE_UP:
-            var cnt = this.visibleItems();
-            this.fireEvent('pageup', cnt);
-        break;
-
-        case VK_PAGE_DOWN:
-            var cnt = this.visibleItems();
-            this.fireEvent('pagedown', cnt);
-        break;
-
-        case VK_HOME:
-            this.fireEvent('pagefirst');
-        break;
-
-        case VK_END:
-            this.fireEvent('pagelast');
-        break;
-
-        case VK_SPACE:
-        case VK_ENTER:
-            this.fireEvent('naventer');
-        break;
-
-        case VK_BACKSPACE:
-        case VK_ESCAPE:
-        case VK_BACK:
-            this.fireEvent('navback');
-        break;
-
-        default:
-        return false;
-        }
+            switch(e.getKey()) {
+
+                case VK_UP:
+                    this.fireEvent('navup', 1);
+                    break;
+
+                case VK_DOWN:
+                    this.fireEvent('navdown', 1);
+                    break;
+
+                case VK_LEFT:
+                case VK_PAGE_UP:
+                    var cnt = this.visibleItems();
+                    this.fireEvent('pageup', cnt);
+                    break;
+
+                case VK_RIGHT:
+                case VK_PAGE_DOWN:
+                    var cnt = this.visibleItems();
+                    this.fireEvent('pagedown', cnt);
+                    break;
+
+                case VK_HOME:
+                    this.fireEvent('pagefirst');
+                    break;
+
+                case VK_END:
+                    this.fireEvent('pagelast');
+                    break;
+
+                case VK_SPACE:
+                case VK_ENTER:
+                    this.fireEvent('naventer');
+                    break;
+
+                case VK_BACKSPACE:
+                case VK_ESCAPE:
+                case VK_BACK:
+                    this.fireEvent('navback');
+                    break;
+
+                default:
+                    return false;
+                }
 
-        e.stopEvent();
-        return true;
+            e.stopEvent();
+            return true;
 
-    }.bind(this));
+        }.bind(this));
     }
 });
 
 tv.app = function() {
     return {
-    init: function() {
-
-        var channelStore = new Ext.data.JsonStore({
-            autoLoad: {params:{start: 0, limit: 8}}, // limit initial page size to 8
-            root : 'entries',
-            fields : ['icon_public_url', 'number', 'name', 'uuid'],
-            id : 'uuid',
-            sortInfo : {
-                field : 'number', // WIBI: Ideally, sort the whole channel list at source
-                direction : "ASC"
-            },
-            url : "api/channel/grid"
-        });
-
-        var videoPlayer = new tv.ui.VideoPlayer({
-            params: { },
-            renderTo: Ext.getBody()
-        });
-
-        videoPlayer.setDisplaySize('100%', '00%');
-
-        var chList = new tv.ui.ChannelList({
-            autoScroll: true,
-            store: channelStore
-        });
-
-// Play button that calls the "I've pressed Enter!" event when clicked
-
-        var playButton = new Ext.Button({
-            text: 'Play Selected Channel',
-            handler: function() {
-                chList.fireEvent('naventer');
-            }
-        });
-
-// Paging bar so you can move through the list of channels
-
-        var pageBar = new Ext.PagingToolbar({
-            store: channelStore,
-            pageSize: 8 // replicates initial page size
-        });
-
-        var chListPanel1 = new Ext.Panel({
-            items: [ pageBar, playButton ],
-            cls: 'tv-channel-list-header'
-        });
-
-        var chListPanel2 = new Ext.Panel({
-            items: [ chList ],
-            cls: 'tv-channel-list-content'
-        });
-
-        var chListPanel = new Ext.Panel({
-            title:'Channels',
-            items: [ chListPanel1, chListPanel2 ],
-            cls: 'tv-channel-list',
-            renderTo: Ext.getBody()
-        });
-
-        window.onresize = function() {
-            var h = chListPanel.el.getHeight();
-            h -= chListPanel.header.getHeight();
-            h -= 250;
-            chList.setHeight(h);
-        };
-
-        chListPanel.on('show', function() {
-            window.onresize();
-        });
-
-        chList.on('navback', function() {
-            chListPanel.hide();
-            chList.blur();
-        });
-
-        chList.on('naventer', function() {
-            var indices = this.getSelectedIndexes();
-            if(indices.length == 0)
-                return;
-
-            var item = this.store.getAt(indices[0]);
-            videoPlayer.zapTo(item.id);
-            chListPanel.hide();
-            chList.blur();
-        });
-
-        chList.on('navup', function(cnt) {
-            var indices = chList.getSelectedIndexes();
-
-//IH
-            console.log(indices);
-            console.log(indices.length);
-            console.log(this.store.getTotalCount());
-//
-
-            if(indices.length == 0)
-                this.select(this.store.getTotalCount() - 1);
-            else if(indices[0] - cnt >= 0)
-                this.select(indices[0] - cnt);
-            else
-                this.select(0);
-        });
-
-        chList.on('navdown', function(cnt) {
-            var indices = chList.getSelectedIndexes();
-            if(indices.length == 0)
-                this.select(0);
-            else if(indices[0] + cnt < this.store.getTotalCount())
-                this.select(indices[0] + cnt);
-            else
-                this.select(this.store.getTotalCount() - 1);
-        });
-
-        chList.on('navleft', function() {
-            pageBar.movePrevious();
-        });
-
-        chList.on('navright', function() {
-            pageBar.moveNext();
-        });
-
-        chList.on('pageup', function() {
-            pageBar.movePrevious();
-        });
-
-        chList.on('pagedown', function() {
-            pageBar.moveNext();
-        });
-
-        chList.on('pagefirst', function() {
-            pageBar.moveFirst();
-        });
-
-        chList.on('pagelast', function() {
-            pageBar.moveLast();
-        });
-
-        Ext.getDoc().on('keydown', function(e) {
-            switch(e.getKey()) {
-            case VK_ENTER:
-                chListPanel.show();
-                chList.focus();
-            }
-        });
-
-        chListPanel.show();
-        chList.focus();
-    }
+        init: function() {
+    
+            var channelStore = new Ext.data.JsonStore({
+                autoLoad: {params:{start: 0, limit: 8}}, // limit initial page size to 8
+                root : 'entries',
+                fields : ['icon_public_url', 'number', 'name', 'uuid'],
+                id : 'uuid',
+                sortInfo : {
+                    field : 'number', // WIBI: Ideally, sort the whole channel list at source
+                    direction : "ASC"
+                },
+                url : "api/channel/grid"
+            });
+    
+            var videoPlayer = new tv.ui.VideoPlayer({
+                params: { },
+                renderTo: Ext.getBody()
+            });
+    
+            videoPlayer.setDisplaySize('100%', '00%');
+    
+            var chList = new tv.ui.ChannelList({
+                autoScroll: true,
+                store: channelStore
+            });
+    
+    // Play button that calls the "I've pressed Enter!" event when clicked
+    
+            var playButton = new Ext.Button({
+                text: 'Play Selected Channel',
+                handler: function() {
+                    chList.fireEvent('naventer');
+                }
+            });
+    
+    // Paging bar so you can move through the list of channels
+    
+            var pageBar = new Ext.PagingToolbar({
+                store: channelStore,
+                pageSize: 8 // replicates initial page size
+            });
+    
+            var chListPanel1 = new Ext.Panel({
+                items: [ pageBar, playButton ],
+                cls: 'tv-channel-list-header'
+            });
+    
+            var chListPanel2 = new Ext.Panel({
+                items: [ chList ],
+                cls: 'tv-channel-list-content'
+            });
+    
+            var chListPanel = new Ext.Panel({
+                title:'Channels',
+                items: [ chListPanel1, chListPanel2 ],
+                cls: 'tv-channel-list',
+                renderTo: Ext.getBody()
+            });
+    
+            window.onresize = function() {
+                var h = chListPanel.el.getHeight();
+                h -= chListPanel.header.getHeight();
+                h -= 250;
+                chList.setHeight(h);
+            };
+    
+            chListPanel.on('show', function() {
+                window.onresize();
+            });
+    
+            chList.on('navback', function() {
+                chListPanel.hide();
+                chList.blur();
+            });
+    
+            chList.on('naventer', function() {
+                var indices = this.getSelectedIndexes();
+                if(indices.length == 0)
+                    return;
+    
+                var item = this.store.getAt(indices[0]);
+                videoPlayer.zapTo(item.id);
+                chListPanel.hide();
+                chList.blur();
+            });
+    
+            chList.on('navup', function(cnt) {
+                var indices = chList.getSelectedIndexes();
+    
+    //IH
+                console.log(indices);
+                console.log(indices.length);
+                console.log(this.store.getTotalCount());
+    //
+    
+                if(indices.length == 0)
+                    this.select(this.store.getTotalCount() - 1);
+                else if(indices[0] - cnt >= 0)
+                    this.select(indices[0] - cnt);
+                else
+                    this.select(0);
+            });
+    
+            chList.on('navdown', function(cnt) {
+                var indices = chList.getSelectedIndexes();
+                if(indices.length == 0)
+                    this.select(0);
+                else if(indices[0] + cnt < this.store.getTotalCount())
+                    this.select(indices[0] + cnt);
+                else
+                    this.select(this.store.getTotalCount() - 1);
+            });
+    
+            chList.on('pageup', function() {
+                pageBar.movePrevious();
+            });
+    
+            chList.on('pagedown', function() {
+                pageBar.moveNext();
+            });
+    
+            chList.on('pagefirst', function() {
+                pageBar.moveFirst();
+            });
+    
+            chList.on('pagelast', function() {
+                pageBar.moveLast();
+            });
+    
+            Ext.getDoc().on('keydown', function(e) {
+                switch(e.getKey()) {
+                    case VK_ENTER:
+                        chListPanel.show();
+                        chList.focus();
+                }
+            });
+    
+            chListPanel.show();
+            chList.focus();
+        }
     };
 }(); // end of app