Merge branch 'feature-contextmenu'

This commit is contained in:
MaysWind 2018-02-21 11:13:05 +08:00
commit cf2a35ec63
12 changed files with 189 additions and 22 deletions

View file

@ -32,6 +32,7 @@
"sweetalert": "^1.1.3",
"awesome-bootstrap-checkbox": "^0.3.7",
"jquery-slimscroll": "^1.3.8",
"bootstrap-contextmenu": "^0.3.4",
"angular": "1.6.5",
"angular-route": "1.6.5",
"angular-sanitize": "1.6.5",
@ -50,6 +51,7 @@
"angular-busy": "^4.1.4",
"angular-promise-buttons": "^0.1.21",
"angular-dragula": "^1.2.8",
"angular-clipboard": "^1.6.2",
"ngSweetAlert": "^1.1.2"
},
"resolutions": {

View file

@ -321,6 +321,7 @@
<script src="../bower_components/AdminLTE/dist/js/app.min.js"></script>
<script src="../bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script>
<script src="../bower_components/sweetalert/dist/sweetalert.min.js"></script>
<script src="../bower_components/bootstrap-contextmenu/bootstrap-contextmenu.js"></script>
<script src="../bower_components/angular-translate/angular-translate.min.js"></script>
<script src="../bower_components/angular-moment/angular-moment.min.js"></script>
<script src="../bower_components/angular-websocket/dist/angular-websocket.min.js"></script>
@ -332,6 +333,7 @@
<script src="../bower_components/angular-busy/dist/angular-busy.min.js"></script>
<script src="../bower_components/angular-promise-buttons/dist/angular-promise-buttons.min.js"></script>
<script src="../bower_components/angular-dragula/dist/angular-dragula.min.js"></script>
<script src="../bower_components/angular-clipboard/angular-clipboard.js"></script>
<script src="../bower_components/ngSweetAlert/SweetAlert.js"></script>
<!-- endbuild -->
<!-- build:js js/aria-ng.min.js -->

View file

@ -20,6 +20,7 @@ Select All=全选
Select None=不选
Select Invert=反选
Display Order=显示顺序
Copy Download Url=复制下载链接
Help=帮助
Search=搜索
Default=默认
@ -87,6 +88,7 @@ Seed Creation Time=种子创建时间
Download Url=下载地址
Download Dir=下载路径
BT Tracker Servers=BT 服务器
Copy=复制
(Choose Files)=(选择文件)
Videos=视频
Audios=音频

View file

@ -20,6 +20,7 @@ Select All=全選
Select None=不選
Select Invert=反選
Display Order=顯示順序
Copy Download Url=複製下載鏈接
Help=幫助
Search=搜索
Default=默認
@ -87,6 +88,7 @@ Seed Creation Time=種子創建時間
Download Url=下載地址
Download Dir=下載路徑
BT Tracker Servers=BT 伺服器
Copy=複製
(Choose Files)=(選擇文件)
Videos=視頻
Audios=音頻

View file

@ -24,6 +24,7 @@
'Select None': 'Select None',
'Select Invert': 'Select Invert',
'Display Order': 'Display Order',
'Copy Download Url': 'Copy Download Url',
'Help': 'Help',
'Search': 'Search',
'Default': 'Default',
@ -91,6 +92,7 @@
'Download Url': 'Download Url',
'Download Dir': 'Download Dir',
'BT Tracker Servers': 'BT Tracker Servers',
'Copy': 'Copy',
'(Choose Files)': '(Choose Files)',
'Videos': 'Videos',
'Audios': 'Audios',

View file

@ -1,7 +1,7 @@
(function () {
'use strict';
angular.module('ariaNg').controller('MainController', ['$rootScope', '$scope', '$route', '$window', '$location', '$document', '$interval', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgTitleService', 'ariaNgMonitorService', 'ariaNgNotificationService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $route, $window, $location, $document, $interval, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, ariaNgTitleService, ariaNgMonitorService, ariaNgNotificationService, aria2TaskService, aria2SettingService) {
angular.module('ariaNg').controller('MainController', ['$rootScope', '$scope', '$route', '$window', '$location', '$document', '$interval', 'clipboard', 'aria2RpcErrors', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgTitleService', 'ariaNgMonitorService', 'ariaNgNotificationService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $route, $window, $location, $document, $interval, clipboard, aria2RpcErrors, ariaNgCommonService, ariaNgSettingService, ariaNgTitleService, ariaNgMonitorService, ariaNgNotificationService, aria2TaskService, aria2SettingService) {
var pageTitleRefreshPromise = null;
var globalStatRefreshPromise = null;
@ -44,6 +44,16 @@
return $rootScope.taskContext.getSelectedTaskIds().length > 0;
};
$scope.isSingleUrlTaskSelected = function () {
var selectedTask = $rootScope.taskContext.getSelectedTasks();
if (selectedTask.length !== 1) {
return false;
}
return !!selectedTask[0].singleUrl;
};
$scope.isSpecifiedTaskSelected = function () {
var selectedTasks = $rootScope.taskContext.getSelectedTasks();
@ -197,6 +207,14 @@
$rootScope.taskContext.selectAll();
};
$scope.copySelectedOneTaskDownloadLink = function () {
var selectedTask = $rootScope.taskContext.getSelectedTasks();
if (selectedTask.length === 1) {
clipboard.copyText(selectedTask[0].singleUrl);
}
};
$scope.changeDisplayOrder = function (type, autoSetReverse) {
var oldType = ariaNgCommonService.parseOrderType(ariaNgSettingService.getDisplayOrder());
var newType = ariaNgCommonService.parseOrderType(type);

View file

@ -1,10 +1,11 @@
(function () {
'use strict';
angular.module('ariaNg').controller('TaskDetailController', ['$rootScope', '$scope', '$routeParams', '$interval', 'aria2RpcErrors', 'ariaNgFileTypes', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgMonitorService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $interval, aria2RpcErrors, ariaNgFileTypes, ariaNgCommonService, ariaNgSettingService, ariaNgMonitorService, aria2TaskService, aria2SettingService) {
angular.module('ariaNg').controller('TaskDetailController', ['$rootScope', '$scope', '$routeParams', '$interval', 'clipboard', 'aria2RpcErrors', 'ariaNgFileTypes', 'ariaNgCommonService', 'ariaNgSettingService', 'ariaNgMonitorService', 'aria2TaskService', 'aria2SettingService', function ($rootScope, $scope, $routeParams, $interval, clipboard, aria2RpcErrors, ariaNgFileTypes, ariaNgCommonService, ariaNgSettingService, ariaNgMonitorService, aria2TaskService, aria2SettingService) {
var tabOrders = ['overview', 'blocks', 'filelist', 'btpeers'];
var downloadTaskRefreshPromise = null;
var pauseDownloadTaskRefresh = false;
var currentRowTriggeredMenu = null;
var getAvailableOptions = function (status, isBittorrent) {
var keys = aria2SettingService.getAvailableTaskOptionKeys(status, isBittorrent);
@ -308,6 +309,26 @@
}, true);
};
$scope.copySelectedRowText = function () {
if (!currentRowTriggeredMenu) {
return;
}
var name = currentRowTriggeredMenu.find('.setting-key > span').text().trim();
var value = "";
currentRowTriggeredMenu.find('.setting-value > span').each(function (i, element) {
if (i > 0) {
value += '\n';
}
value += angular.element(element).text().trim();
});
var info = name + ': ' + value;
clipboard.copyText(info);
};
if (ariaNgSettingService.getDownloadTaskRefreshInterval() > 0) {
downloadTaskRefreshPromise = $interval(function () {
if ($scope.task && ($scope.task.status === 'complete' || $scope.task.status === 'error' || $scope.task.status === 'removed')) {
@ -325,6 +346,17 @@
}
});
angular.element('#overview-items .row').contextmenu({
target: '#task-overview-contextmenu',
before: function (e, context) {
currentRowTriggeredMenu = context;
}
});
angular.element('#task-overview-contextmenu').on('hide.bs.context', function () {
currentRowTriggeredMenu = null;
});
$rootScope.loadPromise = refreshDownloadTask(false);
}]);
}());

View file

@ -19,6 +19,7 @@
'cgBusy',
'angularPromiseButtons',
'oitozero.ngSweetAlert',
'angular-clipboard',
angularDragula(angular)
]);
}());

View file

@ -24,6 +24,10 @@
border-top: inherit;
}
.settings-table + .settings-table > div.row:first-child {
border-top: 1px solid #ddd;
}
.settings-table .input-group-addon {
background-color: #eee;
}
@ -36,6 +40,7 @@
color: #888;
font-size: 12px;
font-weight: normal;
font-style: normal;
}
.settings-table .description {
@ -91,6 +96,10 @@
padding: 4px 8px 4px 8px;
}
.settings-table .multi-line {
display: block;
}
@media (max-width: 767px) {
.settings-table .setting-key {
font-weight: bold;

View file

@ -181,6 +181,10 @@ td {
margin-right: -10px;
}
.dropdown-menu > li.dropdown-submenu:hover {
background-color: #e1e3e9;
}
.dropdown-submenu:hover > a:after {
border-left-color: #fff;
}

View file

@ -33,7 +33,8 @@
</div>
</div>
<div class="task-table-body" ng-class="{'draggable': isSupportDragTask()}" dragula="'task-list'" dragula-model="taskContext.list">
<div class="row" ng-repeat="task in taskContext.list | filter: filterByTaskName | taskOrderBy: getOrderType()" data-gid="{{task.gid}}">
<div class="row" ng-repeat="task in taskContext.list | filter: filterByTaskName | taskOrderBy: getOrderType()"
data-gid="{{task.gid}}" data-toggle="context" data-target="#task-table-contextmenu">
<div class="col-md-8 col-sm-7 col-xs-12">
<div class="checkbox checkbox-primary" ng-class="{'checkbox-hide': !taskContext.selected[task.gid]}">
<input id="{{'task_' + task.gid}}" type="checkbox" ng-model="taskContext.selected[task.gid]"/>
@ -72,5 +73,85 @@
</div>
</div>
</div>
<div id="task-table-contextmenu">
<ul class="dropdown-menu" role="menu">
<li ng-show="isSpecifiedTaskSelected('paused')">
<a tabindex="-1" class="pointer-cursor" title="{{'Start' | translate}}" ng-click="changeTasksState('start')">
<i class="fa fa-play"></i>
<span translate>Start</span>
</a>
</li>
<li ng-show="isSpecifiedTaskSelected('active', 'waiting')">
<a tabindex="-1" class="pointer-cursor" title="{{'Pause' | translate}}" ng-click="changeTasksState('pause')">
<i class="fa fa-pause"></i>
<span translate>Pause</span>
</a>
</li>
<li ng-show="isTaskSelected()">
<a tabindex="-1" class="pointer-cursor" title="{{'Delete' | translate}}" ng-click="removeTasks()">
<i class="fa fa-trash-o"></i>
<span translate>Delete</span>
</a>
</li>
<li class="divider" ng-show="isTaskSelected()"></li>
<li class="dropdown dropdown-submenu">
<a tabindex="-1" title="{{'Display Order' | translate}}" href="javascript:void(0);">
<i class="fa fa-sort-alpha-asc"></i>
<span translate>Display Order</span>
</a>
<ul class="dropdown-menu" style="right: 160px;">
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('default:asc')">
<span translate>Default</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('default')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('name:asc')">
<span translate>By File Name</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('name')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('size:asc')">
<span translate>By File Size</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('size')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('percent:desc')">
<span translate>By Progress</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('percent')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('remain:asc')">
<span translate>By Remain Time</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('remain')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('dspeed:desc')">
<span translate>By Download Speed</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('dspeed')}"></i>
</a>
</li>
<li>
<a class="pointer-cursor" ng-click="changeDisplayOrder('uspeed:desc')">
<span translate>By Upload Speed</span>
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('uspeed')}"></i>
</a>
</li>
</ul>
</li>
<li class="divider" ng-show="isSingleUrlTaskSelected()"></li>
<li ng-show="isSingleUrlTaskSelected()">
<a tabindex="-1" class="pointer-cursor" title="{{'Copy Download Url' | translate}}" ng-click="copySelectedOneTaskDownloadLink()">
<i class="fa fa-copy"></i>
<span translate>Copy Download Url</span>
</a>
</li>
</ul>
</div>
</div>
</section>

View file

@ -22,8 +22,8 @@
<div class="tab-content no-padding">
<div class="tab-pane" ng-class="{'active': context.currentTab == 'overview'}">
<div class="settings-table striped hoverable">
<div class="row" ng-if="task">
<div id="overview-items" class="settings-table striped hoverable" data-toggle="context" data-target="#task-overview-contextmenu">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span translate>Task Name</span>
</div>
@ -32,7 +32,7 @@
ng-tooltip="{{(task.bittorrent && task.bittorrent.comment) ? task.bittorrent.comment : task.taskName}}"></span>
</div>
</div>
<div class="row" ng-if="task">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span translate>Task Size</span>
</div>
@ -43,7 +43,7 @@
</a>
</div>
</div>
<div class="row" ng-if="task">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span translate>Task Status</span>
</div>
@ -53,7 +53,7 @@
ng-tooltip="{{task.errorMessage}}" ng-tooltip-container="body" ng-tooltip-placement="top"></i>
</div>
</div>
<div class="row" ng-if="task && task.status == 'error' && task.errorDescription">
<div class="row" ng-show="task && task.status == 'error' && task.errorDescription">
<div class="setting-key col-sm-4">
<span translate>Error Description</span>
</div>
@ -61,7 +61,7 @@
<span ng-bind="task.errorDescription | translate"></span>
</div>
</div>
<div class="row" ng-if="task">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span ng-bind="('Progress' | translate) + (task.status == 'active' && task.bittorrent ? ' (' + ('Health Percentage' | translate) + ')' : '')"></span>
</div>
@ -69,7 +69,7 @@
<span ng-bind="(task.completePercent | percent: 2) + '%' + (task.status == 'active' && task.bittorrent ? ' (' + (context.healthPercent | percent: 2) + '%' + ')' : '')"></span>
</div>
</div>
<div class="row" ng-if="task">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span translate>Download</span>
</div>
@ -77,7 +77,7 @@
<span ng-bind="(task.completedLength | readableVolume) + (task.status == 'active' ? ' @ ' + (task.downloadSpeed | readableVolume) + '/s' : '')"></span>
</div>
</div>
<div class="row" ng-if="task && task.bittorrent">
<div class="row" ng-show="task && task.bittorrent">
<div class="setting-key col-sm-4">
<span translate>Upload</span>
</div>
@ -85,7 +85,7 @@
<span ng-bind="(task.uploadLength | readableVolume) + (task.status == 'active' ? ' @ ' + (task.uploadSpeed | readableVolume) + '/s' : '')"></span>
</div>
</div>
<div class="row" ng-if="task && task.bittorrent">
<div class="row" ng-show="task && task.bittorrent">
<div class="setting-key col-sm-4">
<span translate>Share Ratio</span>
</div>
@ -93,7 +93,7 @@
<span ng-bind="(task.shareRatio | number: 2)"></span>
</div>
</div>
<div class="row" ng-if="task && task.status == 'active' && task.completedLength < task.totalLength">
<div class="row" ng-show="task && task.status == 'active' && task.completedLength < task.totalLength">
<div class="setting-key col-sm-4">
<span translate>Remain Time</span>
</div>
@ -101,7 +101,7 @@
<span ng-bind="0 <= task.remainTime && task.remainTime < 86400? (task.remainTime | dateDuration: 'second': 'HH:mm:ss') : ('More Than One Day' | translate)"></span>
</div>
</div>
<div class="row" ng-if="task && task.status == 'active'">
<div class="row" ng-show="task && task.status == 'active'">
<div class="setting-key col-sm-4">
<span ng-bind="(task.bittorrent ? ('Seeders' | translate) + ' / ' : '') + ('Connections' | translate)">Connections</span>
</div>
@ -109,7 +109,7 @@
<span ng-bind="(task.numSeeders ? (task.numSeeders + ' / ') : '') + task.connections"></span>
</div>
</div>
<div class="row" ng-if="task && task.bittorrent && task.bittorrent.creationDate">
<div class="row" ng-show="task && task.bittorrent && task.bittorrent.creationDate">
<div class="setting-key col-sm-4">
<span translate>Seed Creation Time</span>
</div>
@ -117,7 +117,7 @@
<span ng-bind="task.bittorrent.creationDate | amFromUnix | longDate"></span>
</div>
</div>
<div class="row" ng-if="task && task.infoHash">
<div class="row" ng-show="task && task.infoHash">
<div class="setting-key col-sm-4">
<span translate>Info Hash</span>
</div>
@ -125,7 +125,7 @@
<span class="allow-word-break" ng-bind="task.infoHash"></span>
</div>
</div>
<div class="row" ng-if="task && task.singleUrl">
<div class="row" ng-show="task && task.singleUrl">
<div class="setting-key col-sm-4">
<span translate>Download Url</span>
</div>
@ -133,7 +133,7 @@
<span class="allow-word-break" ng-bind="task.singleUrl"></span>
</div>
</div>
<div class="row" ng-if="task">
<div class="row" ng-show="task">
<div class="setting-key col-sm-4">
<span translate>Download Dir</span>
</div>
@ -141,20 +141,22 @@
<span class="allow-word-break" ng-bind="task.dir"></span>
</div>
</div>
<div class="row" ng-if="task && task.bittorrent && task.bittorrent.announceList && task.bittorrent.announceList.length > 0">
<div class="row" ng-show="task && task.bittorrent && task.bittorrent.announceList && task.bittorrent.announceList.length > 0">
<div class="setting-key col-sm-4">
<span translate>BT Tracker Servers</span>
<span class="description-inline" ng-bind="'format.settings.total-count' | translate: {count: task.bittorrent.announceList.length}"></span>
<em class="description-inline" ng-bind="'format.settings.total-count' | translate: {count: task.bittorrent.announceList.length}"></em>
<i class="icon-expand pointer-cursor fa" ng-if="task.bittorrent.announceList.length > 1"
ng-class="{'fa-plus': context.collapseTrackers, 'fa-minus': !context.collapseTrackers}"
ng-click="context.collapseTrackers = !context.collapseTrackers"
title="{{(context.collapseTrackers ? 'Expand' : 'Collapse') | translate}}"></i>
</div>
<div class="setting-value col-sm-8">
<div class="auto-ellipsis" ng-bind="serverAddress.length ? serverAddress.join(',') : serverAddress" title="{{serverAddress.length ? serverAddress.join(',') : serverAddress}}"
ng-repeat="serverAddress in task.bittorrent.announceList | limitTo: (context.collapseTrackers ? 1 : task.bittorrent.announceList.length)"></div>
<span class="multi-line auto-ellipsis" ng-bind="serverAddress.length ? serverAddress.join(',') : serverAddress" title="{{serverAddress.length ? serverAddress.join(',') : serverAddress}}"
ng-repeat="serverAddress in task.bittorrent.announceList | limitTo: (context.collapseTrackers ? 1 : task.bittorrent.announceList.length)"></span>
</div>
</div>
</div>
<div class="settings-table">
<div class="row no-hover no-background" ng-if="context.isEnableSpeedChart && task && task.status == 'active'">
<div class="col-sm-12">
<div class="task-status-chart-wrapper">
@ -337,4 +339,14 @@
</div>
</div>
</div><!-- /.nav-tabs-custom -->
<div id="task-overview-contextmenu">
<ul class="dropdown-menu" role="menu">
<li>
<a id="mnu-overview-copy" tabindex="-1" class="mnu-copy pointer-cursor" title="{{'Copy' | translate}}" ng-click="copySelectedRowText()">
<i class="fa fa-copy"></i>
<span translate>Copy</span>
</a>
</li>
</ul>
</div>
</section>