From f44e2f20fc3e8bb1e591160f4206002e3aafa4aa Mon Sep 17 00:00:00 2001 From: hummypkg Date: Thu, 5 Jun 2014 21:12:25 +0000 Subject: [PATCH] 1.0.14 --- CONTROL/control | 4 +- webif/plugin/sweeper/auto.hook | 80 ++++++++- webif/plugin/sweeper/config.jim | 13 +- webif/plugin/sweeper/edit.jim | 50 +++++- webif/plugin/sweeper/img/arrow.png | Bin 0 -> 1775 bytes webif/plugin/sweeper/img/disable.png | Bin 0 -> 1001 bytes webif/plugin/sweeper/img/redstripes.gif | Bin 0 -> 5119 bytes webif/plugin/sweeper/rules_json.jim | 23 ++- webif/plugin/sweeper/save.jim | 15 ++ webif/plugin/sweeper/schema.js | 213 +++++++++++++++++++++++- webif/plugin/sweeper/script.js | 208 ++++++++++++++++++----- webif/plugin/sweeper/style.css | 74 +++++++- 12 files changed, 601 insertions(+), 79 deletions(-) create mode 100644 webif/plugin/sweeper/img/arrow.png create mode 100644 webif/plugin/sweeper/img/disable.png create mode 100644 webif/plugin/sweeper/img/redstripes.gif diff --git a/CONTROL/control b/CONTROL/control index 7e180ba..e5e8bf4 100644 --- a/CONTROL/control +++ b/CONTROL/control @@ -1,9 +1,9 @@ Package: sweeper Priority: optional Section: misc -Version: 1.0.13 +Version: 1.0.14 Architecture: mipsel Maintainer: af123@hummypkg.org.uk -Depends: webif(>=1.0.14-2) +Depends: webif(>=1.0.14-3) Description: Automatically manage single recording files. [Web Interface. Multi-folder support.] Tags: http://hummy.tv/forum/threads/3843/ diff --git a/webif/plugin/sweeper/auto.hook b/webif/plugin/sweeper/auto.hook index e9c8fbc..63d38f9 100644 --- a/webif/plugin/sweeper/auto.hook +++ b/webif/plugin/sweeper/auto.hook @@ -57,7 +57,7 @@ proc ::sweeper::strcontains {ref val} { } ###################################################################### -# Rule clauses +# Rule criteria proc ::sweeper::flag {ts flag} { return [$ts flag $flag] @@ -124,15 +124,23 @@ proc ::sweeper::genre {ts genre} { proc ::sweeper::lock {ts g} { if {$g} { - log "Locked recording." 0 - $ts lock + if {![$ts flag Locked]} { + log "Locked recording." 0 + $ts lock + } } else { - log "Unlocked recording." 0 - $ts unlock + if {[$ts flag Locked]} { + log "Unlocked recording." 0 + $ts unlock + } } return 1 } +proc ::sweeper::folder_fflag {ts flag} { + return [file exists "[file dirname [$ts get file]]/.$flag"] +} + ###################################################################### proc ::sweeper::action {ts cmds} { @@ -172,6 +180,20 @@ proc ::sweeper::action {ts cmds} { } return 1 } + lock { + if {![$ts flag Locked]} { + log "Locked [$ts get file]" 0 + $ts lock + } + return 0 + } + unlock { + if {[$ts flag Locked]} { + log "Unlocked [$ts get file]" 0 + $ts unlock + } + return 0 + } default { log "Unknown action '$cmd'" 0 } @@ -195,6 +217,32 @@ proc ::sweeper::find {root target orig} { return "" } +proc ::sweeper::folder_apply {dir callback} { + log "Applying action to recordings in $dir" 2 + foreach e [readdir -nocomplain $dir] { + if {![string match {*.ts} $e]} continue + set entry "$dir/$e" + + log "+ folder_apply processing $entry" 2 + + if {[catch {set ts [ts fetch $entry]} msg} { + log "Error reading TS file, $msg" 0 + continue + } + + if {$ts == "0"} { + log "Invalid TS file." 2 + continue + } + + if {[$ts inuse]} { + log "Recording in use." 2 + continue + } + $callback $ts + } +} + proc ::sweeper:folder_merge {src dst} { if {$src eq $dst} return log "Moving recordings from $src to $dst" 0 @@ -287,6 +335,24 @@ proc ::sweeper::folder_action {ts cmds} { ::sweeper:folder_merge $folder $target return 1 } + lock { + ::sweeper::folder_apply $folder [lambda {ts} { + if {![$ts flag Locked]} { + log "Locked [$ts get file]" 0 + $ts lock + } + }] + return 0 + } + unlock { + ::sweeper::folder_apply $folder [lambda {ts} { + if {[$ts flag Locked]} { + log "Unlocked [$ts get file]" 0 + $ts unlock + } + }] + return 0 + } default { log "Unknown action '$cmd'" 0 } @@ -384,7 +450,9 @@ proc ::sweeper::apply {dir cf} { if {[string match {\[*} $e]} continue if {$e eq $dustbin} continue - log "+ Sweeper processing folder $entry" 2 + log "" 2 + log "==== folder $entry ====" 2 + log "" 2 if {![file exists "$entry/.series"]} { log "Not series folder." 2 diff --git a/webif/plugin/sweeper/config.jim b/webif/plugin/sweeper/config.jim index 469515d..784407f 100755 --- a/webif/plugin/sweeper/config.jim +++ b/webif/plugin/sweeper/config.jim @@ -6,9 +6,14 @@ require system.class httpheader "text/javascript" -puts { - -var showraw = true; - +set raw 0 +if {[file exists /mod/webif/plugin/sweeper/.raw]} { + set raw 1 } +puts " + +var showraw = $raw; + +" + diff --git a/webif/plugin/sweeper/edit.jim b/webif/plugin/sweeper/edit.jim index e9081e5..061fed0 100755 --- a/webif/plugin/sweeper/edit.jim +++ b/webif/plugin/sweeper/edit.jim @@ -39,6 +39,14 @@ puts {
+
+Add pre-defined ruleset: + + +
+ + + } footer diff --git a/webif/plugin/sweeper/img/arrow.png b/webif/plugin/sweeper/img/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..1e027b1e0c2582f54c6779956d88897a5239f1b2 GIT binary patch literal 1775 zcmbVNX;c$e6b>#JHkXzvi`F4%1%=FHBa4J3%K&N+0t&^VWEn_=$;4zLA+8vUOA$mV zASf!JsI?xeg;JD)cyJdtL_t&(7Zj{mLfgB)yK zY)K@NLrAblO03f?FWH*-J|N}g5sNb}j>aRfcsyCALr8&2OpX8{s4M}IA~I#lvh#>9 zi8L}^9T|;BOXl$u7)q5{bf`vDOQ1<4Uw@-krbt9^K#nA+HGIm;6V((zt>japSQ1F0 z6(TBiut|qRm_j2JrbGo-N%8jse2qMU07Y;aU__HNdY+L_8Q|p+d&@CM0R~j?L_THE zsc1eT@lkDkWQrC6 zrHCFg=oCaf;@yYAMD9Lq$f8Ji!<(;D6Gf3Fi7gmDPtHKX8PL)k|7w=uBccN>+YhZz z2p@(A(GU}(BSxdMLYGBM+|&?JV5G6RGw;g$&jTILF1dI;C%dtH>pGh=Kf8?<%9lP2 zS8$!?!*9T~=Hwo`F8|hXU8Me0n-=d)QLM6jvdL3N3!jtKw1%&&x3BZX>ru{EVQ|VDS2E?6 z^kP*&_mp$9dDah{$Cmjy0{g8lUiz-4ZN|8`mAszxi8-Ka``)VB7WXg7v6547BXz}# zJg`jYPDYG8A9OOeHh87i#XB`zM@VSL%&%PnZP&j^U~;TZz4anzm2RLcEmy9u9nY)+ znGR7$?q^(G)a0K^FBz3PA*Cd@qtM^+>D)7MVQ*_h+hBXjj4_x~gZI*JGXm_t^4q<* zZC6MPP*gjo-S_xh^wF`*+Lr1SBNtcwrGd|Hp4gqL8qxLMOWKpOCZvEWon;vDu*xqc zCTWD$DLbduWoNY6M#EI^xbj=?wHUhGxcflV?$GY7EY|UlnFL;mQd*?ZbBxyzNolr%w!-b}n#v=k*XgAbMMp2|-m!|+L zM7K32J>7N7|NLd|$}PK7tdBplR*Y%p_Pw(*`MqdMrcbuLsnX}gq^2JJ=1Fps-rcv_ z=d=6>Q46PMRLMKBouZ%0uzuC;*|9(T9s(uJ_;KvBE#Y=;@A??pJx}h)(dxv!R4?bu zP{Y)tJ3*Vv*_A1)p@8pC8vGuo^?6DTt(cVNoSt^+ZuW`x(}n&0dkht;?I4n0gKNgZ S=Xp_lRRCGiTx9)GVo2qvJ literal 0 HcmV?d00001 diff --git a/webif/plugin/sweeper/img/disable.png b/webif/plugin/sweeper/img/disable.png new file mode 100644 index 0000000000000000000000000000000000000000..26fbe851e0a784835a1c702298245352ee495b0b GIT binary patch literal 1001 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 hZsq%n;#F?s^ 1} { set rule [lassign $rule cmd arg] if {$cmd eq "action"} break + if {$cmd eq "lock"} { set lockfound $arg } if {$c} { add_json ",\n" } incr c @@ -78,7 +87,17 @@ proc rule {id rule} { add_json " }" } add_json "\n" - if {$cmd ne "action"} { set arg "continue" } + if {$cmd ne "action"} { + if {$lockfound != -1} { + if {$lockfound == "1"} { + set arg "lock" + } else { + set arg "unlock" + } + } else { + set arg "continue" + } + } lassign $arg cmd arg if {$cmd eq "preserve"} { set cmd 'stop' } add_json " ],\n" @@ -95,8 +114,8 @@ foreach rule $rules { if {[string index $rule 0] eq "#"} { if {[string index $rule 1] ne "#"} { comment $n [string range $rule 1 end] + continue } - continue } if {[llength $rule] < 2} continue incr n diff --git a/webif/plugin/sweeper/save.jim b/webif/plugin/sweeper/save.jim index 86a8249..dd23042 100755 --- a/webif/plugin/sweeper/save.jim +++ b/webif/plugin/sweeper/save.jim @@ -6,6 +6,21 @@ require system.class httpheader +set act [cgi_get act "save"] + +switch $act { + raw { + set val [cgi_get val 0] + if {$val} { + file touch /mod/webif/plugin/sweeper/.raw + } else { + file delete -force /mod/webif/plugin/sweeper/.raw + } + puts "Done." + exit; + } +} + set dir [cgi_get dir ""] set root [system mediaroot] diff --git a/webif/plugin/sweeper/schema.js b/webif/plugin/sweeper/schema.js index 32e3e45..cd91d9b 100644 --- a/webif/plugin/sweeper/schema.js +++ b/webif/plugin/sweeper/schema.js @@ -1,56 +1,67 @@ var schema = { criterion: { lcn: { + 'class': 'all', type: 'int', desc: 'Logical Channel Number', def: "0" }, duration: { + 'class': 'all', type: 'int', desc: 'Recording duration (in minutes)', def: "0" }, schedduration: { + 'class': 'all', type: 'int', desc: 'Scheduled duration (in minutes)', def: "0" }, size: { + 'class': 'all', type: 'int', desc: 'Recording size (in bytes)', def: "0" }, hour: { + 'class': 'all', type: 'int', desc: 'Hour in which the recording started', def: "0" }, age: { + 'class': 'all', type: 'int', desc: 'Age (in hours)', def: "0" }, wage: { + 'class': 'all', type: 'int', desc: 'Time since last watched, or recorded (in hours)', def: "0" }, title: { + 'class': 'all', type: 'substr', desc: 'Recording Title contains', def: 'Enter text here...' }, synopsis: { + 'class': 'all', type: 'substr', desc: 'Synopsis contains', def: 'Enter text here...' }, guidance: { + 'class': 'all', type: 'substr', desc: 'Guidance Text contains', def: 'Enter text here...' }, genre: { + 'class': 'all', type: 'select', desc: 'Recording Genre', select: { @@ -67,6 +78,7 @@ var schema = { def: 'Unclassified' }, definition: { + 'class': 'all', type: 'select', desc: 'Recording Definition', select: { @@ -76,6 +88,7 @@ var schema = { def: 'SD' }, flag: { + 'class': 'all', type: 'select', desc: 'Recording Flagged as', select: { @@ -90,13 +103,21 @@ var schema = { def: 'New' }, lock: { + 'class': 'all', type: 'select', desc: 'Change Recording Lock', select: { 1: 'Lock Recording', 0: 'Unlock Recording' }, - def: 1 + def: 1, + deprecated: true + }, + fflag: { + 'class': 'folder', + type: 'string', + desc: 'Folder flagged as', + def: 'noflatten' } }, action: { @@ -104,50 +125,224 @@ var schema = { 'class': 'all', argtype: 'none', desc: 'Continue on to next rule', - showcont: false + continues: true }, stop: { 'class': 'all', argtype: 'none', desc: 'Do nothing and stop processing rules', - showcont: false + continues: false }, move: { 'class': 'all', argtype: 'folder', desc: 'Move recording to folder...', - showcont: true + continues: false + }, + lock: { + 'class': 'all', + argtype: 'none', + desc: 'Lock recordings', + continues: true + }, + unlock: { + 'class': 'all', + argtype: 'none', + desc: 'Unlock recordings', + continues: true }, movecreate: { 'class': 'all', argtype: 'folder', desc: 'Move recording to folder (creating if necessary)', - showcont: true + continues: false }, fileunder: { 'class': 'folder', argtype: 'folder', desc: 'Merge into first folder of same name found under...', - showcont: true + continues: false }, fileundercreate: { 'class': 'folder', argtype: 'folder', desc: 'Merge into or create folder of ' + 'same name found under...', - showcont: true + continues: false } } }; -var select_criteria = {}; +var macros = { + seriesfiler: { + desc: 'Series-Filer', + rules: [ + { + "raw": "action {fileunder ""}", + "name": "Emulate Seriesfiler", + "type": "folder", + "enabled": "1", + "criteria": [], + "action": { + "cmd": "fileunder", + "arg": "" + } + } + ] + }, + example: { + desc: 'Example rules', + rules: [ + { + "raw": "lcn {>= 70} lcn {<= 79} duration {>= 90} action {move Children/Films}", + "name": "Move any Children's films (by length)", + "type": "file", + "enabled": "0", + "criteria": [ + { + "cmd": "lcn", + "arg": ">= 70" + }, + { + "cmd": "lcn", + "arg": "<= 79" + }, + { + "cmd": "duration", + "arg": ">= 90" + } + ], + "action": { + "cmd": "move", + "arg": "Children/Films" + } + }, + { + "raw": "lcn {>= 70} lcn {<= 79} genre Film action {move Children/Films}", + "name": "Move any Children's films (by genre)", + "type": "file", + "enabled": "0", + "criteria": [ + { + "cmd": "lcn", + "arg": ">= 70" + }, + { + "cmd": "lcn", + "arg": "<= 79" + }, + { + "cmd": "genre", + "arg": "Film" + } + ], + "action": { + "cmd": "move", + "arg": "Children/Films" + } + }, + { + "raw": "lcn {>= 70} lcn {<= 79} action {move Children/Miscellaneous}", + "name": "Move anything else recorded from a children's channel", + "type": "file", + "enabled": "0", + "criteria": [ + { + "cmd": "lcn", + "arg": ">= 70" + }, + { + "cmd": "lcn", + "arg": "<= 79" + } + ], + "action": { + "cmd": "move", + "arg": "Children/Miscellaneous" + } + }, + { + "raw": "lcn {>= 70} lcn {<= 79} action {fileundercreate Children}", + "name": "Move any series recordings from a Children's channel (folder rule)", + "type": "folder", + "enabled": "0", + "criteria": [ + { + "cmd": "lcn", + "arg": ">= 70" + }, + { + "cmd": "lcn", + "arg": "<= 79" + } + ], + "action": { + "cmd": "fileundercreate", + "arg": "Children" + } + }, + { + "raw": "title {Formula 1} action {move F1}", + "name": "Move any one-off Formula 1 recordings into the F1 folder", + "type": "file", + "enabled": "0", + "criteria": [ + { + "cmd": "title", + "arg": "Formula 1" + } + ], + "action": { + "cmd": "move", + "arg": "F1" + } + }, + { + "raw": "age {> 120} action {movecreate Misc}", + "name": "Move any one-off recordings into a folder called Misc after a while", + "type": "file", + "enabled": "0", + "criteria": [ + { + "cmd": "age", + "arg": "> 120" + } + ], + "action": { + "cmd": "movecreate", + "arg": "Misc" + } + } +] + } + +}; + +var select_file_criteria = {}; +var select_folder_criteria = {}; $.each(schema.criterion, function(k, v) { - select_criteria[k] = v.desc; + if (v.deprecated) + return; + switch (v['class']) + { + case 'file': + select_file_criteria[k] = v.desc; + break; + case 'folder': + select_folder_criteria[k] = v.desc; + break; + case 'all': + select_file_criteria[k] = v.desc; + select_folder_criteria[k] = v.desc; + break; + } }); var select_file_actions = {}; var select_folder_actions = {}; $.each(schema.action, function(k, v) { + if (v.deprecated) + return; switch (v['class']) { case 'file': diff --git a/webif/plugin/sweeper/script.js b/webif/plugin/sweeper/script.js index 97a7d72..f86037d 100644 --- a/webif/plugin/sweeper/script.js +++ b/webif/plugin/sweeper/script.js @@ -6,7 +6,7 @@ function quot(str) if (!str) return '""'; - if (str.indexOf(" ") == -1) + if (str.indexOf(" ") == -1 && str.indexOf('"') == -1) return str; return '{' + str + '}'; } @@ -15,6 +15,11 @@ function fixupdown() { $('#ruleset a.uprule').enable().filter(':first').disable(); $('#ruleset a.downrule').enable().filter(':last').disable(); + + $('#ruleset a.uprule img').attr('src', '/img/nav/up.png') + .first().attr('src', '/img/nav/up-grey.png'); + $('#ruleset a.downrule img').attr('src', '/img/nav/down.png') + .last().attr('src', '/img/nav/down-grey.png'); } function changed(c) @@ -23,12 +28,12 @@ function changed(c) return; if (c) { - $('#b_save,#b_revert').enable(); + $('#b_save,#b_revert').button('enable'); $('#pendingnote').show(); } else { - $('#b_save,#b_revert').disable(); + $('#b_save,#b_revert').button('disable'); $('#pendingnote').hide(); } changed.last = c; @@ -52,6 +57,9 @@ var setters = { substr: function(cmd, a) { return a; }, + 'string': function(cmd, a) { + return a; + }, select: function(cmd, a) { return schema.criterion[cmd].select[a]; } @@ -70,6 +78,9 @@ var getters = { substr: function(cmd, a) { return a; }, + 'string': function(cmd, a) { + return a; + }, select: function(cmd, a) { var c = schema.criterion[cmd].select; for (key in c) @@ -83,11 +94,13 @@ function ruleconf(rule) { var s = ''; - if ($(rule).attr('type') == 'folder') + if (rule.hasClass('ruledisabled')) + s += '## '; + if (rule.attr('type') == 'folder') s += 'folder '; - $(rule).find('tr.clause').each(function(i) { - cmd = $(this).find('th').attr('cmd'); + rule.find('tr.clause').each(function(i) { + cmd = $(this).find('th.cmd').attr('cmd'); c = schema.criterion[cmd]; val = $.trim($(this).find('td.val').text()); if (getters[c.type]) @@ -96,12 +109,17 @@ function ruleconf(rule) s += cmd + ' ' + quot(val) + ' '; }); - act = $(rule).find('tr.action th').attr('cmd'); - arg = $.trim($(rule).find('tr.action td.val').text()); + act = rule.find('tr.action th.cmd').attr('cmd'); + arg = $.trim(rule.find('tr.action td.val').text()); if (schema.action[act].argtype == 'folder' && arg == mroot) arg = ''; if (act != 'continue') - s += 'action {' + act + ' ' + quot(arg) + '}'; + { + if (schema.action[act].argtype == 'none') + s += 'action ' + act; + else + s += 'action {' + act + ' ' + quot(arg) + '}'; + } return s; } @@ -120,12 +138,22 @@ function conffile() function rulerefresh(rule) { + if (!showraw) + rule.find('.raw').hide(); rule.find('.raw').html(ruleconf(rule)); - rule.find('tr.clause td.title').text('And:').first().text('If:'); + rule.find('tr.clause th.title').text('And:').first().text('If:'); if (rule.find('tr.clause').length < 1) - rule.find('tr.action td.title').text('Always:'); + { + rule.find('tr.action th.title').text('Always:'); + rule.find('tr.otherwise').hide(); + rule.find('div.criteria,div.arrow').hide(); + } else - rule.find('tr.action td.title').text('Then:'); + { + rule.find('tr.action th.title').text('Then:'); + rule.find('tr.otherwise').show(); + rule.find('div.criteria,div.arrow').show(); + } } function criterion(data) @@ -133,8 +161,9 @@ function criterion(data) var c = schema.criterion[data.cmd]; var s; - s = 'And:' + - '' + c.desc + ''; + s = 'And:' + + '' + + c.desc + ''; if (setters[c.type]) s += setters[c.type](data.cmd, data.arg); @@ -160,16 +189,26 @@ function action(data) data.arg = mroot; s = '' + - 'Then:' + - '' + c.desc + '' + + 'Then:' + + '' + c.desc + '' + '' + data.arg + '' + '' + '' + ''; - if (c.showcont) - s += 'Else:' + - 'Continue on to next rule.'; + if (data.cmd != 'continue') + { + if (c.continues) + s += 'And:' + + 'Continue to next rule.'; + else if (data.cmd != 'stop') + s += 'And:' + + 'Stop processing rules.'; + + s += ' ' + + 'Otherwise:' + + 'Continue to next rule.'; + } return s; } @@ -196,16 +235,25 @@ function addrule(id, data) var $c = rule.find('table.criteria'); $.each(data.criteria, function(key, val) { + if (val.cmd == 'lock' && ( + data.action.cmd == 'lock' || data.action.cmd == 'unlock')) + return; $c.find('tbody').append(criterion(val)); }); - $c.find('td.title:first').text('If:'); + $c.find('th.title:first').text('If:'); rule.find('table.action tbody').append(action(data.action)); + if (data.enabled == 0) + { + rule.addClass('ruledisabled'); + rule.find('span.disabledtext').removeClass('hidden'); + } + $('#ruleset').append(rule); - rule.find('button.addcriterion') - .button({icons: { primary: "ui-icon-plus"}}); +// rule.find('button.addcriterion') +// .button({icons: { primary: "ui-icon-plus"}}); rulerefresh(rule); @@ -241,6 +289,8 @@ function edit_text(obj, title, text, callback) } } }); + if (text == 'Enter text here...') + $('#edit_text_field').focus().select(); } function edit_int(obj, title, op, val, callback) @@ -310,10 +360,10 @@ function edit_select(obj, title, options, val, callback) function edit_clause(obj) { - var cmd = $(obj).find('th').attr('cmd'); + var cmd = $(obj).find('th.cmd').attr('cmd'); var target = $(obj).find('td.val'); var val = $.trim($(target).text()); - var title = $(obj).find('th').html(); + var title = $(obj).find('th.cmd').html(); if (!schema.criterion[cmd]) { alert('Unhandled command (' + cmd + ')'); @@ -364,7 +414,7 @@ function loadrules(dir) if (!data.length) { $('#ruleset').attr('empty', true) - .html('No rules defined for this folder.'); + .html($('#empty_rulebase').html()); return; } $.each(data, function(key, val) { @@ -412,18 +462,18 @@ $('#b_add').button({icons: {primary: "ui-icon-plus"}}) } }); $('#newrule_type_file').prop('checked', true); - $('#newrule_comment').focus().val('').val('Unnamed rule'); + $('#newrule_comment').focus().val('').val('Unnamed rule').select(); }); -$('#b_save').button({icons: {primary: "ui-icon-disk"}}) - .on('click', function(e) { +$('#b_save').button({icons: {primary: "ui-icon-disk"}}); +$('#buttons') + .on('click', '#b_save', function(e) { e.preventDefault(); $(this).dojConfirmAction({ question: 'Save changes?', yesAnswer: 'Yes', cancelAnswer: 'No' }, function(el) { - $('.jcaquestion').fadeOut(300); $.post('save.jim', { dir: $('span.dir').text(), data: conffile() @@ -435,15 +485,15 @@ $('#b_save').button({icons: {primary: "ui-icon-disk"}}) }); }); -$('#b_revert').button({icons: {primary: "ui-icon-arrowrefresh-1-w"}}) - .on('click', function(e) { +$('#b_revert').button({icons: {primary: "ui-icon-arrowrefresh-1-w"}}); +$('#buttons') + .on('click', '#b_revert', function(e) { e.preventDefault(); $(this).dojConfirmAction({ question: 'Discard changes?', yesAnswer: 'Yes', cancelAnswer: 'No' }, function(el) { - $('.jcaquestion').fadeOut(300); loadrules($('span.dir').text()); changed(0); }); @@ -470,6 +520,32 @@ $('#b_show').button({icons: {primary: "ui-icon-clipboard"}}) $('#b_raw').button({icons: {primary: "ui-icon-gear"}}) .on('click', function(e) { $('#ruleset div.raw').toggle('slow'); + showraw = !showraw; + $.get('save.jim?act=raw&val=' + (showraw ? 1 : 0)); +}); + +$('#b_macro').button({disabled: true, icons: {primary: "ui-icon-plus"}}); +$('#macros').on('click', '#b_macro', function(e) { + e.preventDefault(); + var set = $('#macroselect').val(); + if (!set) return; + var desc = macros[set].desc; + $(this).dojConfirmAction({ + question: 'Add ' + desc + '?', + yesAnswer: 'Yes', + cancelAnswer: 'No' + }, function(el) { + $('.jcaquestion').remove(); + $.each(macros[set].rules, function(k, v) { + addrule(last_ruleid + 1, v).hide().addClass('hl'); + }); + $('.hl').slideDown('slow', function() { + $(this).removeClass('hl'); + }); + fixupdown(); + changed(1); + $('#macroselect').val(0); + }); }); changed(0); @@ -479,11 +555,17 @@ $('#ruleset') e.preventDefault(); edit_clause($(this).closest('tr.clause')); }) - .on('click', 'button.addcriterion', function(e) { + .on('click', 'a.addcriterion', function(e) { e.preventDefault(); var rule = $(this).closest('div.rule'); - edit_select(rule, 'Select new criterion', - select_criteria, '', function(rule, val) { + var type = rule.attr('type'); + + if (type == 'folder') + options = select_folder_criteria; + else + options = select_file_criteria; + edit_select(rule, 'Add new condition', + options, '', function(rule, val) { var id = rule.attr('id'); rule.find('table.criteria tbody') .append(criterion({ @@ -537,6 +619,35 @@ $('#ruleset') }); }); }) + .on('click', 'a.cprule', function(e) { + e.preventDefault(); + $(this).dojConfirmAction({ + question: 'Duplicate rule?', + yesAnswer: 'Yes', + cancelAnswer: 'No' + }, function(el) { + $('.jcaquestion').remove(); + var rule = $(el).closest('div.rule'); + rule.clone() + .attr('id', 'rule_' + ++last_ruleid) + .addClass('hl').hide() + .insertAfter(rule) + .slideDown('slow', function() { + $(this).removeClass('hl'); + changed(1); + }) + .find('span.comment').append(' (copy)'); + }); + }) + .on('click', 'a.enadisrule', function(e) { + e.preventDefault(); + var rule = $(this).closest('div.rule') + .toggleClass('ruledisabled'); + rule.find('span.disabledtext').toggleClass('hidden', + !rule.hasClass('ruledisabled')); + rulerefresh(rule); + changed(1); + }) .on('click', 'a.editaction', function(e) { e.preventDefault(); @@ -555,7 +666,7 @@ $('#ruleset') ); }); - var cmd = rule.find('tr.action th').attr('cmd'); + var cmd = rule.find('tr.action th.cmd').attr('cmd'); var arg = rule.find('tr.action td.val').html(); if (schema.action[cmd].argtype == 'none') @@ -596,11 +707,10 @@ $('#ruleset') .on('click', 'a.delclause', function(e) { e.preventDefault(); $(this).dojConfirmAction({ - question: 'Delete criterion?', + question: 'Delete condition?', yesAnswer: 'Yes', cancelAnswer: 'No' }, function(el) { - $('.jcaquestion').fadeOut(300); var rule = $(el).closest('div.rule'); $(el).closest('tr.clause').fadeOut('slow', function() { $(this).remove(); @@ -616,19 +726,33 @@ $('#ruleset') yesAnswer: 'Yes', cancelAnswer: 'No' }, function(el) { - $('.jcaquestion').fadeOut(300); - $(el).closest('div.rule').slideUp('slow', function() { + $(el).closest('div.rule') + .addClass('hl') + .slideUp('slow', function() { $(this).remove(); changed(1); fixupdown(); if ($('div.rule').length < 1) $('#ruleset').attr('empty', true) - .html('No rules defined for this ' + - 'folder.'); + .html($('#empty_rulebase').html()); }); }); }); + // Set up macros + $.each(macros, function(key, val) { + $('#macroselect').append( + $('').attr('value', key).text(val.desc) + ); + }); + + $('#macroselect').on('change', function(el) { + if ($(this).val() == "0") + $('#b_macro').button('disable'); + else + $('#b_macro').button('enable'); + }); + loadrules($('span.dir').text()); }); diff --git a/webif/plugin/sweeper/style.css b/webif/plugin/sweeper/style.css index 4d46b47..ffbc131 100644 --- a/webif/plugin/sweeper/style.css +++ b/webif/plugin/sweeper/style.css @@ -1,4 +1,9 @@ +a +{ + outline: 0; +} + span.ruleicon img { height: 21px; @@ -20,15 +25,30 @@ img background: yellow; } +.ruledisabled +{ + background: #663436 url(img/redstripes.gif) repeat; +} + div.action { - padding-left: 1em; float: left; } +a.addcriterion +{ + padding: 4px 2px 0 0; + float: left; + clear: left; +} + div.criteria { - clear: left; + float: left; +} + +div.arrow +{ float: left; } @@ -47,11 +67,9 @@ div#buttons padding-top: 1em; } -td.title,th.title +div#macros { - line-height: 1em; - text-align: left !important; - background: #eee !important; + padding-top: 1em; } div.rule @@ -86,3 +104,47 @@ span.legendright background: transparent; } +table +{ + border: 0; +} + +table th +{ + background: #ccff99; + font-weight: bold; + text-align: right; + color: black; + xpadding: 0.5em; +} + +table td +{ + background: #ffffcc; + color: black; +} + +td.title,th.title +{ + line-height: 1em; + background: #eee !important; + font-style: italic; +} + +td.title +{ + text-align: left !important; +} + +th.title +{ + font-weight: normal; + text-align: right !important; +} + +tr.blank td +{ + background: transparent; + line-height: 7px; +} +