From a7c304a443329d1df86b3705483d61c2a14f1e11 Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 29 Jun 2014 15:59:01 +0100 Subject: [PATCH] webui: add clear filter option to all individual EPG filters --- src/webui/static/app/chconf.js | 20 ++++ src/webui/static/app/epg.js | 202 +++++++++++++++++++++++---------- 2 files changed, 162 insertions(+), 60 deletions(-) diff --git a/src/webui/static/app/chconf.js b/src/webui/static/app/chconf.js index 1b70bfb1..fe748791 100644 --- a/src/webui/static/app/chconf.js +++ b/src/webui/static/app/chconf.js @@ -1,6 +1,13 @@ /** * Channel tags */ +insertChannelTagsClearOption = function( scope, records, options ){ + var placeholder = scope.getAt(1); //create a 'template' copy of an existing record + placeholder.set('identifier',-1); + placeholder.set('name',"(Clear filter)"); + scope.insert(0, placeholder); +}; + tvheadend.channelTags = new Ext.data.JsonStore({ autoLoad: true, root: 'entries', @@ -9,6 +16,9 @@ tvheadend.channelTags = new Ext.data.JsonStore({ url: 'channeltags', baseParams: { op: 'listTags' + }, + listeners: { + 'load': insertChannelTagsClearOption } }); @@ -26,6 +36,13 @@ tvheadend.channelrec = new Ext.data.Record.create( ['name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start', 'epg_post_end', 'number']); +insertChannelClearOption = function( scope, records, options ){ + var placeholder = scope.getAt(1); //create a 'template' copy of an existing record + placeholder.set('key',-1); + placeholder.set('val',"(Clear filter)"); + scope.insert(0, placeholder); +}; + tvheadend.channels = new Ext.data.JsonStore({ url: 'api/channel/list', root: 'entries', @@ -35,6 +52,9 @@ tvheadend.channels = new Ext.data.JsonStore({ sortInfo: { field: 'val', direction: 'ASC' + }, + listeners: { + 'load': insertChannelClearOption } }); diff --git a/src/webui/static/app/epg.js b/src/webui/static/app/epg.js index c10e25a6..b63143cc 100644 --- a/src/webui/static/app/epg.js +++ b/src/webui/static/app/epg.js @@ -7,13 +7,24 @@ tvheadend.brands = new Ext.data.JsonStore({ op: 'brandList' } }); + +insertContentGroupClearOption = function( scope, records, options ){ + var placeholder = scope.getAt(1); //create a 'template' copy of an existing record + placeholder.set('code',-1); + placeholder.set('name',"(Clear filter)"); + scope.insert(0, placeholder); +}; + //WIBNI: might want this store to periodically update tvheadend.ContentGroupStore = new Ext.data.JsonStore({ root: 'entries', fields: ['name', 'code'], autoLoad: true, - url: 'ecglist' + url: 'ecglist', + listeners: { + 'load': insertContentGroupClearOption + } }); tvheadend.contentGroupLookupName = function(code) { @@ -40,8 +51,24 @@ tvheadend.channelLookupName = function(key) { return channelString; }; +// Store for duration filters - EPG, autorec dialog and autorec rules in the DVR grid +// NB: 'no max' is defined as 9999999s, or about 3 months... + +tvheadend.DurationStore = new Ext.data.SimpleStore({ + storeId: 'durationnames', + idIndex: 0, + fields: ['identifier','label','minvalue','maxvalue'], + data: [['-1', '(Clear filter)',"",""], + ['1','00:00:01 - 00:15:00',1, 900], + ['2','00:15:01 - 00:30:00', 901, 1800], + ['3','00:30:01 - 01:30:00', 1801, 5400], + ['4','01:30:01 - 03:00:00', 5401, 10800], + ['5','03:00:01 - No maximum', 10801, 9999999]] +}); + +// Function to convert numeric duration to corresponding label string // Note: triggered by minimum duration only. This would fail if ranges -// had the same minimum (e.g. 15-30 mins and 15-60 minutes) (which we don't). +// had the same minimum (e.g. 15-30 mins and 15-60 minutes) (which we don't have). tvheadend.durationLookupRange = function(value) { durationString = ""; @@ -54,22 +81,6 @@ tvheadend.durationLookupRange = function(value) { return durationString; }; -// NB: in the duration stores, 'no max' is defined as 9999999s, or about 3 months... - -// Store for autorec dialog and for autorec rules in the DVR grid - -tvheadend.DurationStore = new Ext.data.SimpleStore({ - storeId: 'durationnames', - idIndex: 0, - fields: ['identifier','label','minvalue','maxvalue'], - data: [['0', '(Clear filter)',"",""], - ['1','00:00:01 - 00:15:00',1, 900], - ['2','00:15:01 - 00:30:00', 901, 1800], - ['3','00:30:01 - 01:30:00', 1801, 5400], - ['4','01:30:01 - 03:00:00', 5401, 10800], - ['5','03:00:01 - No maximum', 10801, 9999999]] -}); - tvheadend.epgDetails = function(event) { var content = ''; @@ -419,7 +430,17 @@ tvheadend.epg = function() { editable: true, forceSelection: true, triggerAction: 'all', - emptyText: 'Filter channel...' + forceSelection: true, + typeAhead: true, + emptyText: 'Filter channel...', + listeners: { + blur: function () { + if(this.getRawValue() == "" ) { + clearChannelFilter(); + epgStore.reload(); + } + } + } }); // Tags, uses global store @@ -432,7 +453,18 @@ tvheadend.epg = function() { editable: true, forceSelection: true, triggerAction: 'all', - emptyText: 'Filter tag...' + forceSelection: true, + typeAhead: true, + emptyText: 'Filter tag...', + listeners: { + blur: function () { + if(this.getRawValue() == "" ) { + clearChannelTagsFilter(); + epgStore.reload(); + } + } + } + }); // Content groups @@ -446,75 +478,125 @@ tvheadend.epg = function() { editable: true, forceSelection: true, triggerAction: 'all', - emptyText: 'Filter content type...' + forceSelection: true, + typeAhead: true, + emptyText: 'Filter content type...', + listeners: { + blur: function () { + if(this.getRawValue() == "" ) { + clearContentGroupFilter(); + epgStore.reload(); + } + } + } }); var epgFilterDuration = new Ext.form.ComboBox({ loadingText: 'Loading...', - width: 200, + width: 150, displayField: 'label', store: tvheadend.DurationStore, mode: 'local', editable: true, forceSelection: true, triggerAction: 'all', - emptyText: 'Filter duration...' + forceSelection: true, + typeAhead: true, + emptyText: 'Filter duration...', + listeners: { + blur: function () { + if(this.getRawValue() == "" ) { + clearDurationFilter(); + epgStore.reload(); + } + } + } + }); - function epgQueryClear() { +/* + * Clear filter functions + */ - delete epgStore.baseParams.channel; - delete epgStore.baseParams.tag; - delete epgStore.baseParams.contenttype; + clearTitleFilter = function() { delete epgStore.baseParams.title; - delete epgStore.baseParams.minduration; - delete epgStore.baseParams.maxduration; - - epgFilterChannels.setValue(""); - epgFilterChannelTags.setValue(""); - epgFilterContentGroup.setValue(""); - epgFilterDuration.setValue(""); epgFilterTitle.setValue(""); + }; + clearChannelFilter = function() { + delete epgStore.baseParams.channel; + epgFilterChannels.setValue(""); + }; + + clearChannelTagsFilter = function() { + delete epgStore.baseParams.tag; + epgFilterChannelTags.setValue(""); + }; + + clearContentGroupFilter = function() { + delete epgStore.baseParams.contenttype; + epgFilterContentGroup.setValue(""); + }; + + clearDurationFilter = function() { + delete epgStore.baseParams.minduration; + delete epgStore.baseParams.maxduration; + epgFilterDuration.setValue(""); + }; + + function epgQueryClear() { + clearTitleFilter(); + clearChannelFilter(); + clearChannelTagsFilter(); + clearDurationFilter(); + clearContentGroupFilter(); epgStore.reload(); - } + }; +/* + * Filter selection event handlers + */ + epgFilterChannels.on('select', function(c, r) { - if (epgStore.baseParams.channel !== r.data.key) { - epgStore.baseParams.channel = r.data.key; - epgStore.reload(); - } + if (r.data.key == -1) + clearChannelFilter(); + else if (epgStore.baseParams.channel !== r.data.key) + epgStore.baseParams.channel = r.data.key; + epgStore.reload(); }); epgFilterChannelTags.on('select', function(c, r) { - if (epgStore.baseParams.tag !== r.data.name) { - epgStore.baseParams.tag = r.data.name; - epgStore.reload(); - } - }); + if (r.data.identifier == -1) + clearChannelTagsFilter(); + else if (epgStore.baseParams.tag !== r.data.name) + epgStore.baseParams.tag = r.data.name; + epgStore.reload(); + }); + +//IH +// TODO - check what gets saved and where, and how we filter out null tages - may happen automatically because there's +// already a null tag. I think this only applies to tags, as they're saved to config +// +// Also, check that the insert method is genuinely inserting and not over-writing the first record. epgFilterContentGroup.on('select', function(c, r) { - if (epgStore.baseParams.contenttype !== r.data.code) { - epgStore.baseParams.contenttype = r.data.code; - epgStore.reload(); - } + if (r.data.code == -1) + clearContentGroupFilter(); + else if (epgStore.baseParams.contenttype !== r.data.code) + epgStore.baseParams.contenttype = r.data.code; + epgStore.reload(); }); epgFilterDuration.on('select', function(c, r) { - if (epgStore.baseParams.minduration !== r.data.minvalue) { - if (r.data.identifier == 0) { - delete epgStore.baseParams.minduration; - delete epgStore.baseParams.maxduration; - epgFilterDuration.setValue(""); - } else - { - epgStore.baseParams.minduration = r.data.minvalue; - epgStore.baseParams.maxduration = r.data.maxvalue; - } - epgStore.reload(); + if (r.data.identifier == -1) + clearDurationFilter(); + else if (epgStore.baseParams.minduration !== r.data.minvalue) { + epgStore.baseParams.minduration = r.data.minvalue; + epgStore.baseParams.maxduration = r.data.maxvalue; } + epgStore.reload(); }); - + epgFilterTitle.on('valid', function(c) { var value = c.getValue();