]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
WEBUI: Add initial UI level handling for idnode panels
authorJaroslav Kysela <perex@perex.cz>
Tue, 1 Dec 2015 14:06:25 +0000 (15:06 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 1 Dec 2015 14:06:25 +0000 (15:06 +0100)
src/channels.c
src/config.c
src/dvr/dvr_config.c
src/webui/static/app/ext.css
src/webui/static/app/idnode.js
src/webui/static/app/tvheadend.js
src/webui/static/icons/application_form.png [new symlink]

index f049fd5dcaceb667b51c19e4f1fd2df249355e42..080ac33f1ba47b0e1ebab5800cdfe7bb61e5d258 100644 (file)
@@ -359,6 +359,7 @@ const idclass_t channel_class = {
       .name     = N_("Automatically name from network"),
       .off      = offsetof(channel_t, ch_autoname),
       .set      = channel_class_autoname_set,
+      .opts     = PO_ADVANCED,
       .opts     = PO_NOSAVE,
     },
     {
@@ -384,19 +385,21 @@ const idclass_t channel_class = {
       .name     = N_("User icon"),
       .off      = offsetof(channel_t, ch_icon),
       .notify   = channel_class_icon_notify,
+      .opts     = PO_ADVANCED,
     },
     {
       .type     = PT_STR,
       .id       = "icon_public_url",
       .name     = N_("Icon URL"),
       .get      = channel_class_get_icon,
-      .opts     = PO_RDONLY | PO_NOSAVE | PO_HIDDEN,
+      .opts     = PO_RDONLY | PO_NOSAVE | PO_HIDDEN | PO_EXPERT,
     },
     {
       .type     = PT_BOOL,
       .id       = "epgauto",
       .name     = N_("Automatically map EPG source"),
       .off      = offsetof(channel_t, ch_epgauto),
+      .opts     = PO_ADVANCED,
     },
     {
       .type     = PT_STR,
@@ -406,7 +409,7 @@ const idclass_t channel_class = {
       .set      = channel_class_epggrab_set,
       .get      = channel_class_epggrab_get,
       .list     = channel_class_epggrab_list,
-      .opts     = PO_NOSAVE,
+      .opts     = PO_NOSAVE | PO_ADVANCED,
     },
     {
       .type     = PT_INT,
@@ -439,6 +442,7 @@ const idclass_t channel_class = {
       .set      = channel_class_services_set,
       .list     = channel_class_services_enum,
       .rend     = channel_class_services_rend,
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_STR,
@@ -448,7 +452,8 @@ const idclass_t channel_class = {
       .get      = channel_class_tags_get,
       .set      = channel_class_tags_set,
       .list     = channel_tag_class_get_list,
-      .rend     = channel_class_tags_rend
+      .rend     = channel_class_tags_rend,
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_STR,
@@ -457,7 +462,7 @@ const idclass_t channel_class = {
       .get      = channel_class_bouquet_get,
       .set      = channel_class_bouquet_set,
       .list     = bouquet_class_get_list,
-      .opts     = PO_RDONLY
+      .opts     = PO_RDONLY | PO_ADVANCED
     },
     {
       .type     = PT_STR,
@@ -466,7 +471,7 @@ const idclass_t channel_class = {
       .set      = channel_class_epg_parent_set,
       .list     = channel_class_get_list,
       .off      = offsetof(channel_t, ch_epg_parent),
-      .opts     = PO_ADVANCED
+      .opts     = PO_EXPERT
     },
     {}
   }
@@ -1279,6 +1284,7 @@ const idclass_t channel_tag_class = {
       .id       = "index",
       .name     = N_("Sort index"),
       .off      = offsetof(channel_tag_t, ct_index),
+      .opts     = PO_ADVANCED,
     },
     {
       .type     = PT_STR,
@@ -1291,12 +1297,14 @@ const idclass_t channel_tag_class = {
       .id       = "internal",
       .name     = N_("Internal"),
       .off      = offsetof(channel_tag_t, ct_internal),
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_BOOL,
       .id       = "private",
       .name     = N_("Private"),
       .off      = offsetof(channel_tag_t, ct_private),
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_STR,
@@ -1304,19 +1312,21 @@ const idclass_t channel_tag_class = {
       .name     = N_("Icon (full URL)"),
       .off      = offsetof(channel_tag_t, ct_icon),
       .notify   = channel_tag_class_icon_notify,
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_STR,
       .id       = "icon_public_url",
       .name     = N_("Icon URL"),
       .get      = channel_tag_class_get_icon,
-      .opts     = PO_RDONLY | PO_NOSAVE | PO_HIDDEN,
+      .opts     = PO_RDONLY | PO_NOSAVE | PO_HIDDEN | PO_EXPERT,
     },
     {
       .type     = PT_BOOL,
       .id       = "titled_icon",
       .name     = N_("Icon has title"),
       .off      = offsetof(channel_tag_t, ct_titled_icon),
+      .opts     = PO_ADVANCED
     },
     {
       .type     = PT_STR,
index ef891cd9c46d15922db1173d83223371e49d0902..fee0440331640250f85671d2501f5a75b1a4949c 100644 (file)
@@ -1948,7 +1948,7 @@ const idclass_t config_class = {
       .id     = "version",
       .name   = N_("Configuration version"),
       .off    = offsetof(config_t, version),
-      .opts   = PO_RDONLY | PO_HIDDEN,
+      .opts   = PO_RDONLY | PO_HIDDEN | PO_EXPERT,
       .group  = 1
     },
     {
@@ -1956,7 +1956,7 @@ const idclass_t config_class = {
       .id     = "full_version",
       .name   = N_("Last updated from"),
       .off    = offsetof(config_t, full_version),
-      .opts   = PO_RDONLY | PO_HIDDEN,
+      .opts   = PO_RDONLY | PO_HIDDEN | PO_EXPERT,
       .group  = 1
     },
     {
@@ -1979,6 +1979,7 @@ const idclass_t config_class = {
       .id     = "cookie_expires",
       .name   = N_("Cookie expiration (days)"),
       .off    = offsetof(config_t, cookie_expires),
+      .opts   = PO_ADVANCED,
       .group  = 1
     },
     {
@@ -1987,6 +1988,7 @@ const idclass_t config_class = {
       .name   = N_("HTTP CORS origin"),
       .set    = config_class_cors_origin_set,
       .off    = offsetof(config_t, cors_origin),
+      .opts   = PO_EXPERT,
       .group  = 1
     },
     {
@@ -1995,6 +1997,7 @@ const idclass_t config_class = {
       .name   = N_("DSCP/TOS for streaming"),
       .off    = offsetof(config_t, dscp),
       .list   = config_class_dscp_list,
+      .opts   = PO_EXPERT,
       .group  = 1
     },
     {
@@ -2002,6 +2005,7 @@ const idclass_t config_class = {
       .id     = "descrambler_buffer",
       .name   = N_("Descrambler buffer (TS packets)"),
       .off    = offsetof(config_t, descrambler_buffer),
+      .opts   = PO_EXPERT,
       .group  = 1
     },
     {
@@ -2023,7 +2027,7 @@ const idclass_t config_class = {
       .set    = config_class_info_area_set,
       .get    = config_class_info_area_get,
       .list   = config_class_info_area_list,
-      .opts   = PO_LORDER,
+      .opts   = PO_LORDER | PO_ADVANCED,
       .group  = 3
     },
     {
@@ -2039,6 +2043,7 @@ const idclass_t config_class = {
       .id     = "muxconfpath",
       .name   = N_("DVB scan files path"),
       .off    = offsetof(config_t, muxconf_path),
+      .opts   = PO_ADVANCED,
       .group  = 4
     },
     {
@@ -2046,6 +2051,7 @@ const idclass_t config_class = {
       .id     = "tvhtime_update_enabled",
       .name   = N_("Update time"),
       .off    = offsetof(config_t, tvhtime_update_enabled),
+      .opts   = PO_EXPERT,
       .group  = 5,
     },
     {
@@ -2053,6 +2059,7 @@ const idclass_t config_class = {
       .id     = "tvhtime_ntp_enabled",
       .name   = N_("Enable NTP driver"),
       .off    = offsetof(config_t, tvhtime_update_enabled),
+      .opts   = PO_EXPERT,
       .group  = 5,
     },
     {
@@ -2060,6 +2067,7 @@ const idclass_t config_class = {
       .id     = "tvhtime_tolerance",
       .name   = N_("Update tolerance (ms)"),
       .off    = offsetof(config_t, tvhtime_tolerance),
+      .opts   = PO_EXPERT,
       .group  = 5,
     },
     {
@@ -2067,6 +2075,7 @@ const idclass_t config_class = {
       .id     = "prefer_picon",
       .name   = N_("Prefer picons over channel name"),
       .off    = offsetof(config_t, prefer_picon),
+      .opts   = PO_ADVANCED,
       .group  = 6,
     },
     {
@@ -2074,6 +2083,7 @@ const idclass_t config_class = {
       .id     = "chiconpath",
       .name   = N_("Channel icon path (see Help)"),
       .off    = offsetof(config_t, chicon_path),
+      .opts   = PO_ADVANCED,
       .group  = 6,
     },
     {
@@ -2081,6 +2091,7 @@ const idclass_t config_class = {
       .id     = "chiconlowercase",
       .name   = N_("Channel icon name lower-case"),
       .off    = offsetof(config_t, chicon_lowercase),
+      .opts   = PO_ADVANCED,
       .group  = 6,
     },
     {
@@ -2088,6 +2099,7 @@ const idclass_t config_class = {
       .id     = "piconpath",
       .name   = N_("Picon path (see Help)"),
       .off    = offsetof(config_t, picon_path),
+      .opts   = PO_ADVANCED,
       .group  = 6,
     },
     {}
index f23d47f99f393b982cb91a4049844fd107e91c4d..988d3d1f4bafcff8b622542358a330192ab1d8cd 100644 (file)
@@ -807,6 +807,7 @@ const idclass_t dvr_config_class = {
       .off      = offsetof(dvr_config_t, dvr_muxcnf.m_cache),
       .def.i    = MC_CACHE_DONTKEEP,
       .list     = dvr_config_class_cache_list,
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -829,6 +830,7 @@ const idclass_t dvr_config_class = {
       .id       = "clone",
       .name     = N_("Clone scheduled entry on error"),
       .off      = offsetof(dvr_config_t, dvr_clone),
+      .opts     = PO_ADVANCED,
       .def.u32  = 1,
       .group    = 1,
     },
@@ -837,6 +839,7 @@ const idclass_t dvr_config_class = {
       .id       = "rerecord-errors",
       .name     = N_("Schedule a re-recording if more errors than (0=off)"),
       .off      = offsetof(dvr_config_t, dvr_rerecord_errors),
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -844,6 +847,7 @@ const idclass_t dvr_config_class = {
       .id       = "warm-time",
       .name     = N_("Extra warming up time (seconds)"),
       .off      = offsetof(dvr_config_t, dvr_warm_time),
+      .opts     = PO_ADVANCED,
       .group    = 1,
       .def.u32  = 30
     },
@@ -853,6 +857,7 @@ const idclass_t dvr_config_class = {
       .name     = N_("Extra padding before recordings (minutes)"),
       .off      = offsetof(dvr_config_t, dvr_extra_time_pre),
       .list     = dvr_config_class_extra_list,
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -861,6 +866,7 @@ const idclass_t dvr_config_class = {
       .name     = N_("Extra padding after recordings (minutes)"),
       .off      = offsetof(dvr_config_t, dvr_extra_time_post),
       .list     = dvr_config_class_extra_list,
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -870,6 +876,7 @@ const idclass_t dvr_config_class = {
       .off      = offsetof(dvr_config_t, dvr_update_window),
       .list     = dvr_config_entry_class_update_window_list,
       .def.u32  = 24*3600,
+      .opts     = PO_EXPERT,
       .group    = 1,
     },
     {
@@ -877,6 +884,7 @@ const idclass_t dvr_config_class = {
       .id       = "epg-running",
       .name     = N_("Use EPG running state"),
       .off      = offsetof(dvr_config_t, dvr_running),
+      .opts     = PO_ADVANCED,
       .def.u32  = 1,
       .group    = 1,
     },
@@ -885,6 +893,7 @@ const idclass_t dvr_config_class = {
       .id       = "autorec-maxcount",
       .name     = N_("Autorec maximum count (0=unlimited)"),
       .off      = offsetof(dvr_config_t, dvr_autorec_max_count),
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -892,6 +901,7 @@ const idclass_t dvr_config_class = {
       .id       = "autorec-maxsched",
       .name     = N_("Autorec maximum schedules limit (0=unlimited)"),
       .off      = offsetof(dvr_config_t, dvr_autorec_max_sched_count),
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -899,6 +909,7 @@ const idclass_t dvr_config_class = {
       .id       = "postproc",
       .name     = N_("Post-processor command"),
       .off      = offsetof(dvr_config_t, dvr_postproc),
+      .opts     = PO_ADVANCED,
       .group    = 1,
     },
     {
@@ -906,6 +917,7 @@ const idclass_t dvr_config_class = {
       .id       = "postremove",
       .name     = N_("Post-remove command"),
       .off      = offsetof(dvr_config_t, dvr_postremove),
+      .opts     = PO_EXPERT,
       .group    = 1,
     },
     {
@@ -920,6 +932,7 @@ const idclass_t dvr_config_class = {
       .id       = "file-permissions",
       .name     = N_("File permissions (octal, e.g. 0664)"),
       .off      = offsetof(dvr_config_t, dvr_muxcnf.m_file_permissions),
+      .opts     = PO_EXPERT,
       .def.u32  = 0664,
       .group    = 2,
     },
@@ -930,6 +943,7 @@ const idclass_t dvr_config_class = {
       .off      = offsetof(dvr_config_t, dvr_charset),
       .set      = dvr_config_class_charset_set,
       .list     = dvr_config_class_charset_list,
+      .opts     = PO_ADVANCED,
       .def.s    = "UTF-8",
       .group    = 2,
     },
@@ -938,6 +952,7 @@ const idclass_t dvr_config_class = {
       .id       = "tag-files",
       .name     = N_("Tag files with metadata"),
       .off      = offsetof(dvr_config_t, dvr_tag_files),
+      .opts     = PO_ADVANCED,
       .def.i    = 1,
       .group    = 2,
     },
@@ -946,6 +961,7 @@ const idclass_t dvr_config_class = {
       .id       = "skip-commercials",
       .name     = N_("Skip commercials"),
       .off      = offsetof(dvr_config_t, dvr_skip_commercials),
+      .opts     = PO_ADVANCED,
       .def.i    = 1,
       .group    = 2,
     },
@@ -955,6 +971,7 @@ const idclass_t dvr_config_class = {
       .name     = N_("Format String"),
       .set      = dvr_config_class_pathname_set,
       .off      = offsetof(dvr_config_t, dvr_pathname),
+      .opts     = PO_EXPERT,
       .group    = 3,
     },
     {
@@ -962,6 +979,7 @@ const idclass_t dvr_config_class = {
       .id       = "directory-permissions",
       .name     = N_("Directory permissions (octal, e.g. 0775)"),
       .off      = offsetof(dvr_config_t, dvr_muxcnf.m_directory_permissions),
+      .opts     = PO_EXPERT,
       .def.u32  = 0775,
       .group    = 4,
     },
@@ -970,6 +988,7 @@ const idclass_t dvr_config_class = {
       .id       = "day-dir",
       .name     = N_("Make subdirectories per day"),
       .off      = offsetof(dvr_config_t, dvr_dir_per_day),
+      .opts     = PO_EXPERT,
       .group    = 4,
     },
     {
@@ -977,6 +996,7 @@ const idclass_t dvr_config_class = {
       .id       = "channel-dir",
       .name     = N_("Make subdirectories per channel"),
       .off      = offsetof(dvr_config_t, dvr_channel_dir),
+      .opts     = PO_EXPERT,
       .group    = 4,
     },
     {
@@ -984,6 +1004,7 @@ const idclass_t dvr_config_class = {
       .id       = "title-dir",
       .name     = N_("Make subdirectories per title"),
       .off      = offsetof(dvr_config_t, dvr_title_dir),
+      .opts     = PO_EXPERT,
       .group    = 4,
     },
     {
@@ -991,6 +1012,7 @@ const idclass_t dvr_config_class = {
       .id       = "channel-in-title",
       .name     = N_("Include channel name in filename"),
       .off      = offsetof(dvr_config_t, dvr_channel_in_title),
+      .opts     = PO_EXPERT,
       .group    = 5,
     },
     {
@@ -998,6 +1020,7 @@ const idclass_t dvr_config_class = {
       .id       = "date-in-title",
       .name     = N_("Include date In filename"),
       .off      = offsetof(dvr_config_t, dvr_date_in_title),
+      .opts     = PO_EXPERT,
       .group    = 5,
     },
     {
@@ -1005,6 +1028,7 @@ const idclass_t dvr_config_class = {
       .id       = "time-in-title",
       .name     = N_("Include time In filename"),
       .off      = offsetof(dvr_config_t, dvr_time_in_title),
+      .opts     = PO_EXPERT,
       .group    = 5,
     },
     {
@@ -1012,6 +1036,7 @@ const idclass_t dvr_config_class = {
       .id       = "episode-in-title",
       .name     = N_("Include episode in filename"),
       .off      = offsetof(dvr_config_t, dvr_episode_in_title),
+      .opts     = PO_EXPERT,
       .group    = 5,
     },
     {
@@ -1019,6 +1044,7 @@ const idclass_t dvr_config_class = {
       .id       = "subtitle-in-title",
       .name     = N_("Include subtitle in filename"),
       .off      = offsetof(dvr_config_t, dvr_subtitle_in_title),
+      .opts     = PO_EXPERT,
       .group    = 6,
     },
     {
@@ -1026,6 +1052,7 @@ const idclass_t dvr_config_class = {
       .id       = "omit-title",
       .name     = N_("Don't include title in filename"),
       .off      = offsetof(dvr_config_t, dvr_omit_title),
+      .opts     = PO_EXPERT,
       .group    = 6,
     },
     {
@@ -1033,6 +1060,7 @@ const idclass_t dvr_config_class = {
       .id       = "clean-title",
       .name     = N_("Remove all unsafe characters from filename"),
       .off      = offsetof(dvr_config_t, dvr_clean_title),
+      .opts     = PO_EXPERT,
       .group    = 6,
     },
     {
@@ -1040,6 +1068,7 @@ const idclass_t dvr_config_class = {
       .id       = "whitespace-in-title",
       .name     = N_("Replace whitespace in title with '-'"),
       .off      = offsetof(dvr_config_t, dvr_whitespace_in_title),
+      .opts     = PO_EXPERT,
       .group    = 6,
     },
     {
@@ -1047,6 +1076,7 @@ const idclass_t dvr_config_class = {
       .id       = "windows-compatible-filenames",
       .name     = N_("Use Windows-compatible filenames"),
       .off      = offsetof(dvr_config_t, dvr_windows_compatible_filenames),
+      .opts     = PO_EXPERT,
       .group    = 6,
     },
     {}
index 7b21936520d6b002c6162bb440347439cbc229dd..93152bfab5cceb916fb7becac85cee3d35c3d234 100644 (file)
     background-image: url(../icons/find.png) !important;
 }
 
+.uilevel {
+    background-image: url(../icons/application_form.png) !important;
+}
+
 .imdb {
     background-image: url(../icons/imdb.png) !important;
 }
index 1d1f443525c077fcdaa8d851e89d4e32c586218b..1de95c14d86944ff9e94d0e98e2d7fdb02b5e931 100644 (file)
@@ -240,7 +240,8 @@ tvheadend.IdNodeField = function(conf)
     this.rdonly = conf.rdonly;
     this.wronly = conf.wronly;
     this.wronce = conf.wronce;
-    this.hidden = conf.hidden || conf.advanced;
+    this.hidden = conf.hidden;
+    this.uilevel = conf.expert ? 'expert' : (conf.advanced ? 'advanced' : 'basic');
     this.password = conf.showpwd ? false : conf.password;
     this.duration = conf.duration;
     this.date = conf.date;
@@ -275,7 +276,19 @@ tvheadend.IdNodeField = function(conf)
             st.un('load', callback);
     }
 
-    this.column = function(conf)
+    this.get_hidden = function(uilevel) {
+        var hidden = this.hidden;
+        console.log('init hidden for', this.id, ' is ', hidden);
+        if (uilevel !== 'expert') {
+            if (uilevel === 'advanced' && this.uilevel === 'expert')
+                hidden = true;
+            else if (uilevel === 'basic' && this.uilevel !== 'basic')
+                hidden = true;
+        }
+        return hidden;
+    }
+
+    this.column = function(uilevel, conf)
     {
         var cfg = conf && this.id in conf ? conf[this.id] : {};
         var w = 300;
@@ -309,7 +322,7 @@ tvheadend.IdNodeField = function(conf)
             editor: this.editor({create: false}),
             renderer: cfg.renderer ? cfg.renderer(this.store) : this.renderer(this.store),
             editable: !this.rdonly,
-            hidden: this.hidden,
+            hidden: this.get_hidden(uilevel),
             filter: {
                 type: ftype,
                 dataIndex: this.id,
@@ -560,6 +573,42 @@ tvheadend.IdNode = function(conf)
     };
 };
 
+/*
+ *
+ */
+tvheadend.idnode_uilevel_text = function(uilevel)
+{
+    if (uilevel === 'basic')
+        return _('Basic');
+    if (uilevel === 'advanced')
+        return _('Advanced');
+    return _('Expert');
+}
+
+tvheadend.idnode_uilevel_change = function(button, uilevel)
+{
+    if (uilevel == 'basic')
+        uilevel = 'advanced';
+    else if (uilevel == 'advanced')
+        uilevel = 'expert';
+    else
+        uilevel = 'basic';
+    button.setText(tvheadend.idnode_uilevel_text(uilevel));
+    return uilevel;
+}
+
+tvheadend.idnode_uilevel_button = function(uilevel, handler)
+{
+    var b = new Ext.Toolbar.Button({
+        tooltip: _('Change the user interface level (basic, advanced, expert)'),
+        iconCls: 'uilevel',
+        text: tvheadend.idnode_uilevel_text(uilevel),
+        disabled: true,
+        handler: handler
+    });
+    b.setDisabled(false);
+    return b;
+}
 
 /*
  * Field editor
@@ -758,7 +807,7 @@ tvheadend.idnode_editor_field = function(f, conf)
 /*
  * ID node editor form fields
  */
-tvheadend.idnode_editor_form = function(d, meta, panel, conf)
+tvheadend.idnode_editor_form = function(uilevel, d, meta, panel, conf)
 {
     var af = [];
     var ef = [];
@@ -800,6 +849,7 @@ tvheadend.idnode_editor_form = function(d, meta, panel, conf)
             });
         }
         if (p.group && meta.groups) {
+            f.tvh_uilevel = p.expert ? 'expert' : (p.advanced ? 'advanced' : 'basic');
             if (!groups)
                 groups = {};
             if (!(p.group in groups))
@@ -807,14 +857,20 @@ tvheadend.idnode_editor_form = function(d, meta, panel, conf)
             else
                 groups[p.group].push(f);
         } else {
-            if (p.rdonly)
-                rf.push(f);
-            else if (p.expert)
-                ef.push(f);
-            else if (p.advanced)
-                af.push(f);
-            else
+            if (p.rdonly) {
+                if (uilevel === 'expert' || (!p.advanced && !p.expert))
+                    rf.push(f);
+                else if (p.advanced && p.advanced)
+                    rf.push(f);
+            } else if (p.expert) {
+                if (uilevel === 'expert')
+                    ef.push(f);
+            } else if (p.advanced) {
+                if (uilevel !== 'basic')
+                    af.push(f);
+            } else {
                 df.push(f);
+            }
         }
     }
 
@@ -880,10 +936,28 @@ tvheadend.idnode_editor_form = function(d, meta, panel, conf)
         }
         for (var number in groups) {
             var g = groups[number];
-            for (var i = 0; i < g.length; i++)
-                cfs[number].add(g[i]);
-            if (number in mfs)
+            var cnt = 0;
+            for (var i = 0; i < g.length; i++) {
+                var f = g[i];
+                var hide = false;
+                if (uilevel == 'basic') {
+                    hide = f.tvh_uilevel !== 'basic';
+                } else if (uilevel == 'advanced') {
+                    hide = f.tvh_uilevel === 'expert';
+                }
+                if (hide)
+                    f.setVisible(false);
+                else
+                    cnt++;
+                cfs[number].add(f);
+            }
+            if (!cnt)
+                cfs[number].setVisible(false);
+            if (number in mfs) {
                 panel.add(mfs[number]);
+                if (!cnt)
+                    mfs[number].setVisible(false);
+            }
         }
     }
     if (df.length && !af.length && !rf.length) {
@@ -919,10 +993,25 @@ tvheadend.idnode_editor_form = function(d, meta, panel, conf)
 /*
  * ID node editor panel
  */
-tvheadend.idnode_editor = function(item, conf)
+tvheadend.idnode_editor = function(_uilevel, item, conf)
 {
     var panel = null;
     var buttons = [];
+    var uilevel = _uilevel;
+
+    function destroy() {
+        panel.removeAll();
+    }
+    
+    function build() {
+        var c = {
+            showpwd: conf.showpwd,
+            uuids: conf.uuids,
+            labelWidth: conf.labelWidth || 200
+        };
+
+        tvheadend.idnode_editor_form(uilevel, item.props || item.params, item.meta, panel, c);
+    }
 
     /* Buttons */
     if (!conf.noButtons) {
@@ -983,12 +1072,23 @@ tvheadend.idnode_editor = function(item, conf)
             buttons.push(applyBtn);
         }
 
+        var uilevelBtn = tvheadend.idnode_uilevel_button(uilevel, function() {
+            uilevel = tvheadend.idnode_uilevel_change(uilevelBtn, uilevel);
+            var values = panel.getForm().getFieldValues();
+            destroy();
+            build();
+            panel.getForm().setValues(values);
+        });
+        buttons.push('-');
+        buttons.push(uilevelBtn);
+
         if (conf.help) {
             var helpBtn = new Ext.Button({
                 text: _('Help'),
                 iconCls: 'help',
                 handler: conf.help
             });
+            buttons.push('-');
             buttons.push(helpBtn);
         }
     }
@@ -1009,12 +1109,7 @@ tvheadend.idnode_editor = function(item, conf)
         buttons: buttons
     });
 
-    var c = {
-        showpwd: conf.showpwd,
-        uuids: conf.uuids,
-        labelWidth: conf.labelWidth || 200
-    };
-    tvheadend.idnode_editor_form(item.props || item.params, item.meta, panel, c);
+    build();
     return panel;
 };
 
@@ -1028,6 +1123,7 @@ tvheadend.idnode_create = function(conf, onlyDefault)
     var panel = null;
     var win   = null;
     var pclass = null;
+    var uilevel = tvheadend.uilevel;
 
     /* Buttons */
     var saveBtn = new Ext.Button({
@@ -1138,7 +1234,7 @@ tvheadend.idnode_create = function(conf, onlyDefault)
                         pclass = r.get(conf.select.valueField);
                         win.setTitle(String.format(_('Add {0}'), s.lastSelectionText));
                         panel.remove(s);
-                        tvheadend.idnode_editor_form(d, null, panel, { create: true, showpwd: true });
+                        tvheadend.idnode_editor_form(uilevel, d, null, panel, { create: true, showpwd: true });
                         saveBtn.setVisible(true);
                         applyBtn.setVisible(true);
                         win.setOriginSize(true);
@@ -1155,7 +1251,7 @@ tvheadend.idnode_create = function(conf, onlyDefault)
                     success: function(d) {
                         panel.remove(s);
                         d = json_decode(d);
-                        tvheadend.idnode_editor_form(d.props, d, panel, { create: true, showpwd: true });
+                        tvheadend.idnode_editor_form(uilevel, d.props, d, panel, { create: true, showpwd: true });
                         saveBtn.setVisible(true);
                         applyBtn.setVisible(true);
                         win.setOriginSize(true);
@@ -1188,7 +1284,7 @@ tvheadend.idnode_create = function(conf, onlyDefault)
             params: conf.params,
             success: function(d) {
                 d = json_decode(d);
-                tvheadend.idnode_editor_form(d.props, d, panel, { create: true, showpwd: true });
+                tvheadend.idnode_editor_form(uilevel, d.props, d, panel, { create: true, showpwd: true });
                 if (onlyDefault) {
                     saveBtn.handler();
                     panel.destroy();
@@ -1266,9 +1362,11 @@ tvheadend.idnode_grid = function(panel, conf)
         var columns = [];
         var filters = [];
         var fields = [];
+        var ifields = [];
         var buttons = [];
         var abuttons = {};
         var plugins = conf.plugins ? conf.plugins.slice() : [];
+        var uilevel = tvheadend.uilevel;
 
         /* Some copies */
         if (conf.add && !conf.add.titleS && conf.titleS)
@@ -1283,8 +1381,9 @@ tvheadend.idnode_grid = function(panel, conf)
         idnode = new tvheadend.IdNode(d);
         for (var i = 0; i < idnode.length(); i++) {
             var f = idnode.field(i);
-            var c = f.column(conf.columns);
+            var c = f.column(uilevel, conf.columns);
             fields.push(f.id);
+            ifields.push(f);
             c['tooltip'] = f.text;
             columns.push(c);
             if (c.filter)
@@ -1555,7 +1654,7 @@ tvheadend.idnode_grid = function(panel, conf)
                                     } else {
                                         var title = String.format(_('Edit {0}'), conf.titleS);
                                     }
-                                    var p = tvheadend.idnode_editor(d[0], c);
+                                    var p = tvheadend.idnode_editor(uilevel, d[0], c);
                                     var width = p.fixedWidth;
                                     w = new Ext.ux.Window({
                                         title: title,
@@ -1672,6 +1771,17 @@ tvheadend.idnode_grid = function(panel, conf)
             }
         }
 
+        abuttons.uilevel = tvheadend.idnode_uilevel_button(uilevel, function () {
+            uilevel = tvheadend.idnode_uilevel_change(abuttons.uilevel, uilevel);
+            for (var i = 0; i < ifields.length; i++) {
+                var h = ifields[i].get_hidden(uilevel);
+                console.log('idx', i, 'hidden', h);
+                model.setHidden(model.findColumnIndex(ifields[i].id), h);
+            }
+        });
+        buttons.push('-');
+        buttons.push(abuttons.uilevel);
+
         /* Help */
         if (conf.help) {
             buttons.push('->');
@@ -1808,6 +1918,7 @@ tvheadend.idnode_form_grid = function(panel, conf)
         var plugins = conf.plugins ? conf.plugins.slice() : [];
         var current = null;
         var selectuuid = null;
+        var uilevel = tvheadend.uilevel;
 
         /* Store */
         var listurl = conf.list ? conf.list.url : null;
@@ -2028,6 +2139,19 @@ tvheadend.idnode_form_grid = function(panel, conf)
             }
         }
 
+        abuttons.uilevel = tvheadend.idnode_uilevel_button(uilevel, function () {
+            uilevel = tvheadend.idnode_uilevel_change(abuttons.uilevel, uilevel);
+            var values = null;
+            if (current)
+                values = current.editor.getForm().getFieldValues();
+            roweditor_destroy();
+            roweditor(select.getSelected());
+            if (values && current)
+                current.editor.getForm().setValues(values);
+        });
+        buttons.push('-');
+        buttons.push(abuttons.uilevel);
+
         /* Help */
         if (conf.help) {
             buttons.push('->');
@@ -2058,7 +2182,7 @@ tvheadend.idnode_form_grid = function(panel, conf)
                 success: function(d) {
                     d = json_decode(d);
                     roweditor_destroy();
-                    var editor = new tvheadend.idnode_editor(d[0], {
+                    var editor = new tvheadend.idnode_editor(uilevel, d[0], {
                                     title: _('Parameters'),
                                     labelWidth: 300,
                                     fixedHeight: true,
@@ -2197,6 +2321,7 @@ tvheadend.idnode_tree = function(panel, conf)
         var current = null;
         var uuid = null;
         var params = conf.params || {};
+        var uilevel = tvheadend.uilevel;
         var loader = new Ext.tree.TreeLoader({
             dataUrl: conf.url,
             baseParams: params,
@@ -2244,7 +2369,7 @@ tvheadend.idnode_tree = function(panel, conf)
                     }
                     if (!n.isRoot) {
                         uuid = n.attributes.uuid;
-                        current = new tvheadend.idnode_editor(n.attributes, {
+                        current = new tvheadend.idnode_editor(uilevel, n.attributes, {
                             title: _('Parameters'),
                             width: 550,
                             noautoWidth: true,
@@ -2334,6 +2459,51 @@ tvheadend.idnode_simple = function(panel, conf)
         var buttons = [];
         var abuttons = {};
         var current = null;
+        var uilevel = tvheadend.uilevel;
+        var lastdata = null;
+
+        function fonchange(f, o, n) {
+            if (current)
+                conf.onchange(current, f, o, n);
+        }
+
+        function form_build(d) {
+
+            var fpanel = new Ext.form.FormPanel({
+                frame: true,
+                border: true,
+                bodyStyle: 'padding: 5px',
+                labelAlign: 'left',
+                labelWidth: conf.labelWidth || 300,
+                autoWidth: false,
+                autoHeight: false,
+                width: conf.nowidth ? null : (conf.width || 730),
+                defaultType: 'textfield',
+                buttonAlign: 'left',
+                autoScroll: true
+            });
+
+            tvheadend.idnode_editor_form(uilevel, d.props || d.params, d.meta,
+                                         fpanel, { showpwd: conf.showpwd });
+
+            if (conf.onchange) {
+                var f = fpanel.getForm().items;
+                for (var i = 0; i < f.items.length; i++) {
+                   var it = f.items[i];
+                   it.on('check', fonchange);
+                   it.on('change', fonchange);
+                }
+            }
+            lastdata = d;
+            return fpanel;
+
+        }
+
+        function form_destroy() {
+            if (current)
+                mpanel.remove(current);
+            current = null;
+        }
 
         /* Top bar */
         abuttons.save = new Ext.Toolbar.Button({
@@ -2367,6 +2537,25 @@ tvheadend.idnode_simple = function(panel, conf)
         });
         buttons.push(abuttons.undo);
 
+        abuttons.uilevel = tvheadend.idnode_uilevel_button(uilevel, function () {
+            uilevel = tvheadend.idnode_uilevel_change(abuttons.uilevel, uilevel);
+            var values = null;
+            if (current)
+                values = current.getForm().getFieldValues();
+            form_destroy();
+            if (lastdata) {
+                current = form_build(lastdata);
+                if (values && current)
+                     current.getForm().setValues(values);
+                if (current) {
+                     mpanel.add(current);
+                     mpanel.doLayout();
+                }
+            }
+        });
+        buttons.push('-');
+        buttons.push(abuttons.uilevel);
+
         /* Extra buttons */
         if (conf.tbar) {
             buttons.push('-');
@@ -2397,48 +2586,6 @@ tvheadend.idnode_simple = function(panel, conf)
             });
         }
 
-        function fonchange(f, o, n) {
-            if (current)
-                conf.onchange(current, f, o, n);
-        }
-
-        function form_build(d) {
-
-            var fpanel = new Ext.form.FormPanel({
-                frame: true,
-                border: true,
-                bodyStyle: 'padding: 5px',
-                labelAlign: 'left',
-                labelWidth: conf.labelWidth || 300,
-                autoWidth: false,
-                autoHeight: false,
-                width: conf.nowidth ? null : (conf.width || 730),
-                defaultType: 'textfield',
-                buttonAlign: 'left',
-                autoScroll: true
-            });
-
-            tvheadend.idnode_editor_form(d.props || d.params, d.meta,
-                                         fpanel, { showpwd: conf.showpwd });
-
-            if (conf.onchange) {
-                var f = fpanel.getForm().items;
-                for (var i = 0; i < f.items.length; i++) {
-                   var it = f.items[i];
-                   it.on('check', fonchange);
-                   it.on('change', fonchange);
-                }
-            }
-            return fpanel;
-
-        }
-
-        function form_destroy() {
-            if (current)
-                mpanel.remove(current);
-            current = null;
-        }
-
         function form_load(force) {
             if (!force && current)
                 return;
@@ -2453,8 +2600,6 @@ tvheadend.idnode_simple = function(panel, conf)
                     current = new form_build(d[0]);
                     abuttons.save.setDisabled(false);
                     abuttons.undo.setDisabled(false);
-                    if (abuttons.del)
-                      abuttons.del.setDisabled(false);
                     mpanel.add(current);
                     mpanel.doLayout();
                 }
index 304455b8fdeea47aa46d6480fd437d26f4620eaf..707ac27fc21bb9a4a4dbcf5f19ebd1df5fd5579a 100644 (file)
@@ -3,6 +3,7 @@ tvheadend.accessupdate = null;
 tvheadend.capabilities = null;
 tvheadend.admin = false;
 tvheadend.dialog = null;
+tvheadend.uilevel = 'expert';
 
 tvheadend.cookieProvider = new Ext.state.CookieProvider({
   // 7 days from now
@@ -405,6 +406,8 @@ function accessUpdate(o) {
         return;
 
     tvheadend.admin = o.admin == true;
+    if (o.uilevel)
+        tvheadend.uilevel = o.uilevel;
 
     if ('info_area' in o)
         tvheadend.rootTabPanel.setInfoArea(o.info_area);
diff --git a/src/webui/static/icons/application_form.png b/src/webui/static/icons/application_form.png
new file mode 120000 (symlink)
index 0000000..99dd638
--- /dev/null
@@ -0,0 +1 @@
+../../../../vendor/famfamsilk/application_form.png
\ No newline at end of file