Update: SignalR 2.0.3 Migration; Noticeboards
Migrate all SignalR 1.x Persistent Connections to SignalR 2.x Hubs. Abstracts ScheduledTaskStatus with core interface and adds a Mock for optional status reporting. Noticeboards rewritten (with new theme) to be more resilient and accurate.
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.AspNet.SignalR.Utils" version="2.0.3" />
|
||||
</packages>
|
||||
@@ -12,7 +12,8 @@ namespace Disco.BI.DocumentTemplateBI.Importer
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Trigger Daily @ 12:30am
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Disco.BI.Expressions
|
||||
public override string TaskName { get { return "Expression Cache - Preload Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
|
||||
@@ -29,16 +29,13 @@ namespace Disco.BI.Interop.Community
|
||||
return string.Format("{0}.{1}.{2:0000}.{3:0000}", v.Major, v.Minor, v.Build, v.Revision);
|
||||
}
|
||||
|
||||
public static UpdateResponse Check(DiscoDataContext Database, bool UseProxy, ScheduledTaskStatus status = null)
|
||||
public static UpdateResponse Check(DiscoDataContext Database, bool UseProxy, IScheduledTaskStatus status)
|
||||
{
|
||||
if (status != null)
|
||||
status.UpdateStatus(10, "Building Update Request");
|
||||
status.UpdateStatus(10, "Building Update Request");
|
||||
|
||||
var request = BuildRequest(Database);
|
||||
//var requestJson = JsonConvert.SerializeObject(request);
|
||||
|
||||
if (status != null)
|
||||
status.UpdateStatus(40, "Sending Request");
|
||||
status.UpdateStatus(40, "Sending Request");
|
||||
|
||||
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
||||
|
||||
@@ -61,21 +58,18 @@ namespace Disco.BI.Interop.Community
|
||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateRequestV1));
|
||||
xml.Serialize(wrStream, request);
|
||||
}
|
||||
if (status != null)
|
||||
status.UpdateStatus(50, "Waiting for Response");
|
||||
status.UpdateStatus(50, "Waiting for Response");
|
||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
||||
{
|
||||
if (webResponse.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
if (status != null)
|
||||
status.UpdateStatus(90, "Reading Response");
|
||||
status.UpdateStatus(90, "Reading Response");
|
||||
UpdateResponse result;
|
||||
using (var wResStream = webResponse.GetResponseStream())
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateResponse));
|
||||
result = (UpdateResponse)xml.Deserialize(wResStream);
|
||||
}
|
||||
//var result = JsonConvert.DeserializeObject<UpdateResponse>(responseContent);
|
||||
Database.DiscoConfiguration.UpdateLastCheck = result;
|
||||
Database.SaveChanges();
|
||||
|
||||
@@ -85,8 +79,7 @@ namespace Disco.BI.Interop.Community
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status != null)
|
||||
status.SetTaskException(new WebException(string.Format("Server responded with: [{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription)));
|
||||
status.SetTaskException(new WebException(string.Format("Server responded with: [{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription)));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using Disco.Services.Users;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class AuthorizedPersistentConnection : PersistentConnection
|
||||
{
|
||||
private string authorizedClaim = null;
|
||||
|
||||
protected virtual string AuthorizedClaim { get { return authorizedClaim; } }
|
||||
|
||||
protected override bool AuthorizeRequest(IRequest request)
|
||||
{
|
||||
if (!request.User.Identity.IsAuthenticated)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
var authToken = UserService.CurrentAuthorization;
|
||||
|
||||
if (authToken == null)
|
||||
return false; // No Current User
|
||||
|
||||
if (authorizedClaim == null)
|
||||
return true; // Just Authenticate - no Authorization
|
||||
else
|
||||
return authToken.Has(authorizedClaim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class HeldDeviceNotifications : PersistentConnection
|
||||
{
|
||||
private static bool subscribed = false;
|
||||
private static object subscribeLock = new object();
|
||||
private static IPersistentConnectionContext notificationContext;
|
||||
|
||||
static HeldDeviceNotifications()
|
||||
{
|
||||
if (!subscribed)
|
||||
lock (subscribeLock)
|
||||
if (!subscribed)
|
||||
{
|
||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<HeldDeviceNotifications>();
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
(e.ModifiedProperties.Contains("Location") ||
|
||||
e.ModifiedProperties.Contains("DeviceModelId") ||
|
||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
||||
e.ModifiedProperties.Contains("ComputerName") ||
|
||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
).Subscribe(DeviceUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(User) &&
|
||||
e.ModifiedProperties.Contains("DisplayName")
|
||||
).Subscribe(UserUpdated);
|
||||
|
||||
subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Job j = (Job)e.Entity;
|
||||
|
||||
if (j.DeviceSerialNumber != null)
|
||||
notificationContext.Connection.Broadcast(j.DeviceSerialNumber);
|
||||
}
|
||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Device d = (Device)e.Entity;
|
||||
|
||||
notificationContext.Connection.Broadcast(d.SerialNumber);
|
||||
}
|
||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
User u = (User)e.Entity;
|
||||
|
||||
var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.UserId);
|
||||
|
||||
foreach (var userDevice in userDevices)
|
||||
{
|
||||
notificationContext.Connection.Broadcast(userDevice.SerialNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Logging.Models;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class LogNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
public static bool initialized = false;
|
||||
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public LogNotifications()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
Disco.Services.Logging.Targets.LogLiveContext.LogBroadcast += Broadcast;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
internal static void Broadcast(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments)
|
||||
{
|
||||
var message = LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
|
||||
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<LogNotifications>();
|
||||
connectionContext.Groups.Send(_GroupNameAll, message);
|
||||
connectionContext.Groups.Send(logModule.ModuleName, message);
|
||||
}
|
||||
|
||||
private const string _GroupNameAll = "__All";
|
||||
|
||||
public static string AllNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GroupNameAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Services.Authorization;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class RepositoryMonitorNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
RepositoryMonitor.StreamAfterCommit.Subscribe(AfterCommit);
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
private static void AfterCommit(RepositoryMonitorEvent e)
|
||||
{
|
||||
GlobalHost.ConnectionManager.GetConnectionContext<RepositoryMonitorNotifications>().Groups.Send(e.EntityType.Name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Tasks;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class ScheduledTasksStatusNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
public static bool initialized = false;
|
||||
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public ScheduledTasksStatusNotifications()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
Disco.Services.Tasks.ScheduledTaskStatus.UpdatedBroadcast += Broadcast;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
internal static void Broadcast(ScheduledTaskStatusLive SessionStatus)
|
||||
{
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<ScheduledTasksStatusNotifications>();
|
||||
connectionContext.Groups.Send(_GroupNameAll, SessionStatus);
|
||||
connectionContext.Groups.Send(SessionStatus.SessionId, SessionStatus);
|
||||
}
|
||||
|
||||
private const string _GroupNameAll = "__All";
|
||||
|
||||
public static string AllNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GroupNameAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.SessionState;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Owin;
|
||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Required for SignalR 1.1.0 NTLM support in Firefox & Safari
|
||||
/// Returns 401 (Unauthorized) instead of 403 (Forbidden) when an unauthenticated request is processed
|
||||
///
|
||||
/// TODO: Remove this workaround when implementing SignalR 2.x
|
||||
///
|
||||
/// Thanks to David Fowler (@davidfowl)
|
||||
/// </summary>
|
||||
public static class SignalRAuthenticationWorkaround
|
||||
{
|
||||
public static void AddMiddleware(IAppBuilder app)
|
||||
{
|
||||
Func<AppFunc, AppFunc> convert403To401 = Convert403To401;
|
||||
|
||||
app.Use(convert403To401);
|
||||
}
|
||||
|
||||
private static AppFunc Convert403To401(AppFunc next)
|
||||
{
|
||||
return env =>
|
||||
{
|
||||
// Execute the SignalR pipeline
|
||||
Task task = next(env);
|
||||
|
||||
// Get the status code
|
||||
int statusCode = 0;
|
||||
if (env.ContainsKey("owin.ResponseStatusCode"))
|
||||
{
|
||||
statusCode = (int)env["owin.ResponseStatusCode"];
|
||||
}
|
||||
|
||||
// If its 403 then convert it to 401 (we shouldn't do
|
||||
// this if it's a cross domain request since it doesn't make sense)
|
||||
if (statusCode == 403)
|
||||
{
|
||||
env["owin.ResponseStatusCode"] = 401;
|
||||
}
|
||||
|
||||
// Return the original task
|
||||
return task;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class UserHeldDeviceNotifications : PersistentConnection
|
||||
{
|
||||
private static bool subscribed = false;
|
||||
private static object subscribeLock = new object();
|
||||
private static IPersistentConnectionContext notificationContext;
|
||||
|
||||
static UserHeldDeviceNotifications()
|
||||
{
|
||||
if (!subscribed)
|
||||
lock (subscribeLock)
|
||||
if (!subscribed)
|
||||
{
|
||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<UserHeldDeviceNotifications>();
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
(e.ModifiedProperties.Contains("DeviceModelId") ||
|
||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
).Subscribe(DeviceUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(User) &&
|
||||
e.ModifiedProperties.Contains("DisplayName")
|
||||
).Subscribe(UserUpdated);
|
||||
|
||||
subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Job j = (Job)e.Entity;
|
||||
|
||||
if (j.DeviceSerialNumber != null)
|
||||
{
|
||||
var jobDevice = e.Database.Devices.Where(d => d.SerialNumber == j.DeviceSerialNumber).FirstOrDefault();
|
||||
|
||||
if (jobDevice.AssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(jobDevice.AssignedUserId);
|
||||
}
|
||||
}
|
||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Device d = (Device)e.Entity;
|
||||
|
||||
string previouslyAssignedUserId = null;
|
||||
|
||||
if (e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
previouslyAssignedUserId = e.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
e.ExecuteAfterCommit(me =>
|
||||
{
|
||||
if (previouslyAssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(previouslyAssignedUserId);
|
||||
|
||||
if (d.AssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(d.AssignedUserId);
|
||||
});
|
||||
}
|
||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
User u = (User)e.Entity;
|
||||
|
||||
notificationContext.Connection.Broadcast(u.UserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ namespace Disco.BI.JobBI.Statistics
|
||||
public override string TaskName { get { return "Job Statistics - Daily Opened/Closed Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
|
||||
@@ -46,32 +46,6 @@
|
||||
<Reference Include="itextsharp">
|
||||
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.1.2\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.1.2\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Quartz">
|
||||
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -172,13 +146,6 @@
|
||||
<Compile Include="BI\Interop\MimeTypes.cs" />
|
||||
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
||||
<Compile Include="BI\Interop\Pdf\PdfImporter.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\AuthorizedPersistentConnection.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\HeldDeviceNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\LogNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\RepositoryMonitorNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\ScheduledTasksStatusNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\SignalRAuthenticationWorkaround.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\UserHeldDeviceNotifications.cs" />
|
||||
<Compile Include="BI\JobBI\Statistics\DailyOpenedClosed.cs" />
|
||||
<Compile Include="BI\JobBI\Utilities.cs" />
|
||||
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
||||
@@ -235,7 +202,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
|
||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" />
|
||||
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Interfaces" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Linq" version="2.1.30214.0" targetFramework="net45" />
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
<Compile Include="Services\Jobs\JobLists\JobTableStatusItemModel.cs" />
|
||||
<Compile Include="Services\Jobs\JobLists\JobTableStatusQueueItemModel.cs" />
|
||||
<Compile Include="Services\Jobs\JobQueues\IJobQueueToken.cs" />
|
||||
<Compile Include="Services\Jobs\Noticeboards\IHeldDeviceItem.cs" />
|
||||
<Compile Include="Services\Searching\DeviceSearchResultItem.cs" />
|
||||
<Compile Include="Services\Searching\ISearchResultItem.cs" />
|
||||
<Compile Include="Services\Searching\JobSearchResultItem.cs" />
|
||||
@@ -151,7 +152,7 @@
|
||||
<Compile Include="UI\Config\JobQueue\ConfigJobQueueIndexModel.cs" />
|
||||
<Compile Include="UI\Config\JobQueue\ConfigJobQueueShowModel.cs" />
|
||||
<Compile Include="UI\Config\Logging\ConfigLoggingIndexModel.cs" />
|
||||
<Compile Include="UI\Config\Logging\ConfigLoggingTaskStatusModel.cs" />
|
||||
<Compile Include="UI\Config\Shared\ConfigSharedTaskStatusModel.cs" />
|
||||
<Compile Include="UI\Config\Organisation\ConfigOrganisationIndexModel.cs" />
|
||||
<Compile Include="UI\Device\DeviceAddOfflineModel.cs" />
|
||||
<Compile Include="UI\Device\DeviceExportModel.cs" />
|
||||
@@ -175,7 +176,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Models.Services.Jobs.Noticeboards
|
||||
{
|
||||
public interface IHeldDeviceItem
|
||||
{
|
||||
int JobId { get; }
|
||||
|
||||
string DeviceSerialNumber { get; }
|
||||
string DeviceComputerNameFriendly { get; }
|
||||
string DeviceComputerName { get; }
|
||||
|
||||
string DeviceLocation { get; }
|
||||
string DeviceDescription { get; }
|
||||
|
||||
int DeviceProfileId { get; }
|
||||
int? DeviceAddressId { get; }
|
||||
string DeviceAddressShortName { get; }
|
||||
|
||||
string UserId { get; }
|
||||
string UserIdFriendly { get; }
|
||||
string UserDisplayName { get; }
|
||||
|
||||
bool WaitingForUserAction { get; }
|
||||
DateTime? WaitingForUserActionSince { get; }
|
||||
long? WaitingForUserActionSinceUnixEpoc { get; }
|
||||
|
||||
bool ReadyForReturn { get; }
|
||||
DateTime? EstimatedReturnTime { get; }
|
||||
long? EstimatedReturnTimeUnixEpoc { get; }
|
||||
DateTime? ReadyForReturnSince { get; }
|
||||
long? ReadyForReturnSinceUnixEpoc { get; }
|
||||
|
||||
bool IsAlert { get; }
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -4,9 +4,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Models.UI.Config.Logging
|
||||
namespace Disco.Models.UI.Config.Shared
|
||||
{
|
||||
public interface ConfigLoggingTaskStatusModel : BaseUIModel
|
||||
public interface ConfigSharedTaskStatusModel : BaseUIModel
|
||||
{
|
||||
string SessionId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Web.Signalling;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.Services.Devices
|
||||
{
|
||||
[HubName("deviceUpdates"), DiscoHubAuthorizeAll(Claims.Device.Show, Claims.Device.ShowAttachments)]
|
||||
public class DeviceUpdatesHub : Hub
|
||||
{
|
||||
private const string UserPrefix = "Device_";
|
||||
public static IHubContext HubContext { get; private set; }
|
||||
|
||||
private static IDisposable RepositoryBeforeSubscription;
|
||||
private static IDisposable RepositoryAfterSubscription;
|
||||
|
||||
static DeviceUpdatesHub()
|
||||
{
|
||||
HubContext = GlobalHost.ConnectionManager.GetHubContext<DeviceUpdatesHub>();
|
||||
|
||||
// Subscribe to Repository Monitor for Changes
|
||||
RepositoryBeforeSubscription = RepositoryMonitor.StreamBeforeCommit
|
||||
.Where(e => e.EntityType == typeof(DeviceAttachment) && e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
.Subscribe(RepositoryEventBefore);
|
||||
RepositoryAfterSubscription = RepositoryMonitor.StreamAfterCommit
|
||||
.Where(e => e.EntityType == typeof(DeviceAttachment) && e.EventType == RepositoryMonitorEventType.Added)
|
||||
.Subscribe(RepositoryAfterEvent);
|
||||
}
|
||||
|
||||
private static string GroupName(string DeviceSerialNumber)
|
||||
{
|
||||
return UserPrefix + DeviceSerialNumber;
|
||||
}
|
||||
|
||||
public override Task OnConnected()
|
||||
{
|
||||
var deviceSerialNumber = Context.QueryString["DeviceSerialNumber"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(deviceSerialNumber))
|
||||
throw new ArgumentNullException("DeviceSerialNumber");
|
||||
|
||||
Groups.Add(Context.ConnectionId, GroupName(deviceSerialNumber));
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
|
||||
private static void RepositoryEventBefore(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
{
|
||||
if (e.EntityType == typeof(DeviceAttachment))
|
||||
{
|
||||
var repositoryAttachment = (DeviceAttachment)e.Entity;
|
||||
string attachmentDeviceSerialNumber;
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
attachmentDeviceSerialNumber = Database.DeviceAttachments.Where(a => a.Id == repositoryAttachment.Id).Select(a => a.DeviceSerialNumber).First();
|
||||
|
||||
HubContext.Clients.Group(GroupName(attachmentDeviceSerialNumber)).removeAttachment(repositoryAttachment.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RepositoryAfterEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Added)
|
||||
{
|
||||
if (e.EntityType == typeof(DeviceAttachment))
|
||||
{
|
||||
var a = (DeviceAttachment)e.Entity;
|
||||
|
||||
HubContext.Clients.Group(GroupName(a.DeviceSerialNumber)).addAttachment(a.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Disco.Services.Devices.Exporting
|
||||
public static class DeviceExport
|
||||
{
|
||||
|
||||
public static DeviceExportResult GenerateExport(DiscoDataContext Database, IQueryable<Device> Devices, DeviceExportOptions Options, IScheduledTaskBasicStatus TaskStatus)
|
||||
public static DeviceExportResult GenerateExport(DiscoDataContext Database, IQueryable<Device> Devices, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus)
|
||||
{
|
||||
TaskStatus.UpdateStatus(15, "Building metadata and database query");
|
||||
var metadata = Options.BuildMetadata();
|
||||
@@ -32,15 +32,17 @@ namespace Disco.Services.Devices.Exporting
|
||||
Options.AssignedUserEmailAddress)
|
||||
{
|
||||
TaskStatus.UpdateStatus(20, "Updating Assigned User details");
|
||||
var users = Devices.Where(d => d.AssignedUserId != null).Select(d => d.AssignedUserId).Distinct().ToList();
|
||||
|
||||
Devices.Where(d => d.AssignedUserId != null).Select(d => d.AssignedUserId).Distinct().ToList().ForEach(userId =>
|
||||
users.Select((userId, index) =>
|
||||
{
|
||||
TaskStatus.UpdateStatus(20 + (((double)20 / users.Count) * index), string.Format("Updating Assigned User details: {0}", userId));
|
||||
try
|
||||
{
|
||||
UserService.GetUser(userId, Database);
|
||||
return UserService.GetUser(userId, Database);
|
||||
}
|
||||
catch (Exception) { } // Ignore Errors
|
||||
});
|
||||
catch (Exception) { return null; } // Ignore Errors
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
// Update Last Network Logon Date
|
||||
@@ -49,8 +51,16 @@ namespace Disco.Services.Devices.Exporting
|
||||
TaskStatus.UpdateStatus(40, "Updating device last network logon dates");
|
||||
try
|
||||
{
|
||||
Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDates(Database, ScheduledTaskMockStatus.Create());
|
||||
TaskStatus.IgnoreCurrentProcessChanges = true;
|
||||
TaskStatus.ProgressMultiplier = 20 / 100;
|
||||
TaskStatus.ProgressOffset = 40;
|
||||
|
||||
Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDates(Database, TaskStatus);
|
||||
Database.SaveChanges();
|
||||
|
||||
TaskStatus.IgnoreCurrentProcessChanges = false;
|
||||
TaskStatus.ProgressMultiplier = 1;
|
||||
TaskStatus.ProgressOffset = 0;
|
||||
}
|
||||
catch (Exception) { } // Ignore Errors
|
||||
}
|
||||
@@ -103,7 +113,7 @@ namespace Disco.Services.Devices.Exporting
|
||||
return GenerateExport(Database, Devices, Options, ScheduledTaskMockStatus.Create());
|
||||
}
|
||||
|
||||
public static DeviceExportResult GenerateExport(DiscoDataContext Database, DeviceExportOptions Options, IScheduledTaskBasicStatus TaskStatus)
|
||||
public static DeviceExportResult GenerateExport(DiscoDataContext Database, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus)
|
||||
{
|
||||
switch (Options.ExportType)
|
||||
{
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Disco.Services.Devices.Importing
|
||||
Context.Header = Context.Header.Zip(HeaderTypes, (h, ht) => Tuple.Create(h.Item1, ht)).ToList();
|
||||
}
|
||||
|
||||
public static void ParseRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskBasicStatus Status)
|
||||
public static void ParseRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskStatus Status)
|
||||
{
|
||||
if (Context.Header == null)
|
||||
throw new InvalidOperationException("The Import Context has not been initialized");
|
||||
@@ -129,18 +129,13 @@ namespace Disco.Services.Devices.Importing
|
||||
.Select(h => new Tuple<string, DeviceImportFieldTypes, Func<string[], string>, Type>(h.Item1, h.Item2, (f) => f[h.Item3], DeviceImport.FieldHandlers.Value[h.Item2]))
|
||||
.ToList();
|
||||
|
||||
DateTime nextProgress = DateTime.Now;
|
||||
Status.UpdateStatus(0, "Parsing Import Records", "Starting...");
|
||||
|
||||
Context.Records = Context.RawData.Select((d, recordIndex) =>
|
||||
{
|
||||
string deviceSerialNumber = Fields.DeviceSerialNumberImportField.ParseRawDeviceSerialNumber(d[Context.HeaderDeviceSerialNumberIndex]);
|
||||
|
||||
if (nextProgress <= DateTime.Now)
|
||||
{
|
||||
Status.UpdateStatus(((double)recordIndex / Context.RawData.Count) * 100, string.Format("Parsing: {0}", deviceSerialNumber));
|
||||
nextProgress = DateTime.Now.AddSeconds(.5);
|
||||
}
|
||||
Status.UpdateStatus(((double)recordIndex / Context.RawData.Count) * 100, string.Format("Parsing: {0}", deviceSerialNumber));
|
||||
|
||||
Device existingDevice = null;
|
||||
if (Fields.DeviceSerialNumberImportField.IsDeviceSerialNumberValid(deviceSerialNumber))
|
||||
@@ -170,7 +165,7 @@ namespace Disco.Services.Devices.Importing
|
||||
}).Cast<IDeviceImportRecord>().ToList();
|
||||
}
|
||||
|
||||
public static int ApplyRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskBasicStatus Status)
|
||||
public static int ApplyRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskStatus Status)
|
||||
{
|
||||
if (Context.Records == null)
|
||||
throw new InvalidOperationException("Import Records have not been parsed");
|
||||
@@ -178,18 +173,13 @@ namespace Disco.Services.Devices.Importing
|
||||
if (Context.Records.Count == 0)
|
||||
throw new InvalidOperationException("There are no records to import");
|
||||
|
||||
DateTime nextProgress = DateTime.Now;
|
||||
Status.UpdateStatus(0, "Applying Import Records to Database", "Starting...");
|
||||
|
||||
int affectedRecords = 0;
|
||||
|
||||
foreach (var record in Context.Records.Cast<DeviceImportRecord>().Select((r, i) => Tuple.Create(r, i)))
|
||||
{
|
||||
if (nextProgress <= DateTime.Now)
|
||||
{
|
||||
Status.UpdateStatus(((double)record.Item2 / Context.Records.Count) * 100, string.Format("Applying: {0}", record.Item1.DeviceSerialNumber));
|
||||
nextProgress = DateTime.Now.AddSeconds(.5);
|
||||
}
|
||||
Status.UpdateStatus(((double)record.Item2 / Context.Records.Count) * 100, string.Format("Applying: {0}", record.Item1.DeviceSerialNumber));
|
||||
|
||||
if (record.Item1.Apply(Database))
|
||||
affectedRecords++;
|
||||
|
||||
@@ -42,21 +42,21 @@
|
||||
<Reference Include="LumenWorks.Framework.IO">
|
||||
<HintPath>..\packages\LumenWorks.Framework.IO.3.8.0\lib\net20\LumenWorks.Framework.IO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Core">
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.2.0.3\lib\net45\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.1.2\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
|
||||
<Reference Include="Microsoft.Owin">
|
||||
<HintPath>..\packages\Microsoft.Owin.2.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Security">
|
||||
<HintPath>..\packages\Microsoft.Owin.Security.2.0.1\lib\net45\Microsoft.Owin.Security.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
@@ -201,7 +201,9 @@
|
||||
<Compile Include="Devices\Importing\Fields\DeviceSerialNumberImportField.cs" />
|
||||
<Compile Include="Devices\Importing\Fields\ModelIdImportField.cs" />
|
||||
<Compile Include="Devices\Importing\IDeviceImportCache.cs" />
|
||||
<Compile Include="Devices\DeviceUpdatesHub.cs" />
|
||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||
<Compile Include="Extensions\RxExtensions.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
|
||||
@@ -227,6 +229,11 @@
|
||||
<Compile Include="Jobs\JobQueues\JobQueueService.cs" />
|
||||
<Compile Include="Jobs\JobQueues\JobQueueToken.cs" />
|
||||
<Compile Include="Jobs\JobLists\ManagedJobList.cs" />
|
||||
<Compile Include="Jobs\JobUpdatesHub.cs" />
|
||||
<Compile Include="Jobs\Noticeboards\HeldDeviceItem.cs" />
|
||||
<Compile Include="Jobs\Noticeboards\NoticeboardUpdatesHub.cs" />
|
||||
<Compile Include="Jobs\Noticeboards\HeldDevices.cs" />
|
||||
<Compile Include="Jobs\Noticeboards\HeldDevicesForUsers.cs" />
|
||||
<Compile Include="Logging\LogBase.cs" />
|
||||
<Compile Include="Logging\LogContext.cs" />
|
||||
<Compile Include="Logging\LogReInitalizeJob.cs" />
|
||||
@@ -236,9 +243,8 @@
|
||||
<Compile Include="Logging\Models\LogModule.cs" />
|
||||
<Compile Include="Logging\ReadLogContext.cs" />
|
||||
<Compile Include="Logging\SystemLog.cs" />
|
||||
<Compile Include="Logging\Targets\LogLiveContext.cs" />
|
||||
<Compile Include="Logging\Targets\LogPersistContext.cs" />
|
||||
<Compile Include="Logging\Targets\LogPersistContextInitializer.cs" />
|
||||
<Compile Include="Logging\Persistance\LogPersistContext.cs" />
|
||||
<Compile Include="Logging\Persistance\LogPersistContextInitializer.cs" />
|
||||
<Compile Include="Logging\Utilities.cs" />
|
||||
<Compile Include="Plugins\CommunityInterop\PluginLibraryUpdateTask.cs" />
|
||||
<Compile Include="Plugins\Features\UIExtension\Results\LiteralResult.cs" />
|
||||
@@ -278,9 +284,10 @@
|
||||
<Compile Include="Plugins\WebPageHelper.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Searching\Search.cs" />
|
||||
<Compile Include="Tasks\IScheduledTaskBasicStatus.cs" />
|
||||
<Compile Include="Tasks\IScheduledTaskStatus.cs" />
|
||||
<Compile Include="Tasks\ScheduledTask.cs" />
|
||||
<Compile Include="Tasks\ScheduledTaskMockStatus.cs" />
|
||||
<Compile Include="Tasks\ScheduledTaskNotificationsHub.cs" />
|
||||
<Compile Include="Tasks\ScheduledTasks.cs" />
|
||||
<Compile Include="Tasks\ScheduledTasksLog.cs" />
|
||||
<Compile Include="Tasks\ScheduledTaskStatus.cs" />
|
||||
@@ -290,17 +297,24 @@
|
||||
<Compile Include="Users\CacheCleanTask.cs" />
|
||||
<Compile Include="Users\UserExtensions.cs" />
|
||||
<Compile Include="Users\UserService.cs" />
|
||||
<Compile Include="Users\UserUpdatesHub.cs" />
|
||||
<Compile Include="Web\AuthorizedController.cs" />
|
||||
<Compile Include="Web\AuthorizedDatabaseController.cs" />
|
||||
<Compile Include="Web\BaseController.cs" />
|
||||
<Compile Include="Web\Bundles\Bundle.cs" />
|
||||
<Compile Include="Web\Bundles\FileBundle.cs" />
|
||||
<Compile Include="Web\Bundles\IBundle.cs" />
|
||||
<Compile Include="Web\Bundles\BundleExtensions.cs" />
|
||||
<Compile Include="Web\Bundles\BundleHandler.cs" />
|
||||
<Compile Include="Web\Bundles\BundleModule.cs" />
|
||||
<Compile Include="Web\Bundles\BundleTable.cs" />
|
||||
<Compile Include="Web\Bundles\UrlBundle.cs" />
|
||||
<Compile Include="Web\DatabaseController.cs" />
|
||||
<Compile Include="Web\HandleErrorAttribute.cs" />
|
||||
<Compile Include="Web\HelperExtensions.cs" />
|
||||
<Compile Include="Web\Signalling\DiscoHubAuthorizeAllAttribute.cs" />
|
||||
<Compile Include="Web\Signalling\DiscoHubAuthorizeAnyAttribute.cs" />
|
||||
<Compile Include="Web\Signalling\DiscoHubAuthorizeAttribute.cs" />
|
||||
<Compile Include="Logging\LogNotificationsHub.cs" />
|
||||
<Compile Include="Web\WebViewPage.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -328,7 +342,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco
|
||||
{
|
||||
public static class RxExtensions
|
||||
{
|
||||
|
||||
#region RxExtensions
|
||||
|
||||
public static IObservable<IEnumerable<T>> DelayBuffer<T>(this IObservable<T> source, TimeSpan delay)
|
||||
{
|
||||
return Observable.Create<IEnumerable<T>>(o =>
|
||||
{
|
||||
var gate = new object();
|
||||
var buffer = new List<T>();
|
||||
var trigger = (IDisposable)null;
|
||||
var subscription = (IDisposable)null;
|
||||
var scheduler = Scheduler.Default;
|
||||
|
||||
Action dump = () =>
|
||||
{
|
||||
var bts = buffer.ToArray();
|
||||
buffer = new List<T>();
|
||||
if (o != null)
|
||||
o.OnNext(bts);
|
||||
if (trigger != null)
|
||||
{
|
||||
trigger.Dispose();
|
||||
trigger = null;
|
||||
}
|
||||
};
|
||||
|
||||
Action dispose = () =>
|
||||
{
|
||||
if (subscription != null)
|
||||
subscription.Dispose();
|
||||
if (trigger != null)
|
||||
{
|
||||
trigger.Dispose();
|
||||
trigger = null;
|
||||
}
|
||||
};
|
||||
|
||||
Action<Action<IObserver<IEnumerable<T>>>> onErrorOrCompleted =
|
||||
onAction =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
dispose();
|
||||
dump();
|
||||
if (o != null)
|
||||
onAction(o);
|
||||
}
|
||||
};
|
||||
|
||||
Action<Exception> onError = ex =>
|
||||
onErrorOrCompleted(x => x.OnError(ex));
|
||||
|
||||
Action onCompleted = () => onErrorOrCompleted(x => x.OnCompleted());
|
||||
|
||||
Action<T> onNext = t =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
buffer.Add(t);
|
||||
|
||||
if (trigger == null)
|
||||
{
|
||||
trigger = scheduler.Schedule(delay, () =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
dump();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
subscription =
|
||||
source
|
||||
.ObserveOn(scheduler)
|
||||
.Subscribe(onNext, onError, onCompleted);
|
||||
|
||||
return () =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
o = null;
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<IEnumerable<T>> BufferWithInactivity<T>(this IObservable<T> source, TimeSpan inactivity)
|
||||
{
|
||||
return Observable.Create<IEnumerable<T>>(o =>
|
||||
{
|
||||
var gate = new object();
|
||||
var buffer = new List<T>();
|
||||
var mutable = new SerialDisposable();
|
||||
var subscription = (IDisposable)null;
|
||||
var scheduler = Scheduler.Default;
|
||||
|
||||
Action dump = () =>
|
||||
{
|
||||
var bts = buffer.ToArray();
|
||||
buffer = new List<T>();
|
||||
if (o != null)
|
||||
{
|
||||
o.OnNext(bts);
|
||||
}
|
||||
};
|
||||
|
||||
Action dispose = () =>
|
||||
{
|
||||
if (subscription != null)
|
||||
{
|
||||
subscription.Dispose();
|
||||
}
|
||||
mutable.Dispose();
|
||||
};
|
||||
|
||||
Action<Action<IObserver<IEnumerable<T>>>> onErrorOrCompleted =
|
||||
onAction =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
dispose();
|
||||
dump();
|
||||
if (o != null)
|
||||
{
|
||||
onAction(o);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Action<Exception> onError = ex =>
|
||||
onErrorOrCompleted(x => x.OnError(ex));
|
||||
|
||||
Action onCompleted = () => onErrorOrCompleted(x => x.OnCompleted());
|
||||
|
||||
Action<T> onNext = t =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
buffer.Add(t);
|
||||
mutable.Disposable = scheduler.Schedule(inactivity, () =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
dump();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
subscription =
|
||||
source
|
||||
.ObserveOn(scheduler)
|
||||
.Subscribe(onNext, onError, onCompleted);
|
||||
|
||||
return () =>
|
||||
{
|
||||
lock (gate)
|
||||
{
|
||||
o = null;
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void UpdateLastNetworkLogonDates(DiscoDataContext Database, IScheduledTaskBasicStatus status)
|
||||
public static void UpdateLastNetworkLogonDates(DiscoDataContext Database, IScheduledTaskStatus status)
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
const string ldapFilter = "(objectCategory=Computer)";
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Disco.Services.Jobs.JobQueues
|
||||
|
||||
return _cache.UpdateQueue(JobQueue);
|
||||
}
|
||||
public static void DeleteJobQueue(DiscoDataContext Database, int JobQueueId, ScheduledTaskStatus Status)
|
||||
public static void DeleteJobQueue(DiscoDataContext Database, int JobQueueId, IScheduledTaskStatus Status)
|
||||
{
|
||||
JobQueue queue = Database.JobQueues.Find(JobQueueId);
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Web.Signalling;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Services.Users;
|
||||
|
||||
namespace Disco.Services.Jobs
|
||||
{
|
||||
[HubName("jobUpdates"), DiscoHubAuthorize(Claims.Job.Show)]
|
||||
public class JobUpdatesHub : Hub
|
||||
{
|
||||
private const string JobLogsPrefix = "JobLogs_";
|
||||
private const string JobAttachmentsPrefix = "JobAttachments_";
|
||||
public static IHubContext HubContext { get; private set; }
|
||||
|
||||
private static IDisposable RepositoryBeforeSubscription;
|
||||
private static IDisposable RepositoryAfterSubscription;
|
||||
|
||||
static JobUpdatesHub()
|
||||
{
|
||||
HubContext = GlobalHost.ConnectionManager.GetHubContext<JobUpdatesHub>();
|
||||
|
||||
// Subscribe to Repository Monitor for Changes
|
||||
RepositoryBeforeSubscription = RepositoryMonitor.StreamBeforeCommit
|
||||
.Where(e => (
|
||||
e.EntityType == typeof(JobLog) && e.EventType == RepositoryMonitorEventType.Deleted ||
|
||||
e.EntityType == typeof(JobAttachment) && e.EventType == RepositoryMonitorEventType.Deleted
|
||||
))
|
||||
.Subscribe(RepositoryEventBefore);
|
||||
RepositoryAfterSubscription = RepositoryMonitor.StreamAfterCommit
|
||||
.Where(e => (
|
||||
e.EntityType == typeof(JobLog) && e.EventType == RepositoryMonitorEventType.Added ||
|
||||
e.EntityType == typeof(JobAttachment) && e.EventType == RepositoryMonitorEventType.Added
|
||||
))
|
||||
.Subscribe(RepositoryAfterEvent);
|
||||
}
|
||||
|
||||
private static string LogsGroupName(int JobId)
|
||||
{
|
||||
return JobLogsPrefix + JobId.ToString();
|
||||
}
|
||||
private static string AttachmentsGroupName(int JobId)
|
||||
{
|
||||
return JobAttachmentsPrefix + JobId.ToString();
|
||||
}
|
||||
|
||||
public override Task OnConnected()
|
||||
{
|
||||
int jobId;
|
||||
string jobIdParam;
|
||||
|
||||
jobIdParam = Context.QueryString["JobId"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(jobIdParam))
|
||||
throw new ArgumentNullException("JobId");
|
||||
if (!int.TryParse(jobIdParam, out jobId))
|
||||
throw new ArgumentException("An integer was expected", "JobId");
|
||||
|
||||
var userAuth = UserService.GetAuthorization(Context.User.Identity.Name);
|
||||
|
||||
if (userAuth.Has(Claims.Job.ShowLogs))
|
||||
Groups.Add(Context.ConnectionId, LogsGroupName(jobId));
|
||||
if (userAuth.Has(Claims.Job.ShowAttachments))
|
||||
Groups.Add(Context.ConnectionId, AttachmentsGroupName(jobId));
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
|
||||
private static void RepositoryEventBefore(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
{
|
||||
if (e.EntityType == typeof(JobLog))
|
||||
{
|
||||
var repositoryLog = (JobLog)e.Entity;
|
||||
int logJobId;
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
logJobId = Database.JobLogs.Where(l => l.Id == repositoryLog.Id).Select(a => a.JobId).First();
|
||||
|
||||
HubContext.Clients.Group(LogsGroupName(logJobId)).removeLog(repositoryLog.Id);
|
||||
}
|
||||
if (e.EntityType == typeof(JobAttachment))
|
||||
{
|
||||
var repositoryAttachment = (JobAttachment)e.Entity;
|
||||
int attachmentJobId;
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
attachmentJobId = Database.JobAttachments.Where(a => a.Id == repositoryAttachment.Id).Select(a => a.JobId).First();
|
||||
|
||||
HubContext.Clients.Group(AttachmentsGroupName(attachmentJobId)).removeAttachment(repositoryAttachment.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RepositoryAfterEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Added)
|
||||
{
|
||||
if (e.EntityType == typeof(JobLog))
|
||||
{
|
||||
var a = (JobLog)e.Entity;
|
||||
|
||||
HubContext.Clients.Group(LogsGroupName(a.JobId)).addLog(a.Id);
|
||||
}
|
||||
if (e.EntityType == typeof(JobAttachment))
|
||||
{
|
||||
var a = (JobAttachment)e.Entity;
|
||||
|
||||
HubContext.Clients.Group(AttachmentsGroupName(a.JobId)).addAttachment(a.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using Disco.Data.Configuration.Modules;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.Noticeboards;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
public class HeldDeviceItem : IHeldDeviceItem
|
||||
{
|
||||
public int JobId { get; set; }
|
||||
|
||||
public string DeviceSerialNumber { get; set; }
|
||||
public string DeviceComputerNameFriendly
|
||||
{
|
||||
get
|
||||
{
|
||||
return DeviceComputerName == null ? null : UserExtensions.FriendlyUserId(DeviceComputerName);
|
||||
}
|
||||
}
|
||||
public string DeviceComputerName { get; set; }
|
||||
|
||||
public string DeviceLocation { get; set; }
|
||||
public string DeviceDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(this.DeviceComputerNameFriendly);
|
||||
|
||||
if (UserId != null)
|
||||
sb.Append(" - ").Append(this.UserDisplayName).Append(" (").Append(this.UserIdFriendly).Append(")");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(this.DeviceLocation))
|
||||
sb.Append(" - ").Append(this.DeviceLocation);
|
||||
else if (UserId == null)
|
||||
sb.Append(" - ").Append(this.DeviceSerialNumber);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public int DeviceProfileId { get; set; }
|
||||
public int? DeviceAddressId { get; set; }
|
||||
public string DeviceAddressShortName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DeviceAddressId.HasValue)
|
||||
{
|
||||
var config = new OrganisationAddressesConfiguration(null);
|
||||
var address = config.GetAddress(DeviceAddressId.Value);
|
||||
if (address != null)
|
||||
return address.ShortName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string UserId { get; set; }
|
||||
public string UserIdFriendly
|
||||
{
|
||||
get
|
||||
{
|
||||
return UserId == null ? null : UserExtensions.FriendlyUserId(UserId);
|
||||
}
|
||||
}
|
||||
public string UserDisplayName { get; set; }
|
||||
|
||||
public bool WaitingForUserAction { get; set; }
|
||||
public DateTime? WaitingForUserActionSince { get; set; }
|
||||
public long? WaitingForUserActionSinceUnixEpoc
|
||||
{
|
||||
get
|
||||
{
|
||||
return WaitingForUserActionSince.ToUnixEpoc();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadyForReturn { get; set; }
|
||||
public DateTime? EstimatedReturnTime { get; set; }
|
||||
public long? EstimatedReturnTimeUnixEpoc
|
||||
{
|
||||
get
|
||||
{
|
||||
return EstimatedReturnTime.ToUnixEpoc();
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime? ReadyForReturnSince { get; set; }
|
||||
public long? ReadyForReturnSinceUnixEpoc
|
||||
{
|
||||
get
|
||||
{
|
||||
return ReadyForReturnSince.ToUnixEpoc();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAlert
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ReadyForReturn && (this.ReadyForReturnSince.Value < DateTime.Now.AddDays(-3)))
|
||||
return true;
|
||||
|
||||
if (this.WaitingForUserAction && (this.WaitingForUserActionSince.Value < DateTime.Now.AddDays(-6)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<HeldDeviceItem> FromJobs(IQueryable<Job> jobs)
|
||||
{
|
||||
return jobs.Select(j =>
|
||||
new HeldDeviceItem
|
||||
{
|
||||
JobId = j.Id,
|
||||
DeviceSerialNumber = j.DeviceSerialNumber,
|
||||
DeviceComputerName = j.Device.DeviceDomainId,
|
||||
DeviceLocation = j.Device.Location,
|
||||
DeviceProfileId = j.Device.DeviceProfileId,
|
||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
||||
UserId = j.Device.AssignedUserId,
|
||||
UserDisplayName = j.Device.AssignedUser.DisplayName,
|
||||
WaitingForUserAction = j.WaitingForUserAction.HasValue || ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue),
|
||||
WaitingForUserActionSince = j.WaitingForUserAction.HasValue ? j.WaitingForUserAction : (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue ? j.JobMetaNonWarranty.AccountingChargeRequiredDate : j.JobMetaNonWarranty.AccountingChargeAddedDate),
|
||||
ReadyForReturn = j.DeviceReadyForReturn.HasValue && !j.DeviceReturnedDate.HasValue,
|
||||
EstimatedReturnTime = j.ExpectedClosedDate,
|
||||
ReadyForReturnSince = j.DeviceReadyForReturn
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.Noticeboards;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
public static class HeldDevices
|
||||
{
|
||||
public const string Name = "HeldDevices";
|
||||
|
||||
private readonly static List<string> MonitorJobProperties = new List<string>() {
|
||||
"DeviceSerialNumber",
|
||||
"UserId",
|
||||
"ExpectedClosedDate",
|
||||
"ClosedDate",
|
||||
"WaitingForUserAction",
|
||||
"DeviceHeld",
|
||||
"DeviceReadyForReturn",
|
||||
"DeviceReturnedDate"
|
||||
};
|
||||
private readonly static List<string> MonitorJobMetaNonWarrantyProperties = new List<string>(){
|
||||
"AccountingChargeRequiredDate",
|
||||
"AccountingChargeAddedDate",
|
||||
"AccountingChargePaidDate"
|
||||
};
|
||||
private readonly static List<string> MonitorDeviceProperties = new List<string>(){
|
||||
"Location",
|
||||
"DeviceProfileId",
|
||||
"DeviceDomainId",
|
||||
"AssignedUserId",
|
||||
};
|
||||
private readonly static List<string> MonitorDeviceProfileProperties = new List<string>(){
|
||||
"DefaultOrganisationAddress"
|
||||
};
|
||||
private readonly static List<string> MonitorUserProperties = new List<string>(){
|
||||
"DisplayName"
|
||||
};
|
||||
|
||||
static HeldDevices()
|
||||
{
|
||||
// Subscribe to Repository Notifications
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
(e.EntityType == typeof(Job) &&
|
||||
(e.EventType == RepositoryMonitorEventType.Added ||
|
||||
e.EventType == RepositoryMonitorEventType.Deleted ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorJobProperties.Contains(p))))
|
||||
) ||
|
||||
(e.EntityType == typeof(JobMetaNonWarranty) &&
|
||||
(e.EventType == RepositoryMonitorEventType.Added ||
|
||||
e.EventType == RepositoryMonitorEventType.Deleted ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorJobMetaNonWarrantyProperties.Contains(p))))
|
||||
) ||
|
||||
(e.EntityType == typeof(Device) &&
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorDeviceProperties.Contains(p)))
|
||||
) ||
|
||||
(e.EntityType == typeof(DeviceProfile) &&
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorDeviceProfileProperties.Contains(p)))
|
||||
) ||
|
||||
(e.EntityType == typeof(User) &&
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Any(p => MonitorUserProperties.Contains(p)))
|
||||
)
|
||||
)
|
||||
.DelayBuffer(TimeSpan.FromMilliseconds(500))
|
||||
.Subscribe(RepositoryEvent);
|
||||
}
|
||||
|
||||
private static void RepositoryEvent(IEnumerable<RepositoryMonitorEvent> e)
|
||||
{
|
||||
List<string> deviceSerialNumbers = new List<string>();
|
||||
List<string> userIds = new List<string>();
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
{
|
||||
foreach (var i in e)
|
||||
{
|
||||
if (i.EntityType == typeof(Job))
|
||||
{
|
||||
if (i.EventType == RepositoryMonitorEventType.Modified &&
|
||||
i.ModifiedProperties.Contains("DeviceSerialNumber"))
|
||||
{
|
||||
var p = i.GetPreviousPropertyValue<string>("DeviceSerialNumber");
|
||||
if (p != null)
|
||||
deviceSerialNumbers.Add(p);
|
||||
}
|
||||
|
||||
var j = (Job)i.Entity;
|
||||
if (j.DeviceSerialNumber != null)
|
||||
deviceSerialNumbers.Add(j.DeviceSerialNumber);
|
||||
}
|
||||
else if (i.EntityType == typeof(JobMetaNonWarranty))
|
||||
{
|
||||
var jmnw = (JobMetaNonWarranty)i.Entity;
|
||||
|
||||
if (jmnw.Job != null)
|
||||
{
|
||||
if (jmnw.Job.DeviceSerialNumber != null)
|
||||
deviceSerialNumbers.Add(jmnw.Job.DeviceSerialNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sn = Database.Jobs.Where(j => j.Id == jmnw.JobId).Select(j => j.DeviceSerialNumber).FirstOrDefault();
|
||||
if (sn != null)
|
||||
deviceSerialNumbers.Add(sn);
|
||||
}
|
||||
}
|
||||
else if (i.EntityType == typeof(Device))
|
||||
{
|
||||
var d = (Device)i.Entity;
|
||||
deviceSerialNumbers.Add(d.SerialNumber);
|
||||
|
||||
if (i.EventType == RepositoryMonitorEventType.Modified &&
|
||||
i.ModifiedProperties.Contains("AssignedUserId"))
|
||||
{
|
||||
var p = i.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
if (p != null)
|
||||
userIds.Add(p);
|
||||
}
|
||||
}
|
||||
else if (i.EntityType == typeof(DeviceProfile))
|
||||
{
|
||||
var dp = (DeviceProfile)i.Entity;
|
||||
|
||||
deviceSerialNumbers.AddRange(
|
||||
Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.Device.DeviceProfileId == dp.Id)
|
||||
.Select(j => j.DeviceSerialNumber)
|
||||
);
|
||||
}
|
||||
else if (i.EntityType == typeof(User))
|
||||
{
|
||||
var u = (User)i.Entity;
|
||||
|
||||
deviceSerialNumbers.AddRange(
|
||||
Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.Device.AssignedUserId == u.UserId)
|
||||
.Select(j => j.DeviceSerialNumber)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
deviceSerialNumbers = deviceSerialNumbers.Distinct().ToList();
|
||||
|
||||
// Determine Held Devices for Users
|
||||
userIds.AddRange(
|
||||
Database.Devices
|
||||
.Where(d => d.AssignedUserId != null && deviceSerialNumbers.Contains(d.SerialNumber))
|
||||
.Select(d => d.AssignedUserId)
|
||||
);
|
||||
userIds = userIds.Distinct().ToList();
|
||||
|
||||
|
||||
// Notify Held Devices
|
||||
HeldDevices.BroadcastUpdates(Database, deviceSerialNumbers);
|
||||
|
||||
// Notify Held Devices for Users
|
||||
HeldDevicesForUsers.BroadcastUpdates(Database, userIds);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void BroadcastUpdates(DiscoDataContext Database, List<string> DeviceSerialNumbers)
|
||||
{
|
||||
var jobs = Database.Jobs.Where(j => DeviceSerialNumbers.Contains(j.DeviceSerialNumber));
|
||||
|
||||
var items = GetHeldDevices(jobs).ToDictionary(i => i.DeviceSerialNumber, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
for (int skipAmount = 0; skipAmount < DeviceSerialNumbers.Count; skipAmount = skipAmount + 30)
|
||||
{
|
||||
var updates = DeviceSerialNumbers
|
||||
.Skip(skipAmount).Take(30)
|
||||
.ToDictionary(dsn => dsn,
|
||||
dsn => {
|
||||
IHeldDeviceItem item;
|
||||
items.TryGetValue(dsn, out item);
|
||||
return item;
|
||||
});
|
||||
|
||||
NoticeboardUpdatesHub.HubContext.Clients
|
||||
.Group(HeldDevices.Name)
|
||||
.updateHeldDevice(updates);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IHeldDeviceItem> GetHeldDevices(IQueryable<Job> query)
|
||||
{
|
||||
var jobs = query
|
||||
.Where(j =>
|
||||
!j.ClosedDate.HasValue &&
|
||||
j.DeviceSerialNumber != null &&
|
||||
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
|
||||
)
|
||||
.SelectHeldDeviceItems()
|
||||
.GroupBy(j => j.DeviceSerialNumber);
|
||||
|
||||
foreach (var job in jobs.ToList())
|
||||
{
|
||||
if (job.Any(j => j.WaitingForUserAction))
|
||||
{
|
||||
var item = job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (job.All(j => j.ReadyForReturn))
|
||||
{
|
||||
var item = job.OrderByDescending(j => j.ReadyForReturnSince).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IHeldDeviceItem> GetHeldDevices(DiscoDataContext Database)
|
||||
{
|
||||
return GetHeldDevices(Database.Jobs);
|
||||
}
|
||||
public static IHeldDeviceItem GetHeldDevice(DiscoDataContext Database, string DeviceSerialNumber)
|
||||
{
|
||||
return GetHeldDevices(Database.Jobs.Where(j => j.DeviceSerialNumber == DeviceSerialNumber)).FirstOrDefault();
|
||||
}
|
||||
|
||||
internal static IEnumerable<HeldDeviceItem> SelectHeldDeviceItems(this IQueryable<Job> jobs)
|
||||
{
|
||||
return HeldDeviceItem.FromJobs(jobs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.Noticeboards;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
public class HeldDevicesForUsers
|
||||
{
|
||||
public const string Name = "HeldDevicesForUsers";
|
||||
|
||||
// NOTE: Calculation for updates is performed by HeldDevices to avoid duplication
|
||||
|
||||
internal static void BroadcastUpdates(DiscoDataContext Database, List<string> UserIds)
|
||||
{
|
||||
var jobs = Database.Devices.Where(d => UserIds.Contains(d.AssignedUserId)).SelectMany(d => d.Jobs);
|
||||
|
||||
var items = GetHeldDevicesForUsers(jobs).ToDictionary(i => i.UserId, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
for (int skipAmount = 0; skipAmount < UserIds.Count; skipAmount = skipAmount + 30)
|
||||
{
|
||||
var updates = UserIds
|
||||
.Skip(skipAmount).Take(30)
|
||||
.ToDictionary(userId => userId,
|
||||
userId =>
|
||||
{
|
||||
IHeldDeviceItem item;
|
||||
items.TryGetValue(userId, out item);
|
||||
return item;
|
||||
});
|
||||
|
||||
NoticeboardUpdatesHub.HubContext.Clients
|
||||
.Group(HeldDevicesForUsers.Name)
|
||||
.updateHeldDeviceForUser(updates);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IHeldDeviceItem> GetHeldDevicesForUsers(IQueryable<Job> query)
|
||||
{
|
||||
var jobs = query
|
||||
.Where(j =>
|
||||
!j.ClosedDate.HasValue &&
|
||||
j.DeviceSerialNumber != null &&
|
||||
j.Device.AssignedUserId != null &&
|
||||
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
|
||||
)
|
||||
.SelectHeldDeviceItems()
|
||||
.GroupBy(j => j.UserId);
|
||||
|
||||
foreach (var job in jobs.ToList())
|
||||
{
|
||||
if (job.Any(j => j.WaitingForUserAction))
|
||||
{
|
||||
var item = job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (job.All(j => j.ReadyForReturn))
|
||||
{
|
||||
var item = job.OrderByDescending(j => j.ReadyForReturnSince).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).First();
|
||||
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IHeldDeviceItem> GetHeldDevicesForUsers(DiscoDataContext Database)
|
||||
{
|
||||
return GetHeldDevicesForUsers(Database.Jobs);
|
||||
}
|
||||
public static IHeldDeviceItem GetHeldDeviceForUsers(DiscoDataContext Database, string UserId)
|
||||
{
|
||||
var split = UserExtensions.SplitUserId(UserId);
|
||||
if (split.Item1 == null)
|
||||
UserId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, UserId);
|
||||
|
||||
return GetHeldDevicesForUsers(Database.Devices.Where(d => d.AssignedUserId == UserId).SelectMany(d => d.Jobs)).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
[HubName("noticeboardUpdates")] // Public
|
||||
public class NoticeboardUpdatesHub : Hub
|
||||
{
|
||||
public static IHubContext HubContext { get; private set; }
|
||||
|
||||
static NoticeboardUpdatesHub()
|
||||
{
|
||||
HubContext = GlobalHost.ConnectionManager.GetHubContext<NoticeboardUpdatesHub>();
|
||||
}
|
||||
|
||||
public override Task OnConnected()
|
||||
{
|
||||
var noticeboardId = Context.QueryString["Noticeboard"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(noticeboardId))
|
||||
throw new ArgumentNullException("Noticeboard");
|
||||
|
||||
switch (noticeboardId)
|
||||
{
|
||||
case HeldDevicesForUsers.Name:
|
||||
Groups.Add(Context.ConnectionId, HeldDevicesForUsers.Name);
|
||||
break;
|
||||
case HeldDevices.Name:
|
||||
Groups.Add(Context.ConnectionId, HeldDevices.Name);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Invalid Noticeboard Specified", "Noticeboard");
|
||||
}
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ namespace Disco.Services.Logging
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitalizeDatabase(Targets.LogPersistContext LogDatabase)
|
||||
private static void InitalizeDatabase(Persistance.LogPersistContext LogDatabase)
|
||||
{
|
||||
// Add Modules
|
||||
var existingModules = LogDatabase.Modules.Include("EventTypes").ToDictionary(m => m.Id);
|
||||
@@ -183,7 +183,7 @@ namespace Disco.Services.Logging
|
||||
if (!File.Exists(logPath))
|
||||
{
|
||||
// Create Database
|
||||
using (var context = new Targets.LogPersistContext(connectionString))
|
||||
using (var context = new Persistance.LogPersistContext(connectionString))
|
||||
{
|
||||
context.Database.CreateIfNotExists();
|
||||
}
|
||||
@@ -191,7 +191,7 @@ namespace Disco.Services.Logging
|
||||
|
||||
// Add Modules/Event Types
|
||||
InitalizeModules();
|
||||
using (var context = new Targets.LogPersistContext(connectionString))
|
||||
using (var context = new Persistance.LogPersistContext(connectionString))
|
||||
{
|
||||
InitalizeDatabase(context);
|
||||
}
|
||||
@@ -211,7 +211,7 @@ namespace Disco.Services.Logging
|
||||
sqlCeCSB.DataSource = yesterdaysLogPath;
|
||||
var connectionString = sqlCeCSB.ToString();
|
||||
int logCount;
|
||||
using (var context = new Targets.LogPersistContext(connectionString))
|
||||
using (var context = new Persistance.LogPersistContext(connectionString))
|
||||
{
|
||||
logCount = context.Events.Where(e => !(e.ModuleId == 0 && e.EventTypeId == 100)).Count();
|
||||
if (logCount == 0)
|
||||
@@ -267,7 +267,7 @@ namespace Disco.Services.Logging
|
||||
var eventTimestamp = DateTime.Now;
|
||||
if (eventType.UseLive)
|
||||
{
|
||||
Targets.LogLiveContext.Broadcast(logModule, eventType, eventTimestamp, Args);
|
||||
LogNotificationsHub.BroadcastLog(logModule, eventType, eventTimestamp, Args);
|
||||
}
|
||||
if (eventType.UsePersist)
|
||||
{
|
||||
@@ -276,7 +276,7 @@ namespace Disco.Services.Logging
|
||||
{
|
||||
args = JsonConvert.SerializeObject(Args);
|
||||
}
|
||||
using (var context = new Targets.LogPersistContext(PersistantStoreConnectionString))
|
||||
using (var context = new Persistance.LogPersistContext(PersistantStoreConnectionString))
|
||||
{
|
||||
var e = new Models.LogEvent()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Logging.Models;
|
||||
using Disco.Services.Web.Signalling;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Logging
|
||||
{
|
||||
[HubName("logNotifications"), DiscoHubAuthorize(Claims.Config.Logging.Show)]
|
||||
public class LogNotificationsHub : Hub
|
||||
{
|
||||
private const string NotificationsModulePrefix = "Logging_";
|
||||
public const string AllLoggingNotification = NotificationsModulePrefix + "_ALL";
|
||||
|
||||
public override Task OnConnected()
|
||||
{
|
||||
var logModules = Context.QueryString["LogModules"];
|
||||
if (!string.IsNullOrWhiteSpace(logModules) && logModules.Length > 0)
|
||||
{
|
||||
foreach (var modules in ValidLogModuleGroupNames(logModules))
|
||||
Groups.Add(Context.ConnectionId, modules);
|
||||
}
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
|
||||
internal static void BroadcastLog(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments)
|
||||
{
|
||||
var message = LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
|
||||
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var context = connectionManager.GetHubContext<LogNotificationsHub>();
|
||||
var targets = new List<string> { AllLoggingNotification, NotificationsModulePrefix + logModule.ModuleName };
|
||||
context.Clients.Groups(targets).receiveLog(message);
|
||||
}
|
||||
|
||||
private IEnumerable<string> ValidLogModuleGroupNames(string ModuleNames)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ModuleNames))
|
||||
yield break;
|
||||
|
||||
var names = ModuleNames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var name in names)
|
||||
{
|
||||
// Special Case: __ALL
|
||||
if (name.Equals(AllLoggingNotification, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
yield return AllLoggingNotification;
|
||||
}
|
||||
else
|
||||
{
|
||||
var module = LogContext.LogModules.Values.FirstOrDefault(m => m.ModuleName.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (module == null)
|
||||
throw new ArgumentException(string.Format("Invalid Module Name specified: {0}", name), "ModuleNames");
|
||||
|
||||
yield return NotificationsModulePrefix + module.ModuleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Data.Entity;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
|
||||
namespace Disco.Services.Logging.Targets
|
||||
namespace Disco.Services.Logging.Persistance
|
||||
{
|
||||
public class LogPersistContext : DbContext
|
||||
{
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Logging.Targets
|
||||
namespace Disco.Services.Logging.Persistance
|
||||
{
|
||||
public class LogPersistContextInitializer : IDatabaseInitializer<LogPersistContext>
|
||||
{
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Services.Logging.Targets;
|
||||
using Disco.Data.Repository;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Data.SqlServerCe;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Logging.Models;
|
||||
using Disco.Services.Logging.Persistance;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Disco.Services.Logging
|
||||
{
|
||||
@@ -45,7 +44,7 @@ namespace Disco.Services.Logging
|
||||
|
||||
var logModules = LogContext.LogModules;
|
||||
|
||||
using (var context = new Targets.LogPersistContext(sqlCeCSB.ToString()))
|
||||
using (var context = new LogPersistContext(sqlCeCSB.ToString()))
|
||||
{
|
||||
var query = this.BuildQuery(context, logFile.Item2, results.Count);
|
||||
IEnumerable<LogEvent> queryResults = query; // Run the Query
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using Disco.Services.Logging.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Logging.Targets
|
||||
{
|
||||
public static class LogLiveContext
|
||||
{
|
||||
public delegate void LogBroadcastEvent(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments);
|
||||
public static event LogBroadcastEvent LogBroadcast;
|
||||
|
||||
internal static void Broadcast(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments)
|
||||
{
|
||||
if (LogBroadcast != null)
|
||||
LogBroadcast.Invoke(logModule, eventType, Timestamp, Arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,11 @@ namespace Disco.Services.Plugins.Features.UIExtension.Results
|
||||
this._resource = Resource;
|
||||
this._resourceUrl = Source.PluginManifest.WebResourceUrl(Resource);
|
||||
|
||||
var deferredBundles = HttpContext.Current.Items[Bundle.UIExtensionCssKey] as List<string>;
|
||||
var deferredBundles = HttpContext.Current.Items[BundleTable.UIExtensionCssKey] as List<string>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<string>();
|
||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
||||
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(this._resourceUrl))
|
||||
deferredBundles.Add(this._resourceUrl);
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace Disco.Services.Plugins.Features.UIExtension.Results
|
||||
|
||||
if (this._placeInPageHead)
|
||||
{
|
||||
var deferredBundles = HttpContext.Current.Items[Bundle.UIExtensionScriptsKey] as List<string>;
|
||||
var deferredBundles = HttpContext.Current.Items[BundleTable.UIExtensionScriptsKey] as List<string>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<string>();
|
||||
HttpContext.Current.Items[Bundle.UIExtensionScriptsKey] = deferredBundles;
|
||||
HttpContext.Current.Items[BundleTable.UIExtensionScriptsKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(this._resourceUrl))
|
||||
deferredBundles.Add(this._resourceUrl);
|
||||
|
||||
@@ -97,12 +97,12 @@ namespace Disco.Services.Plugins
|
||||
public static void IncludeStyleSheetResource(this HttpContextBase Context, string Resource, PluginManifest manifest)
|
||||
{
|
||||
var resourceUrl = manifest.WebResourceUrl(Resource);
|
||||
|
||||
var deferredBundles = Context.Items[Bundle.UIExtensionCssKey] as List<string>;
|
||||
|
||||
var deferredBundles = Context.Items[BundleTable.UIExtensionCssKey] as List<string>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<string>();
|
||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
||||
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(resourceUrl))
|
||||
deferredBundles.Add(resourceUrl);
|
||||
@@ -111,11 +111,11 @@ namespace Disco.Services.Plugins
|
||||
{
|
||||
var resourcePath = manifest.WebResourceUrl(Resource);
|
||||
|
||||
var deferredBundles = Context.Items[Bundle.UIExtensionScriptsKey] as List<string>;
|
||||
var deferredBundles = Context.Items[BundleTable.UIExtensionScriptsKey] as List<string>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<string>();
|
||||
HttpContext.Current.Items[Bundle.UIExtensionScriptsKey] = deferredBundles;
|
||||
HttpContext.Current.Items[BundleTable.UIExtensionScriptsKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(resourcePath))
|
||||
deferredBundles.Add(resourcePath);
|
||||
@@ -223,7 +223,9 @@ namespace Disco.Services.Plugins
|
||||
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, PluginAction = PluginAction });
|
||||
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
|
||||
|
||||
#pragma warning disable 618
|
||||
return ViewPage.FormHelper(pluginActionUrl, method, htmlAttributes);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
[Obsolete("Inherit ViewPages from 'Disco.Services.Plugins.WebViewPage' instead.")]
|
||||
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction, FormMethod method)
|
||||
@@ -302,11 +304,11 @@ namespace Disco.Services.Plugins
|
||||
|
||||
HtmlString pluginResourceUrlHtml = new HtmlString(pluginResourceUrl);
|
||||
|
||||
var deferredBundles = RequestContext.HttpContext.Items[Bundle.UIExtensionCssKey] as List<HtmlString>;
|
||||
var deferredBundles = RequestContext.HttpContext.Items[BundleTable.UIExtensionCssKey] as List<HtmlString>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<HtmlString>();
|
||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
||||
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(pluginResourceUrlHtml))
|
||||
deferredBundles.Add(pluginResourceUrlHtml);
|
||||
|
||||
+19
-1
@@ -6,12 +6,22 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Tasks
|
||||
{
|
||||
public interface IScheduledTaskBasicStatus
|
||||
public interface IScheduledTaskStatus
|
||||
{
|
||||
byte Progress { get; }
|
||||
string CurrentProcess { get; }
|
||||
string CurrentDescription { get; }
|
||||
|
||||
bool IgnoreCurrentProcessChanges { get; set; }
|
||||
bool IgnoreCurrentDescription { get; set; }
|
||||
double ProgressMultiplier { get; set; }
|
||||
byte ProgressOffset { get; set; }
|
||||
|
||||
string FinishedMessage { get; }
|
||||
string FinishedUrl { get; }
|
||||
|
||||
Exception TaskException { get; }
|
||||
|
||||
void UpdateStatus(byte Progress);
|
||||
void UpdateStatus(double Progress);
|
||||
void UpdateStatus(string CurrentDescription);
|
||||
@@ -19,5 +29,13 @@ namespace Disco.Services.Tasks
|
||||
void UpdateStatus(double Progress, string CurrentDescription);
|
||||
void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription);
|
||||
void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription);
|
||||
|
||||
void SetFinishedUrl(string FinishedUrl);
|
||||
void SetFinishedMessage(string FinishedMessage);
|
||||
void Finished();
|
||||
void Finished(string FinishedMessage);
|
||||
void Finished(string FinishedMessage, string FinishedUrl);
|
||||
|
||||
void SetTaskException(Exception TaskException);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ namespace Disco.Services.Tasks
|
||||
|
||||
public virtual bool CancelInitiallySupported { get { return true; } }
|
||||
public virtual bool SingleInstanceTask { get { return true; } }
|
||||
public virtual bool IsSilent { get { return false; } }
|
||||
public virtual bool LogExceptionsOnly { get { return false; } }
|
||||
|
||||
public abstract string TaskName { get; }
|
||||
protected abstract void ExecuteTask();
|
||||
|
||||
|
||||
@@ -6,19 +6,30 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Tasks
|
||||
{
|
||||
public class ScheduledTaskMockStatus : IScheduledTaskBasicStatus
|
||||
public class ScheduledTaskMockStatus : IScheduledTaskStatus
|
||||
{
|
||||
private byte progress;
|
||||
private string currentProcess;
|
||||
private string currentDescription;
|
||||
public byte Progress { get; set; }
|
||||
public string CurrentProcess { get; set; }
|
||||
public string CurrentDescription { get; set; }
|
||||
|
||||
public byte Progress { get { return this.progress; } }
|
||||
public string CurrentProcess { get { return this.currentProcess; } }
|
||||
public string CurrentDescription { get { return this.currentDescription; } }
|
||||
public bool IgnoreCurrentProcessChanges { get; set; }
|
||||
public bool IgnoreCurrentDescription { get; set; }
|
||||
public double ProgressMultiplier { get; set; }
|
||||
public byte ProgressOffset { get; set; }
|
||||
|
||||
public string FinishedMessage { get; set; }
|
||||
public string FinishedUrl { get; set; }
|
||||
|
||||
public Exception TaskException { get; set; }
|
||||
|
||||
private byte CalculateProgressValue(byte Progress)
|
||||
{
|
||||
return (byte)((Progress * this.ProgressMultiplier) + this.ProgressOffset);
|
||||
}
|
||||
|
||||
public void UpdateStatus(byte Progress)
|
||||
{
|
||||
this.progress = Progress;
|
||||
this.Progress = CalculateProgressValue(Progress);
|
||||
}
|
||||
public void UpdateStatus(double Progress)
|
||||
{
|
||||
@@ -26,12 +37,14 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
public void UpdateStatus(string CurrentDescription)
|
||||
{
|
||||
this.currentDescription = CurrentDescription;
|
||||
if (!IgnoreCurrentDescription)
|
||||
this.CurrentDescription = CurrentDescription;
|
||||
}
|
||||
public void UpdateStatus(byte Progress, string CurrentDescription)
|
||||
{
|
||||
this.progress = Progress;
|
||||
this.currentDescription = CurrentDescription;
|
||||
this.Progress = CalculateProgressValue(Progress);
|
||||
if (!IgnoreCurrentDescription)
|
||||
this.CurrentDescription = CurrentDescription;
|
||||
}
|
||||
public void UpdateStatus(double Progress, string CurrentDescription)
|
||||
{
|
||||
@@ -39,15 +52,46 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
|
||||
{
|
||||
this.progress = Progress;
|
||||
this.currentProcess = CurrentProcess;
|
||||
this.currentDescription = CurrentDescription;
|
||||
this.Progress = CalculateProgressValue(Progress);
|
||||
if (!IgnoreCurrentProcessChanges)
|
||||
this.CurrentProcess = CurrentProcess;
|
||||
if (!IgnoreCurrentDescription)
|
||||
this.CurrentDescription = CurrentDescription;
|
||||
}
|
||||
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
|
||||
{
|
||||
UpdateStatus((byte)Progress, CurrentProcess, CurrentDescription);
|
||||
}
|
||||
|
||||
public void SetFinishedUrl(string FinishedUrl)
|
||||
{
|
||||
this.FinishedUrl = FinishedUrl;
|
||||
}
|
||||
public void SetFinishedMessage(string FinishedMessage)
|
||||
{
|
||||
this.FinishedMessage = FinishedMessage;
|
||||
}
|
||||
public void Finished()
|
||||
{
|
||||
Finished(this.FinishedMessage, this.FinishedUrl);
|
||||
}
|
||||
public void Finished(string FinishedMessage)
|
||||
{
|
||||
Finished(FinishedMessage, this.FinishedUrl);
|
||||
}
|
||||
public void Finished(string FinishedMessage, string FinishedUrl)
|
||||
{
|
||||
this.FinishedMessage = FinishedMessage;
|
||||
this.FinishedUrl = FinishedUrl;
|
||||
}
|
||||
|
||||
public void SetTaskException(Exception TaskException)
|
||||
{
|
||||
this.TaskException = TaskException;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ScheduledTaskMockStatus Create()
|
||||
{
|
||||
return new ScheduledTaskMockStatus();
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using Disco.Services.Web.Signalling;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Linq;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Tasks
|
||||
{
|
||||
using System.Reactive.Subjects;
|
||||
using ChangedItem = KeyValuePair<string, object>;
|
||||
|
||||
[HubName("scheduledTaskNotifications"), DiscoHubAuthorize()]
|
||||
public class ScheduledTaskNotificationsHub : Hub
|
||||
{
|
||||
private const string NotificationsPrefix = "Logging_";
|
||||
private static Subject<Tuple<string, IEnumerable<ChangedItem>>> taskUpdatesStream = new Subject<Tuple<string, IEnumerable<ChangedItem>>>();
|
||||
private static IDisposable taskUpdatesStreamSubscription;
|
||||
|
||||
internal static void Initialize()
|
||||
{
|
||||
if (taskUpdatesStreamSubscription == null)
|
||||
{
|
||||
lock (taskUpdatesStream)
|
||||
{
|
||||
if (taskUpdatesStreamSubscription == null)
|
||||
{
|
||||
taskUpdatesStreamSubscription = taskUpdatesStream
|
||||
.DelayBuffer(TimeSpan.FromMilliseconds(200))
|
||||
.Subscribe(BroadcastBufferedEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PublishEvent(string TaskSessionId, IEnumerable<ChangedItem> ChangedItems)
|
||||
{
|
||||
taskUpdatesStream.OnNext(Tuple.Create(TaskSessionId, ChangedItems));
|
||||
}
|
||||
|
||||
public override System.Threading.Tasks.Task OnConnected()
|
||||
{
|
||||
var taskSessionId = Context.QueryString["TaskSessionId"];
|
||||
|
||||
if (string.IsNullOrEmpty(taskSessionId))
|
||||
throw new ArgumentNullException("TaskSessionId");
|
||||
|
||||
var status = ScheduledTasks.GetTaskStatus(taskSessionId);
|
||||
|
||||
if (status == null)
|
||||
throw new ArgumentException("Invalid ScheduledTask SessionId", "TaskSessionId");
|
||||
|
||||
// Send Status:
|
||||
var currentStatus = ScheduledTaskStatusLive.FromScheduledTaskStatus(status, null);
|
||||
Clients.Caller.initializeTaskStatus(currentStatus);
|
||||
|
||||
// Add to Group
|
||||
var groupName = NotificationsPrefix + taskSessionId;
|
||||
Groups.Add(Context.ConnectionId, groupName);
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
|
||||
private static void BroadcastBufferedEvents(IEnumerable<Tuple<string, IEnumerable<ChangedItem>>> Events)
|
||||
{
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var context = connectionManager.GetHubContext<ScheduledTaskNotificationsHub>();
|
||||
|
||||
var taskStatusEvents = Events.GroupBy(e => e.Item1).Select(taskEventsGroup =>
|
||||
{
|
||||
Dictionary<string, object> changes = new Dictionary<string, object>();
|
||||
|
||||
foreach (var changeEvents in taskEventsGroup.Select(taskEvents => taskEvents.Item2))
|
||||
foreach (var changeEvent in changeEvents)
|
||||
changes[changeEvent.Key] = changeEvent.Value;
|
||||
|
||||
return Tuple.Create(taskEventsGroup.Key, changes);
|
||||
});
|
||||
|
||||
foreach (var taskStatusEvent in taskStatusEvents)
|
||||
{
|
||||
var groupName = NotificationsPrefix + taskStatusEvent.Item1;
|
||||
context.Clients.Group(groupName).updateTaskStatus(taskStatusEvent.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Tasks
|
||||
{
|
||||
public class ScheduledTaskStatus : IScheduledTaskBasicStatus
|
||||
using ChangedItem = KeyValuePair<string, object>;
|
||||
|
||||
public class ScheduledTaskStatus : IScheduledTaskStatus
|
||||
{
|
||||
#region Backing Fields
|
||||
|
||||
@@ -52,6 +54,11 @@ namespace Disco.Services.Tasks
|
||||
public string CurrentProcess { get { return this._currentProcess; } }
|
||||
public string CurrentDescription { get { return this._currentDescription; } }
|
||||
|
||||
public bool IgnoreCurrentProcessChanges { get; set; }
|
||||
public bool IgnoreCurrentDescription { get; set; }
|
||||
public double ProgressMultiplier { get; set; }
|
||||
public byte ProgressOffset { get; set; }
|
||||
|
||||
public Exception TaskException { get { return this._taskException; } }
|
||||
public bool CancelSupported { get { return this._cancelSupported; } }
|
||||
public bool IsCanceling { get { return this._isCanceling; } }
|
||||
@@ -73,21 +80,13 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public Task CompletionTask
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tcs.Task;
|
||||
}
|
||||
}
|
||||
public Task CompletionTask { get { return _tcs.Task; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public delegate void UpdatedBroadcastEvent(ScheduledTaskStatusLive SessionStatus);
|
||||
public delegate void UpdatedEvent(ScheduledTaskStatus sender, string[] ChangedProperties);
|
||||
public delegate void UpdatedEvent(ScheduledTaskStatus sender, KeyValuePair<string, object>[] ChangedProperties);
|
||||
public delegate void CancelingEvent(ScheduledTaskStatus sender);
|
||||
public static event UpdatedBroadcastEvent UpdatedBroadcast;
|
||||
public event UpdatedEvent Updated;
|
||||
public event CancelingEvent Canceling;
|
||||
#endregion
|
||||
@@ -112,10 +111,15 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
|
||||
#region Progress Actions
|
||||
private byte CalculateProgressValue(byte Progress)
|
||||
{
|
||||
return (byte)((Progress * this.ProgressMultiplier) + this.ProgressOffset);
|
||||
}
|
||||
|
||||
public void UpdateStatus(byte Progress)
|
||||
{
|
||||
this._progress = Progress;
|
||||
UpdateTriggered(new string[] { "Progress" });
|
||||
this._progress = CalculateProgressValue(Progress);
|
||||
UpdateTriggered("Progress", this._progress);
|
||||
}
|
||||
public void UpdateStatus(double Progress)
|
||||
{
|
||||
@@ -123,14 +127,27 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
public void UpdateStatus(string CurrentDescription)
|
||||
{
|
||||
this._currentDescription = CurrentDescription;
|
||||
UpdateTriggered(new string[] { "CurrentDescription" });
|
||||
if (!IgnoreCurrentDescription)
|
||||
{
|
||||
this._currentDescription = CurrentDescription;
|
||||
UpdateTriggered("CurrentDescription", this._currentDescription);
|
||||
}
|
||||
}
|
||||
public void UpdateStatus(byte Progress, string CurrentDescription)
|
||||
{
|
||||
this._progress = Progress;
|
||||
this._currentDescription = CurrentDescription;
|
||||
UpdateTriggered(new string[] { "Progress", "CurrentDescription" });
|
||||
this._progress = CalculateProgressValue(Progress);
|
||||
|
||||
var changedProperties = new List<ChangedItem>() {
|
||||
new ChangedItem("Progress", Progress)
|
||||
};
|
||||
|
||||
if (!IgnoreCurrentDescription)
|
||||
{
|
||||
this._currentDescription = CurrentDescription;
|
||||
changedProperties.Add(new ChangedItem("CurrentDescription", CurrentDescription));
|
||||
}
|
||||
|
||||
UpdateTriggered(changedProperties.ToArray());
|
||||
}
|
||||
public void UpdateStatus(double Progress, string CurrentDescription)
|
||||
{
|
||||
@@ -138,10 +155,24 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
|
||||
{
|
||||
this._progress = Progress;
|
||||
this._currentProcess = CurrentProcess;
|
||||
this._currentDescription = CurrentDescription;
|
||||
UpdateTriggered(new string[] { "Progress", "CurrentProcess", "CurrentDescription" });
|
||||
this._progress = CalculateProgressValue(Progress);
|
||||
|
||||
var changedProperties = new List<ChangedItem>() {
|
||||
new ChangedItem("Progress", Progress)
|
||||
};
|
||||
|
||||
if (!IgnoreCurrentProcessChanges)
|
||||
{
|
||||
this._currentProcess = CurrentProcess;
|
||||
changedProperties.Add(new ChangedItem("CurrentProcess", CurrentProcess));
|
||||
}
|
||||
if (!IgnoreCurrentDescription)
|
||||
{
|
||||
this._currentDescription = CurrentDescription;
|
||||
changedProperties.Add(new ChangedItem("CurrentDescription", CurrentDescription));
|
||||
}
|
||||
|
||||
UpdateTriggered(changedProperties.ToArray());
|
||||
}
|
||||
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
|
||||
{
|
||||
@@ -157,7 +188,7 @@ namespace Disco.Services.Tasks
|
||||
if (_cancelSupported)
|
||||
{ // Cancelling
|
||||
this._isCanceling = true;
|
||||
UpdateTriggered(new string[] { "IsCancelling" });
|
||||
UpdateTriggered("IsCancelling", true);
|
||||
if (this.Canceling != null)
|
||||
Canceling(this);
|
||||
return true;
|
||||
@@ -177,7 +208,7 @@ namespace Disco.Services.Tasks
|
||||
if (this._cancelSupported != CancelSupported)
|
||||
{
|
||||
this._cancelSupported = CancelSupported;
|
||||
UpdateTriggered(new string[] { "CancelSupported" });
|
||||
UpdateTriggered("CancelSupported", CancelSupported);
|
||||
}
|
||||
}
|
||||
public void SetTaskException(Exception TaskException)
|
||||
@@ -185,7 +216,7 @@ namespace Disco.Services.Tasks
|
||||
if (this._taskException != TaskException)
|
||||
{
|
||||
this._taskException = TaskException;
|
||||
UpdateTriggered(new string[] { "TaskException" });
|
||||
UpdateTriggered("TaskExceptionMessage", (this._taskException == null ? null : this._taskException.Message));
|
||||
}
|
||||
}
|
||||
public void SetIsSilent(bool IsSilent)
|
||||
@@ -198,7 +229,7 @@ namespace Disco.Services.Tasks
|
||||
if (this._finishedUrl != FinishedUrl)
|
||||
{
|
||||
this._finishedUrl = FinishedUrl;
|
||||
UpdateTriggered(new string[] { "FinishedUrl" });
|
||||
UpdateTriggered("FinishedUrl", FinishedUrl);
|
||||
}
|
||||
}
|
||||
public void SetFinishedMessage(string FinishedMessage)
|
||||
@@ -206,7 +237,7 @@ namespace Disco.Services.Tasks
|
||||
if (this._finishedMessage != FinishedMessage)
|
||||
{
|
||||
this._finishedMessage = FinishedMessage;
|
||||
UpdateTriggered(new string[] { "FinishedMessage" });
|
||||
UpdateTriggered("FinishedMessage", FinishedMessage);
|
||||
}
|
||||
}
|
||||
public void SetNextScheduledTimestamp(DateTime? NextScheduledTimestamp)
|
||||
@@ -214,59 +245,62 @@ namespace Disco.Services.Tasks
|
||||
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
||||
{
|
||||
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
||||
UpdateTriggered(new string[] { "NextScheduledTimestamp" });
|
||||
UpdateTriggered("NextScheduledTimestamp", NextScheduledTimestamp);
|
||||
}
|
||||
}
|
||||
public void Started()
|
||||
{
|
||||
List<string> changedProperties = new List<string>() { "IsRunning", "StartedTimestamp" };
|
||||
var changedProperties = new List<ChangedItem>();
|
||||
|
||||
// Change StartedTimestamp
|
||||
this._startedTimestamp = DateTime.Now;
|
||||
changedProperties.Add(new ChangedItem("StartedTimestamp", this.StartedTimestamp));
|
||||
|
||||
if (this._finishedTimestamp != null)
|
||||
{
|
||||
this._finishedTimestamp = null;
|
||||
changedProperties.Add(new ChangedItem("FinishedTimestamp", this._finishedTimestamp));
|
||||
}
|
||||
|
||||
if (this._nextScheduledTimestamp != null)
|
||||
{
|
||||
this._nextScheduledTimestamp = null;
|
||||
changedProperties.Add("NextScheduledTimestamp");
|
||||
}
|
||||
if (this._finishedTimestamp != null)
|
||||
{
|
||||
this._finishedTimestamp = null;
|
||||
changedProperties.Add("FinishedTimestamp");
|
||||
changedProperties.Add(new ChangedItem("NextScheduledTimestamp", this._nextScheduledTimestamp));
|
||||
}
|
||||
|
||||
changedProperties.Add(new ChangedItem("IsRunning", this.IsRunning));
|
||||
|
||||
if (this._progress != 0)
|
||||
{
|
||||
this._progress = 0;
|
||||
changedProperties.Add("Progress");
|
||||
changedProperties.Add(new ChangedItem("Progress", this._progress));
|
||||
}
|
||||
if (this._currentProcess != "Starting")
|
||||
{
|
||||
this._currentProcess = "Starting";
|
||||
changedProperties.Add("CurrentProcess");
|
||||
changedProperties.Add(new ChangedItem("CurrentProcess", this._currentProcess));
|
||||
}
|
||||
if (this._currentDescription != "Initializing Task for Execution")
|
||||
{
|
||||
this._currentDescription = "Initializing Task for Execution";
|
||||
changedProperties.Add("CurrentDescription");
|
||||
changedProperties.Add(new ChangedItem("CurrentDescription", this._currentDescription));
|
||||
}
|
||||
if (this._taskException != null)
|
||||
{
|
||||
this._taskException = null;
|
||||
changedProperties.Add("TaskException");
|
||||
changedProperties.Add(new ChangedItem("TaskExceptionMessage", (this._taskException == null ? null : this._taskException.Message)));
|
||||
}
|
||||
if (this._cancelSupported != this._cancelInitiallySupported)
|
||||
{
|
||||
this._cancelSupported = this._cancelInitiallySupported;
|
||||
changedProperties.Add("CancelSupported");
|
||||
}
|
||||
{
|
||||
this._isCanceling = false;
|
||||
changedProperties.Add("IsCanceling");
|
||||
changedProperties.Add(new ChangedItem("CancelSupported", this._cancelSupported));
|
||||
}
|
||||
if (this._isCanceling)
|
||||
{
|
||||
this._isCanceling = false;
|
||||
changedProperties.Add("IsCanceling");
|
||||
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||
}
|
||||
|
||||
UpdateTriggered(changedProperties.ToArray());
|
||||
}
|
||||
public void Finished()
|
||||
@@ -279,26 +313,29 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
public void Finished(string FinishedMessage, string FinishedUrl)
|
||||
{
|
||||
List<string> changedProperties = new List<string>() { "IsRunning", "FinishedTimestamp" };
|
||||
var changedProperties = new List<ChangedItem>();
|
||||
|
||||
this._finishedTimestamp = DateTime.Now;
|
||||
changedProperties.Add(new ChangedItem("FinishedTimestamp", this._finishedTimestamp));
|
||||
changedProperties.Add(new ChangedItem("IsRunning", this.IsRunning));
|
||||
|
||||
if (FinishedMessage != this._finishedMessage)
|
||||
{
|
||||
this._finishedMessage = FinishedMessage;
|
||||
changedProperties.Add("FinishedMessage");
|
||||
changedProperties.Add(new ChangedItem("FinishedMessage", this._finishedMessage));
|
||||
}
|
||||
if (FinishedUrl != this._finishedUrl)
|
||||
{
|
||||
this._finishedUrl = FinishedUrl;
|
||||
changedProperties.Add("FinishedUrl");
|
||||
changedProperties.Add(new ChangedItem("FinishedUrl", this._finishedUrl));
|
||||
}
|
||||
|
||||
if (this._isCanceling)
|
||||
{
|
||||
this._isCanceling = false;
|
||||
changedProperties.Add("IsCanceling");
|
||||
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||
}
|
||||
|
||||
UpdateTriggered(changedProperties.ToArray());
|
||||
}
|
||||
internal void Finally()
|
||||
@@ -311,53 +348,58 @@ namespace Disco.Services.Tasks
|
||||
this._tcs.Task.Dispose();
|
||||
this._tcs = new TaskCompletionSource<ScheduledTaskStatus>();
|
||||
|
||||
List<string> changedProperties = new List<string>();
|
||||
var changedProperties = new List<ChangedItem>();
|
||||
|
||||
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
||||
{
|
||||
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
||||
changedProperties.Add("NextScheduledTimestamp");
|
||||
changedProperties.Add(new ChangedItem("NextScheduledTimestamp", this._nextScheduledTimestamp));
|
||||
}
|
||||
|
||||
if (this._startedTimestamp != null)
|
||||
{
|
||||
this._startedTimestamp = null;
|
||||
changedProperties.Add("StartedTimestamp");
|
||||
changedProperties.Add(new ChangedItem("StartedTimestamp", this._startedTimestamp));
|
||||
}
|
||||
if (this._finishedTimestamp != null)
|
||||
{
|
||||
this._finishedTimestamp = null;
|
||||
changedProperties.Add("FinishedTimestamp");
|
||||
changedProperties.Add(new ChangedItem("FinishedTimestamp", this._finishedTimestamp));
|
||||
}
|
||||
if (this._finishedMessage != null)
|
||||
{
|
||||
this._finishedMessage = null;
|
||||
changedProperties.Add("FinishedMessage");
|
||||
changedProperties.Add(new ChangedItem("FinishedMessage", this._finishedMessage));
|
||||
}
|
||||
if (this._finishedUrl != null)
|
||||
{
|
||||
this._finishedUrl = null;
|
||||
changedProperties.Add("FinishedUrl");
|
||||
changedProperties.Add(new ChangedItem("FinishedUrl", this._finishedUrl));
|
||||
}
|
||||
if (this._progress != 0)
|
||||
{
|
||||
this._progress = 0;
|
||||
changedProperties.Add("Progress");
|
||||
changedProperties.Add(new ChangedItem("Progress", this._progress));
|
||||
}
|
||||
this.ProgressMultiplier = 0;
|
||||
this.ProgressOffset = 0;
|
||||
this.IgnoreCurrentDescription = false;
|
||||
this.IgnoreCurrentProcessChanges = false;
|
||||
|
||||
if (this._currentProcess != "Scheduled")
|
||||
{
|
||||
this._currentProcess = "Scheduled";
|
||||
changedProperties.Add("CurrentProcess");
|
||||
changedProperties.Add(new ChangedItem("CurrentProcess", this._currentProcess));
|
||||
}
|
||||
if (this._currentDescription != "Scheduled Task for Execution")
|
||||
{
|
||||
this._currentDescription = "Scheduled Task for Execution";
|
||||
changedProperties.Add("CurrentDescription");
|
||||
changedProperties.Add(new ChangedItem("CurrentDescription", this._currentDescription));
|
||||
}
|
||||
if (this._isCanceling)
|
||||
{
|
||||
this._isCanceling = false;
|
||||
changedProperties.Add("IsCanceling");
|
||||
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||
}
|
||||
UpdateTriggered(changedProperties.ToArray());
|
||||
}
|
||||
@@ -373,15 +415,20 @@ namespace Disco.Services.Tasks
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void UpdateTriggered(string[] ChangedProperties)
|
||||
private void UpdateTriggered(string ChangedProperty, object NewValue)
|
||||
{
|
||||
UpdateTriggered(new ChangedItem[] { new ChangedItem(ChangedProperty, NewValue) });
|
||||
}
|
||||
|
||||
private void UpdateTriggered(params ChangedItem[] ChangedProperties)
|
||||
{
|
||||
this._statusVersion++;
|
||||
|
||||
if (Updated != null)
|
||||
Updated(this, ChangedProperties);
|
||||
|
||||
if (!_isSilent && UpdatedBroadcast != null)
|
||||
UpdatedBroadcast.Invoke(ScheduledTaskStatusLive.FromScheduledTaskStatus(this, ChangedProperties));
|
||||
if (!_isSilent)
|
||||
ScheduledTaskNotificationsHub.PublishEvent(this.SessionId, ChangedProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,16 @@ namespace Disco.Services.Tasks
|
||||
// Scheduled Cleanup
|
||||
ScheduledTaskCleanup.Schedule(_TaskScheduler);
|
||||
|
||||
ScheduledTaskNotificationsHub.Initialize();
|
||||
|
||||
if (InitiallySchedule)
|
||||
{
|
||||
// Discover DiscoScheduledTask
|
||||
var appDomain = AppDomain.CurrentDomain;
|
||||
var scheduledTasksHostAssemblyName = typeof(ScheduledTask).Assembly.GetName().Name;
|
||||
|
||||
var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
|
||||
where !a.GlobalAssemblyCache && !a.IsDynamic
|
||||
where !a.GlobalAssemblyCache && !a.IsDynamic && a.GetReferencedAssemblies().Any(ra => ra.Name == scheduledTasksHostAssemblyName)
|
||||
from type in a.GetTypes()
|
||||
where typeof(ScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
||||
select type);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services
|
||||
{
|
||||
@@ -15,6 +11,11 @@ namespace Disco.Services
|
||||
return u.Domain.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string ToStringFriendly(this User u)
|
||||
{
|
||||
return string.Format("{0} ({1})", u.DisplayName, u.FriendlyId());
|
||||
}
|
||||
|
||||
public static string FriendlyId(this User u)
|
||||
{
|
||||
return FriendlyUserId(u.UserId);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Web.Signalling;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.Services.Users
|
||||
{
|
||||
[HubName("userUpdates"), DiscoHubAuthorizeAll(Claims.User.Show, Claims.User.ShowAttachments)]
|
||||
public class UserUpdatesHub : Hub
|
||||
{
|
||||
private const string UserPrefix = "User_";
|
||||
public static IHubContext HubContext { get; private set; }
|
||||
|
||||
private static IDisposable RepositoryBeforeSubscription;
|
||||
private static IDisposable RepositoryAfterSubscription;
|
||||
|
||||
static UserUpdatesHub()
|
||||
{
|
||||
HubContext = GlobalHost.ConnectionManager.GetHubContext<UserUpdatesHub>();
|
||||
|
||||
// Subscribe to Repository Monitor for Changes
|
||||
RepositoryBeforeSubscription = RepositoryMonitor.StreamBeforeCommit
|
||||
.Where(e => e.EntityType == typeof(UserAttachment) && e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
.Subscribe(RepositoryEventBefore);
|
||||
RepositoryAfterSubscription = RepositoryMonitor.StreamAfterCommit
|
||||
.Where(e => e.EntityType == typeof(UserAttachment) && e.EventType == RepositoryMonitorEventType.Added)
|
||||
.Subscribe(RepositoryAfterEvent);
|
||||
}
|
||||
|
||||
private static string GroupName(string UserId)
|
||||
{
|
||||
return UserPrefix + UserId;
|
||||
}
|
||||
|
||||
public override Task OnConnected()
|
||||
{
|
||||
var userId = Context.QueryString["UserId"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(userId))
|
||||
throw new ArgumentNullException("UserId");
|
||||
|
||||
Groups.Add(Context.ConnectionId, GroupName(userId));
|
||||
|
||||
return base.OnConnected();
|
||||
}
|
||||
|
||||
private static void RepositoryEventBefore(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
{
|
||||
if (e.EntityType == typeof(UserAttachment))
|
||||
{
|
||||
var repositoryAttachment = (UserAttachment)e.Entity;
|
||||
string attachmentUserId;
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
attachmentUserId = Database.UserAttachments.Where(a => a.Id == repositoryAttachment.Id).Select(a => a.UserId).First();
|
||||
|
||||
HubContext.Clients.Group(GroupName(attachmentUserId)).removeAttachment(repositoryAttachment.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RepositoryAfterEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
if (e.EventType == RepositoryMonitorEventType.Added)
|
||||
{
|
||||
if (e.EntityType == typeof(UserAttachment))
|
||||
{
|
||||
var a = (UserAttachment)e.Entity;
|
||||
|
||||
HubContext.Clients.Group(GroupName(a.UserId)).addAttachment(a.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,21 @@ namespace Disco.Services.Web
|
||||
// Ensure 'App-Relative' Url:
|
||||
BundleUrl = BundleUrl.StartsWith("~/") ? BundleUrl : (BundleUrl.StartsWith("/") ? string.Concat("~", BundleUrl) : string.Concat("~/", BundleUrl));
|
||||
|
||||
var deferredBundles = htmlHelper.ViewContext.HttpContext.Items[Bundle.DeferredKey] as List<string>;
|
||||
var deferredBundles = htmlHelper.ViewContext.HttpContext.Items[BundleTable.DeferredKey] as List<string>;
|
||||
if (deferredBundles == null)
|
||||
{
|
||||
deferredBundles = new List<string>();
|
||||
htmlHelper.ViewContext.HttpContext.Items[Bundle.DeferredKey] = deferredBundles;
|
||||
htmlHelper.ViewContext.HttpContext.Items[BundleTable.DeferredKey] = deferredBundles;
|
||||
}
|
||||
if (!deferredBundles.Contains(BundleUrl))
|
||||
deferredBundles.Add(BundleUrl);
|
||||
}
|
||||
public static HtmlString BundleRenderDeferred(this HtmlHelper htmlHelper)
|
||||
{
|
||||
var deferredBundles = htmlHelper.ViewContext.HttpContext.Items[Bundle.DeferredKey] as List<string>;
|
||||
var deferredBundles = htmlHelper.ViewContext.HttpContext.Items[BundleTable.DeferredKey] as List<string>;
|
||||
|
||||
var uiExtensionScripts = htmlHelper.ViewContext.HttpContext.Items[Bundle.UIExtensionScriptsKey] as List<string>;
|
||||
var uiExtensionCss = htmlHelper.ViewContext.HttpContext.Items[Bundle.UIExtensionCssKey] as List<string>;
|
||||
var uiExtensionScripts = htmlHelper.ViewContext.HttpContext.Items[BundleTable.UIExtensionScriptsKey] as List<string>;
|
||||
var uiExtensionCss = htmlHelper.ViewContext.HttpContext.Items[BundleTable.UIExtensionCssKey] as List<string>;
|
||||
|
||||
if (deferredBundles != null || uiExtensionScripts != null || uiExtensionCss != null)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,10 @@ namespace Disco.Services.Web.Bundles
|
||||
{
|
||||
internal sealed class BundleHandler : IHttpHandler
|
||||
{
|
||||
public Bundle RequestBundle { get; private set; }
|
||||
public IBundle RequestBundle { get; private set; }
|
||||
public string BundleVirtualPath { get; private set; }
|
||||
|
||||
public BundleHandler(Bundle requestBundle, string bundleVirtualPath)
|
||||
public BundleHandler(IBundle requestBundle, string bundleVirtualPath)
|
||||
{
|
||||
this.RequestBundle = requestBundle;
|
||||
this.BundleVirtualPath = bundleVirtualPath;
|
||||
|
||||
@@ -9,14 +9,18 @@ namespace Disco.Services.Web.Bundles
|
||||
{
|
||||
public static class BundleTable
|
||||
{
|
||||
private static Dictionary<string, Bundle> _bundles;
|
||||
public const string DeferredKey = "Bundles.Deferred";
|
||||
public const string UIExtensionScriptsKey = "Bundles.UIExtensionScripts";
|
||||
public const string UIExtensionCssKey = "Bundles.UIExtensionCss";
|
||||
|
||||
private static Dictionary<string, IBundle> _bundles;
|
||||
|
||||
static BundleTable()
|
||||
{
|
||||
_bundles = new Dictionary<string, Bundle>();
|
||||
_bundles = new Dictionary<string, IBundle>();
|
||||
}
|
||||
|
||||
public static void Add(Bundle Bundle)
|
||||
public static void Add(IBundle Bundle)
|
||||
{
|
||||
_bundles[Bundle.Url] = Bundle;
|
||||
}
|
||||
@@ -29,7 +33,7 @@ namespace Disco.Services.Web.Bundles
|
||||
}
|
||||
}
|
||||
|
||||
internal static Bundle GetBundleFor(string Url)
|
||||
internal static IBundle GetBundleFor(string Url)
|
||||
{
|
||||
if (_bundles.ContainsKey(Url))
|
||||
{
|
||||
|
||||
@@ -9,16 +9,13 @@ using System.Web;
|
||||
|
||||
namespace Disco.Services.Web.Bundles
|
||||
{
|
||||
public class Bundle
|
||||
public class FileBundle : IBundle
|
||||
{
|
||||
public const string DeferredKey = "Bundles.Deferred";
|
||||
public const string UIExtensionScriptsKey = "Bundles.UIExtensionScripts";
|
||||
public const string UIExtensionCssKey = "Bundles.UIExtensionCss";
|
||||
|
||||
private DateTime? _FileLastModified { get; set; }
|
||||
private string _FileHash { get; set; }
|
||||
private string _VersionUrl { get; set; }
|
||||
|
||||
public bool RemapRequest { get { return true; } }
|
||||
public string Url { get; private set; }
|
||||
public string File { get; private set; }
|
||||
public string FileHash
|
||||
@@ -44,7 +41,7 @@ namespace Disco.Services.Web.Bundles
|
||||
}
|
||||
}
|
||||
|
||||
public Bundle(string Url, string File)
|
||||
public FileBundle(string Url, string File)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Url))
|
||||
throw new ArgumentNullException("Url");
|
||||
@@ -117,7 +114,7 @@ namespace Disco.Services.Web.Bundles
|
||||
this._FileHash = string.Empty;
|
||||
}
|
||||
|
||||
internal void ProcessRequest(HttpContext context)
|
||||
public void ProcessRequest(HttpContext context)
|
||||
{
|
||||
// Write Content Type
|
||||
context.Response.ContentType = this.ContentType;
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Services.Web.Bundles
|
||||
{
|
||||
public interface IBundle
|
||||
{
|
||||
bool RemapRequest { get; }
|
||||
|
||||
string Url { get; }
|
||||
string VersionUrl { get; }
|
||||
|
||||
string ContentType { get; }
|
||||
|
||||
void ProcessRequest(HttpContext context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Services.Web.Bundles
|
||||
{
|
||||
public class UrlBundle : IBundle
|
||||
{
|
||||
public bool RemapRequest { get { return false; } }
|
||||
|
||||
public string Url { get; private set; }
|
||||
public string VersionUrl { get; private set; }
|
||||
|
||||
public string ContentType { get; private set; }
|
||||
|
||||
public void ProcessRequest(System.Web.HttpContext context)
|
||||
{
|
||||
// Not needed for Url Bundle
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public UrlBundle(string Url, string ContentType)
|
||||
{
|
||||
this.Url = Url;
|
||||
this.VersionUrl = Url;
|
||||
|
||||
this.ContentType = ContentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Disco.Services.Users;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Web.Signalling
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class DiscoHubAuthorizeAllAttribute : AuthorizeAttribute
|
||||
{
|
||||
string[] authorizedClaims;
|
||||
|
||||
public DiscoHubAuthorizeAllAttribute(params string[] AuthorisedClaims)
|
||||
{
|
||||
if (AuthorisedClaims == null || AuthorisedClaims.Length == 0)
|
||||
throw new ArgumentNullException("AuthorisedClaims");
|
||||
|
||||
this.authorizedClaims = AuthorisedClaims;
|
||||
}
|
||||
|
||||
protected override bool UserAuthorized(IPrincipal user)
|
||||
{
|
||||
if (user == null || !user.Identity.IsAuthenticated)
|
||||
return false;
|
||||
|
||||
var username = user.Identity.Name;
|
||||
var userToken = UserService.GetAuthorization(username);
|
||||
|
||||
if (userToken == null)
|
||||
return false; // No User
|
||||
|
||||
return userToken.HasAll(authorizedClaims);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Disco.Services.Users;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Web.Signalling
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class DiscoHubAuthorizeAnyAttribute : AuthorizeAttribute
|
||||
{
|
||||
string[] authorizedClaims;
|
||||
|
||||
public DiscoHubAuthorizeAnyAttribute(params string[] AuthorisedClaims)
|
||||
{
|
||||
if (AuthorisedClaims == null || AuthorisedClaims.Length == 0)
|
||||
throw new ArgumentNullException("AuthorisedClaims");
|
||||
|
||||
this.authorizedClaims = AuthorisedClaims;
|
||||
}
|
||||
|
||||
protected override bool UserAuthorized(IPrincipal user)
|
||||
{
|
||||
if (user == null || !user.Identity.IsAuthenticated)
|
||||
return false;
|
||||
|
||||
var username = user.Identity.Name;
|
||||
var userToken = UserService.GetAuthorization(username);
|
||||
|
||||
if (userToken == null)
|
||||
return false; // No User
|
||||
|
||||
return userToken.HasAny(authorizedClaims);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Disco.Services.Users;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace Disco.Services.Web.Signalling
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||
public class DiscoHubAuthorizeAttribute : AuthorizeAttribute
|
||||
{
|
||||
string authorizedClaim;
|
||||
|
||||
public DiscoHubAuthorizeAttribute() { }
|
||||
|
||||
public DiscoHubAuthorizeAttribute(string AuthorisedClaim)
|
||||
{
|
||||
this.authorizedClaim = AuthorisedClaim;
|
||||
}
|
||||
|
||||
protected override bool UserAuthorized(IPrincipal user)
|
||||
{
|
||||
if (user == null || !user.Identity.IsAuthenticated)
|
||||
return false;
|
||||
|
||||
var username = user.Identity.Name;
|
||||
var userToken = UserService.GetAuthorization(username);
|
||||
|
||||
if (userToken == null)
|
||||
return false; // No User
|
||||
|
||||
if (authorizedClaim == null)
|
||||
return userToken.RoleTokens.Count > 0; // Just Authenticate - no Authorization (but require at least 1 role)
|
||||
else
|
||||
return userToken.Has(authorizedClaim);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,13 @@
|
||||
<package id="LumenWorks.Framework.IO" version="3.8.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Core" version="2.0.3" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin" version="2.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Security" version="2.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.SqlServer.Compact" version="4.0.8876.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
|
||||
<package id="Newtonsoft.Json" version="5.0.1" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="RazorGenerator.Mvc" version="2.1.2" targetFramework="net45" />
|
||||
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Disco.Web
|
||||
DiscoApplication.DocumentDropBoxMonitor.ScheduleCurrentFiles(10);
|
||||
|
||||
// Enable SignalR-based Repository Notifications
|
||||
Disco.BI.Interop.SignalRHandlers.RepositoryMonitorNotifications.Initialize();
|
||||
//Disco.BI.Interop.SignalRHandlers.RepositoryMonitorNotifications.Initialize();
|
||||
}
|
||||
|
||||
public static void InitializeUpdateEnvironment(DiscoDataContext Database, Version PreviousVersion)
|
||||
|
||||
@@ -9,40 +9,40 @@ namespace Disco.Web
|
||||
public static void RegisterBundles()
|
||||
{
|
||||
// Styles - Site Core
|
||||
BundleTable.Add(new Bundle("~/Style/Site", Links.ClientSource.Style.BundleSite_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Site", Links.ClientSource.Style.BundleSite_min_css));
|
||||
|
||||
// Styles - Targeted
|
||||
BundleTable.Add(new Bundle("~/Style/Config", Links.ClientSource.Style.Config_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Device", Links.ClientSource.Style.Device_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Dialog", Links.ClientSource.Style.Dialog_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Job", Links.ClientSource.Style.Job_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/User", Links.ClientSource.Style.User_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Credits", Links.ClientSource.Style.Credits_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/AppMaintenance", Links.ClientSource.Style.AppMaintenance_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/jQueryUI/dynatree", Links.ClientSource.Style.jQueryUI.dynatree.ui_dynatree_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Fancytree", Links.ClientSource.Style.Fancytree.disco_fancytree_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Shadowbox", Links.ClientSource.Style.Shadowbox_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Timeline", Links.ClientSource.Style.Timeline_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Config", Links.ClientSource.Style.Config_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Device", Links.ClientSource.Style.Device_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Dialog", Links.ClientSource.Style.Dialog_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Job", Links.ClientSource.Style.Job_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/User", Links.ClientSource.Style.User_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Credits", Links.ClientSource.Style.Credits_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/AppMaintenance", Links.ClientSource.Style.AppMaintenance_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/jQueryUI/dynatree", Links.ClientSource.Style.jQueryUI.dynatree.ui_dynatree_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Fancytree", Links.ClientSource.Style.Fancytree.disco_fancytree_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Shadowbox", Links.ClientSource.Style.Shadowbox_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Timeline", Links.ClientSource.Style.Timeline_min_css));
|
||||
|
||||
// Styles - Public Targeted
|
||||
BundleTable.Add(new Bundle("~/Style/Public/HeldDevices", Links.ClientSource.Style.Public.HeldDevices_min_css));
|
||||
BundleTable.Add(new Bundle("~/Style/Public/HeldDevicesNoticeboard", Links.ClientSource.Style.Public.HeldDevicesNoticeboard_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Public/HeldDevices", Links.ClientSource.Style.Public.HeldDevices_min_css));
|
||||
BundleTable.Add(new FileBundle("~/Style/Public/HeldDevicesNoticeboard", Links.ClientSource.Style.Public.HeldDevicesNoticeboard_min_css));
|
||||
|
||||
|
||||
// Scripts - Core
|
||||
#if DEBUG
|
||||
BundleTable.Add(new Bundle("~/ClientScripts/Core", Links.ClientSource.Scripts.Core_js));
|
||||
BundleTable.Add(new FileBundle("~/ClientScripts/Core", Links.ClientSource.Scripts.Core_js));
|
||||
#else
|
||||
BundleTable.Add(new Bundle("~/ClientScripts/Core", Links.ClientSource.Scripts.Core_min_js));
|
||||
BundleTable.Add(new FileBundle("~/ClientScripts/Core", Links.ClientSource.Scripts.Core_min_js));
|
||||
#endif
|
||||
|
||||
// Scripts - Modules
|
||||
#if DEBUG
|
||||
foreach (FileInfo f in new DirectoryInfo(HttpContext.Current.Server.MapPath("~/ClientSource/Scripts/Modules")).EnumerateFiles("*.js", SearchOption.TopDirectoryOnly))
|
||||
BundleTable.Add(new Bundle(string.Format("~/ClientScripts/Modules/{0}", f.Name.Substring(0, f.Name.Length - 3)), f.FullName));
|
||||
BundleTable.Add(new FileBundle(string.Format("~/ClientScripts/Modules/{0}", f.Name.Substring(0, f.Name.Length - 3)), f.FullName));
|
||||
#else
|
||||
foreach (FileInfo f in new DirectoryInfo(HttpContext.Current.Server.MapPath("~/ClientSource/Scripts/Modules")).EnumerateFiles("*.min.js", SearchOption.TopDirectoryOnly))
|
||||
BundleTable.Add(new Bundle(string.Format("~/ClientScripts/Modules/{0}", f.Name.Substring(0, f.Name.Length - 7)), f.FullName));
|
||||
BundleTable.Add(new FileBundle(string.Format("~/ClientScripts/Modules/{0}", f.Name.Substring(0, f.Name.Length - 7)), f.FullName));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.Owin;
|
||||
using Owin;
|
||||
|
||||
[assembly: OwinStartup(typeof(Disco.Web.OwinStartupConfig))]
|
||||
|
||||
namespace Disco.Web
|
||||
{
|
||||
public class OwinStartupConfig
|
||||
{
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
var hubConfig = new HubConfiguration()
|
||||
{
|
||||
EnableJavaScriptProxies = false
|
||||
};
|
||||
|
||||
app.MapSignalR("/API/Signalling", hubConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ using System.Web.Mvc;
|
||||
using System.Web.WebPages;
|
||||
using RazorGenerator.Mvc;
|
||||
|
||||
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(Disco.Web.App_Start.RazorGeneratorMvcStart), "Start")]
|
||||
[assembly: WebActivatorEx.PostApplicationStartMethod(typeof(Disco.Web.RazorGeneratorMvcStart), "Start")]
|
||||
|
||||
namespace Disco.Web.App_Start {
|
||||
namespace Disco.Web {
|
||||
public static class RazorGeneratorMvcStart {
|
||||
public static void Start() {
|
||||
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Disco.BI.Interop.SignalRHandlers;
|
||||
|
||||
namespace Disco.Web
|
||||
{
|
||||
@@ -74,11 +73,6 @@ namespace Disco.Web
|
||||
|
||||
public static void RegisterUpdateRoutes(RouteCollection routes)
|
||||
{
|
||||
// Task Status SignalR Route
|
||||
routes.MapConnection<ScheduledTasksStatusNotifications>(
|
||||
"API_Logging_TaskStatusNotifications",
|
||||
"API/Logging/TaskStatusNotifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
|
||||
// Task Status Ajax Route
|
||||
routes.MapRoute(
|
||||
name: "API_Logging_ScheduledTaskStatus", // Route name
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Disco.BI.Interop.SignalRHandlers;
|
||||
|
||||
namespace Disco.Web.Areas.API
|
||||
{
|
||||
@@ -17,15 +16,6 @@ namespace Disco.Web.Areas.API
|
||||
|
||||
public override void RegisterArea(AreaRegistrationContext context)
|
||||
{
|
||||
context.Routes.MapConnection<LogNotifications>(
|
||||
"API_Logging_Notifications", "API/Logging/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
|
||||
context.Routes.MapConnection<ScheduledTasksStatusNotifications>(
|
||||
"API_Logging_TaskStatusNotifications", "API/Logging/TaskStatusNotifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
|
||||
context.Routes.MapConnection<RepositoryMonitorNotifications>(
|
||||
"API_Repository_Notifications", "API/Repository/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
|
||||
context.MapRoute(
|
||||
"API_Update",
|
||||
"API/{controller}/Update/{id}/{key}",
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Disco.BI;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Services;
|
||||
using System;
|
||||
|
||||
namespace Disco.Web.Areas.API.Models.Attachment
|
||||
{
|
||||
@@ -27,7 +23,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
||||
ParentId = ua.UserId,
|
||||
Id = ua.Id,
|
||||
AuthorId = ua.TechUserId,
|
||||
Author = ua.TechUser.ToString(),
|
||||
Author = ua.TechUser.ToStringFriendly(),
|
||||
Timestamp = ua.Timestamp,
|
||||
Comments = ua.Comments,
|
||||
Filename = ua.Filename,
|
||||
@@ -41,7 +37,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
||||
ParentId = ja.JobId.ToString(),
|
||||
Id = ja.Id,
|
||||
AuthorId = ja.TechUserId,
|
||||
Author = ja.TechUser.ToString(),
|
||||
Author = ja.TechUser.ToStringFriendly(),
|
||||
Timestamp = ja.Timestamp,
|
||||
Comments = ja.Comments,
|
||||
Filename = ja.Filename,
|
||||
@@ -55,7 +51,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
||||
ParentId = da.DeviceSerialNumber,
|
||||
Id = da.Id,
|
||||
AuthorId = da.TechUserId,
|
||||
Author = da.TechUser.ToString(),
|
||||
Author = da.TechUser.ToStringFriendly(),
|
||||
Timestamp = da.Timestamp,
|
||||
Comments = da.Comments,
|
||||
Filename = da.Filename,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Models.UI.Config.Logging;
|
||||
using Disco.Models.UI.Config.Shared;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Logging.Models;
|
||||
@@ -42,10 +43,10 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
if (taskStatus == null)
|
||||
return RedirectToAction(MVC.Config.Logging.Index());
|
||||
|
||||
var m = new Models.Logging.TaskStatusModel() { SessionId = taskStatus.SessionId };
|
||||
var m = new Models.Shared.TaskStatusModel() { SessionId = taskStatus.SessionId };
|
||||
|
||||
// UI Extensions
|
||||
UIExtensions.ExecuteExtensions<ConfigLoggingTaskStatusModel>(this.ControllerContext, m);
|
||||
UIExtensions.ExecuteExtensions<ConfigSharedTaskStatusModel>(this.ControllerContext, m);
|
||||
|
||||
return View(m);
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
using Disco.Models.UI.Config.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.Logging
|
||||
{
|
||||
public class TaskStatusModel : ConfigLoggingTaskStatusModel
|
||||
{
|
||||
public string SessionId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Disco.Models.UI.Config.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.Shared
|
||||
{
|
||||
public class TaskStatusModel : ConfigSharedTaskStatusModel
|
||||
{
|
||||
public string SessionId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,255 +1,5 @@
|
||||
@model Disco.Web.Areas.Config.Models.Logging.TaskStatusModel
|
||||
@model Disco.Web.Areas.Config.Models.Shared.TaskStatusModel
|
||||
@{
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Logging", MVC.Config.Logging.Index(), "Task Status");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
}
|
||||
<div style="min-height: 300px;">
|
||||
<div id="scheduledTaskStatus" class="form" style="width: 520px;" data-bind="visible: Initialized">
|
||||
<h2 data-bind="text: TaskName"> </h2>
|
||||
<table>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<th class="process" data-bind="text: CurrentProcess">
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<td class="description" data-bind="text: CurrentDescription">
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<td class="progress">
|
||||
<div data-bind="progressValue: Progress">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: FinishedTimestamp">
|
||||
<td class="finishedTimestamp">
|
||||
<h3>Finished: <span data-bind="text: FinishedTimestampFormatted"></span>
|
||||
</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: FinishedTimestamp() && !TaskExceptionMessage()">
|
||||
<td class="finishedMessage" data-bind="css: { finishedRedirect: FinishedUrl }">
|
||||
<span data-bind="text: FinishedMessage"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: TaskExceptionMessage">
|
||||
<td class="exception">Last Error:
|
||||
<div class="code" data-bind="text: TaskExceptionMessage">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: NextScheduledTimestamp">
|
||||
<td class="nextScheduledTimestamp">Next Scheduled: <span data-bind="text: NextScheduledTimestampFormatted"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
ko.bindingHandlers.progressValue = {
|
||||
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
|
||||
var $element = $(element);
|
||||
if (!$element.is('.ui-progressbar'))
|
||||
$element.progressbar();
|
||||
},
|
||||
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
|
||||
var v = ko.utils.unwrapObservable(valueAccessor());
|
||||
var vInt = parseInt(v);
|
||||
if (vInt >= 0) {
|
||||
$(element).progressbar('option', 'value', vInt);
|
||||
}
|
||||
}
|
||||
};
|
||||
//* http://webcloud.se/log/JavaScript-and-ISO-8601/
|
||||
Date.prototype.setISO8601 = function (string) {
|
||||
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
|
||||
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
|
||||
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
|
||||
var d = string.match(new RegExp(regexp));
|
||||
|
||||
var offset = 0;
|
||||
var date = new Date(d[1], 0, 1);
|
||||
|
||||
if (d[3]) { date.setMonth(d[3] - 1); }
|
||||
if (d[5]) { date.setDate(d[5]); }
|
||||
if (d[7]) { date.setHours(d[7]); }
|
||||
if (d[8]) { date.setMinutes(d[8]); }
|
||||
if (d[10]) { date.setSeconds(d[10]); }
|
||||
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= ((d[15] == '-') ? 1 : -1);
|
||||
}
|
||||
|
||||
offset -= date.getTimezoneOffset();
|
||||
time = (Number(date) + (offset * 60 * 1000));
|
||||
this.setTime(Number(time));
|
||||
return this;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var sessionId = '@(Model.SessionId)';
|
||||
var sessionStatusUrl = '@(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)))';
|
||||
|
||||
var view = $('#scheduledTaskStatus');
|
||||
var vm = null;
|
||||
|
||||
var liveConnection = null;
|
||||
|
||||
var statusViewModel = function (sessionId) {
|
||||
var self = this;
|
||||
|
||||
self.Initialized = ko.observable(false);
|
||||
|
||||
self.TimestampParse = function (timestamp) {
|
||||
if (timestamp) {
|
||||
if (timestamp.indexOf("\/Date(") == 0)
|
||||
return new Date(parseInt(timestamp.substr(6)));
|
||||
else
|
||||
return (new Date()).setISO8601(timestamp);
|
||||
}
|
||||
return new Date();
|
||||
}
|
||||
self.TimestampFormat = function (timestamp) {
|
||||
var addZero = function (v) { v = v + ''; if (v.length == 1) v = '0' + v; return v; }
|
||||
return timestamp.getFullYear() + '/' + addZero((1 + timestamp.getMonth())) + '/' + addZero(timestamp.getDate()) + ' ' + addZero(timestamp.getHours()) + ':' + addZero(timestamp.getMinutes()) + ':' + addZero(timestamp.getSeconds());
|
||||
}
|
||||
|
||||
self.SessionId = sessionId;
|
||||
self.TaskName = ko.observable(null);
|
||||
self.StatusVersion = -1;
|
||||
|
||||
self.Progress = ko.observable(0);
|
||||
self.CurrentProcess = ko.observable(null);
|
||||
self.CurrentDescription = ko.observable(null);
|
||||
|
||||
self.IsRunning = ko.observable(null);
|
||||
|
||||
self.TaskExceptionMessage = ko.observable(null);
|
||||
|
||||
self.FinishedTimestamp = ko.observable(null);
|
||||
self.NextScheduledTimestamp = ko.observable(null)
|
||||
|
||||
self.NextScheduledTimestampFormatted = ko.computed(function () {
|
||||
return self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));
|
||||
});
|
||||
self.FinishedTimestampFormatted = ko.computed(function () {
|
||||
return self.TimestampFormat(self.TimestampParse(self.FinishedTimestamp()));
|
||||
});
|
||||
|
||||
self.FinishedUrl = ko.observable(null);
|
||||
self.FinishedMessage = ko.observable(null);
|
||||
|
||||
self.Finished = function () {
|
||||
if (self.FinishedTimestamp()) {
|
||||
if (self.FinishedUrl() && !self.TaskExceptionMessage()) {
|
||||
if (self.FinishedMessage())
|
||||
window.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);
|
||||
else
|
||||
window.location.href = self.FinishedUrl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.Initialize = function (taskStatus) {
|
||||
self.TaskName(taskStatus.TaskName);
|
||||
self.FinishedUrl(taskStatus.FinishedUrl);
|
||||
|
||||
self.Progress(taskStatus.Progress);
|
||||
self.CurrentProcess(taskStatus.CurrentProcess);
|
||||
self.CurrentDescription(taskStatus.CurrentDescription);
|
||||
|
||||
self.IsRunning(taskStatus.IsRunning);
|
||||
|
||||
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
|
||||
|
||||
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
|
||||
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
|
||||
|
||||
self.FinishedMessage(taskStatus.FinishedMessage);
|
||||
|
||||
self.Initialized(true);
|
||||
|
||||
self.Finished();
|
||||
}
|
||||
self.Update = function (taskStatus) {
|
||||
if (!self.Initialized())
|
||||
return self.Initialize(taskStatus);
|
||||
|
||||
if (taskStatus.StatusVersion < self.StatusVersion)
|
||||
return; // Have Newer Status Update
|
||||
self.StatusVersion = taskStatus.StatusVersion;
|
||||
|
||||
if (taskStatus.ChangedProperties) {
|
||||
for (var changedPropertyIndex = 0; changedPropertyIndex < taskStatus.ChangedProperties.length; changedPropertyIndex++) {
|
||||
switch (taskStatus.ChangedProperties[changedPropertyIndex]) {
|
||||
case 'Progress':
|
||||
self.Progress(taskStatus.Progress);
|
||||
break;
|
||||
case 'CurrentProcess':
|
||||
self.CurrentProcess(taskStatus.CurrentProcess);
|
||||
break;
|
||||
case 'CurrentDescription':
|
||||
self.CurrentDescription(taskStatus.CurrentDescription);
|
||||
break;
|
||||
case 'IsRunning':
|
||||
self.IsRunning(taskStatus.IsRunning);
|
||||
break;
|
||||
case 'TaskException':
|
||||
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
|
||||
break;
|
||||
case 'NextScheduledTimestamp':
|
||||
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
|
||||
break;
|
||||
case 'FinishedUrl':
|
||||
self.FinishedUrl(taskStatus.FinishedUrl);
|
||||
break;
|
||||
case 'FinishedMessage':
|
||||
self.FinishedMessage(taskStatus.FinishedMessage);
|
||||
break;
|
||||
case 'FinishedTimestamp':
|
||||
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
|
||||
window.setTimeout(self.Finished, 1);
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm = new statusViewModel(sessionId);
|
||||
ko.applyBindings(vm, view[0]);
|
||||
|
||||
// Start Live Connection
|
||||
updateWithLive();
|
||||
|
||||
function updateWithAjax(onSuccess) {
|
||||
$.ajax({
|
||||
url: sessionStatusUrl,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
traditional: true,
|
||||
success: update_Received,
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to load Session: ' + errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateWithLive() {
|
||||
liveConnection = $.connection('@(Url.Content("~/API/Logging/TaskStatusNotifications"))', { addToGroups: sessionId });
|
||||
liveConnection.received(update_Received);
|
||||
liveConnection.error(function (e) { if (e.status != 200) alert('Live-Status Error: ' + e.statusText + ': ' + e.responseText); });
|
||||
liveConnection.start(function () {
|
||||
updateWithAjax();
|
||||
});
|
||||
}
|
||||
function update_Received(taskStatus) {
|
||||
vm.Update(taskStatus);
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
@Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId)
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -37,7 +37,7 @@ namespace Disco.Web.Areas.Config.Views.Logging
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Logging/TaskStatus.cshtml")]
|
||||
public partial class TaskStatus : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Logging.TaskStatusModel>
|
||||
public partial class TaskStatus : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Shared.TaskStatusModel>
|
||||
{
|
||||
public TaskStatus()
|
||||
{
|
||||
@@ -48,269 +48,19 @@ namespace Disco.Web.Areas.Config.Views.Logging
|
||||
#line 2 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Logging", MVC.Config.Logging.Index(), "Task Status");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n<div");
|
||||
|
||||
WriteLiteral(" style=\"min-height: 300px;\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"scheduledTaskStatus\"");
|
||||
|
||||
WriteLiteral(" class=\"form\"");
|
||||
|
||||
WriteLiteral(" style=\"width: 520px;\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: Initialized\"");
|
||||
|
||||
WriteLiteral(">\r\n <h2");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: TaskName\"");
|
||||
|
||||
WriteLiteral("> </h2>\r\n <table>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <th");
|
||||
|
||||
WriteLiteral(" class=\"process\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: CurrentProcess\"");
|
||||
|
||||
WriteLiteral("> \r\n </th>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"description\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: CurrentDescription\"");
|
||||
|
||||
WriteLiteral("> \r\n </td>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"progress\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" data-bind=\"progressValue: Progress\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: FinishedTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"finishedTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>Finished: <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: FinishedTimestampFormatted\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: FinishedTimestamp() && !TaskExceptionMessage()\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"finishedMessage\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"css: { finishedRedirect: FinishedUrl }\"");
|
||||
|
||||
WriteLiteral(">\r\n <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: FinishedMessage\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: TaskExceptionMessage\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"exception\"");
|
||||
|
||||
WriteLiteral(">Last Error:\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: TaskExceptionMessage\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: NextScheduledTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"nextScheduledTimestamp\"");
|
||||
|
||||
WriteLiteral(">Next Scheduled: <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: NextScheduledTimestampFormatted\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r" +
|
||||
"\n</div>\r\n<script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
|
||||
WriteLiteral(">\r\n ko.bindingHandlers.progressValue = {\r\n init: function (element, val" +
|
||||
"ueAccessor, allBindingsAccessor, viewModel) {\r\n var $element = $(elem" +
|
||||
"ent);\r\n if (!$element.is(\'.ui-progressbar\'))\r\n $elemen" +
|
||||
"t.progressbar();\r\n },\r\n update: function (element, valueAccessor, " +
|
||||
"allBindingsAccessor, viewModel) {\r\n var v = ko.utils.unwrapObservable" +
|
||||
"(valueAccessor());\r\n var vInt = parseInt(v);\r\n if (vInt >=" +
|
||||
" 0) {\r\n $(element).progressbar(\'option\', \'value\', vInt);\r\n " +
|
||||
" }\r\n }\r\n };\r\n //* http://webcloud.se/log/JavaScript-and-ISO-860" +
|
||||
"1/\r\n Date.prototype.setISO8601 = function (string) {\r\n var regexp = \"(" +
|
||||
"[0-9]{4})(-([0-9]{2})(-([0-9]{2})\" +\r\n \"(T([0-9]{2}):([0-9]{2})(:([0-9]{2" +
|
||||
"})(\\.([0-9]+))?)?\" +\r\n \"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?\";\r\n " +
|
||||
" var d = string.match(new RegExp(regexp));\r\n\r\n var offset = 0;\r\n " +
|
||||
" var date = new Date(d[1], 0, 1);\r\n\r\n if (d[3]) { date.setMonth(d[3] - 1)" +
|
||||
"; }\r\n if (d[5]) { date.setDate(d[5]); }\r\n if (d[7]) { date.setHour" +
|
||||
"s(d[7]); }\r\n if (d[8]) { date.setMinutes(d[8]); }\r\n if (d[10]) { d" +
|
||||
"ate.setSeconds(d[10]); }\r\n if (d[12]) { date.setMilliseconds(Number(\"0.\" " +
|
||||
"+ d[12]) * 1000); }\r\n if (d[14]) {\r\n offset = (Number(d[16]) *" +
|
||||
" 60) + Number(d[17]);\r\n offset *= ((d[15] == \'-\') ? 1 : -1);\r\n " +
|
||||
" }\r\n\r\n offset -= date.getTimezoneOffset();\r\n time = (Number(date) " +
|
||||
"+ (offset * 60 * 1000));\r\n this.setTime(Number(time));\r\n return th" +
|
||||
"is;\r\n }\r\n</script>\r\n<script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
|
||||
WriteLiteral(">\r\n $(function () {\r\n var sessionId = \'");
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
|
||||
#line 93 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||
Write(Model.SessionId);
|
||||
#line 5 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||
Write(Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n var sessionStatusUrl = \'");
|
||||
|
||||
|
||||
#line 94 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||
Write(Url.Action(MVC.API.Logging.ScheduledTaskStatus(Model.SessionId)));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n\r\n var view = $(\'#scheduledTaskStatus\');\r\n var vm = null;\r\n\r\n " +
|
||||
" var liveConnection = null;\r\n\r\n var statusViewModel = function (sess" +
|
||||
"ionId) {\r\n var self = this;\r\n\r\n self.Initialized = ko.obse" +
|
||||
"rvable(false);\r\n\r\n self.TimestampParse = function (timestamp) {\r\n " +
|
||||
" if (timestamp) {\r\n if (timestamp.indexOf(\"\\/Date(" +
|
||||
"\") == 0)\r\n return new Date(parseInt(timestamp.substr(6)))" +
|
||||
";\r\n else\r\n return (new Date()).setISO8" +
|
||||
"601(timestamp);\r\n }\r\n return new Date();\r\n " +
|
||||
" }\r\n self.TimestampFormat = function (timestamp) {\r\n " +
|
||||
" var addZero = function (v) { v = v + \'\'; if (v.length == 1) v = \'0\' + v; retur" +
|
||||
"n v; }\r\n return timestamp.getFullYear() + \'/\' + addZero((1 + time" +
|
||||
"stamp.getMonth())) + \'/\' + addZero(timestamp.getDate()) + \' \' + addZero(timestam" +
|
||||
"p.getHours()) + \':\' + addZero(timestamp.getMinutes()) + \':\' + addZero(timestamp." +
|
||||
"getSeconds());\r\n }\r\n\r\n self.SessionId = sessionId;\r\n " +
|
||||
" self.TaskName = ko.observable(null);\r\n self.StatusVersion = -1;" +
|
||||
"\r\n\r\n self.Progress = ko.observable(0);\r\n self.CurrentProce" +
|
||||
"ss = ko.observable(null);\r\n self.CurrentDescription = ko.observable(n" +
|
||||
"ull);\r\n\r\n self.IsRunning = ko.observable(null);\r\n\r\n self.T" +
|
||||
"askExceptionMessage = ko.observable(null);\r\n\r\n self.FinishedTimestamp" +
|
||||
" = ko.observable(null);\r\n self.NextScheduledTimestamp = ko.observable" +
|
||||
"(null)\r\n\r\n self.NextScheduledTimestampFormatted = ko.computed(functio" +
|
||||
"n () {\r\n return self.TimestampFormat(self.TimestampParse(self.Nex" +
|
||||
"tScheduledTimestamp()));\r\n });\r\n self.FinishedTimestampFor" +
|
||||
"matted = ko.computed(function () {\r\n return self.TimestampFormat(" +
|
||||
"self.TimestampParse(self.FinishedTimestamp()));\r\n });\r\n\r\n " +
|
||||
"self.FinishedUrl = ko.observable(null);\r\n self.FinishedMessage = ko.o" +
|
||||
"bservable(null);\r\n\r\n self.Finished = function () {\r\n i" +
|
||||
"f (self.FinishedTimestamp()) {\r\n if (self.FinishedUrl() && !s" +
|
||||
"elf.TaskExceptionMessage()) {\r\n if (self.FinishedMessage(" +
|
||||
"))\r\n window.setTimeout(function () { window.location." +
|
||||
"href = self.FinishedUrl(); }, 3000);\r\n else\r\n " +
|
||||
" window.location.href = self.FinishedUrl();\r\n " +
|
||||
"}\r\n }\r\n }\r\n\r\n self.Initialize = function (t" +
|
||||
"askStatus) {\r\n self.TaskName(taskStatus.TaskName);\r\n " +
|
||||
" self.FinishedUrl(taskStatus.FinishedUrl);\r\n\r\n self.Progress(ta" +
|
||||
"skStatus.Progress);\r\n self.CurrentProcess(taskStatus.CurrentProce" +
|
||||
"ss);\r\n self.CurrentDescription(taskStatus.CurrentDescription);\r\n\r" +
|
||||
"\n self.IsRunning(taskStatus.IsRunning);\r\n\r\n self.T" +
|
||||
"askExceptionMessage(taskStatus.TaskExceptionMessage);\r\n\r\n self.Fi" +
|
||||
"nishedTimestamp(taskStatus.FinishedTimestamp);\r\n self.NextSchedul" +
|
||||
"edTimestamp(taskStatus.NextScheduledTimestamp);\r\n\r\n self.Finished" +
|
||||
"Message(taskStatus.FinishedMessage);\r\n\r\n self.Initialized(true);\r" +
|
||||
"\n\r\n self.Finished();\r\n }\r\n self.Update = fu" +
|
||||
"nction (taskStatus) {\r\n if (!self.Initialized())\r\n " +
|
||||
" return self.Initialize(taskStatus);\r\n\r\n if (taskStatus.Statu" +
|
||||
"sVersion < self.StatusVersion)\r\n return; // Have Newer Status" +
|
||||
" Update\r\n self.StatusVersion = taskStatus.StatusVersion;\r\n\r\n " +
|
||||
" if (taskStatus.ChangedProperties) {\r\n for (var cha" +
|
||||
"ngedPropertyIndex = 0; changedPropertyIndex < taskStatus.ChangedProperties.lengt" +
|
||||
"h; changedPropertyIndex++) {\r\n switch (taskStatus.Changed" +
|
||||
"Properties[changedPropertyIndex]) {\r\n case \'Progress\'" +
|
||||
":\r\n self.Progress(taskStatus.Progress);\r\n " +
|
||||
" break;\r\n case \'CurrentProcess" +
|
||||
"\':\r\n self.CurrentProcess(taskStatus.CurrentProces" +
|
||||
"s);\r\n break;\r\n case \'C" +
|
||||
"urrentDescription\':\r\n self.CurrentDescription(tas" +
|
||||
"kStatus.CurrentDescription);\r\n break;\r\n " +
|
||||
" case \'IsRunning\':\r\n self.IsRunn" +
|
||||
"ing(taskStatus.IsRunning);\r\n break;\r\n " +
|
||||
" case \'TaskException\':\r\n self.Task" +
|
||||
"ExceptionMessage(taskStatus.TaskExceptionMessage);\r\n " +
|
||||
" break;\r\n case \'NextScheduledTimestamp\':\r\n " +
|
||||
" self.NextScheduledTimestamp(taskStatus.NextScheduledTime" +
|
||||
"stamp);\r\n break;\r\n cas" +
|
||||
"e \'FinishedUrl\':\r\n self.FinishedUrl(taskStatus.Fi" +
|
||||
"nishedUrl);\r\n break;\r\n " +
|
||||
" case \'FinishedMessage\':\r\n self.FinishedMessage(t" +
|
||||
"askStatus.FinishedMessage);\r\n break;\r\n " +
|
||||
" case \'FinishedTimestamp\':\r\n self" +
|
||||
".FinishedTimestamp(taskStatus.FinishedTimestamp);\r\n " +
|
||||
" window.setTimeout(self.Finished, 1);\r\n break;\r" +
|
||||
"\n default:\r\n // Ignore" +
|
||||
"\r\n }\r\n }\r\n }\r\n " +
|
||||
" }\r\n }\r\n\r\n vm = new statusViewModel(sessionId);\r\n ko.appl" +
|
||||
"yBindings(vm, view[0]);\r\n\r\n // Start Live Connection\r\n updateWithL" +
|
||||
"ive();\r\n\r\n function updateWithAjax(onSuccess) {\r\n $.ajax({\r\n " +
|
||||
" url: sessionStatusUrl,\r\n dataType: \'json\',\r\n " +
|
||||
" type: \'POST\',\r\n traditional: true,\r\n succ" +
|
||||
"ess: update_Received,\r\n error: function (jqXHR, textStatus, error" +
|
||||
"Thrown) {\r\n alert(\'Unable to load Session: \' + errorThrown);\r" +
|
||||
"\n }\r\n });\r\n }\r\n function updateWithLive(" +
|
||||
") {\r\n liveConnection = $.connection(\'");
|
||||
|
||||
|
||||
#line 243 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||
Write(Url.Content("~/API/Logging/TaskStatusNotifications"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"', { addToGroups: sessionId });
|
||||
liveConnection.received(update_Received);
|
||||
liveConnection.error(function (e) { if (e.status != 200) alert('Live-Status Error: ' + e.statusText + ': ' + e.responseText); });
|
||||
liveConnection.start(function () {
|
||||
updateWithAjax();
|
||||
});
|
||||
}
|
||||
function update_Received(taskStatus) {
|
||||
vm.Update(taskStatus);
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@model Disco.Web.Areas.Config.Models.Shared.LogEventsModel
|
||||
@{
|
||||
Authorization.Require(Claims.Config.Logging.Show);
|
||||
|
||||
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
var uniqueId = Guid.NewGuid().ToString("N");
|
||||
@@ -44,12 +44,12 @@
|
||||
$(function () {
|
||||
var logEventsHost = $('LogEvents_@(uniqueId)');
|
||||
var logModuleId = '@(Model.ModuleFilter != null ? Model.ModuleFilter.ModuleId.ToString() : null)';
|
||||
var logModuleLiveGroupName = '@(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.BI.Interop.SignalRHandlers.LogNotifications.AllNotifications)';
|
||||
var logEventTypeFiltered = @(eventTypesFilterJson);
|
||||
var logModuleLiveGroupName = '@(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.Services.Logging.LogNotificationsHub.AllLoggingNotification)';
|
||||
var logEventTypeFiltered = @(eventTypesFilterJson);
|
||||
var logStartFiler = @(AjaxHelpers.JsonDate(Model.StartFilter));
|
||||
var logEndFiler = @(AjaxHelpers.JsonDate(Model.EndFilter));
|
||||
var logTakeFiler = '@(Model.TakeFilter)';
|
||||
var liveConnection = null;
|
||||
var logHub = null;
|
||||
var liveEventReceivedFunction = '@(Model.JavascriptLiveEventFunctionName)';
|
||||
var useLive = ('True'==='@(Model.IsLive)');
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: loadData,
|
||||
success: function (d) {
|
||||
success: function (d) {
|
||||
initLogs(d);
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
@@ -113,16 +113,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
liveConnection = $.connection('@(Url.Content("~/API/Logging/Notifications"))', {addToGroups: logModuleLiveGroupName});
|
||||
liveConnection.received(logReceived);
|
||||
liveConnection.error(function(e){if (e.status != 200) alert('Live-Log Error: '+e.statusText +': '+e.responseText);});
|
||||
liveConnection.start();
|
||||
}
|
||||
}
|
||||
logHub = $.connection.logNotifications;
|
||||
logHub.client.receiveLog = function(message){
|
||||
if (message.UseDisplay) logsViewModel.EventLogs.unshift(message);
|
||||
if (liveEventReceivedFunction) liveEventReceivedFunction(message);
|
||||
};
|
||||
|
||||
function logReceived(log){
|
||||
if (log.UseDisplay) logsViewModel.EventLogs.unshift(log);
|
||||
if (liveEventReceivedFunction) liveEventReceivedFunction(log);
|
||||
$.connection.hub.qs = {LogModules: logModuleLiveGroupName};
|
||||
$.connection.hub.error(function(error){
|
||||
alert('Live-Log Error: '+error);
|
||||
});
|
||||
|
||||
$.connection.hub.start().fail(function(error){
|
||||
alert('Live-Log Connection Error: '+error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadInitialData();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -48,7 +48,7 @@ namespace Disco.Web.Areas.Config.Views.Shared
|
||||
#line 2 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
|
||||
Authorization.Require(Claims.Config.Logging.Show);
|
||||
|
||||
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
var uniqueId = Guid.NewGuid().ToString("N");
|
||||
@@ -58,15 +58,15 @@ namespace Disco.Web.Areas.Config.Views.Shared
|
||||
#line hidden
|
||||
WriteLiteral("\r\n<div");
|
||||
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 313), Tuple.Create("\"", 339)
|
||||
, Tuple.Create(Tuple.Create("", 318), Tuple.Create("LogEvents_", 318), true)
|
||||
WriteAttribute("id", Tuple.Create(" id=\"", 309), Tuple.Create("\"", 335)
|
||||
, Tuple.Create(Tuple.Create("", 314), Tuple.Create("LogEvents_", 314), true)
|
||||
|
||||
#line 9 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 328), Tuple.Create<System.Object, System.Int32>(uniqueId
|
||||
, Tuple.Create(Tuple.Create("", 324), Tuple.Create<System.Object, System.Int32>(uniqueId
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 328), false)
|
||||
, 324), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" class=\"logEventsViewport\"");
|
||||
@@ -96,21 +96,21 @@ WriteLiteral(">Message\r\n </th>\r\n </tr>\r\n
|
||||
|
||||
WriteLiteral(" class=\"logEventsViewportContainer\"");
|
||||
|
||||
WriteAttribute("style", Tuple.Create(" style=\"", 814), Tuple.Create("\"", 1024)
|
||||
WriteAttribute("style", Tuple.Create(" style=\"", 810), Tuple.Create("\"", 1020)
|
||||
|
||||
#line 24 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 822), Tuple.Create<System.Object, System.Int32>(Model.ViewPortWidth.HasValue ? string.Format("width:{0}px;", Model.ViewPortWidth.Value) : null
|
||||
, Tuple.Create(Tuple.Create("", 818), Tuple.Create<System.Object, System.Int32>(Model.ViewPortWidth.HasValue ? string.Format("width:{0}px;", Model.ViewPortWidth.Value) : null
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 822), false)
|
||||
, 818), false)
|
||||
|
||||
#line 24 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 919), Tuple.Create<System.Object, System.Int32>(Model.ViewPortHeight.HasValue ? string.Format("height:{0}px;", Model.ViewPortHeight.Value - 18) : null
|
||||
, Tuple.Create(Tuple.Create("", 915), Tuple.Create<System.Object, System.Int32>(Model.ViewPortHeight.HasValue ? string.Format("height:{0}px;", Model.ViewPortHeight.Value - 18) : null
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 919), false)
|
||||
, 915), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
@@ -205,7 +205,7 @@ WriteLiteral("\';\r\n var logModuleLiveGroupName = \'");
|
||||
|
||||
|
||||
#line 47 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
Write(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.BI.Interop.SignalRHandlers.LogNotifications.AllNotifications);
|
||||
Write(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.Services.Logging.LogNotificationsHub.AllLoggingNotification);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -219,7 +219,7 @@ WriteLiteral("\';\r\n var logEventTypeFiltered = ");
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(";\r\n var logStartFiler = ");
|
||||
WriteLiteral("; \r\n var logStartFiler = ");
|
||||
|
||||
|
||||
#line 49 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
@@ -246,8 +246,8 @@ WriteLiteral(";\r\n var logTakeFiler = \'");
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n var liveConnection = null;\r\n var liveEventReceivedFunc" +
|
||||
"tion = \'");
|
||||
WriteLiteral("\';\r\n var logHub = null;\r\n var liveEventReceivedFunction = \'" +
|
||||
"");
|
||||
|
||||
|
||||
#line 53 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
@@ -308,60 +308,33 @@ WriteLiteral(@"');
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"',
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
data: loadData,
|
||||
success: function (d) {
|
||||
initLogs(d);
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to retrieve logs: ' + textStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initLogs(loadedLogs){
|
||||
logsViewModel = new LogsViewModel(loadedLogs);
|
||||
ko.applyBindings(logsViewModel, logEventsHost.get(0));
|
||||
|
||||
if (useLive){
|
||||
if (liveEventReceivedFunction){
|
||||
if (!document.DiscoFunctions) document.DiscoFunctions = {};
|
||||
if (!document.DiscoFunctions.LogEventsFunctions) document.DiscoFunctions.LogEventsFunctions = {};
|
||||
if (document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction]){
|
||||
liveEventReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction];
|
||||
}else{
|
||||
liveEventReceivedFunction = null;
|
||||
}
|
||||
}
|
||||
|
||||
liveConnection = $.connection('");
|
||||
|
||||
|
||||
#line 116 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||
Write(Url.Content("~/API/Logging/Notifications"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"', {addToGroups: logModuleLiveGroupName});
|
||||
liveConnection.received(logReceived);
|
||||
liveConnection.error(function(e){if (e.status != 200) alert('Live-Log Error: '+e.statusText +': '+e.responseText);});
|
||||
liveConnection.start();
|
||||
}
|
||||
}
|
||||
|
||||
function logReceived(log){
|
||||
if (log.UseDisplay) logsViewModel.EventLogs.unshift(log);
|
||||
if (liveEventReceivedFunction) liveEventReceivedFunction(log);
|
||||
}
|
||||
|
||||
loadInitialData();
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
");
|
||||
WriteLiteral("\',\r\n dataType: \'json\',\r\n type: \'POST\',\r\n " +
|
||||
" data: loadData,\r\n success: function (d) { \r\n" +
|
||||
" initLogs(d);\r\n },\r\n " +
|
||||
" error: function (jqXHR, textStatus, errorThrown) {\r\n al" +
|
||||
"ert(\'Unable to retrieve logs: \' + textStatus);\r\n }\r\n " +
|
||||
" });\r\n }\r\n\r\n function initLogs(loadedLogs){\r\n " +
|
||||
" logsViewModel = new LogsViewModel(loadedLogs);\r\n ko.appl" +
|
||||
"yBindings(logsViewModel, logEventsHost.get(0));\r\n\r\n if (useLive){" +
|
||||
"\r\n if (liveEventReceivedFunction){\r\n i" +
|
||||
"f (!document.DiscoFunctions) document.DiscoFunctions = {};\r\n " +
|
||||
" if (!document.DiscoFunctions.LogEventsFunctions) document.DiscoFunctions.Log" +
|
||||
"EventsFunctions = {};\r\n if (document.DiscoFunctions.LogEv" +
|
||||
"entsFunctions[liveEventReceivedFunction]){\r\n liveEven" +
|
||||
"tReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceived" +
|
||||
"Function];\r\n }else{\r\n liveEven" +
|
||||
"tReceivedFunction = null;\r\n }\r\n }\r\n\r\n " +
|
||||
" logHub = $.connection.logNotifications;\r\n " +
|
||||
"logHub.client.receiveLog = function(message){\r\n if (messa" +
|
||||
"ge.UseDisplay) logsViewModel.EventLogs.unshift(message);\r\n " +
|
||||
" if (liveEventReceivedFunction) liveEventReceivedFunction(message);\r\n " +
|
||||
" };\r\n\r\n $.connection.hub.qs = {LogModules: logModule" +
|
||||
"LiveGroupName};\r\n $.connection.hub.error(function(error){\r\n " +
|
||||
" alert(\'Live-Log Error: \'+error);\r\n });\r" +
|
||||
"\n\r\n $.connection.hub.start().fail(function(error){\r\n " +
|
||||
" alert(\'Live-Log Connection Error: \'+error);\r\n " +
|
||||
"});\r\n }\r\n }\r\n\r\n loadInitialData();\r\n " +
|
||||
" });\r\n </script>\r\n</div>\r\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
@model string
|
||||
@{
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
}
|
||||
<div style="min-height: 300px;">
|
||||
<div id="Logging_Task_Status" class="form" style="width: 520px;" data-bind="visible: Initialized">
|
||||
<h2 data-bind="text: TaskName"> </h2>
|
||||
<table>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<th class="process" data-bind="text: CurrentProcess">
|
||||
</th>
|
||||
</tr>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<td class="description" data-bind="text: CurrentDescription">
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: IsRunning">
|
||||
<td class="progress">
|
||||
<div data-bind="progressValue: Progress">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: FinishedTimestamp">
|
||||
<td class="finishedTimestamp">
|
||||
<h3>Finished: <span data-bind="text: FinishedTimestampFormatted"></span>
|
||||
</h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: FinishedTimestamp() && !TaskExceptionMessage()">
|
||||
<td class="finishedMessage" data-bind="css: { finishedRedirect: FinishedUrl }">
|
||||
<span data-bind="text: FinishedMessage"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: TaskExceptionMessage">
|
||||
<td class="exception">Last Error:
|
||||
<div class="code" data-bind="text: TaskExceptionMessage">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-bind="visible: NextScheduledTimestamp">
|
||||
<td class="nextScheduledTimestamp">Next Scheduled: <span data-bind="text: NextScheduledTimestampFormatted"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
ko.bindingHandlers.progressValue = {
|
||||
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
|
||||
var $element = $(element);
|
||||
if (!$element.is('.ui-progressbar'))
|
||||
$element.progressbar();
|
||||
},
|
||||
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
|
||||
var v = ko.utils.unwrapObservable(valueAccessor());
|
||||
var vInt = parseInt(v);
|
||||
if (vInt >= 0) {
|
||||
$(element).progressbar('option', 'value', vInt);
|
||||
}
|
||||
}
|
||||
};
|
||||
//* http://webcloud.se/log/JavaScript-and-ISO-8601/
|
||||
Date.prototype.setISO8601 = function (string) {
|
||||
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
|
||||
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
|
||||
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
|
||||
var d = string.match(new RegExp(regexp));
|
||||
|
||||
var offset = 0;
|
||||
var date = new Date(d[1], 0, 1);
|
||||
|
||||
if (d[3]) { date.setMonth(d[3] - 1); }
|
||||
if (d[5]) { date.setDate(d[5]); }
|
||||
if (d[7]) { date.setHours(d[7]); }
|
||||
if (d[8]) { date.setMinutes(d[8]); }
|
||||
if (d[10]) { date.setSeconds(d[10]); }
|
||||
if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
|
||||
if (d[14]) {
|
||||
offset = (Number(d[16]) * 60) + Number(d[17]);
|
||||
offset *= ((d[15] == '-') ? 1 : -1);
|
||||
}
|
||||
|
||||
offset -= date.getTimezoneOffset();
|
||||
time = (Number(date) + (offset * 60 * 1000));
|
||||
this.setTime(Number(time));
|
||||
return this;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var sessionId = '@(Model)';
|
||||
|
||||
var view = $('#Logging_Task_Status');
|
||||
var vm = null;
|
||||
|
||||
var notificationsHub = null;
|
||||
|
||||
var statusViewModel = function (sessionId) {
|
||||
var self = this;
|
||||
|
||||
self.Initialized = ko.observable(false);
|
||||
|
||||
self.TimestampParse = function (timestamp) {
|
||||
if (timestamp) {
|
||||
if (timestamp.indexOf("\/Date(") == 0)
|
||||
return new Date(parseInt(timestamp.substr(6)));
|
||||
else
|
||||
return (new Date()).setISO8601(timestamp);
|
||||
}
|
||||
return new Date();
|
||||
}
|
||||
self.TimestampFormat = function (timestamp) {
|
||||
var addZero = function (v) { v = v + ''; if (v.length == 1) v = '0' + v; return v; }
|
||||
return timestamp.getFullYear() + '/' + addZero((1 + timestamp.getMonth())) + '/' + addZero(timestamp.getDate()) + ' ' + addZero(timestamp.getHours()) + ':' + addZero(timestamp.getMinutes()) + ':' + addZero(timestamp.getSeconds());
|
||||
}
|
||||
|
||||
self.SessionId = sessionId;
|
||||
self.TaskName = ko.observable(null);
|
||||
|
||||
self.Progress = ko.observable(0);
|
||||
self.CurrentProcess = ko.observable(null);
|
||||
self.CurrentDescription = ko.observable(null);
|
||||
|
||||
self.IsRunning = ko.observable(null);
|
||||
|
||||
self.TaskExceptionMessage = ko.observable(null);
|
||||
|
||||
self.FinishedTimestamp = ko.observable(null);
|
||||
self.NextScheduledTimestamp = ko.observable(null)
|
||||
|
||||
self.NextScheduledTimestampFormatted = ko.computed(function () {
|
||||
return self.TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));
|
||||
});
|
||||
self.FinishedTimestampFormatted = ko.computed(function () {
|
||||
return self.TimestampFormat(self.TimestampParse(self.FinishedTimestamp()));
|
||||
});
|
||||
|
||||
self.FinishedUrl = ko.observable(null);
|
||||
self.FinishedMessage = ko.observable(null);
|
||||
|
||||
self.Finished = function () {
|
||||
if (self.FinishedTimestamp()) {
|
||||
if (self.FinishedUrl() && !self.TaskExceptionMessage()) {
|
||||
if (self.FinishedMessage())
|
||||
window.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);
|
||||
else
|
||||
window.location.href = self.FinishedUrl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.Initialize = function (taskStatus) {
|
||||
if (!self.Initialized()) {
|
||||
self.TaskName(taskStatus.TaskName);
|
||||
self.FinishedUrl(taskStatus.FinishedUrl);
|
||||
|
||||
self.Progress(taskStatus.Progress);
|
||||
self.CurrentProcess(taskStatus.CurrentProcess);
|
||||
self.CurrentDescription(taskStatus.CurrentDescription);
|
||||
|
||||
self.IsRunning(taskStatus.IsRunning);
|
||||
|
||||
self.TaskExceptionMessage(taskStatus.TaskExceptionMessage);
|
||||
|
||||
self.FinishedTimestamp(taskStatus.FinishedTimestamp);
|
||||
self.NextScheduledTimestamp(taskStatus.NextScheduledTimestamp);
|
||||
|
||||
self.FinishedMessage(taskStatus.FinishedMessage);
|
||||
|
||||
self.Initialized(true);
|
||||
|
||||
self.Finished();
|
||||
}
|
||||
}
|
||||
self.Update = function (taskStatus) {
|
||||
if (!self.Initialized())
|
||||
return;
|
||||
|
||||
if (taskStatus) {
|
||||
$.each(taskStatus, function (key, value) {
|
||||
switch (key) {
|
||||
case 'Progress':
|
||||
self.Progress(value);
|
||||
break;
|
||||
case 'CurrentProcess':
|
||||
self.CurrentProcess(value);
|
||||
break;
|
||||
case 'CurrentDescription':
|
||||
self.CurrentDescription(value);
|
||||
break;
|
||||
case 'IsRunning':
|
||||
self.IsRunning(value);
|
||||
break;
|
||||
case 'TaskExceptionMessage':
|
||||
self.TaskExceptionMessage(value);
|
||||
break;
|
||||
case 'NextScheduledTimestamp':
|
||||
self.NextScheduledTimestamp(value);
|
||||
break;
|
||||
case 'FinishedUrl':
|
||||
self.FinishedUrl(value);
|
||||
break;
|
||||
case 'FinishedMessage':
|
||||
self.FinishedMessage(value);
|
||||
break;
|
||||
case 'FinishedTimestamp':
|
||||
self.FinishedTimestamp(value);
|
||||
window.setTimeout(self.Finished, 1);
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm = new statusViewModel(sessionId);
|
||||
ko.applyBindings(vm, view[0]);
|
||||
|
||||
// Start Live Connection
|
||||
updateWithLive();
|
||||
|
||||
function updateWithLive() {
|
||||
notificationsHub = $.connection.scheduledTaskNotifications;
|
||||
notificationsHub.client.initializeTaskStatus = vm.Initialize;
|
||||
notificationsHub.client.updateTaskStatus = vm.Update;
|
||||
|
||||
$.connection.hub.qs = { TaskSessionId: sessionId };
|
||||
$.connection.hub.error(function (error) {
|
||||
alert('Live-Status Error: ' + error);
|
||||
});
|
||||
|
||||
$.connection.hub.start()
|
||||
.fail(function (error) {
|
||||
alert('Live-Status Connection Error: ' + error);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,281 @@
|
||||
#pragma warning disable 1591
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Disco.Web.Areas.Config.Views.Shared
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Ajax;
|
||||
using System.Web.Mvc.Html;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.UI;
|
||||
using System.Web.WebPages;
|
||||
using Disco;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web;
|
||||
using Disco.Web.Extensions;
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Shared/TaskStatus.cshtml")]
|
||||
public partial class TaskStatus : Disco.Services.Web.WebViewPage<string>
|
||||
{
|
||||
public TaskStatus()
|
||||
{
|
||||
}
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
#line 2 "..\..\Areas\Config\Views\Shared\TaskStatus.cshtml"
|
||||
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n<div");
|
||||
|
||||
WriteLiteral(" style=\"min-height: 300px;\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"Logging_Task_Status\"");
|
||||
|
||||
WriteLiteral(" class=\"form\"");
|
||||
|
||||
WriteLiteral(" style=\"width: 520px;\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: Initialized\"");
|
||||
|
||||
WriteLiteral(">\r\n <h2");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: TaskName\"");
|
||||
|
||||
WriteLiteral("> </h2>\r\n <table>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <th");
|
||||
|
||||
WriteLiteral(" class=\"process\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: CurrentProcess\"");
|
||||
|
||||
WriteLiteral("> \r\n </th>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"description\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: CurrentDescription\"");
|
||||
|
||||
WriteLiteral("> \r\n </td>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: IsRunning\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"progress\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" data-bind=\"progressValue: Progress\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: FinishedTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"finishedTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>Finished: <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: FinishedTimestampFormatted\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: FinishedTimestamp() && !TaskExceptionMessage()\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"finishedMessage\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"css: { finishedRedirect: FinishedUrl }\"");
|
||||
|
||||
WriteLiteral(">\r\n <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: FinishedMessage\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: TaskExceptionMessage\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"exception\"");
|
||||
|
||||
WriteLiteral(">Last Error:\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: TaskExceptionMessage\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n </td>\r\n </tr>\r\n " +
|
||||
" <tr");
|
||||
|
||||
WriteLiteral(" data-bind=\"visible: NextScheduledTimestamp\"");
|
||||
|
||||
WriteLiteral(">\r\n <td");
|
||||
|
||||
WriteLiteral(" class=\"nextScheduledTimestamp\"");
|
||||
|
||||
WriteLiteral(">Next Scheduled: <span");
|
||||
|
||||
WriteLiteral(" data-bind=\"text: NextScheduledTimestampFormatted\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r" +
|
||||
"\n</div>\r\n<script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
|
||||
WriteLiteral(">\r\n ko.bindingHandlers.progressValue = {\r\n init: function (element, val" +
|
||||
"ueAccessor, allBindingsAccessor, viewModel) {\r\n var $element = $(elem" +
|
||||
"ent);\r\n if (!$element.is(\'.ui-progressbar\'))\r\n $elemen" +
|
||||
"t.progressbar();\r\n },\r\n update: function (element, valueAccessor, " +
|
||||
"allBindingsAccessor, viewModel) {\r\n var v = ko.utils.unwrapObservable" +
|
||||
"(valueAccessor());\r\n var vInt = parseInt(v);\r\n if (vInt >=" +
|
||||
" 0) {\r\n $(element).progressbar(\'option\', \'value\', vInt);\r\n " +
|
||||
" }\r\n }\r\n };\r\n //* http://webcloud.se/log/JavaScript-and-ISO-860" +
|
||||
"1/\r\n Date.prototype.setISO8601 = function (string) {\r\n var regexp = \"(" +
|
||||
"[0-9]{4})(-([0-9]{2})(-([0-9]{2})\" +\r\n \"(T([0-9]{2}):([0-9]{2})(:([0-9]{2" +
|
||||
"})(\\.([0-9]+))?)?\" +\r\n \"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?\";\r\n " +
|
||||
" var d = string.match(new RegExp(regexp));\r\n\r\n var offset = 0;\r\n " +
|
||||
" var date = new Date(d[1], 0, 1);\r\n\r\n if (d[3]) { date.setMonth(d[3] - 1)" +
|
||||
"; }\r\n if (d[5]) { date.setDate(d[5]); }\r\n if (d[7]) { date.setHour" +
|
||||
"s(d[7]); }\r\n if (d[8]) { date.setMinutes(d[8]); }\r\n if (d[10]) { d" +
|
||||
"ate.setSeconds(d[10]); }\r\n if (d[12]) { date.setMilliseconds(Number(\"0.\" " +
|
||||
"+ d[12]) * 1000); }\r\n if (d[14]) {\r\n offset = (Number(d[16]) *" +
|
||||
" 60) + Number(d[17]);\r\n offset *= ((d[15] == \'-\') ? 1 : -1);\r\n " +
|
||||
" }\r\n\r\n offset -= date.getTimezoneOffset();\r\n time = (Number(date) " +
|
||||
"+ (offset * 60 * 1000));\r\n this.setTime(Number(time));\r\n return th" +
|
||||
"is;\r\n }\r\n</script>\r\n<script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
|
||||
WriteLiteral(">\r\n $(function () {\r\n var sessionId = \'");
|
||||
|
||||
|
||||
#line 92 "..\..\Areas\Config\Views\Shared\TaskStatus.cshtml"
|
||||
Write(Model);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n\r\n var view = $(\'#Logging_Task_Status\');\r\n var vm = null;\r\n\r\n " +
|
||||
" var notificationsHub = null;\r\n\r\n var statusViewModel = function (se" +
|
||||
"ssionId) {\r\n var self = this;\r\n\r\n self.Initialized = ko.ob" +
|
||||
"servable(false);\r\n\r\n self.TimestampParse = function (timestamp) {\r\n " +
|
||||
" if (timestamp) {\r\n if (timestamp.indexOf(\"\\/Dat" +
|
||||
"e(\") == 0)\r\n return new Date(parseInt(timestamp.substr(6)" +
|
||||
"));\r\n else\r\n return (new Date()).setIS" +
|
||||
"O8601(timestamp);\r\n }\r\n return new Date();\r\n " +
|
||||
" }\r\n self.TimestampFormat = function (timestamp) {\r\n " +
|
||||
" var addZero = function (v) { v = v + \'\'; if (v.length == 1) v = \'0\' + v; ret" +
|
||||
"urn v; }\r\n return timestamp.getFullYear() + \'/\' + addZero((1 + ti" +
|
||||
"mestamp.getMonth())) + \'/\' + addZero(timestamp.getDate()) + \' \' + addZero(timest" +
|
||||
"amp.getHours()) + \':\' + addZero(timestamp.getMinutes()) + \':\' + addZero(timestam" +
|
||||
"p.getSeconds());\r\n }\r\n\r\n self.SessionId = sessionId;\r\n " +
|
||||
" self.TaskName = ko.observable(null);\r\n\r\n self.Progress = ko.o" +
|
||||
"bservable(0);\r\n self.CurrentProcess = ko.observable(null);\r\n " +
|
||||
" self.CurrentDescription = ko.observable(null);\r\n\r\n self.IsRunning " +
|
||||
"= ko.observable(null);\r\n\r\n self.TaskExceptionMessage = ko.observable(" +
|
||||
"null);\r\n\r\n self.FinishedTimestamp = ko.observable(null);\r\n " +
|
||||
" self.NextScheduledTimestamp = ko.observable(null)\r\n\r\n self.NextSched" +
|
||||
"uledTimestampFormatted = ko.computed(function () {\r\n return self." +
|
||||
"TimestampFormat(self.TimestampParse(self.NextScheduledTimestamp()));\r\n " +
|
||||
" });\r\n self.FinishedTimestampFormatted = ko.computed(function () {\r\n" +
|
||||
" return self.TimestampFormat(self.TimestampParse(self.FinishedTim" +
|
||||
"estamp()));\r\n });\r\n\r\n self.FinishedUrl = ko.observable(nul" +
|
||||
"l);\r\n self.FinishedMessage = ko.observable(null);\r\n\r\n self" +
|
||||
".Finished = function () {\r\n if (self.FinishedTimestamp()) {\r\n " +
|
||||
" if (self.FinishedUrl() && !self.TaskExceptionMessage()) {\r\n " +
|
||||
" if (self.FinishedMessage())\r\n wind" +
|
||||
"ow.setTimeout(function () { window.location.href = self.FinishedUrl(); }, 3000);" +
|
||||
"\r\n else\r\n window.location.href" +
|
||||
" = self.FinishedUrl();\r\n }\r\n }\r\n }\r" +
|
||||
"\n\r\n self.Initialize = function (taskStatus) {\r\n if (!s" +
|
||||
"elf.Initialized()) {\r\n self.TaskName(taskStatus.TaskName);\r\n " +
|
||||
" self.FinishedUrl(taskStatus.FinishedUrl);\r\n\r\n " +
|
||||
" self.Progress(taskStatus.Progress);\r\n self.CurrentProcess" +
|
||||
"(taskStatus.CurrentProcess);\r\n self.CurrentDescription(taskSt" +
|
||||
"atus.CurrentDescription);\r\n\r\n self.IsRunning(taskStatus.IsRun" +
|
||||
"ning);\r\n\r\n self.TaskExceptionMessage(taskStatus.TaskException" +
|
||||
"Message);\r\n\r\n self.FinishedTimestamp(taskStatus.FinishedTimes" +
|
||||
"tamp);\r\n self.NextScheduledTimestamp(taskStatus.NextScheduled" +
|
||||
"Timestamp);\r\n\r\n self.FinishedMessage(taskStatus.FinishedMessa" +
|
||||
"ge);\r\n\r\n self.Initialized(true);\r\n\r\n self." +
|
||||
"Finished();\r\n }\r\n }\r\n self.Update = functio" +
|
||||
"n (taskStatus) {\r\n if (!self.Initialized())\r\n " +
|
||||
"return;\r\n\r\n if (taskStatus) {\r\n $.each(taskSta" +
|
||||
"tus, function (key, value) {\r\n switch (key) {\r\n " +
|
||||
" case \'Progress\':\r\n self.Progres" +
|
||||
"s(value);\r\n break;\r\n c" +
|
||||
"ase \'CurrentProcess\':\r\n self.CurrentProcess(value" +
|
||||
");\r\n break;\r\n case \'Cu" +
|
||||
"rrentDescription\':\r\n self.CurrentDescription(valu" +
|
||||
"e);\r\n break;\r\n case \'I" +
|
||||
"sRunning\':\r\n self.IsRunning(value);\r\n " +
|
||||
" break;\r\n case \'TaskExceptionMessa" +
|
||||
"ge\':\r\n self.TaskExceptionMessage(value);\r\n " +
|
||||
" break;\r\n case \'NextScheduled" +
|
||||
"Timestamp\':\r\n self.NextScheduledTimestamp(value);" +
|
||||
"\r\n break;\r\n case \'Fini" +
|
||||
"shedUrl\':\r\n self.FinishedUrl(value);\r\n " +
|
||||
" break;\r\n case \'FinishedMessage\':" +
|
||||
"\r\n self.FinishedMessage(value);\r\n " +
|
||||
" break;\r\n case \'FinishedTimestamp\':\r\n " +
|
||||
" self.FinishedTimestamp(value);\r\n " +
|
||||
" window.setTimeout(self.Finished, 1);\r\n " +
|
||||
" break;\r\n default:\r\n " +
|
||||
" // Ignore\r\n }\r\n });\r\n " +
|
||||
" }\r\n }\r\n }\r\n\r\n vm = new statusViewModel(sessionId);\r\n " +
|
||||
" ko.applyBindings(vm, view[0]);\r\n\r\n // Start Live Connection\r\n " +
|
||||
" updateWithLive();\r\n\r\n function updateWithLive() {\r\n notific" +
|
||||
"ationsHub = $.connection.scheduledTaskNotifications;\r\n notificationsH" +
|
||||
"ub.client.initializeTaskStatus = vm.Initialize;\r\n notificationsHub.cl" +
|
||||
"ient.updateTaskStatus = vm.Update;\r\n\r\n $.connection.hub.qs = { TaskSe" +
|
||||
"ssionId: sessionId };\r\n $.connection.hub.error(function (error) {\r\n " +
|
||||
" alert(\'Live-Status Error: \' + error);\r\n });\r\n\r\n " +
|
||||
" $.connection.hub.start()\r\n .fail(function (error) {\r\n " +
|
||||
" alert(\'Live-Status Connection Error: \' + error);\r\n })" +
|
||||
";\r\n }\r\n\r\n });\r\n</script>\r\n");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
@@ -1,6 +1,5 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Jobs.Noticeboards;
|
||||
using Disco.Services.Web;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
|
||||
@@ -8,81 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
|
||||
{
|
||||
public partial class HeldDevicesController : DatabaseController
|
||||
{
|
||||
#region Helpers
|
||||
|
||||
private List<Models.HeldDevices.HeldDeviceModel> GetHeldDevices(IQueryable<Job> query)
|
||||
{
|
||||
var jobs = query.Where(j =>
|
||||
!j.ClosedDate.HasValue &&
|
||||
j.DeviceSerialNumber != null &&
|
||||
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
|
||||
).Select(j => new Models.HeldDevices.HeldDeviceQueryModel
|
||||
{
|
||||
JobId = j.Id,
|
||||
DeviceSerialNumber = j.DeviceSerialNumber,
|
||||
DeviceComputerName = j.Device.DeviceDomainId,
|
||||
DeviceLocation = j.Device.Location,
|
||||
DeviceProfileId = j.Device.DeviceProfileId,
|
||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
||||
UserId = j.Device.AssignedUserId,
|
||||
UserDisplayName = j.Device.AssignedUser.DisplayName,
|
||||
WaitingForUserAction = j.WaitingForUserAction.HasValue || ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue),
|
||||
WaitingForUserActionSince = j.WaitingForUserAction.HasValue ? j.WaitingForUserAction : (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue ? j.JobMetaNonWarranty.AccountingChargeRequiredDate : j.JobMetaNonWarranty.AccountingChargeAddedDate),
|
||||
ReadyForReturn = j.DeviceReadyForReturn.HasValue,
|
||||
EstimatedReturnTime = j.ExpectedClosedDate,
|
||||
ReadyForReturnSince = j.DeviceReadyForReturn
|
||||
}).GroupBy(j => j.DeviceSerialNumber);
|
||||
|
||||
var thd = new List<Models.HeldDevices.HeldDeviceModel>();
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
if (job.Any(j => j.WaitingForUserAction))
|
||||
{
|
||||
thd.Add(job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (job.All(j => j.ReadyForReturn))
|
||||
{
|
||||
thd.Add(job.FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
else
|
||||
{
|
||||
thd.Add(job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
}
|
||||
}
|
||||
return thd;
|
||||
}
|
||||
|
||||
private List<Models.HeldDevices.HeldDeviceModel> GetHeldDevices()
|
||||
{
|
||||
return GetHeldDevices(Database.Jobs);
|
||||
}
|
||||
private Models.HeldDevices.HeldDeviceModel GetHeldDevice(string DeviceSerialNumber)
|
||||
{
|
||||
return GetHeldDevices(Database.Jobs.Where(j => j.DeviceSerialNumber == DeviceSerialNumber)).FirstOrDefault();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public virtual ActionResult Index()
|
||||
{
|
||||
return View(GetHeldDevices());
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
|
||||
|
||||
return View(m);
|
||||
}
|
||||
|
||||
public virtual ActionResult ReadyForReturnXml()
|
||||
{
|
||||
var readyForReturn = GetHeldDevices().Where(j => j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
|
||||
var readyForReturn = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
|
||||
.Where(j => j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(readyForReturn);
|
||||
}
|
||||
public virtual ActionResult WaitingForUserActionXml()
|
||||
{
|
||||
var waitingForUserAction = GetHeldDevices().Where(j => j.WaitingForUserAction).ToArray();
|
||||
var waitingForUserAction = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
|
||||
.Where(j => j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(waitingForUserAction);
|
||||
}
|
||||
public virtual ActionResult HeldDevicesXml()
|
||||
{
|
||||
var heldDevices = GetHeldDevices().Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
|
||||
var heldDevices = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database)
|
||||
.Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(heldDevices);
|
||||
}
|
||||
|
||||
@@ -93,13 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
|
||||
|
||||
public virtual ActionResult HeldDevice(string id)
|
||||
{
|
||||
var uhd = GetHeldDevice(id);
|
||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevice(Database, id);
|
||||
|
||||
return Json(m, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
public virtual ActionResult HeldDevices()
|
||||
{
|
||||
var uhd = GetHeldDevices();
|
||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
|
||||
|
||||
return Json(m, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Jobs.Noticeboards;
|
||||
using Disco.Services.Web;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
|
||||
@@ -8,79 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
|
||||
{
|
||||
public partial class UserHeldDevicesController : DatabaseController
|
||||
{
|
||||
#region Helpers
|
||||
|
||||
private List<Models.UserHeldDevices.UserHeldDeviceModel> GetUserHeldDevices(IQueryable<Job> query)
|
||||
{
|
||||
var jobs = query.Where(j =>
|
||||
!j.ClosedDate.HasValue && j.Device.AssignedUserId != null &&
|
||||
j.DeviceSerialNumber != null &&
|
||||
((j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue) || j.WaitingForUserAction.HasValue)
|
||||
).Select(j => new Models.UserHeldDevices.HeldJobDeviceModel
|
||||
{
|
||||
JobId = j.Id,
|
||||
WaitingForUserAction = j.WaitingForUserAction.HasValue || ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue),
|
||||
WaitingForUserActionSince = j.WaitingForUserAction.HasValue ? j.WaitingForUserAction : (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue ? j.JobMetaNonWarranty.AccountingChargeRequiredDate : j.JobMetaNonWarranty.AccountingChargeAddedDate),
|
||||
ReadyForReturn = j.DeviceReadyForReturn.HasValue,
|
||||
EstimatedReturnTime = j.ExpectedClosedDate,
|
||||
ReadyForReturnSince = j.DeviceReadyForReturn,
|
||||
UserId = j.Device.AssignedUserId,
|
||||
UserDisplayName = j.Device.AssignedUser.DisplayName,
|
||||
DeviceProfileId = j.Device.DeviceProfileId,
|
||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress
|
||||
}).GroupBy(j => j.UserId);
|
||||
|
||||
var thd = new List<Models.UserHeldDevices.UserHeldDeviceModel>();
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
if (job.Any(j => j.WaitingForUserAction))
|
||||
{
|
||||
thd.Add(job.Where(j => j.WaitingForUserAction).OrderBy(j => j.WaitingForUserActionSince).FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (job.All(j => j.ReadyForReturn))
|
||||
{
|
||||
thd.Add(job.FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
else
|
||||
{
|
||||
thd.Add(job.Where(j => !j.ReadyForReturn).OrderByDescending(j => j.EstimatedReturnTime).FirstOrDefault().ToUserHeldDeviceModel(Database));
|
||||
}
|
||||
}
|
||||
}
|
||||
return thd;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private List<Models.UserHeldDevices.UserHeldDeviceModel> GetUserHeldDevices()
|
||||
{
|
||||
return GetUserHeldDevices(Database.Jobs);
|
||||
}
|
||||
private Models.UserHeldDevices.UserHeldDeviceModel GetUserHeldDevice(string UserId)
|
||||
{
|
||||
return GetUserHeldDevices(Database.Jobs.Where(j => j.Device.AssignedUserId == UserId)).FirstOrDefault();
|
||||
}
|
||||
|
||||
public virtual ActionResult Index()
|
||||
{
|
||||
return View(GetUserHeldDevices());
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
|
||||
|
||||
return View(m);
|
||||
}
|
||||
|
||||
public virtual ActionResult ReadyForReturnXml()
|
||||
{
|
||||
var readyForReturn = GetUserHeldDevices().Where(j => j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
|
||||
var readyForReturn = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
|
||||
.Where(j => j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(readyForReturn);
|
||||
}
|
||||
public virtual ActionResult WaitingForUserActionXml()
|
||||
{
|
||||
var userHeldDevices = GetUserHeldDevices().Where(j => j.WaitingForUserAction).ToArray();
|
||||
var userHeldDevices = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
|
||||
.Where(j => j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(userHeldDevices);
|
||||
}
|
||||
public virtual ActionResult UserHeldDevicesXml()
|
||||
{
|
||||
var userHeldDevices = GetUserHeldDevices().Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).ToArray();
|
||||
var userHeldDevices = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database)
|
||||
.Where(j => !j.ReadyForReturn && !j.WaitingForUserAction).Cast<HeldDeviceItem>().ToArray();
|
||||
|
||||
return new Extensions.XmlResult(userHeldDevices);
|
||||
}
|
||||
|
||||
@@ -91,14 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
|
||||
|
||||
public virtual ActionResult UserHeldDevice(string id)
|
||||
{
|
||||
var uhd = GetUserHeldDevice(id);
|
||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDeviceForUsers(Database, id);
|
||||
|
||||
return Json(m, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
public virtual ActionResult UserHeldDevices()
|
||||
{
|
||||
var uhd = GetUserHeldDevices();
|
||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
|
||||
|
||||
return Json(m, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
namespace Disco.Web.Areas.Public.Models.HeldDevices
|
||||
{
|
||||
public class HeldDeviceModel
|
||||
{
|
||||
public string DeviceSerialNumber { get; set; }
|
||||
public string DeviceComputerName { get; set; }
|
||||
public int DeviceProfileId { get; set; }
|
||||
public string DeviceAddress { get; set; }
|
||||
public string DeviceLocation { get; set; }
|
||||
public string DeviceDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(this.DeviceComputerName);
|
||||
|
||||
if (UserId != null)
|
||||
sb.Append(" - ").Append(this.UserDisplayName).Append(" (").Append(this.UserId).Append(")");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(this.DeviceLocation))
|
||||
sb.Append(" - ").Append(this.DeviceLocation);
|
||||
else if (UserId == null)
|
||||
sb.Append(" - ").Append(this.DeviceSerialNumber);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public string UserId { get; set; }
|
||||
public string UserDisplayName { get; set; }
|
||||
public bool WaitingForUserAction { get; set; }
|
||||
public string WaitingForUserActionSince { get; set; }
|
||||
|
||||
public bool ReadyForReturn { get; set; }
|
||||
public string EstimatedReturnTime { get; set; }
|
||||
public string ReadyForReturnSince { get; set; }
|
||||
public bool IsAlert { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Disco.BI.Extensions;
|
||||
|
||||
namespace Disco.Web.Areas.Public.Models.HeldDevices
|
||||
{
|
||||
public class HeldDeviceQueryModel
|
||||
{
|
||||
public int JobId { get; set; }
|
||||
|
||||
public string DeviceSerialNumber { get; set; }
|
||||
public string DeviceComputerName { get; set; }
|
||||
public int DeviceProfileId { get; set; }
|
||||
public int? DeviceAddressId { get; set; }
|
||||
public string DeviceLocation { get; set; }
|
||||
|
||||
public string UserId { get; set; }
|
||||
public string UserDisplayName { get; set; }
|
||||
|
||||
public bool ReadyForReturn { get; set; }
|
||||
public bool WaitingForUserAction { get; set; }
|
||||
public DateTime? EstimatedReturnTime { get; set; }
|
||||
public DateTime? ReadyForReturnSince { get; set; }
|
||||
public DateTime? WaitingForUserActionSince { get; set; }
|
||||
|
||||
public HeldDeviceModel ToUserHeldDeviceModel(DiscoDataContext Database)
|
||||
{
|
||||
var uhdm = new HeldDeviceModel()
|
||||
{
|
||||
DeviceSerialNumber = this.DeviceSerialNumber,
|
||||
DeviceComputerName = this.DeviceComputerName,
|
||||
DeviceLocation = this.DeviceLocation,
|
||||
DeviceProfileId = this.DeviceProfileId,
|
||||
DeviceAddress = (this.DeviceAddressId.HasValue ? Database.DiscoConfiguration.OrganisationAddresses.GetAddress(this.DeviceAddressId.Value).ShortName : string.Empty),
|
||||
UserId = this.UserId,
|
||||
UserDisplayName = this.UserDisplayName,
|
||||
ReadyForReturn = this.ReadyForReturn,
|
||||
WaitingForUserAction = this.WaitingForUserAction
|
||||
};
|
||||
var n = DateTime.Now;
|
||||
if (!this.ReadyForReturn && this.EstimatedReturnTime.HasValue && this.EstimatedReturnTime.Value > n)
|
||||
{
|
||||
uhdm.EstimatedReturnTime = this.EstimatedReturnTime.FromNow();
|
||||
}
|
||||
if (this.ReadyForReturn)
|
||||
{
|
||||
uhdm.ReadyForReturnSince = this.ReadyForReturnSince.FromNow();
|
||||
uhdm.IsAlert = (this.ReadyForReturnSince.Value < DateTime.Now.AddDays(-3));
|
||||
}
|
||||
if (this.WaitingForUserAction)
|
||||
{
|
||||
uhdm.WaitingForUserActionSince = this.WaitingForUserActionSince.FromNow();
|
||||
uhdm.IsAlert = (this.WaitingForUserActionSince.Value < n.AddDays(-6));
|
||||
}
|
||||
return uhdm;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Disco.BI.Interop.SignalRHandlers;
|
||||
|
||||
namespace Disco.Web.Areas.Public
|
||||
{
|
||||
@@ -17,11 +16,6 @@ namespace Disco.Web.Areas.Public
|
||||
|
||||
public override void RegisterArea(AreaRegistrationContext context)
|
||||
{
|
||||
context.Routes.MapConnection<UserHeldDeviceNotifications>(
|
||||
"Public_UserHeldDevices_Notifications", "Public/UserHeldDevices/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
context.Routes.MapConnection<HeldDeviceNotifications>(
|
||||
"Public_HeldDevices_Notifications", "Public/HeldDevices/Notifications", new ConnectionConfiguration(), SignalRAuthenticationWorkaround.AddMiddleware);
|
||||
|
||||
context.MapRoute(
|
||||
"Public_Credits",
|
||||
"Public/Credits/{id}",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@model IEnumerable<Disco.Web.Areas.Public.Models.HeldDevices.HeldDeviceModel>
|
||||
@model IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>
|
||||
@{
|
||||
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices", null);
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
||||
@@ -10,16 +10,16 @@
|
||||
}
|
||||
<h2>In Process (@DevicesInProcess.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in DevicesInProcess)
|
||||
@foreach (var item in DevicesInProcess.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.DeviceComputerName
|
||||
@item.DeviceComputerNameFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@if (item.UserId != null)
|
||||
{
|
||||
<span class="user">@item.UserDisplayName (@item.UserId)</span>
|
||||
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||
{
|
||||
@@ -36,9 +36,9 @@
|
||||
@item.DeviceSerialNumber
|
||||
}
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
|
||||
@if (item.EstimatedReturnTime.HasValue)
|
||||
{
|
||||
<span class="smallMessage">(Expected: @item.EstimatedReturnTime)</span>
|
||||
<span class="smallMessage">(Expected: @CommonHelpers.FriendlyDate(item.EstimatedReturnTime))</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -51,16 +51,16 @@
|
||||
}
|
||||
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in WaitingForUserActionJobs)
|
||||
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.DeviceComputerName
|
||||
@item.DeviceComputerNameFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@if (item.UserId != null)
|
||||
{
|
||||
<span class="user">@item.UserDisplayName (@item.UserId)</span>
|
||||
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||
{
|
||||
@@ -78,7 +78,7 @@
|
||||
}
|
||||
}
|
||||
</td>
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @item.WaitingForUserActionSince
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @CommonHelpers.FriendlyDate(item.WaitingForUserActionSince)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@@ -89,16 +89,16 @@
|
||||
}
|
||||
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in DevicesReadyForReturn)
|
||||
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.DeviceComputerName
|
||||
@item.DeviceComputerNameFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@if (item.UserId != null)
|
||||
{
|
||||
<span class="user">@item.UserDisplayName (@item.UserId)</span>
|
||||
<span class="user">@item.UserDisplayName (@item.UserIdFriendly)</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||
{
|
||||
@@ -116,7 +116,7 @@
|
||||
}
|
||||
}
|
||||
</td>
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @item.ReadyForReturnSince
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @CommonHelpers.FriendlyDate(item.ReadyForReturnSince)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -36,7 +36,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/HeldDevices/Index.cshtml")]
|
||||
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Web.Areas.Public.Models.HeldDevices.HeldDeviceModel>>
|
||||
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>>
|
||||
{
|
||||
public Index()
|
||||
{
|
||||
@@ -99,7 +99,7 @@ WriteLiteral(">\r\n");
|
||||
#line hidden
|
||||
|
||||
#line 13 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesInProcess)
|
||||
foreach (var item in DevicesInProcess.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 17 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.DeviceComputerName);
|
||||
Write(item.DeviceComputerNameFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -157,7 +157,7 @@ WriteLiteral(" (");
|
||||
|
||||
|
||||
#line 22 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -235,7 +235,7 @@ WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 39 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
|
||||
if (item.EstimatedReturnTime.HasValue)
|
||||
{
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ WriteLiteral(">(Expected: ");
|
||||
|
||||
|
||||
#line 41 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.EstimatedReturnTime);
|
||||
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -315,7 +315,7 @@ WriteLiteral(">\r\n");
|
||||
#line hidden
|
||||
|
||||
#line 54 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
foreach (var item in WaitingForUserActionJobs)
|
||||
foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -331,7 +331,7 @@ WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 58 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.DeviceComputerName);
|
||||
Write(item.DeviceComputerNameFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -373,7 +373,7 @@ WriteLiteral(" (");
|
||||
|
||||
|
||||
#line 63 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -449,22 +449,22 @@ WriteLiteral("\r\n");
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n <td");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 3267), Tuple.Create("\"", 3325)
|
||||
, Tuple.Create(Tuple.Create("", 3275), Tuple.Create("timestamp", 3275), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 3397), Tuple.Create("\"", 3455)
|
||||
, Tuple.Create(Tuple.Create("", 3405), Tuple.Create("timestamp", 3405), true)
|
||||
|
||||
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 3284), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
, Tuple.Create(Tuple.Create("", 3414), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 3284), false)
|
||||
, 3414), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">Since ");
|
||||
|
||||
|
||||
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.WaitingForUserActionSince);
|
||||
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -517,7 +517,7 @@ WriteLiteral(">\r\n");
|
||||
#line hidden
|
||||
|
||||
#line 92 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesReadyForReturn)
|
||||
foreach (var item in DevicesReadyForReturn.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -533,7 +533,7 @@ WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 96 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.DeviceComputerName);
|
||||
Write(item.DeviceComputerNameFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -575,7 +575,7 @@ WriteLiteral(" (");
|
||||
|
||||
|
||||
#line 101 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -651,22 +651,22 @@ WriteLiteral("\r\n");
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n <td");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4805), Tuple.Create("\"", 4863)
|
||||
, Tuple.Create(Tuple.Create("", 4813), Tuple.Create("timestamp", 4813), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 5022), Tuple.Create("\"", 5080)
|
||||
, Tuple.Create(Tuple.Create("", 5030), Tuple.Create("timestamp", 5030), true)
|
||||
|
||||
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4822), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
, Tuple.Create(Tuple.Create("", 5039), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 4822), false)
|
||||
, 5039), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">Ready ");
|
||||
|
||||
|
||||
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||
Write(item.ReadyForReturnSince);
|
||||
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
|
||||
|
||||
|
||||
#line default
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@{
|
||||
Layout = null;
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
Html.BundleDeferred("~/ClientScripts/Core");
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||
@@ -9,468 +10,397 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Disco - Held Devices</title>
|
||||
<title>Disco ICT - Held Devices</title>
|
||||
@Html.BundleRenderDeferred()
|
||||
</head>
|
||||
<body>
|
||||
<body class="status-connecting">
|
||||
<div id="page">
|
||||
<header id="mainHeader">
|
||||
Held Devices
|
||||
<header id="header">
|
||||
<div id="heading">Held Devices</div>
|
||||
<div id="statusConnecting"><i class="fa fa-cog fa-spin"></i><span>connecting...</span></div>
|
||||
<div id="statusError"><i class="fa fa-cog fa-spin"></i><span>disconnected, reconnecting...</span></div>
|
||||
<div id="credits">
|
||||
powered by Disco ICT <i title="Disco ICT - Jobs"></i>
|
||||
</div>
|
||||
</header>
|
||||
<section id="mainSection">
|
||||
<div id="inProcess" class="list">
|
||||
<h3>In Process <span id="inProcessCount"></span>
|
||||
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: inProcess().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="readyForReturn" class="list">
|
||||
<h3>Ready for Return <span id="readyForReturnCount"></span>
|
||||
<h3>Ready for Return (<span data-bind="text: readyForReturn().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: readyForReturn().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="waitingForUserAction" class="list">
|
||||
<h3>Waiting for User Action <span id="waitingForUserActionCount"></span>
|
||||
<h3>Waiting for User Action (<span data-bind="text: waitingForUserAction().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: waitingForUserAction().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<footer id="footer">
|
||||
</footer>
|
||||
</section>
|
||||
<footer>
|
||||
</footer>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// Resizing
|
||||
$(function () {
|
||||
var $inProcess = $('#inProcess');
|
||||
var $inProcessContent = $inProcess.find('.content');
|
||||
var $inProcessHeader = $inProcess.find('.h3');
|
||||
var $readyForReturn = $('#readyForReturn');
|
||||
var $readyForReturnContent = $readyForReturn.find('.content');
|
||||
var $readyForReturnHeader = $readyForReturn.find('.h3');
|
||||
var $waitingForUserAction = $('#waitingForUserAction');
|
||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
|
||||
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
|
||||
var $mainSection = $('#mainSection');
|
||||
var $mainHeader = $('#mainHeader');
|
||||
var $mainFooter = $('#mainFooter');
|
||||
|
||||
var onResize = function () {
|
||||
var width = $mainSection.width();
|
||||
var height = $(window).height() - $mainHeader.outerHeight() - $mainFooter.outerHeight() - 25;
|
||||
|
||||
$inProcess.height(height);
|
||||
$inProcess.width((width * .28) - 11);
|
||||
$inProcessContent.height(height - $inProcessHeader.outerHeight() - 56);
|
||||
|
||||
$readyForReturn.height(height);
|
||||
$readyForReturn.width((width * .36) - 11);
|
||||
$readyForReturnContent.height(height - $readyForReturnHeader.outerHeight() - 56);
|
||||
|
||||
$waitingForUserAction.height(height);
|
||||
$waitingForUserAction.width((width * .36) - 11);
|
||||
$waitingForUserActionContent.height(height - $waitingForUserActionHeader.outerHeight() - 56);
|
||||
};
|
||||
|
||||
$(window).resize(onResize);
|
||||
onResize();
|
||||
});
|
||||
<script type="text/html" id="item-template">
|
||||
<li data-bind="css: { alert: IsAlert }">
|
||||
<span data-bind="text: DeviceDescription"></span>
|
||||
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
|
||||
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: WaitingForUserAction -->
|
||||
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
|
||||
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
</li>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// Hide Mouse Mouse
|
||||
$(function () {
|
||||
var mouseVisible = true;
|
||||
var mouseHideToken;
|
||||
var documentBody = $('body');
|
||||
<script>
|
||||
ko.bindingHandlers.livestamp = {
|
||||
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
var value = valueAccessor();
|
||||
var valueUnwrapped = ko.unwrap(value);
|
||||
|
||||
var hideMouse = function () {
|
||||
if (mouseVisible) {
|
||||
documentBody.css('cursor', 'none');
|
||||
mouseVisible = false;
|
||||
}
|
||||
};
|
||||
var showMouse = function () {
|
||||
if (!mouseVisible) {
|
||||
documentBody.css('cursor', 'auto');
|
||||
mouseVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).mousemove(function () {
|
||||
showMouse();
|
||||
if (mouseHideToken)
|
||||
window.clearTimeout(mouseHideToken);
|
||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var models = {};
|
||||
var modelsInProcessSorted = [];
|
||||
var modelsInProcessCount = 0;
|
||||
var modelsReadyForReturnSorted = [];
|
||||
var modelsReadyForReturnCount = 0;
|
||||
var modelsWaitingForUserActionSorted = [];
|
||||
var modelsWaitingForUserActionCount = 0;
|
||||
var $inProcess = $('#inProcess');
|
||||
var $inProcessContent = $inProcess.find('.content ul');
|
||||
var $readyForReturn = $('#readyForReturn');
|
||||
var $readyForReturnContent = $readyForReturn.find('.content ul');
|
||||
var $waitingForUserAction = $('#waitingForUserAction');
|
||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content ul');
|
||||
var modelsInProcessIndexOffset = 0;
|
||||
var scrollInProcessToken = null;
|
||||
var modelsReadyForReturnIndexOffset = 0;
|
||||
var scrollReadyForReturnToken = null;
|
||||
var modelsWaitingForUserActionIndexOffset = 0;
|
||||
var scrollWaitingForUserActionToken = null;
|
||||
var scrollSpeed = 3000;
|
||||
var persistantConnection = null;
|
||||
var filterDeviceAddressInclude;
|
||||
var filterDeviceAddressExclude;
|
||||
var filterDeviceProfileInclude;
|
||||
var filterDeviceProfileExclude;
|
||||
|
||||
var getParameterByName = function (name) {
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
||||
var regex = new RegExp(regexS);
|
||||
var results = regex.exec(window.location.search);
|
||||
if (results == null)
|
||||
return "";
|
||||
if (valueUnwrapped)
|
||||
$(element).livestamp(valueUnwrapped);
|
||||
else
|
||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
$(element).livestamp('destroy');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
$(function () {
|
||||
var hub;
|
||||
var viewModel;
|
||||
|
||||
var buildFilters = function () {
|
||||
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
|
||||
if (deviceAddressInclude) {
|
||||
filterDeviceAddressInclude = {};
|
||||
var split = deviceAddressInclude.split(",");
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
filterDeviceAddressInclude[split[i].toLowerCase()] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceAddressExclude = getParameterByName('deviceAddressExclude');
|
||||
if (deviceAddressExclude) {
|
||||
filterDeviceAddressExclude = {};
|
||||
var split = deviceAddressExclude.split(",");
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
filterDeviceAddressExclude[split[i].toLowerCase()] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceProfileInclude = getParameterByName('deviceProfileInclude');
|
||||
if (deviceProfileInclude) {
|
||||
filterDeviceProfileInclude = {};
|
||||
var deviceProfileIncludeSplit = deviceProfileInclude.split(",");
|
||||
for (var i = 0; i < deviceProfileIncludeSplit.length; i++) {
|
||||
filterDeviceProfileInclude[parseInt(deviceProfileIncludeSplit[i])] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceProfileExclude = getParameterByName('deviceProfileExclude');
|
||||
if (deviceProfileExclude) {
|
||||
filterDeviceProfileExclude = {};
|
||||
var deviceProfileExcludeSplit = deviceProfileExclude.split(",");
|
||||
for (var i = 0; i < deviceProfileExcludeSplit.length; i++) {
|
||||
filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var calculateFilter = function (model) {
|
||||
if (model) {
|
||||
if (filterDeviceAddressInclude) {
|
||||
return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)
|
||||
}
|
||||
if (filterDeviceAddressExclude) {
|
||||
return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()])
|
||||
}
|
||||
if (filterDeviceProfileInclude) {
|
||||
return (filterDeviceProfileInclude[model.DeviceProfileId] == true)
|
||||
}
|
||||
if (filterDeviceProfileExclude) {
|
||||
return (!filterDeviceProfileExclude[model.DeviceProfileId])
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var rotateSpeed = 3000;
|
||||
var itemFilters;
|
||||
|
||||
var sortModels = function () {
|
||||
modelsInProcessSorted = [];
|
||||
modelsReadyForReturnSorted = [];
|
||||
modelsWaitingForUserActionSorted = [];
|
||||
var modelSortFunc = function (a, b) {
|
||||
if (a.DeviceSerialNumber.toUpperCase() == b.DeviceSerialNumber.toUpperCase()) {
|
||||
return 0;
|
||||
} else {
|
||||
if (a.DeviceSerialNumber.toUpperCase() < b.DeviceSerialNumber.toUpperCase()) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
};
|
||||
for (var key in models) {
|
||||
var model = models[key];
|
||||
if (model) {
|
||||
if (model.WaitingForUserAction) {
|
||||
modelsWaitingForUserActionSorted.push(model);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
modelsReadyForReturnSorted.push(model);
|
||||
} else {
|
||||
modelsInProcessSorted.push(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortFunc);
|
||||
modelsInProcessSorted = modelsInProcessSorted.sort(modelSortFunc);
|
||||
modelsWaitingForUserActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);
|
||||
var $inProcessList = $('#inProcess').find('ul');
|
||||
var $readyForReturnList = $('#readyForReturn').find('ul');
|
||||
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
|
||||
|
||||
if (modelsInProcessSorted.length != modelsInProcessCount) {
|
||||
modelsInProcessCount = modelsInProcessSorted.length;
|
||||
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
|
||||
}
|
||||
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
|
||||
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
|
||||
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
|
||||
}
|
||||
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
|
||||
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
|
||||
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
|
||||
}
|
||||
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
|
||||
var self = this;
|
||||
|
||||
};
|
||||
self.initialized = false;
|
||||
|
||||
var scrollReadyForReturn = function () {
|
||||
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
|
||||
modelsReadyForReturnIndexOffset++;
|
||||
if (modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {
|
||||
modelsReadyForReturnIndexOffset = 0;
|
||||
}
|
||||
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
|
||||
};
|
||||
var updateScrollReadyForReturn = function () {
|
||||
var containerHeight = $readyForReturn.find('.content').height();
|
||||
var contentHeight = $readyForReturnContent.height();
|
||||
if (containerHeight >= contentHeight && scrollReadyForReturnToken) {
|
||||
window.clearTimeout(scrollReadyForReturnToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollReadyForReturnToken == null) {
|
||||
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
|
||||
}
|
||||
};
|
||||
var scrollInProcess = function () {
|
||||
$inProcessContent.find('li').last().detach().prependTo($inProcessContent).hide().slideDown('slow');
|
||||
modelsInProcessIndexOffset++;
|
||||
if (modelsInProcessIndexOffset >= modelsInProcessSorted.length) {
|
||||
modelsInProcessIndexOffset = 0;
|
||||
}
|
||||
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
|
||||
};
|
||||
var updateScrollInProcess = function () {
|
||||
var containerHeight = $inProcess.find('.content').height();
|
||||
var contentHeight = $inProcessContent.height();
|
||||
if (containerHeight >= contentHeight && scrollInProcessToken) {
|
||||
window.clearTimeout(scrollInProcessToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollInProcessToken == null) {
|
||||
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
|
||||
}
|
||||
};
|
||||
var scrollWaitingForUserAction = function () {
|
||||
$waitingForUserActionContent.find('li').last().detach().prependTo($waitingForUserActionContent).hide().slideDown('slow');
|
||||
modelsInProcessIndexOffset++;
|
||||
if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserActionSorted.length) {
|
||||
modelsWaitingForUserActionIndexOffset = 0;
|
||||
}
|
||||
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
|
||||
};
|
||||
var updateScrollWaitingForUserAction = function () {
|
||||
var containerHeight = $waitingForUserAction.find('.content').height();
|
||||
var contentHeight = $waitingForUserActionContent.height();
|
||||
if (containerHeight >= contentHeight && scrollWaitingForUserActionToken) {
|
||||
window.clearTimeout(scrollWaitingForUserActionToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollWaitingForUserActionToken == null) {
|
||||
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
|
||||
}
|
||||
};
|
||||
self.inProcess = ko.observableArray(inProcess);
|
||||
self.readyForReturn = ko.observableArray(readyForReturn);
|
||||
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
|
||||
|
||||
var modelInsertIndex = function (model) {
|
||||
sortModels();
|
||||
var findIndex = function (model, array, offset) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (model.DeviceSerialNumber == array[i].DeviceSerialNumber) {
|
||||
var index = i + offset;
|
||||
if (index > (array.length - 1)) {
|
||||
index = index - (array.length - 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
};
|
||||
if (model.WaitingForUserAction) {
|
||||
return findIndex(model, modelsWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
return findIndex(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);
|
||||
} else {
|
||||
return findIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
var modelInsert = function (model) {
|
||||
var index = modelInsertIndex(model);
|
||||
var insertTo = function (model, host) {
|
||||
var hostLi = host.children('li');
|
||||
if (hostLi.length == 0 || hostLi.length < index) {
|
||||
host.append(model.htmlLi);
|
||||
} else {
|
||||
if (index == 0) {
|
||||
host.prepend(model.htmlLi);
|
||||
} else {
|
||||
$(hostLi.get(index - 1)).after(model.htmlLi);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.WaitingForUserAction) {
|
||||
insertTo(model, $waitingForUserActionContent);
|
||||
window.setTimeout(updateScrollWaitingForUserAction, 100);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
insertTo(model, $readyForReturnContent);
|
||||
window.setTimeout(updateScrollReadyForReturn, 100);
|
||||
} else {
|
||||
insertTo(model, $inProcessContent);
|
||||
window.setTimeout(updateScrollInProcess, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeModel = function (model) {
|
||||
if (model) {
|
||||
model.htmlLi.slideUp('fast', function () {
|
||||
model.htmlLi.remove();
|
||||
self.onRemove = function (element, index, data) {
|
||||
$(element).slideUp(400, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var processModel = function (id, model, init) {
|
||||
if (!calculateFilter(model)) {
|
||||
removeModel(models[id]);
|
||||
delete models[id];
|
||||
sortModels();
|
||||
} else {
|
||||
var existing = models[id];
|
||||
models[id] = model;
|
||||
|
||||
// Add
|
||||
model.htmlContent = $('<div>').text(model.DeviceDescription);
|
||||
if (!model.ReadyForReturn && model.EstimatedReturnTime) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Expected: ' + model.EstimatedReturnTime + ')'));
|
||||
}
|
||||
if (model.WaitingForUserAction) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Since ' + model.WaitingForUserActionSince + ')'));
|
||||
} else {
|
||||
if (model.ReadyForReturn && model.ReadyForReturnSince) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Ready ' + model.ReadyForReturnSince + ')'));
|
||||
}
|
||||
}
|
||||
|
||||
if (existing) {
|
||||
if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction) {
|
||||
removeModel(existing);
|
||||
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
|
||||
modelInsert(model);
|
||||
if (init) {
|
||||
model.htmlLi.fadeIn();
|
||||
} else {
|
||||
model.htmlLi.slideDown();
|
||||
}
|
||||
} else {
|
||||
model.htmlLi = existing.htmlLi;
|
||||
model.htmlLi.slideUp('fast', function () {
|
||||
model.htmlLi.html(model.htmlContent).slideDown();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
|
||||
modelInsert(model);
|
||||
if (init) {
|
||||
model.htmlLi.fadeIn();
|
||||
} else {
|
||||
model.htmlLi.slideDown('slow');
|
||||
}
|
||||
}
|
||||
if (model.htmlLi && model.IsAlert) {
|
||||
model.htmlLi.addClass('alert');
|
||||
}
|
||||
self.onAdd = function (element, index, data) {
|
||||
if (self.initialized)
|
||||
$(element).hide().slideDown(400);
|
||||
}
|
||||
};
|
||||
|
||||
var updatedModel = function (id) {
|
||||
var deviceSerialNumber = id.toString();
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '@(Url.Action(MVC.Public.HeldDevices.HeldDevice()))',
|
||||
data: { id: deviceSerialNumber },
|
||||
success: function (data) {
|
||||
processModel(deviceSerialNumber, data, false);
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
if (textStatus == 'parsererror') // null Result
|
||||
processModel(deviceSerialNumber, null, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var connectionError = function () {
|
||||
if (persistantConnection) {
|
||||
persistantConnection.stop();
|
||||
persistantConnection = null;
|
||||
window.setTimeout(function () {
|
||||
window.location.href = '@(Url.Action(MVC.Public.HeldDevices.Noticeboard()))';
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
var init = function () {
|
||||
buildFilters();
|
||||
persistantConnection = $.connection('@(Url.Content("~/Public/HeldDevices/Notifications"))');
|
||||
persistantConnection.received(updatedModel);
|
||||
persistantConnection.error(connectionError);
|
||||
persistantConnection.start(function () {
|
||||
$.getJSON('@(Url.Action(MVC.Public.HeldDevices.HeldDevices()))', null, function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
processModel(data[i].DeviceSerialNumber, data[i], true);
|
||||
}
|
||||
function init() {
|
||||
// Connect to Hub
|
||||
hub = $.connection.noticeboardUpdates;
|
||||
|
||||
// Map Functions
|
||||
hub.client.updateHeldDevice = updateHeldDevice;
|
||||
|
||||
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevices.Name)' };
|
||||
$.connection.hub.error(connectionError);
|
||||
$.connection.hub.disconnected(connectionError);
|
||||
$.connection.hub.reconnected(connectionError);
|
||||
|
||||
// Start Connection
|
||||
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||
}
|
||||
|
||||
// Called after SignalR is connected
|
||||
function loadData() {
|
||||
$.getJSON('@(Url.Action(MVC.Public.HeldDevices.HeldDevices()))', null, function (data) {
|
||||
|
||||
var inProcess = [];
|
||||
var readyForReturn = [];
|
||||
var waitingForUserAction = [];
|
||||
|
||||
data.filter(function (heldDeviceItem) {
|
||||
return includeItem(heldDeviceItem)
|
||||
}).forEach(function (heldDeviceItem) {
|
||||
if (isWaitingForUserAction(heldDeviceItem))
|
||||
waitingForUserAction.push(heldDeviceItem);
|
||||
else if (isReadyForReturn(heldDeviceItem))
|
||||
readyForReturn.push(heldDeviceItem);
|
||||
else if (isInProcess(heldDeviceItem))
|
||||
inProcess.push(heldDeviceItem);
|
||||
});
|
||||
|
||||
inProcess.sort(sortFunction);
|
||||
readyForReturn.sort(sortFunction);
|
||||
waitingForUserAction.sort(sortFunction);
|
||||
|
||||
viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction);
|
||||
|
||||
ko.applyBindings(viewModel);
|
||||
viewModel.initialized = true;
|
||||
|
||||
$('body').removeClass('status-connecting');
|
||||
|
||||
window.setTimeout(scheduleRotation, rotateSpeed);
|
||||
});
|
||||
};
|
||||
init();
|
||||
buildFilters();
|
||||
}
|
||||
|
||||
// Called by SignalR
|
||||
function updateHeldDevice(updates) {
|
||||
if (viewModel) {
|
||||
|
||||
$.each(updates, function (deviceSerialNumber, heldDeviceItem) {
|
||||
// Remove Existing
|
||||
removeItem(deviceSerialNumber);
|
||||
|
||||
// Add Item
|
||||
addItem(heldDeviceItem);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function removeItem(deviceSerialNumber) {
|
||||
removeItemFromArray(viewModel.inProcess, deviceSerialNumber);
|
||||
removeItemFromArray(viewModel.readyForReturn, deviceSerialNumber);
|
||||
removeItemFromArray(viewModel.waitingForUserAction, deviceSerialNumber);
|
||||
}
|
||||
|
||||
function addItem(heldDeviceItem) {
|
||||
if (heldDeviceItem !== null &&
|
||||
heldDeviceItem !== undefined &&
|
||||
includeItem(heldDeviceItem)) {
|
||||
|
||||
var array;
|
||||
|
||||
if (isWaitingForUserAction(heldDeviceItem))
|
||||
array = viewModel.waitingForUserAction;
|
||||
else if (isReadyForReturn(heldDeviceItem))
|
||||
array = viewModel.readyForReturn;
|
||||
else if (isInProcess(heldDeviceItem))
|
||||
array = viewModel.inProcess;
|
||||
|
||||
if (array().length === 0) {
|
||||
array.push(heldDeviceItem);
|
||||
} else {
|
||||
var index = findSortedInsertIndex(array, heldDeviceItem);
|
||||
if (index === -1)
|
||||
array.push(heldDeviceItem);
|
||||
else
|
||||
array.splice(index, 0, heldDeviceItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rotateArrays() {
|
||||
rotateArray(viewModel.inProcess, $inProcessList);
|
||||
rotateArray(viewModel.readyForReturn, $readyForReturnList);
|
||||
rotateArray(viewModel.waitingForUserAction, $waitingForUserActionList);
|
||||
}
|
||||
|
||||
function scheduleRotation() {
|
||||
rotateArrays();
|
||||
|
||||
window.setTimeout(scheduleRotation, rotateSpeed);
|
||||
}
|
||||
|
||||
function includeItem(heldDeviceItem) {
|
||||
if (itemFilters == null || itemFilters.length == 0)
|
||||
return true;
|
||||
|
||||
return itemFilters.reduce(function (previousValue, currentValue, index, array) {
|
||||
if (previousValue === false)
|
||||
return false;
|
||||
return currentValue(heldDeviceItem);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function buildFilters() {
|
||||
var filters = [];
|
||||
var queryStringParameters = getQueryStringParameters();
|
||||
|
||||
if (queryStringParameters !== null) {
|
||||
$.each(queryStringParameters, function (key, value) {
|
||||
switch (key.toLowerCase()) {
|
||||
case 'deviceaddressinclude':
|
||||
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
|
||||
if (deviceAddresses.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// false if DeviceAddressShortName is null
|
||||
if (!heldDeviceItem.DeviceAddressShortName)
|
||||
return false;
|
||||
|
||||
// true if DeviceAddressShortName is included
|
||||
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) >= 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceaddressexclude':
|
||||
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
|
||||
if (deviceAddresses.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceAddressShortName is null
|
||||
if (!heldDeviceItem.DeviceAddressShortName)
|
||||
return true;
|
||||
|
||||
// true if DeviceAddressShortName is excluded
|
||||
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) < 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceprofileinclude':
|
||||
var deviceProfiles = value.split(",");
|
||||
if (deviceProfiles.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceProfileId is included
|
||||
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceprofileexclude':
|
||||
var deviceProfiles = value.split(",");
|
||||
if (deviceProfiles.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceProfileId is excluded
|
||||
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (filters.length > 0)
|
||||
itemFilters = filters;
|
||||
else
|
||||
itemFilters = null;
|
||||
}
|
||||
|
||||
function connectionError() {
|
||||
try {
|
||||
$('body').addClass('status-error');
|
||||
$.connection.hub.stop();
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.href = window.location.href;
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
function rotateArray(koArray, element) {
|
||||
var items = koArray();
|
||||
|
||||
if (items.length <= 1)
|
||||
return 0;
|
||||
|
||||
if (element.height() < (element.parent().height() - 30)) {
|
||||
|
||||
if (findUnsortedArrayTopIndex(items) !== 0)
|
||||
koArray.sort(sortFunction);
|
||||
|
||||
// Don't rotate if small & sorted correctly
|
||||
return;
|
||||
}
|
||||
|
||||
// Move Last Item to Top
|
||||
var item = koArray.pop();
|
||||
koArray.unshift(item);
|
||||
}
|
||||
function removeItemFromArray(koArray, deviceSerialNumber) {
|
||||
var items = koArray();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].DeviceSerialNumber == deviceSerialNumber) {
|
||||
koArray.splice(i, 1);
|
||||
items = koArray();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
function findUnsortedArrayTopIndex(items) {
|
||||
// Only one Item
|
||||
if (items.length <= 1)
|
||||
return 0;
|
||||
|
||||
for (var i = 1; i < items.length; i++) {
|
||||
var s = sortFunction(items[i - 1], items[i]);
|
||||
if (s > 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
function findSortedInsertIndex(koArray, heldDeviceItem) {
|
||||
var items = koArray();
|
||||
var startIndex = findUnsortedArrayTopIndex(items);
|
||||
for (var i = startIndex; i < items.length; i++) {
|
||||
var s = sortFunction(heldDeviceItem, items[i]);
|
||||
if (s <= 0)
|
||||
return i;
|
||||
}
|
||||
if (startIndex !== 0) {
|
||||
for (var i = 0; i < startIndex; i++) {
|
||||
var s = sortFunction(heldDeviceItem, items[i]);
|
||||
if (s <= 0)
|
||||
return i;
|
||||
}
|
||||
return startIndex;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
function sortFunction(l, r) {
|
||||
return l.DeviceDescription.toLowerCase() == r.DeviceDescription.toLowerCase() ? 0 : (l.DeviceDescription.toLowerCase() < r.DeviceDescription.toLowerCase() ? -1 : 1)
|
||||
}
|
||||
function isInProcess(i) {
|
||||
return !i.ReadyForReturn && !i.WaitingForUserAction;
|
||||
}
|
||||
function isReadyForReturn(i) {
|
||||
return i.ReadyForReturn && !i.WaitingForUserAction;
|
||||
}
|
||||
function isWaitingForUserAction(i) {
|
||||
return i.WaitingForUserAction;
|
||||
}
|
||||
function getQueryStringParameters() {
|
||||
|
||||
if (window.location.search.length === 0)
|
||||
return null;
|
||||
|
||||
var params = {};
|
||||
window.location.search.substr(1).split("&").forEach(function (pair) {
|
||||
if (pair === "") return;
|
||||
var parts = pair.split("=");
|
||||
params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace(/\+/g, " "));
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
<div id="mainFooter">
|
||||
<img style="width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;" src="@Links.ClientSource.Style.Images.Heading_png" alt="Disco Logo" />
|
||||
powered by Disco
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices
|
||||
#line 1 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
|
||||
Layout = null;
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
Html.BundleDeferred("~/ClientScripts/Core");
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
|
||||
|
||||
WriteLiteral(" content=\"IE=edge\"");
|
||||
|
||||
WriteLiteral(" />\r\n <title>Disco - Held Devices</title>\r\n");
|
||||
WriteLiteral(" />\r\n <title>Disco ICT - Held Devices</title>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 13 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
#line 14 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Html.BundleRenderDeferred());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n</head>\r\n<body>\r\n <div");
|
||||
WriteLiteral("\r\n</head>\r\n<body");
|
||||
|
||||
WriteLiteral(" class=\"status-connecting\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"page\"");
|
||||
|
||||
WriteLiteral(">\r\n <header");
|
||||
|
||||
WriteLiteral(" id=\"mainHeader\"");
|
||||
WriteLiteral(" id=\"header\"");
|
||||
|
||||
WriteLiteral(">\r\n Held Devices\r\n </header>\r\n <section");
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"heading\"");
|
||||
|
||||
WriteLiteral(">Held Devices</div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"statusConnecting\"");
|
||||
|
||||
WriteLiteral("><i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
|
||||
|
||||
WriteLiteral("></i><span>connecting...</span></div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"statusError\"");
|
||||
|
||||
WriteLiteral("><i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
|
||||
|
||||
WriteLiteral("></i><span>disconnected, reconnecting...</span></div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"credits\"");
|
||||
|
||||
WriteLiteral(">\r\n powered by Disco ICT <i");
|
||||
|
||||
WriteLiteral(" title=\"Disco ICT - Jobs\"");
|
||||
|
||||
WriteLiteral("></i>\r\n </div>\r\n </header>\r\n <section");
|
||||
|
||||
WriteLiteral(" id=\"mainSection\"");
|
||||
|
||||
@@ -93,403 +126,289 @@ WriteLiteral(" id=\"inProcess\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>In Process <span");
|
||||
WriteLiteral(">\r\n <h3>In Process (<span");
|
||||
|
||||
WriteLiteral(" id=\"inProcessCount\"");
|
||||
WriteLiteral(" data-bind=\"text: inProcess().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n <div");
|
||||
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: inProcess, afterRender: o" +
|
||||
"nAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"readyForReturn\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>Ready for Return <span");
|
||||
WriteLiteral(">\r\n <h3>Ready for Return (<span");
|
||||
|
||||
WriteLiteral(" id=\"readyForReturnCount\"");
|
||||
WriteLiteral(" data-bind=\"text: readyForReturn().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n <div");
|
||||
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: readyForReturn, afterRend" +
|
||||
"er: onAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"waitingForUserAction\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>Waiting for User Action <span");
|
||||
WriteLiteral(">\r\n <h3>Waiting for User Action (<span");
|
||||
|
||||
WriteLiteral(" id=\"waitingForUserActionCount\"");
|
||||
WriteLiteral(" data-bind=\"text: waitingForUserAction().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
|
||||
"</div>\r\n <script");
|
||||
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
|
||||
"#inProcess\');\r\n var $inProcessContent = $inProcess.find(\'.content\');\r" +
|
||||
"\n var $inProcessHeader = $inProcess.find(\'.h3\');\r\n var $re" +
|
||||
"adyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnContent = $" +
|
||||
"readyForReturn.find(\'.content\');\r\n var $readyForReturnHeader = $ready" +
|
||||
"ForReturn.find(\'.h3\');\r\n var $waitingForUserAction = $(\'#waitingForUs" +
|
||||
"erAction\');\r\n var $waitingForUserActionContent = $waitingForUserActio" +
|
||||
"n.find(\'.content\');\r\n var $waitingForUserActionHeader = $waitingForUs" +
|
||||
"erAction.find(\'.h3\');\r\n var $mainSection = $(\'#mainSection\');\r\n " +
|
||||
" var $mainHeader = $(\'#mainHeader\');\r\n var $mainFooter = $(\'#mai" +
|
||||
"nFooter\');\r\n\r\n var onResize = function () {\r\n var widt" +
|
||||
"h = $mainSection.width();\r\n var height = $(window).height() - $ma" +
|
||||
"inHeader.outerHeight() - $mainFooter.outerHeight() - 25;\r\n\r\n $inP" +
|
||||
"rocess.height(height);\r\n $inProcess.width((width * .28) - 11);\r\n " +
|
||||
" $inProcessContent.height(height - $inProcessHeader.outerHeight() " +
|
||||
"- 56);\r\n\r\n $readyForReturn.height(height);\r\n $read" +
|
||||
"yForReturn.width((width * .36) - 11);\r\n $readyForReturnContent.he" +
|
||||
"ight(height - $readyForReturnHeader.outerHeight() - 56);\r\n\r\n $wai" +
|
||||
"tingForUserAction.height(height);\r\n $waitingForUserAction.width((" +
|
||||
"width * .36) - 11);\r\n $waitingForUserActionContent.height(height " +
|
||||
"- $waitingForUserActionHeader.outerHeight() - 56);\r\n };\r\n\r\n " +
|
||||
" $(window).resize(onResize);\r\n onResize();\r\n });\r\n </scrip" +
|
||||
"t>\r\n <script");
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
|
||||
"erAdd: onAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral(@">
|
||||
// Hide Mouse Mouse
|
||||
$(function () {
|
||||
var mouseVisible = true;
|
||||
var mouseHideToken;
|
||||
var documentBody = $('body');
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
|
||||
|
||||
var hideMouse = function () {
|
||||
if (mouseVisible) {
|
||||
documentBody.css('cursor', 'none');
|
||||
mouseVisible = false;
|
||||
}
|
||||
};
|
||||
var showMouse = function () {
|
||||
if (!mouseVisible) {
|
||||
documentBody.css('cursor', 'auto');
|
||||
mouseVisible = true;
|
||||
}
|
||||
};
|
||||
WriteLiteral(" id=\"footer\"");
|
||||
|
||||
$(document).mousemove(function () {
|
||||
showMouse();
|
||||
if (mouseHideToken)
|
||||
window.clearTimeout(mouseHideToken);
|
||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script");
|
||||
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" type=\"text/html\"");
|
||||
|
||||
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
|
||||
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
|
||||
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
|
||||
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
|
||||
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
|
||||
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
|
||||
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
|
||||
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
|
||||
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
|
||||
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
|
||||
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
|
||||
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
|
||||
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
|
||||
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
|
||||
" var persistantConnection = null;\r\n var filterDeviceAddress" +
|
||||
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
|
||||
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n\r\n v" +
|
||||
"ar getParameterByName = function (name) {\r\n name = name.replace(/" +
|
||||
"[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS = \"[\\\\?&]\" +" +
|
||||
" name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS);\r\n " +
|
||||
" var results = regex.exec(window.location.search);\r\n if (re" +
|
||||
"sults == null)\r\n return \"\";\r\n else\r\n " +
|
||||
" return decodeURIComponent(results[1].replace(/\\+/g, \" \"));\r\n " +
|
||||
" }\r\n\r\n var buildFilters = function () {\r\n var deviceA" +
|
||||
"ddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n if " +
|
||||
"(deviceAddressInclude) {\r\n filterDeviceAddressInclude = {};\r\n" +
|
||||
" var split = deviceAddressInclude.split(\",\");\r\n " +
|
||||
" for (var i = 0; i < split.length; i++) {\r\n filterDe" +
|
||||
"viceAddressInclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
|
||||
" } else {\r\n var deviceAddressExclude = getParameter" +
|
||||
"ByName(\'deviceAddressExclude\');\r\n if (deviceAddressExclude) {" +
|
||||
"\r\n filterDeviceAddressExclude = {};\r\n " +
|
||||
" var split = deviceAddressExclude.split(\",\");\r\n for (v" +
|
||||
"ar i = 0; i < split.length; i++) {\r\n filterDeviceAddr" +
|
||||
"essExclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
|
||||
" } else {\r\n var deviceProfileInclude = getParam" +
|
||||
"eterByName(\'deviceProfileInclude\');\r\n if (deviceProfileIn" +
|
||||
"clude) {\r\n filterDeviceProfileInclude = {};\r\n " +
|
||||
" var deviceProfileIncludeSplit = deviceProfileInclude.split(\"" +
|
||||
",\");\r\n for (var i = 0; i < deviceProfileIncludeSplit." +
|
||||
"length; i++) {\r\n filterDeviceProfileInclude[parse" +
|
||||
"Int(deviceProfileIncludeSplit[i])] = true;\r\n }\r\n " +
|
||||
" } else {\r\n var deviceProfileExclud" +
|
||||
"e = getParameterByName(\'deviceProfileExclude\');\r\n if " +
|
||||
"(deviceProfileExclude) {\r\n filterDeviceProfileExc" +
|
||||
"lude = {};\r\n var deviceProfileExcludeSplit = devi" +
|
||||
"ceProfileExclude.split(\",\");\r\n for (var i = 0; i " +
|
||||
"< deviceProfileExcludeSplit.length; i++) {\r\n " +
|
||||
"filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;\r\n " +
|
||||
" }\r\n }\r\n " +
|
||||
" }\r\n }\r\n }\r\n }\r\n va" +
|
||||
"r calculateFilter = function (model) {\r\n if (model) {\r\n " +
|
||||
" if (filterDeviceAddressInclude) {\r\n return (fil" +
|
||||
"terDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)\r\n " +
|
||||
" }\r\n if (filterDeviceAddressExclude) {\r\n " +
|
||||
" return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()" +
|
||||
"])\r\n }\r\n if (filterDeviceProfileInclude) {" +
|
||||
"\r\n return (filterDeviceProfileInclude[model.DeviceProfile" +
|
||||
"Id] == true)\r\n }\r\n if (filterDeviceProfile" +
|
||||
"Exclude) {\r\n return (!filterDeviceProfileExclude[model.De" +
|
||||
"viceProfileId])\r\n }\r\n return true;\r\n " +
|
||||
" }\r\n return false;\r\n }\r\n\r\n var sor" +
|
||||
"tModels = function () {\r\n modelsInProcessSorted = [];\r\n " +
|
||||
" modelsReadyForReturnSorted = [];\r\n modelsWaitingForUserActi" +
|
||||
"onSorted = [];\r\n var modelSortFunc = function (a, b) {\r\n " +
|
||||
" if (a.DeviceSerialNumber.toUpperCase() == b.DeviceSerialNumber.toUppe" +
|
||||
"rCase()) {\r\n return 0;\r\n } else {\r\n " +
|
||||
" if (a.DeviceSerialNumber.toUpperCase() < b.DeviceSerialNumb" +
|
||||
"er.toUpperCase()) {\r\n return -1\r\n " +
|
||||
" } else {\r\n return 1\r\n }\r\n " +
|
||||
" }\r\n };\r\n for (var key in models" +
|
||||
") {\r\n var model = models[key];\r\n if (model" +
|
||||
") {\r\n if (model.WaitingForUserAction) {\r\n " +
|
||||
" modelsWaitingForUserActionSorted.push(model);\r\n " +
|
||||
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
|
||||
" modelsReadyForReturnSorted.push(model);\r\n " +
|
||||
" } else {\r\n modelsInProcessSorted.push(" +
|
||||
"model);\r\n }\r\n }\r\n " +
|
||||
" }\r\n }\r\n modelsReadyForReturnSorted = models" +
|
||||
"ReadyForReturnSorted.sort(modelSortFunc);\r\n modelsInProcessSorted" +
|
||||
" = modelsInProcessSorted.sort(modelSortFunc);\r\n modelsWaitingForU" +
|
||||
"serActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);\r\n\r\n " +
|
||||
" if (modelsInProcessSorted.length != modelsInProcessCount) {\r\n " +
|
||||
" modelsInProcessCount = modelsInProcessSorted.length;\r\n " +
|
||||
" $(\'#inProcessCount\').text(\'(\' + modelsInProcessCount + \')\');\r\n " +
|
||||
" }\r\n if (modelsReadyForReturnSorted.length != modelsReadyForRe" +
|
||||
"turnCount) {\r\n modelsReadyForReturnCount = modelsReadyForRetu" +
|
||||
"rnSorted.length;\r\n $(\'#readyForReturnCount\').text(\'(\' + model" +
|
||||
"sReadyForReturnCount + \')\');\r\n }\r\n if (modelsWaiti" +
|
||||
"ngForUserActionSorted.length != modelsWaitingForUserActionCount) {\r\n " +
|
||||
" modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.lengt" +
|
||||
"h;\r\n $(\'#waitingForUserActionCount\').text(\'(\' + modelsWaiting" +
|
||||
"ForUserActionCount + \')\');\r\n }\r\n\r\n };\r\n\r\n v" +
|
||||
"ar scrollReadyForReturn = function () {\r\n $readyForReturnContent." +
|
||||
"find(\'li\').last().detach().prependTo($readyForReturnContent).hide().slideDown(\'s" +
|
||||
"low\');\r\n modelsReadyForReturnIndexOffset++;\r\n if (" +
|
||||
"modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {\r\n " +
|
||||
" modelsReadyForReturnIndexOffset = 0;\r\n }\r\n " +
|
||||
" scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scroll" +
|
||||
"Speed);\r\n };\r\n var updateScrollReadyForReturn = function (" +
|
||||
") {\r\n var containerHeight = $readyForReturn.find(\'.content\').heig" +
|
||||
"ht();\r\n var contentHeight = $readyForReturnContent.height();\r\n " +
|
||||
" if (containerHeight >= contentHeight && scrollReadyForReturnToken) " +
|
||||
"{\r\n window.clearTimeout(scrollReadyForReturnToken);\r\n " +
|
||||
" return;\r\n }\r\n if (containerHeight < co" +
|
||||
"ntentHeight && scrollReadyForReturnToken == null) {\r\n scrollR" +
|
||||
"eadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);\r\n " +
|
||||
" }\r\n };\r\n var scrollInProcess = function () {\r\n" +
|
||||
" $inProcessContent.find(\'li\').last().detach().prependTo($inProces" +
|
||||
"sContent).hide().slideDown(\'slow\');\r\n modelsInProcessIndexOffset+" +
|
||||
"+;\r\n if (modelsInProcessIndexOffset >= modelsInProcessSorted.leng" +
|
||||
"th) {\r\n modelsInProcessIndexOffset = 0;\r\n }\r\n " +
|
||||
" scrollInProcessToken = window.setTimeout(scrollInProcess, scrollS" +
|
||||
"peed);\r\n };\r\n var updateScrollInProcess = function () {\r\n " +
|
||||
" var containerHeight = $inProcess.find(\'.content\').height();\r\n " +
|
||||
" var contentHeight = $inProcessContent.height();\r\n if " +
|
||||
"(containerHeight >= contentHeight && scrollInProcessToken) {\r\n " +
|
||||
" window.clearTimeout(scrollInProcessToken);\r\n return;\r\n " +
|
||||
" }\r\n if (containerHeight < contentHeight && scrollInPro" +
|
||||
"cessToken == null) {\r\n scrollInProcessToken = window.setTimeo" +
|
||||
"ut(scrollInProcess, scrollSpeed);\r\n }\r\n };\r\n " +
|
||||
" var scrollWaitingForUserAction = function () {\r\n $waitingForUse" +
|
||||
"rActionContent.find(\'li\').last().detach().prependTo($waitingForUserActionContent" +
|
||||
").hide().slideDown(\'slow\');\r\n modelsInProcessIndexOffset++;\r\n " +
|
||||
" if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserAct" +
|
||||
"ionSorted.length) {\r\n modelsWaitingForUserActionIndexOffset =" +
|
||||
" 0;\r\n }\r\n scrollWaitingForUserActionToken = window" +
|
||||
".setTimeout(scrollWaitingForUserAction, scrollSpeed);\r\n };\r\n " +
|
||||
" var updateScrollWaitingForUserAction = function () {\r\n var con" +
|
||||
"tainerHeight = $waitingForUserAction.find(\'.content\').height();\r\n " +
|
||||
" var contentHeight = $waitingForUserActionContent.height();\r\n if " +
|
||||
"(containerHeight >= contentHeight && scrollWaitingForUserActionToken) {\r\n " +
|
||||
" window.clearTimeout(scrollWaitingForUserActionToken);\r\n " +
|
||||
" return;\r\n }\r\n if (containerHeight < conten" +
|
||||
"tHeight && scrollWaitingForUserActionToken == null) {\r\n scrol" +
|
||||
"lWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrol" +
|
||||
"lSpeed);\r\n }\r\n };\r\n\r\n var modelInsertIndex " +
|
||||
"= function (model) {\r\n sortModels();\r\n var findInd" +
|
||||
"ex = function (model, array, offset) {\r\n for (var i = 0; i < " +
|
||||
"array.length; i++) {\r\n if (model.DeviceSerialNumber == ar" +
|
||||
"ray[i].DeviceSerialNumber) {\r\n var index = i + offset" +
|
||||
";\r\n if (index > (array.length - 1)) {\r\n " +
|
||||
" index = index - (array.length - 1);\r\n " +
|
||||
" }\r\n return index;\r\n }\r\n " +
|
||||
" };\r\n };\r\n if (model.WaitingForUser" +
|
||||
"Action) {\r\n return findIndex(model, modelsWaitingForUserActio" +
|
||||
"nSorted, modelsWaitingForUserActionIndexOffset);\r\n } else {\r\n " +
|
||||
" if (model.ReadyForReturn) {\r\n return find" +
|
||||
"Index(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);\r\n " +
|
||||
" } else {\r\n return findIndex(model, models" +
|
||||
"InProcessSorted, modelsInProcessIndexOffset);\r\n }\r\n " +
|
||||
" }\r\n }\r\n var modelInsert = function (model) {\r\n " +
|
||||
" var index = modelInsertIndex(model);\r\n var insertTo = f" +
|
||||
"unction (model, host) {\r\n var hostLi = host.children(\'li\');\r\n" +
|
||||
" if (hostLi.length == 0 || hostLi.length < index) {\r\n " +
|
||||
" host.append(model.htmlLi);\r\n } else {\r\n " +
|
||||
" if (index == 0) {\r\n host.prepend(mo" +
|
||||
"del.htmlLi);\r\n } else {\r\n $(ho" +
|
||||
"stLi.get(index - 1)).after(model.htmlLi);\r\n }\r\n " +
|
||||
" }\r\n }\r\n if (model.WaitingForUserAction) " +
|
||||
"{\r\n insertTo(model, $waitingForUserActionContent);\r\n " +
|
||||
" window.setTimeout(updateScrollWaitingForUserAction, 100);\r\n " +
|
||||
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
|
||||
" insertTo(model, $readyForReturnContent);\r\n windo" +
|
||||
"w.setTimeout(updateScrollReadyForReturn, 100);\r\n } else {\r\n " +
|
||||
" insertTo(model, $inProcessContent);\r\n " +
|
||||
" window.setTimeout(updateScrollInProcess, 100);\r\n }\r\n " +
|
||||
" }\r\n }\r\n\r\n var removeModel = function (model) {\r\n" +
|
||||
" if (model) {\r\n model.htmlLi.slideUp(\'fast\', f" +
|
||||
"unction () {\r\n model.htmlLi.remove();\r\n " +
|
||||
" });\r\n }\r\n };\r\n\r\n var processModel = funct" +
|
||||
"ion (id, model, init) {\r\n if (!calculateFilter(model)) {\r\n " +
|
||||
" removeModel(models[id]);\r\n delete models[id];\r\n " +
|
||||
" sortModels();\r\n } else {\r\n " +
|
||||
"var existing = models[id];\r\n models[id] = model;\r\n\r\n " +
|
||||
" // Add\r\n model.htmlContent = $(\'<div>\').text(model" +
|
||||
".DeviceDescription);\r\n if (!model.ReadyForReturn && model.Est" +
|
||||
"imatedReturnTime) {\r\n model.htmlContent.append($(\'<span c" +
|
||||
"lass=\"small\">\').text(\' (Expected: \' + model.EstimatedReturnTime + \')\'));\r\n " +
|
||||
" }\r\n if (model.WaitingForUserAction) {\r\n " +
|
||||
" model.htmlContent.append($(\'<span class=\"small\">\').text(\' (Since" +
|
||||
" \' + model.WaitingForUserActionSince + \')\'));\r\n } else {\r\n " +
|
||||
" if (model.ReadyForReturn && model.ReadyForReturnSince) {\r\n " +
|
||||
" model.htmlContent.append($(\'<span class=\"small\">\').te" +
|
||||
"xt(\' (Ready \' + model.ReadyForReturnSince + \')\'));\r\n }\r\n " +
|
||||
" }\r\n\r\n if (existing) {\r\n " +
|
||||
" if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForU" +
|
||||
"serAction != model.WaitingForUserAction) {\r\n removeMo" +
|
||||
"del(existing);\r\n model.htmlLi = $(\'<li>\').html(model." +
|
||||
"htmlContent).data(\'ModelId\', id).hide();\r\n modelInser" +
|
||||
"t(model);\r\n if (init) {\r\n " +
|
||||
" model.htmlLi.fadeIn();\r\n } else {\r\n " +
|
||||
" model.htmlLi.slideDown();\r\n }\r\n " +
|
||||
" } else {\r\n model.htmlLi = existin" +
|
||||
"g.htmlLi;\r\n model.htmlLi.slideUp(\'fast\', function () " +
|
||||
"{\r\n model.htmlLi.html(model.htmlContent).slideDow" +
|
||||
"n();\r\n });\r\n }\r\n " +
|
||||
" } else {\r\n model.htmlLi = $(\'<li>\').html(model.html" +
|
||||
"Content).data(\'ModelId\', id).hide();\r\n modelInsert(model)" +
|
||||
";\r\n if (init) {\r\n model.htmlLi" +
|
||||
".fadeIn();\r\n } else {\r\n model." +
|
||||
"htmlLi.slideDown(\'slow\');\r\n }\r\n }\r\n " +
|
||||
" if (model.htmlLi && model.IsAlert) {\r\n m" +
|
||||
"odel.htmlLi.addClass(\'alert\');\r\n }\r\n }\r\n " +
|
||||
" };\r\n\r\n var updatedModel = function (id) {\r\n var " +
|
||||
"deviceSerialNumber = id.toString();\r\n\r\n $.ajax({\r\n " +
|
||||
" dataType: \'json\',\r\n url: \'");
|
||||
WriteLiteral(" id=\"item-template\"");
|
||||
|
||||
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
|
||||
"\"text: DeviceDescription\"></span>\r\n <!-- ko if: !ReadyForReturn && Es" +
|
||||
"timatedReturnTimeUnixEpoc -->\r\n <span class=\"small\">(Expected <span d" +
|
||||
"ata-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>)</span>\r\n <" +
|
||||
"!-- /ko -->\r\n <!-- ko if: WaitingForUserAction -->\r\n <span" +
|
||||
" class=\"small\">(Since <span data-bind=\"livestamp: WaitingForUserActionSinceUnixE" +
|
||||
"poc\"></span>)</span>\r\n <!-- /ko -->\r\n <!-- ko if: ReadyFor" +
|
||||
"Return && !WaitingForUserAction -->\r\n <span class=\"small\">(Ready <spa" +
|
||||
"n data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></span>)</span>\r\n " +
|
||||
" <!-- /ko -->\r\n </li>\r\n </script>\r\n <script>\r\n ko.bindingHa" +
|
||||
"ndlers.livestamp = {\r\n init: function (element, valueAccessor, allBin" +
|
||||
"dings, viewModel, bindingContext) {\r\n var value = valueAccessor()" +
|
||||
";\r\n var valueUnwrapped = ko.unwrap(value);\r\n\r\n if " +
|
||||
"(valueUnwrapped)\r\n $(element).livestamp(valueUnwrapped);\r\n " +
|
||||
" else\r\n $(element).livestamp(\'destroy\');\r\n " +
|
||||
" }\r\n };\r\n </script>\r\n <script>\r\n $(function () {\r\n " +
|
||||
" var hub;\r\n var viewModel;\r\n\r\n var rotateSpeed = 3000" +
|
||||
";\r\n var itemFilters;\r\n\r\n var $inProcessList = $(\'#inProces" +
|
||||
"s\').find(\'ul\');\r\n var $readyForReturnList = $(\'#readyForReturn\').find" +
|
||||
"(\'ul\');\r\n var $waitingForUserActionList = $(\'#waitingForUserAction\')." +
|
||||
"find(\'ul\');\r\n\r\n function noticeboardViewModel(inProcess, readyForRetu" +
|
||||
"rn, waitingForUserAction) {\r\n var self = this;\r\n\r\n " +
|
||||
" self.initialized = false;\r\n\r\n self.inProcess = ko.observableArra" +
|
||||
"y(inProcess);\r\n self.readyForReturn = ko.observableArray(readyFor" +
|
||||
"Return);\r\n self.waitingForUserAction = ko.observableArray(waiting" +
|
||||
"ForUserAction);\r\n\r\n self.onRemove = function (element, index, dat" +
|
||||
"a) {\r\n $(element).slideUp(400, function () {\r\n " +
|
||||
" $(this).remove();\r\n });\r\n }\r\n " +
|
||||
" self.onAdd = function (element, index, data) {\r\n if (" +
|
||||
"self.initialized)\r\n $(element).hide().slideDown(400);\r\n " +
|
||||
" }\r\n }\r\n\r\n function init() {\r\n " +
|
||||
" // Connect to Hub\r\n hub = $.connection.noticeboardUpdates;\r\n\r\n " +
|
||||
" // Map Functions\r\n hub.client.updateHeldDevice = up" +
|
||||
"dateHeldDevice;\r\n\r\n $.connection.hub.qs = { Noticeboard: \'");
|
||||
|
||||
|
||||
#line 432 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.HeldDevices.HeldDevice()));
|
||||
#line 127 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Disco.Services.Jobs.Noticeboards.HeldDevices.Name);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"',
|
||||
data: { id: deviceSerialNumber },
|
||||
success: function (data) {
|
||||
processModel(deviceSerialNumber, data, false);
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
if (textStatus == 'parsererror') // null Result
|
||||
processModel(deviceSerialNumber, null, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
WriteLiteral(@"' };
|
||||
$.connection.hub.error(connectionError);
|
||||
$.connection.hub.disconnected(connectionError);
|
||||
$.connection.hub.reconnected(connectionError);
|
||||
|
||||
var connectionError = function () {
|
||||
if (persistantConnection) {
|
||||
persistantConnection.stop();
|
||||
persistantConnection = null;
|
||||
window.setTimeout(function () {
|
||||
window.location.href = '");
|
||||
// Start Connection
|
||||
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||
}
|
||||
|
||||
// Called after SignalR is connected
|
||||
function loadData() {
|
||||
$.getJSON('");
|
||||
|
||||
|
||||
#line 449 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.HeldDevices.Noticeboard()));
|
||||
#line 138 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
|
||||
" var init = function () {\r\n buildFilters();\r\n " +
|
||||
" persistantConnection = $.connection(\'");
|
||||
|
||||
|
||||
#line 456 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Content("~/Public/HeldDevices/Notifications"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
|
||||
" persistantConnection.error(connectionError);\r\n persistantConnec" +
|
||||
"tion.start(function () {\r\n $.getJSON(\'");
|
||||
|
||||
|
||||
#line 460 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"', null, function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
processModel(data[i].DeviceSerialNumber, data[i], true);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
init();
|
||||
|
||||
});
|
||||
</script>
|
||||
<div");
|
||||
|
||||
WriteLiteral(" id=\"mainFooter\"");
|
||||
|
||||
WriteLiteral(">\r\n <img");
|
||||
|
||||
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
|
||||
|
||||
WriteAttribute("src", Tuple.Create(" src=\"", 22627), Tuple.Create("\"", 22677)
|
||||
|
||||
#line 472 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 22633), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 22633), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" alt=\"Disco Logo\"");
|
||||
|
||||
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
|
||||
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
|
||||
" var readyForReturn = [];\r\n var waitingForUserAction" +
|
||||
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
|
||||
" return includeItem(heldDeviceItem)\r\n }).forEac" +
|
||||
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
|
||||
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
|
||||
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
|
||||
" readyForReturn.push(heldDeviceItem);\r\n " +
|
||||
" else if (isInProcess(heldDeviceItem))\r\n inP" +
|
||||
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
|
||||
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
|
||||
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
|
||||
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
|
||||
"orUserAction);\r\n\r\n ko.applyBindings(viewModel);\r\n " +
|
||||
" viewModel.initialized = true;\r\n\r\n $(\'body\').removeCla" +
|
||||
"ss(\'status-connecting\');\r\n\r\n window.setTimeout(scheduleRotati" +
|
||||
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
|
||||
" }\r\n\r\n // Called by SignalR\r\n function updateHeldDevic" +
|
||||
"e(updates) {\r\n if (viewModel) {\r\n\r\n $.each(upd" +
|
||||
"ates, function (deviceSerialNumber, heldDeviceItem) {\r\n /" +
|
||||
"/ Remove Existing\r\n removeItem(deviceSerialNumber);\r\n\r\n " +
|
||||
" // Add Item\r\n addItem(heldDeviceIte" +
|
||||
"m);\r\n });\r\n }\r\n }\r\n\r\n fu" +
|
||||
"nction removeItem(deviceSerialNumber) {\r\n removeItemFromArray(vie" +
|
||||
"wModel.inProcess, deviceSerialNumber);\r\n removeItemFromArray(view" +
|
||||
"Model.readyForReturn, deviceSerialNumber);\r\n removeItemFromArray(" +
|
||||
"viewModel.waitingForUserAction, deviceSerialNumber);\r\n }\r\n\r\n " +
|
||||
" function addItem(heldDeviceItem) {\r\n if (heldDeviceItem !== nu" +
|
||||
"ll &&\r\n heldDeviceItem !== undefined &&\r\n " +
|
||||
"includeItem(heldDeviceItem)) {\r\n\r\n var array;\r\n\r\n " +
|
||||
" if (isWaitingForUserAction(heldDeviceItem))\r\n arr" +
|
||||
"ay = viewModel.waitingForUserAction;\r\n else if (isReadyForRet" +
|
||||
"urn(heldDeviceItem))\r\n array = viewModel.readyForReturn;\r" +
|
||||
"\n else if (isInProcess(heldDeviceItem))\r\n " +
|
||||
" array = viewModel.inProcess;\r\n\r\n if (array().length === 0" +
|
||||
") {\r\n array.push(heldDeviceItem);\r\n } " +
|
||||
"else {\r\n var index = findSortedInsertIndex(array, heldDev" +
|
||||
"iceItem);\r\n if (index === -1)\r\n " +
|
||||
" array.push(heldDeviceItem);\r\n else\r\n " +
|
||||
" array.splice(index, 0, heldDeviceItem);\r\n }\r\n " +
|
||||
" }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
|
||||
" rotateArray(viewModel.inProcess, $inProcessList);\r\n rotateArr" +
|
||||
"ay(viewModel.readyForReturn, $readyForReturnList);\r\n rotateArray(" +
|
||||
"viewModel.waitingForUserAction, $waitingForUserActionList);\r\n }\r\n\r\n " +
|
||||
" function scheduleRotation() {\r\n rotateArrays();\r\n\r\n " +
|
||||
" window.setTimeout(scheduleRotation, rotateSpeed);\r\n }\r\n\r\n" +
|
||||
" function includeItem(heldDeviceItem) {\r\n if (itemFilt" +
|
||||
"ers == null || itemFilters.length == 0)\r\n return true;\r\n\r\n " +
|
||||
" return itemFilters.reduce(function (previousValue, currentValue, in" +
|
||||
"dex, array) {\r\n if (previousValue === false)\r\n " +
|
||||
" return false;\r\n return currentValue(heldDeviceItem);" +
|
||||
"\r\n }, true);\r\n }\r\n\r\n function buildFilters(" +
|
||||
") {\r\n var filters = [];\r\n var queryStringParameter" +
|
||||
"s = getQueryStringParameters();\r\n\r\n if (queryStringParameters !==" +
|
||||
" null) {\r\n $.each(queryStringParameters, function (key, value" +
|
||||
") {\r\n switch (key.toLowerCase()) {\r\n " +
|
||||
" case \'deviceaddressinclude\':\r\n var deviceA" +
|
||||
"ddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); });\r\n " +
|
||||
" if (deviceAddresses.length > 0) {\r\n " +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // false if DeviceAddressShortName is null\r\n " +
|
||||
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
|
||||
" return false;\r\n\r\n " +
|
||||
" // true if DeviceAddressShortName is included\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceAddressShortName.toLower" +
|
||||
"Case(), deviceAddresses) >= 0;\r\n });\r\n " +
|
||||
" }\r\n break;\r\n " +
|
||||
" case \'deviceaddressexclude\':\r\n va" +
|
||||
"r deviceAddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); " +
|
||||
"});\r\n if (deviceAddresses.length > 0) {\r\n " +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // true if DeviceAddressShortName is null\r\n " +
|
||||
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
|
||||
" return true;\r\n\r\n " +
|
||||
" // true if DeviceAddressShortName is excluded\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceAddressShortName." +
|
||||
"toLowerCase(), deviceAddresses) < 0;\r\n });\r\n " +
|
||||
" }\r\n break;\r\n " +
|
||||
" case \'deviceprofileinclude\':\r\n " +
|
||||
" var deviceProfiles = value.split(\",\");\r\n if (" +
|
||||
"deviceProfiles.length > 0) {\r\n filters.push(f" +
|
||||
"unction (heldDeviceItem) {\r\n // true if D" +
|
||||
"eviceProfileId is included\r\n return $.inA" +
|
||||
"rray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;\r\n " +
|
||||
" });\r\n }\r\n " +
|
||||
" break;\r\n case \'deviceprofileexclude\':\r\n " +
|
||||
" var deviceProfiles = value.split(\",\");\r\n " +
|
||||
" if (deviceProfiles.length > 0) {\r\n " +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // true if DeviceProfileId is excluded\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;\r" +
|
||||
"\n });\r\n }\r\n " +
|
||||
" break;\r\n }\r\n " +
|
||||
" });\r\n }\r\n\r\n if (filters.length > 0)\r\n " +
|
||||
" itemFilters = filters;\r\n else\r\n ite" +
|
||||
"mFilters = null;\r\n }\r\n\r\n function connectionError() {\r\n " +
|
||||
" try {\r\n $(\'body\').addClass(\'status-error\');\r\n " +
|
||||
" $.connection.hub.stop();\r\n } catch (e) {\r\n " +
|
||||
" // Ignore\r\n }\r\n\r\n window.setTimeout(" +
|
||||
"function () {\r\n window.location.href = window.location.href;\r" +
|
||||
"\n }, 10000);\r\n }\r\n\r\n // Helpers\r\n " +
|
||||
" function rotateArray(koArray, element) {\r\n var items = koArray(" +
|
||||
");\r\n\r\n if (items.length <= 1)\r\n return 0;\r\n\r\n " +
|
||||
" if (element.height() < (element.parent().height() - 30)) {\r\n\r\n " +
|
||||
" if (findUnsortedArrayTopIndex(items) !== 0)\r\n " +
|
||||
" koArray.sort(sortFunction);\r\n\r\n // Don\'t rotate if smal" +
|
||||
"l & sorted correctly\r\n return;\r\n }\r\n\r\n " +
|
||||
" // Move Last Item to Top\r\n var item = koArray.pop();\r\n " +
|
||||
" koArray.unshift(item);\r\n }\r\n function removeI" +
|
||||
"temFromArray(koArray, deviceSerialNumber) {\r\n var items = koArray" +
|
||||
"();\r\n for (var i = 0; i < items.length; i++) {\r\n " +
|
||||
" if (items[i].DeviceSerialNumber == deviceSerialNumber) {\r\n " +
|
||||
" koArray.splice(i, 1);\r\n items = koArray();\r\n " +
|
||||
" i--;\r\n }\r\n }\r\n }\r\n " +
|
||||
" function findUnsortedArrayTopIndex(items) {\r\n // Only " +
|
||||
"one Item\r\n if (items.length <= 1)\r\n return 0;\r" +
|
||||
"\n\r\n for (var i = 1; i < items.length; i++) {\r\n " +
|
||||
" var s = sortFunction(items[i - 1], items[i]);\r\n if (s > 0)\r\n" +
|
||||
" return i;\r\n }\r\n\r\n return 0" +
|
||||
";\r\n }\r\n function findSortedInsertIndex(koArray, heldDevice" +
|
||||
"Item) {\r\n var items = koArray();\r\n var startIndex " +
|
||||
"= findUnsortedArrayTopIndex(items);\r\n for (var i = startIndex; i " +
|
||||
"< items.length; i++) {\r\n var s = sortFunction(heldDeviceItem," +
|
||||
" items[i]);\r\n if (s <= 0)\r\n return i;\r" +
|
||||
"\n }\r\n if (startIndex !== 0) {\r\n " +
|
||||
" for (var i = 0; i < startIndex; i++) {\r\n var s = sortFun" +
|
||||
"ction(heldDeviceItem, items[i]);\r\n if (s <= 0)\r\n " +
|
||||
" return i;\r\n }\r\n return " +
|
||||
"startIndex;\r\n } else {\r\n return -1;\r\n " +
|
||||
" }\r\n }\r\n function sortFunction(l, r) {\r\n " +
|
||||
" return l.DeviceDescription.toLowerCase() == r.DeviceDescription.toLowerCase(" +
|
||||
") ? 0 : (l.DeviceDescription.toLowerCase() < r.DeviceDescription.toLowerCase() ?" +
|
||||
" -1 : 1)\r\n }\r\n function isInProcess(i) {\r\n " +
|
||||
"return !i.ReadyForReturn && !i.WaitingForUserAction;\r\n }\r\n " +
|
||||
" function isReadyForReturn(i) {\r\n return i.ReadyForReturn && !i.W" +
|
||||
"aitingForUserAction;\r\n }\r\n function isWaitingForUserAction" +
|
||||
"(i) {\r\n return i.WaitingForUserAction;\r\n }\r\n " +
|
||||
" function getQueryStringParameters() {\r\n\r\n if (window.location.s" +
|
||||
"earch.length === 0)\r\n return null;\r\n\r\n var par" +
|
||||
"ams = {};\r\n window.location.search.substr(1).split(\"&\").forEach(f" +
|
||||
"unction (pair) {\r\n if (pair === \"\") return;\r\n " +
|
||||
" var parts = pair.split(\"=\");\r\n params[parts[0]] = parts[1" +
|
||||
"] && decodeURIComponent(parts[1].replace(/\\+/g, \" \"));\r\n });\r\n " +
|
||||
" return params;\r\n }\r\n\r\n init();\r\n });\r\n" +
|
||||
" </script>\r\n</body>\r\n</html>");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@model IEnumerable<Disco.Web.Areas.Public.Models.UserHeldDevices.UserHeldDeviceModel>
|
||||
@model IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>
|
||||
@{
|
||||
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices for Users", null);
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
||||
@@ -8,21 +8,19 @@
|
||||
@{
|
||||
var DevicesInProcess = Model.Where(i => !i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||
}
|
||||
<h2>
|
||||
In Process (@DevicesInProcess.Length)</h2>
|
||||
<h2>In Process (@DevicesInProcess.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in DevicesInProcess)
|
||||
@foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.UserId
|
||||
@item.UserIdFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@item.UserDisplayName@{
|
||||
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
|
||||
{
|
||||
<span class="smallMessage">(Expected: @item.EstimatedReturnTime)</span>
|
||||
}
|
||||
@item.UserDisplayName
|
||||
@if (item.EstimatedReturnTime.HasValue)
|
||||
{
|
||||
<span class="smallMessage">(Expected: @CommonHelpers.FriendlyDate(item.EstimatedReturnTime))</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -33,20 +31,18 @@
|
||||
@{
|
||||
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
|
||||
}
|
||||
<h2>
|
||||
Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
||||
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in WaitingForUserActionJobs)
|
||||
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.UserId
|
||||
@item.UserIdFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@item.UserDisplayName
|
||||
</td>
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
|
||||
Since @item.WaitingForUserActionSince
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @CommonHelpers.FriendlyDate(item.WaitingForUserActionSince)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@@ -55,20 +51,18 @@
|
||||
@{
|
||||
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||
}
|
||||
<h2>
|
||||
Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
||||
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
||||
<table class="dataTable">
|
||||
@foreach (var item in DevicesReadyForReturn)
|
||||
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
<tr>
|
||||
<td class="id">
|
||||
@item.UserId
|
||||
@item.UserIdFriendly
|
||||
</td>
|
||||
<td class="description">
|
||||
@item.UserDisplayName
|
||||
</td>
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
|
||||
Ready @item.ReadyForReturnSince
|
||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @CommonHelpers.FriendlyDate(item.ReadyForReturnSince)
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -36,7 +36,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/UserHeldDevices/Index.cshtml")]
|
||||
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Web.Areas.Public.Models.UserHeldDevices.UserHeldDeviceModel>>
|
||||
public partial class Index : Disco.Services.Web.WebViewPage<IEnumerable<Disco.Models.Services.Jobs.Noticeboards.IHeldDeviceItem>>
|
||||
{
|
||||
public Index()
|
||||
{
|
||||
@@ -76,10 +76,10 @@ WriteLiteral(">\r\n");
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n <h2>\r\n In Process (");
|
||||
WriteLiteral("\r\n <h2>In Process (");
|
||||
|
||||
|
||||
#line 12 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 11 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(DevicesInProcess.Length);
|
||||
|
||||
|
||||
@@ -92,14 +92,14 @@ WriteLiteral(" class=\"dataTable\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesInProcess)
|
||||
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -114,8 +114,8 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 18 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
#line 17 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -129,17 +129,24 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 20 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserDisplayName);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
|
||||
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
if (item.EstimatedReturnTime.HasValue)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
@@ -151,8 +158,8 @@ WriteLiteral(" class=\"smallMessage\"");
|
||||
WriteLiteral(">(Expected: ");
|
||||
|
||||
|
||||
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.EstimatedReturnTime);
|
||||
#line 23 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -160,16 +167,16 @@ WriteLiteral(">(Expected: ");
|
||||
WriteLiteral(")</span>\r\n");
|
||||
|
||||
|
||||
#line 25 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
}
|
||||
|
||||
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 29 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 27 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -182,23 +189,23 @@ WriteLiteral(" class=\"column2\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 33 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 31 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 33 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 31 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n <h2>\r\n Waiting for User Action (");
|
||||
WriteLiteral("\r\n <h2>Waiting for User Action (");
|
||||
|
||||
|
||||
#line 37 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 34 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(WaitingForUserActionJobs.Length);
|
||||
|
||||
|
||||
@@ -211,14 +218,14 @@ WriteLiteral(" class=\"dataTable\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in WaitingForUserActionJobs)
|
||||
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -233,8 +240,8 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
#line 40 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -248,7 +255,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 46 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserDisplayName);
|
||||
|
||||
|
||||
@@ -256,22 +263,22 @@ WriteLiteral(" ");
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </td>\r\n <td");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 1795), Tuple.Create("\"", 1853)
|
||||
, Tuple.Create(Tuple.Create("", 1803), Tuple.Create("timestamp", 1803), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 1845), Tuple.Create("\"", 1903)
|
||||
, Tuple.Create(Tuple.Create("", 1853), Tuple.Create("timestamp", 1853), true)
|
||||
|
||||
#line 48 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1812), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1862), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1812), false)
|
||||
, 1862), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n Since ");
|
||||
WriteLiteral(">Since ");
|
||||
|
||||
|
||||
#line 49 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.WaitingForUserActionSince);
|
||||
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -279,7 +286,7 @@ WriteLiteral(">\r\n Since ");
|
||||
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 52 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 48 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -288,23 +295,23 @@ WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
||||
WriteLiteral(" </table>\r\n <hr />\r\n");
|
||||
|
||||
|
||||
#line 55 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 51 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 55 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 51 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n <h2>\r\n Ready for Return (");
|
||||
WriteLiteral("\r\n <h2>Ready for Return (");
|
||||
|
||||
|
||||
#line 59 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 54 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(DevicesReadyForReturn.Length);
|
||||
|
||||
|
||||
@@ -317,14 +324,14 @@ WriteLiteral(" class=\"dataTable\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesReadyForReturn)
|
||||
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
|
||||
{
|
||||
|
||||
|
||||
@@ -339,8 +346,8 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserId);
|
||||
#line 60 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserIdFriendly);
|
||||
|
||||
|
||||
#line default
|
||||
@@ -354,7 +361,7 @@ WriteLiteral(">\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 68 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 63 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.UserDisplayName);
|
||||
|
||||
|
||||
@@ -362,22 +369,22 @@ WriteLiteral(" ");
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </td>\r\n <td");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 2612), Tuple.Create("\"", 2670)
|
||||
, Tuple.Create(Tuple.Create("", 2620), Tuple.Create("timestamp", 2620), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 2689), Tuple.Create("\"", 2747)
|
||||
, Tuple.Create(Tuple.Create("", 2697), Tuple.Create("timestamp", 2697), true)
|
||||
|
||||
#line 70 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 2629), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 2706), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 2629), false)
|
||||
, 2706), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n Ready ");
|
||||
WriteLiteral(">Ready ");
|
||||
|
||||
|
||||
#line 71 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(item.ReadyForReturnSince);
|
||||
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -385,7 +392,7 @@ WriteLiteral(">\r\n Ready ");
|
||||
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 74 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
#line 68 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@{
|
||||
Layout = null;
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
Html.BundleDeferred("~/ClientScripts/Core");
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||
@@ -9,471 +10,397 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Disco - Technician Held Devices for Users</title>
|
||||
<title>Disco ICT - Held Devices for Users</title>
|
||||
@Html.BundleRenderDeferred()
|
||||
</head>
|
||||
<body>
|
||||
<body class="status-connecting">
|
||||
<div id="page">
|
||||
<header id="mainHeader">
|
||||
Technician Held Devices for Users
|
||||
</header>
|
||||
<header id="header">
|
||||
<div id="heading">Held Devices for Users</div>
|
||||
<div id="statusConnecting"><i class="fa fa-cog fa-spin"></i><span>connecting...</span></div>
|
||||
<div id="statusError"><i class="fa fa-cog fa-spin"></i><span>disconnected, reconnecting...</span></div>
|
||||
<div id="credits">
|
||||
powered by Disco ICT <i title="Disco ICT - Jobs"></i>
|
||||
</div>
|
||||
</header>
|
||||
<section id="mainSection">
|
||||
<div id="inProcess" class="list">
|
||||
<h3>
|
||||
In Process <span id="inProcessCount"></span>
|
||||
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: inProcess().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="readyForReturn" class="list">
|
||||
<h3>
|
||||
Ready for Return <span id="readyForReturnCount"></span>
|
||||
<h3>Ready for Return (<span data-bind="text: readyForReturn().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: readyForReturn().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="waitingForUserAction" class="list">
|
||||
<h3>
|
||||
Waiting for User Action <span id="waitingForUserActionCount"></span>
|
||||
<h3>Waiting for User Action (<span data-bind="text: waitingForUserAction().length"></span>)
|
||||
</h3>
|
||||
<div class="content">
|
||||
<ul>
|
||||
</ul>
|
||||
<!-- ko if: waitingForUserAction().length == 0 -->
|
||||
<div class="noContent"><None></div>
|
||||
<!-- /ko -->
|
||||
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<footer id="footer">
|
||||
</footer>
|
||||
</section>
|
||||
<footer>
|
||||
</footer>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
// Resizing
|
||||
$(function () {
|
||||
var $inProcess = $('#inProcess');
|
||||
var $inProcessContent = $inProcess.find('.content');
|
||||
var $inProcessHeader = $inProcess.find('.h3');
|
||||
var $readyForReturn = $('#readyForReturn');
|
||||
var $readyForReturnContent = $readyForReturn.find('.content');
|
||||
var $readyForReturnHeader = $readyForReturn.find('.h3');
|
||||
var $waitingForUserAction = $('#waitingForUserAction');
|
||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
|
||||
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
|
||||
var $mainSection = $('#mainSection');
|
||||
var $mainHeader = $('#mainHeader');
|
||||
var $mainFooter = $('#mainFooter');
|
||||
|
||||
var onResize = function () {
|
||||
var width = $mainSection.width();
|
||||
var height = $(window).height() - $mainHeader.outerHeight() - $mainFooter.outerHeight() - 25;
|
||||
|
||||
$inProcess.height(height);
|
||||
$inProcess.width((width * .28) - 11);
|
||||
$inProcessContent.height(height - $inProcessHeader.outerHeight() - 56);
|
||||
|
||||
$readyForReturn.height(height);
|
||||
$readyForReturn.width((width * .36) - 11);
|
||||
$readyForReturnContent.height(height - $readyForReturnHeader.outerHeight() - 56);
|
||||
|
||||
$waitingForUserAction.height(height);
|
||||
$waitingForUserAction.width((width * .36) - 11);
|
||||
$waitingForUserActionContent.height(height - $waitingForUserActionHeader.outerHeight() - 56);
|
||||
};
|
||||
|
||||
$(window).resize(onResize);
|
||||
onResize();
|
||||
});
|
||||
<script type="text/html" id="item-template">
|
||||
<li data-bind="css: { alert: IsAlert }">
|
||||
<span data-bind="text: UserIdFriendly + ' - ' + UserDisplayName"></span>
|
||||
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
|
||||
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: WaitingForUserAction -->
|
||||
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
|
||||
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
|
||||
<!-- /ko -->
|
||||
</li>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// Hide Mouse Mouse
|
||||
$(function () {
|
||||
var mouseVisible = true;
|
||||
var mouseHideToken;
|
||||
var documentBody = $('body');
|
||||
<script>
|
||||
ko.bindingHandlers.livestamp = {
|
||||
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
var value = valueAccessor();
|
||||
var valueUnwrapped = ko.unwrap(value);
|
||||
|
||||
var hideMouse = function () {
|
||||
if (mouseVisible) {
|
||||
documentBody.css('cursor', 'none');
|
||||
mouseVisible = false;
|
||||
}
|
||||
};
|
||||
var showMouse = function () {
|
||||
if (!mouseVisible) {
|
||||
documentBody.css('cursor', 'auto');
|
||||
mouseVisible = true;
|
||||
}
|
||||
};
|
||||
|
||||
$(document).mousemove(function () {
|
||||
showMouse();
|
||||
if (mouseHideToken)
|
||||
window.clearTimeout(mouseHideToken);
|
||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var models = {};
|
||||
var modelsInProcessSorted = [];
|
||||
var modelsInProcessCount = 0;
|
||||
var modelsReadyForReturnSorted = [];
|
||||
var modelsReadyForReturnCount = 0;
|
||||
var modelsWaitingForUserActionSorted = [];
|
||||
var modelsWaitingForUserActionCount = 0;
|
||||
var $inProcess = $('#inProcess');
|
||||
var $inProcessContent = $inProcess.find('.content ul');
|
||||
var $readyForReturn = $('#readyForReturn');
|
||||
var $readyForReturnContent = $readyForReturn.find('.content ul');
|
||||
var $waitingForUserAction = $('#waitingForUserAction');
|
||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content ul');
|
||||
var modelsInProcessIndexOffset = 0;
|
||||
var scrollInProcessToken = null;
|
||||
var modelsReadyForReturnIndexOffset = 0;
|
||||
var scrollReadyForReturnToken = null;
|
||||
var modelsWaitingForUserActionIndexOffset = 0;
|
||||
var scrollWaitingForUserActionToken = null;
|
||||
var scrollSpeed = 3000;
|
||||
var persistantConnection = null;
|
||||
var filterDeviceAddressInclude;
|
||||
var filterDeviceAddressExclude;
|
||||
var filterDeviceProfileInclude;
|
||||
var filterDeviceProfileExclude;
|
||||
|
||||
var getParameterByName = function (name) {
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
||||
var regex = new RegExp(regexS);
|
||||
var results = regex.exec(window.location.search);
|
||||
if (results == null)
|
||||
return "";
|
||||
if (valueUnwrapped)
|
||||
$(element).livestamp(valueUnwrapped);
|
||||
else
|
||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
||||
$(element).livestamp('destroy');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
$(function () {
|
||||
var hub;
|
||||
var viewModel;
|
||||
|
||||
var buildFilters = function () {
|
||||
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
|
||||
if (deviceAddressInclude) {
|
||||
filterDeviceAddressInclude = {};
|
||||
var split = deviceAddressInclude.split(",");
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
filterDeviceAddressInclude[split[i].toLowerCase()] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceAddressExclude = getParameterByName('deviceAddressExclude');
|
||||
if (deviceAddressExclude) {
|
||||
filterDeviceAddressExclude = {};
|
||||
var split = deviceAddressExclude.split(",");
|
||||
for (var i = 0; i < split.length; i++) {
|
||||
filterDeviceAddressExclude[split[i].toLowerCase()] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceProfileInclude = getParameterByName('deviceProfileInclude');
|
||||
if (deviceProfileInclude) {
|
||||
filterDeviceProfileInclude = {};
|
||||
var deviceProfileIncludeSplit = deviceProfileInclude.split(",");
|
||||
for (var i = 0; i < deviceProfileIncludeSplit.length; i++) {
|
||||
filterDeviceProfileInclude[parseInt(deviceProfileIncludeSplit[i])] = true;
|
||||
}
|
||||
} else {
|
||||
var deviceProfileExclude = getParameterByName('deviceProfileExclude');
|
||||
if (deviceProfileExclude) {
|
||||
filterDeviceProfileExclude = {};
|
||||
var deviceProfileExcludeSplit = deviceProfileExclude.split(",");
|
||||
for (var i = 0; i < deviceProfileExcludeSplit.length; i++) {
|
||||
filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var calculateFilter = function (model) {
|
||||
if (model) {
|
||||
if (filterDeviceAddressInclude) {
|
||||
return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)
|
||||
}
|
||||
if (filterDeviceAddressExclude) {
|
||||
return (!filterDeviceAddressExclude[model.DeviceAddress.toLowerCase()])
|
||||
}
|
||||
if (filterDeviceProfileInclude) {
|
||||
return (filterDeviceProfileInclude[model.DeviceProfileId] == true)
|
||||
}
|
||||
if (filterDeviceProfileExclude) {
|
||||
return (!filterDeviceProfileExclude[model.DeviceProfileId])
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
var rotateSpeed = 3000;
|
||||
var itemFilters;
|
||||
|
||||
var sortModels = function () {
|
||||
modelsInProcessSorted = [];
|
||||
modelsReadyForReturnSorted = [];
|
||||
modelsWaitingForUserActionSorted = [];
|
||||
var modelSortFunc = function (a, b) {
|
||||
if (a.UserId.toUpperCase() == b.UserId.toUpperCase()) {
|
||||
return 0;
|
||||
} else {
|
||||
if (a.UserId.toUpperCase() < b.UserId.toUpperCase()) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
};
|
||||
for (var key in models) {
|
||||
var model = models[key];
|
||||
if (model) {
|
||||
if (model.WaitingForUserAction) {
|
||||
modelsWaitingForUserActionSorted.push(model);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
modelsReadyForReturnSorted.push(model);
|
||||
} else {
|
||||
modelsInProcessSorted.push(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortFunc);
|
||||
modelsInProcessSorted = modelsInProcessSorted.sort(modelSortFunc);
|
||||
modelsWaitingForUserActionSorted = modelsWaitingForUserActionSorted.sort(modelSortFunc);
|
||||
var $inProcessList = $('#inProcess').find('ul');
|
||||
var $readyForReturnList = $('#readyForReturn').find('ul');
|
||||
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
|
||||
|
||||
if (modelsInProcessSorted.length != modelsInProcessCount) {
|
||||
modelsInProcessCount = modelsInProcessSorted.length;
|
||||
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
|
||||
}
|
||||
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
|
||||
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
|
||||
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
|
||||
}
|
||||
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
|
||||
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
|
||||
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
|
||||
}
|
||||
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
|
||||
var self = this;
|
||||
|
||||
};
|
||||
self.initialized = false;
|
||||
|
||||
var scrollReadyForReturn = function () {
|
||||
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
|
||||
modelsReadyForReturnIndexOffset++;
|
||||
if (modelsReadyForReturnIndexOffset >= modelsReadyForReturnSorted.length) {
|
||||
modelsReadyForReturnIndexOffset = 0;
|
||||
}
|
||||
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
|
||||
};
|
||||
var updateScrollReadyForReturn = function () {
|
||||
var containerHeight = $readyForReturn.find('.content').height();
|
||||
var contentHeight = $readyForReturnContent.height();
|
||||
if (containerHeight >= contentHeight && scrollReadyForReturnToken) {
|
||||
window.clearTimeout(scrollReadyForReturnToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollReadyForReturnToken == null) {
|
||||
scrollReadyForReturnToken = window.setTimeout(scrollReadyForReturn, scrollSpeed);
|
||||
}
|
||||
};
|
||||
var scrollInProcess = function () {
|
||||
$inProcessContent.find('li').last().detach().prependTo($inProcessContent).hide().slideDown('slow');
|
||||
modelsInProcessIndexOffset++;
|
||||
if (modelsInProcessIndexOffset >= modelsInProcessSorted.length) {
|
||||
modelsInProcessIndexOffset = 0;
|
||||
}
|
||||
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
|
||||
};
|
||||
var updateScrollInProcess = function () {
|
||||
var containerHeight = $inProcess.find('.content').height();
|
||||
var contentHeight = $inProcessContent.height();
|
||||
if (containerHeight >= contentHeight && scrollInProcessToken) {
|
||||
window.clearTimeout(scrollInProcessToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollInProcessToken == null) {
|
||||
scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);
|
||||
}
|
||||
};
|
||||
var scrollWaitingForUserAction = function () {
|
||||
$waitingForUserActionContent.find('li').last().detach().prependTo($waitingForUserActionContent).hide().slideDown('slow');
|
||||
modelsInProcessIndexOffset++;
|
||||
if (modelsWaitingForUserActionIndexOffset >= modelsWaitingForUserActionSorted.length) {
|
||||
modelsWaitingForUserActionIndexOffset = 0;
|
||||
}
|
||||
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
|
||||
};
|
||||
var updateScrollWaitingForUserAction = function () {
|
||||
var containerHeight = $waitingForUserAction.find('.content').height();
|
||||
var contentHeight = $waitingForUserActionContent.height();
|
||||
if (containerHeight >= contentHeight && scrollWaitingForUserActionToken) {
|
||||
window.clearTimeout(scrollWaitingForUserActionToken);
|
||||
return;
|
||||
}
|
||||
if (containerHeight < contentHeight && scrollWaitingForUserActionToken == null) {
|
||||
scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserAction, scrollSpeed);
|
||||
}
|
||||
};
|
||||
self.inProcess = ko.observableArray(inProcess);
|
||||
self.readyForReturn = ko.observableArray(readyForReturn);
|
||||
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
|
||||
|
||||
var modelInsertIndex = function (model) {
|
||||
sortModels();
|
||||
var findIndex = function (model, array, offset) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (model.UserId == array[i].UserId) {
|
||||
var index = i + offset;
|
||||
if (index > (array.length - 1)) {
|
||||
index = index - (array.length - 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
};
|
||||
};
|
||||
if (model.WaitingForUserAction) {
|
||||
return findIndex(model, modelsWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
return findIndex(model, modelsReadyForReturnSorted, modelsReadyForReturnIndexOffset);
|
||||
} else {
|
||||
return findIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
var modelInsert = function (model) {
|
||||
var index = modelInsertIndex(model);
|
||||
var insertTo = function (model, host) {
|
||||
var hostLi = host.children('li');
|
||||
if (hostLi.length == 0 || hostLi.length < index) {
|
||||
host.append(model.htmlLi);
|
||||
} else {
|
||||
if (index == 0) {
|
||||
host.prepend(model.htmlLi);
|
||||
} else {
|
||||
$(hostLi.get(index - 1)).after(model.htmlLi);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (model.WaitingForUserAction) {
|
||||
insertTo(model, $waitingForUserActionContent);
|
||||
window.setTimeout(updateScrollWaitingForUserAction, 100);
|
||||
} else {
|
||||
if (model.ReadyForReturn) {
|
||||
insertTo(model, $readyForReturnContent);
|
||||
window.setTimeout(updateScrollReadyForReturn, 100);
|
||||
} else {
|
||||
insertTo(model, $inProcessContent);
|
||||
window.setTimeout(updateScrollInProcess, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removeModel = function (model) {
|
||||
if (model) {
|
||||
model.htmlLi.slideUp('fast', function () {
|
||||
model.htmlLi.remove();
|
||||
self.onRemove = function (element, index, data) {
|
||||
$(element).slideUp(400, function () {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var processModel = function (id, model, init) {
|
||||
if (!calculateFilter(model)) {
|
||||
removeModel(models[id]);
|
||||
delete models[id];
|
||||
sortModels();
|
||||
} else {
|
||||
var existing = models[id];
|
||||
models[id] = model;
|
||||
|
||||
// Add
|
||||
model.htmlContent = $('<div>').text(model.UserId + ' - ' + model.UserDisplayName);
|
||||
if (!model.ReadyForReturn && model.EstimatedReturnTime) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Expected: ' + model.EstimatedReturnTime + ')'));
|
||||
}
|
||||
if (model.WaitingForUserAction) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Since ' + model.WaitingForUserActionSince + ')'));
|
||||
} else {
|
||||
if (model.ReadyForReturn && model.ReadyForReturnSince) {
|
||||
model.htmlContent.append($('<span class="small">').text(' (Ready ' + model.ReadyForReturnSince + ')'));
|
||||
}
|
||||
}
|
||||
|
||||
if (existing) {
|
||||
if (existing.ReadyForReturn != model.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction) {
|
||||
removeModel(existing);
|
||||
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
|
||||
modelInsert(model);
|
||||
if (init) {
|
||||
model.htmlLi.fadeIn();
|
||||
} else {
|
||||
model.htmlLi.slideDown();
|
||||
}
|
||||
} else {
|
||||
model.htmlLi = existing.htmlLi;
|
||||
model.htmlLi.slideUp('fast', function () {
|
||||
model.htmlLi.html(model.htmlContent).slideDown();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
model.htmlLi = $('<li>').html(model.htmlContent).data('ModelId', id).hide();
|
||||
modelInsert(model);
|
||||
if (init) {
|
||||
model.htmlLi.fadeIn();
|
||||
} else {
|
||||
model.htmlLi.slideDown('slow');
|
||||
}
|
||||
}
|
||||
if (model.htmlLi && model.IsAlert) {
|
||||
model.htmlLi.addClass('alert');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var updatedModel = function (id) {
|
||||
var userId = id.toString();
|
||||
|
||||
$.ajax({
|
||||
dataType: 'json',
|
||||
url: '@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevice()))',
|
||||
data: { id: userId },
|
||||
success: function (data) {
|
||||
processModel(userId, data, false);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown){
|
||||
if (textStatus == 'parsererror') // null Result
|
||||
processModel(userId, null, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var connectionError = function () {
|
||||
if (persistantConnection) {
|
||||
persistantConnection.stop();
|
||||
persistantConnection = null;
|
||||
window.setTimeout(function () {
|
||||
window.location.href = '@(Url.Action(MVC.Public.UserHeldDevices.Noticeboard()))';
|
||||
}, 10000);
|
||||
self.onAdd = function (element, index, data) {
|
||||
if (self.initialized)
|
||||
$(element).hide().slideDown(400);
|
||||
}
|
||||
}
|
||||
|
||||
var init = function () {
|
||||
buildFilters();
|
||||
persistantConnection = $.connection('@(Url.Content("~/Public/UserHeldDevices/Notifications"))');
|
||||
persistantConnection.received(updatedModel);
|
||||
persistantConnection.error(connectionError);
|
||||
persistantConnection.start(function () {
|
||||
$.getJSON('@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()))', null, function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
processModel(data[i].UserId, data[i], true);
|
||||
}
|
||||
function init() {
|
||||
// Connect to Hub
|
||||
hub = $.connection.noticeboardUpdates;
|
||||
|
||||
// Map Functions
|
||||
hub.client.updateHeldDeviceForUser = updateHeldDevice;
|
||||
|
||||
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name)' };
|
||||
$.connection.hub.error(connectionError);
|
||||
$.connection.hub.disconnected(connectionError);
|
||||
$.connection.hub.reconnected(connectionError);
|
||||
|
||||
// Start Connection
|
||||
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||
}
|
||||
|
||||
// Called after SignalR is connected
|
||||
function loadData() {
|
||||
$.getJSON('@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()))', null, function (data) {
|
||||
|
||||
var inProcess = [];
|
||||
var readyForReturn = [];
|
||||
var waitingForUserAction = [];
|
||||
|
||||
data.filter(function (heldDeviceItem) {
|
||||
return includeItem(heldDeviceItem)
|
||||
}).forEach(function (heldDeviceItem) {
|
||||
if (isWaitingForUserAction(heldDeviceItem))
|
||||
waitingForUserAction.push(heldDeviceItem);
|
||||
else if (isReadyForReturn(heldDeviceItem))
|
||||
readyForReturn.push(heldDeviceItem);
|
||||
else if (isInProcess(heldDeviceItem))
|
||||
inProcess.push(heldDeviceItem);
|
||||
});
|
||||
|
||||
inProcess.sort(sortFunction);
|
||||
readyForReturn.sort(sortFunction);
|
||||
waitingForUserAction.sort(sortFunction);
|
||||
|
||||
viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction);
|
||||
|
||||
ko.applyBindings(viewModel);
|
||||
viewModel.initialized = true;
|
||||
|
||||
$('body').removeClass('status-connecting');
|
||||
|
||||
window.setTimeout(scheduleRotation, rotateSpeed);
|
||||
});
|
||||
};
|
||||
init();
|
||||
buildFilters();
|
||||
}
|
||||
|
||||
// Called by SignalR
|
||||
function updateHeldDevice(updates) {
|
||||
if (viewModel) {
|
||||
|
||||
$.each(updates, function (UserId, heldDeviceItem) {
|
||||
// Remove Existing
|
||||
removeItem(UserId);
|
||||
|
||||
// Add Item
|
||||
addItem(heldDeviceItem);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function removeItem(UserId) {
|
||||
removeItemFromArray(viewModel.inProcess, UserId);
|
||||
removeItemFromArray(viewModel.readyForReturn, UserId);
|
||||
removeItemFromArray(viewModel.waitingForUserAction, UserId);
|
||||
}
|
||||
|
||||
function addItem(heldDeviceItem) {
|
||||
if (heldDeviceItem !== null &&
|
||||
heldDeviceItem !== undefined &&
|
||||
includeItem(heldDeviceItem)) {
|
||||
|
||||
var array;
|
||||
|
||||
if (isWaitingForUserAction(heldDeviceItem))
|
||||
array = viewModel.waitingForUserAction;
|
||||
else if (isReadyForReturn(heldDeviceItem))
|
||||
array = viewModel.readyForReturn;
|
||||
else if (isInProcess(heldDeviceItem))
|
||||
array = viewModel.inProcess;
|
||||
|
||||
if (array().length === 0) {
|
||||
array.push(heldDeviceItem);
|
||||
} else {
|
||||
var index = findSortedInsertIndex(array, heldDeviceItem);
|
||||
if (index === -1)
|
||||
array.push(heldDeviceItem);
|
||||
else
|
||||
array.splice(index, 0, heldDeviceItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rotateArrays() {
|
||||
rotateArray(viewModel.inProcess, $inProcessList);
|
||||
rotateArray(viewModel.readyForReturn, $readyForReturnList);
|
||||
rotateArray(viewModel.waitingForUserAction, $waitingForUserActionList);
|
||||
}
|
||||
|
||||
function scheduleRotation() {
|
||||
rotateArrays();
|
||||
|
||||
window.setTimeout(scheduleRotation, rotateSpeed);
|
||||
}
|
||||
|
||||
function includeItem(heldDeviceItem) {
|
||||
if (itemFilters == null || itemFilters.length == 0)
|
||||
return true;
|
||||
|
||||
return itemFilters.reduce(function (previousValue, currentValue, index, array) {
|
||||
if (previousValue === false)
|
||||
return false;
|
||||
return currentValue(heldDeviceItem);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function buildFilters() {
|
||||
var filters = [];
|
||||
var queryStringParameters = getQueryStringParameters();
|
||||
|
||||
if (queryStringParameters !== null) {
|
||||
$.each(queryStringParameters, function (key, value) {
|
||||
switch (key.toLowerCase()) {
|
||||
case 'deviceaddressinclude':
|
||||
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
|
||||
if (deviceAddresses.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// false if DeviceAddressShortName is null
|
||||
if (!heldDeviceItem.DeviceAddressShortName)
|
||||
return false;
|
||||
|
||||
// true if DeviceAddressShortName is included
|
||||
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) >= 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceaddressexclude':
|
||||
var deviceAddresses = value.split(",").map(function (v) { return v.toLowerCase(); });
|
||||
if (deviceAddresses.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceAddressShortName is null
|
||||
if (!heldDeviceItem.DeviceAddressShortName)
|
||||
return true;
|
||||
|
||||
// true if DeviceAddressShortName is excluded
|
||||
return $.inArray(heldDeviceItem.DeviceAddressShortName.toLowerCase(), deviceAddresses) < 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceprofileinclude':
|
||||
var deviceProfiles = value.split(",");
|
||||
if (deviceProfiles.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceProfileId is included
|
||||
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'deviceprofileexclude':
|
||||
var deviceProfiles = value.split(",");
|
||||
if (deviceProfiles.length > 0) {
|
||||
filters.push(function (heldDeviceItem) {
|
||||
// true if DeviceProfileId is excluded
|
||||
return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) < 0;
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (filters.length > 0)
|
||||
itemFilters = filters;
|
||||
else
|
||||
itemFilters = null;
|
||||
}
|
||||
|
||||
function connectionError() {
|
||||
try {
|
||||
$('body').addClass('status-error');
|
||||
$.connection.hub.stop();
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
window.setTimeout(function () {
|
||||
window.location.href = window.location.href;
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
function rotateArray(koArray, element) {
|
||||
var items = koArray();
|
||||
|
||||
if (items.length <= 1)
|
||||
return 0;
|
||||
|
||||
if (element.height() < (element.parent().height() - 30)) {
|
||||
|
||||
if (findUnsortedArrayTopIndex(items) !== 0)
|
||||
koArray.sort(sortFunction);
|
||||
|
||||
// Don't rotate if small & sorted correctly
|
||||
return;
|
||||
}
|
||||
|
||||
// Move Last Item to Top
|
||||
var item = koArray.pop();
|
||||
koArray.unshift(item);
|
||||
}
|
||||
function removeItemFromArray(koArray, UserId) {
|
||||
var items = koArray();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].UserId == UserId) {
|
||||
koArray.splice(i, 1);
|
||||
items = koArray();
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
function findUnsortedArrayTopIndex(items) {
|
||||
// Only one Item
|
||||
if (items.length <= 1)
|
||||
return 0;
|
||||
|
||||
for (var i = 1; i < items.length; i++) {
|
||||
var s = sortFunction(items[i - 1], items[i]);
|
||||
if (s > 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
function findSortedInsertIndex(koArray, heldDeviceItem) {
|
||||
var items = koArray();
|
||||
var startIndex = findUnsortedArrayTopIndex(items);
|
||||
for (var i = startIndex; i < items.length; i++) {
|
||||
var s = sortFunction(heldDeviceItem, items[i]);
|
||||
if (s <= 0)
|
||||
return i;
|
||||
}
|
||||
if (startIndex !== 0) {
|
||||
for (var i = 0; i < startIndex; i++) {
|
||||
var s = sortFunction(heldDeviceItem, items[i]);
|
||||
if (s <= 0)
|
||||
return i;
|
||||
}
|
||||
return startIndex;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
function sortFunction(l, r) {
|
||||
return l.UserIdFriendly.toLowerCase() == r.UserIdFriendly.toLowerCase() ? 0 : (l.UserIdFriendly.toLowerCase() < r.UserIdFriendly.toLowerCase() ? -1 : 1)
|
||||
}
|
||||
function isInProcess(i) {
|
||||
return !i.ReadyForReturn && !i.WaitingForUserAction;
|
||||
}
|
||||
function isReadyForReturn(i) {
|
||||
return i.ReadyForReturn && !i.WaitingForUserAction;
|
||||
}
|
||||
function isWaitingForUserAction(i) {
|
||||
return i.WaitingForUserAction;
|
||||
}
|
||||
function getQueryStringParameters() {
|
||||
|
||||
if (window.location.search.length === 0)
|
||||
return null;
|
||||
|
||||
var params = {};
|
||||
window.location.search.substr(1).split("&").forEach(function (pair) {
|
||||
if (pair === "") return;
|
||||
var parts = pair.split("=");
|
||||
params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace(/\+/g, " "));
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
<div id="mainFooter">
|
||||
<img style="width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;" src="@Links.ClientSource.Style.Images.Heading_png" alt="Disco Logo" />
|
||||
powered by Disco
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34011
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices
|
||||
#line 1 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
|
||||
Layout = null;
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||
Html.BundleDeferred("~/ClientScripts/Core");
|
||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
|
||||
|
||||
WriteLiteral(" content=\"IE=edge\"");
|
||||
|
||||
WriteLiteral(" />\r\n <title>Disco - Technician Held Devices for Users</title>\r\n");
|
||||
WriteLiteral(" />\r\n <title>Disco ICT - Held Devices for Users</title>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Html.BundleRenderDeferred());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n</head>\r\n<body>\r\n <div");
|
||||
WriteLiteral("\r\n</head>\r\n<body");
|
||||
|
||||
WriteLiteral(" class=\"status-connecting\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"page\"");
|
||||
|
||||
WriteLiteral(">\r\n <header");
|
||||
|
||||
WriteLiteral(" id=\"mainHeader\"");
|
||||
WriteLiteral(" id=\"header\"");
|
||||
|
||||
WriteLiteral(">\r\n Technician Held Devices for Users\r\n </header>\r\n <section");
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"heading\"");
|
||||
|
||||
WriteLiteral(">Held Devices for Users</div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"statusConnecting\"");
|
||||
|
||||
WriteLiteral("><i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
|
||||
|
||||
WriteLiteral("></i><span>connecting...</span></div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"statusError\"");
|
||||
|
||||
WriteLiteral("><i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-cog fa-spin\"");
|
||||
|
||||
WriteLiteral("></i><span>disconnected, reconnecting...</span></div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"credits\"");
|
||||
|
||||
WriteLiteral(">\r\n powered by Disco ICT <i");
|
||||
|
||||
WriteLiteral(" title=\"Disco ICT - Jobs\"");
|
||||
|
||||
WriteLiteral("></i>\r\n </div>\r\n </header>\r\n <section");
|
||||
|
||||
WriteLiteral(" id=\"mainSection\"");
|
||||
|
||||
@@ -93,402 +126,288 @@ WriteLiteral(" id=\"inProcess\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>\r\n In Process <span");
|
||||
WriteLiteral(">\r\n <h3>In Process (<span");
|
||||
|
||||
WriteLiteral(" id=\"inProcessCount\"");
|
||||
WriteLiteral(" data-bind=\"text: inProcess().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n <div");
|
||||
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: inProcess, afterRender: o" +
|
||||
"nAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"readyForReturn\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>\r\n Ready for Return <span");
|
||||
WriteLiteral(">\r\n <h3>Ready for Return (<span");
|
||||
|
||||
WriteLiteral(" id=\"readyForReturnCount\"");
|
||||
WriteLiteral(" data-bind=\"text: readyForReturn().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n <div");
|
||||
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: readyForReturn, afterRend" +
|
||||
"er: onAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"waitingForUserAction\"");
|
||||
|
||||
WriteLiteral(" class=\"list\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3>\r\n Waiting for User Action <span");
|
||||
WriteLiteral(">\r\n <h3>Waiting for User Action (<span");
|
||||
|
||||
WriteLiteral(" id=\"waitingForUserActionCount\"");
|
||||
WriteLiteral(" data-bind=\"text: waitingForUserAction().length\"");
|
||||
|
||||
WriteLiteral("></span>\r\n </h3>\r\n <div");
|
||||
WriteLiteral("></span>)\r\n </h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"content\"");
|
||||
|
||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
||||
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
|
||||
"</div>\r\n <script");
|
||||
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
|
||||
" <div");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" class=\"noContent\"");
|
||||
|
||||
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
|
||||
"#inProcess\');\r\n var $inProcessContent = $inProcess.find(\'.content\');\r" +
|
||||
"\n var $inProcessHeader = $inProcess.find(\'.h3\');\r\n var $re" +
|
||||
"adyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnContent = $" +
|
||||
"readyForReturn.find(\'.content\');\r\n var $readyForReturnHeader = $ready" +
|
||||
"ForReturn.find(\'.h3\');\r\n var $waitingForUserAction = $(\'#waitingForUs" +
|
||||
"erAction\');\r\n var $waitingForUserActionContent = $waitingForUserActio" +
|
||||
"n.find(\'.content\');\r\n var $waitingForUserActionHeader = $waitingForUs" +
|
||||
"erAction.find(\'.h3\');\r\n var $mainSection = $(\'#mainSection\');\r\n " +
|
||||
" var $mainHeader = $(\'#mainHeader\');\r\n var $mainFooter = $(\'#mai" +
|
||||
"nFooter\');\r\n\r\n var onResize = function () {\r\n var widt" +
|
||||
"h = $mainSection.width();\r\n var height = $(window).height() - $ma" +
|
||||
"inHeader.outerHeight() - $mainFooter.outerHeight() - 25;\r\n\r\n $inP" +
|
||||
"rocess.height(height);\r\n $inProcess.width((width * .28) - 11);\r\n " +
|
||||
" $inProcessContent.height(height - $inProcessHeader.outerHeight() " +
|
||||
"- 56);\r\n\r\n $readyForReturn.height(height);\r\n $read" +
|
||||
"yForReturn.width((width * .36) - 11);\r\n $readyForReturnContent.he" +
|
||||
"ight(height - $readyForReturnHeader.outerHeight() - 56);\r\n\r\n $wai" +
|
||||
"tingForUserAction.height(height);\r\n $waitingForUserAction.width((" +
|
||||
"width * .36) - 11);\r\n $waitingForUserActionContent.height(height " +
|
||||
"- $waitingForUserActionHeader.outerHeight() - 56);\r\n };\r\n\r\n " +
|
||||
" $(window).resize(onResize);\r\n onResize();\r\n });\r\n </scrip" +
|
||||
"t>\r\n <script");
|
||||
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
|
||||
"erAdd: onAdd, beforeRemove: onRemove }\"");
|
||||
|
||||
WriteLiteral(@">
|
||||
// Hide Mouse Mouse
|
||||
$(function () {
|
||||
var mouseVisible = true;
|
||||
var mouseHideToken;
|
||||
var documentBody = $('body');
|
||||
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
|
||||
|
||||
var hideMouse = function () {
|
||||
if (mouseVisible) {
|
||||
documentBody.css('cursor', 'none');
|
||||
mouseVisible = false;
|
||||
}
|
||||
};
|
||||
var showMouse = function () {
|
||||
if (!mouseVisible) {
|
||||
documentBody.css('cursor', 'auto');
|
||||
mouseVisible = true;
|
||||
}
|
||||
};
|
||||
WriteLiteral(" id=\"footer\"");
|
||||
|
||||
$(document).mousemove(function () {
|
||||
showMouse();
|
||||
if (mouseHideToken)
|
||||
window.clearTimeout(mouseHideToken);
|
||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script");
|
||||
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
|
||||
|
||||
WriteLiteral(" type=\"text/javascript\"");
|
||||
WriteLiteral(" type=\"text/html\"");
|
||||
|
||||
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
|
||||
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
|
||||
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
|
||||
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
|
||||
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
|
||||
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
|
||||
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
|
||||
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
|
||||
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
|
||||
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
|
||||
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
|
||||
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
|
||||
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
|
||||
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
|
||||
" var persistantConnection = null;\r\n var filterDeviceAddress" +
|
||||
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
|
||||
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n \r\n " +
|
||||
" var getParameterByName = function (name) {\r\n name = na" +
|
||||
"me.replace(/[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS " +
|
||||
"= \"[\\\\?&]\" + name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS)" +
|
||||
";\r\n var results = regex.exec(window.location.search);\r\n " +
|
||||
" if (results == null)\r\n return \"\";\r\n else" +
|
||||
"\r\n return decodeURIComponent(results[1].replace(/\\+/g, \" \"));" +
|
||||
"\r\n }\r\n\r\n var buildFilters = function () {\r\n " +
|
||||
" var deviceAddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n " +
|
||||
" if (deviceAddressInclude) {\r\n filterDeviceAddressInc" +
|
||||
"lude = {};\r\n var split = deviceAddressInclude.split(\",\");\r\n " +
|
||||
" for (var i = 0; i < split.length; i++) {\r\n " +
|
||||
" filterDeviceAddressInclude[split[i].toLowerCase()] = true;\r\n " +
|
||||
" }\r\n } else {\r\n var deviceAddressExclude = " +
|
||||
"getParameterByName(\'deviceAddressExclude\');\r\n if (deviceAddre" +
|
||||
"ssExclude) {\r\n filterDeviceAddressExclude = {};\r\n " +
|
||||
" var split = deviceAddressExclude.split(\",\");\r\n " +
|
||||
" for (var i = 0; i < split.length; i++) {\r\n filt" +
|
||||
"erDeviceAddressExclude[split[i].toLowerCase()] = true;\r\n " +
|
||||
"}\r\n } else {\r\n var deviceProfileInclud" +
|
||||
"e = getParameterByName(\'deviceProfileInclude\');\r\n if (dev" +
|
||||
"iceProfileInclude) {\r\n filterDeviceProfileInclude = {" +
|
||||
"};\r\n var deviceProfileIncludeSplit = deviceProfileInc" +
|
||||
"lude.split(\",\");\r\n for (var i = 0; i < deviceProfileI" +
|
||||
"ncludeSplit.length; i++) {\r\n filterDeviceProfileI" +
|
||||
"nclude[parseInt(deviceProfileIncludeSplit[i])] = true;\r\n " +
|
||||
" }\r\n } else {\r\n var deviceP" +
|
||||
"rofileExclude = getParameterByName(\'deviceProfileExclude\');\r\n " +
|
||||
" if (deviceProfileExclude) {\r\n filterDevi" +
|
||||
"ceProfileExclude = {};\r\n var deviceProfileExclude" +
|
||||
"Split = deviceProfileExclude.split(\",\");\r\n for (v" +
|
||||
"ar i = 0; i < deviceProfileExcludeSplit.length; i++) {\r\n " +
|
||||
" filterDeviceProfileExclude[parseInt(deviceProfileExcludeSplit[i])] =" +
|
||||
" true;\r\n }\r\n }\r\n " +
|
||||
" }\r\n }\r\n }\r\n }\r\n " +
|
||||
" var calculateFilter = function (model) {\r\n if (model) {" +
|
||||
"\r\n if (filterDeviceAddressInclude) {\r\n " +
|
||||
" return (filterDeviceAddressInclude[model.DeviceAddress.toLowerCase()] == true)\r" +
|
||||
"\n }\r\n if (filterDeviceAddressExclude) {\r\n " +
|
||||
" return (!filterDeviceAddressExclude[model.DeviceAddress.t" +
|
||||
"oLowerCase()])\r\n }\r\n if (filterDeviceProfi" +
|
||||
"leInclude) {\r\n return (filterDeviceProfileInclude[model.D" +
|
||||
"eviceProfileId] == true)\r\n }\r\n if (filterD" +
|
||||
"eviceProfileExclude) {\r\n return (!filterDeviceProfileExcl" +
|
||||
"ude[model.DeviceProfileId])\r\n }\r\n return t" +
|
||||
"rue;\r\n }\r\n return false;\r\n }\r\n\r\n " +
|
||||
" var sortModels = function () {\r\n modelsInProcessSorted = [];" +
|
||||
"\r\n modelsReadyForReturnSorted = [];\r\n modelsWaitin" +
|
||||
"gForUserActionSorted = [];\r\n var modelSortFunc = function (a, b) " +
|
||||
"{\r\n if (a.UserId.toUpperCase() == b.UserId.toUpperCase()) {\r\n" +
|
||||
" return 0;\r\n } else {\r\n " +
|
||||
" if (a.UserId.toUpperCase() < b.UserId.toUpperCase()) {\r\n " +
|
||||
" return -1\r\n } else {\r\n " +
|
||||
" return 1\r\n }\r\n }\r\n " +
|
||||
" };\r\n for (var key in models) {\r\n var model =" +
|
||||
" models[key];\r\n if (model) {\r\n if (mod" +
|
||||
"el.WaitingForUserAction) {\r\n modelsWaitingForUserActi" +
|
||||
"onSorted.push(model);\r\n } else {\r\n " +
|
||||
" if (model.ReadyForReturn) {\r\n modelsReadyFor" +
|
||||
"ReturnSorted.push(model);\r\n } else {\r\n " +
|
||||
" modelsInProcessSorted.push(model);\r\n " +
|
||||
" }\r\n }\r\n }\r\n }\r\n " +
|
||||
" modelsReadyForReturnSorted = modelsReadyForReturnSorted.sort(modelSortF" +
|
||||
"unc);\r\n modelsInProcessSorted = modelsInProcessSorted.sort(modelS" +
|
||||
"ortFunc);\r\n modelsWaitingForUserActionSorted = modelsWaitingForUs" +
|
||||
"erActionSorted.sort(modelSortFunc);\r\n\r\n if (modelsInProcessSorted" +
|
||||
".length != modelsInProcessCount) {\r\n modelsInProcessCount = m" +
|
||||
"odelsInProcessSorted.length;\r\n $(\'#inProcessCount\').text(\'(\' " +
|
||||
"+ modelsInProcessCount + \')\');\r\n }\r\n if (modelsRea" +
|
||||
"dyForReturnSorted.length != modelsReadyForReturnCount) {\r\n mo" +
|
||||
"delsReadyForReturnCount = modelsReadyForReturnSorted.length;\r\n " +
|
||||
" $(\'#readyForReturnCount\').text(\'(\' + modelsReadyForReturnCount + \')\');\r\n " +
|
||||
" }\r\n if (modelsWaitingForUserActionSorted.length != mode" +
|
||||
"lsWaitingForUserActionCount) {\r\n modelsWaitingForUserActionCo" +
|
||||
"unt = modelsWaitingForUserActionSorted.length;\r\n $(\'#waitingF" +
|
||||
"orUserActionCount\').text(\'(\' + modelsWaitingForUserActionCount + \')\');\r\n " +
|
||||
" }\r\n\r\n };\r\n\r\n var scrollReadyForReturn = function (" +
|
||||
") {\r\n $readyForReturnContent.find(\'li\').last().detach().prependTo" +
|
||||
"($readyForReturnContent).hide().slideDown(\'slow\');\r\n modelsReadyF" +
|
||||
"orReturnIndexOffset++;\r\n if (modelsReadyForReturnIndexOffset >= m" +
|
||||
"odelsReadyForReturnSorted.length) {\r\n modelsReadyForReturnInd" +
|
||||
"exOffset = 0;\r\n }\r\n scrollReadyForReturnToken = wi" +
|
||||
"ndow.setTimeout(scrollReadyForReturn, scrollSpeed);\r\n };\r\n " +
|
||||
" var updateScrollReadyForReturn = function () {\r\n var containerHe" +
|
||||
"ight = $readyForReturn.find(\'.content\').height();\r\n var contentHe" +
|
||||
"ight = $readyForReturnContent.height();\r\n if (containerHeight >= " +
|
||||
"contentHeight && scrollReadyForReturnToken) {\r\n window.clearT" +
|
||||
"imeout(scrollReadyForReturnToken);\r\n return;\r\n " +
|
||||
" }\r\n if (containerHeight < contentHeight && scrollReadyForReturnT" +
|
||||
"oken == null) {\r\n scrollReadyForReturnToken = window.setTimeo" +
|
||||
"ut(scrollReadyForReturn, scrollSpeed);\r\n }\r\n };\r\n " +
|
||||
" var scrollInProcess = function () {\r\n $inProcessContent.fi" +
|
||||
"nd(\'li\').last().detach().prependTo($inProcessContent).hide().slideDown(\'slow\');\r" +
|
||||
"\n modelsInProcessIndexOffset++;\r\n if (modelsInProc" +
|
||||
"essIndexOffset >= modelsInProcessSorted.length) {\r\n modelsInP" +
|
||||
"rocessIndexOffset = 0;\r\n }\r\n scrollInProcessToken " +
|
||||
"= window.setTimeout(scrollInProcess, scrollSpeed);\r\n };\r\n " +
|
||||
"var updateScrollInProcess = function () {\r\n var containerHeight =" +
|
||||
" $inProcess.find(\'.content\').height();\r\n var contentHeight = $inP" +
|
||||
"rocessContent.height();\r\n if (containerHeight >= contentHeight &&" +
|
||||
" scrollInProcessToken) {\r\n window.clearTimeout(scrollInProces" +
|
||||
"sToken);\r\n return;\r\n }\r\n if (co" +
|
||||
"ntainerHeight < contentHeight && scrollInProcessToken == null) {\r\n " +
|
||||
" scrollInProcessToken = window.setTimeout(scrollInProcess, scrollSpeed);\r\n " +
|
||||
" }\r\n };\r\n var scrollWaitingForUserAction = f" +
|
||||
"unction () {\r\n $waitingForUserActionContent.find(\'li\').last().det" +
|
||||
"ach().prependTo($waitingForUserActionContent).hide().slideDown(\'slow\');\r\n " +
|
||||
" modelsInProcessIndexOffset++;\r\n if (modelsWaitingForUser" +
|
||||
"ActionIndexOffset >= modelsWaitingForUserActionSorted.length) {\r\n " +
|
||||
" modelsWaitingForUserActionIndexOffset = 0;\r\n }\r\n " +
|
||||
" scrollWaitingForUserActionToken = window.setTimeout(scrollWaitingForUserActi" +
|
||||
"on, scrollSpeed);\r\n };\r\n var updateScrollWaitingForUserAct" +
|
||||
"ion = function () {\r\n var containerHeight = $waitingForUserAction" +
|
||||
".find(\'.content\').height();\r\n var contentHeight = $waitingForUser" +
|
||||
"ActionContent.height();\r\n if (containerHeight >= contentHeight &&" +
|
||||
" scrollWaitingForUserActionToken) {\r\n window.clearTimeout(scr" +
|
||||
"ollWaitingForUserActionToken);\r\n return;\r\n }\r\n" +
|
||||
" if (containerHeight < contentHeight && scrollWaitingForUserActio" +
|
||||
"nToken == null) {\r\n scrollWaitingForUserActionToken = window." +
|
||||
"setTimeout(scrollWaitingForUserAction, scrollSpeed);\r\n }\r\n " +
|
||||
" };\r\n\r\n var modelInsertIndex = function (model) {\r\n " +
|
||||
" sortModels();\r\n var findIndex = function (model, array, offset)" +
|
||||
" {\r\n for (var i = 0; i < array.length; i++) {\r\n " +
|
||||
" if (model.UserId == array[i].UserId) {\r\n va" +
|
||||
"r index = i + offset;\r\n if (index > (array.length - 1" +
|
||||
")) {\r\n index = index - (array.length - 1);\r\n " +
|
||||
" }\r\n return index;\r\n " +
|
||||
" }\r\n };\r\n };\r\n if (" +
|
||||
"model.WaitingForUserAction) {\r\n return findIndex(model, model" +
|
||||
"sWaitingForUserActionSorted, modelsWaitingForUserActionIndexOffset);\r\n " +
|
||||
" } else {\r\n if (model.ReadyForReturn) {\r\n " +
|
||||
" return findIndex(model, modelsReadyForReturnSorted, modelsReadyForRetur" +
|
||||
"nIndexOffset);\r\n } else {\r\n return fin" +
|
||||
"dIndex(model, modelsInProcessSorted, modelsInProcessIndexOffset);\r\n " +
|
||||
" }\r\n }\r\n }\r\n var modelInsert = functi" +
|
||||
"on (model) {\r\n var index = modelInsertIndex(model);\r\n " +
|
||||
" var insertTo = function (model, host) {\r\n var hostLi = ho" +
|
||||
"st.children(\'li\');\r\n if (hostLi.length == 0 || hostLi.length " +
|
||||
"< index) {\r\n host.append(model.htmlLi);\r\n " +
|
||||
" } else {\r\n if (index == 0) {\r\n " +
|
||||
" host.prepend(model.htmlLi);\r\n } else {\r\n " +
|
||||
" $(hostLi.get(index - 1)).after(model.htmlLi);\r\n " +
|
||||
" }\r\n }\r\n }\r\n if (model.Wa" +
|
||||
"itingForUserAction) {\r\n insertTo(model, $waitingForUserAction" +
|
||||
"Content);\r\n window.setTimeout(updateScrollWaitingForUserActio" +
|
||||
"n, 100);\r\n } else {\r\n if (model.ReadyForReturn" +
|
||||
") {\r\n insertTo(model, $readyForReturnContent);\r\n " +
|
||||
" window.setTimeout(updateScrollReadyForReturn, 100);\r\n " +
|
||||
" } else {\r\n insertTo(model, $inProcessContent);\r\n " +
|
||||
" window.setTimeout(updateScrollInProcess, 100);\r\n " +
|
||||
" }\r\n }\r\n }\r\n\r\n var removeModel = " +
|
||||
"function (model) {\r\n if (model) {\r\n model.html" +
|
||||
"Li.slideUp(\'fast\', function () {\r\n model.htmlLi.remove();" +
|
||||
"\r\n });\r\n }\r\n };\r\n\r\n var " +
|
||||
"processModel = function (id, model, init) {\r\n if (!calculateFilte" +
|
||||
"r(model)) {\r\n removeModel(models[id]);\r\n d" +
|
||||
"elete models[id];\r\n sortModels();\r\n } else {\r\n" +
|
||||
" var existing = models[id];\r\n models[id] =" +
|
||||
" model;\r\n\r\n // Add\r\n model.htmlContent = $" +
|
||||
"(\'<div>\').text(model.UserId + \' - \' + model.UserDisplayName);\r\n " +
|
||||
" if (!model.ReadyForReturn && model.EstimatedReturnTime) {\r\n " +
|
||||
" model.htmlContent.append($(\'<span class=\"small\">\').text(\' (Expected: \' + m" +
|
||||
"odel.EstimatedReturnTime + \')\'));\r\n }\r\n if" +
|
||||
" (model.WaitingForUserAction) {\r\n model.htmlContent.appen" +
|
||||
"d($(\'<span class=\"small\">\').text(\' (Since \' + model.WaitingForUserActionSince + " +
|
||||
"\')\'));\r\n } else {\r\n if (model.ReadyFor" +
|
||||
"Return && model.ReadyForReturnSince) {\r\n model.htmlCo" +
|
||||
"ntent.append($(\'<span class=\"small\">\').text(\' (Ready \' + model.ReadyForReturnSin" +
|
||||
"ce + \')\'));\r\n }\r\n }\r\n\r\n " +
|
||||
" if (existing) {\r\n if (existing.ReadyForReturn != mod" +
|
||||
"el.ReadyForReturn || existing.WaitingForUserAction != model.WaitingForUserAction" +
|
||||
") {\r\n removeModel(existing);\r\n " +
|
||||
" model.htmlLi = $(\'<li>\').html(model.htmlContent).data(\'ModelId\', id).hide()" +
|
||||
";\r\n modelInsert(model);\r\n " +
|
||||
"if (init) {\r\n model.htmlLi.fadeIn();\r\n " +
|
||||
" } else {\r\n model.htmlLi.slideDow" +
|
||||
"n();\r\n }\r\n } else {\r\n " +
|
||||
" model.htmlLi = existing.htmlLi;\r\n " +
|
||||
"model.htmlLi.slideUp(\'fast\', function () {\r\n mode" +
|
||||
"l.htmlLi.html(model.htmlContent).slideDown();\r\n });\r\n" +
|
||||
" }\r\n } else {\r\n " +
|
||||
" model.htmlLi = $(\'<li>\').html(model.htmlContent).data(\'ModelId\', id).hide();\r\n " +
|
||||
" modelInsert(model);\r\n if (init) {\r" +
|
||||
"\n model.htmlLi.fadeIn();\r\n } e" +
|
||||
"lse {\r\n model.htmlLi.slideDown(\'slow\');\r\n " +
|
||||
" }\r\n }\r\n if (model.htmlLi && mo" +
|
||||
"del.IsAlert) {\r\n model.htmlLi.addClass(\'alert\');\r\n " +
|
||||
" }\r\n }\r\n };\r\n\r\n var updatedMode" +
|
||||
"l = function (id) {\r\n var userId = id.toString();\r\n\r\n " +
|
||||
" $.ajax({\r\n dataType: \'json\',\r\n url: \'");
|
||||
WriteLiteral(" id=\"item-template\"");
|
||||
|
||||
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
|
||||
"\"text: UserIdFriendly + \' - \' + UserDisplayName\"></span>\r\n <!-- ko if" +
|
||||
": !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->\r\n <span class=\"s" +
|
||||
"mall\">(Expected <span data-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>" +
|
||||
")</span>\r\n <!-- /ko -->\r\n <!-- ko if: WaitingForUserAction" +
|
||||
" -->\r\n <span class=\"small\">(Since <span data-bind=\"livestamp: Waiting" +
|
||||
"ForUserActionSinceUnixEpoc\"></span>)</span>\r\n <!-- /ko -->\r\n " +
|
||||
" <!-- ko if: ReadyForReturn && !WaitingForUserAction -->\r\n <span cl" +
|
||||
"ass=\"small\">(Ready <span data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></sp" +
|
||||
"an>)</span>\r\n <!-- /ko -->\r\n </li>\r\n </script>\r\n <script" +
|
||||
">\r\n ko.bindingHandlers.livestamp = {\r\n init: function (element" +
|
||||
", valueAccessor, allBindings, viewModel, bindingContext) {\r\n var " +
|
||||
"value = valueAccessor();\r\n var valueUnwrapped = ko.unwrap(value);" +
|
||||
"\r\n\r\n if (valueUnwrapped)\r\n $(element).livestam" +
|
||||
"p(valueUnwrapped);\r\n else\r\n $(element).livesta" +
|
||||
"mp(\'destroy\');\r\n }\r\n };\r\n </script>\r\n <script>\r\n " +
|
||||
"$(function () {\r\n var hub;\r\n var viewModel;\r\n\r\n " +
|
||||
" var rotateSpeed = 3000;\r\n var itemFilters;\r\n\r\n var $inPro" +
|
||||
"cessList = $(\'#inProcess\').find(\'ul\');\r\n var $readyForReturnList = $(" +
|
||||
"\'#readyForReturn\').find(\'ul\');\r\n var $waitingForUserActionList = $(\'#" +
|
||||
"waitingForUserAction\').find(\'ul\');\r\n\r\n function noticeboardViewModel(" +
|
||||
"inProcess, readyForReturn, waitingForUserAction) {\r\n var self = t" +
|
||||
"his;\r\n\r\n self.initialized = false;\r\n\r\n self.inProc" +
|
||||
"ess = ko.observableArray(inProcess);\r\n self.readyForReturn = ko.o" +
|
||||
"bservableArray(readyForReturn);\r\n self.waitingForUserAction = ko." +
|
||||
"observableArray(waitingForUserAction);\r\n\r\n self.onRemove = functi" +
|
||||
"on (element, index, data) {\r\n $(element).slideUp(400, functio" +
|
||||
"n () {\r\n $(this).remove();\r\n });\r\n " +
|
||||
" }\r\n self.onAdd = function (element, index, data) {\r\n " +
|
||||
" if (self.initialized)\r\n $(element).hid" +
|
||||
"e().slideDown(400);\r\n }\r\n }\r\n\r\n function in" +
|
||||
"it() {\r\n // Connect to Hub\r\n hub = $.connection.no" +
|
||||
"ticeboardUpdates;\r\n\r\n // Map Functions\r\n hub.clien" +
|
||||
"t.updateHeldDeviceForUser = updateHeldDevice;\r\n\r\n $.connection.hu" +
|
||||
"b.qs = { Noticeboard: \'");
|
||||
|
||||
|
||||
#line 435 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevice()));
|
||||
#line 127 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"',
|
||||
data: { id: userId },
|
||||
success: function (data) {
|
||||
processModel(userId, data, false);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown){
|
||||
if (textStatus == 'parsererror') // null Result
|
||||
processModel(userId, null, false);
|
||||
}
|
||||
})
|
||||
};
|
||||
WriteLiteral(@"' };
|
||||
$.connection.hub.error(connectionError);
|
||||
$.connection.hub.disconnected(connectionError);
|
||||
$.connection.hub.reconnected(connectionError);
|
||||
|
||||
var connectionError = function () {
|
||||
if (persistantConnection) {
|
||||
persistantConnection.stop();
|
||||
persistantConnection = null;
|
||||
window.setTimeout(function () {
|
||||
window.location.href = '");
|
||||
// Start Connection
|
||||
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||
}
|
||||
|
||||
// Called after SignalR is connected
|
||||
function loadData() {
|
||||
$.getJSON('");
|
||||
|
||||
|
||||
#line 452 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.UserHeldDevices.Noticeboard()));
|
||||
#line 138 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
|
||||
" var init = function () {\r\n buildFilters();\r\n pe" +
|
||||
"rsistantConnection = $.connection(\'");
|
||||
|
||||
|
||||
#line 459 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Content("~/Public/UserHeldDevices/Notifications"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
|
||||
" persistantConnection.error(connectionError);\r\n persistantConnec" +
|
||||
"tion.start(function () {\r\n $.getJSON(\'");
|
||||
|
||||
|
||||
#line 463 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"', null, function (data) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
processModel(data[i].UserId, data[i], true);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
init();
|
||||
|
||||
});
|
||||
</script>
|
||||
<div");
|
||||
|
||||
WriteLiteral(" id=\"mainFooter\"");
|
||||
|
||||
WriteLiteral(">\r\n <img");
|
||||
|
||||
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
|
||||
|
||||
WriteAttribute("src", Tuple.Create(" src=\"", 22642), Tuple.Create("\"", 22692)
|
||||
|
||||
#line 475 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 22648), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 22648), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" alt=\"Disco Logo\"");
|
||||
|
||||
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
|
||||
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
|
||||
" var readyForReturn = [];\r\n var waitingForUserAction" +
|
||||
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
|
||||
" return includeItem(heldDeviceItem)\r\n }).forEac" +
|
||||
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
|
||||
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
|
||||
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
|
||||
" readyForReturn.push(heldDeviceItem);\r\n " +
|
||||
" else if (isInProcess(heldDeviceItem))\r\n inP" +
|
||||
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
|
||||
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
|
||||
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
|
||||
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
|
||||
"orUserAction);\r\n\r\n ko.applyBindings(viewModel);\r\n " +
|
||||
" viewModel.initialized = true;\r\n\r\n $(\'body\').removeCla" +
|
||||
"ss(\'status-connecting\');\r\n\r\n window.setTimeout(scheduleRotati" +
|
||||
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
|
||||
" }\r\n\r\n // Called by SignalR\r\n function updateHeldDevic" +
|
||||
"e(updates) {\r\n if (viewModel) {\r\n\r\n $.each(upd" +
|
||||
"ates, function (UserId, heldDeviceItem) {\r\n // Remove Exi" +
|
||||
"sting\r\n removeItem(UserId);\r\n\r\n //" +
|
||||
" Add Item\r\n addItem(heldDeviceItem);\r\n " +
|
||||
" });\r\n }\r\n }\r\n\r\n function removeItem(UserId" +
|
||||
") {\r\n removeItemFromArray(viewModel.inProcess, UserId);\r\n " +
|
||||
" removeItemFromArray(viewModel.readyForReturn, UserId);\r\n " +
|
||||
"removeItemFromArray(viewModel.waitingForUserAction, UserId);\r\n }\r\n\r\n " +
|
||||
" function addItem(heldDeviceItem) {\r\n if (heldDeviceIte" +
|
||||
"m !== null &&\r\n heldDeviceItem !== undefined &&\r\n " +
|
||||
" includeItem(heldDeviceItem)) {\r\n\r\n var array;\r\n\r\n " +
|
||||
" if (isWaitingForUserAction(heldDeviceItem))\r\n " +
|
||||
" array = viewModel.waitingForUserAction;\r\n else if (isRea" +
|
||||
"dyForReturn(heldDeviceItem))\r\n array = viewModel.readyFor" +
|
||||
"Return;\r\n else if (isInProcess(heldDeviceItem))\r\n " +
|
||||
" array = viewModel.inProcess;\r\n\r\n if (array().leng" +
|
||||
"th === 0) {\r\n array.push(heldDeviceItem);\r\n " +
|
||||
" } else {\r\n var index = findSortedInsertIndex(array," +
|
||||
" heldDeviceItem);\r\n if (index === -1)\r\n " +
|
||||
" array.push(heldDeviceItem);\r\n else\r\n " +
|
||||
" array.splice(index, 0, heldDeviceItem);\r\n }\r" +
|
||||
"\n }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
|
||||
" rotateArray(viewModel.inProcess, $inProcessList);\r\n r" +
|
||||
"otateArray(viewModel.readyForReturn, $readyForReturnList);\r\n rota" +
|
||||
"teArray(viewModel.waitingForUserAction, $waitingForUserActionList);\r\n " +
|
||||
" }\r\n\r\n function scheduleRotation() {\r\n rotateArrays();" +
|
||||
"\r\n\r\n window.setTimeout(scheduleRotation, rotateSpeed);\r\n " +
|
||||
" }\r\n\r\n function includeItem(heldDeviceItem) {\r\n if (" +
|
||||
"itemFilters == null || itemFilters.length == 0)\r\n return true" +
|
||||
";\r\n\r\n return itemFilters.reduce(function (previousValue, currentV" +
|
||||
"alue, index, array) {\r\n if (previousValue === false)\r\n " +
|
||||
" return false;\r\n return currentValue(heldDevi" +
|
||||
"ceItem);\r\n }, true);\r\n }\r\n\r\n function build" +
|
||||
"Filters() {\r\n var filters = [];\r\n var queryStringP" +
|
||||
"arameters = getQueryStringParameters();\r\n\r\n if (queryStringParame" +
|
||||
"ters !== null) {\r\n $.each(queryStringParameters, function (ke" +
|
||||
"y, value) {\r\n switch (key.toLowerCase()) {\r\n " +
|
||||
" case \'deviceaddressinclude\':\r\n var" +
|
||||
" deviceAddresses = value.split(\",\").map(function (v) { return v.toLowerCase(); }" +
|
||||
");\r\n if (deviceAddresses.length > 0) {\r\n " +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // false if DeviceAddressShortName is null\r\n " +
|
||||
" if (!heldDeviceItem.DeviceAddressShortName)\r\n " +
|
||||
" return false;\r\n\r\n " +
|
||||
" // true if DeviceAddressShortName is included\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceAddressShortName" +
|
||||
".toLowerCase(), deviceAddresses) >= 0;\r\n });\r" +
|
||||
"\n }\r\n break;\r\n " +
|
||||
" case \'deviceaddressexclude\':\r\n " +
|
||||
" var deviceAddresses = value.split(\",\").map(function (v) { return v.toLower" +
|
||||
"Case(); });\r\n if (deviceAddresses.length > 0) {\r\n" +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // true if DeviceAddressShortName is null\r" +
|
||||
"\n if (!heldDeviceItem.DeviceAddressShortN" +
|
||||
"ame)\r\n return true;\r\n\r\n " +
|
||||
" // true if DeviceAddressShortName is excluded\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceAddressSh" +
|
||||
"ortName.toLowerCase(), deviceAddresses) < 0;\r\n " +
|
||||
" });\r\n }\r\n break;" +
|
||||
"\r\n case \'deviceprofileinclude\':\r\n " +
|
||||
" var deviceProfiles = value.split(\",\");\r\n " +
|
||||
" if (deviceProfiles.length > 0) {\r\n filter" +
|
||||
"s.push(function (heldDeviceItem) {\r\n // t" +
|
||||
"rue if DeviceProfileId is included\r\n retu" +
|
||||
"rn $.inArray(heldDeviceItem.DeviceProfileId, deviceProfiles) >= 0;\r\n " +
|
||||
" });\r\n }\r\n " +
|
||||
" break;\r\n case \'deviceprofileexclude\':" +
|
||||
"\r\n var deviceProfiles = value.split(\",\");\r\n " +
|
||||
" if (deviceProfiles.length > 0) {\r\n " +
|
||||
" filters.push(function (heldDeviceItem) {\r\n " +
|
||||
" // true if DeviceProfileId is excluded\r\n " +
|
||||
" return $.inArray(heldDeviceItem.DeviceProfileId, deviceProfile" +
|
||||
"s) < 0;\r\n });\r\n " +
|
||||
" }\r\n break;\r\n }\r\n " +
|
||||
" });\r\n }\r\n\r\n if (filters.length > 0)\r\n " +
|
||||
" itemFilters = filters;\r\n else\r\n " +
|
||||
" itemFilters = null;\r\n }\r\n\r\n function connectionError(" +
|
||||
") {\r\n try {\r\n $(\'body\').addClass(\'status-error" +
|
||||
"\');\r\n $.connection.hub.stop();\r\n } catch (e) {" +
|
||||
"\r\n // Ignore\r\n }\r\n\r\n window.set" +
|
||||
"Timeout(function () {\r\n window.location.href = window.locatio" +
|
||||
"n.href;\r\n }, 10000);\r\n }\r\n\r\n // Helpers\r\n " +
|
||||
" function rotateArray(koArray, element) {\r\n var items = " +
|
||||
"koArray();\r\n\r\n if (items.length <= 1)\r\n return" +
|
||||
" 0;\r\n\r\n if (element.height() < (element.parent().height() - 30)) " +
|
||||
"{\r\n\r\n if (findUnsortedArrayTopIndex(items) !== 0)\r\n " +
|
||||
" koArray.sort(sortFunction);\r\n\r\n // Don\'t rotate" +
|
||||
" if small & sorted correctly\r\n return;\r\n }\r\n\r\n" +
|
||||
" // Move Last Item to Top\r\n var item = koArray.pop" +
|
||||
"();\r\n koArray.unshift(item);\r\n }\r\n function" +
|
||||
" removeItemFromArray(koArray, UserId) {\r\n var items = koArray();\r" +
|
||||
"\n for (var i = 0; i < items.length; i++) {\r\n i" +
|
||||
"f (items[i].UserId == UserId) {\r\n koArray.splice(i, 1);\r\n" +
|
||||
" items = koArray();\r\n i--;\r\n " +
|
||||
" }\r\n }\r\n }\r\n function findUnso" +
|
||||
"rtedArrayTopIndex(items) {\r\n // Only one Item\r\n if" +
|
||||
" (items.length <= 1)\r\n return 0;\r\n\r\n for (var " +
|
||||
"i = 1; i < items.length; i++) {\r\n var s = sortFunction(items[" +
|
||||
"i - 1], items[i]);\r\n if (s > 0)\r\n retu" +
|
||||
"rn i;\r\n }\r\n\r\n return 0;\r\n }\r\n " +
|
||||
" function findSortedInsertIndex(koArray, heldDeviceItem) {\r\n var" +
|
||||
" items = koArray();\r\n var startIndex = findUnsortedArrayTopIndex(" +
|
||||
"items);\r\n for (var i = startIndex; i < items.length; i++) {\r\n " +
|
||||
" var s = sortFunction(heldDeviceItem, items[i]);\r\n " +
|
||||
" if (s <= 0)\r\n return i;\r\n }\r\n " +
|
||||
" if (startIndex !== 0) {\r\n for (var i = 0; i < startIn" +
|
||||
"dex; i++) {\r\n var s = sortFunction(heldDeviceItem, items[" +
|
||||
"i]);\r\n if (s <= 0)\r\n return i;" +
|
||||
"\r\n }\r\n return startIndex;\r\n " +
|
||||
" } else {\r\n return -1;\r\n }\r\n }\r\n " +
|
||||
" function sortFunction(l, r) {\r\n return l.UserIdFriendly." +
|
||||
"toLowerCase() == r.UserIdFriendly.toLowerCase() ? 0 : (l.UserIdFriendly.toLowerC" +
|
||||
"ase() < r.UserIdFriendly.toLowerCase() ? -1 : 1)\r\n }\r\n fun" +
|
||||
"ction isInProcess(i) {\r\n return !i.ReadyForReturn && !i.WaitingFo" +
|
||||
"rUserAction;\r\n }\r\n function isReadyForReturn(i) {\r\n " +
|
||||
" return i.ReadyForReturn && !i.WaitingForUserAction;\r\n }\r\n " +
|
||||
" function isWaitingForUserAction(i) {\r\n return i.WaitingF" +
|
||||
"orUserAction;\r\n }\r\n function getQueryStringParameters() {\r" +
|
||||
"\n\r\n if (window.location.search.length === 0)\r\n " +
|
||||
" return null;\r\n\r\n var params = {};\r\n window.locati" +
|
||||
"on.search.substr(1).split(\"&\").forEach(function (pair) {\r\n if" +
|
||||
" (pair === \"\") return;\r\n var parts = pair.split(\"=\");\r\n " +
|
||||
" params[parts[0]] = parts[1] && decodeURIComponent(parts[1].replace" +
|
||||
"(/\\+/g, \" \"));\r\n });\r\n return params;\r\n " +
|
||||
" }\r\n\r\n init();\r\n });\r\n </script>\r\n</body>\r\n</html>");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,90 +1,98 @@
|
||||
///#source 1 1 /ClientSource/Scripts/Modules/Knockout/knockout-2.3.0.js
|
||||
// Knockout JavaScript library v2.3.0
|
||||
///#source 1 1 /ClientSource/Scripts/Modules/Knockout/knockout-3.1.0.js
|
||||
// Knockout JavaScript library v3.1.0
|
||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
(function() {function F(q){return function(){return q}};(function(q){var w=this||(0,eval)("this"),s=w.document,H=w.navigator,t=w.jQuery,y=w.JSON;(function(q){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?q(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],q):q(w.ko={})})(function(C){function G(b,c,d,f){a.d[b]={init:function(b){a.a.f.set(b,I,{});return{controlsDescendantBindings:!0}},update:function(b,e,m,h,k){m=a.a.f.get(b,I);e=a.a.c(e());h=!d!==!e;var l=!m.fb;if(l||c||h!==m.vb)l&&(m.fb=
|
||||
a.a.Oa(a.e.childNodes(b),!0)),h?(l||a.e.P(b,a.a.Oa(m.fb)),a.Ja(f?f(k,e):k,b)):a.e.ba(b),m.vb=h}};a.g.S[b]=!1;a.e.L[b]=!0}function J(b,c,d){d&&c!==a.h.n(b)&&a.h.W(b,c);c!==a.h.n(b)&&a.q.I(a.a.Ga,null,[b,"change"])}var a="undefined"!==typeof C?C:{};a.b=function(b,c){for(var d=b.split("."),f=a,g=0;g<d.length-1;g++)f=f[d[g]];f[d[d.length-1]]=c};a.r=function(a,c,d){a[c]=d};a.version="2.3.0";a.b("version",a.version);a.a=function(){function b(a,b){for(var e in a)a.hasOwnProperty(e)&&b(e,a[e])}function c(b,
|
||||
e){if("input"!==a.a.u(b)||!b.type||"click"!=e.toLowerCase())return!1;var k=b.type;return"checkbox"==k||"radio"==k}var d={},f={};d[H&&/Firefox\/2/i.test(H.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(d,function(a,b){if(b.length)for(var e=0,c=b.length;e<c;e++)f[b[e]]=a});var g={propertychange:!0},e=s&&function(){for(var a=3,b=s.createElement("div"),e=b.getElementsByTagName("i");b.innerHTML=
|
||||
"\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",e[0];);return 4<a?a:q}();return{Ta:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],p:function(a,b){for(var e=0,c=a.length;e<c;e++)b(a[e])},k:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var e=0,c=a.length;e<c;e++)if(a[e]===b)return e;return-1},La:function(a,b,e){for(var c=0,d=a.length;c<d;c++)if(b.call(e,a[c]))return a[c];return null},ka:function(b,e){var c=a.a.k(b,e);0<=c&&
|
||||
b.splice(c,1)},Ma:function(b){b=b||[];for(var e=[],c=0,d=b.length;c<d;c++)0>a.a.k(e,b[c])&&e.push(b[c]);return e},Z:function(a,b){a=a||[];for(var e=[],c=0,d=a.length;c<d;c++)e.push(b(a[c]));return e},Y:function(a,b){a=a||[];for(var e=[],c=0,d=a.length;c<d;c++)b(a[c])&&e.push(a[c]);return e},R:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var e=0,c=b.length;e<c;e++)a.push(b[e]);return a},ja:function(b,e,c){var d=b.indexOf?b.indexOf(e):a.a.k(b,e);0>d?c&&b.push(e):c||b.splice(d,1)},
|
||||
extend:function(a,b){if(b)for(var e in b)b.hasOwnProperty(e)&&(a[e]=b[e]);return a},w:b,oa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Mb:function(b){b=a.a.N(b);for(var e=s.createElement("div"),c=0,d=b.length;c<d;c++)e.appendChild(a.H(b[c]));return e},Oa:function(b,e){for(var c=0,d=b.length,g=[];c<d;c++){var f=b[c].cloneNode(!0);g.push(e?a.H(f):f)}return g},P:function(b,e){a.a.oa(b);if(e)for(var c=0,d=e.length;c<d;c++)b.appendChild(e[c])},eb:function(b,e){var c=b.nodeType?[b]:b;if(0<
|
||||
c.length){for(var d=c[0],g=d.parentNode,f=0,r=e.length;f<r;f++)g.insertBefore(e[f],d);f=0;for(r=c.length;f<r;f++)a.removeNode(c[f])}},hb:function(a,b){7>e?a.setAttribute("selected",b):a.selected=b},F:function(a){return null===a||a===q?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},Wb:function(b,e){for(var c=[],d=(b||"").split(e),g=0,f=d.length;g<f;g++){var r=a.a.F(d[g]);""!==r&&c.push(r)}return c},Tb:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===
|
||||
b},yb:function(a,b){if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;null!=a;){if(a==b)return!0;a=a.parentNode}return!1},aa:function(b){return a.a.yb(b,b.ownerDocument)},pb:function(b){return!!a.a.La(b,a.a.aa)},u:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},o:function(b,d,k){var f=e&&g[d];if(f||"undefined"==typeof t)if(f||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var n=function(a){k.call(b,a)},p="on"+d;b.attachEvent(p,n);
|
||||
a.a.C.ia(b,function(){b.detachEvent(p,n)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(d,k,!1);else{if(c(b,d)){var r=k;k=function(a,b){var e=this.checked;b&&(this.checked=!0!==b.sb);r.call(this,a);this.checked=e}}t(b).bind(d,k)}},Ga:function(a,b){if(!a||!a.nodeType)throw Error("element must be a DOM node when calling triggerEvent");if("undefined"!=typeof t){var e=[];c(a,b)&&e.push({sb:a.checked});t(a).trigger(b,e)}else if("function"==typeof s.createEvent)if("function"==
|
||||
typeof a.dispatchEvent)e=s.createEvent(f[b]||"HTMLEvents"),e.initEvent(b,!0,!0,w,0,0,0,0,0,!1,!1,!1,!1,0,a),a.dispatchEvent(e);else throw Error("The supplied element doesn't support dispatchEvent");else if("undefined"!=typeof a.fireEvent)c(a,b)&&(a.checked=!0!==a.checked),a.fireEvent("on"+b);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.T(b)?b():b},ya:function(b){return a.T(b)?b.t():b},ga:function(b,e,c){if(e){var d=/\S+/g,g=b.className.match(d)||[];a.a.p(e.match(d),
|
||||
function(b){a.a.ja(g,b,c)});b.className=g.join(" ")}},ib:function(b,e){var c=a.a.c(e);if(null===c||c===q)c="";var d=a.e.firstChild(b);!d||3!=d.nodeType||a.e.nextSibling(d)?a.e.P(b,[s.createTextNode(c)]):d.data=c;a.a.Bb(b)},gb:function(a,b){a.name=b;if(7>=e)try{a.mergeAttributes(s.createElement("<input name='"+a.name+"'/>"),!1)}catch(c){}},Bb:function(a){9<=e&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},zb:function(a){if(e){var b=a.style.width;a.style.width=0;a.style.width=
|
||||
b}},Qb:function(b,e){b=a.a.c(b);e=a.a.c(e);for(var c=[],d=b;d<=e;d++)c.push(d);return c},N:function(a){for(var b=[],e=0,c=a.length;e<c;e++)b.push(a[e]);return b},Ub:6===e,Vb:7===e,ca:e,Ua:function(b,e){for(var c=a.a.N(b.getElementsByTagName("input")).concat(a.a.N(b.getElementsByTagName("textarea"))),d="string"==typeof e?function(a){return a.name===e}:function(a){return e.test(a.name)},g=[],f=c.length-1;0<=f;f--)d(c[f])&&g.push(c[f]);return g},Nb:function(b){return"string"==typeof b&&(b=a.a.F(b))?
|
||||
y&&y.parse?y.parse(b):(new Function("return "+b))():null},Ca:function(b,e,c){if(!y||!y.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return y.stringify(a.a.c(b),e,c)},Ob:function(e,c,d){d=d||{};var g=d.params||{},f=d.includeFields||this.Ta,p=e;if("object"==typeof e&&"form"===a.a.u(e))for(var p=e.action,r=f.length-1;0<=r;r--)for(var z=
|
||||
a.a.Ua(e,f[r]),D=z.length-1;0<=D;D--)g[z[D].name]=z[D].value;c=a.a.c(c);var q=s.createElement("form");q.style.display="none";q.action=p;q.method="post";for(var v in c)e=s.createElement("input"),e.name=v,e.value=a.a.Ca(a.a.c(c[v])),q.appendChild(e);b(g,function(a,b){var e=s.createElement("input");e.name=a;e.value=b;q.appendChild(e)});s.body.appendChild(q);d.submitter?d.submitter(q):q.submit();setTimeout(function(){q.parentNode.removeChild(q)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.p);
|
||||
a.b("utils.arrayFirst",a.a.La);a.b("utils.arrayFilter",a.a.Y);a.b("utils.arrayGetDistinctValues",a.a.Ma);a.b("utils.arrayIndexOf",a.a.k);a.b("utils.arrayMap",a.a.Z);a.b("utils.arrayPushAll",a.a.R);a.b("utils.arrayRemoveItem",a.a.ka);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.Ta);a.b("utils.getFormFields",a.a.Ua);a.b("utils.peekObservable",a.a.ya);a.b("utils.postJson",a.a.Ob);a.b("utils.parseJson",a.a.Nb);a.b("utils.registerEventHandler",a.a.o);a.b("utils.stringifyJson",
|
||||
a.a.Ca);a.b("utils.range",a.a.Qb);a.b("utils.toggleDomNodeCssClass",a.a.ga);a.b("utils.triggerEvent",a.a.Ga);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.w);a.b("utils.addOrRemoveItem",a.a.ja);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){var b=0,c="__ko__"+(new Date).getTime(),
|
||||
d={};return{get:function(b,c){var e=a.a.f.pa(b,!1);return e===q?q:e[c]},set:function(b,c,e){if(e!==q||a.a.f.pa(b,!1)!==q)a.a.f.pa(b,!0)[c]=e},pa:function(a,g){var e=a[c];if(!e||"null"===e||!d[e]){if(!g)return q;e=a[c]="ko"+b++;d[e]={}}return d[e]},clear:function(a){var b=a[c];return b?(delete d[b],a[c]=null,!0):!1}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.C=new function(){function b(b,c){var g=a.a.f.get(b,d);g===q&&c&&(g=[],a.a.f.set(b,d,g));return g}function c(e){var d=
|
||||
b(e,!1);if(d)for(var d=d.slice(0),f=0;f<d.length;f++)d[f](e);a.a.f.clear(e);"function"==typeof t&&"function"==typeof t.cleanData&&t.cleanData([e]);if(g[e.nodeType])for(d=e.firstChild;e=d;)d=e.nextSibling,8===e.nodeType&&c(e)}var d="__ko_domNodeDisposal__"+(new Date).getTime(),f={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{ia:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},cb:function(e,c){var g=b(e,!1);g&&(a.a.ka(g,c),0==g.length&&a.a.f.set(e,d,q))},H:function(b){if(f[b.nodeType]&&
|
||||
(c(b),g[b.nodeType])){var d=[];a.a.R(d,b.getElementsByTagName("*"));for(var h=0,k=d.length;h<k;h++)c(d[h])}return b},removeNode:function(b){a.H(b);b.parentNode&&b.parentNode.removeChild(b)}}};a.H=a.a.C.H;a.removeNode=a.a.C.removeNode;a.b("cleanNode",a.H);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.C);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.C.ia);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.C.cb);(function(){a.a.xa=function(b){var c;if("undefined"!=typeof t)if(t.parseHTML)c=
|
||||
t.parseHTML(b)||[];else{if((c=t.clean([b]))&&c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.F(b).toLowerCase();c=s.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof w.innerShiv?
|
||||
c.appendChild(w.innerShiv(b)):c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.N(c.lastChild.childNodes)}return c};a.a.fa=function(b,c){a.a.oa(b);c=a.a.c(c);if(null!==c&&c!==q)if("string"!=typeof c&&(c=c.toString()),"undefined"!=typeof t)t(b).html(c);else for(var d=a.a.xa(c),f=0;f<d.length;f++)b.appendChild(d[f])}})();a.b("utils.parseHtmlFragment",a.a.xa);a.b("utils.setHtml",a.a.fa);a.s=function(){function b(c,f){if(c)if(8==c.nodeType){var g=a.s.$a(c.nodeValue);null!=g&&f.push({xb:c,Kb:g})}else if(1==c.nodeType)for(var g=
|
||||
0,e=c.childNodes,m=e.length;g<m;g++)b(e[g],f)}var c={};return{va:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},mb:function(a,b){var g=c[a];if(g===q)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return g.apply(null,b||[]),
|
||||
!0}finally{delete c[a]}},nb:function(c,f){var g=[];b(c,g);for(var e=0,m=g.length;e<m;e++){var h=g[e].xb,k=[h];f&&a.a.R(k,f);a.s.mb(g[e].Kb,k);h.nodeValue="";h.parentNode&&h.parentNode.removeChild(h)}},$a:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.s);a.b("memoization.memoize",a.s.va);a.b("memoization.unmemoize",a.s.mb);a.b("memoization.parseMemoText",a.s.$a);a.b("memoization.unmemoizeDomNodeAndDescendants",a.s.nb);a.Sa={throttle:function(b,c){b.throttleEvaluation=
|
||||
c;var d=null;return a.j({read:b,write:function(a){clearTimeout(d);d=setTimeout(function(){b(a)},c)}})},notify:function(b,c){b.equalityComparer="always"==c?F(!1):a.m.fn.equalityComparer;return b}};a.b("extenders",a.Sa);a.kb=function(b,c,d){this.target=b;this.la=c;this.wb=d;a.r(this,"dispose",this.B)};a.kb.prototype.B=function(){this.Hb=!0;this.wb()};a.V=function(){this.G={};a.a.extend(this,a.V.fn);a.r(this,"subscribe",this.Da);a.r(this,"extend",this.extend);a.r(this,"getSubscriptionsCount",this.Db)};
|
||||
a.V.fn={Da:function(b,c,d){d=d||"change";var f=new a.kb(this,c?b.bind(c):b,function(){a.a.ka(this.G[d],f)}.bind(this));this.G[d]||(this.G[d]=[]);this.G[d].push(f);return f},notifySubscribers:function(b,c){c=c||"change";this.G[c]&&a.q.I(function(){a.a.p(this.G[c].slice(0),function(a){a&&!0!==a.Hb&&a.la(b)})},this)},Db:function(){var b=0;a.a.w(this.G,function(a,d){b+=d.length});return b},extend:function(b){var c=this;b&&a.a.w(b,function(b,f){var g=a.Sa[b];"function"==typeof g&&(c=g(c,f))});return c}};
|
||||
a.Wa=function(a){return null!=a&&"function"==typeof a.Da&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.V);a.b("isSubscribable",a.Wa);a.q=function(){var b=[];return{rb:function(a){b.push({la:a,Ra:[]})},end:function(){b.pop()},bb:function(c){if(!a.Wa(c))throw Error("Only subscribable things can act as dependencies");if(0<b.length){var d=b[b.length-1];!d||0<=a.a.k(d.Ra,c)||(d.Ra.push(c),d.la(c))}},I:function(a,d,f){try{return b.push(null),a.apply(d,f||[])}finally{b.pop()}}}}();var L=
|
||||
{undefined:!0,"boolean":!0,number:!0,string:!0};a.m=function(b){function c(){if(0<arguments.length)return c.equalityComparer&&c.equalityComparer(d,arguments[0])||(c.K(),d=arguments[0],c.J()),this;a.q.bb(c);return d}var d=b;a.V.call(c);c.t=function(){return d};c.J=function(){c.notifySubscribers(d)};c.K=function(){c.notifySubscribers(d,"beforeChange")};a.a.extend(c,a.m.fn);a.r(c,"peek",c.t);a.r(c,"valueHasMutated",c.J);a.r(c,"valueWillMutate",c.K);return c};a.m.fn={equalityComparer:function(a,c){return null===
|
||||
a||typeof a in L?a===c:!1}};var A=a.m.Pb="__ko_proto__";a.m.fn[A]=a.m;a.qa=function(b,c){return null===b||b===q||b[A]===q?!1:b[A]===c?!0:a.qa(b[A],c)};a.T=function(b){return a.qa(b,a.m)};a.Xa=function(b){return"function"==typeof b&&b[A]===a.m||"function"==typeof b&&b[A]===a.j&&b.Eb?!0:!1};a.b("observable",a.m);a.b("isObservable",a.T);a.b("isWriteableObservable",a.Xa);a.U=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
|
||||
b=a.m(b);a.a.extend(b,a.U.fn);return b};a.U.fn={remove:function(a){for(var c=this.t(),d=[],f="function"==typeof a?a:function(e){return e===a},g=0;g<c.length;g++){var e=c[g];f(e)&&(0===d.length&&this.K(),d.push(e),c.splice(g,1),g--)}d.length&&this.J();return d},removeAll:function(b){if(b===q){var c=this.t(),d=c.slice(0);this.K();c.splice(0,c.length);this.J();return d}return b?this.remove(function(c){return 0<=a.a.k(b,c)}):[]},destroy:function(a){var c=this.t(),d="function"==typeof a?a:function(c){return c===
|
||||
a};this.K();for(var f=c.length-1;0<=f;f--)d(c[f])&&(c[f]._destroy=!0);this.J()},destroyAll:function(b){return b===q?this.destroy(F(!0)):b?this.destroy(function(c){return 0<=a.a.k(b,c)}):[]},indexOf:function(b){var c=this();return a.a.k(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.K(),this.t()[d]=c,this.J())}};a.a.p("pop push reverse shift sort splice unshift".split(" "),function(b){a.U.fn[b]=function(){var a=this.t();this.K();a=a[b].apply(a,arguments);this.J();return a}});a.a.p(["slice"],
|
||||
function(b){a.U.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.U);a.j=function(b,c,d){function f(){a.a.p(v,function(a){a.B()});v=[]}function g(){var a=m.throttleEvaluation;a&&0<=a?(clearTimeout(t),t=setTimeout(e,a)):e()}function e(){if(!n)if(l&&D())x();else{n=!0;try{var b=a.a.Z(v,function(a){return a.target});a.q.rb(function(e){var c;0<=(c=a.a.k(b,e))?b[c]=q:v.push(e.Da(g))});for(var e=p.call(c),d=b.length-1;0<=d;d--)b[d]&&v.splice(d,1)[0].B();l=!0;m.notifySubscribers(k,
|
||||
"beforeChange");k=e;m.notifySubscribers(k)}finally{a.q.end(),n=!1}v.length||x()}}function m(){if(0<arguments.length){if("function"===typeof r)r.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}l||e();a.q.bb(m);return k}function h(){return!l||0<v.length}var k,l=!1,n=!1,p=b;p&&"object"==typeof p?(d=p,p=d.read):(d=d||{},p||(p=d.read));if("function"!=typeof p)throw Error("Pass a function that returns the value of the ko.computed");
|
||||
var r=d.write,z=d.disposeWhenNodeIsRemoved||d.$||null,D=d.disposeWhen||d.Qa||F(!1),x=f,v=[],t=null;c||(c=d.owner);m.t=function(){l||e();return k};m.Cb=function(){return v.length};m.Eb="function"===typeof d.write;m.B=function(){x()};m.ta=h;a.V.call(m);a.a.extend(m,a.j.fn);a.r(m,"peek",m.t);a.r(m,"dispose",m.B);a.r(m,"isActive",m.ta);a.r(m,"getDependenciesCount",m.Cb);!0!==d.deferEvaluation&&e();if(z&&h()){x=function(){a.a.C.cb(z,x);f()};a.a.C.ia(z,x);var s=D,D=function(){return!a.a.aa(z)||s()}}return m};
|
||||
a.Gb=function(b){return a.qa(b,a.j)};C=a.m.Pb;a.j[C]=a.m;a.j.fn={};a.j.fn[C]=a.j;a.b("dependentObservable",a.j);a.b("computed",a.j);a.b("isComputed",a.Gb);(function(){function b(a,g,e){e=e||new d;a=g(a);if("object"!=typeof a||null===a||a===q||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var m=a instanceof Array?[]:{};e.save(a,m);c(a,function(c){var d=g(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":m[c]=d;break;case "object":case "undefined":var l=
|
||||
e.get(d);m[c]=l!==q?l:b(d,g,e)}});return m}function c(a,b){if(a instanceof Array){for(var e=0;e<a.length;e++)b(e);"function"==typeof a.toJSON&&b("toJSON")}else for(e in a)b(e)}function d(){this.keys=[];this.Ha=[]}a.lb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var e=0;a.T(b)&&10>e;e++)b=b();return b})};a.toJSON=function(b,c,e){b=a.lb(b);return a.a.Ca(b,c,e)};d.prototype={save:function(b,c){var e=a.a.k(this.keys,
|
||||
b);0<=e?this.Ha[e]=c:(this.keys.push(b),this.Ha.push(c))},get:function(b){b=a.a.k(this.keys,b);return 0<=b?this.Ha[b]:q}}})();a.b("toJS",a.lb);a.b("toJSON",a.toJSON);(function(){a.h={n:function(b){switch(a.a.u(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.wa):7>=a.a.ca?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.h.n(b.options[b.selectedIndex]):q;default:return b.value}},W:function(b,
|
||||
c){switch(a.a.u(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.wa,q);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.wa,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":""===c&&(c=q);if(null===c||c===q)b.selectedIndex=-1;for(var d=b.options.length-1;0<=d;d--)if(a.h.n(b.options[d])==c){b.selectedIndex=d;break}1<b.size||-1!==b.selectedIndex||(b.selectedIndex=
|
||||
0);break;default:if(null===c||c===q)c="";b.value=c}}}})();a.b("selectExtensions",a.h);a.b("selectExtensions.readValue",a.h.n);a.b("selectExtensions.writeValue",a.h.W);a.g=function(){function b(a,b){for(var d=null;a!=d;)d=a,a=a.replace(c,function(a,c){return b[c]});return a}var c=/\@ko_token_(\d+)\@/g,d=["true","false","null","undefined"],f=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;return{S:[],da:function(c){var e=a.a.F(c);if(3>e.length)return[];"{"===e.charAt(0)&&(e=e.substring(1,e.length-
|
||||
1));c=[];for(var d=null,f,k=0;k<e.length;k++){var l=e.charAt(k);if(null===d)switch(l){case '"':case "'":case "/":d=k,f=l}else if(l==f&&"\\"!==e.charAt(k-1)){l=e.substring(d,k+1);c.push(l);var n="@ko_token_"+(c.length-1)+"@",e=e.substring(0,d)+n+e.substring(k+1),k=k-(l.length-n.length),d=null}}f=d=null;for(var p=0,r=null,k=0;k<e.length;k++){l=e.charAt(k);if(null===d)switch(l){case "{":d=k;r=l;f="}";break;case "(":d=k;r=l;f=")";break;case "[":d=k,r=l,f="]"}l===r?p++:l===f&&(p--,0===p&&(l=e.substring(d,
|
||||
k+1),c.push(l),n="@ko_token_"+(c.length-1)+"@",e=e.substring(0,d)+n+e.substring(k+1),k-=l.length-n.length,d=null))}f=[];e=e.split(",");d=0;for(k=e.length;d<k;d++)p=e[d],r=p.indexOf(":"),0<r&&r<p.length-1?(l=p.substring(r+1),f.push({key:b(p.substring(0,r),c),value:b(l,c)})):f.push({unknown:b(p,c)});return f},ea:function(b){var e="string"===typeof b?a.g.da(b):b,c=[];b=[];for(var h,k=0;h=e[k];k++)if(0<c.length&&c.push(","),h.key){var l;a:{l=h.key;var n=a.a.F(l);switch(n.length&&n.charAt(0)){case "'":case '"':break a;
|
||||
default:l="'"+n+"'"}}h=h.value;c.push(l);c.push(":");c.push(h);h=a.a.F(h);0<=a.a.k(d,a.a.F(h).toLowerCase())?h=!1:(n=h.match(f),h=null===n?!1:n[1]?"Object("+n[1]+")"+n[2]:h);h&&(0<b.length&&b.push(", "),b.push(l+" : function(__ko_value) { "+h+" = __ko_value; }"))}else h.unknown&&c.push(h.unknown);e=c.join("");0<b.length&&(e=e+", '_ko_property_writers' : { "+b.join("")+" } ");return e},Jb:function(b,c){for(var d=0;d<b.length;d++)if(a.a.F(b[d].key)==c)return!0;return!1},ha:function(b,c,d,f,k){if(b&&
|
||||
a.T(b))!a.Xa(b)||k&&b.t()===f||b(f);else if((b=c()._ko_property_writers)&&b[d])b[d](f)}}}();a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.S);a.b("expressionRewriting.parseObjectLiteral",a.g.da);a.b("expressionRewriting.preProcessBindings",a.g.ea);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.ea);(function(){function b(a){return 8==a.nodeType&&(g?a.text:a.nodeValue).match(e)}function c(a){return 8==a.nodeType&&
|
||||
(g?a.text:a.nodeValue).match(m)}function d(a,e){for(var d=a,g=1,f=[];d=d.nextSibling;){if(c(d)&&(g--,0===g))return f;f.push(d);b(d)&&g++}if(!e)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function f(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var g=s&&"\x3c!--test--\x3e"===s.createComment("test").text,e=g?/^\x3c!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*--\x3e$/:/^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/,m=g?/^\x3c!--\s*\/ko\s*--\x3e$/:
|
||||
/^\s*\/ko\s*$/,h={ul:!0,ol:!0};a.e={L:{},childNodes:function(a){return b(a)?d(a):a.childNodes},ba:function(c){if(b(c)){c=a.e.childNodes(c);for(var e=0,d=c.length;e<d;e++)a.removeNode(c[e])}else a.a.oa(c)},P:function(c,e){if(b(c)){a.e.ba(c);for(var d=c.nextSibling,g=0,f=e.length;g<f;g++)d.parentNode.insertBefore(e[g],d)}else a.a.P(c,e)},ab:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},Va:function(c,e,d){d?b(c)?c.parentNode.insertBefore(e,
|
||||
d.nextSibling):d.nextSibling?c.insertBefore(e,d.nextSibling):c.appendChild(e):a.e.ab(c,e)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=f(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},ob:function(a){return(a=b(a))?a[1]:null},Za:function(e){if(h[a.a.u(e)]){var d=e.firstChild;if(d){do if(1===d.nodeType){var g;g=d.firstChild;var m=null;if(g){do if(m)m.push(g);else if(b(g)){var r=f(g,!0);r?g=r:m=
|
||||
[g]}else c(g)&&(m=[g]);while(g=g.nextSibling)}if(g=m)for(m=d.nextSibling,r=0;r<g.length;r++)m?e.insertBefore(g[r],m):e.appendChild(g[r])}while(d=d.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.L);a.b("virtualElements.emptyNode",a.e.ba);a.b("virtualElements.insertAfter",a.e.Va);a.b("virtualElements.prepend",a.e.ab);a.b("virtualElements.setDomNodeChildren",a.e.P);(function(){a.M=function(){this.Na={}};a.a.extend(a.M.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
|
||||
b.getAttribute("data-bind");case 8:return null!=a.e.ob(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.e.ob(b);default:return null}},parseBindingsString:function(b,c,d){try{var f;if(!(f=this.Na[b])){var g=this.Na,e,m="with($context){with($data||{}){return{"+a.g.ea(b)+"}}}";e=new Function("$context","$element",m);
|
||||
f=g[b]=e}return f(c,d)}catch(h){throw h.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+h.message,h;}}});a.M.instance=new a.M})();a.b("bindingProvider",a.M);(function(){function b(b,e,d){for(var f=a.e.firstChild(e);e=f;)f=a.e.nextSibling(e),c(b,e,d)}function c(c,e,f){var h=!0,k=1===e.nodeType;k&&a.e.Za(e);if(k&&f||a.M.instance.nodeHasBindings(e))h=d(e,null,c,f).Sb;h&&b(c,e,!k)}function d(b,c,d,h){function k(a){return function(){return p[a]}}function l(){return p}var n=0,p,r,
|
||||
z=a.a.f.get(b,f);if(!c){if(z)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,f,!0)}a.j(function(){var f=d&&d instanceof a.A?d:new a.A(a.a.c(d)),x=f.$data;!z&&h&&a.jb(b,f);if(p=("function"==typeof c?c(f,b):c)||a.M.instance.getBindings(b,f))0===n&&(n=1,a.a.w(p,function(c){var e=a.d[c];if(e&&8===b.nodeType&&!a.e.L[c])throw Error("The binding '"+c+"' cannot be used with virtual elements");if(e&&"function"==typeof e.init&&(e=(0,e.init)(b,k(c),l,x,f))&&e.controlsDescendantBindings){if(r!==
|
||||
q)throw Error("Multiple bindings ("+r+" and "+c+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");r=c}}),n=2),2===n&&a.a.w(p,function(c){var e=a.d[c];e&&"function"==typeof e.update&&(0,e.update)(b,k(c),l,x,f)})},null,{$:b});return{Sb:r===q}}a.d={};a.A=function(b,c,d){c?(a.a.extend(this,c),this.$parentContext=c,this.$parent=c.$data,this.$parents=(c.$parents||[]).slice(0),this.$parents.unshift(this.$parent)):(this.$parents=
|
||||
[],this.$root=b,this.ko=a);this.$data=b;d&&(this[d]=b)};a.A.prototype.createChildContext=function(b,c){return new a.A(b,this,c)};a.A.prototype.extend=function(b){var c=a.a.extend(new a.A,this);return a.a.extend(c,b)};var f="__ko_boundElement";a.jb=function(b,c){if(2==arguments.length)a.a.f.set(b,"__ko_bindingContext__",c);else return a.a.f.get(b,"__ko_bindingContext__")};a.Ka=function(b,c,f){1===b.nodeType&&a.e.Za(b);return d(b,c,f,!0)};a.Ja=function(a,c){1!==c.nodeType&&8!==c.nodeType||b(a,c,!0)};
|
||||
a.Ia=function(a,b){if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||w.document.body;c(a,b,!0)};a.na=function(b){switch(b.nodeType){case 1:case 8:var c=a.jb(b);if(c)return c;if(b.parentNode)return a.na(b.parentNode)}return q};a.ub=function(b){return(b=a.na(b))?b.$data:q};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Ia);a.b("applyBindingsToDescendants",a.Ja);a.b("applyBindingsToNode",a.Ka);
|
||||
a.b("contextFor",a.na);a.b("dataFor",a.ub)})();var K={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.w(d,function(c,d){d=a.a.c(d);var e=!1===d||null===d||d===q;e&&b.removeAttribute(c);8>=a.a.ca&&c in K?(c=K[c],e?b.removeAttribute(c):b[c]=d):e||b.setAttribute(c,d.toString());"name"===c&&a.a.gb(b,e?"":d.toString())})}};a.d.checked={init:function(b,c,d){a.a.o(b,"click",function(){var f;if("checkbox"==b.type)f=b.checked;else if("radio"==b.type&&b.checked)f=
|
||||
b.value;else return;var g=c(),e=a.a.c(g);"checkbox"==b.type&&e instanceof Array?a.a.ja(g,b.value,b.checked):a.g.ha(g,d,"checked",f,!0)});"radio"!=b.type||b.name||a.d.uniqueName.init(b,F(!0))},update:function(b,c){var d=a.a.c(c());"checkbox"==b.type?b.checked=d instanceof Array?0<=a.a.k(d,b.value):d:"radio"==b.type&&(b.checked=b.value==d)}};a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.w(d,function(c,d){d=a.a.c(d);a.a.ga(b,c,d)}):(d=String(d||""),a.a.ga(b,b.__ko__cssValue,!1),
|
||||
b.__ko__cssValue=d,a.a.ga(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,f){var g=c()||{};a.a.w(g,function(e){"string"==typeof e&&a.a.o(b,e,function(b){var g,k=c()[e];if(k){var l=d();try{var n=a.a.N(arguments);n.unshift(f);g=k.apply(f,n)}finally{!0!==g&&(b.preventDefault?b.preventDefault():b.returnValue=
|
||||
!1)}!1===l[e+"Bubble"]&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={Ya:function(b){return function(){var c=b(),d=a.a.ya(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.D.sa};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.D.sa}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.Ya(c))},
|
||||
update:function(b,c,d,f,g){return a.d.template.update(b,a.d.foreach.Ya(c),d,f,g)}};a.g.S.foreach=!1;a.e.L.foreach=!0;a.d.hasfocus={init:function(b,c,d){function f(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(l){g=f.body}e=g===b}f=c();a.g.ha(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var g=f.bind(null,!0),e=f.bind(null,!1);a.a.o(b,"focus",g);a.a.o(b,"focusin",g);a.a.o(b,"blur",e);a.a.o(b,"focusout",e)},
|
||||
update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.q.I(a.a.Ga,null,[b,d?"focusin":"focusout"]))}};a.d.hasFocus=a.d.hasfocus;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.fa(b,c())}};var I="__ko_withIfBindingData";G("if");G("ifnot",!1,!0);G("with",!0,!1,function(a,c){return a.createChildContext(c)});a.d.options={init:function(b){if("select"!==a.a.u(b))throw Error("options binding applies only to SELECT elements");
|
||||
for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(b,c){if(p){var d=0<=a.a.k(p,a.h.n(c[0]));a.a.hb(c[0],d)}}var e=0==b.length,m=!e&&b.multiple?b.scrollTop:null;c=a.a.c(c());var h=d(),k=h.optionsIncludeDestroyed,l={},n,p;b.multiple?p=a.a.Z(b.selectedOptions||a.a.Y(b.childNodes,function(b){return b.tagName&&"option"===a.a.u(b)&&b.selected}),function(b){return a.h.n(b)}):0<=
|
||||
b.selectedIndex&&(p=[a.h.n(b.options[b.selectedIndex])]);if(c){"undefined"==typeof c.length&&(c=[c]);var r=a.a.Y(c,function(b){return k||b===q||null===b||!a.a.c(b._destroy)});"optionsCaption"in h&&(n=a.a.c(h.optionsCaption),null!==n&&n!==q&&r.unshift(l))}else c=[];d=g;h.optionsAfterRender&&(d=function(b,c){g(0,c);a.q.I(h.optionsAfterRender,null,[c[0],b!==l?b:q])});a.a.Aa(b,r,function(b,c,d){d.length&&(p=d[0].selected&&[a.h.n(d[0])]);c=s.createElement("option");b===l?(a.a.fa(c,n),a.h.W(c,q)):(d=f(b,
|
||||
h.optionsValue,b),a.h.W(c,a.a.c(d)),b=f(b,h.optionsText,d),a.a.ib(c,b));return[c]},null,d);p=null;e&&"value"in h&&J(b,a.a.ya(h.value),!0);a.a.zb(b);m&&20<Math.abs(m-b.scrollTop)&&(b.scrollTop=m)}};a.d.options.wa="__ko.optionValueDomData__";a.d.selectedOptions={init:function(b,c,d){a.a.o(b,"change",function(){var f=c(),g=[];a.a.p(b.getElementsByTagName("option"),function(b){b.selected&&g.push(a.h.n(b))});a.g.ha(f,d,"selectedOptions",g)})},update:function(b,c){if("select"!=a.a.u(b))throw Error("values binding applies only to SELECT elements");
|
||||
var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.p(b.getElementsByTagName("option"),function(b){var c=0<=a.a.k(d,a.h.n(b));a.a.hb(b,c)})}};a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.w(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.o(b,"submit",function(a){var d,m=c();try{d=m.call(f,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};
|
||||
a.d.text={update:function(b,c){a.a.ib(b,c())}};a.e.L.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.tb;a.a.gb(b,d)}}};a.d.uniqueName.tb=0;a.d.value={init:function(b,c,d){function f(){m=!1;var e=c(),f=a.h.n(b);a.g.ha(e,d,"value",f)}var g=["change"],e=d().valueUpdate,m=!1;e&&("string"==typeof e&&(e=[e]),a.a.R(g,e),g=a.a.Ma(g));!a.a.ca||("input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete)||-1!=a.a.k(g,"propertychange")||
|
||||
(a.a.o(b,"propertychange",function(){m=!0}),a.a.o(b,"blur",function(){m&&f()}));a.a.p(g,function(c){var d=f;a.a.Tb(c,"after")&&(d=function(){setTimeout(f,0)},c=c.substring(5));a.a.o(b,c,d)})},update:function(b,c){var d="select"===a.a.u(b),f=a.a.c(c()),g=a.h.n(b);f!==g&&(g=function(){a.h.W(b,f)},g(),d&&setTimeout(g,0));d&&0<b.length&&J(b,f,!1)}};a.d.visible={update:function(b,c){var d=a.a.c(c()),f="none"!=b.style.display;d&&!f?b.style.display="":!d&&f&&(b.style.display="none")}};(function(b){a.d[b]=
|
||||
{init:function(c,d,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},f,g)}}})("click");a.v=function(){};a.v.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.v.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.v.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||s;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.l.i(d)}if(1==
|
||||
b.nodeType||8==b.nodeType)return new a.l.Q(b);throw Error("Unknown template type: "+b);};a.v.prototype.renderTemplate=function(a,c,d,f){a=this.makeTemplateSource(a,f);return this.renderTemplateSource(a,c,d)};a.v.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.v.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.v);
|
||||
a.Ea=function(){function b(b,c,d,m){b=a.g.da(b);for(var h=a.g.S,k=0;k<b.length;k++){var l=b[k].key;if(h.hasOwnProperty(l)){var n=h[l];if("function"===typeof n){if(l=n(b[k].value))throw Error(l);}else if(!n)throw Error("This template engine does not support the '"+l+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.ea(b)+" } })()},'"+d.toLowerCase()+"')";return m.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,
|
||||
d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ab:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Ea.Lb(b,c)},d)},Lb:function(a,g){return a.replace(c,function(a,c,d,f,l){return b(l,c,d,g)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",g)})},qb:function(b,c){return a.s.va(function(d,m){var h=d.nextSibling;h&&h.nodeName.toLowerCase()===c&&a.Ka(h,b,m)})}}}();a.b("__tr_ambtns",a.Ea.qb);(function(){a.l={};a.l.i=function(a){this.i=a};a.l.i.prototype.text=
|
||||
function(){var b=a.a.u(this.i),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.i[b];var c=arguments[0];"innerHTML"===b?a.a.fa(this.i,c):this.i[b]=c};a.l.i.prototype.data=function(b){if(1===arguments.length)return a.a.f.get(this.i,"templateSourceData_"+b);a.a.f.set(this.i,"templateSourceData_"+b,arguments[1])};a.l.Q=function(a){this.i=a};a.l.Q.prototype=new a.l.i;a.l.Q.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.i,"__ko_anon_template__")||
|
||||
{};b.Fa===q&&b.ma&&(b.Fa=b.ma.innerHTML);return b.Fa}a.a.f.set(this.i,"__ko_anon_template__",{Fa:arguments[0]})};a.l.i.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.i,"__ko_anon_template__")||{}).ma;a.a.f.set(this.i,"__ko_anon_template__",{ma:arguments[0]})};a.b("templateSources",a.l);a.b("templateSources.domElement",a.l.i);a.b("templateSources.anonymousTemplate",a.l.Q)})();(function(){function b(b,c,d){var f;for(c=a.e.nextSibling(c);b&&(f=b)!==c;)b=a.e.nextSibling(f),1!==
|
||||
f.nodeType&&8!==f.nodeType||d(f)}function c(c,d){if(c.length){var f=c[0],g=c[c.length-1];b(f,g,function(b){a.Ia(d,b)});b(f,g,function(b){a.s.nb(b,[d])})}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function f(b,f,h,k,l){l=l||{};var n=b&&d(b),n=n&&n.ownerDocument,p=l.templateEngine||g;a.Ea.Ab(h,p,n);h=p.renderTemplate(h,k,l,n);if("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)throw Error("Template engine must return an array of DOM nodes");n=!1;switch(f){case "replaceChildren":a.e.P(b,
|
||||
h);n=!0;break;case "replaceNode":a.a.eb(b,h);n=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+f);}n&&(c(h,k),l.afterRender&&a.q.I(l.afterRender,null,[h,k.$data]));return h}var g;a.Ba=function(b){if(b!=q&&!(b instanceof a.v))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.za=function(b,c,h,k,l){h=h||{};if((h.templateEngine||g)==q)throw Error("Set a template engine before calling renderTemplate");l=l||"replaceChildren";if(k){var n=d(k);return a.j(function(){var g=
|
||||
c&&c instanceof a.A?c:new a.A(a.a.c(c)),r="function"==typeof b?b(g.$data,g):b,g=f(k,l,r,g,h);"replaceNode"==l&&(k=g,n=d(k))},null,{Qa:function(){return!n||!a.a.aa(n)},$:n&&"replaceNode"==l?n.parentNode:n})}return a.s.va(function(d){a.za(b,c,h,d,"replaceNode")})};a.Rb=function(b,d,g,k,l){function n(a,b){c(b,r);g.afterRender&&g.afterRender(b,a)}function p(c,d){r=l.createChildContext(a.a.c(c),g.as);r.$index=d;var k="function"==typeof b?b(c,r):b;return f(null,"ignoreTargetNode",k,r,g)}var r;return a.j(function(){var b=
|
||||
a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Y(b,function(b){return g.includeDestroyed||b===q||null===b||!a.a.c(b._destroy)});a.q.I(a.a.Aa,null,[k,b,p,g,n])},null,{$:k})};a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||(d.name||1!=b.nodeType&&8!=b.nodeType)||(d=1==b.nodeType?b.childNodes:a.e.childNodes(b),d=a.a.Mb(d),(new a.l.Q(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,f,g){c=a.a.c(c());d={};f=!0;var n,p=null;"string"!=typeof c&&(d=
|
||||
c,c=a.a.c(d.name),"if"in d&&(f=a.a.c(d["if"])),f&&"ifnot"in d&&(f=!a.a.c(d.ifnot)),n=a.a.c(d.data));"foreach"in d?p=a.Rb(c||b,f&&d.foreach||[],d,b,g):f?(g="data"in d?g.createChildContext(n,d.as):g,p=a.za(c||b,g,d,b)):a.e.ba(b);g=p;(n=a.a.f.get(b,"__ko__templateComputedDomDataKey__"))&&"function"==typeof n.B&&n.B();a.a.f.set(b,"__ko__templateComputedDomDataKey__",g&&g.ta()?g:q)}};a.g.S.template=function(b){b=a.g.da(b);return 1==b.length&&b[0].unknown||a.g.Jb(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};
|
||||
a.e.L.template=!0})();a.b("setTemplateEngine",a.Ba);a.b("renderTemplate",a.za);a.a.Pa=function(){function a(b,d,f,g,e){var m=Math.min,h=Math.max,k=[],l,n=b.length,p,r=d.length,q=r-n||1,t=n+r+1,s,v,w;for(l=0;l<=n;l++)for(v=s,k.push(s=[]),w=m(r,l+q),p=h(0,l-1);p<=w;p++)s[p]=p?l?b[l-1]===d[p-1]?v[p-1]:m(v[p]||t,s[p-1]||t)+1:p+1:l+1;m=[];h=[];q=[];l=n;for(p=r;l||p;)r=k[l][p]-1,p&&r===k[l][p-1]?h.push(m[m.length]={status:f,value:d[--p],index:p}):l&&r===k[l-1][p]?q.push(m[m.length]={status:g,value:b[--l],
|
||||
index:l}):(m.push({status:"retained",value:d[--p]}),--l);if(h.length&&q.length){b=10*n;var E;for(d=f=0;(e||d<b)&&(E=h[f]);f++){for(g=0;k=q[g];g++)if(E.value===k.value){E.moved=k.index;k.moved=E.index;q.splice(g,1);d=g=0;break}d+=g}}return m.reverse()}return function(c,d,f){c=c||[];d=d||[];return c.length<=d.length?a(c,d,"added","deleted",f):a(d,c,"deleted","added",f)}}();a.b("utils.compareArrays",a.a.Pa);(function(){function b(b){for(;b.length&&!a.a.aa(b[0]);)b.splice(0,1);if(1<b.length){for(var c=
|
||||
b[0],g=b[b.length-1],e=[c];c!==g;){c=c.nextSibling;if(!c)return;e.push(c)}Array.prototype.splice.apply(b,[0,b.length].concat(e))}return b}function c(c,f,g,e,m){var h=[];c=a.j(function(){var c=f(g,m,b(h))||[];0<h.length&&(a.a.eb(h,c),e&&a.q.I(e,null,[g,c,m]));h.splice(0,h.length);a.a.R(h,c)},null,{$:c,Qa:function(){return!a.a.pb(h)}});return{O:h,j:c.ta()?c:q}}a.a.Aa=function(d,f,g,e,m){function h(a,c){u=n[c];x!==c&&(E[a]=u);u.ra(x++);b(u.O);t.push(u);w.push(u)}function k(b,c){if(b)for(var d=0,e=c.length;d<
|
||||
e;d++)c[d]&&a.a.p(c[d].O,function(a){b(a,d,c[d].X)})}f=f||[];e=e||{};var l=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===q,n=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],p=a.a.Z(n,function(a){return a.X}),r=a.a.Pa(p,f,e.dontLimitMoves),t=[],s=0,x=0,v=[],w=[];f=[];for(var E=[],p=[],u,B=0,y,A;y=r[B];B++)switch(A=y.moved,y.status){case "deleted":A===q&&(u=n[s],u.j&&u.j.B(),v.push.apply(v,b(u.O)),e.beforeRemove&&(f[B]=u,w.push(u)));s++;break;case "retained":h(B,
|
||||
s++);break;case "added":A!==q?h(B,A):(u={X:y.value,ra:a.m(x++)},t.push(u),w.push(u),l||(p[B]=u))}k(e.beforeMove,E);a.a.p(v,e.beforeRemove?a.H:a.removeNode);for(var B=0,l=a.e.firstChild(d),C;u=w[B];B++){u.O||a.a.extend(u,c(d,g,u.X,m,u.ra));for(s=0;r=u.O[s];l=r.nextSibling,C=r,s++)r!==l&&a.e.Va(d,r,C);!u.Fb&&m&&(m(u.X,u.O,u.ra),u.Fb=!0)}k(e.beforeRemove,f);k(e.afterMove,E);k(e.afterAdd,p);a.a.f.set(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult",t)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",
|
||||
a.a.Aa);a.D=function(){this.allowTemplateRewriting=!1};a.D.prototype=new a.v;a.D.prototype.renderTemplateSource=function(b){var c=(9>a.a.ca?0:b.nodes)?b.nodes():null;if(c)return a.a.N(c.cloneNode(!0).childNodes);b=b.text();return a.a.xa(b)};a.D.sa=new a.D;a.Ba(a.D.sa);a.b("nativeTemplateEngine",a.D);(function(){a.ua=function(){var a=this.Ib=function(){if("undefined"==typeof t||!t.tmpl)return 0;try{if(0<=t.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=
|
||||
function(b,f,g){g=g||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var e=b.data("precompiled");e||(e=b.text()||"",e=t.template(null,"{{ko_with $item.koBindingContext}}"+e+"{{/ko_with}}"),b.data("precompiled",e));b=[f.$data];f=t.extend({koBindingContext:f},g.templateOptions);f=t.tmpl(e,b,f);f.appendTo(s.createElement("div"));t.fragments={};return f};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+
|
||||
a+" })()) }}"};this.addTemplate=function(a,b){s.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(t.tmpl.tag.ko_code={open:"__.push($1 || '');"},t.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.ua.prototype=new a.v;var b=new a.ua;0<b.Ib&&a.Ba(b);a.b("jqueryTmplTemplateEngine",a.ua)})()})})();
|
||||
})();
|
||||
(function() {(function(p){var A=this||(0,eval)("this"),w=A.document,K=A.navigator,t=A.jQuery,C=A.JSON;(function(p){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?p(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],p):p(A.ko={})})(function(z){function G(a,c){return null===a||typeof a in M?a===c:!1}function N(a,c){var d;return function(){d||(d=setTimeout(function(){d=p;a()},c))}}function O(a,c){var d;return function(){clearTimeout(d);d=setTimeout(a,
|
||||
c)}}function H(b,c,d,e){a.d[b]={init:function(b,h,g,k,l){var n,r;a.ba(function(){var g=a.a.c(h()),k=!d!==!g,s=!r;if(s||c||k!==n)s&&a.ca.fa()&&(r=a.a.lb(a.e.childNodes(b),!0)),k?(s||a.e.U(b,a.a.lb(r)),a.gb(e?e(l,g):l,b)):a.e.da(b),n=k},null,{G:b});return{controlsDescendantBindings:!0}}};a.g.aa[b]=!1;a.e.Q[b]=!0}var a="undefined"!==typeof z?z:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.s=function(a,c,d){a[c]=d};a.version="3.1.0";a.b("version",
|
||||
a.version);a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}var e={__proto__:[]}instanceof Array,f={},h={};f[K&&/Firefox\/2/i.test(K.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];f.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(f,function(a,b){if(b.length)for(var c=0,
|
||||
d=b.length;c<d;c++)h[b[c]]=a});var g={propertychange:!0},k=w&&function(){for(var a=3,b=w.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:p}();return{mb:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],r:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},l:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===
|
||||
b)return c;return-1},hb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];return null},ma:function(b,c){var d=a.a.l(b,c);0<d?b.splice(d,1):0===d&&b.shift()},ib:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.l(c,b[d])&&c.push(b[d]);return c},ya:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},la:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},$:function(a,b){if(b instanceof Array)a.push.apply(a,
|
||||
b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},Y:function(b,c,d){var e=a.a.l(a.a.Sa(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},na:e,extend:c,ra:d,sa:e?d:c,A:b,Oa:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},Fa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},ec:function(b){b=a.a.R(b);for(var c=w.createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.M(b[d]));return c},lb:function(b,c){for(var d=0,e=b.length,g=[];d<
|
||||
e;d++){var k=b[d].cloneNode(!0);g.push(c?a.M(k):k)}return g},U:function(b,c){a.a.Fa(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},Bb:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],g=e.parentNode,k=0,h=c.length;k<h;k++)g.insertBefore(c[k],e);k=0;for(h=d.length;k<h;k++)a.removeNode(d[k])}},ea:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.shift();if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)if(a.push(c),
|
||||
c=c.nextSibling,!c)return;a.push(d)}}return a},Db:function(a,b){7>k?a.setAttribute("selected",b):a.selected=b},ta:function(a){return null===a||a===p?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},oc:function(b,c){for(var d=[],e=(b||"").split(c),g=0,k=e.length;g<k;g++){var h=a.a.ta(e[g]);""!==h&&d.push(h)}return d},kc:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Sb:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===
|
||||
a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},Ea:function(b){return a.a.Sb(b,b.ownerDocument.documentElement)},eb:function(b){return!!a.a.hb(b,a.a.Ea)},B:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},q:function(b,c,d){var e=k&&g[c];if(!e&&t)t(b).bind(c,d);else if(e||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var h=function(a){d.call(b,a)},f="on"+c;b.attachEvent(f,
|
||||
h);a.a.u.ja(b,function(){b.detachEvent(f,h)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,d,!1)},ha:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.B(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(t&&!d)t(b).trigger(c);else if("function"==typeof w.createEvent)if("function"==typeof b.dispatchEvent)d=w.createEvent(h[c]||"HTMLEvents"),
|
||||
d.initEvent(c,!0,!0,A,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.v(b)?b():b},Sa:function(b){return a.v(b)?b.o():b},ua:function(b,c,d){if(c){var e=/\S+/g,g=b.className.match(e)||[];a.a.r(c.match(e),function(b){a.a.Y(g,b,d)});b.className=g.join(" ")}},Xa:function(b,
|
||||
c){var d=a.a.c(c);if(null===d||d===p)d="";var e=a.e.firstChild(b);!e||3!=e.nodeType||a.e.nextSibling(e)?a.e.U(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Vb(b)},Cb:function(a,b){a.name=b;if(7>=k)try{a.mergeAttributes(w.createElement("<input name='"+a.name+"'/>"),!1)}catch(c){}},Vb:function(a){9<=k&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Tb:function(a){if(k){var b=a.style.width;a.style.width=0;a.style.width=b}},ic:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=
|
||||
[],e=b;e<=c;e++)d.push(e);return d},R:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},mc:6===k,nc:7===k,oa:k,ob:function(b,c){for(var d=a.a.R(b.getElementsByTagName("input")).concat(a.a.R(b.getElementsByTagName("textarea"))),e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},g=[],k=d.length-1;0<=k;k--)e(d[k])&&g.push(d[k]);return g},fc:function(b){return"string"==typeof b&&(b=a.a.ta(b))?C&&C.parse?C.parse(b):(new Function("return "+b))():
|
||||
null},Ya:function(b,c,d){if(!C||!C.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return C.stringify(a.a.c(b),c,d)},gc:function(c,d,e){e=e||{};var g=e.params||{},k=e.includeFields||this.mb,h=c;if("object"==typeof c&&"form"===a.a.B(c))for(var h=c.action,f=k.length-1;0<=f;f--)for(var u=a.a.ob(c,k[f]),D=u.length-1;0<=D;D--)g[u[D].name]=
|
||||
u[D].value;d=a.a.c(d);var y=w.createElement("form");y.style.display="none";y.action=h;y.method="post";for(var p in d)c=w.createElement("input"),c.name=p,c.value=a.a.Ya(a.a.c(d[p])),y.appendChild(c);b(g,function(a,b){var c=w.createElement("input");c.name=a;c.value=b;y.appendChild(c)});w.body.appendChild(y);e.submitter?e.submitter(y):y.submit();setTimeout(function(){y.parentNode.removeChild(y)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.r);a.b("utils.arrayFirst",a.a.hb);a.b("utils.arrayFilter",
|
||||
a.a.la);a.b("utils.arrayGetDistinctValues",a.a.ib);a.b("utils.arrayIndexOf",a.a.l);a.b("utils.arrayMap",a.a.ya);a.b("utils.arrayPushAll",a.a.$);a.b("utils.arrayRemoveItem",a.a.ma);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.mb);a.b("utils.getFormFields",a.a.ob);a.b("utils.peekObservable",a.a.Sa);a.b("utils.postJson",a.a.gc);a.b("utils.parseJson",a.a.fc);a.b("utils.registerEventHandler",a.a.q);a.b("utils.stringifyJson",a.a.Ya);a.b("utils.range",a.a.ic);a.b("utils.toggleDomNodeCssClass",
|
||||
a.a.ua);a.b("utils.triggerEvent",a.a.ha);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.A);a.b("utils.addOrRemoveItem",a.a.Y);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){function a(b,h){var g=b[d];if(!g||"null"===g||!e[g]){if(!h)return p;g=b[d]="ko"+c++;e[g]={}}return e[g]}
|
||||
var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===p?p:e[d]},set:function(c,d,e){if(e!==p||a(c,!1)!==p)a(c,!0)[d]=e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},L:function(){return c++ +d}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.u=new function(){function b(b,c){var e=a.a.f.get(b,d);e===p&&c&&(e=[],a.a.f.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),k=0;k<e.length;k++)e[k](d);
|
||||
a.a.f.clear(d);a.a.u.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.f.L(),e={1:!0,8:!0,9:!0},f={1:!0,9:!0};return{ja:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},Ab:function(c,e){var k=b(c,!1);k&&(a.a.ma(k,e),0==k.length&&a.a.f.set(c,d,p))},M:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.$(d,b.getElementsByTagName("*"));for(var k=0,l=d.length;k<l;k++)c(d[k])}return b},
|
||||
removeNode:function(b){a.M(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){t&&"function"==typeof t.cleanData&&t.cleanData([a])}}};a.M=a.a.u.M;a.removeNode=a.a.u.removeNode;a.b("cleanNode",a.M);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.u);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.u.ja);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.u.Ab);(function(){a.a.Qa=function(b){var c;if(t)if(t.parseHTML)c=t.parseHTML(b)||[];else{if((c=t.clean([b]))&&
|
||||
c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.ta(b).toLowerCase();c=w.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof A.innerShiv?c.appendChild(A.innerShiv(b)):
|
||||
c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.R(c.lastChild.childNodes)}return c};a.a.Va=function(b,c){a.a.Fa(b);c=a.a.c(c);if(null!==c&&c!==p)if("string"!=typeof c&&(c=c.toString()),t)t(b).html(c);else for(var d=a.a.Qa(c),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.Qa);a.b("utils.setHtml",a.a.Va);a.w=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.w.xb(c.nodeValue);null!=f&&e.push({Rb:c,cc:f})}else if(1==c.nodeType)for(var f=0,h=c.childNodes,g=h.length;f<g;f++)b(h[f],
|
||||
e)}var c={};return{Na:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},Hb:function(a,b){var f=c[a];if(f===p)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),!0}finally{delete c[a]}},Ib:function(c,e){var f=
|
||||
[];b(c,f);for(var h=0,g=f.length;h<g;h++){var k=f[h].Rb,l=[k];e&&a.a.$(l,e);a.w.Hb(f[h].cc,l);k.nodeValue="";k.parentNode&&k.parentNode.removeChild(k)}},xb:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.w);a.b("memoization.memoize",a.w.Na);a.b("memoization.unmemoize",a.w.Hb);a.b("memoization.parseMemoText",a.w.xb);a.b("memoization.unmemoizeDomNodeAndDescendants",a.w.Ib);a.Ga={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.h({read:b,write:function(a){clearTimeout(d);
|
||||
d=setTimeout(function(){b(a)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);f="notifyWhenChangesStop"==e?O:N;a.Ma(function(a){return f(a,d)})},notify:function(a,c){a.equalityComparer="always"==c?null:G}};var M={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Ga);a.Fb=function(b,c,d){this.target=b;this.za=c;this.Qb=d;this.sb=!1;a.s(this,"dispose",this.F)};a.Fb.prototype.F=function(){this.sb=!0;this.Qb()};a.N=function(){a.a.sa(this,a.N.fn);this.H=
|
||||
{}};var F="change";z={V:function(b,c,d){var e=this;d=d||F;var f=new a.Fb(e,c?b.bind(c):b,function(){a.a.ma(e.H[d],f)});e.o&&e.o();e.H[d]||(e.H[d]=[]);e.H[d].push(f);return f},notifySubscribers:function(b,c){c=c||F;if(this.qb(c))try{a.k.jb();for(var d=this.H[c].slice(0),e=0,f;f=d[e];++e)f.sb||f.za(b)}finally{a.k.end()}},Ma:function(b){var c=this,d=a.v(c),e,f,h;c.ia||(c.ia=c.notifySubscribers,c.notifySubscribers=function(a,b){b&&b!==F?"beforeChange"===b?c.bb(a):c.ia(a,b):c.cb(a)});var g=b(function(){d&&
|
||||
h===c&&(h=c());e=!1;c.Ka(f,h)&&c.ia(f=h)});c.cb=function(a){e=!0;h=a;g()};c.bb=function(a){e||(f=a,c.ia(a,"beforeChange"))}},qb:function(a){return this.H[a]&&this.H[a].length},Wb:function(){var b=0;a.a.A(this.H,function(a,d){b+=d.length});return b},Ka:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.A(b,function(b,e){var f=a.Ga[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.s(z,"subscribe",z.V);a.s(z,"extend",z.extend);a.s(z,"getSubscriptionsCount",
|
||||
z.Wb);a.a.na&&a.a.ra(z,Function.prototype);a.N.fn=z;a.tb=function(a){return null!=a&&"function"==typeof a.V&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.N);a.b("isSubscribable",a.tb);a.ca=a.k=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{jb:b,end:c,zb:function(b){if(e){if(!a.tb(b))throw Error("Only subscribable things can act as dependencies");e.za(b,b.Kb||(b.Kb=++f))}},t:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},fa:function(){if(e)return e.ba.fa()},
|
||||
pa:function(){if(e)return e.pa}}}();a.b("computedContext",a.ca);a.b("computedContext.getDependenciesCount",a.ca.fa);a.b("computedContext.isInitial",a.ca.pa);a.m=function(b){function c(){if(0<arguments.length)return c.Ka(d,arguments[0])&&(c.P(),d=arguments[0],c.O()),this;a.k.zb(c);return d}var d=b;a.N.call(c);a.a.sa(c,a.m.fn);c.o=function(){return d};c.O=function(){c.notifySubscribers(d)};c.P=function(){c.notifySubscribers(d,"beforeChange")};a.s(c,"peek",c.o);a.s(c,"valueHasMutated",c.O);a.s(c,"valueWillMutate",
|
||||
c.P);return c};a.m.fn={equalityComparer:G};var E=a.m.hc="__ko_proto__";a.m.fn[E]=a.m;a.a.na&&a.a.ra(a.m.fn,a.N.fn);a.Ha=function(b,c){return null===b||b===p||b[E]===p?!1:b[E]===c?!0:a.Ha(b[E],c)};a.v=function(b){return a.Ha(b,a.m)};a.ub=function(b){return"function"==typeof b&&b[E]===a.m||"function"==typeof b&&b[E]===a.h&&b.Yb?!0:!1};a.b("observable",a.m);a.b("isObservable",a.v);a.b("isWriteableObservable",a.ub);a.T=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
|
||||
b=a.m(b);a.a.sa(b,a.T.fn);return b.extend({trackArrayChanges:!0})};a.T.fn={remove:function(b){for(var c=this.o(),d=[],e="function"!=typeof b||a.v(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var h=c[f];e(h)&&(0===d.length&&this.P(),d.push(h),c.splice(f,1),f--)}d.length&&this.O();return d},removeAll:function(b){if(b===p){var c=this.o(),d=c.slice(0);this.P();c.splice(0,c.length);this.O();return d}return b?this.remove(function(c){return 0<=a.a.l(b,c)}):[]},destroy:function(b){var c=this.o(),d=
|
||||
"function"!=typeof b||a.v(b)?function(a){return a===b}:b;this.P();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.O()},destroyAll:function(b){return b===p?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.l(b,c)}):[]},indexOf:function(b){var c=this();return a.a.l(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.P(),this.o()[d]=c,this.O())}};a.a.r("pop push reverse shift sort splice unshift".split(" "),function(b){a.T.fn[b]=function(){var a=this.o();
|
||||
this.P();this.kb(a,b,arguments);a=a[b].apply(a,arguments);this.O();return a}});a.a.r(["slice"],function(b){a.T.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.a.na&&a.a.ra(a.T.fn,a.m.fn);a.b("observableArray",a.T);var I="arrayChange";a.Ga.trackArrayChanges=function(b){function c(){if(!d){d=!0;var c=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==F||++f;return c.apply(this,arguments)};var k=[].concat(b.o()||[]);e=null;b.V(function(c){c=[].concat(c||[]);if(b.qb(I)){var d;
|
||||
if(!e||1<f)e=a.a.Aa(k,c,{sparse:!0});d=e;d.length&&b.notifySubscribers(d,I)}k=c;e=null;f=0})}}if(!b.kb){var d=!1,e=null,f=0,h=b.V;b.V=b.subscribe=function(a,b,d){d===I&&c();return h.apply(this,arguments)};b.kb=function(b,c,l){function h(a,b,c){return r[r.length]={status:a,value:b,index:c}}if(d&&!f){var r=[],m=b.length,q=l.length,s=0;switch(c){case "push":s=m;case "unshift":for(c=0;c<q;c++)h("added",l[c],s+c);break;case "pop":s=m-1;case "shift":m&&h("deleted",b[s],s);break;case "splice":c=Math.min(Math.max(0,
|
||||
0>l[0]?m+l[0]:l[0]),m);for(var m=1===q?m:Math.min(c+(l[1]||0),m),q=c+q-2,s=Math.max(m,q),B=[],u=[],D=2;c<s;++c,++D)c<m&&u.push(h("deleted",b[c],c)),c<q&&B.push(h("added",l[D],c));a.a.nb(u,B);break;default:return}e=r}}}};a.ba=a.h=function(b,c,d){function e(){q=!0;a.a.A(v,function(a,b){b.F()});v={};x=0;n=!1}function f(){var a=g.throttleEvaluation;a&&0<=a?(clearTimeout(t),t=setTimeout(h,a)):g.wa?g.wa():h()}function h(){if(!r&&!q){if(y&&y()){if(!m){p();return}}else m=!1;r=!0;try{var b=v,d=x;a.k.jb({za:function(a,
|
||||
c){q||(d&&b[c]?(v[c]=b[c],++x,delete b[c],--d):v[c]||(v[c]=a.V(f),++x))},ba:g,pa:!x});v={};x=0;try{var e=c?s.call(c):s()}finally{a.k.end(),d&&a.a.A(b,function(a,b){b.F()}),n=!1}g.Ka(l,e)&&(g.notifySubscribers(l,"beforeChange"),l=e,g.wa&&!g.throttleEvaluation||g.notifySubscribers(l))}finally{r=!1}x||p()}}function g(){if(0<arguments.length){if("function"===typeof B)B.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
|
||||
return this}n&&h();a.k.zb(g);return l}function k(){return n||0<x}var l,n=!0,r=!1,m=!1,q=!1,s=b;s&&"object"==typeof s?(d=s,s=d.read):(d=d||{},s||(s=d.read));if("function"!=typeof s)throw Error("Pass a function that returns the value of the ko.computed");var B=d.write,u=d.disposeWhenNodeIsRemoved||d.G||null,D=d.disposeWhen||d.Da,y=D,p=e,v={},x=0,t=null;c||(c=d.owner);a.N.call(g);a.a.sa(g,a.h.fn);g.o=function(){n&&!x&&h();return l};g.fa=function(){return x};g.Yb="function"===typeof d.write;g.F=function(){p()};
|
||||
g.ga=k;var w=g.Ma;g.Ma=function(a){w.call(g,a);g.wa=function(){g.bb(l);n=!0;g.cb(g)}};a.s(g,"peek",g.o);a.s(g,"dispose",g.F);a.s(g,"isActive",g.ga);a.s(g,"getDependenciesCount",g.fa);u&&(m=!0,u.nodeType&&(y=function(){return!a.a.Ea(u)||D&&D()}));!0!==d.deferEvaluation&&h();u&&k()&&u.nodeType&&(p=function(){a.a.u.Ab(u,p);e()},a.a.u.ja(u,p));return g};a.$b=function(b){return a.Ha(b,a.h)};z=a.m.hc;a.h[z]=a.m;a.h.fn={equalityComparer:G};a.h.fn[z]=a.h;a.a.na&&a.a.ra(a.h.fn,a.N.fn);a.b("dependentObservable",
|
||||
a.h);a.b("computed",a.h);a.b("isComputed",a.$b);(function(){function b(a,f,h){h=h||new d;a=f(a);if("object"!=typeof a||null===a||a===p||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var g=a instanceof Array?[]:{};h.save(a,g);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":g[c]=d;break;case "object":case "undefined":var n=h.get(d);g[c]=n!==p?n:b(d,f,h)}});return g}function c(a,b){if(a instanceof Array){for(var c=
|
||||
0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.ab=[]}a.Gb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.v(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.Gb(b);return a.a.Ya(b,c,d)};d.prototype={save:function(b,c){var d=a.a.l(this.keys,b);0<=d?this.ab[d]=c:(this.keys.push(b),this.ab.push(c))},get:function(b){b=a.a.l(this.keys,
|
||||
b);return 0<=b?this.ab[b]:p}}})();a.b("toJS",a.Gb);a.b("toJSON",a.toJSON);(function(){a.i={p:function(b){switch(a.a.B(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.Pa):7>=a.a.oa?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.i.p(b.options[b.selectedIndex]):p;default:return b.value}},X:function(b,c,d){switch(a.a.B(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.Pa,
|
||||
p);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.Pa,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||null===c)c=p;for(var e=-1,f=0,h=b.options.length,g;f<h;++f)if(g=a.i.p(b.options[f]),g==c||""==g&&c===p){e=f;break}if(d||0<=e||c===p&&1<b.size)b.selectedIndex=e;break;default:if(null===c||c===p)c="";b.value=c}}}})();a.b("selectExtensions",a.i);a.b("selectExtensions.readValue",
|
||||
a.i.p);a.b("selectExtensions.writeValue",a.i.X);a.g=function(){function b(b){b=a.a.ta(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),g,m,q=0;if(d){d.push(",");for(var s=0,B;B=d[s];++s){var u=B.charCodeAt(0);if(44===u){if(0>=q){g&&c.push(m?{key:g,value:m.join("")}:{unknown:g});g=m=q=0;continue}}else if(58===u){if(!m)continue}else if(47===u&&s&&1<B.length)(u=d[s-1].match(f))&&!h[u[0]]&&(b=b.substr(b.indexOf(B)+1),d=b.match(e),d.push(","),s=-1,B="/");else if(40===u||123===u||91===
|
||||
u)++q;else if(41===u||125===u||93===u)--q;else if(!g&&!m){g=34===u||39===u?B.slice(1,-1):B;continue}m?m.push(B):m=[B]}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,h={"in":1,"return":1,"typeof":1},g={};return{aa:[],W:g,Ra:b,qa:function(e,l){function f(b,e){var l,k=a.getBindingHandler(b);
|
||||
if(k&&k.preprocess?e=k.preprocess(e,b,f):1){if(k=g[b])l=e,0<=a.a.l(c,l)?l=!1:(k=l.match(d),l=null===k?!1:k[1]?"Object("+k[1]+")"+k[2]:l),k=l;k&&m.push("'"+b+"':function(_z){"+l+"=_z}");q&&(e="function(){return "+e+" }");h.push("'"+b+"':"+e)}}l=l||{};var h=[],m=[],q=l.valueAccessors,s="string"===typeof e?b(e):e;a.a.r(s,function(a){f(a.key||a.unknown,a.value)});m.length&&f("_ko_property_writers","{"+m.join(",")+" }");return h.join(",")},bc:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;
|
||||
return!1},va:function(b,c,d,e,g){if(b&&a.v(b))!a.ub(b)||g&&b.o()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.aa);a.b("expressionRewriting.parseObjectLiteral",a.g.Ra);a.b("expressionRewriting.preProcessBindings",a.g.qa);a.b("expressionRewriting._twoWayBindings",a.g.W);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.qa);(function(){function b(a){return 8==
|
||||
a.nodeType&&h.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,g=1,k=[];e=e.nextSibling;){if(c(e)&&(g--,0===g))return k;k.push(e);b(e)&&g++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=w&&"\x3c!--test--\x3e"===w.createComment("test").text,h=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,
|
||||
g=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,k={ul:!0,ol:!0};a.e={Q:{},childNodes:function(a){return b(a)?d(a):a.childNodes},da:function(c){if(b(c)){c=a.e.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.Fa(c)},U:function(c,d){if(b(c)){a.e.da(c);for(var e=c.nextSibling,g=0,k=d.length;g<k;g++)e.parentNode.insertBefore(d[g],e)}else a.a.U(c,d)},yb:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},rb:function(c,
|
||||
d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.e.yb(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Xb:b,lc:function(a){return(a=(f?a.text:a.nodeValue).match(h))?a[1]:null},wb:function(d){if(k[a.a.B(d)]){var g=d.firstChild;if(g){do if(1===g.nodeType){var f;f=g.firstChild;
|
||||
var h=null;if(f){do if(h)h.push(f);else if(b(f)){var q=e(f,!0);q?f=q:h=[f]}else c(f)&&(h=[f]);while(f=f.nextSibling)}if(f=h)for(h=g.nextSibling,q=0;q<f.length;q++)h?d.insertBefore(f[q],h):d.appendChild(f[q])}while(g=g.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.Q);a.b("virtualElements.emptyNode",a.e.da);a.b("virtualElements.insertAfter",a.e.rb);a.b("virtualElements.prepend",a.e.yb);a.b("virtualElements.setDomNodeChildren",a.e.U);(function(){a.J=function(){this.Nb=
|
||||
{}};a.a.extend(a.J.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind");case 8:return a.e.Xb(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingAccessors:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a,{valueAccessors:!0}):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");
|
||||
case 8:return a.e.lc(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Nb,h=b+(e&&e.valueAccessors||""),g;if(!(g=f[h])){var k,l="with($context){with($data||{}){return{"+a.g.qa(b,e)+"}}}";k=new Function("$context","$element",l);g=f[h]=k}return g(c,d)}catch(n){throw n.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+n.message,n;}}});a.J.instance=new a.J})();a.b("bindingProvider",a.J);(function(){function b(a){return function(){return a}}function c(a){return a()}
|
||||
function d(b){return a.a.Oa(a.k.t(b),function(a,c){return function(){return b()[c]}})}function e(a,b){return d(this.getBindings.bind(this,a,b))}function f(b,c,d){var e,g=a.e.firstChild(c),k=a.J.instance,f=k.preprocessNode;if(f){for(;e=g;)g=a.e.nextSibling(e),f.call(k,e);g=a.e.firstChild(c)}for(;e=g;)g=a.e.nextSibling(e),h(b,e,d)}function h(b,c,d){var e=!0,g=1===c.nodeType;g&&a.e.wb(c);if(g&&d||a.J.instance.nodeHasBindings(c))e=k(c,null,b,d).shouldBindDescendants;e&&!n[a.a.B(c)]&&f(b,c,!g)}function g(b){var c=
|
||||
[],d={},e=[];a.a.A(b,function y(g){if(!d[g]){var k=a.getBindingHandler(g);k&&(k.after&&(e.push(g),a.a.r(k.after,function(c){if(b[c]){if(-1!==a.a.l(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));y(c)}}),e.length--),c.push({key:g,pb:k}));d[g]=!0}});return c}function k(b,d,k,f){var h=a.a.f.get(b,r);if(!d){if(h)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,r,!0)}!h&&f&&a.Eb(b,k);var l;if(d&&"function"!==
|
||||
typeof d)l=d;else{var n=a.J.instance,m=n.getBindingAccessors||e,x=a.h(function(){(l=d?d(k,b):m.call(n,b,k))&&k.D&&k.D();return l},null,{G:b});l&&x.ga()||(x=null)}var t;if(l){var w=x?function(a){return function(){return c(x()[a])}}:function(a){return l[a]},z=function(){return a.a.Oa(x?x():l,c)};z.get=function(a){return l[a]&&c(w(a))};z.has=function(a){return a in l};f=g(l);a.a.r(f,function(c){var d=c.pb.init,e=c.pb.update,g=c.key;if(8===b.nodeType&&!a.e.Q[g])throw Error("The binding '"+g+"' cannot be used with virtual elements");
|
||||
try{"function"==typeof d&&a.k.t(function(){var a=d(b,w(g),z,k.$data,k);if(a&&a.controlsDescendantBindings){if(t!==p)throw Error("Multiple bindings ("+t+" and "+g+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");t=g}}),"function"==typeof e&&a.h(function(){e(b,w(g),z,k.$data,k)},null,{G:b})}catch(f){throw f.message='Unable to process binding "'+g+": "+l[g]+'"\nMessage: '+f.message,f;}})}return{shouldBindDescendants:t===p}}
|
||||
function l(b){return b&&b instanceof a.I?b:new a.I(b)}a.d={};var n={script:!0};a.getBindingHandler=function(b){return a.d[b]};a.I=function(b,c,d,e){var g=this,k="function"==typeof b&&!a.v(b),f,h=a.h(function(){var f=k?b():b,l=a.a.c(f);c?(c.D&&c.D(),a.a.extend(g,c),h&&(g.D=h)):(g.$parents=[],g.$root=l,g.ko=a);g.$rawData=f;g.$data=l;d&&(g[d]=l);e&&e(g,c,l);return g.$data},null,{Da:function(){return f&&!a.a.eb(f)},G:!0});h.ga()&&(g.D=h,h.equalityComparer=null,f=[],h.Jb=function(b){f.push(b);a.a.u.ja(b,
|
||||
function(b){a.a.ma(f,b);f.length||(h.F(),g.D=h=p)})})};a.I.prototype.createChildContext=function(b,c,d){return new a.I(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.I.prototype.extend=function(b){return new a.I(this.D||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};var r=a.a.f.L(),m=a.a.f.L();a.Eb=function(b,c){if(2==arguments.length)a.a.f.set(b,m,c),
|
||||
c.D&&c.D.Jb(b);else return a.a.f.get(b,m)};a.xa=function(b,c,d){1===b.nodeType&&a.e.wb(b);return k(b,c,l(d),!0)};a.Lb=function(c,e,g){g=l(g);return a.xa(c,"function"===typeof e?d(e.bind(null,g,c)):a.a.Oa(e,b),g)};a.gb=function(a,b){1!==b.nodeType&&8!==b.nodeType||f(l(a),b,!0)};a.fb=function(a,b){!t&&A.jQuery&&(t=A.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||A.document.body;h(l(a),
|
||||
b,!0)};a.Ca=function(b){switch(b.nodeType){case 1:case 8:var c=a.Eb(b);if(c)return c;if(b.parentNode)return a.Ca(b.parentNode)}return p};a.Pb=function(b){return(b=a.Ca(b))?b.$data:p};a.b("bindingHandlers",a.d);a.b("applyBindings",a.fb);a.b("applyBindingsToDescendants",a.gb);a.b("applyBindingAccessorsToNode",a.xa);a.b("applyBindingsToNode",a.Lb);a.b("contextFor",a.Ca);a.b("dataFor",a.Pb)})();var L={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.A(d,function(c,
|
||||
d){d=a.a.c(d);var h=!1===d||null===d||d===p;h&&b.removeAttribute(c);8>=a.a.oa&&c in L?(c=L[c],h?b.removeAttribute(c):b[c]=d):h||b.setAttribute(c,d.toString());"name"===c&&a.a.Cb(b,h?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):b.value}function f(){var g=b.checked,f=r?e():g;if(!a.ca.pa()&&(!k||g)){var h=a.k.t(c);l?n!==f?(g&&(a.a.Y(h,f,!0),a.a.Y(h,n,!1)),n=f):a.a.Y(h,f,g):a.g.va(h,d,"checked",
|
||||
f,!0)}}function h(){var d=a.a.c(c());b.checked=l?0<=a.a.l(d,e()):g?d:e()===d}var g="checkbox"==b.type,k="radio"==b.type;if(g||k){var l=g&&a.a.c(c())instanceof Array,n=l?e():p,r=k||l;k&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.ba(f,null,{G:b});a.a.q(b,"click",f);a.ba(h,null,{G:b})}}};a.g.W.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.A(d,function(c,d){d=a.a.c(d);a.a.ua(b,c,d)}):(d=String(d||
|
||||
""),a.a.ua(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.ua(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var h=c()||{};a.a.A(h,function(g){"string"==typeof g&&a.a.q(b,g,function(b){var h,n=c()[g];if(n){try{var r=a.a.R(arguments);e=f.$data;r.unshift(e);h=n.apply(e,r)}finally{!0!==h&&(b.preventDefault?
|
||||
b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={vb:function(b){return function(){var c=b(),d=a.a.Sa(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.K.Ja};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.K.Ja}}},init:function(b,
|
||||
c){return a.d.template.init(b,a.d.foreach.vb(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.vb(c),d,e,f)}};a.g.aa.foreach=!1;a.e.Q.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var k=b.ownerDocument;if("activeElement"in k){var f;try{f=k.activeElement}catch(h){f=k.body}e=f===b}k=c();a.g.va(k,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),h=e.bind(null,!1);a.a.q(b,"focus",f);a.a.q(b,"focusin",
|
||||
f);a.a.q(b,"blur",h);a.a.q(b,"focusout",h)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.k.t(a.a.ha,null,[b,d?"focusin":"focusout"]))}};a.g.W.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.g.W.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Va(b,c())}};H("if");H("ifnot",!1,!0);H("with",!0,!1,function(a,c){return a.createChildContext(c)});var J={};a.d.options={init:function(b){if("select"!==
|
||||
a.a.B(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.la(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function h(c,d){if(r.length){var e=0<=a.a.l(r,a.i.p(d[0]));a.a.Db(d[0],e);m&&!e&&a.k.t(a.a.ha,null,[b,"change"])}}var g=0!=b.length&&b.multiple?b.scrollTop:null,k=a.a.c(c()),l=d.get("optionsIncludeDestroyed");
|
||||
c={};var n,r;r=b.multiple?a.a.ya(e(),a.i.p):0<=b.selectedIndex?[a.i.p(b.options[b.selectedIndex])]:[];k&&("undefined"==typeof k.length&&(k=[k]),n=a.a.la(k,function(b){return l||b===p||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(k=a.a.c(d.get("optionsCaption")),null!==k&&k!==p&&n.unshift(J)));var m=!1;c.beforeRemove=function(a){b.removeChild(a)};k=h;d.has("optionsAfterRender")&&(k=function(b,c){h(0,c);a.k.t(d.get("optionsAfterRender"),null,[c[0],b!==J?b:p])});a.a.Ua(b,n,function(c,e,g){g.length&&
|
||||
(r=g[0].selected?[a.i.p(g[0])]:[],m=!0);e=b.ownerDocument.createElement("option");c===J?(a.a.Xa(e,d.get("optionsCaption")),a.i.X(e,p)):(g=f(c,d.get("optionsValue"),c),a.i.X(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.Xa(e,c));return[e]},c,k);a.k.t(function(){d.get("valueAllowUnset")&&d.has("value")?a.i.X(b,a.a.c(d.get("value")),!0):(b.multiple?r.length&&e().length<r.length:r.length&&0<=b.selectedIndex?a.i.p(b.options[b.selectedIndex])!==r[0]:r.length||0<=b.selectedIndex)&&a.a.ha(b,"change")});a.a.Tb(b);
|
||||
g&&20<Math.abs(g-b.scrollTop)&&(b.scrollTop=g)}};a.d.options.Pa=a.a.f.L();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.q(b,"change",function(){var e=c(),f=[];a.a.r(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.i.p(b))});a.g.va(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=a.a.B(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.r(b.getElementsByTagName("option"),function(b){var c=
|
||||
0<=a.a.l(d,a.i.p(b));a.a.Db(b,c)})}};a.g.W.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.A(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.q(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},
|
||||
update:function(b,c){a.a.Xa(b,c())}};a.e.Q.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Ob;a.a.Cb(b,d)}}};a.d.uniqueName.Ob=0;a.d.value={after:["options","foreach"],init:function(b,c,d){function e(){g=!1;var e=c(),f=a.i.p(b);a.g.va(e,d,"value",f)}var f=["change"],h=d.get("valueUpdate"),g=!1;h&&("string"==typeof h&&(h=[h]),a.a.$(f,h),f=a.a.ib(f));!a.a.oa||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||
|
||||
-1!=a.a.l(f,"propertychange")||(a.a.q(b,"propertychange",function(){g=!0}),a.a.q(b,"focus",function(){g=!1}),a.a.q(b,"blur",function(){g&&e()}));a.a.r(f,function(c){var d=e;a.a.kc(c,"after")&&(d=function(){setTimeout(e,0)},c=c.substring(5));a.a.q(b,c,d)})},update:function(b,c,d){var e=a.a.c(c());c=a.i.p(b);if(e!==c)if("select"===a.a.B(b)){var f=d.get("valueAllowUnset");d=function(){a.i.X(b,e,f)};d();f||e===a.i.p(b)?setTimeout(d,0):a.k.t(a.a.ha,null,[b,"change"])}else a.i.X(b,e)}};a.g.W.value=!0;a.d.visible=
|
||||
{update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,h){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,h)}}})("click");a.C=function(){};a.C.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.C.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.C.prototype.makeTemplateSource=
|
||||
function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.n.j(d)}if(1==b.nodeType||8==b.nodeType)return new a.n.Z(b);throw Error("Unknown template type: "+b);};a.C.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d)};a.C.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.C.prototype.rewriteTemplate=
|
||||
function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.C);a.Za=function(){function b(b,c,d,g){b=a.g.Ra(b);for(var k=a.g.aa,l=0;l<b.length;l++){var n=b[l].key;if(k.hasOwnProperty(n)){var r=k[n];if("function"===typeof r){if(n=r(b[l].value))throw Error(n);}else if(!r)throw Error("This template engine does not support the '"+n+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.qa(b,
|
||||
{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return g.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ub:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Za.dc(b,c)},d)},dc:function(a,f){return a.replace(c,function(a,c,d,e,n){return b(n,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e",
|
||||
"#comment",f)})},Mb:function(b,c){return a.w.Na(function(d,g){var k=d.nextSibling;k&&k.nodeName.toLowerCase()===c&&a.xa(k,b,g)})}}}();a.b("__tr_ambtns",a.Za.Mb);(function(){a.n={};a.n.j=function(a){this.j=a};a.n.j.prototype.text=function(){var b=a.a.B(this.j),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.j[b];var c=arguments[0];"innerHTML"===b?a.a.Va(this.j,c):this.j[b]=c};var b=a.a.f.L()+"_";a.n.j.prototype.data=function(c){if(1===arguments.length)return a.a.f.get(this.j,
|
||||
b+c);a.a.f.set(this.j,b+c,arguments[1])};var c=a.a.f.L();a.n.Z=function(a){this.j=a};a.n.Z.prototype=new a.n.j;a.n.Z.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.j,c)||{};b.$a===p&&b.Ba&&(b.$a=b.Ba.innerHTML);return b.$a}a.a.f.set(this.j,c,{$a:arguments[0]})};a.n.j.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.j,c)||{}).Ba;a.a.f.set(this.j,c,{Ba:arguments[0]})};a.b("templateSources",a.n);a.b("templateSources.domElement",a.n.j);a.b("templateSources.anonymousTemplate",
|
||||
a.n.Z)})();(function(){function b(b,c,d){var e;for(c=a.e.nextSibling(c);b&&(e=b)!==c;)b=a.e.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],h=e.parentNode,m=a.J.instance,q=m.preprocessNode;if(q){b(e,f,function(a,b){var c=a.previousSibling,d=q.call(m,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.ea(c,h))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.fb(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==
|
||||
b.nodeType||a.w.Ib(b,[d])});a.a.ea(c,h)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,h,n,r){r=r||{};var m=b&&d(b),m=m&&m.ownerDocument,q=r.templateEngine||f;a.Za.Ub(h,q,m);h=q.renderTemplate(h,n,r,m);if("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)throw Error("Template engine must return an array of DOM nodes");m=!1;switch(e){case "replaceChildren":a.e.U(b,h);m=!0;break;case "replaceNode":a.a.Bb(b,h);m=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+
|
||||
e);}m&&(c(h,n),r.afterRender&&a.k.t(r.afterRender,null,[h,n.$data]));return h}var f;a.Wa=function(b){if(b!=p&&!(b instanceof a.C))throw Error("templateEngine must inherit from ko.templateEngine");f=b};a.Ta=function(b,c,h,n,r){h=h||{};if((h.templateEngine||f)==p)throw Error("Set a template engine before calling renderTemplate");r=r||"replaceChildren";if(n){var m=d(n);return a.h(function(){var f=c&&c instanceof a.I?c:new a.I(a.a.c(c)),p=a.v(b)?b():"function"==typeof b?b(f.$data,f):b,f=e(n,r,p,f,h);
|
||||
"replaceNode"==r&&(n=f,m=d(n))},null,{Da:function(){return!m||!a.a.Ea(m)},G:m&&"replaceNode"==r?m.parentNode:m})}return a.w.Na(function(d){a.Ta(b,c,h,d,"replaceNode")})};a.jc=function(b,d,f,h,r){function m(a,b){c(b,s);f.afterRender&&f.afterRender(b,a)}function q(a,c){s=r.createChildContext(a,f.as,function(a){a.$index=c});var d="function"==typeof b?b(a,s):b;return e(null,"ignoreTargetNode",d,s,f)}var s;return a.h(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.la(b,function(b){return f.includeDestroyed||
|
||||
b===p||null===b||!a.a.c(b._destroy)});a.k.t(a.a.Ua,null,[h,b,q,f,m])},null,{G:h})};var h=a.a.f.L();a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||d.name?a.e.da(b):(d=a.e.childNodes(b),d=a.a.ec(d),(new a.n.Z(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var m=c(),q;c=a.a.c(m);d=!0;e=null;"string"==typeof c?c={}:(m=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in c&&(d=!a.a.c(c.ifnot)),q=a.a.c(c.data));"foreach"in c?e=a.jc(m||b,d&&c.foreach||
|
||||
[],c,b,f):d?(f="data"in c?f.createChildContext(q,c.as):f,e=a.Ta(m||b,f,c,b)):a.e.da(b);f=e;(q=a.a.f.get(b,h))&&"function"==typeof q.F&&q.F();a.a.f.set(b,h,f&&f.ga()?f:p)}};a.g.aa.template=function(b){b=a.g.Ra(b);return 1==b.length&&b[0].unknown||a.g.bc(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.e.Q.template=!0})();a.b("setTemplateEngine",a.Wa);a.b("renderTemplate",a.Ta);a.a.nb=function(a,c,d){if(a.length&&c.length){var e,f,h,g,k;for(e=
|
||||
f=0;(!d||e<d)&&(g=a[f]);++f){for(h=0;k=c[h];++h)if(g.value===k.value){g.moved=k.index;k.moved=g.index;c.splice(h,1);e=h=0;break}e+=h}}};a.a.Aa=function(){function b(b,d,e,f,h){var g=Math.min,k=Math.max,l=[],n,p=b.length,m,q=d.length,s=q-p||1,t=p+q+1,u,w,y;for(n=0;n<=p;n++)for(w=u,l.push(u=[]),y=g(q,n+s),m=k(0,n-1);m<=y;m++)u[m]=m?n?b[n-1]===d[m-1]?w[m-1]:g(w[m]||t,u[m-1]||t)+1:m+1:n+1;g=[];k=[];s=[];n=p;for(m=q;n||m;)q=l[n][m]-1,m&&q===l[n][m-1]?k.push(g[g.length]={status:e,value:d[--m],index:m}):
|
||||
n&&q===l[n-1][m]?s.push(g[g.length]={status:f,value:b[--n],index:n}):(--m,--n,h.sparse||g.push({status:"retained",value:d[m]}));a.a.nb(k,s,10*p);return g.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<=d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.Aa);(function(){function b(b,c,f,h,g){var k=[],l=a.h(function(){var l=c(f,g,a.a.ea(k,b))||[];0<k.length&&(a.a.Bb(k,l),h&&a.k.t(h,null,[f,
|
||||
l,g]));k.length=0;a.a.$(k,l)},null,{G:b,Da:function(){return!a.a.eb(k)}});return{S:k,h:l.ga()?l:p}}var c=a.a.f.L();a.a.Ua=function(d,e,f,h,g){function k(b,c){v=r[c];u!==c&&(z[b]=v);v.Ia(u++);a.a.ea(v.S,d);s.push(v);y.push(v)}function l(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.r(c[d].S,function(a){b(a,d,c[d].ka)})}e=e||[];h=h||{};var n=a.a.f.get(d,c)===p,r=a.a.f.get(d,c)||[],m=a.a.ya(r,function(a){return a.ka}),q=a.a.Aa(m,e,h.dontLimitMoves),s=[],t=0,u=0,w=[],y=[];e=[];for(var z=[],m=[],
|
||||
v,x=0,A,C;A=q[x];x++)switch(C=A.moved,A.status){case "deleted":C===p&&(v=r[t],v.h&&v.h.F(),w.push.apply(w,a.a.ea(v.S,d)),h.beforeRemove&&(e[x]=v,y.push(v)));t++;break;case "retained":k(x,t++);break;case "added":C!==p?k(x,C):(v={ka:A.value,Ia:a.m(u++)},s.push(v),y.push(v),n||(m[x]=v))}l(h.beforeMove,z);a.a.r(w,h.beforeRemove?a.M:a.removeNode);for(var x=0,n=a.e.firstChild(d),E;v=y[x];x++){v.S||a.a.extend(v,b(d,f,v.ka,g,v.Ia));for(t=0;q=v.S[t];n=q.nextSibling,E=q,t++)q!==n&&a.e.rb(d,q,E);!v.Zb&&g&&(g(v.ka,
|
||||
v.S,v.Ia),v.Zb=!0)}l(h.beforeRemove,e);l(h.afterMove,z);l(h.afterAdd,m);a.a.f.set(d,c,s)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Ua);a.K=function(){this.allowTemplateRewriting=!1};a.K.prototype=new a.C;a.K.prototype.renderTemplateSource=function(b){var c=(9>a.a.oa?0:b.nodes)?b.nodes():null;if(c)return a.a.R(c.cloneNode(!0).childNodes);b=b.text();return a.a.Qa(b)};a.K.Ja=new a.K;a.Wa(a.K.Ja);a.b("nativeTemplateEngine",a.K);(function(){a.La=function(){var a=this.ac=function(){if(!t||
|
||||
!t.tmpl)return 0;try{if(0<=t.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f){f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=t.template(null,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=t.extend({koBindingContext:e},f.templateOptions);e=t.tmpl(h,b,e);e.appendTo(w.createElement("div"));
|
||||
t.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(t.tmpl.tag.ko_code={open:"__.push($1 || '');"},t.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.La.prototype=new a.C;var b=new a.La;0<b.ac&&a.Wa(b);a.b("jqueryTmplTemplateEngine",a.La)})()})})();})();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bundle minify="true" runOnBuild="true">
|
||||
<file>/ClientSource/Scripts/Modules/Knockout/knockout-2.3.0.js</file>
|
||||
<file>/ClientSource/Scripts/Modules/Knockout/knockout-3.1.0.js</file>
|
||||
</bundle>
|
||||
+4
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,88 +0,0 @@
|
||||
// Knockout JavaScript library v2.3.0
|
||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
(function() {function F(q){return function(){return q}};(function(q){var w=this||(0,eval)("this"),s=w.document,H=w.navigator,t=w.jQuery,y=w.JSON;(function(q){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?q(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],q):q(w.ko={})})(function(C){function G(b,c,d,f){a.d[b]={init:function(b){a.a.f.set(b,I,{});return{controlsDescendantBindings:!0}},update:function(b,e,m,h,k){m=a.a.f.get(b,I);e=a.a.c(e());h=!d!==!e;var l=!m.fb;if(l||c||h!==m.vb)l&&(m.fb=
|
||||
a.a.Oa(a.e.childNodes(b),!0)),h?(l||a.e.P(b,a.a.Oa(m.fb)),a.Ja(f?f(k,e):k,b)):a.e.ba(b),m.vb=h}};a.g.S[b]=!1;a.e.L[b]=!0}function J(b,c,d){d&&c!==a.h.n(b)&&a.h.W(b,c);c!==a.h.n(b)&&a.q.I(a.a.Ga,null,[b,"change"])}var a="undefined"!==typeof C?C:{};a.b=function(b,c){for(var d=b.split("."),f=a,g=0;g<d.length-1;g++)f=f[d[g]];f[d[d.length-1]]=c};a.r=function(a,c,d){a[c]=d};a.version="2.3.0";a.b("version",a.version);a.a=function(){function b(a,b){for(var e in a)a.hasOwnProperty(e)&&b(e,a[e])}function c(b,
|
||||
e){if("input"!==a.a.u(b)||!b.type||"click"!=e.toLowerCase())return!1;var k=b.type;return"checkbox"==k||"radio"==k}var d={},f={};d[H&&/Firefox\/2/i.test(H.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(d,function(a,b){if(b.length)for(var e=0,c=b.length;e<c;e++)f[b[e]]=a});var g={propertychange:!0},e=s&&function(){for(var a=3,b=s.createElement("div"),e=b.getElementsByTagName("i");b.innerHTML=
|
||||
"\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",e[0];);return 4<a?a:q}();return{Ta:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],p:function(a,b){for(var e=0,c=a.length;e<c;e++)b(a[e])},k:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var e=0,c=a.length;e<c;e++)if(a[e]===b)return e;return-1},La:function(a,b,e){for(var c=0,d=a.length;c<d;c++)if(b.call(e,a[c]))return a[c];return null},ka:function(b,e){var c=a.a.k(b,e);0<=c&&
|
||||
b.splice(c,1)},Ma:function(b){b=b||[];for(var e=[],c=0,d=b.length;c<d;c++)0>a.a.k(e,b[c])&&e.push(b[c]);return e},Z:function(a,b){a=a||[];for(var e=[],c=0,d=a.length;c<d;c++)e.push(b(a[c]));return e},Y:function(a,b){a=a||[];for(var e=[],c=0,d=a.length;c<d;c++)b(a[c])&&e.push(a[c]);return e},R:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var e=0,c=b.length;e<c;e++)a.push(b[e]);return a},ja:function(b,e,c){var d=b.indexOf?b.indexOf(e):a.a.k(b,e);0>d?c&&b.push(e):c||b.splice(d,1)},
|
||||
extend:function(a,b){if(b)for(var e in b)b.hasOwnProperty(e)&&(a[e]=b[e]);return a},w:b,oa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Mb:function(b){b=a.a.N(b);for(var e=s.createElement("div"),c=0,d=b.length;c<d;c++)e.appendChild(a.H(b[c]));return e},Oa:function(b,e){for(var c=0,d=b.length,g=[];c<d;c++){var f=b[c].cloneNode(!0);g.push(e?a.H(f):f)}return g},P:function(b,e){a.a.oa(b);if(e)for(var c=0,d=e.length;c<d;c++)b.appendChild(e[c])},eb:function(b,e){var c=b.nodeType?[b]:b;if(0<
|
||||
c.length){for(var d=c[0],g=d.parentNode,f=0,r=e.length;f<r;f++)g.insertBefore(e[f],d);f=0;for(r=c.length;f<r;f++)a.removeNode(c[f])}},hb:function(a,b){7>e?a.setAttribute("selected",b):a.selected=b},F:function(a){return null===a||a===q?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},Wb:function(b,e){for(var c=[],d=(b||"").split(e),g=0,f=d.length;g<f;g++){var r=a.a.F(d[g]);""!==r&&c.push(r)}return c},Tb:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===
|
||||
b},yb:function(a,b){if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;null!=a;){if(a==b)return!0;a=a.parentNode}return!1},aa:function(b){return a.a.yb(b,b.ownerDocument)},pb:function(b){return!!a.a.La(b,a.a.aa)},u:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},o:function(b,d,k){var f=e&&g[d];if(f||"undefined"==typeof t)if(f||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var n=function(a){k.call(b,a)},p="on"+d;b.attachEvent(p,n);
|
||||
a.a.C.ia(b,function(){b.detachEvent(p,n)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(d,k,!1);else{if(c(b,d)){var r=k;k=function(a,b){var e=this.checked;b&&(this.checked=!0!==b.sb);r.call(this,a);this.checked=e}}t(b).bind(d,k)}},Ga:function(a,b){if(!a||!a.nodeType)throw Error("element must be a DOM node when calling triggerEvent");if("undefined"!=typeof t){var e=[];c(a,b)&&e.push({sb:a.checked});t(a).trigger(b,e)}else if("function"==typeof s.createEvent)if("function"==
|
||||
typeof a.dispatchEvent)e=s.createEvent(f[b]||"HTMLEvents"),e.initEvent(b,!0,!0,w,0,0,0,0,0,!1,!1,!1,!1,0,a),a.dispatchEvent(e);else throw Error("The supplied element doesn't support dispatchEvent");else if("undefined"!=typeof a.fireEvent)c(a,b)&&(a.checked=!0!==a.checked),a.fireEvent("on"+b);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.T(b)?b():b},ya:function(b){return a.T(b)?b.t():b},ga:function(b,e,c){if(e){var d=/\S+/g,g=b.className.match(d)||[];a.a.p(e.match(d),
|
||||
function(b){a.a.ja(g,b,c)});b.className=g.join(" ")}},ib:function(b,e){var c=a.a.c(e);if(null===c||c===q)c="";var d=a.e.firstChild(b);!d||3!=d.nodeType||a.e.nextSibling(d)?a.e.P(b,[s.createTextNode(c)]):d.data=c;a.a.Bb(b)},gb:function(a,b){a.name=b;if(7>=e)try{a.mergeAttributes(s.createElement("<input name='"+a.name+"'/>"),!1)}catch(c){}},Bb:function(a){9<=e&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},zb:function(a){if(e){var b=a.style.width;a.style.width=0;a.style.width=
|
||||
b}},Qb:function(b,e){b=a.a.c(b);e=a.a.c(e);for(var c=[],d=b;d<=e;d++)c.push(d);return c},N:function(a){for(var b=[],e=0,c=a.length;e<c;e++)b.push(a[e]);return b},Ub:6===e,Vb:7===e,ca:e,Ua:function(b,e){for(var c=a.a.N(b.getElementsByTagName("input")).concat(a.a.N(b.getElementsByTagName("textarea"))),d="string"==typeof e?function(a){return a.name===e}:function(a){return e.test(a.name)},g=[],f=c.length-1;0<=f;f--)d(c[f])&&g.push(c[f]);return g},Nb:function(b){return"string"==typeof b&&(b=a.a.F(b))?
|
||||
y&&y.parse?y.parse(b):(new Function("return "+b))():null},Ca:function(b,e,c){if(!y||!y.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return y.stringify(a.a.c(b),e,c)},Ob:function(e,c,d){d=d||{};var g=d.params||{},f=d.includeFields||this.Ta,p=e;if("object"==typeof e&&"form"===a.a.u(e))for(var p=e.action,r=f.length-1;0<=r;r--)for(var z=
|
||||
a.a.Ua(e,f[r]),D=z.length-1;0<=D;D--)g[z[D].name]=z[D].value;c=a.a.c(c);var q=s.createElement("form");q.style.display="none";q.action=p;q.method="post";for(var v in c)e=s.createElement("input"),e.name=v,e.value=a.a.Ca(a.a.c(c[v])),q.appendChild(e);b(g,function(a,b){var e=s.createElement("input");e.name=a;e.value=b;q.appendChild(e)});s.body.appendChild(q);d.submitter?d.submitter(q):q.submit();setTimeout(function(){q.parentNode.removeChild(q)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.p);
|
||||
a.b("utils.arrayFirst",a.a.La);a.b("utils.arrayFilter",a.a.Y);a.b("utils.arrayGetDistinctValues",a.a.Ma);a.b("utils.arrayIndexOf",a.a.k);a.b("utils.arrayMap",a.a.Z);a.b("utils.arrayPushAll",a.a.R);a.b("utils.arrayRemoveItem",a.a.ka);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.Ta);a.b("utils.getFormFields",a.a.Ua);a.b("utils.peekObservable",a.a.ya);a.b("utils.postJson",a.a.Ob);a.b("utils.parseJson",a.a.Nb);a.b("utils.registerEventHandler",a.a.o);a.b("utils.stringifyJson",
|
||||
a.a.Ca);a.b("utils.range",a.a.Qb);a.b("utils.toggleDomNodeCssClass",a.a.ga);a.b("utils.triggerEvent",a.a.Ga);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.w);a.b("utils.addOrRemoveItem",a.a.ja);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){var b=0,c="__ko__"+(new Date).getTime(),
|
||||
d={};return{get:function(b,c){var e=a.a.f.pa(b,!1);return e===q?q:e[c]},set:function(b,c,e){if(e!==q||a.a.f.pa(b,!1)!==q)a.a.f.pa(b,!0)[c]=e},pa:function(a,g){var e=a[c];if(!e||"null"===e||!d[e]){if(!g)return q;e=a[c]="ko"+b++;d[e]={}}return d[e]},clear:function(a){var b=a[c];return b?(delete d[b],a[c]=null,!0):!1}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.C=new function(){function b(b,c){var g=a.a.f.get(b,d);g===q&&c&&(g=[],a.a.f.set(b,d,g));return g}function c(e){var d=
|
||||
b(e,!1);if(d)for(var d=d.slice(0),f=0;f<d.length;f++)d[f](e);a.a.f.clear(e);"function"==typeof t&&"function"==typeof t.cleanData&&t.cleanData([e]);if(g[e.nodeType])for(d=e.firstChild;e=d;)d=e.nextSibling,8===e.nodeType&&c(e)}var d="__ko_domNodeDisposal__"+(new Date).getTime(),f={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{ia:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},cb:function(e,c){var g=b(e,!1);g&&(a.a.ka(g,c),0==g.length&&a.a.f.set(e,d,q))},H:function(b){if(f[b.nodeType]&&
|
||||
(c(b),g[b.nodeType])){var d=[];a.a.R(d,b.getElementsByTagName("*"));for(var h=0,k=d.length;h<k;h++)c(d[h])}return b},removeNode:function(b){a.H(b);b.parentNode&&b.parentNode.removeChild(b)}}};a.H=a.a.C.H;a.removeNode=a.a.C.removeNode;a.b("cleanNode",a.H);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.C);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.C.ia);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.C.cb);(function(){a.a.xa=function(b){var c;if("undefined"!=typeof t)if(t.parseHTML)c=
|
||||
t.parseHTML(b)||[];else{if((c=t.clean([b]))&&c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.F(b).toLowerCase();c=s.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof w.innerShiv?
|
||||
c.appendChild(w.innerShiv(b)):c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.N(c.lastChild.childNodes)}return c};a.a.fa=function(b,c){a.a.oa(b);c=a.a.c(c);if(null!==c&&c!==q)if("string"!=typeof c&&(c=c.toString()),"undefined"!=typeof t)t(b).html(c);else for(var d=a.a.xa(c),f=0;f<d.length;f++)b.appendChild(d[f])}})();a.b("utils.parseHtmlFragment",a.a.xa);a.b("utils.setHtml",a.a.fa);a.s=function(){function b(c,f){if(c)if(8==c.nodeType){var g=a.s.$a(c.nodeValue);null!=g&&f.push({xb:c,Kb:g})}else if(1==c.nodeType)for(var g=
|
||||
0,e=c.childNodes,m=e.length;g<m;g++)b(e[g],f)}var c={};return{va:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},mb:function(a,b){var g=c[a];if(g===q)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return g.apply(null,b||[]),
|
||||
!0}finally{delete c[a]}},nb:function(c,f){var g=[];b(c,g);for(var e=0,m=g.length;e<m;e++){var h=g[e].xb,k=[h];f&&a.a.R(k,f);a.s.mb(g[e].Kb,k);h.nodeValue="";h.parentNode&&h.parentNode.removeChild(h)}},$a:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.s);a.b("memoization.memoize",a.s.va);a.b("memoization.unmemoize",a.s.mb);a.b("memoization.parseMemoText",a.s.$a);a.b("memoization.unmemoizeDomNodeAndDescendants",a.s.nb);a.Sa={throttle:function(b,c){b.throttleEvaluation=
|
||||
c;var d=null;return a.j({read:b,write:function(a){clearTimeout(d);d=setTimeout(function(){b(a)},c)}})},notify:function(b,c){b.equalityComparer="always"==c?F(!1):a.m.fn.equalityComparer;return b}};a.b("extenders",a.Sa);a.kb=function(b,c,d){this.target=b;this.la=c;this.wb=d;a.r(this,"dispose",this.B)};a.kb.prototype.B=function(){this.Hb=!0;this.wb()};a.V=function(){this.G={};a.a.extend(this,a.V.fn);a.r(this,"subscribe",this.Da);a.r(this,"extend",this.extend);a.r(this,"getSubscriptionsCount",this.Db)};
|
||||
a.V.fn={Da:function(b,c,d){d=d||"change";var f=new a.kb(this,c?b.bind(c):b,function(){a.a.ka(this.G[d],f)}.bind(this));this.G[d]||(this.G[d]=[]);this.G[d].push(f);return f},notifySubscribers:function(b,c){c=c||"change";this.G[c]&&a.q.I(function(){a.a.p(this.G[c].slice(0),function(a){a&&!0!==a.Hb&&a.la(b)})},this)},Db:function(){var b=0;a.a.w(this.G,function(a,d){b+=d.length});return b},extend:function(b){var c=this;b&&a.a.w(b,function(b,f){var g=a.Sa[b];"function"==typeof g&&(c=g(c,f))});return c}};
|
||||
a.Wa=function(a){return null!=a&&"function"==typeof a.Da&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.V);a.b("isSubscribable",a.Wa);a.q=function(){var b=[];return{rb:function(a){b.push({la:a,Ra:[]})},end:function(){b.pop()},bb:function(c){if(!a.Wa(c))throw Error("Only subscribable things can act as dependencies");if(0<b.length){var d=b[b.length-1];!d||0<=a.a.k(d.Ra,c)||(d.Ra.push(c),d.la(c))}},I:function(a,d,f){try{return b.push(null),a.apply(d,f||[])}finally{b.pop()}}}}();var L=
|
||||
{undefined:!0,"boolean":!0,number:!0,string:!0};a.m=function(b){function c(){if(0<arguments.length)return c.equalityComparer&&c.equalityComparer(d,arguments[0])||(c.K(),d=arguments[0],c.J()),this;a.q.bb(c);return d}var d=b;a.V.call(c);c.t=function(){return d};c.J=function(){c.notifySubscribers(d)};c.K=function(){c.notifySubscribers(d,"beforeChange")};a.a.extend(c,a.m.fn);a.r(c,"peek",c.t);a.r(c,"valueHasMutated",c.J);a.r(c,"valueWillMutate",c.K);return c};a.m.fn={equalityComparer:function(a,c){return null===
|
||||
a||typeof a in L?a===c:!1}};var A=a.m.Pb="__ko_proto__";a.m.fn[A]=a.m;a.qa=function(b,c){return null===b||b===q||b[A]===q?!1:b[A]===c?!0:a.qa(b[A],c)};a.T=function(b){return a.qa(b,a.m)};a.Xa=function(b){return"function"==typeof b&&b[A]===a.m||"function"==typeof b&&b[A]===a.j&&b.Eb?!0:!1};a.b("observable",a.m);a.b("isObservable",a.T);a.b("isWriteableObservable",a.Xa);a.U=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
|
||||
b=a.m(b);a.a.extend(b,a.U.fn);return b};a.U.fn={remove:function(a){for(var c=this.t(),d=[],f="function"==typeof a?a:function(e){return e===a},g=0;g<c.length;g++){var e=c[g];f(e)&&(0===d.length&&this.K(),d.push(e),c.splice(g,1),g--)}d.length&&this.J();return d},removeAll:function(b){if(b===q){var c=this.t(),d=c.slice(0);this.K();c.splice(0,c.length);this.J();return d}return b?this.remove(function(c){return 0<=a.a.k(b,c)}):[]},destroy:function(a){var c=this.t(),d="function"==typeof a?a:function(c){return c===
|
||||
a};this.K();for(var f=c.length-1;0<=f;f--)d(c[f])&&(c[f]._destroy=!0);this.J()},destroyAll:function(b){return b===q?this.destroy(F(!0)):b?this.destroy(function(c){return 0<=a.a.k(b,c)}):[]},indexOf:function(b){var c=this();return a.a.k(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.K(),this.t()[d]=c,this.J())}};a.a.p("pop push reverse shift sort splice unshift".split(" "),function(b){a.U.fn[b]=function(){var a=this.t();this.K();a=a[b].apply(a,arguments);this.J();return a}});a.a.p(["slice"],
|
||||
function(b){a.U.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.U);a.j=function(b,c,d){function f(){a.a.p(v,function(a){a.B()});v=[]}function g(){var a=m.throttleEvaluation;a&&0<=a?(clearTimeout(t),t=setTimeout(e,a)):e()}function e(){if(!n)if(l&&D())x();else{n=!0;try{var b=a.a.Z(v,function(a){return a.target});a.q.rb(function(e){var c;0<=(c=a.a.k(b,e))?b[c]=q:v.push(e.Da(g))});for(var e=p.call(c),d=b.length-1;0<=d;d--)b[d]&&v.splice(d,1)[0].B();l=!0;m.notifySubscribers(k,
|
||||
"beforeChange");k=e;m.notifySubscribers(k)}finally{a.q.end(),n=!1}v.length||x()}}function m(){if(0<arguments.length){if("function"===typeof r)r.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}l||e();a.q.bb(m);return k}function h(){return!l||0<v.length}var k,l=!1,n=!1,p=b;p&&"object"==typeof p?(d=p,p=d.read):(d=d||{},p||(p=d.read));if("function"!=typeof p)throw Error("Pass a function that returns the value of the ko.computed");
|
||||
var r=d.write,z=d.disposeWhenNodeIsRemoved||d.$||null,D=d.disposeWhen||d.Qa||F(!1),x=f,v=[],t=null;c||(c=d.owner);m.t=function(){l||e();return k};m.Cb=function(){return v.length};m.Eb="function"===typeof d.write;m.B=function(){x()};m.ta=h;a.V.call(m);a.a.extend(m,a.j.fn);a.r(m,"peek",m.t);a.r(m,"dispose",m.B);a.r(m,"isActive",m.ta);a.r(m,"getDependenciesCount",m.Cb);!0!==d.deferEvaluation&&e();if(z&&h()){x=function(){a.a.C.cb(z,x);f()};a.a.C.ia(z,x);var s=D,D=function(){return!a.a.aa(z)||s()}}return m};
|
||||
a.Gb=function(b){return a.qa(b,a.j)};C=a.m.Pb;a.j[C]=a.m;a.j.fn={};a.j.fn[C]=a.j;a.b("dependentObservable",a.j);a.b("computed",a.j);a.b("isComputed",a.Gb);(function(){function b(a,g,e){e=e||new d;a=g(a);if("object"!=typeof a||null===a||a===q||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var m=a instanceof Array?[]:{};e.save(a,m);c(a,function(c){var d=g(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":m[c]=d;break;case "object":case "undefined":var l=
|
||||
e.get(d);m[c]=l!==q?l:b(d,g,e)}});return m}function c(a,b){if(a instanceof Array){for(var e=0;e<a.length;e++)b(e);"function"==typeof a.toJSON&&b("toJSON")}else for(e in a)b(e)}function d(){this.keys=[];this.Ha=[]}a.lb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var e=0;a.T(b)&&10>e;e++)b=b();return b})};a.toJSON=function(b,c,e){b=a.lb(b);return a.a.Ca(b,c,e)};d.prototype={save:function(b,c){var e=a.a.k(this.keys,
|
||||
b);0<=e?this.Ha[e]=c:(this.keys.push(b),this.Ha.push(c))},get:function(b){b=a.a.k(this.keys,b);return 0<=b?this.Ha[b]:q}}})();a.b("toJS",a.lb);a.b("toJSON",a.toJSON);(function(){a.h={n:function(b){switch(a.a.u(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.wa):7>=a.a.ca?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.h.n(b.options[b.selectedIndex]):q;default:return b.value}},W:function(b,
|
||||
c){switch(a.a.u(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.wa,q);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.wa,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":""===c&&(c=q);if(null===c||c===q)b.selectedIndex=-1;for(var d=b.options.length-1;0<=d;d--)if(a.h.n(b.options[d])==c){b.selectedIndex=d;break}1<b.size||-1!==b.selectedIndex||(b.selectedIndex=
|
||||
0);break;default:if(null===c||c===q)c="";b.value=c}}}})();a.b("selectExtensions",a.h);a.b("selectExtensions.readValue",a.h.n);a.b("selectExtensions.writeValue",a.h.W);a.g=function(){function b(a,b){for(var d=null;a!=d;)d=a,a=a.replace(c,function(a,c){return b[c]});return a}var c=/\@ko_token_(\d+)\@/g,d=["true","false","null","undefined"],f=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;return{S:[],da:function(c){var e=a.a.F(c);if(3>e.length)return[];"{"===e.charAt(0)&&(e=e.substring(1,e.length-
|
||||
1));c=[];for(var d=null,f,k=0;k<e.length;k++){var l=e.charAt(k);if(null===d)switch(l){case '"':case "'":case "/":d=k,f=l}else if(l==f&&"\\"!==e.charAt(k-1)){l=e.substring(d,k+1);c.push(l);var n="@ko_token_"+(c.length-1)+"@",e=e.substring(0,d)+n+e.substring(k+1),k=k-(l.length-n.length),d=null}}f=d=null;for(var p=0,r=null,k=0;k<e.length;k++){l=e.charAt(k);if(null===d)switch(l){case "{":d=k;r=l;f="}";break;case "(":d=k;r=l;f=")";break;case "[":d=k,r=l,f="]"}l===r?p++:l===f&&(p--,0===p&&(l=e.substring(d,
|
||||
k+1),c.push(l),n="@ko_token_"+(c.length-1)+"@",e=e.substring(0,d)+n+e.substring(k+1),k-=l.length-n.length,d=null))}f=[];e=e.split(",");d=0;for(k=e.length;d<k;d++)p=e[d],r=p.indexOf(":"),0<r&&r<p.length-1?(l=p.substring(r+1),f.push({key:b(p.substring(0,r),c),value:b(l,c)})):f.push({unknown:b(p,c)});return f},ea:function(b){var e="string"===typeof b?a.g.da(b):b,c=[];b=[];for(var h,k=0;h=e[k];k++)if(0<c.length&&c.push(","),h.key){var l;a:{l=h.key;var n=a.a.F(l);switch(n.length&&n.charAt(0)){case "'":case '"':break a;
|
||||
default:l="'"+n+"'"}}h=h.value;c.push(l);c.push(":");c.push(h);h=a.a.F(h);0<=a.a.k(d,a.a.F(h).toLowerCase())?h=!1:(n=h.match(f),h=null===n?!1:n[1]?"Object("+n[1]+")"+n[2]:h);h&&(0<b.length&&b.push(", "),b.push(l+" : function(__ko_value) { "+h+" = __ko_value; }"))}else h.unknown&&c.push(h.unknown);e=c.join("");0<b.length&&(e=e+", '_ko_property_writers' : { "+b.join("")+" } ");return e},Jb:function(b,c){for(var d=0;d<b.length;d++)if(a.a.F(b[d].key)==c)return!0;return!1},ha:function(b,c,d,f,k){if(b&&
|
||||
a.T(b))!a.Xa(b)||k&&b.t()===f||b(f);else if((b=c()._ko_property_writers)&&b[d])b[d](f)}}}();a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.S);a.b("expressionRewriting.parseObjectLiteral",a.g.da);a.b("expressionRewriting.preProcessBindings",a.g.ea);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.ea);(function(){function b(a){return 8==a.nodeType&&(g?a.text:a.nodeValue).match(e)}function c(a){return 8==a.nodeType&&
|
||||
(g?a.text:a.nodeValue).match(m)}function d(a,e){for(var d=a,g=1,f=[];d=d.nextSibling;){if(c(d)&&(g--,0===g))return f;f.push(d);b(d)&&g++}if(!e)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function f(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var g=s&&"\x3c!--test--\x3e"===s.createComment("test").text,e=g?/^\x3c!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*--\x3e$/:/^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/,m=g?/^\x3c!--\s*\/ko\s*--\x3e$/:
|
||||
/^\s*\/ko\s*$/,h={ul:!0,ol:!0};a.e={L:{},childNodes:function(a){return b(a)?d(a):a.childNodes},ba:function(c){if(b(c)){c=a.e.childNodes(c);for(var e=0,d=c.length;e<d;e++)a.removeNode(c[e])}else a.a.oa(c)},P:function(c,e){if(b(c)){a.e.ba(c);for(var d=c.nextSibling,g=0,f=e.length;g<f;g++)d.parentNode.insertBefore(e[g],d)}else a.a.P(c,e)},ab:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},Va:function(c,e,d){d?b(c)?c.parentNode.insertBefore(e,
|
||||
d.nextSibling):d.nextSibling?c.insertBefore(e,d.nextSibling):c.appendChild(e):a.e.ab(c,e)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=f(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},ob:function(a){return(a=b(a))?a[1]:null},Za:function(e){if(h[a.a.u(e)]){var d=e.firstChild;if(d){do if(1===d.nodeType){var g;g=d.firstChild;var m=null;if(g){do if(m)m.push(g);else if(b(g)){var r=f(g,!0);r?g=r:m=
|
||||
[g]}else c(g)&&(m=[g]);while(g=g.nextSibling)}if(g=m)for(m=d.nextSibling,r=0;r<g.length;r++)m?e.insertBefore(g[r],m):e.appendChild(g[r])}while(d=d.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.L);a.b("virtualElements.emptyNode",a.e.ba);a.b("virtualElements.insertAfter",a.e.Va);a.b("virtualElements.prepend",a.e.ab);a.b("virtualElements.setDomNodeChildren",a.e.P);(function(){a.M=function(){this.Na={}};a.a.extend(a.M.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
|
||||
b.getAttribute("data-bind");case 8:return null!=a.e.ob(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.e.ob(b);default:return null}},parseBindingsString:function(b,c,d){try{var f;if(!(f=this.Na[b])){var g=this.Na,e,m="with($context){with($data||{}){return{"+a.g.ea(b)+"}}}";e=new Function("$context","$element",m);
|
||||
f=g[b]=e}return f(c,d)}catch(h){throw h.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+h.message,h;}}});a.M.instance=new a.M})();a.b("bindingProvider",a.M);(function(){function b(b,e,d){for(var f=a.e.firstChild(e);e=f;)f=a.e.nextSibling(e),c(b,e,d)}function c(c,e,f){var h=!0,k=1===e.nodeType;k&&a.e.Za(e);if(k&&f||a.M.instance.nodeHasBindings(e))h=d(e,null,c,f).Sb;h&&b(c,e,!k)}function d(b,c,d,h){function k(a){return function(){return p[a]}}function l(){return p}var n=0,p,r,
|
||||
z=a.a.f.get(b,f);if(!c){if(z)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,f,!0)}a.j(function(){var f=d&&d instanceof a.A?d:new a.A(a.a.c(d)),x=f.$data;!z&&h&&a.jb(b,f);if(p=("function"==typeof c?c(f,b):c)||a.M.instance.getBindings(b,f))0===n&&(n=1,a.a.w(p,function(c){var e=a.d[c];if(e&&8===b.nodeType&&!a.e.L[c])throw Error("The binding '"+c+"' cannot be used with virtual elements");if(e&&"function"==typeof e.init&&(e=(0,e.init)(b,k(c),l,x,f))&&e.controlsDescendantBindings){if(r!==
|
||||
q)throw Error("Multiple bindings ("+r+" and "+c+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");r=c}}),n=2),2===n&&a.a.w(p,function(c){var e=a.d[c];e&&"function"==typeof e.update&&(0,e.update)(b,k(c),l,x,f)})},null,{$:b});return{Sb:r===q}}a.d={};a.A=function(b,c,d){c?(a.a.extend(this,c),this.$parentContext=c,this.$parent=c.$data,this.$parents=(c.$parents||[]).slice(0),this.$parents.unshift(this.$parent)):(this.$parents=
|
||||
[],this.$root=b,this.ko=a);this.$data=b;d&&(this[d]=b)};a.A.prototype.createChildContext=function(b,c){return new a.A(b,this,c)};a.A.prototype.extend=function(b){var c=a.a.extend(new a.A,this);return a.a.extend(c,b)};var f="__ko_boundElement";a.jb=function(b,c){if(2==arguments.length)a.a.f.set(b,"__ko_bindingContext__",c);else return a.a.f.get(b,"__ko_bindingContext__")};a.Ka=function(b,c,f){1===b.nodeType&&a.e.Za(b);return d(b,c,f,!0)};a.Ja=function(a,c){1!==c.nodeType&&8!==c.nodeType||b(a,c,!0)};
|
||||
a.Ia=function(a,b){if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||w.document.body;c(a,b,!0)};a.na=function(b){switch(b.nodeType){case 1:case 8:var c=a.jb(b);if(c)return c;if(b.parentNode)return a.na(b.parentNode)}return q};a.ub=function(b){return(b=a.na(b))?b.$data:q};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Ia);a.b("applyBindingsToDescendants",a.Ja);a.b("applyBindingsToNode",a.Ka);
|
||||
a.b("contextFor",a.na);a.b("dataFor",a.ub)})();var K={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.w(d,function(c,d){d=a.a.c(d);var e=!1===d||null===d||d===q;e&&b.removeAttribute(c);8>=a.a.ca&&c in K?(c=K[c],e?b.removeAttribute(c):b[c]=d):e||b.setAttribute(c,d.toString());"name"===c&&a.a.gb(b,e?"":d.toString())})}};a.d.checked={init:function(b,c,d){a.a.o(b,"click",function(){var f;if("checkbox"==b.type)f=b.checked;else if("radio"==b.type&&b.checked)f=
|
||||
b.value;else return;var g=c(),e=a.a.c(g);"checkbox"==b.type&&e instanceof Array?a.a.ja(g,b.value,b.checked):a.g.ha(g,d,"checked",f,!0)});"radio"!=b.type||b.name||a.d.uniqueName.init(b,F(!0))},update:function(b,c){var d=a.a.c(c());"checkbox"==b.type?b.checked=d instanceof Array?0<=a.a.k(d,b.value):d:"radio"==b.type&&(b.checked=b.value==d)}};a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.w(d,function(c,d){d=a.a.c(d);a.a.ga(b,c,d)}):(d=String(d||""),a.a.ga(b,b.__ko__cssValue,!1),
|
||||
b.__ko__cssValue=d,a.a.ga(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,f){var g=c()||{};a.a.w(g,function(e){"string"==typeof e&&a.a.o(b,e,function(b){var g,k=c()[e];if(k){var l=d();try{var n=a.a.N(arguments);n.unshift(f);g=k.apply(f,n)}finally{!0!==g&&(b.preventDefault?b.preventDefault():b.returnValue=
|
||||
!1)}!1===l[e+"Bubble"]&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={Ya:function(b){return function(){var c=b(),d=a.a.ya(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.D.sa};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.D.sa}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.Ya(c))},
|
||||
update:function(b,c,d,f,g){return a.d.template.update(b,a.d.foreach.Ya(c),d,f,g)}};a.g.S.foreach=!1;a.e.L.foreach=!0;a.d.hasfocus={init:function(b,c,d){function f(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(l){g=f.body}e=g===b}f=c();a.g.ha(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var g=f.bind(null,!0),e=f.bind(null,!1);a.a.o(b,"focus",g);a.a.o(b,"focusin",g);a.a.o(b,"blur",e);a.a.o(b,"focusout",e)},
|
||||
update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.q.I(a.a.Ga,null,[b,d?"focusin":"focusout"]))}};a.d.hasFocus=a.d.hasfocus;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.fa(b,c())}};var I="__ko_withIfBindingData";G("if");G("ifnot",!1,!0);G("with",!0,!1,function(a,c){return a.createChildContext(c)});a.d.options={init:function(b){if("select"!==a.a.u(b))throw Error("options binding applies only to SELECT elements");
|
||||
for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(b,c){if(p){var d=0<=a.a.k(p,a.h.n(c[0]));a.a.hb(c[0],d)}}var e=0==b.length,m=!e&&b.multiple?b.scrollTop:null;c=a.a.c(c());var h=d(),k=h.optionsIncludeDestroyed,l={},n,p;b.multiple?p=a.a.Z(b.selectedOptions||a.a.Y(b.childNodes,function(b){return b.tagName&&"option"===a.a.u(b)&&b.selected}),function(b){return a.h.n(b)}):0<=
|
||||
b.selectedIndex&&(p=[a.h.n(b.options[b.selectedIndex])]);if(c){"undefined"==typeof c.length&&(c=[c]);var r=a.a.Y(c,function(b){return k||b===q||null===b||!a.a.c(b._destroy)});"optionsCaption"in h&&(n=a.a.c(h.optionsCaption),null!==n&&n!==q&&r.unshift(l))}else c=[];d=g;h.optionsAfterRender&&(d=function(b,c){g(0,c);a.q.I(h.optionsAfterRender,null,[c[0],b!==l?b:q])});a.a.Aa(b,r,function(b,c,d){d.length&&(p=d[0].selected&&[a.h.n(d[0])]);c=s.createElement("option");b===l?(a.a.fa(c,n),a.h.W(c,q)):(d=f(b,
|
||||
h.optionsValue,b),a.h.W(c,a.a.c(d)),b=f(b,h.optionsText,d),a.a.ib(c,b));return[c]},null,d);p=null;e&&"value"in h&&J(b,a.a.ya(h.value),!0);a.a.zb(b);m&&20<Math.abs(m-b.scrollTop)&&(b.scrollTop=m)}};a.d.options.wa="__ko.optionValueDomData__";a.d.selectedOptions={init:function(b,c,d){a.a.o(b,"change",function(){var f=c(),g=[];a.a.p(b.getElementsByTagName("option"),function(b){b.selected&&g.push(a.h.n(b))});a.g.ha(f,d,"selectedOptions",g)})},update:function(b,c){if("select"!=a.a.u(b))throw Error("values binding applies only to SELECT elements");
|
||||
var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.p(b.getElementsByTagName("option"),function(b){var c=0<=a.a.k(d,a.h.n(b));a.a.hb(b,c)})}};a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.w(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.o(b,"submit",function(a){var d,m=c();try{d=m.call(f,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};
|
||||
a.d.text={update:function(b,c){a.a.ib(b,c())}};a.e.L.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.tb;a.a.gb(b,d)}}};a.d.uniqueName.tb=0;a.d.value={init:function(b,c,d){function f(){m=!1;var e=c(),f=a.h.n(b);a.g.ha(e,d,"value",f)}var g=["change"],e=d().valueUpdate,m=!1;e&&("string"==typeof e&&(e=[e]),a.a.R(g,e),g=a.a.Ma(g));!a.a.ca||("input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete)||-1!=a.a.k(g,"propertychange")||
|
||||
(a.a.o(b,"propertychange",function(){m=!0}),a.a.o(b,"blur",function(){m&&f()}));a.a.p(g,function(c){var d=f;a.a.Tb(c,"after")&&(d=function(){setTimeout(f,0)},c=c.substring(5));a.a.o(b,c,d)})},update:function(b,c){var d="select"===a.a.u(b),f=a.a.c(c()),g=a.h.n(b);f!==g&&(g=function(){a.h.W(b,f)},g(),d&&setTimeout(g,0));d&&0<b.length&&J(b,f,!1)}};a.d.visible={update:function(b,c){var d=a.a.c(c()),f="none"!=b.style.display;d&&!f?b.style.display="":!d&&f&&(b.style.display="none")}};(function(b){a.d[b]=
|
||||
{init:function(c,d,f,g){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},f,g)}}})("click");a.v=function(){};a.v.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.v.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.v.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||s;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.l.i(d)}if(1==
|
||||
b.nodeType||8==b.nodeType)return new a.l.Q(b);throw Error("Unknown template type: "+b);};a.v.prototype.renderTemplate=function(a,c,d,f){a=this.makeTemplateSource(a,f);return this.renderTemplateSource(a,c,d)};a.v.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.v.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.v);
|
||||
a.Ea=function(){function b(b,c,d,m){b=a.g.da(b);for(var h=a.g.S,k=0;k<b.length;k++){var l=b[k].key;if(h.hasOwnProperty(l)){var n=h[l];if("function"===typeof n){if(l=n(b[k].value))throw Error(l);}else if(!n)throw Error("This template engine does not support the '"+l+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.ea(b)+" } })()},'"+d.toLowerCase()+"')";return m.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,
|
||||
d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ab:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Ea.Lb(b,c)},d)},Lb:function(a,g){return a.replace(c,function(a,c,d,f,l){return b(l,c,d,g)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",g)})},qb:function(b,c){return a.s.va(function(d,m){var h=d.nextSibling;h&&h.nodeName.toLowerCase()===c&&a.Ka(h,b,m)})}}}();a.b("__tr_ambtns",a.Ea.qb);(function(){a.l={};a.l.i=function(a){this.i=a};a.l.i.prototype.text=
|
||||
function(){var b=a.a.u(this.i),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.i[b];var c=arguments[0];"innerHTML"===b?a.a.fa(this.i,c):this.i[b]=c};a.l.i.prototype.data=function(b){if(1===arguments.length)return a.a.f.get(this.i,"templateSourceData_"+b);a.a.f.set(this.i,"templateSourceData_"+b,arguments[1])};a.l.Q=function(a){this.i=a};a.l.Q.prototype=new a.l.i;a.l.Q.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.i,"__ko_anon_template__")||
|
||||
{};b.Fa===q&&b.ma&&(b.Fa=b.ma.innerHTML);return b.Fa}a.a.f.set(this.i,"__ko_anon_template__",{Fa:arguments[0]})};a.l.i.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.i,"__ko_anon_template__")||{}).ma;a.a.f.set(this.i,"__ko_anon_template__",{ma:arguments[0]})};a.b("templateSources",a.l);a.b("templateSources.domElement",a.l.i);a.b("templateSources.anonymousTemplate",a.l.Q)})();(function(){function b(b,c,d){var f;for(c=a.e.nextSibling(c);b&&(f=b)!==c;)b=a.e.nextSibling(f),1!==
|
||||
f.nodeType&&8!==f.nodeType||d(f)}function c(c,d){if(c.length){var f=c[0],g=c[c.length-1];b(f,g,function(b){a.Ia(d,b)});b(f,g,function(b){a.s.nb(b,[d])})}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function f(b,f,h,k,l){l=l||{};var n=b&&d(b),n=n&&n.ownerDocument,p=l.templateEngine||g;a.Ea.Ab(h,p,n);h=p.renderTemplate(h,k,l,n);if("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)throw Error("Template engine must return an array of DOM nodes");n=!1;switch(f){case "replaceChildren":a.e.P(b,
|
||||
h);n=!0;break;case "replaceNode":a.a.eb(b,h);n=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+f);}n&&(c(h,k),l.afterRender&&a.q.I(l.afterRender,null,[h,k.$data]));return h}var g;a.Ba=function(b){if(b!=q&&!(b instanceof a.v))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.za=function(b,c,h,k,l){h=h||{};if((h.templateEngine||g)==q)throw Error("Set a template engine before calling renderTemplate");l=l||"replaceChildren";if(k){var n=d(k);return a.j(function(){var g=
|
||||
c&&c instanceof a.A?c:new a.A(a.a.c(c)),r="function"==typeof b?b(g.$data,g):b,g=f(k,l,r,g,h);"replaceNode"==l&&(k=g,n=d(k))},null,{Qa:function(){return!n||!a.a.aa(n)},$:n&&"replaceNode"==l?n.parentNode:n})}return a.s.va(function(d){a.za(b,c,h,d,"replaceNode")})};a.Rb=function(b,d,g,k,l){function n(a,b){c(b,r);g.afterRender&&g.afterRender(b,a)}function p(c,d){r=l.createChildContext(a.a.c(c),g.as);r.$index=d;var k="function"==typeof b?b(c,r):b;return f(null,"ignoreTargetNode",k,r,g)}var r;return a.j(function(){var b=
|
||||
a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.Y(b,function(b){return g.includeDestroyed||b===q||null===b||!a.a.c(b._destroy)});a.q.I(a.a.Aa,null,[k,b,p,g,n])},null,{$:k})};a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||(d.name||1!=b.nodeType&&8!=b.nodeType)||(d=1==b.nodeType?b.childNodes:a.e.childNodes(b),d=a.a.Mb(d),(new a.l.Q(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,f,g){c=a.a.c(c());d={};f=!0;var n,p=null;"string"!=typeof c&&(d=
|
||||
c,c=a.a.c(d.name),"if"in d&&(f=a.a.c(d["if"])),f&&"ifnot"in d&&(f=!a.a.c(d.ifnot)),n=a.a.c(d.data));"foreach"in d?p=a.Rb(c||b,f&&d.foreach||[],d,b,g):f?(g="data"in d?g.createChildContext(n,d.as):g,p=a.za(c||b,g,d,b)):a.e.ba(b);g=p;(n=a.a.f.get(b,"__ko__templateComputedDomDataKey__"))&&"function"==typeof n.B&&n.B();a.a.f.set(b,"__ko__templateComputedDomDataKey__",g&&g.ta()?g:q)}};a.g.S.template=function(b){b=a.g.da(b);return 1==b.length&&b[0].unknown||a.g.Jb(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};
|
||||
a.e.L.template=!0})();a.b("setTemplateEngine",a.Ba);a.b("renderTemplate",a.za);a.a.Pa=function(){function a(b,d,f,g,e){var m=Math.min,h=Math.max,k=[],l,n=b.length,p,r=d.length,q=r-n||1,t=n+r+1,s,v,w;for(l=0;l<=n;l++)for(v=s,k.push(s=[]),w=m(r,l+q),p=h(0,l-1);p<=w;p++)s[p]=p?l?b[l-1]===d[p-1]?v[p-1]:m(v[p]||t,s[p-1]||t)+1:p+1:l+1;m=[];h=[];q=[];l=n;for(p=r;l||p;)r=k[l][p]-1,p&&r===k[l][p-1]?h.push(m[m.length]={status:f,value:d[--p],index:p}):l&&r===k[l-1][p]?q.push(m[m.length]={status:g,value:b[--l],
|
||||
index:l}):(m.push({status:"retained",value:d[--p]}),--l);if(h.length&&q.length){b=10*n;var E;for(d=f=0;(e||d<b)&&(E=h[f]);f++){for(g=0;k=q[g];g++)if(E.value===k.value){E.moved=k.index;k.moved=E.index;q.splice(g,1);d=g=0;break}d+=g}}return m.reverse()}return function(c,d,f){c=c||[];d=d||[];return c.length<=d.length?a(c,d,"added","deleted",f):a(d,c,"deleted","added",f)}}();a.b("utils.compareArrays",a.a.Pa);(function(){function b(b){for(;b.length&&!a.a.aa(b[0]);)b.splice(0,1);if(1<b.length){for(var c=
|
||||
b[0],g=b[b.length-1],e=[c];c!==g;){c=c.nextSibling;if(!c)return;e.push(c)}Array.prototype.splice.apply(b,[0,b.length].concat(e))}return b}function c(c,f,g,e,m){var h=[];c=a.j(function(){var c=f(g,m,b(h))||[];0<h.length&&(a.a.eb(h,c),e&&a.q.I(e,null,[g,c,m]));h.splice(0,h.length);a.a.R(h,c)},null,{$:c,Qa:function(){return!a.a.pb(h)}});return{O:h,j:c.ta()?c:q}}a.a.Aa=function(d,f,g,e,m){function h(a,c){u=n[c];x!==c&&(E[a]=u);u.ra(x++);b(u.O);t.push(u);w.push(u)}function k(b,c){if(b)for(var d=0,e=c.length;d<
|
||||
e;d++)c[d]&&a.a.p(c[d].O,function(a){b(a,d,c[d].X)})}f=f||[];e=e||{};var l=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===q,n=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],p=a.a.Z(n,function(a){return a.X}),r=a.a.Pa(p,f,e.dontLimitMoves),t=[],s=0,x=0,v=[],w=[];f=[];for(var E=[],p=[],u,B=0,y,A;y=r[B];B++)switch(A=y.moved,y.status){case "deleted":A===q&&(u=n[s],u.j&&u.j.B(),v.push.apply(v,b(u.O)),e.beforeRemove&&(f[B]=u,w.push(u)));s++;break;case "retained":h(B,
|
||||
s++);break;case "added":A!==q?h(B,A):(u={X:y.value,ra:a.m(x++)},t.push(u),w.push(u),l||(p[B]=u))}k(e.beforeMove,E);a.a.p(v,e.beforeRemove?a.H:a.removeNode);for(var B=0,l=a.e.firstChild(d),C;u=w[B];B++){u.O||a.a.extend(u,c(d,g,u.X,m,u.ra));for(s=0;r=u.O[s];l=r.nextSibling,C=r,s++)r!==l&&a.e.Va(d,r,C);!u.Fb&&m&&(m(u.X,u.O,u.ra),u.Fb=!0)}k(e.beforeRemove,f);k(e.afterMove,E);k(e.afterAdd,p);a.a.f.set(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult",t)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",
|
||||
a.a.Aa);a.D=function(){this.allowTemplateRewriting=!1};a.D.prototype=new a.v;a.D.prototype.renderTemplateSource=function(b){var c=(9>a.a.ca?0:b.nodes)?b.nodes():null;if(c)return a.a.N(c.cloneNode(!0).childNodes);b=b.text();return a.a.xa(b)};a.D.sa=new a.D;a.Ba(a.D.sa);a.b("nativeTemplateEngine",a.D);(function(){a.ua=function(){var a=this.Ib=function(){if("undefined"==typeof t||!t.tmpl)return 0;try{if(0<=t.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=
|
||||
function(b,f,g){g=g||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var e=b.data("precompiled");e||(e=b.text()||"",e=t.template(null,"{{ko_with $item.koBindingContext}}"+e+"{{/ko_with}}"),b.data("precompiled",e));b=[f.$data];f=t.extend({koBindingContext:f},g.templateOptions);f=t.tmpl(e,b,f);f.appendTo(s.createElement("div"));t.fragments={};return f};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+
|
||||
a+" })()) }}"};this.addTemplate=function(a,b){s.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(t.tmpl.tag.ko_code={open:"__.push($1 || '');"},t.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.ua.prototype=new a.v;var b=new a.ua;0<b.Ib&&a.Ba(b);a.b("jqueryTmplTemplateEngine",a.ua)})()})})();
|
||||
})();
|
||||
@@ -0,0 +1,96 @@
|
||||
// Knockout JavaScript library v3.1.0
|
||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
(function() {(function(p){var A=this||(0,eval)("this"),w=A.document,K=A.navigator,t=A.jQuery,C=A.JSON;(function(p){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?p(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],p):p(A.ko={})})(function(z){function G(a,c){return null===a||typeof a in M?a===c:!1}function N(a,c){var d;return function(){d||(d=setTimeout(function(){d=p;a()},c))}}function O(a,c){var d;return function(){clearTimeout(d);d=setTimeout(a,
|
||||
c)}}function H(b,c,d,e){a.d[b]={init:function(b,h,g,k,l){var n,r;a.ba(function(){var g=a.a.c(h()),k=!d!==!g,s=!r;if(s||c||k!==n)s&&a.ca.fa()&&(r=a.a.lb(a.e.childNodes(b),!0)),k?(s||a.e.U(b,a.a.lb(r)),a.gb(e?e(l,g):l,b)):a.e.da(b),n=k},null,{G:b});return{controlsDescendantBindings:!0}}};a.g.aa[b]=!1;a.e.Q[b]=!0}var a="undefined"!==typeof z?z:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.s=function(a,c,d){a[c]=d};a.version="3.1.0";a.b("version",
|
||||
a.version);a.a=function(){function b(a,b){for(var c in a)a.hasOwnProperty(c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}var e={__proto__:[]}instanceof Array,f={},h={};f[K&&/Firefox\/2/i.test(K.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];f.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(f,function(a,b){if(b.length)for(var c=0,
|
||||
d=b.length;c<d;c++)h[b[c]]=a});var g={propertychange:!0},k=w&&function(){for(var a=3,b=w.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:p}();return{mb:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],r:function(a,b){for(var c=0,d=a.length;c<d;c++)b(a[c],c)},l:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,d=a.length;c<d;c++)if(a[c]===
|
||||
b)return c;return-1},hb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d))return a[d];return null},ma:function(b,c){var d=a.a.l(b,c);0<d?b.splice(d,1):0===d&&b.shift()},ib:function(b){b=b||[];for(var c=[],d=0,e=b.length;d<e;d++)0>a.a.l(c,b[d])&&c.push(b[d]);return c},ya:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)c.push(b(a[d],d));return c},la:function(a,b){a=a||[];for(var c=[],d=0,e=a.length;d<e;d++)b(a[d],d)&&c.push(a[d]);return c},$:function(a,b){if(b instanceof Array)a.push.apply(a,
|
||||
b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},Y:function(b,c,d){var e=a.a.l(a.a.Sa(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},na:e,extend:c,ra:d,sa:e?d:c,A:b,Oa:function(a,b){if(!a)return a;var c={},d;for(d in a)a.hasOwnProperty(d)&&(c[d]=b(a[d],d,a));return c},Fa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},ec:function(b){b=a.a.R(b);for(var c=w.createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.M(b[d]));return c},lb:function(b,c){for(var d=0,e=b.length,g=[];d<
|
||||
e;d++){var k=b[d].cloneNode(!0);g.push(c?a.M(k):k)}return g},U:function(b,c){a.a.Fa(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},Bb:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],g=e.parentNode,k=0,h=c.length;k<h;k++)g.insertBefore(c[k],e);k=0;for(h=d.length;k<h;k++)a.removeNode(d[k])}},ea:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.shift();if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)if(a.push(c),
|
||||
c=c.nextSibling,!c)return;a.push(d)}}return a},Db:function(a,b){7>k?a.setAttribute("selected",b):a.selected=b},ta:function(a){return null===a||a===p?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},oc:function(b,c){for(var d=[],e=(b||"").split(c),g=0,k=e.length;g<k;g++){var h=a.a.ta(e[g]);""!==h&&d.push(h)}return d},kc:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Sb:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===
|
||||
a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},Ea:function(b){return a.a.Sb(b,b.ownerDocument.documentElement)},eb:function(b){return!!a.a.hb(b,a.a.Ea)},B:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},q:function(b,c,d){var e=k&&g[c];if(!e&&t)t(b).bind(c,d);else if(e||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var h=function(a){d.call(b,a)},f="on"+c;b.attachEvent(f,
|
||||
h);a.a.u.ja(b,function(){b.detachEvent(f,h)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,d,!1)},ha:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.B(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(t&&!d)t(b).trigger(c);else if("function"==typeof w.createEvent)if("function"==typeof b.dispatchEvent)d=w.createEvent(h[c]||"HTMLEvents"),
|
||||
d.initEvent(c,!0,!0,A,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.v(b)?b():b},Sa:function(b){return a.v(b)?b.o():b},ua:function(b,c,d){if(c){var e=/\S+/g,g=b.className.match(e)||[];a.a.r(c.match(e),function(b){a.a.Y(g,b,d)});b.className=g.join(" ")}},Xa:function(b,
|
||||
c){var d=a.a.c(c);if(null===d||d===p)d="";var e=a.e.firstChild(b);!e||3!=e.nodeType||a.e.nextSibling(e)?a.e.U(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Vb(b)},Cb:function(a,b){a.name=b;if(7>=k)try{a.mergeAttributes(w.createElement("<input name='"+a.name+"'/>"),!1)}catch(c){}},Vb:function(a){9<=k&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Tb:function(a){if(k){var b=a.style.width;a.style.width=0;a.style.width=b}},ic:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var d=
|
||||
[],e=b;e<=c;e++)d.push(e);return d},R:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},mc:6===k,nc:7===k,oa:k,ob:function(b,c){for(var d=a.a.R(b.getElementsByTagName("input")).concat(a.a.R(b.getElementsByTagName("textarea"))),e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},g=[],k=d.length-1;0<=k;k--)e(d[k])&&g.push(d[k]);return g},fc:function(b){return"string"==typeof b&&(b=a.a.ta(b))?C&&C.parse?C.parse(b):(new Function("return "+b))():
|
||||
null},Ya:function(b,c,d){if(!C||!C.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");return C.stringify(a.a.c(b),c,d)},gc:function(c,d,e){e=e||{};var g=e.params||{},k=e.includeFields||this.mb,h=c;if("object"==typeof c&&"form"===a.a.B(c))for(var h=c.action,f=k.length-1;0<=f;f--)for(var u=a.a.ob(c,k[f]),D=u.length-1;0<=D;D--)g[u[D].name]=
|
||||
u[D].value;d=a.a.c(d);var y=w.createElement("form");y.style.display="none";y.action=h;y.method="post";for(var p in d)c=w.createElement("input"),c.name=p,c.value=a.a.Ya(a.a.c(d[p])),y.appendChild(c);b(g,function(a,b){var c=w.createElement("input");c.name=a;c.value=b;y.appendChild(c)});w.body.appendChild(y);e.submitter?e.submitter(y):y.submit();setTimeout(function(){y.parentNode.removeChild(y)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.r);a.b("utils.arrayFirst",a.a.hb);a.b("utils.arrayFilter",
|
||||
a.a.la);a.b("utils.arrayGetDistinctValues",a.a.ib);a.b("utils.arrayIndexOf",a.a.l);a.b("utils.arrayMap",a.a.ya);a.b("utils.arrayPushAll",a.a.$);a.b("utils.arrayRemoveItem",a.a.ma);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.mb);a.b("utils.getFormFields",a.a.ob);a.b("utils.peekObservable",a.a.Sa);a.b("utils.postJson",a.a.gc);a.b("utils.parseJson",a.a.fc);a.b("utils.registerEventHandler",a.a.q);a.b("utils.stringifyJson",a.a.Ya);a.b("utils.range",a.a.ic);a.b("utils.toggleDomNodeCssClass",
|
||||
a.a.ua);a.b("utils.triggerEvent",a.a.ha);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.A);a.b("utils.addOrRemoveItem",a.a.Y);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){function a(b,h){var g=b[d];if(!g||"null"===g||!e[g]){if(!h)return p;g=b[d]="ko"+c++;e[g]={}}return e[g]}
|
||||
var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===p?p:e[d]},set:function(c,d,e){if(e!==p||a(c,!1)!==p)a(c,!0)[d]=e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},L:function(){return c++ +d}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.u=new function(){function b(b,c){var e=a.a.f.get(b,d);e===p&&c&&(e=[],a.a.f.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),k=0;k<e.length;k++)e[k](d);
|
||||
a.a.f.clear(d);a.a.u.cleanExternalData(d);if(f[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.f.L(),e={1:!0,8:!0,9:!0},f={1:!0,9:!0};return{ja:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},Ab:function(c,e){var k=b(c,!1);k&&(a.a.ma(k,e),0==k.length&&a.a.f.set(c,d,p))},M:function(b){if(e[b.nodeType]&&(c(b),f[b.nodeType])){var d=[];a.a.$(d,b.getElementsByTagName("*"));for(var k=0,l=d.length;k<l;k++)c(d[k])}return b},
|
||||
removeNode:function(b){a.M(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){t&&"function"==typeof t.cleanData&&t.cleanData([a])}}};a.M=a.a.u.M;a.removeNode=a.a.u.removeNode;a.b("cleanNode",a.M);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.u);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.u.ja);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.u.Ab);(function(){a.a.Qa=function(b){var c;if(t)if(t.parseHTML)c=t.parseHTML(b)||[];else{if((c=t.clean([b]))&&
|
||||
c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.ta(b).toLowerCase();c=w.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof A.innerShiv?c.appendChild(A.innerShiv(b)):
|
||||
c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.R(c.lastChild.childNodes)}return c};a.a.Va=function(b,c){a.a.Fa(b);c=a.a.c(c);if(null!==c&&c!==p)if("string"!=typeof c&&(c=c.toString()),t)t(b).html(c);else for(var d=a.a.Qa(c),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.Qa);a.b("utils.setHtml",a.a.Va);a.w=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.w.xb(c.nodeValue);null!=f&&e.push({Rb:c,cc:f})}else if(1==c.nodeType)for(var f=0,h=c.childNodes,g=h.length;f<g;f++)b(h[f],
|
||||
e)}var c={};return{Na:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},Hb:function(a,b){var f=c[a];if(f===p)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),!0}finally{delete c[a]}},Ib:function(c,e){var f=
|
||||
[];b(c,f);for(var h=0,g=f.length;h<g;h++){var k=f[h].Rb,l=[k];e&&a.a.$(l,e);a.w.Hb(f[h].cc,l);k.nodeValue="";k.parentNode&&k.parentNode.removeChild(k)}},xb:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.w);a.b("memoization.memoize",a.w.Na);a.b("memoization.unmemoize",a.w.Hb);a.b("memoization.parseMemoText",a.w.xb);a.b("memoization.unmemoizeDomNodeAndDescendants",a.w.Ib);a.Ga={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.h({read:b,write:function(a){clearTimeout(d);
|
||||
d=setTimeout(function(){b(a)},c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);f="notifyWhenChangesStop"==e?O:N;a.Ma(function(a){return f(a,d)})},notify:function(a,c){a.equalityComparer="always"==c?null:G}};var M={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Ga);a.Fb=function(b,c,d){this.target=b;this.za=c;this.Qb=d;this.sb=!1;a.s(this,"dispose",this.F)};a.Fb.prototype.F=function(){this.sb=!0;this.Qb()};a.N=function(){a.a.sa(this,a.N.fn);this.H=
|
||||
{}};var F="change";z={V:function(b,c,d){var e=this;d=d||F;var f=new a.Fb(e,c?b.bind(c):b,function(){a.a.ma(e.H[d],f)});e.o&&e.o();e.H[d]||(e.H[d]=[]);e.H[d].push(f);return f},notifySubscribers:function(b,c){c=c||F;if(this.qb(c))try{a.k.jb();for(var d=this.H[c].slice(0),e=0,f;f=d[e];++e)f.sb||f.za(b)}finally{a.k.end()}},Ma:function(b){var c=this,d=a.v(c),e,f,h;c.ia||(c.ia=c.notifySubscribers,c.notifySubscribers=function(a,b){b&&b!==F?"beforeChange"===b?c.bb(a):c.ia(a,b):c.cb(a)});var g=b(function(){d&&
|
||||
h===c&&(h=c());e=!1;c.Ka(f,h)&&c.ia(f=h)});c.cb=function(a){e=!0;h=a;g()};c.bb=function(a){e||(f=a,c.ia(a,"beforeChange"))}},qb:function(a){return this.H[a]&&this.H[a].length},Wb:function(){var b=0;a.a.A(this.H,function(a,d){b+=d.length});return b},Ka:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},extend:function(b){var c=this;b&&a.a.A(b,function(b,e){var f=a.Ga[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.s(z,"subscribe",z.V);a.s(z,"extend",z.extend);a.s(z,"getSubscriptionsCount",
|
||||
z.Wb);a.a.na&&a.a.ra(z,Function.prototype);a.N.fn=z;a.tb=function(a){return null!=a&&"function"==typeof a.V&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.N);a.b("isSubscribable",a.tb);a.ca=a.k=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{jb:b,end:c,zb:function(b){if(e){if(!a.tb(b))throw Error("Only subscribable things can act as dependencies");e.za(b,b.Kb||(b.Kb=++f))}},t:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},fa:function(){if(e)return e.ba.fa()},
|
||||
pa:function(){if(e)return e.pa}}}();a.b("computedContext",a.ca);a.b("computedContext.getDependenciesCount",a.ca.fa);a.b("computedContext.isInitial",a.ca.pa);a.m=function(b){function c(){if(0<arguments.length)return c.Ka(d,arguments[0])&&(c.P(),d=arguments[0],c.O()),this;a.k.zb(c);return d}var d=b;a.N.call(c);a.a.sa(c,a.m.fn);c.o=function(){return d};c.O=function(){c.notifySubscribers(d)};c.P=function(){c.notifySubscribers(d,"beforeChange")};a.s(c,"peek",c.o);a.s(c,"valueHasMutated",c.O);a.s(c,"valueWillMutate",
|
||||
c.P);return c};a.m.fn={equalityComparer:G};var E=a.m.hc="__ko_proto__";a.m.fn[E]=a.m;a.a.na&&a.a.ra(a.m.fn,a.N.fn);a.Ha=function(b,c){return null===b||b===p||b[E]===p?!1:b[E]===c?!0:a.Ha(b[E],c)};a.v=function(b){return a.Ha(b,a.m)};a.ub=function(b){return"function"==typeof b&&b[E]===a.m||"function"==typeof b&&b[E]===a.h&&b.Yb?!0:!1};a.b("observable",a.m);a.b("isObservable",a.v);a.b("isWriteableObservable",a.ub);a.T=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
|
||||
b=a.m(b);a.a.sa(b,a.T.fn);return b.extend({trackArrayChanges:!0})};a.T.fn={remove:function(b){for(var c=this.o(),d=[],e="function"!=typeof b||a.v(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var h=c[f];e(h)&&(0===d.length&&this.P(),d.push(h),c.splice(f,1),f--)}d.length&&this.O();return d},removeAll:function(b){if(b===p){var c=this.o(),d=c.slice(0);this.P();c.splice(0,c.length);this.O();return d}return b?this.remove(function(c){return 0<=a.a.l(b,c)}):[]},destroy:function(b){var c=this.o(),d=
|
||||
"function"!=typeof b||a.v(b)?function(a){return a===b}:b;this.P();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.O()},destroyAll:function(b){return b===p?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.l(b,c)}):[]},indexOf:function(b){var c=this();return a.a.l(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.P(),this.o()[d]=c,this.O())}};a.a.r("pop push reverse shift sort splice unshift".split(" "),function(b){a.T.fn[b]=function(){var a=this.o();
|
||||
this.P();this.kb(a,b,arguments);a=a[b].apply(a,arguments);this.O();return a}});a.a.r(["slice"],function(b){a.T.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.a.na&&a.a.ra(a.T.fn,a.m.fn);a.b("observableArray",a.T);var I="arrayChange";a.Ga.trackArrayChanges=function(b){function c(){if(!d){d=!0;var c=b.notifySubscribers;b.notifySubscribers=function(a,b){b&&b!==F||++f;return c.apply(this,arguments)};var k=[].concat(b.o()||[]);e=null;b.V(function(c){c=[].concat(c||[]);if(b.qb(I)){var d;
|
||||
if(!e||1<f)e=a.a.Aa(k,c,{sparse:!0});d=e;d.length&&b.notifySubscribers(d,I)}k=c;e=null;f=0})}}if(!b.kb){var d=!1,e=null,f=0,h=b.V;b.V=b.subscribe=function(a,b,d){d===I&&c();return h.apply(this,arguments)};b.kb=function(b,c,l){function h(a,b,c){return r[r.length]={status:a,value:b,index:c}}if(d&&!f){var r=[],m=b.length,q=l.length,s=0;switch(c){case "push":s=m;case "unshift":for(c=0;c<q;c++)h("added",l[c],s+c);break;case "pop":s=m-1;case "shift":m&&h("deleted",b[s],s);break;case "splice":c=Math.min(Math.max(0,
|
||||
0>l[0]?m+l[0]:l[0]),m);for(var m=1===q?m:Math.min(c+(l[1]||0),m),q=c+q-2,s=Math.max(m,q),B=[],u=[],D=2;c<s;++c,++D)c<m&&u.push(h("deleted",b[c],c)),c<q&&B.push(h("added",l[D],c));a.a.nb(u,B);break;default:return}e=r}}}};a.ba=a.h=function(b,c,d){function e(){q=!0;a.a.A(v,function(a,b){b.F()});v={};x=0;n=!1}function f(){var a=g.throttleEvaluation;a&&0<=a?(clearTimeout(t),t=setTimeout(h,a)):g.wa?g.wa():h()}function h(){if(!r&&!q){if(y&&y()){if(!m){p();return}}else m=!1;r=!0;try{var b=v,d=x;a.k.jb({za:function(a,
|
||||
c){q||(d&&b[c]?(v[c]=b[c],++x,delete b[c],--d):v[c]||(v[c]=a.V(f),++x))},ba:g,pa:!x});v={};x=0;try{var e=c?s.call(c):s()}finally{a.k.end(),d&&a.a.A(b,function(a,b){b.F()}),n=!1}g.Ka(l,e)&&(g.notifySubscribers(l,"beforeChange"),l=e,g.wa&&!g.throttleEvaluation||g.notifySubscribers(l))}finally{r=!1}x||p()}}function g(){if(0<arguments.length){if("function"===typeof B)B.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
|
||||
return this}n&&h();a.k.zb(g);return l}function k(){return n||0<x}var l,n=!0,r=!1,m=!1,q=!1,s=b;s&&"object"==typeof s?(d=s,s=d.read):(d=d||{},s||(s=d.read));if("function"!=typeof s)throw Error("Pass a function that returns the value of the ko.computed");var B=d.write,u=d.disposeWhenNodeIsRemoved||d.G||null,D=d.disposeWhen||d.Da,y=D,p=e,v={},x=0,t=null;c||(c=d.owner);a.N.call(g);a.a.sa(g,a.h.fn);g.o=function(){n&&!x&&h();return l};g.fa=function(){return x};g.Yb="function"===typeof d.write;g.F=function(){p()};
|
||||
g.ga=k;var w=g.Ma;g.Ma=function(a){w.call(g,a);g.wa=function(){g.bb(l);n=!0;g.cb(g)}};a.s(g,"peek",g.o);a.s(g,"dispose",g.F);a.s(g,"isActive",g.ga);a.s(g,"getDependenciesCount",g.fa);u&&(m=!0,u.nodeType&&(y=function(){return!a.a.Ea(u)||D&&D()}));!0!==d.deferEvaluation&&h();u&&k()&&u.nodeType&&(p=function(){a.a.u.Ab(u,p);e()},a.a.u.ja(u,p));return g};a.$b=function(b){return a.Ha(b,a.h)};z=a.m.hc;a.h[z]=a.m;a.h.fn={equalityComparer:G};a.h.fn[z]=a.h;a.a.na&&a.a.ra(a.h.fn,a.N.fn);a.b("dependentObservable",
|
||||
a.h);a.b("computed",a.h);a.b("isComputed",a.$b);(function(){function b(a,f,h){h=h||new d;a=f(a);if("object"!=typeof a||null===a||a===p||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var g=a instanceof Array?[]:{};h.save(a,g);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":g[c]=d;break;case "object":case "undefined":var n=h.get(d);g[c]=n!==p?n:b(d,f,h)}});return g}function c(a,b){if(a instanceof Array){for(var c=
|
||||
0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.ab=[]}a.Gb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.v(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.Gb(b);return a.a.Ya(b,c,d)};d.prototype={save:function(b,c){var d=a.a.l(this.keys,b);0<=d?this.ab[d]=c:(this.keys.push(b),this.ab.push(c))},get:function(b){b=a.a.l(this.keys,
|
||||
b);return 0<=b?this.ab[b]:p}}})();a.b("toJS",a.Gb);a.b("toJSON",a.toJSON);(function(){a.i={p:function(b){switch(a.a.B(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.Pa):7>=a.a.oa?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.i.p(b.options[b.selectedIndex]):p;default:return b.value}},X:function(b,c,d){switch(a.a.B(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.Pa,
|
||||
p);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.Pa,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===typeof c?c:""}break;case "select":if(""===c||null===c)c=p;for(var e=-1,f=0,h=b.options.length,g;f<h;++f)if(g=a.i.p(b.options[f]),g==c||""==g&&c===p){e=f;break}if(d||0<=e||c===p&&1<b.size)b.selectedIndex=e;break;default:if(null===c||c===p)c="";b.value=c}}}})();a.b("selectExtensions",a.i);a.b("selectExtensions.readValue",
|
||||
a.i.p);a.b("selectExtensions.writeValue",a.i.X);a.g=function(){function b(b){b=a.a.ta(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=[],d=b.match(e),g,m,q=0;if(d){d.push(",");for(var s=0,B;B=d[s];++s){var u=B.charCodeAt(0);if(44===u){if(0>=q){g&&c.push(m?{key:g,value:m.join("")}:{unknown:g});g=m=q=0;continue}}else if(58===u){if(!m)continue}else if(47===u&&s&&1<B.length)(u=d[s-1].match(f))&&!h[u[0]]&&(b=b.substr(b.indexOf(B)+1),d=b.match(e),d.push(","),s=-1,B="/");else if(40===u||123===u||91===
|
||||
u)++q;else if(41===u||125===u||93===u)--q;else if(!g&&!m){g=34===u||39===u?B.slice(1,-1):B;continue}m?m.push(B):m=[B]}}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,h={"in":1,"return":1,"typeof":1},g={};return{aa:[],W:g,Ra:b,qa:function(e,l){function f(b,e){var l,k=a.getBindingHandler(b);
|
||||
if(k&&k.preprocess?e=k.preprocess(e,b,f):1){if(k=g[b])l=e,0<=a.a.l(c,l)?l=!1:(k=l.match(d),l=null===k?!1:k[1]?"Object("+k[1]+")"+k[2]:l),k=l;k&&m.push("'"+b+"':function(_z){"+l+"=_z}");q&&(e="function(){return "+e+" }");h.push("'"+b+"':"+e)}}l=l||{};var h=[],m=[],q=l.valueAccessors,s="string"===typeof e?b(e):e;a.a.r(s,function(a){f(a.key||a.unknown,a.value)});m.length&&f("_ko_property_writers","{"+m.join(",")+" }");return h.join(",")},bc:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;
|
||||
return!1},va:function(b,c,d,e,g){if(b&&a.v(b))!a.ub(b)||g&&b.o()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.aa);a.b("expressionRewriting.parseObjectLiteral",a.g.Ra);a.b("expressionRewriting.preProcessBindings",a.g.qa);a.b("expressionRewriting._twoWayBindings",a.g.W);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.qa);(function(){function b(a){return 8==
|
||||
a.nodeType&&h.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function d(a,d){for(var e=a,g=1,k=[];e=e.nextSibling;){if(c(e)&&(g--,0===g))return k;k.push(e);b(e)&&g++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=w&&"\x3c!--test--\x3e"===w.createComment("test").text,h=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,
|
||||
g=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,k={ul:!0,ol:!0};a.e={Q:{},childNodes:function(a){return b(a)?d(a):a.childNodes},da:function(c){if(b(c)){c=a.e.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.Fa(c)},U:function(c,d){if(b(c)){a.e.da(c);for(var e=c.nextSibling,g=0,k=d.length;g<k;g++)e.parentNode.insertBefore(d[g],e)}else a.a.U(c,d)},yb:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},rb:function(c,
|
||||
d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):c.appendChild(d):a.e.yb(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Xb:b,lc:function(a){return(a=(f?a.text:a.nodeValue).match(h))?a[1]:null},wb:function(d){if(k[a.a.B(d)]){var g=d.firstChild;if(g){do if(1===g.nodeType){var f;f=g.firstChild;
|
||||
var h=null;if(f){do if(h)h.push(f);else if(b(f)){var q=e(f,!0);q?f=q:h=[f]}else c(f)&&(h=[f]);while(f=f.nextSibling)}if(f=h)for(h=g.nextSibling,q=0;q<f.length;q++)h?d.insertBefore(f[q],h):d.appendChild(f[q])}while(g=g.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.Q);a.b("virtualElements.emptyNode",a.e.da);a.b("virtualElements.insertAfter",a.e.rb);a.b("virtualElements.prepend",a.e.yb);a.b("virtualElements.setDomNodeChildren",a.e.U);(function(){a.J=function(){this.Nb=
|
||||
{}};a.a.extend(a.J.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=b.getAttribute("data-bind");case 8:return a.e.Xb(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingAccessors:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a,{valueAccessors:!0}):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");
|
||||
case 8:return a.e.lc(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var f=this.Nb,h=b+(e&&e.valueAccessors||""),g;if(!(g=f[h])){var k,l="with($context){with($data||{}){return{"+a.g.qa(b,e)+"}}}";k=new Function("$context","$element",l);g=f[h]=k}return g(c,d)}catch(n){throw n.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+n.message,n;}}});a.J.instance=new a.J})();a.b("bindingProvider",a.J);(function(){function b(a){return function(){return a}}function c(a){return a()}
|
||||
function d(b){return a.a.Oa(a.k.t(b),function(a,c){return function(){return b()[c]}})}function e(a,b){return d(this.getBindings.bind(this,a,b))}function f(b,c,d){var e,g=a.e.firstChild(c),k=a.J.instance,f=k.preprocessNode;if(f){for(;e=g;)g=a.e.nextSibling(e),f.call(k,e);g=a.e.firstChild(c)}for(;e=g;)g=a.e.nextSibling(e),h(b,e,d)}function h(b,c,d){var e=!0,g=1===c.nodeType;g&&a.e.wb(c);if(g&&d||a.J.instance.nodeHasBindings(c))e=k(c,null,b,d).shouldBindDescendants;e&&!n[a.a.B(c)]&&f(b,c,!g)}function g(b){var c=
|
||||
[],d={},e=[];a.a.A(b,function y(g){if(!d[g]){var k=a.getBindingHandler(g);k&&(k.after&&(e.push(g),a.a.r(k.after,function(c){if(b[c]){if(-1!==a.a.l(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));y(c)}}),e.length--),c.push({key:g,pb:k}));d[g]=!0}});return c}function k(b,d,k,f){var h=a.a.f.get(b,r);if(!d){if(h)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,r,!0)}!h&&f&&a.Eb(b,k);var l;if(d&&"function"!==
|
||||
typeof d)l=d;else{var n=a.J.instance,m=n.getBindingAccessors||e,x=a.h(function(){(l=d?d(k,b):m.call(n,b,k))&&k.D&&k.D();return l},null,{G:b});l&&x.ga()||(x=null)}var t;if(l){var w=x?function(a){return function(){return c(x()[a])}}:function(a){return l[a]},z=function(){return a.a.Oa(x?x():l,c)};z.get=function(a){return l[a]&&c(w(a))};z.has=function(a){return a in l};f=g(l);a.a.r(f,function(c){var d=c.pb.init,e=c.pb.update,g=c.key;if(8===b.nodeType&&!a.e.Q[g])throw Error("The binding '"+g+"' cannot be used with virtual elements");
|
||||
try{"function"==typeof d&&a.k.t(function(){var a=d(b,w(g),z,k.$data,k);if(a&&a.controlsDescendantBindings){if(t!==p)throw Error("Multiple bindings ("+t+" and "+g+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");t=g}}),"function"==typeof e&&a.h(function(){e(b,w(g),z,k.$data,k)},null,{G:b})}catch(f){throw f.message='Unable to process binding "'+g+": "+l[g]+'"\nMessage: '+f.message,f;}})}return{shouldBindDescendants:t===p}}
|
||||
function l(b){return b&&b instanceof a.I?b:new a.I(b)}a.d={};var n={script:!0};a.getBindingHandler=function(b){return a.d[b]};a.I=function(b,c,d,e){var g=this,k="function"==typeof b&&!a.v(b),f,h=a.h(function(){var f=k?b():b,l=a.a.c(f);c?(c.D&&c.D(),a.a.extend(g,c),h&&(g.D=h)):(g.$parents=[],g.$root=l,g.ko=a);g.$rawData=f;g.$data=l;d&&(g[d]=l);e&&e(g,c,l);return g.$data},null,{Da:function(){return f&&!a.a.eb(f)},G:!0});h.ga()&&(g.D=h,h.equalityComparer=null,f=[],h.Jb=function(b){f.push(b);a.a.u.ja(b,
|
||||
function(b){a.a.ma(f,b);f.length||(h.F(),g.D=h=p)})})};a.I.prototype.createChildContext=function(b,c,d){return new a.I(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.I.prototype.extend=function(b){return new a.I(this.D||this.$data,this,null,function(c,d){c.$rawData=d.$rawData;a.a.extend(c,"function"==typeof b?b():b)})};var r=a.a.f.L(),m=a.a.f.L();a.Eb=function(b,c){if(2==arguments.length)a.a.f.set(b,m,c),
|
||||
c.D&&c.D.Jb(b);else return a.a.f.get(b,m)};a.xa=function(b,c,d){1===b.nodeType&&a.e.wb(b);return k(b,c,l(d),!0)};a.Lb=function(c,e,g){g=l(g);return a.xa(c,"function"===typeof e?d(e.bind(null,g,c)):a.a.Oa(e,b),g)};a.gb=function(a,b){1!==b.nodeType&&8!==b.nodeType||f(l(a),b,!0)};a.fb=function(a,b){!t&&A.jQuery&&(t=A.jQuery);if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||A.document.body;h(l(a),
|
||||
b,!0)};a.Ca=function(b){switch(b.nodeType){case 1:case 8:var c=a.Eb(b);if(c)return c;if(b.parentNode)return a.Ca(b.parentNode)}return p};a.Pb=function(b){return(b=a.Ca(b))?b.$data:p};a.b("bindingHandlers",a.d);a.b("applyBindings",a.fb);a.b("applyBindingsToDescendants",a.gb);a.b("applyBindingAccessorsToNode",a.xa);a.b("applyBindingsToNode",a.Lb);a.b("contextFor",a.Ca);a.b("dataFor",a.Pb)})();var L={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.A(d,function(c,
|
||||
d){d=a.a.c(d);var h=!1===d||null===d||d===p;h&&b.removeAttribute(c);8>=a.a.oa&&c in L?(c=L[c],h?b.removeAttribute(c):b[c]=d):h||b.setAttribute(c,d.toString());"name"===c&&a.a.Cb(b,h?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):b.value}function f(){var g=b.checked,f=r?e():g;if(!a.ca.pa()&&(!k||g)){var h=a.k.t(c);l?n!==f?(g&&(a.a.Y(h,f,!0),a.a.Y(h,n,!1)),n=f):a.a.Y(h,f,g):a.g.va(h,d,"checked",
|
||||
f,!0)}}function h(){var d=a.a.c(c());b.checked=l?0<=a.a.l(d,e()):g?d:e()===d}var g="checkbox"==b.type,k="radio"==b.type;if(g||k){var l=g&&a.a.c(c())instanceof Array,n=l?e():p,r=k||l;k&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.ba(f,null,{G:b});a.a.q(b,"click",f);a.ba(h,null,{G:b})}}};a.g.W.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.A(d,function(c,d){d=a.a.c(d);a.a.ua(b,c,d)}):(d=String(d||
|
||||
""),a.a.ua(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.ua(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,f){var h=c()||{};a.a.A(h,function(g){"string"==typeof g&&a.a.q(b,g,function(b){var h,n=c()[g];if(n){try{var r=a.a.R(arguments);e=f.$data;r.unshift(e);h=n.apply(e,r)}finally{!0!==h&&(b.preventDefault?
|
||||
b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={vb:function(b){return function(){var c=b(),d=a.a.Sa(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.K.Ja};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.K.Ja}}},init:function(b,
|
||||
c){return a.d.template.init(b,a.d.foreach.vb(c))},update:function(b,c,d,e,f){return a.d.template.update(b,a.d.foreach.vb(c),d,e,f)}};a.g.aa.foreach=!1;a.e.Q.foreach=!0;a.d.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var k=b.ownerDocument;if("activeElement"in k){var f;try{f=k.activeElement}catch(h){f=k.body}e=f===b}k=c();a.g.va(k,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),h=e.bind(null,!1);a.a.q(b,"focus",f);a.a.q(b,"focusin",
|
||||
f);a.a.q(b,"blur",h);a.a.q(b,"focusout",h)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.k.t(a.a.ha,null,[b,d?"focusin":"focusout"]))}};a.g.W.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.g.W.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Va(b,c())}};H("if");H("ifnot",!1,!0);H("with",!0,!1,function(a,c){return a.createChildContext(c)});var J={};a.d.options={init:function(b){if("select"!==
|
||||
a.a.B(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.la(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function h(c,d){if(r.length){var e=0<=a.a.l(r,a.i.p(d[0]));a.a.Db(d[0],e);m&&!e&&a.k.t(a.a.ha,null,[b,"change"])}}var g=0!=b.length&&b.multiple?b.scrollTop:null,k=a.a.c(c()),l=d.get("optionsIncludeDestroyed");
|
||||
c={};var n,r;r=b.multiple?a.a.ya(e(),a.i.p):0<=b.selectedIndex?[a.i.p(b.options[b.selectedIndex])]:[];k&&("undefined"==typeof k.length&&(k=[k]),n=a.a.la(k,function(b){return l||b===p||null===b||!a.a.c(b._destroy)}),d.has("optionsCaption")&&(k=a.a.c(d.get("optionsCaption")),null!==k&&k!==p&&n.unshift(J)));var m=!1;c.beforeRemove=function(a){b.removeChild(a)};k=h;d.has("optionsAfterRender")&&(k=function(b,c){h(0,c);a.k.t(d.get("optionsAfterRender"),null,[c[0],b!==J?b:p])});a.a.Ua(b,n,function(c,e,g){g.length&&
|
||||
(r=g[0].selected?[a.i.p(g[0])]:[],m=!0);e=b.ownerDocument.createElement("option");c===J?(a.a.Xa(e,d.get("optionsCaption")),a.i.X(e,p)):(g=f(c,d.get("optionsValue"),c),a.i.X(e,a.a.c(g)),c=f(c,d.get("optionsText"),g),a.a.Xa(e,c));return[e]},c,k);a.k.t(function(){d.get("valueAllowUnset")&&d.has("value")?a.i.X(b,a.a.c(d.get("value")),!0):(b.multiple?r.length&&e().length<r.length:r.length&&0<=b.selectedIndex?a.i.p(b.options[b.selectedIndex])!==r[0]:r.length||0<=b.selectedIndex)&&a.a.ha(b,"change")});a.a.Tb(b);
|
||||
g&&20<Math.abs(g-b.scrollTop)&&(b.scrollTop=g)}};a.d.options.Pa=a.a.f.L();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.q(b,"change",function(){var e=c(),f=[];a.a.r(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.i.p(b))});a.g.va(e,d,"selectedOptions",f)})},update:function(b,c){if("select"!=a.a.B(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.r(b.getElementsByTagName("option"),function(b){var c=
|
||||
0<=a.a.l(d,a.i.p(b));a.a.Db(b,c)})}};a.g.W.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.A(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.q(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},
|
||||
update:function(b,c){a.a.Xa(b,c())}};a.e.Q.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Ob;a.a.Cb(b,d)}}};a.d.uniqueName.Ob=0;a.d.value={after:["options","foreach"],init:function(b,c,d){function e(){g=!1;var e=c(),f=a.i.p(b);a.g.va(e,d,"value",f)}var f=["change"],h=d.get("valueUpdate"),g=!1;h&&("string"==typeof h&&(h=[h]),a.a.$(f,h),f=a.a.ib(f));!a.a.oa||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||
|
||||
-1!=a.a.l(f,"propertychange")||(a.a.q(b,"propertychange",function(){g=!0}),a.a.q(b,"focus",function(){g=!1}),a.a.q(b,"blur",function(){g&&e()}));a.a.r(f,function(c){var d=e;a.a.kc(c,"after")&&(d=function(){setTimeout(e,0)},c=c.substring(5));a.a.q(b,c,d)})},update:function(b,c,d){var e=a.a.c(c());c=a.i.p(b);if(e!==c)if("select"===a.a.B(b)){var f=d.get("valueAllowUnset");d=function(){a.i.X(b,e,f)};d();f||e===a.i.p(b)?setTimeout(d,0):a.k.t(a.a.ha,null,[b,"change"])}else a.i.X(b,e)}};a.g.W.value=!0;a.d.visible=
|
||||
{update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,f,h){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,h)}}})("click");a.C=function(){};a.C.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.C.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.C.prototype.makeTemplateSource=
|
||||
function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.n.j(d)}if(1==b.nodeType||8==b.nodeType)return new a.n.Z(b);throw Error("Unknown template type: "+b);};a.C.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d)};a.C.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.C.prototype.rewriteTemplate=
|
||||
function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.C);a.Za=function(){function b(b,c,d,g){b=a.g.Ra(b);for(var k=a.g.aa,l=0;l<b.length;l++){var n=b[l].key;if(k.hasOwnProperty(n)){var r=k[n];if("function"===typeof r){if(n=r(b[l].value))throw Error(n);}else if(!r)throw Error("This template engine does not support the '"+n+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.qa(b,
|
||||
{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return g.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ub:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Za.dc(b,c)},d)},dc:function(a,f){return a.replace(c,function(a,c,d,e,n){return b(n,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e",
|
||||
"#comment",f)})},Mb:function(b,c){return a.w.Na(function(d,g){var k=d.nextSibling;k&&k.nodeName.toLowerCase()===c&&a.xa(k,b,g)})}}}();a.b("__tr_ambtns",a.Za.Mb);(function(){a.n={};a.n.j=function(a){this.j=a};a.n.j.prototype.text=function(){var b=a.a.B(this.j),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.j[b];var c=arguments[0];"innerHTML"===b?a.a.Va(this.j,c):this.j[b]=c};var b=a.a.f.L()+"_";a.n.j.prototype.data=function(c){if(1===arguments.length)return a.a.f.get(this.j,
|
||||
b+c);a.a.f.set(this.j,b+c,arguments[1])};var c=a.a.f.L();a.n.Z=function(a){this.j=a};a.n.Z.prototype=new a.n.j;a.n.Z.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.j,c)||{};b.$a===p&&b.Ba&&(b.$a=b.Ba.innerHTML);return b.$a}a.a.f.set(this.j,c,{$a:arguments[0]})};a.n.j.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.j,c)||{}).Ba;a.a.f.set(this.j,c,{Ba:arguments[0]})};a.b("templateSources",a.n);a.b("templateSources.domElement",a.n.j);a.b("templateSources.anonymousTemplate",
|
||||
a.n.Z)})();(function(){function b(b,c,d){var e;for(c=a.e.nextSibling(c);b&&(e=b)!==c;)b=a.e.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],h=e.parentNode,m=a.J.instance,q=m.preprocessNode;if(q){b(e,f,function(a,b){var c=a.previousSibling,d=q.call(m,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):(c.push(e,f),a.a.ea(c,h))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.fb(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==
|
||||
b.nodeType||a.w.Ib(b,[d])});a.a.ea(c,h)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,h,n,r){r=r||{};var m=b&&d(b),m=m&&m.ownerDocument,q=r.templateEngine||f;a.Za.Ub(h,q,m);h=q.renderTemplate(h,n,r,m);if("number"!=typeof h.length||0<h.length&&"number"!=typeof h[0].nodeType)throw Error("Template engine must return an array of DOM nodes");m=!1;switch(e){case "replaceChildren":a.e.U(b,h);m=!0;break;case "replaceNode":a.a.Bb(b,h);m=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+
|
||||
e);}m&&(c(h,n),r.afterRender&&a.k.t(r.afterRender,null,[h,n.$data]));return h}var f;a.Wa=function(b){if(b!=p&&!(b instanceof a.C))throw Error("templateEngine must inherit from ko.templateEngine");f=b};a.Ta=function(b,c,h,n,r){h=h||{};if((h.templateEngine||f)==p)throw Error("Set a template engine before calling renderTemplate");r=r||"replaceChildren";if(n){var m=d(n);return a.h(function(){var f=c&&c instanceof a.I?c:new a.I(a.a.c(c)),p=a.v(b)?b():"function"==typeof b?b(f.$data,f):b,f=e(n,r,p,f,h);
|
||||
"replaceNode"==r&&(n=f,m=d(n))},null,{Da:function(){return!m||!a.a.Ea(m)},G:m&&"replaceNode"==r?m.parentNode:m})}return a.w.Na(function(d){a.Ta(b,c,h,d,"replaceNode")})};a.jc=function(b,d,f,h,r){function m(a,b){c(b,s);f.afterRender&&f.afterRender(b,a)}function q(a,c){s=r.createChildContext(a,f.as,function(a){a.$index=c});var d="function"==typeof b?b(a,s):b;return e(null,"ignoreTargetNode",d,s,f)}var s;return a.h(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.la(b,function(b){return f.includeDestroyed||
|
||||
b===p||null===b||!a.a.c(b._destroy)});a.k.t(a.a.Ua,null,[h,b,q,f,m])},null,{G:h})};var h=a.a.f.L();a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||d.name?a.e.da(b):(d=a.e.childNodes(b),d=a.a.ec(d),(new a.n.Z(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var m=c(),q;c=a.a.c(m);d=!0;e=null;"string"==typeof c?c={}:(m=c.name,"if"in c&&(d=a.a.c(c["if"])),d&&"ifnot"in c&&(d=!a.a.c(c.ifnot)),q=a.a.c(c.data));"foreach"in c?e=a.jc(m||b,d&&c.foreach||
|
||||
[],c,b,f):d?(f="data"in c?f.createChildContext(q,c.as):f,e=a.Ta(m||b,f,c,b)):a.e.da(b);f=e;(q=a.a.f.get(b,h))&&"function"==typeof q.F&&q.F();a.a.f.set(b,h,f&&f.ga()?f:p)}};a.g.aa.template=function(b){b=a.g.Ra(b);return 1==b.length&&b[0].unknown||a.g.bc(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.e.Q.template=!0})();a.b("setTemplateEngine",a.Wa);a.b("renderTemplate",a.Ta);a.a.nb=function(a,c,d){if(a.length&&c.length){var e,f,h,g,k;for(e=
|
||||
f=0;(!d||e<d)&&(g=a[f]);++f){for(h=0;k=c[h];++h)if(g.value===k.value){g.moved=k.index;k.moved=g.index;c.splice(h,1);e=h=0;break}e+=h}}};a.a.Aa=function(){function b(b,d,e,f,h){var g=Math.min,k=Math.max,l=[],n,p=b.length,m,q=d.length,s=q-p||1,t=p+q+1,u,w,y;for(n=0;n<=p;n++)for(w=u,l.push(u=[]),y=g(q,n+s),m=k(0,n-1);m<=y;m++)u[m]=m?n?b[n-1]===d[m-1]?w[m-1]:g(w[m]||t,u[m-1]||t)+1:m+1:n+1;g=[];k=[];s=[];n=p;for(m=q;n||m;)q=l[n][m]-1,m&&q===l[n][m-1]?k.push(g[g.length]={status:e,value:d[--m],index:m}):
|
||||
n&&q===l[n-1][m]?s.push(g[g.length]={status:f,value:b[--n],index:n}):(--m,--n,h.sparse||g.push({status:"retained",value:d[m]}));a.a.nb(k,s,10*p);return g.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<=d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.Aa);(function(){function b(b,c,f,h,g){var k=[],l=a.h(function(){var l=c(f,g,a.a.ea(k,b))||[];0<k.length&&(a.a.Bb(k,l),h&&a.k.t(h,null,[f,
|
||||
l,g]));k.length=0;a.a.$(k,l)},null,{G:b,Da:function(){return!a.a.eb(k)}});return{S:k,h:l.ga()?l:p}}var c=a.a.f.L();a.a.Ua=function(d,e,f,h,g){function k(b,c){v=r[c];u!==c&&(z[b]=v);v.Ia(u++);a.a.ea(v.S,d);s.push(v);y.push(v)}function l(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.r(c[d].S,function(a){b(a,d,c[d].ka)})}e=e||[];h=h||{};var n=a.a.f.get(d,c)===p,r=a.a.f.get(d,c)||[],m=a.a.ya(r,function(a){return a.ka}),q=a.a.Aa(m,e,h.dontLimitMoves),s=[],t=0,u=0,w=[],y=[];e=[];for(var z=[],m=[],
|
||||
v,x=0,A,C;A=q[x];x++)switch(C=A.moved,A.status){case "deleted":C===p&&(v=r[t],v.h&&v.h.F(),w.push.apply(w,a.a.ea(v.S,d)),h.beforeRemove&&(e[x]=v,y.push(v)));t++;break;case "retained":k(x,t++);break;case "added":C!==p?k(x,C):(v={ka:A.value,Ia:a.m(u++)},s.push(v),y.push(v),n||(m[x]=v))}l(h.beforeMove,z);a.a.r(w,h.beforeRemove?a.M:a.removeNode);for(var x=0,n=a.e.firstChild(d),E;v=y[x];x++){v.S||a.a.extend(v,b(d,f,v.ka,g,v.Ia));for(t=0;q=v.S[t];n=q.nextSibling,E=q,t++)q!==n&&a.e.rb(d,q,E);!v.Zb&&g&&(g(v.ka,
|
||||
v.S,v.Ia),v.Zb=!0)}l(h.beforeRemove,e);l(h.afterMove,z);l(h.afterAdd,m);a.a.f.set(d,c,s)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Ua);a.K=function(){this.allowTemplateRewriting=!1};a.K.prototype=new a.C;a.K.prototype.renderTemplateSource=function(b){var c=(9>a.a.oa?0:b.nodes)?b.nodes():null;if(c)return a.a.R(c.cloneNode(!0).childNodes);b=b.text();return a.a.Qa(b)};a.K.Ja=new a.K;a.Wa(a.K.Ja);a.b("nativeTemplateEngine",a.K);(function(){a.La=function(){var a=this.ac=function(){if(!t||
|
||||
!t.tmpl)return 0;try{if(0<=t.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,f){f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=t.template(null,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=t.extend({koBindingContext:e},f.templateOptions);e=t.tmpl(h,b,e);e.appendTo(w.createElement("div"));
|
||||
t.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(t.tmpl.tag.ko_code={open:"__.push($1 || '');"},t.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.La.prototype=new a.C;var b=new a.La;0<b.ac&&a.Wa(b);a.b("jqueryTmplTemplateEngine",a.La)})()})})();})();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<bundle minify="true" runOnBuild="true">
|
||||
<file>/ClientSource/Scripts/Modules/jQuery-SignalR/jquery.signalR-1.1.2.js</file>
|
||||
<file>/ClientSource/Scripts/Modules/jQuery-SignalR/jquery.signalR-2.0.3.js</file>
|
||||
<file>/ClientSource/Scripts/Modules/jQuery-SignalR/disco-hubs.js</file>
|
||||
</bundle>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,117 @@
|
||||
/*!
|
||||
* ASP.NET SignalR JavaScript Library v2.0.3
|
||||
* http://signalr.net/
|
||||
*
|
||||
* Copyright Microsoft Open Technologies, Inc. All rights reserved.
|
||||
* Licensed under the Apache 2.0
|
||||
* https://github.com/SignalR/SignalR/blob/master/LICENSE.md
|
||||
*
|
||||
*/
|
||||
|
||||
/// <reference path="..\..\SignalR.Client.JS\Scripts\jquery-1.6.4.js" />
|
||||
/// <reference path="jquery.signalR.js" />
|
||||
(function ($, window, undefined) {
|
||||
/// <param name="$" type="jQuery" />
|
||||
"use strict";
|
||||
|
||||
if (typeof ($.signalR) !== "function") {
|
||||
throw new Error("SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/js.");
|
||||
}
|
||||
|
||||
var signalR = $.signalR;
|
||||
|
||||
function makeProxyCallback(hub, callback) {
|
||||
return function () {
|
||||
// Call the client hub method
|
||||
callback.apply(hub, $.makeArray(arguments));
|
||||
};
|
||||
}
|
||||
|
||||
function registerHubProxies(instance, shouldSubscribe) {
|
||||
var key, hub, memberKey, memberValue, subscriptionMethod;
|
||||
|
||||
for (key in instance) {
|
||||
if (instance.hasOwnProperty(key)) {
|
||||
hub = instance[key];
|
||||
|
||||
if (!(hub.hubName)) {
|
||||
// Not a client hub
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shouldSubscribe) {
|
||||
// We want to subscribe to the hub events
|
||||
subscriptionMethod = hub.on;
|
||||
} else {
|
||||
// We want to unsubscribe from the hub events
|
||||
subscriptionMethod = hub.off;
|
||||
}
|
||||
|
||||
// Loop through all members on the hub and find client hub functions to subscribe/unsubscribe
|
||||
for (memberKey in hub.client) {
|
||||
if (hub.client.hasOwnProperty(memberKey)) {
|
||||
memberValue = hub.client[memberKey];
|
||||
|
||||
if (!$.isFunction(memberValue)) {
|
||||
// Not a client hub function
|
||||
continue;
|
||||
}
|
||||
|
||||
subscriptionMethod.call(hub, memberKey, makeProxyCallback(hub, memberValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$.hubConnection.prototype.createHubProxies = function () {
|
||||
var proxies = {};
|
||||
this.starting(function () {
|
||||
// Register the hub proxies as subscribed
|
||||
// (instance, shouldSubscribe)
|
||||
registerHubProxies(proxies, true);
|
||||
|
||||
this._registerSubscribedHubs();
|
||||
}).disconnected(function () {
|
||||
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
|
||||
// (instance, shouldSubscribe)
|
||||
registerHubProxies(proxies, false);
|
||||
});
|
||||
|
||||
proxies.deviceUpdates = this.createHubProxy('deviceUpdates');
|
||||
proxies.deviceUpdates.client = { };
|
||||
proxies.deviceUpdates.server = {
|
||||
};
|
||||
|
||||
proxies.jobUpdates = this.createHubProxy('jobUpdates');
|
||||
proxies.jobUpdates.client = { };
|
||||
proxies.jobUpdates.server = {
|
||||
};
|
||||
|
||||
proxies.logNotifications = this.createHubProxy('logNotifications');
|
||||
proxies.logNotifications.client = { };
|
||||
proxies.logNotifications.server = {
|
||||
};
|
||||
|
||||
proxies.noticeboardUpdates = this.createHubProxy('noticeboardUpdates');
|
||||
proxies.noticeboardUpdates.client = { };
|
||||
proxies.noticeboardUpdates.server = {
|
||||
};
|
||||
|
||||
proxies.scheduledTaskNotifications = this.createHubProxy('scheduledTaskNotifications');
|
||||
proxies.scheduledTaskNotifications.client = { };
|
||||
proxies.scheduledTaskNotifications.server = {
|
||||
};
|
||||
|
||||
proxies.userUpdates = this.createHubProxy('userUpdates');
|
||||
proxies.userUpdates.client = { };
|
||||
proxies.userUpdates.server = {
|
||||
};
|
||||
|
||||
return proxies;
|
||||
};
|
||||
|
||||
signalR.hub = $.hubConnection("/API/Signalling", { useDefaultPath: false });
|
||||
$.extend(signalR, signalR.hub.createHubProxies());
|
||||
|
||||
}(window.jQuery, window));
|
||||
+1199
-629
File diff suppressed because it is too large
Load Diff
@@ -328,31 +328,31 @@ table.deviceProfileTable th.deviceCount {
|
||||
background-position: right top;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
#scheduledTaskStatus {
|
||||
#Logging_Task_Status {
|
||||
width: 520px;
|
||||
margin: 40px auto 60px auto;
|
||||
}
|
||||
#scheduledTaskStatus th.process {
|
||||
#Logging_Task_Status th.process {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
background-color: #f4f4f4;
|
||||
min-height: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#scheduledTaskStatus td.description {
|
||||
#Logging_Task_Status td.description {
|
||||
font-size: 0.9em;
|
||||
min-height: 60px;
|
||||
}
|
||||
#scheduledTaskStatus td.progress {
|
||||
#Logging_Task_Status td.progress {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
#scheduledTaskStatus td.finishedRedirect {
|
||||
#Logging_Task_Status td.finishedRedirect {
|
||||
background-position: right center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(data:image/gif;base64,R0lGODlhEAALAPQAAP///zNah+Hm7dng6O7x9DddiTNah1d3nJqtw3+Xs8fS3k5vlm6JqaGzx4KatcrU4FFymDZciHGMq+ru8t/l7Pb3+V9+oeLo7vT2+MTP3LLB0dTc5fHz9gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA) /*Images/Status/loading.gif*/;
|
||||
padding-right: 20px;
|
||||
}
|
||||
#scheduledTaskStatus td.exception {
|
||||
#Logging_Task_Status td.exception {
|
||||
background-color: #FFD8D8;
|
||||
}
|
||||
div.logEventsViewport {
|
||||
|
||||
@@ -270,7 +270,7 @@ table.deviceProfileTable {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#scheduledTaskStatus {
|
||||
#Logging_Task_Status {
|
||||
width: 520px;
|
||||
margin: 40px auto 60px auto;
|
||||
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user