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,6 +12,7 @@ namespace Disco.BI.DocumentTemplateBI.Importer
|
|||||||
|
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
public override bool SingleInstanceTask { get { return true; } }
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
|
public override bool LogExceptionsOnly { get { return true; } }
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace Disco.BI.Expressions
|
|||||||
public override string TaskName { get { return "Expression Cache - Preload Task"; } }
|
public override string TaskName { get { return "Expression Cache - Preload Task"; } }
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
public override bool SingleInstanceTask { get { return true; } }
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
|
public override bool LogExceptionsOnly { get { return true; } }
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
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);
|
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 request = BuildRequest(Database);
|
||||||
//var requestJson = JsonConvert.SerializeObject(request);
|
|
||||||
|
|
||||||
if (status != null)
|
status.UpdateStatus(40, "Sending Request");
|
||||||
status.UpdateStatus(40, "Sending Request");
|
|
||||||
|
|
||||||
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
||||||
|
|
||||||
@@ -61,21 +58,18 @@ namespace Disco.BI.Interop.Community
|
|||||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateRequestV1));
|
XmlSerializer xml = new XmlSerializer(typeof(UpdateRequestV1));
|
||||||
xml.Serialize(wrStream, request);
|
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())
|
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
||||||
{
|
{
|
||||||
if (webResponse.StatusCode == HttpStatusCode.OK)
|
if (webResponse.StatusCode == HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
if (status != null)
|
status.UpdateStatus(90, "Reading Response");
|
||||||
status.UpdateStatus(90, "Reading Response");
|
|
||||||
UpdateResponse result;
|
UpdateResponse result;
|
||||||
using (var wResStream = webResponse.GetResponseStream())
|
using (var wResStream = webResponse.GetResponseStream())
|
||||||
{
|
{
|
||||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateResponse));
|
XmlSerializer xml = new XmlSerializer(typeof(UpdateResponse));
|
||||||
result = (UpdateResponse)xml.Deserialize(wResStream);
|
result = (UpdateResponse)xml.Deserialize(wResStream);
|
||||||
}
|
}
|
||||||
//var result = JsonConvert.DeserializeObject<UpdateResponse>(responseContent);
|
|
||||||
Database.DiscoConfiguration.UpdateLastCheck = result;
|
Database.DiscoConfiguration.UpdateLastCheck = result;
|
||||||
Database.SaveChanges();
|
Database.SaveChanges();
|
||||||
|
|
||||||
@@ -85,8 +79,7 @@ namespace Disco.BI.Interop.Community
|
|||||||
}
|
}
|
||||||
else
|
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;
|
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 string TaskName { get { return "Job Statistics - Daily Opened/Closed Task"; } }
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
public override bool SingleInstanceTask { get { return true; } }
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
|
public override bool LogExceptionsOnly { get { return true; } }
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,32 +46,6 @@
|
|||||||
<Reference Include="itextsharp">
|
<Reference Include="itextsharp">
|
||||||
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
||||||
</Reference>
|
</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">
|
<Reference Include="Quartz">
|
||||||
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -172,13 +146,6 @@
|
|||||||
<Compile Include="BI\Interop\MimeTypes.cs" />
|
<Compile Include="BI\Interop\MimeTypes.cs" />
|
||||||
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
||||||
<Compile Include="BI\Interop\Pdf\PdfImporter.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\Statistics\DailyOpenedClosed.cs" />
|
||||||
<Compile Include="BI\JobBI\Utilities.cs" />
|
<Compile Include="BI\JobBI\Utilities.cs" />
|
||||||
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
||||||
@@ -235,7 +202,7 @@
|
|||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<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>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
<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-Core" version="2.1.30214.0" targetFramework="net45" />
|
||||||
<package id="Rx-Interfaces" 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" />
|
<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\JobTableStatusItemModel.cs" />
|
||||||
<Compile Include="Services\Jobs\JobLists\JobTableStatusQueueItemModel.cs" />
|
<Compile Include="Services\Jobs\JobLists\JobTableStatusQueueItemModel.cs" />
|
||||||
<Compile Include="Services\Jobs\JobQueues\IJobQueueToken.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\DeviceSearchResultItem.cs" />
|
||||||
<Compile Include="Services\Searching\ISearchResultItem.cs" />
|
<Compile Include="Services\Searching\ISearchResultItem.cs" />
|
||||||
<Compile Include="Services\Searching\JobSearchResultItem.cs" />
|
<Compile Include="Services\Searching\JobSearchResultItem.cs" />
|
||||||
@@ -151,7 +152,7 @@
|
|||||||
<Compile Include="UI\Config\JobQueue\ConfigJobQueueIndexModel.cs" />
|
<Compile Include="UI\Config\JobQueue\ConfigJobQueueIndexModel.cs" />
|
||||||
<Compile Include="UI\Config\JobQueue\ConfigJobQueueShowModel.cs" />
|
<Compile Include="UI\Config\JobQueue\ConfigJobQueueShowModel.cs" />
|
||||||
<Compile Include="UI\Config\Logging\ConfigLoggingIndexModel.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\Config\Organisation\ConfigOrganisationIndexModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceAddOfflineModel.cs" />
|
<Compile Include="UI\Device\DeviceAddOfflineModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceExportModel.cs" />
|
<Compile Include="UI\Device\DeviceExportModel.cs" />
|
||||||
@@ -175,7 +176,7 @@
|
|||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<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>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<PropertyGroup>
|
<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.Text;
|
||||||
using System.Threading.Tasks;
|
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; }
|
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 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");
|
TaskStatus.UpdateStatus(15, "Building metadata and database query");
|
||||||
var metadata = Options.BuildMetadata();
|
var metadata = Options.BuildMetadata();
|
||||||
@@ -32,15 +32,17 @@ namespace Disco.Services.Devices.Exporting
|
|||||||
Options.AssignedUserEmailAddress)
|
Options.AssignedUserEmailAddress)
|
||||||
{
|
{
|
||||||
TaskStatus.UpdateStatus(20, "Updating Assigned User details");
|
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
|
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
|
// Update Last Network Logon Date
|
||||||
@@ -49,8 +51,16 @@ namespace Disco.Services.Devices.Exporting
|
|||||||
TaskStatus.UpdateStatus(40, "Updating device last network logon dates");
|
TaskStatus.UpdateStatus(40, "Updating device last network logon dates");
|
||||||
try
|
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();
|
Database.SaveChanges();
|
||||||
|
|
||||||
|
TaskStatus.IgnoreCurrentProcessChanges = false;
|
||||||
|
TaskStatus.ProgressMultiplier = 1;
|
||||||
|
TaskStatus.ProgressOffset = 0;
|
||||||
}
|
}
|
||||||
catch (Exception) { } // Ignore Errors
|
catch (Exception) { } // Ignore Errors
|
||||||
}
|
}
|
||||||
@@ -103,7 +113,7 @@ namespace Disco.Services.Devices.Exporting
|
|||||||
return GenerateExport(Database, Devices, Options, ScheduledTaskMockStatus.Create());
|
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)
|
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();
|
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)
|
if (Context.Header == null)
|
||||||
throw new InvalidOperationException("The Import Context has not been initialized");
|
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]))
|
.Select(h => new Tuple<string, DeviceImportFieldTypes, Func<string[], string>, Type>(h.Item1, h.Item2, (f) => f[h.Item3], DeviceImport.FieldHandlers.Value[h.Item2]))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
DateTime nextProgress = DateTime.Now;
|
|
||||||
Status.UpdateStatus(0, "Parsing Import Records", "Starting...");
|
Status.UpdateStatus(0, "Parsing Import Records", "Starting...");
|
||||||
|
|
||||||
Context.Records = Context.RawData.Select((d, recordIndex) =>
|
Context.Records = Context.RawData.Select((d, recordIndex) =>
|
||||||
{
|
{
|
||||||
string deviceSerialNumber = Fields.DeviceSerialNumberImportField.ParseRawDeviceSerialNumber(d[Context.HeaderDeviceSerialNumberIndex]);
|
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));
|
||||||
{
|
|
||||||
Status.UpdateStatus(((double)recordIndex / Context.RawData.Count) * 100, string.Format("Parsing: {0}", deviceSerialNumber));
|
|
||||||
nextProgress = DateTime.Now.AddSeconds(.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
Device existingDevice = null;
|
Device existingDevice = null;
|
||||||
if (Fields.DeviceSerialNumberImportField.IsDeviceSerialNumberValid(deviceSerialNumber))
|
if (Fields.DeviceSerialNumberImportField.IsDeviceSerialNumberValid(deviceSerialNumber))
|
||||||
@@ -170,7 +165,7 @@ namespace Disco.Services.Devices.Importing
|
|||||||
}).Cast<IDeviceImportRecord>().ToList();
|
}).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)
|
if (Context.Records == null)
|
||||||
throw new InvalidOperationException("Import Records have not been parsed");
|
throw new InvalidOperationException("Import Records have not been parsed");
|
||||||
@@ -178,18 +173,13 @@ namespace Disco.Services.Devices.Importing
|
|||||||
if (Context.Records.Count == 0)
|
if (Context.Records.Count == 0)
|
||||||
throw new InvalidOperationException("There are no records to import");
|
throw new InvalidOperationException("There are no records to import");
|
||||||
|
|
||||||
DateTime nextProgress = DateTime.Now;
|
|
||||||
Status.UpdateStatus(0, "Applying Import Records to Database", "Starting...");
|
Status.UpdateStatus(0, "Applying Import Records to Database", "Starting...");
|
||||||
|
|
||||||
int affectedRecords = 0;
|
int affectedRecords = 0;
|
||||||
|
|
||||||
foreach (var record in Context.Records.Cast<DeviceImportRecord>().Select((r, i) => Tuple.Create(r, i)))
|
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));
|
||||||
{
|
|
||||||
Status.UpdateStatus(((double)record.Item2 / Context.Records.Count) * 100, string.Format("Applying: {0}", record.Item1.DeviceSerialNumber));
|
|
||||||
nextProgress = DateTime.Now.AddSeconds(.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (record.Item1.Apply(Database))
|
if (record.Item1.Apply(Database))
|
||||||
affectedRecords++;
|
affectedRecords++;
|
||||||
|
|||||||
@@ -42,21 +42,21 @@
|
|||||||
<Reference Include="LumenWorks.Framework.IO">
|
<Reference Include="LumenWorks.Framework.IO">
|
||||||
<HintPath>..\packages\LumenWorks.Framework.IO.3.8.0\lib\net20\LumenWorks.Framework.IO.dll</HintPath>
|
<HintPath>..\packages\LumenWorks.Framework.IO.3.8.0\lib\net20\LumenWorks.Framework.IO.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.AspNet.SignalR.Core">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.2.0.3\lib\net45\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Owin">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Microsoft.Owin.2.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.1.2\lib\net45\Microsoft.AspNet.SignalR.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>
|
||||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Newtonsoft.Json.5.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Owin">
|
<Reference Include="Owin">
|
||||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
<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\DeviceSerialNumberImportField.cs" />
|
||||||
<Compile Include="Devices\Importing\Fields\ModelIdImportField.cs" />
|
<Compile Include="Devices\Importing\Fields\ModelIdImportField.cs" />
|
||||||
<Compile Include="Devices\Importing\IDeviceImportCache.cs" />
|
<Compile Include="Devices\Importing\IDeviceImportCache.cs" />
|
||||||
|
<Compile Include="Devices\DeviceUpdatesHub.cs" />
|
||||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||||
|
<Compile Include="Extensions\RxExtensions.cs" />
|
||||||
<Compile Include="Extensions\StringExtensions.cs" />
|
<Compile Include="Extensions\StringExtensions.cs" />
|
||||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
||||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
|
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
|
||||||
@@ -227,6 +229,11 @@
|
|||||||
<Compile Include="Jobs\JobQueues\JobQueueService.cs" />
|
<Compile Include="Jobs\JobQueues\JobQueueService.cs" />
|
||||||
<Compile Include="Jobs\JobQueues\JobQueueToken.cs" />
|
<Compile Include="Jobs\JobQueues\JobQueueToken.cs" />
|
||||||
<Compile Include="Jobs\JobLists\ManagedJobList.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\LogBase.cs" />
|
||||||
<Compile Include="Logging\LogContext.cs" />
|
<Compile Include="Logging\LogContext.cs" />
|
||||||
<Compile Include="Logging\LogReInitalizeJob.cs" />
|
<Compile Include="Logging\LogReInitalizeJob.cs" />
|
||||||
@@ -236,9 +243,8 @@
|
|||||||
<Compile Include="Logging\Models\LogModule.cs" />
|
<Compile Include="Logging\Models\LogModule.cs" />
|
||||||
<Compile Include="Logging\ReadLogContext.cs" />
|
<Compile Include="Logging\ReadLogContext.cs" />
|
||||||
<Compile Include="Logging\SystemLog.cs" />
|
<Compile Include="Logging\SystemLog.cs" />
|
||||||
<Compile Include="Logging\Targets\LogLiveContext.cs" />
|
<Compile Include="Logging\Persistance\LogPersistContext.cs" />
|
||||||
<Compile Include="Logging\Targets\LogPersistContext.cs" />
|
<Compile Include="Logging\Persistance\LogPersistContextInitializer.cs" />
|
||||||
<Compile Include="Logging\Targets\LogPersistContextInitializer.cs" />
|
|
||||||
<Compile Include="Logging\Utilities.cs" />
|
<Compile Include="Logging\Utilities.cs" />
|
||||||
<Compile Include="Plugins\CommunityInterop\PluginLibraryUpdateTask.cs" />
|
<Compile Include="Plugins\CommunityInterop\PluginLibraryUpdateTask.cs" />
|
||||||
<Compile Include="Plugins\Features\UIExtension\Results\LiteralResult.cs" />
|
<Compile Include="Plugins\Features\UIExtension\Results\LiteralResult.cs" />
|
||||||
@@ -278,9 +284,10 @@
|
|||||||
<Compile Include="Plugins\WebPageHelper.cs" />
|
<Compile Include="Plugins\WebPageHelper.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Searching\Search.cs" />
|
<Compile Include="Searching\Search.cs" />
|
||||||
<Compile Include="Tasks\IScheduledTaskBasicStatus.cs" />
|
<Compile Include="Tasks\IScheduledTaskStatus.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTask.cs" />
|
<Compile Include="Tasks\ScheduledTask.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTaskMockStatus.cs" />
|
<Compile Include="Tasks\ScheduledTaskMockStatus.cs" />
|
||||||
|
<Compile Include="Tasks\ScheduledTaskNotificationsHub.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTasks.cs" />
|
<Compile Include="Tasks\ScheduledTasks.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTasksLog.cs" />
|
<Compile Include="Tasks\ScheduledTasksLog.cs" />
|
||||||
<Compile Include="Tasks\ScheduledTaskStatus.cs" />
|
<Compile Include="Tasks\ScheduledTaskStatus.cs" />
|
||||||
@@ -290,17 +297,24 @@
|
|||||||
<Compile Include="Users\CacheCleanTask.cs" />
|
<Compile Include="Users\CacheCleanTask.cs" />
|
||||||
<Compile Include="Users\UserExtensions.cs" />
|
<Compile Include="Users\UserExtensions.cs" />
|
||||||
<Compile Include="Users\UserService.cs" />
|
<Compile Include="Users\UserService.cs" />
|
||||||
|
<Compile Include="Users\UserUpdatesHub.cs" />
|
||||||
<Compile Include="Web\AuthorizedController.cs" />
|
<Compile Include="Web\AuthorizedController.cs" />
|
||||||
<Compile Include="Web\AuthorizedDatabaseController.cs" />
|
<Compile Include="Web\AuthorizedDatabaseController.cs" />
|
||||||
<Compile Include="Web\BaseController.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\BundleExtensions.cs" />
|
||||||
<Compile Include="Web\Bundles\BundleHandler.cs" />
|
<Compile Include="Web\Bundles\BundleHandler.cs" />
|
||||||
<Compile Include="Web\Bundles\BundleModule.cs" />
|
<Compile Include="Web\Bundles\BundleModule.cs" />
|
||||||
<Compile Include="Web\Bundles\BundleTable.cs" />
|
<Compile Include="Web\Bundles\BundleTable.cs" />
|
||||||
|
<Compile Include="Web\Bundles\UrlBundle.cs" />
|
||||||
<Compile Include="Web\DatabaseController.cs" />
|
<Compile Include="Web\DatabaseController.cs" />
|
||||||
<Compile Include="Web\HandleErrorAttribute.cs" />
|
<Compile Include="Web\HandleErrorAttribute.cs" />
|
||||||
<Compile Include="Web\HelperExtensions.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" />
|
<Compile Include="Web\WebViewPage.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -328,7 +342,7 @@
|
|||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<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>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<PropertyGroup>
|
<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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateLastNetworkLogonDates(DiscoDataContext Database, IScheduledTaskBasicStatus status)
|
public static void UpdateLastNetworkLogonDates(DiscoDataContext Database, IScheduledTaskStatus status)
|
||||||
{
|
{
|
||||||
var context = ActiveDirectory.Context;
|
var context = ActiveDirectory.Context;
|
||||||
const string ldapFilter = "(objectCategory=Computer)";
|
const string ldapFilter = "(objectCategory=Computer)";
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace Disco.Services.Jobs.JobQueues
|
|||||||
|
|
||||||
return _cache.UpdateQueue(JobQueue);
|
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);
|
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
|
// Add Modules
|
||||||
var existingModules = LogDatabase.Modules.Include("EventTypes").ToDictionary(m => m.Id);
|
var existingModules = LogDatabase.Modules.Include("EventTypes").ToDictionary(m => m.Id);
|
||||||
@@ -183,7 +183,7 @@ namespace Disco.Services.Logging
|
|||||||
if (!File.Exists(logPath))
|
if (!File.Exists(logPath))
|
||||||
{
|
{
|
||||||
// Create Database
|
// Create Database
|
||||||
using (var context = new Targets.LogPersistContext(connectionString))
|
using (var context = new Persistance.LogPersistContext(connectionString))
|
||||||
{
|
{
|
||||||
context.Database.CreateIfNotExists();
|
context.Database.CreateIfNotExists();
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ namespace Disco.Services.Logging
|
|||||||
|
|
||||||
// Add Modules/Event Types
|
// Add Modules/Event Types
|
||||||
InitalizeModules();
|
InitalizeModules();
|
||||||
using (var context = new Targets.LogPersistContext(connectionString))
|
using (var context = new Persistance.LogPersistContext(connectionString))
|
||||||
{
|
{
|
||||||
InitalizeDatabase(context);
|
InitalizeDatabase(context);
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ namespace Disco.Services.Logging
|
|||||||
sqlCeCSB.DataSource = yesterdaysLogPath;
|
sqlCeCSB.DataSource = yesterdaysLogPath;
|
||||||
var connectionString = sqlCeCSB.ToString();
|
var connectionString = sqlCeCSB.ToString();
|
||||||
int logCount;
|
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();
|
logCount = context.Events.Where(e => !(e.ModuleId == 0 && e.EventTypeId == 100)).Count();
|
||||||
if (logCount == 0)
|
if (logCount == 0)
|
||||||
@@ -267,7 +267,7 @@ namespace Disco.Services.Logging
|
|||||||
var eventTimestamp = DateTime.Now;
|
var eventTimestamp = DateTime.Now;
|
||||||
if (eventType.UseLive)
|
if (eventType.UseLive)
|
||||||
{
|
{
|
||||||
Targets.LogLiveContext.Broadcast(logModule, eventType, eventTimestamp, Args);
|
LogNotificationsHub.BroadcastLog(logModule, eventType, eventTimestamp, Args);
|
||||||
}
|
}
|
||||||
if (eventType.UsePersist)
|
if (eventType.UsePersist)
|
||||||
{
|
{
|
||||||
@@ -276,7 +276,7 @@ namespace Disco.Services.Logging
|
|||||||
{
|
{
|
||||||
args = JsonConvert.SerializeObject(Args);
|
args = JsonConvert.SerializeObject(Args);
|
||||||
}
|
}
|
||||||
using (var context = new Targets.LogPersistContext(PersistantStoreConnectionString))
|
using (var context = new Persistance.LogPersistContext(PersistantStoreConnectionString))
|
||||||
{
|
{
|
||||||
var e = new Models.LogEvent()
|
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;
|
||||||
using System.Data.Entity.Infrastructure;
|
using System.Data.Entity.Infrastructure;
|
||||||
|
|
||||||
namespace Disco.Services.Logging.Targets
|
namespace Disco.Services.Logging.Persistance
|
||||||
{
|
{
|
||||||
public class LogPersistContext : DbContext
|
public class LogPersistContext : DbContext
|
||||||
{
|
{
|
||||||
+1
-1
@@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Disco.Services.Logging.Targets
|
namespace Disco.Services.Logging.Persistance
|
||||||
{
|
{
|
||||||
public class LogPersistContextInitializer : IDatabaseInitializer<LogPersistContext>
|
public class LogPersistContextInitializer : IDatabaseInitializer<LogPersistContext>
|
||||||
{
|
{
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using System;
|
using Disco.Data.Repository;
|
||||||
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.Services.Logging.Models;
|
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
|
namespace Disco.Services.Logging
|
||||||
{
|
{
|
||||||
@@ -45,7 +44,7 @@ namespace Disco.Services.Logging
|
|||||||
|
|
||||||
var logModules = LogContext.LogModules;
|
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);
|
var query = this.BuildQuery(context, logFile.Item2, results.Count);
|
||||||
IEnumerable<LogEvent> queryResults = query; // Run the Query
|
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._resource = Resource;
|
||||||
this._resourceUrl = Source.PluginManifest.WebResourceUrl(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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<string>();
|
deferredBundles = new List<string>();
|
||||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(this._resourceUrl))
|
if (!deferredBundles.Contains(this._resourceUrl))
|
||||||
deferredBundles.Add(this._resourceUrl);
|
deferredBundles.Add(this._resourceUrl);
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ namespace Disco.Services.Plugins.Features.UIExtension.Results
|
|||||||
|
|
||||||
if (this._placeInPageHead)
|
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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<string>();
|
deferredBundles = new List<string>();
|
||||||
HttpContext.Current.Items[Bundle.UIExtensionScriptsKey] = deferredBundles;
|
HttpContext.Current.Items[BundleTable.UIExtensionScriptsKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(this._resourceUrl))
|
if (!deferredBundles.Contains(this._resourceUrl))
|
||||||
deferredBundles.Add(this._resourceUrl);
|
deferredBundles.Add(this._resourceUrl);
|
||||||
|
|||||||
@@ -98,11 +98,11 @@ namespace Disco.Services.Plugins
|
|||||||
{
|
{
|
||||||
var resourceUrl = manifest.WebResourceUrl(Resource);
|
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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<string>();
|
deferredBundles = new List<string>();
|
||||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(resourceUrl))
|
if (!deferredBundles.Contains(resourceUrl))
|
||||||
deferredBundles.Add(resourceUrl);
|
deferredBundles.Add(resourceUrl);
|
||||||
@@ -111,11 +111,11 @@ namespace Disco.Services.Plugins
|
|||||||
{
|
{
|
||||||
var resourcePath = manifest.WebResourceUrl(Resource);
|
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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<string>();
|
deferredBundles = new List<string>();
|
||||||
HttpContext.Current.Items[Bundle.UIExtensionScriptsKey] = deferredBundles;
|
HttpContext.Current.Items[BundleTable.UIExtensionScriptsKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(resourcePath))
|
if (!deferredBundles.Contains(resourcePath))
|
||||||
deferredBundles.Add(resourcePath);
|
deferredBundles.Add(resourcePath);
|
||||||
@@ -223,7 +223,9 @@ namespace Disco.Services.Plugins
|
|||||||
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, PluginAction = PluginAction });
|
var routeValues = new RouteValueDictionary(new { PluginId = manifest.Id, PluginAction = PluginAction });
|
||||||
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
|
string pluginActionUrl = UrlHelper.GenerateUrl("Plugin", null, null, routeValues, RouteTable.Routes, ViewPage.ViewContext.RequestContext, false);
|
||||||
|
|
||||||
|
#pragma warning disable 618
|
||||||
return ViewPage.FormHelper(pluginActionUrl, method, htmlAttributes);
|
return ViewPage.FormHelper(pluginActionUrl, method, htmlAttributes);
|
||||||
|
#pragma warning restore 618
|
||||||
}
|
}
|
||||||
[Obsolete("Inherit ViewPages from 'Disco.Services.Plugins.WebViewPage' instead.")]
|
[Obsolete("Inherit ViewPages from 'Disco.Services.Plugins.WebViewPage' instead.")]
|
||||||
public static MvcForm DiscoPluginActionBeginForm<T>(this WebViewPage<T> ViewPage, string PluginAction, FormMethod method)
|
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);
|
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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<HtmlString>();
|
deferredBundles = new List<HtmlString>();
|
||||||
HttpContext.Current.Items[Bundle.UIExtensionCssKey] = deferredBundles;
|
HttpContext.Current.Items[BundleTable.UIExtensionCssKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(pluginResourceUrlHtml))
|
if (!deferredBundles.Contains(pluginResourceUrlHtml))
|
||||||
deferredBundles.Add(pluginResourceUrlHtml);
|
deferredBundles.Add(pluginResourceUrlHtml);
|
||||||
|
|||||||
+19
-1
@@ -6,12 +6,22 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Disco.Services.Tasks
|
namespace Disco.Services.Tasks
|
||||||
{
|
{
|
||||||
public interface IScheduledTaskBasicStatus
|
public interface IScheduledTaskStatus
|
||||||
{
|
{
|
||||||
byte Progress { get; }
|
byte Progress { get; }
|
||||||
string CurrentProcess { get; }
|
string CurrentProcess { get; }
|
||||||
string CurrentDescription { 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(byte Progress);
|
||||||
void UpdateStatus(double Progress);
|
void UpdateStatus(double Progress);
|
||||||
void UpdateStatus(string CurrentDescription);
|
void UpdateStatus(string CurrentDescription);
|
||||||
@@ -19,5 +29,13 @@ namespace Disco.Services.Tasks
|
|||||||
void UpdateStatus(double Progress, string CurrentDescription);
|
void UpdateStatus(double Progress, string CurrentDescription);
|
||||||
void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription);
|
void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription);
|
||||||
void UpdateStatus(double 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 CancelInitiallySupported { get { return true; } }
|
||||||
public virtual bool SingleInstanceTask { 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 virtual bool LogExceptionsOnly { get { return false; } }
|
||||||
|
|
||||||
public abstract string TaskName { get; }
|
public abstract string TaskName { get; }
|
||||||
protected abstract void ExecuteTask();
|
protected abstract void ExecuteTask();
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,30 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Disco.Services.Tasks
|
namespace Disco.Services.Tasks
|
||||||
{
|
{
|
||||||
public class ScheduledTaskMockStatus : IScheduledTaskBasicStatus
|
public class ScheduledTaskMockStatus : IScheduledTaskStatus
|
||||||
{
|
{
|
||||||
private byte progress;
|
public byte Progress { get; set; }
|
||||||
private string currentProcess;
|
public string CurrentProcess { get; set; }
|
||||||
private string currentDescription;
|
public string CurrentDescription { get; set; }
|
||||||
|
|
||||||
public byte Progress { get { return this.progress; } }
|
public bool IgnoreCurrentProcessChanges { get; set; }
|
||||||
public string CurrentProcess { get { return this.currentProcess; } }
|
public bool IgnoreCurrentDescription { get; set; }
|
||||||
public string CurrentDescription { get { return this.currentDescription; } }
|
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)
|
public void UpdateStatus(byte Progress)
|
||||||
{
|
{
|
||||||
this.progress = Progress;
|
this.Progress = CalculateProgressValue(Progress);
|
||||||
}
|
}
|
||||||
public void UpdateStatus(double Progress)
|
public void UpdateStatus(double Progress)
|
||||||
{
|
{
|
||||||
@@ -26,12 +37,14 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
public void UpdateStatus(string CurrentDescription)
|
public void UpdateStatus(string CurrentDescription)
|
||||||
{
|
{
|
||||||
this.currentDescription = CurrentDescription;
|
if (!IgnoreCurrentDescription)
|
||||||
|
this.CurrentDescription = CurrentDescription;
|
||||||
}
|
}
|
||||||
public void UpdateStatus(byte Progress, string CurrentDescription)
|
public void UpdateStatus(byte Progress, string CurrentDescription)
|
||||||
{
|
{
|
||||||
this.progress = Progress;
|
this.Progress = CalculateProgressValue(Progress);
|
||||||
this.currentDescription = CurrentDescription;
|
if (!IgnoreCurrentDescription)
|
||||||
|
this.CurrentDescription = CurrentDescription;
|
||||||
}
|
}
|
||||||
public void UpdateStatus(double Progress, string 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)
|
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
|
||||||
{
|
{
|
||||||
this.progress = Progress;
|
this.Progress = CalculateProgressValue(Progress);
|
||||||
this.currentProcess = CurrentProcess;
|
if (!IgnoreCurrentProcessChanges)
|
||||||
this.currentDescription = CurrentDescription;
|
this.CurrentProcess = CurrentProcess;
|
||||||
|
if (!IgnoreCurrentDescription)
|
||||||
|
this.CurrentDescription = CurrentDescription;
|
||||||
}
|
}
|
||||||
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
|
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
|
||||||
{
|
{
|
||||||
UpdateStatus((byte)Progress, CurrentProcess, 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()
|
public static ScheduledTaskMockStatus Create()
|
||||||
{
|
{
|
||||||
return new ScheduledTaskMockStatus();
|
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
|
namespace Disco.Services.Tasks
|
||||||
{
|
{
|
||||||
public class ScheduledTaskStatus : IScheduledTaskBasicStatus
|
using ChangedItem = KeyValuePair<string, object>;
|
||||||
|
|
||||||
|
public class ScheduledTaskStatus : IScheduledTaskStatus
|
||||||
{
|
{
|
||||||
#region Backing Fields
|
#region Backing Fields
|
||||||
|
|
||||||
@@ -52,6 +54,11 @@ namespace Disco.Services.Tasks
|
|||||||
public string CurrentProcess { get { return this._currentProcess; } }
|
public string CurrentProcess { get { return this._currentProcess; } }
|
||||||
public string CurrentDescription { get { return this._currentDescription; } }
|
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 Exception TaskException { get { return this._taskException; } }
|
||||||
public bool CancelSupported { get { return this._cancelSupported; } }
|
public bool CancelSupported { get { return this._cancelSupported; } }
|
||||||
public bool IsCanceling { get { return this._isCanceling; } }
|
public bool IsCanceling { get { return this._isCanceling; } }
|
||||||
@@ -73,21 +80,13 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CompletionTask
|
public Task CompletionTask { get { return _tcs.Task; } }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tcs.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
public delegate void UpdatedBroadcastEvent(ScheduledTaskStatusLive SessionStatus);
|
public delegate void UpdatedEvent(ScheduledTaskStatus sender, KeyValuePair<string, object>[] ChangedProperties);
|
||||||
public delegate void UpdatedEvent(ScheduledTaskStatus sender, string[] ChangedProperties);
|
|
||||||
public delegate void CancelingEvent(ScheduledTaskStatus sender);
|
public delegate void CancelingEvent(ScheduledTaskStatus sender);
|
||||||
public static event UpdatedBroadcastEvent UpdatedBroadcast;
|
|
||||||
public event UpdatedEvent Updated;
|
public event UpdatedEvent Updated;
|
||||||
public event CancelingEvent Canceling;
|
public event CancelingEvent Canceling;
|
||||||
#endregion
|
#endregion
|
||||||
@@ -112,10 +111,15 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Progress Actions
|
#region Progress Actions
|
||||||
|
private byte CalculateProgressValue(byte Progress)
|
||||||
|
{
|
||||||
|
return (byte)((Progress * this.ProgressMultiplier) + this.ProgressOffset);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateStatus(byte Progress)
|
public void UpdateStatus(byte Progress)
|
||||||
{
|
{
|
||||||
this._progress = Progress;
|
this._progress = CalculateProgressValue(Progress);
|
||||||
UpdateTriggered(new string[] { "Progress" });
|
UpdateTriggered("Progress", this._progress);
|
||||||
}
|
}
|
||||||
public void UpdateStatus(double Progress)
|
public void UpdateStatus(double Progress)
|
||||||
{
|
{
|
||||||
@@ -123,14 +127,27 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
public void UpdateStatus(string CurrentDescription)
|
public void UpdateStatus(string CurrentDescription)
|
||||||
{
|
{
|
||||||
this._currentDescription = CurrentDescription;
|
if (!IgnoreCurrentDescription)
|
||||||
UpdateTriggered(new string[] { "CurrentDescription" });
|
{
|
||||||
|
this._currentDescription = CurrentDescription;
|
||||||
|
UpdateTriggered("CurrentDescription", this._currentDescription);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void UpdateStatus(byte Progress, string CurrentDescription)
|
public void UpdateStatus(byte Progress, string CurrentDescription)
|
||||||
{
|
{
|
||||||
this._progress = Progress;
|
this._progress = CalculateProgressValue(Progress);
|
||||||
this._currentDescription = CurrentDescription;
|
|
||||||
UpdateTriggered(new string[] { "Progress", "CurrentDescription" });
|
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)
|
public void UpdateStatus(double Progress, string CurrentDescription)
|
||||||
{
|
{
|
||||||
@@ -138,10 +155,24 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
|
public void UpdateStatus(byte Progress, string CurrentProcess, string CurrentDescription)
|
||||||
{
|
{
|
||||||
this._progress = Progress;
|
this._progress = CalculateProgressValue(Progress);
|
||||||
this._currentProcess = CurrentProcess;
|
|
||||||
this._currentDescription = CurrentDescription;
|
var changedProperties = new List<ChangedItem>() {
|
||||||
UpdateTriggered(new string[] { "Progress", "CurrentProcess", "CurrentDescription" });
|
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)
|
public void UpdateStatus(double Progress, string CurrentProcess, string CurrentDescription)
|
||||||
{
|
{
|
||||||
@@ -157,7 +188,7 @@ namespace Disco.Services.Tasks
|
|||||||
if (_cancelSupported)
|
if (_cancelSupported)
|
||||||
{ // Cancelling
|
{ // Cancelling
|
||||||
this._isCanceling = true;
|
this._isCanceling = true;
|
||||||
UpdateTriggered(new string[] { "IsCancelling" });
|
UpdateTriggered("IsCancelling", true);
|
||||||
if (this.Canceling != null)
|
if (this.Canceling != null)
|
||||||
Canceling(this);
|
Canceling(this);
|
||||||
return true;
|
return true;
|
||||||
@@ -177,7 +208,7 @@ namespace Disco.Services.Tasks
|
|||||||
if (this._cancelSupported != CancelSupported)
|
if (this._cancelSupported != CancelSupported)
|
||||||
{
|
{
|
||||||
this._cancelSupported = CancelSupported;
|
this._cancelSupported = CancelSupported;
|
||||||
UpdateTriggered(new string[] { "CancelSupported" });
|
UpdateTriggered("CancelSupported", CancelSupported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SetTaskException(Exception TaskException)
|
public void SetTaskException(Exception TaskException)
|
||||||
@@ -185,7 +216,7 @@ namespace Disco.Services.Tasks
|
|||||||
if (this._taskException != TaskException)
|
if (this._taskException != TaskException)
|
||||||
{
|
{
|
||||||
this._taskException = TaskException;
|
this._taskException = TaskException;
|
||||||
UpdateTriggered(new string[] { "TaskException" });
|
UpdateTriggered("TaskExceptionMessage", (this._taskException == null ? null : this._taskException.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SetIsSilent(bool IsSilent)
|
public void SetIsSilent(bool IsSilent)
|
||||||
@@ -198,7 +229,7 @@ namespace Disco.Services.Tasks
|
|||||||
if (this._finishedUrl != FinishedUrl)
|
if (this._finishedUrl != FinishedUrl)
|
||||||
{
|
{
|
||||||
this._finishedUrl = FinishedUrl;
|
this._finishedUrl = FinishedUrl;
|
||||||
UpdateTriggered(new string[] { "FinishedUrl" });
|
UpdateTriggered("FinishedUrl", FinishedUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SetFinishedMessage(string FinishedMessage)
|
public void SetFinishedMessage(string FinishedMessage)
|
||||||
@@ -206,7 +237,7 @@ namespace Disco.Services.Tasks
|
|||||||
if (this._finishedMessage != FinishedMessage)
|
if (this._finishedMessage != FinishedMessage)
|
||||||
{
|
{
|
||||||
this._finishedMessage = FinishedMessage;
|
this._finishedMessage = FinishedMessage;
|
||||||
UpdateTriggered(new string[] { "FinishedMessage" });
|
UpdateTriggered("FinishedMessage", FinishedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SetNextScheduledTimestamp(DateTime? NextScheduledTimestamp)
|
public void SetNextScheduledTimestamp(DateTime? NextScheduledTimestamp)
|
||||||
@@ -214,59 +245,62 @@ namespace Disco.Services.Tasks
|
|||||||
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
||||||
{
|
{
|
||||||
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
||||||
UpdateTriggered(new string[] { "NextScheduledTimestamp" });
|
UpdateTriggered("NextScheduledTimestamp", NextScheduledTimestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void Started()
|
public void Started()
|
||||||
{
|
{
|
||||||
List<string> changedProperties = new List<string>() { "IsRunning", "StartedTimestamp" };
|
var changedProperties = new List<ChangedItem>();
|
||||||
|
|
||||||
|
// Change StartedTimestamp
|
||||||
this._startedTimestamp = DateTime.Now;
|
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)
|
if (this._nextScheduledTimestamp != null)
|
||||||
{
|
{
|
||||||
this._nextScheduledTimestamp = null;
|
this._nextScheduledTimestamp = null;
|
||||||
changedProperties.Add("NextScheduledTimestamp");
|
changedProperties.Add(new ChangedItem("NextScheduledTimestamp", this._nextScheduledTimestamp));
|
||||||
}
|
|
||||||
if (this._finishedTimestamp != null)
|
|
||||||
{
|
|
||||||
this._finishedTimestamp = null;
|
|
||||||
changedProperties.Add("FinishedTimestamp");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changedProperties.Add(new ChangedItem("IsRunning", this.IsRunning));
|
||||||
|
|
||||||
if (this._progress != 0)
|
if (this._progress != 0)
|
||||||
{
|
{
|
||||||
this._progress = 0;
|
this._progress = 0;
|
||||||
changedProperties.Add("Progress");
|
changedProperties.Add(new ChangedItem("Progress", this._progress));
|
||||||
}
|
}
|
||||||
if (this._currentProcess != "Starting")
|
if (this._currentProcess != "Starting")
|
||||||
{
|
{
|
||||||
this._currentProcess = "Starting";
|
this._currentProcess = "Starting";
|
||||||
changedProperties.Add("CurrentProcess");
|
changedProperties.Add(new ChangedItem("CurrentProcess", this._currentProcess));
|
||||||
}
|
}
|
||||||
if (this._currentDescription != "Initializing Task for Execution")
|
if (this._currentDescription != "Initializing Task for Execution")
|
||||||
{
|
{
|
||||||
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)
|
if (this._taskException != null)
|
||||||
{
|
{
|
||||||
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)
|
if (this._cancelSupported != this._cancelInitiallySupported)
|
||||||
{
|
{
|
||||||
this._cancelSupported = this._cancelInitiallySupported;
|
this._cancelSupported = this._cancelInitiallySupported;
|
||||||
changedProperties.Add("CancelSupported");
|
changedProperties.Add(new ChangedItem("CancelSupported", this._cancelSupported));
|
||||||
}
|
|
||||||
{
|
|
||||||
this._isCanceling = false;
|
|
||||||
changedProperties.Add("IsCanceling");
|
|
||||||
}
|
}
|
||||||
if (this._isCanceling)
|
if (this._isCanceling)
|
||||||
{
|
{
|
||||||
this._isCanceling = false;
|
this._isCanceling = false;
|
||||||
changedProperties.Add("IsCanceling");
|
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTriggered(changedProperties.ToArray());
|
UpdateTriggered(changedProperties.ToArray());
|
||||||
}
|
}
|
||||||
public void Finished()
|
public void Finished()
|
||||||
@@ -279,26 +313,29 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
public void Finished(string FinishedMessage, string FinishedUrl)
|
public void Finished(string FinishedMessage, string FinishedUrl)
|
||||||
{
|
{
|
||||||
List<string> changedProperties = new List<string>() { "IsRunning", "FinishedTimestamp" };
|
var changedProperties = new List<ChangedItem>();
|
||||||
|
|
||||||
this._finishedTimestamp = DateTime.Now;
|
this._finishedTimestamp = DateTime.Now;
|
||||||
|
changedProperties.Add(new ChangedItem("FinishedTimestamp", this._finishedTimestamp));
|
||||||
|
changedProperties.Add(new ChangedItem("IsRunning", this.IsRunning));
|
||||||
|
|
||||||
if (FinishedMessage != this._finishedMessage)
|
if (FinishedMessage != this._finishedMessage)
|
||||||
{
|
{
|
||||||
this._finishedMessage = FinishedMessage;
|
this._finishedMessage = FinishedMessage;
|
||||||
changedProperties.Add("FinishedMessage");
|
changedProperties.Add(new ChangedItem("FinishedMessage", this._finishedMessage));
|
||||||
}
|
}
|
||||||
if (FinishedUrl != this._finishedUrl)
|
if (FinishedUrl != this._finishedUrl)
|
||||||
{
|
{
|
||||||
this._finishedUrl = FinishedUrl;
|
this._finishedUrl = FinishedUrl;
|
||||||
changedProperties.Add("FinishedUrl");
|
changedProperties.Add(new ChangedItem("FinishedUrl", this._finishedUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._isCanceling)
|
if (this._isCanceling)
|
||||||
{
|
{
|
||||||
this._isCanceling = false;
|
this._isCanceling = false;
|
||||||
changedProperties.Add("IsCanceling");
|
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTriggered(changedProperties.ToArray());
|
UpdateTriggered(changedProperties.ToArray());
|
||||||
}
|
}
|
||||||
internal void Finally()
|
internal void Finally()
|
||||||
@@ -311,53 +348,58 @@ namespace Disco.Services.Tasks
|
|||||||
this._tcs.Task.Dispose();
|
this._tcs.Task.Dispose();
|
||||||
this._tcs = new TaskCompletionSource<ScheduledTaskStatus>();
|
this._tcs = new TaskCompletionSource<ScheduledTaskStatus>();
|
||||||
|
|
||||||
List<string> changedProperties = new List<string>();
|
var changedProperties = new List<ChangedItem>();
|
||||||
|
|
||||||
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
if (this._nextScheduledTimestamp != NextScheduledTimestamp)
|
||||||
{
|
{
|
||||||
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
this._nextScheduledTimestamp = NextScheduledTimestamp;
|
||||||
changedProperties.Add("NextScheduledTimestamp");
|
changedProperties.Add(new ChangedItem("NextScheduledTimestamp", this._nextScheduledTimestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._startedTimestamp != null)
|
if (this._startedTimestamp != null)
|
||||||
{
|
{
|
||||||
this._startedTimestamp = null;
|
this._startedTimestamp = null;
|
||||||
changedProperties.Add("StartedTimestamp");
|
changedProperties.Add(new ChangedItem("StartedTimestamp", this._startedTimestamp));
|
||||||
}
|
}
|
||||||
if (this._finishedTimestamp != null)
|
if (this._finishedTimestamp != null)
|
||||||
{
|
{
|
||||||
this._finishedTimestamp = null;
|
this._finishedTimestamp = null;
|
||||||
changedProperties.Add("FinishedTimestamp");
|
changedProperties.Add(new ChangedItem("FinishedTimestamp", this._finishedTimestamp));
|
||||||
}
|
}
|
||||||
if (this._finishedMessage != null)
|
if (this._finishedMessage != null)
|
||||||
{
|
{
|
||||||
this._finishedMessage = null;
|
this._finishedMessage = null;
|
||||||
changedProperties.Add("FinishedMessage");
|
changedProperties.Add(new ChangedItem("FinishedMessage", this._finishedMessage));
|
||||||
}
|
}
|
||||||
if (this._finishedUrl != null)
|
if (this._finishedUrl != null)
|
||||||
{
|
{
|
||||||
this._finishedUrl = null;
|
this._finishedUrl = null;
|
||||||
changedProperties.Add("FinishedUrl");
|
changedProperties.Add(new ChangedItem("FinishedUrl", this._finishedUrl));
|
||||||
}
|
}
|
||||||
if (this._progress != 0)
|
if (this._progress != 0)
|
||||||
{
|
{
|
||||||
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")
|
if (this._currentProcess != "Scheduled")
|
||||||
{
|
{
|
||||||
this._currentProcess = "Scheduled";
|
this._currentProcess = "Scheduled";
|
||||||
changedProperties.Add("CurrentProcess");
|
changedProperties.Add(new ChangedItem("CurrentProcess", this._currentProcess));
|
||||||
}
|
}
|
||||||
if (this._currentDescription != "Scheduled Task for Execution")
|
if (this._currentDescription != "Scheduled Task for Execution")
|
||||||
{
|
{
|
||||||
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)
|
if (this._isCanceling)
|
||||||
{
|
{
|
||||||
this._isCanceling = false;
|
this._isCanceling = false;
|
||||||
changedProperties.Add("IsCanceling");
|
changedProperties.Add(new ChangedItem("IsCanceling", this._isCanceling));
|
||||||
}
|
}
|
||||||
UpdateTriggered(changedProperties.ToArray());
|
UpdateTriggered(changedProperties.ToArray());
|
||||||
}
|
}
|
||||||
@@ -373,15 +415,20 @@ namespace Disco.Services.Tasks
|
|||||||
}
|
}
|
||||||
#endregion
|
#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++;
|
this._statusVersion++;
|
||||||
|
|
||||||
if (Updated != null)
|
if (Updated != null)
|
||||||
Updated(this, ChangedProperties);
|
Updated(this, ChangedProperties);
|
||||||
|
|
||||||
if (!_isSilent && UpdatedBroadcast != null)
|
if (!_isSilent)
|
||||||
UpdatedBroadcast.Invoke(ScheduledTaskStatusLive.FromScheduledTaskStatus(this, ChangedProperties));
|
ScheduledTaskNotificationsHub.PublishEvent(this.SessionId, ChangedProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,16 @@ namespace Disco.Services.Tasks
|
|||||||
// Scheduled Cleanup
|
// Scheduled Cleanup
|
||||||
ScheduledTaskCleanup.Schedule(_TaskScheduler);
|
ScheduledTaskCleanup.Schedule(_TaskScheduler);
|
||||||
|
|
||||||
|
ScheduledTaskNotificationsHub.Initialize();
|
||||||
|
|
||||||
if (InitiallySchedule)
|
if (InitiallySchedule)
|
||||||
{
|
{
|
||||||
// Discover DiscoScheduledTask
|
// Discover DiscoScheduledTask
|
||||||
var appDomain = AppDomain.CurrentDomain;
|
var appDomain = AppDomain.CurrentDomain;
|
||||||
|
var scheduledTasksHostAssemblyName = typeof(ScheduledTask).Assembly.GetName().Name;
|
||||||
|
|
||||||
var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
|
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()
|
from type in a.GetTypes()
|
||||||
where typeof(ScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
where typeof(ScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
||||||
select type);
|
select type);
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.Services
|
namespace Disco.Services
|
||||||
{
|
{
|
||||||
@@ -15,6 +11,11 @@ namespace Disco.Services
|
|||||||
return u.Domain.Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase);
|
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)
|
public static string FriendlyId(this User u)
|
||||||
{
|
{
|
||||||
return FriendlyUserId(u.UserId);
|
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:
|
// Ensure 'App-Relative' Url:
|
||||||
BundleUrl = BundleUrl.StartsWith("~/") ? BundleUrl : (BundleUrl.StartsWith("/") ? string.Concat("~", BundleUrl) : string.Concat("~/", BundleUrl));
|
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)
|
if (deferredBundles == null)
|
||||||
{
|
{
|
||||||
deferredBundles = new List<string>();
|
deferredBundles = new List<string>();
|
||||||
htmlHelper.ViewContext.HttpContext.Items[Bundle.DeferredKey] = deferredBundles;
|
htmlHelper.ViewContext.HttpContext.Items[BundleTable.DeferredKey] = deferredBundles;
|
||||||
}
|
}
|
||||||
if (!deferredBundles.Contains(BundleUrl))
|
if (!deferredBundles.Contains(BundleUrl))
|
||||||
deferredBundles.Add(BundleUrl);
|
deferredBundles.Add(BundleUrl);
|
||||||
}
|
}
|
||||||
public static HtmlString BundleRenderDeferred(this HtmlHelper htmlHelper)
|
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 uiExtensionScripts = htmlHelper.ViewContext.HttpContext.Items[BundleTable.UIExtensionScriptsKey] as List<string>;
|
||||||
var uiExtensionCss = htmlHelper.ViewContext.HttpContext.Items[Bundle.UIExtensionCssKey] as List<string>;
|
var uiExtensionCss = htmlHelper.ViewContext.HttpContext.Items[BundleTable.UIExtensionCssKey] as List<string>;
|
||||||
|
|
||||||
if (deferredBundles != null || uiExtensionScripts != null || uiExtensionCss != null)
|
if (deferredBundles != null || uiExtensionScripts != null || uiExtensionCss != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ namespace Disco.Services.Web.Bundles
|
|||||||
{
|
{
|
||||||
internal sealed class BundleHandler : IHttpHandler
|
internal sealed class BundleHandler : IHttpHandler
|
||||||
{
|
{
|
||||||
public Bundle RequestBundle { get; private set; }
|
public IBundle RequestBundle { get; private set; }
|
||||||
public string BundleVirtualPath { 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.RequestBundle = requestBundle;
|
||||||
this.BundleVirtualPath = bundleVirtualPath;
|
this.BundleVirtualPath = bundleVirtualPath;
|
||||||
|
|||||||
@@ -9,14 +9,18 @@ namespace Disco.Services.Web.Bundles
|
|||||||
{
|
{
|
||||||
public static class BundleTable
|
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()
|
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;
|
_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))
|
if (_bundles.ContainsKey(Url))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,16 +9,13 @@ using System.Web;
|
|||||||
|
|
||||||
namespace Disco.Services.Web.Bundles
|
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 DateTime? _FileLastModified { get; set; }
|
||||||
private string _FileHash { get; set; }
|
private string _FileHash { get; set; }
|
||||||
private string _VersionUrl { get; set; }
|
private string _VersionUrl { get; set; }
|
||||||
|
|
||||||
|
public bool RemapRequest { get { return true; } }
|
||||||
public string Url { get; private set; }
|
public string Url { get; private set; }
|
||||||
public string File { get; private set; }
|
public string File { get; private set; }
|
||||||
public string FileHash
|
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))
|
if (string.IsNullOrWhiteSpace(Url))
|
||||||
throw new ArgumentNullException("Url");
|
throw new ArgumentNullException("Url");
|
||||||
@@ -117,7 +114,7 @@ namespace Disco.Services.Web.Bundles
|
|||||||
this._FileHash = string.Empty;
|
this._FileHash = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ProcessRequest(HttpContext context)
|
public void ProcessRequest(HttpContext context)
|
||||||
{
|
{
|
||||||
// Write Content Type
|
// Write Content Type
|
||||||
context.Response.ContentType = this.ContentType;
|
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="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.Mvc" version="4.0.30506.0" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.Razor" version="2.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.Core" version="2.0.3" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
|
|
||||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" 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.SqlServer.Compact" version="4.0.8876.1" targetFramework="net45" />
|
||||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
<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="Owin" version="1.0" targetFramework="net45" />
|
||||||
<package id="RazorGenerator.Mvc" version="2.1.2" targetFramework="net45" />
|
<package id="RazorGenerator.Mvc" version="2.1.2" targetFramework="net45" />
|
||||||
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace Disco.Web
|
|||||||
DiscoApplication.DocumentDropBoxMonitor.ScheduleCurrentFiles(10);
|
DiscoApplication.DocumentDropBoxMonitor.ScheduleCurrentFiles(10);
|
||||||
|
|
||||||
// Enable SignalR-based Repository Notifications
|
// 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)
|
public static void InitializeUpdateEnvironment(DiscoDataContext Database, Version PreviousVersion)
|
||||||
|
|||||||
@@ -9,40 +9,40 @@ namespace Disco.Web
|
|||||||
public static void RegisterBundles()
|
public static void RegisterBundles()
|
||||||
{
|
{
|
||||||
// Styles - Site Core
|
// 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
|
// Styles - Targeted
|
||||||
BundleTable.Add(new Bundle("~/Style/Config", Links.ClientSource.Style.Config_min_css));
|
BundleTable.Add(new FileBundle("~/Style/Config", Links.ClientSource.Style.Config_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/Device", Links.ClientSource.Style.Device_min_css));
|
BundleTable.Add(new FileBundle("~/Style/Device", Links.ClientSource.Style.Device_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/Dialog", Links.ClientSource.Style.Dialog_min_css));
|
BundleTable.Add(new FileBundle("~/Style/Dialog", Links.ClientSource.Style.Dialog_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/Job", Links.ClientSource.Style.Job_min_css));
|
BundleTable.Add(new FileBundle("~/Style/Job", Links.ClientSource.Style.Job_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/User", Links.ClientSource.Style.User_min_css));
|
BundleTable.Add(new FileBundle("~/Style/User", Links.ClientSource.Style.User_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/Credits", Links.ClientSource.Style.Credits_min_css));
|
BundleTable.Add(new FileBundle("~/Style/Credits", Links.ClientSource.Style.Credits_min_css));
|
||||||
BundleTable.Add(new Bundle("~/Style/AppMaintenance", Links.ClientSource.Style.AppMaintenance_min_css));
|
BundleTable.Add(new FileBundle("~/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 FileBundle("~/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 FileBundle("~/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 FileBundle("~/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/Timeline", Links.ClientSource.Style.Timeline_min_css));
|
||||||
|
|
||||||
// Styles - Public Targeted
|
// Styles - Public Targeted
|
||||||
BundleTable.Add(new Bundle("~/Style/Public/HeldDevices", Links.ClientSource.Style.Public.HeldDevices_min_css));
|
BundleTable.Add(new FileBundle("~/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/HeldDevicesNoticeboard", Links.ClientSource.Style.Public.HeldDevicesNoticeboard_min_css));
|
||||||
|
|
||||||
|
|
||||||
// Scripts - Core
|
// Scripts - Core
|
||||||
#if DEBUG
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
// Scripts - Modules
|
// Scripts - Modules
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
foreach (FileInfo f in new DirectoryInfo(HttpContext.Current.Server.MapPath("~/ClientSource/Scripts/Modules")).EnumerateFiles("*.js", SearchOption.TopDirectoryOnly))
|
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
|
#else
|
||||||
foreach (FileInfo f in new DirectoryInfo(HttpContext.Current.Server.MapPath("~/ClientSource/Scripts/Modules")).EnumerateFiles("*.min.js", SearchOption.TopDirectoryOnly))
|
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
|
#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 System.Web.WebPages;
|
||||||
using RazorGenerator.Mvc;
|
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 class RazorGeneratorMvcStart {
|
||||||
public static void Start() {
|
public static void Start() {
|
||||||
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
|
var engine = new PrecompiledMvcEngine(typeof(RazorGeneratorMvcStart).Assembly) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System.Web;
|
|||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using Microsoft.AspNet.SignalR;
|
using Microsoft.AspNet.SignalR;
|
||||||
using Disco.BI.Interop.SignalRHandlers;
|
|
||||||
|
|
||||||
namespace Disco.Web
|
namespace Disco.Web
|
||||||
{
|
{
|
||||||
@@ -74,11 +73,6 @@ namespace Disco.Web
|
|||||||
|
|
||||||
public static void RegisterUpdateRoutes(RouteCollection routes)
|
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
|
// Task Status Ajax Route
|
||||||
routes.MapRoute(
|
routes.MapRoute(
|
||||||
name: "API_Logging_ScheduledTaskStatus", // Route name
|
name: "API_Logging_ScheduledTaskStatus", // Route name
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using Microsoft.AspNet.SignalR;
|
using Microsoft.AspNet.SignalR;
|
||||||
using Disco.BI.Interop.SignalRHandlers;
|
|
||||||
|
|
||||||
namespace Disco.Web.Areas.API
|
namespace Disco.Web.Areas.API
|
||||||
{
|
{
|
||||||
@@ -17,15 +16,6 @@ namespace Disco.Web.Areas.API
|
|||||||
|
|
||||||
public override void RegisterArea(AreaRegistrationContext context)
|
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(
|
context.MapRoute(
|
||||||
"API_Update",
|
"API_Update",
|
||||||
"API/{controller}/Update/{id}/{key}",
|
"API/{controller}/Update/{id}/{key}",
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using Disco.Services;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Disco.BI;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
|
|
||||||
namespace Disco.Web.Areas.API.Models.Attachment
|
namespace Disco.Web.Areas.API.Models.Attachment
|
||||||
{
|
{
|
||||||
@@ -27,7 +23,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
|||||||
ParentId = ua.UserId,
|
ParentId = ua.UserId,
|
||||||
Id = ua.Id,
|
Id = ua.Id,
|
||||||
AuthorId = ua.TechUserId,
|
AuthorId = ua.TechUserId,
|
||||||
Author = ua.TechUser.ToString(),
|
Author = ua.TechUser.ToStringFriendly(),
|
||||||
Timestamp = ua.Timestamp,
|
Timestamp = ua.Timestamp,
|
||||||
Comments = ua.Comments,
|
Comments = ua.Comments,
|
||||||
Filename = ua.Filename,
|
Filename = ua.Filename,
|
||||||
@@ -41,7 +37,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
|||||||
ParentId = ja.JobId.ToString(),
|
ParentId = ja.JobId.ToString(),
|
||||||
Id = ja.Id,
|
Id = ja.Id,
|
||||||
AuthorId = ja.TechUserId,
|
AuthorId = ja.TechUserId,
|
||||||
Author = ja.TechUser.ToString(),
|
Author = ja.TechUser.ToStringFriendly(),
|
||||||
Timestamp = ja.Timestamp,
|
Timestamp = ja.Timestamp,
|
||||||
Comments = ja.Comments,
|
Comments = ja.Comments,
|
||||||
Filename = ja.Filename,
|
Filename = ja.Filename,
|
||||||
@@ -55,7 +51,7 @@ namespace Disco.Web.Areas.API.Models.Attachment
|
|||||||
ParentId = da.DeviceSerialNumber,
|
ParentId = da.DeviceSerialNumber,
|
||||||
Id = da.Id,
|
Id = da.Id,
|
||||||
AuthorId = da.TechUserId,
|
AuthorId = da.TechUserId,
|
||||||
Author = da.TechUser.ToString(),
|
Author = da.TechUser.ToStringFriendly(),
|
||||||
Timestamp = da.Timestamp,
|
Timestamp = da.Timestamp,
|
||||||
Comments = da.Comments,
|
Comments = da.Comments,
|
||||||
Filename = da.Filename,
|
Filename = da.Filename,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Disco.Models.UI.Config.Logging;
|
using Disco.Models.UI.Config.Logging;
|
||||||
|
using Disco.Models.UI.Config.Shared;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Logging;
|
using Disco.Services.Logging;
|
||||||
using Disco.Services.Logging.Models;
|
using Disco.Services.Logging.Models;
|
||||||
@@ -42,10 +43,10 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
if (taskStatus == null)
|
if (taskStatus == null)
|
||||||
return RedirectToAction(MVC.Config.Logging.Index());
|
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
|
// UI Extensions
|
||||||
UIExtensions.ExecuteExtensions<ConfigLoggingTaskStatusModel>(this.ControllerContext, m);
|
UIExtensions.ExecuteExtensions<ConfigSharedTaskStatusModel>(this.ControllerContext, m);
|
||||||
|
|
||||||
return View(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");
|
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;">
|
@Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId)
|
||||||
<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>
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// 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.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Logging/TaskStatus.cshtml")]
|
[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()
|
public TaskStatus()
|
||||||
{
|
{
|
||||||
@@ -48,269 +48,19 @@ namespace Disco.Web.Areas.Config.Views.Logging
|
|||||||
#line 2 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
#line 2 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||||
|
|
||||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Logging", MVC.Config.Logging.Index(), "Task Status");
|
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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\r\n<div");
|
WriteLiteral("\r\n");
|
||||||
|
|
||||||
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 = \'");
|
|
||||||
|
|
||||||
|
|
||||||
#line 93 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
#line 5 "..\..\Areas\Config\Views\Logging\TaskStatus.cshtml"
|
||||||
Write(Model.SessionId);
|
Write(Html.PartialCompiled(typeof(Disco.Web.Areas.Config.Views.Shared.TaskStatus), Model.SessionId));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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>
|
|
||||||
");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,12 @@
|
|||||||
$(function () {
|
$(function () {
|
||||||
var logEventsHost = $('LogEvents_@(uniqueId)');
|
var logEventsHost = $('LogEvents_@(uniqueId)');
|
||||||
var logModuleId = '@(Model.ModuleFilter != null ? Model.ModuleFilter.ModuleId.ToString() : null)';
|
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 logModuleLiveGroupName = '@(Model.ModuleFilter != null ? Model.ModuleFilter.LiveLogGroupName : Disco.Services.Logging.LogNotificationsHub.AllLoggingNotification)';
|
||||||
var logEventTypeFiltered = @(eventTypesFilterJson);
|
var logEventTypeFiltered = @(eventTypesFilterJson);
|
||||||
var logStartFiler = @(AjaxHelpers.JsonDate(Model.StartFilter));
|
var logStartFiler = @(AjaxHelpers.JsonDate(Model.StartFilter));
|
||||||
var logEndFiler = @(AjaxHelpers.JsonDate(Model.EndFilter));
|
var logEndFiler = @(AjaxHelpers.JsonDate(Model.EndFilter));
|
||||||
var logTakeFiler = '@(Model.TakeFilter)';
|
var logTakeFiler = '@(Model.TakeFilter)';
|
||||||
var liveConnection = null;
|
var logHub = null;
|
||||||
var liveEventReceivedFunction = '@(Model.JavascriptLiveEventFunctionName)';
|
var liveEventReceivedFunction = '@(Model.JavascriptLiveEventFunctionName)';
|
||||||
var useLive = ('True'==='@(Model.IsLive)');
|
var useLive = ('True'==='@(Model.IsLive)');
|
||||||
|
|
||||||
@@ -113,16 +113,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
liveConnection = $.connection('@(Url.Content("~/API/Logging/Notifications"))', {addToGroups: logModuleLiveGroupName});
|
logHub = $.connection.logNotifications;
|
||||||
liveConnection.received(logReceived);
|
logHub.client.receiveLog = function(message){
|
||||||
liveConnection.error(function(e){if (e.status != 200) alert('Live-Log Error: '+e.statusText +': '+e.responseText);});
|
if (message.UseDisplay) logsViewModel.EventLogs.unshift(message);
|
||||||
liveConnection.start();
|
if (liveEventReceivedFunction) liveEventReceivedFunction(message);
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function logReceived(log){
|
$.connection.hub.qs = {LogModules: logModuleLiveGroupName};
|
||||||
if (log.UseDisplay) logsViewModel.EventLogs.unshift(log);
|
$.connection.hub.error(function(error){
|
||||||
if (liveEventReceivedFunction) liveEventReceivedFunction(log);
|
alert('Live-Log Error: '+error);
|
||||||
|
});
|
||||||
|
|
||||||
|
$.connection.hub.start().fail(function(error){
|
||||||
|
alert('Live-Log Connection Error: '+error);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadInitialData();
|
loadInitialData();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -58,15 +58,15 @@ namespace Disco.Web.Areas.Config.Views.Shared
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\r\n<div");
|
WriteLiteral("\r\n<div");
|
||||||
|
|
||||||
WriteAttribute("id", Tuple.Create(" id=\"", 313), Tuple.Create("\"", 339)
|
WriteAttribute("id", Tuple.Create(" id=\"", 309), Tuple.Create("\"", 335)
|
||||||
, Tuple.Create(Tuple.Create("", 318), Tuple.Create("LogEvents_", 318), true)
|
, Tuple.Create(Tuple.Create("", 314), Tuple.Create("LogEvents_", 314), true)
|
||||||
|
|
||||||
#line 9 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
#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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 328), false)
|
, 324), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(" class=\"logEventsViewport\"");
|
WriteLiteral(" class=\"logEventsViewport\"");
|
||||||
@@ -96,21 +96,21 @@ WriteLiteral(">Message\r\n </th>\r\n </tr>\r\n
|
|||||||
|
|
||||||
WriteLiteral(" class=\"logEventsViewportContainer\"");
|
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"
|
#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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 822), false)
|
, 818), false)
|
||||||
|
|
||||||
#line 24 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
#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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 919), false)
|
, 915), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">\r\n <div");
|
WriteLiteral(">\r\n <div");
|
||||||
@@ -205,7 +205,7 @@ WriteLiteral("\';\r\n var logModuleLiveGroupName = \'");
|
|||||||
|
|
||||||
|
|
||||||
#line 47 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
#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
|
#line default
|
||||||
@@ -219,7 +219,7 @@ WriteLiteral("\';\r\n var logEventTypeFiltered = ");
|
|||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(";\r\n var logStartFiler = ");
|
WriteLiteral("; \r\n var logStartFiler = ");
|
||||||
|
|
||||||
|
|
||||||
#line 49 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
#line 49 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||||
@@ -246,8 +246,8 @@ WriteLiteral(";\r\n var logTakeFiler = \'");
|
|||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\';\r\n var liveConnection = null;\r\n var liveEventReceivedFunc" +
|
WriteLiteral("\';\r\n var logHub = null;\r\n var liveEventReceivedFunction = \'" +
|
||||||
"tion = \'");
|
"");
|
||||||
|
|
||||||
|
|
||||||
#line 53 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
#line 53 "..\..\Areas\Config\Views\Shared\LogEvents.cshtml"
|
||||||
@@ -308,60 +308,33 @@ WriteLiteral(@"');
|
|||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(@"',
|
WriteLiteral("\',\r\n dataType: \'json\',\r\n type: \'POST\',\r\n " +
|
||||||
dataType: 'json',
|
" data: loadData,\r\n success: function (d) { \r\n" +
|
||||||
type: 'POST',
|
" initLogs(d);\r\n },\r\n " +
|
||||||
data: loadData,
|
" error: function (jqXHR, textStatus, errorThrown) {\r\n al" +
|
||||||
success: function (d) {
|
"ert(\'Unable to retrieve logs: \' + textStatus);\r\n }\r\n " +
|
||||||
initLogs(d);
|
" });\r\n }\r\n\r\n function initLogs(loadedLogs){\r\n " +
|
||||||
},
|
" logsViewModel = new LogsViewModel(loadedLogs);\r\n ko.appl" +
|
||||||
error: function (jqXHR, textStatus, errorThrown) {
|
"yBindings(logsViewModel, logEventsHost.get(0));\r\n\r\n if (useLive){" +
|
||||||
alert('Unable to retrieve logs: ' + textStatus);
|
"\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" +
|
||||||
function initLogs(loadedLogs){
|
"tReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceived" +
|
||||||
logsViewModel = new LogsViewModel(loadedLogs);
|
"Function];\r\n }else{\r\n liveEven" +
|
||||||
ko.applyBindings(logsViewModel, logEventsHost.get(0));
|
"tReceivedFunction = null;\r\n }\r\n }\r\n\r\n " +
|
||||||
|
" logHub = $.connection.logNotifications;\r\n " +
|
||||||
if (useLive){
|
"logHub.client.receiveLog = function(message){\r\n if (messa" +
|
||||||
if (liveEventReceivedFunction){
|
"ge.UseDisplay) logsViewModel.EventLogs.unshift(message);\r\n " +
|
||||||
if (!document.DiscoFunctions) document.DiscoFunctions = {};
|
" if (liveEventReceivedFunction) liveEventReceivedFunction(message);\r\n " +
|
||||||
if (!document.DiscoFunctions.LogEventsFunctions) document.DiscoFunctions.LogEventsFunctions = {};
|
" };\r\n\r\n $.connection.hub.qs = {LogModules: logModule" +
|
||||||
if (document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction]){
|
"LiveGroupName};\r\n $.connection.hub.error(function(error){\r\n " +
|
||||||
liveEventReceivedFunction = document.DiscoFunctions.LogEventsFunctions[liveEventReceivedFunction];
|
" alert(\'Live-Log Error: \'+error);\r\n });\r" +
|
||||||
}else{
|
"\n\r\n $.connection.hub.start().fail(function(error){\r\n " +
|
||||||
liveEventReceivedFunction = null;
|
" 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");
|
||||||
|
|
||||||
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>
|
|
||||||
");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 Disco.Services.Web;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
|
||||||
@@ -8,81 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
|
|||||||
{
|
{
|
||||||
public partial class HeldDevicesController : DatabaseController
|
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()
|
public virtual ActionResult Index()
|
||||||
{
|
{
|
||||||
return View(GetHeldDevices());
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
|
||||||
|
|
||||||
|
return View(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual ActionResult ReadyForReturnXml()
|
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);
|
return new Extensions.XmlResult(readyForReturn);
|
||||||
}
|
}
|
||||||
public virtual ActionResult WaitingForUserActionXml()
|
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);
|
return new Extensions.XmlResult(waitingForUserAction);
|
||||||
}
|
}
|
||||||
public virtual ActionResult HeldDevicesXml()
|
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);
|
return new Extensions.XmlResult(heldDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,13 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
|
|||||||
|
|
||||||
public virtual ActionResult HeldDevice(string id)
|
public virtual ActionResult HeldDevice(string id)
|
||||||
{
|
{
|
||||||
var uhd = GetHeldDevice(id);
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevice(Database, id);
|
||||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
|
||||||
|
return Json(m, JsonRequestBehavior.AllowGet);
|
||||||
}
|
}
|
||||||
public virtual ActionResult HeldDevices()
|
public virtual ActionResult HeldDevices()
|
||||||
{
|
{
|
||||||
var uhd = GetHeldDevices();
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevices.GetHeldDevices(Database);
|
||||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
|
||||||
|
return Json(m, JsonRequestBehavior.AllowGet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Disco.Models.Repository;
|
using Disco.Services.Jobs.Noticeboards;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
|
|
||||||
@@ -8,79 +7,32 @@ namespace Disco.Web.Areas.Public.Controllers
|
|||||||
{
|
{
|
||||||
public partial class UserHeldDevicesController : DatabaseController
|
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()
|
public virtual ActionResult Index()
|
||||||
{
|
{
|
||||||
return View(GetUserHeldDevices());
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
|
||||||
|
|
||||||
|
return View(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual ActionResult ReadyForReturnXml()
|
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);
|
return new Extensions.XmlResult(readyForReturn);
|
||||||
}
|
}
|
||||||
public virtual ActionResult WaitingForUserActionXml()
|
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);
|
return new Extensions.XmlResult(userHeldDevices);
|
||||||
}
|
}
|
||||||
public virtual ActionResult UserHeldDevicesXml()
|
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);
|
return new Extensions.XmlResult(userHeldDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,14 +43,15 @@ namespace Disco.Web.Areas.Public.Controllers
|
|||||||
|
|
||||||
public virtual ActionResult UserHeldDevice(string id)
|
public virtual ActionResult UserHeldDevice(string id)
|
||||||
{
|
{
|
||||||
var uhd = GetUserHeldDevice(id);
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDeviceForUsers(Database, id);
|
||||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
|
||||||
|
return Json(m, JsonRequestBehavior.AllowGet);
|
||||||
}
|
}
|
||||||
public virtual ActionResult UserHeldDevices()
|
public virtual ActionResult UserHeldDevices()
|
||||||
{
|
{
|
||||||
var uhd = GetUserHeldDevices();
|
var m = Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.GetHeldDevicesForUsers(Database);
|
||||||
return Json(uhd, JsonRequestBehavior.AllowGet);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using Microsoft.AspNet.SignalR;
|
using Microsoft.AspNet.SignalR;
|
||||||
using Disco.BI.Interop.SignalRHandlers;
|
|
||||||
|
|
||||||
namespace Disco.Web.Areas.Public
|
namespace Disco.Web.Areas.Public
|
||||||
{
|
{
|
||||||
@@ -17,11 +16,6 @@ namespace Disco.Web.Areas.Public
|
|||||||
|
|
||||||
public override void RegisterArea(AreaRegistrationContext context)
|
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(
|
context.MapRoute(
|
||||||
"Public_Credits",
|
"Public_Credits",
|
||||||
"Public/Credits/{id}",
|
"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);
|
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices", null);
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
||||||
@@ -10,16 +10,16 @@
|
|||||||
}
|
}
|
||||||
<h2>In Process (@DevicesInProcess.Length)</h2>
|
<h2>In Process (@DevicesInProcess.Length)</h2>
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in DevicesInProcess)
|
@foreach (var item in DevicesInProcess.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.DeviceComputerName
|
@item.DeviceComputerNameFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@if (item.UserId != null)
|
@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))
|
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||||
{
|
{
|
||||||
@@ -36,9 +36,9 @@
|
|||||||
@item.DeviceSerialNumber
|
@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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -51,16 +51,16 @@
|
|||||||
}
|
}
|
||||||
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in WaitingForUserActionJobs)
|
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.DeviceComputerName
|
@item.DeviceComputerNameFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@if (item.UserId != null)
|
@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))
|
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||||
{
|
{
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</td>
|
</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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
@@ -89,16 +89,16 @@
|
|||||||
}
|
}
|
||||||
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in DevicesReadyForReturn)
|
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.DeviceComputerNameFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.DeviceComputerName
|
@item.DeviceComputerNameFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@if (item.UserId != null)
|
@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))
|
@if (!string.IsNullOrWhiteSpace(item.DeviceLocation))
|
||||||
{
|
{
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</td>
|
</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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// 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.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/HeldDevices/Index.cshtml")]
|
[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()
|
public Index()
|
||||||
{
|
{
|
||||||
@@ -99,7 +99,7 @@ WriteLiteral(">\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 13 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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"
|
#line 17 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.DeviceComputerName);
|
Write(item.DeviceComputerNameFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -157,7 +157,7 @@ WriteLiteral(" (");
|
|||||||
|
|
||||||
|
|
||||||
#line 22 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#line 22 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -235,7 +235,7 @@ WriteLiteral(" ");
|
|||||||
|
|
||||||
|
|
||||||
#line 39 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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"
|
#line 41 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.EstimatedReturnTime);
|
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -315,7 +315,7 @@ WriteLiteral(">\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 54 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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"
|
#line 58 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.DeviceComputerName);
|
Write(item.DeviceComputerNameFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -373,7 +373,7 @@ WriteLiteral(" (");
|
|||||||
|
|
||||||
|
|
||||||
#line 63 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#line 63 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -449,22 +449,22 @@ WriteLiteral("\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(" </td>\r\n <td");
|
WriteLiteral(" </td>\r\n <td");
|
||||||
|
|
||||||
WriteAttribute("class", Tuple.Create(" class=\"", 3267), Tuple.Create("\"", 3325)
|
WriteAttribute("class", Tuple.Create(" class=\"", 3397), Tuple.Create("\"", 3455)
|
||||||
, Tuple.Create(Tuple.Create("", 3275), Tuple.Create("timestamp", 3275), true)
|
, Tuple.Create(Tuple.Create("", 3405), Tuple.Create("timestamp", 3405), true)
|
||||||
|
|
||||||
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 3284), false)
|
, 3414), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">Since ");
|
WriteLiteral(">Since ");
|
||||||
|
|
||||||
|
|
||||||
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#line 81 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.WaitingForUserActionSince);
|
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -517,7 +517,7 @@ WriteLiteral(">\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 92 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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"
|
#line 96 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.DeviceComputerName);
|
Write(item.DeviceComputerNameFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -575,7 +575,7 @@ WriteLiteral(" (");
|
|||||||
|
|
||||||
|
|
||||||
#line 101 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#line 101 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -651,22 +651,22 @@ WriteLiteral("\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(" </td>\r\n <td");
|
WriteLiteral(" </td>\r\n <td");
|
||||||
|
|
||||||
WriteAttribute("class", Tuple.Create(" class=\"", 4805), Tuple.Create("\"", 4863)
|
WriteAttribute("class", Tuple.Create(" class=\"", 5022), Tuple.Create("\"", 5080)
|
||||||
, Tuple.Create(Tuple.Create("", 4813), Tuple.Create("timestamp", 4813), true)
|
, Tuple.Create(Tuple.Create("", 5030), Tuple.Create("timestamp", 5030), true)
|
||||||
|
|
||||||
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#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 default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 4822), false)
|
, 5039), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">Ready ");
|
WriteLiteral(">Ready ");
|
||||||
|
|
||||||
|
|
||||||
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
#line 119 "..\..\Areas\Public\Views\HeldDevices\Index.cshtml"
|
||||||
Write(item.ReadyForReturnSince);
|
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
|
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||||
Html.BundleDeferred("~/ClientScripts/Core");
|
Html.BundleDeferred("~/ClientScripts/Core");
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||||
@@ -9,468 +10,397 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<title>Disco - Held Devices</title>
|
<title>Disco ICT - Held Devices</title>
|
||||||
@Html.BundleRenderDeferred()
|
@Html.BundleRenderDeferred()
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="status-connecting">
|
||||||
<div id="page">
|
<div id="page">
|
||||||
<header id="mainHeader">
|
<header id="header">
|
||||||
Held Devices
|
<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>
|
</header>
|
||||||
<section id="mainSection">
|
<section id="mainSection">
|
||||||
<div id="inProcess" class="list">
|
<div id="inProcess" class="list">
|
||||||
<h3>In Process <span id="inProcessCount"></span>
|
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
|
||||||
</h3>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: inProcess().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="readyForReturn" class="list">
|
<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>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: readyForReturn().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="waitingForUserAction" class="list">
|
<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>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: waitingForUserAction().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<footer id="footer">
|
||||||
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
<footer>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/html" id="item-template">
|
||||||
// Resizing
|
<li data-bind="css: { alert: IsAlert }">
|
||||||
$(function () {
|
<span data-bind="text: DeviceDescription"></span>
|
||||||
var $inProcess = $('#inProcess');
|
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
|
||||||
var $inProcessContent = $inProcess.find('.content');
|
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
|
||||||
var $inProcessHeader = $inProcess.find('.h3');
|
<!-- /ko -->
|
||||||
var $readyForReturn = $('#readyForReturn');
|
<!-- ko if: WaitingForUserAction -->
|
||||||
var $readyForReturnContent = $readyForReturn.find('.content');
|
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
|
||||||
var $readyForReturnHeader = $readyForReturn.find('.h3');
|
<!-- /ko -->
|
||||||
var $waitingForUserAction = $('#waitingForUserAction');
|
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
|
||||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
|
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
|
||||||
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
|
<!-- /ko -->
|
||||||
var $mainSection = $('#mainSection');
|
</li>
|
||||||
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>
|
</script>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
// Hide Mouse Mouse
|
ko.bindingHandlers.livestamp = {
|
||||||
$(function () {
|
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||||
var mouseVisible = true;
|
var value = valueAccessor();
|
||||||
var mouseHideToken;
|
var valueUnwrapped = ko.unwrap(value);
|
||||||
var documentBody = $('body');
|
|
||||||
|
|
||||||
var hideMouse = function () {
|
if (valueUnwrapped)
|
||||||
if (mouseVisible) {
|
$(element).livestamp(valueUnwrapped);
|
||||||
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 "";
|
|
||||||
else
|
else
|
||||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
$(element).livestamp('destroy');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var hub;
|
||||||
|
var viewModel;
|
||||||
|
|
||||||
var buildFilters = function () {
|
var rotateSpeed = 3000;
|
||||||
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
|
var itemFilters;
|
||||||
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 sortModels = function () {
|
var $inProcessList = $('#inProcess').find('ul');
|
||||||
modelsInProcessSorted = [];
|
var $readyForReturnList = $('#readyForReturn').find('ul');
|
||||||
modelsReadyForReturnSorted = [];
|
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
|
||||||
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);
|
|
||||||
|
|
||||||
if (modelsInProcessSorted.length != modelsInProcessCount) {
|
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
|
||||||
modelsInProcessCount = modelsInProcessSorted.length;
|
var self = this;
|
||||||
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
|
|
||||||
}
|
|
||||||
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
|
|
||||||
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
|
|
||||||
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
|
|
||||||
}
|
|
||||||
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
|
|
||||||
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
|
|
||||||
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
self.initialized = false;
|
||||||
|
|
||||||
var scrollReadyForReturn = function () {
|
self.inProcess = ko.observableArray(inProcess);
|
||||||
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
|
self.readyForReturn = ko.observableArray(readyForReturn);
|
||||||
modelsReadyForReturnIndexOffset++;
|
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var modelInsertIndex = function (model) {
|
self.onRemove = function (element, index, data) {
|
||||||
sortModels();
|
$(element).slideUp(400, function () {
|
||||||
var findIndex = function (model, array, offset) {
|
$(this).remove();
|
||||||
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.onAdd = function (element, index, data) {
|
||||||
|
if (self.initialized)
|
||||||
var processModel = function (id, model, init) {
|
$(element).hide().slideDown(400);
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
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 () {
|
function init() {
|
||||||
buildFilters();
|
// Connect to Hub
|
||||||
persistantConnection = $.connection('@(Url.Content("~/Public/HeldDevices/Notifications"))');
|
hub = $.connection.noticeboardUpdates;
|
||||||
persistantConnection.received(updatedModel);
|
|
||||||
persistantConnection.error(connectionError);
|
// Map Functions
|
||||||
persistantConnection.start(function () {
|
hub.client.updateHeldDevice = updateHeldDevice;
|
||||||
$.getJSON('@(Url.Action(MVC.Public.HeldDevices.HeldDevices()))', null, function (data) {
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevices.Name)' };
|
||||||
processModel(data[i].DeviceSerialNumber, data[i], true);
|
$.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);
|
||||||
});
|
});
|
||||||
};
|
buildFilters();
|
||||||
init();
|
}
|
||||||
|
|
||||||
|
// 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>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices
|
|||||||
#line 1 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
#line 1 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||||
|
|
||||||
Layout = null;
|
Layout = null;
|
||||||
|
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||||
Html.BundleDeferred("~/ClientScripts/Core");
|
Html.BundleDeferred("~/ClientScripts/Core");
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||||
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
|
|||||||
|
|
||||||
WriteLiteral(" content=\"IE=edge\"");
|
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(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 13 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
#line 14 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||||
Write(Html.BundleRenderDeferred());
|
Write(Html.BundleRenderDeferred());
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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(" id=\"page\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <header");
|
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\"");
|
WriteLiteral(" id=\"mainSection\"");
|
||||||
|
|
||||||
@@ -93,403 +126,289 @@ WriteLiteral(" id=\"inProcess\"");
|
|||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
|
||||||
" </div>\r\n <div");
|
" <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(" id=\"readyForReturn\"");
|
||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
|
||||||
" </div>\r\n <div");
|
" <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(" id=\"waitingForUserAction\"");
|
||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
|
||||||
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
|
" <div");
|
||||||
"</div>\r\n <script");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"text/javascript\"");
|
WriteLiteral(" class=\"noContent\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
|
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||||
"#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(" type=\"text/javascript\"");
|
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
|
||||||
|
"erAdd: onAdd, beforeRemove: onRemove }\"");
|
||||||
|
|
||||||
WriteLiteral(@">
|
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
|
||||||
// Hide Mouse Mouse
|
|
||||||
$(function () {
|
|
||||||
var mouseVisible = true;
|
|
||||||
var mouseHideToken;
|
|
||||||
var documentBody = $('body');
|
|
||||||
|
|
||||||
var hideMouse = function () {
|
WriteLiteral(" id=\"footer\"");
|
||||||
if (mouseVisible) {
|
|
||||||
documentBody.css('cursor', 'none');
|
|
||||||
mouseVisible = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var showMouse = function () {
|
|
||||||
if (!mouseVisible) {
|
|
||||||
documentBody.css('cursor', 'auto');
|
|
||||||
mouseVisible = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).mousemove(function () {
|
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
|
||||||
showMouse();
|
|
||||||
if (mouseHideToken)
|
|
||||||
window.clearTimeout(mouseHideToken);
|
|
||||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"text/javascript\"");
|
WriteLiteral(" type=\"text/html\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
|
WriteLiteral(" id=\"item-template\"");
|
||||||
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
|
|
||||||
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
|
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
|
||||||
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
|
"\"text: DeviceDescription\"></span>\r\n <!-- ko if: !ReadyForReturn && Es" +
|
||||||
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
|
"timatedReturnTimeUnixEpoc -->\r\n <span class=\"small\">(Expected <span d" +
|
||||||
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
|
"ata-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>)</span>\r\n <" +
|
||||||
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
|
"!-- /ko -->\r\n <!-- ko if: WaitingForUserAction -->\r\n <span" +
|
||||||
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
|
" class=\"small\">(Since <span data-bind=\"livestamp: WaitingForUserActionSinceUnixE" +
|
||||||
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
|
"poc\"></span>)</span>\r\n <!-- /ko -->\r\n <!-- ko if: ReadyFor" +
|
||||||
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
|
"Return && !WaitingForUserAction -->\r\n <span class=\"small\">(Ready <spa" +
|
||||||
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
|
"n data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></span>)</span>\r\n " +
|
||||||
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
|
" <!-- /ko -->\r\n </li>\r\n </script>\r\n <script>\r\n ko.bindingHa" +
|
||||||
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
|
"ndlers.livestamp = {\r\n init: function (element, valueAccessor, allBin" +
|
||||||
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
|
"dings, viewModel, bindingContext) {\r\n var value = valueAccessor()" +
|
||||||
" var persistantConnection = null;\r\n var filterDeviceAddress" +
|
";\r\n var valueUnwrapped = ko.unwrap(value);\r\n\r\n if " +
|
||||||
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
|
"(valueUnwrapped)\r\n $(element).livestamp(valueUnwrapped);\r\n " +
|
||||||
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n\r\n v" +
|
" else\r\n $(element).livestamp(\'destroy\');\r\n " +
|
||||||
"ar getParameterByName = function (name) {\r\n name = name.replace(/" +
|
" }\r\n };\r\n </script>\r\n <script>\r\n $(function () {\r\n " +
|
||||||
"[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS = \"[\\\\?&]\" +" +
|
" var hub;\r\n var viewModel;\r\n\r\n var rotateSpeed = 3000" +
|
||||||
" name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS);\r\n " +
|
";\r\n var itemFilters;\r\n\r\n var $inProcessList = $(\'#inProces" +
|
||||||
" var results = regex.exec(window.location.search);\r\n if (re" +
|
"s\').find(\'ul\');\r\n var $readyForReturnList = $(\'#readyForReturn\').find" +
|
||||||
"sults == null)\r\n return \"\";\r\n else\r\n " +
|
"(\'ul\');\r\n var $waitingForUserActionList = $(\'#waitingForUserAction\')." +
|
||||||
" return decodeURIComponent(results[1].replace(/\\+/g, \" \"));\r\n " +
|
"find(\'ul\');\r\n\r\n function noticeboardViewModel(inProcess, readyForRetu" +
|
||||||
" }\r\n\r\n var buildFilters = function () {\r\n var deviceA" +
|
"rn, waitingForUserAction) {\r\n var self = this;\r\n\r\n " +
|
||||||
"ddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n if " +
|
" self.initialized = false;\r\n\r\n self.inProcess = ko.observableArra" +
|
||||||
"(deviceAddressInclude) {\r\n filterDeviceAddressInclude = {};\r\n" +
|
"y(inProcess);\r\n self.readyForReturn = ko.observableArray(readyFor" +
|
||||||
" var split = deviceAddressInclude.split(\",\");\r\n " +
|
"Return);\r\n self.waitingForUserAction = ko.observableArray(waiting" +
|
||||||
" for (var i = 0; i < split.length; i++) {\r\n filterDe" +
|
"ForUserAction);\r\n\r\n self.onRemove = function (element, index, dat" +
|
||||||
"viceAddressInclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
|
"a) {\r\n $(element).slideUp(400, function () {\r\n " +
|
||||||
" } else {\r\n var deviceAddressExclude = getParameter" +
|
" $(this).remove();\r\n });\r\n }\r\n " +
|
||||||
"ByName(\'deviceAddressExclude\');\r\n if (deviceAddressExclude) {" +
|
" self.onAdd = function (element, index, data) {\r\n if (" +
|
||||||
"\r\n filterDeviceAddressExclude = {};\r\n " +
|
"self.initialized)\r\n $(element).hide().slideDown(400);\r\n " +
|
||||||
" var split = deviceAddressExclude.split(\",\");\r\n for (v" +
|
" }\r\n }\r\n\r\n function init() {\r\n " +
|
||||||
"ar i = 0; i < split.length; i++) {\r\n filterDeviceAddr" +
|
" // Connect to Hub\r\n hub = $.connection.noticeboardUpdates;\r\n\r\n " +
|
||||||
"essExclude[split[i].toLowerCase()] = true;\r\n }\r\n " +
|
" // Map Functions\r\n hub.client.updateHeldDevice = up" +
|
||||||
" } else {\r\n var deviceProfileInclude = getParam" +
|
"dateHeldDevice;\r\n\r\n $.connection.hub.qs = { Noticeboard: \'");
|
||||||
"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: \'");
|
|
||||||
|
|
||||||
|
|
||||||
#line 432 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
#line 127 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||||
Write(Url.Action(MVC.Public.HeldDevices.HeldDevice()));
|
Write(Disco.Services.Jobs.Noticeboards.HeldDevices.Name);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(@"',
|
WriteLiteral(@"' };
|
||||||
data: { id: deviceSerialNumber },
|
$.connection.hub.error(connectionError);
|
||||||
success: function (data) {
|
$.connection.hub.disconnected(connectionError);
|
||||||
processModel(deviceSerialNumber, data, false);
|
$.connection.hub.reconnected(connectionError);
|
||||||
},
|
|
||||||
error: function (jqXHR, textStatus, errorThrown) {
|
|
||||||
if (textStatus == 'parsererror') // null Result
|
|
||||||
processModel(deviceSerialNumber, null, false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
var connectionError = function () {
|
// Start Connection
|
||||||
if (persistantConnection) {
|
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||||
persistantConnection.stop();
|
}
|
||||||
persistantConnection = null;
|
|
||||||
window.setTimeout(function () {
|
// Called after SignalR is connected
|
||||||
window.location.href = '");
|
function loadData() {
|
||||||
|
$.getJSON('");
|
||||||
|
|
||||||
|
|
||||||
#line 449 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
#line 138 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
||||||
Write(Url.Action(MVC.Public.HeldDevices.Noticeboard()));
|
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
|
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
|
||||||
" var init = function () {\r\n buildFilters();\r\n " +
|
" var readyForReturn = [];\r\n var waitingForUserAction" +
|
||||||
" persistantConnection = $.connection(\'");
|
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
|
||||||
|
" return includeItem(heldDeviceItem)\r\n }).forEac" +
|
||||||
|
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
|
||||||
#line 456 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
|
||||||
Write(Url.Content("~/Public/HeldDevices/Notifications"));
|
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
|
||||||
|
" readyForReturn.push(heldDeviceItem);\r\n " +
|
||||||
|
" else if (isInProcess(heldDeviceItem))\r\n inP" +
|
||||||
#line default
|
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
|
||||||
#line hidden
|
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
|
||||||
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
|
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
|
||||||
" persistantConnection.error(connectionError);\r\n persistantConnec" +
|
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
|
||||||
"tion.start(function () {\r\n $.getJSON(\'");
|
"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" +
|
||||||
#line 460 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
|
||||||
Write(Url.Action(MVC.Public.HeldDevices.HeldDevices()));
|
" }\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 /" +
|
||||||
#line default
|
"/ Remove Existing\r\n removeItem(deviceSerialNumber);\r\n\r\n " +
|
||||||
#line hidden
|
" // Add Item\r\n addItem(heldDeviceIte" +
|
||||||
WriteLiteral(@"', null, function (data) {
|
"m);\r\n });\r\n }\r\n }\r\n\r\n fu" +
|
||||||
for (var i = 0; i < data.length; i++) {
|
"nction removeItem(deviceSerialNumber) {\r\n removeItemFromArray(vie" +
|
||||||
processModel(data[i].DeviceSerialNumber, data[i], true);
|
"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 " +
|
||||||
init();
|
"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" +
|
||||||
</script>
|
"urn(heldDeviceItem))\r\n array = viewModel.readyForReturn;\r" +
|
||||||
<div");
|
"\n else if (isInProcess(heldDeviceItem))\r\n " +
|
||||||
|
" array = viewModel.inProcess;\r\n\r\n if (array().length === 0" +
|
||||||
WriteLiteral(" id=\"mainFooter\"");
|
") {\r\n array.push(heldDeviceItem);\r\n } " +
|
||||||
|
"else {\r\n var index = findSortedInsertIndex(array, heldDev" +
|
||||||
WriteLiteral(">\r\n <img");
|
"iceItem);\r\n if (index === -1)\r\n " +
|
||||||
|
" array.push(heldDeviceItem);\r\n else\r\n " +
|
||||||
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
|
" array.splice(index, 0, heldDeviceItem);\r\n }\r\n " +
|
||||||
|
" }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
|
||||||
WriteAttribute("src", Tuple.Create(" src=\"", 22627), Tuple.Create("\"", 22677)
|
" rotateArray(viewModel.inProcess, $inProcessList);\r\n rotateArr" +
|
||||||
|
"ay(viewModel.readyForReturn, $readyForReturnList);\r\n rotateArray(" +
|
||||||
#line 472 "..\..\Areas\Public\Views\HeldDevices\Noticeboard.cshtml"
|
"viewModel.waitingForUserAction, $waitingForUserActionList);\r\n }\r\n\r\n " +
|
||||||
, Tuple.Create(Tuple.Create("", 22633), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
|
" function scheduleRotation() {\r\n rotateArrays();\r\n\r\n " +
|
||||||
|
" window.setTimeout(scheduleRotation, rotateSpeed);\r\n }\r\n\r\n" +
|
||||||
#line default
|
" function includeItem(heldDeviceItem) {\r\n if (itemFilt" +
|
||||||
#line hidden
|
"ers == null || itemFilters.length == 0)\r\n return true;\r\n\r\n " +
|
||||||
, 22633), false)
|
" return itemFilters.reduce(function (previousValue, currentValue, in" +
|
||||||
);
|
"dex, array) {\r\n if (previousValue === false)\r\n " +
|
||||||
|
" return false;\r\n return currentValue(heldDeviceItem);" +
|
||||||
WriteLiteral(" alt=\"Disco Logo\"");
|
"\r\n }, true);\r\n }\r\n\r\n function buildFilters(" +
|
||||||
|
") {\r\n var filters = [];\r\n var queryStringParameter" +
|
||||||
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
|
"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);
|
ViewBag.Title = Html.ToBreadcrumb("Public Reports", MVC.Public.Public.Index(), "Held Devices for Users", null);
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
Html.BundleDeferred("~/Style/Public/HeldDevices");
|
||||||
@@ -8,21 +8,19 @@
|
|||||||
@{
|
@{
|
||||||
var DevicesInProcess = Model.Where(i => !i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
var DevicesInProcess = Model.Where(i => !i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||||
}
|
}
|
||||||
<h2>
|
<h2>In Process (@DevicesInProcess.Length)</h2>
|
||||||
In Process (@DevicesInProcess.Length)</h2>
|
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in DevicesInProcess)
|
@foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.UserId
|
@item.UserIdFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@item.UserDisplayName@{
|
@item.UserDisplayName
|
||||||
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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -33,20 +31,18 @@
|
|||||||
@{
|
@{
|
||||||
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
|
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
|
||||||
}
|
}
|
||||||
<h2>
|
<h2>Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
||||||
Waiting for User Action (@WaitingForUserActionJobs.Length)</h2>
|
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in WaitingForUserActionJobs)
|
@foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.UserId
|
@item.UserIdFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@item.UserDisplayName
|
@item.UserDisplayName
|
||||||
</td>
|
</td>
|
||||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
|
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Since @CommonHelpers.FriendlyDate(item.WaitingForUserActionSince)
|
||||||
Since @item.WaitingForUserActionSince
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
@@ -55,20 +51,18 @@
|
|||||||
@{
|
@{
|
||||||
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||||
}
|
}
|
||||||
<h2>
|
<h2>Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
||||||
Ready for Return (@DevicesReadyForReturn.Length)</h2>
|
|
||||||
<table class="dataTable">
|
<table class="dataTable">
|
||||||
@foreach (var item in DevicesReadyForReturn)
|
@foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="id">
|
<td class="id">
|
||||||
@item.UserId
|
@item.UserIdFriendly
|
||||||
</td>
|
</td>
|
||||||
<td class="description">
|
<td class="description">
|
||||||
@item.UserDisplayName
|
@item.UserDisplayName
|
||||||
</td>
|
</td>
|
||||||
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">
|
<td class="timestamp@(item.IsAlert ? " Alert" : string.Empty)">Ready @CommonHelpers.FriendlyDate(item.ReadyForReturnSince)
|
||||||
Ready @item.ReadyForReturnSince
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// 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.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Public/Views/UserHeldDevices/Index.cshtml")]
|
[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()
|
public Index()
|
||||||
{
|
{
|
||||||
@@ -76,10 +76,10 @@ WriteLiteral(">\r\n");
|
|||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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);
|
Write(DevicesInProcess.Length);
|
||||||
|
|
||||||
|
|
||||||
@@ -92,14 +92,14 @@ WriteLiteral(" class=\"dataTable\"");
|
|||||||
WriteLiteral(">\r\n");
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
foreach (var item in DevicesInProcess)
|
foreach (var item in DevicesInProcess.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@@ -114,8 +114,8 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 18 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 17 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -129,17 +129,24 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 20 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserDisplayName);
|
Write(item.UserDisplayName);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 21 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
if (item.EstimatedReturnTime.HasValue)
|
||||||
if (!string.IsNullOrEmpty(item.EstimatedReturnTime))
|
{
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -151,8 +158,8 @@ WriteLiteral(" class=\"smallMessage\"");
|
|||||||
WriteLiteral(">(Expected: ");
|
WriteLiteral(">(Expected: ");
|
||||||
|
|
||||||
|
|
||||||
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 23 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.EstimatedReturnTime);
|
Write(CommonHelpers.FriendlyDate(item.EstimatedReturnTime));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -160,16 +167,16 @@ WriteLiteral(">(Expected: ");
|
|||||||
WriteLiteral(")</span>\r\n");
|
WriteLiteral(")</span>\r\n");
|
||||||
|
|
||||||
|
|
||||||
#line 25 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 24 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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");
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
#line 33 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 31 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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();
|
var WaitingForUserActionJobs = Model.Where(i => i.WaitingForUserAction).ToArray();
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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);
|
Write(WaitingForUserActionJobs.Length);
|
||||||
|
|
||||||
|
|
||||||
@@ -211,14 +218,14 @@ WriteLiteral(" class=\"dataTable\"");
|
|||||||
WriteLiteral(">\r\n");
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 39 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 36 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
foreach (var item in WaitingForUserActionJobs)
|
foreach (var item in WaitingForUserActionJobs.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@@ -233,8 +240,8 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 40 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -248,7 +255,7 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 46 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 43 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserDisplayName);
|
Write(item.UserDisplayName);
|
||||||
|
|
||||||
|
|
||||||
@@ -256,22 +263,22 @@ WriteLiteral(" ");
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\r\n </td>\r\n <td");
|
WriteLiteral("\r\n </td>\r\n <td");
|
||||||
|
|
||||||
WriteAttribute("class", Tuple.Create(" class=\"", 1795), Tuple.Create("\"", 1853)
|
WriteAttribute("class", Tuple.Create(" class=\"", 1845), Tuple.Create("\"", 1903)
|
||||||
, Tuple.Create(Tuple.Create("", 1803), Tuple.Create("timestamp", 1803), true)
|
, Tuple.Create(Tuple.Create("", 1853), Tuple.Create("timestamp", 1853), true)
|
||||||
|
|
||||||
#line 48 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
, Tuple.Create(Tuple.Create("", 1812), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
, Tuple.Create(Tuple.Create("", 1862), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 1812), false)
|
, 1862), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">\r\n Since ");
|
WriteLiteral(">Since ");
|
||||||
|
|
||||||
|
|
||||||
#line 49 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 45 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.WaitingForUserActionSince);
|
Write(CommonHelpers.FriendlyDate(item.WaitingForUserActionSince));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -279,7 +286,7 @@ WriteLiteral(">\r\n Since ");
|
|||||||
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
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");
|
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 default
|
||||||
#line hidden
|
#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();
|
var DevicesReadyForReturn = Model.Where(i => i.ReadyForReturn && !i.WaitingForUserAction).ToArray();
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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);
|
Write(DevicesReadyForReturn.Length);
|
||||||
|
|
||||||
|
|
||||||
@@ -317,14 +324,14 @@ WriteLiteral(" class=\"dataTable\"");
|
|||||||
WriteLiteral(">\r\n");
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 61 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 56 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
foreach (var item in DevicesReadyForReturn)
|
foreach (var item in DevicesReadyForReturn.OrderBy(i => i.UserIdFriendly))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@@ -339,8 +346,8 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 60 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserId);
|
Write(item.UserIdFriendly);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -354,7 +361,7 @@ WriteLiteral(">\r\n");
|
|||||||
WriteLiteral(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 68 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 63 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.UserDisplayName);
|
Write(item.UserDisplayName);
|
||||||
|
|
||||||
|
|
||||||
@@ -362,22 +369,22 @@ WriteLiteral(" ");
|
|||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\r\n </td>\r\n <td");
|
WriteLiteral("\r\n </td>\r\n <td");
|
||||||
|
|
||||||
WriteAttribute("class", Tuple.Create(" class=\"", 2612), Tuple.Create("\"", 2670)
|
WriteAttribute("class", Tuple.Create(" class=\"", 2689), Tuple.Create("\"", 2747)
|
||||||
, Tuple.Create(Tuple.Create("", 2620), Tuple.Create("timestamp", 2620), true)
|
, Tuple.Create(Tuple.Create("", 2697), Tuple.Create("timestamp", 2697), true)
|
||||||
|
|
||||||
#line 70 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
, Tuple.Create(Tuple.Create("", 2629), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
, Tuple.Create(Tuple.Create("", 2706), Tuple.Create<System.Object, System.Int32>(item.IsAlert ? " Alert" : string.Empty
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
, 2629), false)
|
, 2706), false)
|
||||||
);
|
);
|
||||||
|
|
||||||
WriteLiteral(">\r\n Ready ");
|
WriteLiteral(">Ready ");
|
||||||
|
|
||||||
|
|
||||||
#line 71 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
#line 65 "..\..\Areas\Public\Views\UserHeldDevices\Index.cshtml"
|
||||||
Write(item.ReadyForReturnSince);
|
Write(CommonHelpers.FriendlyDate(item.ReadyForReturnSince));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
@@ -385,7 +392,7 @@ WriteLiteral(">\r\n Ready ");
|
|||||||
WriteLiteral("\r\n </td>\r\n </tr>\r\n");
|
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;
|
Layout = null;
|
||||||
|
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||||
Html.BundleDeferred("~/ClientScripts/Core");
|
Html.BundleDeferred("~/ClientScripts/Core");
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||||
@@ -9,471 +10,397 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<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()
|
@Html.BundleRenderDeferred()
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="status-connecting">
|
||||||
<div id="page">
|
<div id="page">
|
||||||
<header id="mainHeader">
|
<header id="header">
|
||||||
Technician Held Devices for Users
|
<div id="heading">Held Devices for Users</div>
|
||||||
</header>
|
<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">
|
<section id="mainSection">
|
||||||
<div id="inProcess" class="list">
|
<div id="inProcess" class="list">
|
||||||
<h3>
|
<h3>In Process (<span data-bind="text: inProcess().length"></span>)
|
||||||
In Process <span id="inProcessCount"></span>
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: inProcess().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: inProcess, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="readyForReturn" class="list">
|
<div id="readyForReturn" class="list">
|
||||||
<h3>
|
<h3>Ready for Return (<span data-bind="text: readyForReturn().length"></span>)
|
||||||
Ready for Return <span id="readyForReturnCount"></span>
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: readyForReturn().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: readyForReturn, afterRender: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="waitingForUserAction" class="list">
|
<div id="waitingForUserAction" class="list">
|
||||||
<h3>
|
<h3>Waiting for User Action (<span data-bind="text: waitingForUserAction().length"></span>)
|
||||||
Waiting for User Action <span id="waitingForUserActionCount"></span>
|
|
||||||
</h3>
|
</h3>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ul>
|
<!-- ko if: waitingForUserAction().length == 0 -->
|
||||||
</ul>
|
<div class="noContent"><None></div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<ul data-bind="template: { name: 'item-template', foreach: waitingForUserAction, afterAdd: onAdd, beforeRemove: onRemove }"></ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<footer id="footer">
|
||||||
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
<footer>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/html" id="item-template">
|
||||||
// Resizing
|
<li data-bind="css: { alert: IsAlert }">
|
||||||
$(function () {
|
<span data-bind="text: UserIdFriendly + ' - ' + UserDisplayName"></span>
|
||||||
var $inProcess = $('#inProcess');
|
<!-- ko if: !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->
|
||||||
var $inProcessContent = $inProcess.find('.content');
|
<span class="small">(Expected <span data-bind="livestamp: EstimatedReturnTimeUnixEpoc"></span>)</span>
|
||||||
var $inProcessHeader = $inProcess.find('.h3');
|
<!-- /ko -->
|
||||||
var $readyForReturn = $('#readyForReturn');
|
<!-- ko if: WaitingForUserAction -->
|
||||||
var $readyForReturnContent = $readyForReturn.find('.content');
|
<span class="small">(Since <span data-bind="livestamp: WaitingForUserActionSinceUnixEpoc"></span>)</span>
|
||||||
var $readyForReturnHeader = $readyForReturn.find('.h3');
|
<!-- /ko -->
|
||||||
var $waitingForUserAction = $('#waitingForUserAction');
|
<!-- ko if: ReadyForReturn && !WaitingForUserAction -->
|
||||||
var $waitingForUserActionContent = $waitingForUserAction.find('.content');
|
<span class="small">(Ready <span data-bind="livestamp: ReadyForReturnSinceUnixEpoc"></span>)</span>
|
||||||
var $waitingForUserActionHeader = $waitingForUserAction.find('.h3');
|
<!-- /ko -->
|
||||||
var $mainSection = $('#mainSection');
|
</li>
|
||||||
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>
|
</script>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
// Hide Mouse Mouse
|
ko.bindingHandlers.livestamp = {
|
||||||
$(function () {
|
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||||
var mouseVisible = true;
|
var value = valueAccessor();
|
||||||
var mouseHideToken;
|
var valueUnwrapped = ko.unwrap(value);
|
||||||
var documentBody = $('body');
|
|
||||||
|
|
||||||
var hideMouse = function () {
|
if (valueUnwrapped)
|
||||||
if (mouseVisible) {
|
$(element).livestamp(valueUnwrapped);
|
||||||
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 "";
|
|
||||||
else
|
else
|
||||||
return decodeURIComponent(results[1].replace(/\+/g, " "));
|
$(element).livestamp('destroy');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var hub;
|
||||||
|
var viewModel;
|
||||||
|
|
||||||
var buildFilters = function () {
|
var rotateSpeed = 3000;
|
||||||
var deviceAddressInclude = getParameterByName('deviceAddressInclude');
|
var itemFilters;
|
||||||
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 sortModels = function () {
|
var $inProcessList = $('#inProcess').find('ul');
|
||||||
modelsInProcessSorted = [];
|
var $readyForReturnList = $('#readyForReturn').find('ul');
|
||||||
modelsReadyForReturnSorted = [];
|
var $waitingForUserActionList = $('#waitingForUserAction').find('ul');
|
||||||
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);
|
|
||||||
|
|
||||||
if (modelsInProcessSorted.length != modelsInProcessCount) {
|
function noticeboardViewModel(inProcess, readyForReturn, waitingForUserAction) {
|
||||||
modelsInProcessCount = modelsInProcessSorted.length;
|
var self = this;
|
||||||
$('#inProcessCount').text('(' + modelsInProcessCount + ')');
|
|
||||||
}
|
|
||||||
if (modelsReadyForReturnSorted.length != modelsReadyForReturnCount) {
|
|
||||||
modelsReadyForReturnCount = modelsReadyForReturnSorted.length;
|
|
||||||
$('#readyForReturnCount').text('(' + modelsReadyForReturnCount + ')');
|
|
||||||
}
|
|
||||||
if (modelsWaitingForUserActionSorted.length != modelsWaitingForUserActionCount) {
|
|
||||||
modelsWaitingForUserActionCount = modelsWaitingForUserActionSorted.length;
|
|
||||||
$('#waitingForUserActionCount').text('(' + modelsWaitingForUserActionCount + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
self.initialized = false;
|
||||||
|
|
||||||
var scrollReadyForReturn = function () {
|
self.inProcess = ko.observableArray(inProcess);
|
||||||
$readyForReturnContent.find('li').last().detach().prependTo($readyForReturnContent).hide().slideDown('slow');
|
self.readyForReturn = ko.observableArray(readyForReturn);
|
||||||
modelsReadyForReturnIndexOffset++;
|
self.waitingForUserAction = ko.observableArray(waitingForUserAction);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var modelInsertIndex = function (model) {
|
self.onRemove = function (element, index, data) {
|
||||||
sortModels();
|
$(element).slideUp(400, function () {
|
||||||
var findIndex = function (model, array, offset) {
|
$(this).remove();
|
||||||
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.onAdd = function (element, index, data) {
|
||||||
|
if (self.initialized)
|
||||||
var processModel = function (id, model, init) {
|
$(element).hide().slideDown(400);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var init = function () {
|
function init() {
|
||||||
buildFilters();
|
// Connect to Hub
|
||||||
persistantConnection = $.connection('@(Url.Content("~/Public/UserHeldDevices/Notifications"))');
|
hub = $.connection.noticeboardUpdates;
|
||||||
persistantConnection.received(updatedModel);
|
|
||||||
persistantConnection.error(connectionError);
|
// Map Functions
|
||||||
persistantConnection.start(function () {
|
hub.client.updateHeldDeviceForUser = updateHeldDevice;
|
||||||
$.getJSON('@(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()))', null, function (data) {
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
$.connection.hub.qs = { Noticeboard: '@(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name)' };
|
||||||
processModel(data[i].UserId, data[i], true);
|
$.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);
|
||||||
});
|
});
|
||||||
};
|
buildFilters();
|
||||||
init();
|
}
|
||||||
|
|
||||||
|
// 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>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// 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
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -47,6 +47,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices
|
|||||||
#line 1 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
#line 1 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||||
|
|
||||||
Layout = null;
|
Layout = null;
|
||||||
|
Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
|
||||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
|
||||||
Html.BundleDeferred("~/ClientScripts/Core");
|
Html.BundleDeferred("~/ClientScripts/Core");
|
||||||
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
Html.BundleDeferred("~/Style/Public/HeldDevicesNoticeboard");
|
||||||
@@ -64,26 +65,58 @@ WriteLiteral(" http-equiv=\"X-UA-Compatible\"");
|
|||||||
|
|
||||||
WriteLiteral(" content=\"IE=edge\"");
|
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(" ");
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
#line 13 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
#line 14 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||||
Write(Html.BundleRenderDeferred());
|
Write(Html.BundleRenderDeferred());
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#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(" id=\"page\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <header");
|
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\"");
|
WriteLiteral(" id=\"mainSection\"");
|
||||||
|
|
||||||
@@ -93,402 +126,288 @@ WriteLiteral(" id=\"inProcess\"");
|
|||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: inProcess().length == 0 -->\r\n " +
|
||||||
" </div>\r\n <div");
|
" <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(" id=\"readyForReturn\"");
|
||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: readyForReturn().length == 0 -->\r\n " +
|
||||||
" </div>\r\n <div");
|
" <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(" id=\"waitingForUserAction\"");
|
||||||
|
|
||||||
WriteLiteral(" class=\"list\"");
|
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(" class=\"content\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n <ul>\r\n </ul>\r\n </div>\r\n " +
|
WriteLiteral(">\r\n <!-- ko if: waitingForUserAction().length == 0 -->\r\n " +
|
||||||
" </div>\r\n </section>\r\n <footer>\r\n </footer>\r\n " +
|
" <div");
|
||||||
"</div>\r\n <script");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"text/javascript\"");
|
WriteLiteral(" class=\"noContent\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n // Resizing\r\n $(function () {\r\n var $inProcess = $(\'" +
|
WriteLiteral("><None></div>\r\n <!-- /ko -->\r\n <ul");
|
||||||
"#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(" type=\"text/javascript\"");
|
WriteLiteral(" data-bind=\"template: { name: \'item-template\', foreach: waitingForUserAction, aft" +
|
||||||
|
"erAdd: onAdd, beforeRemove: onRemove }\"");
|
||||||
|
|
||||||
WriteLiteral(@">
|
WriteLiteral("></ul>\r\n </div>\r\n </div>\r\n <footer");
|
||||||
// Hide Mouse Mouse
|
|
||||||
$(function () {
|
|
||||||
var mouseVisible = true;
|
|
||||||
var mouseHideToken;
|
|
||||||
var documentBody = $('body');
|
|
||||||
|
|
||||||
var hideMouse = function () {
|
WriteLiteral(" id=\"footer\"");
|
||||||
if (mouseVisible) {
|
|
||||||
documentBody.css('cursor', 'none');
|
|
||||||
mouseVisible = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var showMouse = function () {
|
|
||||||
if (!mouseVisible) {
|
|
||||||
documentBody.css('cursor', 'auto');
|
|
||||||
mouseVisible = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).mousemove(function () {
|
WriteLiteral(">\r\n </footer>\r\n </section>\r\n </div>\r\n <script");
|
||||||
showMouse();
|
|
||||||
if (mouseHideToken)
|
|
||||||
window.clearTimeout(mouseHideToken);
|
|
||||||
mouseHideToken = window.setTimeout(hideMouse, 2000);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"text/javascript\"");
|
WriteLiteral(" type=\"text/html\"");
|
||||||
|
|
||||||
WriteLiteral(">\r\n $(function () {\r\n var models = {};\r\n var modelsI" +
|
WriteLiteral(" id=\"item-template\"");
|
||||||
"nProcessSorted = [];\r\n var modelsInProcessCount = 0;\r\n var" +
|
|
||||||
" modelsReadyForReturnSorted = [];\r\n var modelsReadyForReturnCount = 0" +
|
WriteLiteral(">\r\n <li data-bind=\"css: { alert: IsAlert }\">\r\n <span data-bind=" +
|
||||||
";\r\n var modelsWaitingForUserActionSorted = [];\r\n var model" +
|
"\"text: UserIdFriendly + \' - \' + UserDisplayName\"></span>\r\n <!-- ko if" +
|
||||||
"sWaitingForUserActionCount = 0;\r\n var $inProcess = $(\'#inProcess\');\r\n" +
|
": !ReadyForReturn && EstimatedReturnTimeUnixEpoc -->\r\n <span class=\"s" +
|
||||||
" var $inProcessContent = $inProcess.find(\'.content ul\');\r\n " +
|
"mall\">(Expected <span data-bind=\"livestamp: EstimatedReturnTimeUnixEpoc\"></span>" +
|
||||||
" var $readyForReturn = $(\'#readyForReturn\');\r\n var $readyForReturnCon" +
|
")</span>\r\n <!-- /ko -->\r\n <!-- ko if: WaitingForUserAction" +
|
||||||
"tent = $readyForReturn.find(\'.content ul\');\r\n var $waitingForUserActi" +
|
" -->\r\n <span class=\"small\">(Since <span data-bind=\"livestamp: Waiting" +
|
||||||
"on = $(\'#waitingForUserAction\');\r\n var $waitingForUserActionContent =" +
|
"ForUserActionSinceUnixEpoc\"></span>)</span>\r\n <!-- /ko -->\r\n " +
|
||||||
" $waitingForUserAction.find(\'.content ul\');\r\n var modelsInProcessInde" +
|
" <!-- ko if: ReadyForReturn && !WaitingForUserAction -->\r\n <span cl" +
|
||||||
"xOffset = 0;\r\n var scrollInProcessToken = null;\r\n var mode" +
|
"ass=\"small\">(Ready <span data-bind=\"livestamp: ReadyForReturnSinceUnixEpoc\"></sp" +
|
||||||
"lsReadyForReturnIndexOffset = 0;\r\n var scrollReadyForReturnToken = nu" +
|
"an>)</span>\r\n <!-- /ko -->\r\n </li>\r\n </script>\r\n <script" +
|
||||||
"ll;\r\n var modelsWaitingForUserActionIndexOffset = 0;\r\n var" +
|
">\r\n ko.bindingHandlers.livestamp = {\r\n init: function (element" +
|
||||||
" scrollWaitingForUserActionToken = null;\r\n var scrollSpeed = 3000;\r\n " +
|
", valueAccessor, allBindings, viewModel, bindingContext) {\r\n var " +
|
||||||
" var persistantConnection = null;\r\n var filterDeviceAddress" +
|
"value = valueAccessor();\r\n var valueUnwrapped = ko.unwrap(value);" +
|
||||||
"Include;\r\n var filterDeviceAddressExclude;\r\n var filterDev" +
|
"\r\n\r\n if (valueUnwrapped)\r\n $(element).livestam" +
|
||||||
"iceProfileInclude;\r\n var filterDeviceProfileExclude;\r\n \r\n " +
|
"p(valueUnwrapped);\r\n else\r\n $(element).livesta" +
|
||||||
" var getParameterByName = function (name) {\r\n name = na" +
|
"mp(\'destroy\');\r\n }\r\n };\r\n </script>\r\n <script>\r\n " +
|
||||||
"me.replace(/[\\[]/, \"\\\\\\[\").replace(/[\\]]/, \"\\\\\\]\");\r\n var regexS " +
|
"$(function () {\r\n var hub;\r\n var viewModel;\r\n\r\n " +
|
||||||
"= \"[\\\\?&]\" + name + \"=([^&#]*)\";\r\n var regex = new RegExp(regexS)" +
|
" var rotateSpeed = 3000;\r\n var itemFilters;\r\n\r\n var $inPro" +
|
||||||
";\r\n var results = regex.exec(window.location.search);\r\n " +
|
"cessList = $(\'#inProcess\').find(\'ul\');\r\n var $readyForReturnList = $(" +
|
||||||
" if (results == null)\r\n return \"\";\r\n else" +
|
"\'#readyForReturn\').find(\'ul\');\r\n var $waitingForUserActionList = $(\'#" +
|
||||||
"\r\n return decodeURIComponent(results[1].replace(/\\+/g, \" \"));" +
|
"waitingForUserAction\').find(\'ul\');\r\n\r\n function noticeboardViewModel(" +
|
||||||
"\r\n }\r\n\r\n var buildFilters = function () {\r\n " +
|
"inProcess, readyForReturn, waitingForUserAction) {\r\n var self = t" +
|
||||||
" var deviceAddressInclude = getParameterByName(\'deviceAddressInclude\');\r\n " +
|
"his;\r\n\r\n self.initialized = false;\r\n\r\n self.inProc" +
|
||||||
" if (deviceAddressInclude) {\r\n filterDeviceAddressInc" +
|
"ess = ko.observableArray(inProcess);\r\n self.readyForReturn = ko.o" +
|
||||||
"lude = {};\r\n var split = deviceAddressInclude.split(\",\");\r\n " +
|
"bservableArray(readyForReturn);\r\n self.waitingForUserAction = ko." +
|
||||||
" for (var i = 0; i < split.length; i++) {\r\n " +
|
"observableArray(waitingForUserAction);\r\n\r\n self.onRemove = functi" +
|
||||||
" filterDeviceAddressInclude[split[i].toLowerCase()] = true;\r\n " +
|
"on (element, index, data) {\r\n $(element).slideUp(400, functio" +
|
||||||
" }\r\n } else {\r\n var deviceAddressExclude = " +
|
"n () {\r\n $(this).remove();\r\n });\r\n " +
|
||||||
"getParameterByName(\'deviceAddressExclude\');\r\n if (deviceAddre" +
|
" }\r\n self.onAdd = function (element, index, data) {\r\n " +
|
||||||
"ssExclude) {\r\n filterDeviceAddressExclude = {};\r\n " +
|
" if (self.initialized)\r\n $(element).hid" +
|
||||||
" var split = deviceAddressExclude.split(\",\");\r\n " +
|
"e().slideDown(400);\r\n }\r\n }\r\n\r\n function in" +
|
||||||
" for (var i = 0; i < split.length; i++) {\r\n filt" +
|
"it() {\r\n // Connect to Hub\r\n hub = $.connection.no" +
|
||||||
"erDeviceAddressExclude[split[i].toLowerCase()] = true;\r\n " +
|
"ticeboardUpdates;\r\n\r\n // Map Functions\r\n hub.clien" +
|
||||||
"}\r\n } else {\r\n var deviceProfileInclud" +
|
"t.updateHeldDeviceForUser = updateHeldDevice;\r\n\r\n $.connection.hu" +
|
||||||
"e = getParameterByName(\'deviceProfileInclude\');\r\n if (dev" +
|
"b.qs = { Noticeboard: \'");
|
||||||
"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: \'");
|
|
||||||
|
|
||||||
|
|
||||||
#line 435 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
#line 127 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||||
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevice()));
|
Write(Disco.Services.Jobs.Noticeboards.HeldDevicesForUsers.Name);
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral(@"',
|
WriteLiteral(@"' };
|
||||||
data: { id: userId },
|
$.connection.hub.error(connectionError);
|
||||||
success: function (data) {
|
$.connection.hub.disconnected(connectionError);
|
||||||
processModel(userId, data, false);
|
$.connection.hub.reconnected(connectionError);
|
||||||
},
|
|
||||||
error: function(jqXHR, textStatus, errorThrown){
|
|
||||||
if (textStatus == 'parsererror') // null Result
|
|
||||||
processModel(userId, null, false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
var connectionError = function () {
|
// Start Connection
|
||||||
if (persistantConnection) {
|
$.connection.hub.start().fail(connectionError).done(loadData);
|
||||||
persistantConnection.stop();
|
}
|
||||||
persistantConnection = null;
|
|
||||||
window.setTimeout(function () {
|
// Called after SignalR is connected
|
||||||
window.location.href = '");
|
function loadData() {
|
||||||
|
$.getJSON('");
|
||||||
|
|
||||||
|
|
||||||
#line 452 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
#line 138 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
||||||
Write(Url.Action(MVC.Public.UserHeldDevices.Noticeboard()));
|
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
#line hidden
|
#line hidden
|
||||||
WriteLiteral("\';\r\n }, 10000);\r\n }\r\n }\r\n\r\n " +
|
WriteLiteral("\', null, function (data) {\r\n\r\n var inProcess = [];\r\n " +
|
||||||
" var init = function () {\r\n buildFilters();\r\n pe" +
|
" var readyForReturn = [];\r\n var waitingForUserAction" +
|
||||||
"rsistantConnection = $.connection(\'");
|
" = [];\r\n\r\n data.filter(function (heldDeviceItem) {\r\n " +
|
||||||
|
" return includeItem(heldDeviceItem)\r\n }).forEac" +
|
||||||
|
"h(function (heldDeviceItem) {\r\n if (isWaitingForUserActio" +
|
||||||
#line 459 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
"n(heldDeviceItem))\r\n waitingForUserAction.push(heldDe" +
|
||||||
Write(Url.Content("~/Public/UserHeldDevices/Notifications"));
|
"viceItem);\r\n else if (isReadyForReturn(heldDeviceItem))\r\n" +
|
||||||
|
" readyForReturn.push(heldDeviceItem);\r\n " +
|
||||||
|
" else if (isInProcess(heldDeviceItem))\r\n inP" +
|
||||||
#line default
|
"rocess.push(heldDeviceItem);\r\n });\r\n\r\n inP" +
|
||||||
#line hidden
|
"rocess.sort(sortFunction);\r\n readyForReturn.sort(sortFunction" +
|
||||||
WriteLiteral("\');\r\n persistantConnection.received(updatedModel);\r\n " +
|
");\r\n waitingForUserAction.sort(sortFunction);\r\n\r\n " +
|
||||||
" persistantConnection.error(connectionError);\r\n persistantConnec" +
|
" viewModel = new noticeboardViewModel(inProcess, readyForReturn, waitingF" +
|
||||||
"tion.start(function () {\r\n $.getJSON(\'");
|
"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" +
|
||||||
#line 463 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
"on, rotateSpeed);\r\n });\r\n buildFilters();\r\n " +
|
||||||
Write(Url.Action(MVC.Public.UserHeldDevices.UserHeldDevices()));
|
" }\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" +
|
||||||
#line default
|
"sting\r\n removeItem(UserId);\r\n\r\n //" +
|
||||||
#line hidden
|
" Add Item\r\n addItem(heldDeviceItem);\r\n " +
|
||||||
WriteLiteral(@"', null, function (data) {
|
" });\r\n }\r\n }\r\n\r\n function removeItem(UserId" +
|
||||||
for (var i = 0; i < data.length; i++) {
|
") {\r\n removeItemFromArray(viewModel.inProcess, UserId);\r\n " +
|
||||||
processModel(data[i].UserId, data[i], true);
|
" 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 " +
|
||||||
init();
|
" if (isWaitingForUserAction(heldDeviceItem))\r\n " +
|
||||||
|
" array = viewModel.waitingForUserAction;\r\n else if (isRea" +
|
||||||
});
|
"dyForReturn(heldDeviceItem))\r\n array = viewModel.readyFor" +
|
||||||
</script>
|
"Return;\r\n else if (isInProcess(heldDeviceItem))\r\n " +
|
||||||
<div");
|
" array = viewModel.inProcess;\r\n\r\n if (array().leng" +
|
||||||
|
"th === 0) {\r\n array.push(heldDeviceItem);\r\n " +
|
||||||
WriteLiteral(" id=\"mainFooter\"");
|
" } else {\r\n var index = findSortedInsertIndex(array," +
|
||||||
|
" heldDeviceItem);\r\n if (index === -1)\r\n " +
|
||||||
WriteLiteral(">\r\n <img");
|
" array.push(heldDeviceItem);\r\n else\r\n " +
|
||||||
|
" array.splice(index, 0, heldDeviceItem);\r\n }\r" +
|
||||||
WriteLiteral(" style=\"width: 34px; height: 34px; margin-top: -5px; margin-bottom: -12px;\"");
|
"\n }\r\n }\r\n\r\n function rotateArrays() {\r\n " +
|
||||||
|
" rotateArray(viewModel.inProcess, $inProcessList);\r\n r" +
|
||||||
WriteAttribute("src", Tuple.Create(" src=\"", 22642), Tuple.Create("\"", 22692)
|
"otateArray(viewModel.readyForReturn, $readyForReturnList);\r\n rota" +
|
||||||
|
"teArray(viewModel.waitingForUserAction, $waitingForUserActionList);\r\n " +
|
||||||
#line 475 "..\..\Areas\Public\Views\UserHeldDevices\Noticeboard.cshtml"
|
" }\r\n\r\n function scheduleRotation() {\r\n rotateArrays();" +
|
||||||
, Tuple.Create(Tuple.Create("", 22648), Tuple.Create<System.Object, System.Int32>(Links.ClientSource.Style.Images.Heading_png
|
"\r\n\r\n window.setTimeout(scheduleRotation, rotateSpeed);\r\n " +
|
||||||
|
" }\r\n\r\n function includeItem(heldDeviceItem) {\r\n if (" +
|
||||||
#line default
|
"itemFilters == null || itemFilters.length == 0)\r\n return true" +
|
||||||
#line hidden
|
";\r\n\r\n return itemFilters.reduce(function (previousValue, currentV" +
|
||||||
, 22648), false)
|
"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" +
|
||||||
WriteLiteral(" alt=\"Disco Logo\"");
|
"Filters() {\r\n var filters = [];\r\n var queryStringP" +
|
||||||
|
"arameters = getQueryStringParameters();\r\n\r\n if (queryStringParame" +
|
||||||
WriteLiteral(" />\r\n powered by Disco\r\n </div>\r\n</body>\r\n</html>\r\n");
|
"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
|
///#source 1 1 /ClientSource/Scripts/Modules/Knockout/knockout-3.1.0.js
|
||||||
// Knockout JavaScript library v2.3.0
|
// Knockout JavaScript library v3.1.0
|
||||||
// (c) Steven Sanderson - http://knockoutjs.com/
|
// (c) Steven Sanderson - http://knockoutjs.com/
|
||||||
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
// 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=
|
(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,
|
||||||
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,
|
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",
|
||||||
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=
|
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,
|
||||||
"\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&&
|
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.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)},
|
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,
|
||||||
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<
|
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<
|
||||||
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)===
|
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),
|
||||||
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);
|
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.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"==
|
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,
|
||||||
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),
|
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"),
|
||||||
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=
|
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,
|
||||||
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))?
|
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=
|
||||||
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=
|
[],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))():
|
||||||
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);
|
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]=
|
||||||
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",
|
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.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(),
|
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",
|
||||||
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=
|
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]}
|
||||||
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]&&
|
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);
|
||||||
(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=
|
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},
|
||||||
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?
|
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.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=
|
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)):
|
||||||
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||[]),
|
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],
|
||||||
!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=
|
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=
|
||||||
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)};
|
[];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);
|
||||||
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}};
|
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=
|
||||||
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=
|
{}};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&&
|
||||||
{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===
|
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",
|
||||||
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.");
|
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()},
|
||||||
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===
|
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",
|
||||||
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"],
|
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.");
|
||||||
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,
|
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=
|
||||||
"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");
|
"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();
|
||||||
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};
|
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;
|
||||||
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=
|
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,
|
||||||
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,
|
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,
|
||||||
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){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.");
|
||||||
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=
|
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()};
|
||||||
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-
|
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",
|
||||||
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,
|
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=
|
||||||
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;
|
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,
|
||||||
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&&
|
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,
|
||||||
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&&
|
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",
|
||||||
(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$/:
|
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===
|
||||||
/^\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,
|
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);
|
||||||
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=
|
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;
|
||||||
[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!=
|
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==
|
||||||
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);
|
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*$/,
|
||||||
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,
|
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,
|
||||||
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!==
|
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;
|
||||||
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=
|
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=
|
||||||
[],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.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");
|
||||||
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);
|
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()}
|
||||||
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=
|
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=
|
||||||
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),
|
[],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"!==
|
||||||
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=
|
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");
|
||||||
!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))},
|
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}}
|
||||||
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)},
|
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,
|
||||||
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");
|
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),
|
||||||
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<=
|
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.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,
|
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,
|
||||||
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");
|
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",
|
||||||
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)}})}};
|
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.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.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?
|
||||||
(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]=
|
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,
|
||||||
{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==
|
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",
|
||||||
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);
|
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.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,
|
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");
|
||||||
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=
|
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&&
|
||||||
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__")||
|
(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);
|
||||||
{};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!==
|
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=
|
||||||
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,
|
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}},
|
||||||
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=
|
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||
|
||||||
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=
|
-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=
|
||||||
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=
|
{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=
|
||||||
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"};
|
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=
|
||||||
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],
|
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,
|
||||||
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=
|
{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",
|
||||||
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<
|
"#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,
|
||||||
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,
|
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",
|
||||||
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.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!==
|
||||||
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=
|
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: "+
|
||||||
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 "+
|
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);
|
||||||
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)})()})})();
|
"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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<bundle minify="true" runOnBuild="true">
|
<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>
|
</bundle>
|
||||||
+3
-1
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<bundle minify="true" runOnBuild="true">
|
<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>
|
</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));
|
||||||
+1196
-626
File diff suppressed because it is too large
Load Diff
@@ -328,31 +328,31 @@ table.deviceProfileTable th.deviceCount {
|
|||||||
background-position: right top;
|
background-position: right top;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus {
|
#Logging_Task_Status {
|
||||||
width: 520px;
|
width: 520px;
|
||||||
margin: 40px auto 60px auto;
|
margin: 40px auto 60px auto;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus th.process {
|
#Logging_Task_Status th.process {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: #f4f4f4;
|
background-color: #f4f4f4;
|
||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus td.description {
|
#Logging_Task_Status td.description {
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus td.progress {
|
#Logging_Task_Status td.progress {
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus td.finishedRedirect {
|
#Logging_Task_Status td.finishedRedirect {
|
||||||
background-position: right center;
|
background-position: right center;
|
||||||
background-repeat: no-repeat;
|
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*/;
|
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;
|
padding-right: 20px;
|
||||||
}
|
}
|
||||||
#scheduledTaskStatus td.exception {
|
#Logging_Task_Status td.exception {
|
||||||
background-color: #FFD8D8;
|
background-color: #FFD8D8;
|
||||||
}
|
}
|
||||||
div.logEventsViewport {
|
div.logEventsViewport {
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ table.deviceProfileTable {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#scheduledTaskStatus {
|
#Logging_Task_Status {
|
||||||
width: 520px;
|
width: 520px;
|
||||||
margin: 40px auto 60px auto;
|
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