
30 changed files with 1628 additions and 1 deletions
-
3.bowerrc
-
30.editorconfig
-
1.gitattributes
-
128.gitignore
-
2README.md
-
193app/index.html
-
4app/robots.txt
-
93app/scripts/controllers/list.js
-
33app/scripts/controllers/main.js
-
27app/scripts/core/__core.js
-
36app/scripts/core/__fix.js
-
20app/scripts/core/app.js
-
48app/scripts/core/config.js
-
15app/scripts/core/constants.js
-
22app/scripts/core/router.js
-
42app/scripts/core/utils.js
-
11app/scripts/filters/dateDuration.js
-
32app/scripts/filters/substring.js
-
21app/scripts/filters/taskOrderBy.js
-
28app/scripts/filters/volumn.js
-
26app/scripts/langs/en-US.js
-
26app/scripts/langs/zh-CN.js
-
125app/scripts/services/aria2RpcService.js
-
52app/scripts/services/aria2WebSocketRpcService.js
-
74app/scripts/services/ariaNgSettingService.js
-
299app/styles/aria-ng.css
-
28app/views/list.html
-
49bower.json
-
116gulpfile.js
-
45package.json
@ -0,0 +1,3 @@ |
|||
{ |
|||
"directory": "bower_components" |
|||
} |
@ -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 |
|||
|
@ -0,0 +1 @@ |
|||
* text=auto |
@ -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) |
@ -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> |
@ -0,0 +1,4 @@ |
|||
# AriaNg |
|||
|
|||
User-agent: * |
|||
Disallow: / |
@ -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()); |
|||
}]); |
|||
})(); |
@ -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()); |
|||
}]); |
|||
})(); |
@ -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); |
|||
} |
|||
})(); |
@ -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(); |
|||
})(); |
@ -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' |
|||
]); |
|||
})(); |
@ -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(); |
|||
}); |
|||
}]); |
|||
})(); |
@ -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' |
|||
}); |
|||
})(); |
@ -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' |
|||
}); |
|||
}]); |
|||
})(); |
@ -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); |
|||
} |
|||
}; |
|||
}]); |
|||
})(); |
@ -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); |
|||
} |
|||
}]); |
|||
})(); |
@ -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; |
|||
} |
|||
}); |
|||
})(); |
@ -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; |
|||
} |
|||
} |
|||
}]); |
|||
})(); |
@ -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; |
|||
} |
|||
}]); |
|||
})(); |
@ -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' |
|||
}); |
|||
}]) |
|||
})(); |
@ -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': '未知' |
|||
}); |
|||
}]) |
|||
})(); |
@ -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); |
|||
} |
|||
}; |
|||
}]); |
|||
})(); |
@ -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); |
|||
} |
|||
}; |
|||
}]); |
|||
})(); |
@ -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); |
|||
} |
|||
}; |
|||
}]); |
|||
})(); |
@ -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; |
|||
} |
@ -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> |
@ -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" |
|||
} |
|||
} |
@ -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'); |
|||
}); |
@ -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" |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue