From 74fee8a1fd06ec2979cbceb6e2871454b51d6dac Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 18 Oct 2014 11:21:43 +0100 Subject: [PATCH] WebTV: Code cosmetics --- src/webui/static/tv.js | 886 ++++++++++++++++++++--------------------- 1 file changed, 436 insertions(+), 450 deletions(-) diff --git a/src/webui/static/tv.js b/src/webui/static/tv.js index 91694382..1c610a28 100644 --- a/src/webui/static/tv.js +++ b/src/webui/static/tv.js @@ -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; + 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); + }); + } + } } - }, - 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); - }); + }); + 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( - '', - '
', - '{name}', - '
', - '
'), - - 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); + 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( + '', + '
', + '{name}', + '
', + '
' + ), + + 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'); + } + } } - }, - 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()) { + switch(e.getKey()) { - case VK_LEFT: - this.fireEvent('navleft'); - break; + case VK_UP: + this.fireEvent('navup', 1); + break; - case VK_RIGHT: - this.fireEvent('navright'); - break; + case VK_DOWN: + this.fireEvent('navdown', 1); + break; - case VK_UP: - this.fireEvent('navup', 1); - break; + case VK_LEFT: + case VK_PAGE_UP: + var cnt = this.visibleItems(); + this.fireEvent('pageup', cnt); + break; - case VK_DOWN: - this.fireEvent('navdown', 1); - break; + case VK_RIGHT: + case VK_PAGE_DOWN: + var cnt = this.visibleItems(); + this.fireEvent('pagedown', cnt); + break; - case VK_PAGE_UP: - var cnt = this.visibleItems(); - this.fireEvent('pageup', cnt); - break; + case VK_HOME: + this.fireEvent('pagefirst'); + break; - case VK_PAGE_DOWN: - var cnt = this.visibleItems(); - this.fireEvent('pagedown', cnt); - break; + case VK_END: + this.fireEvent('pagelast'); + break; - case VK_HOME: - this.fireEvent('pagefirst'); - break; + case VK_SPACE: + case VK_ENTER: + this.fireEvent('naventer'); + break; - case VK_END: - this.fireEvent('pagelast'); - break; + case VK_BACKSPACE: + case VK_ESCAPE: + case VK_BACK: + this.fireEvent('navback'); + break; - case VK_SPACE: - case VK_ENTER: - this.fireEvent('naventer'); - break; + default: + return false; + } - case VK_BACKSPACE: - case VK_ESCAPE: - case VK_BACK: - this.fireEvent('navback'); - break; + e.stopEvent(); + return true; - default: - return false; - } - - 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