diff options
Diffstat (limited to 'module/web')
-rw-r--r-- | module/web/api_app.py | 2 | ||||
-rw-r--r-- | module/web/pyload_app.py | 3 | ||||
-rw-r--r-- | module/web/static/css/default/style.less | 2 | ||||
-rw-r--r-- | module/web/static/js/app.js | 10 | ||||
-rw-r--r-- | module/web/static/js/helpers/formatSize.js | 2 | ||||
-rw-r--r-- | module/web/static/js/helpers/formatTime.js | 40 | ||||
-rw-r--r-- | module/web/static/js/models/File.js | 7 | ||||
-rw-r--r-- | module/web/static/js/models/ServerStatus.js | 41 | ||||
-rw-r--r-- | module/web/static/js/utils/initHB.js | 2 | ||||
-rw-r--r-- | module/web/static/js/views/abstract/itemView.js | 7 | ||||
-rw-r--r-- | module/web/static/js/views/dashboardView.js | 4 | ||||
-rw-r--r-- | module/web/static/js/views/fileView.js | 5 | ||||
-rw-r--r-- | module/web/static/js/views/headerView.js | 229 | ||||
-rw-r--r-- | module/web/static/js/views/packageView.js | 5 | ||||
-rw-r--r-- | module/web/static/js/views/selectionView.js | 7 | ||||
-rw-r--r-- | module/web/templates/default/base.html | 21 | ||||
-rw-r--r-- | module/web/templates/default/dashboard.html | 1 | ||||
-rw-r--r-- | module/web/webinterface.py | 3 |
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:
|