summaryrefslogtreecommitdiffstats
path: root/module/web
diff options
context:
space:
mode:
Diffstat (limited to 'module/web')
-rw-r--r--module/web/api_app.py2
-rw-r--r--module/web/pyload_app.py3
-rw-r--r--module/web/static/css/default/style.less2
-rw-r--r--module/web/static/js/app.js10
-rw-r--r--module/web/static/js/helpers/formatSize.js2
-rw-r--r--module/web/static/js/helpers/formatTime.js40
-rw-r--r--module/web/static/js/models/File.js7
-rw-r--r--module/web/static/js/models/ServerStatus.js41
-rw-r--r--module/web/static/js/utils/initHB.js2
-rw-r--r--module/web/static/js/views/abstract/itemView.js7
-rw-r--r--module/web/static/js/views/dashboardView.js4
-rw-r--r--module/web/static/js/views/fileView.js5
-rw-r--r--module/web/static/js/views/headerView.js229
-rw-r--r--module/web/static/js/views/packageView.js5
-rw-r--r--module/web/static/js/views/selectionView.js7
-rw-r--r--module/web/templates/default/base.html21
-rw-r--r--module/web/templates/default/dashboard.html1
-rw-r--r--module/web/webinterface.py3
18 files changed, 259 insertions, 132 deletions
diff --git a/module/web/api_app.py b/module/web/api_app.py
index 75a817c46..52903e92b 100644
--- a/module/web/api_app.py
+++ b/module/web/api_app.py
@@ -65,6 +65,8 @@ def callApi(api, func, *args, **kwargs):
print "Invalid API call", func
return HTTPError(404, dumps("Not Found"))
+ # TODO: accept same payload as WS backends, combine into json_converter
+ # TODO: arguments as json dictionaries
# TODO: encoding
result = getattr(api, func)(*[loads(x) for x in args],
**dict([(x, loads(y)) for x, y in kwargs.iteritems()]))
diff --git a/module/web/pyload_app.py b/module/web/pyload_app.py
index f8578fcf0..0c3af103f 100644
--- a/module/web/pyload_app.py
+++ b/module/web/pyload_app.py
@@ -44,7 +44,8 @@ def pre_processor():
return {"user": user,
'server': status,
- 'url': request.url }
+ 'url': request.url ,
+ 'ws': PYLOAD.getWSAddress()}
def base(messages):
diff --git a/module/web/static/css/default/style.less b/module/web/static/css/default/style.less
index d3f23478f..260f9fa52 100644
--- a/module/web/static/css/default/style.less
+++ b/module/web/static/css/default/style.less
@@ -422,7 +422,7 @@ footer { // background-color: @greyDark;
background: url("../../img/default/bgpatterndark.png") repeat;
color: @grey;
height: @footer-height;
- margin-top: -@footer-height + 10px;
+ margin-top: -@footer-height;
position: relative;
width: 100%;
line-height: 16px;
diff --git a/module/web/static/js/app.js b/module/web/static/js/app.js
index b081022af..59ad04fc9 100644
--- a/module/web/static/js/app.js
+++ b/module/web/static/js/app.js
@@ -28,10 +28,14 @@ define([
// Add Global Helper functions
_.extend(Application.prototype, Backbone.Events, {
- restartFailed: function(pids, options) {
+ apiCall: function(method, args, options) {
options || (options = {});
- options.url = 'api/restartFailed';
- $.ajax(options);
+
+
+ },
+
+ openWebSocket: function(path) {
+ return new WebSocket(window.wsAddress.replace('%s', window.location.hostname) + path);
}
});
diff --git a/module/web/static/js/helpers/formatSize.js b/module/web/static/js/helpers/formatSize.js
index a792392b7..a50588bc6 100644
--- a/module/web/static/js/helpers/formatSize.js
+++ b/module/web/static/js/helpers/formatSize.js
@@ -2,7 +2,7 @@
define('helpers/formatSize', ['handlebars'], function(Handlebars) {
var sizes = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
function formatSize(bytes, options) {
- if (bytes === 0) return '0 B';
+ if (!bytes || bytes === 0) return '0 B';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
// round to two digits
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
diff --git a/module/web/static/js/helpers/formatTime.js b/module/web/static/js/helpers/formatTime.js
new file mode 100644
index 000000000..cb635ede9
--- /dev/null
+++ b/module/web/static/js/helpers/formatTime.js
@@ -0,0 +1,40 @@
+// Format bytes in human readable format
+define('helpers/formatTime', ['handlebars'], function(Handlebars) {
+
+ // TODO: seconds are language dependant
+ // time could be better formatted
+ function seconds2time (seconds) {
+ var hours = Math.floor(seconds / 3600);
+ var minutes = Math.floor((seconds - (hours * 3600)) / 60);
+ seconds = seconds - (hours * 3600) - (minutes * 60);
+ var time = "";
+
+ if (hours != 0) {
+ time = hours+":";
+ }
+ if (minutes != 0 || time !== "") {
+ minutes = (minutes < 10 && time !== "") ? "0"+minutes : String(minutes);
+ time += minutes+":";
+ }
+ if (time === "") {
+ time = seconds+"s";
+ }
+ else {
+ time += (seconds < 10) ? "0"+seconds : String(seconds);
+ }
+ return time;
+ }
+
+
+ function formatTime(seconds, options) {
+ if (seconds === Infinity)
+ return '∞';
+ else if (!seconds || seconds <= 0)
+ return "-";
+
+ return seconds2time(seconds);
+ }
+
+ Handlebars.registerHelper('formatTime', formatTime);
+ return formatTime;
+}); \ No newline at end of file
diff --git a/module/web/static/js/models/File.js b/module/web/static/js/models/File.js
index 42275a452..fa0945713 100644
--- a/module/web/static/js/models/File.js
+++ b/module/web/static/js/models/File.js
@@ -31,8 +31,13 @@ define(['jquery', 'backbone', 'underscore', 'utils/apitypes'], function($, Backb
},
- destroy: function() {
+ destroy: function(options) {
+ options || (options = {});
+ // TODO: as post data
+ options.url = 'api/deleteFiles/[' + this.get('fid') + ']';
+ options.type = "post";
+ return Backbone.Model.prototype.destroy.call(this, options);
},
restart: function(options) {
diff --git a/module/web/static/js/models/ServerStatus.js b/module/web/static/js/models/ServerStatus.js
index 35257fcb1..2430a9ffd 100644
--- a/module/web/static/js/models/ServerStatus.js
+++ b/module/web/static/js/models/ServerStatus.js
@@ -1,15 +1,15 @@
-define(['jquery', 'backbone', 'underscore', 'collections/ProgressList'],
- function($, Backbone, _, ProgressList) {
+define(['jquery', 'backbone', 'underscore'],
+ function($, Backbone, _) {
return Backbone.Model.extend({
defaults: {
- queuedDownloads: -1,
- totalDownloads: -1,
- speed: -1,
- pause: false,
+ speed: 0,
+ files: null,
+ notifications: -1,
+ paused: false,
download: false,
- reconnect: false,
+ reconnect: false
},
// Model Constructor
@@ -24,16 +24,23 @@ define(['jquery', 'backbone', 'underscore', 'collections/ProgressList'],
return Backbone.Model.prototype.fetch.call(this, options);
},
- parse: function(resp, xhr) {
- // Package is loaded from tree collection
- if (_.has(resp, 'root')) {
- resp.root.files = new FileList(_.values(resp.files));
- // circular dependencies needs to be avoided
- var PackageList = require('collections/PackageList');
- resp.root.packs = new PackageList(_.values(resp.packages));
- return resp.root;
- }
- return Backbone.model.prototype.fetch.call(this, resp, xhr);
+ toJSON: function(options) {
+ var obj = Backbone.Model.prototype.toJSON.call(this, options);
+
+ // stats are not available
+ if (obj.files === null)
+ return obj;
+
+ obj.files.linksleft = obj.files.linkstotal - obj.files.linksdone;
+ obj.files.sizeleft = obj.files.sizetotal - obj.files.sizedone;
+ if (obj.speed && obj.speed > 0)
+ obj.files.eta = Math.round(obj.files.sizeleft / obj.speed);
+ else if (obj.files.sizeleft > 0)
+ obj.files.eta = Infinity;
+ else
+ obj.files.eta = 0;
+
+ return obj;
}
});
diff --git a/module/web/static/js/utils/initHB.js b/module/web/static/js/utils/initHB.js
index f3a0955b3..c977f063d 100644
--- a/module/web/static/js/utils/initHB.js
+++ b/module/web/static/js/utils/initHB.js
@@ -1,6 +1,6 @@
// Loads all helper and set own handlebars rules
define(['underscore', 'handlebars',
- 'helpers/formatSize', 'helpers/fileHelper'],
+ 'helpers/formatSize', 'helpers/fileHelper', 'helpers/formatTime'],
function(_, Handlebars) {
// Replace with own lexer rules compiled from handlebars.l
Handlebars.Parser.lexer.rules = [/^(?:[^\x00]*?(?=(<%)))/, /^(?:[^\x00]+)/, /^(?:[^\x00]{2,}?(?=(\{\{|$)))/, /^(?:\{\{>)/, /^(?:<%=)/, /^(?:<%\/)/, /^(?:\{\{\^)/, /^(?:<%\s*else\b)/, /^(?:\{<%%)/, /^(?:\{\{&)/, /^(?:<%![\s\S]*?%>)/, /^(?:<%)/, /^(?:=)/, /^(?:\.(?=[%} ]))/, /^(?:\.\.)/, /^(?:[\/.])/, /^(?:\s+)/, /^(?:%%>)/, /^(?:%>)/, /^(?:"(\\["]|[^"])*")/, /^(?:'(\\[']|[^'])*')/, /^(?:@[a-zA-Z]+)/, /^(?:true(?=[%}\s]))/, /^(?:false(?=[%}\s]))/, /^(?:[0-9]+(?=[%}\s]))/, /^(?:[a-zA-Z0-9_$-]+(?=[=%}\s\/.]))/, /^(?:\[[^\]]*\])/, /^(?:.)/, /^(?:$)/];
diff --git a/module/web/static/js/views/abstract/itemView.js b/module/web/static/js/views/abstract/itemView.js
index 75b058874..394044ec4 100644
--- a/module/web/static/js/views/abstract/itemView.js
+++ b/module/web/static/js/views/abstract/itemView.js
@@ -23,6 +23,13 @@ define(['jquery', 'backbone', 'underscore'], function($, Backbone, _) {
this.$el.slideDown();
},
+ unrender: function() {
+ var self = this;
+ this.$el.slideUp(function() {
+ self.destroy();
+ });
+ },
+
deleteItem: function(e) {
if (e)
e.stopPropagation();
diff --git a/module/web/static/js/views/dashboardView.js b/module/web/static/js/views/dashboardView.js
index d9ea8d444..d9ff1c5fc 100644
--- a/module/web/static/js/views/dashboardView.js
+++ b/module/web/static/js/views/dashboardView.js
@@ -1,5 +1,5 @@
define(['jquery', 'backbone', 'underscore', 'app', 'models/TreeCollection',
- 'views/packageView', 'views/fileView', 'views/selectionView', 'views/filterView'],
+ 'views/packageView', 'views/fileView', 'views/selectionView', 'views/filterView', 'select2'],
function($, Backbone, _, App, TreeCollection, packageView, fileView, selectionView, filterView) {
// Renders whole dashboard
@@ -51,6 +51,8 @@ define(['jquery', 'backbone', 'underscore', 'app', 'models/TreeCollection',
});
}});
+
+ this.$('.input').select2({tags: ["a", "b", "sdf"]});
},
render: function() {
diff --git a/module/web/static/js/views/fileView.js b/module/web/static/js/views/fileView.js
index 17da74de3..2459b6cd6 100644
--- a/module/web/static/js/views/fileView.js
+++ b/module/web/static/js/views/fileView.js
@@ -9,14 +9,15 @@ define(['jquery', 'backbone', 'underscore', 'app', 'utils/apitypes', 'views/abst
// template: _.template($("#template-file").html()),
template: _.compile($("#template-file").html()),
events: {
- 'click .checkbox': 'select'
+ 'click .checkbox': 'select',
+ 'click .iconf-trash': 'deleteItem'
},
initialize: function() {
this.listenTo(this.model, 'change', this.render);
// This will be triggered manually and changed before with silent=true
this.listenTo(this.model, 'change:visible', this.visibility_changed);
- this.listenTo(this.model, 'remove', this.destroy);
+ this.listenTo(this.model, 'remove', this.unrender);
this.listenTo(App.vent, 'dashboard:destroyContent', this.destroy);
},
diff --git a/module/web/static/js/views/headerView.js b/module/web/static/js/views/headerView.js
index cfceca6cd..c22f173c4 100644
--- a/module/web/static/js/views/headerView.js
+++ b/module/web/static/js/views/headerView.js
@@ -1,102 +1,153 @@
-define(['jquery', 'underscore', 'backbone', 'flot'], function($, _, Backbone) {
- // Renders the header with all information
- return Backbone.View.extend({
-
- el: 'header',
-
- events: {
- 'click i.iconf-list': 'toggle_taskList',
- 'click .popover .close': 'hide_taskList',
- 'click .btn-grabber': 'open_grabber'
- },
-
- // Will hold the link grabber
- grabber: null,
- notifications: null,
- selections: null,
-
- initialize: function() {
-
- this.notifications = this.$('#notification-area').calculateHeight().height(0);
- this.selections = this.$('#selection-area').calculateHeight().height(0);
-
- var totalPoints = 100;
- var data = [];
-
- function getRandomData() {
- if (data.length > 0)
- data = data.slice(1);
-
- // do a random walk
- while (data.length < totalPoints) {
- var prev = data.length > 0 ? data[data.length - 1] : 50;
- var y = prev + Math.random() * 10 - 5;
- if (y < 0)
- y = 0;
- if (y > 100)
- y = 100;
- data.push(y);
+define(['jquery', 'underscore', 'backbone', 'app', 'models/ServerStatus', 'flot'],
+ function($, _, Backbone, App, ServerStatus) {
+ // Renders the header with all information
+ return Backbone.View.extend({
+
+ el: 'header',
+
+ events: {
+ 'click i.iconf-list': 'toggle_taskList',
+ 'click .popover .close': 'hide_taskList',
+ 'click .btn-grabber': 'open_grabber'
+ },
+
+ templateStatus: _.compile($('#template-header-status').html()),
+
+ // Will hold the link grabber
+ grabber: null,
+ notifications: null,
+ ws: null,
+
+ // Status model
+ status: null,
+
+ initialize: function() {
+ this.notifications = this.$('#notification-area').calculateHeight().height(0);
+
+ this.status = new ServerStatus();
+ this.listenTo(this.status, 'change', this.render);
+
+ // TODO: button to start stop refresh
+ var ws = App.openWebSocket('/async');
+ ws.onopen = function() {
+ ws.send(JSON.stringify('start'));
+ };
+ // TODO compare with polling
+ ws.onmessage = _.bind(this.onData, this);
+
+ this.ws = ws;
+
+ this.initGraph();
+ },
+
+ initGraph: function() {
+ var totalPoints = 100;
+ var data = [];
+
+ function getRandomData() {
+ if (data.length > 0)
+ data = data.slice(1);
+
+ // do a random walk
+ while (data.length < totalPoints) {
+ var prev = data.length > 0 ? data[data.length - 1] : 50;
+ var y = prev + Math.random() * 10 - 5;
+ if (y < 0)
+ y = 0;
+ if (y > 100)
+ y = 100;
+ data.push(y);
+ }
+
+ // zip the generated y values with the x values
+ var res = [];
+ for (var i = 0; i < data.length; ++i)
+ res.push([i, data[i]])
+ return res;
}
- // zip the generated y values with the x values
- var res = [];
- for (var i = 0; i < data.length; ++i)
- res.push([i, data[i]])
- return res;
- }
-
- var updateInterval = 1500;
-
- var speedgraph = $.plot(this.$el.find("#speedgraph"), [getRandomData()], {
- series: {
- lines: { show: true, lineWidth: 2 },
- shadowSize: 0,
- color: "#fee247"
- },
- xaxis: { ticks: [], mode: "time" },
- yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
- grid: {
- show: true,
+ var updateInterval = 1500;
+
+ var speedgraph = $.plot(this.$el.find("#speedgraph"), [getRandomData()], {
+ series: {
+ lines: { show: true, lineWidth: 2 },
+ shadowSize: 0,
+ color: "#fee247"
+ },
+ xaxis: { ticks: [], mode: "time" },
+ yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
+ grid: {
+ show: true,
// borderColor: "#757575",
- borderColor: "white",
- borderWidth: 1,
- labelMargin: 0,
- axisMargin: 0,
- minBorderMargin: 0
+ borderColor: "white",
+ borderWidth: 1,
+ labelMargin: 0,
+ axisMargin: 0,
+ minBorderMargin: 0
+ }
+ });
+
+ function update() {
+ speedgraph.setData([ getRandomData() ]);
+ // since the axes don't change, we don't need to call plot.setupGrid()
+ speedgraph.draw();
+
+ setTimeout(update, updateInterval);
}
- });
- function update() {
- speedgraph.setData([ getRandomData() ]);
- // since the axes don't change, we don't need to call plot.setupGrid()
- speedgraph.draw();
+// update();
- setTimeout(update, updateInterval);
- }
+ },
+
+ render: function() {
+// console.log('Render header');
+
+ this.$('.status-block').html(
+ this.templateStatus(this.status.toJSON())
+ );
+ },
+
+ toggle_taskList: function() {
+ this.$('.popover').animate({opacity: 'toggle'});
+ },
- update();
+ hide_taskList: function() {
+ this.$('.popover').fadeOut();
+ },
- },
+ open_grabber: function() {
+ var self = this;
+ _.requireOnce(['views/linkGrabberModal'], function(modalView) {
+ if (self.grabber === null)
+ self.grabber = new modalView();
- render: function() {
- },
+ self.grabber.show();
+ });
+ },
- toggle_taskList: function() {
- this.$('.popover').animate({opacity: 'toggle'});
- },
+ onData: function(evt) {
+ var data = JSON.parse(evt.data);
+ if (data === null) return;
- hide_taskList: function() {
- this.$('.popover').fadeOut();
- },
+ if (data['@class'] === "ServerStatus") {
+ this.status.set(data);
+ }
+ else if (data['@class'] === 'progress')
+ this.onProgressUpdate(data);
+ else if (data['@class'] === 'event')
+ this.onEvent(data);
+ else
+ console.log('Unknown Async input');
+
+ },
+
+ onProgressUpdate: function(progress) {
- open_grabber: function() {
- var self = this;
- _.requireOnce(['views/linkGrabberModal'], function(modalView) {
- if (self.grabber === null)
- self.grabber = new modalView();
+ },
+
+ onEvent: function(event) {
+
+ }
- self.grabber.show();
- });
- }
- });
-}); \ No newline at end of file
+ });
+ }); \ No newline at end of file
diff --git a/module/web/static/js/views/packageView.js b/module/web/static/js/views/packageView.js
index cfd671611..534fe2ad4 100644
--- a/module/web/static/js/views/packageView.js
+++ b/module/web/static/js/views/packageView.js
@@ -43,10 +43,7 @@ define(['jquery', 'app', 'views/abstract/itemView', 'underscore'],
},
unrender: function() {
- var self = this;
- this.$el.slideUp(function() {
- self.destroy();
- });
+ itemView.prototype.unrender.apply(this);
// TODO: display other package
App.vent.trigger('dashboard:loading', null);
diff --git a/module/web/static/js/views/selectionView.js b/module/web/static/js/views/selectionView.js
index 2237c5f92..480b7127b 100644
--- a/module/web/static/js/views/selectionView.js
+++ b/module/web/static/js/views/selectionView.js
@@ -19,6 +19,8 @@ define(['jquery', 'backbone', 'underscore', 'app'],
current: 0,
initialize: function() {
+ this.$el.calculateHeight().height(0);
+
var render = _.bind(this.render, this);
App.vent.on('dashboard:updated', render);
@@ -69,8 +71,8 @@ define(['jquery', 'backbone', 'underscore', 'app'],
this.current = files + packs;
},
- // Deselects all items, optional only files
- deselect: function(filesOnly) {
+ // Deselects all items
+ deselect: function() {
this.get_files().map(function(file) {
file.set('selected', false);
});
@@ -90,6 +92,7 @@ define(['jquery', 'backbone', 'underscore', 'app'],
},
trash: function() {
+ // TODO: delete many at once, check if package is parent
this.get_files().map(function(file) {
file.destroy();
});
diff --git a/module/web/templates/default/base.html b/module/web/templates/default/base.html
index 621059c8c..e8661cbbc 100644
--- a/module/web/templates/default/base.html
+++ b/module/web/templates/default/base.html
@@ -21,6 +21,9 @@
<script src="/static/js/libs/less-1.3.0.min.js" type="text/javascript"></script>
<script type="text/javascript" data-main="static/js/config" src="/static/js/libs/require-2.1.5.js"></script>
<script>
+ window.wsAddress = "{{ ws }}";
+ window.pathPrefix = ""; // TODO
+
require(['default'], function(App) {
App.init();
{% block require %}
@@ -28,6 +31,13 @@
});
</script>
+ <script type="text/template" id="template-header-status">
+ <span class="pull-right eta"><% formatTime files.eta %></span><br>
+ <span class="pull-right remeaning"><% formatSize files.sizeleft %></span><br>
+ <span class="pull-right"><span
+ style="font-weight:bold;color: #fff !important;"><% files.linksleft %></span> of <% files.linkstotal %></span>
+ </script>
+
{% block head %}
{% endblock %}
</head>
@@ -67,16 +77,11 @@
<div id="speedgraph" class="visible-desktop"></div>
- <div class="header_block right-border">
- <span class="pull-right">8:15:01</span><br>
- <span class="pull-right">Started</span><br>
- <span class="pull-right"><span
- style="font-weight:bold;color: #fff !important;">5</span> of 12</span>
-
+ <div class="header_block right-border status-block">
</div>
<div class="header_block left-border">
- <i class="icon-time icon-white"></i> Remaining:<br>
- <i class="icon-retweet icon-white"></i> Status:<br>
+ <i class="icon-time icon-white"></i> approx. ETA :<br>
+ <i class=" icon-hdd icon-white"></i> Remeaning:<br>
<i class="icon-download-alt icon-white"></i> Downloads: <br>
</div>
diff --git a/module/web/templates/default/dashboard.html b/module/web/templates/default/dashboard.html
index 8c20973e4..7fe9c9635 100644
--- a/module/web/templates/default/dashboard.html
+++ b/module/web/templates/default/dashboard.html
@@ -177,6 +177,7 @@
<div class="sidebar-header">
<i class="iconf-hdd"></i> Local
<div class="pull-right" style="font-size: medium; line-height: normal">
+{# <input type="text" class="input">#}
<i class="iconf-chevron-down" style="font-size: 20px"></i>
</div>
<div class="clearfix"></div>
diff --git a/module/web/webinterface.py b/module/web/webinterface.py
index cec0f24a4..f18157cd7 100644
--- a/module/web/webinterface.py
+++ b/module/web/webinterface.py
@@ -113,7 +113,8 @@ session_opts = {
'session.auto': False
}
-web = StripPathMiddleware(SessionMiddleware(app(), session_opts))
+session = SessionMiddleware(app(), session_opts)
+web = StripPathMiddleware(session)
web = GZipMiddleWare(web)
if PREFIX: