cmd/syncthing: Add UI for version restoration (fixes #2599)
This commit is contained in:
committed by
Jakob Borg
parent
c7f136c2b8
commit
b0e2050cdb
@@ -371,3 +371,7 @@ ul.three-columns li, ul.two-columns li {
|
||||
.tab-content {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.fancytree-ext-table {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@@ -27,3 +27,9 @@
|
||||
.panel-heading:hover, .panel-heading:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title,
|
||||
.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title {
|
||||
color: black !important;
|
||||
font-weight: lighter !important;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"Any devices configured on an introducer device will be added to this device as well.": "Any devices configured on an introducer device will be added to this device as well.",
|
||||
"Are you sure you want to remove device {%name%}?": "Are you sure you want to remove device {{name}}?",
|
||||
"Are you sure you want to remove folder {%label%}?": "Are you sure you want to remove folder {{label}}?",
|
||||
"Are you sure you want to restore {%count%} files?": "Are you sure you want to restore {{count}} files?",
|
||||
"Auto Accept": "Auto Accept",
|
||||
"Automatic upgrade now offers the choice between stable releases and release candidates.": "Automatic upgrade now offers the choice between stable releases and release candidates.",
|
||||
"Automatic upgrades": "Automatic upgrades",
|
||||
@@ -67,6 +68,8 @@
|
||||
"Discovered": "Discovered",
|
||||
"Discovery": "Discovery",
|
||||
"Discovery Failures": "Discovery Failures",
|
||||
"Do not restore": "Do not restore",
|
||||
"Do not restore all": "Do not restore all",
|
||||
"Documentation": "Documentation",
|
||||
"Download Rate": "Download Rate",
|
||||
"Downloaded": "Downloaded",
|
||||
@@ -95,6 +98,8 @@
|
||||
"Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.": "Files are moved to date stamped versions in a .stversions folder when replaced or deleted by Syncthing.",
|
||||
"Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.": "Files are protected from changes made on other devices, but changes made on this device will be sent to the rest of the cluster.",
|
||||
"Filesystem Notifications": "Filesystem Notifications",
|
||||
"Filter by date": "Filter by date",
|
||||
"Filter by name": "Filter by name",
|
||||
"Folder": "Folder",
|
||||
"Folder ID": "Folder ID",
|
||||
"Folder Label": "Folder Label",
|
||||
@@ -141,6 +146,7 @@
|
||||
"Log tailing paused. Click here to continue.": "Log tailing paused. Click here to continue.",
|
||||
"Logs": "Logs",
|
||||
"Major Upgrade": "Major Upgrade",
|
||||
"Mass actions": "Mass actions",
|
||||
"Master": "Master",
|
||||
"Maximum Age": "Maximum Age",
|
||||
"Metadata Only": "Metadata Only",
|
||||
@@ -201,6 +207,8 @@
|
||||
"Restart": "Restart",
|
||||
"Restart Needed": "Restart Needed",
|
||||
"Restarting": "Restarting",
|
||||
"Restore": "Restore",
|
||||
"Restore Versions": "Restore Versions",
|
||||
"Resume": "Resume",
|
||||
"Resume All": "Resume All",
|
||||
"Reused": "Reused",
|
||||
@@ -210,6 +218,8 @@
|
||||
"See external versioner help for supported templated command line parameters.": "See external versioner help for supported templated command line parameters.",
|
||||
"See external versioning help for supported templated command line parameters.": "See external versioning help for supported templated command line parameters.",
|
||||
"Select a version": "Select a version",
|
||||
"Select latest version": "Select latest version",
|
||||
"Select oldest version": "Select oldest version",
|
||||
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
|
||||
"Select the folders to share with this device.": "Select the folders to share with this device.",
|
||||
"Send \u0026 Receive": "Send \u0026 Receive",
|
||||
@@ -232,6 +242,7 @@
|
||||
"Single level wildcard (matches within a directory only)": "Single level wildcard (matches within a directory only)",
|
||||
"Size": "Size",
|
||||
"Smallest First": "Smallest First",
|
||||
"Some items could not be restored:": "Some items could not be restored:",
|
||||
"Source Code": "Source Code",
|
||||
"Stable releases and release candidates": "Stable releases and release candidates",
|
||||
"Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.": "Stable releases are delayed by about two weeks. During this time they go through testing as release candidates.",
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
|
||||
<title ng-bind="thisDeviceName() + ' | Syncthing'"></title>
|
||||
<link href="vendor/bootstrap/css/bootstrap.css" rel="stylesheet"/>
|
||||
<link href="vendor/bootstrap/css/daterangepicker.css" rel="stylesheet"/>
|
||||
<link href="assets/font/raleway.css" rel="stylesheet"/>
|
||||
<link href="vendor/font-awesome/css/font-awesome.css" rel="stylesheet"/>
|
||||
<link href="assets/css/overrides.css" rel="stylesheet"/>
|
||||
<link href="assets/css/theme.css" rel="stylesheet"/>
|
||||
<link href="vendor/fancytree/css/ui.fancytree.css" rel="stylesheet"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -434,6 +436,9 @@
|
||||
<button ng-if="folder.paused" type="button" class="btn btn-sm btn-default" ng-click="setFolderPause(folder.id, false)">
|
||||
<span class="fa fa-play"></span> <span translate>Resume</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" ng-click="restoreVersions.show(folder.id)" ng-if="folder.versioning.type">
|
||||
<span class="fa fa-undo"></span> <span translate>Versions</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-default" ng-click="rescanFolder(folder.id)" ng-show="['idle', 'stopped', 'unshared'].indexOf(folderStatus(folder)) > -1">
|
||||
<span class="fa fa-refresh"></span> <span translate>Rescan</span>
|
||||
</button>
|
||||
@@ -723,6 +728,8 @@
|
||||
<ng-include src="'syncthing/device/globalChangesModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/folder/editFolderModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/folder/editIgnoresModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/folder/restoreVersionsModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/folder/restoreVersionsConfirmation.html'"></ng-include>
|
||||
<ng-include src="'syncthing/settings/settingsModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/settings/advancedSettingsModalView.html'"></ng-include>
|
||||
<ng-include src="'syncthing/usagereport/usageReportModalView.html'"></ng-include>
|
||||
@@ -744,7 +751,10 @@
|
||||
<script type="text/javascript" src="vendor/angular/angular-translate.js"></script>
|
||||
<script type="text/javascript" src="vendor/angular/angular-translate-loader-static-files.js"></script>
|
||||
<script type="text/javascript" src="vendor/angular/angular-dirPagination.js"></script>
|
||||
<script type="text/javascript" src="vendor/moment/moment.js"></script>
|
||||
<script type="text/javascript" src="vendor/bootstrap/js/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="vendor/bootstrap/js/daterangepicker.js"></script>
|
||||
<script type="text/javascript" src="vendor/fancytree/jquery.fancytree-all-deps.js"></script>
|
||||
<!-- / vendor scripts -->
|
||||
|
||||
<!-- gui application code -->
|
||||
|
||||
@@ -134,3 +134,75 @@ function debounce(func, wait) {
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function buildTree(children) {
|
||||
/* Converts
|
||||
*
|
||||
* {
|
||||
* 'foo/bar': [...],
|
||||
* 'foo/baz': [...]
|
||||
* }
|
||||
*
|
||||
* to
|
||||
*
|
||||
* [
|
||||
* {
|
||||
* title: 'foo',
|
||||
* children: [
|
||||
* {
|
||||
* title: 'bar',
|
||||
* versions: [...],
|
||||
* ...
|
||||
* },
|
||||
* {
|
||||
* title: 'baz',
|
||||
* versions: [...],
|
||||
* ...
|
||||
* }
|
||||
* ],
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
var root = {
|
||||
children: []
|
||||
}
|
||||
|
||||
$.each(children, function(path, data) {
|
||||
var parts = path.split('/');
|
||||
var name = parts.splice(-1)[0];
|
||||
|
||||
var keySoFar = [];
|
||||
var parent = root;
|
||||
while (parts.length > 0) {
|
||||
var part = parts.shift();
|
||||
keySoFar.push(part);
|
||||
var found = false;
|
||||
for (var i = 0; i < parent.children.length; i++) {
|
||||
if (parent.children[i].title == part) {
|
||||
parent = parent.children[i];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
var child = {
|
||||
title: part,
|
||||
key: keySoFar.join('/'),
|
||||
folder: true,
|
||||
children: []
|
||||
}
|
||||
parent.children.push(child);
|
||||
parent = child;
|
||||
}
|
||||
}
|
||||
|
||||
parent.children.push({
|
||||
title: name,
|
||||
key: path,
|
||||
folder: false,
|
||||
versions: data,
|
||||
});
|
||||
});
|
||||
|
||||
return root.children;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ angular.module('syncthing.core')
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode({enabled: true, requireBase: false}).hashPrefix('!');
|
||||
})
|
||||
.controller('SyncthingController', function ($scope, $http, $location, LocaleService, Events, $filter, $q, $interval) {
|
||||
.controller('SyncthingController', function ($scope, $http, $location, LocaleService, Events, $filter, $q, $compile, $timeout, $rootScope) {
|
||||
'use strict';
|
||||
|
||||
// private/helper definitions
|
||||
@@ -1107,9 +1107,9 @@ angular.module('syncthing.core')
|
||||
},
|
||||
show: function() {
|
||||
$scope.logging.refreshFacilities();
|
||||
$scope.logging.timer = $interval($scope.logging.fetch, 0, 1);
|
||||
$scope.logging.timer = $timeout($scope.logging.fetch);
|
||||
$('#logViewer').modal().on('hidden.bs.modal', function () {
|
||||
$interval.cancel($scope.logging.timer);
|
||||
$timeout.cancel($scope.logging.timer);
|
||||
$scope.logging.timer = null;
|
||||
$scope.logging.entries = [];
|
||||
});
|
||||
@@ -1138,7 +1138,7 @@ angular.module('syncthing.core')
|
||||
var textArea = $('#logViewerText');
|
||||
if (textArea.is(":focus")) {
|
||||
if (!$scope.logging.timer) return;
|
||||
$scope.logging.timer = $interval($scope.logging.fetch, 500, 1);
|
||||
$scope.logging.timer = $timeout($scope.logging.fetch, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1149,7 +1149,7 @@ angular.module('syncthing.core')
|
||||
|
||||
$http.get(urlbase + '/system/log' + (last ? '?since=' + encodeURIComponent(last) : '')).success(function (data) {
|
||||
if (!$scope.logging.timer) return;
|
||||
$scope.logging.timer = $interval($scope.logging.fetch, 2000, 1);
|
||||
$scope.logging.timer = $timeout($scope.logging.fetch, 2000);
|
||||
if (!textArea.is(":focus")) {
|
||||
if (data.messages) {
|
||||
$scope.logging.entries.push.apply($scope.logging.entries, data.messages);
|
||||
@@ -1767,6 +1767,233 @@ angular.module('syncthing.core')
|
||||
});
|
||||
};
|
||||
|
||||
function resetRestoreVersions() {
|
||||
$scope.restoreVersions = {
|
||||
folder: null,
|
||||
selections: {},
|
||||
versions: null,
|
||||
tree: null,
|
||||
errors: null,
|
||||
filters: {},
|
||||
massAction: function (name, action) {
|
||||
$.each($scope.restoreVersions.versions, function(key) {
|
||||
if (key.startsWith(name + '/') && (!$scope.restoreVersions.filters.text || key.indexOf($scope.restoreVersions.filters.text) > -1)) {
|
||||
if (action == 'unset') {
|
||||
delete $scope.restoreVersions.selections[key];
|
||||
return;
|
||||
}
|
||||
|
||||
var availableVersions = [];
|
||||
$.each($scope.restoreVersions.filterVersions($scope.restoreVersions.versions[key]), function(idx, version) {
|
||||
availableVersions.push(version.versionTime);
|
||||
})
|
||||
|
||||
if (availableVersions.length) {
|
||||
availableVersions.sort(function (a, b) { return a - b; });
|
||||
if (action == 'latest') {
|
||||
$scope.restoreVersions.selections[key] = availableVersions.pop();
|
||||
} else if (action == 'oldest') {
|
||||
$scope.restoreVersions.selections[key] = availableVersions.shift();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
filterVersions: function(versions) {
|
||||
var filteredVersions = [];
|
||||
$.each(versions, function (idx, version) {
|
||||
if (moment(version.versionTime).isBetween($scope.restoreVersions.filters['start'], $scope.restoreVersions.filters['end'], null, '[]')) {
|
||||
filteredVersions.push(version);
|
||||
}
|
||||
});
|
||||
return filteredVersions;
|
||||
},
|
||||
selectionCount: function() {
|
||||
var count = 0;
|
||||
$.each($scope.restoreVersions.selections, function(key, value) {
|
||||
if (value) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
},
|
||||
|
||||
restore: function() {
|
||||
$scope.restoreVersions.tree.clear();
|
||||
$scope.restoreVersions.tree = null;
|
||||
$scope.restoreVersions.versions = null;
|
||||
var selections = {};
|
||||
$.each($scope.restoreVersions.selections, function(key, value) {
|
||||
if (value) {
|
||||
selections[key] = value;
|
||||
}
|
||||
});
|
||||
$scope.restoreVersions.selections = {};
|
||||
|
||||
$http.post(urlbase + '/folder/versions?folder=' + encodeURIComponent($scope.restoreVersions.folder), selections).success(function (data) {
|
||||
if (Object.keys(data).length == 0) {
|
||||
$('#restoreVersions').modal('hide');
|
||||
} else {
|
||||
$scope.restoreVersions.errors = data;
|
||||
}
|
||||
});
|
||||
},
|
||||
show: function(folder) {
|
||||
$scope.restoreVersions.folder = folder;
|
||||
|
||||
var closed = false;
|
||||
var modalShown = $q.defer();
|
||||
$('#restoreVersions').modal().on('hidden.bs.modal', function () {
|
||||
closed = true;
|
||||
resetRestoreVersions();
|
||||
}).on('shown.bs.modal', function() {
|
||||
modalShown.resolve();
|
||||
});
|
||||
|
||||
var dataReceived = $http.get(urlbase + '/folder/versions?folder=' + encodeURIComponent($scope.restoreVersions.folder))
|
||||
.success(function (data) {
|
||||
$.each(data, function(key, values) {
|
||||
$.each(values, function(idx, value) {
|
||||
value.modTime = new Date(value.modTime);
|
||||
value.versionTime = new Date(value.versionTime);
|
||||
});
|
||||
});
|
||||
if (closed) return;
|
||||
$scope.restoreVersions.versions = data;
|
||||
});
|
||||
|
||||
$q.all([dataReceived, modalShown.promise]).then(function() {
|
||||
if (closed) {
|
||||
resetRestoreVersions();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.restoreVersions.tree = $("#restoreTree").fancytree({
|
||||
extensions: ["table", "filter"],
|
||||
quicksearch: true,
|
||||
filter: {
|
||||
autoApply: true,
|
||||
counter: true,
|
||||
hideExpandedCounter: true,
|
||||
hideExpanders: true,
|
||||
highlight: true,
|
||||
leavesOnly: false,
|
||||
nodata: true,
|
||||
mode: "hide"
|
||||
},
|
||||
table: {
|
||||
indentation: 20,
|
||||
nodeColumnIdx: 0,
|
||||
},
|
||||
debugLevel: 2,
|
||||
source: buildTree($scope.restoreVersions.versions),
|
||||
renderColumns: function(event, data) {
|
||||
var node = data.node,
|
||||
$tdList = $(node.tr).find(">td"),
|
||||
template;
|
||||
if (node.folder) {
|
||||
template = '<div ng-include="\'syncthing/folder/restoreVersionsMassActions.html\'" class="pull-right"/>';
|
||||
} else {
|
||||
template = '<div ng-include="\'syncthing/folder/restoreVersionsVersionSelector.html\'" class="pull-right"/>';
|
||||
}
|
||||
|
||||
var scope = $rootScope.$new(true);
|
||||
scope.key = node.key;
|
||||
scope.restoreVersions = $scope.restoreVersions;
|
||||
|
||||
$tdList.eq(1).html(
|
||||
$compile(template)(scope)
|
||||
);
|
||||
|
||||
// Force angular to redraw.
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
}).fancytree("getTree");
|
||||
|
||||
var minDate = moment(),
|
||||
maxDate = moment(0, 'X'),
|
||||
date;
|
||||
|
||||
// Find version window.
|
||||
$.each($scope.restoreVersions.versions, function(key) {
|
||||
$.each($scope.restoreVersions.versions[key], function(idx, version) {
|
||||
date = moment(version.versionTime);
|
||||
if (date.isBefore(minDate)) {
|
||||
minDate = date;
|
||||
}
|
||||
if (date.isAfter(maxDate)) {
|
||||
maxDate = date;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.restoreVersions.filters['start'] = minDate;
|
||||
$scope.restoreVersions.filters['end'] = maxDate;
|
||||
|
||||
var ranges = {
|
||||
'All time': [minDate, maxDate],
|
||||
'Today': [moment(), moment()],
|
||||
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
|
||||
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
|
||||
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
|
||||
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
||||
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
|
||||
};
|
||||
|
||||
// Filter out invalid ranges.
|
||||
$.each(ranges, function(key, range) {
|
||||
if (!range[0].isBetween(minDate, maxDate, null, '[]') && !range[1].isBetween(minDate, maxDate, null, '[]')) {
|
||||
delete ranges[key];
|
||||
}
|
||||
});
|
||||
|
||||
$("#restoreVersionDateRange").daterangepicker({
|
||||
timePicker: true,
|
||||
timePicker24Hour: true,
|
||||
timePickerSeconds: true,
|
||||
autoUpdateInput: true,
|
||||
opens: "left",
|
||||
drops: "up",
|
||||
startDate: minDate,
|
||||
endDate: maxDate,
|
||||
minDate: minDate,
|
||||
maxDate: maxDate,
|
||||
ranges: ranges,
|
||||
locale: {
|
||||
format: 'YYYY/MM/DD HH:mm:ss',
|
||||
}
|
||||
}).on('apply.daterangepicker', function(ev, picker) {
|
||||
$scope.restoreVersions.filters['start'] = picker.startDate;
|
||||
$scope.restoreVersions.filters['end'] = picker.endDate;
|
||||
// Events for this UI element are not managed by angular.
|
||||
// Force angular to wake up.
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
resetRestoreVersions();
|
||||
|
||||
$scope.$watchCollection('restoreVersions.filters', function() {
|
||||
if (!$scope.restoreVersions.tree) return;
|
||||
|
||||
$scope.restoreVersions.tree.filterNodes(function (node) {
|
||||
if (node.folder) return false;
|
||||
if ($scope.restoreVersions.filters.text && node.key.indexOf($scope.restoreVersions.filters.text) < 0) {
|
||||
return false;
|
||||
}
|
||||
if ($scope.restoreVersions.filterVersions(node.data.versions).length == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
$scope.editIgnoresOnAddingFolder = function () {
|
||||
if ($scope.editingExisting) {
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<modal id="remove-device-confirmation" status="warning" icon="exclamation-circle" heading="{{'Remove Device' | translate}}" large="no" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<p ng-model="currentDevice.name" style=" overflow : hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-name="{{currentDevice.name}}">Are you sure you want to remove device {%name%}?</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="deleteDevice()">
|
||||
<span class="fa fa-minus-circle"></span> <span translate>Yes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>No</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p ng-model="currentDevice.name" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-name="{{currentDevice.name}}">Are you sure you want to remove device {%name%}?</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="deleteDevice()">
|
||||
<span class="fa fa-minus-circle"></span> <span translate>Yes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>No</span>
|
||||
</button>
|
||||
</div>
|
||||
</modal>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<modal id="remove-folder-confirmation" status="warning" icon="exclamation-circle" heading="{{'Remove Folder' | translate}}" large="no" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<p ng-model="currentFolder.label" style=" overflow : hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-label="{{currentFolder.label}}">Are you sure you want to remove folder {%label%}?</span>
|
||||
</p>
|
||||
<p translate>
|
||||
No files will be deleted as a result of this operation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="deleteFolder(currentFolder.id)">
|
||||
<span class="fa fa-minus-circle"></span> <span translate>Yes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>No</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate translate-value-label="{{currentFolder.label}}">Are you sure you want to remove folder {%label%}?</span>
|
||||
</p>
|
||||
<p translate>
|
||||
No files will be deleted as a result of this operation.
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="deleteFolder(currentFolder.id)">
|
||||
<span class="fa fa-minus-circle"></span> <span translate>Yes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>No</span>
|
||||
</button>
|
||||
</div>
|
||||
</modal>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<modal id="restore-versions-confirmation" status="warning" icon="exclamation-circle" heading="{{'Restore Versions' | translate}}" large="no" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<p style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
<span translate-value-count="{{restoreVersions.selectionCount()}}" translate>Are you sure you want to restore {%count%} files?</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning pull-left btn-sm" data-dismiss="modal" ng-click="restoreVersions.restore()">
|
||||
<span class="fa fa-check"></span> <span translate>Yes</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>No</span>
|
||||
</button>
|
||||
</div>
|
||||
</modal>
|
||||
11
gui/default/syncthing/folder/restoreVersionsMassActions.html
Normal file
11
gui/default/syncthing/folder/restoreVersionsMassActions.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<span translate>Mass actions</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" ng-click="restoreVersions.massAction(key, 'unset')" translate>Do not restore all</a></li>
|
||||
<li><a href="#" ng-click="restoreVersions.massAction(key, 'latest')" translate>Select latest version</a></li>
|
||||
<li><a href="#" ng-click="restoreVersions.massAction(key, 'oldest')" translate>Select oldest version</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
51
gui/default/syncthing/folder/restoreVersionsModalView.html
Normal file
51
gui/default/syncthing/folder/restoreVersionsModalView.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<modal id="restoreVersions" status="default" heading="{{'Restore Versions' | translate}}" large="yes" closeable="yes">
|
||||
<div class="modal-body">
|
||||
<span translate ng-if="!restoreVersions.versions && !restoreVersions.errors">Loading data...</span>
|
||||
<div ng-if="restoreVersions.versions">
|
||||
<table id="restoreTree">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr/>
|
||||
<div class="row form-inline">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label translate for="restoreVersionSearch">Filter by name</label>: 
|
||||
<input id="restoreVersionSearch" class="form-control" type="text" ng-model="restoreVersions.filters.text">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label translate for="restoreVersionDate">Filter by date</label>: 
|
||||
<input id="restoreVersionDateRange" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="restoreVersions.errors">
|
||||
<label><span translate>Some items could not be restored:</span></label>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tbody>
|
||||
<tr ng-repeat="(file, error) in restoreVersions.errors">
|
||||
<td>{{ file }}</td>
|
||||
<td>{{ error }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary btn-sm" data-toggle="modal" data-target="#restore-versions-confirmation" ng-if="restoreVersions.versions" ng-disabled="restoreVersions.selectionCount() < 1">
|
||||
<span class="fa fa-check"></span> <span translate>Restore</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
|
||||
<span class="fa fa-times"></span> <span translate>Close</span>
|
||||
</button>
|
||||
</div>
|
||||
</modal>
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<span ng-if="!restoreVersions.selections[key]" translate>Do not restore</span>
|
||||
<span ng-if="restoreVersions.selections[key]">{{ restoreVersions.selections[key] | date:"yyyy/MM/dd HH:mm:ss" }}</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#" ng-click="restoreVersions.selections[key] = undefined" translate>Do not restore</a>
|
||||
</li>
|
||||
<li ng-repeat="version in restoreVersions.filterVersions(restoreVersions.versions[key])">
|
||||
<a href="#" ng-click="restoreVersions.selections[key] = version.versionTime">
|
||||
{{ version.versionTime | date:"yyyy/MM/dd HH:mm:ss" }} {{ version.size | binary }}B
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
269
gui/default/vendor/bootstrap/css/daterangepicker.css
vendored
Normal file
269
gui/default/vendor/bootstrap/css/daterangepicker.css
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
.daterangepicker {
|
||||
position: absolute;
|
||||
color: inherit;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
width: 278px;
|
||||
padding: 4px;
|
||||
margin-top: 1px;
|
||||
top: 100px;
|
||||
left: 20px;
|
||||
/* Calendars */ }
|
||||
.daterangepicker:before, .daterangepicker:after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: ''; }
|
||||
.daterangepicker:before {
|
||||
top: -7px;
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc; }
|
||||
.daterangepicker:after {
|
||||
top: -6px;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-left: 6px solid transparent; }
|
||||
.daterangepicker.opensleft:before {
|
||||
right: 9px; }
|
||||
.daterangepicker.opensleft:after {
|
||||
right: 10px; }
|
||||
.daterangepicker.openscenter:before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto; }
|
||||
.daterangepicker.openscenter:after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto; }
|
||||
.daterangepicker.opensright:before {
|
||||
left: 9px; }
|
||||
.daterangepicker.opensright:after {
|
||||
left: 10px; }
|
||||
.daterangepicker.dropup {
|
||||
margin-top: -5px; }
|
||||
.daterangepicker.dropup:before {
|
||||
top: initial;
|
||||
bottom: -7px;
|
||||
border-bottom: initial;
|
||||
border-top: 7px solid #ccc; }
|
||||
.daterangepicker.dropup:after {
|
||||
top: initial;
|
||||
bottom: -6px;
|
||||
border-bottom: initial;
|
||||
border-top: 6px solid #fff; }
|
||||
.daterangepicker.dropdown-menu {
|
||||
max-width: none;
|
||||
z-index: 3001; }
|
||||
.daterangepicker.single .ranges, .daterangepicker.single .calendar {
|
||||
float: none; }
|
||||
.daterangepicker.show-calendar .calendar {
|
||||
display: block; }
|
||||
.daterangepicker .calendar {
|
||||
display: none;
|
||||
max-width: 270px;
|
||||
margin: 4px; }
|
||||
.daterangepicker .calendar.single .calendar-table {
|
||||
border: none; }
|
||||
.daterangepicker .calendar th, .daterangepicker .calendar td {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
min-width: 32px; }
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid #fff;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: #fff; }
|
||||
.daterangepicker table {
|
||||
width: 100%;
|
||||
margin: 0; }
|
||||
.daterangepicker td, .daterangepicker th {
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
cursor: pointer; }
|
||||
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
|
||||
background-color: #eee;
|
||||
border-color: transparent;
|
||||
color: inherit; }
|
||||
.daterangepicker td.week, .daterangepicker th.week {
|
||||
font-size: 80%;
|
||||
color: #ccc; }
|
||||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
|
||||
background-color: #fff;
|
||||
border-color: transparent;
|
||||
color: #999; }
|
||||
.daterangepicker td.in-range {
|
||||
background-color: #ebf4f8;
|
||||
border-color: transparent;
|
||||
color: #000;
|
||||
border-radius: 0; }
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 4px 0 0 4px; }
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 0 4px 4px 0; }
|
||||
.daterangepicker td.start-date.end-date {
|
||||
border-radius: 4px; }
|
||||
.daterangepicker td.active, .daterangepicker td.active:hover {
|
||||
background-color: #357ebd;
|
||||
border-color: transparent;
|
||||
color: #fff; }
|
||||
.daterangepicker th.month {
|
||||
width: auto; }
|
||||
.daterangepicker td.disabled, .daterangepicker option.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
text-decoration: line-through; }
|
||||
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
cursor: default; }
|
||||
.daterangepicker select.monthselect {
|
||||
margin-right: 2%;
|
||||
width: 56%; }
|
||||
.daterangepicker select.yearselect {
|
||||
width: 40%; }
|
||||
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
|
||||
width: 50px;
|
||||
margin-bottom: 0; }
|
||||
.daterangepicker .input-mini {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
color: #555;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
margin: 0 0 5px 0;
|
||||
padding: 0 6px 0 28px;
|
||||
width: 100%; }
|
||||
.daterangepicker .input-mini.active {
|
||||
border: 1px solid #08c;
|
||||
border-radius: 4px; }
|
||||
.daterangepicker .daterangepicker_input {
|
||||
position: relative; }
|
||||
.daterangepicker .daterangepicker_input i {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 8px; }
|
||||
.daterangepicker.rtl .input-mini {
|
||||
padding-right: 28px;
|
||||
padding-left: 6px; }
|
||||
.daterangepicker.rtl .daterangepicker_input i {
|
||||
left: auto;
|
||||
right: 8px; }
|
||||
.daterangepicker .calendar-time {
|
||||
text-align: center;
|
||||
margin: 5px auto;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
padding-left: 28px; }
|
||||
.daterangepicker .calendar-time select.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed; }
|
||||
|
||||
.ranges {
|
||||
font-size: 11px;
|
||||
float: none;
|
||||
margin: 4px;
|
||||
text-align: left; }
|
||||
.ranges ul {
|
||||
list-style: none;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%; }
|
||||
.ranges li {
|
||||
font-size: 13px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #f5f5f5;
|
||||
border-radius: 4px;
|
||||
color: #08c;
|
||||
padding: 3px 12px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer; }
|
||||
.ranges li:hover {
|
||||
background-color: #08c;
|
||||
border: 1px solid #08c;
|
||||
color: #fff; }
|
||||
.ranges li.active {
|
||||
background-color: #08c;
|
||||
border: 1px solid #08c;
|
||||
color: #fff; }
|
||||
|
||||
/* Larger Screen Styling */
|
||||
@media (min-width: 564px) {
|
||||
.daterangepicker {
|
||||
width: auto; }
|
||||
.daterangepicker .ranges ul {
|
||||
width: 160px; }
|
||||
.daterangepicker.single .ranges ul {
|
||||
width: 100%; }
|
||||
.daterangepicker.single .calendar.left {
|
||||
clear: none; }
|
||||
.daterangepicker.single.ltr .ranges, .daterangepicker.single.ltr .calendar {
|
||||
float: left; }
|
||||
.daterangepicker.single.rtl .ranges, .daterangepicker.single.rtl .calendar {
|
||||
float: right; }
|
||||
.daterangepicker.ltr {
|
||||
direction: ltr;
|
||||
text-align: left; }
|
||||
.daterangepicker.ltr .calendar.left {
|
||||
clear: left;
|
||||
margin-right: 0; }
|
||||
.daterangepicker.ltr .calendar.left .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.daterangepicker.ltr .calendar.right {
|
||||
margin-left: 0; }
|
||||
.daterangepicker.ltr .calendar.right .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0; }
|
||||
.daterangepicker.ltr .left .daterangepicker_input {
|
||||
padding-right: 12px; }
|
||||
.daterangepicker.ltr .calendar.left .calendar-table {
|
||||
padding-right: 12px; }
|
||||
.daterangepicker.ltr .ranges, .daterangepicker.ltr .calendar {
|
||||
float: left; }
|
||||
.daterangepicker.rtl {
|
||||
direction: rtl;
|
||||
text-align: right; }
|
||||
.daterangepicker.rtl .calendar.left {
|
||||
clear: right;
|
||||
margin-left: 0; }
|
||||
.daterangepicker.rtl .calendar.left .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0; }
|
||||
.daterangepicker.rtl .calendar.right {
|
||||
margin-right: 0; }
|
||||
.daterangepicker.rtl .calendar.right .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
.daterangepicker.rtl .left .daterangepicker_input {
|
||||
padding-left: 12px; }
|
||||
.daterangepicker.rtl .calendar.left .calendar-table {
|
||||
padding-left: 12px; }
|
||||
.daterangepicker.rtl .ranges, .daterangepicker.rtl .calendar {
|
||||
text-align: right;
|
||||
float: right; } }
|
||||
@media (min-width: 730px) {
|
||||
.daterangepicker .ranges {
|
||||
width: auto; }
|
||||
.daterangepicker.ltr .ranges {
|
||||
float: left; }
|
||||
.daterangepicker.rtl .ranges {
|
||||
float: right; }
|
||||
.daterangepicker .calendar.left {
|
||||
clear: none !important; } }
|
||||
1626
gui/default/vendor/bootstrap/js/daterangepicker.js
vendored
Normal file
1626
gui/default/vendor/bootstrap/js/daterangepicker.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
663
gui/default/vendor/fancytree/css/ui.fancytree.css
vendored
Normal file
663
gui/default/vendor/fancytree/css/ui.fancytree.css
vendored
Normal file
@@ -0,0 +1,663 @@
|
||||
/*!
|
||||
* Fancytree "Lion" skin.
|
||||
*
|
||||
* DON'T EDIT THE CSS FILE DIRECTLY, since it is automatically generated from
|
||||
* the LESS templates.
|
||||
*/
|
||||
/*
|
||||
Lion colors:
|
||||
gray highlight bar: #D4D4D4
|
||||
blue highlight-bar and -border #3875D7
|
||||
|
||||
*/
|
||||
/*******************************************************************************
|
||||
* Common Styles for Fancytree Skins.
|
||||
*
|
||||
* This section is automatically generated from the `skin-common.less` template.
|
||||
******************************************************************************/
|
||||
/*------------------------------------------------------------------------------
|
||||
* Helpers
|
||||
*----------------------------------------------------------------------------*/
|
||||
.ui-helper-hidden {
|
||||
display: none;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Container and UL / LI
|
||||
*----------------------------------------------------------------------------*/
|
||||
ul.fancytree-container {
|
||||
font-family: tahoma, arial, helvetica;
|
||||
font-size: 10pt;
|
||||
white-space: nowrap;
|
||||
padding: 3px;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
border: 1px dotted gray;
|
||||
min-height: 0%;
|
||||
position: relative;
|
||||
}
|
||||
ul.fancytree-container ul {
|
||||
padding: 0 0 0 16px;
|
||||
margin: 0;
|
||||
}
|
||||
ul.fancytree-container ul > li:before {
|
||||
content: none;
|
||||
}
|
||||
ul.fancytree-container li {
|
||||
list-style-image: none;
|
||||
list-style-position: outside;
|
||||
list-style-type: none;
|
||||
-moz-background-clip: border;
|
||||
-moz-background-inline-policy: continuous;
|
||||
-moz-background-origin: padding;
|
||||
background-attachment: scroll;
|
||||
background-color: transparent;
|
||||
background-position: 0px 0px;
|
||||
background-repeat: repeat-y;
|
||||
background-image: none;
|
||||
margin: 0;
|
||||
}
|
||||
ul.fancytree-container li.fancytree-lastsib {
|
||||
background-image: none;
|
||||
}
|
||||
.ui-fancytree-disabled ul.fancytree-container {
|
||||
opacity: 0.5;
|
||||
background-color: silver;
|
||||
}
|
||||
ul.fancytree-connectors.fancytree-container li {
|
||||
background-image: url("../skin-lion/vline.gif");
|
||||
background-position: 0 0;
|
||||
}
|
||||
ul.fancytree-container li.fancytree-lastsib,
|
||||
ul.fancytree-no-connector > li {
|
||||
background-image: none;
|
||||
}
|
||||
li.fancytree-animating {
|
||||
position: relative;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Common icon definitions
|
||||
*----------------------------------------------------------------------------*/
|
||||
span.fancytree-empty,
|
||||
span.fancytree-vline,
|
||||
span.fancytree-expander,
|
||||
span.fancytree-icon,
|
||||
span.fancytree-checkbox,
|
||||
span.fancytree-drag-helper-img,
|
||||
#fancytree-drop-marker {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left;
|
||||
background-image: url("../skin-lion/icons.gif");
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
span.fancytree-icon,
|
||||
span.fancytree-checkbox,
|
||||
span.fancytree-expander,
|
||||
span.fancytree-custom-icon {
|
||||
margin-top: 0px;
|
||||
}
|
||||
/* Used by icon option: */
|
||||
span.fancytree-custom-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-block;
|
||||
margin-left: 3px;
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
/* Used by 'icon' node option: */
|
||||
img.fancytree-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 3px;
|
||||
margin-top: 0px;
|
||||
vertical-align: top;
|
||||
border-style: none;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Expander icon
|
||||
*
|
||||
* Note: IE6 doesn't correctly evaluate multiples class names,
|
||||
* so we create combined class names that can be used in the CSS.
|
||||
*
|
||||
* Prefix: fancytree-exp-
|
||||
* 1st character: 'e': expanded, 'c': collapsed, 'n': no children
|
||||
* 2nd character (optional): 'd': lazy (Delayed)
|
||||
* 3rd character (optional): 'l': Last sibling
|
||||
*----------------------------------------------------------------------------*/
|
||||
span.fancytree-expander {
|
||||
cursor: pointer;
|
||||
}
|
||||
.fancytree-exp-n span.fancytree-expander,
|
||||
.fancytree-exp-nl span.fancytree-expander {
|
||||
background-image: none;
|
||||
cursor: default;
|
||||
}
|
||||
.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
|
||||
.fancytree-connectors .fancytree-exp-nl span.fancytree-expander {
|
||||
background-image: url("../skin-lion/icons.gif");
|
||||
margin-top: 0;
|
||||
}
|
||||
.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
|
||||
.fancytree-connectors .fancytree-exp-n span.fancytree-expander:hover {
|
||||
background-position: 0px -64px;
|
||||
}
|
||||
.fancytree-connectors .fancytree-exp-nl span.fancytree-expander,
|
||||
.fancytree-connectors .fancytree-exp-nl span.fancytree-expander:hover {
|
||||
background-position: -16px -64px;
|
||||
}
|
||||
.fancytree-exp-c span.fancytree-expander {
|
||||
background-position: 0px -80px;
|
||||
}
|
||||
.fancytree-exp-c span.fancytree-expander:hover {
|
||||
background-position: -16px -80px;
|
||||
}
|
||||
.fancytree-exp-cl span.fancytree-expander {
|
||||
background-position: 0px -96px;
|
||||
}
|
||||
.fancytree-exp-cl span.fancytree-expander:hover {
|
||||
background-position: -16px -96px;
|
||||
}
|
||||
.fancytree-exp-cd span.fancytree-expander {
|
||||
background-position: -64px -80px;
|
||||
}
|
||||
.fancytree-exp-cd span.fancytree-expander:hover {
|
||||
background-position: -80px -80px;
|
||||
}
|
||||
.fancytree-exp-cdl span.fancytree-expander {
|
||||
background-position: -64px -96px;
|
||||
}
|
||||
.fancytree-exp-cdl span.fancytree-expander:hover {
|
||||
background-position: -80px -96px;
|
||||
}
|
||||
.fancytree-exp-e span.fancytree-expander,
|
||||
.fancytree-exp-ed span.fancytree-expander {
|
||||
background-position: -32px -80px;
|
||||
}
|
||||
.fancytree-exp-e span.fancytree-expander:hover,
|
||||
.fancytree-exp-ed span.fancytree-expander:hover {
|
||||
background-position: -48px -80px;
|
||||
}
|
||||
.fancytree-exp-el span.fancytree-expander,
|
||||
.fancytree-exp-edl span.fancytree-expander {
|
||||
background-position: -32px -96px;
|
||||
}
|
||||
.fancytree-exp-el span.fancytree-expander:hover,
|
||||
.fancytree-exp-edl span.fancytree-expander:hover {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
/* Fade out expanders, when container is not hovered or active */
|
||||
.fancytree-fade-expander span.fancytree-expander {
|
||||
transition: opacity 1.5s;
|
||||
opacity: 0;
|
||||
}
|
||||
.fancytree-fade-expander:hover span.fancytree-expander,
|
||||
.fancytree-fade-expander.fancytree-treefocus span.fancytree-expander,
|
||||
.fancytree-fade-expander .fancytree-treefocus span.fancytree-expander,
|
||||
.fancytree-fade-expander [class*='fancytree-statusnode-'] span.fancytree-expander {
|
||||
transition: opacity 0.6s;
|
||||
opacity: 1;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Checkbox icon
|
||||
*----------------------------------------------------------------------------*/
|
||||
span.fancytree-checkbox {
|
||||
margin-left: 3px;
|
||||
background-position: 0px -32px;
|
||||
}
|
||||
span.fancytree-checkbox:hover {
|
||||
background-position: -16px -32px;
|
||||
}
|
||||
span.fancytree-checkbox.fancytree-radio {
|
||||
background-position: 0px -48px;
|
||||
}
|
||||
span.fancytree-checkbox.fancytree-radio:hover {
|
||||
background-position: -16px -48px;
|
||||
}
|
||||
.fancytree-partsel span.fancytree-checkbox {
|
||||
background-position: -64px -32px;
|
||||
}
|
||||
.fancytree-partsel span.fancytree-checkbox:hover {
|
||||
background-position: -80px -32px;
|
||||
}
|
||||
.fancytree-partsel span.fancytree-checkbox.fancytree-radio {
|
||||
background-position: -64px -48px;
|
||||
}
|
||||
.fancytree-partsel span.fancytree-checkbox.fancytree-radio:hover {
|
||||
background-position: -80px -48px;
|
||||
}
|
||||
.fancytree-selected span.fancytree-checkbox {
|
||||
background-position: -32px -32px;
|
||||
}
|
||||
.fancytree-selected span.fancytree-checkbox:hover {
|
||||
background-position: -48px -32px;
|
||||
}
|
||||
.fancytree-selected span.fancytree-checkbox.fancytree-radio {
|
||||
background-position: -32px -48px;
|
||||
}
|
||||
.fancytree-selected span.fancytree-checkbox.fancytree-radio:hover {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
.fancytree-unselectable span.fancytree-checkbox {
|
||||
opacity: 0.4;
|
||||
filter: alpha(opacity=40);
|
||||
}
|
||||
.fancytree-unselectable span.fancytree-checkbox:hover {
|
||||
background-position: 0px -32px;
|
||||
}
|
||||
.fancytree-unselectable.fancytree-partsel span.fancytree-checkbox:hover {
|
||||
background-position: -64px -32px;
|
||||
}
|
||||
.fancytree-unselectable.fancytree-selected span.fancytree-checkbox:hover {
|
||||
background-position: -32px -32px;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Node type icon
|
||||
* Note: IE6 doesn't correctly evaluate multiples class names,
|
||||
* so we create combined class names that can be used in the CSS.
|
||||
*
|
||||
* Prefix: fancytree-ico-
|
||||
* 1st character: 'e': expanded, 'c': collapsed
|
||||
* 2nd character (optional): 'f': folder
|
||||
*----------------------------------------------------------------------------*/
|
||||
span.fancytree-icon {
|
||||
margin-left: 3px;
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
/* Documents */
|
||||
.fancytree-ico-c span.fancytree-icon:hover {
|
||||
background-position: -16px 0px;
|
||||
}
|
||||
.fancytree-has-children.fancytree-ico-c span.fancytree-icon {
|
||||
background-position: -32px 0px;
|
||||
}
|
||||
.fancytree-has-children.fancytree-ico-c span.fancytree-icon:hover {
|
||||
background-position: -48px 0px;
|
||||
}
|
||||
.fancytree-ico-e span.fancytree-icon {
|
||||
background-position: -64px 0px;
|
||||
}
|
||||
.fancytree-ico-e span.fancytree-icon:hover {
|
||||
background-position: -80px 0px;
|
||||
}
|
||||
/* Folders */
|
||||
.fancytree-ico-cf span.fancytree-icon {
|
||||
background-position: 0px -16px;
|
||||
}
|
||||
.fancytree-ico-cf span.fancytree-icon:hover {
|
||||
background-position: -16px -16px;
|
||||
}
|
||||
.fancytree-has-children.fancytree-ico-cf span.fancytree-icon {
|
||||
background-position: -32px -16px;
|
||||
}
|
||||
.fancytree-has-children.fancytree-ico-cf span.fancytree-icon:hover {
|
||||
background-position: -48px -16px;
|
||||
}
|
||||
.fancytree-ico-ef span.fancytree-icon {
|
||||
background-position: -64px -16px;
|
||||
}
|
||||
.fancytree-ico-ef span.fancytree-icon:hover {
|
||||
background-position: -80px -16px;
|
||||
}
|
||||
.fancytree-loading span.fancytree-expander,
|
||||
.fancytree-loading span.fancytree-expander:hover,
|
||||
.fancytree-statusnode-loading span.fancytree-icon,
|
||||
.fancytree-statusnode-loading span.fancytree-icon:hover {
|
||||
background-image: url("../skin-lion/loading.gif");
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
/* Status node icons */
|
||||
.fancytree-statusnode-error span.fancytree-icon,
|
||||
.fancytree-statusnode-error span.fancytree-icon:hover {
|
||||
background-position: 0px -112px;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Node titles and highlighting
|
||||
*----------------------------------------------------------------------------*/
|
||||
span.fancytree-node {
|
||||
/* See #117 */
|
||||
display: inherit;
|
||||
width: 100%;
|
||||
margin-top: 1px;
|
||||
min-height: 16px;
|
||||
}
|
||||
span.fancytree-title {
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
min-height: 16px;
|
||||
padding: 0 3px 0 3px;
|
||||
margin: 0px 0 0 3px;
|
||||
border: 1px solid transparent;
|
||||
-webkit-border-radius: 0px;
|
||||
-moz-border-radius: 0px;
|
||||
-ms-border-radius: 0px;
|
||||
-o-border-radius: 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
span.fancytree-node.fancytree-error span.fancytree-title {
|
||||
color: red;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* Drag'n'drop support
|
||||
*----------------------------------------------------------------------------*/
|
||||
div.fancytree-drag-helper span.fancytree-childcounter,
|
||||
div.fancytree-drag-helper span.fancytree-dnd-modifier {
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
background: #337ab7;
|
||||
border: 1px solid gray;
|
||||
min-width: 10px;
|
||||
height: 10px;
|
||||
line-height: 1;
|
||||
vertical-align: baseline;
|
||||
border-radius: 10px;
|
||||
padding: 2px;
|
||||
text-align: center;
|
||||
font-size: 9px;
|
||||
}
|
||||
div.fancytree-drag-helper span.fancytree-childcounter {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
}
|
||||
div.fancytree-drag-helper span.fancytree-dnd-modifier {
|
||||
background: #5cb85c;
|
||||
border: none;
|
||||
font-weight: bolder;
|
||||
}
|
||||
div.fancytree-drag-helper.fancytree-drop-accept span.fancytree-drag-helper-img {
|
||||
background-position: -32px -112px;
|
||||
}
|
||||
div.fancytree-drag-helper.fancytree-drop-reject span.fancytree-drag-helper-img {
|
||||
background-position: -16px -112px;
|
||||
}
|
||||
/*** Drop marker icon *********************************************************/
|
||||
#fancytree-drop-marker {
|
||||
width: 32px;
|
||||
position: absolute;
|
||||
background-position: 0px -128px;
|
||||
margin: 0;
|
||||
}
|
||||
#fancytree-drop-marker.fancytree-drop-after,
|
||||
#fancytree-drop-marker.fancytree-drop-before {
|
||||
width: 64px;
|
||||
background-position: 0px -144px;
|
||||
}
|
||||
#fancytree-drop-marker.fancytree-drop-copy {
|
||||
background-position: -64px -128px;
|
||||
}
|
||||
#fancytree-drop-marker.fancytree-drop-move {
|
||||
background-position: -32px -128px;
|
||||
}
|
||||
/*** Source node while dragging ***********************************************/
|
||||
span.fancytree-drag-source.fancytree-drag-remove {
|
||||
opacity: 0.15;
|
||||
}
|
||||
/*** Target node while dragging cursor is over it *****************************/
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'rtl' option
|
||||
*----------------------------------------------------------------------------*/
|
||||
.fancytree-container.fancytree-rtl .fancytree-title {
|
||||
/*unicode-bidi: bidi-override;*/
|
||||
/* optional: reverse title letters */
|
||||
}
|
||||
.fancytree-container.fancytree-rtl span.fancytree-connector,
|
||||
.fancytree-container.fancytree-rtl span.fancytree-expander,
|
||||
.fancytree-container.fancytree-rtl span.fancytree-icon,
|
||||
.fancytree-container.fancytree-rtl span.fancytree-drag-helper-img,
|
||||
.fancytree-container.fancytree-rtl #fancytree-drop-marker {
|
||||
background-image: url("../skin-lion/icons-rtl.gif");
|
||||
}
|
||||
.fancytree-container.fancytree-rtl .fancytree-exp-n span.fancytree-expander,
|
||||
.fancytree-container.fancytree-rtl .fancytree-exp-nl span.fancytree-expander {
|
||||
background-image: none;
|
||||
}
|
||||
.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-n span.fancytree-expander,
|
||||
.fancytree-container.fancytree-rtl.fancytree-connectors .fancytree-exp-nl span.fancytree-expander {
|
||||
background-image: url("../skin-lion/icons-rtl.gif");
|
||||
}
|
||||
ul.fancytree-container.fancytree-rtl ul {
|
||||
padding: 0 16px 0 0;
|
||||
}
|
||||
ul.fancytree-container.fancytree-rtl.fancytree-connectors li {
|
||||
background-position: right 0;
|
||||
background-image: url("../skin-lion/vline-rtl.gif");
|
||||
}
|
||||
ul.fancytree-container.fancytree-rtl li.fancytree-lastsib,
|
||||
ul.fancytree-container.fancytree-rtl.fancytree-no-connector > li {
|
||||
background-image: none;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'table' extension
|
||||
*----------------------------------------------------------------------------*/
|
||||
table.fancytree-ext-table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.fancytree-ext-table span.fancytree-node {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'columnview' extension
|
||||
*----------------------------------------------------------------------------*/
|
||||
table.fancytree-ext-columnview tbody tr td {
|
||||
position: relative;
|
||||
border: 1px solid gray;
|
||||
vertical-align: top;
|
||||
overflow: auto;
|
||||
}
|
||||
table.fancytree-ext-columnview tbody tr td > ul {
|
||||
padding: 0;
|
||||
}
|
||||
table.fancytree-ext-columnview tbody tr td > ul li {
|
||||
list-style-image: none;
|
||||
list-style-position: outside;
|
||||
list-style-type: none;
|
||||
-moz-background-clip: border;
|
||||
-moz-background-inline-policy: continuous;
|
||||
-moz-background-origin: padding;
|
||||
background-attachment: scroll;
|
||||
background-color: transparent;
|
||||
background-position: 0px 0px;
|
||||
background-repeat: repeat-y;
|
||||
background-image: none;
|
||||
/* no v-lines */
|
||||
margin: 0;
|
||||
}
|
||||
table.fancytree-ext-columnview span.fancytree-node {
|
||||
position: relative;
|
||||
/* allow positioning of embedded spans */
|
||||
display: inline-block;
|
||||
}
|
||||
table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded {
|
||||
background-color: #CBE8F6;
|
||||
}
|
||||
table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
background-position: 0px -80px;
|
||||
}
|
||||
table.fancytree-ext-columnview .fancytree-has-children span.fancytree-cv-right:hover {
|
||||
background-position: -16px -80px;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'filter' extension
|
||||
*----------------------------------------------------------------------------*/
|
||||
.fancytree-ext-filter-dimm span.fancytree-node span.fancytree-title {
|
||||
color: silver;
|
||||
font-weight: lighter;
|
||||
}
|
||||
.fancytree-ext-filter-dimm tr.fancytree-submatch span.fancytree-title,
|
||||
.fancytree-ext-filter-dimm span.fancytree-node.fancytree-submatch span.fancytree-title {
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
}
|
||||
.fancytree-ext-filter-dimm tr.fancytree-match span.fancytree-title,
|
||||
.fancytree-ext-filter-dimm span.fancytree-node.fancytree-match span.fancytree-title {
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
.fancytree-ext-filter-hide tr.fancytree-hide,
|
||||
.fancytree-ext-filter-hide span.fancytree-node.fancytree-hide {
|
||||
display: none;
|
||||
}
|
||||
.fancytree-ext-filter-hide tr.fancytree-submatch span.fancytree-title,
|
||||
.fancytree-ext-filter-hide span.fancytree-node.fancytree-submatch span.fancytree-title {
|
||||
color: silver;
|
||||
font-weight: lighter;
|
||||
}
|
||||
.fancytree-ext-filter-hide tr.fancytree-match span.fancytree-title,
|
||||
.fancytree-ext-filter-hide span.fancytree-node.fancytree-match span.fancytree-title {
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* Hide expanders if all child nodes are hidden by filter */
|
||||
.fancytree-ext-filter-hide-expanders tr.fancytree-match span.fancytree-expander,
|
||||
.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-match span.fancytree-expander {
|
||||
visibility: hidden;
|
||||
}
|
||||
.fancytree-ext-filter-hide-expanders tr.fancytree-submatch span.fancytree-expander,
|
||||
.fancytree-ext-filter-hide-expanders span.fancytree-node.fancytree-submatch span.fancytree-expander {
|
||||
visibility: visible;
|
||||
}
|
||||
.fancytree-ext-childcounter span.fancytree-icon,
|
||||
.fancytree-ext-filter span.fancytree-icon {
|
||||
position: relative;
|
||||
}
|
||||
.fancytree-ext-childcounter span.fancytree-childcounter,
|
||||
.fancytree-ext-filter span.fancytree-childcounter {
|
||||
color: #fff;
|
||||
background: #777;
|
||||
border: 1px solid gray;
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
min-width: 10px;
|
||||
height: 10px;
|
||||
line-height: 1;
|
||||
vertical-align: baseline;
|
||||
border-radius: 10px;
|
||||
padding: 2px;
|
||||
text-align: center;
|
||||
font-size: 9px;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'wide' extension
|
||||
*----------------------------------------------------------------------------*/
|
||||
ul.fancytree-ext-wide {
|
||||
position: relative;
|
||||
min-width: 100%;
|
||||
z-index: 2;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
ul.fancytree-ext-wide span.fancytree-node > span {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
ul.fancytree-ext-wide span.fancytree-node span.fancytree-title {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 0px;
|
||||
min-width: 100%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/*------------------------------------------------------------------------------
|
||||
* 'fixed' extension
|
||||
*----------------------------------------------------------------------------*/
|
||||
.fancytree-ext-fixed-wrapper .fancytree-ext-fixed-hidden {
|
||||
display: none;
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-scroll-border-bottom {
|
||||
border-bottom: 3px solid rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-scroll-border-right {
|
||||
border-right: 3px solid rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-tl {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
z-index: 3;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-tr {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
top: 0px;
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-bl {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
left: 0px;
|
||||
}
|
||||
.fancytree-ext-fixed-wrapper div.fancytree-ext-fixed-wrapper-br {
|
||||
position: absolute;
|
||||
overflow: scroll;
|
||||
z-index: 1;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* Styles specific to this skin.
|
||||
*
|
||||
* This section is automatically generated from the `ui-fancytree.less` template.
|
||||
******************************************************************************/
|
||||
/*******************************************************************************
|
||||
* Node titles
|
||||
*/
|
||||
span.fancytree-title {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
span.fancytree-focused span.fancytree-title {
|
||||
outline: 1px dotted black;
|
||||
}
|
||||
span.fancytree-selected span.fancytree-title,
|
||||
span.fancytree-active span.fancytree-title {
|
||||
background-color: #D4D4D4;
|
||||
}
|
||||
span.fancytree-selected span.fancytree-title {
|
||||
font-style: italic;
|
||||
}
|
||||
.fancytree-treefocus span.fancytree-selected span.fancytree-title,
|
||||
.fancytree-treefocus span.fancytree-active span.fancytree-title {
|
||||
color: white;
|
||||
background-color: #3875D7;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* 'table' extension
|
||||
*/
|
||||
table.fancytree-ext-table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.fancytree-ext-table tbody tr.fancytree-focused {
|
||||
background-color: #99DEFD;
|
||||
}
|
||||
table.fancytree-ext-table tbody tr.fancytree-active {
|
||||
background-color: royalblue;
|
||||
}
|
||||
table.fancytree-ext-table tbody tr.fancytree-selected {
|
||||
background-color: #99DEFD;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* 'columnview' extension
|
||||
*/
|
||||
table.fancytree-ext-columnview tbody tr td {
|
||||
border: 1px solid gray;
|
||||
}
|
||||
table.fancytree-ext-columnview span.fancytree-node.fancytree-expanded {
|
||||
background-color: #ccc;
|
||||
}
|
||||
table.fancytree-ext-columnview span.fancytree-node.fancytree-active {
|
||||
background-color: royalblue;
|
||||
}
|
||||
12045
gui/default/vendor/fancytree/jquery.fancytree-all-deps.js
vendored
Normal file
12045
gui/default/vendor/fancytree/jquery.fancytree-all-deps.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
gui/default/vendor/fancytree/skin-lion/icons.gif
vendored
Normal file
BIN
gui/default/vendor/fancytree/skin-lion/icons.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
BIN
gui/default/vendor/fancytree/skin-lion/loading.gif
vendored
Normal file
BIN
gui/default/vendor/fancytree/skin-lion/loading.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
gui/default/vendor/fancytree/skin-lion/vline.gif
vendored
Normal file
BIN
gui/default/vendor/fancytree/skin-lion/vline.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 852 B |
4517
gui/default/vendor/moment/moment.js
vendored
Normal file
4517
gui/default/vendor/moment/moment.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user