simple_pvr 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +1 -4
- data/Gemfile.lock +72 -61
- data/README.md +51 -33
- data/bin/pvr_server +14 -6
- data/changelog.txt +11 -0
- data/development_server +14 -6
- data/features/channel_overview.feature +1 -1
- data/features/recordings.feature +30 -0
- data/features/step_definitions/pvr_steps.rb +34 -0
- data/features/support/env.rb +1 -2
- data/features/support/paths.rb +2 -0
- data/lib/simple_pvr.rb +2 -0
- data/lib/simple_pvr/model/database_initializer.rb +8 -0
- data/lib/simple_pvr/model/programme.rb +12 -2
- data/lib/simple_pvr/model/programme_actor.rb +14 -0
- data/lib/simple_pvr/model/programme_category.rb +14 -0
- data/lib/simple_pvr/model/programme_director.rb +13 -0
- data/lib/simple_pvr/model/programme_presenter.rb +13 -0
- data/lib/simple_pvr/model/recording.rb +12 -0
- data/lib/simple_pvr/programme_icon_fetcher.rb +15 -0
- data/lib/simple_pvr/pvr_initializer.rb +4 -4
- data/lib/simple_pvr/recorder.rb +4 -3
- data/lib/simple_pvr/recording_manager.rb +44 -24
- data/lib/simple_pvr/recording_planner.rb +3 -3
- data/lib/simple_pvr/scheduler.rb +12 -4
- data/lib/simple_pvr/server/base_controller.rb +12 -13
- data/lib/simple_pvr/server/channels_controller.rb +5 -5
- data/lib/simple_pvr/server/programmes_controller.rb +2 -2
- data/lib/simple_pvr/server/schedules_controller.rb +4 -4
- data/lib/simple_pvr/server/secured_controller.rb +71 -0
- data/lib/simple_pvr/server/shows_controller.rb +13 -8
- data/lib/simple_pvr/server/status_controller.rb +1 -1
- data/lib/simple_pvr/server/upcoming_recordings_controller.rb +1 -1
- data/lib/simple_pvr/version.rb +1 -1
- data/lib/simple_pvr/xmltv_reader.rb +37 -4
- data/public/css/typeahead.js-bootstrap.css +83 -0
- data/public/index.html +45 -37
- data/public/js/angular/http-auth-interceptor.js +122 -0
- data/public/js/app.js +4 -37
- data/public/js/controllers.js +22 -14
- data/public/js/directives.js +102 -0
- data/public/js/filters.js +0 -31
- data/public/js/services.js +64 -0
- data/public/js/typeahead/typeahead.min.js +7 -0
- data/public/partials/about.html +15 -13
- data/public/partials/channels.html +41 -36
- data/public/partials/programme.html +20 -4
- data/public/partials/programmeListing.html +14 -13
- data/public/partials/schedule.html +91 -86
- data/public/partials/schedules.html +28 -16
- data/public/partials/search.html +10 -11
- data/public/partials/show.html +26 -9
- data/public/partials/shows.html +5 -6
- data/public/partials/status.html +1 -1
- data/public/templates/loginDialog.html +30 -0
- data/public/templates/logoutLink.html +1 -0
- data/public/templates/titleSearch.html +5 -3
- data/simple_pvr.gemspec +6 -4
- data/spec/resources/dummyImage.png +1 -0
- data/spec/resources/programmes-with-categories.xmltv +27 -0
- data/spec/resources/programmes-with-credits.xmltv +24 -0
- data/spec/resources/programmes-with-icons.xmltv +25 -0
- data/spec/resources/programmes-with-presenters.xmltv +19 -0
- data/spec/resources/{programs-without-icon.xmltv → programmes-without-icon.xmltv} +0 -0
- data/spec/resources/{programs.xmltv → programmes.xmltv} +0 -4
- data/spec/simple_pvr/ffmpeg_spec.rb +24 -22
- data/spec/simple_pvr/hdhomerun_spec.rb +69 -67
- data/spec/simple_pvr/model/channel_spec.rb +101 -101
- data/spec/simple_pvr/model/programme_spec.rb +104 -104
- data/spec/simple_pvr/model/schedule_spec.rb +74 -74
- data/spec/simple_pvr/programme_icon_fetcher_spec.rb +25 -0
- data/spec/simple_pvr/pvr_initializer_spec.rb +40 -38
- data/spec/simple_pvr/recorder_spec.rb +37 -26
- data/spec/simple_pvr/recording_manager_spec.rb +160 -133
- data/spec/simple_pvr/recording_planner_spec.rb +213 -211
- data/spec/simple_pvr/scheduler_spec.rb +189 -172
- data/spec/simple_pvr/server/secured_controller_spec.rb +118 -0
- data/spec/simple_pvr/xmltv_reader_spec.rb +89 -41
- data/test/karma.conf.js +7 -4
- data/test/unit/filtersSpec.js +0 -36
- metadata +79 -63
- data/public/css/bootstrap-responsive.min.css +0 -9
- data/public/css/bootstrap.min.css +0 -9
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/js/angular/angular-resource.min.js +0 -10
- data/public/js/angular/angular.min.js +0 -162
- data/public/js/bootstrap/bootstrap.min.js +0 -6
- data/public/js/jquery/jquery.min.js +0 -5
- data/test/lib/angular/angular-mocks.js +0 -1768
data/public/js/services.js
CHANGED
@@ -24,4 +24,68 @@ factory('Recording', function($resource) {
|
|
24
24
|
}).
|
25
25
|
factory('Status', function($resource) {
|
26
26
|
return $resource('/api/status');
|
27
|
+
}).
|
28
|
+
service('loginService', function($http, $cookieStore, authService) {
|
29
|
+
// Taken from http://wemadeyoulook.at/en/blog/implementing-basic-http-authentication-http-requests-angular/
|
30
|
+
function encodeBase64(input) {
|
31
|
+
var keyStr = 'ABCDEFGHIJKLMNOP' +
|
32
|
+
'QRSTUVWXYZabcdef' +
|
33
|
+
'ghijklmnopqrstuv' +
|
34
|
+
'wxyz0123456789+/' +
|
35
|
+
'=';
|
36
|
+
|
37
|
+
var output = '';
|
38
|
+
var chr1, chr2, chr3 = '';
|
39
|
+
var enc1, enc2, enc3, enc4 = '';
|
40
|
+
var i = 0;
|
41
|
+
|
42
|
+
do {
|
43
|
+
chr1 = input.charCodeAt(i++);
|
44
|
+
chr2 = input.charCodeAt(i++);
|
45
|
+
chr3 = input.charCodeAt(i++);
|
46
|
+
|
47
|
+
enc1 = chr1 >> 2;
|
48
|
+
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
49
|
+
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
50
|
+
enc4 = chr3 & 63;
|
51
|
+
|
52
|
+
if (isNaN(chr2)) {
|
53
|
+
enc3 = enc4 = 64;
|
54
|
+
} else if (isNaN(chr3)) {
|
55
|
+
enc4 = 64;
|
56
|
+
}
|
57
|
+
|
58
|
+
output = output +
|
59
|
+
keyStr.charAt(enc1) +
|
60
|
+
keyStr.charAt(enc2) +
|
61
|
+
keyStr.charAt(enc3) +
|
62
|
+
keyStr.charAt(enc4);
|
63
|
+
chr1 = chr2 = chr3 = '';
|
64
|
+
enc1 = enc2 = enc3 = enc4 = '';
|
65
|
+
} while (i < input.length);
|
66
|
+
|
67
|
+
return output;
|
68
|
+
}
|
69
|
+
|
70
|
+
var basicCredentials = $cookieStore.get('basicCredentials');
|
71
|
+
if (basicCredentials) {
|
72
|
+
$http.defaults.headers.common['Authorization'] = 'Basic ' + basicCredentials;
|
73
|
+
}
|
74
|
+
|
75
|
+
return {
|
76
|
+
setUserNameAndPassword: function(userName, password) {
|
77
|
+
var encodedUserNameAndPassword = encodeBase64(userName + ':' + password);
|
78
|
+
$cookieStore.put('basicCredentials', encodedUserNameAndPassword);
|
79
|
+
|
80
|
+
$http.defaults.headers.common['Authorization'] = 'Basic ' + encodedUserNameAndPassword;
|
81
|
+
authService.loginConfirmed();
|
82
|
+
},
|
83
|
+
isLoggedIn: function() {
|
84
|
+
return $cookieStore.get('basicCredentials') !== undefined;
|
85
|
+
},
|
86
|
+
logOut: function() {
|
87
|
+
$cookieStore.remove('basicCredentials');
|
88
|
+
delete $http.defaults.headers.common['Authorization'];
|
89
|
+
}
|
90
|
+
}
|
27
91
|
});
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*!
|
2
|
+
* typeahead.js 0.9.3
|
3
|
+
* https://github.com/twitter/typeahead
|
4
|
+
* Copyright 2013 Twitter, Inc. and other contributors; Licensed MIT
|
5
|
+
*/
|
6
|
+
|
7
|
+
!function(a){var b="0.9.3",c={isMsie:function(){var a=/(msie) ([\w.]+)/i.exec(navigator.userAgent);return a?parseInt(a[2],10):!1},isBlankString:function(a){return!a||/^\s*$/.test(a)},escapeRegExChars:function(a){return a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(a){return"string"==typeof a},isNumber:function(a){return"number"==typeof a},isArray:a.isArray,isFunction:a.isFunction,isObject:a.isPlainObject,isUndefined:function(a){return"undefined"==typeof a},bind:a.proxy,bindAll:function(b){var c;for(var d in b)a.isFunction(c=b[d])&&(b[d]=a.proxy(c,b))},indexOf:function(a,b){for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1},each:a.each,map:a.map,filter:a.grep,every:function(b,c){var d=!0;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?void 0:!1}),!!d):d},some:function(b,c){var d=!1;return b?(a.each(b,function(a,e){return(d=c.call(null,e,a,b))?!1:void 0}),!!d):d},mixin:a.extend,getUniqueId:function(){var a=0;return function(){return a++}}(),defer:function(a){setTimeout(a,0)},debounce:function(a,b,c){var d,e;return function(){var f,g,h=this,i=arguments;return f=function(){d=null,c||(e=a.apply(h,i))},g=c&&!d,clearTimeout(d),d=setTimeout(f,b),g&&(e=a.apply(h,i)),e}},throttle:function(a,b){var c,d,e,f,g,h;return g=0,h=function(){g=new Date,e=null,f=a.apply(c,d)},function(){var i=new Date,j=b-(i-g);return c=this,d=arguments,0>=j?(clearTimeout(e),e=null,g=i,f=a.apply(c,d)):e||(e=setTimeout(h,j)),f}},tokenizeQuery:function(b){return a.trim(b).toLowerCase().split(/[\s]+/)},tokenizeText:function(b){return a.trim(b).toLowerCase().split(/[\s\-_]+/)},getProtocol:function(){return location.protocol},noop:function(){}},d=function(){var a=/\s+/;return{on:function(b,c){var d;if(!c)return this;for(this._callbacks=this._callbacks||{},b=b.split(a);d=b.shift();)this._callbacks[d]=this._callbacks[d]||[],this._callbacks[d].push(c);return this},trigger:function(b,c){var d,e;if(!this._callbacks)return this;for(b=b.split(a);d=b.shift();)if(e=this._callbacks[d])for(var f=0;f<e.length;f+=1)e[f].call(this,{type:d,data:c});return this}}}(),e=function(){function b(b){b&&b.el||a.error("EventBus initialized without el"),this.$el=a(b.el)}var d="typeahead:";return c.mixin(b.prototype,{trigger:function(a){var b=[].slice.call(arguments,1);this.$el.trigger(d+a,b)}}),b}(),f=function(){function a(a){this.prefix=["__",a,"__"].join(""),this.ttlKey="__ttl__",this.keyMatcher=new RegExp("^"+this.prefix)}function b(){return(new Date).getTime()}function d(a){return JSON.stringify(c.isUndefined(a)?null:a)}function e(a){return JSON.parse(a)}var f,g;try{f=window.localStorage,f.setItem("~~~","!"),f.removeItem("~~~")}catch(h){f=null}return g=f&&window.JSON?{_prefix:function(a){return this.prefix+a},_ttlKey:function(a){return this._prefix(a)+this.ttlKey},get:function(a){return this.isExpired(a)&&this.remove(a),e(f.getItem(this._prefix(a)))},set:function(a,e,g){return c.isNumber(g)?f.setItem(this._ttlKey(a),d(b()+g)):f.removeItem(this._ttlKey(a)),f.setItem(this._prefix(a),d(e))},remove:function(a){return f.removeItem(this._ttlKey(a)),f.removeItem(this._prefix(a)),this},clear:function(){var a,b,c=[],d=f.length;for(a=0;d>a;a++)(b=f.key(a)).match(this.keyMatcher)&&c.push(b.replace(this.keyMatcher,""));for(a=c.length;a--;)this.remove(c[a]);return this},isExpired:function(a){var d=e(f.getItem(this._ttlKey(a)));return c.isNumber(d)&&b()>d?!0:!1}}:{get:c.noop,set:c.noop,remove:c.noop,clear:c.noop,isExpired:c.noop},c.mixin(a.prototype,g),a}(),g=function(){function a(a){c.bindAll(this),a=a||{},this.sizeLimit=a.sizeLimit||10,this.cache={},this.cachedKeysByAge=[]}return c.mixin(a.prototype,{get:function(a){return this.cache[a]},set:function(a,b){var c;this.cachedKeysByAge.length===this.sizeLimit&&(c=this.cachedKeysByAge.shift(),delete this.cache[c]),this.cache[a]=b,this.cachedKeysByAge.push(a)}}),a}(),h=function(){function b(a){c.bindAll(this),a=c.isString(a)?{url:a}:a,i=i||new g,h=c.isNumber(a.maxParallelRequests)?a.maxParallelRequests:h||6,this.url=a.url,this.wildcard=a.wildcard||"%QUERY",this.filter=a.filter,this.replace=a.replace,this.ajaxSettings={type:"get",cache:a.cache,timeout:a.timeout,dataType:a.dataType||"json",beforeSend:a.beforeSend},this._get=(/^throttle$/i.test(a.rateLimitFn)?c.throttle:c.debounce)(this._get,a.rateLimitWait||300)}function d(){j++}function e(){j--}function f(){return h>j}var h,i,j=0,k={};return c.mixin(b.prototype,{_get:function(a,b){function c(c){var e=d.filter?d.filter(c):c;b&&b(e),i.set(a,c)}var d=this;f()?this._sendRequest(a).done(c):this.onDeckRequestArgs=[].slice.call(arguments,0)},_sendRequest:function(b){function c(){e(),k[b]=null,f.onDeckRequestArgs&&(f._get.apply(f,f.onDeckRequestArgs),f.onDeckRequestArgs=null)}var f=this,g=k[b];return g||(d(),g=k[b]=a.ajax(b,this.ajaxSettings).always(c)),g},get:function(a,b){var d,e,f=this,g=encodeURIComponent(a||"");return b=b||c.noop,d=this.replace?this.replace(this.url,g):this.url.replace(this.wildcard,g),(e=i.get(d))?c.defer(function(){b(f.filter?f.filter(e):e)}):this._get(d,b),!!e}}),b}(),i=function(){function d(b){c.bindAll(this),c.isString(b.template)&&!b.engine&&a.error("no template engine specified"),b.local||b.prefetch||b.remote||a.error("one of local, prefetch, or remote is required"),this.name=b.name||c.getUniqueId(),this.limit=b.limit||5,this.minLength=b.minLength||1,this.header=b.header,this.footer=b.footer,this.valueKey=b.valueKey||"value",this.template=e(b.template,b.engine,this.valueKey),this.local=b.local,this.prefetch=b.prefetch,this.remote=b.remote,this.itemHash={},this.adjacencyList={},this.storage=b.name?new f(b.name):null}function e(a,b,d){var e,f;return c.isFunction(a)?e=a:c.isString(a)?(f=b.compile(a),e=c.bind(f.render,f)):e=function(a){return"<p>"+a[d]+"</p>"},e}var g={thumbprint:"thumbprint",protocol:"protocol",itemHash:"itemHash",adjacencyList:"adjacencyList"};return c.mixin(d.prototype,{_processLocalData:function(a){this._mergeProcessedData(this._processData(a))},_loadPrefetchData:function(d){function e(a){var b=d.filter?d.filter(a):a,e=m._processData(b),f=e.itemHash,h=e.adjacencyList;m.storage&&(m.storage.set(g.itemHash,f,d.ttl),m.storage.set(g.adjacencyList,h,d.ttl),m.storage.set(g.thumbprint,n,d.ttl),m.storage.set(g.protocol,c.getProtocol(),d.ttl)),m._mergeProcessedData(e)}var f,h,i,j,k,l,m=this,n=b+(d.thumbprint||"");return this.storage&&(f=this.storage.get(g.thumbprint),h=this.storage.get(g.protocol),i=this.storage.get(g.itemHash),j=this.storage.get(g.adjacencyList)),k=f!==n||h!==c.getProtocol(),d=c.isString(d)?{url:d}:d,d.ttl=c.isNumber(d.ttl)?d.ttl:864e5,i&&j&&!k?(this._mergeProcessedData({itemHash:i,adjacencyList:j}),l=a.Deferred().resolve()):l=a.getJSON(d.url).done(e),l},_transformDatum:function(a){var b=c.isString(a)?a:a[this.valueKey],d=a.tokens||c.tokenizeText(b),e={value:b,tokens:d};return c.isString(a)?(e.datum={},e.datum[this.valueKey]=a):e.datum=a,e.tokens=c.filter(e.tokens,function(a){return!c.isBlankString(a)}),e.tokens=c.map(e.tokens,function(a){return a.toLowerCase()}),e},_processData:function(a){var b=this,d={},e={};return c.each(a,function(a,f){var g=b._transformDatum(f),h=c.getUniqueId(g.value);d[h]=g,c.each(g.tokens,function(a,b){var d=b.charAt(0),f=e[d]||(e[d]=[h]);!~c.indexOf(f,h)&&f.push(h)})}),{itemHash:d,adjacencyList:e}},_mergeProcessedData:function(a){var b=this;c.mixin(this.itemHash,a.itemHash),c.each(a.adjacencyList,function(a,c){var d=b.adjacencyList[a];b.adjacencyList[a]=d?d.concat(c):c})},_getLocalSuggestions:function(a){var b,d=this,e=[],f=[],g=[];return c.each(a,function(a,b){var d=b.charAt(0);!~c.indexOf(e,d)&&e.push(d)}),c.each(e,function(a,c){var e=d.adjacencyList[c];return e?(f.push(e),(!b||e.length<b.length)&&(b=e),void 0):!1}),f.length<e.length?[]:(c.each(b,function(b,e){var h,i,j=d.itemHash[e];h=c.every(f,function(a){return~c.indexOf(a,e)}),i=h&&c.every(a,function(a){return c.some(j.tokens,function(b){return 0===b.indexOf(a)})}),i&&g.push(j)}),g)},initialize:function(){var b;return this.local&&this._processLocalData(this.local),this.transport=this.remote?new h(this.remote):null,b=this.prefetch?this._loadPrefetchData(this.prefetch):a.Deferred().resolve(),this.local=this.prefetch=this.remote=null,this.initialize=function(){return b},b},getSuggestions:function(a,b){function d(a){f=f.slice(0),c.each(a,function(a,b){var d,e=g._transformDatum(b);return d=c.some(f,function(a){return e.value===a.value}),!d&&f.push(e),f.length<g.limit}),b&&b(f)}var e,f,g=this,h=!1;a.length<this.minLength||(e=c.tokenizeQuery(a),f=this._getLocalSuggestions(e).slice(0,this.limit),f.length<this.limit&&this.transport&&(h=this.transport.get(a,d)),!h&&b&&b(f))}}),d}(),j=function(){function b(b){var d=this;c.bindAll(this),this.specialKeyCodeMap={9:"tab",27:"esc",37:"left",39:"right",13:"enter",38:"up",40:"down"},this.$hint=a(b.hint),this.$input=a(b.input).on("blur.tt",this._handleBlur).on("focus.tt",this._handleFocus).on("keydown.tt",this._handleSpecialKeyEvent),c.isMsie()?this.$input.on("keydown.tt keypress.tt cut.tt paste.tt",function(a){d.specialKeyCodeMap[a.which||a.keyCode]||c.defer(d._compareQueryToInputValue)}):this.$input.on("input.tt",this._compareQueryToInputValue),this.query=this.$input.val(),this.$overflowHelper=e(this.$input)}function e(b){return a("<span></span>").css({position:"absolute",left:"-9999px",visibility:"hidden",whiteSpace:"nowrap",fontFamily:b.css("font-family"),fontSize:b.css("font-size"),fontStyle:b.css("font-style"),fontVariant:b.css("font-variant"),fontWeight:b.css("font-weight"),wordSpacing:b.css("word-spacing"),letterSpacing:b.css("letter-spacing"),textIndent:b.css("text-indent"),textRendering:b.css("text-rendering"),textTransform:b.css("text-transform")}).insertAfter(b)}function f(a,b){return a=(a||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),b=(b||"").replace(/^\s*/g,"").replace(/\s{2,}/g," "),a===b}return c.mixin(b.prototype,d,{_handleFocus:function(){this.trigger("focused")},_handleBlur:function(){this.trigger("blured")},_handleSpecialKeyEvent:function(a){var b=this.specialKeyCodeMap[a.which||a.keyCode];b&&this.trigger(b+"Keyed",a)},_compareQueryToInputValue:function(){var a=this.getInputValue(),b=f(this.query,a),c=b?this.query.length!==a.length:!1;c?this.trigger("whitespaceChanged",{value:this.query}):b||this.trigger("queryChanged",{value:this.query=a})},destroy:function(){this.$hint.off(".tt"),this.$input.off(".tt"),this.$hint=this.$input=this.$overflowHelper=null},focus:function(){this.$input.focus()},blur:function(){this.$input.blur()},getQuery:function(){return this.query},setQuery:function(a){this.query=a},getInputValue:function(){return this.$input.val()},setInputValue:function(a,b){this.$input.val(a),!b&&this._compareQueryToInputValue()},getHintValue:function(){return this.$hint.val()},setHintValue:function(a){this.$hint.val(a)},getLanguageDirection:function(){return(this.$input.css("direction")||"ltr").toLowerCase()},isOverflow:function(){return this.$overflowHelper.text(this.getInputValue()),this.$overflowHelper.width()>this.$input.width()},isCursorAtEnd:function(){var a,b=this.$input.val().length,d=this.$input[0].selectionStart;return c.isNumber(d)?d===b:document.selection?(a=document.selection.createRange(),a.moveStart("character",-b),b===a.text.length):!0}}),b}(),k=function(){function b(b){c.bindAll(this),this.isOpen=!1,this.isEmpty=!0,this.isMouseOverDropdown=!1,this.$menu=a(b.menu).on("mouseenter.tt",this._handleMouseenter).on("mouseleave.tt",this._handleMouseleave).on("click.tt",".tt-suggestion",this._handleSelection).on("mouseover.tt",".tt-suggestion",this._handleMouseover)}function e(a){return a.data("suggestion")}var f={suggestionsList:'<span class="tt-suggestions"></span>'},g={suggestionsList:{display:"block"},suggestion:{whiteSpace:"nowrap",cursor:"pointer"},suggestionChild:{whiteSpace:"normal"}};return c.mixin(b.prototype,d,{_handleMouseenter:function(){this.isMouseOverDropdown=!0},_handleMouseleave:function(){this.isMouseOverDropdown=!1},_handleMouseover:function(b){var c=a(b.currentTarget);this._getSuggestions().removeClass("tt-is-under-cursor"),c.addClass("tt-is-under-cursor")},_handleSelection:function(b){var c=a(b.currentTarget);this.trigger("suggestionSelected",e(c))},_show:function(){this.$menu.css("display","block")},_hide:function(){this.$menu.hide()},_moveCursor:function(a){var b,c,d,f;if(this.isVisible()){if(b=this._getSuggestions(),c=b.filter(".tt-is-under-cursor"),c.removeClass("tt-is-under-cursor"),d=b.index(c)+a,d=(d+1)%(b.length+1)-1,-1===d)return this.trigger("cursorRemoved"),void 0;-1>d&&(d=b.length-1),f=b.eq(d).addClass("tt-is-under-cursor"),this._ensureVisibility(f),this.trigger("cursorMoved",e(f))}},_getSuggestions:function(){return this.$menu.find(".tt-suggestions > .tt-suggestion")},_ensureVisibility:function(a){var b=this.$menu.height()+parseInt(this.$menu.css("paddingTop"),10)+parseInt(this.$menu.css("paddingBottom"),10),c=this.$menu.scrollTop(),d=a.position().top,e=d+a.outerHeight(!0);0>d?this.$menu.scrollTop(c+d):e>b&&this.$menu.scrollTop(c+(e-b))},destroy:function(){this.$menu.off(".tt"),this.$menu=null},isVisible:function(){return this.isOpen&&!this.isEmpty},closeUnlessMouseIsOverDropdown:function(){this.isMouseOverDropdown||this.close()},close:function(){this.isOpen&&(this.isOpen=!1,this.isMouseOverDropdown=!1,this._hide(),this.$menu.find(".tt-suggestions > .tt-suggestion").removeClass("tt-is-under-cursor"),this.trigger("closed"))},open:function(){this.isOpen||(this.isOpen=!0,!this.isEmpty&&this._show(),this.trigger("opened"))},setLanguageDirection:function(a){var b={left:"0",right:"auto"},c={left:"auto",right:" 0"};"ltr"===a?this.$menu.css(b):this.$menu.css(c)},moveCursorUp:function(){this._moveCursor(-1)},moveCursorDown:function(){this._moveCursor(1)},getSuggestionUnderCursor:function(){var a=this._getSuggestions().filter(".tt-is-under-cursor").first();return a.length>0?e(a):null},getFirstSuggestion:function(){var a=this._getSuggestions().first();return a.length>0?e(a):null},renderSuggestions:function(b,d){var e,h,i,j,k,l="tt-dataset-"+b.name,m='<div class="tt-suggestion">%body</div>',n=this.$menu.find("."+l);0===n.length&&(h=a(f.suggestionsList).css(g.suggestionsList),n=a("<div></div>").addClass(l).append(b.header).append(h).append(b.footer).appendTo(this.$menu)),d.length>0?(this.isEmpty=!1,this.isOpen&&this._show(),i=document.createElement("div"),j=document.createDocumentFragment(),c.each(d,function(c,d){d.dataset=b.name,e=b.template(d.datum),i.innerHTML=m.replace("%body",e),k=a(i.firstChild).css(g.suggestion).data("suggestion",d),k.children().each(function(){a(this).css(g.suggestionChild)}),j.appendChild(k[0])}),n.show().find(".tt-suggestions").html(j)):this.clearSuggestions(b.name),this.trigger("suggestionsRendered")},clearSuggestions:function(a){var b=a?this.$menu.find(".tt-dataset-"+a):this.$menu.find('[class^="tt-dataset-"]'),c=b.find(".tt-suggestions");b.hide(),c.empty(),0===this._getSuggestions().length&&(this.isEmpty=!0,this._hide())}}),b}(),l=function(){function b(a){var b,d,f;c.bindAll(this),this.$node=e(a.input),this.datasets=a.datasets,this.dir=null,this.eventBus=a.eventBus,b=this.$node.find(".tt-dropdown-menu"),d=this.$node.find(".tt-query"),f=this.$node.find(".tt-hint"),this.dropdownView=new k({menu:b}).on("suggestionSelected",this._handleSelection).on("cursorMoved",this._clearHint).on("cursorMoved",this._setInputValueToSuggestionUnderCursor).on("cursorRemoved",this._setInputValueToQuery).on("cursorRemoved",this._updateHint).on("suggestionsRendered",this._updateHint).on("opened",this._updateHint).on("closed",this._clearHint).on("opened closed",this._propagateEvent),this.inputView=new j({input:d,hint:f}).on("focused",this._openDropdown).on("blured",this._closeDropdown).on("blured",this._setInputValueToQuery).on("enterKeyed tabKeyed",this._handleSelection).on("queryChanged",this._clearHint).on("queryChanged",this._clearSuggestions).on("queryChanged",this._getSuggestions).on("whitespaceChanged",this._updateHint).on("queryChanged whitespaceChanged",this._openDropdown).on("queryChanged whitespaceChanged",this._setLanguageDirection).on("escKeyed",this._closeDropdown).on("escKeyed",this._setInputValueToQuery).on("tabKeyed upKeyed downKeyed",this._managePreventDefault).on("upKeyed downKeyed",this._moveDropdownCursor).on("upKeyed downKeyed",this._openDropdown).on("tabKeyed leftKeyed rightKeyed",this._autocomplete)}function e(b){var c=a(g.wrapper),d=a(g.dropdown),e=a(b),f=a(g.hint);c=c.css(h.wrapper),d=d.css(h.dropdown),f.css(h.hint).css({backgroundAttachment:e.css("background-attachment"),backgroundClip:e.css("background-clip"),backgroundColor:e.css("background-color"),backgroundImage:e.css("background-image"),backgroundOrigin:e.css("background-origin"),backgroundPosition:e.css("background-position"),backgroundRepeat:e.css("background-repeat"),backgroundSize:e.css("background-size")}),e.data("ttAttrs",{dir:e.attr("dir"),autocomplete:e.attr("autocomplete"),spellcheck:e.attr("spellcheck"),style:e.attr("style")}),e.addClass("tt-query").attr({autocomplete:"off",spellcheck:!1}).css(h.query);try{!e.attr("dir")&&e.attr("dir","auto")}catch(i){}return e.wrap(c).parent().prepend(f).append(d)}function f(a){var b=a.find(".tt-query");c.each(b.data("ttAttrs"),function(a,d){c.isUndefined(d)?b.removeAttr(a):b.attr(a,d)}),b.detach().removeData("ttAttrs").removeClass("tt-query").insertAfter(a),a.remove()}var g={wrapper:'<span class="twitter-typeahead"></span>',hint:'<input class="tt-hint" type="text" autocomplete="off" spellcheck="off" disabled>',dropdown:'<span class="tt-dropdown-menu"></span>'},h={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none"},query:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},dropdown:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"}};return c.isMsie()&&c.mixin(h.query,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),c.isMsie()&&c.isMsie()<=7&&(c.mixin(h.wrapper,{display:"inline",zoom:"1"}),c.mixin(h.query,{marginTop:"-1px"})),c.mixin(b.prototype,d,{_managePreventDefault:function(a){var b,c,d=a.data,e=!1;switch(a.type){case"tabKeyed":b=this.inputView.getHintValue(),c=this.inputView.getInputValue(),e=b&&b!==c;break;case"upKeyed":case"downKeyed":e=!d.shiftKey&&!d.ctrlKey&&!d.metaKey}e&&d.preventDefault()},_setLanguageDirection:function(){var a=this.inputView.getLanguageDirection();a!==this.dir&&(this.dir=a,this.$node.css("direction",a),this.dropdownView.setLanguageDirection(a))},_updateHint:function(){var a,b,d,e,f,g=this.dropdownView.getFirstSuggestion(),h=g?g.value:null,i=this.dropdownView.isVisible(),j=this.inputView.isOverflow();h&&i&&!j&&(a=this.inputView.getInputValue(),b=a.replace(/\s{2,}/g," ").replace(/^\s+/g,""),d=c.escapeRegExChars(b),e=new RegExp("^(?:"+d+")(.*$)","i"),f=e.exec(h),this.inputView.setHintValue(a+(f?f[1]:"")))},_clearHint:function(){this.inputView.setHintValue("")},_clearSuggestions:function(){this.dropdownView.clearSuggestions()},_setInputValueToQuery:function(){this.inputView.setInputValue(this.inputView.getQuery())},_setInputValueToSuggestionUnderCursor:function(a){var b=a.data;this.inputView.setInputValue(b.value,!0)},_openDropdown:function(){this.dropdownView.open()},_closeDropdown:function(a){this.dropdownView["blured"===a.type?"closeUnlessMouseIsOverDropdown":"close"]()},_moveDropdownCursor:function(a){var b=a.data;b.shiftKey||b.ctrlKey||b.metaKey||this.dropdownView["upKeyed"===a.type?"moveCursorUp":"moveCursorDown"]()},_handleSelection:function(a){var b="suggestionSelected"===a.type,d=b?a.data:this.dropdownView.getSuggestionUnderCursor();d&&(this.inputView.setInputValue(d.value),b?this.inputView.focus():a.data.preventDefault(),b&&c.isMsie()?c.defer(this.dropdownView.close):this.dropdownView.close(),this.eventBus.trigger("selected",d.datum,d.dataset))},_getSuggestions:function(){var a=this,b=this.inputView.getQuery();c.isBlankString(b)||c.each(this.datasets,function(c,d){d.getSuggestions(b,function(c){b===a.inputView.getQuery()&&a.dropdownView.renderSuggestions(d,c)})})},_autocomplete:function(a){var b,c,d,e,f;("rightKeyed"!==a.type&&"leftKeyed"!==a.type||(b=this.inputView.isCursorAtEnd(),c="ltr"===this.inputView.getLanguageDirection()?"leftKeyed"===a.type:"rightKeyed"===a.type,b&&!c))&&(d=this.inputView.getQuery(),e=this.inputView.getHintValue(),""!==e&&d!==e&&(f=this.dropdownView.getFirstSuggestion(),this.inputView.setInputValue(f.value),this.eventBus.trigger("autocompleted",f.datum,f.dataset)))},_propagateEvent:function(a){this.eventBus.trigger(a.type)},destroy:function(){this.inputView.destroy(),this.dropdownView.destroy(),f(this.$node),this.$node=null},setQuery:function(a){this.inputView.setQuery(a),this.inputView.setInputValue(a),this._clearHint(),this._clearSuggestions(),this._getSuggestions()}}),b}();!function(){var b,d={},f="ttView";b={initialize:function(b){function g(){var b,d=a(this),g=new e({el:d});b=c.map(h,function(a){return a.initialize()}),d.data(f,new l({input:d,eventBus:g=new e({el:d}),datasets:h})),a.when.apply(a,b).always(function(){c.defer(function(){g.trigger("initialized")})})}var h;return b=c.isArray(b)?b:[b],0===b.length&&a.error("no datasets provided"),h=c.map(b,function(a){var b=d[a.name]?d[a.name]:new i(a);return a.name&&(d[a.name]=b),b}),this.each(g)},destroy:function(){function b(){var b=a(this),c=b.data(f);c&&(c.destroy(),b.removeData(f))}return this.each(b)},setQuery:function(b){function c(){var c=a(this).data(f);c&&c.setQuery(b)}return this.each(c)}},jQuery.fn.typeahead=function(a){return b[a]?b[a].apply(this,[].slice.call(arguments,1)):b.initialize.apply(this,arguments)}}()}(window.jQuery);
|
data/public/partials/about.html
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
<div class="
|
1
|
+
<div class="jumbotron">
|
2
2
|
<h1>SimplePVR</h1>
|
3
3
|
<p>A really, really simple PVR (Personal Video Recorder) system which only supports the HDHomeRun network tuners. It's written in Ruby and is highly hackable. If you don't want to hack it, but just want a solid PVR system, no worries: It's dead-simple to use.</p>
|
4
|
-
<p><a href="https://github.com/olefriis/simplepvr" class="btn btn-primary btn-large">Learn more »</a></p>
|
4
|
+
<p><a href="https://github.com/olefriis/simplepvr-backend-ruby/wiki" class="btn btn-primary btn-large">Learn more »</a></p>
|
5
5
|
</div>
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
</
|
16
|
-
|
6
|
+
<h2>Thanks!</h2>
|
7
|
+
<p>SimplePVR is built on top of a number of really great, free products. A huge "thank you!" goes to all the people developing and
|
8
|
+
supporting them!
|
9
|
+
<ul>
|
10
|
+
<li><a href="http://jquery.com/">JQuery</a> (<a href="https://jquery.org/license/">MIT license</a>)</li>
|
11
|
+
<li><a href="http://angularjs.org/">AngularJS</a> (<a href="https://github.com/angular/angular.js/blob/master/LICENSE">MIT license</a>)</li>
|
12
|
+
<li><a href="http://getbootstrap.com/">Twitter Bootstrap</a> (<a href="https://github.com/twbs/bootstrap/blob/master/LICENSE">MIT license</a>)</li>
|
13
|
+
<li><a href="http://glyphicons.com/">Glyphicons</a> (<a href="https://github.com/twbs/bootstrap/blob/master/LICENSE">MIT license</a>, as <a href="http://glyphicons.com/license/">it's used with Twitter Bootstrap</a>)</li>
|
14
|
+
<li>Slightly modified version of <a href="https://github.com/witoldsz/angular-http-auth">angular-http-auth</a> (<a href="https://github.com/witoldsz/angular-http-auth/blob/master/LICENSE">MIT license</a>)</li>
|
15
|
+
<li><a href="http://wemadeyoulook.at/en/blog/implementing-basic-http-authentication-http-requests-angular/">JavaScript Base64 encoder</a> (no license)</li>
|
16
|
+
</ul>
|
17
|
+
<p>SimplePVR is itself licensed under the <a href="http://www.wtfpl.net/">Do What the Fuck You Want to Public License</a>.
|
18
|
+
</p>
|
@@ -1,41 +1,46 @@
|
|
1
1
|
<div class="row">
|
2
|
-
<div class="
|
2
|
+
<div class="col-md-12">
|
3
3
|
<form class="form-inline">
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
<div class="form-group">
|
5
|
+
<input id="channel_filter" type="text" class="form-control" placeholder="Filter..." ng-model="channelFilter">
|
6
|
+
</div>
|
7
|
+
<div class="form-group">
|
8
|
+
<div class="checkbox">
|
9
|
+
<label>
|
10
|
+
<input type="checkbox" ng-model="showHiddenChannels"> Show hidden channels</input>
|
11
|
+
</label>
|
12
|
+
</div>
|
13
|
+
</div>
|
8
14
|
</form>
|
9
15
|
</div>
|
10
16
|
</div>
|
11
|
-
<div class="
|
12
|
-
<
|
13
|
-
<
|
14
|
-
<
|
15
|
-
<
|
16
|
-
<
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
<
|
27
|
-
<
|
28
|
-
|
29
|
-
|
30
|
-
<
|
31
|
-
|
32
|
-
|
33
|
-
<
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
</div>
|
17
|
+
<div class="col-md-4" ng-repeat-start="channel in channels | orderBy:name | filter:shouldShowChannel | filter:channelFilter">
|
18
|
+
<table class="table table-condensed">
|
19
|
+
<thead>
|
20
|
+
<tr>
|
21
|
+
<th colspan="2">
|
22
|
+
<img ng-show="channel.icon_url" class="channel-icon" ng-src="{{channel.icon_url}}" />
|
23
|
+
<span class="channel-name">
|
24
|
+
{{channel.name}}
|
25
|
+
</span>
|
26
|
+
<a ng-hide="channel.hidden" class="glyphicon glyphicon-remove pull-right" style="color:black" ng-click="hideChannel(channel)" title="Hide channel" ></a>
|
27
|
+
<a ng-href="channels" ng-show="channel.hidden" class="glyphicon glyphicon-ok pull-right" style="color:black" ng-click="showChannel(channel)" title="Show channel"></a>
|
28
|
+
</th>
|
29
|
+
</tr>
|
30
|
+
</thead>
|
31
|
+
<tbody>
|
32
|
+
<tr ng-show="channel.current_programme" ng-class="classForProgrammeLine(channel.current_programme)">
|
33
|
+
<td class="col-md-1">{{channel.current_programme.start_time | date:'HH:mm'}}</td>
|
34
|
+
<td><a ng-href="/programmes/{{channel.current_programme.id}}">{{channel.current_programme.title}}</td></tr>
|
35
|
+
<tr ng-repeat="upcomingProgramme in channel.upcoming_programmes" ng-class="classForProgrammeLine(upcomingProgramme)">
|
36
|
+
<td class="col-md-1">{{upcomingProgramme.start_time | date:'HH:mm'}}</td>
|
37
|
+
<td><a ng-href="/programmes/{{upcomingProgramme.id}}">{{upcomingProgramme.title}}</a></td></tr>
|
38
|
+
<tr>
|
39
|
+
<td colspan="2">
|
40
|
+
<a ng-href="/channels/{{channel.id}}/programmeListings/today" class="pull-right">...</a>
|
41
|
+
</td>
|
42
|
+
</tr>
|
43
|
+
</tbody>
|
44
|
+
</table>
|
45
|
+
</div>
|
46
|
+
<div class="clearfix" ng-show="$index % 3 == 2" ng-repeat-end></div>
|
@@ -1,9 +1,25 @@
|
|
1
|
-
<div class="
|
2
|
-
<div class="row" ng-show="programme.id">
|
3
|
-
|
4
|
-
<
|
1
|
+
<div class="col-md-12">
|
2
|
+
<div class="row media" ng-show="programme.id">
|
3
|
+
<img class="media-object pull-left" ng-if="programme.icon_url" ng-src="{{programme.icon_url}}">
|
4
|
+
<h1 class="media-heading">{{programme.title}}</h1>
|
5
5
|
<p>{{programme.subtitle}}</p>
|
6
|
+
<p>{{programme.start_time | date:'fullDate'}} at {{programme.start_time | date:'HH:mm'}} on channel {{programme.channel.name}}.</p>
|
6
7
|
<p>{{programme.description}}</p>
|
8
|
+
<p ng-repeat="director in programme.directors">
|
9
|
+
<strong>Director:</strong> {{director}}
|
10
|
+
</p>
|
11
|
+
<p ng-repeat="presenter in programme.presenters">
|
12
|
+
<strong>Presenter:</strong> {{presenter}}
|
13
|
+
</p>
|
14
|
+
<p ng-repeat="actor in programme.actors">
|
15
|
+
<strong ng-show="actor.role_name">{{actor.role_name}}:</strong> {{actor.actor_name}}
|
16
|
+
</p>
|
17
|
+
<p ng-show="programme.categories">
|
18
|
+
<strong>Categories:</strong>
|
19
|
+
<span ng-repeat="category in programme.categories">
|
20
|
+
{{category}}<span ng-hide="$last">, </span>
|
21
|
+
</span>
|
22
|
+
</p>
|
7
23
|
|
8
24
|
<div ng-show="programme.episode_num">Episode {{programme.episode_num | formatEpisode}}</div>
|
9
25
|
<div ng-show="programme.is_scheduled">
|
@@ -1,18 +1,19 @@
|
|
1
|
-
<
|
1
|
+
<form class="form-inline">
|
2
2
|
<a ng-show="programmeListing.previous_date" ng-href="/channels/{{programmeListing.channel.id}}/programmeListings/{{programmeListing.previous_date}}"><<</a>
|
3
3
|
<a ng-show="programmeListing.next_date" ng-href="/channels/{{programmeListing.channel.id}}/programmeListings/{{programmeListing.next_date}}">>></a>
|
4
|
-
<
|
4
|
+
<div class="form-group">
|
5
|
+
<input type="text" class="form-control" placeholder="Filter..." ng-model="programmeFilter">
|
6
|
+
</div>
|
5
7
|
<img class="channel-icon" src="{{programmeListing.channel.icon_url}}" />
|
6
8
|
<span class="channel-name">{{programmeListing.channel.name}}</span>
|
7
|
-
</
|
8
|
-
<div class="
|
9
|
-
<
|
10
|
-
<
|
11
|
-
|
12
|
-
<
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
</table>
|
17
|
-
</div>
|
9
|
+
</form>
|
10
|
+
<div class="col-lg-4" ng-repeat-start="day in programmeListing.days">
|
11
|
+
<table class="table table-condensed table-bordered">
|
12
|
+
<th colspan="2">{{day.date | date:'fullDate'}}</th>
|
13
|
+
<tr ng-repeat="programme in day.programmes | filter:programmeFilter" class="{{classForProgrammeLine(programme)}}">
|
14
|
+
<td class="col-md-1">{{programme.start_time | date:'HH:mm'}}</td>
|
15
|
+
<td><a ng-href="/programmes/{{programme.id}}">{{programme.title}}</td>
|
16
|
+
</tr>
|
17
|
+
</table>
|
18
18
|
</div>
|
19
|
+
<div class="clearfix" ng-show="$index % 3 == 2" ng-repeat-end></div>
|
@@ -1,119 +1,124 @@
|
|
1
1
|
<div class="row" ng-show="schedule">
|
2
|
-
<form class="form-horizontal" name="scheduleForm">
|
3
|
-
<div class="
|
4
|
-
<label class="control-label" for="showName">Name of show</label>
|
5
|
-
<div class="
|
6
|
-
<input type="text" ng-model="schedule.title" id="showName" placeholder="Show name">
|
2
|
+
<form class="form-horizontal" name="scheduleForm" role="form">
|
3
|
+
<div class="form-group">
|
4
|
+
<label class="col-lg-2 control-label" for="showName">Name of show</label>
|
5
|
+
<div class="col-lg-4">
|
6
|
+
<input type="text" class="form-control" ng-model="schedule.title" id="showName" placeholder="Show name">
|
7
7
|
</div>
|
8
8
|
</div>
|
9
|
-
<div class="
|
10
|
-
<label class="control-label" for="channel">On channel</label>
|
11
|
-
<div class="
|
12
|
-
<select id="channel" ng-model="channel" ng-options="c.name for c in channels">
|
9
|
+
<div class="form-group">
|
10
|
+
<label class="col-lg-2 control-label" for="channel">On channel</label>
|
11
|
+
<div class="col-lg-4">
|
12
|
+
<select class="form-control" id="channel" ng-model="channel" ng-options="c.name for c in channels">
|
13
13
|
<option value="">-- Any channel --</option>
|
14
14
|
</select>
|
15
15
|
</div>
|
16
16
|
</div>
|
17
17
|
|
18
|
-
<div class="
|
19
|
-
<label class="control-label" for="startEarly">Start early</label>
|
20
|
-
<div class="
|
21
|
-
<
|
22
|
-
|
23
|
-
<span class="add-on">minutes</span>
|
24
|
-
</div>
|
18
|
+
<div class="form-group" ng-class="{error: scheduleForm.startEarly.$invalid}">
|
19
|
+
<label class="col-lg-2 control-label" for="startEarly">Start early</label>
|
20
|
+
<div class="col-lg-2 input-group">
|
21
|
+
<input type="text" class="form-control" style="text-align: right" ng-model="schedule.custom_start_early_minutes" ng-pattern="/^[0-9]*$/" name="startEarly" id="startEarly" placeholder="2">
|
22
|
+
<span class="input-group-addon">minutes</span>
|
25
23
|
</div>
|
26
24
|
</div>
|
27
|
-
<div class="
|
28
|
-
<label class="control-label" for="endLate">End late</label>
|
29
|
-
<div class="
|
30
|
-
<
|
31
|
-
|
32
|
-
<span class="add-on">minutes</span>
|
33
|
-
</div>
|
25
|
+
<div class="form-group" ng-class="{error: scheduleForm.endLate.$invalid}">
|
26
|
+
<label class="col-lg-2 control-label" for="endLate">End late</label>
|
27
|
+
<div class="col-lg-2 input-group">
|
28
|
+
<input type="text" class="form-control" style="text-align: right" ng-model="schedule.custom_end_late_minutes" ng-pattern="/^[0-9]*$/" name="endLate" id="endLate" placeholder="5">
|
29
|
+
<span class="input-group-addon">minutes</span>
|
34
30
|
</div>
|
35
31
|
</div>
|
36
32
|
|
37
|
-
<div class="
|
38
|
-
<div class="
|
39
|
-
<
|
40
|
-
<
|
41
|
-
|
33
|
+
<div class="form-group">
|
34
|
+
<div class="col-lg-offset-2 col-lg-10">
|
35
|
+
<div class="checkbox">
|
36
|
+
<label>
|
37
|
+
<input type="checkbox" id="filterByTimeOfDay" ng-model="schedule.filter_by_time_of_day">Filter by time of day
|
38
|
+
</label>
|
39
|
+
</div>
|
42
40
|
</div>
|
43
41
|
</div>
|
44
|
-
<div class="
|
45
|
-
<
|
46
|
-
|
47
|
-
<
|
42
|
+
<div class="col-lg-offset-2 col-lg-12" ng-show="schedule.filter_by_time_of_day">
|
43
|
+
<div class="form-group" ng-class="{'has-error': scheduleForm.startTime.$invalid}">
|
44
|
+
<label class="col-lg-1 control-label" for="startTime">From</label>
|
45
|
+
<div class="col-lg-1">
|
46
|
+
<input type="text" class="form-control col-lg-2" style="text-align: right" ng-model="schedule.from_time_of_day" ng-pattern="/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/" name="startTime" id="startTime" placeholder="00:00">
|
47
|
+
</div>
|
48
48
|
</div>
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
<div class="form-group" ng-class="{'has-error': scheduleForm.endTime.$invalid}">
|
50
|
+
<label class="col-lg-1 control-label" for="endTime">To</label>
|
51
|
+
<div class="col-lg-1">
|
52
|
+
<input type="text" class="form-control col-lg-2" style="text-align: right" ng-model="schedule.to_time_of_day" ng-pattern="/^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/" id="endTime" placeholder="00:00">
|
53
|
+
</div>
|
54
54
|
</div>
|
55
55
|
</div>
|
56
56
|
|
57
|
-
<div class="
|
58
|
-
<div class="
|
59
|
-
<
|
60
|
-
<
|
61
|
-
|
57
|
+
<div class="form-group">
|
58
|
+
<div class="col-lg-offset-2 col-lg-10">
|
59
|
+
<div class="checkbox">
|
60
|
+
<label>
|
61
|
+
<input type="checkbox" id="filterByWeekday" ng-model="schedule.filter_by_weekday">Filter by weekday
|
62
|
+
</label>
|
63
|
+
</div>
|
62
64
|
</div>
|
63
65
|
</div>
|
64
|
-
<div class="
|
65
|
-
<div class="
|
66
|
-
<
|
67
|
-
<
|
68
|
-
|
66
|
+
<div class="col-lg-offset-3 col-lg-9" ng-show="schedule.filter_by_weekday">
|
67
|
+
<div class="form-group">
|
68
|
+
<div class="checkbox">
|
69
|
+
<label>
|
70
|
+
<input type="checkbox" id="recordMondays" ng-model="schedule.monday">Record Mondays
|
71
|
+
</label>
|
72
|
+
</div>
|
69
73
|
</div>
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
</
|
74
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
75
|
+
<div class="checkbox">
|
76
|
+
<label>
|
77
|
+
<input type="checkbox" id="recordTuesdays" ng-model="schedule.tuesday">Record Tuesdays
|
78
|
+
</label>
|
79
|
+
</div>
|
76
80
|
</div>
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
</
|
81
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
82
|
+
<div class="checkbox">
|
83
|
+
<label>
|
84
|
+
<input type="checkbox" id="recordWednesdays" ng-model="schedule.wednesday">Record Wednesdays
|
85
|
+
</label>
|
86
|
+
</div>
|
83
87
|
</div>
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
</
|
88
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
89
|
+
<div class="checkbox">
|
90
|
+
<label>
|
91
|
+
<input type="checkbox" id="recordThursdays" ng-model="schedule.thursday">Record Thursdays
|
92
|
+
</label>
|
93
|
+
</div>
|
90
94
|
</div>
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
</
|
95
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
96
|
+
<div class="checkbox">
|
97
|
+
<label>
|
98
|
+
<input type="checkbox" id="recordFridays" ng-model="schedule.friday">Record Fridays
|
99
|
+
</label>
|
100
|
+
</div>
|
97
101
|
</div>
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
</
|
102
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
103
|
+
<div class="checkbox">
|
104
|
+
<label>
|
105
|
+
<input type="checkbox" id="recordSaturdays" ng-model="schedule.saturday">Record Saturdays
|
106
|
+
</label>
|
107
|
+
</div>
|
104
108
|
</div>
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
</
|
109
|
+
<div class="form-group" ng-show="schedule.filter_by_weekday">
|
110
|
+
<div class="checkbox">
|
111
|
+
<label>
|
112
|
+
<input type="checkbox" id="recordSundays" ng-model="schedule.sunday">Record Sundays
|
113
|
+
</label>
|
114
|
+
</div>
|
111
115
|
</div>
|
112
116
|
</div>
|
113
|
-
|
114
|
-
|
117
|
+
|
118
|
+
<div class="form-group">
|
119
|
+
<div class="col-lg-offset-2 col-lg-10">
|
115
120
|
<button type="submit" class="btn btn-primary" ng-class="{disabled: scheduleForm.$invalid}" ng-click="update()" ng-disabled="scheduleForm.$invalid">Update</button>
|
116
|
-
<a ng-href="/schedules" class="btn">Cancel</a>
|
121
|
+
<a ng-href="/schedules" class="btn btn-default">Cancel</a>
|
117
122
|
</div>
|
118
123
|
</div>
|
119
124
|
</form>
|