Rebase after PR #381

Conflicts:
	src/webui/static/app/config.js
	src/webui/static/app/dvr.js
	src/webui/static/app/timeshift.js
This commit is contained in:
Ian 2014-05-24 23:28:07 +01:00
commit b23472ce51
29 changed files with 7017 additions and 7001 deletions

View file

@ -34,7 +34,6 @@
#include <sys/un.h>
#include <netdb.h>
#include <netinet/in.h>
#include <linux/dvb/ca.h>
#include <fcntl.h>
#include "tvheadend.h"
@ -44,6 +43,7 @@
#if ENABLE_LINUXDVB
#include <linux/dvb/ca.h>
#include "notify.h"
#include "subscriptions.h"
#include "dtable.h"

View file

@ -20,7 +20,6 @@
#include <assert.h>
#include <unistd.h>
#include <regex.h>
#include <linux/dvb/dmx.h>
#include "tvheadend.h"
#include "channels.h"
#include "huffman.h"

View file

@ -30,8 +30,6 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <linux/dvb/version.h>
#include <linux/dvb/frontend.h>
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
};

View file

@ -22,7 +22,9 @@
#include "input.h"
#if ENABLE_LINUXDVB
#include <linux/dvb/version.h>
#endif
#define DVB_VER_INT(maj,min) (((maj) << 16) + (min))

View file

@ -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);

View file

@ -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 '<span class="tvh-grid-unset">Hidden</span>';
},
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 '<span class="tvh-grid-unset">Hidden</span>';
},
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');
};

View file

@ -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');
};

View file

@ -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 "<a href='stream/channel/" + r.id + "'>Play</a>";
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 "<a href='stream/channel/" + r.id + "'>Play</a>";
}
}
],
sort: {
field: 'number',
direction: 'ASC'
}
});
};

View file

@ -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);
};

View file

@ -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;
};

View file

@ -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');
};

View file

@ -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 '<span class="tvh-grid-unset">Hidden</span>';
},
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 '<span class="tvh-grid-unset">Hidden</span>';
},
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 '<span class="tvh-grid-unset">Hidden</span>';
},
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 '<span class="tvh-grid-unset">Hidden</span>';
},
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;
};

File diff suppressed because it is too large Load diff

948
src/webui/static/app/epg.js Executable file → Normal file

File diff suppressed because it is too large Load diff

View file

@ -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;
};

View file

@ -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');
}
});
};

View file

@ -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 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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
: '<span class="tvh-grid-unset">Unmapped</span>';
},
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 : '<span class="tvh-grid-unset">Unset</span>';
},
editor : new fm.TextField({
allowBlank : false
})
},
{
header : "Group",
dataIndex : 'group',
width : 100,
renderer : function(value, metadata, record, row, col, store) {
return value ? value : '<span class="tvh-grid-unset">Unset</span>';
},
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')
: '<span class="tvh-grid-unset">Unset</span>';
}
}, {
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
: '<span class="tvh-grid-unset">Unmapped</span>';
},
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 : '<span class="tvh-grid-unset">Unset</span>';
},
editor: new fm.TextField({
allowBlank: false
})
},
{
header: "Group",
dataIndex: 'group',
width: 100,
renderer: function(value, metadata, record, row, col, store) {
return value ? value : '<span class="tvh-grid-unset">Unset</span>';
},
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')
: '<span class="tvh-grid-unset">Unset</span>';
}
}, {
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;
};

View file

@ -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 "<a href='stream/mux/" + r.id + "'>Play</a>";
}
}
],
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 "<a href='stream/mux/" + r.id + "'>Play</a>";
});
};
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 = '&nbsp;' + r;
}
}
],
sort : {
field : 'name',
direction : 'ASC'
return r;
}
});
}
tvheadend.show_service_streams = function ( data ) {
var i, j;
var html = '';
function header( ) {
html += '<table style="font-size:8pt;font-family:mono;padding:2px"';
html += '<tr>';
html += '<th style="width:50px;font-weight:bold">Index</th>';
html += '<th style="width:120px;font-weight:bold">PID</th>';
html += '<th style="width:100px;font-weight:bold">Type</th>';
html += '<th style="width:75px;font-weight:bold">Language</th>';
html += '<th style="width:*;font-weight:bold">Details</th>';
html += '</tr>';
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 = '&nbsp;' + r;
}
return r;
}
function header ( ) {
html += '<table style="font-size:8pt;font-family:mono;padding:2px"';
html += '<tr>';
html += '<th style="width:50px;font-weight:bold">Index</th>';
html += '<th style="width:120px;font-weight:bold">PID</th>';
html += '<th style="width:100px;font-weight:bold">Type</th>';
html += '<th style="width:75px;font-weight:bold">Language</th>';
html += '<th style="width:*;font-weight:bold">Details</th>';
html += '</tr>';
}
function single ( s ) {
html += '<tr><td colspan="5">' + s + '</td></tr>';
}
function stream ( s ) {
var d = '&nbsp;';
var p = '0x' + hexstr(s.pid) + '&nbsp;/&nbsp;' + fixstr(s.pid);
html += '<tr>';
html += '<td>' + (s.index > 0 ? s.index : '&nbsp;') + '</td>';
html += '<td>' + p + '</td>';
html += '<td>' + s.type + '</td>';
html += '<td>' + (s.language || '&nbsp;') + '</td>'
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 += '<tr><td colspan="5">' + s + '</td></tr>';
}
html += '<td>' + d + '</td>';
html += '</tr>';
}
header();
function stream(s) {
var d = '&nbsp;';
var p = '0x' + hexstr(s.pid) + '&nbsp;/&nbsp;' + fixstr(s.pid);
if (data.streams.length) {
for (i = 0; i < data.streams.length; i++)
stream(data.streams[i]);
} else
single('None');
html += '<tr>';
html += '<td>' + (s.index > 0 ? s.index : '&nbsp;') + '</td>';
html += '<td>' + p + '</td>';
html += '<td>' + s.type + '</td>';
html += '<td>' + (s.language || '&nbsp;') + '</td>';
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 += '<td>' + d + '</td>';
html += '</tr>';
}
single('&nbsp;');
single('<h3>After filtering and reordering (without PCR and PMT)</h3>');
header();
header();
if (data.fstreams.length)
for (i = 0; i < data.fstreams.length; i++)
stream(data.fstreams[i]);
else
single('<p>None</p>');
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('&nbsp;');
single('<h3>After filtering and reordering (without PCR and PMT)</h3>');
header();
if (data.fstreams.length)
for (i = 0; i < data.fstreams.length; i++)
stream(data.fstreams[i]);
else
single('<p>None</p>');
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 "<a href='stream/service/" + r.id + "'>Play</a>";
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 "<a href='stream/service/" + r.id + "'>Play</a>";
}
},
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
});
};

View file

@ -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();
};

File diff suppressed because it is too large Load diff

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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');
}
});
};

View file

@ -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 ? '<div style="' + style + '">' : '<div>'
s = style ? '<div style="' + style + '">' : '<div>';
sl = Ext.get('systemlog');
e = Ext.DomHelper.append(sl, s + '<pre>' + msg + '</pre></div>');
e.scrollIntoView('systemlog');
}
sl = Ext.get('systemlog');
e = Ext.DomHelper.append(sl, s + '<pre>' + msg + '</pre></div>');
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: '<div id="header"><h1>Tvheadend Web-Panel</h1></div>'
});
// public methods
init : function() {
var header = new Ext.Panel({
split: true,
region: 'north',
height : 45,
boxMaxHeight : 45,
boxMinHeight : 45,
border: false,
hidden: true,
html: '<div id="header"><h1>Tvheadend Web-Panel</h1></div>'
});
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

View file

@ -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;
};

View file

@ -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(
'<h2 style="font-size: 150%">Hardware</h2>'
+ '<h3>Device path:</h3>{path}' + '<h3>Device name:</h3>{devicename}'
+ '<h2 style="font-size: 150%">Status</h2>'
+ '<h3>Currently tuned to:</h3>{currentMux}&nbsp');
var infoTemplate = new Ext.XTemplate(
'<h2 style="font-size: 150%">Hardware</h2>'
+ '<h3>Device path:</h3>{path}' + '<h3>Device name:</h3>{devicename}'
+ '<h2 style="font-size: 150%">Status</h2>'
+ '<h3>Currently tuned to:</h3>{currentMux}&nbsp');
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 : '<span class="tvh-grid-unset">Unmapped</span>';
},
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 : '<span class="tvh-grid-unset">Unmapped</span>';
},
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;
};