summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-20 21:39:30 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-20 21:39:30 +0100
commit63cef4c7d641ffddaeabcd768020674e2681ba05 (patch)
tree10b9ee50b927a7673d93db15b896a15a1012f482 /module
parentadded ReadWrite lock, render file progress on dashboard (diff)
downloadpyload-63cef4c7d641ffddaeabcd768020674e2681ba05.tar.xz
improved ui, render waiting files
Diffstat (limited to 'module')
-rw-r--r--module/Api.py9
-rw-r--r--module/FileManager.py4
-rw-r--r--module/datatypes/PyFile.py7
-rw-r--r--module/datatypes/User.py6
-rw-r--r--module/plugins/Hoster.py3
-rw-r--r--module/plugins/hoster/BasePlugin.py13
-rw-r--r--module/utils/__init__.py9
-rw-r--r--module/web/static/css/default/dashboard.less4
-rw-r--r--module/web/static/css/fontawesome.css97
-rw-r--r--module/web/static/fonts/fontawesome-webfont.eotbin30762 -> 30955 bytes
-rw-r--r--module/web/static/fonts/fontawesome-webfont.ttfbin14904 -> 15080 bytes
-rw-r--r--module/web/static/fonts/fontawesome-webfont.woffbin22220 -> 22368 bytes
-rw-r--r--module/web/static/fonts/fontawesome.txt1
-rw-r--r--module/web/static/js/app.js17
-rw-r--r--module/web/static/js/helpers/fileHelper.js11
-rw-r--r--module/web/static/js/models/File.js36
-rw-r--r--module/web/static/js/models/Package.js36
-rw-r--r--module/web/static/js/models/Progress.js6
-rw-r--r--module/web/static/js/models/TreeCollection.js12
-rw-r--r--module/web/static/js/views/fileView.js6
-rw-r--r--module/web/static/js/views/headerView.js29
-rw-r--r--module/web/static/js/views/linkGrabberModal.js29
-rw-r--r--module/web/static/js/views/packageView.js5
-rw-r--r--module/web/static/js/views/selectionView.js40
-rw-r--r--module/web/templates/default/base.html10
-rw-r--r--module/web/templates/default/dashboard.html14
26 files changed, 238 insertions, 166 deletions
diff --git a/module/Api.py b/module/Api.py
index 27d3e8ffe..bfeeff10c 100644
--- a/module/Api.py
+++ b/module/Api.py
@@ -21,8 +21,6 @@ from types import MethodType
from remote.apitypes import *
-from utils import bits_set, primary_uid
-
# contains function names mapped to their permissions
# unlisted functions are for admins only
perm_map = {}
@@ -36,7 +34,6 @@ def RequirePerm(bits):
return _Dec
-
urlmatcher = re.compile(r"((https?|ftps?|xdcc|sftp):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-=\\\.&]*)", re.IGNORECASE)
stateMap = {
@@ -52,10 +49,6 @@ stateMap[DownloadState.Unfinished] = frozenset(stateMap[DownloadState.All].diffe
def state_string(state):
return ",".join(str(x) for x in stateMap[state])
-
-def has_permission(userPermission, Permission):
- return bits_set(Permission, userPermission)
-
from datatypes.User import User
class Api(Iface):
@@ -85,7 +78,7 @@ class Api(Iface):
@property
def primaryUID(self):
- return primary_uid(self.user)
+ return self.user.primary if self.user else None
@classmethod
def initComponents(cls):
diff --git a/module/FileManager.py b/module/FileManager.py
index 52fdab703..7b14613f7 100644
--- a/module/FileManager.py
+++ b/module/FileManager.py
@@ -296,14 +296,14 @@ class FileManager:
def getDownloadStats(self, user=None):
""" return number of downloads """
if user not in self.downloadstats:
- self.downloadstats[user] = self.db.downloadstats()
+ self.downloadstats[user] = self.db.downloadstats(user)
return self.downloadstats[user]
def getQueueStats(self, user=None, force=False):
"""number of files that have to be processed, failed files will not be included"""
if user not in self.queuestats or force:
- self.queuestats[user] = self.db.processstats()
+ self.queuestats[user] = self.db.queuestats(user)
return self.queuestats[user]
diff --git a/module/datatypes/PyFile.py b/module/datatypes/PyFile.py
index bd335a05a..5f2be8769 100644
--- a/module/datatypes/PyFile.py
+++ b/module/datatypes/PyFile.py
@@ -16,7 +16,7 @@
# @author: RaNaN
###############################################################################
-from time import sleep
+from time import sleep, time
from ReadWriteLock import ReadWriteLock
from module.Api import ProgressInfo, DownloadProgress, FileInfo, DownloadInfo, DownloadStatus
@@ -229,8 +229,11 @@ class PyFile(object):
return 0
def getETA(self):
- """ gets established time of arrival"""
+ """ gets established time of arrival / or waiting time"""
try:
+ if self.status == DownloadStatus.Waiting:
+ return self.waitUntil - time()
+
return self.getBytesLeft() / self.getSpeed()
except:
return 0
diff --git a/module/datatypes/User.py b/module/datatypes/User.py
index bdf52d860..da7fb90bf 100644
--- a/module/datatypes/User.py
+++ b/module/datatypes/User.py
@@ -17,7 +17,8 @@
###############################################################################
-from module.Api import UserData, Permission, Role, has_permission
+from module.Api import UserData, Permission, Role
+from module.utils import bits_set
#TODO: activate user
#noinspection PyUnresolvedReferences
@@ -39,11 +40,10 @@ class User(UserData):
def hasPermission(self, perms):
""" Accepts permission bit or name """
-
if isinstance(perms, basestring) and hasattr(Permission, perms):
perms = getattr(Role, perms)
- return has_permission(self.permission, perms)
+ return bits_set(perms, self.permission)
def hasRole(self, role):
if isinstance(role, basestring) and hasattr(Role, role):
diff --git a/module/plugins/Hoster.py b/module/plugins/Hoster.py
index fbe1c7480..651471a93 100644
--- a/module/plugins/Hoster.py
+++ b/module/plugins/Hoster.py
@@ -66,8 +66,7 @@ class Hoster(Base):
#: enables resume (will be ignored if server dont accept chunks)
self.resumeDownload = False
- #: time() + wait in seconds
- self.waitUntil = 0
+ #: plugin is waiting
self.waiting = False
self.ocr = None #captcha reader instance
diff --git a/module/plugins/hoster/BasePlugin.py b/module/plugins/hoster/BasePlugin.py
index b495be873..293049a1a 100644
--- a/module/plugins/hoster/BasePlugin.py
+++ b/module/plugins/hoster/BasePlugin.py
@@ -29,12 +29,13 @@ class BasePlugin(Hoster):
self.multiDL = False
return
-# self.__name__ = "NetloadIn"
-# pyfile.name = "test"
-# self.html = self.load("http://localhost:9000/short")
-# self.download("http://localhost:9000/short")
-# self.api = self.load("http://localhost:9000/short")
-# self.decryptCaptcha("http://localhost:9000/captcha")
+ #TODO: remove debug
+ if pyfile.url.lower().startswith("debug"):
+ self.setWait(30)
+ self.wait()
+ self.decryptCaptcha("http://pyload.org/pie.png")
+ self.download("http://pyload.org/random100.bin")
+ return
#
# if pyfile.url == "79":
# self.core.api.addPackage("test", [str(i) for i in range(80)], 1)
diff --git a/module/utils/__init__.py b/module/utils/__init__.py
index 8f7ed6231..901f553e7 100644
--- a/module/utils/__init__.py
+++ b/module/utils/__init__.py
@@ -9,6 +9,15 @@ from string import maketrans
from itertools import islice
from htmlentitydefs import name2codepoint
+# abstraction layer for json operations
+try: # since python 2.6
+ import json
+except ImportError: #use system simplejson if available
+ import simplejson as json
+
+json_loads = json.loads
+json_dumps = json.dumps
+
def decode(string):
""" decode string with utf if possible """
try:
diff --git a/module/web/static/css/default/dashboard.less b/module/web/static/css/default/dashboard.less
index 865812e41..b1d8326d8 100644
--- a/module/web/static/css/default/dashboard.less
+++ b/module/web/static/css/default/dashboard.less
@@ -260,8 +260,10 @@
}
.bar {
+ text-align: left;
.gradient(top, @yellow, @yellowDark);
- color: @light;
+ color: @dark;
+ padding: 0px 5px;
}
}
diff --git a/module/web/static/css/fontawesome.css b/module/web/static/css/fontawesome.css
index d8cb66237..76d44e089 100644
--- a/module/web/static/css/fontawesome.css
+++ b/module/web/static/css/fontawesome.css
@@ -280,51 +280,52 @@ ul.icons li [class*=" iconf-"] {
.iconf-remove:before { content: "\f02a"; }
.iconf-cog:before { content: "\f02b"; }
.iconf-trash:before { content: "\f02c"; }
-.iconf-repeat:before { content: "\f02d"; }
-.iconf-refresh:before { content: "\f02e"; }
-.iconf-list-alt:before { content: "\f02f"; }
-.iconf-lock:before { content: "\f030"; }
-.iconf-tag:before { content: "\f031"; }
-.iconf-tags:before { content: "\f032"; }
-.iconf-print:before { content: "\f033"; }
-.iconf-list:before { content: "\f034"; }
-.iconf-picture:before { content: "\f035"; }
-.iconf-pencil:before { content: "\f036"; }
-.iconf-edit:before { content: "\f037"; }
-.iconf-share:before { content: "\f038"; }
-.iconf-check:before { content: "\f039"; }
-.iconf-play:before { content: "\f03a"; }
-.iconf-pause:before { content: "\f03b"; }
-.iconf-stop:before { content: "\f03c"; }
-.iconf-eye-open:before { content: "\f03d"; }
-.iconf-eye-close:before { content: "\f03e"; }
-.iconf-bar-chart:before { content: "\f03f"; }
-.iconf-check-empty:before { content: "\f040"; }
-.iconf-globe:before { content: "\f041"; }
-.iconf-tasks:before { content: "\f042"; }
-.iconf-filter:before { content: "\f043"; }
-.iconf-plus-sign:before { content: "\f044"; }
-.iconf-chevron-left:before { content: "\f045"; }
-.iconf-chevron-right:before { content: "\f046"; }
-.iconf-chevron-up:before { content: "\f047"; }
-.iconf-chevron-down:before { content: "\f048"; }
-.iconf-key:before { content: "\f049"; }
-.iconf-cogs:before { content: "\f04a"; }
-.iconf-signout:before { content: "\f04b"; }
-.iconf-signin:before { content: "\f04c"; }
-.iconf-wrench:before { content: "\f04d"; }
-.iconf-inbox:before { content: "\f04e"; }
-.iconf-share:before { content: "\f04f"; }
-.iconf-hdd:before { content: "\f050"; }
-.iconf-group:before { content: "\f051"; }
-.iconf-cloud:before { content: "\f052"; }
-.iconf-save:before { content: "\f053"; }
-.iconf-carret-left:before { content: "\f054"; }
-.iconf-sort-down:before { content: "\f055"; }
-.iconf-sort-up:before { content: "\f056"; }
-.iconf-sitemap:before { content: "\f057"; }
-.iconf-file-alt:before { content: "\f058"; }
-.iconf-folder-open:before { content: "\f059"; }
-.iconf-folder-open-alt:before { content: "\f05a"; }
-.iconf-folder-close:before { content: "\f05b"; }
-.iconf-folder-close-alt:before { content: "\f05c"; }
+.iconf-time:before { content: "\f02d"; }
+.iconf-repeat:before { content: "\f02e"; }
+.iconf-refresh:before { content: "\f02f"; }
+.iconf-list-alt:before { content: "\f030"; }
+.iconf-lock:before { content: "\f031"; }
+.iconf-tag:before { content: "\f032"; }
+.iconf-tags:before { content: "\f033"; }
+.iconf-print:before { content: "\f034"; }
+.iconf-list:before { content: "\f035"; }
+.iconf-picture:before { content: "\f036"; }
+.iconf-pencil:before { content: "\f037"; }
+.iconf-edit:before { content: "\f038"; }
+.iconf-share:before { content: "\f039"; }
+.iconf-check:before { content: "\f03a"; }
+.iconf-play:before { content: "\f03b"; }
+.iconf-pause:before { content: "\f03c"; }
+.iconf-stop:before { content: "\f03d"; }
+.iconf-eye-open:before { content: "\f03e"; }
+.iconf-eye-close:before { content: "\f03f"; }
+.iconf-bar-chart:before { content: "\f040"; }
+.iconf-check-empty:before { content: "\f041"; }
+.iconf-globe:before { content: "\f042"; }
+.iconf-tasks:before { content: "\f043"; }
+.iconf-filter:before { content: "\f044"; }
+.iconf-plus-sign:before { content: "\f045"; }
+.iconf-chevron-left:before { content: "\f046"; }
+.iconf-chevron-right:before { content: "\f047"; }
+.iconf-chevron-up:before { content: "\f048"; }
+.iconf-chevron-down:before { content: "\f049"; }
+.iconf-key:before { content: "\f04a"; }
+.iconf-cogs:before { content: "\f04b"; }
+.iconf-signout:before { content: "\f04c"; }
+.iconf-signin:before { content: "\f04d"; }
+.iconf-wrench:before { content: "\f04e"; }
+.iconf-inbox:before { content: "\f04f"; }
+.iconf-share:before { content: "\f050"; }
+.iconf-hdd:before { content: "\f051"; }
+.iconf-group:before { content: "\f052"; }
+.iconf-cloud:before { content: "\f053"; }
+.iconf-save:before { content: "\f054"; }
+.iconf-carret-left:before { content: "\f055"; }
+.iconf-sort-down:before { content: "\f056"; }
+.iconf-sort-up:before { content: "\f057"; }
+.iconf-sitemap:before { content: "\f058"; }
+.iconf-file-alt:before { content: "\f059"; }
+.iconf-folder-open:before { content: "\f05a"; }
+.iconf-folder-open-alt:before { content: "\f05b"; }
+.iconf-folder-close:before { content: "\f05c"; }
+.iconf-folder-close-alt:before { content: "\f05d"; }
diff --git a/module/web/static/fonts/fontawesome-webfont.eot b/module/web/static/fonts/fontawesome-webfont.eot
index 003be9855..ada4b3415 100644
--- a/module/web/static/fonts/fontawesome-webfont.eot
+++ b/module/web/static/fonts/fontawesome-webfont.eot
Binary files differ
diff --git a/module/web/static/fonts/fontawesome-webfont.ttf b/module/web/static/fonts/fontawesome-webfont.ttf
index 6a4169e81..ac46f999d 100644
--- a/module/web/static/fonts/fontawesome-webfont.ttf
+++ b/module/web/static/fonts/fontawesome-webfont.ttf
Binary files differ
diff --git a/module/web/static/fonts/fontawesome-webfont.woff b/module/web/static/fonts/fontawesome-webfont.woff
index 04af9711a..83239c5d6 100644
--- a/module/web/static/fonts/fontawesome-webfont.woff
+++ b/module/web/static/fonts/fontawesome-webfont.woff
Binary files differ
diff --git a/module/web/static/fonts/fontawesome.txt b/module/web/static/fonts/fontawesome.txt
index 7279cf794..5889ebe1e 100644
--- a/module/web/static/fonts/fontawesome.txt
+++ b/module/web/static/fonts/fontawesome.txt
@@ -12,6 +12,7 @@ ok 00c
remove 00d
cog 013
trash 014
+time 017
repeat 01e
refresh 021
list-alt 022
diff --git a/module/web/static/js/app.js b/module/web/static/js/app.js
index 59ad04fc9..53af4b797 100644
--- a/module/web/static/js/app.js
+++ b/module/web/static/js/app.js
@@ -28,10 +28,21 @@ define([
// Add Global Helper functions
_.extend(Application.prototype, Backbone.Events, {
- apiCall: function(method, args, options) {
+ // Generates options dict that can be used for xhr requests
+ apiRequest: function(method, data, options) {
options || (options = {});
-
-
+ options.url = window.pathPrefix + "/api/" + method;
+ options.dataType = "json";
+ if (data) {
+ options.type = "POST";
+ options.data = {};
+ // Convert arguments to json
+ _.keys(data).map(function(key) {
+ options.data[key] = JSON.stringify(data[key]);
+ });
+ }
+
+ return options;
},
openWebSocket: function(path) {
diff --git a/module/web/static/js/helpers/fileHelper.js b/module/web/static/js/helpers/fileHelper.js
index dde831bdd..ad7c44142 100644
--- a/module/web/static/js/helpers/fileHelper.js
+++ b/module/web/static/js/helpers/fileHelper.js
@@ -1,6 +1,6 @@
// Helpers to render the file view
-define('helpers/fileHelper', ['handlebars', 'utils/apitypes'],
- function(Handlebars, Api) {
+define('helpers/fileHelper', ['handlebars', 'utils/apitypes', 'helpers/formatTime'],
+ function(Handlebars, Api, formatTime) {
function fileClass(file, options) {
if (file.finished)
@@ -36,8 +36,11 @@ define('helpers/fileHelper', ['handlebars', 'utils/apitypes'],
else s += msg;
} else if (file.finished)
s = "<i class='iconf-ok'></i>&nbsp;" + msg;
- else if(file.downloading)
- s= "<div class='progress'><div class='bar' style='width: " + file.progress + "%'></div></div>";
+ else if (file.downloading)
+ s = "<div class='progress'><div class='bar' style='width: " + file.progress + "%'>" +
+ formatTime(file.eta) + "</div></div>";
+ else if (file.waiting)
+ s = "<i class='iconf-time'></i>&nbsp;" + formatTime(file.eta);
else
s = msg;
diff --git a/module/web/static/js/models/File.js b/module/web/static/js/models/File.js
index 22ff231cc..524637cb4 100644
--- a/module/web/static/js/models/File.js
+++ b/module/web/static/js/models/File.js
@@ -1,4 +1,4 @@
-define(['jquery', 'backbone', 'underscore', 'utils/apitypes'], function($, Backbone, _, Api) {
+define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes'], function($, Backbone, _, App, Api) {
var Finished = [Api.DownloadStatus.Finished, Api.DownloadStatus.Skipped];
var Failed = [Api.DownloadStatus.Failed, Api.DownloadStatus.Aborted, Api.DownloadStatus.TempOffline, Api.DownloadStatus.Offline];
@@ -23,34 +23,44 @@ define(['jquery', 'backbone', 'underscore', 'utils/apitypes'], function($, Backb
// UI attributes
selected: false,
visible: true,
- progress: 0
+ progress: 0,
+ eta: 0
},
-
// Model Constructor
initialize: function() {
},
- fetch: function(options){
- options || (options = {});
- options.url = 'api/getFileInfo/' + this.get('fid');
+ fetch: function(options) {
+ options = App.apiRequest(
+ 'getFileInfo',
+ {fid: this.get('fid')},
+ options);
return Backbone.Model.prototype.fetch.call(this, options);
},
destroy: function(options) {
- options || (options = {});
- // TODO: as post data
- options.url = 'api/deleteFiles/[' + this.get('fid') + ']';
- options.type = "post";
+ // also not working when using data
+ options = App.apiRequest(
+ 'deleteFiles/[' + this.get('fid') + ']',
+ null, options);
+ options.method = "post";
return Backbone.Model.prototype.destroy.call(this, options);
},
+ // Does not send a request to the server
+ destroyLocal: function(options) {
+ this.trigger('destroy', this, this.collection, options);
+ },
+
restart: function(options) {
- options || (options = {});
- options.url = 'api/restartFile/' + this.get('fid');
+ options = App.apiRequest(
+ 'restartFile',
+ {fid: this.get('fid')},
+ options);
return $.ajax(options);
},
@@ -60,7 +70,7 @@ define(['jquery', 'backbone', 'underscore', 'utils/apitypes'], function($, Backb
},
- isDownload : function() {
+ isDownload: function() {
return this.has('download');
},
diff --git a/module/web/static/js/models/Package.js b/module/web/static/js/models/Package.js
index ba024381e..0b9efca10 100644
--- a/module/web/static/js/models/Package.js
+++ b/module/web/static/js/models/Package.js
@@ -1,5 +1,5 @@
-define(['jquery', 'backbone', 'underscore', 'collections/FileList', 'require'],
- function($, Backbone, _, FileList, require) {
+define(['jquery', 'backbone', 'underscore', 'app', 'collections/FileList', 'require'],
+ function($, Backbone, _, App, FileList, require) {
return Backbone.Model.extend({
@@ -34,18 +34,20 @@ define(['jquery', 'backbone', 'underscore', 'collections/FileList', 'require'],
// Changes url + method and delegates call to super class
fetch: function(options) {
- options || (options = {});
- options.url = 'api/getFileTree/' + this.get('pid') + '/false';
- options.type = "post";
+ options = App.apiRequest(
+ 'getFileTree/' + this.get('pid'),
+ {full: false},
+ options);
return Backbone.Model.prototype.fetch.call(this, options);
},
// Create a pseudo package und use search to populate data
search: function(qry, options) {
- options || (options = {});
- options.url = 'api/findFiles/"' + qry + '"';
- options.type = "post";
+ options = App.apiRequest(
+ 'findFiles',
+ {pattern: qry},
+ options);
return Backbone.Model.prototype.fetch.call(this, options);
},
@@ -55,18 +57,24 @@ define(['jquery', 'backbone', 'underscore', 'collections/FileList', 'require'],
},
destroy: function(options) {
- options || (options = {});
- // TODO: as post data
- options.url = 'api/deletePackages/[' + this.get('pid') + ']';
- options.type = "post";
+ // TODO: Not working when using data?, array seems to break it
+ options = App.apiRequest(
+ 'deletePackages/[' + this.get('pid') + ']',
+ null, options);
+ options.method = 'post';
+
+ console.log(options);
return Backbone.Model.prototype.destroy.call(this, options);
},
restart: function(options) {
- options || (options = {});
+ options = App.apiRequest(
+ 'restartPackage',
+ {pid: this.get('pid')},
+ options);
+
var self = this;
- options.url = 'api/restartPackage/' + this.get('pid');
options.success = function() {
self.fetch();
};
diff --git a/module/web/static/js/models/Progress.js b/module/web/static/js/models/Progress.js
index d2d54bdb4..87e7b350b 100644
--- a/module/web/static/js/models/Progress.js
+++ b/module/web/static/js/models/Progress.js
@@ -1,4 +1,4 @@
-define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) {
+define(['jquery', 'backbone', 'underscore', 'utils/apitypes'], function($, Backbone, _, Api) {
return Backbone.Model.extend({
@@ -35,6 +35,10 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) {
toJSON: function(options) {
var obj = Backbone.Model.prototype.toJSON.call(this, options);
obj.percent = this.getPercent();
+ if (this.isDownload() && this.get('download').status === Api.DownloadStatus.Downloading)
+ obj.downloading = true;
+ else
+ obj.downloading = false;
return obj;
},
diff --git a/module/web/static/js/models/TreeCollection.js b/module/web/static/js/models/TreeCollection.js
index 7bcc7bd5b..bf14478ce 100644
--- a/module/web/static/js/models/TreeCollection.js
+++ b/module/web/static/js/models/TreeCollection.js
@@ -1,5 +1,5 @@
-define(['jquery', 'backbone', 'underscore', 'models/Package', 'collections/FileList', 'collections/PackageList'],
- function($, Backbone, _, Package, FileList, PackageList) {
+define(['jquery', 'backbone', 'underscore', 'app', 'models/Package', 'collections/FileList', 'collections/PackageList'],
+ function($, Backbone, _, App, Package, FileList, PackageList) {
// TreeCollection
// A Model and not a collection, aggregates other collections
@@ -19,12 +19,12 @@ define(['jquery', 'backbone', 'underscore', 'models/Package', 'collections/FileL
options || (options = {});
var pid = options.pid || -1;
- // TODO: more options possible
- options.url = 'api/getFileTree/' + pid + '/false';
- options.type = "post";
+ options = App.apiRequest(
+ 'getFileTree/' + pid,
+ {full: false},
+ options);
console.log('Fetching package tree ' + pid);
-
return Backbone.Model.prototype.fetch.call(this, options);
},
diff --git a/module/web/static/js/views/fileView.js b/module/web/static/js/views/fileView.js
index 68e8df176..2d5d844c8 100644
--- a/module/web/static/js/views/fileView.js
+++ b/module/web/static/js/views/fileView.js
@@ -9,7 +9,8 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes', 'views/abst
template: _.compile($("#template-file").html()),
events: {
'click .checkbox': 'select',
- 'click .iconf-trash': 'deleteItem'
+ 'click .btn-delete': 'deleteItem',
+ 'click .btn-restart': 'restart'
},
initialize: function() {
@@ -49,9 +50,8 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes', 'views/abst
if (this.model.get('visible'))
this.$el.show();
- else {
+ else
this.$el.hide();
- }
return this;
},
diff --git a/module/web/static/js/views/headerView.js b/module/web/static/js/views/headerView.js
index d9c56b332..49c3aa30e 100644
--- a/module/web/static/js/views/headerView.js
+++ b/module/web/static/js/views/headerView.js
@@ -7,7 +7,7 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'colle
events: {
'click .iconf-list': 'toggle_taskList',
- 'click .popover .close': 'hide_taskList',
+ 'click .popover .close': 'toggle_taskList',
'click .btn-grabber': 'open_grabber'
},
@@ -26,6 +26,9 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'colle
status: null,
progressList: null,
+ // save if last progress was empty
+ wasEmpty: false,
+
initialize: function() {
var self = this;
this.notifications = this.$('#notification-area').calculateHeight().height(0);
@@ -138,10 +141,6 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'colle
this.$('.popover').animate({opacity: 'toggle'});
},
- hide_taskList: function() {
- this.$('.popover').fadeOut();
- },
-
open_grabber: function() {
var self = this;
_.requireOnce(['views/linkGrabberModal'], function(modalView) {
@@ -180,14 +179,26 @@ define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'colle
this.progressList.update(progress);
// update currently open files with progress
this.progressList.each(function(prog) {
- if(prog.isDownload() && App.dashboard.files){
+ if (prog.isDownload() && App.dashboard.files) {
var file = App.dashboard.files.get(prog.get('download').fid);
if (file)
- file.set('progress', prog.getPercent());
+ file.set({
+ progress: prog.getPercent(),
+ eta: prog.get('eta')
+ });
}
});
- // TODO: only render when changed
- this.render();
+
+ if (progress.length === 0) {
+ // only render one time when last was not empty already
+ if (!this.wasEmpty) {
+ this.render();
+ this.wasEmpty = true;
+ }
+ } else {
+ this.wasEmpty = false;
+ this.render();
+ }
},
onEvent: function(event, args) {
diff --git a/module/web/static/js/views/linkGrabberModal.js b/module/web/static/js/views/linkGrabberModal.js
index 71f97f0bf..3d9a886db 100644
--- a/module/web/static/js/views/linkGrabberModal.js
+++ b/module/web/static/js/views/linkGrabberModal.js
@@ -26,23 +26,22 @@ define(['jquery', 'underscore', 'app', 'views/abstract/modalView', 'text!tpl/def
addPackage: function(e) {
var self = this;
- var settings = {
- type: 'POST',
- data: {
- name: JSON.stringify($('#inputPackageName').val()),
- links: JSON.stringify(['http://download.pyload.org/random.bin', 'http://download.pyload.org/random100.bin',
- 'invalid link', 'invalid link 2', 'invalid link 3', 'inavlid link 4',
- 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin', 'http://download.pyload.org/random.bin',
- 'A really really long invalid url that should exceed length of most of the urls by far and split into two lines'])
+ var options = App.apiRequest('addPackage',
+ {
+ name: $('#inputPackageName').val(),
+ // TODO: better parsing / tokenization
+ links: $('#inputLinks').val().split("\n")
},
- success: function() {
- App.vent.trigger('package:added');
- self.hide();
- }
- };
-
- $.ajax('api/addPackage', settings);
+ {
+ success: function() {
+ App.vent.trigger('package:added');
+ self.hide();
+ }
+ });
+
+ $.ajax(options);
$('#inputPackageName').val('');
+ $('#inputLinks').val('');
},
onShow: function() {
diff --git a/module/web/static/js/views/packageView.js b/module/web/static/js/views/packageView.js
index 534fe2ad4..547c1470d 100644
--- a/module/web/static/js/views/packageView.js
+++ b/module/web/static/js/views/packageView.js
@@ -8,9 +8,10 @@ define(['jquery', 'app', 'views/abstract/itemView', 'underscore'],
className: 'package-view',
template: _.compile($("#template-package").html()),
events: {
- 'click .package-name': 'open',
+ 'click .package-name, .btn-open': 'open',
'click .iconf-refresh': 'restart',
- 'click .select': 'select'
+ 'click .select': 'select',
+ 'click .btn-delete': 'deleteItem'
},
// Ul for child packages (unused)
diff --git a/module/web/static/js/views/selectionView.js b/module/web/static/js/views/selectionView.js
index 480b7127b..4f235b2f5 100644
--- a/module/web/static/js/views/selectionView.js
+++ b/module/web/static/js/views/selectionView.js
@@ -30,8 +30,10 @@ define(['jquery', 'backbone', 'underscore', 'app'],
this.actionBar = $('.actionbar .btn-check');
this.actionBar.parent().click(_.bind(this.select_toggle, this));
- // TODO when something gets deleted
-// this.tree.get('packages').on('delete', _.bind(this.render, this));
+
+ // API events, maybe better to rely on internal ones?
+ App.vent.on('package:deleted', render);
+ App.vent.on('file:deleted', render);
},
get_files: function(all) {
@@ -85,23 +87,33 @@ define(['jquery', 'backbone', 'underscore', 'app'],
},
pause: function() {
- _.confirm('default/confirmDialog.html', function() {
- alert("Not implemented yet");
- this.deselect();
- }, this);
+ alert("Not implemented yet");
+ this.deselect();
},
trash: function() {
- // TODO: delete many at once, check if package is parent
- this.get_files().map(function(file) {
- file.destroy();
- });
+ _.confirm('default/confirmDialog.html', function() {
- this.get_packs().map(function(pack) {
- pack.destroy();
- });
+ var pids = [];
+ // TODO: delete many at once
+ this.get_packs().map(function(pack) {
+ pids.push(pack.get('pid'));
+ pack.destroy();
+ });
- this.deselect();
+ // get only the fids of non deleted packages
+ var fids = _.filter(this.get_files(),function(file) {
+ return !_.contains(pids, file.get('package'));
+ }).map(function(file) {
+ file.destroyLocal();
+ return file.get('fid');
+ });
+
+ if (fids.length > 0)
+ $.ajax(App.apiRequest('deleteFiles', {fids: fids}));
+
+ this.deselect();
+ }, this);
},
restart: function() {
diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html
index ebaac59e9..f8dd10c4e 100644
--- a/module/web/templates/default/base.html
+++ b/module/web/templates/default/base.html
@@ -40,7 +40,7 @@
</script>
<script type="text/template" id="template-header">
<%= if downloads %>
- <% downloads %> downloads running (<% formatSize speed %>/s)
+ <% downloads %> downloads running <%= if speed %>(<% formatSize speed %>/s)<%/if%>
<% else %>
No running tasks
<%/if%>
@@ -64,9 +64,13 @@
<div class="progress">
<div class="bar" style="width: <% percent %>%"></div>
</div>
- <% formatSize done %> of <% formatSize total %> (<% formatSize download.speed %>/s)
+ <%= if downloading %>
+ <% formatSize done %> of <% formatSize total %> (<% formatSize download.speed %>/s)
+ <% else %>
+ <% statusmsg %>
+ <%/if%>
<span class="pull-right">
- <% percent %>%
+{# <% percent %>%#}
<% formatTime eta %>
</span>
</script>
diff --git a/module/web/templates/default/dashboard.html b/module/web/templates/default/dashboard.html
index 7fe9c9635..f0756cdfb 100644
--- a/module/web/templates/default/dashboard.html
+++ b/module/web/templates/default/dashboard.html
@@ -38,11 +38,11 @@
<i class="iconf-chevron-down" data-toggle="dropdown">
</i>
<ul class="dropdown-menu" role="menu">
- <li><a href="#"><i class="iconf-folder-open-alt"></i> Open</a></li>
+ <li><a href="#" class="btn-open"><i class="iconf-folder-open-alt"></i> Open</a></li>
<li><a href="#"><i class="iconf-plus-sign"></i> Add links</a></li>
<li><a href="#"><i class="iconf-edit"></i> Details</a></li>
- <li><a href="#"><i class="iconf-trash"></i> Delete</a></li>
- <li><a href="#"><i class="iconf-refresh"></i> Recheck</a></li>
+ <li><a href="#" class="btn-delete"><i class="iconf-trash"></i> Delete</a></li>
+ <li><a href="#" class="btn-recheck"><i class="iconf-refresh"></i> Recheck</a></li>
<li class="divider"></li>
<li class="dropdown-submenu">
<a>Addons</a>
@@ -83,10 +83,10 @@
<% download.plugin %>&nbsp;
<i class="iconf-chevron-down" data-toggle="dropdown"></i>
<ul class="dropdown-menu" role="menu">
- <li><a href="#"><i class="iconf-trash"></i> Delete</a></li>
- <li><a href="#"><i class="iconf-refresh"></i> Restart</a></li>
- <li><a href="#"><i class="iconf-download"></i> Download</a></li>
- <li><a href="#"><i class="iconf-share"></i> Share</a></li>
+ <li><a href="#" class="btn-delete"><i class="iconf-trash"></i> Delete</a></li>
+ <li><a href="#" class="btn-restart"><i class="iconf-refresh"></i> Restart</a></li>
+ <li><a href="#" class="btn-dowload"><i class="iconf-download"></i> Download</a></li>
+ <li><a href="#" class="btn-share"><i class="iconf-share"></i> Share</a></li>
<li class="divider"></li>
<li class="dropdown-submenu pull-left">
<a>Addons</a>