diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 3cc16c16..b7908e41 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include "tvheadend.h" @@ -44,6 +43,7 @@ #if ENABLE_LINUXDVB +#include #include "notify.h" #include "subscriptions.h" #include "dtable.h" diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index dbee117e..1e3069fc 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "tvheadend.h" #include "channels.h" #include "huffman.h" diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index 071eb9d4..51e79853 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -30,8 +30,6 @@ #include #include #include -#include -#include SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state); @@ -171,7 +169,7 @@ dvb_desc_cable_del int frequency, symrate; dvb_mux_conf_t dmc; - static const fe_modulation_t qtab [6] = { + static const dvb_fe_modulation_t qtab [6] = { DVB_MOD_QAM_AUTO, DVB_MOD_QAM_16, DVB_MOD_QAM_32, DVB_MOD_QAM_64, DVB_MOD_QAM_128, DVB_MOD_QAM_256 }; @@ -203,7 +201,7 @@ dvb_desc_cable_del dmc.u.dmc_fe_qam.symbol_rate = symrate * 100; if((ptr[6] & 0x0f) >= sizeof(qtab)) - dmc.dmc_fe_modulation = QAM_AUTO; + dmc.dmc_fe_modulation = DVB_MOD_QAM_AUTO; else dmc.dmc_fe_modulation = qtab[ptr[6] & 0x0f]; dmc.u.dmc_fe_qam.fec_inner = fec_tab[ptr[10] & 0x07]; @@ -227,26 +225,26 @@ dvb_desc_terr_del (mpegts_mux_t *mm, uint16_t onid, uint16_t tsid, const uint8_t *ptr, int len ) { - static const fe_bandwidth_t btab [8] = { + static const dvb_fe_bandwidth_t btab [8] = { DVB_BANDWIDTH_8_MHZ, DVB_BANDWIDTH_7_MHZ, DVB_BANDWIDTH_6_MHZ, DVB_BANDWIDTH_AUTO, DVB_BANDWIDTH_AUTO, DVB_BANDWIDTH_AUTO, DVB_BANDWIDTH_AUTO, DVB_BANDWIDTH_AUTO }; - static const fe_modulation_t ctab [4] = { + static const dvb_fe_modulation_t ctab [4] = { DVB_MOD_QPSK, DVB_MOD_QAM_16, DVB_MOD_QAM_64, DVB_MOD_QAM_AUTO }; - static const fe_guard_interval_t gtab [4] = { + static const dvb_fe_guard_interval_t gtab [4] = { DVB_GUARD_INTERVAL_1_32, DVB_GUARD_INTERVAL_1_16, DVB_GUARD_INTERVAL_1_8, DVB_GUARD_INTERVAL_1_4 }; - static const fe_transmit_mode_t ttab [4] = { + static const dvb_fe_transmit_mode_t ttab [4] = { DVB_TRANSMISSION_MODE_2K, DVB_TRANSMISSION_MODE_8K, DVB_TRANSMISSION_MODE_4K, DVB_TRANSMISSION_MODE_AUTO }; - static const fe_hierarchy_t htab [8] = { + static const dvb_fe_hierarchy_t htab [8] = { DVB_HIERARCHY_NONE, DVB_HIERARCHY_1, DVB_HIERARCHY_2, DVB_HIERARCHY_4, DVB_HIERARCHY_NONE, DVB_HIERARCHY_1, DVB_HIERARCHY_2, DVB_HIERARCHY_4 }; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index d0365e17..79d68a42 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -22,7 +22,9 @@ #include "input.h" +#if ENABLE_LINUXDVB #include +#endif #define DVB_VER_INT(maj,min) (((maj) << 16) + (min)) diff --git a/src/udp.c b/src/udp.c index aeaaad52..5452456b 100644 --- a/src/udp.c +++ b/src/udp.c @@ -300,9 +300,10 @@ udp_connect ( const char *subsystem, const char *name, } /* Bind to interface */ - memset(&ifr, 0, sizeof(ifr)); if (ifname && *ifname) { - snprintf(ifr.ifr_name, IFNAMSIZ, "%s", ifname); + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; if (ioctl(fd, SIOCGIFINDEX, &ifr)) { tvherror(subsystem, "%s - could not find interface %s", name, ifname); diff --git a/src/webui/static/app/acleditor.js b/src/webui/static/app/acleditor.js index bdde91b3..e3f7244d 100644 --- a/src/webui/static/app/acleditor.js +++ b/src/webui/static/app/acleditor.js @@ -1,78 +1,77 @@ tvheadend.acleditor = function() { - var fm = Ext.form; + var fm = Ext.form; - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [{ + xtype: 'checkcolumn', + header: "Enabled", + dataIndex: 'enabled', + width: 60 + }, { + header: "Username", + dataIndex: 'username', + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Password", + dataIndex: 'password', + renderer: function(value, metadata, record, row, col, store) { + return 'Hidden'; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Prefix", + dataIndex: 'prefix', + editor: new fm.TextField({ + allowBlank: false + }) + }, { + xtype: 'checkcolumn', + header: "Streaming", + dataIndex: 'streaming', + width: 100 + }, { + xtype: 'checkcolumn', + header: "Video Recorder", + dataIndex: 'dvr', + width: 100 + }, { + xtype: 'checkcolumn', + header: "All Configs (VR)", + dataIndex: 'dvrallcfg', + width: 100 + }, { + xtype: 'checkcolumn', + header: "Web Interface", + dataIndex: 'webui', + width: 100 + }, { + xtype: 'checkcolumn', + header: "Admin", + dataIndex: 'admin', + width: 100 + }, { + xtype: 'checkcolumn', + header: "Channel Tag Only", + dataIndex: 'tag_only', + width: 200 + }, { + header: "Comment", + dataIndex: 'comment', + width: 300, + editor: new fm.TextField({}) + }]}); - columns : [{ - xtype: 'checkcolumn', - header : "Enabled", - dataIndex : 'enabled', - width : 60 - }, { - header : "Username", - dataIndex : 'username', - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Password", - dataIndex : 'password', - renderer : function(value, metadata, record, row, col, store) { - return 'Hidden'; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Prefix", - dataIndex : 'prefix', - editor : new fm.TextField({ - allowBlank : false - }) - }, { - xtype: 'checkcolumn', - header : "Streaming", - dataIndex : 'streaming', - width : 100 - }, { - xtype: 'checkcolumn', - header : "Video Recorder", - dataIndex : 'dvr', - width : 100 - }, { - xtype: 'checkcolumn', - header : "All Configs (VR)", - dataIndex : 'dvrallcfg', - width : 100 - }, { - xtype: 'checkcolumn', - header : "Web Interface", - dataIndex : 'webui', - width : 100 - }, { - xtype: 'checkcolumn', - header : "Admin", - dataIndex : 'admin', - width : 100 - }, { - xtype: 'checkcolumn', - header : "Channel Tag Only", - dataIndex : 'tag_only', - width : 200 - }, { - header : "Comment", - dataIndex : 'comment', - width : 300, - editor : new fm.TextField({}) - }]}); + var UserRecord = Ext.data.Record.create( + ['enabled', 'streaming', 'dvr', 'dvrallcfg', 'admin', 'webui', 'username', 'tag_only', + 'prefix', 'password', 'comment' + ]); - var UserRecord = Ext.data.Record.create( - [ 'enabled', 'streaming', 'dvr', 'dvrallcfg', 'admin', 'webui', 'username', 'tag_only', - 'prefix', 'password', 'comment' - ]); - - return new tvheadend.tableEditor('Access control', 'accesscontrol', cm, - UserRecord, [], null, 'config_access.html', - 'group'); -} + return new tvheadend.tableEditor('Access control', 'accesscontrol', cm, + UserRecord, [], null, 'config_access.html', + 'group'); +}; diff --git a/src/webui/static/app/capmteditor.js b/src/webui/static/app/capmteditor.js index 37f55c53..21b85faf 100644 --- a/src/webui/static/app/capmteditor.js +++ b/src/webui/static/app/capmteditor.js @@ -1,106 +1,107 @@ tvheadend.capmteditor = function() { - var fm = Ext.form; + var fm = Ext.form; - function setMetaAttr(meta, record) { - var enabled = record.get('enabled'); - if (!enabled) return; + function setMetaAttr(meta, record) { + var enabled = record.get('enabled'); + if (!enabled) + return; - var connected = record.get('connected'); - if (connected == 2) { - meta.attr = 'style="color:green;"'; - } - else if (connected == 1) { - meta.attr = 'style="color:orange;"'; - } - else { - meta.attr = 'style="color:red;"'; - } - } - var selectMode = new Ext.form.ComboBox({ - displayField:'name', - valueField: 'res', - value: 2, - mode: 'local', - editable: false, - triggerAction: 'all', - emptyText: 'Select mode...', - store: new Ext.data.SimpleStore({ - fields: ['res','name'], - id: 0, - data: [ - ['2','Recent OSCam (svn rev >= 9095)'], - ['1','Older OSCam'], - ['0','Wrapper (capmt_ca.so)'] - ] - }) - }); + var connected = record.get('connected'); + if (connected === 2) { + meta.attr = 'style="color:green;"'; + } + else if (connected === 1) { + meta.attr = 'style="color:orange;"'; + } + else { + meta.attr = 'style="color:red;"'; + } + } + var selectMode = new Ext.form.ComboBox({ + displayField: 'name', + valueField: 'res', + value: 2, + mode: 'local', + editable: false, + triggerAction: 'all', + emptyText: 'Select mode...', + store: new Ext.data.SimpleStore({ + fields: ['res', 'name'], + id: 0, + data: [ + ['2', 'Recent OSCam (svn rev >= 9095)'], + ['1', 'Older OSCam'], + ['0', 'Wrapper (capmt_ca.so)'] + ] + }) + }); - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns: [ { - xtype: 'checkcolumn', - header : "Enabled", - dataIndex : 'enabled', - width : 60 - }, { - header: "Mode", - dataIndex: 'oscam', - width: 150, - editor: selectMode - }, { - header : "Camd.socket Filename", - dataIndex : 'camdfilename', - width : 200, - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Listenport", - dataIndex : 'port', - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Comment", - dataIndex : 'comment', - width : 400, - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField() - } ]}); + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [{ + xtype: 'checkcolumn', + header: "Enabled", + dataIndex: 'enabled', + width: 60 + }, { + header: "Mode", + dataIndex: 'oscam', + width: 150, + editor: selectMode + }, { + header: "Camd.socket Filename", + dataIndex: 'camdfilename', + width: 200, + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Listenport", + dataIndex: 'port', + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Comment", + dataIndex: 'comment', + width: 400, + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField() + }]}); - var rec = Ext.data.Record.create([ 'enabled', 'connected', 'camdfilename', - 'port', 'oscam', 'comment' ]); + var rec = Ext.data.Record.create(['enabled', 'connected', 'camdfilename', + 'port', 'oscam', 'comment']); - store = new Ext.data.JsonStore({ - root : 'entries', - fields : rec, - url : "tablemgr", - autoLoad : true, - id : 'id', - baseParams : { - table : 'capmt', - op : "get" - } - }); + store = new Ext.data.JsonStore({ + root: 'entries', + fields: rec, + url: "tablemgr", + autoLoad: true, + id: 'id', + baseParams: { + table: 'capmt', + op: "get" + } + }); - tvheadend.comet.on('capmt', function(server) { - var rec = store.getById(server.id); - if (rec) { - rec.set('connected', server.connected); - } - }); + tvheadend.comet.on('capmt', function(server) { + var rec = store.getById(server.id); + if (rec) { + rec.set('connected', server.connected); + } + }); - return new tvheadend.tableEditor('Capmt Connections', 'capmt', cm, rec, - [ ], store, 'config_capmt.html', 'key'); -} + return new tvheadend.tableEditor('Capmt Connections', 'capmt', cm, rec, + [], store, 'config_capmt.html', 'key'); +}; diff --git a/src/webui/static/app/chconf.js b/src/webui/static/app/chconf.js index 46bec483..deb0e9b4 100644 --- a/src/webui/static/app/chconf.js +++ b/src/webui/static/app/chconf.js @@ -2,219 +2,222 @@ * Channel tags */ tvheadend.channelTags = new Ext.data.JsonStore({ - autoLoad : true, - root : 'entries', - fields : [ 'identifier', 'name' ], - id : 'identifier', - url : 'channeltags', - baseParams : { - op : 'listTags' - } + autoLoad: true, + root: 'entries', + fields: ['identifier', 'name'], + id: 'identifier', + url: 'channeltags', + baseParams: { + op: 'listTags' + } }); tvheadend.channelTags.setDefaultSort('name', 'ASC'); tvheadend.comet.on('channeltags', function(m) { - if (m.reload != null) tvheadend.channelTags.reload(); + if (m.reload != null) + tvheadend.channelTags.reload(); }); /** * Channels */ tvheadend.channelrec = new Ext.data.Record.create( - [ 'name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start', - 'epg_post_end', 'number' ]); + ['name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start', + 'epg_post_end', 'number']); tvheadend.channels = new Ext.data.JsonStore({ - url : 'api/channel/list', - root : 'entries', - fields : [ 'key', 'val' ], - id : 'key', - autoLoad : true, - sortInfo : { - field : 'val', - direction : 'ASC' - } + url: 'api/channel/list', + root: 'entries', + fields: ['key', 'val'], + id: 'key', + autoLoad: true, + sortInfo: { + field: 'val', + direction: 'ASC' + } }); tvheadend.comet.on('channels', function(m) { - if (m.reload != null) tvheadend.channels.reload(); + if (m.reload != null) + tvheadend.channels.reload(); }); tvheadend.channel_tab = function(panel) { - function assign_low_number() { - var tab = panel.getActiveTab() - var sm = tab.getSelectionModel() - var store = tab.getStore() + function assign_low_number() { + var tab = panel.getActiveTab(); + var sm = tab.getSelectionModel(); + var store = tab.getStore(); - if (sm.getCount() != 1) - return + if (sm.getCount() !== 1) + return; - var nums = [] - store.each(function() { - if(this.data.number > 0) - nums.push(this.data.number) - }) + var nums = []; + store.each(function() { + if (this.data.number > 0) + nums.push(this.data.number); + }); - if(nums.length == 0) - { - sm.getSelected().set('number', 1) - return - } - - nums.sort(function(a,b) { return (a - b) }) - - var max = nums[nums.length - 1] - var low = max + 1 - - for(var i = 1; i <= max; ++i) - { - var ct = false - for(var j = 0; j < nums.length; ++j) - if(nums[j] == i) + if (nums.length === 0) { - ct = true - break + sm.getSelected().set('number', 1); + return; } - if(!ct) - { - low = i - break; - } - } + nums.sort(function(a, b) { + return (a - b); + }); - sm.getSelected().set('number', low) - sm.selectNext() - } + var max = nums[nums.length - 1]; + var low = max + 1; - function move_number_up() { - var tab = panel.getActiveTab() - var sm = tab.getSelectionModel() - var store = tab.getStore() - - if (sm.getCount() != 1) - return - - var sel = sm.getSelected() - var num = sel.data.number - - if(!num) - num = 0 - - store.each(function() { - if(this.data.number == num + 1) - this.set('number', num) - }) - - sel.set('number', num + 1) - } - - function move_number_down() { - var tab = panel.getActiveTab() - var sm = tab.getSelectionModel() - var store = tab.getStore() - - if(sm.getCount() != 1) - return - - var sel = sm.getSelected() - var num = sel.data.number - - if(!num) - num = 0 - - if(num <= 1) - return - - store.each(function() { - if(this.data.number == num - 1) - this.set('number', num) - }) - - sel.set('number', num - 1) - } - - function swap_numbers() { - var tab = panel.getActiveTab() - var sm = tab.getSelectionModel() - var store = tab.getStore() - - if(sm.getCount() != 2) - return - - var sel = sm.getSelections() - var tmp = sel[0].data.number - - sel[0].set('number', sel[1].data.number) - sel[1].set('number', tmp) - } - - var mapButton = new Ext.Toolbar.Button({ - tooltip : 'Map services to channels', - iconCls : 'clone', - text : 'Map Services', - handler : tvheadend.service_mapper, - disabled : false - }); - - var lowNoButton = new Ext.Toolbar.Button({ - tooltip : 'Assign lowest free channel number', - iconCls : 'bullet_add', - text : 'Assign Number', - handler : assign_low_number, - disabled : false - }); - - var noUpButton = new Ext.Toolbar.Button({ - tooltip : 'Move channel one number up', - iconCls : 'arrow_up', - text : 'Number Up', - handler : move_number_up, - disabled : false - }); - - var noDownButton = new Ext.Toolbar.Button({ - tooltip : 'Move channel one number down', - iconCls : 'arrow_down', - text : 'Number Down', - handler : move_number_down, - disabled : false - }); - - var noSwapButton = new Ext.Toolbar.Button({ - tooltip : 'Swap the two selected channels numbers', - iconCls : 'arrow_switch', - text : 'Swap Numbers', - handler : swap_numbers, - disabled : false - }); - - tvheadend.idnode_grid(panel, { - url : 'api/channel', - comet : 'channel', - titleS : 'Channel', - titleP : 'Channels', - tabIndex: 0, - add : { - url : 'api/channel', - create : {} - }, - del : true, - tbar : [ mapButton, lowNoButton, noUpButton, noDownButton, noSwapButton ], - lcol : [ - { - width : 50, - header : 'Play', - renderer : function (v, o, r) { - return "Play"; + for (var i = 1; i <= max; ++i) + { + var ct = false; + for (var j = 0; j < nums.length; ++j) + if (nums[j] === i) + { + ct = true; + break + } + if (!ct) + { + low = i; + break; + } } - } - ], - sort : { - field : 'number', - direction : 'ASC' + + sm.getSelected().set('number', low); + sm.selectNext(); } - }); -} + + function move_number_up() { + var tab = panel.getActiveTab(); + var sm = tab.getSelectionModel(); + var store = tab.getStore(); + + if (sm.getCount() !== 1) + return; + + var sel = sm.getSelected(); + var num = sel.data.number; + + if (!num) + num = 0; + + store.each(function() { + if (this.data.number === num + 1) + this.set('number', num); + }); + + sel.set('number', num + 1); + } + + function move_number_down() { + var tab = panel.getActiveTab(); + var sm = tab.getSelectionModel(); + var store = tab.getStore(); + + if (sm.getCount() !== 1) + return; + + var sel = sm.getSelected(); + var num = sel.data.number; + + if (!num) + num = 0; + + if (num <= 1) + return; + + store.each(function() { + if (this.data.number === num - 1) + this.set('number', num); + }); + + sel.set('number', num - 1); + } + + function swap_numbers() { + var tab = panel.getActiveTab(); + var sm = tab.getSelectionModel(); + var store = tab.getStore(); //store is unused + + if (sm.getCount() !== 2) + return; + + var sel = sm.getSelections(); + var tmp = sel[0].data.number; + + sel[0].set('number', sel[1].data.number); + sel[1].set('number', tmp); + } + + var mapButton = new Ext.Toolbar.Button({ + tooltip: 'Map services to channels', + iconCls: 'clone', + text: 'Map Services', + handler: tvheadend.service_mapper, + disabled: false + }); + + var lowNoButton = new Ext.Toolbar.Button({ + tooltip: 'Assign lowest free channel number', + iconCls: 'bullet_add', + text: 'Assign Number', + handler: assign_low_number, + disabled: false + }); + + var noUpButton = new Ext.Toolbar.Button({ + tooltip: 'Move channel one number up', + iconCls: 'arrow_up', + text: 'Number Up', + handler: move_number_up, + disabled: false + }); + + var noDownButton = new Ext.Toolbar.Button({ + tooltip: 'Move channel one number down', + iconCls: 'arrow_down', + text: 'Number Down', + handler: move_number_down, + disabled: false + }); + + var noSwapButton = new Ext.Toolbar.Button({ + tooltip: 'Swap the two selected channels numbers', + iconCls: 'arrow_switch', + text: 'Swap Numbers', + handler: swap_numbers, + disabled: false + }); + + tvheadend.idnode_grid(panel, { + url: 'api/channel', + comet: 'channel', + titleS: 'Channel', + titleP: 'Channels', + tabIndex: 0, + add: { + url: 'api/channel', + create: {} + }, + del: true, + tbar: [mapButton, lowNoButton, noUpButton, noDownButton, noSwapButton], + lcol: [ + { + width: 50, + header: 'Play', + renderer: function(v, o, r) { + return "Play"; + } + } + ], + sort: { + field: 'number', + direction: 'ASC' + } + }); +}; diff --git a/src/webui/static/app/comet.js b/src/webui/static/app/comet.js index 68455ef5..3b9493e6 100644 --- a/src/webui/static/app/comet.js +++ b/src/webui/static/app/comet.js @@ -2,19 +2,19 @@ * Comet interfaces */ Ext.extend(tvheadend.Comet = function() { - this.addEvents({ - accessUpdate : true, - tvAdapter : true, - dvbMux : true, - dvbStore : true, - dvbSatConf : true, - logmessage : true, - channeltags : true, - autorec : true, - dvrdb : true, - dvrconfig : true, - channels : true - }); + this.addEvents({ + accessUpdate: true, + tvAdapter: true, + dvbMux: true, + dvbStore: true, + dvbSatConf: true, + logmessage: true, + channeltags: true, + autorec: true, + dvrdb: true, + dvrconfig: true, + channels: true + }); }, Ext.util.Observable); tvheadend.comet = new tvheadend.Comet(); @@ -22,53 +22,53 @@ tvheadend.boxid = null; tvheadend.cometPoller = function() { - var failures = 0; + var failures = 0; - var cometRequest = new Ext.util.DelayedTask(function() { + var cometRequest = new Ext.util.DelayedTask(function() { - Ext.Ajax - .request({ - url : 'comet/poll', - params : { - boxid : (tvheadend.boxid ? tvheadend.boxid : null), - immediate : failures > 0 ? 1 : 0 - }, - success : function(result, request) { - parse_comet_response(result.responseText); + Ext.Ajax + .request({ + url: 'comet/poll', + params: { + boxid: (tvheadend.boxid ? tvheadend.boxid : null), + immediate: failures > 0 ? 1 : 0 + }, + success: function(result, request) { + parse_comet_response(result.responseText); - if (failures > 1) { - tvheadend.log('Reconnected to Tvheadend', - 'font-weight: bold; color: #080'); - } - failures = 0; - }, - failure : function(result, request) { - cometRequest.delay(failures ? 1000 : 1); - if (failures == 1) { - tvheadend.log('There seems to be a problem with the ' - + 'live update feed from Tvheadend. ' - + 'Trying to reconnect...', - 'font-weight: bold; color: #f00'); - } - failures++; - } - }); - }); + if (failures > 1) { + tvheadend.log('Reconnected to Tvheadend', + 'font-weight: bold; color: #080'); + } + failures = 0; + }, + failure: function(result, request) { + cometRequest.delay(failures ? 1000 : 1); + if (failures === 1) { + tvheadend.log('There seems to be a problem with the ' + + 'live update feed from Tvheadend. ' + + 'Trying to reconnect...', + 'font-weight: bold; color: #f00'); + } + failures++; + } + }); + }); - function parse_comet_response(responsetxt) { - response = Ext.util.JSON.decode(responsetxt); - tvheadend.boxid = response.boxid - for (x = 0; x < response.messages.length; x++) { - m = response.messages[x]; - try { - tvheadend.comet.fireEvent(m.notificationClass, m); - } catch (e) { - tvheadend.log('comet failure [e=' + e.message + ']'); - } - } - cometRequest.delay(100); - } - ; + function parse_comet_response(responsetxt) { + response = Ext.util.JSON.decode(responsetxt); + tvheadend.boxid = response.boxid; + for (x = 0; x < response.messages.length; x++) { + m = response.messages[x]; + try { + tvheadend.comet.fireEvent(m.notificationClass, m); + } catch (e) { + tvheadend.log('comet failure [e=' + e.message + ']'); + } + } + cometRequest.delay(100); + } + ; - cometRequest.delay(100); -} + cometRequest.delay(100); +}; diff --git a/src/webui/static/app/config.js b/src/webui/static/app/config.js index 41dcbbf1..ab90701e 100644 --- a/src/webui/static/app/config.js +++ b/src/webui/static/app/config.js @@ -1,31 +1,31 @@ // Store: config languages tvheadend.languages = new Ext.data.JsonStore({ - autoLoad:true, - root:'entries', - fields: ['identifier','name'], + autoLoad: true, + root: 'entries', + fields: ['identifier', 'name'], id: 'identifier', - url:'languages', + url: 'languages', baseParams: { - op: 'list' + op: 'list' } }); // Store: all languages tvheadend.config_languages = new Ext.data.JsonStore({ - autoLoad:true, - root:'entries', - fields: ['identifier','name'], + autoLoad: true, + root: 'entries', + fields: ['identifier', 'name'], id: 'identifier', - url:'languages', + url: 'languages', baseParams: { - op: 'config' + op: 'config' } }); tvheadend.languages.setDefaultSort('name', 'ASC'); tvheadend.comet.on('config', function(m) { - if(m.reload != null) { + if (m.reload != null) { tvheadend.languages.reload(); tvheadend.config_languages.reload(); } @@ -33,262 +33,269 @@ tvheadend.comet.on('config', function(m) { tvheadend.miscconf = function() { - /* - * Basic Config - */ - var confreader = new Ext.data.JsonReader({ - root : 'config' - }, [ 'muxconfpath', 'language', - 'tvhtime_update_enabled', 'tvhtime_ntp_enabled', - 'tvhtime_tolerance', 'transcoding_enabled']); + /* + * Basic Config + */ - /* **************************************************************** - * Form Fields - * ***************************************************************/ - - /* - * DVB path - */ - - var dvbscanPath = new Ext.form.TextField({ - fieldLabel : 'DVB scan files path', - name : 'muxconfpath', - allowBlank : true, - width: 400 - }); - - var dvbscanWrap = new Ext.form.FieldSet({ - title: 'DVB Scan Files', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ dvbscanPath ] - }); - - /* - * Language - */ - - var language = new Ext.ux.ItemSelector({ - name: 'language', - fromStore: tvheadend.languages, - toStore: tvheadend.config_languages, - fieldLabel: 'Default Language(s)', - dataFields:['identifier', 'name'], - msWidth: 190, - msHeight: 150, - valueField: 'identifier', - displayField: 'name', - imagePath: 'static/multiselect/resources', - toLegend: 'Selected', - fromLegend: 'Available' - }); - - var languageWrap = new Ext.form.FieldSet({ - title: 'Language Settings', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ language ] - }); - - /* - * Time/Date - */ - var tvhtimeUpdateEnabled = new Ext.form.Checkbox({ - name: 'tvhtime_update_enabled', - fieldLabel: 'Update time' - }); - - var tvhtimeNtpEnabled = new Ext.form.Checkbox({ - name: 'tvhtime_ntp_enabled', - fieldLabel: 'Enable NTP driver' - }); - - var tvhtimeTolerance = new Ext.form.NumberField({ - name: 'tvhtime_tolerance', - fieldLabel: 'Update tolerance (ms)' - }); - - var tvhtimePanel = new Ext.form.FieldSet({ - title: 'Time Update', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ tvhtimeUpdateEnabled, tvhtimeNtpEnabled, tvhtimeTolerance ] - }); - - /* - * Image cache - */ - if (tvheadend.capabilities.indexOf('imagecache') != -1) { - var imagecache_reader = new Ext.data.JsonReader({ - root : 'entries' + var confreader = new Ext.data.JsonReader({ + root: 'config' }, [ - 'enabled', 'ok_period', 'fail_period', 'ignore_sslcert', + 'muxconfpath', 'language', + 'tvhtime_update_enabled', 'tvhtime_ntp_enabled', + 'tvhtime_tolerance', 'transcoding_enabled' ]); - var imagecacheEnabled = new Ext.ux.form.XCheckbox({ - name: 'enabled', - fieldLabel: 'Enabled', + /* **************************************************************** + * Form Fields + * ***************************************************************/ + + /* + * DVB path + */ + + var dvbscanPath = new Ext.form.TextField({ + fieldLabel: 'DVB scan files path', + name: 'muxconfpath', + allowBlank: true, + width: 400 }); - var imagecacheOkPeriod = new Ext.form.NumberField({ - name: 'ok_period', - fieldLabel: 'Re-fetch period (hours)' + var dvbscanWrap = new Ext.form.FieldSet({ + title: 'DVB Scan Files', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items : [ dvbscanPath ] }); - var imagecacheFailPeriod = new Ext.form.NumberField({ - name: 'fail_period', - fieldLabel: 'Re-try period (hours)', + /* + * Language + */ + + var language = new Ext.ux.ItemSelector({ + name: 'language', + fromStore: tvheadend.languages, + toStore: tvheadend.config_languages, + fieldLabel: 'Default Language(s)', + dataFields: ['identifier', 'name'], + msWidth: 190, + msHeight: 150, + valueField: 'identifier', + displayField: 'name', + imagePath: 'static/multiselect/resources', + toLegend: 'Selected', + fromLegend: 'Available' }); - var imagecacheIgnoreSSLCert = new Ext.ux.form.XCheckbox({ - name: 'ignore_sslcert', - fieldLabel: 'Ignore invalid SSL certificate' + var languageWrap = new Ext.form.FieldSet({ + title: 'Language Settings', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items : [ language ] }); - var imagecachePanel = new Ext.form.FieldSet({ - title: 'Image Caching', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ imagecacheEnabled, imagecacheOkPeriod, imagecacheFailPeriod, - imagecacheIgnoreSSLCert ] + /* + * Time/Date + */ + + var tvhtimeUpdateEnabled = new Ext.form.Checkbox({ + name: 'tvhtime_update_enabled', + fieldLabel: 'Update time' }); - var imagecache_form = new Ext.form.FormPanel({ - border : false, - labelAlign : 'left', - labelWidth : 200, - waitMsgTarget : true, - reader: imagecache_reader, - layout : 'form', - defaultType : 'textfield', - autoHeight : true, - animCollapse: true, - items : [ imagecachePanel ] + var tvhtimeNtpEnabled = new Ext.form.Checkbox({ + name: 'tvhtime_ntp_enabled', + fieldLabel: 'Enable NTP driver' }); - } else { - var imagecache_form = null; - } - /* - * Transcoding - */ - var transcodingEnabled = new Ext.form.Checkbox({ - name: 'transcoding_enabled', - fieldLabel: 'Enabled', - }); + var tvhtimeTolerance = new Ext.form.NumberField({ + name: 'tvhtime_tolerance', + fieldLabel: 'Update tolerance (ms)' + }); - var transcodingPanel = new Ext.form.FieldSet({ - title: 'Transcoding', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ transcodingEnabled ] - }); - if (tvheadend.capabilities.indexOf('transcoding') == -1) - transcodingPanel.hide(); + var tvhtimePanel = new Ext.form.FieldSet({ + title: 'Time Update', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [tvhtimeUpdateEnabled, tvhtimeNtpEnabled, tvhtimeTolerance] + }); + /* + * Image cache + */ - /* **************************************************************** - * Form - * ***************************************************************/ - - var saveButton = new Ext.Button({ - text : "Save configuration", - tooltip : 'Save changes made to configuration below', - iconCls : 'save', - handler : saveChanges - }); - - var helpButton = new Ext.Button({ - text : 'Help', - handler : function() { - new tvheadend.help('General Configuration', 'config_misc.html'); - } - }); - - var confpanel = new Ext.form.FormPanel({ - labelAlign : 'left', - labelWidth : 200, - border : false, - waitMsgTarget : true, - reader : confreader, - layout : 'form', - defaultType : 'textfield', - autoHeight : true, - items : [ languageWrap, dvbscanWrap, - tvhtimePanel, - transcodingPanel] - }); - - var _items = [confpanel]; - if (imagecache_form) - _items.push(imagecache_form); - var panel = new Ext.Panel({ - title : 'General', - iconCls : 'wrench', - border : false, - bodyStyle : 'padding:15px', - layout : 'form', - items: _items, - tbar : [ saveButton, '->', helpButton ] - }); - - /* **************************************************************** - * Load/Save - * ***************************************************************/ - - confpanel.on('render', function() { - confpanel.getForm().load({ - url : 'config', - params : { - op : 'loadSettings' - }, - success : function(form, action) { - confpanel.enable(); - } - }); - if (imagecache_form) - imagecache_form.getForm().load({ - url : 'api/imagecache/config/load', - success : function (form, action) { - imagecache_form.enable(); + if (tvheadend.capabilities.indexOf('imagecache') !== -1) { + var imagecache_reader = new Ext.data.JsonReader({ + root: 'entries' }, - failure : function (form, action) { - alert("FAILED"); - } - }); - }); + [ + 'enabled', 'ok_period', 'fail_period', 'ignore_sslcert' + ]); - function saveChanges() { - confpanel.getForm().submit({ - url : 'config', - params : { - op : 'saveSettings' - }, - waitMsg : 'Saving Data...', - failure : function(form, action) { - Ext.Msg.alert('Save failed', action.result.errormsg); - } - }); - if (imagecache_form) - imagecache_form.getForm().submit({ - url : 'api/imagecache/config/save', - waitMsg : 'Saving data...', - failure : function(form, action) { - Ext.Msg.alert('Imagecache save failed', action.result.errormsg); - } - }); - } + var imagecacheEnabled = new Ext.ux.form.XCheckbox({ + name: 'enabled', + fieldLabel: 'Enabled' + }); - return panel; -} + var imagecacheOkPeriod = new Ext.form.NumberField({ + name: 'ok_period', + fieldLabel: 'Re-fetch period (hours)' + }); + + var imagecacheFailPeriod = new Ext.form.NumberField({ + name: 'fail_period', + fieldLabel: 'Re-try period (hours)' + }); + + var imagecacheIgnoreSSLCert = new Ext.ux.form.XCheckbox({ + name: 'ignore_sslcert', + fieldLabel: 'Ignore invalid SSL certificate' + }); + + var imagecachePanel = new Ext.form.FieldSet({ + title: 'Image Caching', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [imagecacheEnabled, imagecacheOkPeriod, imagecacheFailPeriod, + imagecacheIgnoreSSLCert] + }); + + var imagecache_form = new Ext.form.FormPanel({ + border: false, + labelAlign: 'left', + labelWidth: 200, + waitMsgTarget: true, + reader: imagecache_reader, + layout: 'form', + defaultType: 'textfield', + autoHeight: true, + items: [imagecachePanel] + }); + } else { + var imagecache_form = null; + } + + /* + * Transcoding + */ + + var transcodingEnabled = new Ext.form.Checkbox({ + name: 'transcoding_enabled', + fieldLabel: 'Enabled' + }); + + var transcodingPanel = new Ext.form.FieldSet({ + title: 'Transcoding', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [transcodingEnabled] + }); + + if (tvheadend.capabilities.indexOf('transcoding') === -1) + transcodingPanel.hide(); + + + /* **************************************************************** + * Form + * ***************************************************************/ + + var saveButton = new Ext.Button({ + text: "Save configuration", + tooltip: 'Save changes made to configuration below', + iconCls: 'save', + handler: saveChanges + }); + + var helpButton = new Ext.Button({ + text: 'Help', + handler: function() { + new tvheadend.help('General Configuration', 'config_misc.html'); + } + }); + + var confpanel = new Ext.form.FormPanel({ + labelAlign: 'left', + labelWidth: 200, + border: false, + waitMsgTarget: true, + reader: confreader, + layout: 'form', + defaultType: 'textfield', + autoHeight: true, + items: [languageWrap, dvbscanWrap, tvhtimePanel, transcodingPanel] + }); + + var _items = [confpanel]; + + if (imagecache_form) + _items.push(imagecache_form); + + var panel = new Ext.Panel({ + title: 'General', + iconCls: 'wrench', + border: false, + bodyStyle: 'padding:15px', + layout: 'form', + items: _items, + tbar: [saveButton, '->', helpButton] + }); + + /* **************************************************************** + * Load/Save + * ***************************************************************/ + + confpanel.on('render', function() { + confpanel.getForm().load({ + url: 'config', + params: { + op: 'loadSettings' + }, + success: function(form, action) { + confpanel.enable(); + } + }); + if (imagecache_form) + imagecache_form.getForm().load({ + url: 'api/imagecache/config/load', + success: function(form, action) { + imagecache_form.enable(); + }, + failure: function(form, action) { + alert("FAILED"); + } + }); + }); + + function saveChanges() { + confpanel.getForm().submit({ + url: 'config', + params: { + op: 'saveSettings' + }, + waitMsg: 'Saving Data...', + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); + if (imagecache_form) + imagecache_form.getForm().submit({ + url: 'api/imagecache/config/save', + waitMsg: 'Saving data...', + failure: function(form, action) { + Ext.Msg.alert('Imagecache save failed', action.result.errormsg); + } + }); + } + + return panel; +}; diff --git a/src/webui/static/app/cteditor.js b/src/webui/static/app/cteditor.js index 7cbda3d4..3fc36549 100644 --- a/src/webui/static/app/cteditor.js +++ b/src/webui/static/app/cteditor.js @@ -1,49 +1,48 @@ tvheadend.cteditor = function() { - var fm = Ext.form; + var fm = Ext.form; + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [{ + xtype: 'checkcolumn', + header: "Enabled", + dataIndex: 'enabled', + width: 60 + }, { + header: "Name", + dataIndex: 'name', + editor: new fm.TextField({ + allowBlank: false + }) + }, { + xtype: 'checkcolumn', + header: "Internal", + dataIndex: 'internal', + width: 100 + }, { + header: "Icon (full URL)", + dataIndex: 'icon', + width: 400, + editor: new fm.TextField({}) + }, { + xtype: 'checkcolumn', + header: "Icon has title", + dataIndex: 'titledIcon', + width: 100, + tooltip: 'Set this if the supplied icon has a title embedded. ' + + 'This will tell displaying application not to superimpose title ' + + 'on top of logo.' + }, { + header: "Comment", + dataIndex: 'comment', + width: 400, + editor: new fm.TextField({}) + }]}); - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns : [{ - xtype: 'checkcolumn', - header : "Enabled", - dataIndex : 'enabled', - width : 60 - } , { - header : "Name", - dataIndex : 'name', - editor : new fm.TextField({ - allowBlank : false - }) - }, { - xtype: 'checkcolumn', - header : "Internal", - dataIndex : 'internal', - width : 100 - }, { - header : "Icon (full URL)", - dataIndex : 'icon', - width : 400, - editor : new fm.TextField({}) - }, { - xtype: 'checkcolumn', - header : "Icon has title", - dataIndex : 'titledIcon', - width : 100, - tooltip : 'Set this if the supplied icon has a title embedded. ' - + 'This will tell displaying application not to superimpose title ' - + 'on top of logo.' - }, { - header : "Comment", - dataIndex : 'comment', - width : 400, - editor : new fm.TextField({}) - } ]}); + var ChannelTagRecord = Ext.data.Record.create([ + 'enabled', 'name', 'internal', 'icon', 'comment', 'titledIcon']); - var ChannelTagRecord = Ext.data.Record.create([ - 'enabled', 'name', 'internal', 'icon', 'comment', 'titledIcon' ]); - - return new tvheadend.tableEditor('Channel Tags', 'channeltags', cm, - ChannelTagRecord, [], - null, 'config_tags.html', 'tags'); -} + return new tvheadend.tableEditor('Channel Tags', 'channeltags', cm, + ChannelTagRecord, [], + null, 'config_tags.html', 'tags'); +}; diff --git a/src/webui/static/app/cwceditor.js b/src/webui/static/app/cwceditor.js index 7ec176e7..62b88749 100644 --- a/src/webui/static/app/cwceditor.js +++ b/src/webui/static/app/cwceditor.js @@ -1,128 +1,129 @@ tvheadend.cwceditor = function() { - var fm = Ext.form; + var fm = Ext.form; - function setMetaAttr(meta, record) { - var enabled = record.get('enabled'); - if (!enabled) return; + function setMetaAttr(meta, record) { + var enabled = record.get('enabled'); + if (!enabled) + return; - var connected = record.get('connected'); - if (connected == 1) { - meta.attr = 'style="color:green;"'; - } - else { - meta.attr = 'style="color:red;"'; - } - } + var connected = record.get('connected'); + if (connected === 1) { + meta.attr = 'style="color:green;"'; + } + else { + meta.attr = 'style="color:red;"'; + } + } - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns : [ { - xtype: 'checkcolumn', - header : "Enabled", - dataIndex : 'enabled', - width : 60 - }, { - header : "Hostname", - dataIndex : 'hostname', - width : 200, - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Port", - dataIndex : 'port', - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Username", - dataIndex : 'username', - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Password", - dataIndex : 'password', - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return 'Hidden'; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "DES Key", - dataIndex : 'deskey', - width : 300, - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return 'Hidden'; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, { - xtype: 'checkcolumn', - header : "Update Card", - dataIndex : 'emm', - width : 100 - }, { - xtype: 'checkcolumn', - header : "Update One", - dataIndex : 'emmex', - width : 100 - }, { - header : "Comment", - dataIndex : 'comment', - width : 400, - renderer : function(value, metadata, record, row, col, store) { - setMetaAttr(metadata, record); - return value; - }, - editor : new fm.TextField() - } ]}); + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [{ + xtype: 'checkcolumn', + header: "Enabled", + dataIndex: 'enabled', + width: 60 + }, { + header: "Hostname", + dataIndex: 'hostname', + width: 200, + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Port", + dataIndex: 'port', + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Username", + dataIndex: 'username', + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Password", + dataIndex: 'password', + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return 'Hidden'; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "DES Key", + dataIndex: 'deskey', + width: 300, + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return 'Hidden'; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, { + xtype: 'checkcolumn', + header: "Update Card", + dataIndex: 'emm', + width: 100 + }, { + xtype: 'checkcolumn', + header: "Update One", + dataIndex: 'emmex', + width: 100 + }, { + header: "Comment", + dataIndex: 'comment', + width: 400, + renderer: function(value, metadata, record, row, col, store) { + setMetaAttr(metadata, record); + return value; + }, + editor: new fm.TextField() + }]}); - var rec = Ext.data.Record.create([ 'enabled', 'connected', 'hostname', - 'port', 'username', 'password', 'deskey', 'emm', 'emmex', 'comment' ]); + var rec = Ext.data.Record.create(['enabled', 'connected', 'hostname', + 'port', 'username', 'password', 'deskey', 'emm', 'emmex', 'comment']); - var store = new Ext.data.JsonStore({ - root : 'entries', - fields : rec, - url : "tablemgr", - autoLoad : true, - id : 'id', - baseParams : { - table : 'cwc', - op : "get" - }, - sortInfo : { - field : 'username', - direction : 'ASC' - } - }); + var store = new Ext.data.JsonStore({ + root: 'entries', + fields: rec, + url: "tablemgr", + autoLoad: true, + id: 'id', + baseParams: { + table: 'cwc', + op: "get" + }, + sortInfo: { + field: 'username', + direction: 'ASC' + } + }); - var grid = new tvheadend.tableEditor('Code Word Client', 'cwc', cm, rec, [], - store, 'config_cwc.html', 'key'); + var grid = new tvheadend.tableEditor('Code Word Client', 'cwc', cm, rec, [], + store, 'config_cwc.html', 'key'); - tvheadend.comet.on('cwcStatus', function(msg) { - var rec = store.getById(msg.id); - if (rec) { - rec.set('connected', msg.connected); - grid.getView().refresh(); - } - }); + tvheadend.comet.on('cwcStatus', function(msg) { + var rec = store.getById(msg.id); + if (rec) { + rec.set('connected', msg.connected); + grid.getView().refresh(); + } + }); - return grid; -} + return grid; +}; diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index 2ccf5574..305b9072 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -1,63 +1,62 @@ tvheadend.weekdays = new Ext.data.SimpleStore({ - fields : [ 'identifier', 'name' ], - id : 0, - data : [ [ '1', 'Mon' ], [ '2', 'Tue' ], [ '3', 'Wed' ], [ '4', 'Thu' ], - [ '5', 'Fri' ], [ '6', 'Sat' ], [ '7', 'Sun' ] ] + fields: ['identifier', 'name'], + id: 0, + data: [['1', 'Mon'], ['2', 'Tue'], ['3', 'Wed'], ['4', 'Thu'], + ['5', 'Fri'], ['6', 'Sat'], ['7', 'Sun']] }); //This should be loaded from tvheadend tvheadend.dvrprio = new Ext.data.SimpleStore({ - fields : [ 'identifier', 'name' ], - id : 0, - data : [ [ 'important', 'Important' ], [ 'high', 'High' ], - [ 'normal', 'Normal' ], [ 'low', 'Low' ], - [ 'unimportant', 'Unimportant' ] ] + fields: ['identifier', 'name'], + id: 0, + data: [['important', 'Important'], ['high', 'High'], + ['normal', 'Normal'], ['low', 'Low'], + ['unimportant', 'Unimportant']] }); - //For the container configuration tvheadend.containers = new Ext.data.JsonStore({ - autoLoad : true, - root : 'entries', - fields : [ 'name', 'description' ], - id : 'name', - url : 'dvr_containers', - baseParams : { - op : 'list' - } + autoLoad: true, + root: 'entries', + fields: ['name', 'description'], + id: 'name', + url: 'dvr_containers', + baseParams: { + op: 'list' + } }); //For the cache configuration tvheadend.caches = new Ext.data.JsonStore({ - autoLoad : true, - root : 'entries', - fields : [ 'index', 'description' ], - id : 'name', - url : 'dvr_caches', - baseParams : { - op : 'list' - } + autoLoad: true, + root: 'entries', + fields: ['index', 'description'], + id: 'name', + url: 'dvr_caches', + baseParams: { + op: 'list' + } }); - /** * Configuration names */ tvheadend.configNames = new Ext.data.JsonStore({ - autoLoad : true, - root : 'entries', - fields : [ 'identifier', 'name' ], - id : 'identifier', - url : 'confignames', - baseParams : { - op : 'list' - } + autoLoad: true, + root: 'entries', + fields: ['identifier', 'name'], + id: 'identifier', + url: 'confignames', + baseParams: { + op: 'list' + } }); tvheadend.configNames.setDefaultSort('name', 'ASC'); tvheadend.comet.on('dvrconfig', function(m) { - if (m.reload != null) tvheadend.configNames.reload(); + if (m.reload != null) + tvheadend.configNames.reload(); }); /** @@ -65,397 +64,393 @@ tvheadend.comet.on('dvrconfig', function(m) { */ tvheadend.dvrDetails = function(entry) { - var content = ''; - var but; + var content = ''; + var but; - if (entry.chicon != null && entry.chicon.length > 0) content += ''; + if (entry.chicon != null && entry.chicon.length > 0) + content += ''; - content += '
' + entry.title + '
'; - content += '
' + entry.description + '
'; - content += '
' - content += '
Status: ' + entry.status + '
'; + content += '
' + entry.title + '
'; + content += '
' + entry.description + '
'; + content += '
'; + content += '
Status: ' + entry.status + '
'; - if (entry.url != null && entry.filesize > 0) { - content += '
' + 'Download ' - + parseInt(entry.filesize / 1000000) + ' MB
'; + if (entry.url != null && entry.filesize > 0) { + content += '
' + 'Download ' + + parseInt(entry.filesize / 1000000) + ' MB
'; - } + } - var win = new Ext.Window({ - title : entry.title, - layout : 'fit', - width : 400, - height : 300, - constrainHeader : true, - buttonAlign : 'center', - html : content - }); + var win = new Ext.Window({ + title: entry.title, + layout: 'fit', + width: 400, + height: 300, + constrainHeader: true, + buttonAlign: 'center', + html: content + }); - switch (entry.schedstate) { - case 'scheduled': - win.addButton({ - handler : cancelEvent, - text : "Remove from schedule" - }); - break; + switch (entry.schedstate) { + case 'scheduled': + win.addButton({ + handler: cancelEvent, + text: "Remove from schedule" + }); + break; - case 'recording': - case 'recordingError': - win.addButton({ - handler : cancelEvent, - text : "Abort recording" - }); - break; - case 'completedError': - case 'completed': - win.addButton({ - handler : deleteEvent, - text : "Delete recording" - }); - break; - } + case 'recording': + case 'recordingError': + win.addButton({ + handler: cancelEvent, + text: "Abort recording" + }); + break; + case 'completedError': + case 'completed': + win.addButton({ + handler: deleteEvent, + text: "Delete recording" + }); + break; + } - win.show(); + win.show(); - function cancelEvent() { - Ext.Ajax.request({ - url : 'dvr', - params : { - entryId : entry.id, - op : 'cancelEntry' - }, + function cancelEvent() { + Ext.Ajax.request({ + url: 'dvr', + params: { + entryId: entry.id, + op: 'cancelEntry' + }, + success: function(response, options) { + win.close(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('DVR', response.statusText); + } + }); + } - success : function(response, options) { - win.close(); - }, + function deleteEvent() { + Ext.Ajax.request({ + url: 'dvr', + params: { + entryId: entry.id, + op: 'deleteEntry' + }, + success: function(response, options) { + win.close(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('DVR', response.statusText); + } + }); + } - failure : function(response, options) { - Ext.MessageBox.alert('DVR', response.statusText); - } - }); - } - - function deleteEvent() { - Ext.Ajax.request({ - url : 'dvr', - params : { - entryId : entry.id, - op : 'deleteEntry' - }, - - success : function(response, options) { - win.close(); - }, - - failure : function(response, options) { - Ext.MessageBox.alert('DVR', response.statusText); - } - }); - } - -} +}; /** * */ tvheadend.dvrschedule = function(title, iconCls, dvrStore) { - var actions = new Ext.ux.grid.RowActions({ - header : '', - dataIndex : 'actions', - width : 45, - actions : [ { - iconIndex : 'schedstate' - } ] - }); + var actions = new Ext.ux.grid.RowActions({ + header: '', + dataIndex: 'actions', + width: 45, + actions: [{ + iconIndex: 'schedstate' + }] + }); - function renderDate(value) { - var dt = new Date(value); - return dt.format('D j M H:i'); - } + function renderDate(value) { + var dt = new Date(value); + return dt.format('D j M H:i'); + } - function renderDuration(value) { - value = value / 60; /* Nevermind the seconds */ + function renderDuration(value) { + value = value / 60; /* Nevermind the seconds */ - if (value >= 60) { - var min = parseInt(value % 60); - var hours = parseInt(value / 60); + if (value >= 60) { + var min = parseInt(value % 60); + var hours = parseInt(value / 60); - if (min == 0) { - return hours + ' hrs'; - } - return hours + ' hrs, ' + min + ' min'; - } - else { - return parseInt(value) + ' min'; - } - } + if (min === 0) { + return hours + ' hrs'; + } + return hours + ' hrs, ' + min + ' min'; + } + else { + return parseInt(value) + ' min'; + } + } - function renderSize(value) - { - if (value == null) - return ''; - return parseInt(value / 1000000) + ' MB'; - } + function renderSize(value) + { + if (value == null) + return ''; + return parseInt(value / 1000000) + ' MB'; + } - function renderPri(value) { - return tvheadend.dvrprio.getById(value).data.name; - } + function renderPri(value) { + return tvheadend.dvrprio.getById(value).data.name; + } - var dvrCm = new Ext.grid.ColumnModel([ actions, { - width : 250, - id : 'title', - header : "Title", - dataIndex : 'title' - }, { - width : 100, - id : 'episode', - header : "Episode", - dataIndex : 'episode' - }, { - width : 100, - id : 'pri', - header : "Priority", - dataIndex : 'pri', - renderer : renderPri, - hidden : iconCls != 'clock', - }, { - width : 100, - id : 'start', - header : iconCls == 'clock' ? "Start" : "Date/Time", - dataIndex : 'start', - renderer : renderDate - }, { - width : 100, - hidden : true, - id : 'end', - header : "End", - dataIndex : 'end', - renderer : renderDate - }, { - width : 100, - id : 'duration', - header : "Duration", - dataIndex : 'duration', - renderer : renderDuration - }, { - width : 100, - id : 'filesize', - header : "Filesize", - dataIndex : 'filesize', - renderer : renderSize, - hidden : iconCls != 'television' - }, { - width : 250, - id : 'channel', - header : "Channel", - dataIndex : 'channel' - }, { - width : 200, - id : 'creator', - header : "Created by", - hidden : true, - dataIndex : 'creator' - }, { - width : 200, - id : 'config_name', - header : "DVR Configuration", - renderer : function(value, metadata, record, row, col, store) { - if (!value) { - return '(default)'; - } - else { - return value; - } - }, - dataIndex : 'config_name', - hidden: iconCls != 'clock' - }, { - width : 200, - id : 'status', - header : "Status", - dataIndex : 'status', - hidden: iconCls != 'exclamation' - } ]); + var dvrCm = new Ext.grid.ColumnModel([actions, { + width: 250, + id: 'title', + header: "Title", + dataIndex: 'title' + }, { + width: 100, + id: 'episode', + header: "Episode", + dataIndex: 'episode' + }, { + width: 100, + id: 'pri', + header: "Priority", + dataIndex: 'pri', + renderer: renderPri, + hidden: iconCls !== 'clock' + }, { + width: 100, + id: 'start', + header: iconCls === 'clock' ? "Start" : "Date/Time", + dataIndex: 'start', + renderer: renderDate + }, { + width: 100, + hidden: true, + id: 'end', + header: "End", + dataIndex: 'end', + renderer: renderDate + }, { + width: 100, + id: 'duration', + header: "Duration", + dataIndex: 'duration', + renderer: renderDuration + }, { + width: 100, + id: 'filesize', + header: "Filesize", + dataIndex: 'filesize', + renderer: renderSize, + hidden: iconCls !== 'television' + }, { + width: 250, + id: 'channel', + header: "Channel", + dataIndex: 'channel' + }, { + width: 200, + id: 'creator', + header: "Created by", + hidden: true, + dataIndex: 'creator' + }, { + width: 200, + id: 'config_name', + header: "DVR Configuration", + renderer: function(value, metadata, record, row, col, store) { + if (!value) { + return '(default)'; + } + else { + return value; + } + }, + dataIndex: 'config_name', + hidden: iconCls !== 'clock' + }, { + width: 200, + id: 'status', + header: "Status", + dataIndex: 'status', + hidden: iconCls !== 'exclamation' + }]); - function addEntry() { + function addEntry() { - function createRecording() { - panel.getForm().submit({ - params : { - 'op' : 'createEntry' - }, - url : 'dvr/addentry', - waitMsg : 'Creating entry...', - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', 'Unable to create entry'); - }, - success : function() { - win.close(); - } - }); - } + function createRecording() { + panel.getForm().submit({ + params: { + 'op': 'createEntry' + }, + url: 'dvr/addentry', + waitMsg: 'Creating entry...', + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', 'Unable to create entry'); + }, + success: function() { + win.close(); + } + }); + } - var panel = new Ext.FormPanel({ - frame : true, - border : true, - bodyStyle : 'padding:5px', - labelAlign : 'right', - labelWidth : 110, - defaultType : 'textfield', - items : [ new Ext.form.ComboBox({ - fieldLabel : 'Channel', - name : 'channel', - hiddenName : 'channelid', - editable : false, - allowBlank : false, - displayField : 'val', - valueField : 'key', - mode : 'remote', - triggerAction : 'all', - store : tvheadend.channels - }), new Ext.form.DateField({ - allowBlank : false, - fieldLabel : 'Date', - name : 'date' - }), new Ext.form.TimeField({ - allowBlank : false, - fieldLabel : 'Start time', - name : 'starttime', - increment : 10, - format : 'H:i' - }), new Ext.form.TimeField({ - allowBlank : false, - fieldLabel : 'Stop time', - name : 'stoptime', - increment : 10, - format : 'H:i' - }), new Ext.form.ComboBox({ - store : tvheadend.dvrprio, - value : "normal", - triggerAction : 'all', - mode : 'local', - fieldLabel : 'Priority', - valueField : 'identifier', - displayField : 'name', - name : 'pri' - }), { - allowBlank : false, - fieldLabel : 'Title', - name : 'title' - }, new Ext.form.ComboBox({ - store : tvheadend.configNames, - triggerAction : 'all', - mode : 'local', - fieldLabel : 'DVR Configuration', - valueField : 'identifier', - displayField : 'name', - name : 'config_name', - emptyText : '(default)', - value : '', - editable : false - }) ], - buttons : [ { - text : 'Create', - handler : createRecording - } ] + var panel = new Ext.FormPanel({ + frame: true, + border: true, + bodyStyle: 'padding:5px', + labelAlign: 'right', + labelWidth: 110, + defaultType: 'textfield', + items: [new Ext.form.ComboBox({ + fieldLabel: 'Channel', + name: 'channel', + hiddenName: 'channelid', + editable: false, + allowBlank: false, + displayField: 'val', + valueField: 'key', + mode: 'remote', + triggerAction: 'all', + store: tvheadend.channels + }), new Ext.form.DateField({ + allowBlank: false, + fieldLabel: 'Date', + name: 'date' + }), new Ext.form.TimeField({ + allowBlank: false, + fieldLabel: 'Start time', + name: 'starttime', + increment: 10, + format: 'H:i' + }), new Ext.form.TimeField({ + allowBlank: false, + fieldLabel: 'Stop time', + name: 'stoptime', + increment: 10, + format: 'H:i' + }), new Ext.form.ComboBox({ + store: tvheadend.dvrprio, + value: "normal", + triggerAction: 'all', + mode: 'local', + fieldLabel: 'Priority', + valueField: 'identifier', + displayField: 'name', + name: 'pri' + }), { + allowBlank: false, + fieldLabel: 'Title', + name: 'title' + }, new Ext.form.ComboBox({ + store: tvheadend.configNames, + triggerAction: 'all', + mode: 'local', + fieldLabel: 'DVR Configuration', + valueField: 'identifier', + displayField: 'name', + name: 'config_name', + emptyText: '(default)', + value: '', + editable: false + })], + buttons: [{ + text: 'Create', + handler: createRecording + }] + }); - }); - - win = new Ext.Window({ - title : 'Add single recording', - layout : 'fit', - width : 500, - height : 300, - plain : true, - items : panel - }); - win.show(); - new Ext.form.ComboBox({ - store : tvheadend.configNames, - triggerAction : 'all', - mode : 'local', - fieldLabel : 'DVR Configuration', - valueField : 'identifier', - displayField : 'name', - name : 'config_name', - emptyText : '(default)', - value : '', - editable : false - }) - } - ; + win = new Ext.Window({ + title: 'Add single recording', + layout: 'fit', + width: 500, + height: 300, + plain: true, + items: panel + }); + win.show(); + new Ext.form.ComboBox({ + store: tvheadend.configNames, + triggerAction: 'all', + mode: 'local', + fieldLabel: 'DVR Configuration', + valueField: 'identifier', + displayField: 'name', + name: 'config_name', + emptyText: '(default)', + value: '', + editable: false + }); + } + ; /* Create combobox to allow user to select page size for upcoming/completed/failed recordings */ - var itemPageCombo = new Ext.form.ComboBox({ - name : 'itemsperpage', - width: 50, - mode : 'local', - store: new Ext.data.ArrayStore({ - fields: ['perpage'], - data : [ ['10'], ['20'], ['30'], ['40'], ['50'], ['60'], ['70'], ['80'], ['90'], ['100'] ] - }), - value : '20', - listWidth : 40, - triggerAction : 'all', - displayField : 'perpage', - valueField : 'perpage', - editable : true, - forceSelection : true, - listeners : { - scope: this, - 'select' : function(combo, record) { - bbar.pageSize = parseInt(record.get('perpage'), 10); - bbar.doLoad(bbar.cursor); - } - } - }); + var itemPageCombo = new Ext.form.ComboBox({ + name : 'itemsperpage', + width: 50, + mode : 'local', + store: new Ext.data.ArrayStore({ + fields: ['perpage'], + data : [['10'],['20'],['30'],['40'],['50'],['60'],['70'],['80'],['90'],['100']] + }), + value : '20', + listWidth : 40, + triggerAction : 'all', + displayField : 'perpage', + valueField : 'perpage', + editable : true, + forceSelection : true, + listeners : { + scope: this, + 'select' : function(combo, record) { + bbar.pageSize = parseInt(record.get('perpage'), 10); + bbar.doLoad(bbar.cursor); + } + } + }); /* Bottom toolbar to include default previous/goto-page/next and refresh buttons, also number-of-items combobox */ - var bbar = new Ext.PagingToolbar({ - store : dvrStore, - displayInfo : true, - items : [ '-', 'Recordings per page: ', itemPageCombo ], - displayMsg : 'Programs {0} - {1} of {2}', - emptyMsg : "No programs to display" - }); + var bbar = new Ext.PagingToolbar({ + store : dvrStore, + displayInfo : true, + items : ['-','Recordings per page: ',itemPageCombo], + displayMsg : 'Programs {0} - {1} of {2}', + emptyMsg : "No programs to display" + }); - var panel = new Ext.grid.GridPanel({ - loadMask : true, - stripeRows : true, - disableSelection : true, - title : title, - iconCls : iconCls, - store : dvrStore, - cm : dvrCm, - plugins : [ actions ], - viewConfig : { - forceFit : true - }, - tbar : [ { - tooltip : 'Schedule a new recording session on the server.', - iconCls : 'add', - text : 'Add entry', - handler : addEntry - }, '->', { - text : 'Help', - handler : function() { - new tvheadend.help('Digital Video Recorder', 'dvrlog.html'); - } - } ], - bbar : bbar - }); + var panel = new Ext.grid.GridPanel({ + loadMask: true, + stripeRows: true, + disableSelection: true, + title: title, + iconCls: iconCls, + store: dvrStore, + cm: dvrCm, + plugins: [actions], + viewConfig: { + forceFit: true + }, + tbar: [{ + tooltip: 'Schedule a new recording session on the server.', + iconCls: 'add', + text: 'Add entry', + handler: addEntry + }, '->', { + text: 'Help', + handler: function() { + new tvheadend.help('Digital Video Recorder', 'dvrlog.html'); + } + }], + bbar: bbar + }); - panel.on('rowclick', rowclicked); - function rowclicked(grid, index) { - new tvheadend.dvrDetails(grid.getStore().getAt(index).data); - } - return panel; -} + panel.on('rowclick', rowclicked); + function rowclicked(grid, index) { + new tvheadend.dvrDetails(grid.getStore().getAt(index).data); + } + return panel; +}; /** * @@ -465,665 +460,670 @@ tvheadend.dvrschedule = function(title, iconCls, dvrStore) { * */ tvheadend.autoreceditor = function() { - var fm = Ext.form; + var fm = Ext.form; + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: + [ + { + header: 'Enabled', + dataIndex: 'enabled', + width: 30, + xtype: 'checkcolumn' + }, + { + header: "Title (Regexp)", + dataIndex: 'title', + editor: new fm.TextField({ + allowBlank: true + }) + }, + { + header: "Channel", + dataIndex: 'channel', + editor: new Ext.form.ComboBox({ + loadingText: 'Loading...', + displayField: 'val', + valueField: 'key', + store: tvheadend.channels, + mode: 'local', + editable: false, + triggerAction: 'all', + emptyText: 'Only include channel...' + }), + renderer: function(v, m, r) { + var i = tvheadend.channels.find('key', v); + if (i !== -1) + v = tvheadend.channels.getAt(i).get('val'); + return v; + } + }, + { + header: "SeriesLink", + dataIndex: 'serieslink', + renderer: function(v) { + return v ? 'yes' : 'no'; + } + }, + { + header: "Channel tag", + dataIndex: 'tag', + editor: new Ext.form.ComboBox({ + displayField: 'name', + store: tvheadend.channelTags, + mode: 'local', + editable: false, + triggerAction: 'all', + emptyText: 'Only include tag...' + }) + }, + { + header: "Genre", + dataIndex: 'contenttype', + renderer: function(v) { + return tvheadend.contentGroupLookupName(v); + }, + editor: new Ext.form.ComboBox({ + valueField: 'code', + displayField: 'name', + store: tvheadend.ContentGroupStore, + mode: 'local', + editable: false, + triggerAction: 'all', + emptyText: 'Only include content...' + }) + }, + { + header: "Weekdays", + dataIndex: 'weekdays', + renderer: function(value, metadata, record, row, col, store) { + if (value.split) + value = value.split(','); + if (value.length === 7) + return 'All days'; + if (value.length === 0 || value[0] === "") + return 'No days'; + ret = []; + tags = value; + for (var i = 0; i < tags.length; i++) { + var tag = tvheadend.weekdays.getById(tags[i]); + if (typeof tag !== 'undefined') + ret.push(tag.data.name); + } + return ret.join(', '); + }, + editor: new Ext.ux.form.LovCombo({ + store: tvheadend.weekdays, + mode: 'local', + valueField: 'identifier', + displayField: 'name' + }) + }, { + header: "Starting Around", + dataIndex: 'approx_time', + renderer: function(value, metadata, record, row, col, store) { + if (typeof value === 'string') + return value; - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns : - [ - { - header: 'Enabled', - dataIndex: 'enabled', - width: 30, - xtype: 'checkcolumn' - }, + if (value === 0) + return ''; - { - header : "Title (Regexp)", - dataIndex : 'title', - editor : new fm.TextField({ - allowBlank : true - }) - }, - { - header : "Channel", - dataIndex : 'channel', - editor : new Ext.form.ComboBox({ - loadingText : 'Loading...', - displayField : 'val', - valueField: 'key', - store : tvheadend.channels, - mode : 'local', - editable : false, - triggerAction : 'all', - emptyText : 'Only include channel...' - }), - renderer : function (v, m, r) { - var i = tvheadend.channels.find('key', v); - if (i != -1) - v = tvheadend.channels.getAt(i).get('val') - return v - } - }, - { - header : "SeriesLink", - dataIndex : 'serieslink', - renderer : function(v) { - return v ? 'yes' : 'no'; - } - }, - { - header : "Channel tag", - dataIndex : 'tag', - editor : new Ext.form.ComboBox({ - displayField : 'name', - store : tvheadend.channelTags, - mode : 'local', - editable : false, - triggerAction : 'all', - emptyText : 'Only include tag...' - }) - }, - { - header : "Genre", - dataIndex : 'contenttype', - renderer : function(v) { - return tvheadend.contentGroupLookupName(v); - }, - editor : new Ext.form.ComboBox({ - valueField : 'code', - displayField : 'name', - store : tvheadend.ContentGroupStore, - mode : 'local', - editable : false, - triggerAction : 'all', - emptyText : 'Only include content...' - }) - }, - { - header : "Weekdays", - dataIndex : 'weekdays', - renderer : function(value, metadata, record, row, col, store) { - if (value.split) value = value.split(',') - if (value.length == 7) return 'All days'; - if (value.length == 0 || value[0] == "") return 'No days'; - ret = []; - tags = value; - for ( var i = 0; i < tags.length; i++) { - var tag = tvheadend.weekdays.getById(tags[i]); - if (typeof tag !== 'undefined') ret.push(tag.data.name); - } - return ret.join(', '); - }, - editor : new Ext.ux.form.LovCombo({ - store : tvheadend.weekdays, - mode : 'local', - valueField : 'identifier', - displayField : 'name' - }) - }, { - header : "Starting Around", - dataIndex : 'approx_time', - renderer : function(value, metadata, record, row, col, store) { - if (typeof value === 'string') return value; + var hours = Math.floor(value / 60); + var mins = value % 60; + var dt = new Date(); + dt.setHours(hours); + dt.setMinutes(mins); + return dt.format('H:i'); + }, + editor: new Ext.form.TimeField({ + allowBlank: true, + increment: 10, + format: 'H:i' + }) + }, { + header: "Priority", + dataIndex: 'pri', + width: 100, + renderer: function(value, metadata, record, row, col, store) { + return tvheadend.dvrprio.getById(value).data.name; + }, + editor: new fm.ComboBox({ + store: tvheadend.dvrprio, + triggerAction: 'all', + mode: 'local', + valueField: 'identifier', + displayField: 'name' + }) + }, { + header: "DVR Configuration", + dataIndex: 'config_name', + renderer: function(value, metadata, record, row, col, store) { + if (!value) { + return '(default)'; + } + else { + return value; + } + }, + editor: new Ext.form.ComboBox({ + store: tvheadend.configNames, + triggerAction: 'all', + mode: 'local', + valueField: 'identifier', + displayField: 'name', + name: 'config_name', + emptyText: '(default)', + editable: false + }) + }, { + header: "Created by", + dataIndex: 'creator', + editor: new fm.TextField({ + allowBlank: false + }) + }, { + header: "Comment", + dataIndex: 'comment', + editor: new fm.TextField({ + allowBlank: false + }) + }]}); - if (value === 0) return ''; - - var hours = Math.floor(value / 60); - var mins = value % 60; - var dt = new Date(); - dt.setHours(hours); - dt.setMinutes(mins); - return dt.format('H:i'); - }, - editor : new Ext.form.TimeField({ - allowBlank : true, - increment : 10, - format : 'H:i' - }) - }, { - header : "Priority", - dataIndex : 'pri', - width : 100, - renderer : function(value, metadata, record, row, col, store) { - return tvheadend.dvrprio.getById(value).data.name; - }, - editor : new fm.ComboBox({ - store : tvheadend.dvrprio, - triggerAction : 'all', - mode : 'local', - valueField : 'identifier', - displayField : 'name' - }) - }, { - header : "DVR Configuration", - dataIndex : 'config_name', - renderer : function(value, metadata, record, row, col, store) { - if (!value) { - return '(default)'; - } - else { - return value; - } - }, - editor : new Ext.form.ComboBox({ - store : tvheadend.configNames, - triggerAction : 'all', - mode : 'local', - valueField : 'identifier', - displayField : 'name', - name : 'config_name', - emptyText : '(default)', - editable : false - }) - }, { - header : "Created by", - dataIndex : 'creator', - editor : new fm.TextField({ - allowBlank : false - }) - }, { - header : "Comment", - dataIndex : 'comment', - editor : new fm.TextField({ - allowBlank : false - }) - } ]}); - - return new tvheadend.tableEditor('Automatic Recorder', 'autorec', cm, - tvheadend.autorecRecord, [], tvheadend.autorecStore, - 'autorec.html', 'wand'); -} + return new tvheadend.tableEditor('Automatic Recorder', 'autorec', cm, + tvheadend.autorecRecord, [], tvheadend.autorecStore, + 'autorec.html', 'wand'); +}; /** * */ tvheadend.dvr = function() { - function datastoreBuilder(url) { - return new Ext.data.JsonStore({ - root : 'entries', - totalProperty : 'totalCount', - fields : [ { - name : 'id' - }, { - name : 'channel' - }, { - name : 'title' - }, { - name : 'episode' - }, { - name : 'pri' - }, { - name : 'description' - }, { - name : 'chicon' - }, { - name : 'start', - type : 'date', - dateFormat : 'U' /* unix time */ - }, { - name : 'end', - type : 'date', - dateFormat : 'U' /* unix time */ - }, { - name : 'config_name' - }, { - name : 'status' - }, { - name : 'schedstate' - }, { - name : 'error' - }, { - name : 'creator' - }, { - name : 'duration' - }, { - name : 'filesize' - }, { - name : 'url' - } ], - url : url, - autoLoad : true, - id : 'id', - remoteSort : true - }); - } - tvheadend.dvrStoreUpcoming = datastoreBuilder('dvrlist_upcoming'); - tvheadend.dvrStoreFinished = datastoreBuilder('dvrlist_finished'); - tvheadend.dvrStoreFailed = datastoreBuilder('dvrlist_failed'); - tvheadend.dvrStores = [tvheadend.dvrStoreUpcoming, - tvheadend.dvrStoreFinished, - tvheadend.dvrStoreFailed]; + function datastoreBuilder(url) { + return new Ext.data.JsonStore({ + root: 'entries', + totalProperty: 'totalCount', + fields: [{ + name: 'id' + }, { + name: 'channel' + }, { + name: 'title' + }, { + name: 'episode' + }, { + name: 'pri' + }, { + name: 'description' + }, { + name: 'chicon' + }, { + name: 'start', + type: 'date', + dateFormat: 'U' /* unix time */ + }, { + name: 'end', + type: 'date', + dateFormat: 'U' /* unix time */ + }, { + name: 'config_name' + }, { + name: 'status' + }, { + name: 'schedstate' + }, { + name: 'error' + }, { + name: 'creator' + }, { + name: 'duration' + }, { + name: 'filesize' + }, { + name: 'url' + }], + url: url, + autoLoad: true, + id: 'id', + remoteSort: true + }); + } + tvheadend.dvrStoreUpcoming = datastoreBuilder('dvrlist_upcoming'); + tvheadend.dvrStoreFinished = datastoreBuilder('dvrlist_finished'); + tvheadend.dvrStoreFailed = datastoreBuilder('dvrlist_failed'); + tvheadend.dvrStores = [tvheadend.dvrStoreUpcoming, + tvheadend.dvrStoreFinished, + tvheadend.dvrStoreFailed]; - function updateDvrStore(store, r, m) { - r.data.status = m.status; - r.data.schedstate = m.schedstate; + function updateDvrStore(store, r, m) { + r.data.status = m.status; + r.data.schedstate = m.schedstate; - store.afterEdit(r); - store.fireEvent('updated', store, r, - Ext.data.Record.COMMIT); - } + store.afterEdit(r); + store.fireEvent('updated', store, r, + Ext.data.Record.COMMIT); + } - function reloadStores() { - for (var i = 0; i < tvheadend.dvrStores.length; i++) { - tvheadend.dvrStores[i].reload(); - } - } + function reloadStores() { + for (var i = 0; i < tvheadend.dvrStores.length; i++) { + tvheadend.dvrStores[i].reload(); + } + } - tvheadend.comet.on('dvrdb', function(m) { + tvheadend.comet.on('dvrdb', function(m) { - if (m.reload != null) { - reloadStores(); - } + if (m.reload != null) { + reloadStores(); + } - if (m.updateEntry != null) { - for (var i = 0; i < tvheadend.dvrStores.length; i++) { - var store = tvheadend.dvrStores[i]; - r = tvheadend.dvrStoreUpcoming.getById(m.id); - if (typeof r !== 'undefined') { - updateDvrStore(store, r, m); - return; - } - } - reloadStores(); - } - }); + if (m.updateEntry != null) { + for (var i = 0; i < tvheadend.dvrStores.length; i++) { + var store = tvheadend.dvrStores[i]; + r = tvheadend.dvrStoreUpcoming.getById(m.id); + if (typeof r !== 'undefined') { + updateDvrStore(store, r, m); + return; + } + } + reloadStores(); + } + }); - tvheadend.autorecRecord = Ext.data.Record.create([ 'enabled', 'title', - 'serieslink', 'channel', 'tag', 'creator', 'contenttype', 'comment', - 'weekdays', 'pri', 'approx_time', 'config_name' ]); + tvheadend.autorecRecord = Ext.data.Record.create(['enabled', 'title', + 'serieslink', 'channel', 'tag', 'creator', 'contenttype', 'comment', + 'weekdays', 'pri', 'approx_time', 'config_name']); - tvheadend.autorecStore = new Ext.data.JsonStore({ - root : 'entries', - fields : tvheadend.autorecRecord, - url : "tablemgr", - autoLoad : true, - id : 'id', - baseParams : { - table : "autorec", - op : "get" - } - }); + tvheadend.autorecStore = new Ext.data.JsonStore({ + root: 'entries', + fields: tvheadend.autorecRecord, + url: "tablemgr", + autoLoad: true, + id: 'id', + baseParams: { + table: "autorec", + op: "get" + } + }); - tvheadend.comet.on('autorec', function(m) { - if (m.reload != null) tvheadend.autorecStore.reload(); - }); + tvheadend.comet.on('autorec', function(m) { + if (m.reload != null) + tvheadend.autorecStore.reload(); + }); - var panel = new Ext.TabPanel({ - activeTab : 0, - autoScroll : true, - title : 'Digital Video Recorder', - iconCls : 'drive', - items : [ - new tvheadend.dvrschedule('Upcoming recordings', 'clock', tvheadend.dvrStoreUpcoming), - new tvheadend.dvrschedule('Finished recordings', 'television', tvheadend.dvrStoreFinished), - new tvheadend.dvrschedule('Failed recordings', 'exclamation', tvheadend.dvrStoreFailed), - new tvheadend.autoreceditor - ] - }); - return panel; -} + var panel = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'Digital Video Recorder', + iconCls: 'drive', + items: [ + new tvheadend.dvrschedule('Upcoming recordings', 'clock', tvheadend.dvrStoreUpcoming), + new tvheadend.dvrschedule('Finished recordings', 'television', tvheadend.dvrStoreFinished), + new tvheadend.dvrschedule('Failed recordings', 'exclamation', tvheadend.dvrStoreFailed), + new tvheadend.autoreceditor + ] + }); + return panel; +}; /** * Configuration panel (located under configuration) */ tvheadend.dvrsettings = function() { - var confreader = new Ext.data.JsonReader({ - root : 'dvrSettings' - }, [ 'storage', 'filePermissions', 'dirPermissions', 'postproc', 'retention', 'dayDirs', 'channelDirs', - 'channelInTitle', 'container', 'cache', 'dateInTitle', 'timeInTitle', - 'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 'titleDirs', - 'episodeInTitle', 'cleanTitle', 'tagFiles', 'commSkip', 'subtitleInTitle', - 'episodeBeforeDate', 'rewritePAT', 'rewritePMT' ]); + var confreader = new Ext.data.JsonReader({ + root: 'dvrSettings' + }, ['storage', 'filePermissions', 'dirPermissions', 'postproc', 'retention', 'dayDirs', 'channelDirs', + 'channelInTitle', 'container', 'cache', 'dateInTitle', 'timeInTitle', + 'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 'titleDirs', + 'episodeInTitle', 'cleanTitle', 'tagFiles', 'commSkip', 'subtitleInTitle', + 'episodeBeforeDate', 'rewritePAT', 'rewritePMT']); - var confcombo = new Ext.form.ComboBox({ - store : tvheadend.configNames, - triggerAction : 'all', - mode : 'local', - displayField : 'name', - name : 'config_name', - emptyText : '(default)', - value : '', - editable : true - }); - - var delButton = new Ext.Toolbar.Button({ - tooltip : 'Delete named configuration', - iconCls : 'remove', - text : "Delete configuration", - handler : deleteConfiguration, - disabled : true - }); - -/* Config panel variables */ - -/* DVR Behaviour */ - - var recordingContainer = new Ext.form.ComboBox({ - store : tvheadend.containers, - fieldLabel : 'Media container', - triggerAction : 'all', - displayField : 'description', - valueField : 'name', - editable : false, - width : 200, - hiddenName : 'container' - }); - - var cacheScheme = new Ext.form.ComboBox({ - store : tvheadend.caches, - fieldLabel : 'Cache scheme', - triggerAction : 'all', - displayField : 'description', - valueField : 'index', - editable : false, - width : 200, - hiddenName : 'cache' - }); - - var logRetention = new Ext.form.NumberField({ - allowNegative : false, - allowDecimals : false, - minValue : 1, - fieldLabel : 'DVR Log retention time (days)', - name : 'retention' - }); - - var timeBefore = new Ext.form.NumberField({ - allowDecimals : false, - fieldLabel : 'Extra time before recordings (minutes)', - name : 'preExtraTime' + var confcombo = new Ext.form.ComboBox({ + store: tvheadend.configNames, + triggerAction: 'all', + mode: 'local', + displayField: 'name', + name: 'config_name', + emptyText: '(default)', + value: '', + editable: true }); - + + var delButton = new Ext.Toolbar.Button({ + tooltip: 'Delete named configuration', + iconCls: 'remove', + text: "Delete configuration", + handler: deleteConfiguration, + disabled: true + }); + + /* Config panel variables */ + + /* DVR Behaviour */ + + var recordingContainer = new Ext.form.ComboBox({ + store: tvheadend.containers, + fieldLabel: 'Media container', + triggerAction: 'all', + displayField: 'description', + valueField: 'name', + editable: false, + width: 200, + hiddenName: 'container' + }); + + var cacheScheme = new Ext.form.ComboBox({ + store: tvheadend.caches, + fieldLabel: 'Cache scheme', + triggerAction: 'all', + displayField: 'description', + valueField: 'index', + editable: false, + width: 200, + hiddenName: 'cache' + }); + + var logRetention = new Ext.form.NumberField({ + allowNegative: false, + allowDecimals: false, + minValue: 1, + fieldLabel: 'DVR Log retention time (days)', + name: 'retention' + }); + + var timeBefore = new Ext.form.NumberField({ + allowDecimals: false, + fieldLabel: 'Extra time before recordings (minutes)', + name: 'preExtraTime' + }); + var timeAfter = new Ext.form.NumberField({ - allowDecimals : false, - fieldLabel : 'Extra time after recordings (minutes)', - name : 'postExtraTime' - }); - - var postProcessing = new Ext.form.TextField({ - width : 300, - fieldLabel : 'Post-processor command', - name : 'postproc' - }); + allowDecimals: false, + fieldLabel: 'Extra time after recordings (minutes)', + name: 'postExtraTime' + }); -/* Recording File Options */ + var postProcessing = new Ext.form.TextField({ + width: 300, + fieldLabel: 'Post-processor command', + name: 'postproc' + }); - var recordingPath = new Ext.form.TextField({ - width : 300, - fieldLabel : 'Recording system path', - name : 'storage' - }); + /* Recording File Options */ -/* NB: recordingPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */ - - var recordingPermissions = new Ext.form.TextField({ - regex : /^[0][0-7]{3}$/, - maskRe : /[0-7]/, - width : 100, - allowBlank : false, - blankText : 'You must provide a value - use octal chmod notation, e.g. 0664', - fieldLabel : 'File permissions (octal, e.g. 0664)', - name : 'filePermissions' - }); + var recordingPath = new Ext.form.TextField({ + width: 300, + fieldLabel: 'Recording system path', + name: 'storage' + }); -/* TO DO - Add 'override user umask?' option, then trigger fchmod in mkmux.c, muxer_pass.c after file created */ - - var PATrewrite = new Ext.form.Checkbox({ - fieldLabel : 'Rewrite PAT in passthrough mode', - name : 'rewritePAT' - }); - - var PMTrewrite = new Ext.form.Checkbox({ - fieldLabel : 'Rewrite PMT in passthrough mode', - name : 'rewritePMT' - }); - - var tagMetadata = new Ext.form.Checkbox({ - fieldLabel : 'Tag files with metadata', - name : 'tagFiles' - }); - - var skipCommercials = new Ext.form.Checkbox({ - fieldLabel : 'Skip commercials', - name : 'commSkip' - }); - -/* Subdirectories and filename handling */ + /* NB: recordingPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */ -/* NB: directoryPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */ + var recordingPermissions = new Ext.form.TextField({ + regex: /^[0][0-7]{3}$/, + maskRe: /[0-7]/, + width: 100, + allowBlank: false, + blankText: 'You must provide a value - use octal chmod notation, e.g. 0664', + fieldLabel: 'File permissions (octal, e.g. 0664)', + name: 'filePermissions' + }); - var directoryPermissions = new Ext.form.TextField({ - regex : /^[0][0-7]{3}$/, - maskRe : /[0-7]/, - width : 100, - allowBlank : false, - blankText : 'You must provide a value - use octal chmod notation, e.g. 0775', - fieldLabel : 'Directory permissions (octal, e.g. 0775)', - name : 'dirPermissions' - }); - -/* TO DO - Add 'override user umask?' option, then trigger fchmod in utils.c after directory created */ - - var dirsPerDay = new Ext.form.Checkbox({ - fieldLabel : 'Make subdirectories per day', - name : 'dayDirs' - }); - - var dirsPerChannel = new Ext.form.Checkbox({ - fieldLabel : 'Make subdirectories per channel', - name : 'channelDirs' - }); - - var dirsPerTitle = new Ext.form.Checkbox({ - fieldLabel : 'Make subdirectories per title', - name : 'titleDirs' - }); - - var incChannelInTitle = new Ext.form.Checkbox({ - fieldLabel : 'Include channel name in filename', - name : 'channelInTitle' - }); - - var incDateInTitle = new Ext.form.Checkbox({ - fieldLabel : 'Include date in filename', - name : 'dateInTitle' - }); - - var incTimeInTitle = new Ext.form.Checkbox({ - fieldLabel : 'Include time in filename', - name : 'timeInTitle' - }); - - var incEpisodeInTitle = new Ext.form.Checkbox({ - fieldLabel : 'Include episode in filename', - name : 'episodeInTitle' - }); - - var incSubtitleInTitle = new Ext.form.Checkbox({ - fieldLabel : 'Include subtitle in filename', - name : 'subtitleInTitle' - }); - - var episodeFirst = new Ext.form.Checkbox({ - fieldLabel : 'Put episode in filename before date and time', - name : 'episodeBeforeDate' - }); - - var stripUnsafeChars = new Ext.form.Checkbox({ - fieldLabel : 'Remove all unsafe characters from filename', - name : 'cleanTitle' - }); - - var stripWhitespace = new Ext.form.Checkbox({ - fieldLabel : 'Replace whitespace in title with \'-\'', - name : 'whitespaceInTitle' - }); - + /* TO DO - Add 'override user umask?' option, then trigger fchmod in mkmux.c, muxer_pass.c after file created */ -/* Sub-Panel - DVR behaviour */ - - var DVRBehaviour = new Ext.form.FieldSet({ - title: 'DVR Behaviour', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse : true, - items : [ recordingContainer, cacheScheme, logRetention, timeBefore, timeAfter, postProcessing ] - }); + var PATrewrite = new Ext.form.Checkbox({ + fieldLabel: 'Rewrite PAT in passthrough mode', + name: 'rewritePAT' + }); -/* Sub-Panel - File Output */ + var PMTrewrite = new Ext.form.Checkbox({ + fieldLabel: 'Rewrite PMT in passthrough mode', + name: 'rewritePMT' + }); - var FileOutputPanel = new Ext.form.FieldSet({ - title: 'Recording File Options', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse : true, - items : [ recordingPath, recordingPermissions, PATrewrite, PMTrewrite, tagMetadata, skipCommercials ] - }); + var tagMetadata = new Ext.form.Checkbox({ + fieldLabel: 'Tag files with metadata', + name: 'tagFiles' + }); -/* Sub-Panel - Directory operations */ + var skipCommercials = new Ext.form.Checkbox({ + fieldLabel: 'Skip commercials', + name: 'commSkip' + }); - var DirHandlingPanel = new Ext.form.FieldSet({ - title: 'Subdirectory Options', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse : true, - items : [ directoryPermissions, dirsPerDay, dirsPerChannel, dirsPerTitle ] - }); - -/* Sub-Panel - File operations - Break into two 4-item panels */ + /* Subdirectories and filename handling */ - var FileHandlingPanelA = new Ext.form.FieldSet({ - width: 350, - border: false, - autoHeight: true, - items : [ incChannelInTitle, incDateInTitle, incTimeInTitle, incEpisodeInTitle ] - }); + /* NB: directoryPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */ - var FileHandlingPanelB = new Ext.form.FieldSet({ - width: 350, - border: false, - autoHeight: true, - items : [ incSubtitleInTitle, episodeFirst, stripUnsafeChars, stripWhitespace ] - }); + var directoryPermissions = new Ext.form.TextField({ + regex: /^[0][0-7]{3}$/, + maskRe: /[0-7]/, + width: 100, + allowBlank: false, + blankText: 'You must provide a value - use octal chmod notation, e.g. 0775', + fieldLabel: 'Directory permissions (octal, e.g. 0775)', + name: 'dirPermissions' + }); - var FileHandlingPanel = new Ext.form.FieldSet({ - title: 'Filename Options', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse : true, - items : [{ - layout: 'column', - border: false, - items : [ FileHandlingPanelA, FileHandlingPanelB ] - }] - }); + /* TO DO - Add 'override user umask?' option, then trigger fchmod in utils.c after directory created */ -/* Main (form) panel */ - - var confpanel = new Ext.FormPanel({ - title : 'Digital Video Recorder', - iconCls : 'drive', - border : false, - bodyStyle : 'padding:15px', - anchor : '100% 50%', - labelAlign : 'right', - labelWidth : 250, - waitMsgTarget : true, - reader : confreader, - defaultType : 'textfield', - layout : 'form', - items : [ DVRBehaviour, FileOutputPanel, DirHandlingPanel, FileHandlingPanel ], - - tbar : [ confcombo, { - tooltip : 'Save changes made to dvr configuration below', - iconCls : 'save', - text : "Save configuration", - handler : saveChanges - }, delButton, '->', { - text : 'Help', - handler : function() { - new tvheadend.help('DVR configuration', 'config_dvr.html'); - } - } ] - }); + var dirsPerDay = new Ext.form.Checkbox({ + fieldLabel: 'Make subdirectories per day', + name: 'dayDirs' + }); - function loadConfig() { - confpanel.getForm().load({ - url : 'dvr', - params : { - 'op' : 'loadSettings', - 'config_name' : confcombo.getValue() - }, - success : function(form, action) { - confpanel.enable(); - } - }); - } + var dirsPerChannel = new Ext.form.Checkbox({ + fieldLabel: 'Make subdirectories per channel', + name: 'channelDirs' + }); - confcombo.on('select', function() { - if (confcombo.getValue() == '') delButton.disable(); - else delButton.enable(); - loadConfig(); - }); + var dirsPerTitle = new Ext.form.Checkbox({ + fieldLabel: 'Make subdirectories per title', + name: 'titleDirs' + }); - confpanel.on('render', function() { - loadConfig(); - }); + var incChannelInTitle = new Ext.form.Checkbox({ + fieldLabel: 'Include channel name in filename', + name: 'channelInTitle' + }); - function saveChanges() { - var config_name = confcombo.getValue(); - confpanel.getForm().submit({ - url : 'dvr', - params : { - 'op' : 'saveSettings', - 'config_name' : config_name - }, - waitMsg : 'Saving Data...', - success : function(form, action) { - confcombo.setValue(config_name); - confcombo.fireEvent('select'); - }, - failure : function(form, action) { - Ext.Msg.alert('Save failed', action.result.errormsg); - } - }); - } + var incDateInTitle = new Ext.form.Checkbox({ + fieldLabel: 'Include date in filename', + name: 'dateInTitle' + }); - function deleteConfiguration() { - if (confcombo.getValue() != "") { - Ext.MessageBox.confirm('Message', - 'Do you really want to delete DVR configuration \'' - + confcombo.getValue() + '\'?', deleteAction); - } - } + var incTimeInTitle = new Ext.form.Checkbox({ + fieldLabel: 'Include time in filename', + name: 'timeInTitle' + }); - function deleteAction(btn) { - if (btn == 'yes') { - confpanel.getForm().submit({ - url : 'dvr', - params : { - 'op' : 'deleteSettings', - 'config_name' : confcombo.getValue() - }, - waitMsg : 'Deleting Data...', - success : function(form, action) { - confcombo.setValue(''); - confcombo.fireEvent('select'); - }, - failure : function(form, action) { - Ext.Msg.alert('Delete failed', action.result.errormsg); - } - }); - } - } + var incEpisodeInTitle = new Ext.form.Checkbox({ + fieldLabel: 'Include episode in filename', + name: 'episodeInTitle' + }); - return confpanel; -} + var incSubtitleInTitle = new Ext.form.Checkbox({ + fieldLabel: 'Include subtitle in filename', + name: 'subtitleInTitle' + }); + + var episodeFirst = new Ext.form.Checkbox({ + fieldLabel: 'Put episode in filename before date and time', + name: 'episodeBeforeDate' + }); + + var stripUnsafeChars = new Ext.form.Checkbox({ + fieldLabel: 'Remove all unsafe characters from filename', + name: 'cleanTitle' + }); + + var stripWhitespace = new Ext.form.Checkbox({ + fieldLabel: 'Replace whitespace in title with \'-\'', + name: 'whitespaceInTitle' + }); + + /* Sub-Panel - DVR behaviour */ + + var DVRBehaviour = new Ext.form.FieldSet({ + title: 'DVR Behaviour', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [recordingContainer, cacheScheme, logRetention, timeBefore, timeAfter, postProcessing] + }); + + /* Sub-Panel - File Output */ + + var FileOutputPanel = new Ext.form.FieldSet({ + title: 'Recording File Options', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [recordingPath, recordingPermissions, PATrewrite, PMTrewrite, tagMetadata, skipCommercials] + }); + + /* Sub-Panel - Directory operations */ + + var DirHandlingPanel = new Ext.form.FieldSet({ + title: 'Subdirectory Options', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [directoryPermissions, dirsPerDay, dirsPerChannel, dirsPerTitle] + }); + + /* Sub-Panel - File operations - Break into two 4-item panels */ + + var FileHandlingPanelA = new Ext.form.FieldSet({ + width: 350, + border: false, + autoHeight: true, + items : [incChannelInTitle, incDateInTitle, incTimeInTitle, incEpisodeInTitle] + }); + + var FileHandlingPanelB = new Ext.form.FieldSet({ + width: 350, + border: false, + autoHeight: true, + items : [incSubtitleInTitle, episodeFirst, stripUnsafeChars, stripWhitespace] + }); + + var FileHandlingPanel = new Ext.form.FieldSet({ + title: 'Filename Options', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse : true, + items : [{ + layout: 'column', + border: false, + items : [FileHandlingPanelA, FileHandlingPanelB] + }] + }); + + /* Main (form) panel */ + + var confpanel = new Ext.FormPanel({ + title: 'Digital Video Recorder', + iconCls: 'drive', + border: false, + bodyStyle: 'padding:15px', + anchor: '100% 50%', + labelAlign: 'right', + labelWidth: 250, + waitMsgTarget: true, + reader: confreader, + defaultType: 'textfield', + layout: 'form', + items: [DVRBehaviour, FileOutputPanel, DirHandlingPanel, FileHandlingPanel], + tbar: [confcombo, { + tooltip: 'Save changes made to dvr configuration below', + iconCls: 'save', + text: "Save configuration", + handler: saveChanges + }, delButton, '->', { + text: 'Help', + handler: function() { + new tvheadend.help('DVR configuration', 'config_dvr.html'); + } + }] + }); + + function loadConfig() { + confpanel.getForm().load({ + url: 'dvr', + params: { + 'op': 'loadSettings', + 'config_name': confcombo.getValue() + }, + success: function(form, action) { + confpanel.enable(); + } + }); + } + + confcombo.on('select', function() { + if (confcombo.getValue() === '') + delButton.disable(); + else + delButton.enable(); + loadConfig(); + }); + + confpanel.on('render', function() { + loadConfig(); + }); + + function saveChanges() { + var config_name = confcombo.getValue(); + confpanel.getForm().submit({ + url: 'dvr', + params: { + 'op': 'saveSettings', + 'config_name': config_name + }, + waitMsg: 'Saving Data...', + success: function(form, action) { + confcombo.setValue(config_name); + confcombo.fireEvent('select'); + }, + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); + } + + function deleteConfiguration() { + if (confcombo.getValue() !== "") { + Ext.MessageBox.confirm('Message', + 'Do you really want to delete DVR configuration \'' + + confcombo.getValue() + '\'?', deleteAction); + } + } + + function deleteAction(btn) { + if (btn === 'yes') { + confpanel.getForm().submit({ + url: 'dvr', + params: { + 'op': 'deleteSettings', + 'config_name': confcombo.getValue() + }, + waitMsg: 'Deleting Data...', + success: function(form, action) { + confcombo.setValue(''); + confcombo.fireEvent('select'); + }, + failure: function(form, action) { + Ext.Msg.alert('Delete failed', action.result.errormsg); + } + }); + } + } + + return confpanel; +}; diff --git a/src/webui/static/app/epg.js b/src/webui/static/app/epg.js old mode 100755 new mode 100644 index 4bf4c260..c4175e6a --- a/src/webui/static/app/epg.js +++ b/src/webui/static/app/epg.js @@ -1,276 +1,278 @@ tvheadend.brands = new Ext.data.JsonStore({ - root : 'entries', - fields : [ 'uri', 'title' ], - autoLoad : true, - url : 'epgobject', - baseParams : { - op : 'brandList' - } + root: 'entries', + fields: ['uri', 'title'], + autoLoad: true, + url: 'epgobject', + baseParams: { + op: 'brandList' + } }); //WIBNI: might want this store to periodically update tvheadend.ContentGroupStore = new Ext.data.JsonStore({ - root : 'entries', - fields : [ 'name', 'code' ], - autoLoad : true, - url : 'ecglist' + root: 'entries', + fields: ['name', 'code'], + autoLoad: true, + url: 'ecglist' }); tvheadend.contentGroupLookupName = function(code) { - ret = ""; - tvheadend.ContentGroupStore.each(function(r) { - if (r.data.code == code) ret = r.data.name; - else if (ret == "" && r.data.code == (code & 0xF0)) ret = r.data.name; - }); - return ret; -} + ret = ""; + tvheadend.ContentGroupStore.each(function(r) { + if (r.data.code === code) + ret = r.data.name; + else if (ret === "" && r.data.code === (code & 0xF0)) + ret = r.data.name; + }); + return ret; +}; tvheadend.ContentGroupStore.setDefaultSort('code', 'ASC'); tvheadend.epgDetails = function(event) { - var content = ''; - - if (event.chicon != null && event.chicon.length > 0) - content += ''; - - content += '
' + event.title; - if (event.subtitle) - content += " : " + event.subtitle; - content += '
'; - content += '
' + event.episode + '
'; - content += '
' + event.description + '
'; - content += '
' + event.starrating + '
'; - content += '
' + event.agerating + '
'; - content += '
' + tvheadend.contentGroupLookupName(event.contenttype) + '
'; + var content = ''; - if (event.ext_desc != null) - content += '
' + event.ext_desc + '
'; + if (event.chicon != null && event.chicon.length > 0) + content += ''; - if (event.ext_item != null) - content += '
' + event.ext_item + '
'; + content += '
' + event.title; + if (event.subtitle) + content += " : " + event.subtitle; + content += '
'; + content += '
' + event.episode + '
'; + content += '
' + event.description + '
'; + content += '
' + event.starrating + '
'; + content += '
' + event.agerating + '
'; + content += '
' + tvheadend.contentGroupLookupName(event.contenttype) + '
'; - if (event.ext_text != null) - content += '
' + event.ext_text + '
'; + if (event.ext_desc != null) + content += '
' + event.ext_desc + '
'; - content += '' - content += ''; - content += '
'; + if (event.ext_item != null) + content += '
' + event.ext_item + '
'; - var confcombo = new Ext.form.ComboBox({ - store : tvheadend.configNames, - triggerAction : 'all', - mode : 'local', - valueField : 'identifier', - displayField : 'name', - name : 'config_name', - emptyText : '(default)', - value : '', - editable : false - }); + if (event.ext_text != null) + content += '
' + event.ext_text + '
'; - var win = new Ext.Window({ - title : event.title, - layout : 'fit', - width : 500, - height : 300, - constrainHeader : true, - buttons : [ confcombo, new Ext.Button({ - handler : recordEvent, - text : "Record program" - }), new Ext.Button({ - handler : recordSeries, - text : event.serieslink ? "Record series" : "Autorec" - }) ], - buttonAlign : 'center', - html : content - }); - win.show(); + content += ''; + content += ''; + content += '
'; - function recordEvent() { - record('recordEvent'); - } + var confcombo = new Ext.form.ComboBox({ + store: tvheadend.configNames, + triggerAction: 'all', + mode: 'local', + valueField: 'identifier', + displayField: 'name', + name: 'config_name', + emptyText: '(default)', + value: '', + editable: false + }); - function recordSeries() { - record('recordSeries'); - } + var win = new Ext.Window({ + title: event.title, + layout: 'fit', + width: 500, + height: 300, + constrainHeader: true, + buttons: [confcombo, new Ext.Button({ + handler: recordEvent, + text: "Record program" + }), new Ext.Button({ + handler: recordSeries, + text: event.serieslink ? "Record series" : "Autorec" + })], + buttonAlign: 'center', + html: content + }); + win.show(); - function record(op) { - Ext.Ajax.request({ - url : 'dvr', - params : { - eventId : event.id, - op : op, - config_name : confcombo.getValue() - }, + function recordEvent() { + record('recordEvent'); + } - success : function(response, options) { - win.close(); - }, + function recordSeries() { + record('recordSeries'); + } - failure : function(response, options) { - Ext.MessageBox.alert('DVR', response.statusText); - } - }); - } + function record(op) { + Ext.Ajax.request({ + url: 'dvr', + params: { + eventId: event.id, + op: op, + config_name: confcombo.getValue() + }, + success: function(response, options) { + win.close(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('DVR', response.statusText); + } + }); + } - function showAlternatives(s) { - var e = Ext.get('altbcast') - html = ''; - if (s.getTotalCount() > 0) { - html += '
Alternative Broadcasts
'; - for (i = 0; i < s.getTotalCount(); i++) { - var ab = s.getAt(i).data; - var dt = Date.parseDate(ab.start, 'U'); - html += '
' + dt.format('l H:i') - + '   ' + ab.channel + '
'; - } - } - e.dom.innerHTML = html; - } - function showRelated(s) { - var e = Ext.get('related') - html = ''; - if (s.getTotalCount() > 0) { - html += '
Related Episodes
'; - for (i = 0; i < s.getTotalCount(); i++) { - var ee = s.getAt(i).data; - html += '
'; - if (ee.episode) html += ee.episode + '   '; - html += ee.title; - if (ee.subtitle) html += ' : ' + ee.subtitle - html += '
'; - } - } - e.dom.innerHTML = html; - } + function showAlternatives(s) { + var e = Ext.get('altbcast'); + html = ''; + if (s.getTotalCount() > 0) { + html += '
Alternative Broadcasts
'; + for (i = 0; i < s.getTotalCount(); i++) { + var ab = s.getAt(i).data; + var dt = Date.parseDate(ab.start, 'U'); + html += '
' + dt.format('l H:i') + + '   ' + ab.channel + '
'; + } + } + e.dom.innerHTML = html; + } + function showRelated(s) { + var e = Ext.get('related'); + html = ''; + if (s.getTotalCount() > 0) { + html += '
Related Episodes
'; + for (i = 0; i < s.getTotalCount(); i++) { + var ee = s.getAt(i).data; + html += '
'; + if (ee.episode) + html += ee.episode + '   '; + html += ee.title; + if (ee.subtitle) + html += ' : ' + ee.subtitle; + html += '
'; + } + } + e.dom.innerHTML = html; + } - var ab = new Ext.data.JsonStore({ - root : 'entries', - url : 'epgrelated', - autoLoad : false, - id : 'id', - baseParams : { - op : 'get', - id : event.id, - type : 'alternative' - }, - fields : Ext.data.Record.create([ 'id', 'channel', 'start' ]), - listeners : { - 'datachanged' : showAlternatives - } - }); - var re = new Ext.data.JsonStore({ - root : 'entries', - url : 'epgrelated', - autoLoad : false, - id : 'uri', - baseParams : { - op : 'get', - id : event.id, - type : 'related' - }, - fields : Ext.data.Record - .create([ 'uri', 'title', 'subtitle', 'episode' ]), - listeners : { - 'datachanged' : showRelated - } - }); -} + var ab = new Ext.data.JsonStore({ + root: 'entries', + url: 'epgrelated', + autoLoad: false, + id: 'id', + baseParams: { + op: 'get', + id: event.id, + type: 'alternative' + }, + fields: Ext.data.Record.create(['id', 'channel', 'start']), + listeners: { + 'datachanged': showAlternatives + } + }); + var re = new Ext.data.JsonStore({ + root: 'entries', + url: 'epgrelated', + autoLoad: false, + id: 'uri', + baseParams: { + op: 'get', + id: event.id, + type: 'related' + }, + fields: Ext.data.Record + .create(['uri', 'title', 'subtitle', 'episode']), + listeners: { + 'datachanged': showRelated + } + }); +}; tvheadend.epg = function() { - var xg = Ext.grid; + var xg = Ext.grid; - var actions = new Ext.ux.grid.RowActions({ - header : '', - width : 20, - dataIndex : 'actions', - actions : [ { - iconIndex : 'schedstate' - } ] - }); + var actions = new Ext.ux.grid.RowActions({ + header: '', + width: 20, + dataIndex: 'actions', + actions: [{ + iconIndex: 'schedstate' + }] + }); - var epgStore = new Ext.ux.grid.livegrid.Store({ - autoLoad : true, - url : 'epg', - bufferSize : 300, - reader : new Ext.ux.grid.livegrid.JsonReader({ - root : 'entries', - totalProperty : 'totalCount', - id : 'id' - }, [ { - name : 'id' - }, { - name : 'channel' - }, { - name : 'channelid' - }, { - name : 'title' - }, { - name : 'subtitle' - }, { - name : 'episode' - }, { - name : 'description' - }, { - name : 'chicon' - }, { - name : 'start', - type : 'date', - dateFormat : 'U' /* unix time */ - }, { - name : 'end', - type : 'date', - dateFormat : 'U' /* unix time */ - }, { - name : 'duration' - }, { - name : 'starrating' - }, { - name : 'agerating' - }, { - name : 'contenttype' - }, { - name : 'schedstate' - }, { - name : 'serieslink' - } ]) - }); + var epgStore = new Ext.ux.grid.livegrid.Store({ + autoLoad: true, + url: 'epg', + bufferSize: 300, + reader: new Ext.ux.grid.livegrid.JsonReader({ + root: 'entries', + totalProperty: 'totalCount', + id: 'id' + }, [{ + name: 'id' + }, { + name: 'channel' + }, { + name: 'channelid' + }, { + name: 'title' + }, { + name: 'subtitle' + }, { + name: 'episode' + }, { + name: 'description' + }, { + name: 'chicon' + }, { + name: 'start', + type: 'date', + dateFormat: 'U' /* unix time */ + }, { + name: 'end', + type: 'date', + dateFormat: 'U' /* unix time */ + }, { + name: 'duration' + }, { + name: 'starrating' + }, { + name: 'agerating' + }, { + name: 'contenttype' + }, { + name: 'schedstate' + }, { + name: 'serieslink' + }]) + }); - function setMetaAttr(meta, record) { - var now = new Date; - var start = record.get('start'); + function setMetaAttr(meta, record) { + var now = new Date; + var start = record.get('start'); - if (now.getTime() > start.getTime()) { - meta.attr = 'style="font-weight:bold;"'; - } - } + if (now.getTime() > start.getTime()) { + meta.attr = 'style="font-weight:bold;"'; + } + } - function renderDate(value, meta, record, rowIndex, colIndex, store) { - setMetaAttr(meta, record); + function renderDate(value, meta, record, rowIndex, colIndex, store) { + setMetaAttr(meta, record); - var dt = new Date(value); - return dt.format('D, M d, H:i'); - } + var dt = new Date(value); + return dt.format('D, M d, H:i'); + } - function renderDuration(value, meta, record, rowIndex, colIndex, store) { - setMetaAttr(meta, record); + function renderDuration(value, meta, record, rowIndex, colIndex, store) { + setMetaAttr(meta, record); - value = Math.floor(value / 60); + value = Math.floor(value / 60); - if (value >= 60) { - var min = value % 60; - var hours = Math.floor(value / 60); + if (value >= 60) { + var min = value % 60; + var hours = Math.floor(value / 60); - if (min == 0) { - return hours + ' hrs'; - } - return hours + ' hrs, ' + min + ' min'; - } - else { - return value + ' min'; - } - } + if (min === 0) { + return hours + ' hrs'; + } + return hours + ' hrs, ' + min + ' min'; + } + else { + return value + ' min'; + } + } function renderText(value, meta, record, rowIndex, colIndex, store) { setMetaAttr(meta, record); @@ -284,267 +286,267 @@ tvheadend.epg = function() { return '' + value; } - var epgCm = new Ext.grid.ColumnModel([ actions, { - width : 250, - id : 'title', - header : "Title", - dataIndex : 'title', - renderer : renderText - }, { - width : 250, - id : 'subtitle', - header : "SubTitle", - dataIndex : 'subtitle', - renderer : renderText - }, { - width : 100, - id : 'episode', - header : "Episode", - dataIndex : 'episode', - renderer : renderText - }, { - width : 100, - id : 'start', - header : "Start", - dataIndex : 'start', - renderer : renderDate - }, { - width : 100, - hidden : true, - id : 'end', - header : "End", - dataIndex : 'end', - renderer : renderDate - }, { - width : 100, - id : 'duration', - header : "Duration", - dataIndex : 'duration', - renderer : renderDuration - }, { - width : 250, - id : 'channel', - header : "Channel", - dataIndex : 'channel', - renderer : renderText - }, { - width : 50, - id : 'starrating', - header : "Stars", - dataIndex : 'starrating', - renderer : renderInt - }, { - width : 50, - id : 'agerating', - header : "Age", - dataIndex : 'agerating', - renderer : renderInt - }, { - width : 250, - id : 'contenttype', - header : "Content Type", - dataIndex : 'contenttype', - renderer : function(v) { - return tvheadend.contentGroupLookupName(v); - } - } ]); + var epgCm = new Ext.grid.ColumnModel([actions, { + width: 250, + id: 'title', + header: "Title", + dataIndex: 'title', + renderer: renderText + }, { + width: 250, + id: 'subtitle', + header: "SubTitle", + dataIndex: 'subtitle', + renderer: renderText + }, { + width: 100, + id: 'episode', + header: "Episode", + dataIndex: 'episode', + renderer: renderText + }, { + width: 100, + id: 'start', + header: "Start", + dataIndex: 'start', + renderer: renderDate + }, { + width: 100, + hidden: true, + id: 'end', + header: "End", + dataIndex: 'end', + renderer: renderDate + }, { + width: 100, + id: 'duration', + header: "Duration", + dataIndex: 'duration', + renderer: renderDuration + }, { + width: 250, + id: 'channel', + header: "Channel", + dataIndex: 'channel', + renderer: renderText + }, { + width: 50, + id: 'starrating', + header: "Stars", + dataIndex: 'starrating', + renderer: renderInt + }, { + width: 50, + id: 'agerating', + header: "Age", + dataIndex: 'agerating', + renderer: renderInt + }, { + width: 250, + id: 'contenttype', + header: "Content Type", + dataIndex: 'contenttype', + renderer: function(v) { + return tvheadend.contentGroupLookupName(v); + } + }]); - // Title search box + // Title search box - var epgFilterTitle = new Ext.form.TextField({ - emptyText : 'Search title...', - width : 200 - }); + var epgFilterTitle = new Ext.form.TextField({ + emptyText: 'Search title...', + width: 200 + }); - // Channels, uses global store + // Channels, uses global store - var epgFilterChannels = new Ext.form.ComboBox({ - loadingText : 'Loading...', - width : 200, - displayField : 'val', - store : tvheadend.channels, - mode : 'local', - editable : true, - forceSelection: true, - triggerAction : 'all', - emptyText : 'Filter channel...' - }); + var epgFilterChannels = new Ext.form.ComboBox({ + loadingText: 'Loading...', + width: 200, + displayField: 'val', + store: tvheadend.channels, + mode: 'local', + editable: true, + forceSelection: true, + triggerAction: 'all', + emptyText: 'Filter channel...' + }); - // Tags, uses global store + // Tags, uses global store - var epgFilterChannelTags = new Ext.form.ComboBox({ - width : 200, - displayField : 'name', - store : tvheadend.channelTags, - mode : 'local', - editable : true, - forceSelection: true, - triggerAction : 'all', - emptyText : 'Filter tag...' - }); + var epgFilterChannelTags = new Ext.form.ComboBox({ + width: 200, + displayField: 'name', + store: tvheadend.channelTags, + mode: 'local', + editable: true, + forceSelection: true, + triggerAction: 'all', + emptyText: 'Filter tag...' + }); - // Content groups + // Content groups - var epgFilterContentGroup = new Ext.form.ComboBox({ - loadingText : 'Loading...', - width : 200, - displayField : 'name', - store : tvheadend.ContentGroupStore, - mode : 'local', - editable : true, - forceSelection: true, - triggerAction : 'all', - emptyText : 'Filter content type...' - }); + var epgFilterContentGroup = new Ext.form.ComboBox({ + loadingText: 'Loading...', + width: 200, + displayField: 'name', + store: tvheadend.ContentGroupStore, + mode: 'local', + editable: true, + forceSelection: true, + triggerAction: 'all', + emptyText: 'Filter content type...' + }); - function epgQueryClear() { - delete epgStore.baseParams.channel; - delete epgStore.baseParams.tag; - delete epgStore.baseParams.contenttype; - delete epgStore.baseParams.title; + function epgQueryClear() { + delete epgStore.baseParams.channel; + delete epgStore.baseParams.tag; + delete epgStore.baseParams.contenttype; + delete epgStore.baseParams.title; - epgFilterChannels.setValue(""); - epgFilterChannelTags.setValue(""); - epgFilterContentGroup.setValue(""); - epgFilterTitle.setValue(""); + epgFilterChannels.setValue(""); + epgFilterChannelTags.setValue(""); + epgFilterContentGroup.setValue(""); + epgFilterTitle.setValue(""); - epgStore.reload(); - } + epgStore.reload(); + } - epgFilterChannels.on('select', function(c, r) { - if (epgStore.baseParams.channel != r.data.key) { - epgStore.baseParams.channel = r.data.key; - epgStore.reload(); - } - }); + epgFilterChannels.on('select', function(c, r) { + if (epgStore.baseParams.channel !== r.data.key) { + epgStore.baseParams.channel = r.data.key; + epgStore.reload(); + } + }); - epgFilterChannelTags.on('select', function(c, r) { - if (epgStore.baseParams.tag != r.data.name) { - epgStore.baseParams.tag = r.data.name; - epgStore.reload(); - } - }); + epgFilterChannelTags.on('select', function(c, r) { + if (epgStore.baseParams.tag !== r.data.name) { + epgStore.baseParams.tag = r.data.name; + epgStore.reload(); + } + }); - epgFilterContentGroup.on('select', function(c, r) { - if (epgStore.baseParams.contenttype != r.data.code) { - epgStore.baseParams.contenttype = r.data.code; - epgStore.reload(); - } - }); + epgFilterContentGroup.on('select', function(c, r) { + if (epgStore.baseParams.contenttype !== r.data.code) { + epgStore.baseParams.contenttype = r.data.code; + epgStore.reload(); + } + }); - epgFilterTitle.on('valid', function(c) { - var value = c.getValue(); + epgFilterTitle.on('valid', function(c) { + var value = c.getValue(); - if (value.length < 1) value = null; + if (value.length < 1) + value = null; - if (epgStore.baseParams.title != value) { - epgStore.baseParams.title = value; - epgStore.reload(); - } - }); + if (epgStore.baseParams.title !== value) { + epgStore.baseParams.title = value; + epgStore.reload(); + } + }); - var epgView = new Ext.ux.grid.livegrid.GridView({ - nearLimit : 100, - loadMask : { - msg : 'Buffering. Please wait...' - } - }); + var epgView = new Ext.ux.grid.livegrid.GridView({ + nearLimit: 100, + loadMask: { + msg: 'Buffering. Please wait...' + } + }); - var panel = new Ext.ux.grid.livegrid.GridPanel({ - stateful: true, - stateId : 'epggrid', - enableDragDrop : false, - cm : epgCm, - plugins : [ actions ], - title : 'Electronic Program Guide', - iconCls : 'newspaper', - store : epgStore, - selModel : new Ext.ux.grid.livegrid.RowSelectionModel(), - view : epgView, - tbar : [ - epgFilterTitle, - '-', - epgFilterChannels, - '-', - epgFilterChannelTags, - '-', - epgFilterContentGroup, - '-', - { - text : 'Reset', - handler : epgQueryClear - }, - '->', - { - text : 'Watch TV', - iconCls : 'eye', - handler : function() { - new tvheadend.VideoPlayer(); - } - }, - '-', - { - text : 'Create AutoRec', - iconCls : 'wand', - tooltip : 'Create an automatic recording entry that will ' - + 'record all future programmes that matches ' - + 'the current query.', - handler : createAutoRec - }, '-', { - text : 'Help', - handler : function() { - new tvheadend.help('Electronic Program Guide', 'epg.html'); - } - } ], + var panel = new Ext.ux.grid.livegrid.GridPanel({ + stateful: true, + stateId: 'epggrid', + enableDragDrop: false, + cm: epgCm, + plugins: [actions], + title: 'Electronic Program Guide', + iconCls: 'newspaper', + store: epgStore, + selModel: new Ext.ux.grid.livegrid.RowSelectionModel(), + view: epgView, + tbar: [ + epgFilterTitle, + '-', + epgFilterChannels, + '-', + epgFilterChannelTags, + '-', + epgFilterContentGroup, + '-', + { + text: 'Reset', + handler: epgQueryClear + }, + '->', + { + text: 'Watch TV', + iconCls: 'eye', + handler: function() { + new tvheadend.VideoPlayer(); + } + }, + '-', + { + text: 'Create AutoRec', + iconCls: 'wand', + tooltip: 'Create an automatic recording entry that will ' + + 'record all future programmes that matches ' + + 'the current query.', + handler: createAutoRec + }, '-', { + text: 'Help', + handler: function() { + new tvheadend.help('Electronic Program Guide', 'epg.html'); + } + }], + bbar: new Ext.ux.grid.livegrid.Toolbar({ + view: epgView, + displayInfo: true + }) + }); - bbar : new Ext.ux.grid.livegrid.Toolbar({ - view : epgView, - displayInfo : true - }) - }); + panel.on('rowclick', rowclicked); - panel.on('rowclick', rowclicked); + function rowclicked(grid, index) { + new tvheadend.epgDetails(grid.getStore().getAt(index).data); + } - function rowclicked(grid, index) { - new tvheadend.epgDetails(grid.getStore().getAt(index).data); - } + function createAutoRec() { - function createAutoRec() { + var title = epgStore.baseParams.title ? epgStore.baseParams.title + : "Don't care"; + var channel = epgStore.baseParams.channel ? epgStore.baseParams.channel + : "Don't care"; + var tag = epgStore.baseParams.tag ? epgStore.baseParams.tag + : "Don't care"; + var contenttype = epgStore.baseParams.contenttype ? epgStore.baseParams.contenttype + : "Don't care"; - var title = epgStore.baseParams.title ? epgStore.baseParams.title - : "Don't care"; - var channel = epgStore.baseParams.channel ? epgStore.baseParams.channel - : "Don't care"; - var tag = epgStore.baseParams.tag ? epgStore.baseParams.tag - : "Don't care"; - var contenttype = epgStore.baseParams.contenttype ? epgStore.baseParams.contenttype - : "Don't care"; + Ext.MessageBox.confirm('Auto Recorder', + 'This will create an automatic rule that ' + + 'continuously scans the EPG for programmes ' + + 'to record that matches this query: ' + '

' + + '
Title:
' + title + '
' + + '
Channel:
' + channel + '
' + + '
Tag:
' + tag + '
' + + '
Genre:
' + contenttype + '
' + + '
' + 'Currently this will match (and record) ' + + epgStore.getTotalCount() + ' events. ' + 'Are you sure?', + function(button) { + if (button === 'no') + return; + createAutoRec2(epgStore.baseParams); + }); + } - Ext.MessageBox.confirm('Auto Recorder', - 'This will create an automatic rule that ' - + 'continuously scans the EPG for programmes ' - + 'to record that matches this query: ' + '

' - + '
Title:
' + title + '
' - + '
Channel:
' + channel + '
' - + '
Tag:
' + tag + '
' - + '
Genre:
' + contenttype + '
' - + '
' + 'Currently this will match (and record) ' - + epgStore.getTotalCount() + ' events. ' + 'Are you sure?', + function createAutoRec2(params) { + /* Really do it */ + params.op = 'createAutoRec'; + Ext.Ajax.request({ + url: 'dvr', + params: params + }); + } - function(button) { - if (button == 'no') return; - createAutoRec2(epgStore.baseParams); - }); - } - - function createAutoRec2(params) { - /* Really do it */ - params.op = 'createAutoRec'; - Ext.Ajax.request({ - url : 'dvr', - params : params - }); - } - - return panel; -} + return panel; +}; diff --git a/src/webui/static/app/epggrab.js b/src/webui/static/app/epggrab.js index ad8f8088..196e5b2d 100644 --- a/src/webui/static/app/epggrab.js +++ b/src/webui/static/app/epggrab.js @@ -1,427 +1,430 @@ tvheadend.epggrabChannels = new Ext.data.JsonStore({ - root : 'entries', - url : 'epggrab', - baseParams : { - op : 'channelList' - }, - fields : [ 'id', 'mod', 'name', 'icon', 'number', 'channel', 'mod-id', - 'mod-name' ] + root: 'entries', + url: 'epggrab', + baseParams: { + op: 'channelList' + }, + fields: ['id', 'mod', 'name', 'icon', 'number', 'channel', 'mod-id', + 'mod-name'] }); tvheadend.epggrab = function() { - /* **************************************************************** - * Data - * ***************************************************************/ + /* **************************************************************** + * Data + * ***************************************************************/ - /* - * Module lists (I'm sure there is a better way!) - */ - var EPGGRAB_MODULE_INTERNAL = "internal"; - var EPGGRAB_MODULE_EXTERNAL = "external"; - var EPGGRAB_MODULE_OTA = "ota"; + /* + * Module lists (I'm sure there is a better way!) + */ + var EPGGRAB_MODULE_INTERNAL = "internal"; + var EPGGRAB_MODULE_EXTERNAL = "external"; + var EPGGRAB_MODULE_OTA = "ota"; - var moduleStore = new Ext.data.JsonStore({ - root : 'entries', - url : 'epggrab', - baseParams : { - op : 'moduleList' - }, - autoLoad : true, - fields : [ 'id', 'name', 'path', 'type', 'enabled' ] - }); - var internalModuleStore = new Ext.data.Store({ - recordType : moduleStore.recordType - }); - var externalModuleStore = new Ext.data.Store({ - recordType : moduleStore.recordType - }); - var otaModuleStore = new Ext.data.Store({ - recordType : moduleStore.recordType - }); - moduleStore.on('load', function() { - moduleStore.filterBy(function(r) { - return r.get('type') == EPGGRAB_MODULE_INTERNAL; - }); - r = new internalModuleStore.recordType({ - id : '', - name : 'Disabled' - }); - internalModuleStore.add(r); - moduleStore.each(function(r) { - internalModuleStore.add(r.copy()); - }); - moduleStore.filterBy(function(r) { - return r.get('type') == EPGGRAB_MODULE_EXTERNAL; - }); - moduleStore.each(function(r) { - externalModuleStore.add(r.copy()); - }); - moduleStore.filterBy(function(r) { - return r.get('type') == EPGGRAB_MODULE_OTA; - }); - moduleStore.each(function(r) { - otaModuleStore.add(r.copy()); - }); - moduleStore.filterBy(function(r) { - return r.get('type') != EPGGRAB_MODULE_INTERNAL; - }); - }); - - /* Enable module in one of the stores (will auto update primary) */ - function moduleSelect(r, e) { - r.set('enabled', e); - t = moduleStore.getById(r.id); - if (t) t.set('enabled', e); - } - - /* - * Basic Config - */ - - var confreader = new Ext.data.JsonReader({ - root : 'epggrabSettings' - }, [ 'module', 'interval', 'channel_rename', 'channel_renumber', - 'channel_reicon', 'epgdb_periodicsave' ]); - - /* **************************************************************** - * Basic Fields - * ***************************************************************/ - - /* - * Module selector - */ - var internalModule = new Ext.form.ComboBox({ - fieldLabel : 'Module', - hiddenName : 'module', - width : 300, - valueField : 'id', - displayField : 'name', - forceSelection : true, - editable : false, - mode : 'local', - triggerAction : 'all', - store : internalModuleStore - }); - - /* - * Interval selector - */ - var intervalUnits = [ [ 86400, 'Days' ], [ 3600, 'Hours' ], - [ 60, 'Minutes' ], [ 1, 'Seconds' ] ]; - var intervalValue = new Ext.form.NumberField({ - width : 300, - allowNegative : false, - allowDecimals : false, - minValue : 1, - maxValue : 7, - value : 1, - fieldLabel : 'Grab interval', - name : 'intervalValue', - listeners : { - 'valid' : function(e) { - v = e.getValue() * intervalUnit.getValue(); - interval.setValue(v); - } - } - }) - var intervalUnit = new Ext.form.ComboBox({ - name : 'intervalUnit', - width : 300, - valueField : 'key', - displayField : 'value', - value : 86400, - forceSelection : true, - editable : false, - triggerAction : 'all', - mode : 'local', - store : new Ext.data.SimpleStore({ - fields : [ 'key', 'value' ], - data : intervalUnits - }), - listeners : { - 'change' : function(e, n, o) { - intervalValue.maxValue = (7 * 86400) / n; - intervalValue.validate(); - } - } - }); - var interval = new Ext.form.Hidden({ - name : 'interval', - value : 86400, - listeners : { - 'enable' : function(e) { - v = e.getValue(); - for (i = 0; i < intervalUnits.length; i++) { - u = intervalUnits[i][0]; - if ((v % u) == 0) { - intervalUnit.setValue(u); - intervalValue.maxValue = (7 * 86400) / u; - intervalValue.setValue(v / u); - intervalValue.validate(); - break; - } - } - } - } - }); - - /* - * Channel handling - */ - var channelRename = new Ext.form.Checkbox({ - name : 'channel_rename', - fieldLabel : 'Update channel name' - }); - - var channelRenumber = new Ext.form.Checkbox({ - name : 'channel_renumber', - fieldLabel : 'Update channel number' - }); - - var channelReicon = new Ext.form.Checkbox({ - name : 'channel_reicon', - fieldLabel : 'Update channel icon' - }); - - var epgPeriodicSave = new Ext.form.NumberField({ - width : 30, - allowNegative : false, - allowDecimals : false, - minValue : 0, - maxValue : 24, - value : 0, - fieldLabel : 'Periodic save EPG to disk', - name : 'epgdb_periodicsave', + var moduleStore = new Ext.data.JsonStore({ + root: 'entries', + url: 'epggrab', + baseParams: { + op: 'moduleList' + }, + autoLoad: true, + fields: ['id', 'name', 'path', 'type', 'enabled'] + }); + var internalModuleStore = new Ext.data.Store({ + recordType: moduleStore.recordType + }); + var externalModuleStore = new Ext.data.Store({ + recordType: moduleStore.recordType + }); + var otaModuleStore = new Ext.data.Store({ + recordType: moduleStore.recordType + }); + moduleStore.on('load', function() { + moduleStore.filterBy(function(r) { + return r.get('type') === EPGGRAB_MODULE_INTERNAL; }); + r = new internalModuleStore.recordType({ + id: '', + name: 'Disabled' + }); + internalModuleStore.add(r); + moduleStore.each(function(r) { + internalModuleStore.add(r.copy()); + }); + moduleStore.filterBy(function(r) { + return r.get('type') === EPGGRAB_MODULE_EXTERNAL; + }); + moduleStore.each(function(r) { + externalModuleStore.add(r.copy()); + }); + moduleStore.filterBy(function(r) { + return r.get('type') === EPGGRAB_MODULE_OTA; + }); + moduleStore.each(function(r) { + otaModuleStore.add(r.copy()); + }); + moduleStore.filterBy(function(r) { + return r.get('type') !== EPGGRAB_MODULE_INTERNAL; + }); + }); - /* - * Simple fields - */ - var simplePanel = new Ext.form.FieldSet({ - title : 'General Config', - width : 700, - autoHeight : true, - collapsible : true, - items : [ channelRename, channelRenumber, channelReicon, epgPeriodicSave ] - }); + /* Enable module in one of the stores (will auto update primary) */ + function moduleSelect(r, e) { + r.set('enabled', e); + t = moduleStore.getById(r.id); + if (t) + t.set('enabled', e); + } - /* - * Internal grabber - */ - var internalPanel = new Ext.form.FieldSet({ - title : 'Internal Grabber', - width : 700, - autoHeight : true, - collapsible : true, - items : [ interval, internalModule, intervalValue, intervalUnit ] - }); + /* + * Basic Config + */ - /* **************************************************************** - * Advanced Fields - * ***************************************************************/ + var confreader = new Ext.data.JsonReader({ + root: 'epggrabSettings' + }, ['module', 'interval', 'channel_rename', 'channel_renumber', + 'channel_reicon', 'epgdb_periodicsave']); - /* - * External modules - */ - var externalSelectionModel = new Ext.grid.CheckboxSelectionModel({ - singleSelect : false, - listeners : { - 'rowselect' : function(s, ri, r) { - moduleSelect(r, 1); - }, - 'rowdeselect' : function(s, ri, r) { - moduleSelect(r, 0); - } - } - }); + /* **************************************************************** + * Basic Fields + * ***************************************************************/ - var externalColumnModel = new Ext.grid.ColumnModel([ externalSelectionModel, - { - header : 'Module', - dataIndex : 'name', - width : 200, - sortable : false - }, { - header : 'Path', - dataIndex : 'path', - width : 300, - sortable : false - } ]); + /* + * Module selector + */ + var internalModule = new Ext.form.ComboBox({ + fieldLabel: 'Module', + hiddenName: 'module', + width: 300, + valueField: 'id', + displayField: 'name', + forceSelection: true, + editable: false, + mode: 'local', + triggerAction: 'all', + store: internalModuleStore + }); - var externalGrid = new Ext.grid.EditorGridPanel({ - store : externalModuleStore, - cm : externalColumnModel, - sm : externalSelectionModel, - width : 600, - height : 150, - frame : false, - viewConfig : { - forceFit : true - }, - iconCls : 'icon-grid' - }); + /* + * Interval selector + */ + var intervalUnits = [[86400, 'Days'], [3600, 'Hours'], + [60, 'Minutes'], [1, 'Seconds']]; + var intervalValue = new Ext.form.NumberField({ + width: 300, + allowNegative: false, + allowDecimals: false, + minValue: 1, + maxValue: 7, + value: 1, + fieldLabel: 'Grab interval', + name: 'intervalValue', + listeners: { + 'valid': function(e) { + v = e.getValue() * intervalUnit.getValue(); + interval.setValue(v); + } + } + }); + var intervalUnit = new Ext.form.ComboBox({ + name: 'intervalUnit', + width: 300, + valueField: 'key', + displayField: 'value', + value: 86400, + forceSelection: true, + editable: false, + triggerAction: 'all', + mode: 'local', + store: new Ext.data.SimpleStore({ + fields: ['key', 'value'], + data: intervalUnits + }), + listeners: { + 'change': function(e, n, o) { + intervalValue.maxValue = (7 * 86400) / n; + intervalValue.validate(); + } + } + }); + var interval = new Ext.form.Hidden({ + name: 'interval', + value: 86400, + listeners: { + 'enable': function(e) { + v = e.getValue(); + for (i = 0; i < intervalUnits.length; i++) { + u = intervalUnits[i][0]; + if ((v % u) === 0) { + intervalUnit.setValue(u); + intervalValue.maxValue = (7 * 86400) / u; + intervalValue.setValue(v / u); + intervalValue.validate(); + break; + } + } + } + } + }); - var externalPanel = new Ext.form.FieldSet({ - title : 'External Interfaces', - width : 700, - autoHeight : true, - collapsible : true, - collapsed : true, - items : [ externalGrid ] - }); + /* + * Channel handling + */ + var channelRename = new Ext.form.Checkbox({ + name: 'channel_rename', + fieldLabel: 'Update channel name' + }); - /* - * OTA modules - */ + var channelRenumber = new Ext.form.Checkbox({ + name: 'channel_renumber', + fieldLabel: 'Update channel number' + }); - var otaSelectionModel = new Ext.grid.CheckboxSelectionModel({ - singleSelect : false, - listeners : { - 'rowselect' : function(s, ri, r) { - moduleSelect(r, 1); - }, - 'rowdeselect' : function(s, ri, r) { - moduleSelect(r, 0); - } - } - }); + var channelReicon = new Ext.form.Checkbox({ + name: 'channel_reicon', + fieldLabel: 'Update channel icon' + }); - var otaColumnModel = new Ext.grid.ColumnModel([ otaSelectionModel, { - header : 'Module', - dataIndex : 'name', - width : 200, - sortable : false - } ]); + var epgPeriodicSave = new Ext.form.NumberField({ + width: 30, + allowNegative: false, + allowDecimals: false, + minValue: 0, + maxValue: 24, + value: 0, + fieldLabel: 'Periodic save EPG to disk', + name: 'epgdb_periodicsave' + }); - var otaGrid = new Ext.grid.EditorGridPanel({ - store : otaModuleStore, - cm : otaColumnModel, - sm : otaSelectionModel, - width : 600, - height : 150, - frame : false, - viewConfig : { - forceFit : true - }, - iconCls : 'icon-grid' - }); + /* + * Simple fields + */ + var simplePanel = new Ext.form.FieldSet({ + title: 'General Config', + width: 700, + autoHeight: true, + collapsible: true, + items: [channelRename, channelRenumber, channelReicon, epgPeriodicSave] + }); - var otaPanel = new Ext.form.FieldSet({ - title : 'Over-the-air Grabbers', - width : 700, - autoHeight : true, - collapsible : true, - collapsed : true, - items : [ otaGrid ] - }); + /* + * Internal grabber + */ + var internalPanel = new Ext.form.FieldSet({ + title: 'Internal Grabber', + width: 700, + autoHeight: true, + collapsible: true, + items: [interval, internalModule, intervalValue, intervalUnit] + }); - /* **************************************************************** - * Form - * ***************************************************************/ + /* **************************************************************** + * Advanced Fields + * ***************************************************************/ - var saveButton = new Ext.Button({ - text : "Save configuration", - tooltip : 'Save changes made to configuration below', - iconCls : 'save', - handler : saveChanges - }); + /* + * External modules + */ + var externalSelectionModel = new Ext.grid.CheckboxSelectionModel({ + singleSelect: false, + listeners: { + 'rowselect': function(s, ri, r) { + moduleSelect(r, 1); + }, + 'rowdeselect': function(s, ri, r) { + moduleSelect(r, 0); + } + } + }); - var helpButton = new Ext.Button({ - text : 'Help', - handler : function() { - new tvheadend.help('EPG Grab Configuration', 'config_epggrab.html'); - } - }); + var externalColumnModel = new Ext.grid.ColumnModel([externalSelectionModel, + { + header: 'Module', + dataIndex: 'name', + width: 200, + sortable: false + }, { + header: 'Path', + dataIndex: 'path', + width: 300, + sortable: false + }]); - var confpanel = new Ext.FormPanel({ - title : 'EPG Grabber', - iconCls : 'xml', - border : false, - bodyStyle : 'padding:15px', - labelAlign : 'left', - labelWidth : 150, - waitMsgTarget : true, - reader : confreader, - layout : 'form', - defaultType : 'textfield', - autoHeight : true, - items : [ simplePanel, internalPanel, otaPanel, externalPanel ], - tbar : [ saveButton, '->', helpButton ] - }); + var externalGrid = new Ext.grid.EditorGridPanel({ + store: externalModuleStore, + cm: externalColumnModel, + sm: externalSelectionModel, + width: 600, + height: 150, + frame: false, + viewConfig: { + forceFit: true + }, + iconCls: 'icon-grid' + }); - /* **************************************************************** - * Load/Save - * ***************************************************************/ + var externalPanel = new Ext.form.FieldSet({ + title: 'External Interfaces', + width: 700, + autoHeight: true, + collapsible: true, + collapsed: true, + items: [externalGrid] + }); - /* HACK: get display working */ - externalGrid.on('render', function() { - delay = new Ext.util.DelayedTask(function() { - rows = []; - externalModuleStore.each(function(r) { - if (r.get('enabled')) rows.push(r); - }); - externalSelectionModel.selectRecords(rows); - }); - delay.delay(100); - }); - otaGrid.on('render', function() { - delay = new Ext.util.DelayedTask(function() { - rows = []; - otaModuleStore.each(function(r) { - if (r.get('enabled')) rows.push(r); - }); - otaSelectionModel.selectRecords(rows); - }); - delay.delay(100); - }); + /* + * OTA modules + */ - confpanel.on('render', function() { + var otaSelectionModel = new Ext.grid.CheckboxSelectionModel({ + singleSelect: false, + listeners: { + 'rowselect': function(s, ri, r) { + moduleSelect(r, 1); + }, + 'rowdeselect': function(s, ri, r) { + moduleSelect(r, 0); + } + } + }); - /* Hack to get display working */ - delay = new Ext.util.DelayedTask(function() { - simplePanel.doLayout(false); - internalPanel.doLayout(false); - externalPanel.doLayout(false); - otaPanel.doLayout(false); - }); - delay.delay(100); + var otaColumnModel = new Ext.grid.ColumnModel([otaSelectionModel, { + header: 'Module', + dataIndex: 'name', + width: 200, + sortable: false + }]); - confpanel.getForm().load({ - url : 'epggrab', - params : { - op : 'loadSettings' - }, - success : function(form, action) { - confpanel.enable(); - } - }); - }); + var otaGrid = new Ext.grid.EditorGridPanel({ + store: otaModuleStore, + cm: otaColumnModel, + sm: otaSelectionModel, + width: 600, + height: 150, + frame: false, + viewConfig: { + forceFit: true + }, + iconCls: 'icon-grid' + }); - function saveChanges() { - mods = []; - moduleStore.each(function(r) { - mods.push({ - id : r.get('id'), - enabled : r.get('enabled') ? 1 : 0 - }); - }); - mods = Ext.util.JSON.encode(mods); - confpanel.getForm().submit({ - url : 'epggrab', - params : { - op : 'saveSettings', - external : mods - }, - waitMsg : 'Saving Data...', - success : function(form, action) { - externalModuleStore.commitChanges(); - }, - failure : function(form, action) { - Ext.Msg.alert('Save failed', action.result.errormsg); - } - }); - } + var otaPanel = new Ext.form.FieldSet({ + title: 'Over-the-air Grabbers', + width: 700, + autoHeight: true, + collapsible: true, + collapsed: true, + items: [otaGrid] + }); - return confpanel; -} + /* **************************************************************** + * Form + * ***************************************************************/ + + var saveButton = new Ext.Button({ + text: "Save configuration", + tooltip: 'Save changes made to configuration below', + iconCls: 'save', + handler: saveChanges + }); + + var helpButton = new Ext.Button({ + text: 'Help', + handler: function() { + new tvheadend.help('EPG Grab Configuration', 'config_epggrab.html'); + } + }); + + var confpanel = new Ext.FormPanel({ + title: 'EPG Grabber', + iconCls: 'xml', + border: false, + bodyStyle: 'padding:15px', + labelAlign: 'left', + labelWidth: 150, + waitMsgTarget: true, + reader: confreader, + layout: 'form', + defaultType: 'textfield', + autoHeight: true, + items: [simplePanel, internalPanel, otaPanel, externalPanel], + tbar: [saveButton, '->', helpButton] + }); + + /* **************************************************************** + * Load/Save + * ***************************************************************/ + + /* HACK: get display working */ + externalGrid.on('render', function() { + delay = new Ext.util.DelayedTask(function() { + rows = []; + externalModuleStore.each(function(r) { + if (r.get('enabled')) + rows.push(r); + }); + externalSelectionModel.selectRecords(rows); + }); + delay.delay(100); + }); + otaGrid.on('render', function() { + delay = new Ext.util.DelayedTask(function() { + rows = []; + otaModuleStore.each(function(r) { + if (r.get('enabled')) + rows.push(r); + }); + otaSelectionModel.selectRecords(rows); + }); + delay.delay(100); + }); + + confpanel.on('render', function() { + + /* Hack to get display working */ + delay = new Ext.util.DelayedTask(function() { + simplePanel.doLayout(false); + internalPanel.doLayout(false); + externalPanel.doLayout(false); + otaPanel.doLayout(false); + }); + delay.delay(100); + + confpanel.getForm().load({ + url: 'epggrab', + params: { + op: 'loadSettings' + }, + success: function(form, action) { + confpanel.enable(); + } + }); + }); + + function saveChanges() { + mods = []; + moduleStore.each(function(r) { + mods.push({ + id: r.get('id'), + enabled: r.get('enabled') ? 1 : 0 + }); + }); + mods = Ext.util.JSON.encode(mods); + confpanel.getForm().submit({ + url: 'epggrab', + params: { + op: 'saveSettings', + external: mods + }, + waitMsg: 'Saving Data...', + success: function(form, action) { + externalModuleStore.commitChanges(); + }, + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); + } + + return confpanel; +}; diff --git a/src/webui/static/app/esfilter.js b/src/webui/static/app/esfilter.js index 781b46ad..a7ed3873 100644 --- a/src/webui/static/app/esfilter.js +++ b/src/webui/static/app/esfilter.js @@ -4,105 +4,105 @@ tvheadend.esfilter_tab = function(panel) { - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/video', - comet : 'esfilter_video', - titleS : 'Video Stream Filter', - titleP : 'Video Stream Filters', - tabIndex : 0, - add : { - url : 'api/esfilter/video', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/video', + comet: 'esfilter_video', + titleS: 'Video Stream Filter', + titleP: 'Video Stream Filters', + tabIndex: 0, + add: { + url: 'api/esfilter/video', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/audio', - comet : 'esfilter_audio', - titleS : 'Audio Stream Filter', - titleP : 'Audio Stream Filters', - tabIndex : 1, - add : { - url : 'api/esfilter/audio', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/audio', + comet: 'esfilter_audio', + titleS: 'Audio Stream Filter', + titleP: 'Audio Stream Filters', + tabIndex: 1, + add: { + url: 'api/esfilter/audio', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/teletext', - comet : 'esfilter_teletext', - titleS : 'Teletext Stream Filter', - titleP : 'Teletext Stream Filters', - tabIndex : 2, - add : { - url : 'api/esfilter/teletext', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/teletext', + comet: 'esfilter_teletext', + titleS: 'Teletext Stream Filter', + titleP: 'Teletext Stream Filters', + tabIndex: 2, + add: { + url: 'api/esfilter/teletext', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/subtit', - comet : 'esfilter_subtit', - titleS : 'Subtitle Stream Filter', - titleP : 'Subtitle Stream Filters', - tabIndex : 3, - add : { - url : 'api/esfilter/subtit', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/subtit', + comet: 'esfilter_subtit', + titleS: 'Subtitle Stream Filter', + titleP: 'Subtitle Stream Filters', + tabIndex: 3, + add: { + url: 'api/esfilter/subtit', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/ca', - comet : 'esfilter_ca', - titleS : 'CA Stream Filter', - titleP : 'CA Stream Filters', - tabIndex : 4, - add : { - url : 'api/esfilter/ca', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/ca', + comet: 'esfilter_ca', + titleS: 'CA Stream Filter', + titleP: 'CA Stream Filters', + tabIndex: 4, + add: { + url: 'api/esfilter/ca', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); - tvheadend.idnode_grid(panel, { - url : 'api/esfilter/other', - comet : 'esfilter_other', - titleS : 'Other Stream Filter', - titleP : 'Other Stream Filters', - tabIndex : 5, - add : { - url : 'api/esfilter/other', - create : {} - }, - del : true, - move : true, - help : function() { - new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); - } - }); -} + tvheadend.idnode_grid(panel, { + url: 'api/esfilter/other', + comet: 'esfilter_other', + titleS: 'Other Stream Filter', + titleP: 'Other Stream Filters', + tabIndex: 5, + add: { + url: 'api/esfilter/other', + create: {} + }, + del: true, + move: true, + help: function() { + new tvheadend.help('Elementary Stream Filter', 'config_esfilter.html'); + } + }); +}; diff --git a/src/webui/static/app/ext.css b/src/webui/static/app/ext.css index 810ed5df..6eb6767f 100644 --- a/src/webui/static/app/ext.css +++ b/src/webui/static/app/ext.css @@ -6,7 +6,7 @@ * http://extjs.com/license */ #header { - font-family: tahoma,arial; + font-family: tahoma,arial; background-color: #507AAA; color: #F8F8F8; height: 5.3em; @@ -15,8 +15,8 @@ background: url("../img/bg-header.png") repeat-x scroll 0 0 transparent; height: 45px; } - - #header > h1 { + +#header > h1 { background: url("../img/logo.png") no-repeat scroll 10px 20% transparent; color: #E0E0E0; font-size: 22px; @@ -25,341 +25,341 @@ } .x-tree-col { - float: left; - overflow: hidden; - padding: 0 1px; - zoom: 1; + float: left; + overflow: hidden; + padding: 0 1px; + zoom: 1; } .x-tree-col-text,.x-tree-hd-text { - overflow: hidden; - -o-text-overflow: ellipsis; - text-overflow: ellipsis; - padding: 3px 3px 3px 5px; - white-space: nowrap; - font: normal 11px arial, tahoma, helvetica, sans-serif; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + padding: 3px 3px 3px 5px; + white-space: nowrap; + font: normal 11px arial, tahoma, helvetica, sans-serif; } .x-tree-headers { - background: #f9f9f9 - url(../extjs/resources/images/default/grid/grid3-hrow.gif) repeat-x 0 - bottom; - cursor: default; - zoom: 1; + background: #f9f9f9 + url(../extjs/resources/images/default/grid/grid3-hrow.gif) repeat-x 0 + bottom; + cursor: default; + zoom: 1; } .x-tree-hd { - float: left; - overflow: hidden; - border-left: 1px solid #eee; - border-right: 1px solid #d0d0d0; + float: left; + overflow: hidden; + border-left: 1px solid #eee; + border-right: 1px solid #d0d0d0; } .ux-mselect { - overflow: auto; - background: white; - position: relative; /* for calculating scroll offsets */ - zoom: 1; - overflow: auto; + overflow: auto; + background: white; + position: relative; /* for calculating scroll offsets */ + zoom: 1; + overflow: auto; } .ux-mselect-item { - font: normal 12px tahoma, arial, helvetica, sans-serif; - padding: 2px; - border: 1px solid #fff; - white-space: nowrap; - cursor: pointer; + font: normal 12px tahoma, arial, helvetica, sans-serif; + padding: 2px; + border: 1px solid #fff; + white-space: nowrap; + cursor: pointer; } .ux-mselect-selected { - border: 1px dotted #a3bae9 !important; - background: #DFE8F6; - cursor: pointer; + border: 1px dotted #a3bae9 !important; + background: #DFE8F6; + cursor: pointer; } .x-view-drag-insert-above { - border-top: 1px dotted #3366cc; + border-top: 1px dotted #3366cc; } .x-view-drag-insert-below { - border-bottom: 1px dotted #3366cc; + border-bottom: 1px dotted #3366cc; } .x-grid3-progresscol .x-grid3-cell-inner { - padding: 0px 0px 0px 5px; + padding: 0px 0px 0px 5px; } .x-grid3-progresscol .x-progress-bar { - height: 16px; + height: 16px; } .x-grid3-progresscol .x-progress-inner { - height: 16px; + height: 16px; } .x-grid3-progresscol .x-progress-text-front-ie6 { - padding: 2.5px 5px; + padding: 2.5px 5px; } .x-grid3-progresscol .x-progress-text-front { - padding: 2px 5px; + padding: 2px 5px; } .x-progress-bar-red,.x-progress-bar-orange,.x-progress-bar-green { - border-bottom: 1px solid #7fa9e4; - float: left; - height: 16px; + border-bottom: 1px solid #7fa9e4; + float: left; + height: 16px; } .x-progress-bar-red { - background: #ff0000 url(../icons/progress-bg-red.gif) repeat-x scroll - left center; - border-top: 1px solid #ecb7ad; + background: #ff0000 url(../icons/progress-bg-red.gif) repeat-x scroll + left center; + border-top: 1px solid #ecb7ad; } .x-progress-bar-orange { - background: #9cbfee url(../icons/progress-bg-orange.gif) repeat-x scroll - left center; - border-right: 1px solid #deab7e; - border-top: 1px solid #d7b290; + background: #9cbfee url(../icons/progress-bg-orange.gif) repeat-x scroll + left center; + border-right: 1px solid #deab7e; + border-top: 1px solid #d7b290; } .x-progress-bar-green { - background: #00ff00 url(../icons/progress-bg-green.gif) repeat-x scroll - left center; - border-right: 1px solid #5bd976; - border-top: 1px solid #79e18f; + background: #00ff00 url(../icons/progress-bg-green.gif) repeat-x scroll + left center; + border-right: 1px solid #5bd976; + border-top: 1px solid #79e18f; } .tvh-grid-unset { - color: #888; - font-style: italic; + color: #888; + font-style: italic; } .add { - background-image: url(../icons/add.png) !important; + background-image: url(../icons/add.png) !important; } .option { - background-image: url(../icons/plugin.png) !important; + background-image: url(../icons/plugin.png) !important; } .remove { - background-image: url(../icons/delete.png) !important; + background-image: url(../icons/delete.png) !important; } .moveup { - background-image: url(../icons/arrow_up.png) !important; + background-image: url(../icons/arrow_up.png) !important; } .movedown { - background-image: url(../icons/arrow_down.png) !important; + background-image: url(../icons/arrow_down.png) !important; } .save { - background-image: url(../icons/save.png) !important; + background-image: url(../icons/save.png) !important; } .rec { - background-image: url(../icons/rec.png) !important; + background-image: url(../icons/rec.png) !important; } .info { - background-image: url(../icons/information.png) !important; + background-image: url(../icons/information.png) !important; } .undo { - background-image: url(../icons/undo.png) !important; + background-image: url(../icons/undo.png) !important; } .edit { - background-image: url(../icons/edit.png) !important; + background-image: url(../icons/edit.png) !important; } .key { - background-image: url(../icons/key.png) !important; + background-image: url(../icons/key.png) !important; } .tags { - background-image: url(../icons/tag_blue.png) !important; + background-image: url(../icons/tag_blue.png) !important; } .xml { - background-image: url(../icons/tag.png) !important; + background-image: url(../icons/tag.png) !important; } .drive { - background-image: url(../icons/drive.png) !important; + background-image: url(../icons/drive.png) !important; } .group { - background-image: url(../icons/group.png) !important; + background-image: url(../icons/group.png) !important; } .hardware { - background-image: url(../icons/pci.png) !important; + background-image: url(../icons/pci.png) !important; } .television { - background-image: url(../icons/television.png) !important; + background-image: url(../icons/television.png) !important; } .eye { - background-image: url(../icons/eye.png) !important; + background-image: url(../icons/eye.png) !important; } .control_play { - background-image: url(../icons/control_play.png) !important; + background-image: url(../icons/control_play.png) !important; } .control_pause { - background-image: url(../icons/control_pause.png) !important; + background-image: url(../icons/control_pause.png) !important; } .control_stop { - background-image: url(../icons/control_stop.png) !important; + background-image: url(../icons/control_stop.png) !important; } .control_volume { - background-image: url(../icons/sound.png) !important; + background-image: url(../icons/sound.png) !important; } .control_fullscreen { - background-image: url(../icons/arrow_out.png) !important; + background-image: url(../icons/arrow_out.png) !important; } .newspaper { - background-image: url(../icons/newspaper.png) !important; + background-image: url(../icons/newspaper.png) !important; } .clock { - background-image: url(../icons/clock.png) !important; + background-image: url(../icons/clock.png) !important; } .exclamation { - background-image: url(../icons/exclamation.png) !important; + background-image: url(../icons/exclamation.png) !important; } .wrench { - background-image: url(../icons/wrench.png) !important; + background-image: url(../icons/wrench.png) !important; } .wand { - background-image: url(../icons/wand.png) !important; + background-image: url(../icons/wand.png) !important; } .merge { - background-image: url(../icons/arrow_join.png) !important; + background-image: url(../icons/arrow_join.png) !important; } .iptv { - background-image: url(../icons/world.png) !important; + background-image: url(../icons/world.png) !important; } .clone { - background-image: url(../icons/layers.png) !important; + background-image: url(../icons/layers.png) !important; } .scheduled { - background-image: url(../icons/clock.png) !important; + background-image: url(../icons/clock.png) !important; } .recordingError { - background-image: url(../icons/exclamation.png) !important; + background-image: url(../icons/exclamation.png) !important; } .completed { - background-image: url(../icons/tick.png) !important; + background-image: url(../icons/tick.png) !important; } .completedError { - background-image: url(../icons/exclamation.png) !important; + background-image: url(../icons/exclamation.png) !important; } .recording { - background-image: url(../icons/rec.png) !important; + background-image: url(../icons/rec.png) !important; } .bullet_add { - background-image: url(../icons/bullet_add.png) !important; + background-image: url(../icons/bullet_add.png) !important; } .arrow_up { - background-image: url(../icons/arrow_up.png) !important; + background-image: url(../icons/arrow_up.png) !important; } .arrow_down { - background-image: url(../icons/arrow_down.png) !important; + background-image: url(../icons/arrow_down.png) !important; } .arrow_switch { - background-image: url(../icons/arrow_switch.png) !important; + background-image: url(../icons/arrow_switch.png) !important; } .stream_config { - background-image: url(../icons/film_edit.png) !important; + background-image: url(../icons/film_edit.png) !important; } .x-smallhdr { - float: left; - width: 100px; + float: left; + width: 100px; } .x-epg-title { - margin: 5px; - font: normal 15px arial, tahoma, helvetica, sans-serif; - font-weight: bold; + margin: 5px; + font: normal 15px arial, tahoma, helvetica, sans-serif; + font-weight: bold; } .x-epg-subtitle { - margin: 5px; - font: normal 12px arial, tahoma, helvetica, sans-serif; - font-weight: bold; + margin: 5px; + font: normal 12px arial, tahoma, helvetica, sans-serif; + font-weight: bold; } .x-epg-desc { - margin: 5px; + margin: 5px; } .x-epg-chicon { - float: right; - margin: 5px; - max-width: 132px; - max-height: 99px; + float: right; + margin: 5px; + max-width: 132px; + max-height: 99px; } .x-epg-meta { - margin: 5px; + margin: 5px; } .hts-t-info { - float: left; - width: 100px; + float: left; + width: 100px; } .hts-doc-text { - font: normal 11px verdana; - padding: 5px; + font: normal 11px verdana; + padding: 5px; } .hts-doc-text dt { - padding-top: 10px; - font-weight: bold; + padding-top: 10px; + font-weight: bold; } .hts-doc-text dl { - padding-left: 10px; - padding-bottom: 10px; + padding-left: 10px; + padding-bottom: 10px; } .hts-doc-text li { - padding-top: 5px; - padding-bottom: 5px; + padding-top: 5px; + padding-bottom: 5px; } .hts-doc-text img { - padding: 10px; + padding: 10px; } .tv-video-player { @@ -384,8 +384,8 @@ } .about-title { - font-size: 24px; - font-weight: bold; + font-size: 24px; + font-weight: bold; } /** vim: ts=4:sw=4:nu:fdc=4:nospell @@ -408,69 +408,69 @@ /* styles for rows */ .ux-row-action-cell .x-grid3-cell-inner { - padding: 1px 0 0 0; + padding: 1px 0 0 0; } .ux-row-action-item { - float: left; - min-width: 16px; - height: 16px; - background-repeat: no-repeat; - margin: 0 5px 0 0; - cursor: pointer; - overflow: hidden; + float: left; + min-width: 16px; + height: 16px; + background-repeat: no-repeat; + margin: 0 5px 0 0; + cursor: pointer; + overflow: hidden; } .ext-ie .ux-row-action-item { - width: 16px; + width: 16px; } .ext-ie .ux-row-action-text { - width: auto; + width: auto; } .ux-row-action-item span { - vertical-align: middle; - padding: 0 0 0 20px; - line-height: 18px; + vertical-align: middle; + padding: 0 0 0 20px; + line-height: 18px; } .ext-ie .ux-row-action-item span { - width: auto; + width: auto; } /* styles for groups */ .x-grid-group-hd div { - position: relative; - height: 16px; + position: relative; + height: 16px; } .ux-grow-action-item { - min-width: 16px; - height: 16px; - background-repeat: no-repeat; - background-position: 0 50% ! important; - margin: 0 0 0 4px; - padding: 0 ! important; - cursor: pointer; - float: left; + min-width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: 0 50% ! important; + margin: 0 0 0 4px; + padding: 0 ! important; + cursor: pointer; + float: left; } .ext-ie .ux-grow-action-item { - width: 16px; + width: 16px; } .ux-action-right { - float: right; - margin: 0 3px 0 2px; - padding: 0 ! important; + float: right; + margin: 0 3px 0 2px; + padding: 0 ! important; } .ux-grow-action-text { - padding: 0 ! important; - margin: 0 ! important; - background: transparent none ! important; - float: left; + padding: 0 ! important; + margin: 0 ! important; + background: transparent none ! important; + float: left; } /** vim: ts=4:sw=4:nu:fdc=4:nospell @@ -490,21 +490,21 @@ * License details: http://www.gnu.org/licenses/lgpl.html */ .ux-lovcombo-icon { - width: 16px; - height: 16px; - float: left; - background-position: -1px -1px ! important; - background-repeat: no-repeat ! important; + width: 16px; + height: 16px; + float: left; + background-position: -1px -1px ! important; + background-repeat: no-repeat ! important; } .ux-lovcombo-icon-checked { - background: transparent - url(../extjs/resources/images/default/menu/checked.gif); + background: transparent + url(../extjs/resources/images/default/menu/checked.gif); } .ux-lovcombo-icon-unchecked { - background: transparent - url(../extjs/resources/images/default/menu/unchecked.gif); + background: transparent + url(../extjs/resources/images/default/menu/unchecked.gif); } /* eof */ diff --git a/src/webui/static/app/extensions.js b/src/webui/static/app/extensions.js index 5a14d9f8..3ac7579f 100644 --- a/src/webui/static/app/extensions.js +++ b/src/webui/static/app/extensions.js @@ -9,20 +9,20 @@ -/* - * Ext JS Library 2.2 - * Copyright(c) 2006-2008, Ext JS, LLC. - * licensing@extjs.com - * - * http://extjs.com/license - */ - +/* + * Ext JS Library 2.2 + * Copyright(c) 2006-2008, Ext JS, LLC. + * licensing@extjs.com + * + * http://extjs.com/license + */ + /* * Note that this control should still be treated as an example and that the API will most likely * change once it is ported into the Ext core as a standard form control. This is still planned * for a future release, so this should not yet be treated as a final, stable API at this time. */ - + /** * @class Ext.ux.MultiSelect * @extends Ext.form.Field @@ -38,7 +38,7 @@ * Create a new MultiSelect * @param {Object} config Configuration options */ -Ext.ux.Multiselect = Ext.extend(Ext.form.Field, { +Ext.ux.Multiselect = Ext.extend(Ext.form.Field, { /** * @cfg {String} legend Wraps the object with a fieldset and specified legend. */ @@ -50,10 +50,10 @@ Ext.ux.Multiselect = Ext.extend(Ext.form.Field, { */ /** * @cfg {String/Array} dragGroup The ddgroup name(s) for the DDView's DragZone (defaults to undefined). - */ + */ /** * @cfg {String/Array} dropGroup The ddgroup name(s) for the DDView's DropZone (defaults to undefined). - */ + */ /** * @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a * toolbar config, or an array of buttons/button configs to be added to the toolbar. @@ -65,163 +65,157 @@ Ext.ux.Multiselect = Ext.extend(Ext.form.Field, { * @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled * (use for lists which are sorted, defaults to false). */ - appendOnly:false, + appendOnly: false, /** * @cfg {Array} dataFields Inline data definition when not using a pre-initialised store. Known to cause problems * in some browswers for very long lists. Use store for large datasets. */ - dataFields:[], + dataFields: [], /** * @cfg {Array} data Inline data when not using a pre-initialised store. Known to cause problems in some * browswers for very long lists. Use store for large datasets. */ - data:[], + data: [], /** * @cfg {Number} width Width in pixels of the control (defaults to 100). */ - width:100, + width: 100, /** * @cfg {Number} height Height in pixels of the control (defaults to 100). */ - height:100, + height: 100, /** * @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0). */ - displayField:0, + displayField: 0, /** * @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1). */ - valueField:1, + valueField: 1, /** * @cfg {Boolean} allowBlank True to require at least one item in the list to be selected, false to allow no * selection (defaults to true). */ - allowBlank:true, + allowBlank: true, /** * @cfg {Number} minLength Minimum number of selections allowed (defaults to 0). */ - minLength:0, + minLength: 0, /** * @cfg {Number} maxLength Maximum number of selections allowed (defaults to Number.MAX_VALUE). */ - maxLength:Number.MAX_VALUE, + maxLength: Number.MAX_VALUE, /** * @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as * {@link Ext.form.TextField#blankText}. */ - blankText:Ext.form.TextField.prototype.blankText, + blankText: Ext.form.TextField.prototype.blankText, /** * @cfg {String} minLengthText Validation message displayed when {@link #minLength} is not met (defaults to 'Minimum {0} * item(s) required'). The {0} token will be replaced by the value of {@link #minLength}. */ - minLengthText:'Minimum {0} item(s) required', + minLengthText: 'Minimum {0} item(s) required', /** * @cfg {String} maxLengthText Validation message displayed when {@link #maxLength} is not met (defaults to 'Maximum {0} * item(s) allowed'). The {0} token will be replaced by the value of {@link #maxLength}. */ - maxLengthText:'Maximum {0} item(s) allowed', + maxLengthText: 'Maximum {0} item(s) allowed', /** * @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values * (defaults to ','). */ - delimiter:',', - + delimiter: ',', // DDView settings - copy:false, - allowDup:false, - allowTrash:false, - focusClass:undefined, - sortDir:'ASC', - + copy: false, + allowDup: false, + allowTrash: false, + focusClass: undefined, + sortDir: 'ASC', // private - defaultAutoCreate : {tag: "div"}, - + defaultAutoCreate: {tag: "div"}, // private - initComponent: function(){ + initComponent: function() { Ext.ux.Multiselect.superclass.initComponent.call(this); this.addEvents({ - 'dblclick' : true, - 'click' : true, - 'change' : true, - 'drop' : true - }); + 'dblclick': true, + 'click': true, + 'change': true, + 'drop': true + }); }, - // private - onRender: function(ct, position){ + onRender: function(ct, position) { Ext.ux.Multiselect.superclass.onRender.call(this, ct, position); - + var cls = 'ux-mselect'; var fs = new Ext.form.FieldSet({ - renderTo:this.el, - title:this.legend, - height:this.height, - width:this.width, - style:"padding:0;", - tbar:this.tbar + renderTo: this.el, + title: this.legend, + height: this.height, + width: this.width, + style: "padding:0;", + tbar: this.tbar }); //if(!this.legend)fs.el.down('.'+fs.headerCls).remove(); fs.body.addClass(cls); var tpl = '
'; + tpl += '>{' + this.displayField + '}
'; - if(!this.store){ + if (!this.store) { this.store = new Ext.data.SimpleStore({ fields: this.dataFields, - data : this.data + data: this.data }); } this.view = new Ext.ux.DDView({ - multiSelect: true, - store: this.store, - selectedClass: cls+"-selected", - tpl:tpl, - allowDup:this.allowDup, - copy: this.copy, - allowTrash: this.allowTrash, - dragGroup: this.dragGroup, - dropGroup: this.dropGroup, - itemSelector:"."+cls+"-item", - isFormField:false, - applyTo:fs.body, - appendOnly:this.appendOnly, - sortField:this.sortField, - sortDir:this.sortDir + multiSelect: true, + store: this.store, + selectedClass: cls + "-selected", + tpl: tpl, + allowDup: this.allowDup, + copy: this.copy, + allowTrash: this.allowTrash, + dragGroup: this.dragGroup, + dropGroup: this.dropGroup, + itemSelector: "." + cls + "-item", + isFormField: false, + applyTo: fs.body, + appendOnly: this.appendOnly, + sortField: this.sortField, + sortDir: this.sortDir }); fs.add(this.view); - + this.view.on('click', this.onViewClick, this); this.view.on('beforeClick', this.onViewBeforeClick, this); this.view.on('dblclick', this.onViewDblClick, this); - this.view.on('drop', function(ddView, n, dd, e, data){ + this.view.on('drop', function(ddView, n, dd, e, data) { return this.fireEvent("drop", ddView, n, dd, e, data); }, this); - + this.hiddenName = this.name; - var hiddenTag={tag: "input", type: "hidden", value: "", name:this.name}; - if (this.isFormField) { + var hiddenTag = {tag: "input", type: "hidden", value: "", name: this.name}; + if (this.isFormField) { this.hiddenField = this.el.createChild(hiddenTag); } else { this.hiddenField = Ext.get(document.body).createChild(hiddenTag); } fs.doLayout(); }, - // private - initValue:Ext.emptyFn, - + initValue: Ext.emptyFn, // private onViewClick: function(vw, index, node, e) { var arrayIndex = this.preClickSelections.indexOf(index); - if (arrayIndex != -1) + if (arrayIndex !== -1) { this.preClickSelections.splice(arrayIndex, 1); this.view.clearSelections(true); @@ -230,35 +224,34 @@ Ext.ux.Multiselect = Ext.extend(Ext.form.Field, { this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value); this.hiddenField.dom.value = this.getValue(); this.fireEvent('click', this, e); - this.validate(); + this.validate(); }, - // private onViewBeforeClick: function(vw, index, node, e) { this.preClickSelections = this.view.getSelectedIndexes(); - if (this.disabled) {return false;} + if (this.disabled) { + return false; + } }, - // private - onViewDblClick : function(vw, index, node, e) { - return this.fireEvent('dblclick', vw, index, node, e); - }, - + onViewDblClick: function(vw, index, node, e) { + return this.fireEvent('dblclick', vw, index, node, e); }, /** * Returns an array of data values for the selected items in the list. The values will be separated * by {@link #delimiter}. * @return {Array} value An array of string data values */ - getValue: function(valueField){ + getValue: function(valueField) { var returnArray = []; var selectionsArray = this.view.getSelectedIndexes(); - if (selectionsArray.length == 0) {return '';} - for (var i=0; i
{2}
', + textClass, Ext.id(), v + this.textPst + ); + text = (v < 96) ? text.substring(0, text.length - 6) : text.substr(6); + + if (this.colored == true) { + if (v <= 100 && v > 66) + style = '-green'; + if (v < 67 && v > 33) + style = '-orange'; + if (v < 34) + style = '-red'; + } + + p.css += ' x-grid3-progresscol'; + return String.format( + '
{2}
' + + '
', style, v, text + ); } - }, - - onClick : function(e, target) { - var rowIndex = e.getTarget('.x-grid3-row').rowIndex; - var colIndex = this.view.findCellIndex(target.parentNode.parentNode); - - var t = e.getTarget('.x-progress-text'); - if (t) { - this.grid.startEditing(rowIndex, colIndex); - } - }, - - renderer : function(v, p, record) { - var style = ''; - var textClass = (v < 55) ? 'x-progress-text-back' : 'x-progress-text-front' + (Ext.isIE6 ? '-ie6' : ''); - - //ugly hack to deal with IE6 issue - var text = String.format('
{2}
', - textClass, Ext.id(), v + this.textPst - ); - text = (v<96) ? text.substring(0, text.length - 6) : text.substr(6); - - if (this.colored == true) { - if (v <= 100 && v > 66) - style = '-green'; - if (v < 67 && v > 33) - style = '-orange'; - if (v < 34) - style = '-red'; - } - - p.css += ' x-grid3-progresscol'; - return String.format( - '
{2}
' + - '
', style, v, text - ); - } }); //vim: ts=4:sw=4:nu:fdc=4:nospell @@ -481,14 +471,14 @@ Ext.extend(Ext.ux.grid.ProgressColumn, Ext.util.Observable, { Ext.ns('Ext.ux.grid'); // add RegExp.escape if it has not been already added -if('function' !== typeof RegExp.escape) { - RegExp.escape = function(s) { - if('string' !== typeof s) { - return s; - } - // Note: if pasting from forum, precede ]/\ with backslash manually - return s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1'); - }; // eo function escape +if ('function' !== typeof RegExp.escape) { + RegExp.escape = function(s) { + if ('string' !== typeof s) { + return s; + } + // Note: if pasting from forum, precede ]/\ with backslash manually + return s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1'); + }; // eo function escape } /** @@ -497,389 +487,388 @@ if('function' !== typeof RegExp.escape) { * @param {Object} config A config object */ Ext.ux.grid.RowActions = function(config) { - Ext.apply(this, config); + Ext.apply(this, config); - // {{{ - this.addEvents( - /** - * @event beforeaction - * Fires before action event. Return false to cancel the subsequent action event. - * @param {Ext.grid.GridPanel} grid - * @param {Ext.data.Record} record Record corresponding to row clicked - * @param {String} action Identifies the action icon clicked. Equals to icon css class name. - * @param {Integer} rowIndex Index of clicked grid row - * @param {Integer} colIndex Index of clicked grid column that contains all action icons - */ - 'beforeaction' - /** - * @event action - * Fires when icon is clicked - * @param {Ext.grid.GridPanel} grid - * @param {Ext.data.Record} record Record corresponding to row clicked - * @param {String} action Identifies the action icon clicked. Equals to icon css class name. - * @param {Integer} rowIndex Index of clicked grid row - * @param {Integer} colIndex Index of clicked grid column that contains all action icons - */ - ,'action' - /** - * @event beforegroupaction - * Fires before group action event. Return false to cancel the subsequent groupaction event. - * @param {Ext.grid.GridPanel} grid - * @param {Array} records Array of records in this group - * @param {String} action Identifies the action icon clicked. Equals to icon css class name. - * @param {String} groupId Identifies the group clicked - */ - ,'beforegroupaction' - /** - * @event groupaction - * Fires when icon in a group header is clicked - * @param {Ext.grid.GridPanel} grid - * @param {Array} records Array of records in this group - * @param {String} action Identifies the action icon clicked. Equals to icon css class name. - * @param {String} groupId Identifies the group clicked - */ - ,'groupaction' - ); - // }}} + // {{{ + this.addEvents( + /** + * @event beforeaction + * Fires before action event. Return false to cancel the subsequent action event. + * @param {Ext.grid.GridPanel} grid + * @param {Ext.data.Record} record Record corresponding to row clicked + * @param {String} action Identifies the action icon clicked. Equals to icon css class name. + * @param {Integer} rowIndex Index of clicked grid row + * @param {Integer} colIndex Index of clicked grid column that contains all action icons + */ + 'beforeaction' + /** + * @event action + * Fires when icon is clicked + * @param {Ext.grid.GridPanel} grid + * @param {Ext.data.Record} record Record corresponding to row clicked + * @param {String} action Identifies the action icon clicked. Equals to icon css class name. + * @param {Integer} rowIndex Index of clicked grid row + * @param {Integer} colIndex Index of clicked grid column that contains all action icons + */ + , 'action' + /** + * @event beforegroupaction + * Fires before group action event. Return false to cancel the subsequent groupaction event. + * @param {Ext.grid.GridPanel} grid + * @param {Array} records Array of records in this group + * @param {String} action Identifies the action icon clicked. Equals to icon css class name. + * @param {String} groupId Identifies the group clicked + */ + , 'beforegroupaction' + /** + * @event groupaction + * Fires when icon in a group header is clicked + * @param {Ext.grid.GridPanel} grid + * @param {Array} records Array of records in this group + * @param {String} action Identifies the action icon clicked. Equals to icon css class name. + * @param {String} groupId Identifies the group clicked + */ + , 'groupaction' + ); + // }}} - // call parent - Ext.ux.grid.RowActions.superclass.constructor.call(this); + // call parent + Ext.ux.grid.RowActions.superclass.constructor.call(this); }; Ext.extend(Ext.ux.grid.RowActions, Ext.util.Observable, { + // configuration options + // {{{ + /** + * @cfg {Array} actions Mandatory. Array of action configuration objects. The action + * configuration object recognizes the following options: + *
    + *
  • + * {Function} callback (optional). Function to call if the action icon is clicked. + * This function is called with same signature as action event and in its original scope. + * If you need to call it in different scope or with another signature use + * createCallback or createDelegate functions. Works for statically defined actions. Use + * callbacks configuration options for store bound actions. + *
  • + *
  • + * {Function} cb Shortcut for callback. + *
  • + *
  • + * {String} iconIndex Optional, however either iconIndex or iconCls must be + * configured. Field name of the field of the grid store record that contains + * css class of the icon to show. If configured, shown icons can vary depending + * of the value of this field. + *
  • + *
  • + * {String} iconCls CSS class of the icon to show. It is ignored if iconIndex is + * configured. Use this if you want static icons that are not base on the values in the record. + *
  • + *
  • + * {Boolean} hide Optional. True to hide this action while still have a space in + * the grid column allocated to it. IMO, it doesn't make too much sense, use hideIndex instead. + *
  • + *
  • + * {String} hideIndex Optional. Field name of the field of the grid store record that + * contains hide flag (falsie [null, '', 0, false, undefined] to show, anything else to hide). + *
  • + *
  • + * {String} qtipIndex Optional. Field name of the field of the grid store record that + * contains tooltip text. If configured, the tooltip texts are taken from the store. + *
  • + *
  • + * {String} tooltip Optional. Tooltip text to use as icon tooltip. It is ignored if + * qtipIndex is configured. Use this if you want static tooltips that are not taken from the store. + *
  • + *
  • + * {String} qtip Synonym for tooltip + *
  • + *
  • + * {String} textIndex Optional. Field name of the field of the grids store record + * that contains text to display on the right side of the icon. If configured, the text + * shown is taken from record. + *
  • + *
  • + * {String} text Optional. Text to display on the right side of the icon. Use this + * if you want static text that are not taken from record. Ignored if textIndex is set. + *
  • + *
  • + * {String} style Optional. Style to apply to action icon container. + *
  • + *
+ */ - // configuration options - // {{{ - /** - * @cfg {Array} actions Mandatory. Array of action configuration objects. The action - * configuration object recognizes the following options: - *
    - *
  • - * {Function} callback (optional). Function to call if the action icon is clicked. - * This function is called with same signature as action event and in its original scope. - * If you need to call it in different scope or with another signature use - * createCallback or createDelegate functions. Works for statically defined actions. Use - * callbacks configuration options for store bound actions. - *
  • - *
  • - * {Function} cb Shortcut for callback. - *
  • - *
  • - * {String} iconIndex Optional, however either iconIndex or iconCls must be - * configured. Field name of the field of the grid store record that contains - * css class of the icon to show. If configured, shown icons can vary depending - * of the value of this field. - *
  • - *
  • - * {String} iconCls CSS class of the icon to show. It is ignored if iconIndex is - * configured. Use this if you want static icons that are not base on the values in the record. - *
  • - *
  • - * {Boolean} hide Optional. True to hide this action while still have a space in - * the grid column allocated to it. IMO, it doesn't make too much sense, use hideIndex instead. - *
  • - *
  • - * {String} hideIndex Optional. Field name of the field of the grid store record that - * contains hide flag (falsie [null, '', 0, false, undefined] to show, anything else to hide). - *
  • - *
  • - * {String} qtipIndex Optional. Field name of the field of the grid store record that - * contains tooltip text. If configured, the tooltip texts are taken from the store. - *
  • - *
  • - * {String} tooltip Optional. Tooltip text to use as icon tooltip. It is ignored if - * qtipIndex is configured. Use this if you want static tooltips that are not taken from the store. - *
  • - *
  • - * {String} qtip Synonym for tooltip - *
  • - *
  • - * {String} textIndex Optional. Field name of the field of the grids store record - * that contains text to display on the right side of the icon. If configured, the text - * shown is taken from record. - *
  • - *
  • - * {String} text Optional. Text to display on the right side of the icon. Use this - * if you want static text that are not taken from record. Ignored if textIndex is set. - *
  • - *
  • - * {String} style Optional. Style to apply to action icon container. - *
  • - *
- */ + /** + * @cfg {String} actionEvent Event to trigger actions, e.g. click, dblclick, mouseover (defaults to 'click') + */ + actionEvent: 'click' + /** + * @cfg {Boolean} autoWidth true to calculate field width for iconic actions only (defaults to true). + * If true, the width is calculated as {@link #widthSlope} * number of actions + {@link #widthIntercept}. + */ + , autoWidth: true - /** - * @cfg {String} actionEvent Event to trigger actions, e.g. click, dblclick, mouseover (defaults to 'click') - */ - actionEvent:'click' - /** - * @cfg {Boolean} autoWidth true to calculate field width for iconic actions only (defaults to true). - * If true, the width is calculated as {@link #widthSlope} * number of actions + {@link #widthIntercept}. - */ - ,autoWidth:true + /** + * @cfg {String} dataIndex - Do not touch! + * @private + */ + , dataIndex: '' - /** - * @cfg {String} dataIndex - Do not touch! - * @private - */ - ,dataIndex:'' + /** + * @cfg {Boolean} editable - Do not touch! + * Must be false to prevent errors in editable grids + */ + , editable: false - /** - * @cfg {Boolean} editable - Do not touch! - * Must be false to prevent errors in editable grids - */ - ,editable:false + /** + * @cfg {Array} groupActions Array of action to use for group headers of grouping grids. + * These actions support static icons, texts and tooltips same way as {@link #actions}. There is one + * more action config option recognized: + *
    + *
  • + * {String} align Set it to 'left' to place action icon next to the group header text. + * (defaults to undefined = icons are placed at the right side of the group header. + *
  • + *
+ */ - /** - * @cfg {Array} groupActions Array of action to use for group headers of grouping grids. - * These actions support static icons, texts and tooltips same way as {@link #actions}. There is one - * more action config option recognized: - *
    - *
  • - * {String} align Set it to 'left' to place action icon next to the group header text. - * (defaults to undefined = icons are placed at the right side of the group header. - *
  • - *
- */ + /** + * @cfg {Object} callbacks iconCls keyed object that contains callback functions. For example: + *
+             * callbacks:{
+             *      'icon-open':function(...) {...}
+             *     ,'icon-save':function(...) {...}
+             * }
+             * 
+ */ - /** - * @cfg {Object} callbacks iconCls keyed object that contains callback functions. For example: - *
-	 * callbacks:{
-	 *      'icon-open':function(...) {...}
-	 *     ,'icon-save':function(...) {...}
-	 * }
-	 * 
- */ + /** + * @cfg {String} header Actions column header + */ + , header: '' - /** - * @cfg {String} header Actions column header - */ - ,header:'' + /** + * @cfg {Boolean} isColumn + * Tell ColumnModel that we are column. Do not touch! + * @private + */ + , isColumn: true - /** - * @cfg {Boolean} isColumn - * Tell ColumnModel that we are column. Do not touch! - * @private - */ - ,isColumn:true + /** + * @cfg {Boolean} keepSelection + * Set it to true if you do not want action clicks to affect selected row(s) (defaults to false). + * By default, when user clicks an action icon the clicked row is selected and the action events are fired. + * If this option is true then the current selection is not affected, only the action events are fired. + */ + , keepSelection: false - /** - * @cfg {Boolean} keepSelection - * Set it to true if you do not want action clicks to affect selected row(s) (defaults to false). - * By default, when user clicks an action icon the clicked row is selected and the action events are fired. - * If this option is true then the current selection is not affected, only the action events are fired. - */ - ,keepSelection:false + /** + * @cfg {Boolean} menuDisabled No sense to display header menu for this column + * @private + */ + , menuDisabled: true - /** - * @cfg {Boolean} menuDisabled No sense to display header menu for this column - * @private - */ - ,menuDisabled:true + /** + * @cfg {Boolean} sortable Usually it has no sense to sort by this column + * @private + */ + , sortable: false - /** - * @cfg {Boolean} sortable Usually it has no sense to sort by this column - * @private - */ - ,sortable:false + /** + * @cfg {String} tplGroup Template for group actions + * @private + */ + , tplGroup: + '' + + '
ux-action-right ' + + '{cls}" style="{style}" qtip="{qtip}">{text}
' + + '
' - /** - * @cfg {String} tplGroup Template for group actions - * @private - */ - ,tplGroup: - '' - +'
ux-action-right ' - +'{cls}" style="{style}" qtip="{qtip}">{text}
' - +'
' + /** + * @cfg {String} tplRow Template for row actions + * @private + */ + , tplRow: + '
' + + '' + + '
' + + 'ux-row-action-text" style="{hide}{style}" qtip="{qtip}">' + + '{text}
' + + '
' + + '
' - /** - * @cfg {String} tplRow Template for row actions - * @private - */ - ,tplRow: - '
' - +'' - +'
' - +'ux-row-action-text" style="{hide}{style}" qtip="{qtip}">' - +'{text}
' - +'
' - +'
' + /** + * @cfg {String} hideMode How to hide hidden icons. Valid values are: 'visibility' and 'display' + * (defaluts to 'visibility'). If the mode is visibility the hidden icon is not visible but there + * is still blank space occupied by the icon. In display mode, the visible icons are shifted taking + * the space of the hidden icon. + */ + , hideMode: 'visibility' - /** - * @cfg {String} hideMode How to hide hidden icons. Valid values are: 'visibility' and 'display' - * (defaluts to 'visibility'). If the mode is visibility the hidden icon is not visible but there - * is still blank space occupied by the icon. In display mode, the visible icons are shifted taking - * the space of the hidden icon. - */ - ,hideMode:'visibility' + /** + * @cfg {Number} widthIntercept Constant used for auto-width calculation (defaults to 4). + * See {@link #autoWidth} for explanation. + */ + , widthIntercept: 4 - /** - * @cfg {Number} widthIntercept Constant used for auto-width calculation (defaults to 4). - * See {@link #autoWidth} for explanation. - */ - ,widthIntercept:4 + /** + * @cfg {Number} widthSlope Constant used for auto-width calculation (defaults to 21). + * See {@link #autoWidth} for explanation. + */ + , widthSlope: 21 + // }}} - /** - * @cfg {Number} widthSlope Constant used for auto-width calculation (defaults to 21). - * See {@link #autoWidth} for explanation. - */ - ,widthSlope:21 - // }}} + // methods + // {{{ + /** + * Init function + * @param {Ext.grid.GridPanel} grid Grid this plugin is in + */ + , init: function(grid) { + this.grid = grid; - // methods - // {{{ - /** - * Init function - * @param {Ext.grid.GridPanel} grid Grid this plugin is in - */ - ,init:function(grid) { - this.grid = grid; - - // the actions column must have an id for Ext 3.x - this.id = this.id || Ext.id(); + // the actions column must have an id for Ext 3.x + this.id = this.id || Ext.id(); - // for Ext 3.x compatibility - var lookup = grid.getColumnModel().lookup; - delete(lookup[undefined]); - lookup[this.id] = this; + // for Ext 3.x compatibility + var lookup = grid.getColumnModel().lookup; + delete(lookup[undefined]); + lookup[this.id] = this; - // {{{ - // setup template - if(!this.tpl) { - this.tpl = this.processActions(this.actions); + // {{{ + // setup template + if (!this.tpl) { + this.tpl = this.processActions(this.actions); - } // eo template setup - // }}} + } // eo template setup + // }}} - // calculate width - if(this.autoWidth) { - this.width = this.widthSlope * this.actions.length + this.widthIntercept; - this.fixed = true; - } + // calculate width + if (this.autoWidth) { + this.width = this.widthSlope * this.actions.length + this.widthIntercept; + this.fixed = true; + } - // body click handler - var view = grid.getView(); - var cfg = {scope:this}; - cfg[this.actionEvent] = this.onClick; - grid.afterRender = grid.afterRender.createSequence(function() { - view.mainBody.on(cfg); - grid.on('destroy', this.purgeListeners, this); - }, this); + // body click handler + var view = grid.getView(); + var cfg = {scope: this}; + cfg[this.actionEvent] = this.onClick; + grid.afterRender = grid.afterRender.createSequence(function() { + view.mainBody.on(cfg); + grid.on('destroy', this.purgeListeners, this); + }, this); - // setup renderer - if(!this.renderer) { - this.renderer = function(value, cell, record, row, col, store) { - cell.css += (cell.css ? ' ' : '') + 'ux-row-action-cell'; - return this.tpl.apply(this.getData(value, cell, record, row, col, store)); - }.createDelegate(this); - } + // setup renderer + if (!this.renderer) { + this.renderer = function(value, cell, record, row, col, store) { + cell.css += (cell.css ? ' ' : '') + 'ux-row-action-cell'; + return this.tpl.apply(this.getData(value, cell, record, row, col, store)); + }.createDelegate(this); + } - // actions in grouping grids support - if(view.groupTextTpl && this.groupActions) { - view.interceptMouse = view.interceptMouse.createInterceptor(function(e) { - if(e.getTarget('.ux-grow-action-item')) { - return false; - } - }); - view.groupTextTpl = - '
' + view.groupTextTpl +'
' - +this.processActions(this.groupActions, this.tplGroup).apply() - ; - } + // actions in grouping grids support + if (view.groupTextTpl && this.groupActions) { + view.interceptMouse = view.interceptMouse.createInterceptor(function(e) { + if (e.getTarget('.ux-grow-action-item')) { + return false; + } + }); + view.groupTextTpl = + '
' + view.groupTextTpl + '
' + + this.processActions(this.groupActions, this.tplGroup).apply() + ; + } - // cancel click - if(true === this.keepSelection) { - grid.processEvent = grid.processEvent.createInterceptor(function(name, e) { - if('mousedown' === name) { - return !this.getAction(e); - } - }, this); - } - - } // eo function init - // }}} - // {{{ - /** - * Returns data to apply to template. Override this if needed. - * @param {Mixed} value - * @param {Object} cell object to set some attributes of the grid cell - * @param {Ext.data.Record} record from which the data is extracted - * @param {Number} row row index - * @param {Number} col col index - * @param {Ext.data.Store} store object from which the record is extracted - * @return {Object} data to apply to template - */ - ,getData:function(value, cell, record, row, col, store) { - return record.data || {}; - } // eo function getData - // }}} - // {{{ - /** - * Processes actions configs and returns template. - * @param {Array} actions - * @param {String} template Optional. Template to use for one action item. - * @return {String} - * @private - */ - ,processActions:function(actions, template) { - var acts = []; + // cancel click + if (true === this.keepSelection) { + grid.processEvent = grid.processEvent.createInterceptor(function(name, e) { + if ('mousedown' === name) { + return !this.getAction(e); + } + }, this); + } - // actions loop - Ext.each(actions, function(a, i) { - // save callback - if(a.iconCls && 'function' === typeof (a.callback || a.cb)) { - this.callbacks = this.callbacks || {}; - this.callbacks[a.iconCls] = a.callback || a.cb; - } + } // eo function init + // }}} + // {{{ + /** + * Returns data to apply to template. Override this if needed. + * @param {Mixed} value + * @param {Object} cell object to set some attributes of the grid cell + * @param {Ext.data.Record} record from which the data is extracted + * @param {Number} row row index + * @param {Number} col col index + * @param {Ext.data.Store} store object from which the record is extracted + * @return {Object} data to apply to template + */ + , getData: function(value, cell, record, row, col, store) { + return record.data || {}; + } // eo function getData + // }}} + // {{{ + /** + * Processes actions configs and returns template. + * @param {Array} actions + * @param {String} template Optional. Template to use for one action item. + * @return {String} + * @private + */ + , processActions: function(actions, template) { + var acts = []; - // data for intermediate template - var o = { - cls:a.iconIndex ? '{' + a.iconIndex + '}' : (a.iconCls ? a.iconCls : '') - ,qtip:a.qtipIndex ? '{' + a.qtipIndex + '}' : (a.tooltip || a.qtip ? a.tooltip || a.qtip : '') - ,text:a.textIndex ? '{' + a.textIndex + '}' : (a.text ? a.text : '') - ,hide:a.hideIndex - ? '' - + ('display' === this.hideMode ? 'display:none' :'visibility:hidden') + ';' - : (a.hide ? ('display' === this.hideMode ? 'display:none' :'visibility:hidden;') : '') - ,align:a.align || 'right' - ,style:a.style ? a.style : '' - }; - acts.push(o); + // actions loop + Ext.each(actions, function(a, i) { + // save callback + if (a.iconCls && 'function' === typeof (a.callback || a.cb)) { + this.callbacks = this.callbacks || {}; + this.callbacks[a.iconCls] = a.callback || a.cb; + } - }, this); // eo actions loop + // data for intermediate template + var o = { + cls: a.iconIndex ? '{' + a.iconIndex + '}' : (a.iconCls ? a.iconCls : '') + , qtip: a.qtipIndex ? '{' + a.qtipIndex + '}' : (a.tooltip || a.qtip ? a.tooltip || a.qtip : '') + , text: a.textIndex ? '{' + a.textIndex + '}' : (a.text ? a.text : '') + , hide: a.hideIndex + ? '' + + ('display' === this.hideMode ? 'display:none' : 'visibility:hidden') + ';' + : (a.hide ? ('display' === this.hideMode ? 'display:none' : 'visibility:hidden;') : '') + , align: a.align || 'right' + , style: a.style ? a.style : '' + }; + acts.push(o); - var xt = new Ext.XTemplate(template || this.tplRow); - return new Ext.XTemplate(xt.apply({actions:acts})); + }, this); // eo actions loop - } // eo function processActions - // }}} - ,getAction:function(e) { - var action = false; - var t = e.getTarget('.ux-row-action-item'); - if(t) { - action = t.className.replace(/ux-row-action-item /, ''); - if(action) { - action = action.replace(/ ux-row-action-text/, ''); - action = action.trim(); - } - } - return action; - } // eo function getAction - // {{{ - /** - * Grid body actionEvent event handler - * @private - */ - ,onClick:function(e, target) { + var xt = new Ext.XTemplate(template || this.tplRow); + return new Ext.XTemplate(xt.apply({actions: acts})); - var view = this.grid.getView(); + } // eo function processActions + // }}} + , getAction: function(e) { + var action = false; + var t = e.getTarget('.ux-row-action-item'); + if (t) { + action = t.className.replace(/ux-row-action-item /, ''); + if (action) { + action = action.replace(/ ux-row-action-text/, ''); + action = action.trim(); + } + } + return action; + } // eo function getAction + // {{{ + /** + * Grid body actionEvent event handler + * @private + */ + , onClick: function(e, target) { - // handle row action click - var row = e.getTarget('.x-grid3-row'); - var col = view.findCellIndex(target.parentNode.parentNode); - var action = this.getAction(e); + var view = this.grid.getView(); + + // handle row action click + var row = e.getTarget('.x-grid3-row'); + var col = view.findCellIndex(target.parentNode.parentNode); + var action = this.getAction(e); // var t = e.getTarget('.ux-row-action-item'); // if(t) { @@ -890,55 +879,55 @@ Ext.extend(Ext.ux.grid.RowActions, Ext.util.Observable, { // action = action.trim(); // } // } - if(false !== row && false !== col && false !== action) { - var record = this.grid.store.getAt(row.rowIndex); + if (false !== row && false !== col && false !== action) { + var record = this.grid.store.getAt(row.rowIndex); - // call callback if any - if(this.callbacks && 'function' === typeof this.callbacks[action]) { - this.callbacks[action](this.grid, record, action, row.rowIndex, col); - } + // call callback if any + if (this.callbacks && 'function' === typeof this.callbacks[action]) { + this.callbacks[action](this.grid, record, action, row.rowIndex, col); + } - // fire events - if(true !== this.eventsSuspended && false === this.fireEvent('beforeaction', this.grid, record, action, row.rowIndex, col)) { - return; - } - else if(true !== this.eventsSuspended) { - this.fireEvent('action', this.grid, record, action, row.rowIndex, col); - } + // fire events + if (true !== this.eventsSuspended && false === this.fireEvent('beforeaction', this.grid, record, action, row.rowIndex, col)) { + return; + } + else if (true !== this.eventsSuspended) { + this.fireEvent('action', this.grid, record, action, row.rowIndex, col); + } - } + } - // handle group action click - t = e.getTarget('.ux-grow-action-item'); - if(t) { - // get groupId - var group = view.findGroup(target); - var groupId = group ? group.id.replace(/ext-gen[0-9]+-gp-/, '') : null; + // handle group action click + t = e.getTarget('.ux-grow-action-item'); + if (t) { + // get groupId + var group = view.findGroup(target); + var groupId = group ? group.id.replace(/ext-gen[0-9]+-gp-/, '') : null; - // get matching records - var records; - if(groupId) { - var re = new RegExp(RegExp.escape(groupId)); - records = this.grid.store.queryBy(function(r) { - return r._groupId.match(re); - }); - records = records ? records.items : []; - } - action = t.className.replace(/ux-grow-action-item (ux-action-right )*/, ''); + // get matching records + var records; + if (groupId) { + var re = new RegExp(RegExp.escape(groupId)); + records = this.grid.store.queryBy(function(r) { + return r._groupId.match(re); + }); + records = records ? records.items : []; + } + action = t.className.replace(/ux-grow-action-item (ux-action-right )*/, ''); - // call callback if any - if('function' === typeof this.callbacks[action]) { - this.callbacks[action](this.grid, records, action, groupId); - } + // call callback if any + if ('function' === typeof this.callbacks[action]) { + this.callbacks[action](this.grid, records, action, groupId); + } - // fire events - if(true !== this.eventsSuspended && false === this.fireEvent('beforegroupaction', this.grid, records, action, groupId)) { - return false; - } - this.fireEvent('groupaction', this.grid, records, action, groupId); - } - } // eo function onClick - // }}} + // fire events + if (true !== this.eventsSuspended && false === this.fireEvent('beforegroupaction', this.grid, records, action, groupId)) { + return false; + } + this.fireEvent('groupaction', this.grid, records, action, groupId); + } + } // eo function onClick + // }}} }); @@ -964,251 +953,250 @@ Ext.reg('rowactions', Ext.ux.grid.RowActions); * * License details: http://www.gnu.org/licenses/lgpl.html */ - + /*global Ext */ // add RegExp.escape if it has not been already added -if('function' !== typeof RegExp.escape) { - RegExp.escape = function(s) { - if('string' !== typeof s) { - return s; - } - // Note: if pasting from forum, precede ]/\ with backslash manually - return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); - }; // eo function escape +if ('function' !== typeof RegExp.escape) { + RegExp.escape = function(s) { + if ('string' !== typeof s) { + return s; + } + // Note: if pasting from forum, precede ]/\ with backslash manually + return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); + }; // eo function escape } // create namespace Ext.ns('Ext.ux.form'); - + /** * * @class Ext.ux.form.LovCombo * @extends Ext.form.ComboBox */ Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, { - - // {{{ - // configuration options - /** - * @cfg {String} checkField name of field used to store checked state. - * It is automatically added to existing fields. - * Change it only if it collides with your normal field. - */ - checkField:'checked' - - /** - * @cfg {String} separator separator to use between values and texts - */ - ,separator:',' - - /** - * @cfg {String/Array} tpl Template for items. - * Change it only if you know what you are doing. - */ - // }}} // {{{ - ,initComponent:function() { - - // template with checkbox - if(!this.tpl) { - this.tpl = - '' - +'
' - +'' - +'
{' + (this.displayField || 'text' )+ '}
' - +'
' - +'
' - ; - } - + // configuration options + /** + * @cfg {String} checkField name of field used to store checked state. + * It is automatically added to existing fields. + * Change it only if it collides with your normal field. + */ + checkField: 'checked' + + /** + * @cfg {String} separator separator to use between values and texts + */ + , separator: ',' + + /** + * @cfg {String/Array} tpl Template for items. + * Change it only if you know what you are doing. + */ + // }}} + // {{{ + , initComponent: function() { + + // template with checkbox + if (!this.tpl) { + this.tpl = + '' + + '
' + + '' + + '
{' + (this.displayField || 'text') + '}
' + + '
' + + '
' + ; + } + // call parent Ext.ux.form.LovCombo.superclass.initComponent.apply(this, arguments); - // install internal event handlers - this.on({ - scope:this - ,beforequery:this.onBeforeQuery - ,blur:this.onRealBlur - }); + // install internal event handlers + this.on({ + scope: this + , beforequery: this.onBeforeQuery + , blur: this.onRealBlur + }); + + // remove selection from input field + this.onLoad = this.onLoad.createSequence(function() { + if (this.el) { + var v = this.el.dom.value; + this.el.dom.value = ''; + this.el.dom.value = v; + } + }); - // remove selection from input field - this.onLoad = this.onLoad.createSequence(function() { - if(this.el) { - var v = this.el.dom.value; - this.el.dom.value = ''; - this.el.dom.value = v; - } - }); - } // e/o function initComponent // }}} - // {{{ - /** - * Disables default tab key bahavior - * @private - */ - ,initEvents:function() { - Ext.ux.form.LovCombo.superclass.initEvents.apply(this, arguments); + // {{{ + /** + * Disables default tab key bahavior + * @private + */ + , initEvents: function() { + Ext.ux.form.LovCombo.superclass.initEvents.apply(this, arguments); - // disable default tab handling - does no good - this.keyNav.tab = false; + // disable default tab handling - does no good + this.keyNav.tab = false; - } // eo function initEvents - // }}} - // {{{ - /** - * clears value - */ - ,clearValue:function() { - this.value = ''; - this.setRawValue(this.value); - this.store.clearFilter(); - this.store.each(function(r) { - r.set(this.checkField, false); - }, this); - if(this.hiddenField) { - this.hiddenField.value = ''; - } - this.applyEmptyText(); - } // eo function clearValue - // }}} - // {{{ - /** - * @return {String} separator (plus space) separated list of selected displayFields - * @private - */ - ,getCheckedDisplay:function() { - var re = new RegExp(this.separator, "g"); - return this.getCheckedValue(this.displayField).replace(re, this.separator + ' '); - } // eo function getCheckedDisplay - // }}} - // {{{ - /** - * @return {String} separator separated list of selected valueFields - * @private - */ - ,getCheckedValue:function(field) { - field = field || this.valueField; - var c = []; + } // eo function initEvents + // }}} + // {{{ + /** + * clears value + */ + , clearValue: function() { + this.value = ''; + this.setRawValue(this.value); + this.store.clearFilter(); + this.store.each(function(r) { + r.set(this.checkField, false); + }, this); + if (this.hiddenField) { + this.hiddenField.value = ''; + } + this.applyEmptyText(); + } // eo function clearValue + // }}} + // {{{ + /** + * @return {String} separator (plus space) separated list of selected displayFields + * @private + */ + , getCheckedDisplay: function() { + var re = new RegExp(this.separator, "g"); + return this.getCheckedValue(this.displayField).replace(re, this.separator + ' '); + } // eo function getCheckedDisplay + // }}} + // {{{ + /** + * @return {String} separator separated list of selected valueFields + * @private + */ + , getCheckedValue: function(field) { + field = field || this.valueField; + var c = []; - // store may be filtered so get all records - var snapshot = this.store.snapshot || this.store.data; + // store may be filtered so get all records + var snapshot = this.store.snapshot || this.store.data; - snapshot.each(function(r) { - if(r.get(this.checkField)) { - c.push(r.get(field)); - } - }, this); + snapshot.each(function(r) { + if (r.get(this.checkField)) { + c.push(r.get(field)); + } + }, this); - return c.join(this.separator); - } // eo function getCheckedValue - // }}} - // {{{ - /** - * beforequery event handler - handles multiple selections - * @param {Object} qe query event - * @private - */ - ,onBeforeQuery:function(qe) { - qe.query = qe.query.replace(new RegExp(this.getCheckedDisplay() + '[ ' + this.separator + ']*'), ''); - } // eo function onBeforeQuery - // }}} - // {{{ - /** - * blur event handler - runs only when real blur event is fired - */ - ,onRealBlur:function() { - this.list.hide(); - var rv = this.getRawValue(); - var rva = rv.split(new RegExp(RegExp.escape(this.separator) + ' *')); - var va = []; - var snapshot = this.store.snapshot || this.store.data; + return c.join(this.separator); + } // eo function getCheckedValue + // }}} + // {{{ + /** + * beforequery event handler - handles multiple selections + * @param {Object} qe query event + * @private + */ + , onBeforeQuery: function(qe) { + qe.query = qe.query.replace(new RegExp(this.getCheckedDisplay() + '[ ' + this.separator + ']*'), ''); + } // eo function onBeforeQuery + // }}} + // {{{ + /** + * blur event handler - runs only when real blur event is fired + */ + , onRealBlur: function() { + this.list.hide(); + var rv = this.getRawValue(); + var rva = rv.split(new RegExp(RegExp.escape(this.separator) + ' *')); + var va = []; + var snapshot = this.store.snapshot || this.store.data; - // iterate through raw values and records and check/uncheck items - Ext.each(rva, function(v) { - snapshot.each(function(r) { - if(v === r.get(this.displayField)) { - va.push(r.get(this.valueField)); - } - }, this); - }, this); - this.setValue(va.join(this.separator)); - this.store.clearFilter(); - } // eo function onRealBlur - // }}} - // {{{ - /** - * Combo's onSelect override - * @private - * @param {Ext.data.Record} record record that has been selected in the list - * @param {Number} index index of selected (clicked) record - */ - ,onSelect:function(record, index) { - if(this.fireEvent('beforeselect', this, record, index) !== false){ + // iterate through raw values and records and check/uncheck items + Ext.each(rva, function(v) { + snapshot.each(function(r) { + if (v === r.get(this.displayField)) { + va.push(r.get(this.valueField)); + } + }, this); + }, this); + this.setValue(va.join(this.separator)); + this.store.clearFilter(); + } // eo function onRealBlur + // }}} + // {{{ + /** + * Combo's onSelect override + * @private + * @param {Ext.data.Record} record record that has been selected in the list + * @param {Number} index index of selected (clicked) record + */ + , onSelect: function(record, index) { + if (this.fireEvent('beforeselect', this, record, index) !== false) { - // toggle checked field - record.set(this.checkField, !record.get(this.checkField)); + // toggle checked field + record.set(this.checkField, !record.get(this.checkField)); - // display full list - if(this.store.isFiltered()) { - this.doQuery(this.allQuery); - } + // display full list + if (this.store.isFiltered()) { + this.doQuery(this.allQuery); + } - // set (update) value and fire event - this.setValue(this.getCheckedValue()); + // set (update) value and fire event + this.setValue(this.getCheckedValue()); this.fireEvent('select', this, record, index); } - } // eo function onSelect - // }}} - // {{{ - /** - * Sets the value of the LovCombo - * @param {Mixed} v value - */ - ,setValue:function(v) { - if(v) { - v = '' + v; - if(this.valueField) { - this.store.clearFilter(); - this.store.each(function(r) { - var checked = !(!v.match( - '(^|' + this.separator + ')' + RegExp.escape(r.get(this.valueField)) - +'(' + this.separator + '|$)')) - ; + } // eo function onSelect + // }}} + // {{{ + /** + * Sets the value of the LovCombo + * @param {Mixed} v value + */ + , setValue: function(v) { + if (v) { + v = '' + v; + if (this.valueField) { + this.store.clearFilter(); + this.store.each(function(r) { + var checked = !(!v.match( + '(^|' + this.separator + ')' + RegExp.escape(r.get(this.valueField)) + + '(' + this.separator + '|$)')) + ; - r.set(this.checkField, checked); - }, this); - this.value = this.getCheckedValue(); - this.setRawValue(this.getCheckedDisplay()); - if(this.hiddenField) { - this.hiddenField.value = this.value; - } - } - else { - this.value = v; - this.setRawValue(v); - if(this.hiddenField) { - this.hiddenField.value = v; - } - } - if(this.el) { - this.el.removeClass(this.emptyClass); - } - } - else { - this.clearValue(); - } - } // eo function setValue - // }}} - // {{{ - /** - * Selects all items - */ - ,selectAll:function() { - this.store.each(function(record){ + r.set(this.checkField, checked); + }, this); + this.value = this.getCheckedValue(); + this.setRawValue(this.getCheckedDisplay()); + if (this.hiddenField) { + this.hiddenField.value = this.value; + } + } + else { + this.value = v; + this.setRawValue(v); + if (this.hiddenField) { + this.hiddenField.value = v; + } + } + if (this.el) { + this.el.removeClass(this.emptyClass); + } + } + else { + this.clearValue(); + } + } // eo function setValue + // }}} + // {{{ + /** + * Selects all items + */ + , selectAll: function() { + this.store.each(function(record) { // toggle checked field record.set(this.checkField, true); }, this); @@ -1217,17 +1205,17 @@ Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, { this.doQuery(this.allQuery); this.setValue(this.getCheckedValue()); } // eo full selectAll - // }}} - // {{{ - /** - * Deselects all items. Synonym for clearValue - */ - ,deselectAll:function() { - this.clearValue(); + // }}} + // {{{ + /** + * Deselects all items. Synonym for clearValue + */ + , deselectAll: function() { + this.clearValue(); } // eo full deselectAll - // }}} + // }}} }); // eo extend - + // register xtype -Ext.reg('lovcombo', Ext.ux.form.LovCombo); +Ext.reg('lovcombo', Ext.ux.form.LovCombo); diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index 8c7108d1..f6648609 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -3,303 +3,306 @@ */ tvheadend.idnode_enum_stores = {} -tvheadend.idnode_get_enum = function ( conf ) +tvheadend.idnode_get_enum = function(conf) { - /* Build key */ - var key = conf.url; - if (conf.params) - key += '?' + Ext.util.JSON.encode(conf.params); - if (conf.event) - key += '+' + conf.event; + /* Build key */ + var key = conf.url; + if (conf.params) + key += '?' + Ext.util.JSON.encode(conf.params); + if (conf.event) + key += '+' + conf.event; - /* Use cached */ - if (key in tvheadend.idnode_enum_stores) - return tvheadend.idnode_enum_stores[key]; + /* Use cached */ + if (key in tvheadend.idnode_enum_stores) + return tvheadend.idnode_enum_stores[key]; - /* Build combobox */ - var st = new Ext.data.JsonStore({ - root : conf.root || 'entries', - url : conf.url, - baseParams : conf.params || {}, - fields : conf.fields || [ 'key', 'val' ], - id : conf.id || 'key', - autoLoad : true, - sortInfo : { - field : 'val', - direction : 'ASC' - } - }); - tvheadend.idnode_enum_stores[key] = st; - - /* Event to update */ - if (conf.event) { - tvheadend.comet.on(conf.event, function(){ - st.reload(); + /* Build combobox */ + var st = new Ext.data.JsonStore({ + root: conf.root || 'entries', + url: conf.url, + baseParams: conf.params || {}, + fields: conf.fields || ['key', 'val'], + id: conf.id || 'key', + autoLoad: true, + sortInfo: { + field: 'val', + direction: 'ASC' + } }); - } + tvheadend.idnode_enum_stores[key] = st; - return st; -} + /* Event to update */ + if (conf.event) { + tvheadend.comet.on(conf.event, function() { + st.reload(); + }); + } + + return st; +}; json_decode = function(d) { - if (d && d.responseText) { - d = Ext.util.JSON.decode(d.responseText) - if (d.entries) - d = d.entries; - if (d.nodes) - d = d.nodes; - } else { - d = [] - } - return d; -} + if (d && d.responseText) { + d = Ext.util.JSON.decode(d.responseText); + if (d.entries) + d = d.entries; + if (d.nodes) + d = d.nodes; + } else { + d = []; + } + return d; +}; /* * Build enum data store */ tvheadend.idnode_enum_store = function(f) { - var store = null; + var store = null; - /* API fetch */ - if (f.enum.type == 'api') { - return tvheadend.idnode_get_enum({ - url : 'api/' + f.enum.uri, - params : f.enum.params, - event : f.enum.event - }); - } - - switch (f.type) { - case 'str': - if (f.enum.length > 0 && f.enum[0] instanceof Object) - store = new Ext.data.JsonStore({ - id : 'key', - fields : [ 'key', 'val' ], - data : f.enum, + /* API fetch */ + if (f.enum.type === 'api') { + return tvheadend.idnode_get_enum({ + url: 'api/' + f.enum.uri, + params: f.enum.params, + event: f.enum.event }); - else - store = f.enum; - break; - case 'int': - case 'u32': - case 'u16': - case 'dbl': - var data = null; - if (f.enum.length > 0 && f.enum[0] instanceof Object) { - data = f.enum; - } else { - data = [] - for ( i = 0; i < f.enum.length; i++ ) - data.push({ key: i, val: f.enum[i]}); - } - store = new Ext.data.JsonStore({ - id : 'key', - fields : [ 'key', 'val' ], - data : data - }); - break; - } - return store; -} - -tvheadend.IdNodeField = function (conf) -{ - /* - * Properties - */ - this.id = conf.id; - this.text = conf.caption || this.id; - this.type = conf.type; - this.list = conf.list; - this.rdonly = conf.rdonly; - this.wronly = conf.wronly; - this.wronce = conf.wronce; - this.hidden = conf.hidden || conf.advanced; - this.enum = conf.enum; - this.store = null; - if (this.enum) - this.store = tvheadend.idnode_enum_store(this); - this.ordered = false; - - /* - * Methods - */ - - this.column = function () - { - var w = 300; - var ftype = 'string'; - if (this.type == 'int' || this.type == 'u32' || - this.type == 'u16' || this.type == 'dbl') { - ftype = 'numeric'; - w = 80; - } else if (this.type == 'bool') { - ftype = 'boolean'; - w = 60; } - if (this.enum || this.list) - w = 300; - return { - width : w, - dataIndex: this.id, - header : this.text, - editor : this.editor({create: false}), - renderer : this.renderer(), - hidden : this.hidden, - filter : { - type : ftype, - dataIndex : this.id - } - }; - } - - this.renderer = function () - { - if (!this.store) - return null; - - var st = this.store; - return function (v) { - if (st && st instanceof Ext.data.JsonStore) { - var t = [] - var d; - if (v.push) - d = v; - else - d = [ v ]; - for (var i = 0; i < d.length; i++) { - var r = st.find('key', d[i]); - if (r != -1) { - var nv = st.getAt(r).get('val'); - if (nv) - t.push(nv); - } - } - v = t.join(','); - } - return v; - }; - } - - this.editor = function (conf) - { - var cons = null; - - /* Editable? */ - var d = this.rdonly; - if (this.wronly && !conf.create) - d = false; - - /* Basic */ - var c = { - fieldLabel : this.text, - name : this.id, - value : conf.value || null, - disabled : d, - width : 300, - }; - - /* ComboBox */ - if (this.enum) { - cons = Ext.form.ComboBox; - if (this.list) - cons = Ext.ux.form.LovCombo; - - /* Combo settings */ - c['mode'] = 'local'; - c['valueField'] = 'key'; - c['displayField'] = 'val'; - c['store'] = this.store; - c['typeAhead'] = true; - c['forceSelection'] = false; - c['triggerAction'] = 'all', - c['emptyText'] = 'Select ' + this.text + ' ...'; - - /* Single */ - } else { - switch (this.type) { - case 'bool': - cons = Ext.form.Checkbox; - break; + switch (f.type) { + case 'str': + if (f.enum.length > 0 && f.enum[0] instanceof Object) + store = new Ext.data.JsonStore({ + id: 'key', + fields: ['key', 'val'], + data: f.enum + }); + else + store = f.enum; + break; case 'int': case 'u32': case 'u16': case 'dbl': - cons = Ext.form.NumberField; - break; - - default: - cons = Ext.form.TextField; - break; - } + var data = null; + if (f.enum.length > 0 && f.enum[0] instanceof Object) { + data = f.enum; + } else { + data = []; + for (i = 0; i < f.enum.length; i++) + data.push({key: i, val: f.enum[i]}); + } + store = new Ext.data.JsonStore({ + id: 'key', + fields: ['key', 'val'], + data: data + }); + break; } + return store; +}; - return new cons(c); - } -} +tvheadend.IdNodeField = function(conf) +{ + /* + * Properties + */ + this.id = conf.id; + this.text = conf.caption || this.id; + this.type = conf.type; + this.list = conf.list; + this.rdonly = conf.rdonly; + this.wronly = conf.wronly; + this.wronce = conf.wronce; + this.hidden = conf.hidden || conf.advanced; + this.enum = conf.enum; + this.store = null; + if (this.enum) + this.store = tvheadend.idnode_enum_store(this); + this.ordered = false; + + /* + * Methods + */ + + this.column = function() + { + var w = 300; + var ftype = 'string'; + if (this.type === 'int' || this.type === 'u32' || + this.type === 'u16' || this.type === 'dbl') { + ftype = 'numeric'; + w = 80; + } else if (this.type === 'bool') { + ftype = 'boolean'; + w = 60; + } + if (this.enum || this.list) + w = 300; + return { + width: w, + dataIndex: this.id, + header: this.text, + editor: this.editor({create: false}), + renderer: this.renderer(), + hidden: this.hidden, + filter: { + type: ftype, + dataIndex: this.id + } + }; + }; + + this.renderer = function() + { + if (!this.store) + return null; + + var st = this.store; + return function(v) { + if (st && st instanceof Ext.data.JsonStore) { + var t = []; + var d; + if (v.push) + d = v; + else + d = [v]; + for (var i = 0; i < d.length; i++) { + var r = st.find('key', d[i]); + if (r !== -1) { + var nv = st.getAt(r).get('val'); + if (nv) + t.push(nv); + } + } + v = t.join(','); + } + return v; + }; + }; + + this.editor = function(conf) + { + var cons = null; + + /* Editable? */ + var d = this.rdonly; + if (this.wronly && !conf.create) + d = false; + + /* Basic */ + var c = { + fieldLabel: this.text, + name: this.id, + value: conf.value || null, + disabled: d, + width: 300 + }; + + /* ComboBox */ + if (this.enum) { + cons = Ext.form.ComboBox; + if (this.list) + cons = Ext.ux.form.LovCombo; + + /* Combo settings */ + c['mode'] = 'local'; + c['valueField'] = 'key'; + c['displayField'] = 'val'; + c['store'] = this.store; + c['typeAhead'] = true; + c['forceSelection'] = false; + c['triggerAction'] = 'all', + c['emptyText'] = 'Select ' + this.text + ' ...'; + + /* Single */ + } else { + switch (this.type) { + case 'bool': + cons = Ext.form.Checkbox; + break; + + case 'int': + case 'u32': + case 'u16': + case 'dbl': + cons = Ext.form.NumberField; + break; + + default: + cons = Ext.form.TextField; + break; + } + } + + return new cons(c); + }; +}; /* * IdNode */ -tvheadend.IdNode = function (conf) +tvheadend.IdNode = function(conf) { - /* - * Properties - */ - this.clazz = conf.class; - this.text = conf.caption || this.clazz; - this.props = conf.props; - this.order = []; - this.fields = []; - for (var i = 0; i < this.props.length; i++) { - this.fields.push(new tvheadend.IdNodeField(this.props[i])); - } - var o = []; - if (conf.order) - o = conf.order.split(','); - if (o) { - while (o.length < this.fields.length) - o.push(null); - for (var i = 0; i < o.length; i++) { - this.order[i] = null; - if (o[i]) { - for (var j = 0; j < this.fields.length; j++) { - if (this.fields[j].id == o[i]) { - this.order[i] = this.fields[j]; - this.fields[j].ordered = true; - break; - } - } - } + /* + * Properties + */ + this.clazz = conf.class; + this.text = conf.caption || this.clazz; + this.props = conf.props; + this.order = []; + this.fields = []; + for (var i = 0; i < this.props.length; i++) { + this.fields.push(new tvheadend.IdNodeField(this.props[i])); } - for (var i = 0; i < o.length; i++) { - if (this.order[i] == null) { - for (var j = 0; j < this.fields.length; j++) { - if (!this.fields[j].ordered) { - this.fields[j].ordered = true; - this.order[i] = this.fields[j]; - break; - } + var o = []; + if (conf.order) + o = conf.order.split(','); + if (o) { + while (o.length < this.fields.length) + o.push(null); + for (var i = 0; i < o.length; i++) { + this.order[i] = null; + if (o[i]) { + for (var j = 0; j < this.fields.length; j++) { + if (this.fields[j].id === o[i]) { + this.order[i] = this.fields[j]; + this.fields[j].ordered = true; + break; + } + } + } + } + for (var i = 0; i < o.length; i++) { + if (this.order[i] == null) { + for (var j = 0; j < this.fields.length; j++) { + if (!this.fields[j].ordered) { + this.fields[j].ordered = true; + this.order[i] = this.fields[j]; + break; + } + } + } } - } } - } - /* - * Methods - */ + /* + * Methods + */ - this.length = function () { - return this.fields.length; - } - - this.field = function ( index ) { - if (this.order) return this.order[index]; else return this.fields[index]; - } -} + this.length = function() { + return this.fields.length; + }; + + this.field = function(index) { + if (this.order) + return this.order[index]; + else + return this.fields[index]; + }; +}; /* @@ -307,205 +310,208 @@ tvheadend.IdNode = function (conf) */ tvheadend.idnode_editor_field = function(f, create) { - var d = f.rdonly || false; - if (f.wronly && !create) d = false; - var value = f.value; - if (value == null) - value = f.default; - - /* Enumerated (combobox) type */ - if (f.enum) { - var cons = Ext.form.ComboBox; - if (f.list) - cons = Ext.ux.form.LovCombo; - var st = tvheadend.idnode_enum_store(f); - var r = new cons({ - fieldLabel : f.caption, - name : f.id, - value : value, - disabled : d, - width : 300, - mode : 'local', - valueField : 'key', - displayField : 'val', - store : st, - typeAhead : true, // TODO: this does strange things in multi - forceSelection : false, - triggerAction : 'all', - emptyText :'Select ' + f.caption +' ...', - listeners : { - beforequery: function(qe){ - delete qe.combo.lastQuery; + var d = f.rdonly || false; + if (f.wronly && !create) + d = false; + var value = f.value; + if (value == null) + value = f.default; + + /* Enumerated (combobox) type */ + if (f.enum) { + var cons = Ext.form.ComboBox; + if (f.list) + cons = Ext.ux.form.LovCombo; + var st = tvheadend.idnode_enum_store(f); + var r = new cons({ + fieldLabel: f.caption, + name: f.id, + value: value, + disabled: d, + width: 300, + mode: 'local', + valueField: 'key', + displayField: 'val', + store: st, + typeAhead: true, // TODO: this does strange things in multi + forceSelection: false, + triggerAction: 'all', + emptyText: 'Select ' + f.caption + ' ...', + listeners: { + beforequery: function(qe) { + delete qe.combo.lastQuery; + } + } + }); + if (st.on) { + var fn = function() { + st.un('load', fn); + r.setValue(value); // HACK: to get extjs to display properly + }; + st.on('load', fn); } - } - }); - if (st.on) { - var fn = function() { - st.un('load', fn); - r.setValue(value); // HACK: to get extjs to display properly - }; - st.on('load', fn); + return r; + /* TODO: listeners for regexp? + listeners : { + keyup: function() { + this.store.filter('val', this.getRawValue(), true, false); + }, + beforequery: function(queryEvent) { + queryEvent.combo.onLoad(); + // prevent doQuery from firing and clearing out my filter. + return false; + } + } + */ } - return r; - /* TODO: listeners for regexp? - listeners : { - keyup: function() { - this.store.filter('val', this.getRawValue(), true, false); - }, - beforequery: function(queryEvent) { - queryEvent.combo.onLoad(); - // prevent doQuery from firing and clearing out my filter. - return false; - } + + /* Singular */ + switch (f.type) { + case 'str': + return new Ext.form.TextField({ + fieldLabel: f.caption, + name: f.id, + value: value, + disabled: d, + width: 300 + }); + break; + + case 'bool': + return new Ext.ux.form.XCheckbox({ + fieldLabel: f.caption, + name: f.id, + checked: value, + disabled: d + }); + break; + + case 'int': + case 'u32': + case 'u16': + case 'dbl': + return new Ext.form.NumberField({ + fieldLabel: f.caption, + name: f.id, + value: value, + disabled: d, + width: 300 + }); + break; } - */ - } - - /* Singular */ - switch(f.type) { - case 'str': - return new Ext.form.TextField({ - fieldLabel : f.caption, - name : f.id, - value : value, - disabled : d, - width : 300 - }); - break; - - case 'bool': - return new Ext.ux.form.XCheckbox({ - fieldLabel : f.caption, - name : f.id, - checked : value, - disabled : d - }); - break; - - case 'int': - case 'u32': - case 'u16': - case 'dbl': - return new Ext.form.NumberField({ - fieldLabel : f.caption, - name : f.id, - value : value, - disabled : d, - width : 300 - }); - break; - } - return null; -} + return null; +}; /* * ID node editor form fields */ -tvheadend.idnode_editor_form = function ( d, panel ) +tvheadend.idnode_editor_form = function(d, panel) { - var af = []; - var rf = []; - var df = []; + var af = []; + var rf = []; + var df = []; - /* Fields */ - for (var i = 0; i < d.length; i++) { - var f = tvheadend.idnode_editor_field(d[i]); - if (!f) continue; - if (d[i].rdonly) - rf.push(f) - else if (d[i].advanced) - af.push(f); - else - df.push(f); - } - if (df.length) { - panel.add(new Ext.form.FieldSet({ - title : 'Basic Settings', - autoHeight : true, - autoWidth : true, - collapsible : true, - collapsed : false, - items : df - })); - } - if (af.length) { - panel.add(new Ext.form.FieldSet({ - title : 'Advanced Settings', - autoHeight : true, - autoWidth : true, - collapsible : true, - collapsed : false,//true, - items : af - })); - } - if (rf.length) { - panel.add(new Ext.form.FieldSet({ - title : 'Read-only Info', - autoHeight : true, - autoWidth : true, - collapsible : true, - collapsed : false,//true, - items : rf - })); - } - panel.doLayout(); -} + /* Fields */ + for (var i = 0; i < d.length; i++) { + var f = tvheadend.idnode_editor_field(d[i]); + if (!f) + continue; + if (d[i].rdonly) + rf.push(f); + else if (d[i].advanced) + af.push(f); + else + df.push(f); + } + if (df.length) { + panel.add(new Ext.form.FieldSet({ + title: 'Basic Settings', + autoHeight: true, + autoWidth: true, + collapsible: true, + collapsed: false, + items: df + })); + } + if (af.length) { + panel.add(new Ext.form.FieldSet({ + title: 'Advanced Settings', + autoHeight: true, + autoWidth: true, + collapsible: true, + collapsed: false, //true, + items: af + })); + } + if (rf.length) { + panel.add(new Ext.form.FieldSet({ + title: 'Read-only Info', + autoHeight: true, + autoWidth: true, + collapsible: true, + collapsed: false, //true, + items: rf + })); + } + panel.doLayout(); +}; /* * ID node editor panel */ tvheadend.idnode_editor = function(item, conf) { - var panel = null; - var buttons = []; + var panel = null; + var buttons = []; - /* Buttons */ - var saveBtn = new Ext.Button({ - text : 'Save', - handler : function() { - var node = panel.getForm().getFieldValues(); - node.uuid = item.uuid; - Ext.Ajax.request({ - url : 'api/idnode/save', - params : { - node: Ext.encode(node) - }, - success : function(d) { - if (conf.win) conf.win.hide(); + /* Buttons */ + var saveBtn = new Ext.Button({ + text: 'Save', + handler: function() { + var node = panel.getForm().getFieldValues(); + node.uuid = item.uuid; + Ext.Ajax.request({ + url: 'api/idnode/save', + params: { + node: Ext.encode(node) + }, + success: function(d) { + if (conf.win) + conf.win.hide(); + } + }); } - }); - } - }); - buttons.push(saveBtn); - - if (conf.help) { - var helpBtn = new Ext.Button({ - text : 'Help', - handler : conf.help }); - buttons.push(helpBtn); - } + buttons.push(saveBtn); - panel = new Ext.FormPanel({ - title : conf.title || null, - frame : true, - border : true, - bodyStyle : 'padding: 5px', - labelAlign : 'left', - labelWidth : 200, - autoWidth : true, - autoHeight : !conf.fixedHeight, - width : 600, - //defaults: {width: 330}, - defaultType : 'textfield', - buttonAlign : 'left', - buttons : buttons - }); + if (conf.help) { + var helpBtn = new Ext.Button({ + text: 'Help', + handler: conf.help + }); + buttons.push(helpBtn); + } - tvheadend.idnode_editor_form(item.props || item.params, panel); + panel = new Ext.FormPanel({ + title: conf.title || null, + frame: true, + border: true, + bodyStyle: 'padding: 5px', + labelAlign: 'left', + labelWidth: 200, + autoWidth: true, + autoHeight: !conf.fixedHeight, + width: 600, + //defaults: {width: 330}, + defaultType: 'textfield', + buttonAlign: 'left', + buttons: buttons + }); - return panel; -} + tvheadend.idnode_editor_form(item.props || item.params, panel); + + return panel; +}; /* @@ -513,139 +519,139 @@ tvheadend.idnode_editor = function(item, conf) */ tvheadend.idnode_create = function(conf) { - var puuid = null; - var panel = null; - var pclass = null; + var puuid = null; + var panel = null; + var pclass = null; - /* Buttons */ - var saveBtn = new Ext.Button({ - tooltip : 'Create new entry', - text : 'Create', - hidden : true, - handler : function(){ - params = conf.create.params || {} - if (puuid) - params['uuid'] = puuid; - if (pclass) - params['class'] = pclass - params['conf'] = Ext.encode(panel.getForm().getFieldValues()); - Ext.Ajax.request({ - url : conf.create.url || conf.url + '/create', - params : params, - success : function(d) { - win.close(); + /* Buttons */ + var saveBtn = new Ext.Button({ + tooltip: 'Create new entry', + text: 'Create', + hidden: true, + handler: function() { + params = conf.create.params || {}; + if (puuid) + params['uuid'] = puuid; + if (pclass) + params['class'] = pclass; + params['conf'] = Ext.encode(panel.getForm().getFieldValues()); + Ext.Ajax.request({ + url: conf.create.url || conf.url + '/create', + params: params, + success: function(d) { + win.close(); + } + }); } - }); - } - }); - var undoBtn = new Ext.Button({ - tooltip : 'Cancel operation', - text : 'Cancel', - handler : function(){ - win.close(); - } - }); - - /* Form */ - panel = new Ext.FormPanel({ - frame : true, - border : true, - bodyStyle : 'padding: 5px', - labelAlign : 'left', - labelWidth : 200, - autoWidth : true, - autoHeight : true, - defaultType : 'textfield', - buttonAlign : 'left', - items : [], - buttons : [ undoBtn, saveBtn ] - }); - - /* Create window */ - win = new Ext.Window({ - title : 'Add ' + conf.titleS, - layout : 'fit', - autoWidth : true, - autoHeight : true, - plain : true, - items : panel - }); - - - /* Do we need to first select a class? */ - if (conf.select) { - var store = conf.select.store; - if (!store) { - store = new Ext.data.JsonStore({ - root : 'entries', - url : conf.select.url || conf.url, - baseParams : conf.select.params, - fields : [ conf.select.valueField, conf.select.displayField ] - }); - } - var select = null; - if (conf.select.propField) { - select = function (s, n, o) { - var r = store.getAt(s.selectedIndex); - if (r) { - var d = r.get(conf.select.propField); - if (d) { - pclass = r.get(conf.select.valueField); - win.setTitle('Add ' + s.lastSelectionText); - panel.remove(s); - tvheadend.idnode_editor_form(d, panel); - saveBtn.setVisible(true); - } + }); + var undoBtn = new Ext.Button({ + tooltip: 'Cancel operation', + text: 'Cancel', + handler: function() { + win.close(); } - } - } else { - select = function (s, n, o) { - params = conf.select.clazz.params || {}; - params['uuid'] = puuid = n.id; - Ext.Ajax.request({ - url : conf.select.clazz.url || conf.select.url || conf.url, - success : function(d) { - panel.remove(s); - d = json_decode(d); - tvheadend.idnode_editor_form(d.props, panel); - saveBtn.setVisible(true); - }, - params : params + }); + + /* Form */ + panel = new Ext.FormPanel({ + frame: true, + border: true, + bodyStyle: 'padding: 5px', + labelAlign: 'left', + labelWidth: 200, + autoWidth: true, + autoHeight: true, + defaultType: 'textfield', + buttonAlign: 'left', + items: [], + buttons: [undoBtn, saveBtn] + }); + + /* Create window */ + win = new Ext.Window({ + title: 'Add ' + conf.titleS, + layout: 'fit', + autoWidth: true, + autoHeight: true, + plain: true, + items: panel + }); + + + /* Do we need to first select a class? */ + if (conf.select) { + var store = conf.select.store; + if (!store) { + store = new Ext.data.JsonStore({ + root: 'entries', + url: conf.select.url || conf.url, + baseParams: conf.select.params, + fields: [conf.select.valueField, conf.select.displayField] + }); + } + var select = null; + if (conf.select.propField) { + select = function(s, n, o) { + var r = store.getAt(s.selectedIndex); + if (r) { + var d = r.get(conf.select.propField); + if (d) { + pclass = r.get(conf.select.valueField); + win.setTitle('Add ' + s.lastSelectionText); + panel.remove(s); + tvheadend.idnode_editor_form(d, panel); + saveBtn.setVisible(true); + } + } + }; + } else { + select = function(s, n, o) { + params = conf.select.clazz.params || {}; + params['uuid'] = puuid = n.id; + Ext.Ajax.request({ + url: conf.select.clazz.url || conf.select.url || conf.url, + success: function(d) { + panel.remove(s); + d = json_decode(d); + tvheadend.idnode_editor_form(d.props, panel); + saveBtn.setVisible(true); + }, + params: params + }); + }; + } + + /* Parent selector */ + var combo = new Ext.form.ComboBox({ + fieldLabel: conf.select.label, + grow: true, + editable: false, + allowBlank: false, + displayField: conf.select.displayField, + valueField: conf.select.valueField, + mode: 'remote', + triggerAction: 'all', + store: store, + listeners: { + select: select + } }); - }; - } - /* Parent selector */ - var combo = new Ext.form.ComboBox({ - fieldLabel : conf.select.label, - grow : true, - editable : false, - allowBlank : false, - displayField : conf.select.displayField, - valueField : conf.select.valueField, - mode : 'remote', - triggerAction : 'all', - store : store, - listeners : { - select : select - } - }); - - panel.add(combo); - win.show(); - } else { - Ext.Ajax.request({ - url : conf.url + '/class', - params : conf.params, - success : function(d) { - d = json_decode(d); - tvheadend.idnode_editor_form(d.props, panel); - saveBtn.setVisible(true); + panel.add(combo); win.show(); - } - }); - } -} + } else { + Ext.Ajax.request({ + url: conf.url + '/class', + params: conf.params, + success: function(d) { + d = json_decode(d); + tvheadend.idnode_editor_form(d.props, panel); + saveBtn.setVisible(true); + win.show(); + } + }); + } +}; /* @@ -653,502 +659,506 @@ tvheadend.idnode_create = function(conf) */ tvheadend.idnode_grid = function(panel, conf) { - function build (d) - { - var columns = conf.lcol || []; - var filters = []; - var fields = []; - var buttons = []; - var plugins = conf.plugins || []; - var saveBtn = null; - var undoBtn = null; - var addBtn = null; - var delBtn = null; - var upBtn = null; - var downBtn = null; - var editBtn = null; + function build(d) + { + var columns = conf.lcol || []; + var filters = []; + var fields = []; + var buttons = []; + var plugins = conf.plugins || []; + var saveBtn = null; + var undoBtn = null; + var addBtn = null; + var delBtn = null; + var upBtn = null; + var downBtn = null; + var editBtn = null; - /* Model */ - var idnode = new tvheadend.IdNode(d); - for (var i = 0; i < idnode.length(); i++) { - var f = idnode.field(i); - var c = f.column(); - fields.push(f.id); - columns.push(c); - if (c.filter) - filters.push(c.filter); - } - - /* Right-hand columns */ - if (conf.rcol) - for (i = 0; i < conf.rcol.length; i++) - columns.push(conf.rcol[i]) - - /* Filters */ - var filter = new Ext.ux.grid.GridFilters({ - encode : true, - local : false, - filters : filters - }); - - var sort = null; - if (conf.sort) - sort = conf.sort; - - /* Store */ - var store = new Ext.data.JsonStore({ - root : 'entries', - url : conf.url + '/grid', - autoLoad : true, - id : 'uuid', - totalProperty : 'total', - fields : fields, - remoteSort : true, - pruneModifiedRecords : true, - sortInfo : sort - }); - - /* Model */ - var sortable = true; - if (conf.move) - sortable = false; - var model = new Ext.grid.ColumnModel({ - defaultSortable : sortable, - columns : columns - }); - - /* Selection */ - var select = new Ext.grid.RowSelectionModel({ - singleSelect : false - }); - - /* Event handlers */ - store.on('update', function(s, r, o){ - var d = (s.getModifiedRecords().length == 0); - undoBtn.setDisabled(d); - saveBtn.setDisabled(d); - }); - select.on('selectionchange', function(s){ - if (delBtn) - delBtn.setDisabled(s.getCount() == 0); - if (upBtn) { - upBtn.setDisabled(s.getCount() == 0); - downBtn.setDisabled(s.getCount() == 0); - } - editBtn.setDisabled(s.getCount() != 1); - if (conf.selected) - conf.selected(s); - }); - - /* Top bar */ - saveBtn = new Ext.Toolbar.Button({ - tooltip : 'Save pending changes (marked with red border)', - iconCls : 'save', - text : 'Save', - disabled : true, - handler : function(){ - var mr = store.getModifiedRecords(); - var out = new Array(); - for (var x = 0; x < mr.length; x++) { - v = mr[x].getChanges(); - out[x] = v; - out[x].uuid = mr[x].id; + /* Model */ + var idnode = new tvheadend.IdNode(d); + for (var i = 0; i < idnode.length(); i++) { + var f = idnode.field(i); + var c = f.column(); + fields.push(f.id); + columns.push(c); + if (c.filter) + filters.push(c.filter); } - Ext.Ajax.request({ - url : 'api/idnode/save', - params : { - node: Ext.encode(out) - }, - success : function(d) - { - if (!auto.getValue()) store.reload(); - } + + /* Right-hand columns */ + if (conf.rcol) + for (i = 0; i < conf.rcol.length; i++) + columns.push(conf.rcol[i]); + + /* Filters */ + var filter = new Ext.ux.grid.GridFilters({ + encode: true, + local: false, + filters: filters }); - } - }); - buttons.push(saveBtn); - undoBtn = new Ext.Toolbar.Button({ - tooltip : 'Revert pending changes (marked with red border)', - iconCls : 'undo', - text : 'Undo', - disabled : true, - handler : function() { - store.rejectChanges(); - } - }); - buttons.push(undoBtn); - buttons.push('-'); - if (conf.add) { - addBtn = new Ext.Toolbar.Button({ - tooltip : 'Add a new entry', - iconCls : 'add', - text : 'Add', - disabled : false, - handler : function() { - tvheadend.idnode_create(conf.add); - } - }); - buttons.push(addBtn); - } - if (conf.del) { - delBtn = new Ext.Toolbar.Button({ - tooltip : 'Delete selected entries', - iconCls : 'remove', - text : 'Delete', - disabled : true, - handler : function() { - var r = select.getSelections(); - if (r && r.length > 0) { - var uuids = [] - for ( var i = 0; i < r.length; i++ ) - uuids.push(r[i].id) - Ext.Ajax.request({ - url : 'api/idnode/delete', - params : { - uuid: Ext.encode(uuids) - }, - success : function(d) - { - if (!auto.getValue()) store.reload(); - } - }); - } - } - }); - buttons.push(delBtn); - } - if (conf.move) { - upBtn = new Ext.Toolbar.Button({ - tooltip : 'Move selected entries up', - iconCls : 'moveup', - text : 'Move Up', - disabled : true, - handler : function() { - var r = select.getSelections(); - if (r && r.length > 0) { - var uuids = [] - for ( var i = 0; i < r.length; i++ ) - uuids.push(r[i].id) - Ext.Ajax.request({ - url : 'api/idnode/moveup', - params : { - uuid: Ext.encode(uuids) - }, - success : function(d) - { - store.reload(); - } - }); - } - } - }); - buttons.push(upBtn); - downBtn = new Ext.Toolbar.Button({ - tooltip : 'Move selected entries down', - iconCls : 'movedown', - text : 'Move Down', - disabled : true, - handler : function() { - var r = select.getSelections(); - if (r && r.length > 0) { - var uuids = [] - for ( var i = 0; i < r.length; i++ ) - uuids.push(r[i].id) - Ext.Ajax.request({ - url : 'api/idnode/movedown', - params : { - uuid: Ext.encode(uuids) - }, - success : function(d) - { - store.reload(); - } - }); - } - } - }); - buttons.push(downBtn); - } - if (conf.add || conf.del || conf.move) - buttons.push('-'); - editBtn = new Ext.Toolbar.Button({ - tooltip : 'Edit selected entry', - iconCls : 'edit', - text : 'Edit', - disabled : true, - handler : function() { - var r = select.getSelected(); - if (r) { - if (conf.edittree) { - var p = tvheadend.idnode_tree({ - url : 'api/idnode/tree', - params : { - root : r.id - } - }); - p.setSize(800,600); - var w = new Ext.Window({ - title : 'Edit ' + conf.titleS, - layout : 'fit', - autoWidth : true, - autoHeight : true, - plain : true, - items : p - }); - w.show(); - } else { - Ext.Ajax.request({ - url : 'api/idnode/load', - params : { - uuid: r.id - }, - success : function(d) - { - d = json_decode(d); - var w = null; - var c = { win: w }; - var p = tvheadend.idnode_editor(d[0], c); - w = new Ext.Window({ - title : 'Edit ' + conf.titleS, - layout : 'fit', - autoWidth : true, - autoHeight : true, - plain : true, - items : p + + var sort = null; + if (conf.sort) + sort = conf.sort; + + /* Store */ + var store = new Ext.data.JsonStore({ + root: 'entries', + url: conf.url + '/grid', + autoLoad: true, + id: 'uuid', + totalProperty: 'total', + fields: fields, + remoteSort: true, + pruneModifiedRecords: true, + sortInfo: sort + }); + + /* Model */ + var sortable = true; + if (conf.move) + sortable = false; + var model = new Ext.grid.ColumnModel({ + defaultSortable: sortable, + columns: columns + }); + + /* Selection */ + var select = new Ext.grid.RowSelectionModel({ + singleSelect: false + }); + + /* Event handlers */ + store.on('update', function(s, r, o) { + var d = (s.getModifiedRecords().length === 0); + undoBtn.setDisabled(d); + saveBtn.setDisabled(d); + }); + select.on('selectionchange', function(s) { + if (delBtn) + delBtn.setDisabled(s.getCount() === 0); + if (upBtn) { + upBtn.setDisabled(s.getCount() === 0); + downBtn.setDisabled(s.getCount() === 0); + } + editBtn.setDisabled(s.getCount() !== 1); + if (conf.selected) + conf.selected(s); + }); + + /* Top bar */ + saveBtn = new Ext.Toolbar.Button({ + tooltip: 'Save pending changes (marked with red border)', + iconCls: 'save', + text: 'Save', + disabled: true, + handler: function() { + var mr = store.getModifiedRecords(); + var out = new Array(); + for (var x = 0; x < mr.length; x++) { + v = mr[x].getChanges(); + out[x] = v; + out[x].uuid = mr[x].id; + } + Ext.Ajax.request({ + url: 'api/idnode/save', + params: { + node: Ext.encode(out) + }, + success: function(d) + { + if (!auto.getValue()) + store.reload(); + } }); - c.win = w; - w.show(); - } + } + }); + buttons.push(saveBtn); + undoBtn = new Ext.Toolbar.Button({ + tooltip: 'Revert pending changes (marked with red border)', + iconCls: 'undo', + text: 'Undo', + disabled: true, + handler: function() { + store.rejectChanges(); + } + }); + buttons.push(undoBtn); + buttons.push('-'); + if (conf.add) { + addBtn = new Ext.Toolbar.Button({ + tooltip: 'Add a new entry', + iconCls: 'add', + text: 'Add', + disabled: false, + handler: function() { + tvheadend.idnode_create(conf.add); + } }); - } + buttons.push(addBtn); } - } - }); - buttons.push(editBtn); + if (conf.del) { + delBtn = new Ext.Toolbar.Button({ + tooltip: 'Delete selected entries', + iconCls: 'remove', + text: 'Delete', + disabled: true, + handler: function() { + var r = select.getSelections(); + if (r && r.length > 0) { + var uuids = []; + for (var i = 0; i < r.length; i++) + uuids.push(r[i].id); + Ext.Ajax.request({ + url: 'api/idnode/delete', + params: { + uuid: Ext.encode(uuids) + }, + success: function(d) + { + if (!auto.getValue()) + store.reload(); + } + }); + } + } + }); + buttons.push(delBtn); + } + if (conf.move) { + upBtn = new Ext.Toolbar.Button({ + tooltip: 'Move selected entries up', + iconCls: 'moveup', + text: 'Move Up', + disabled: true, + handler: function() { + var r = select.getSelections(); + if (r && r.length > 0) { + var uuids = []; + for (var i = 0; i < r.length; i++) + uuids.push(r[i].id); + Ext.Ajax.request({ + url: 'api/idnode/moveup', + params: { + uuid: Ext.encode(uuids) + }, + success: function(d) + { + store.reload(); + } + }); + } + } + }); + buttons.push(upBtn); + downBtn = new Ext.Toolbar.Button({ + tooltip: 'Move selected entries down', + iconCls: 'movedown', + text: 'Move Down', + disabled: true, + handler: function() { + var r = select.getSelections(); + if (r && r.length > 0) { + var uuids = []; + for (var i = 0; i < r.length; i++) + uuids.push(r[i].id); + Ext.Ajax.request({ + url: 'api/idnode/movedown', + params: { + uuid: Ext.encode(uuids) + }, + success: function(d) + { + store.reload(); + } + }); + } + } + }); + buttons.push(downBtn); + } + if (conf.add || conf.del || conf.move) + buttons.push('-'); + editBtn = new Ext.Toolbar.Button({ + tooltip: 'Edit selected entry', + iconCls: 'edit', + text: 'Edit', + disabled: true, + handler: function() { + var r = select.getSelected(); + if (r) { + if (conf.edittree) { + var p = tvheadend.idnode_tree({ + url: 'api/idnode/tree', + params: { + root: r.id + } + }); + p.setSize(800, 600); + var w = new Ext.Window({ + title: 'Edit ' + conf.titleS, + layout: 'fit', + autoWidth: true, + autoHeight: true, + plain: true, + items: p + }); + w.show(); + } else { + Ext.Ajax.request({ + url: 'api/idnode/load', + params: { + uuid: r.id + }, + success: function(d) + { + d = json_decode(d); + var w = null; + var c = {win: w}; + var p = tvheadend.idnode_editor(d[0], c); + w = new Ext.Window({ + title: 'Edit ' + conf.titleS, + layout: 'fit', + autoWidth: true, + autoHeight: true, + plain: true, + items: p + }); + c.win = w; + w.show(); + } + }); + } + } + } + }); + buttons.push(editBtn); - /* Hide Mode */ - if (conf.hidemode) { - var hidemode = new Ext.form.ComboBox({ - width : 100, - displayField : 'val', - valueField : 'key', - store : new Ext.data.ArrayStore({ - id : 0, - fields : [ 'key', 'val' ], - data : [ ['default', 'Parent disabled'], - ['all', 'All' ], - ['none', 'None' ] ], - }), - value : 'default', - mode : 'local', - forceSelection : false, - triggerAction : 'all', - listeners : { - select : function (s, r) { - store.baseParams.hidemode = r.id; + /* Hide Mode */ + if (conf.hidemode) { + var hidemode = new Ext.form.ComboBox({ + width: 100, + displayField: 'val', + valueField: 'key', + store: new Ext.data.ArrayStore({ + id: 0, + fields: ['key', 'val'], + data: [['default', 'Parent disabled'], + ['all', 'All'], + ['none', 'None']] + }), + value: 'default', + mode: 'local', + forceSelection: false, + triggerAction: 'all', + listeners: { + select: function(s, r) { + store.baseParams.hidemode = r.id; + page.changePage(0); + store.reload(); + } + } + }); + buttons.push('-'); + buttons.push('Hide:'); + buttons.push(hidemode); + } + var page = new Ext.PagingToolbar({ + store: store, + pageSize: 50, + displayInfo: true, + displayMsg: conf.titleP + ' {0} - {1} of {2}', + width: 50 + }); + + /* Extra buttons */ + if (conf.tbar) { + buttons.push('-'); + for (i = 0; i < conf.tbar.length; i++) { + if (conf.tbar[i].callback) { + conf.tbar[i].handler = function(b, e) { + this.callback(this, e, store, select); + }; + } + buttons.push(conf.tbar[i]); + } + } + + /* Help */ + if (conf.help) { + buttons.push('->'); + buttons.push({ + text: 'Help', + handler: conf.help + }); + } + + /* Grid Panel */ + var auto = new Ext.form.Checkbox({ + checked: true, + listeners: { + check: function(s, c) { + if (c) + store.reload(); + } + } + }); + var count = new Ext.form.ComboBox({ + width: 50, + displayField: 'val', + valueField: 'key', + store: new Ext.data.ArrayStore({ + id: 0, + fields: ['key', 'val'], + data: [[25, '25'], [50, '50'], [100, '100'], + [200, '200'], [9999999999, 'All']] + }), + value: 50, + mode: 'local', + forceSelection: false, + triggerAction: 'all', + listeners: { + select: function(s, r) { + if (r !== page.pageSize) { + page.pageSize = r.id; + page.changePage(0); + store.reload(); + // TODO: currently setting pageSize=-1 to disable paging confuses + // the UI elements, and I don't know how to sort that! + } + } + } + }); + var page = new Ext.PagingToolbar({ + store: store, + pageSize: 50, + displayInfo: true, + displayMsg: conf.titleP + ' {0} - {1} of {2}', + emptyMsg: 'No ' + conf.titleP.toLowerCase() + ' to display', + items: ['-', 'Auto-refresh', auto, + '->', '-', 'Per page', count] + }); + plugins.push(filter); + var grid = new Ext.grid.EditorGridPanel({ + stateful: true, + stateId: conf.url, + stripeRows: true, + title: conf.titleP, + store: store, + cm: model, + selModel: select, + plugins: plugins, + viewConfig: { + forceFit: true + }, + tbar: buttons, + bbar: page + }); + grid.on('filterupdate', function() { page.changePage(0); - store.reload(); - } - } - }); - buttons.push('-'); - buttons.push('Hide:'); - buttons.push(hidemode); - } - var page = new Ext.PagingToolbar({ - store : store, - pageSize : 50, - displayInfo : true, - displayMsg : conf.titleP + ' {0} - {1} of {2}', - width : 50, - }); + }); - /* Extra buttons */ - if (conf.tbar) { - buttons.push('-') - for (i = 0; i < conf.tbar.length; i++) { - if (conf.tbar[i].callback) { - conf.tbar[i].handler = function (b, e) { - this.callback(this, e, store, select); - } - } - buttons.push(conf.tbar[i]) - } + if (conf.tabIndex != null) + panel.insert(conf.tabIndex, grid); + else + panel.add(grid); + + /* Add comet listeners */ + var update = function(o) { + if (auto.getValue()) + store.reload(); + }; + if (conf.comet) + tvheadend.comet.on(conf.comet, update); + tvheadend.comet.on('idnodeUpdated', update); + tvheadend.comet.on('idnodeDeleted', update); } - /* Help */ - if (conf.help) { - buttons.push('->'); - buttons.push({ - text : 'Help', - handler : conf.help - }); + /* Request data */ + if (!conf.fields) { + Ext.Ajax.request({ + url: conf.url + '/class', + success: function(d) + { + var d = json_decode(d); + build(d); + } + }); + } else { + build(conf.fields); } +}; - /* Grid Panel */ - var auto = new Ext.form.Checkbox({ - checked : true, - listeners : { - check : function ( s, c ) { - if (c) store.reload(); - } - } - }); - var count = new Ext.form.ComboBox({ - width : 50, - displayField : 'val', - valueField : 'key', - store : new Ext.data.ArrayStore({ - id : 0, - fields : [ 'key', 'val' ], - data : [[25, '25'], [50, '50'], [100, '100'], - [200, '200'], [9999999999, 'All']] - }), - value : 50, - mode : 'local', - forceSelection : false, - triggerAction : 'all', - listeners : { - select : function (s, r) { - if (r != page.pageSize) { - page.pageSize = r.id; - page.changePage(0); - store.reload(); - // TODO: currently setting pageSize=-1 to disable paging confuses - // the UI elements, and I don't know how to sort that! - } - } - } - }); - var page = new Ext.PagingToolbar({ - store : store, - pageSize : 50, - displayInfo : true, - displayMsg : conf.titleP + ' {0} - {1} of {2}', - emptyMsg : 'No ' + conf.titleP.toLowerCase() + ' to display', - items : [ '-', 'Auto-refresh', auto, - '->', '-', 'Per page', count ] - }); - plugins.push(filter); - var grid = new Ext.grid.EditorGridPanel({ - stateful : true, - stateId : conf.url, - stripeRows : true, - title : conf.titleP, - store : store, - cm : model, - selModel : select, - plugins : plugins, - viewConfig : { - forceFit : true - }, - tbar : buttons, - bbar : page - }); - grid.on('filterupdate', function() { - page.changePage(0); - }); - - if (conf.tabIndex != null) - panel.insert(conf.tabIndex, grid); - else - panel.add(grid); - - /* Add comet listeners */ - var update = function(o) { - if (auto.getValue()) - store.reload(); - }; - if (conf.comet) - tvheadend.comet.on(conf.comet, update); - tvheadend.comet.on('idnodeUpdated', update); - tvheadend.comet.on('idnodeDeleted', update); - } - - /* Request data */ - if (!conf.fields) { - Ext.Ajax.request({ - url : conf.url + '/class', - success : function(d) - { - var d = json_decode(d); - build(d); - } - }); - } else { - build(conf.fields); - } -} - -tvheadend.idnode_tree = function (conf) +tvheadend.idnode_tree = function(conf) { - var current = null; - var params = conf.params || {}; - var loader = new Ext.tree.TreeLoader({ - dataUrl : conf.url, - baseParams : params, - preloadChildren : conf.preload, - nodeParameter : 'uuid' - }); - - var tree = new Ext.tree.TreePanel({ - loader : loader, - flex : 1, - border : false, - animate : false, - root : new Ext.tree.AsyncTreeNode({ - id : conf.root || 'root', - text : conf.title || '' - }), - listeners : { - click: function(n) { - if(current) - panel.remove(current); - if(!n.isRoot) - current = panel.add(new tvheadend.idnode_editor(n.attributes, { - title : 'Parameters', - fixedHeight : true, - help : conf.help || null, - })); - panel.doLayout(); - } - } - }); - - if (conf.comet) { - tvheadend.comet.on(conf.comet, function(o) { - if (o.reload) - tree.getRootNode().reload(); + var current = null; + var params = conf.params || {}; + var loader = new Ext.tree.TreeLoader({ + dataUrl: conf.url, + baseParams: params, + preloadChildren: conf.preload, + nodeParameter: 'uuid' }); - } - // TODO: top-level reload - tvheadend.comet.on('idnodeUpdated', function(o) { - var n = tree.getNodeById(o.uuid); - if (n) { - if (o.text) n.setText(o.text); - tree.getRootNode().reload(); - // cannot get this to properly reload children and maintain state + var tree = new Ext.tree.TreePanel({ + loader: loader, + flex: 1, + border: false, + animate: false, + root: new Ext.tree.AsyncTreeNode({ + id: conf.root || 'root', + text: conf.title || '' + }), + listeners: { + click: function(n) { + if (current) + panel.remove(current); + if (!n.isRoot) + current = panel.add(new tvheadend.idnode_editor(n.attributes, { + title: 'Parameters', + fixedHeight: true, + help: conf.help || null + })); + panel.doLayout(); + } + } + }); + + if (conf.comet) { + tvheadend.comet.on(conf.comet, function(o) { + if (o.reload) + tree.getRootNode().reload(); + }); } - }); - var panel = new Ext.Panel({ - title : conf.title || '', - layout : 'hbox', - flex : 1, - padding : 5, - border : false, - layoutConfig : { - align : 'stretch' - }, - items: [ tree ] - }); + // TODO: top-level reload + tvheadend.comet.on('idnodeUpdated', function(o) { + var n = tree.getNodeById(o.uuid); + if (n) { + if (o.text) + n.setText(o.text); + tree.getRootNode().reload(); + // cannot get this to properly reload children and maintain state + } + }); + + var panel = new Ext.Panel({ + title: conf.title || '', + layout: 'hbox', + flex: 1, + padding: 5, + border: false, + layoutConfig: { + align: 'stretch' + }, + items: [tree] + }); - tree.on('beforerender', function() { - // To be honest this isn't quite right, but it'll do - tree.expandAll(); - }); + tree.on('beforerender', function() { + // To be honest this isn't quite right, but it'll do + tree.expandAll(); + }); - return panel; -} + return panel; +}; diff --git a/src/webui/static/app/iptv.js b/src/webui/static/app/iptv.js index d5fc6e19..83609b35 100644 --- a/src/webui/static/app/iptv.js +++ b/src/webui/static/app/iptv.js @@ -3,316 +3,316 @@ */ tvheadend.iptv = function(adapterId) { - var servicetypeStore = new Ext.data.JsonStore({ - root : 'entries', - id : 'val', - url : '/iptv/services', - baseParams : { - op : 'servicetypeList' - }, - fields : [ 'val', 'str' ], - autoLoad : false, - sortInfo : { - field : 'channelname', - direction : 'ASC' - } - }); + var servicetypeStore = new Ext.data.JsonStore({ + root: 'entries', + id: 'val', + url: '/iptv/services', + baseParams: { + op: 'servicetypeList' + }, + fields: ['val', 'str'], + autoLoad: false, + sortInfo: { + field: 'channelname', + direction: 'ASC' + } + }); - var fm = Ext.form; + var fm = Ext.form; - var actions = new Ext.ux.grid.RowActions({ - header : '', - dataIndex : 'actions', - width : 45, - actions : [ { - iconCls : 'info', - qtip : 'Detailed information about service', - cb : function(grid, record, action, row, col) { - Ext.Ajax.request({ - url : "servicedetails/" + record.id, - success : function(response, options) { - r = Ext.util.JSON.decode(response.responseText); - tvheadend.showTransportDetails(r); - } - }) - } - } ] - }); + var actions = new Ext.ux.grid.RowActions({ + header: '', + dataIndex: 'actions', + width: 45, + actions: [{ + iconCls: 'info', + qtip: 'Detailed information about service', + cb: function(grid, record, action, row, col) { + Ext.Ajax.request({ + url: "servicedetails/" + record.id, + success: function(response, options) { + r = Ext.util.JSON.decode(response.responseText); + tvheadend.showTransportDetails(r); + } + }); + } + }] + }); - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns : [ - { - xtype: 'checkcolumn', - header : "Enabled", - dataIndex : 'enabled', - width : 45 - }, - { - header : "Channel name", - dataIndex : 'channelname', - width : 150, - renderer : function(value, metadata, record, row, col, store) { - return value ? value - : 'Unmapped'; - }, - editor : new fm.ComboBox({ - store : tvheadend.channels, - allowBlank : true, - typeAhead : true, - minChars : 2, - lazyRender : true, - triggerAction : 'all', - mode : 'local', - displayField : 'name' - }) - }, - { - header : "Interface", - dataIndex : 'interface', - width : 100, - renderer : function(value, metadata, record, row, col, store) { - return value ? value : 'Unset'; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, - { - header : "Group", - dataIndex : 'group', - width : 100, - renderer : function(value, metadata, record, row, col, store) { - return value ? value : 'Unset'; - }, - editor : new fm.TextField({ - allowBlank : false - }) - }, - { - header : "UDP Port", - dataIndex : 'port', - width : 60, - editor : new fm.NumberField({ - minValue : 1, - maxValue : 65535 - }) - }, - { - header : "Service ID", - dataIndex : 'sid', - width : 50, - hidden : true - }, - { - header : 'Service Type', - width : 100, - dataIndex : 'stype', - hidden : true, - editor : new fm.ComboBox({ - valueField : 'val', - displayField : 'str', - forceSelection : false, - editable : false, - mode : 'local', - triggerAction : 'all', - store : servicetypeStore - }), - renderer : function(value, metadata, record, row, col, store) { - var val = value ? servicetypeStore.getById(value) : null; - return val ? val.get('str') - : 'Unset'; - } - }, { - header : "PMT PID", - dataIndex : 'pmt', - width : 50, - hidden : true - }, { - header : "PCR PID", - dataIndex : 'pcr', - width : 50, - hidden : true - }, actions ]}); + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [ + { + xtype: 'checkcolumn', + header: "Enabled", + dataIndex: 'enabled', + width: 45 + }, + { + header: "Channel name", + dataIndex: 'channelname', + width: 150, + renderer: function(value, metadata, record, row, col, store) { + return value ? value + : 'Unmapped'; + }, + editor: new fm.ComboBox({ + store: tvheadend.channels, + allowBlank: true, + typeAhead: true, + minChars: 2, + lazyRender: true, + triggerAction: 'all', + mode: 'local', + displayField: 'name' + }) + }, + { + header: "Interface", + dataIndex: 'interface', + width: 100, + renderer: function(value, metadata, record, row, col, store) { + return value ? value : 'Unset'; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, + { + header: "Group", + dataIndex: 'group', + width: 100, + renderer: function(value, metadata, record, row, col, store) { + return value ? value : 'Unset'; + }, + editor: new fm.TextField({ + allowBlank: false + }) + }, + { + header: "UDP Port", + dataIndex: 'port', + width: 60, + editor: new fm.NumberField({ + minValue: 1, + maxValue: 65535 + }) + }, + { + header: "Service ID", + dataIndex: 'sid', + width: 50, + hidden: true + }, + { + header: 'Service Type', + width: 100, + dataIndex: 'stype', + hidden: true, + editor: new fm.ComboBox({ + valueField: 'val', + displayField: 'str', + forceSelection: false, + editable: false, + mode: 'local', + triggerAction: 'all', + store: servicetypeStore + }), + renderer: function(value, metadata, record, row, col, store) { + var val = value ? servicetypeStore.getById(value) : null; + return val ? val.get('str') + : 'Unset'; + } + }, { + header: "PMT PID", + dataIndex: 'pmt', + width: 50, + hidden: true + }, { + header: "PCR PID", + dataIndex: 'pcr', + width: 50, + hidden: true + }, actions]}); - var rec = Ext.data.Record.create([ 'id', 'enabled', 'channelname', - 'interface', 'group', 'port', 'sid', 'pmt', 'pcr', 'stype' ]); + var rec = Ext.data.Record.create(['id', 'enabled', 'channelname', + 'interface', 'group', 'port', 'sid', 'pmt', 'pcr', 'stype']); - var store = new Ext.data.JsonStore({ - root : 'entries', - fields : rec, - url : "iptv/services", - autoLoad : true, - id : 'id', - baseParams : { - op : "get" - }, - listeners : { - 'update' : function(s, r, o) { - d = s.getModifiedRecords().length == 0 - saveBtn.setDisabled(d); - rejectBtn.setDisabled(d); - } - } - }); + var store = new Ext.data.JsonStore({ + root: 'entries', + fields: rec, + url: "iptv/services", + autoLoad: true, + id: 'id', + baseParams: { + op: "get" + }, + listeners: { + 'update': function(s, r, o) { + d = s.getModifiedRecords().length === 0 + saveBtn.setDisabled(d); + rejectBtn.setDisabled(d); + } + } + }); - /* - var storeReloader = new Ext.util.DelayedTask(function() { - store.reload() - }); + /* + var storeReloader = new Ext.util.DelayedTask(function() { + store.reload() + }); + + tvheadend.comet.on('dvbService', function(m) { + storeReloader.delay(500); + }); + */ - tvheadend.comet.on('dvbService', function(m) { - storeReloader.delay(500); - }); - */ + function addRecord() { + Ext.Ajax.request({ + url: "iptv/services", + params: { + op: "create" + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', + 'Unable to generate new record'); + }, + success: function(response, options) { + var responseData = Ext.util.JSON.decode(response.responseText); + var p = new rec(responseData, responseData.id); + grid.stopEditing(); + store.insert(0, p); + grid.startEditing(0, 0); + } + }); + } + ; - function addRecord() { - Ext.Ajax.request({ - url : "iptv/services", - params : { - op : "create" - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', - 'Unable to generate new record'); - }, - success : function(response, options) { - var responseData = Ext.util.JSON.decode(response.responseText); - var p = new rec(responseData, responseData.id); - grid.stopEditing(); - store.insert(0, p); - grid.startEditing(0, 0); - } - }) - } - ; + function delSelected() { + var selectedKeys = grid.selModel.selections.keys; + if (selectedKeys.length > 0) { + Ext.MessageBox.confirm('Message', + 'Do you really want to delete selection?', deleteRecord); + } + else { + Ext.MessageBox.alert('Message', + 'Please select at least one item to delete'); + } + } + ; - function delSelected() { - var selectedKeys = grid.selModel.selections.keys; - if (selectedKeys.length > 0) { - Ext.MessageBox.confirm('Message', - 'Do you really want to delete selection?', deleteRecord); - } - else { - Ext.MessageBox.alert('Message', - 'Please select at least one item to delete'); - } - } - ; + function deleteRecord(btn) { + if (btn === 'yes') { + var selectedKeys = grid.selModel.selections.keys; - function deleteRecord(btn) { - if (btn == 'yes') { - var selectedKeys = grid.selModel.selections.keys; + Ext.Ajax.request({ + url: "iptv/services", + params: { + op: "delete", + entries: Ext.encode(selectedKeys) + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', 'Unable to delete'); + }, + success: function(response, options) { + store.reload(); + } + }); + } + } - Ext.Ajax.request({ - url : "iptv/services", - params : { - op : "delete", - entries : Ext.encode(selectedKeys) - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', 'Unable to delete'); - }, - success : function(response, options) { - store.reload(); - } - }) - } - } + function saveChanges() { + var mr = store.getModifiedRecords(); + var out = new Array(); + for (var x = 0; x < mr.length; x++) { + v = mr[x].getChanges(); + out[x] = v; + out[x].id = mr[x].id; + } - function saveChanges() { - var mr = store.getModifiedRecords(); - var out = new Array(); - for ( var x = 0; x < mr.length; x++) { - v = mr[x].getChanges(); - out[x] = v; - out[x].id = mr[x].id; - } + Ext.Ajax.request({ + url: "iptv/services", + params: { + op: "update", + entries: Ext.encode(out) + }, + success: function(response, options) { + store.commitChanges(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('Message', response.statusText); + } + }); + } - Ext.Ajax.request({ - url : "iptv/services", - params : { - op : "update", - entries : Ext.encode(out) - }, - success : function(response, options) { - store.commitChanges(); - }, - failure : function(response, options) { - Ext.MessageBox.alert('Message', response.statusText); - } - }); - } + var delButton = new Ext.Toolbar.Button({ + tooltip: 'Delete one or more selected rows', + iconCls: 'remove', + text: 'Delete selected services', + handler: delSelected, + disabled: true + }); - var delButton = new Ext.Toolbar.Button({ - tooltip : 'Delete one or more selected rows', - iconCls : 'remove', - text : 'Delete selected services', - handler : delSelected, - disabled : true - }); + var saveBtn = new Ext.Toolbar.Button({ + tooltip: 'Save any changes made (Changed cells have red borders).', + iconCls: 'save', + text: "Save changes", + handler: saveChanges, + disabled: true + }); - var saveBtn = new Ext.Toolbar.Button({ - tooltip : 'Save any changes made (Changed cells have red borders).', - iconCls : 'save', - text : "Save changes", - handler : saveChanges, - disabled : true - }); + var rejectBtn = new Ext.Toolbar.Button({ + tooltip: 'Revert any changes made (Changed cells have red borders).', + iconCls: 'undo', + text: "Revert changes", + handler: function() { + store.rejectChanges(); + }, + disabled: true + }); - var rejectBtn = new Ext.Toolbar.Button({ - tooltip : 'Revert any changes made (Changed cells have red borders).', - iconCls : 'undo', - text : "Revert changes", - handler : function() { - store.rejectChanges(); - }, - disabled : true - }); + var selModel = new Ext.grid.RowSelectionModel({ + singleSelect: false + }); - var selModel = new Ext.grid.RowSelectionModel({ - singleSelect : false - }); + var grid = new Ext.grid.EditorGridPanel({ + stripeRows: true, + title: 'IPTV', + iconCls: 'iptv', + plugins: [actions], + store: store, + clicksToEdit: 2, + cm: cm, + viewConfig: { + forceFit: true + }, + selModel: selModel, + tbar: [ + { + tooltip: 'Create a new entry on the server. ' + + 'The new entry is initially disabled so it must be enabled ' + + 'before it start taking effect.', + iconCls: 'add', + text: 'Add service', + handler: addRecord + }, '-', delButton, '-', saveBtn, rejectBtn, '->', + { + text: 'Help', + handler: function() { + new tvheadend.help('IPTV', 'config_iptv.html'); + } + }] + }); - var grid = new Ext.grid.EditorGridPanel({ - stripeRows : true, - title : 'IPTV', - iconCls : 'iptv', - plugins : [ actions ], - store : store, - clicksToEdit : 2, - cm : cm, - viewConfig : { - forceFit : true - }, - selModel : selModel, - tbar : [ - { - tooltip : 'Create a new entry on the server. ' - + 'The new entry is initially disabled so it must be enabled ' - + 'before it start taking effect.', - iconCls : 'add', - text : 'Add service', - handler : addRecord - }, '-', delButton, '-', saveBtn, rejectBtn, '->', - { - text : 'Help', - handler : function() { - new tvheadend.help('IPTV', 'config_iptv.html'); - } - } ] - }); + store.on('update', function(s, r, o) { + d = s.getModifiedRecords().length === 0; + saveBtn.setDisabled(d); + rejectBtn.setDisabled(d); + }); - store.on('update', function(s, r, o) { - d = s.getModifiedRecords().length == 0 - saveBtn.setDisabled(d); - rejectBtn.setDisabled(d); - }); + selModel.on('selectionchange', function(self) { + delButton.setDisabled(self.getCount() === 0); + }); - selModel.on('selectionchange', function(self) { - delButton.setDisabled(self.getCount() == 0); - }); - - return grid; -} + return grid; +}; diff --git a/src/webui/static/app/mpegts.js b/src/webui/static/app/mpegts.js index 3249bbec..920ccd3e 100644 --- a/src/webui/static/app/mpegts.js +++ b/src/webui/static/app/mpegts.js @@ -3,270 +3,271 @@ */ tvheadend.network_builders = new Ext.data.JsonStore({ - url : 'api/mpegts/network/builders', - root : 'entries', - fields : [ 'class', 'caption', 'props' ], - id : 'class', - autoLoad : true, + url: 'api/mpegts/network/builders', + root: 'entries', + fields: ['class', 'caption', 'props'], + id: 'class', + autoLoad: true }); tvheadend.network_list = new Ext.data.JsonStore({ - url : 'api/idnode/load', - baseParams : { class : 'mpegts_network', enum: 1 }, - root : 'entries', - fields : [ 'key', 'val' ], - id : 'key', - autoLoad : true, + url: 'api/idnode/load', + baseParams: {class: 'mpegts_network', enum: 1}, + root: 'entries', + fields: ['key', 'val'], + id: 'key', + autoLoad: true }); tvheadend.comet.on('mpegts_network', function() { - // TODO: Might be a bit excessive - tvheadend.network_builders.reload(); - tvheadend.network_list.reload(); + // TODO: Might be a bit excessive + tvheadend.network_builders.reload(); + tvheadend.network_list.reload(); }); tvheadend.networks = function(panel) { - tvheadend.idnode_grid(panel, { - url : 'api/mpegts/network', - comet : 'mpegts_network', - titleS : 'Network', - titleP : 'Networks', - tabIndex : 1, - add : { - titleS : 'Network', - select : { - label : 'Type', - store : tvheadend.network_builders, - displayField : 'caption', - valueField : 'class', - propField : 'props', - }, - create : { - url : 'api/mpegts/network/create' - } - }, - del : true, - sort : { - field : 'networkname', - direction : 'ASC' - } - }); -} + tvheadend.idnode_grid(panel, { + url: 'api/mpegts/network', + comet: 'mpegts_network', + titleS: 'Network', + titleP: 'Networks', + tabIndex: 1, + add: { + titleS: 'Network', + select: { + label: 'Type', + store: tvheadend.network_builders, + displayField: 'caption', + valueField: 'class', + propField: 'props' + }, + create: { + url: 'api/mpegts/network/create' + } + }, + del: true, + sort: { + field: 'networkname', + direction: 'ASC' + } + }); +}; tvheadend.muxes = function(panel) { - tvheadend.idnode_grid(panel, { - url : 'api/mpegts/mux', - comet : 'mpegts_mux', - titleS : 'Mux', - titleP : 'Muxes', - tabIndex : 2, - hidemode : true, - add : { - titleS : 'Mux', - select : { - label : 'Network', - store : tvheadend.network_list, - valueField : 'key', - displayField : 'val', - clazz : { - url : 'api/mpegts/network/mux_class' + tvheadend.idnode_grid(panel, { + url: 'api/mpegts/mux', + comet: 'mpegts_mux', + titleS: 'Mux', + titleP: 'Muxes', + tabIndex: 2, + hidemode: true, + add: { + titleS: 'Mux', + select: { + label: 'Network', + store: tvheadend.network_list, + valueField: 'key', + displayField: 'val', + clazz: { + url: 'api/mpegts/network/mux_class' + } + }, + create: { + url: 'api/mpegts/network/mux_create' + } + }, + del: true, + lcol: [ + { + width: 50, + header: 'Play', + renderer: function(v, o, r) { + return "Play"; + } + } + ], + sort: { + field: 'name', + direction: 'ASC' } - }, - create : { - url : 'api/mpegts/network/mux_create', - } - }, - del : true, - lcol : [ - { - width : 50, - header : 'Play', - renderer : function(v, o, r) { - return "Play"; + }); +}; + +tvheadend.show_service_streams = function(data) { + var i, j; + var html = ''; + + function hexstr(d) { + return ('0000' + d.toString(16)).slice(-4); + } + + function hexstr6(d) { + return ('000000' + d.toString(16)).slice(-6); + } + + function fixstr(d) { + var r = d.toString(); + var l = r.length; + var i; + for (i = l; i < 5; i++) { + r = ' ' + r; } - } - ], - sort : { - field : 'name', - direction : 'ASC' + return r; } - }); -} -tvheadend.show_service_streams = function ( data ) { - var i, j; - var html = ''; + function header( ) { + html += ''; - } - - function stream ( s ) { - var d = ' '; - var p = '0x' + hexstr(s.pid) + ' / ' + fixstr(s.pid); - - html += ''; - html += ''; - html += ''; - html += ''; - html += '' - if (s.type == 'CA') { - d = 'CAIDS: '; - for (j = 0; j < s.caids.length; j++) { - if (j > 0) d += ', '; - d += hexstr(s.caids[j].caid) + ':'; - d += hexstr6(s.caids[j].provider); - } + function single(s) { + html += ''; } - html += ''; - html += ''; - } - header(); + function stream(s) { + var d = ' '; + var p = '0x' + hexstr(s.pid) + ' / ' + fixstr(s.pid); - if (data.streams.length) { - for (i = 0; i < data.streams.length; i++) - stream(data.streams[i]); - } else - single('None'); + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + if (s.type === 'CA') { + d = 'CAIDS: '; + for (j = 0; j < s.caids.length; j++) { + if (j > 0) + d += ', '; + d += hexstr(s.caids[j].caid) + ':'; + d += hexstr6(s.caids[j].provider); + } + } + html += ''; + html += ''; + } - single(' '); - single('

After filtering and reordering (without PCR and PMT)

'); - header(); + header(); - if (data.fstreams.length) - for (i = 0; i < data.fstreams.length; i++) - stream(data.fstreams[i]); - else - single('

None

'); + if (data.streams.length) { + for (i = 0; i < data.streams.length; i++) + stream(data.streams[i]); + } else + single('None'); - var win = new Ext.Window({ - title : 'Service details for ' + data.name, - layout : 'fit', - width : 650, - height : 400, - plain : true, - bodyStyle : 'padding: 5px', - html : html, - autoScroll: true, - autoShow: true - }); - win.show(); -} + single(' '); + single('

After filtering and reordering (without PCR and PMT)

'); + header(); + + if (data.fstreams.length) + for (i = 0; i < data.fstreams.length; i++) + stream(data.fstreams[i]); + else + single('

None

'); + + var win = new Ext.Window({ + title: 'Service details for ' + data.name, + layout: 'fit', + width: 650, + height: 400, + plain: true, + bodyStyle: 'padding: 5px', + html: html, + autoScroll: true, + autoShow: true + }); + win.show(); +}; tvheadend.services = function(panel) { - var mapButton = new Ext.Toolbar.Button({ - tooltip : 'Map services to channels', - iconCls : 'clone', - text : 'Map All', - callback : tvheadend.service_mapper, - disabled : false, - }); - var selected = function (s) - { - if (s.getCount() > 0) - mapButton.setText('Map Selected') - else - mapButton.setText('Map All') - } - var actions = new Ext.ux.grid.RowActions({ - header : '', - width : 10, - actions : [ { - iconCls : 'info', - qtip : 'Detailed stream info', - cb : function ( grid, rec, act, row, col ) { - Ext.Ajax.request({ - url : 'api/service/streams', - params : { - uuid : rec.id - }, - success : function (r, o) { - var d = Ext.util.JSON.decode(r.responseText); - tvheadend.show_service_streams(d); - } - }); - } - } ] - }); - tvheadend.idnode_grid(panel, { - url : 'api/mpegts/service', - comet : 'service', - titleS : 'Service', - titleP : 'Services', - tabIndex : 3, - hidemode : true, - add : false, - del : false, - selected : selected, - tbar : [ mapButton ], - lcol : [ - { - width : 50, - header : 'Play', - renderer : function(v, o, r) { - return "Play"; + var mapButton = new Ext.Toolbar.Button({ + tooltip: 'Map services to channels', + iconCls: 'clone', + text: 'Map All', + callback: tvheadend.service_mapper, + disabled: false + }); + var selected = function(s) + { + if (s.getCount() > 0) + mapButton.setText('Map Selected'); + else + mapButton.setText('Map All'); + }; + var actions = new Ext.ux.grid.RowActions({ + header: '', + width: 10, + actions: [{ + iconCls: 'info', + qtip: 'Detailed stream info', + cb: function(grid, rec, act, row, col) { + Ext.Ajax.request({ + url: 'api/service/streams', + params: { + uuid: rec.id + }, + success: function(r, o) { + var d = Ext.util.JSON.decode(r.responseText); + tvheadend.show_service_streams(d); + } + }); + } + }] + }); + tvheadend.idnode_grid(panel, { + url: 'api/mpegts/service', + comet: 'service', + titleS: 'Service', + titleP: 'Services', + tabIndex: 3, + hidemode: true, + add: false, + del: false, + selected: selected, + tbar: [mapButton], + lcol: [ + { + width: 50, + header: 'Play', + renderer: function(v, o, r) { + return "Play"; + } + }, + actions + ], + plugins: [actions], + sort: { + field: 'svcname', + direction: 'ASC' } - }, - actions - ], - plugins : [ actions ], - sort : { - field : 'svcname', - direction : 'ASC' - } - }); -} + }); +}; tvheadend.mux_sched = function(panel) { - tvheadend.idnode_grid(panel, { - url : 'api/mpegts/mux_sched', - comet : 'mpegts_mux_sched', - titleS : 'Mux Scheduler', - titleP : 'Mux Schedulers', - tabIndex : 4, - hidemode : true, - add : { - url : 'api/mpegts/mux_sched', - titleS : 'Mux Scheduler', - create : { - url : 'api/mpegts/mux_sched/create' - } - }, - del : true - }); -} + tvheadend.idnode_grid(panel, { + url: 'api/mpegts/mux_sched', + comet: 'mpegts_mux_sched', + titleS: 'Mux Scheduler', + titleP: 'Mux Schedulers', + tabIndex: 4, + hidemode: true, + add: { + url: 'api/mpegts/mux_sched', + titleS: 'Mux Scheduler', + create: { + url: 'api/mpegts/mux_sched/create' + } + }, + del: true + }); +}; diff --git a/src/webui/static/app/servicemapper.js b/src/webui/static/app/servicemapper.js index 39e5575a..f4e8873d 100644 --- a/src/webui/static/app/servicemapper.js +++ b/src/webui/static/app/servicemapper.js @@ -4,182 +4,182 @@ tvheadend.service_mapper_status_panel = null; -tvheadend.service_mapper_status = function () +tvheadend.service_mapper_status = function() { - var panel; + var panel; - /* Fields */ - var ok = new Ext.form.Label({ - fieldLabel : 'Mapped', - text : '0' - }); - var fail = new Ext.form.Label({ - fieldLabel : 'Failed', - text : '0' - }); - var ignore = new Ext.form.Label({ - fieldLabel : 'Ignored', - text : '0' - }); - var active = new Ext.form.Label({ - width : 200, - fieldLabel : 'Active', - text : '' - }); - var prog = new Ext.ProgressBar({ - text : '0 / 0' - }); + /* Fields */ + var ok = new Ext.form.Label({ + fieldLabel: 'Mapped', + text: '0' + }); + var fail = new Ext.form.Label({ + fieldLabel: 'Failed', + text: '0' + }); + var ignore = new Ext.form.Label({ + fieldLabel: 'Ignored', + text: '0' + }); + var active = new Ext.form.Label({ + width: 200, + fieldLabel: 'Active', + text: '' + }); + var prog = new Ext.ProgressBar({ + text: '0 / 0' + }); - /* Panel */ - panel = new Ext.FormPanel({ - method : 'get', - title : 'Service Mapper', - frame : true, - border : true, - bodyStyle : 'padding: 5px', - labelAlign : 'left', - labelWidth : 200, - width : 400, - autoHeight : true, - defaultType : 'textfield', - buttonAlign : 'left', - items : [ ok, ignore, fail, active, prog ] - }); + /* Panel */ + panel = new Ext.FormPanel({ + method: 'get', + title: 'Service Mapper', + frame: true, + border: true, + bodyStyle: 'padding: 5px', + labelAlign: 'left', + labelWidth: 200, + width: 400, + autoHeight: true, + defaultType: 'textfield', + buttonAlign: 'left', + items: [ok, ignore, fail, active, prog] + }); - /* Comet */ - tvheadend.comet.on('servicemapper', function(m) { - var n = m.ok + m.ignore + m.fail; - ok.setText('' + m.ok); - ignore.setText('' + m.ignore); - fail.setText('' + m.fail); - active.setText(''); - prog.updateProgress(n / m.total, '' + n + ' / ' + m.total); + /* Comet */ + tvheadend.comet.on('servicemapper', function(m) { + var n = m.ok + m.ignore + m.fail; + ok.setText('' + m.ok); + ignore.setText('' + m.ignore); + fail.setText('' + m.fail); + active.setText(''); + prog.updateProgress(n / m.total, '' + n + ' / ' + m.total); - if (m.active) { - Ext.Ajax.request({ - url : 'api/idnode/load', - params : { - uuid : m.active - }, - success : function (d) { - d = Ext.util.JSON.decode(d.responseText); - try { - active.setText(d.entries[0].text); - } catch (e) { - } + if (m.active) { + Ext.Ajax.request({ + url: 'api/idnode/load', + params: { + uuid: m.active + }, + success: function(d) { + d = Ext.util.JSON.decode(d.responseText); + try { + active.setText(d.entries[0].text); + } catch (e) { + } + } + }); } - }); - } - }); + }); - tvheadend.service_mapper_status_panel = panel; - return panel; -} + tvheadend.service_mapper_status_panel = panel; + return panel; +}; /* * Start mapping */ tvheadend.service_mapper = function(t, e, store, select) { - var panel = null; - var win = null; + var panel = null; + var win = null; - /* Form fields */ - var availCheck = new Ext.form.Checkbox({ - name : 'check_availability', - fieldLabel : 'Check availability', - checked : false - }); - var ftaCheck = new Ext.form.Checkbox({ - name : 'encrypted', - fieldLabel : 'Include encrypted services', - checked : false, - // TODO: make dependent on CSA config - }); - var mergeCheck = new Ext.form.Checkbox({ - name : 'merge_same_name', - fieldLabel : 'Merge same name', - checked : false - }); - var provtagCheck = new Ext.form.Checkbox({ - name : 'provider_tags', - fieldLabel : 'Create provider tags', - checked : false - }); + /* Form fields */ + var availCheck = new Ext.form.Checkbox({ + name: 'check_availability', + fieldLabel: 'Check availability', + checked: false + }); + var ftaCheck = new Ext.form.Checkbox({ + name: 'encrypted', + fieldLabel: 'Include encrypted services', + checked: false + // TODO: make dependent on CSA config + }); + var mergeCheck = new Ext.form.Checkbox({ + name: 'merge_same_name', + fieldLabel: 'Merge same name', + checked: false + }); + var provtagCheck = new Ext.form.Checkbox({ + name: 'provider_tags', + fieldLabel: 'Create provider tags', + checked: false + }); - // TODO: provider list - items = [ availCheck, ftaCheck, mergeCheck, provtagCheck ]; + // TODO: provider list + items = [availCheck, ftaCheck, mergeCheck, provtagCheck]; - /* Form */ - var undoBtn = new Ext.Button({ - text : 'Cancel', - handler : function () { - win.close(); - } - }); - - var saveBtn = new Ext.Button({ - text : 'Map', - tooltip : 'Begin mapping', - handler : function () { - p = null; - if (select) { - var r = select.getSelections(); - if (r.length > 0) { - var uuids = []; - for (var i = 0; i < r.length; i++) - uuids.push(r[i].id); - p = { uuids: Ext.encode(uuids) }; + /* Form */ + var undoBtn = new Ext.Button({ + text: 'Cancel', + handler: function() { + win.close(); } - } + }); + + var saveBtn = new Ext.Button({ + text: 'Map', + tooltip: 'Begin mapping', + handler: function() { + p = null; + if (select) { + var r = select.getSelections(); + if (r.length > 0) { + var uuids = []; + for (var i = 0; i < r.length; i++) + uuids.push(r[i].id); + p = {uuids: Ext.encode(uuids)}; + } + } - panel.getForm().submit({ - url : 'api/service/mapper/start', - waitMessage : 'Mapping services...', - params : p - }); + panel.getForm().submit({ + url: 'api/service/mapper/start', + waitMessage: 'Mapping services...', + params: p + }); - win.hide(); + win.hide(); - /* Dialog */ - win = new Ext.Window({ - title : 'Service Mapper Status', - layout : 'fit', - autoWidth : true, - autoHeight : true, - plain : false, - items : tvheadend.service_mapper_status_panel - // TODO: buttons - }); - win.show(); - } - }); + /* Dialog */ + win = new Ext.Window({ + title: 'Service Mapper Status', + layout: 'fit', + autoWidth: true, + autoHeight: true, + plain: false, + items: tvheadend.service_mapper_status_panel + // TODO: buttons + }); + win.show(); + } + }); - panel = new Ext.FormPanel({ - method : 'post', - frame : true, - border : true, - bodyStyle : 'padding: 5px', - labelAlign : 'left', - labelWidth : 200, - autoWidth : true, - autoHeight : true, - defaultType : 'textfield', - buttonAlign : 'left', - items : items, - buttons : [ undoBtn, saveBtn ] - }); - - /* Create window */ - win = new Ext.Window({ - title : 'Map services', - layout : 'fit', - autoWidth : true, - autoHeight : true, - plain : true, - items : panel - }); + panel = new Ext.FormPanel({ + method: 'post', + frame: true, + border: true, + bodyStyle: 'padding: 5px', + labelAlign: 'left', + labelWidth: 200, + autoWidth: true, + autoHeight: true, + defaultType: 'textfield', + buttonAlign: 'left', + items: items, + buttons: [undoBtn, saveBtn] + }); - win.show(); -} + /* Create window */ + win = new Ext.Window({ + title: 'Map services', + layout: 'fit', + autoWidth: true, + autoHeight: true, + plain: true, + items: panel + }); + + win.show(); +}; diff --git a/src/webui/static/app/status.js b/src/webui/static/app/status.js index 546f59bf..80d328f7 100644 --- a/src/webui/static/app/status.js +++ b/src/webui/static/app/status.js @@ -3,147 +3,148 @@ */ tvheadend.status_subs = function() { - tvheadend.subsStore = new Ext.data.JsonStore({ - root : 'entries', - totalProperty : 'totalCount', - fields : [ { - name : 'id' - }, { - name : 'hostname' - }, { - name : 'username' - }, { - name : 'title' - }, { - name : 'channel' - }, { - name : 'service' - }, { - name : 'state' - }, { - name : 'errors' - }, { - name : 'in' - }, { - name : 'out' - }, { - name : 'start', - type : 'date', - dateFormat : 'U' /* unix time */ - } ], - url : 'api/status/subscriptions', - autoLoad : true, - id : 'id' - }); + tvheadend.subsStore = new Ext.data.JsonStore({ + root: 'entries', + totalProperty: 'totalCount', + fields: [{ + name: 'id' + }, { + name: 'hostname' + }, { + name: 'username' + }, { + name: 'title' + }, { + name: 'channel' + }, { + name: 'service' + }, { + name: 'state' + }, { + name: 'errors' + }, { + name: 'in' + }, { + name: 'out' + }, { + name: 'start', + type: 'date', + dateFormat: 'U' /* unix time */ + }], + url: 'api/status/subscriptions', + autoLoad: true, + id: 'id' + }); - tvheadend.comet.on('subscriptions', function(m) { + tvheadend.comet.on('subscriptions', function(m) { - if (m.reload != null) tvheadend.subsStore.reload(); + if (m.reload != null) + tvheadend.subsStore.reload(); - if (m.updateEntry != null) { - r = tvheadend.subsStore.getById(m.id) - if (typeof r === 'undefined') { - tvheadend.subsStore.reload(); - return; - } + if (m.updateEntry != null) { + r = tvheadend.subsStore.getById(m.id); + if (typeof r === 'undefined') { + tvheadend.subsStore.reload(); + return; + } - r.data.channel = m.channel; - r.data.service = m.service; - r.data.state = m.state; - r.data.errors = m.errors; - r.data.in = m.in; - r.data.out = m.out; + r.data.channel = m.channel; + r.data.service = m.service; + r.data.state = m.state; + r.data.errors = m.errors; + r.data.in = m.in; + r.data.out = m.out; - tvheadend.subsStore.afterEdit(r); - tvheadend.subsStore.fireEvent('updated', tvheadend.subsStore, r, - Ext.data.Record.COMMIT); - } - }); + tvheadend.subsStore.afterEdit(r); + tvheadend.subsStore.fireEvent('updated', tvheadend.subsStore, r, + Ext.data.Record.COMMIT); + } + }); - function renderDate(value) { - var dt = new Date(value); - return dt.format('D j M H:i'); - } + function renderDate(value) { + var dt = new Date(value); + return dt.format('D j M H:i'); + } - function renderBw(value, item, store) { - var txt = parseInt(value / 125); - var href = 'javascript:tvheadend.subscription_bw_monitor(' + store.id + ');'; - return '' + txt + ''; - } + function renderBw(value, item, store) { + var txt = parseInt(value / 125); + var href = 'javascript:tvheadend.subscription_bw_monitor(' + store.id + ');'; + return '' + txt + ''; + } - var subsCm = new Ext.grid.ColumnModel([{ - width : 50, - id : 'hostname', - header : "Hostname", - dataIndex : 'hostname' - }, { - width : 50, - id : 'username', - header : "Username", - dataIndex : 'username' - }, { - width : 80, - id : 'title', - header : "Title", - dataIndex : 'title' - }, { - width : 50, - id : 'channel', - header : "Channel", - dataIndex : 'channel' - }, { - width : 200, - id : 'service', - header : "Service", - dataIndex : 'service', - }, { - width : 50, - id : 'start', - header : "Start", - dataIndex : 'start', - renderer : renderDate - }, { - width : 50, - id : 'state', - header : "State", - dataIndex : 'state' - }, { - width : 50, - id : 'errors', - header : "Errors", - dataIndex : 'errors' - }, { - width : 50, - id : 'in', - header : "Input (kb/s)", - dataIndex : 'in', - renderer: renderBw - }, { - width : 50, - id : 'out', - header : "Output (kb/s)", - dataIndex : 'out', - renderer: renderBw - } ]); + var subsCm = new Ext.grid.ColumnModel([{ + width: 50, + id: 'hostname', + header: "Hostname", + dataIndex: 'hostname' + }, { + width: 50, + id: 'username', + header: "Username", + dataIndex: 'username' + }, { + width: 80, + id: 'title', + header: "Title", + dataIndex: 'title' + }, { + width: 50, + id: 'channel', + header: "Channel", + dataIndex: 'channel' + }, { + width: 200, + id: 'service', + header: "Service", + dataIndex: 'service' + }, { + width: 50, + id: 'start', + header: "Start", + dataIndex: 'start', + renderer: renderDate + }, { + width: 50, + id: 'state', + header: "State", + dataIndex: 'state' + }, { + width: 50, + id: 'errors', + header: "Errors", + dataIndex: 'errors' + }, { + width: 50, + id: 'in', + header: "Input (kb/s)", + dataIndex: 'in', + renderer: renderBw + }, { + width: 50, + id: 'out', + header: "Output (kb/s)", + dataIndex: 'out', + renderer: renderBw + }]); - var subs = new Ext.grid.GridPanel({ - border: false, - loadMask : true, - stripeRows : true, - disableSelection : true, - title : 'Subscriptions', - iconCls : 'eye', - store : tvheadend.subsStore, - cm : subsCm, - flex: 1, - viewConfig : { - forceFit : true - } - }); - return subs; -} + var subs = new Ext.grid.GridPanel({ + border: false, + loadMask: true, + stripeRows: true, + disableSelection: true, + title: 'Subscriptions', + iconCls: 'eye', + store: tvheadend.subsStore, + cm: subsCm, + flex: 1, + viewConfig: { + forceFit: true + } + }); + return subs; +}; /** @@ -151,419 +152,421 @@ tvheadend.status_subs = function() { */ tvheadend.status_streams = function() { - tvheadend.streamStatusStore = new Ext.data.JsonStore({ - root : 'entries', - totalProperty : 'totalCount', - fields : [ { - name : 'uuid' - }, { - name : 'input' - }, { - name : 'username' - }, { - name : 'stream' - }, { - name : 'subs' - }, { - name : 'weight' - }, { - name : 'signal' - }, { - name : 'ber' - }, { - name : 'unc' - }, { - name : 'snr' - }, { - name : 'bps' - }, { - name : 'cc' - }, { - name : 'te' - }, - ], - url : 'api/status/inputs', - autoLoad : true, - id : 'uuid' - }); + tvheadend.streamStatusStore = new Ext.data.JsonStore({ + root: 'entries', + totalProperty: 'totalCount', + fields: [{ + name: 'uuid' + }, { + name: 'input' + }, { + name: 'username' + }, { + name: 'stream' + }, { + name: 'subs' + }, { + name: 'weight' + }, { + name: 'signal' + }, { + name: 'ber' + }, { + name: 'unc' + }, { + name: 'snr' + }, { + name: 'bps' + }, { + name: 'cc' + }, { + name: 'te' + } + ], + url: 'api/status/inputs', + autoLoad: true, + id: 'uuid' + }); - tvheadend.comet.on('input_status', function(m){ - if (m.reload != null) tvheadend.streamStatusStore.reload(); - if (m.update != null) { - var r = tvheadend.streamStatusStore.getById(m.uuid); - if (r) { - r.data.subs = m.subs; - r.data.weight = m.weight; - r.data.signal = m.signal; - r.data.ber = m.ber; - r.data.unc = m.unc; - r.data.snr = m.snr; - r.data.bps = m.bps; - r.data.cc = m.cc; - r.data.te = m.te; + tvheadend.comet.on('input_status', function(m) { + if (m.reload != null) + tvheadend.streamStatusStore.reload(); + if (m.update != null) { + var r = tvheadend.streamStatusStore.getById(m.uuid); + if (r) { + r.data.subs = m.subs; + r.data.weight = m.weight; + r.data.signal = m.signal; + r.data.ber = m.ber; + r.data.unc = m.unc; + r.data.snr = m.snr; + r.data.bps = m.bps; + r.data.cc = m.cc; + r.data.te = m.te; - tvheadend.streamStatusStore.afterEdit(r); - tvheadend.streamStatusStore.fireEvent('updated', - tvheadend.streamStatusStore, - r, - Ext.data.Record.COMMIT); - } else { - tvheadend.streamStatusStore.reload(); - } + tvheadend.streamStatusStore.afterEdit(r); + tvheadend.streamStatusStore.fireEvent('updated', + tvheadend.streamStatusStore, + r, + Ext.data.Record.COMMIT); + } else { + tvheadend.streamStatusStore.reload(); + } + } + }); + + var signal = new Ext.ux.grid.ProgressColumn({ + header: "Signal Strength", + dataIndex: 'signal', + width: 85, + textPst: '%', + colored: true + }); + + function renderBw(value, item, store) { + var txt = parseInt(value / 1024); + var href = "javascript:tvheadend.stream_bw_monitor('" + store.id + "');"; + return '' + txt + ''; } - }); - var signal = new Ext.ux.grid.ProgressColumn({ - header : "Signal Strength", - dataIndex : 'signal', - width : 85, - textPst : '%', - colored : true - }); - - function renderBw(value, item, store) { - var txt = parseInt(value / 1024); - var href = "javascript:tvheadend.stream_bw_monitor('" + store.id + "');"; - return '' + txt + ''; - } - - var cm = new Ext.grid.ColumnModel([{ - width : 100, - header : "Input", - dataIndex : 'input' - },{ - width : 100, - header : "Stream", - dataIndex : 'stream' - },{ - width : 50, - header : "Subs #", - dataIndex : 'subs' - },{ - width : 50, - header : "Weight", - dataIndex : 'weight' - },{ - width : 50, - header : "Bandwidth (kb/s)", - dataIndex : 'bps', - renderer: renderBw - },{ - width : 50, - header : "BER", - dataIndex : 'ber' - },{ - width : 50, - header : "Uncorrected BER", - dataIndex : 'unc' - },{ - width : 50, - header : "Transport Error", - dataIndex : 'te' - },{ - width : 50, - header : "Continuity Error", - dataIndex : 'cc' - },{ - width : 50, - header : "SNR", - dataIndex : 'snr', - renderer: function(value) { - if(value > 0) { - return value.toFixed(1) + " dB"; - } else { - return 'Unknown'; - } + var cm = new Ext.grid.ColumnModel([{ + width: 100, + header: "Input", + dataIndex: 'input' + }, { + width: 100, + header: "Stream", + dataIndex: 'stream' + }, { + width: 50, + header: "Subs #", + dataIndex: 'subs' + }, { + width: 50, + header: "Weight", + dataIndex: 'weight' + }, { + width: 50, + header: "Bandwidth (kb/s)", + dataIndex: 'bps', + renderer: renderBw + }, { + width: 50, + header: "BER", + dataIndex: 'ber' + }, { + width: 50, + header: "Uncorrected BER", + dataIndex: 'unc' + }, { + width: 50, + header: "Transport Error", + dataIndex: 'te' + }, { + width: 50, + header: "Continuity Error", + dataIndex: 'cc' + }, { + width: 50, + header: "SNR", + dataIndex: 'snr', + renderer: function(value) { + if (value > 0) { + return value.toFixed(1) + " dB"; + } else { + return 'Unknown'; } + } }, signal]); - var panel = new Ext.grid.GridPanel({ - border: false, - loadMask : true, - stripeRows : true, - disableSelection : true, - title : 'Stream', - iconCls : 'hardware', - store : tvheadend.streamStatusStore, - cm : cm, - flex: 1, - viewConfig : { - forceFit : true - } - }); - return panel; -} + var panel = new Ext.grid.GridPanel({ + border: false, + loadMask: true, + stripeRows: true, + disableSelection: true, + title: 'Stream', + iconCls: 'hardware', + store: tvheadend.streamStatusStore, + cm: cm, + flex: 1, + viewConfig: { + forceFit: true + } + }); + return panel; +}; /** * */ tvheadend.status_conns = function() { - var store = new Ext.data.JsonStore({ - root : 'entries', - totalProperty : 'totalCount', - fields : [ { - name : 'id' - }, { - name : 'type' - }, { - name : 'peer' - }, { - name : 'user' - }, { - name : 'started', - type : 'date', - dateFormat : 'U' /* unix time */ - } ], - url : 'api/status/connections', - autoLoad : true, - id : 'id' - }); + var store = new Ext.data.JsonStore({ + root: 'entries', + totalProperty: 'totalCount', + fields: [{ + name: 'id' + }, { + name: 'type' + }, { + name: 'peer' + }, { + name: 'user' + }, { + name: 'started', + type: 'date', + dateFormat: 'U' /* unix time */ + }], + url: 'api/status/connections', + autoLoad: true, + id: 'id' + }); - tvheadend.comet.on('connections', function(m) { - if (m.reload != null) store.reload(); - }); + tvheadend.comet.on('connections', function(m) { + if (m.reload != null) + store.reload(); + }); - function renderDate(value) { - var dt = new Date(value); - return dt.format('Y-m-d H:i:s'); - } + function renderDate(value) { + var dt = new Date(value); + return dt.format('Y-m-d H:i:s'); + } - var cm = new Ext.grid.ColumnModel([{ - width : 50, - id : 'type', - header : "Type", - dataIndex : 'type' - }, { - width : 50, - id : 'peer', - header : "IP Address", - dataIndex : 'peer' - }, { - width : 50, - id : 'user', - header : "Username", - dataIndex : 'user' - }, { - width : 50, - id : 'started', - header : "Started", - dataIndex : 'started', - renderer : renderDate - } ]); + var cm = new Ext.grid.ColumnModel([{ + width: 50, + id: 'type', + header: "Type", + dataIndex: 'type' + }, { + width: 50, + id: 'peer', + header: "IP Address", + dataIndex: 'peer' + }, { + width: 50, + id: 'user', + header: "Username", + dataIndex: 'user' + }, { + width: 50, + id: 'started', + header: "Started", + dataIndex: 'started', + renderer: renderDate + }]); - var panel = new Ext.grid.GridPanel({ - border: false, - loadMask : true, - stripeRows : true, - disableSelection : true, - title : 'Connections', - iconCls : 'eye', - store : store, - cm : cm, - flex: 1, - viewConfig : { - forceFit : true - } - }); - return panel; -} + var panel = new Ext.grid.GridPanel({ + border: false, + loadMask: true, + stripeRows: true, + disableSelection: true, + title: 'Connections', + iconCls: 'eye', + store: store, + cm: cm, + flex: 1, + viewConfig: { + forceFit: true + } + }); + return panel; +}; tvheadend.status = function() { - var panel = new Ext.TabPanel({ - title : 'Status', - autoScroll : true, - activeTab : 0, - iconCls : 'eye', - items : [ - new tvheadend.status_streams, - new tvheadend.status_subs, - new tvheadend.status_conns, - new tvheadend.service_mapper_status - ] - }); - return panel; -} + var panel = new Ext.TabPanel({ + title: 'Status', + autoScroll: true, + activeTab: 0, + iconCls: 'eye', + items: [ + new tvheadend.status_streams, + new tvheadend.status_subs, + new tvheadend.status_conns, + new tvheadend.service_mapper_status + ] + }); + return panel; +}; tvheadend.subscription_bw_monitor = function(id) { - var inputSeries = new TimeSeries(); + var inputSeries = new TimeSeries(); var outputSeries = new TimeSeries(); var chart = new SmoothieChart({ - minValue: 0, - grid: { - sharpLines: true, - fillStyle: 'transparent', - verticalSections: 0, - millisPerLine: 0 - }, - labels: { - disabled: false, - fillStyle: '#000000', - fontSize: 12 - } + minValue: 0, + grid: { + sharpLines: true, + fillStyle: 'transparent', + verticalSections: 0, + millisPerLine: 0 + }, + labels: { + disabled: false, + fillStyle: '#000000', + fontSize: 12 + } }); chart.addTimeSeries(inputSeries, { - strokeStyle: 'rgb(0, 255, 0)', - fillStyle: 'rgba(0, 255, 0, 0.5)', - lineWidth: 3 + strokeStyle: 'rgb(0, 255, 0)', + fillStyle: 'rgba(0, 255, 0, 0.5)', + lineWidth: 3 }); chart.addTimeSeries(outputSeries, { - strokeStyle: 'rgb(255, 0, 255)', - fillStyle: 'rgba(255, 0, 255, 0.5)', - lineWidth: 3 + strokeStyle: 'rgb(255, 0, 255)', + fillStyle: 'rgba(255, 0, 255, 0.5)', + lineWidth: 3 }); - + var inputLbl = new Ext.form.Label(); var outputLbl = new Ext.form.Label(); var comprLbl = new Ext.form.Label(); var win = new Ext.Window({ title: 'Bandwidth monitor', - layout:'fit', - resizable: false, - width : 450 + 30, - height : 150 + 50, - constrainHeader : true, - tbar : [inputLbl, '-', outputLbl, '-', comprLbl], - items: { - xtype: 'box', - autoEl: { - tag: 'canvas', - width: 450, - height: 150 - }, - listeners: { - render: { - scope: this, - fn: function(item) { - chart.streamTo(item.el.dom, 1000); - } - }, - resize: { - scope: this, - fn: function(item) { - chart.render(item.el.dom, 1000); + layout: 'fit', + resizable: false, + width: 450 + 30, + height: 150 + 50, + constrainHeader: true, + tbar: [inputLbl, '-', outputLbl, '-', comprLbl], + items: { + xtype: 'box', + autoEl: { + tag: 'canvas', + width: 450, + height: 150 + }, + listeners: { + render: { + scope: this, + fn: function(item) { + chart.streamTo(item.el.dom, 1000); } - } - } - } + }, + resize: { + scope: this, + fn: function(item) { + chart.render(item.el.dom, 1000); + } + } + } + } }); var task = { - interval: 1000, - run: function() { - r = tvheadend.subsStore.getById(id); - if (typeof r === 'undefined') { - chart.stop(); - Ext.TaskMgr.stop(task); - return; - } + interval: 1000, + run: function() { + r = tvheadend.subsStore.getById(id); + if (typeof r === 'undefined') { + chart.stop(); + Ext.TaskMgr.stop(task); + return; + } - var input = Math.round(r.data.in / 125); - var output = Math.round(r.data.out / 125); - var ratio = new Number(r.data.in / r.data.out).toPrecision(3); + var input = Math.round(r.data.in / 125); + var output = Math.round(r.data.out / 125); + var ratio = new Number(r.data.in / r.data.out).toPrecision(3); - win.setTitle(r.data.channel); - inputLbl.setText('In: ' + input + ' kb/s'); - outputLbl.setText('Out: ' + output + ' kb/s'); - comprLbl.setText('Compression ratio: ' + ratio); + win.setTitle(r.data.channel); + inputLbl.setText('In: ' + input + ' kb/s'); + outputLbl.setText('Out: ' + output + ' kb/s'); + comprLbl.setText('Compression ratio: ' + ratio); - inputSeries.append(new Date().getTime(), input); - outputSeries.append(new Date().getTime(), output); - } + inputSeries.append(new Date().getTime(), input); + outputSeries.append(new Date().getTime(), output); + } }; win.on('close', function() { - chart.stop(); - Ext.TaskMgr.stop(task); + chart.stop(); + Ext.TaskMgr.stop(task); }); win.show(); - + Ext.TaskMgr.start(task); }; tvheadend.stream_bw_monitor = function(id) { - var inputSeries = new TimeSeries(); + var inputSeries = new TimeSeries(); var chart = new SmoothieChart({ - minValue: 0, - grid: { - sharpLines: true, - fillStyle: 'transparent', - verticalSections: 0, - millisPerLine: 0 - }, - labels: { - disabled: false, - fillStyle: '#000000', - fontSize: 12 - } + minValue: 0, + grid: { + sharpLines: true, + fillStyle: 'transparent', + verticalSections: 0, + millisPerLine: 0 + }, + labels: { + disabled: false, + fillStyle: '#000000', + fontSize: 12 + } }); chart.addTimeSeries(inputSeries, { - strokeStyle: 'rgb(0, 255, 0)', - fillStyle: 'rgba(0, 255, 0, 0.5)', - lineWidth: 3 + strokeStyle: 'rgb(0, 255, 0)', + fillStyle: 'rgba(0, 255, 0, 0.5)', + lineWidth: 3 }); var inputLbl = new Ext.form.Label(); var win = new Ext.Window({ title: 'Bandwidth monitor', - layout:'fit', - resizable: false, - width : 450 + 30, - height : 150 + 50, - constrainHeader : true, - tbar : [inputLbl], - items: { - xtype: 'box', - autoEl: { - tag: 'canvas', - width: 450, - height: 150 - }, - listeners: { - render: { - scope: this, - fn: function(item) { - chart.streamTo(item.el.dom, 1000); - } - }, - resize: { - scope: this, - fn: function(item) { - chart.render(item.el.dom, 1000); + layout: 'fit', + resizable: false, + width: 450 + 30, + height: 150 + 50, + constrainHeader: true, + tbar: [inputLbl], + items: { + xtype: 'box', + autoEl: { + tag: 'canvas', + width: 450, + height: 150 + }, + listeners: { + render: { + scope: this, + fn: function(item) { + chart.streamTo(item.el.dom, 1000); } - } - } - } + }, + resize: { + scope: this, + fn: function(item) { + chart.render(item.el.dom, 1000); + } + } + } + } }); var task = { - interval: 1000, - run: function() { - r = tvheadend.streamStatusStore.getById(id); - if (typeof r === 'undefined') { - chart.stop(); - Ext.TaskMgr.stop(task); - return; - } + interval: 1000, + run: function() { + r = tvheadend.streamStatusStore.getById(id); + if (typeof r === 'undefined') { + chart.stop(); + Ext.TaskMgr.stop(task); + return; + } - win.setTitle(r.data.input + ' (' + r.data.stream + ')'); - var input = Math.round(r.data.bps / 1024); - inputLbl.setText('Input: ' + input + ' kb/s'); - inputSeries.append(new Date().getTime(), input); - } + win.setTitle(r.data.input + ' (' + r.data.stream + ')'); + var input = Math.round(r.data.bps / 1024); + inputLbl.setText('Input: ' + input + ' kb/s'); + inputSeries.append(new Date().getTime(), input); + } }; win.on('close', function() { - chart.stop(); - Ext.TaskMgr.stop(task); + chart.stop(); + Ext.TaskMgr.stop(task); }); win.show(); diff --git a/src/webui/static/app/tableeditor.js b/src/webui/static/app/tableeditor.js index c36498d8..92782612 100644 --- a/src/webui/static/app/tableeditor.js +++ b/src/webui/static/app/tableeditor.js @@ -1,177 +1,177 @@ tvheadend.tableEditor = function(title, dtable, cm, rec, plugins, store, - helpContent, icon) { + helpContent, icon) { - if (store == null) { - store = new Ext.data.JsonStore({ - root : 'entries', - fields : rec, - url : "tablemgr", - autoLoad : true, - id : 'id', - baseParams : { - table : dtable, - op : "get" - } - }); - } + if (store == null) { + store = new Ext.data.JsonStore({ + root: 'entries', + fields: rec, + url: "tablemgr", + autoLoad: true, + id: 'id', + baseParams: { + table: dtable, + op: "get" + } + }); + } - tvheadend.comet.on(dtable, function(m){ - if (m.reload) - store.reload(); - }); + tvheadend.comet.on(dtable, function(m) { + if (m.reload) + store.reload(); + }); - function addRecord() { - Ext.Ajax.request({ - url : "tablemgr", - params : { - op : "create", - table : dtable - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', - 'Unable to generate new record'); - }, - success : function(response, options) { - var responseData = Ext.util.JSON.decode(response.responseText); - var p = new rec(responseData, responseData.id); - grid.stopEditing(); - store.insert(0, p); - grid.startEditing(0, 0); - } - }) - } - ; + function addRecord() { + Ext.Ajax.request({ + url: "tablemgr", + params: { + op: "create", + table: dtable + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', + 'Unable to generate new record'); + }, + success: function(response, options) { + var responseData = Ext.util.JSON.decode(response.responseText); + var p = new rec(responseData, responseData.id); + grid.stopEditing(); + store.insert(0, p); + grid.startEditing(0, 0); + } + }); + } + ; - function delSelected() { - var selectedKeys = grid.selModel.selections.keys; - if (selectedKeys.length > 0) { - Ext.MessageBox.confirm('Message', - 'Do you really want to delete selection?', deleteRecord); - } - else { - Ext.MessageBox.alert('Message', - 'Please select at least one item to delete'); - } - } - ; + function delSelected() { + var selectedKeys = grid.selModel.selections.keys; + if (selectedKeys.length > 0) { + Ext.MessageBox.confirm('Message', + 'Do you really want to delete selection?', deleteRecord); + } + else { + Ext.MessageBox.alert('Message', + 'Please select at least one item to delete'); + } + } + ; - function deleteRecord(btn) { - if (btn == 'yes') { - var selectedKeys = grid.selModel.selections.keys; + function deleteRecord(btn) { + if (btn === 'yes') { + var selectedKeys = grid.selModel.selections.keys; - Ext.Ajax.request({ - url : "tablemgr", - params : { - op : "delete", - table : dtable, - entries : Ext.encode(selectedKeys) - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', 'Unable to delete'); - }, - success : function(response, options) { - } - }) - } - } + Ext.Ajax.request({ + url: "tablemgr", + params: { + op: "delete", + table: dtable, + entries: Ext.encode(selectedKeys) + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', 'Unable to delete'); + }, + success: function(response, options) { + } + }); + } + } - function saveChanges() { - var mr = store.getModifiedRecords(); - var out = new Array(); - for ( var x = 0; x < mr.length; x++) { - v = mr[x].getChanges(); - out[x] = v; - out[x].id = mr[x].id; - } + function saveChanges() { + var mr = store.getModifiedRecords(); + var out = new Array(); + for (var x = 0; x < mr.length; x++) { + v = mr[x].getChanges(); + out[x] = v; + out[x].id = mr[x].id; + } - Ext.Ajax.request({ - url : "tablemgr", - params : { - op : "update", - table : dtable, - entries : Ext.encode(out) - }, - success : function(response, options) { - // Note: this call is mostly redundant (comet update will pick it up anyway) - store.commitChanges(); - }, - failure : function(response, options) { - Ext.MessageBox.alert('Message', response.statusText); - } - }); - } + Ext.Ajax.request({ + url: "tablemgr", + params: { + op: "update", + table: dtable, + entries: Ext.encode(out) + }, + success: function(response, options) { + // Note: this call is mostly redundant (comet update will pick it up anyway) + store.commitChanges(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('Message', response.statusText); + } + }); + } - var selModel = new Ext.grid.RowSelectionModel({ - singleSelect : false - }); + var selModel = new Ext.grid.RowSelectionModel({ + singleSelect: false + }); - var delButton = new Ext.Toolbar.Button({ - tooltip : 'Delete one or more selected rows', - iconCls : 'remove', - text : 'Delete selected', - handler : delSelected, - disabled : true - }); + var delButton = new Ext.Toolbar.Button({ + tooltip: 'Delete one or more selected rows', + iconCls: 'remove', + text: 'Delete selected', + handler: delSelected, + disabled: true + }); - var saveBtn = new Ext.Toolbar.Button({ - tooltip : 'Save any changes made (Changed cells have red borders)', - iconCls : 'save', - text : "Save changes", - handler : saveChanges, - disabled : true - }); + var saveBtn = new Ext.Toolbar.Button({ + tooltip: 'Save any changes made (Changed cells have red borders)', + iconCls: 'save', + text: "Save changes", + handler: saveChanges, + disabled: true + }); - var rejectBtn = new Ext.Toolbar.Button({ - tooltip : 'Revert any changes made (Changed cells have red borders)', - iconCls : 'undo', - text : "Revert changes", - handler : function() { - store.rejectChanges(); - }, - disabled : true - }); + var rejectBtn = new Ext.Toolbar.Button({ + tooltip: 'Revert any changes made (Changed cells have red borders)', + iconCls: 'undo', + text: "Revert changes", + handler: function() { + store.rejectChanges(); + }, + disabled: true + }); - store.on('update', function(s, r, o) { - d = s.getModifiedRecords().length == 0 - saveBtn.setDisabled(d); - rejectBtn.setDisabled(d); - }); + store.on('update', function(s, r, o) { + d = s.getModifiedRecords().length === 0; + saveBtn.setDisabled(d); + rejectBtn.setDisabled(d); + }); - selModel.on('selectionchange', function(self) { - if (self.getCount() > 0) { - delButton.enable(); - } - else { - delButton.disable(); - } - }); + selModel.on('selectionchange', function(self) { + if (self.getCount() > 0) { + delButton.enable(); + } + else { + delButton.disable(); + } + }); - var grid = new Ext.grid.EditorGridPanel({ - title : title, - iconCls : icon, - plugins : plugins, - store : store, - clicksToEdit : 2, - cm : cm, - viewConfig : { - forceFit : true - }, - selModel : selModel, - stripeRows : true, - tbar : [ - { - tooltip : 'Create a new entry on the server. ' - + 'The new entry is initially disabled so it must be enabled ' - + 'before it start taking effect.', - iconCls : 'add', - text : 'Add entry', - handler : addRecord - }, '-', delButton, '-', saveBtn, rejectBtn, '->', { - text : 'Help', - handler : function() { - new tvheadend.help(title, helpContent); - } - } ] - }); - return grid; -} + var grid = new Ext.grid.EditorGridPanel({ + title: title, + iconCls: icon, + plugins: plugins, + store: store, + clicksToEdit: 2, + cm: cm, + viewConfig: { + forceFit: true + }, + selModel: selModel, + stripeRows: true, + tbar: [ + { + tooltip: 'Create a new entry on the server. ' + + 'The new entry is initially disabled so it must be enabled ' + + 'before it start taking effect.', + iconCls: 'add', + text: 'Add entry', + handler: addRecord + }, '-', delButton, '-', saveBtn, rejectBtn, '->', { + text: 'Help', + handler: function() { + new tvheadend.help(title, helpContent); + } + }] + }); + return grid; +}; diff --git a/src/webui/static/app/timeshift.js b/src/webui/static/app/timeshift.js index 1a6c1589..9e03c43a 100644 --- a/src/webui/static/app/timeshift.js +++ b/src/webui/static/app/timeshift.js @@ -1,180 +1,181 @@ tvheadend.timeshift = function() { - /* **************************************************************** - * Data - * ***************************************************************/ + /* **************************************************************** + * Data + * ***************************************************************/ - var confreader = new Ext.data.JsonReader( - { - root: 'config' - }, + var confreader = new Ext.data.JsonReader( + { + root: 'config' + }, [ - 'timeshift_enabled', 'timeshift_ondemand', - 'timeshift_path', - 'timeshift_unlimited_period', 'timeshift_max_period', - 'timeshift_unlimited_size', 'timeshift_max_size' + 'timeshift_enabled', 'timeshift_ondemand', + 'timeshift_path', + 'timeshift_unlimited_period', 'timeshift_max_period', + 'timeshift_unlimited_size', 'timeshift_max_size' ] - ); + ); - /* **************************************************************** - * Fields - * ***************************************************************/ + /* **************************************************************** + * Fields + * ***************************************************************/ - var timeshiftEnabled = new Ext.form.Checkbox({ - fieldLabel: 'Enabled', - name: 'timeshift_enabled', - width: 300 - }); + var timeshiftEnabled = new Ext.form.Checkbox({ + fieldLabel: 'Enabled', + name: 'timeshift_enabled', + width: 300 + }); - var timeshiftOndemand = new Ext.form.Checkbox({ - fieldLabel: 'On-Demand', - name: 'timeshift_ondemand', - width: 300 - }); + var timeshiftOndemand = new Ext.form.Checkbox({ + fieldLabel: 'On-Demand', + name: 'timeshift_ondemand', + width: 300 + }); - var timeshiftPath = new Ext.form.TextField({ - fieldLabel: 'Storage Path', - name: 'timeshift_path', - allowBlank: true, - width: 300 - }); + var timeshiftPath = new Ext.form.TextField({ + fieldLabel: 'Storage Path', + name: 'timeshift_path', + allowBlank: true, + width: 300 + }); - var timeshiftMaxPeriod = new Ext.form.NumberField({ - fieldLabel: 'Max. Period (mins)', - name: 'timeshift_max_period', - allowBlank: false, - width: 300 - }); + var timeshiftMaxPeriod = new Ext.form.NumberField({ + fieldLabel: 'Max. Period (mins)', + name: 'timeshift_max_period', + allowBlank: false, + width: 300 + }); - var timeshiftUnlPeriod = new Ext.form.Checkbox({ - fieldLabel: 'Unlimited time', - name: 'timeshift_unlimited_period', - Width: 300 - }); + var timeshiftUnlPeriod = new Ext.form.Checkbox({ + fieldLabel: 'Unlimited time', + name: 'timeshift_unlimited_period', + width: 300 + }); - var timeshiftMaxSize = new Ext.form.NumberField({ - fieldLabel: 'Max. Size (MB)', - name: 'timeshift_max_size', - allowBlank: false, - width: 300 - }); + var timeshiftMaxSize = new Ext.form.NumberField({ + fieldLabel: 'Max. Size (MB)', + name: 'timeshift_max_size', + allowBlank: false, + width: 300 + }); - var timeshiftUnlSize = new Ext.form.Checkbox({ - fieldLabel: 'Unlimited size', - name: 'timeshift_unlimited_size', - Width: 300 - }); + var timeshiftUnlSize = new Ext.form.Checkbox({ + fieldLabel: 'Unlimited size', + name: 'timeshift_unlimited_size', + width: 300 + }); - /* **************************************************************** - * Events - * ***************************************************************/ + /* **************************************************************** + * Events + * ***************************************************************/ - timeshiftUnlPeriod.on('check', function(e, c){ - timeshiftMaxPeriod.setDisabled(c); - }); - timeshiftUnlSize.on('check', function(e, c){ - timeshiftMaxSize.setDisabled(c); - }); + timeshiftUnlPeriod.on('check', function(e, c){ + timeshiftMaxPeriod.setDisabled(c); + }); - /* **************************************************************** - * Form - * ***************************************************************/ + timeshiftUnlSize.on('check', function(e, c){ + timeshiftMaxSize.setDisabled(c); + }); - var saveButton = new Ext.Button({ - text : "Save configuration", - tooltip : 'Save changes made to configuration below', - iconCls : 'save', - handler : saveChanges - }); + /* **************************************************************** + * Form + * ***************************************************************/ - var helpButton = new Ext.Button({ - text : 'Help', - handler : function() { - new tvheadend.help('Timeshift Configuration', 'config_timeshift.html'); + var saveButton = new Ext.Button({ + text: "Save configuration", + tooltip: 'Save changes made to configuration below', + iconCls: 'save', + handler: saveChanges + }); + + var helpButton = new Ext.Button({ + text: 'Help', + handler: function() { + new tvheadend.help('Timeshift Configuration', 'config_timeshift.html'); + } + }); + + var timeshiftPanelA = new Ext.form.FieldSet({ + width: 500, + autoHeight: true, + border: false, + items : [timeshiftMaxPeriod, timeshiftMaxSize] + }); + + var timeshiftPanelB = new Ext.form.FieldSet({ + width: 200, + autoHeight: true, + border: false, + items : [timeshiftUnlPeriod,timeshiftUnlSize] + }); + + var timeshiftPanel = new Ext.form.FieldSet({ + title: 'Timeshift Options', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items : [ + timeshiftEnabled, + timeshiftOndemand, + timeshiftPath, + { + layout: 'column', + border: false, + items: [timeshiftPanelA, timeshiftPanelB] + } + ] + }); + + var confpanel = new Ext.form.FormPanel({ + title : 'Timeshift', + iconCls : 'clock', + border : false, + bodyStyle : 'padding:15px', + labelAlign : 'left', + labelWidth : 150, + waitMsgTarget : true, + reader : confreader, + layout : 'form', + defaultType : 'textfield', + autoHeight : true, + animCollapse : true, + items : [timeshiftPanel], + tbar : [saveButton, '->', helpButton] + }); + + /* **************************************************************** + * Load/Save + * ***************************************************************/ + + confpanel.on('render', function() { + confpanel.getForm().load({ + url: 'timeshift', + params: { + 'op': 'loadSettings' + }, + success: function() { + confpanel.enable(); + timeshiftMaxPeriod.setDisabled(timeshiftUnlPeriod.getValue()); + timeshiftMaxSize.setDisabled(timeshiftUnlSize.getValue()); + } + }); + }); + + function saveChanges() { + confpanel.getForm().submit({ + url: 'timeshift', + params: { + op: 'saveSettings' + }, + waitMsg: 'Saving Data...', + success: function(form, action) { + }, + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); } - }); - var timeshiftPanelA = new Ext.form.FieldSet({ - width: 500, - autoHeight: true, - border: false, - items : [ timeshiftMaxPeriod, timeshiftMaxSize ] - }); - - var timeshiftPanelB = new Ext.form.FieldSet({ - width: 200, - autoHeight: true, - border: false, - items : [ timeshiftUnlPeriod,timeshiftUnlSize ] - }); - - var timeshiftPanel = new Ext.form.FieldSet({ - title: 'Timeshift Options', - width: 700, - autoHeight: true, - collapsible: true, - animCollapse: true, - items : [ - timeshiftEnabled, - timeshiftOndemand, - timeshiftPath, - { - layout: 'column', - border: false, - items: [ timeshiftPanelA, timeshiftPanelB] - } - ] - }); - - var confpanel = new Ext.form.FormPanel({ - title : 'Timeshift', - iconCls : 'clock', - border : false, - bodyStyle : 'padding:15px', - labelAlign : 'left', - labelWidth : 150, - waitMsgTarget : true, - reader : confreader, - layout : 'form', - defaultType : 'textfield', - autoHeight : true, - animCollapse : true, - items : [ timeshiftPanel ], - tbar : [ saveButton, '->', helpButton ] - }); - - /* **************************************************************** - * Load/Save - * ***************************************************************/ - - confpanel.on('render', function() { - confpanel.getForm().load({ - url: 'timeshift', - params: { - 'op': 'loadSettings' - }, - success: function() { - confpanel.enable(); - timeshiftMaxPeriod.setDisabled(timeshiftUnlPeriod.getValue()); - timeshiftMaxSize.setDisabled(timeshiftUnlSize.getValue()); - } - }); - }); - - function saveChanges() { - confpanel.getForm().submit({ - url : 'timeshift', - params : { - op : 'saveSettings', - }, - waitMsg : 'Saving Data...', - success : function(form, action) { - }, - failure : function(form, action) { - Ext.Msg.alert('Save failed', action.result.errormsg); - } - }); - } - - return confpanel; -} + return confpanel; +}; diff --git a/src/webui/static/app/tvadapters.js b/src/webui/static/app/tvadapters.js index d3353c09..50e32480 100644 --- a/src/webui/static/app/tvadapters.js +++ b/src/webui/static/app/tvadapters.js @@ -1,10 +1,10 @@ tvheadend.tvadapters = function() { - return tvheadend.idnode_tree( { - url : 'api/hardware/tree', - title : 'TV adapters', - comet : 'hardware', - help : function() { - new tvheadend.help('TV adapters', 'config_tvadapters.html'); - } - }); -} + return tvheadend.idnode_tree({ + url: 'api/hardware/tree', + title: 'TV adapters', + comet: 'hardware', + help: function() { + new tvheadend.help('TV adapters', 'config_tvadapters.html'); + } + }); +}; diff --git a/src/webui/static/app/tvheadend.js b/src/webui/static/app/tvheadend.js index dd9806a9..7fe99e4e 100644 --- a/src/webui/static/app/tvheadend.js +++ b/src/webui/static/app/tvheadend.js @@ -1,105 +1,105 @@ tvheadend.accessupdate = null; -tvheadend.capabilties = null; -tvheadend.conf_chepg = null; -tvheadend.conf_dvbin = null; -tvheadend.conf_tsdvr = null; -tvheadend.conf_csa = null; +tvheadend.capabilties = null; +tvheadend.conf_chepg = null; +tvheadend.conf_dvbin = null; +tvheadend.conf_tsdvr = null; +tvheadend.conf_csa = null; /* State Provider */ Ext.state.Manager.setProvider(new Ext.state.CookieProvider({ - // 7 days from now - expires : new Date(new Date().getTime()+(1000*60*60*24*7)), + // 7 days from now + expires: new Date(new Date().getTime() + (1000 * 60 * 60 * 24 * 7)) })); /** * Displays a help popup window */ tvheadend.help = function(title, pagename) { - Ext.Ajax.request({ - url : 'docs/' + pagename, - success : function(result, request) { + Ext.Ajax.request({ + url: 'docs/' + pagename, + success: function(result, request) { - var content = new Ext.Panel({ - autoScroll : true, - border : false, - layout : 'fit', - html : result.responseText - }); + var content = new Ext.Panel({ + autoScroll: true, + border: false, + layout: 'fit', + html: result.responseText + }); - var win = new Ext.Window({ - title : 'Help for ' + title, - layout : 'fit', - width : 900, - height : 400, - constrainHeader : true, - items : [ content ] - }); - win.show(); + var win = new Ext.Window({ + title: 'Help for ' + title, + layout: 'fit', + width: 900, + height: 400, + constrainHeader: true, + items: [content] + }); + win.show(); - } - }); -} + } + }); +}; /* * General capabilities */ Ext.Ajax.request({ - url: 'capabilities', - success: function(d) - { - if (d && d.responseText) - tvheadend.capabilities = Ext.util.JSON.decode(d.responseText); - if (tvheadend.capabilities && tvheadend.accessupdate) - accessUpdate(tvheadend.accessUpdate); - - } + url: 'capabilities', + success: function(d) + { + if (d && d.responseText) + tvheadend.capabilities = Ext.util.JSON.decode(d.responseText); + if (tvheadend.capabilities && tvheadend.accessupdate) + accessUpdate(tvheadend.accessUpdate); + + } }); /** * Displays a mediaplayer using the html5 video element */ tvheadend.VideoPlayer = function(url) { - + var videoPlayer = new tv.ui.VideoPlayer({ - params: { - resolution: 384 - } + params: { + resolution: 384 + } }); var selectChannel = new Ext.form.ComboBox({ - loadingText : 'Loading...', - width : 200, - displayField : 'val', - store : tvheadend.channels, - mode : 'local', - editable : true, - triggerAction : 'all', - emptyText : 'Select channel...' + loadingText: 'Loading...', + width: 200, + displayField: 'val', + store: tvheadend.channels, + mode: 'local', + editable: true, + triggerAction: 'all', + emptyText: 'Select channel...' }); - + selectChannel.on('select', function(c, r) { - videoPlayer.zapTo(r.id); + videoPlayer.zapTo(r.id); }); var slider = new Ext.Slider({ - width : 135, - height : 20, - value : 90, - increment : 1, - minValue : 0, - maxValue : 100 + width: 135, + height: 20, + value: 90, + increment: 1, + minValue: 0, + maxValue: 100 }); var sliderLabel = new Ext.form.Label(); sliderLabel.setText("90%"); slider.addListener('change', function() { - videoPlayer.setVolume(slider.getValue()); - sliderLabel.setText(videoPlayer.getVolume() + '%'); + videoPlayer.setVolume(slider.getValue()); + sliderLabel.setText(videoPlayer.getVolume() + '%'); }); var selectResolution = new Ext.form.ComboBox({ width: 150, - displayField:'name', + displayField: 'name', valueField: 'res', value: 384, mode: 'local', @@ -107,101 +107,101 @@ tvheadend.VideoPlayer = function(url) { triggerAction: 'all', emptyText: 'Select resolution...', store: new Ext.data.SimpleStore({ - fields: ['res','name'], + fields: ['res', 'name'], id: 0, data: [ - ['288','288p'], - ['384','384p'], - ['480','480p'], - ['576','576p'] + ['288', '288p'], + ['384', '384p'], + ['480', '480p'], + ['576', '576p'] ] }) }); selectResolution.on('select', function(c, r) { - videoPlayer.setResolution(r.data.res); - if(videoPlayer.isIdle()) - return; - - var index = selectChannel.selectedIndex; - if(index < 0) - return; - - var ch = selectChannel.getStore().getAt(index); - videoPlayer.zapTo(ch.id); + videoPlayer.setResolution(r.data.res); + if (videoPlayer.isIdle()) + return; + + var index = selectChannel.selectedIndex; + if (index < 0) + return; + + var ch = selectChannel.getStore().getAt(index); + videoPlayer.zapTo(ch.id); }); var win = new Ext.Window({ - title : 'Live TV Player', - layout : 'fit', - width : 682 + 14, - height : 384 + 56, - constrainHeader : true, - iconCls : 'eye', - resizable : true, - tbar : [ - selectChannel, - '-', - { - iconCls : 'control_play', - tooltip : 'Play', - handler : function() { - if(!videoPlayer.isIdle()) { //probobly paused - videoPlayer.play(); - return; - } + title: 'Live TV Player', + layout: 'fit', + width: 682 + 14, + height: 384 + 56, + constrainHeader: true, + iconCls: 'eye', + resizable: true, + tbar: [ + selectChannel, + '-', + { + iconCls: 'control_play', + tooltip: 'Play', + handler: function() { + if (!videoPlayer.isIdle()) { //probobly paused + videoPlayer.play(); + return; + } - var index = selectChannel.selectedIndex; - if(index < 0) - return; - - var ch = selectChannel.getStore().getAt(index); - videoPlayer.zapTo(ch.id); - } - }, - { - iconCls : 'control_pause', - tooltip : 'Pause', - handler : function() { - videoPlayer.pause(); - } - }, - { - iconCls : 'control_stop', - tooltip : 'Stop', - handler : function() { - videoPlayer.stop(); - } - }, - '-', - { - iconCls : 'control_fullscreen', - tooltip : 'Fullscreen', - handler : function() { - videoPlayer.fullscreen(); - } - }, - '-', - selectResolution, - '-', - { - iconCls : 'control_volume', - tooltip : 'Volume', - disabled : true - }, ], - items : [videoPlayer] + var index = selectChannel.selectedIndex; + if (index < 0) + return; + + var ch = selectChannel.getStore().getAt(index); + videoPlayer.zapTo(ch.id); + } + }, + { + iconCls: 'control_pause', + tooltip: 'Pause', + handler: function() { + videoPlayer.pause(); + } + }, + { + iconCls: 'control_stop', + tooltip: 'Stop', + handler: function() { + videoPlayer.stop(); + } + }, + '-', + { + iconCls: 'control_fullscreen', + tooltip: 'Fullscreen', + handler: function() { + videoPlayer.fullscreen(); + } + }, + '-', + selectResolution, + '-', + { + iconCls: 'control_volume', + tooltip: 'Volume', + disabled: true + }], + items: [videoPlayer] }); - + win.on('beforeShow', function() { - win.getTopToolbar().add(slider); - win.getTopToolbar().add(new Ext.Toolbar.Spacer()); - win.getTopToolbar().add(new Ext.Toolbar.Spacer()); - win.getTopToolbar().add(new Ext.Toolbar.Spacer()); - win.getTopToolbar().add(sliderLabel); + win.getTopToolbar().add(slider); + win.getTopToolbar().add(new Ext.Toolbar.Spacer()); + win.getTopToolbar().add(new Ext.Toolbar.Spacer()); + win.getTopToolbar().add(new Ext.Toolbar.Spacer()); + win.getTopToolbar().add(sliderLabel); }); - + win.on('close', function() { - videoPlayer.stop(); + videoPlayer.stop(); }); win.show(); @@ -214,154 +214,154 @@ tvheadend.VideoPlayer = function(url) { * Obviosuly, access is verified in the server too. */ function accessUpdate(o) { - tvheadend.accessUpdate = o; - if (!tvheadend.capabilities) - return; + tvheadend.accessUpdate = o; + if (!tvheadend.capabilities) + return; - if (o.dvr == true && tvheadend.dvrpanel == null) { - tvheadend.dvrpanel = new tvheadend.dvr; - tvheadend.rootTabPanel.add(tvheadend.dvrpanel); - } - - if (o.admin == true && tvheadend.confpanel == null) { - var tabs1 = [ - new tvheadend.miscconf, - new tvheadend.acleditor - ] - var tabs2; - - /* DVB inputs */ - tabs2 = []; - if (tvheadend.capabilities.indexOf('linuxdvb') != -1 || - tvheadend.capabilities.indexOf('v4l') != -1) { - tabs2.push(new tvheadend.tvadapters); - } -/* - tabs2.push(new tvheadend.iptv); -*/ - tvheadend.conf_dvbin = new Ext.TabPanel({ - activeTab: 0, - autoScroll: true, - title: 'DVB Inputs', - iconCls: 'hardware', - items : tabs2 - }); - tvheadend.networks(tvheadend.conf_dvbin); - tvheadend.muxes(tvheadend.conf_dvbin); - tvheadend.services(tvheadend.conf_dvbin); - tvheadend.mux_sched(tvheadend.conf_dvbin); - tabs1.push(tvheadend.conf_dvbin); - - /* Channel / EPG */ - tvheadend.conf_chepg = new Ext.TabPanel({ - activeTab: 0, - autoScroll: true, - title : 'Channel / EPG', - iconCls : 'television', - items : [ - new tvheadend.cteditor, - new tvheadend.epggrab - ] - }); - tvheadend.channel_tab(tvheadend.conf_chepg); - tabs1.push(tvheadend.conf_chepg); - - /* DVR / Timeshift */ - tabs2 = [ new tvheadend.dvrsettings ]; - if (tvheadend.capabilities.indexOf('timeshift') != -1) { - tabs2.push(new tvheadend.timeshift) - } - tvheadend.conf_tsdvr = new Ext.TabPanel({ - activeTab: 0, - autoScroll: true, - title: 'Recording', - iconCls: 'drive', - items : tabs2 - }); - tabs1.push(tvheadend.conf_tsdvr); - - /* CSA */ - if (tvheadend.capabilities.indexOf('cwc') != -1) { - tvheadend.conf_csa = new Ext.TabPanel({ - activeTab: 0, - autoScroll: true, - title: 'CSA', - iconCls: 'key', - items: [ - new tvheadend.cwceditor, - new tvheadend.capmteditor - ] - }); - tabs1.push(tvheadend.conf_csa); + if (o.dvr == true && tvheadend.dvrpanel == null) { + tvheadend.dvrpanel = new tvheadend.dvr; + tvheadend.rootTabPanel.add(tvheadend.dvrpanel); } - /* Stream Config */ - tvheadend.conf_stream = new Ext.TabPanel({ - activeTab: 0, - autoScroll: true, - title: 'Stream', - iconCls: 'stream_config', - items: [] - }); - tvheadend.esfilter_tab(tvheadend.conf_stream); - tabs1.push(tvheadend.conf_stream); + if (o.admin == true && tvheadend.confpanel == null) { + var tabs1 = [ + new tvheadend.miscconf, + new tvheadend.acleditor + ]; + var tabs2; - /* Debug */ - tabs1.push(new tvheadend.tvhlog); + /* DVB inputs */ + tabs2 = []; + if (tvheadend.capabilities.indexOf('linuxdvb') !== -1 || + tvheadend.capabilities.indexOf('v4l') !== -1) { + tabs2.push(new tvheadend.tvadapters); + } + /* + tabs2.push(new tvheadend.iptv); + */ + tvheadend.conf_dvbin = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'DVB Inputs', + iconCls: 'hardware', + items: tabs2 + }); + tvheadend.networks(tvheadend.conf_dvbin); + tvheadend.muxes(tvheadend.conf_dvbin); + tvheadend.services(tvheadend.conf_dvbin); + tvheadend.mux_sched(tvheadend.conf_dvbin); + tabs1.push(tvheadend.conf_dvbin); - tvheadend.confpanel = new Ext.TabPanel({ - activeTab : 0, - autoScroll : true, - title : 'Configuration', - iconCls : 'wrench', - items : tabs1 - }); + /* Channel / EPG */ + tvheadend.conf_chepg = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'Channel / EPG', + iconCls: 'television', + items: [ + new tvheadend.cteditor, + new tvheadend.epggrab + ] + }); + tvheadend.channel_tab(tvheadend.conf_chepg); + tabs1.push(tvheadend.conf_chepg); - tvheadend.rootTabPanel.add(tvheadend.confpanel); - tvheadend.confpanel.doLayout(); - } + /* DVR / Timeshift */ + tabs2 = [new tvheadend.dvrsettings]; + if (tvheadend.capabilities.indexOf('timeshift') !== -1) { + tabs2.push(new tvheadend.timeshift); + } + tvheadend.conf_tsdvr = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'Recording', + iconCls: 'drive', + items: tabs2 + }); + tabs1.push(tvheadend.conf_tsdvr); - if (o.admin == true && tvheadend.statuspanel == null) { - tvheadend.statuspanel = new tvheadend.status; - tvheadend.rootTabPanel.add(tvheadend.statuspanel); - } + /* CSA */ + if (tvheadend.capabilities.indexOf('cwc') !== -1) { + tvheadend.conf_csa = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'CSA', + iconCls: 'key', + items: [ + new tvheadend.cwceditor, + new tvheadend.capmteditor + ] + }); + tabs1.push(tvheadend.conf_csa); + } - if (tvheadend.aboutPanel == null) { - tvheadend.aboutPanel = new Ext.Panel({ - border : false, - layout : 'fit', - title : 'About', - iconCls : 'info', - autoLoad : 'about.html' - }); - tvheadend.rootTabPanel.add(tvheadend.aboutPanel); - } + /* Stream Config */ + tvheadend.conf_stream = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'Stream', + iconCls: 'stream_config', + items: [] + }); + tvheadend.esfilter_tab(tvheadend.conf_stream); + tabs1.push(tvheadend.conf_stream); - tvheadend.rootTabPanel.doLayout(); + /* Debug */ + tabs1.push(new tvheadend.tvhlog); + + tvheadend.confpanel = new Ext.TabPanel({ + activeTab: 0, + autoScroll: true, + title: 'Configuration', + iconCls: 'wrench', + items: tabs1 + }); + + tvheadend.rootTabPanel.add(tvheadend.confpanel); + tvheadend.confpanel.doLayout(); + } + + if (o.admin == true && tvheadend.statuspanel == null) { + tvheadend.statuspanel = new tvheadend.status; + tvheadend.rootTabPanel.add(tvheadend.statuspanel); + } + + if (tvheadend.aboutPanel == null) { + tvheadend.aboutPanel = new Ext.Panel({ + border: false, + layout: 'fit', + title: 'About', + iconCls: 'info', + autoLoad: 'about.html' + }); + tvheadend.rootTabPanel.add(tvheadend.aboutPanel); + } + + tvheadend.rootTabPanel.doLayout(); } /** * */ function setServerIpPort(o) { - tvheadend.serverIp = o.ip; - tvheadend.serverPort = o.port; + tvheadend.serverIp = o.ip; + tvheadend.serverPort = o.port; } function makeRTSPprefix() { - return 'rtsp://' + tvheadend.serverIp + ':' + tvheadend.serverPort + '/'; + return 'rtsp://' + tvheadend.serverIp + ':' + tvheadend.serverPort + '/'; } /** * */ tvheadend.log = function(msg, style) { - s = style ? '
' : '
' + s = style ? '
' : '
'; - sl = Ext.get('systemlog'); - e = Ext.DomHelper.append(sl, s + '
' + msg + '
'); - e.scrollIntoView('systemlog'); -} + sl = Ext.get('systemlog'); + e = Ext.DomHelper.append(sl, s + '
' + msg + '
'); + e.scrollIntoView('systemlog'); +}; /** * @@ -369,73 +369,72 @@ tvheadend.log = function(msg, style) { //create application tvheadend.app = function() { - // public space - return { + // public space + return { + // public methods + init: function() { + var header = new Ext.Panel({ + split: true, + region: 'north', + height: 45, + boxMaxHeight: 45, + boxMinHeight: 45, + border: false, + hidden: true, + html: '' + }); - // public methods - init : function() { - var header = new Ext.Panel({ - split: true, - region: 'north', - height : 45, - boxMaxHeight : 45, - boxMinHeight : 45, - border: false, - hidden: true, - html: '' - }); - - tvheadend.rootTabPanel = new Ext.TabPanel({ - region : 'center', - activeTab : 0, - items : [ new tvheadend.epg ] - }); + tvheadend.rootTabPanel = new Ext.TabPanel({ + region: 'center', + activeTab: 0, + items: [new tvheadend.epg] + }); - var viewport = new Ext.Viewport({ - layout : 'border', - items : [{ - region : 'south', - contentEl : 'systemlog', - split : true, - autoScroll : true, - height : 150, - minSize : 100, - maxSize : 400, - collapsible : true, - collapsed : true, - title : 'System log', - margins : '0 0 0 0', - tools : [ { - id : 'gear', - qtip : 'Enable debug output', - handler : function(event, toolEl, panel) { - Ext.Ajax.request({ - url : 'comet/debug', - params : { - boxid : tvheadend.boxid - } - }); - } - } ] - }, tvheadend.rootTabPanel, header ] - }); + var viewport = new Ext.Viewport({ + layout: 'border', + items: [{ + region: 'south', + contentEl: 'systemlog', + split: true, + autoScroll: true, + height: 150, + minSize: 100, + maxSize: 400, + collapsible: true, + collapsed: true, + title: 'System log', + margins: '0 0 0 0', + tools: [{ + id: 'gear', + qtip: 'Enable debug output', + handler: function(event, toolEl, panel) { + Ext.Ajax.request({ + url: 'comet/debug', + params: { + boxid: tvheadend.boxid + } + }); + } + }] + }, tvheadend.rootTabPanel, header] + }); - tvheadend.comet.on('accessUpdate', accessUpdate); + tvheadend.comet.on('accessUpdate', accessUpdate); - tvheadend.comet.on('setServerIpPort', setServerIpPort); + tvheadend.comet.on('setServerIpPort', setServerIpPort); - tvheadend.comet.on('logmessage', function(m) { - tvheadend.log(m.logtxt); - }); + tvheadend.comet.on('logmessage', function(m) { + tvheadend.log(m.logtxt); + }); - new tvheadend.cometPoller; + new tvheadend.cometPoller; - Ext.QuickTips.init(); + Ext.QuickTips.init(); - // Load the chart library smoothie.js, as used by the bandwidth monitor. - Ext.Loader.load('static/smoothie.js'); - } + // Load the chart library smoothie.js, as used by the bandwidth monitor. + Ext.Loader.load('static/smoothie.js'); + } - }; + }; }(); // end of app diff --git a/src/webui/static/app/tvhlog.js b/src/webui/static/app/tvhlog.js index 2d344ad5..d5c6e92c 100644 --- a/src/webui/static/app/tvhlog.js +++ b/src/webui/static/app/tvhlog.js @@ -1,110 +1,110 @@ tvheadend.tvhlog = function() { - /* - * Basic Config - */ - var confreader = new Ext.data.JsonReader({ - root : 'config' - }, [ 'tvhlog_path', 'tvhlog_dbg_syslog', 'tvhlog_trace_on', - 'tvhlog_debug', 'tvhlog_trace' ]); + /* + * Basic Config + */ + var confreader = new Ext.data.JsonReader({ + root: 'config' + }, ['tvhlog_path', 'tvhlog_dbg_syslog', 'tvhlog_trace_on', + 'tvhlog_debug', 'tvhlog_trace']); - /* **************************************************************** - * Form Fields - * ***************************************************************/ + /* **************************************************************** + * Form Fields + * ***************************************************************/ - var tvhlogLogPath = new Ext.form.TextField({ - fieldLabel : 'Debug Log Path', - name : 'tvhlog_path', - allowBlank : true, - width: 400 - }); + var tvhlogLogPath = new Ext.form.TextField({ + fieldLabel: 'Debug Log Path', + name: 'tvhlog_path', + allowBlank: true, + width: 400 + }); - var tvhlogToSyslog = new Ext.form.Checkbox({ - name: 'tvhlog_dbg_syslog', - fieldLabel: 'Debug to syslog' - }); - - var tvhlogTraceOn = new Ext.form.Checkbox({ - name: 'tvhlog_trace_on', - fieldLabel: 'Debug trace (low-level stuff)' - }); + var tvhlogToSyslog = new Ext.form.Checkbox({ + name: 'tvhlog_dbg_syslog', + fieldLabel: 'Debug to syslog' + }); - var tvhlogDebugSubsys = new Ext.form.TextField({ - fieldLabel : 'Debug Subsystems', - name : 'tvhlog_debug', - allowBlank : true, - width: 400 - }); + var tvhlogTraceOn = new Ext.form.Checkbox({ + name: 'tvhlog_trace_on', + fieldLabel: 'Debug trace (low-level stuff)' + }); - var tvhlogTraceSubsys = new Ext.form.TextField({ - fieldLabel : 'Trace Subsystems', - name : 'tvhlog_trace', - allowBlank : true, - width: 400 - }); + var tvhlogDebugSubsys = new Ext.form.TextField({ + fieldLabel: 'Debug Subsystems', + name: 'tvhlog_debug', + allowBlank: true, + width: 400 + }); - /* **************************************************************** - * Form - * ***************************************************************/ + var tvhlogTraceSubsys = new Ext.form.TextField({ + fieldLabel: 'Trace Subsystems', + name: 'tvhlog_trace', + allowBlank: true, + width: 400 + }); - var saveButton = new Ext.Button({ - text : "Save configuration", - tooltip : 'Save changes made to configuration below', - iconCls : 'save', - handler : saveChanges - }); + /* **************************************************************** + * Form + * ***************************************************************/ - var helpButton = new Ext.Button({ - text : 'Help', - handler : function() { - new tvheadend.help('Debug Configuration', 'config_tvhlog.html'); - } - }); + var saveButton = new Ext.Button({ + text: "Save configuration", + tooltip: 'Save changes made to configuration below', + iconCls: 'save', + handler: saveChanges + }); - var confpanel = new Ext.form.FormPanel({ - title : 'Debugging', - iconCls : 'wrench', - border : false, - bodyStyle : 'padding:15px', - labelAlign : 'left', - labelWidth : 200, - waitMsgTarget : true, - reader : confreader, - layout : 'form', - defaultType : 'textfield', - autoHeight : true, - items : [ tvhlogLogPath, tvhlogToSyslog, - tvhlogTraceOn, tvhlogDebugSubsys, tvhlogTraceSubsys ], - tbar : [ saveButton, '->', helpButton ] - }); + var helpButton = new Ext.Button({ + text: 'Help', + handler: function() { + new tvheadend.help('Debug Configuration', 'config_tvhlog.html'); + } + }); - /* **************************************************************** - * Load/Save - * ***************************************************************/ + var confpanel = new Ext.form.FormPanel({ + title: 'Debugging', + iconCls: 'wrench', + border: false, + bodyStyle: 'padding:15px', + labelAlign: 'left', + labelWidth: 200, + waitMsgTarget: true, + reader: confreader, + layout: 'form', + defaultType: 'textfield', + autoHeight: true, + items: [tvhlogLogPath, tvhlogToSyslog, + tvhlogTraceOn, tvhlogDebugSubsys, tvhlogTraceSubsys], + tbar: [saveButton, '->', helpButton] + }); - confpanel.on('render', function() { - confpanel.getForm().load({ - url : 'tvhlog', - params : { - op : 'loadSettings' - }, - success : function(form, action) { - confpanel.enable(); - } - }); - }); + /* **************************************************************** + * Load/Save + * ***************************************************************/ - function saveChanges() { - confpanel.getForm().submit({ - url : 'tvhlog', - params : { - op : 'saveSettings' - }, - waitMsg : 'Saving Data...', - failure : function(form, action) { - Ext.Msg.alert('Save failed', action.result.errormsg); - } - }); - } + confpanel.on('render', function() { + confpanel.getForm().load({ + url: 'tvhlog', + params: { + op: 'loadSettings' + }, + success: function(form, action) { + confpanel.enable(); + } + }); + }); - return confpanel; -} + function saveChanges() { + confpanel.getForm().submit({ + url: 'tvhlog', + params: { + op: 'saveSettings' + }, + waitMsg: 'Saving Data...', + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); + } + + return confpanel; +}; diff --git a/src/webui/static/app/v4l.js b/src/webui/static/app/v4l.js index d755d714..ab355e10 100644 --- a/src/webui/static/app/v4l.js +++ b/src/webui/static/app/v4l.js @@ -3,320 +3,319 @@ */ tvheadend.v4l_adapter_general = function(adapterData) { - adapterId = adapterData.identifier; + adapterId = adapterData.identifier; - /* Conf panel */ + /* Conf panel */ - var confreader = new Ext.data.JsonReader({ - root : 'v4ladapters' - }, [ 'name', 'logging' ]); + var confreader = new Ext.data.JsonReader({ + root: 'v4ladapters' + }, ['name', 'logging']); - function saveConfForm() { - confform.getForm().submit({ - url : 'v4l/adapter/' + adapterId, - params : { - 'op' : 'save' - }, - waitMsg : 'Saving Data...' - }); - } + function saveConfForm() { + confform.getForm().submit({ + url: 'v4l/adapter/' + adapterId, + params: { + 'op': 'save' + }, + waitMsg: 'Saving Data...' + }); + } - var items = [ { - fieldLabel : 'Adapter name', - name : 'name', - width : 250 - }, new Ext.form.Checkbox({ - fieldLabel : 'Detailed logging', - name : 'logging' - }) ]; + var items = [{ + fieldLabel: 'Adapter name', + name: 'name', + width: 250 + }, new Ext.form.Checkbox({ + fieldLabel: 'Detailed logging', + name: 'logging' + })]; - var confform = new Ext.FormPanel({ - title : 'Adapter configuration', - columnWidth : .40, - frame : true, - border : true, - disabled : true, - style : 'margin:10px', - bodyStyle : 'padding:5px', - labelAlign : 'right', - labelWidth : 110, - waitMsgTarget : true, - reader : confreader, - defaultType : 'textfield', - items : items, - buttons : [ { - text : 'Save', - handler : saveConfForm - } ] - }); + var confform = new Ext.FormPanel({ + title: 'Adapter configuration', + columnWidth: .40, + frame: true, + border: true, + disabled: true, + style: 'margin:10px', + bodyStyle: 'padding:5px', + labelAlign: 'right', + labelWidth: 110, + waitMsgTarget: true, + reader: confreader, + defaultType: 'textfield', + items: items, + buttons: [{ + text: 'Save', + handler: saveConfForm + }] + }); - confform.getForm().load({ - url : 'v4l/adapter/' + adapterId, - params : { - 'op' : 'load' - }, - success : function(form, action) { - confform.enable(); - } - }); + confform.getForm().load({ + url: 'v4l/adapter/' + adapterId, + params: { + 'op': 'load' + }, + success: function(form, action) { + confform.enable(); + } + }); - /** - * Information / capabilities panel - */ + /** + * Information / capabilities panel + */ - var infoTemplate = new Ext.XTemplate( - '

Hardware

' - + '

Device path:

{path}' + '

Device name:

{devicename}' - + '

Status

' - + '

Currently tuned to:

{currentMux} '); + var infoTemplate = new Ext.XTemplate( + '

Hardware

' + + '

Device path:

{path}' + '

Device name:

{devicename}' + + '

Status

' + + '

Currently tuned to:

{currentMux} '); - var infoPanel = new Ext.Panel({ - title : 'Information and capabilities', - columnWidth : .35, - frame : true, - border : true, - style : 'margin:10px', - bodyStyle : 'padding:5px', - html : infoTemplate.applyTemplate(adapterData) - }); + var infoPanel = new Ext.Panel({ + title: 'Information and capabilities', + columnWidth: .35, + frame: true, + border: true, + style: 'margin:10px', + bodyStyle: 'padding:5px', + html: infoTemplate.applyTemplate(adapterData) + }); - /** - * Main adapter panel - */ - var panel = new Ext.Panel({ - title : 'General', - layout : 'column', - items : [ confform, infoPanel ] - }); + /** + * Main adapter panel + */ + var panel = new Ext.Panel({ + title: 'General', + layout: 'column', + items: [confform, infoPanel] + }); - /** - * Subscribe and react on updates for this adapter - */ - tvheadend.tvAdapterStore.on('update', function(s, r, o) { - if (r.data.identifier != adapterId) return; - infoTemplate.overwrite(infoPanel.body, r.data); - }); + /** + * Subscribe and react on updates for this adapter + */ + tvheadend.tvAdapterStore.on('update', function(s, r, o) { + if (r.data.identifier !== adapterId) + return; + infoTemplate.overwrite(infoPanel.body, r.data); + }); - return panel; -} + return panel; +}; /** * V4L service grid */ tvheadend.v4l_services = function(adapterId) { - var fm = Ext.form; + var fm = Ext.form; - var enabledColumn = new Ext.grid.CheckColumn({ - header : "Enabled", - dataIndex : 'enabled', - width : 45 - }); + var enabledColumn = new Ext.grid.CheckColumn({ + header: "Enabled", + dataIndex: 'enabled', + width: 45 + }); - var cm = new Ext.grid.ColumnModel({ - defaultSortable: true, - columns : [ - enabledColumn, { - header : "Channel name", - dataIndex : 'channelname', - width : 150, - renderer : function(value, metadata, record, row, col, store) { - return value ? value : 'Unmapped'; - }, - editor : new fm.ComboBox({ - store : tvheadend.channels, - allowBlank : true, - typeAhead : true, - minChars : 2, - lazyRender : true, - triggerAction : 'all', - mode : 'local', - displayField : 'name' - }) - }, { - header : "Frequency", - dataIndex : 'frequency', - width : 60, - editor : new fm.NumberField({ - minValue : 10000, - maxValue : 1000000000 - }) - } ]}); + var cm = new Ext.grid.ColumnModel({ + defaultSortable: true, + columns: [ + enabledColumn, { + header: "Channel name", + dataIndex: 'channelname', + width: 150, + renderer: function(value, metadata, record, row, col, store) { + return value ? value : 'Unmapped'; + }, + editor: new fm.ComboBox({ + store: tvheadend.channels, + allowBlank: true, + typeAhead: true, + minChars: 2, + lazyRender: true, + triggerAction: 'all', + mode: 'local', + displayField: 'name' + }) + }, { + header: "Frequency", + dataIndex: 'frequency', + width: 60, + editor: new fm.NumberField({ + minValue: 10000, + maxValue: 1000000000 + }) + }]}); - var rec = Ext.data.Record.create([ 'id', 'enabled', 'channelname', - 'frequency' ]); + var rec = Ext.data.Record.create(['id', 'enabled', 'channelname', + 'frequency']); - var store = new Ext.data.JsonStore({ - root : 'entries', - fields : rec, - url : "v4l/services/" + adapterId, - autoLoad : true, - id : 'id', - baseParams : { - op : "get" - }, - listeners : { - 'update' : function(s, r, o) { - d = s.getModifiedRecords().length == 0 - saveBtn.setDisabled(d); - rejectBtn.setDisabled(d); - } - } - }); + var store = new Ext.data.JsonStore({ + root: 'entries', + fields: rec, + url: "v4l/services/" + adapterId, + autoLoad: true, + id: 'id', + baseParams: { + op: "get" + }, + listeners: { + 'update': function(s, r, o) { + d = s.getModifiedRecords().length === 0; + saveBtn.setDisabled(d); + rejectBtn.setDisabled(d); + } + } + }); - function addRecord() { - Ext.Ajax.request({ - url : "v4l/services/" + adapterId, - params : { - op : "create" - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', - 'Unable to generate new record'); - }, - success : function(response, options) { - var responseData = Ext.util.JSON.decode(response.responseText); - var p = new rec(responseData, responseData.id); - grid.stopEditing(); - store.insert(0, p); - grid.startEditing(0, 0); - } - }) - } - ; + function addRecord() { + Ext.Ajax.request({ + url: "v4l/services/" + adapterId, + params: { + op: "create" + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', + 'Unable to generate new record'); + }, + success: function(response, options) { + var responseData = Ext.util.JSON.decode(response.responseText); + var p = new rec(responseData, responseData.id); + grid.stopEditing(); + store.insert(0, p); + grid.startEditing(0, 0); + } + }); + }; - function delSelected() { - var selectedKeys = grid.selModel.selections.keys; - if (selectedKeys.length > 0) { - Ext.MessageBox.confirm('Message', - 'Do you really want to delete selection?', deleteRecord); - } - else { - Ext.MessageBox.alert('Message', - 'Please select at least one item to delete'); - } - } - ; + function delSelected() { + var selectedKeys = grid.selModel.selections.keys; + if (selectedKeys.length > 0) { + Ext.MessageBox.confirm('Message', + 'Do you really want to delete selection?', deleteRecord); + } + else { + Ext.MessageBox.alert('Message', + 'Please select at least one item to delete'); + } + }; - function deleteRecord(btn) { - if (btn == 'yes') { - var selectedKeys = grid.selModel.selections.keys; + function deleteRecord(btn) { + if (btn === 'yes') { + var selectedKeys = grid.selModel.selections.keys; - Ext.Ajax.request({ - url : "v4l/services/" + adapterId, - params : { - op : "delete", - entries : Ext.encode(selectedKeys) - }, - failure : function(response, options) { - Ext.MessageBox.alert('Server Error', 'Unable to delete'); - }, - success : function(response, options) { - store.reload(); - } - }) - } - } + Ext.Ajax.request({ + url: "v4l/services/" + adapterId, + params: { + op: "delete", + entries: Ext.encode(selectedKeys) + }, + failure: function(response, options) { + Ext.MessageBox.alert('Server Error', 'Unable to delete'); + }, + success: function(response, options) { + store.reload(); + } + }); + } + } - function saveChanges() { - var mr = store.getModifiedRecords(); - var out = new Array(); - for ( var x = 0; x < mr.length; x++) { - v = mr[x].getChanges(); - out[x] = v; - out[x].id = mr[x].id; - } + function saveChanges() { + var mr = store.getModifiedRecords(); + var out = new Array(); + for (var x = 0; x < mr.length; x++) { + v = mr[x].getChanges(); + out[x] = v; + out[x].id = mr[x].id; + } - Ext.Ajax.request({ - url : "v4l/services/" + adapterId, - params : { - op : "update", - entries : Ext.encode(out) - }, - success : function(response, options) { - store.commitChanges(); - }, - failure : function(response, options) { - Ext.MessageBox.alert('Message', response.statusText); - } - }); - } + Ext.Ajax.request({ + url: "v4l/services/" + adapterId, + params: { + op: "update", + entries: Ext.encode(out) + }, + success: function(response, options) { + store.commitChanges(); + }, + failure: function(response, options) { + Ext.MessageBox.alert('Message', response.statusText); + } + }); + } - var delButton = new Ext.Toolbar.Button({ - tooltip : 'Delete one or more selected rows', - iconCls : 'remove', - text : 'Delete selected services', - handler : delSelected, - disabled : true - }); + var delButton = new Ext.Toolbar.Button({ + tooltip: 'Delete one or more selected rows', + iconCls: 'remove', + text: 'Delete selected services', + handler: delSelected, + disabled: true + }); - var saveBtn = new Ext.Toolbar.Button({ - tooltip : 'Save any changes made (Changed cells have red borders).', - iconCls : 'save', - text : "Save changes", - handler : saveChanges, - disabled : true - }); + var saveBtn = new Ext.Toolbar.Button({ + tooltip: 'Save any changes made (Changed cells have red borders).', + iconCls: 'save', + text: "Save changes", + handler: saveChanges, + disabled: true + }); - var rejectBtn = new Ext.Toolbar.Button({ - tooltip : 'Revert any changes made (Changed cells have red borders).', - iconCls : 'undo', - text : "Revert changes", - handler : function() { - store.rejectChanges(); - }, - disabled : true - }); + var rejectBtn = new Ext.Toolbar.Button({ + tooltip: 'Revert any changes made (Changed cells have red borders).', + iconCls: 'undo', + text: "Revert changes", + handler: function() { + store.rejectChanges(); + }, + disabled: true + }); - var selModel = new Ext.grid.RowSelectionModel({ - singleSelect : false - }); + var selModel = new Ext.grid.RowSelectionModel({ + singleSelect: false + }); - var grid = new Ext.grid.EditorGridPanel({ - stripeRows : true, - title : 'Services', - plugins : [ enabledColumn ], - store : store, - clicksToEdit : 2, - cm : cm, - viewConfig : { - forceFit : true - }, - selModel : selModel, - tbar : [ - { - tooltip : 'Create a new entry on the server. ' - + 'The new entry is initially disabled so it must be enabled ' - + 'before it start taking effect.', - iconCls : 'add', - text : 'Add service', - handler : addRecord - }, '-', delButton, '-', saveBtn, rejectBtn ] - }); + var grid = new Ext.grid.EditorGridPanel({ + stripeRows: true, + title: 'Services', + plugins: [enabledColumn], + store: store, + clicksToEdit: 2, + cm: cm, + viewConfig: { + forceFit: true + }, + selModel: selModel, + tbar: [ + { + tooltip: 'Create a new entry on the server. ' + + 'The new entry is initially disabled so it must be enabled ' + + 'before it start taking effect.', + iconCls: 'add', + text: 'Add service', + handler: addRecord + }, '-', delButton, '-', saveBtn, rejectBtn] + }); - store.on('update', function(s, r, o) { - d = s.getModifiedRecords().length == 0 - saveBtn.setDisabled(d); - rejectBtn.setDisabled(d); - }); + store.on('update', function(s, r, o) { + d = s.getModifiedRecords().length === 0; + saveBtn.setDisabled(d); + rejectBtn.setDisabled(d); + }); - selModel.on('selectionchange', function(self) { - delButton.setDisabled(self.getCount() == 0); - }); + selModel.on('selectionchange', function(self) { + delButton.setDisabled(self.getCount() === 0); + }); - return grid; -} + return grid; +}; /** * */ tvheadend.v4l_adapter = function(data) { - var panel = new Ext.TabPanel({ - border : false, - activeTab : 0, - autoScroll : true, - items : [ new tvheadend.v4l_adapter_general(data), - new tvheadend.v4l_services(data.identifier) ] - }); - return panel; -} + var panel = new Ext.TabPanel({ + border: false, + activeTab: 0, + autoScroll: true, + items: [new tvheadend.v4l_adapter_general(data), + new tvheadend.v4l_services(data.identifier)] + }); + return panel; +};
' + (s.index > 0 ? s.index : ' ') + '' + p + '' + s.type + '' + (s.language || ' ') + '
' + s + '
' + d + '
' + (s.index > 0 ? s.index : ' ') + '' + p + '' + s.type + '' + (s.language || ' ') + '' + d + '