Calendar/Date localization
New: Choose calendar starting day of week New: Choose prefered date/time formats New: Option to disable relative dates and show absolute dates instead
This commit is contained in:
parent
0ba19f0cd7
commit
18874e2c79
|
@ -0,0 +1,45 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using Omu.ValueInjecter;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Config
|
||||||
|
{
|
||||||
|
public class UiConfigModule : NzbDroneRestModule<UiConfigResource>
|
||||||
|
{
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
|
||||||
|
public UiConfigModule(IConfigService configService)
|
||||||
|
: base("/config/ui")
|
||||||
|
{
|
||||||
|
_configService = configService;
|
||||||
|
|
||||||
|
GetResourceSingle = GetUiConfig;
|
||||||
|
GetResourceById = GetUiConfig;
|
||||||
|
UpdateResource = SaveUiConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UiConfigResource GetUiConfig()
|
||||||
|
{
|
||||||
|
var resource = new UiConfigResource();
|
||||||
|
resource.InjectFrom(_configService);
|
||||||
|
resource.Id = 1;
|
||||||
|
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UiConfigResource GetUiConfig(int id)
|
||||||
|
{
|
||||||
|
return GetUiConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveUiConfig(UiConfigResource resource)
|
||||||
|
{
|
||||||
|
var dictionary = resource.GetType()
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||||
|
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
|
||||||
|
|
||||||
|
_configService.SaveConfigDictionary(dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Config
|
||||||
|
{
|
||||||
|
public class UiConfigResource : RestResource
|
||||||
|
{
|
||||||
|
//Calendar
|
||||||
|
public Int32 FirstDayOfWeek { get; set; }
|
||||||
|
public String CalendarWeekColumnHeader { get; set; }
|
||||||
|
|
||||||
|
//Dates
|
||||||
|
public String ShortDateFormat { get; set; }
|
||||||
|
public String LongDateFormat { get; set; }
|
||||||
|
public String TimeFormat { get; set; }
|
||||||
|
public Boolean ShowRelativeDates { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,6 +92,8 @@
|
||||||
<Compile Include="ClientSchema\SelectOption.cs" />
|
<Compile Include="ClientSchema\SelectOption.cs" />
|
||||||
<Compile Include="Commands\CommandModule.cs" />
|
<Compile Include="Commands\CommandModule.cs" />
|
||||||
<Compile Include="Commands\CommandResource.cs" />
|
<Compile Include="Commands\CommandResource.cs" />
|
||||||
|
<Compile Include="Config\UiConfigModule.cs" />
|
||||||
|
<Compile Include="Config\UiConfigResource.cs" />
|
||||||
<Compile Include="Config\DownloadClientConfigModule.cs" />
|
<Compile Include="Config\DownloadClientConfigModule.cs" />
|
||||||
<Compile Include="Config\DownloadClientConfigResource.cs" />
|
<Compile Include="Config\DownloadClientConfigResource.cs" />
|
||||||
<Compile Include="Config\HostConfigModule.cs" />
|
<Compile Include="Config\HostConfigModule.cs" />
|
||||||
|
|
|
@ -3,11 +3,9 @@ using Nancy.Routing;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Processes;
|
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Lifecycle;
|
using NzbDrone.Core.Lifecycle;
|
||||||
using NzbDrone.Core.Lifecycle.Commands;
|
|
||||||
|
|
||||||
namespace NzbDrone.Api.System
|
namespace NzbDrone.Api.System
|
||||||
{
|
{
|
||||||
|
@ -60,7 +58,6 @@ namespace NzbDrone.Api.System
|
||||||
IsWindows = OsInfo.IsWindows,
|
IsWindows = OsInfo.IsWindows,
|
||||||
Branch = _configFileProvider.Branch,
|
Branch = _configFileProvider.Branch,
|
||||||
Authentication = _configFileProvider.AuthenticationEnabled,
|
Authentication = _configFileProvider.AuthenticationEnabled,
|
||||||
StartOfWeek = (int)OsInfo.FirstDayOfWeek,
|
|
||||||
SqliteVersion = _database.Version,
|
SqliteVersion = _database.Version,
|
||||||
UrlBase = _configFileProvider.UrlBase,
|
UrlBase = _configFileProvider.UrlBase,
|
||||||
RuntimeVersion = OsInfo.IsMono ? _runtimeInfo.RuntimeVersion : null
|
RuntimeVersion = OsInfo.IsMono ? _runtimeInfo.RuntimeVersion : null
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnsureThat;
|
using NzbDrone.Common.EnsureThat;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Configuration.Events;
|
using NzbDrone.Core.Configuration.Events;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
@ -254,6 +255,48 @@ namespace NzbDrone.Core.Configuration
|
||||||
set { SetValue("ChownGroup", value); }
|
set { SetValue("ChownGroup", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Int32 FirstDayOfWeek
|
||||||
|
{
|
||||||
|
get { return GetValueInt("FirstDayOfWeek", (int)OsInfo.FirstDayOfWeek); }
|
||||||
|
|
||||||
|
set { SetValue("FirstDayOfWeek", value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String CalendarWeekColumnHeader
|
||||||
|
{
|
||||||
|
get { return GetValue("CalendarWeekColumnHeader", "ddd M/D"); }
|
||||||
|
|
||||||
|
set { SetValue("CalendarWeekColumnHeader", value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String ShortDateFormat
|
||||||
|
{
|
||||||
|
get { return GetValue("ShortDateFormat", "MMM D YYYY"); }
|
||||||
|
|
||||||
|
set { SetValue("ShortDateFormat", value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String LongDateFormat
|
||||||
|
{
|
||||||
|
get { return GetValue("LongDateFormat", "dddd, MMMM D YYYY"); }
|
||||||
|
|
||||||
|
set { SetValue("LongDateFormat", value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public String TimeFormat
|
||||||
|
{
|
||||||
|
get { return GetValue("TimeFormat", "h(:mm)a"); }
|
||||||
|
|
||||||
|
set { SetValue("TimeFormat", value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean ShowRelativeDates
|
||||||
|
{
|
||||||
|
get { return GetValueBoolean("ShowRelativeDates", true); }
|
||||||
|
|
||||||
|
set { SetValue("ShowRelativeDates", value); }
|
||||||
|
}
|
||||||
|
|
||||||
private string GetValue(string key)
|
private string GetValue(string key)
|
||||||
{
|
{
|
||||||
return GetValue(key, String.Empty);
|
return GetValue(key, String.Empty);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Update;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Configuration
|
namespace NzbDrone.Core.Configuration
|
||||||
{
|
{
|
||||||
|
@ -49,5 +48,14 @@ namespace NzbDrone.Core.Configuration
|
||||||
Int32 Retention { get; set; }
|
Int32 Retention { get; set; }
|
||||||
Int32 RssSyncInterval { get; set; }
|
Int32 RssSyncInterval { get; set; }
|
||||||
String ReleaseRestrictions { get; set; }
|
String ReleaseRestrictions { get; set; }
|
||||||
|
|
||||||
|
//UI
|
||||||
|
Int32 FirstDayOfWeek { get; set; }
|
||||||
|
String CalendarWeekColumnHeader { get; set; }
|
||||||
|
|
||||||
|
String ShortDateFormat { get; set; }
|
||||||
|
String LongDateFormat { get; set; }
|
||||||
|
String TimeFormat { get; set; }
|
||||||
|
Boolean ShowRelativeDates { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ define(
|
||||||
'marionette',
|
'marionette',
|
||||||
'moment',
|
'moment',
|
||||||
'Calendar/Collection',
|
'Calendar/Collection',
|
||||||
'System/StatusModel',
|
'Shared/UiSettingsModel',
|
||||||
'History/Queue/QueueCollection',
|
'History/Queue/QueueCollection',
|
||||||
'Config',
|
'Config',
|
||||||
'Mixins/backbone.signalr.mixin',
|
'Mixins/backbone.signalr.mixin',
|
||||||
'fullcalendar',
|
'fullcalendar',
|
||||||
'jquery.easypiechart'
|
'jquery.easypiechart'
|
||||||
], function ($, vent, Marionette, moment, CalendarCollection, StatusModel, QueueCollection, Config) {
|
], function ($, vent, Marionette, moment, CalendarCollection, UiSettings, QueueCollection, Config) {
|
||||||
|
|
||||||
return Marionette.ItemView.extend({
|
return Marionette.ItemView.extend({
|
||||||
storageKey: 'calendar.view',
|
storageKey: 'calendar.view',
|
||||||
|
@ -44,39 +44,45 @@ define(
|
||||||
this.$(element).addClass(event.statusLevel);
|
this.$(element).addClass(event.statusLevel);
|
||||||
this.$(element).children('.fc-event-inner').addClass(event.statusLevel);
|
this.$(element).children('.fc-event-inner').addClass(event.statusLevel);
|
||||||
|
|
||||||
if (event.progress > 0) {
|
if (event.downloading) {
|
||||||
this.$(element).find('.fc-event-time')
|
var progress = 100 - (event.downloading.get('sizeleft') / event.downloading.get('size') * 100);
|
||||||
.after('<span class="chart pull-right" data-percent="{0}"></span>'.format(event.progress));
|
var releaseTitle = event.downloading.get('title');
|
||||||
|
var estimatedCompletionTime = moment(event.downloading.get('estimatedCompletionTime')).fromNow();
|
||||||
|
|
||||||
this.$(element).find('.chart').easyPieChart({
|
if (event.downloading.get('status').toLocaleLowerCase() === 'pending') {
|
||||||
barColor : '#ffffff',
|
this.$(element).find('.fc-event-time')
|
||||||
trackColor: false,
|
.after('<span class="pending pull-right"><i class="icon-time"></i></span>');
|
||||||
scaleColor: false,
|
|
||||||
lineWidth : 2,
|
|
||||||
size : 14,
|
|
||||||
animate : false
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$(element).find('.chart').tooltip({
|
this.$(element).find('.pending').tooltip({
|
||||||
title: 'Episode is downloading - {0}% {1}'.format(event.progress.toFixed(1), event.releaseTitle),
|
title: 'Release will be processed {0}'.format(estimatedCompletionTime),
|
||||||
container: 'body'
|
container: 'body'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.pending) {
|
else {
|
||||||
this.$(element).find('.fc-event-time')
|
this.$(element).find('.fc-event-time')
|
||||||
.after('<span class="pending pull-right"><i class="icon-time"></i></span>');
|
.after('<span class="chart pull-right" data-percent="{0}"></span>'.format(progress));
|
||||||
|
|
||||||
this.$(element).find('.pending').tooltip({
|
this.$(element).find('.chart').easyPieChart({
|
||||||
title: 'Release will be processed {0}'.format(event.pending),
|
barColor : '#ffffff',
|
||||||
container: 'body'
|
trackColor: false,
|
||||||
});
|
scaleColor: false,
|
||||||
|
lineWidth : 2,
|
||||||
|
size : 14,
|
||||||
|
animate : false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$(element).find('.chart').tooltip({
|
||||||
|
title: 'Episode is downloading - {0}% {1}'.format(progress.toFixed(1), releaseTitle),
|
||||||
|
container: 'body'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_getEvents: function (view) {
|
_getEvents: function (view) {
|
||||||
var start = moment(view.visStart).toISOString();
|
var start = view.start.toISOString();
|
||||||
var end = moment(view.visEnd).toISOString();
|
var end = view.end.toISOString();
|
||||||
|
|
||||||
this.$el.fullCalendar('removeEvents');
|
this.$el.fullCalendar('removeEvents');
|
||||||
|
|
||||||
|
@ -99,13 +105,10 @@ define(
|
||||||
|
|
||||||
var event = {
|
var event = {
|
||||||
title : seriesTitle,
|
title : seriesTitle,
|
||||||
start : start,
|
start : moment(start),
|
||||||
end : end,
|
end : moment(end),
|
||||||
allDay : false,
|
allDay : false,
|
||||||
statusLevel : self._getStatusLevel(model, end),
|
statusLevel : self._getStatusLevel(model, end),
|
||||||
progress : self._getDownloadProgress(model),
|
|
||||||
pending : self._getPendingInfo(model),
|
|
||||||
releaseTitle: self._getReleaseTitle(model),
|
|
||||||
downloading : QueueCollection.findEpisode(model.get('id')),
|
downloading : QueueCollection.findEpisode(model.get('id')),
|
||||||
model : model
|
model : model
|
||||||
};
|
};
|
||||||
|
@ -153,47 +156,12 @@ define(
|
||||||
this._setEventData(this.collection);
|
this._setEventData(this.collection);
|
||||||
},
|
},
|
||||||
|
|
||||||
_getDownloadProgress: function (element) {
|
|
||||||
var downloading = QueueCollection.findEpisode(element.get('id'));
|
|
||||||
|
|
||||||
if (!downloading) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 100 - (downloading.get('sizeleft') / downloading.get('size') * 100);
|
|
||||||
},
|
|
||||||
|
|
||||||
_getPendingInfo: function (element) {
|
|
||||||
var pending = QueueCollection.findEpisode(element.get('id'));
|
|
||||||
|
|
||||||
if (!pending || pending.get('status').toLocaleLowerCase() !== 'pending') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return moment(pending.get('estimatedCompletionTime')).fromNow();
|
|
||||||
},
|
|
||||||
|
|
||||||
_getReleaseTitle: function (element) {
|
|
||||||
var downloading = QueueCollection.findEpisode(element.get('id'));
|
|
||||||
|
|
||||||
if (!downloading) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return downloading.get('title');
|
|
||||||
},
|
|
||||||
|
|
||||||
_getOptions: function () {
|
_getOptions: function () {
|
||||||
var options = {
|
var options = {
|
||||||
allDayDefault : false,
|
allDayDefault : false,
|
||||||
ignoreTimezone: false,
|
|
||||||
weekMode : 'variable',
|
weekMode : 'variable',
|
||||||
firstDay : StatusModel.get('startOfWeek'),
|
firstDay : UiSettings.get('firstDayOfWeek'),
|
||||||
timeFormat : 'h(:mm)tt',
|
timeFormat : 'h(:mm)a',
|
||||||
buttonText : {
|
|
||||||
prev: '<i class="icon-arrow-left"></i>',
|
|
||||||
next: '<i class="icon-arrow-right"></i>'
|
|
||||||
},
|
|
||||||
viewRender : this._viewRender.bind(this),
|
viewRender : this._viewRender.bind(this),
|
||||||
eventRender : this._eventRender.bind(this),
|
eventRender : this._eventRender.bind(this),
|
||||||
eventClick : function (event) {
|
eventClick : function (event) {
|
||||||
|
@ -204,12 +172,6 @@ define(
|
||||||
if ($(window).width() < 768) {
|
if ($(window).width() < 768) {
|
||||||
options.defaultView = Config.getValue(this.storageKey, 'basicDay');
|
options.defaultView = Config.getValue(this.storageKey, 'basicDay');
|
||||||
|
|
||||||
options.titleFormat = {
|
|
||||||
month: 'MMM yyyy', // September 2009
|
|
||||||
week: 'MMM d[ yyyy]{ \'—\'[ MMM] d yyyy}', // Sep 7 - 13 2009
|
|
||||||
day: 'ddd, MMM d, yyyy' // Tuesday, Sep 8, 2009
|
|
||||||
};
|
|
||||||
|
|
||||||
options.header = {
|
options.header = {
|
||||||
left : 'prev,next today',
|
left : 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
|
@ -220,12 +182,6 @@ define(
|
||||||
else {
|
else {
|
||||||
options.defaultView = Config.getValue(this.storageKey, 'basicWeek');
|
options.defaultView = Config.getValue(this.storageKey, 'basicWeek');
|
||||||
|
|
||||||
options.titleFormat = {
|
|
||||||
month: 'MMM yyyy', // September 2009
|
|
||||||
week: 'MMM d[ yyyy]{ \'—\'[ MMM] d yyyy}', // Sep 7 - 13 2009
|
|
||||||
day: 'dddd, MMM d, yyyy' // Tues, Sep 8, 2009
|
|
||||||
};
|
|
||||||
|
|
||||||
options.header = {
|
options.header = {
|
||||||
left : 'prev,next today',
|
left : 'prev,next today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
|
@ -233,6 +189,22 @@ define(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.titleFormat = {
|
||||||
|
month : 'MMMM YYYY',
|
||||||
|
week : UiSettings.get('shortDateFormat'),
|
||||||
|
day : UiSettings.get('longDateFormat')
|
||||||
|
};
|
||||||
|
|
||||||
|
options.columnFormat = {
|
||||||
|
month : 'ddd', // Mon
|
||||||
|
week : UiSettings.get('calendarWeekColumnHeader'),
|
||||||
|
day : 'dddd' // Monday
|
||||||
|
};
|
||||||
|
|
||||||
|
options.timeFormat = {
|
||||||
|
'default': UiSettings.get('timeFormat')
|
||||||
|
};
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,18 +4,18 @@ define(
|
||||||
'backbone',
|
'backbone',
|
||||||
'moment',
|
'moment',
|
||||||
'Series/EpisodeModel'
|
'Series/EpisodeModel'
|
||||||
], function (Backbone, Moment, EpisodeModel) {
|
], function (Backbone, moment, EpisodeModel) {
|
||||||
return Backbone.Collection.extend({
|
return Backbone.Collection.extend({
|
||||||
url : window.NzbDrone.ApiRoot + '/calendar',
|
url : window.NzbDrone.ApiRoot + '/calendar',
|
||||||
model: EpisodeModel,
|
model: EpisodeModel,
|
||||||
|
|
||||||
comparator: function (model1, model2) {
|
comparator: function (model1, model2) {
|
||||||
var airDate1 = model1.get('airDateUtc');
|
var airDate1 = model1.get('airDateUtc');
|
||||||
var date1 = Moment(airDate1);
|
var date1 = moment(airDate1);
|
||||||
var time1 = date1.unix();
|
var time1 = date1.unix();
|
||||||
|
|
||||||
var airDate2 = model2.get('airDateUtc');
|
var airDate2 = model2.get('airDateUtc');
|
||||||
var date2 = Moment(airDate2);
|
var date2 = moment(airDate2);
|
||||||
var time2 = date2.unix();
|
var time2 = date2.unix();
|
||||||
|
|
||||||
if (time1 < time2){
|
if (time1 < time2){
|
||||||
|
|
|
@ -5,7 +5,7 @@ define(
|
||||||
'vent',
|
'vent',
|
||||||
'marionette',
|
'marionette',
|
||||||
'moment'
|
'moment'
|
||||||
], function (vent, Marionette, Moment) {
|
], function (vent, Marionette, moment) {
|
||||||
return Marionette.ItemView.extend({
|
return Marionette.ItemView.extend({
|
||||||
template: 'Calendar/UpcomingItemViewTemplate',
|
template: 'Calendar/UpcomingItemViewTemplate',
|
||||||
tagName : 'div',
|
tagName : 'div',
|
||||||
|
@ -17,7 +17,7 @@ define(
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
var start = this.model.get('airDateUtc');
|
var start = this.model.get('airDateUtc');
|
||||||
var runtime = this.model.get('series').runtime;
|
var runtime = this.model.get('series').runtime;
|
||||||
var end = Moment(start).add('minutes', runtime);
|
var end = moment(start).add('minutes', runtime);
|
||||||
|
|
||||||
this.model.set({
|
this.model.set({
|
||||||
end: end.toISOString()
|
end: end.toISOString()
|
||||||
|
|
|
@ -8,7 +8,7 @@ define(
|
||||||
'History/Queue/QueueCollection',
|
'History/Queue/QueueCollection',
|
||||||
'moment',
|
'moment',
|
||||||
'Shared/FormatHelpers'
|
'Shared/FormatHelpers'
|
||||||
], function (reqres, Backbone, NzbDroneCell, QueueCollection, Moment, FormatHelpers) {
|
], function (reqres, Backbone, NzbDroneCell, QueueCollection, moment, FormatHelpers) {
|
||||||
return NzbDroneCell.extend({
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
className: 'episode-status-cell',
|
className: 'episode-status-cell',
|
||||||
|
@ -29,7 +29,7 @@ define(
|
||||||
var icon;
|
var icon;
|
||||||
var tooltip;
|
var tooltip;
|
||||||
|
|
||||||
var hasAired = Moment(this.model.get('airDateUtc')).isBefore(Moment());
|
var hasAired = moment(this.model.get('airDateUtc')).isBefore(moment());
|
||||||
var hasFile = this.model.get('hasFile');
|
var hasFile = this.model.get('hasFile');
|
||||||
|
|
||||||
if (hasFile) {
|
if (hasFile) {
|
||||||
|
|
|
@ -3,18 +3,32 @@ define(
|
||||||
[
|
[
|
||||||
'Cells/NzbDroneCell',
|
'Cells/NzbDroneCell',
|
||||||
'moment',
|
'moment',
|
||||||
'Shared/FormatHelpers'
|
'Shared/FormatHelpers',
|
||||||
], function (NzbDroneCell, Moment, FormatHelpers) {
|
'Shared/UiSettingsModel'
|
||||||
|
], function (NzbDroneCell, moment, FormatHelpers, UiSettings) {
|
||||||
return NzbDroneCell.extend({
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
className: 'relative-date-cell',
|
className: 'relative-date-cell',
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
|
|
||||||
var date = this.model.get(this.column.get('name'));
|
var dateStr = this.model.get(this.column.get('name'));
|
||||||
|
|
||||||
if (date) {
|
if (dateStr) {
|
||||||
this.$el.html('<span title="' + Moment(date).format('LLLL') + '" >' + FormatHelpers.dateHelper(date) + '</span>');
|
var date = moment(dateStr);
|
||||||
|
var result = '<span title="{0}">{1}</span>';
|
||||||
|
var tooltip = date.format(UiSettings.longDateTime());
|
||||||
|
var text;
|
||||||
|
|
||||||
|
if (UiSettings.get('showRelativeDates')) {
|
||||||
|
text = FormatHelpers.relativeDate(dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
text = date.format(UiSettings.get('shortDateFormat'));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$el.html(result.format(tooltip, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* FullCalendar v1.6.4 Stylesheet
|
* FullCalendar v2.0.2 Stylesheet
|
||||||
* Docs & License: http://arshaw.com/fullcalendar/
|
* Docs & License: http://arshaw.com/fullcalendar/
|
||||||
* (c) 2013 Adam Shaw
|
* (c) 2013 Adam Shaw
|
||||||
*/
|
*/
|
||||||
|
@ -101,11 +101,14 @@ html .fc,
|
||||||
------------------------------------------------------------------------*/
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
.fc-content {
|
.fc-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1; /* scopes all other z-index's to be inside this container */
|
||||||
clear: both;
|
clear: both;
|
||||||
zoom: 1; /* for IE7, gives accurate coordinates for [un]freezeContentHeight */
|
zoom: 1; /* for IE7, gives accurate coordinates for [un]freezeContentHeight */
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-view {
|
.fc-view {
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -165,32 +168,38 @@ html .fc,
|
||||||
and we'll try to make them look good cross-browser.
|
and we'll try to make them look good cross-browser.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.fc-text-arrow {
|
.fc-button .fc-icon {
|
||||||
margin: 0 .1em;
|
margin: 0 .1em;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
font-family: "Courier New", Courier, monospace;
|
font-family: "Courier New", Courier, monospace;
|
||||||
vertical-align: baseline; /* for IE7 */
|
vertical-align: baseline; /* for IE7 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-button-prev .fc-text-arrow,
|
.fc-icon-left-single-arrow:after {
|
||||||
.fc-button-next .fc-text-arrow { /* for ‹ › */
|
content: "\02039";
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-icon-right-single-arrow:after {
|
||||||
|
content: "\0203A";
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-icon-left-double-arrow:after {
|
||||||
|
content: "\000AB";
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-icon-right-double-arrow:after {
|
||||||
|
content: "\000BB";
|
||||||
|
}
|
||||||
|
|
||||||
/* icon (for jquery ui) */
|
/* icon (for jquery ui) */
|
||||||
|
|
||||||
.fc-button .fc-icon-wrap {
|
|
||||||
position: relative;
|
|
||||||
float: left;
|
|
||||||
top: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fc-button .ui-icon {
|
.fc-button .ui-icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
float: left;
|
float: left;
|
||||||
margin-top: -50%;
|
margin-top: -8px; /* we know jqui icons are always 16px tall */
|
||||||
*margin-top: 0;
|
|
||||||
*top: -50%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -447,10 +456,13 @@ table.fc-border-separate {
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
white-space: nowrap;
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-agenda-slots .fc-agenda-axis {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.fc-agenda .fc-week-number {
|
.fc-agenda .fc-week-number {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<span class="label label-info">{{network}}</span>
|
<span class="label label-info">{{network}}</span>
|
||||||
{{/with}}
|
{{/with}}
|
||||||
<span class="label label-info">{{StartTime airDateUtc}}</span>
|
<span class="label label-info">{{StartTime airDateUtc}}</span>
|
||||||
<span class="label label-info">{{NextAiring airDateUtc}}</span>
|
<span class="label label-info">{{RelativeDate airDateUtc}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="episode-overview">
|
<div class="episode-overview">
|
||||||
|
|
|
@ -3,26 +3,39 @@ define(
|
||||||
[
|
[
|
||||||
'handlebars',
|
'handlebars',
|
||||||
'moment',
|
'moment',
|
||||||
'Shared/FormatHelpers'
|
'Shared/FormatHelpers',
|
||||||
], function (Handlebars, Moment, FormatHelpers) {
|
'Shared/UiSettingsModel'
|
||||||
|
], function (Handlebars, moment, FormatHelpers, UiSettings) {
|
||||||
Handlebars.registerHelper('ShortDate', function (input) {
|
Handlebars.registerHelper('ShortDate', function (input) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = Moment(input);
|
var date = moment(input);
|
||||||
var result = '<span title="' + date.format('LLLL') + '">' + date.format('LL') + '</span>';
|
var result = '<span title="' + date.format(UiSettings.longDateTime()) + '">' + date.format(UiSettings.get('shortDateFormat')) + '</span>';
|
||||||
|
|
||||||
return new Handlebars.SafeString(result);
|
return new Handlebars.SafeString(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('NextAiring', function (input) {
|
Handlebars.registerHelper('RelativeDate', function (input) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = Moment(input);
|
var date = moment(input);
|
||||||
var result = '<span title="' + date.format('LLLL') + '">' + FormatHelpers.dateHelper(input) + '</span>';
|
var result = '<span title="{0}">{1}</span>';
|
||||||
|
var tooltip = date.format(UiSettings.longDateTime());
|
||||||
|
var text;
|
||||||
|
|
||||||
|
if (UiSettings.get('showRelativeDates')) {
|
||||||
|
text = FormatHelpers.relativeDate(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
text = date.format(UiSettings.get('shortDateFormat'));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.format(tooltip, text);
|
||||||
|
|
||||||
return new Handlebars.SafeString(result);
|
return new Handlebars.SafeString(result);
|
||||||
});
|
});
|
||||||
|
@ -32,7 +45,7 @@ define(
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return Moment(input).format('DD');
|
return moment(input).format('DD');
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('Month', function (input) {
|
Handlebars.registerHelper('Month', function (input) {
|
||||||
|
@ -40,7 +53,7 @@ define(
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return Moment(input).format('MMM');
|
return moment(input).format('MMM');
|
||||||
});
|
});
|
||||||
|
|
||||||
Handlebars.registerHelper('StartTime', function (input) {
|
Handlebars.registerHelper('StartTime', function (input) {
|
||||||
|
@ -48,11 +61,11 @@ define(
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = Moment(input);
|
var date = moment(input);
|
||||||
if (date.format('mm') === '00') {
|
if (date.format('mm') === '00') {
|
||||||
return date.format('ha');
|
return date.format('ha');
|
||||||
}
|
}
|
||||||
|
|
||||||
return date.format('h.mma');
|
return date.format('h:mma');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,11 +4,11 @@ define(
|
||||||
'handlebars',
|
'handlebars',
|
||||||
'Shared/FormatHelpers',
|
'Shared/FormatHelpers',
|
||||||
'moment'
|
'moment'
|
||||||
], function (Handlebars, FormatHelpers, Moment) {
|
], function (Handlebars, FormatHelpers, moment) {
|
||||||
Handlebars.registerHelper('EpisodeNumber', function () {
|
Handlebars.registerHelper('EpisodeNumber', function () {
|
||||||
|
|
||||||
if (this.series.seriesType === 'daily') {
|
if (this.series.seriesType === 'daily') {
|
||||||
return Moment(this.airDate).format('L');
|
return moment(this.airDate).format('L');
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
@ -21,9 +21,9 @@ define(
|
||||||
|
|
||||||
var hasFile = this.hasFile;
|
var hasFile = this.hasFile;
|
||||||
var downloading = require('History/Queue/QueueCollection').findEpisode(this.id) || this.downloading;
|
var downloading = require('History/Queue/QueueCollection').findEpisode(this.id) || this.downloading;
|
||||||
var currentTime = Moment();
|
var currentTime = moment();
|
||||||
var start = Moment(this.airDateUtc);
|
var start = moment(this.airDateUtc);
|
||||||
var end = Moment(this.end);
|
var end = moment(this.end);
|
||||||
|
|
||||||
if (hasFile) {
|
if (hasFile) {
|
||||||
return 'success';
|
return 'success';
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -26,7 +26,7 @@ define(
|
||||||
EpisodeNumberCell,
|
EpisodeNumberCell,
|
||||||
EpisodeWarningCell,
|
EpisodeWarningCell,
|
||||||
CommandController,
|
CommandController,
|
||||||
Moment,
|
moment,
|
||||||
_,
|
_,
|
||||||
Messenger) {
|
Messenger) {
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
|
@ -213,15 +213,15 @@ define(
|
||||||
},
|
},
|
||||||
|
|
||||||
_shouldShowEpisodes: function () {
|
_shouldShowEpisodes: function () {
|
||||||
var startDate = Moment().add('month', -1);
|
var startDate = moment().add('month', -1);
|
||||||
var endDate = Moment().add('year', 1);
|
var endDate = moment().add('year', 1);
|
||||||
|
|
||||||
return this.episodeCollection.some(function (episode) {
|
return this.episodeCollection.some(function (episode) {
|
||||||
|
|
||||||
var airDate = episode.get('airDateUtc');
|
var airDate = episode.get('airDateUtc');
|
||||||
|
|
||||||
if (airDate) {
|
if (airDate) {
|
||||||
var airDateMoment = Moment(airDate);
|
var airDateMoment = moment(airDate);
|
||||||
|
|
||||||
if (airDateMoment.isAfter(startDate) && airDateMoment.isBefore(endDate)) {
|
if (airDateMoment.isAfter(startDate) && airDateMoment.isBefore(endDate)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -235,7 +235,7 @@ define(
|
||||||
templateHelpers: function () {
|
templateHelpers: function () {
|
||||||
|
|
||||||
var episodeCount = this.episodeCollection.filter(function (episode) {
|
var episodeCount = this.episodeCollection.filter(function (episode) {
|
||||||
return episode.get('hasFile') || (episode.get('monitored') && Moment(episode.get('airDateUtc')).isBefore(Moment()));
|
return episode.get('hasFile') || (episode.get('monitored') && moment(episode.get('airDateUtc')).isBefore(moment()));
|
||||||
}).length;
|
}).length;
|
||||||
|
|
||||||
var episodeFileCount = this.episodeCollection.where({ hasFile: true }).length;
|
var episodeFileCount = this.episodeCollection.where({ hasFile: true }).length;
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<div class="col-md-10 col-xs-8">
|
<div class="col-md-10 col-xs-8">
|
||||||
{{#if_eq status compare="continuing"}}
|
{{#if_eq status compare="continuing"}}
|
||||||
{{#if nextAiring}}
|
{{#if nextAiring}}
|
||||||
<span class="label label-default">{{NextAiring nextAiring}}</span>
|
<span class="label label-default">{{RelativeDate nextAiring}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="label label-danger">Ended</span>
|
<span class="label label-danger">Ended</span>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<div class="labels">
|
<div class="labels">
|
||||||
{{#if_eq status compare="continuing"}}
|
{{#if_eq status compare="continuing"}}
|
||||||
{{#if nextAiring}}
|
{{#if nextAiring}}
|
||||||
<span class="label label-default">{{NextAiring nextAiring}}</span>
|
<span class="label label-default">{{RelativeDate nextAiring}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if_eq}}
|
{{/if_eq}}
|
||||||
{{> EpisodeProgressPartial }}
|
{{> EpisodeProgressPartial }}
|
||||||
|
|
|
@ -65,9 +65,9 @@ define(
|
||||||
cell : 'integer'
|
cell : 'integer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'profileId',
|
name : 'profileId',
|
||||||
label: 'Profile',
|
label : 'Profile',
|
||||||
cell : ProfileCell
|
cell : ProfileCell
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name : 'network',
|
name : 'network',
|
||||||
|
|
|
@ -10,7 +10,7 @@ define(
|
||||||
'Mixins/AsSortedCollection',
|
'Mixins/AsSortedCollection',
|
||||||
'Mixins/AsPersistedStateCollection',
|
'Mixins/AsPersistedStateCollection',
|
||||||
'moment'
|
'moment'
|
||||||
], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection, Moment) {
|
], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection, moment) {
|
||||||
var Collection = PageableCollection.extend({
|
var Collection = PageableCollection.extend({
|
||||||
url : window.NzbDrone.ApiRoot + '/series',
|
url : window.NzbDrone.ApiRoot + '/series',
|
||||||
model: SeriesModel,
|
model: SeriesModel,
|
||||||
|
@ -63,13 +63,13 @@ define(
|
||||||
var nextAiring = model.get(attr);
|
var nextAiring = model.get(attr);
|
||||||
|
|
||||||
if (nextAiring) {
|
if (nextAiring) {
|
||||||
return Moment(nextAiring).unix();
|
return moment(nextAiring).unix();
|
||||||
}
|
}
|
||||||
|
|
||||||
var previousAiring = model.get(attr.replace('nextAiring', 'previousAiring'));
|
var previousAiring = model.get(attr.replace('nextAiring', 'previousAiring'));
|
||||||
|
|
||||||
if (previousAiring) {
|
if (previousAiring) {
|
||||||
return 10000000000 - Moment(previousAiring).unix();
|
return 10000000000 - moment(previousAiring).unix();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Number.MAX_VALUE;
|
return Number.MAX_VALUE;
|
||||||
|
|
|
@ -21,6 +21,8 @@ define(
|
||||||
'Settings/Notifications/NotificationCollection',
|
'Settings/Notifications/NotificationCollection',
|
||||||
'Settings/Metadata/MetadataLayout',
|
'Settings/Metadata/MetadataLayout',
|
||||||
'Settings/General/GeneralView',
|
'Settings/General/GeneralView',
|
||||||
|
'Settings/UI/UiView',
|
||||||
|
'Settings/UI/UiSettingsModel',
|
||||||
'Shared/LoadingView',
|
'Shared/LoadingView',
|
||||||
'Config'
|
'Config'
|
||||||
], function ($,
|
], function ($,
|
||||||
|
@ -43,6 +45,8 @@ define(
|
||||||
NotificationCollection,
|
NotificationCollection,
|
||||||
MetadataLayout,
|
MetadataLayout,
|
||||||
GeneralView,
|
GeneralView,
|
||||||
|
UiView,
|
||||||
|
UiSettingsModel,
|
||||||
LoadingView,
|
LoadingView,
|
||||||
Config) {
|
Config) {
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
|
@ -57,6 +61,7 @@ define(
|
||||||
notifications : '#notifications',
|
notifications : '#notifications',
|
||||||
metadata : '#metadata',
|
metadata : '#metadata',
|
||||||
general : '#general',
|
general : '#general',
|
||||||
|
uiRegion : '#ui',
|
||||||
loading : '#loading-region'
|
loading : '#loading-region'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -69,6 +74,7 @@ define(
|
||||||
notificationsTab : '.x-notifications-tab',
|
notificationsTab : '.x-notifications-tab',
|
||||||
metadataTab : '.x-metadata-tab',
|
metadataTab : '.x-metadata-tab',
|
||||||
generalTab : '.x-general-tab',
|
generalTab : '.x-general-tab',
|
||||||
|
uiTab : '.x-ui-tab',
|
||||||
advancedSettings : '.x-advanced-settings'
|
advancedSettings : '.x-advanced-settings'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -81,6 +87,7 @@ define(
|
||||||
'click .x-notifications-tab' : '_showNotifications',
|
'click .x-notifications-tab' : '_showNotifications',
|
||||||
'click .x-metadata-tab' : '_showMetadata',
|
'click .x-metadata-tab' : '_showMetadata',
|
||||||
'click .x-general-tab' : '_showGeneral',
|
'click .x-general-tab' : '_showGeneral',
|
||||||
|
'click .x-ui-tab' : '_showUi',
|
||||||
'click .x-save-settings' : '_save',
|
'click .x-save-settings' : '_save',
|
||||||
'change .x-advanced-settings' : '_toggleAdvancedSettings'
|
'change .x-advanced-settings' : '_toggleAdvancedSettings'
|
||||||
},
|
},
|
||||||
|
@ -103,6 +110,7 @@ define(
|
||||||
this.downloadClientSettings = new DownloadClientSettingsModel();
|
this.downloadClientSettings = new DownloadClientSettingsModel();
|
||||||
this.notificationCollection = new NotificationCollection();
|
this.notificationCollection = new NotificationCollection();
|
||||||
this.generalSettings = new GeneralSettingsModel();
|
this.generalSettings = new GeneralSettingsModel();
|
||||||
|
this.uiSettings = new UiSettingsModel();
|
||||||
|
|
||||||
Backbone.$.when(
|
Backbone.$.when(
|
||||||
this.mediaManagementSettings.fetch(),
|
this.mediaManagementSettings.fetch(),
|
||||||
|
@ -110,7 +118,8 @@ define(
|
||||||
this.indexerSettings.fetch(),
|
this.indexerSettings.fetch(),
|
||||||
this.downloadClientSettings.fetch(),
|
this.downloadClientSettings.fetch(),
|
||||||
this.notificationCollection.fetch(),
|
this.notificationCollection.fetch(),
|
||||||
this.generalSettings.fetch()
|
this.generalSettings.fetch(),
|
||||||
|
this.uiSettings.fetch()
|
||||||
).done(function () {
|
).done(function () {
|
||||||
if(!self.isClosed)
|
if(!self.isClosed)
|
||||||
{
|
{
|
||||||
|
@ -123,6 +132,7 @@ define(
|
||||||
self.notifications.show(new NotificationCollectionView({ collection: self.notificationCollection }));
|
self.notifications.show(new NotificationCollectionView({ collection: self.notificationCollection }));
|
||||||
self.metadata.show(new MetadataLayout());
|
self.metadata.show(new MetadataLayout());
|
||||||
self.general.show(new GeneralView({ model: self.generalSettings }));
|
self.general.show(new GeneralView({ model: self.generalSettings }));
|
||||||
|
self.uiRegion.show(new UiView({ model: self.uiSettings }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -155,6 +165,9 @@ define(
|
||||||
case 'general':
|
case 'general':
|
||||||
this._showGeneral();
|
this._showGeneral();
|
||||||
break;
|
break;
|
||||||
|
case 'ui':
|
||||||
|
this._showUi();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this._showMediaManagement();
|
this._showMediaManagement();
|
||||||
}
|
}
|
||||||
|
@ -232,6 +245,15 @@ define(
|
||||||
this._navigate('settings/general');
|
this._navigate('settings/general');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showUi: function (e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ui.uiTab.tab('show');
|
||||||
|
this._navigate('settings/ui');
|
||||||
|
},
|
||||||
|
|
||||||
_navigate:function(route){
|
_navigate:function(route){
|
||||||
Backbone.history.navigate(route, { trigger: false, replace: true });
|
Backbone.history.navigate(route, { trigger: false, replace: true });
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<li><a href="#notifications" class="x-notifications-tab no-router">Connect</a></li>
|
<li><a href="#notifications" class="x-notifications-tab no-router">Connect</a></li>
|
||||||
<li><a href="#metadata" class="x-metadata-tab no-router">Metadata</a></li>
|
<li><a href="#metadata" class="x-metadata-tab no-router">Metadata</a></li>
|
||||||
<li><a href="#general" class="x-general-tab no-router">General</a></li>
|
<li><a href="#general" class="x-general-tab no-router">General</a></li>
|
||||||
|
<li><a href="#ui" class="x-ui-tab no-router">UI</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="row settings-controls">
|
<div class="row settings-controls">
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
<div class="tab-pane" id="notifications"></div>
|
<div class="tab-pane" id="notifications"></div>
|
||||||
<div class="tab-pane" id="metadata"></div>
|
<div class="tab-pane" id="metadata"></div>
|
||||||
<div class="tab-pane" id="general"></div>
|
<div class="tab-pane" id="general"></div>
|
||||||
|
<div class="tab-pane" id="ui"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="loading-region"></div>
|
<div id="loading-region"></div>
|
|
@ -0,0 +1,12 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'Settings/SettingsModelBase'
|
||||||
|
], function (SettingsModelBase) {
|
||||||
|
return SettingsModelBase.extend({
|
||||||
|
|
||||||
|
url : window.NzbDrone.ApiRoot + '/config/ui',
|
||||||
|
successMessage: 'UI settings saved',
|
||||||
|
errorMessage : 'Failed to save UI settings'
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,27 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'vent',
|
||||||
|
'marionette',
|
||||||
|
'Shared/UiSettingsModel',
|
||||||
|
'Mixins/AsModelBoundView',
|
||||||
|
'Mixins/AsValidatedView'
|
||||||
|
], function (vent, Marionette, UiSettingsModel, AsModelBoundView, AsValidatedView) {
|
||||||
|
var view = Marionette.ItemView.extend({
|
||||||
|
template: 'Settings/UI/UiViewTemplate',
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
|
this.listenTo(this.model, 'sync', this._reloadUiSettings);
|
||||||
|
},
|
||||||
|
|
||||||
|
_reloadUiSettings: function() {
|
||||||
|
UiSettingsModel.fetch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AsModelBoundView.call(view);
|
||||||
|
AsValidatedView.call(view);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
<div class="form-horizontal">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Calendar</legend>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">First Day of Week</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select name="firstDayOfWeek" class="form-control">
|
||||||
|
<option value="0">Sunday</option>
|
||||||
|
<option value="1">Monday</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Week Column Header</label>
|
||||||
|
|
||||||
|
<div class="col-sm-1 col-sm-push-4 help-inline">
|
||||||
|
<i class="icon-nd-form-warning" title="Shown above each column when week is the active view"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4 col-sm-pull-1">
|
||||||
|
<select name="calendarWeekColumnHeader" class="form-control">
|
||||||
|
<option value="ddd M/D">Tue 3/25</option>
|
||||||
|
<option value="ddd MM/DD">Tue 03/25</option>
|
||||||
|
<option value="ddd D/M">Tue 25/3</option>
|
||||||
|
<option value="ddd DD/MM">Tue 25/03</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Dates</legend>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Short Date Format</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select name="shortDateFormat" class="form-control">
|
||||||
|
<option value="MMM D YYYY">Mar 25 2014</option>
|
||||||
|
<option value="DD MMM YYYY">25 Mar 2014</option>
|
||||||
|
<option value="MM/D/YYYY">03/25/2014</option>
|
||||||
|
<option value="DD/MM/YYYY">25/03/2014</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Long Date Format</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select name="longDateFormat" class="form-control">
|
||||||
|
<option value="dddd, MMMM D YYYY">Tuesday, March 25, 2014</option>
|
||||||
|
<option value="dddd, D MMMM YYYY">Tuesday, 25 March, 2014</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Time Format</label>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select name="timeFormat" class="form-control">
|
||||||
|
<option value="h(:mm)a">5pm/5:30pm</option>
|
||||||
|
<option value="HH:mm">17:00/17:30</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-3 control-label">Show Relative Dates</label>
|
||||||
|
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<label class="checkbox toggle well">
|
||||||
|
<input type="checkbox" name="showRelativeDates"/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<span>Yes</span>
|
||||||
|
<span>No</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="btn btn-primary slide-button"/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<span class="help-inline-checkbox">
|
||||||
|
<i class="icon-nd-form-info" title="Show relative (Today/Yesterday/etc) or absolute dates"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
|
@ -109,6 +109,10 @@ li.save-and-add:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-tabs {
|
.settings-tabs {
|
||||||
|
li>a {
|
||||||
|
padding : 10px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: @screen-sm-min) and (max-width: @screen-md-max) {
|
@media (min-width: @screen-sm-min) and (max-width: @screen-md-max) {
|
||||||
li {
|
li {
|
||||||
a {
|
a {
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'moment',
|
'moment',
|
||||||
'filesize'
|
'filesize',
|
||||||
], function (Moment, Filesize) {
|
'Shared/UiSettingsModel'
|
||||||
|
], function (moment, filesize, UiSettings) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
||||||
|
@ -15,16 +16,15 @@ define(
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return Filesize(size, { base: 2, round: 1 });
|
return filesize(size, { base: 2, round: 1 });
|
||||||
},
|
},
|
||||||
|
|
||||||
dateHelper: function (sourceDate) {
|
relativeDate: function (sourceDate) {
|
||||||
if (!sourceDate) {
|
if (!sourceDate) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var date = Moment(sourceDate);
|
var date = moment(sourceDate);
|
||||||
|
|
||||||
var calendarDate = date.calendar();
|
var calendarDate = date.calendar();
|
||||||
|
|
||||||
//TODO: It would be nice to not have to hack this...
|
//TODO: It would be nice to not have to hack this...
|
||||||
|
@ -34,12 +34,12 @@ define(
|
||||||
return strippedCalendarDate;
|
return strippedCalendarDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (date.isAfter(Moment())) {
|
if (date.isAfter(moment())) {
|
||||||
return date.fromNow(true);
|
return date.fromNow(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (date.isBefore(Moment().add('years', -1))) {
|
if (date.isBefore(moment().add('years', -1))) {
|
||||||
return date.format('ll');
|
return date.format(UiSettings.get('shortDateFormat'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return date.fromNow();
|
return date.fromNow();
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone',
|
||||||
|
'api!config/ui'
|
||||||
|
], function (Backbone, uiSettings) {
|
||||||
|
var UiSettings = Backbone.Model.extend({
|
||||||
|
|
||||||
|
url : window.NzbDrone.ApiRoot + '/config/ui',
|
||||||
|
|
||||||
|
shortDateTime : function () {
|
||||||
|
return this.get('shortDateFormat') + ' ' + this.get('timeFormat').replace('(', '').replace(')', '');
|
||||||
|
},
|
||||||
|
|
||||||
|
longDateTime : function () {
|
||||||
|
return this.get('longDateFormat') + ' ' + this.get('timeFormat').replace('(', '').replace(')', '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var instance = new UiSettings(uiSettings);
|
||||||
|
return instance;
|
||||||
|
});
|
|
@ -2,16 +2,17 @@
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'Cells/NzbDroneCell',
|
'Cells/NzbDroneCell',
|
||||||
'moment'
|
'moment',
|
||||||
], function (NzbDroneCell, Moment) {
|
'Shared/UiSettingsModel'
|
||||||
|
], function (NzbDroneCell, moment, UiSettings) {
|
||||||
return NzbDroneCell.extend({
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
className: 'log-time-cell',
|
className: 'log-time-cell',
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
|
|
||||||
var date = Moment(this._getValue());
|
var date = moment(this._getValue());
|
||||||
this.$el.html('<span title="{1}">{0}</span>'.format(date.format('LT'), date.format('LLLL')));
|
this.$el.html('<span title="{1}">{0}</span>'.format(date.format(UiSettings.get('timeFormat')), date.format(UiSettings.longDateFormat())));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,6 @@ require.config({
|
||||||
headerCell: 'NzbDrone',
|
headerCell: 'NzbDrone',
|
||||||
sortType : 'toggle'
|
sortType : 'toggle'
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -247,7 +246,19 @@ define(
|
||||||
'Instrumentation/StringFormat',
|
'Instrumentation/StringFormat',
|
||||||
'LifeCycle',
|
'LifeCycle',
|
||||||
'Hotkeys/Hotkeys'
|
'Hotkeys/Hotkeys'
|
||||||
], function ($, Backbone, Marionette, RouteBinder, SignalRBroadcaster, NavbarView, AppLayout, SeriesController, Router, ModalController, ControlPanelController, serverStatusModel, Tooltip) {
|
], function ($,
|
||||||
|
Backbone,
|
||||||
|
Marionette,
|
||||||
|
RouteBinder,
|
||||||
|
SignalRBroadcaster,
|
||||||
|
NavbarView,
|
||||||
|
AppLayout,
|
||||||
|
SeriesController,
|
||||||
|
Router,
|
||||||
|
ModalController,
|
||||||
|
ControlPanelController,
|
||||||
|
serverStatusModel,
|
||||||
|
Tooltip) {
|
||||||
|
|
||||||
new SeriesController();
|
new SeriesController();
|
||||||
new ModalController();
|
new ModalController();
|
||||||
|
|
Loading…
Reference in New Issue