init
This commit is contained in:
parent
3dd8bfa73b
commit
920cfb39b8
30
.editorconfig
Normal file
30
.editorconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[gulpfile.js]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
* text=auto
|
128
.gitignore
vendored
Normal file
128
.gitignore
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Yeoman template
|
||||
node_modules/
|
||||
bower_components/
|
||||
*.log
|
||||
|
||||
build/
|
||||
dist/
|
||||
### Windows template
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
### Linux template
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
.idea/
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Node template
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
### OSX template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
.tmp
|
|
@ -1,2 +1,2 @@
|
|||
# AriaNg
|
||||
Aria2 Ng Frontend
|
||||
A Better Frontend for Aria2 (Under construction)
|
||||
|
|
193
app/index.html
Normal file
193
app/index.html
Normal file
|
@ -0,0 +1,193 @@
|
|||
<!DOCTYPE html>
|
||||
<html ng-app="ariaNg">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
<meta name="description" content="Aria2 Ng Frontend">
|
||||
<title>AriaNg</title>
|
||||
<!-- build:css css/bootstrap-3.3.6.min.css -->
|
||||
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css"/>
|
||||
<!-- endbuild -->
|
||||
<!-- build:css css/plugins.min.css -->
|
||||
<link rel="stylesheet" href="../bower_components/font-awesome/css/font-awesome.min.css"/>
|
||||
<link rel="stylesheet" href="../bower_components/AdminLTE/dist/css/AdminLTE.min.css"/>
|
||||
<link rel="stylesheet" href="../bower_components/sweetalert/dist/sweetalert.css"/>
|
||||
<link rel="stylesheet" href="../bower_components/seiyria-bootstrap-slider/dist/css/bootstrap-slider.min.css"/>
|
||||
<link rel="stylesheet" href="../bower_components/angular/angular-csp.css"/>
|
||||
<link rel="stylesheet" href="../bower_components/angular-busy/dist/angular-busy.min.css"/>
|
||||
<!-- endbuild -->
|
||||
<!-- build:css css/aria-ng.min.css -->
|
||||
<link rel="stylesheet" href="styles/aria-ng.css">
|
||||
<!-- endbuild -->
|
||||
</head>
|
||||
<body class="hold-transition skin-aria-ng sidebar-mini">
|
||||
<div class="wrapper" ng-controller="MainController">
|
||||
<header class="main-header">
|
||||
<a class="logo" href="#">
|
||||
<span class="logo-mini">Aria</span>
|
||||
<span class="logo-lg">AriaNg</span>
|
||||
</a>
|
||||
|
||||
<nav class="navbar navbar-static-top" role="navigation">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a class="pointer-cursor" title="{{'New' | translate}}">
|
||||
<i class="fa fa-plus"></i>
|
||||
<span translate>New</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" title="{{'Start' | translate}}">
|
||||
<i class="fa fa-play"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" title="{{'Pause' | translate}}">
|
||||
<i class="fa fa-pause"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" title="{{'Delete' | translate}}">
|
||||
<i class="fa fa-trash-o"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor dropdown-toggle" data-toggle="dropdown" title="{{'Display Order' | translate}}">
|
||||
<i class="fa fa-sort-alpha-asc"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li>
|
||||
<a class="pointer-cursor" ng-click="changeDisplayOrder('default')">
|
||||
<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')">
|
||||
<span translate>File Name</span>
|
||||
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('name')}"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" ng-click="changeDisplayOrder('percent')">
|
||||
<span translate>Completed Percent</span>
|
||||
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('percent')}"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" ng-click="changeDisplayOrder('remain')">
|
||||
<span translate>Remain Time</span>
|
||||
<i class="fa" ng-class="{'fa-check': isSetDisplayOrder('remain')}"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a class="pointer-cursor" title="{{'Settings' | translate}}">
|
||||
<i class="fa fa-cog"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<aside class="main-sidebar">
|
||||
<section class="sidebar">
|
||||
<ul id="siderbar-menu" class="sidebar-menu">
|
||||
<li class="header" translate>Download</li>
|
||||
<li data-href-match="/downloading">
|
||||
<a href="#/downloading"><i class="fa fa-arrow-down"></i> <span ng-bind="('Downloading' | translate) + (globalStat && globalStat.numActive > 0 ? ' (' + globalStat.numActive + ')' : '')">Downloading</span></a>
|
||||
</li>
|
||||
<li data-href-match="/scheduling">
|
||||
<a href="#/scheduling"><i class="fa fa-hourglass-half"></i> <span ng-bind="('Scheduling' | translate) + (globalStat && globalStat.numWaiting > 0 ? ' (' + globalStat.numWaiting + ')' : '')">Scheduling</span></a>
|
||||
</li>
|
||||
<li data-href-match="/stopped">
|
||||
<a href="#/stopped"><i class="fa fa-stop-circle-o"></i> <span ng-bind="('Stopped' | translate) + (globalStat && globalStat.numStopped > 0 ? ' (' + globalStat.numStopped + ')' : '')">Stopped</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<div id="content-wrapper" class="content-wrapper">
|
||||
<div ng-view cg-busy="{ promise: loadPromise, message: ('Loading' | translate) }"></div>
|
||||
</div>
|
||||
|
||||
<footer class="main-footer">
|
||||
<a class="sidebar-toggle" data-toggle="offcanvas" role="button" title="{{'Toggle Navigation' | translate}}"></a>
|
||||
|
||||
<span> </span>
|
||||
|
||||
<div class="pull-right">
|
||||
<span class="realtime-upload">
|
||||
<i class="fa fa-arrow-down"></i>
|
||||
<span ng-bind="(globalStat.downloadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
<span class="realtime-download">
|
||||
<i class="fa fa-arrow-up"></i>
|
||||
<span ng-bind="(globalStat.uploadSpeed | readableVolumn) + '/s'"></span>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<!-- build:js js/jquery-2.2.3.min.js -->
|
||||
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/angular-packages-1.4.10.min.js -->
|
||||
<script src="../bower_components/angular/angular.min.js"></script>
|
||||
<script src="../bower_components/angular-route/angular-route.min.js"></script>
|
||||
<script src="../bower_components/angular-sanitize/angular-sanitize.min.js"></script>
|
||||
<script src="../bower_components/angular-touch/angular-touch.min.js"></script>
|
||||
<script src="../bower_components/angular-messages/angular-messages.min.js"></script>
|
||||
<script src="../bower_components/angular-cookies/angular-cookies.min.js"></script>
|
||||
<script src="../bower_components/angular-animate/angular-animate.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/bootstrap-3.3.6.min.js -->
|
||||
<script src="../bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/moment-with-locales-2.13.0.min.js -->
|
||||
<script src="../bower_components/moment/min/moment.min.js"></script>
|
||||
<script src="../bower_components/moment/locale/zh-cn.js"></script>
|
||||
<script src="../bower_components/moment/locale/zh-tw.js"></script>
|
||||
<script src="../bower_components/moment-timezone/builds/moment-timezone-with-data-2010-2020.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/echarts.simple-3.1.9.min.js -->
|
||||
<script src="../bower_components/echarts/dist/echarts.simple.min.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/plugins.min.js -->
|
||||
<script src="../bower_components/AdminLTE/dist/js/app.min.js"></script>
|
||||
<script src="../bower_components/sweetalert/dist/sweetalert.min.js"></script>
|
||||
<script src="../bower_components/seiyria-bootstrap-slider/dist/bootstrap-slider.min.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/angular-websocket.min.js"></script>
|
||||
<script src="../bower_components/angular-base64/angular-base64.min.js"></script>
|
||||
<script src="../bower_components/angular-local-storage/dist/angular-local-storage.min.js"></script>
|
||||
<script src="../bower_components/angular-busy/dist/angular-busy.min.js"></script>
|
||||
<script src="../bower_components/angular-bootstrap-slider/slider.js"></script>
|
||||
<script src="../bower_components/ngSweetAlert/SweetAlert.js"></script>
|
||||
<!-- endbuild -->
|
||||
<!-- build:js js/aria-ng.min.js -->
|
||||
<script src="scripts/core/__core.js"></script>
|
||||
<script src="scripts/core/__fix.js"></script>
|
||||
<script src="scripts/core/app.js"></script>
|
||||
<script src="scripts/core/config.js"></script>
|
||||
<script src="scripts/core/constants.js"></script>
|
||||
<script src="scripts/core/router.js"></script>
|
||||
<script src="scripts/core/utils.js"></script>
|
||||
<script src="scripts/controllers/list.js"></script>
|
||||
<script src="scripts/controllers/main.js"></script>
|
||||
<script src="scripts/filters/dateDuration.js"></script>
|
||||
<script src="scripts/filters/substring.js"></script>
|
||||
<script src="scripts/filters/taskOrderBy.js"></script>
|
||||
<script src="scripts/filters/volumn.js"></script>
|
||||
<script src="scripts/langs/en-US.js"></script>
|
||||
<script src="scripts/langs/zh-CN.js"></script>
|
||||
<script src="scripts/services/aria2RpcService.js"></script>
|
||||
<script src="scripts/services/aria2WebSocketRpcService.js"></script>
|
||||
<script src="scripts/services/ariaNgSettingService.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
</html>
|
4
app/robots.txt
Normal file
4
app/robots.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
# AriaNg
|
||||
|
||||
User-agent: *
|
||||
Disallow: /
|
93
app/scripts/controllers/list.js
Normal file
93
app/scripts/controllers/list.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').controller('DownloadListController', ['$rootScope', '$scope', '$window', '$location', '$interval', 'translateFilter', 'aria2RpcService', 'ariaNgSettingService', 'utils', function ($rootScope, $scope, $window, $location, $interval, translateFilter, aria2RpcService, ariaNgSettingService, utils) {
|
||||
var location = $location.path().substring(1);
|
||||
|
||||
var getTitleWidth = function () {
|
||||
var titleColumn = angular.element('.task-table > .row > .col-md-8:first-child');
|
||||
|
||||
if (titleColumn.length > 0) {
|
||||
return titleColumn.width();
|
||||
} else {
|
||||
var taskTable = angular.element('.task-table');
|
||||
|
||||
if ($window.innerWidth <= 767) {
|
||||
return taskTable.width();
|
||||
} else {
|
||||
return taskTable.width() / 12 * 8;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var calculateDownloadRemainTime = function (remainBytes, downloadSpeed) {
|
||||
if (downloadSpeed == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return remainBytes / downloadSpeed;
|
||||
};
|
||||
|
||||
var processDownloadTask = function (task) {
|
||||
var remainLength = task.totalLength - task.completedLength;
|
||||
|
||||
if (task.bittorrent && task.bittorrent.info) {
|
||||
task.taskName = task.bittorrent.info.name;
|
||||
} else if (task.files && task.files.length >= 1) {
|
||||
task.taskName = utils.getFileNameFromPath(task.files[0].path);
|
||||
} else {
|
||||
task.taskName = translateFilter('Unknown');
|
||||
}
|
||||
|
||||
task.completePercent = task.completedLength / task.totalLength * 100;
|
||||
task.idle = task.downloadSpeed == 0;
|
||||
task.remainTime = calculateDownloadRemainTime(remainLength, task.downloadSpeed);
|
||||
};
|
||||
|
||||
$scope.titleWidth = getTitleWidth();
|
||||
|
||||
angular.element($window).bind('resize', function () {
|
||||
$scope.titleWidth = getTitleWidth();
|
||||
});
|
||||
|
||||
$scope.getOrderType = function () {
|
||||
return ariaNgSettingService.getDisplayOrder();
|
||||
};
|
||||
|
||||
if ($rootScope.downloadTaskRefreshTimer) {
|
||||
$interval.cancel($rootScope.downloadTaskRefreshTimer);
|
||||
}
|
||||
|
||||
$rootScope.downloadTaskRefreshTimer = $interval(function () {
|
||||
var invokeMethod = null;
|
||||
var params = [];
|
||||
|
||||
if (location == 'downloading') {
|
||||
invokeMethod = aria2RpcService.tellActive;
|
||||
} else if (location == 'scheduling') {
|
||||
invokeMethod = aria2RpcService.tellWaiting;
|
||||
params = [0, 1000];
|
||||
} else if (location == 'downloaded') {
|
||||
invokeMethod = aria2RpcService.tellStopped;
|
||||
params = [0, 1000];
|
||||
}
|
||||
|
||||
if (invokeMethod) {
|
||||
invokeMethod({
|
||||
params: params,
|
||||
callback: function (result) {
|
||||
if (result && result.length > 0) {
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
processDownloadTask(result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!utils.replaceArray(result, $scope.downloadTasks, 'gid')) {
|
||||
$scope.downloadTasks = result;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, ariaNgSettingService.getDownloadTaskRefreshInterval());
|
||||
}]);
|
||||
})();
|
33
app/scripts/controllers/main.js
Normal file
33
app/scripts/controllers/main.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').controller('MainController', ['$scope', '$interval', 'aria2RpcService', 'ariaNgSettingService', function ($scope, $interval, aria2RpcService, ariaNgSettingService) {
|
||||
var processStatResult = function (stat) {
|
||||
var activeCount = parseInt(stat.numActive);
|
||||
var waitingCount = parseInt(stat.numWaiting);
|
||||
var totalRunningCount = activeCount + waitingCount;
|
||||
|
||||
stat.totalRunningCount = totalRunningCount;
|
||||
};
|
||||
|
||||
$scope.changeDisplayOrder = function (type) {
|
||||
ariaNgSettingService.setDisplayOrder(type);
|
||||
};
|
||||
|
||||
$scope.isSetDisplayOrder = function (type) {
|
||||
return ariaNgSettingService.getDisplayOrder() === type;
|
||||
};
|
||||
|
||||
$interval(function () {
|
||||
aria2RpcService.getGlobalStat({
|
||||
callback: function (result) {
|
||||
if (result) {
|
||||
processStatResult(result);
|
||||
}
|
||||
|
||||
$scope.globalStat = result;
|
||||
}
|
||||
});
|
||||
}, ariaNgSettingService.getGlobalStatRefreshInterval());
|
||||
}]);
|
||||
})();
|
27
app/scripts/core/__core.js
Normal file
27
app/scripts/core/__core.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*!
|
||||
* AriaNg
|
||||
* https://github.com/mayswind/AriaNg
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var ltIE10 = (function () {
|
||||
var browserName = navigator.appName;
|
||||
var browserVersions = navigator.appVersion.split(';');
|
||||
var browserVersion = (browserVersions && browserVersions.length > 1 ? browserVersions[1].replace(/[ ]/g, '') : '');
|
||||
|
||||
if (browserName == 'Microsoft Internet Explorer' && (browserVersion == 'MSIE6.0' || browserVersion == 'MSIE7.0' || browserVersion == 'MSIE8.0' || browserVersion == 'MSIE9.0')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
})();
|
||||
|
||||
if (ltIE10) {
|
||||
var tip = document.createElement('div');
|
||||
tip.className = 'alert alert-danger';
|
||||
tip.innerHTML = 'Sorry, AriaNg cannot support this browser, please upgrade your browser!';
|
||||
document.getElementById('content-wrapper').appendChild(tip);
|
||||
}
|
||||
})();
|
36
app/scripts/core/__fix.js
Normal file
36
app/scripts/core/__fix.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
//copy from AdminLTE app.js
|
||||
var fixContentWrapperHeight = function () {
|
||||
var neg = $('.main-header').outerHeight() + $('.main-footer').outerHeight();
|
||||
var window_height = $(window).height();
|
||||
var sidebar_height = $(".sidebar").height();
|
||||
|
||||
if ($("body").hasClass("fixed")) {
|
||||
$(".content-wrapper, .right-side").css('height', window_height - $('.main-footer').outerHeight());
|
||||
} else {
|
||||
var postSetWidth;
|
||||
if (window_height >= sidebar_height) {
|
||||
$(".content-wrapper, .right-side").css('height', window_height - neg);
|
||||
postSetWidth = window_height - neg;
|
||||
} else {
|
||||
$(".content-wrapper, .right-side").css('height', sidebar_height);
|
||||
postSetWidth = sidebar_height;
|
||||
}
|
||||
|
||||
//Fix for the control sidebar height
|
||||
var controlSidebar = $($.AdminLTE.options.controlSidebarOptions.selector);
|
||||
if (typeof controlSidebar !== "undefined") {
|
||||
if (controlSidebar.height() > postSetWidth)
|
||||
$(".content-wrapper, .right-side").css('height', controlSidebar.height());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(window, ".wrapper").resize(function () {
|
||||
fixContentWrapperHeight();
|
||||
});
|
||||
|
||||
fixContentWrapperHeight();
|
||||
})();
|
20
app/scripts/core/app.js
Normal file
20
app/scripts/core/app.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var ariaNg = angular.module('ariaNg', [
|
||||
'ngRoute',
|
||||
'ngSanitize',
|
||||
'ngTouch',
|
||||
'ngMessages',
|
||||
'ngCookies',
|
||||
'ngAnimate',
|
||||
'pascalprecht.translate',
|
||||
'angularMoment',
|
||||
'ngWebSocket',
|
||||
'base64',
|
||||
'LocalStorageModule',
|
||||
'cgBusy',
|
||||
'ui.bootstrap-slider',
|
||||
'oitozero.ngSweetAlert'
|
||||
]);
|
||||
})();
|
48
app/scripts/core/config.js
Normal file
48
app/scripts/core/config.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').config(['$translateProvider', 'localStorageServiceProvider', 'ariaNgConstants', function ($translateProvider, localStorageServiceProvider, ariaNgConstants) {
|
||||
localStorageServiceProvider
|
||||
.setPrefix(ariaNgConstants.appPrefix)
|
||||
.setStorageType('localStorage')
|
||||
.setStorageCookie(365, '/');
|
||||
|
||||
$translateProvider.preferredLanguage('en-US');
|
||||
$translateProvider.useSanitizeValueStrategy('escape');
|
||||
}]).run(['$translate', 'amMoment', 'moment', 'ariaNgConstants', 'ariaNgSettingService', function ($translate, amMoment, moment, ariaNgConstants, ariaNgSettingService) {
|
||||
$translate.use(ariaNgSettingService.getLocaleName());
|
||||
|
||||
moment.updateLocale('zh-cn', {
|
||||
week: null
|
||||
});
|
||||
|
||||
amMoment.changeLocale(ariaNgSettingService.getLocaleName());
|
||||
}]).run(['$rootScope', '$location', '$document', 'SweetAlert', 'ariaNgConstants', function ($rootScope, $location, $document, SweetAlert, ariaNgConstants) {
|
||||
var setNavbarSelected = function (location) {
|
||||
angular.element('section.sidebar > ul li').removeClass('active');
|
||||
angular.element('section.sidebar > ul > li[data-href-match]').each(function (index, element) {
|
||||
var prefix = angular.element(element).attr('data-href-match');
|
||||
|
||||
if (location.indexOf(prefix) == 0) {
|
||||
angular.element(element).addClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
angular.element('section.sidebar > ul > li.treeview > ul.treeview-menu > li[data-href-match]').each(function (index, element) {
|
||||
var prefix = angular.element(element).attr('data-href-match');
|
||||
|
||||
if (location.indexOf(prefix) == 0) {
|
||||
angular.element(element).addClass('active').parent().parent().addClass('active');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$rootScope.$on('$routeChangeStart', function (event, next, current) {
|
||||
var location = $location.path();
|
||||
|
||||
setNavbarSelected(location);
|
||||
$document.unbind('keypress');
|
||||
SweetAlert.close();
|
||||
});
|
||||
}]);
|
||||
})();
|
15
app/scripts/core/constants.js
Normal file
15
app/scripts/core/constants.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').constant('ariaNgConstants', {
|
||||
title: 'Aria Ng',
|
||||
appPrefix: 'AriaNg'
|
||||
}).constant('ariaNgDefaultOptions', {
|
||||
localeName: 'en-US',
|
||||
globalStatRefreshInterval: 1000,
|
||||
downloadTaskRefreshInterval: 1000
|
||||
}).constant('aria2RpcConstants', {
|
||||
rpcServiceVersion: '2.0',
|
||||
rpcServiceName: 'aria2'
|
||||
});
|
||||
})();
|
22
app/scripts/core/router.js
Normal file
22
app/scripts/core/router.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').config(['$routeProvider', function ($routeProvider) {
|
||||
$routeProvider
|
||||
.when('/downloading', {
|
||||
templateUrl: 'views/list.html',
|
||||
controller: 'DownloadListController'
|
||||
})
|
||||
.when('/scheduling', {
|
||||
templateUrl: 'views/list.html',
|
||||
controller: 'DownloadListController'
|
||||
})
|
||||
.when('/stopped', {
|
||||
templateUrl: 'views/list.html',
|
||||
controller: 'DownloadListController'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/downloading'
|
||||
});
|
||||
}]);
|
||||
})();
|
42
app/scripts/core/utils.js
Normal file
42
app/scripts/core/utils.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').factory('utils', ['$location', '$base64', 'ariaNgConstants', function ($location, $base64, ariaNgConstants) {
|
||||
return {
|
||||
generateUniqueId: function () {
|
||||
var sourceId = ariaNgConstants.appPrefix + '_' + Math.round(new Date().getTime() / 1000) + '_' + Math.random();
|
||||
var hashedId = $base64.encode(sourceId);
|
||||
|
||||
return hashedId;
|
||||
},
|
||||
replaceArray: function (sourceArray, targetArray, keyProperty) {
|
||||
if (!targetArray || !sourceArray || sourceArray.length != targetArray.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < targetArray.length; i++) {
|
||||
if (targetArray[i][keyProperty] == sourceArray[i][keyProperty]) {
|
||||
angular.extend(targetArray[i], sourceArray[i]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
getFileNameFromPath: function (path) {
|
||||
if (!path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
var index = path.lastIndexOf('/');
|
||||
|
||||
if (index <= 0 || index == path.length) {
|
||||
return path;
|
||||
}
|
||||
|
||||
return path.substring(index + 1);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
})();
|
11
app/scripts/filters/dateDuration.js
Normal file
11
app/scripts/filters/dateDuration.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module("ariaNg").filter('dateDuration', ['moment', function (moment) {
|
||||
return function (duration, sourceUnit, format) {
|
||||
var timespan = moment.duration(duration, sourceUnit);
|
||||
var time = moment.utc(timespan.asMilliseconds());
|
||||
return time.format(format);
|
||||
}
|
||||
}]);
|
||||
})();
|
32
app/scripts/filters/substring.js
Normal file
32
app/scripts/filters/substring.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module("ariaNg").filter('substring', function () {
|
||||
return function (value, count) {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
var actualCount = Math.round(count);
|
||||
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var ch = value.charAt(i);
|
||||
var code = value.charCodeAt(i);
|
||||
|
||||
if (code < 128) {
|
||||
if (!('A' <= ch && ch <= 'Z')) {
|
||||
actualCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actualCount = Math.round(actualCount);
|
||||
|
||||
if (value.length > actualCount) {
|
||||
value = value.substring(0, actualCount) + '...';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
});
|
||||
})();
|
21
app/scripts/filters/taskOrderBy.js
Normal file
21
app/scripts/filters/taskOrderBy.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module("ariaNg").filter('taskOrderBy', ['orderByFilter', function (orderByFilter) {
|
||||
return function (array, type) {
|
||||
if (!angular.isArray(array)) {
|
||||
return array;
|
||||
}
|
||||
|
||||
if (type == 'name') {
|
||||
return orderByFilter(array, ['taskName'], false);
|
||||
} else if (type == 'percent') {
|
||||
return orderByFilter(array, ['completePercent'], true);
|
||||
} else if (type == 'remain') {
|
||||
return orderByFilter(array, ['idle', 'remainTime'], false);
|
||||
} else {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}]);
|
||||
})();
|
28
app/scripts/filters/volumn.js
Normal file
28
app/scripts/filters/volumn.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module("ariaNg").filter('readableVolumn', ['numberFilter', function (numberFilter) {
|
||||
var units = [ 'B', 'KB', 'MB', 'GB' ];
|
||||
|
||||
return function (value) {
|
||||
var unit = units[0];
|
||||
|
||||
if (!value) {
|
||||
value = 0;
|
||||
} else {
|
||||
for (var i = 1; i < units.length; i++) {
|
||||
if (value >= 1024) {
|
||||
value = value / 1024;
|
||||
unit = units[i];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
value = numberFilter(value, 2);
|
||||
}
|
||||
|
||||
return value + ' ' + unit;
|
||||
}
|
||||
}]);
|
||||
})();
|
26
app/scripts/langs/en-US.js
Normal file
26
app/scripts/langs/en-US.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').config(['$translateProvider', function ($translateProvider) {
|
||||
$translateProvider.translations('en-US', {
|
||||
'New': 'New',
|
||||
'Start': 'Start',
|
||||
'Pause': 'Pause',
|
||||
'Delete': 'Delete',
|
||||
'Display Order': 'Display Order',
|
||||
'Default': 'Default',
|
||||
'File Name': 'File Name',
|
||||
'Completed Percent': 'Completed Percent',
|
||||
'Remain Time': 'Remain Time',
|
||||
'Settings': 'Settings',
|
||||
'Download': 'Download',
|
||||
'Downloading': 'Downloading',
|
||||
'Scheduling': 'Scheduling',
|
||||
'Stopped': 'Stopped',
|
||||
'Toggle Navigation': 'Toggle Navigation',
|
||||
'Loading': 'Loading...',
|
||||
'More Than One Day': 'More than 1 day',
|
||||
'Unknown': 'Unknown'
|
||||
});
|
||||
}])
|
||||
})();
|
26
app/scripts/langs/zh-CN.js
Normal file
26
app/scripts/langs/zh-CN.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').config(['$translateProvider', function ($translateProvider) {
|
||||
$translateProvider.translations('zh-CN', {
|
||||
'New': '新建',
|
||||
'Start': '开始下载任务',
|
||||
'Pause': '暂停下载任务',
|
||||
'Delete': '删除下载任务',
|
||||
'Display Order': '显示顺序',
|
||||
'Default': '默认',
|
||||
'File Name': '文件名',
|
||||
'Completed Percent': '完成度',
|
||||
'Remain Time': '剩余时间',
|
||||
'Settings': '系统设置',
|
||||
'Download': '下载',
|
||||
'Downloading': '正在下载',
|
||||
'Scheduling': '正在排队',
|
||||
'Stopped': '已停止',
|
||||
'Toggle Navigation': '切换导航',
|
||||
'Loading': '正在加载...',
|
||||
'More Than One Day': '超过1天',
|
||||
'Unknown': '未知'
|
||||
});
|
||||
}])
|
||||
})();
|
125
app/scripts/services/aria2RpcService.js
Normal file
125
app/scripts/services/aria2RpcService.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').factory('aria2RpcService', ['aria2RpcConstants', 'aria2WebSocketRpcService', 'utils', function (aria2RpcConstants, aria2WebSocketRpcService, utils) {
|
||||
var invoke = function (method, context) {
|
||||
context.uniqueId = utils.generateUniqueId();
|
||||
context.requestBody = {
|
||||
jsonrpc: aria2RpcConstants.rpcServiceVersion,
|
||||
method: aria2RpcConstants.rpcServiceName + '.' + method,
|
||||
id: context.uniqueId,
|
||||
params: context.params
|
||||
};
|
||||
|
||||
return aria2WebSocketRpcService.request(context);
|
||||
};
|
||||
|
||||
return {
|
||||
addUri: function (context) {
|
||||
return invoke('addUri', context);
|
||||
},
|
||||
addTorrent: function (context) {
|
||||
return invoke('addTorrent', context);
|
||||
},
|
||||
addMetalink: function (context) {
|
||||
return invoke('addMetalink', context);
|
||||
},
|
||||
remove: function (context) {
|
||||
return invoke('remove', context);
|
||||
},
|
||||
forceRemove: function (context) {
|
||||
return invoke('forceRemove', context);
|
||||
},
|
||||
pause: function (context) {
|
||||
return invoke('pause', context);
|
||||
},
|
||||
pauseAll: function (context) {
|
||||
return invoke('pauseAll', context);
|
||||
},
|
||||
forcePause: function (context) {
|
||||
return invoke('forcePause', context);
|
||||
},
|
||||
forcePauseAll: function (context) {
|
||||
return invoke('forcePauseAll', context);
|
||||
},
|
||||
unpause: function (context) {
|
||||
return invoke('unpause', context);
|
||||
},
|
||||
unpauseAll: function (context) {
|
||||
return invoke('unpauseAll', context);
|
||||
},
|
||||
tellStatus: function (context) {
|
||||
return invoke('tellStatus', context);
|
||||
},
|
||||
getUris: function (context) {
|
||||
return invoke('getUris', context);
|
||||
},
|
||||
getFiles: function (context) {
|
||||
return invoke('getFiles', context);
|
||||
},
|
||||
getPeers: function (context) {
|
||||
return invoke('getPeers', context);
|
||||
},
|
||||
getServers: function (context) {
|
||||
return invoke('getServers', context);
|
||||
},
|
||||
tellActive: function (context) {
|
||||
return invoke('tellActive', context);
|
||||
},
|
||||
tellWaiting: function (context) {
|
||||
return invoke('tellWaiting', context);
|
||||
},
|
||||
tellStopped: function (context) {
|
||||
return invoke('tellStopped', context);
|
||||
},
|
||||
changePosition: function (context) {
|
||||
return invoke('changePosition', context);
|
||||
},
|
||||
changeUri: function (context) {
|
||||
return invoke('changeUri', context);
|
||||
},
|
||||
getOption: function (context) {
|
||||
return invoke('getOption', context);
|
||||
},
|
||||
changeOption: function (context) {
|
||||
return invoke('changeOption', context);
|
||||
},
|
||||
getGlobalOption: function (context) {
|
||||
return invoke('getGlobalOption', context);
|
||||
},
|
||||
changeGlobalOption: function (context) {
|
||||
return invoke('changeGlobalOption', context);
|
||||
},
|
||||
getGlobalStat: function (context) {
|
||||
return invoke('getGlobalStat', context);
|
||||
},
|
||||
purgeDownloadResult: function (context) {
|
||||
return invoke('purgeDownloadResult', context);
|
||||
},
|
||||
removeDownloadResult: function (context) {
|
||||
return invoke('removeDownloadResult', context);
|
||||
},
|
||||
getVersion: function (context) {
|
||||
return invoke('getVersion', context);
|
||||
},
|
||||
getSessionInfo: function (context) {
|
||||
return invoke('getSessionInfo', context);
|
||||
},
|
||||
shutdown: function (context) {
|
||||
return invoke('shutdown', context);
|
||||
},
|
||||
forceShutdown: function (context) {
|
||||
return invoke('forceShutdown', context);
|
||||
},
|
||||
saveSession: function (context) {
|
||||
return invoke('saveSession', context);
|
||||
},
|
||||
multicall: function (context) {
|
||||
return invoke('multicall', context);
|
||||
},
|
||||
listMethods: function (context) {
|
||||
return invoke('listMethods', context);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
})();
|
52
app/scripts/services/aria2WebSocketRpcService.js
Normal file
52
app/scripts/services/aria2WebSocketRpcService.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').factory('aria2WebSocketRpcService', ['$websocket', 'ariaNgSettingService', function ($websocket, ariaNgSettingService) {
|
||||
var rpcUrl = ariaNgSettingService.getJsonRpcUrl();
|
||||
var socketClient = $websocket(rpcUrl);
|
||||
var sendIdMapping = {};
|
||||
|
||||
socketClient.onMessage(function (message) {
|
||||
if (!message || !message.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
var content = angular.fromJson(message.data);
|
||||
|
||||
if (!content || !content.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
var uniqueId = content.id;
|
||||
var result = content.result;
|
||||
|
||||
if (!sendIdMapping[uniqueId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = sendIdMapping[uniqueId];
|
||||
var callbackMethod = context.callback;
|
||||
|
||||
if (callbackMethod) {
|
||||
callbackMethod(result);
|
||||
}
|
||||
|
||||
delete sendIdMapping[uniqueId];
|
||||
});
|
||||
|
||||
return {
|
||||
request: function (context) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
var uniqueId = context.uniqueId;
|
||||
var requestBody = angular.toJson(context.requestBody);
|
||||
|
||||
sendIdMapping[uniqueId] = context;
|
||||
|
||||
return socketClient.send(requestBody);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
})();
|
74
app/scripts/services/ariaNgSettingService.js
Normal file
74
app/scripts/services/ariaNgSettingService.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
angular.module('ariaNg').factory('ariaNgSettingService', ['$location', '$translate', 'localStorageService', 'ariaNgDefaultOptions', function ($location, $translate, localStorageService, ariaNgDefaultOptions) {
|
||||
var setOptions = function (options) {
|
||||
return localStorageService.set('Options', options);
|
||||
};
|
||||
|
||||
var getOptions = function () {
|
||||
var options = localStorageService.get('Options');
|
||||
|
||||
if (!options) {
|
||||
options = angular.extend({}, ariaNgDefaultOptions);
|
||||
setOptions(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
var getOption = function (key) {
|
||||
return getOptions()[key];
|
||||
};
|
||||
|
||||
var setOption = function (key, value) {
|
||||
var options = getOptions();
|
||||
options[key] = value;
|
||||
|
||||
setOptions(options);
|
||||
};
|
||||
|
||||
return {
|
||||
get: function (key) {
|
||||
return getOption(key);
|
||||
},
|
||||
set: function (key, value) {
|
||||
return setOption(key, value);
|
||||
},
|
||||
getLocaleName: function () {
|
||||
return getOption('localeName');
|
||||
},
|
||||
setLocaleName: function (value) {
|
||||
setOption('localeName', value);
|
||||
$translate.use(value);
|
||||
},
|
||||
getJsonRpcUrl: function () {
|
||||
var rpcHost = getOption('aria2RpcHost');
|
||||
|
||||
if (!rpcHost) {
|
||||
rpcHost = $location.$$host + ':6800';
|
||||
}
|
||||
|
||||
return 'ws://' + rpcHost + '/jsonrpc';
|
||||
},
|
||||
getGlobalStatRefreshInterval: function () {
|
||||
return getOption('globalStatRefreshInterval');
|
||||
},
|
||||
getDownloadTaskRefreshInterval: function () {
|
||||
return getOption('downloadTaskRefreshInterval');
|
||||
},
|
||||
getDisplayOrder: function () {
|
||||
var value = getOption('displayOrder');
|
||||
|
||||
if (!value) {
|
||||
value = 'default';
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
setDisplayOrder: function (value) {
|
||||
setOption('displayOrder', value);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
})();
|
299
app/styles/aria-ng.css
Normal file
299
app/styles/aria-ng.css
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*!
|
||||
* AriaNg
|
||||
* https://github.com/mayswind/AriaNg
|
||||
*/
|
||||
|
||||
/* skin-aria-ng */
|
||||
.skin-aria-ng, h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
font-family: 'Hiragino Sans GB', 'Microsoft YaHei', 'STHeiti', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .nav > li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .nav > li > a {
|
||||
color: #707070;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .nav > li > a:hover,
|
||||
.skin-aria-ng .main-header .navbar .nav > li > a:active,
|
||||
.skin-aria-ng .main-header .navbar .nav > li > a:focus,
|
||||
.skin-aria-ng .main-header .navbar .nav .open > a,
|
||||
.skin-aria-ng .main-header .navbar .nav .open > a:hover,
|
||||
.skin-aria-ng .main-header .navbar .nav .open > a:focus,
|
||||
.skin-aria-ng .main-header .navbar .nav > .active > a {
|
||||
color: #0080ff;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .sidebar-toggle, .skin-aria-ng .main-footer .sidebar-toggle {
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .sidebar-toggle:hover, .skin-aria-ng .main-footer .sidebar-toggle:hover {
|
||||
color: #0080ff;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.skin-aria-ng .main-header .navbar {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .navbar .dropdown-menu li.divider {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .logo {
|
||||
background-color: #3c4852;
|
||||
color: #ffffff;
|
||||
border-bottom: 1px solid #59636b;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-header .logo:hover {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.skin-aria-ng .content-header {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.skin-aria-ng .wrapper,
|
||||
.skin-aria-ng .main-sidebar,
|
||||
.skin-aria-ng .left-side {
|
||||
background-color: #3c4852;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar-menu > li.header {
|
||||
color: #707070;
|
||||
background-color: #2e343c;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar-menu > li > a {
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar-menu > li:hover > a {
|
||||
color: #f8f8f8;
|
||||
background-color: #313a42;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar-menu > li.active > a {
|
||||
color: #65b0ff;
|
||||
background-color: #252c30;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar-menu > li > .treeview-menu {
|
||||
margin: 0 1px;
|
||||
background-color: #2a343b;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar a {
|
||||
color: #b8c7ce;
|
||||
}
|
||||
|
||||
.skin-aria-ng .sidebar a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.skin-aria-ng .main-sidebar {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.skin-aria-ng .treeview-menu > li > a {
|
||||
color: #8aa4af;
|
||||
}
|
||||
|
||||
.skin-aria-ng .treeview-menu > li > a:hover {
|
||||
color: #fefefe;
|
||||
}
|
||||
|
||||
.skin-aria-ng .treeview-menu > li.active > a {
|
||||
color: #0080ff;
|
||||
}
|
||||
|
||||
.skin-aria-ng .content-wrapper {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.skin-aria-ng .content-wrapper, .right-side {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.skin-aria-ng .content-wrapper .content {
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-footer {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-footer .sidebar-toggle {
|
||||
float: left;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
padding: 0 15px 0 0;
|
||||
font-family: fontAwesome;
|
||||
}
|
||||
|
||||
.skin-aria-ng .main-footer .sidebar-toggle:before {
|
||||
content: "\f0c9";
|
||||
}
|
||||
|
||||
.skin-aria-ng .progress-bar-primary {
|
||||
background-color: #208fe5;
|
||||
}
|
||||
|
||||
/* override */
|
||||
td {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.default-cursor {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
.pointer-cursor {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.navbar-nav .open .dropdown-menu {
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* dropdown-submenu */
|
||||
.dropdown-menu small {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.dropdown-submenu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-submenu > .dropdown-menu {
|
||||
top: 0;
|
||||
left: 100%;
|
||||
margin-top: -6px;
|
||||
margin-left: -1px;
|
||||
-webkit-border-radius: 0 6px 6px 6px;
|
||||
-moz-border-radius: 0 6px 6px;
|
||||
border-radius: 0 6px 6px 6px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover > .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdown-submenu > a:after {
|
||||
display: block;
|
||||
content: " ";
|
||||
float: right;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 0 5px 5px;
|
||||
border-left-color: #ccc;
|
||||
margin-top: 5px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
|
||||
.dropdown-submenu:hover > a:after {
|
||||
border-left-color: #fff;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.dropdown-submenu.pull-left > .dropdown-menu {
|
||||
left: -100%;
|
||||
margin-left: 10px;
|
||||
-webkit-border-radius: 6px 0 6px 6px;
|
||||
-moz-border-radius: 6px 0 6px 6px;
|
||||
border-radius: 6px 0 6px 6px;
|
||||
}
|
||||
|
||||
/* scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-clip: padding-box;
|
||||
background-color: #c4d2db;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover, ::-webkit-scrollbar-thumb:active {
|
||||
background-color: #d4dfe7;
|
||||
}
|
||||
|
||||
/* task-table */
|
||||
.task-table {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.task-table > div.row {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.task-table > div.row:nth-of-type(odd) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.task-table > div.row:hover {
|
||||
background-color: #f5f5f5 !important;
|
||||
}
|
||||
|
||||
.task-table .task-name {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.task-table .task-volumn {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.task-table .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.task-table .task-last-time, .task-table .task-seeders {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.task-table .task-download-speed {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* miscellaneous */
|
||||
span.realtime-upload, span.realtime-download {
|
||||
padding: 0 15px 0 15px;
|
||||
}
|
||||
|
||||
span.realtime-upload > i {
|
||||
color: #3a89e9;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
span.realtime-download > i {
|
||||
color: #74a329;
|
||||
padding-right: 2px;
|
||||
}
|
28
app/views/list.html
Normal file
28
app/views/list.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<section class="content no-padding">
|
||||
<div id="task-table" class="task-table">
|
||||
<div class="row" ng-repeat="task in downloadTasks | taskOrderBy: getOrderType()">
|
||||
<div class="col-md-8">
|
||||
<span class="task-name" ng-bind="task.taskName | substring: (titleWidth / 20)" title="{{task.taskName}}"></span>
|
||||
<span class="task-volumn" ng-bind="task.totalLength | readableVolumn"></span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-primary" role="progressbar"
|
||||
aria-valuenow="{{task.completePercent}}" aria-valuemin="1"
|
||||
aria-valuemax="100" style="width: {{task.completePercent}}%;">
|
||||
<div ng-class="{'lower': task.completePercent < 50}"
|
||||
ng-bind="(task.completePercent | number: 2) + '%'"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="task-last-time"
|
||||
ng-bind="0 <= task.remainTime && task.remainTime < 86400? (task.remainTime | dateDuration: 'second': 'HH:mm:ss') : ('More Than One Day' | translate)"></span>
|
||||
<span class="task-seeders pull-right" ng-bind="(task.numSeeders ? (task.numSeeders + '/') : '') + task.connections"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="task-download-speed" ng-bind="(task.downloadSpeed | readableVolumn) + '/s'"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
49
bower.json
Normal file
49
bower.json
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "aria-ng",
|
||||
"description": "Aria2 Ng Frontend",
|
||||
"main": "index.html",
|
||||
"authors": [
|
||||
"MaysWind <i@mayswind.net>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"Aria2",
|
||||
"Web",
|
||||
"Frontend"
|
||||
],
|
||||
"homepage": "https://github.com/mayswind/AriaNg",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": "^2.2.3",
|
||||
"bootstrap": "^3.3.6",
|
||||
"moment": "^2.13.0",
|
||||
"moment-timezone": "^0.5.4",
|
||||
"echarts": "^3.1.9",
|
||||
"font-awesome": "font-awsome#^4.6.3",
|
||||
"AdminLTE": "admin-lte#^2.3.3",
|
||||
"sweetalert": "^1.1.3",
|
||||
"seiyria-bootstrap-slider": "^7.0.3",
|
||||
"angular": "1.4.10",
|
||||
"angular-route": "1.4.10",
|
||||
"angular-sanitize": "1.4.10",
|
||||
"angular-touch": "1.4.10",
|
||||
"angular-messages": "1.4.10",
|
||||
"angular-cookies": "1.4.10",
|
||||
"angular-animate": "1.4.10",
|
||||
"angular-translate": "^2.11.0",
|
||||
"angular-moment": "1.0.0-beta.6",
|
||||
"angular-websocket": "^1.1.0",
|
||||
"angular-base64": "^2.0.5",
|
||||
"angular-local-storage": "^0.2.7",
|
||||
"angular-busy": "^4.1.3",
|
||||
"angular-bootstrap-slider": "^0.1.28",
|
||||
"ngSweetAlert": "https://github.com/oitozero/ngSweetAlert.git#8df6c30b0996f09cb4cf5e90a41115a6c09fa852"
|
||||
}
|
||||
}
|
116
gulpfile.js
Normal file
116
gulpfile.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
var gulp = require('gulp');
|
||||
var gulpLoadPlugins = require('gulp-load-plugins');
|
||||
var browserSync = require('browser-sync');
|
||||
var del = require('del');
|
||||
|
||||
var $ = gulpLoadPlugins();
|
||||
var reload = browserSync.reload;
|
||||
|
||||
gulp.task('styles', function () {
|
||||
return gulp.src([
|
||||
'app/styles/**/*.css'
|
||||
]).pipe($.autoprefixer({browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']}))
|
||||
.pipe(gulp.dest('.tmp/styles'))
|
||||
.pipe(reload({stream: true}));
|
||||
});
|
||||
|
||||
gulp.task('scripts', function () {
|
||||
return gulp.src([
|
||||
'app/scripts/**/*.js'
|
||||
]).pipe($.plumber())
|
||||
.pipe(gulp.dest('.tmp/scripts'))
|
||||
.pipe(reload({stream: true}));
|
||||
});
|
||||
|
||||
gulp.task('lint', function () {
|
||||
return gulp.src([
|
||||
'app/scripts/**/*.js'
|
||||
]).pipe(reload({stream: true, once: true}))
|
||||
.pipe($.eslint({fix: true}))
|
||||
.pipe($.eslint.format())
|
||||
.pipe($.if(!browserSync.active, $.eslint.failAfterError()))
|
||||
.pipe(gulp.dest('app/scripts'));
|
||||
});
|
||||
|
||||
gulp.task('html', ['styles', 'scripts'], function () {
|
||||
return gulp.src('app/*.html')
|
||||
.pipe($.useref({searchPath: ['.tmp', 'app', '.']}))
|
||||
.pipe($.if('js/*.js', $.replace(/\/\/# sourceMappingURL=.*/g, '')))
|
||||
.pipe($.if('css/*.css', $.replace(/\/\*# sourceMappingURL=.* \*\/$/g, '')))
|
||||
.pipe($.if(['js/moment-with-locales-*.min.js', 'js/plugins.min.js', 'js/aria-ng.min.js'], $.uglify({preserveComments: 'license'})))
|
||||
.pipe($.if(['css/plugins.min.css', 'css/aria-ng.min.css'], $.cssnano({safe: true, autoprefixer: false})))
|
||||
.pipe($.if('*.html', $.htmlmin({collapseWhitespace: true})))
|
||||
.pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('views', function () {
|
||||
return gulp.src('app/views/**/*')
|
||||
.pipe($.htmlmin({collapseWhitespace: true}))
|
||||
.pipe(gulp.dest('dist/views'));
|
||||
});
|
||||
|
||||
gulp.task('images', function () {
|
||||
return gulp.src('app/imgs/**/*')
|
||||
.pipe(gulp.dest('dist/imgs'));
|
||||
});
|
||||
|
||||
gulp.task('fonts', function () {
|
||||
return gulp.src([
|
||||
'bower_components/bootstrap/fonts/**/*',
|
||||
'bower_components/font-awesome/fonts/**/*'
|
||||
]).pipe(gulp.dest('.tmp/fonts'))
|
||||
.pipe(gulp.dest('dist/fonts'));
|
||||
});
|
||||
|
||||
gulp.task('extras', function () {
|
||||
return gulp.src([
|
||||
'app/*.*',
|
||||
'!app/*.html'
|
||||
], {
|
||||
dot: true
|
||||
}).pipe(gulp.dest('dist'));
|
||||
});
|
||||
|
||||
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));
|
||||
|
||||
gulp.task('serve', ['styles', 'scripts', 'fonts'], function () {
|
||||
browserSync({
|
||||
notify: false,
|
||||
port: 9000,
|
||||
server: {
|
||||
baseDir: ['.tmp', 'app'],
|
||||
routes: {
|
||||
'/bower_components': 'bower_components'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
gulp.watch([
|
||||
'app/*.html',
|
||||
'app/views/*.html',
|
||||
'app/imgs/**/*',
|
||||
'.tmp/fonts/**/*'
|
||||
]).on('change', reload);
|
||||
|
||||
gulp.watch('app/styles/**/*.css', ['styles']);
|
||||
gulp.watch('app/scripts/**/*.js', ['scripts']);
|
||||
gulp.watch('app/fonts/**/*', ['fonts']);
|
||||
});
|
||||
|
||||
gulp.task('serve:dist', function () {
|
||||
browserSync({
|
||||
notify: false,
|
||||
port: 9000,
|
||||
server: {
|
||||
baseDir: ['dist']
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('build', ['lint', 'html', 'views', 'images', 'fonts', 'extras'], function () {
|
||||
return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
|
||||
});
|
||||
|
||||
gulp.task('default', ['clean'], function () {
|
||||
gulp.start('build');
|
||||
});
|
45
package.json
Normal file
45
package.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browser-sync": "^2.2.1",
|
||||
"del": "^1.1.1",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-autoprefixer": "^3.0.1",
|
||||
"gulp-cssnano": "^2.0.0",
|
||||
"gulp-eslint": "^2.0.0",
|
||||
"gulp-htmlmin": "^1.3.0",
|
||||
"gulp-if": "^2.0.0",
|
||||
"gulp-load-plugins": "^0.10.0",
|
||||
"gulp-plumber": "^1.0.1",
|
||||
"gulp-replace": "^0.5.4",
|
||||
"gulp-size": "^1.2.1",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
"gulp-uglify": "^1.1.0",
|
||||
"gulp-useref": "^3.0.0"
|
||||
},
|
||||
"name": "aria-ng",
|
||||
"description": "Aria2 Ng Frontend",
|
||||
"version": "0.1.0",
|
||||
"main": "index.html",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mayswind/AriaNg.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Aria2",
|
||||
"Web",
|
||||
"Frontend"
|
||||
],
|
||||
"author": "MaysWind <i@mayswind.net>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mayswind/AriaNg/issues"
|
||||
},
|
||||
"homepage": "https://github.com/mayswind/AriaNg#readme"
|
||||
}
|
Reference in a new issue