This commit is contained in:
hummypkg 2014-06-05 21:12:25 +00:00
parent 3f6259fa09
commit f44e2f20fc
12 changed files with 601 additions and 79 deletions

View File

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

View File

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

View File

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

View File

@ -39,6 +39,14 @@ puts {
</div>
<div id=output></div>
<div id=macros>
Add pre-defined ruleset:
<select id=macroselect>
<option value=0>--- Select ruleset ---</option>
</select>
<button id=b_macro>Add to rules</button>
</div>
<div id=rule_template class="hidden">
<fieldset class=rule>
<legend class=comment>
@ -55,25 +63,44 @@ puts {
</a>
</span>
<span class=legendright>
<span class="disabledtext blood hidden">
(Disabled)
</span>
<a class=enadisrule href=#>
<img src=img/disable.png
alt="Enable/Disable Rule"
title="Enable/Disable Rule">
</a>
<a class=delrule href=#>
<img src=/img/context/delete.png>
<img src=/img/context/delete.png
alt="Delete Rule" title="Delete Rule">
</a>
<a class=cprule href=#>
<img src=/img/context/page_white_copy.png
alt="Duplicate Rule" title="Duplicate Rule">
</a>
<a class=uprule href=#>
<img src=/img/nav/up.png>
<img src=/img/nav/up.png
alt="Move Rule Up" title="Move Rule Up">
</a>
<a class=downrule href=#>
<img src=/img/nav/down.png>
<img src=/img/nav/down.png
alt="Move Rule Down" title="Move Rule Down">
</a>
</span>
</legend>
<a href=# class=addcriterion>
<img src=/img/context/plus.png
alt="Add condition" title="Add condition">
</a>
<div class=criteria>
<table class="criteria keyval"><tbody>
</tbody></table>
<table class="criteria"><tbody></tbody></table>
</div>
<div class=arrow>
<img src=img/arrow.png height=32>
</div>
<div class=action>
<table class="action keyval"><tbody>
</tbody></table>
<button class=addcriterion>Add Criterion</button>
<table class="action"><tbody></tbody></table>
</div>
<div class=raw></div>
</fieldset>
@ -119,6 +146,13 @@ puts {
</select>
<input name=edit_action_arg id=edit_action_arg size=60 maxlength=255 />
</div>
<div class=hidden id=empty_rulebase>
<b>There are no rules currently defined for this folder.</b>
<br>
You can add some example rules by using the <i>Add pre-defined ruleset</i>
option at the bottom of the screen.
</div>
}
footer

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -48,6 +48,12 @@ proc quot {str} {
proc rule {id rule} {
global clausedescr lcomment
set enabled 1
if {[lindex $rule 0] eq "##"} {
set enabled 0
set rule [lrange $rule 1 end]
}
if {$lcomment eq ""} { set lcomment "Unnamed rule" }
if {[lindex $rule 0] eq "folder"} {
set type "folder"
@ -61,14 +67,17 @@ proc rule {id rule} {
add_json " \"raw\": \"[quot $rule]\",\n"
add_json " \"name\": \"[quot $lcomment]\",\n"
add_json " \"type\": \"$type\",\n"
add_json " \"enabled\": \"$enabled\",\n"
add_json " \"criteria\": \[\n"
set lcomment ""
set c 0
set lockfound -1
while {[llength $rule] > 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

View File

@ -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]

View File

@ -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 &quot;&quot;}",
"name": "Emulate Seriesfiler",
"type": "folder",
"enabled": "1",
"criteria": [],
"action": {
"cmd": "fileunder",
"arg": ""
}
}
]
},
example: {
desc: 'Example rules',
rules: [
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} duration {&gt;= 90} action {move Children/Films}",
"name": "Move any Children's films (by length)",
"type": "file",
"enabled": "0",
"criteria": [
{
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"cmd": "lcn",
"arg": "&lt;= 79"
},
{
"cmd": "duration",
"arg": "&gt;= 90"
}
],
"action": {
"cmd": "move",
"arg": "Children/Films"
}
},
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} genre Film action {move Children/Films}",
"name": "Move any Children's films (by genre)",
"type": "file",
"enabled": "0",
"criteria": [
{
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"cmd": "lcn",
"arg": "&lt;= 79"
},
{
"cmd": "genre",
"arg": "Film"
}
],
"action": {
"cmd": "move",
"arg": "Children/Films"
}
},
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} action {move Children/Miscellaneous}",
"name": "Move anything else recorded from a children's channel",
"type": "file",
"enabled": "0",
"criteria": [
{
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"cmd": "lcn",
"arg": "&lt;= 79"
}
],
"action": {
"cmd": "move",
"arg": "Children/Miscellaneous"
}
},
{
"raw": "lcn {&gt;= 70} lcn {&lt;= 79} action {fileundercreate Children}",
"name": "Move any series recordings from a Children's channel (folder rule)",
"type": "folder",
"enabled": "0",
"criteria": [
{
"cmd": "lcn",
"arg": "&gt;= 70"
},
{
"cmd": "lcn",
"arg": "&lt;= 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 {&gt; 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": "&gt; 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':

View File

@ -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 = '<tr class=clause><td class=title>And:</td>' +
'<th cmd=' + data.cmd + '>' + c.desc + '</th><td class=val>';
s = '<tr class=clause><th class=title>And:</th>' +
'<th class=cmd cmd=' + data.cmd + '>' +
c.desc + '</th><td class=val>';
if (setters[c.type])
s += setters[c.type](data.cmd, data.arg);
@ -160,16 +189,26 @@ function action(data)
data.arg = mroot;
s = '<tr class=action>' +
'<td class=title>Then:</td>' +
'<th cmd=' + data.cmd + '>' + c.desc + '</th>' +
'<th class=title>Then:</th>' +
'<th class=cmd cmd=' + data.cmd + '>' + c.desc + '</th>' +
'<td class=val>' + data.arg + '</td>' +
'<td><a class=editaction href=#>' +
'<img src=/img/context/edit.png></a></td>' +
'</tr>';
if (c.showcont)
s += '<tr><td class=title>Else:</td>' +
'<th>Continue on to next rule.</th></tr>';
if (data.cmd != 'continue')
{
if (c.continues)
s += '<tr><th class=title>And:</th><td class=title>' +
'Continue to next rule.</td></tr>';
else if (data.cmd != 'stop')
s += '<tr><th class=title>And:</th><td class=title>' +
'Stop processing rules.</td></tr>';
s += '<tr class=blank><td>&nbsp;</th></tr>' +
'<tr class=otherwise><th class=title>Otherwise:</th>' +
'<td class=title>Continue to next rule.</td></tr>';
}
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('<i>No rules defined for this folder.</i>');
.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('<i>No rules defined for this ' +
'folder.</i>');
.html($('#empty_rulebase').html());
});
});
});
// Set up macros
$.each(macros, function(key, val) {
$('#macroselect').append(
$('<option></option>').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());
});

View File

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