support importing/exporting AriaNg settings

This commit is contained in:
MaysWind 2018-08-15 04:20:55 +08:00
parent e6d7e7fd1a
commit 93ab9c4072
9 changed files with 229 additions and 3 deletions

View file

@ -378,6 +378,7 @@
<script src="scripts/directives/settingDialog.js"></script> <script src="scripts/directives/settingDialog.js"></script>
<script src="scripts/directives/tooltip.js"></script> <script src="scripts/directives/tooltip.js"></script>
<script src="scripts/directives/validUrls.js"></script> <script src="scripts/directives/validUrls.js"></script>
<script src="scripts/directives/blobDownload.js"></script>
<script src="scripts/filters/dateDuration.js"></script> <script src="scripts/filters/dateDuration.js"></script>
<script src="scripts/filters/fileOrderBy.js"></script> <script src="scripts/filters/fileOrderBy.js"></script>
<script src="scripts/filters/longDate.js"></script> <script src="scripts/filters/longDate.js"></script>

View file

@ -26,6 +26,9 @@ Search=搜索
Default=默认 Default=默认
Expand=展开 Expand=展开
Collapse=折叠 Collapse=折叠
Open=打开
Save=保存
Import=导入
Remove Task=删除任务 Remove Task=删除任务
Clear Stopped Tasks=清空已结束任务 Clear Stopped Tasks=清空已结束任务
Click to view task detail=点击查看任务详情 Click to view task detail=点击查看任务详情
@ -157,6 +160,12 @@ Navigate to Task Detail Page=转到任务详情页面
RPC List Display Order=RPC 列表显示顺序 RPC List Display Order=RPC 列表显示顺序
Recently Used=最近使用 Recently Used=最近使用
RPC Alias=RPC 别名 RPC Alias=RPC 别名
Import / Export AriaNg Settings=导入 / 导出 AriaNg 设置
Import Settings=导入设置
Export Settings=导出设置
Confirm Import=确认导入
Are you sure you want to import all settings?=您是否要导入所有设置?
Invalid settings data format!=无效的设置数据格式!
Supported Placeholder=支持的占位符 Supported Placeholder=支持的占位符
AriaNg Title=AriaNg 标题 AriaNg Title=AriaNg 标题
Downloading Count=正在下载数量 Downloading Count=正在下载数量

View file

@ -26,6 +26,9 @@ Search=搜尋
Default=預設 Default=預設
Expand=展開 Expand=展開
Collapse=摺疊 Collapse=摺疊
Open=打開
Save=儲存
Import=匯入
Remove Task=刪除工作 Remove Task=刪除工作
Clear Stopped Tasks=清除已結束工作 Clear Stopped Tasks=清除已結束工作
Click to view task detail=點選檢視工作詳情 Click to view task detail=點選檢視工作詳情
@ -157,6 +160,12 @@ Navigate to Task Detail Page=轉到工作詳情頁面
RPC List Display Order=RPC 清單顯示順序 RPC List Display Order=RPC 清單顯示順序
Recently Used=最近使用 Recently Used=最近使用
RPC Alias=RPC 別名 RPC Alias=RPC 別名
Import / Export AriaNg Settings=匯入 / 匯出 AriaNg 設定
Import Settings=匯入設定
Export Settings=匯出設定
Confirm Import=確認匯入
Are you sure you want to import all settings?=您是否要匯入所有設定?
Invalid settings data format!=無效的設定資料格式!
Supported Placeholder=支援的預留位置 Supported Placeholder=支援的預留位置
AriaNg Title=AriaNg 標題 AriaNg Title=AriaNg 標題
Downloading Count=正在下載數量 Downloading Count=正在下載數量

View file

@ -37,6 +37,9 @@
downloadTaskRefreshInterval: 1000, downloadTaskRefreshInterval: 1000,
rpcListDisplayOrder: 'recentlyUsed', rpcListDisplayOrder: 'recentlyUsed',
afterCreatingNewTask: 'task-list', afterCreatingNewTask: 'task-list',
removeOldTaskAfterRestarting: false removeOldTaskAfterRestarting: false,
displayOrder: 'default:asc',
fileListDisplayOrder: 'default:asc',
peerListDisplayOrder: 'default:asc'
}); });
}()); }());

View file

@ -30,6 +30,9 @@
'Default': 'Default', 'Default': 'Default',
'Expand': 'Expand', 'Expand': 'Expand',
'Collapse': 'Collapse', 'Collapse': 'Collapse',
'Open': 'Open',
'Save': 'Save',
'Import': 'Import',
'Remove Task': 'Remove Task', 'Remove Task': 'Remove Task',
'Clear Stopped Tasks': 'Clear Stopped Tasks', 'Clear Stopped Tasks': 'Clear Stopped Tasks',
'Click to view task detail': 'Click to view task detail', 'Click to view task detail': 'Click to view task detail',
@ -161,6 +164,12 @@
'RPC List Display Order': 'RPC List Display Order', 'RPC List Display Order': 'RPC List Display Order',
'Recently Used': 'Recently Used', 'Recently Used': 'Recently Used',
'RPC Alias': 'RPC Alias', 'RPC Alias': 'RPC Alias',
'Import / Export AriaNg Settings': 'Import / Export AriaNg Settings',
'Import Settings': 'Import Settings',
'Export Settings': 'Export Settings',
'Confirm Import': 'Confirm Import',
'Are you sure you want to import all settings?': 'Are you sure you want to import all settings?',
'Invalid settings data format!': 'Invalid settings data format!',
'Supported Placeholder': 'Supported Placeholder', 'Supported Placeholder': 'Supported Placeholder',
'AriaNg Title': 'AriaNg Title', 'AriaNg Title': 'AriaNg Title',
'Downloading Count': 'Downloading Count', 'Downloading Count': 'Downloading Count',

View file

@ -1,7 +1,7 @@
(function () { (function () {
'use strict'; 'use strict';
angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', 'ariaNgLanguages', 'ariaNgCommonService', 'ariaNgNotificationService', 'ariaNgLocalizationService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgTitleService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, ariaNgLanguages, ariaNgCommonService, ariaNgNotificationService, ariaNgLocalizationService, ariaNgSettingService, ariaNgMonitorService, ariaNgTitleService, aria2SettingService) { angular.module('ariaNg').controller('AriaNgSettingsController', ['$rootScope', '$scope', '$routeParams', '$window', '$interval', '$timeout', '$filter', 'ariaNgLanguages', 'ariaNgCommonService', 'ariaNgNotificationService', 'ariaNgLocalizationService', 'ariaNgLogService', 'ariaNgFileService', 'ariaNgSettingService', 'ariaNgMonitorService', 'ariaNgTitleService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $window, $interval, $timeout, $filter, ariaNgLanguages, ariaNgCommonService, ariaNgNotificationService, ariaNgLocalizationService, ariaNgLogService, ariaNgFileService, ariaNgSettingService, ariaNgMonitorService, ariaNgTitleService, aria2SettingService) {
var extendType = $routeParams.extendType; var extendType = $routeParams.extendType;
var lastRefreshPageNotification = null; var lastRefreshPageNotification = null;
@ -41,7 +41,10 @@
isInsecureProtocolDisabled: ariaNgSettingService.isInsecureProtocolDisabled(), isInsecureProtocolDisabled: ariaNgSettingService.isInsecureProtocolDisabled(),
settings: ariaNgSettingService.getAllOptions(), settings: ariaNgSettingService.getAllOptions(),
sessionSettings: ariaNgSettingService.getAllSessionOptions(), sessionSettings: ariaNgSettingService.getAllSessionOptions(),
rpcSettings: ariaNgSettingService.getAllRpcSettings() rpcSettings: ariaNgSettingService.getAllRpcSettings(),
isSupportBlob: ariaNgFileService.isSupportBlob(),
importSettings: null,
exportSettings: null
}; };
$scope.context.showDebugMode = $scope.context.sessionSettings.debugMode || extendType === 'debug'; $scope.context.showDebugMode = $scope.context.sessionSettings.debugMode || extendType === 'debug';
@ -161,6 +164,60 @@
ariaNgSettingService.setRemoveOldTaskAfterRestarting(value); ariaNgSettingService.setRemoveOldTaskAfterRestarting(value);
}; };
$scope.showImportSettingsModal = function () {
$scope.context.importSettings = null;
angular.element('#import-settings-modal').modal();
};
$('#import-settings-modal').on('hide.bs.modal', function (e) {
$scope.context.importSettings = null;
});
$scope.openAriaNgConfigFile = function () {
ariaNgFileService.openFileContent({
fileFilter: '.json',
fileType: 'text'
}, function (result) {
$scope.context.importSettings = result.content;
}, function (error) {
ariaNgLocalizationService.showError(error);
}, angular.element('#import-file-holder'));
};
$scope.importSettings = function (settings) {
var settingsObj = null;
try {
settingsObj = JSON.parse(settings);
} catch (e) {
ariaNgLogService.error('[AriaNgSettingsController.importSettings] parse settings json error', e);
ariaNgLocalizationService.showError('Invalid settings data format!');
return;
}
if (!angular.isObject(settingsObj) || angular.isArray(settingsObj)) {
ariaNgLogService.error('[AriaNgSettingsController.importSettings] settings json is not object');
ariaNgLocalizationService.showError('Invalid settings data format!');
return;
}
if (settingsObj) {
ariaNgLocalizationService.confirm('Confirm Import', 'Are you sure you want to import all settings?', 'warning', function () {
ariaNgSettingService.importAllOptions(settingsObj);
$window.location.reload();
});
}
};
$scope.showExportSettingsModal = function () {
$scope.context.exportSettings = $filter('json')(ariaNgSettingService.exportAllOptions());
angular.element('#export-settings-modal').modal();
};
$('#export-settings-modal').on('hide.bs.modal', function (e) {
$scope.context.exportSettings = null;
});
$scope.addNewRpcSetting = function () { $scope.addNewRpcSetting = function () {
setNeedRefreshPage(); setNeedRefreshPage();

View file

@ -0,0 +1,24 @@
(function () {
'use strict';
angular.module('ariaNg').directive('ngBlobDownload', ['ariaNgFileService', function (ariaNgFileService) {
return {
restrict: 'A',
scope: {
ngBlobDownload: '=ngBlobDownload',
ngFileName: '@',
ngContentType: '@'
},
link: function (scope, element) {
scope.$watch('ngBlobDownload', function (value) {
if (value) {
ariaNgFileService.saveFileContent(value, element, {
fileName: scope.ngFileName,
contentType: scope.ngContentType
});
}
});
}
};
}]);
}());

View file

@ -257,6 +257,49 @@
return result; return result;
}, },
importAllOptions: function (options) {
var finalOptions = angular.copy(ariaNgDefaultOptions);
for (var key in options) {
if (!options.hasOwnProperty(key) || !finalOptions.hasOwnProperty(key)) {
continue;
}
if (angular.isObject(options[key]) || angular.isArray(options[key])) {
continue;
}
finalOptions[key] = options[key];
}
if (angular.isArray(options.extendRpcServers)) {
for (var i = 0; i < options.extendRpcServers.length; i++) {
var rpcSetting = options.extendRpcServers[i];
var finalRpcSetting = createNewRpcSetting();
for (var key in rpcSetting) {
if (!rpcSetting.hasOwnProperty(key) || !finalRpcSetting.hasOwnProperty(key)) {
continue;
}
if (angular.isObject(rpcSetting[key]) || angular.isArray(rpcSetting[key])) {
continue;
}
finalRpcSetting[key] = rpcSetting[key];
}
finalOptions.extendRpcServers.push(finalRpcSetting);
}
}
setOptions(finalOptions);
},
exportAllOptions: function () {
var options = angular.extend({}, ariaNgDefaultOptions, getOptions());
return options;
},
getAllSessionOptions: function () { getAllSessionOptions: function () {
return angular.copy(sessionSettings); return angular.copy(sessionSettings);
}, },

View file

@ -151,6 +151,19 @@
</select> </select>
</div> </div>
</div> </div>
<div class="row">
<div class="setting-key setting-key-without-desc col-sm-4">
<span translate>Import / Export AriaNg Settings</span>
</div>
<div class="setting-value col-sm-8">
<button class="btn btn-sm btn-default" ng-click="showImportSettingsModal()">
<span translate>Import Settings</span>
</button>
<button class="btn btn-sm btn-default" ng-click="showExportSettingsModal()">
<span translate>Export Settings</span>
</button>
</div>
</div>
<div class="row tip no-background no-hover"> <div class="row tip no-background no-hover">
<span class="asterisk">*</span> <span class="asterisk">*</span>
<span translate>Changes to the settings take effect after refreshing page.</span> <span translate>Changes to the settings take effect after refreshing page.</span>
@ -252,6 +265,64 @@
</div> </div>
</div> </div>
</div> </div>
<div id="import-settings-modal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">
<span translate>Import Settings</span>
<small>
<a class="pointer-cursor" title="{{'Open' | translate}}" ng-click="openAriaNgConfigFile()">
<i class="icon-primary fa fa-folder-open-o"></i>
</a>
</small>
</h4>
</div>
<div class="modal-body no-padding">
<div class="settings-table striped">
<input id="import-file-holder" type="file" style="display: none"/>
<textarea class="form-control" ng-model="context.importSettings" rows="20"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" ng-disabled="!context.importSettings || !context.importSettings.length"
ng-click="importSettings(context.importSettings)" translate>Import</button>
<button type="button" class="btn btn-default" data-dismiss="modal" translate>Cancel</button>
</div>
</div>
</div>
</div>
<div id="export-settings-modal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">
<span translate>Export Settings</span>
<small>
<a class="pointer-cursor" title="{{'Copy' | translate}}" text="context.exportSettings" clipboard>
<i class="icon-primary fa fa-copy"></i>
</a>
<a class="pointer-cursor" title="{{'Save' | translate}}" ng-if="context.isSupportBlob"
ng-blob-download="context.exportSettings" ng-file-name="AriaNgConfig.json" ng-content-type="application/json">
<i class="icon-primary fa fa-save"></i>
</a>
</small>
</h4>
</div>
<div class="modal-body no-padding">
<div class="settings-table striped">
<textarea class="form-control" ng-model="context.exportSettings" rows="20" readonly="readonly"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" translate>Cancel</button>
</div>
</div>
</div>
</div>
</section> </section>
<script id="setting-changed-notification.html" type="text/ng-template"> <script id="setting-changed-notification.html" type="text/ng-template">
<div class="ui-notification custom-template"> <div class="ui-notification custom-template">