Some work on the status window
git-svn-id: https://duplicati.googlecode.com/svn/trunk@1273 59da171f-624f-0410-aa54-27559c288bec
This commit is contained in:
@@ -19,8 +19,16 @@
|
||||
}
|
||||
else
|
||||
return v || false;
|
||||
}
|
||||
};
|
||||
|
||||
APP_SCOPE.toJsDate = function(str) {
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
var strtmp = str.replace(/\/Date\((-?\d+(((\+|\-)\d+)|Z|z)?)\)\//gi, "new Date($1)");
|
||||
return eval(strtmp);
|
||||
};
|
||||
|
||||
APP_SCOPE.createHtmlItems = function(html) {
|
||||
if (ls.creator_div == null) {
|
||||
ls.creator_div = document.createElement("div");
|
||||
@@ -44,23 +52,17 @@
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
APP_SCOPE.applyRoundedCornerClass = function() {
|
||||
$('.rounded-corner-box').each(function(index, el) {
|
||||
if (!$(el).hasClass('created-round-corner-box')) {
|
||||
$(el).removeClass('rounded-corner-box');
|
||||
var x = el.innerHTML;
|
||||
el.innerHTML = '<table class="round-corner-box created-round-corner-box"><tr class="top"><td class="left"></td><td class="middle"></td><td class="right"></td></tr><tr class="center"><td class="left"></td><td class="middle">' + x + '</div></td><td class="right"></td></tr><tr class="bottom"><td class="left"></td><td class="middle"></td><td class="right"></td></tr></table>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
APP_SCOPE.getActionUrl = function(action) {
|
||||
//During the design phase, we emulate the server with a folder
|
||||
//return './server-responses/' + encodeURIComponent(action) + '.txt';
|
||||
return APP_SCOPE.ServerURL + 'control.cgi?action=' + encodeURIComponent(action);
|
||||
}
|
||||
|
||||
APP_SCOPE.getCurrentState = function(callback) {
|
||||
$.getJSON(this.getActionUrl('get-current-state'), callback);
|
||||
};
|
||||
|
||||
APP_SCOPE.getApplicationSettings = function(callback) {
|
||||
$.getJSON(this.getActionUrl('list-application-settings'), callback);
|
||||
};
|
||||
@@ -83,7 +85,7 @@
|
||||
callback(APP_SCOPE.CompressionModules);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
APP_SCOPE.getInstalledGenericModules = function(callback) {
|
||||
if (APP_SCOPE.CompressionModules == null) {
|
||||
$.getJSON(this.getActionUrl('list-installed-generic-modules'), function(resp) {
|
||||
@@ -119,7 +121,21 @@
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
if (window.external && window.external.AddSearch == null && window.external.AddSearchProvider == null) {
|
||||
ads = null;
|
||||
adsp = null;
|
||||
extmin = null;
|
||||
|
||||
if (window.external)
|
||||
{
|
||||
try { ads = window.external.AddSearch; }
|
||||
catch (e) {}
|
||||
try { adsp = window.external.AddSearchProvider; }
|
||||
catch (e) {}
|
||||
try { extmin = window.external.setMinSiz; }
|
||||
catch (e) {}
|
||||
}
|
||||
|
||||
if (window.external && ads == null && adsp == null && extmin != null) {
|
||||
APP_SCOPE.external = window.external;
|
||||
APP_SCOPE.activateFunction = function(code) {
|
||||
APP_SCOPE.external.openWindow(code);
|
||||
@@ -129,8 +145,6 @@
|
||||
alert("Unimplemented " + code);
|
||||
}
|
||||
}
|
||||
|
||||
APP_SCOPE.applyRoundedCornerClass();
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* Timeago is a jQuery plugin that makes it easy to support automatically
|
||||
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
||||
*
|
||||
* @name timeago
|
||||
* @version 0.11.2
|
||||
* @requires jQuery v1.2.3+
|
||||
* @author Ryan McGeary
|
||||
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||
*
|
||||
* For usage and examples, visit:
|
||||
* http://timeago.yarp.com/
|
||||
*
|
||||
* Copyright (c) 2008-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
||||
*/
|
||||
(function($) {
|
||||
$.timeago = function(timestamp) {
|
||||
if (timestamp instanceof Date) {
|
||||
return inWords(timestamp);
|
||||
} else if (typeof timestamp === "string") {
|
||||
return inWords($.timeago.parse(timestamp));
|
||||
} else {
|
||||
return inWords($.timeago.datetime(timestamp));
|
||||
}
|
||||
};
|
||||
var $t = $.timeago;
|
||||
|
||||
$.extend($.timeago, {
|
||||
settings: {
|
||||
refreshMillis: 60000,
|
||||
allowFuture: false,
|
||||
strings: {
|
||||
prefixAgo: null,
|
||||
prefixFromNow: null,
|
||||
suffixAgo: "ago",
|
||||
suffixFromNow: "from now",
|
||||
seconds: "less than a minute",
|
||||
minute: "about a minute",
|
||||
minutes: "%d minutes",
|
||||
hour: "about an hour",
|
||||
hours: "about %d hours",
|
||||
day: "a day",
|
||||
days: "%d days",
|
||||
month: "about a month",
|
||||
months: "%d months",
|
||||
year: "about a year",
|
||||
years: "%d years",
|
||||
wordSeparator: " ",
|
||||
numbers: []
|
||||
}
|
||||
},
|
||||
inWords: function(distanceMillis) {
|
||||
var $l = this.settings.strings;
|
||||
var prefix = $l.prefixAgo;
|
||||
var suffix = $l.suffixAgo;
|
||||
if (this.settings.allowFuture) {
|
||||
if (distanceMillis < 0) {
|
||||
prefix = $l.prefixFromNow;
|
||||
suffix = $l.suffixFromNow;
|
||||
}
|
||||
}
|
||||
|
||||
var seconds = Math.abs(distanceMillis) / 1000;
|
||||
var minutes = seconds / 60;
|
||||
var hours = minutes / 60;
|
||||
var days = hours / 24;
|
||||
var years = days / 365;
|
||||
|
||||
function substitute(stringOrFunction, number) {
|
||||
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
||||
var value = ($l.numbers && $l.numbers[number]) || number;
|
||||
return string.replace(/%d/i, value);
|
||||
}
|
||||
|
||||
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
||||
seconds < 90 && substitute($l.minute, 1) ||
|
||||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
||||
minutes < 90 && substitute($l.hour, 1) ||
|
||||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
||||
hours < 42 && substitute($l.day, 1) ||
|
||||
days < 30 && substitute($l.days, Math.round(days)) ||
|
||||
days < 45 && substitute($l.month, 1) ||
|
||||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
||||
years < 1.5 && substitute($l.year, 1) ||
|
||||
substitute($l.years, Math.round(years));
|
||||
|
||||
var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
|
||||
return $.trim([prefix, words, suffix].join(separator));
|
||||
},
|
||||
parse: function(iso8601) {
|
||||
var s = $.trim(iso8601);
|
||||
s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
|
||||
s = s.replace(/-/,"/").replace(/-/,"/");
|
||||
s = s.replace(/T/," ").replace(/Z/," UTC");
|
||||
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
||||
return new Date(s);
|
||||
},
|
||||
datetime: function(elem) {
|
||||
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
|
||||
return $t.parse(iso8601);
|
||||
},
|
||||
isTime: function(elem) {
|
||||
// jQuery's `is()` doesn't play well with HTML5 in IE
|
||||
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
||||
}
|
||||
});
|
||||
|
||||
$.fn.timeago = function() {
|
||||
var self = this;
|
||||
self.each(refresh);
|
||||
|
||||
var $s = $t.settings;
|
||||
if ($s.refreshMillis > 0) {
|
||||
setInterval(function() { self.each(refresh); }, $s.refreshMillis);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
function refresh() {
|
||||
var data = prepareData(this);
|
||||
if (!isNaN(data.datetime)) {
|
||||
$(this).text(inWords(data.datetime));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
function prepareData(element) {
|
||||
element = $(element);
|
||||
if (!element.data("timeago")) {
|
||||
element.data("timeago", { datetime: $t.datetime(element) });
|
||||
var text = $.trim(element.text());
|
||||
if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
|
||||
element.attr("title", text);
|
||||
}
|
||||
}
|
||||
return element.data("timeago");
|
||||
}
|
||||
|
||||
function inWords(date) {
|
||||
return $t.inWords(distance(date));
|
||||
}
|
||||
|
||||
function distance(date) {
|
||||
return (new Date().getTime() - date.getTime());
|
||||
}
|
||||
|
||||
// fix for IE6 suckage
|
||||
document.createElement("abbr");
|
||||
document.createElement("time");
|
||||
}(jQuery));
|
||||
@@ -1,8 +1,8 @@
|
||||
$(document).ready(function(){
|
||||
|
||||
APP_SCOPE.applyRoundedCornerClass();
|
||||
$('#appname').each(function(i, e) { e.innerHTML = APP_SCOPE.AppName;});
|
||||
|
||||
jQuery.timeago.settings.allowFuture = true;
|
||||
|
||||
//Request some initial data for making the display
|
||||
// we execute these in parallel for efficiency
|
||||
APP_SCOPE.getApplicationSettings(function(data) {
|
||||
@@ -14,21 +14,49 @@ $(document).ready(function(){
|
||||
APP_SCOPE.backupSchedules = data;
|
||||
APP_SCOPE.afterInitialRequest();
|
||||
});
|
||||
|
||||
APP_SCOPE.getCurrentState(function(data) {
|
||||
APP_SCOPE.currentState = data;
|
||||
APP_SCOPE.afterInitialRequest();
|
||||
});
|
||||
|
||||
if (window.external)
|
||||
window.external.setMinSize(775, 200);
|
||||
if (APP_SCOPE.external)
|
||||
APP_SCOPE.external.setMinSize(775, 200);
|
||||
|
||||
APP_SCOPE.add_new_backup = function()
|
||||
{
|
||||
window.activateFunction("new-backup");
|
||||
}
|
||||
|
||||
|
||||
APP_SCOPE.scheduleHtmlTemplate = '' +
|
||||
'<div id="%id%" class="status-window-row %oddorevenclass%">' +
|
||||
' <div class="status-window-row-inner status-window-row-inner-left" >' +
|
||||
' <div class="status-window-row-inner-content">%schedule%</div>' +
|
||||
' </div>' +
|
||||
' <div class="status-window-row-inner status-window-row-inner-middle">' +
|
||||
' <div>' +
|
||||
' <div class="ui-state-default ui-corner-all vertical-center status-window-name-bubble"><div><span>%name%</span><span class="ui-button-icon-primary ui-icon ui-icon-triangle-1-s" style="display: inline-block"></span></div></div>' +
|
||||
' <div class="ui-state-default ui-corner-all vertical-center status-window-detail-area">' +
|
||||
' <div>%metadata%</div>' +
|
||||
' <div>%labels%</div>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' <div class="status-window-row-inner status-window-row-inner-right">' +
|
||||
' <div class="status-window-row-inner-content">' +
|
||||
' <div>%error%</div>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
'</div>';
|
||||
|
||||
|
||||
});
|
||||
|
||||
(function(){
|
||||
APP_SCOPE.afterInitialRequest = function() {
|
||||
//Check that all required data is loaded, this prevents
|
||||
if (this.backupSchedules != null && this.applicationSettings != null) {
|
||||
if (this.backupSchedules != null && this.applicationSettings != null && this.currentState != null) {
|
||||
$('#modal-cover').hide();
|
||||
$('#progress-loader').hide();
|
||||
this.buildBackupDisplay();
|
||||
@@ -44,20 +72,63 @@ $(document).ready(function(){
|
||||
var sc = APP_SCOPE.backupSchedules[i];
|
||||
var id = 'backup-schedule-' + sc.ID;
|
||||
var oddClass = (i % 2) == 1 ? 'odd' : 'even';
|
||||
html += '<div id="'+ id + '" class="backup-schedule ' + oddClass + '">';
|
||||
html += '<div class="backup-schedule-inner ui-corner-all ui-helper-clearfix ui-helper">';
|
||||
html += '<div class="backup-schedule-name">' + sc.Name + '</div>';
|
||||
if (sc.Tags != null && sc.Tags != '')
|
||||
html += '<div class="backup-schedule-tags">' + sc.Tags + '</div>';
|
||||
if (sc.Path != null && sc.Path != '')
|
||||
html += '<div class="backup-schedule-path">' + sc.Path + '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
var templateFilled = APP_SCOPE.scheduleHtmlTemplate.replace("%name%", sc.Name).replace("%id%", "id").replace("%oddorevenclass%", oddClass);
|
||||
|
||||
var labels = '';
|
||||
if ((sc.Tags != null && sc.Tags != '') || (sc.Path != null && sc.Path != ''))
|
||||
{
|
||||
labels = 'Labels: ';
|
||||
if (sc.Tags != null && sc.Tags != '')
|
||||
labels += sc.Tags;
|
||||
if (sc.Path != null && sc.Path != '')
|
||||
labels += sc.Path;
|
||||
}
|
||||
|
||||
//TODO: Figure out what the scheduler state is
|
||||
var schedule = '';
|
||||
|
||||
//Is the backup running?
|
||||
if (sc.ID == APP_SCOPE.currentState.ActiveScheduleId) {
|
||||
schedule = '<div>Running</div><div class="link">Cancel</div>';
|
||||
} else {
|
||||
|
||||
//Is the backup in queue?
|
||||
var queueIndex = -1;
|
||||
if (APP_SCOPE.currentState.SchedulerQueueIds != null)
|
||||
for(var sci = 0; sci < APP_SCOPE.currentState.SchedulerQueueIds.length; sci++)
|
||||
if (APP_SCOPE.currentState.SchedulerQueueIds[sci] == sc.ID)
|
||||
{
|
||||
queueIndex = sci;
|
||||
break;
|
||||
}
|
||||
|
||||
if (queueIndex >= 0) {
|
||||
schedule = "No. " + (queueIndex + 1) + " in queue";
|
||||
} else {
|
||||
//Is the backup scheduled?
|
||||
if (sc.NextScheduledTime != null)
|
||||
{
|
||||
var scdate = APP_SCOPE.toJsDate(sc.NextScheduledTime);
|
||||
schedule = '<span title="' + scdate.toLocaleString() + '">' + jQuery.timeago(scdate) + '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO: Make some logic to extract the last error message
|
||||
var error = 'placeholder for error message';
|
||||
|
||||
//TODO: Extract some metadata
|
||||
var metadata = 'placeholder for metadata';
|
||||
|
||||
templateFilled = templateFilled.replace("%labels%", labels).replace("%schedule%", schedule).replace("%error%", error).replace("%metadata%", metadata);
|
||||
|
||||
html += templateFilled;
|
||||
}
|
||||
|
||||
container.innerHTML = html;
|
||||
|
||||
this.applyRoundedCornerClass();
|
||||
container.innerHTML = html;
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<link rel="stylesheet" href="stylesheets/customized.css" />
|
||||
|
||||
<script language="javascript" src="scripts/jquery-1.7.1.js" ></script>
|
||||
<script language="javascript" src="scripts/jquery.timeago.js" ></script>
|
||||
<script language="javascript" src="scripts/app-base.js" ></script>
|
||||
<script language="javascript" src="scripts/app-functions.js" ></script>
|
||||
|
||||
@@ -16,14 +17,13 @@
|
||||
<script language="javascript" src="scripts/customized.js" ></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="modal-cover" class="modal-cover"></div>
|
||||
<div id="progress-loader" class="loader ui-corner-all">Loading ...</div>
|
||||
|
||||
<div id="status-window-toolbar">
|
||||
<div id="status-window-toolbar-inner" class="ui-state-default ui-helper-clearfix ui-helper ui-widget-header">
|
||||
<div id="status-window-main-logo" title="Click to access basic functions" class="ui-state-default ui-helper-clearfix ui-helper ui-widget-header ui-corner-all">
|
||||
<div id="appname" class="appname"></div>
|
||||
<div id="appname" class="appname"></div><span class="ui-button-icon-primary ui-icon ui-icon-triangle-1-s"></span>
|
||||
</div>
|
||||
<div id="status-window-news" title="Click here to open the news page">A new version of Duplicati is available</div>
|
||||
|
||||
|
||||
@@ -39,77 +39,14 @@ body
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.odd { background-color: #efefef; }
|
||||
|
||||
.drop-arrow
|
||||
.even { background-color: #efefef; }
|
||||
.odd { background-color: #ffffff; }
|
||||
.link
|
||||
{
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
background-image: url('../gfx/drop-arrow.gif');
|
||||
background-repeat: no-repeat;
|
||||
color: darkblue;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.round-corner-box
|
||||
{
|
||||
border-collapse: collapse;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-spacing; 0px;
|
||||
}
|
||||
|
||||
.round-corner-box .top,
|
||||
.round-corner-box .bottom
|
||||
{ height: 5px; }
|
||||
|
||||
.round-corner-box .top .left,
|
||||
.round-corner-box .top .right,
|
||||
.round-corner-box .center .left,
|
||||
.round-corner-box .center .right,
|
||||
.round-corner-box .bottom .left,
|
||||
.round-corner-box .bottom .right
|
||||
{
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.round-corner-box .top .left,
|
||||
.round-corner-box .top .right,
|
||||
.round-corner-box .bottom .left,
|
||||
.round-corner-box .bottom .right
|
||||
{
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.round-corner-box .top .left,
|
||||
.round-corner-box .top .right,
|
||||
.round-corner-box .bottom .left,
|
||||
.round-corner-box .bottom .right
|
||||
{
|
||||
background-image: url('../gfx/round-box3.gif');
|
||||
}
|
||||
|
||||
.round-corner-box .center .left,
|
||||
.round-corner-box .center .right,
|
||||
.round-corner-box .top .middle,
|
||||
.round-corner-box .bottom .middle
|
||||
{
|
||||
background-image: url('../gfx/round-dot.gif');
|
||||
}
|
||||
|
||||
.round-corner-box .center .left,
|
||||
.round-corner-box .center .right
|
||||
{ background-repeat: repeat-y; }
|
||||
|
||||
.round-corner-box .top .middle,
|
||||
.round-corner-box .bottom .middle
|
||||
{ background-repeat: repeat-x; }
|
||||
|
||||
.round-corner-box .top .left { background-position: 0px 0px; }
|
||||
.round-corner-box .top .right { background-position: -5px 0px; }
|
||||
.round-corner-box .bottom .left { background-position: 0px -5px; }
|
||||
.round-corner-box .bottom .right { background-position: -5px -5px; }
|
||||
|
||||
.round-corner-box .top .middle { background-position: 0px 0px; }
|
||||
.round-corner-box .bottom .middle { background-position: 0px 4px; }
|
||||
.round-corner-box .center .left { background-position: 0px 0px; }
|
||||
.round-corner-box .center .right { background-position: 4px 0px; }
|
||||
.vertical-center { margin: 0px auto; }
|
||||
|
||||
@@ -8,7 +8,7 @@ body
|
||||
{
|
||||
min-width: 675px;
|
||||
min-height: 200px;
|
||||
display: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.status-window-toolbar-item
|
||||
@@ -131,6 +131,54 @@ body
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.backup-schedule-name
|
||||
.status-window-name-bubble
|
||||
{
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.status-window-row
|
||||
{
|
||||
height: 120px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.status-window-row-inner
|
||||
{
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.status-window-row-inner-left
|
||||
{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.status-window-row-inner-middle
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-window-row-inner-right
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.status-window-row-inner-content
|
||||
{
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
.status-window-detail-area
|
||||
{
|
||||
margin-top: -1px;
|
||||
padding-top: 11px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
min-width: 220px;
|
||||
}
|
||||
Reference in New Issue
Block a user