diff --git a/bower.json b/bower.json index ab89399..c8072b9 100644 --- a/bower.json +++ b/bower.json @@ -51,6 +51,7 @@ "angular-busy": "^4.1.4", "angular-promise-buttons": "^0.1.23", "angular-clipboard": "^1.6.2", + "angular-input-dropdown": "mayswind/angular-input-dropdown#33e48a818215b9d582f5db8d3b59fce4ed6b92c7", "angularjs-dragula": "^2.0.0", "ngSweetAlert": "^1.1.2" }, diff --git a/src/index.html b/src/index.html index cea5be6..289180b 100644 --- a/src/index.html +++ b/src/index.html @@ -29,6 +29,7 @@ + @@ -339,6 +340,7 @@ + diff --git a/src/langs/zh_Hans.txt b/src/langs/zh_Hans.txt index c002add..59592df 100644 --- a/src/langs/zh_Hans.txt +++ b/src/langs/zh_Hans.txt @@ -143,6 +143,8 @@ Activate=激活 Reset Settings=重置设置 Confirm Reset=确认重置 Are you sure you want to reset all settings?=您是否要重置所有设置? +Clear Settings History=清除设置历史 +Are you sure you want to clear all settings history?=您是否要清除所有设置的历史记录? Delete RPC Setting=删除 RPC 设置 Add New RPC Setting=添加新 RPC 设置 Are you sure you want to remove rpc setting "{{rpcName}}"?=您是否要删除 RPC 设置 "{{rpcName}}"? diff --git a/src/langs/zh_Hant.txt b/src/langs/zh_Hant.txt index 79e17ea..2b10a1e 100644 --- a/src/langs/zh_Hant.txt +++ b/src/langs/zh_Hant.txt @@ -143,6 +143,8 @@ Activate=啟用 Reset Settings=重設設定 Confirm Reset=確認重設 Are you sure you want to reset all settings?=您是否要重設所有設定? +Clear Settings History=清除設定歷史 +Are you sure you want to clear all settings history?=您是否要清除所有設定的歷史紀錄? Delete RPC Setting=刪除 RPC 設定 Add New RPC Setting=加入新 RPC 設定 Are you sure you want to remove rpc setting "{{rpcName}}"?=您是否要刪除 RPC 設定 "{{rpcName}}"? diff --git a/src/scripts/config/aria2Options.js b/src/scripts/config/aria2Options.js index 7a94ad1..a4d1ac5 100644 --- a/src/scripts/config/aria2Options.js +++ b/src/scripts/config/aria2Options.js @@ -889,12 +889,14 @@ // category: 'global|http|bittorrent', // [canShow: 'new|active|waiting|paused',] // possible to show in specific status, supporting multiple choice. if not set, always show // [canUpdate: 'new|active|waiting|paused',] // possible to write in specific status, supporting multiple choice. if not set, always writable + // [showHistory: true|false,] // show history under the input box, only supporting "string" type. if not set, this is set to false // } taskOptions: [ { key: 'dir', category: 'global', - canUpdate: 'new' + canUpdate: 'new', + showHistory: true }, { key: 'out', diff --git a/src/scripts/config/constants.js b/src/scripts/config/constants.js index 3909874..ceac949 100644 --- a/src/scripts/config/constants.js +++ b/src/scripts/config/constants.js @@ -6,6 +6,7 @@ appPrefix: 'AriaNg', optionStorageKey: 'Options', languageStorageKeyPrefix: 'Language', + settingHistoryKeyPrefix: 'History', languagePath: 'langs', languageFileExtension: '.txt', defaultLanguage: 'en', @@ -16,6 +17,7 @@ lazySaveTimeout: 500, errorTooltipDelay: 500, notificationInPageTimeout: 2000, + historyMaxStoreCount: 10, cachedDebugLogsLimit: 100 }).constant('ariaNgDefaultOptions', { language: 'en', diff --git a/src/scripts/config/defaultLanguage.js b/src/scripts/config/defaultLanguage.js index 478e280..b05d783 100644 --- a/src/scripts/config/defaultLanguage.js +++ b/src/scripts/config/defaultLanguage.js @@ -147,6 +147,8 @@ 'Reset Settings': 'Reset Settings', 'Confirm Reset': 'Confirm Reset', 'Are you sure you want to reset all settings?': 'Are you sure you want to reset all settings?', + 'Clear Settings History': 'Clear Settings History', + 'Are you sure you want to clear all settings history?': 'Are you sure you want to clear all settings history?', 'Delete RPC Setting': 'Delete RPC Setting', 'Add New RPC Setting': 'Add New RPC Setting', 'Are you sure you want to remove rpc setting "{{rpcName}}"?': 'Are you sure you want to remove rpc setting "{{rpcName}}"?', diff --git a/src/scripts/controllers/new.js b/src/scripts/controllers/new.js index 066c788..6fdfee2 100644 --- a/src/scripts/controllers/new.js +++ b/src/scripts/controllers/new.js @@ -5,6 +5,14 @@ var tabOrders = ['links', 'options']; var parameters = $location.search(); + var saveDownloadPath = function (options) { + if (!options || !options.dir) { + return; + } + + aria2SettingService.addSettingHistory('dir', options.dir); + }; + var downloadByLinks = function (pauseOnAdded, responseCallback) { var urls = ariaNgCommonService.parseUrlsFromOriginInput($scope.context.urls); var options = angular.copy($scope.context.options); @@ -21,6 +29,8 @@ }); } + saveDownloadPath(options); + return aria2TaskService.newUriTasks(tasks, pauseOnAdded, responseCallback); }; @@ -30,6 +40,8 @@ options: angular.copy($scope.context.options) }; + saveDownloadPath(options); + return aria2TaskService.newTorrentTask(task, pauseOnAdded, responseCallback); }; @@ -39,6 +51,8 @@ options: angular.copy($scope.context.options) }; + saveDownloadPath(options); + return aria2TaskService.newMetalinkTask(task, pauseOnAdded, responseCallback); }; diff --git a/src/scripts/controllers/settings-ariang.js b/src/scripts/controllers/settings-ariang.js index 2eeba44..b8bdec6 100644 --- a/src/scripts/controllers/settings-ariang.js +++ b/src/scripts/controllers/settings-ariang.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', 'ariaNgLanguages', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgNotificationService', 'ariaNgTitleService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, ariaNgLanguages, ariaNgCommonService, ariaNgSettingService, ariaNgMonitorService, ariaNgNotificationService, ariaNgTitleService) { + angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', 'ariaNgLanguages', 'ariaNgCommonService', 'aria2SettingService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgNotificationService', 'ariaNgTitleService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, ariaNgLanguages, ariaNgCommonService, aria2SettingService, ariaNgSettingService, ariaNgMonitorService, ariaNgNotificationService, ariaNgTitleService) { var extendType = $routeParams.extendType; var lastRefreshPageNotification = null; @@ -203,6 +203,13 @@ }); }; + $scope.clearHistory = function () { + ariaNgCommonService.confirm('Confirm Clear', 'Are you sure you want to clear all settings history?', 'warning', function () { + aria2SettingService.clearSettingsHistorys(); + $window.location.reload(); + }); + }; + angular.element('[data-toggle="popover"]').popover(); $rootScope.loadPromise = $timeout(function () {}, 100); diff --git a/src/scripts/core/app.js b/src/scripts/core/app.js index 630cde2..a96869a 100644 --- a/src/scripts/core/app.js +++ b/src/scripts/core/app.js @@ -20,6 +20,7 @@ 'angularPromiseButtons', 'oitozero.ngSweetAlert', 'angular-clipboard', + 'inputDropdown', angularDragula(angular) ]); }()); diff --git a/src/scripts/directives/setting.js b/src/scripts/directives/setting.js index 293a45f..69d3060 100644 --- a/src/scripts/directives/setting.js +++ b/src/scripts/directives/setting.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - angular.module('ariaNg').directive('ngSetting', ['$timeout', '$translate', 'ariaNgConstants', function ($timeout, $translate, ariaNgConstants) { + angular.module('ariaNg').directive('ngSetting', ['$timeout', '$q', '$translate', 'ariaNgConstants', 'aria2SettingService', function ($timeout, $q, $translate, ariaNgConstants, aria2SettingService) { return { restrict: 'E', templateUrl: 'views/setting.html', @@ -22,6 +22,14 @@ angular.extend(options, attrs); + var loadHistory = function () { + if (!scope.option || !scope.option.showHistory) { + return; + } + + scope.history = aria2SettingService.getSettingHistory(scope.option.key); + }; + var destroyTooltip = function () { angular.element(element).tooltip('destroy'); }; @@ -229,6 +237,20 @@ } }; + scope.filterHistory = function (userInput) { + var result = []; + + if (scope.history && userInput) { + for (var i = 0; i < scope.history.length; i++) { + if (scope.history[i].indexOf(userInput) === 0) { + result.push(scope.history[i]); + } + } + } + + return $q.resolve(result); + }; + if (ngModel) { scope.$watch(function () { return ngModel.$viewValue; @@ -238,6 +260,7 @@ } scope.$watch('option', function () { + loadHistory(); element.find('[data-toggle="popover"]').popover(); }); @@ -257,6 +280,8 @@ scope.placeholder = getHumanReadableValue(displayValue); }); + + loadHistory(); } }; }]); diff --git a/src/scripts/services/aria2SettingService.js b/src/scripts/services/aria2SettingService.js index d45c10b..4976246 100644 --- a/src/scripts/services/aria2SettingService.js +++ b/src/scripts/services/aria2SettingService.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - angular.module('ariaNg').factory('aria2SettingService', ['aria2AllOptions', 'aria2GlobalAvailableOptions', 'aria2QuickSettingsAvailableOptions', 'aria2TaskAvailableOptions', 'aria2RpcService', 'ariaNgLogService', function (aria2AllOptions, aria2GlobalAvailableOptions, aria2QuickSettingsAvailableOptions, aria2TaskAvailableOptions, aria2RpcService, ariaNgLogService) { + angular.module('ariaNg').factory('aria2SettingService', ['localStorageService', 'ariaNgConstants', 'aria2AllOptions', 'aria2GlobalAvailableOptions', 'aria2QuickSettingsAvailableOptions', 'aria2TaskAvailableOptions', 'aria2RpcService', 'ariaNgLogService', function (localStorageService, ariaNgConstants, aria2AllOptions, aria2GlobalAvailableOptions, aria2QuickSettingsAvailableOptions, aria2TaskAvailableOptions, aria2RpcService, ariaNgLogService) { var processStatResult = function (stat) { if (!stat) { return stat; @@ -16,6 +16,14 @@ return stat; }; + var getSettingHistoryKey = function (key) { + return ariaNgConstants.settingHistoryKeyPrefix + '.' + key; + }; + + var isSettingHistoryKey = function (key) { + return key.indexOf(ariaNgConstants.settingHistoryKeyPrefix + '.') === 0; + }; + return { isOptionKeyValid: function (key) { var option = aria2AllOptions[key]; @@ -88,7 +96,8 @@ var option = allOptions[i]; var optionKey = { key: option.key, - category: option.category + category: option.category, + showHistory: option.showHistory }; if (option.canShow && option.canShow.indexOf('new') < 0) { @@ -115,6 +124,7 @@ var key = keys[i]; var readonly = false; var category = null; + var showHistory = false; if (angular.isObject(key)) { var optionKey = key; @@ -122,6 +132,7 @@ key = optionKey.key; readonly = !!optionKey.readonly; category = optionKey.category; + showHistory = !!optionKey.showHistory; } var option = aria2AllOptions[key]; @@ -148,6 +159,10 @@ option.readonly = true; } + if (showHistory) { + option.showHistory = true; + } + if (extendSettings && extendSettings.disableRequired) { option.required = false; } @@ -170,6 +185,50 @@ return options; }, + getSettingHistory: function (key) { + if (!this.isOptionKeyValid(key)) { + return []; + } + + var storageKey = getSettingHistoryKey(key); + var history = localStorageService.get(storageKey) || []; + var newHistory = []; + + for (var i = 0; i < Math.min(history.length, ariaNgConstants.historyMaxStoreCount); i++) { + newHistory.push(history[i]); + } + + return newHistory; + }, + addSettingHistory: function (key, value) { + if (!this.isOptionKeyValid(key)) { + return []; + } + + var storageKey = getSettingHistoryKey(key); + var history = localStorageService.get(storageKey) || []; + var newHistory = []; + newHistory.push(value); + + for (var i = 0; i < Math.min(history.length, ariaNgConstants.historyMaxStoreCount - 1); i++) { + if (history[i] !== value) { + newHistory.push(history[i]); + } + } + + localStorageService.set(storageKey, newHistory); + + return newHistory; + }, + clearSettingsHistorys: function () { + var keys = localStorageService.keys(); + + for (var i = 0; i < keys.length; i++) { + if (isSettingHistoryKey(keys[i])) { + localStorageService.remove(keys[i]); + } + } + }, getGlobalOption: function (callback, silent) { return aria2RpcService.getGlobalOption({ silent: !!silent, diff --git a/src/styles/core/extend.css b/src/styles/core/extend.css index 1a82030..393411d 100644 --- a/src/styles/core/extend.css +++ b/src/styles/core/extend.css @@ -110,6 +110,23 @@ margin-bottom: 2px; } +/* angular-input-dropdown */ +input-dropdown[input-class-name="form-control"] > .input-dropdown { + width: 100% +} + +.input-dropdown ul { + border: 1px solid #888; +} + +.input-dropdown ul > li.active { + background-color: #e1e3e9; +} + +.input-dropdown ul > li { + padding: 2px 14px 2px 14px; +} + /* angular-dragula extend */ .gu-mirror { cursor: grabbing; diff --git a/src/views/setting.html b/src/views/setting.html index 6226902..8ceca57 100644 --- a/src/views/setting.html +++ b/src/views/setting.html @@ -12,8 +12,14 @@
+ diff --git a/src/views/settings-ariang.html b/src/views/settings-ariang.html index ffd4c23..9654be2 100644 --- a/src/views/settings-ariang.html +++ b/src/views/settings-ariang.html @@ -144,6 +144,9 @@ +