diff --git a/etc/recmon.d/autotrigger b/etc/recmon.d/autotrigger index 25ff2f76..f4d5bd79 100755 --- a/etc/recmon.d/autotrigger +++ b/etc/recmon.d/autotrigger @@ -1,8 +1,17 @@ #!/mod/bin/jimsh -set file [lindex $argv 0] +source /mod/webif/lib/setup +require lock +set file [lindex $argv 0] set dir [file dirname $file] +# Wait up to 10 minutes for any existing auto process to finish... +if {![acquire_lock webif_auto 600]} { + puts "Cannot acquire exclusive lock, terminating." + exit +} +release_lock webif_auto + exec /mod/webif/lib/bin/auto -single $dir diff --git a/webif/cgi-bin/chanlist.jim b/webif/cgi-bin/chanlist.jim new file mode 100755 index 00000000..b28d6a51 --- /dev/null +++ b/webif/cgi-bin/chanlist.jim @@ -0,0 +1,22 @@ +#!/mod/bin/jimsh + +source /mod/webif/lib/setup +require epg.class + +httpheader "application/json" + +puts "{" +set flag 0 + +lmap i [$channeldb query " + select usLcn, szSvcName + from TBL_SVC + order by 1 +"] { + if {$::flag} { puts "," } else { incr ::flag } + lassign $i x lcn x name + puts -nonewline " \"$lcn\": \"[system strip $name]\"" +} + +puts "\n}" + diff --git a/webif/html/css/style.css b/webif/html/css/style.css index f4521f08..c5d4b4de 100644 --- a/webif/html/css/style.css +++ b/webif/html/css/style.css @@ -280,6 +280,12 @@ tr.blueshade > td, .blueshade text-decoration: line-through; } +.error +{ + background: #ffcccc; + color: black; +} + .greenshade { background: #e4faa8; diff --git a/webif/html/dlna/dlna.jim b/webif/html/dlna/dlna.jim index 5b744650..b326b896 100755 --- a/webif/html/dlna/dlna.jim +++ b/webif/html/dlna/dlna.jim @@ -3,11 +3,11 @@ package require cgi package require sqlite3 source /mod/webif/lib/setup -require ts.class pretty_size +require system.class ts.class pretty_size header -#append dmsfile ".rr" +set dmsfile [system dlnadb] set vars { object.container 0 diff --git a/webif/html/lib/jquery.plugin/datepair/jquery.datepair.min.js b/webif/html/lib/jquery.plugin/datepair/jquery.datepair.min.js new file mode 100644 index 00000000..b4c9b28f --- /dev/null +++ b/webif/html/lib/jquery.plugin/datepair/jquery.datepair.min.js @@ -0,0 +1,7 @@ +/*! + * datepair.js v0.4.7 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/Datepair.js + * License: MIT + */ + +!function(a,b){"use strict";function c(a,b){var c=b||{};for(var d in a)d in c||(c[d]=a[d]);return c}function d(a,c){if(h)h(a).trigger(c);else{var d=b.createEvent("CustomEvent");d.initCustomEvent(c,!0,!0,{}),a.dispatchEvent(d)}}function e(a,b){return h?h(a).hasClass(b):a.classList.contains(b)}function f(a,b){this.dateDelta=null,this.timeDelta=null,this._defaults={startClass:"start",endClass:"end",timeClass:"time",dateClass:"date",defaultDateDelta:0,defaultTimeDelta:36e5,anchor:"start",parseTime:function(a){return h(a).timepicker("getTime")},updateTime:function(a,b){h(a).timepicker("setTime",b)},setMinTime:function(a,b){h(a).timepicker("option","minTime",b)},parseDate:function(a){return h(a).datepicker("getDate")},updateDate:function(a,b){h(a).datepicker("update",b)}},this.container=a,this.settings=c(this._defaults,b),this.startDateInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.dateClass),this.endDateInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.dateClass),this.startTimeInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.timeClass),this.endTimeInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.timeClass),this.refresh(),this._updateEndMintime(),this._bindChangeHandler()}var g=864e5,h=a.Zepto||a.jQuery;f.prototype={constructor:f,option:function(a,b){if("object"==typeof a)this.settings=c(this.settings,a);else if("string"==typeof a&&"undefined"!=typeof b)this.settings[a]=b;else if("string"==typeof a)return this.settings[a];this._updateEndMintime()},getTimeDiff:function(){var a=this.dateDelta+this.timeDelta;return!(0>a)||this.startDateInput&&this.endDateInput||(a+=g),a},refresh:function(){if(this.startDateInput&&this.startDateInput.value&&this.endDateInput&&this.endDateInput.value){var a=this.settings.parseDate(this.startDateInput),b=this.settings.parseDate(this.endDateInput);a&&b&&(this.dateDelta=b.getTime()-a.getTime())}if(this.startTimeInput&&this.startTimeInput.value&&this.endTimeInput&&this.endTimeInput.value){var c=this.settings.parseTime(this.startTimeInput),d=this.settings.parseTime(this.endTimeInput);c&&d&&(this.timeDelta=d.getTime()-c.getTime())}},remove:function(){this._unbindChangeHandler()},_bindChangeHandler:function(){h?h(this.container).on("change.datepair",h.proxy(this.handleEvent,this)):this.container.addEventListener("change",this,!1)},_unbindChangeHandler:function(){h?h(this.container).off("change.datepair"):this.container.removeEventListener("change",this,!1)},handleEvent:function(a){this._unbindChangeHandler(),e(a.target,this.settings.dateClass)?""!=a.target.value?this._dateChanged(a.target):this.dateDelta=null:e(a.target,this.settings.timeClass)&&(""!=a.target.value?this._timeChanged(a.target):this.timeDelta=null),this._validateRanges(),this._updateEndMintime(),this._bindChangeHandler()},_dateChanged:function(a){if(this.startDateInput&&this.endDateInput){var b=this.settings.parseDate(this.startDateInput),c=this.settings.parseDate(this.endDateInput);if(b&&c)if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var d=new Date(b.getTime()+this.dateDelta);this.settings.updateDate(this.endDateInput,d)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var d=new Date(c.getTime()-this.dateDelta);this.settings.updateDate(this.startDateInput,d)}else if(b>c){var f=e(a,this.settings.startClass)?this.endDateInput:this.startDateInput,h=this.settings.parseDate(a);this.dateDelta=0,this.settings.updateDate(f,h)}else this.dateDelta=c.getTime()-b.getTime();else if(null!==this.settings.defaultDateDelta){if(b){var i=new Date(b.getTime()+this.settings.defaultDateDelta*g);this.settings.updateDate(this.endDateInput,i)}else if(c){var j=new Date(c.getTime()-this.settings.defaultDateDelta*g);this.settings.updateDate(this.startDateInput,j)}this.dateDelta=this.settings.defaultDateDelta*g}else this.dateDelta=null}},_timeChanged:function(a){if(this.startTimeInput&&this.endTimeInput){var b=this.settings.parseTime(this.startTimeInput),c=this.settings.parseTime(this.endTimeInput);if(!b||!c){if(null===this.settings.defaultTimeDelta)return void(this.timeDelta=null);if(b){var d=new Date(b.getTime()+this.settings.defaultTimeDelta);this.settings.updateTime(this.endTimeInput,d)}else if(c){var f=new Date(c.getTime()-this.settings.defaultTimeDelta);this.settings.updateTime(this.startTimeInput,f)}this.timeDelta=this.settings.defaultTimeDelta}if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var h=new Date(b.getTime()+this.timeDelta);this.settings.updateTime(this.endTimeInput,h),c=this.settings.parseTime(this.endTimeInput)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var h=new Date(c.getTime()-this.timeDelta);this.settings.updateTime(this.startTimeInput,h),b=this.settings.parseTime(this.startTimeInput)}var i=c.getTime()-b.getTime(),j=b>c?g:-1*g;if(null!==this.dateDelta&&this.dateDelta+this.timeDelta<=g&&this.dateDelta+i!=0&&(j>0||0!=this.dateDelta)&&(i>=0&&this.timeDelta<0||0>i&&this.timeDelta>=0))if("start"==this.settings.anchor){var k=this.settings.parseDate(this.endDateInput);this.settings.updateDate(this.endDateInput,new Date(k.getTime()+j)),this._dateChanged(this.endDateInput)}else if("end"==this.settings.anchor){var l=this.settings.parseDate(this.startDateInput);this.settings.updateDate(this.startDateInput,new Date(l.getTime()-j)),this._dateChanged(this.startDateInput)}this.timeDelta=i}},_updateEndMintime:function(){if("function"==typeof this.settings.setMinTime){var a=null;"start"==this.settings.anchor&&(!this.dateDelta||this.dateDelta=0?d(this.container,"rangeSelected"):d(this.container,"rangeError"))}},a.Datepair=f}(window,document),function(a){a&&(a.fn.datepair=function(b){var c;return this.each(function(){var d=a(this),e=d.data("datepair"),f="object"==typeof b&&b;e||(e=new Datepair(this,f),d.data("datepair",e)),"string"==typeof b&&(c=e[b]())}),c||this},a("[data-datepair]").each(function(){var b=a(this);b.datepair(b.data())}))}(window.Zepto||window.jQuery); \ No newline at end of file diff --git a/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.css b/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.css new file mode 100644 index 00000000..cd75f13f --- /dev/null +++ b/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.css @@ -0,0 +1,72 @@ +.ui-timepicker-wrapper { + overflow-y: auto; + height: 150px; + width: 6.5em; + background: #fff; + border: 1px solid #ddd; + -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2); + -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2); + box-shadow:0 5px 10px rgba(0,0,0,0.2); + outline: none; + z-index: 10001; + margin: 0; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration { + width: 13em; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30, +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 { + width: 11em; +} + +.ui-timepicker-list { + margin: 0; + padding: 0; + list-style: none; +} + +.ui-timepicker-duration { + margin-left: 5px; color: #888; +} + +.ui-timepicker-list:hover .ui-timepicker-duration { + color: #888; +} + +.ui-timepicker-list li { + padding: 3px 0 3px 5px; + cursor: pointer; + white-space: nowrap; + color: #000; + list-style: none; + margin: 0; +} + +.ui-timepicker-list:hover .ui-timepicker-selected { + background: #fff; color: #000; +} + +li.ui-timepicker-selected, +.ui-timepicker-list li:hover, +.ui-timepicker-list .ui-timepicker-selected:hover { + background: #1980EC; color: #fff; +} + +li.ui-timepicker-selected .ui-timepicker-duration, +.ui-timepicker-list li:hover .ui-timepicker-duration { + color: #ccc; +} + +.ui-timepicker-list li.ui-timepicker-disabled, +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + color: #888; + cursor: default; +} + +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + background: #f2f2f2; +} diff --git a/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.min.js b/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.min.js new file mode 100644 index 00000000..2a3c329a --- /dev/null +++ b/webif/html/lib/jquery.plugin/timepicker/jquery.timepicker.min.js @@ -0,0 +1,7 @@ +/*! + * jquery-timepicker v1.6.10 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/ + * License: MIT + */ + +!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=t(b.minTime)),b.maxTime&&(b.maxTime=t(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=t(b.durationTime)),"now"==b.scrollDefault?b.scrollDefault=t(new Date):b.scrollDefault?b.scrollDefault=t(b.scrollDefault):b.minTime&&(b.scrollDefault=b.minTime),b.scrollDefault&&(b.scrollDefault=b.roundingFunction(b.scrollDefault,b)),"string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.disableTimeRanges.length>0){for(var c in b.disableTimeRanges)b.disableTimeRanges[c]=[t(b.disableTimeRanges[c][0]),t(b.disableTimeRanges[c][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var c=b.disableTimeRanges.length-1;c>0;c--)b.disableTimeRanges[c][0]<=b.disableTimeRanges[c-1][1]&&(b.disableTimeRanges[c-1]=[Math.min(b.disableTimeRanges[c][0],b.disableTimeRanges[c-1][0]),Math.max(b.disableTimeRanges[c][1],b.disableTimeRanges[c-1][1])],b.disableTimeRanges.splice(c,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a(" + + + + + + +   + + + + + From + + + + + to + + + + + + Channel + + + + + + + Event title + + + + + + + + + +
+ + } diff --git a/webif/html/sched/index.jim b/webif/html/sched/index.jim index 6d5bde78..2416e60b 100755 --- a/webif/html/sched/index.jim +++ b/webif/html/sched/index.jim @@ -4,7 +4,8 @@ package require cgi source /mod/webif/lib/setup require altrow rsv.class progressbar epg.class system.class -jqplugin tablesorter2 contextMenu form blockui confirmAction +jqplugin tablesorter2 contextMenu form blockui confirmAction \ + timepicker datepair jscss script.js header @@ -84,7 +85,8 @@ proc eventrow {event {table TBL_RESERVATION} {pending 0}} { if {$pending} { append attrs " class=\"blueshade strike\"" } - puts "" + altrow $attrs + #puts "" # Checkbox puts ""; @@ -225,9 +227,9 @@ proc eventfooter {rawlink} { } puts " - " - puts " + + + diff --git a/webif/html/sched/manual.jim b/webif/html/sched/manual.jim new file mode 100755 index 00000000..de41a0d0 --- /dev/null +++ b/webif/html/sched/manual.jim @@ -0,0 +1,46 @@ +#!/mod/bin/jimsh + +package require cgi +source /mod/webif/lib/setup +require system.class rsv.class + +httpheader "application/json" + +set fields {start end lcn type repeat} + +set errfields {} +foreach var $fields { + if {[set $var [cgi_get $var -]] eq "-"} { + lappend errfields $var + } +} +set title [cgi_get mrtitle ""] + +puts "{" + +if {[llength $errfields]} { + puts "\"status\" : 0," + puts "\"errfields\": \[" + set flag 0 + foreach e $errfields { + if {$flag} { puts "," } else { incr flag } + puts -nonewline "\"$e\"" + } + puts "" + puts "]" +} else { + if {[catch { + set r [rsv manual $start $end $lcn $type $repeat $title] + } msg]} { + puts "\"status\": 0," + puts "\"err\": \"$msg\"" + } elseif {[catch {$r insert} msg]} { + puts "\"status\": 0," + puts "\"err\": \"$msg\"" + } else { + puts "\"status\": 1" + system restartpending + } +} +puts "}" + diff --git a/webif/html/sched/script.js b/webif/html/sched/script.js index fba8164d..2180f7e6 100755 --- a/webif/html/sched/script.js +++ b/webif/html/sched/script.js @@ -76,7 +76,6 @@ function schedpopup(e, o) } $('a.schedule').click(function(e) { schedpopup(e, $(this)) }); - $('.schedselect:checked').prop('checked', false); $('button.delselected').button({icons:{primary:"ui-icon-trash"}}) @@ -287,5 +286,120 @@ $('#schedule_cleanup').bind('click', function(e) { }); }); +// Manual reservation + +$('#manrsv').dialog({ + autoOpen: false, + height: 'auto', width: 'auto', + modal: true, + buttons: { + "Create event": function() { + var data = $('#mrform').serializeArray(); + + var s = $('#mrstime').timepicker('getTime', + $('#mrsdate').datepicker('getDate')); + if (s) + data.push({ name: "start", value: s.getTime() / 1000}); + + var s = $('#mretime').timepicker('getTime', + $('#mredate').datepicker('getDate')); + if (s) + data.push({ name: "end", value: s.getTime() / 1000}); + + $('#mrerr') + .html(' Creating event...'); + + $.getJSON('manual.jim', data, function(d) { + if (d.status) + window.location.reload(true); + else if (d.errfields) + { + d.errfields.forEach(function(item) { + $('#mrform input[name=' + item + ']') + .addClass('error'); + }); + $('#mrerr').html('The start and end times ' + + 'must be provided.'); + } + else if (d.err) + $('#mrerr').html(d.err); + }); + }, + "Cancel": function() { + $(this).dialog('close'); + } + } +}); + +$('button.manual_rsv').button({icons:{primary:"ui-icon-clock"}}) + .on('click', function() { + $('#mrform').get(0).reset(); + $('#mrform input.date').datepicker('setDate', null); + $('#mrform input.time').timepicker('setTime', null); + $('#manrsv').dialog('open'); + +// $("#manrsv .ui-dialog-buttonpane button:contains('Create')") +// .button('disable') + + if ($('#mrlcn').hasClass('blood')) + { + var $s = $('#mrlcn'); + $.getJSON('/cgi-bin/chanlist.jim', function(data) { + $s.find('option').remove(); + $.each(data, function(lcn, name) { + $('