diff options
Diffstat (limited to 'module/web/static')
-rw-r--r-- | module/web/static/css/default/dashboard.less | 4 | ||||
-rw-r--r-- | module/web/static/css/fontawesome.css | 97 | ||||
-rw-r--r-- | module/web/static/fonts/fontawesome-webfont.eot | bin | 30762 -> 30955 bytes | |||
-rw-r--r-- | module/web/static/fonts/fontawesome-webfont.ttf | bin | 14904 -> 15080 bytes | |||
-rw-r--r-- | module/web/static/fonts/fontawesome-webfont.woff | bin | 22220 -> 22368 bytes | |||
-rw-r--r-- | module/web/static/fonts/fontawesome.txt | 1 | ||||
-rw-r--r-- | module/web/static/js/app.js | 17 | ||||
-rw-r--r-- | module/web/static/js/helpers/fileHelper.js | 11 | ||||
-rw-r--r-- | module/web/static/js/models/File.js | 36 | ||||
-rw-r--r-- | module/web/static/js/models/Package.js | 36 | ||||
-rw-r--r-- | module/web/static/js/models/Progress.js | 6 | ||||
-rw-r--r-- | module/web/static/js/models/TreeCollection.js | 12 | ||||
-rw-r--r-- | module/web/static/js/views/fileView.js | 6 | ||||
-rw-r--r-- | module/web/static/js/views/headerView.js | 29 | ||||
-rw-r--r-- | module/web/static/js/views/linkGrabberModal.js | 29 | ||||
-rw-r--r-- | module/web/static/js/views/packageView.js | 5 | ||||
-rw-r--r-- | module/web/static/js/views/selectionView.js | 40 |
17 files changed, 196 insertions, 133 deletions
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 Binary files differindex 003be9855..ada4b3415 100644 --- a/module/web/static/fonts/fontawesome-webfont.eot +++ b/module/web/static/fonts/fontawesome-webfont.eot diff --git a/module/web/static/fonts/fontawesome-webfont.ttf b/module/web/static/fonts/fontawesome-webfont.ttf Binary files differindex 6a4169e81..ac46f999d 100644 --- a/module/web/static/fonts/fontawesome-webfont.ttf +++ b/module/web/static/fonts/fontawesome-webfont.ttf diff --git a/module/web/static/fonts/fontawesome-webfont.woff b/module/web/static/fonts/fontawesome-webfont.woff Binary files differindex 04af9711a..83239c5d6 100644 --- a/module/web/static/fonts/fontawesome-webfont.woff +++ b/module/web/static/fonts/fontawesome-webfont.woff 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> " + 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> " + 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() { |