瀏覽代碼

gui: Tweak the Restore Versions modal for better usability (#7972)

tomasz1986 3 年之前
父節點
當前提交
9efac0f067

+ 7 - 2
gui/black/assets/css/theme.css

@@ -265,6 +265,11 @@ code.ng-binding{
     color: #222;
 }
 
-.fancytree-title {
-    color: #aaa !important;
+/*
+ * Fancytree tweaks
+ */
+
+.fancytree-container tr:hover,
+.fancytree-focused {
+    background-color: #222;
 }

+ 7 - 2
gui/dark/assets/css/theme.css

@@ -277,6 +277,11 @@ code.ng-binding{
     color: #3fa9f0;
 }
 
-.fancytree-title {
-    color: #aaa !important;
+/*
+ * Fancytree tweaks
+ */
+
+.fancytree-container tr:hover,
+.fancytree-focused {
+    background-color: #424242;
 }

+ 66 - 8
gui/default/assets/css/overrides.css

@@ -301,6 +301,62 @@ ul.three-columns li, ul.two-columns li {
     z-index: 980;
 }
 
+/*
+ * Restore Versions tweaks
+ */
+
+#restoreTree-container {
+    overflow-y: scroll;
+    resize: vertical;
+    /* Limit height to prevent vertical screen overflow. */
+    max-height: calc(100vh - 390px);
+    /* Always fit at least one folder with dropdown open. */
+    min-height: 136px;
+}
+@media (min-width: 768px) {
+    #restoreTree-container {
+        max-height: calc(100vh - 401px);
+    }
+}
+@media (min-width: 992px) {
+    #restoreTree-container {
+        max-height: calc(100vh - 333px);
+    }
+}
+
+/* Ignore fixed height when manually resized. */
+#restoreTree-container[style*="height"] {
+    max-height: none;
+}
+
+/* Remove table outline as rows have own focus style already. */
+#restoreTree:focus {
+    outline: 0;
+}
+
+/* Align dropdown with title first line. */
+#restoreTree td + td {
+    padding-top: 4px;
+    vertical-align: top;
+}
+
+/* Reduce space between toggle and menu on mobile. */
+#restoreTree .dropdown-toggle {
+    margin-bottom: 0;
+}
+
+/* Change direction to remain on screen on mobile. */
+#restoreTree .dropdown-menu {
+    left: auto;
+    right: 0;
+}
+
+/* Ensure maximum space for filtering and date range. */
+#restoreVersions .form-group,
+#restoreVersions .form-control {
+    width: 100%;
+}
+
 /** Footer nav on small devices **/
 @media (max-width: 1199px) {
     /* Stay at the end of the page, with space reserved for the footer
@@ -396,10 +452,6 @@ ul.three-columns li, ul.two-columns li {
     padding-top: 10px;
 }
 
-.fancytree-ext-table {
-    width: 100% !important;
-}
-
 @media (max-width: 419px) {
     /* the selectors are build to target only the content of folder and device
        panels as it would "destroy" e.g. out of sync or recent changes listings */
@@ -420,12 +472,18 @@ ul.three-columns li, ul.two-columns li {
         width: 100%;
     }
 
-    /* all buttons, except panel headings, get bottom margin, as they won't fit
-       beside each other anymore */
+    /* All buttons, except panel headings, get bottom margin, as they
+       won't fit beside each other anymore. Reduce footer padding to
+       compensate for the margin. */
     .btn:not(.panel-heading),
-    /* this "+"-selector is needed to override some bootstrap defaults */
     .btn:not(.panel-heading) + .btn:not(.panel-heading) {
-        margin-bottom: 1rem;
+        margin-bottom: 10px;
+    }
+    .panel-footer {
+        padding-bottom: 0;
+    }
+    .modal-footer {
+        padding-bottom: 5px;
     }
 }
 

+ 58 - 0
gui/default/assets/css/tree.css

@@ -0,0 +1,58 @@
+/*
+// Copyright (C) 2021 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+*/
+
+.fancytree-container {
+    cursor: pointer;
+    width: 100%;
+}
+
+.fancytree-hide {
+    visibility: collapse;
+}
+
+/* Node needs to be block, and expander, icon and title
+   inline-block to properly wrap unbreakable text. */
+.fancytree-node {
+    display: block;
+    white-space: nowrap;
+    /* expander 16px + icon 16px + title padding 8px */
+    padding-right: 40px;
+}
+.fancytree-expander,
+.fancytree-icon,
+.fancytree-title {
+    display: inline-block;
+}
+
+.fancytree-expander,
+.fancytree-icon {
+    margin-top: 4px;
+    vertical-align: top;
+    width: 16px;
+}
+
+.fancytree-childcounter {
+    background: #777;
+    border-radius: 10px;
+    border: 1px solid gray;
+    color: #fff;
+    font-size: 13px;
+    opacity: .75;
+    padding: 2px 3px;
+    position: relative;
+    right: 8px;
+    top: -9px;
+    user-select: none;
+}
+
+.fancytree-title {
+    padding-left: 8px;
+    white-space: normal;
+    word-break: break-all;
+}

+ 1 - 1
gui/default/index.html

@@ -23,9 +23,9 @@
   <link href="assets/font/raleway.css" rel="stylesheet"/>
   <link href="vendor/fork-awesome/css/fork-awesome.css" rel="stylesheet"/>
   <link href="vendor/fork-awesome/css/v5-compat.css" rel="stylesheet"/>
+  <link href="assets/css/tree.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>

+ 11 - 13
gui/default/syncthing/core/syncthingController.js

@@ -2509,23 +2509,22 @@ angular.module('syncthing.core')
                             }
 
                             $scope.restoreVersions.tree = $("#restoreTree").fancytree({
-                                extensions: ["table", "filter"],
+                                extensions: ["table", "filter", "glyph"],
                                 quicksearch: true,
                                 filter: {
-                                    autoApply: true,
-                                    counter: true,
-                                    hideExpandedCounter: true,
                                     hideExpanders: true,
-                                    highlight: true,
-                                    leavesOnly: false,
-                                    nodata: true,
                                     mode: "hide"
                                 },
+                                glyph: {
+                                    preset: "awesome5",
+                                },
                                 table: {
-                                    indentation: 20,
-                                    nodeColumnIdx: 0,
+                                    indentation: 24,
                                 },
-                                debugLevel: 2,
+                                // Set to '1' to silence errors after pressing arrow keys on file nodes.
+                                // Happens on the official option cofiguration from the developer's site
+                                // too, so probably a bug?
+                                debugLevel: 1,
                                 source: buildTree($scope.restoreVersions.versions),
                                 renderColumns: function (event, data) {
                                     // Case insensitive sort with folders on top.
@@ -2540,9 +2539,9 @@ angular.module('syncthing.core')
                                         $tdList = $(node.tr).find(">td"),
                                         template;
                                     if (node.folder) {
-                                        template = '<div ng-include="\'syncthing/folder/restoreVersionsMassActions.html\'" class="pull-right"/>';
+                                        template = '<div ng-include="\'syncthing/folder/restoreVersionsMassActions.html\'"/>';
                                     } else {
-                                        template = '<div ng-include="\'syncthing/folder/restoreVersionsVersionSelector.html\'" class="pull-right"/>';
+                                        template = '<div ng-include="\'syncthing/folder/restoreVersionsVersionSelector.html\'"/>';
                                     }
 
                                     var scope = $rootScope.$new(true);
@@ -2601,7 +2600,6 @@ angular.module('syncthing.core')
                                 timePicker: true,
                                 timePicker24Hour: true,
                                 timePickerSeconds: true,
-                                autoUpdateInput: true,
                                 opens: "left",
                                 drops: "up",
                                 startDate: minDate,

+ 1 - 1
gui/default/syncthing/folder/restoreVersionsMassActions.html

@@ -1,4 +1,4 @@
-<div class="dropdown">
+<div class="dropdown pull-right">
   <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown">
     <span translate>Mass actions</span>
     <span class="caret"></span>

+ 12 - 12
gui/default/syncthing/folder/restoreVersionsModalView.html

@@ -2,27 +2,27 @@
   <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>
+      <div id="restoreTree-container">
+        <table id="restoreTree">
+          <tbody>
+            <tr>
+              <td></td>
+              <td></td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
       <hr />
       <div class="row form-inline">
         <div class="col-md-6">
           <div class="form-group">
-            <label translate for="restoreVersionSearch">Filter by name</label>:&nbsp
+            <label for="restoreVersionSearch"><span translate>Filter by name</span>:&nbsp</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>:&nbsp
+            <label for="restoreVersionDate"><span translate>Filter by date</span>:&nbsp</label>
             <input id="restoreVersionDateRange" class="form-control">
           </div>
         </div>

+ 1 - 1
gui/default/syncthing/folder/restoreVersionsVersionSelector.html

@@ -1,4 +1,4 @@
-<div class="dropdown">
+<div class="dropdown pull-right">
   <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>

+ 3 - 1
gui/default/vendor/daterangepicker/LICENSE

@@ -1,4 +1,6 @@
-Copyright (c) 2012-2018 Dan Grossman
+The MIT License (MIT)
+
+Copyright (c) 2012-2020 Dan Grossman
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 91 - 73
gui/default/vendor/daterangepicker/daterangepicker.css

@@ -88,7 +88,7 @@
   border-top: 6px solid #fff;
 }
 
-.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .calendar {
+.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .drp-calendar {
   float: none;
 }
 
@@ -96,7 +96,7 @@
   display: none;
 }
 
-.daterangepicker.show-calendar .calendar {
+.daterangepicker.show-calendar .drp-calendar {
   display: block;
 }
 
@@ -108,20 +108,20 @@
   display: none;
 }
 
-.daterangepicker .calendar {
+.daterangepicker .drp-calendar {
   display: none;
   max-width: 270px;
 }
 
-.daterangepicker .calendar.left {
-  padding: 12px 0 12px 8px;
+.daterangepicker .drp-calendar.left {
+  padding: 8px 0 8px 8px;
 }
 
-.daterangepicker .calendar.right {
-  padding: 12px 8px;
+.daterangepicker .drp-calendar.right {
+  padding: 8px;
 }
 
-.daterangepicker .calendar.single .calendar-table {
+.daterangepicker .drp-calendar.single .calendar-table {
   border: none;
 }
 
@@ -266,7 +266,7 @@
 .daterangepicker .drp-buttons {
   clear: both;
   text-align: right;
-  padding: 8px 12px;
+  padding: 8px;
   border-top: 1px solid #ddd;
   display: none;
   line-height: 12px;
@@ -286,7 +286,19 @@
   padding: 4px 8px;
 }
 
-.daterangepicker.show-ranges .calendar.left {
+.daterangepicker.show-ranges.single.rtl .drp-calendar.left {
+  border-right: 1px solid #ddd;
+}
+
+.daterangepicker.show-ranges.single.ltr .drp-calendar.left {
+  border-left: 1px solid #ddd;
+}
+
+.daterangepicker.show-ranges.rtl .drp-calendar.right {
+  border-right: 1px solid #ddd;
+}
+
+.daterangepicker.show-ranges.ltr .drp-calendar.left {
   border-left: 1px solid #ddd;
 }
 
@@ -297,7 +309,7 @@
 }
 
 .daterangepicker.show-calendar .ranges {
-  margin-top: 12px;
+  margin-top: 8px;
 }
 
 .daterangepicker .ranges ul {
@@ -325,68 +337,74 @@
 /*  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; } }
+    width: auto;
+  }
+
+  .daterangepicker .ranges ul {
+    width: 140px;
+  }
+
+  .daterangepicker.single .ranges ul {
+    width: 100%;
+  }
+
+  .daterangepicker.single .drp-calendar.left {
+    clear: none;
+  }
+
+  .daterangepicker.single .ranges, .daterangepicker.single .drp-calendar {
+    float: left;
+  }
+
+  .daterangepicker {
+    direction: ltr;
+    text-align: left;
+  }
+
+  .daterangepicker .drp-calendar.left {
+    clear: left;
+    margin-right: 0;
+  }
+
+  .daterangepicker .drp-calendar.left .calendar-table {
+    border-right: none;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+  }
+
+  .daterangepicker .drp-calendar.right {
+    margin-left: 0;
+  }
+
+  .daterangepicker .drp-calendar.right .calendar-table {
+    border-left: none;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+  }
+
+  .daterangepicker .drp-calendar.left .calendar-table {
+    padding-right: 8px;
+  }
+
+  .daterangepicker .ranges, .daterangepicker .drp-calendar {
+    float: left;
+  }
+}
+
 @media (min-width: 730px) {
   .daterangepicker .ranges {
-    width: auto; }
-  .daterangepicker.ltr .ranges {
-    float: left; }
+    width: auto;
+  }
+
+  .daterangepicker .ranges {
+    float: left;
+  }
+
   .daterangepicker.rtl .ranges {
-    float: right; }
-  .daterangepicker .calendar.left {
-    clear: none !important; } }
+    float: right;
+  }
+
+  .daterangepicker .drp-calendar.left {
+    clear: none !important;
+  }
+}

+ 126 - 81
gui/default/vendor/daterangepicker/daterangepicker.js

@@ -1,7 +1,7 @@
 /**
-* @version: 3.0.0
+* @version: 3.1
 * @author: Dan Grossman http://www.dangrossman.info/
-* @copyright: Copyright (c) 2012-2018 Dan Grossman. All rights reserved.
+* @copyright: Copyright (c) 2012-2019 Dan Grossman. All rights reserved.
 * @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
 * @website: http://www.daterangepicker.com/
 */
@@ -11,6 +11,7 @@
         // AMD. Make globaly available as well
         define(['moment', 'jquery'], function (moment, jquery) {
             if (!jquery.fn) jquery.fn = {}; // webpack server rendering
+            if (typeof moment !== 'function' && moment.hasOwnProperty('default')) moment = moment['default']
             return factory(moment, jquery);
         });
     } else if (typeof module === 'object' && module.exports) {
@@ -97,14 +98,14 @@
 
         //html template for the picker UI
         if (typeof options.template !== 'string' && !(options.template instanceof $))
-            options.template = 
+            options.template =
             '<div class="daterangepicker">' +
                 '<div class="ranges"></div>' +
-                '<div class="calendar left">' +
+                '<div class="drp-calendar left">' +
                     '<div class="calendar-table"></div>' +
                     '<div class="calendar-time"></div>' +
                 '</div>' +
-                '<div class="calendar right">' +
+                '<div class="drp-calendar right">' +
                     '<div class="calendar-table"></div>' +
                     '<div class="calendar-time"></div>' +
                 '</div>' +
@@ -290,7 +291,7 @@
 
         //if no start/end dates set, check if an input element contains initial values
         if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
-            if ($(this.element).is('input[type=text]')) {
+            if ($(this.element).is(':text')) {
                 var val = $(this.element).val(),
                     split = val.split(this.locale.separator);
 
@@ -336,7 +337,7 @@
 
                 // If the end of the range is before the minimum or the start of the range is
                 // after the maximum, don't display this range option at all.
-                if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) 
+                if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))
                   || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
                     continue;
 
@@ -382,10 +383,10 @@
 
         if (this.singleDatePicker) {
             this.container.addClass('single');
-            this.container.find('.calendar.left').addClass('single');
-            this.container.find('.calendar.left').show();
-            this.container.find('.calendar.right').hide();
-            if (!this.timePicker) {
+            this.container.find('.drp-calendar.left').addClass('single');
+            this.container.find('.drp-calendar.left').show();
+            this.container.find('.drp-calendar.right').hide();
+            if (!this.timePicker && this.autoApply) {
                 this.container.addClass('auto-apply');
             }
         }
@@ -409,20 +410,21 @@
         // event listeners
         //
 
-        this.container.find('.calendar')
+        this.container.find('.drp-calendar')
             .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
             .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
             .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
+            .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
             .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
             .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
-            .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))
+            .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this));
 
         this.container.find('.ranges')
-            .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
+            .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this));
 
         this.container.find('.drp-buttons')
             .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
-            .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
+            .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this));
 
         if (this.element.is('input') || this.element.is('button')) {
             this.element.on({
@@ -440,13 +442,7 @@
         // if attached to a text input, set the initial value
         //
 
-        if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
-            this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
-            this.element.trigger('change');
-        } else if (this.element.is('input') && this.autoUpdateInput) {
-            this.element.val(this.startDate.format(this.locale.format));
-            this.element.trigger('change');
-        }
+        this.updateElement();
 
     };
 
@@ -493,7 +489,7 @@
                 this.endDate = moment(endDate);
 
             if (!this.timePicker)
-                this.endDate = this.endDate.add(1,'d').startOf('day').subtract(1,'second');
+                this.endDate = this.endDate.endOf('day');
 
             if (this.timePicker && this.timePickerIncrement)
                 this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
@@ -530,9 +526,9 @@
                 this.renderTimePicker('left');
                 this.renderTimePicker('right');
                 if (!this.endDate) {
-                    this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
+                    this.container.find('.right .calendar-time select').prop('disabled', true).addClass('disabled');
                 } else {
-                    this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
+                    this.container.find('.right .calendar-time select').prop('disabled', false).removeClass('disabled');
                 }
             }
             if (this.endDate)
@@ -580,6 +576,9 @@
                 if (this.endDate) {
                     hour = parseInt(this.container.find('.left .hourselect').val(), 10);
                     minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
+                    if (isNaN(minute)) {
+                        minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10);
+                    }
                     second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                     if (!this.timePicker24Hour) {
                         var ampm = this.container.find('.left .ampmselect').val();
@@ -591,6 +590,9 @@
                 } else {
                     hour = parseInt(this.container.find('.right .hourselect').val(), 10);
                     minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
+                    if (isNaN(minute)) {
+                        minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10);
+                    }
                     second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                     if (!this.timePicker24Hour) {
                         var ampm = this.container.find('.right .ampmselect').val();
@@ -714,7 +716,7 @@
 
                 var monthHtml = '<select class="monthselect">';
                 for (var m = 0; m < 12; m++) {
-                    if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
+                    if ((!inMinYear || (minDate && m >= minDate.month())) && (!inMaxYear || (maxDate && m <= maxDate.month()))) {
                         monthHtml += "<option value='" + m + "'" +
                             (m === currentMonth ? " selected='selected'" : "") +
                             ">" + this.locale.monthNames[m] + "</option>";
@@ -791,7 +793,7 @@
 
                     //grey out the dates in other months displayed at beginning and end of this calendar
                     if (calendar[row][col].month() != calendar[1][1].month())
-                        classes.push('off');
+                        classes.push('off', 'ends');
 
                     //don't allow selection of dates before the minimum date
                     if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
@@ -844,7 +846,7 @@
             html += '</tbody>';
             html += '</table>';
 
-            this.container.find('.calendar.' + side + ' .calendar-table').html(html);
+            this.container.find('.drp-calendar.' + side + ' .calendar-table').html(html);
 
         },
 
@@ -856,7 +858,7 @@
 
             var html, selected, minDate, maxDate = this.maxDate;
 
-            if (this.maxSpan && (!this.maxDate || this.startDate.clone().add(this.maxSpan).isAfter(this.maxDate)))
+            if (this.maxSpan && (!this.maxDate || this.startDate.clone().add(this.maxSpan).isBefore(this.maxDate)))
                 maxDate = this.startDate.clone().add(this.maxSpan);
 
             if (side == 'left') {
@@ -867,12 +869,12 @@
                 minDate = this.startDate;
 
                 //Preserve the time already selected
-                var timeSelector = this.container.find('.calendar.right .calendar-time');
+                var timeSelector = this.container.find('.drp-calendar.right .calendar-time');
                 if (timeSelector.html() != '') {
 
-                    selected.hour(selected.hour() || timeSelector.find('.hourselect option:selected').val());
-                    selected.minute(selected.minute() || timeSelector.find('.minuteselect option:selected').val());
-                    selected.second(selected.second() || timeSelector.find('.secondselect option:selected').val());
+                    selected.hour(!isNaN(selected.hour()) ? selected.hour() : timeSelector.find('.hourselect option:selected').val());
+                    selected.minute(!isNaN(selected.minute()) ? selected.minute() : timeSelector.find('.minuteselect option:selected').val());
+                    selected.second(!isNaN(selected.second()) ? selected.second() : timeSelector.find('.secondselect option:selected').val());
 
                     if (!this.timePicker24Hour) {
                         var ampm = timeSelector.find('.ampmselect option:selected').val();
@@ -1005,23 +1007,25 @@
                 html += '</select>';
             }
 
-            this.container.find('.calendar.' + side + ' .calendar-time').html(html);
+            this.container.find('.drp-calendar.' + side + ' .calendar-time').html(html);
 
         },
 
         updateFormInputs: function() {
 
             if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
-                this.container.find('button.applyBtn').removeAttr('disabled');
+                this.container.find('button.applyBtn').prop('disabled', false);
             } else {
-                this.container.find('button.applyBtn').attr('disabled', 'disabled');
+                this.container.find('button.applyBtn').prop('disabled', true);
             }
 
         },
 
         move: function() {
             var parentOffset = { top: 0, left: 0 },
-                containerTop;
+                containerTop,
+                drops = this.drops;
+
             var parentRightEdge = $(window).width();
             if (!this.parentEl.is('body')) {
                 parentOffset = {
@@ -1031,48 +1035,83 @@
                 parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
             }
 
-            if (this.drops == 'up')
+            switch (drops) {
+            case 'auto':
+                containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
+                if (containerTop + this.container.outerHeight() >= this.parentEl[0].scrollHeight) {
+                    containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
+                    drops = 'up';
+                }
+                break;
+            case 'up':
                 containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
-            else
+                break;
+            default:
                 containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
-            this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('drop-up');
+                break;
+            }
+
+            // Force the container to it's actual width
+            this.container.css({
+              top: 0,
+              left: 0,
+              right: 'auto'
+            });
+            var containerWidth = this.container.outerWidth();
+
+            this.container.toggleClass('drop-up', drops == 'up');
 
             if (this.opens == 'left') {
-                this.container.css({
-                    top: containerTop,
-                    right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),
-                    left: 'auto'
-                });
-                if (this.container.offset().left < 0) {
+                var containerRight = parentRightEdge - this.element.offset().left - this.element.outerWidth();
+                if (containerWidth + containerRight > $(window).width()) {
                     this.container.css({
+                        top: containerTop,
                         right: 'auto',
                         left: 9
                     });
+                } else {
+                    this.container.css({
+                        top: containerTop,
+                        right: containerRight,
+                        left: 'auto'
+                    });
                 }
             } else if (this.opens == 'center') {
-                this.container.css({
-                    top: containerTop,
-                    left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
-                            - this.container.outerWidth() / 2,
-                    right: 'auto'
-                });
-                if (this.container.offset().left < 0) {
+                var containerLeft = this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
+                                        - containerWidth / 2;
+                if (containerLeft < 0) {
                     this.container.css({
+                        top: containerTop,
                         right: 'auto',
                         left: 9
                     });
+                } else if (containerLeft + containerWidth > $(window).width()) {
+                    this.container.css({
+                        top: containerTop,
+                        left: 'auto',
+                        right: 0
+                    });
+                } else {
+                    this.container.css({
+                        top: containerTop,
+                        left: containerLeft,
+                        right: 'auto'
+                    });
                 }
             } else {
-                this.container.css({
-                    top: containerTop,
-                    left: this.element.offset().left - parentOffset.left,
-                    right: 'auto'
-                });
-                if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
+                var containerLeft = this.element.offset().left - parentOffset.left;
+                if (containerLeft + containerWidth > $(window).width()) {
                     this.container.css({
+                        top: containerTop,
                         left: 'auto',
                         right: 0
                     });
+                } else {
+                    this.container.css({
+                        top: containerTop,
+                        left: containerLeft,
+                        right: 'auto'
+                    });
                 }
             }
         },
@@ -1186,7 +1225,7 @@
         },
 
         clickPrev: function(e) {
-            var cal = $(e.target).parents('.calendar');
+            var cal = $(e.target).parents('.drp-calendar');
             if (cal.hasClass('left')) {
                 this.leftCalendar.month.subtract(1, 'month');
                 if (this.linkedCalendars)
@@ -1198,7 +1237,7 @@
         },
 
         clickNext: function(e) {
-            var cal = $(e.target).parents('.calendar');
+            var cal = $(e.target).parents('.drp-calendar');
             if (cal.hasClass('left')) {
                 this.leftCalendar.month.add(1, 'month');
             } else {
@@ -1211,18 +1250,13 @@
 
         hoverDate: function(e) {
 
-            //ignore mouse movements while an above-calendar text input has focus
-            //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
-            //    return;
-
             //ignore dates that can't be selected
             if (!$(e.target).hasClass('available')) return;
 
-            //have the text inputs above calendars reflect the date being hovered over
             var title = $(e.target).attr('data-title');
             var row = title.substr(1, 1);
             var col = title.substr(3, 1);
-            var cal = $(e.target).parents('.calendar');
+            var cal = $(e.target).parents('.drp-calendar');
             var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
 
             //highlight the dates between the start date and the date being hovered as a potential end date
@@ -1230,7 +1264,7 @@
             var rightCalendar = this.rightCalendar;
             var startDate = this.startDate;
             if (!this.endDate) {
-                this.container.find('.calendar tbody td').each(function(index, el) {
+                this.container.find('.drp-calendar tbody td').each(function(index, el) {
 
                     //skip week numbers, only look at dates
                     if ($(el).hasClass('week')) return;
@@ -1238,7 +1272,7 @@
                     var title = $(el).attr('data-title');
                     var row = title.substr(1, 1);
                     var col = title.substr(3, 1);
-                    var cal = $(el).parents('.calendar');
+                    var cal = $(el).parents('.drp-calendar');
                     var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
 
                     if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
@@ -1259,7 +1293,7 @@
             var title = $(e.target).attr('data-title');
             var row = title.substr(1, 1);
             var col = title.substr(3, 1);
-            var cal = $(e.target).parents('.calendar');
+            var cal = $(e.target).parents('.drp-calendar');
             var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
 
             //
@@ -1282,6 +1316,9 @@
                             hour = 0;
                     }
                     var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
+                    if (isNaN(minute)) {
+                        minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10);
+                    }
                     var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                     date = date.clone().hour(hour).minute(minute).second(second);
                 }
@@ -1302,6 +1339,9 @@
                             hour = 0;
                     }
                     var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
+                    if (isNaN(minute)) {
+                        minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10);
+                    }
                     var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                     date = date.clone().hour(hour).minute(minute).second(second);
                 }
@@ -1314,7 +1354,7 @@
 
             if (this.singleDatePicker) {
                 this.setEndDate(this.startDate);
-                if (!this.timePicker)
+                if (!this.timePicker && this.autoApply)
                     this.clickApply();
             }
 
@@ -1330,7 +1370,7 @@
             var i = 0;
             for (var range in this.ranges) {
               if (this.timePicker) {
-                    var format = this.timePickerSeconds ? "YYYY-MM-DD hh:mm:ss" : "YYYY-MM-DD hh:mm";
+                    var format = this.timePickerSeconds ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD HH:mm";
                     //ignore times when comparing dates if time picker seconds is not enabled
                     if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) {
                         customRange = false;
@@ -1370,9 +1410,9 @@
         },
 
         monthOrYearChanged: function(e) {
-            var isLeft = $(e.target).closest('.calendar').hasClass('left'),
+            var isLeft = $(e.target).closest('.drp-calendar').hasClass('left'),
                 leftOrRight = isLeft ? 'left' : 'right',
-                cal = this.container.find('.calendar.'+leftOrRight);
+                cal = this.container.find('.drp-calendar.'+leftOrRight);
 
             // Month must be Number for new moment versions
             var month = parseInt(cal.find('.monthselect').val(), 10);
@@ -1413,11 +1453,14 @@
 
         timeChanged: function(e) {
 
-            var cal = $(e.target).closest('.calendar'),
+            var cal = $(e.target).closest('.drp-calendar'),
                 isLeft = cal.hasClass('left');
 
             var hour = parseInt(cal.find('.hourselect').val(), 10);
             var minute = parseInt(cal.find('.minuteselect').val(), 10);
+            if (isNaN(minute)) {
+                minute = parseInt(cal.find('.minuteselect option:last').val(), 10);
+            }
             var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;
 
             if (!this.timePicker24Hour) {
@@ -1500,12 +1543,14 @@
         },
 
         updateElement: function() {
-            if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
-                this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
-                this.element.trigger('change');
-            } else if (this.element.is('input') && this.autoUpdateInput) {
-                this.element.val(this.startDate.format(this.locale.format));
-                this.element.trigger('change');
+            if (this.element.is('input') && this.autoUpdateInput) {
+                var newValue = this.startDate.format(this.locale.format);
+                if (!this.singleDatePicker) {
+                    newValue += this.locale.separator + this.endDate.format(this.locale.format);
+                }
+                if (newValue !== this.element.val()) {
+                    this.element.val(newValue).trigger('change');
+                }
             }
         },
 

+ 2 - 2
gui/default/vendor/fancytree/LICENSE.txt

@@ -1,5 +1,5 @@
-Copyright 2008-2018 Martin Wendt,
-http://wwWendt.de/
+Copyright 2008-2021 Martin Wendt,
+https://wwWendt.de/
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the

+ 0 - 706
gui/default/vendor/fancytree/css/ui.fancytree.css

@@ -1,706 +0,0 @@
-/*!
- * 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
- *----------------------------------------------------------------------------*/
-.fancytree-helper-hidden {
-  display: none;
-}
-.fancytree-helper-indeterminate-cb {
-  color: #777;
-}
-.fancytree-helper-disabled {
-  color: #c0c0c0;
-}
-/* Helper to allow spinning loader icon with glyph-, ligature-, and SVG-icons. */
-.fancytree-helper-spin {
-  -webkit-animation: spin 1000ms infinite linear;
-  animation: spin 1000ms infinite linear;
-}
-@-webkit-keyframes spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-    transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-    transform: rotate(359deg);
-  }
-}
-@keyframes spin {
-  0% {
-    -webkit-transform: rotate(0deg);
-    transform: rotate(0deg);
-  }
-  100% {
-    -webkit-transform: rotate(359deg);
-    transform: rotate(359deg);
-  }
-}
-/*------------------------------------------------------------------------------
- * 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
- *----------------------------------------------------------------------------*/
-/* ext-dnd5: */
-span.fancytree-childcounter {
-  color: #fff;
-  background: #337ab7;
-  border: 1px solid gray;
-  border-radius: 10px;
-  padding: 2px;
-  text-align: center;
-}
-/* ext-dnd: */
-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 {
-  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;
-}
-#fancytree-drop-marker.fancytree-rtl {
-  background-image: url("../skin-lion/icons-rtl.gif");
-}
-/*------------------------------------------------------------------------------
- * '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: #c0c0c0;
-  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: #c0c0c0;
-  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;
-}

文件差異過大導致無法顯示
+ 7094 - 7077
gui/default/vendor/fancytree/jquery.fancytree-all-deps.js


二進制
gui/default/vendor/fancytree/skin-lion/icons.gif


二進制
gui/default/vendor/fancytree/skin-lion/loading.gif


二進制
gui/default/vendor/fancytree/skin-lion/vline.gif


+ 7 - 4
gui/light/assets/css/theme.css

@@ -28,8 +28,11 @@
     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;
+/*
+ * Fancytree tweaks
+ */
+
+.fancytree-container tr:hover,
+.fancytree-focused {
+    background-color: #eeeeee;
 }

部分文件因文件數量過多而無法顯示