diff --git a/src/_h5ai/config.js b/src/_h5ai/config.js index 92710955..bb64c0fa 100644 --- a/src/_h5ai/config.js +++ b/src/_h5ai/config.js @@ -51,6 +51,18 @@ var H5AI_CONFIG = { * Extensions in alphabetical order. */ + /* + * Watch current folder content. + * Folders possibly visible in the tree view that are not the + * current folder might not be updated. + * + * Interval will be a least 1000 milliseconds. + */ + "autoupdate": { + "enabled": true, + "interval": 5000 + }, + /* * Show a clickable breadcrumb. */ diff --git a/src/_h5ai/js/inc/core/event.js b/src/_h5ai/js/inc/core/event.js index 81ce4284..c6cb387a 100644 --- a/src/_h5ai/js/inc/core/event.js +++ b/src/_h5ai/js/inc/core/event.js @@ -13,7 +13,7 @@ modulejs.define('core/event', ['amplify'], function (amplify) { pub = function (topic, data) { - // console.log('EVENT PUB', topic, data); + console.log('EVENT PUB', topic, data); amplify.publish(topic, data); }; diff --git a/src/_h5ai/js/inc/ext/autoupdate.js b/src/_h5ai/js/inc/ext/autoupdate.js new file mode 100644 index 00000000..d8f837bb --- /dev/null +++ b/src/_h5ai/js/inc/ext/autoupdate.js @@ -0,0 +1,64 @@ + +modulejs.define('ext/autoupdate', ['_', '$', 'core/settings', 'core/event', 'core/resource', 'model/entry'], function (_, $, allsettings, event, resource, Entry) { + + var defaults = { + enabled: false, + interval: 5000 + }, + + settings = _.extend({}, defaults, allsettings.autoupdate), + + parseJson = function (entry, json) { + + var found = {}; + + _.each(json.entries, function (jsonEntry) { + + found[jsonEntry.absHref] = true; + Entry.get(jsonEntry.absHref, jsonEntry.time, jsonEntry.size, jsonEntry.status, jsonEntry.content); + }); + + _.each(entry.content, function (e) { + if (!found[e.absHref]) { + Entry.remove(e.absHref); + } + }); + }, + + heartbeat = function () { + + var entry = Entry.get(); + + $.ajax({ + url: resource.api(), + data: { + action: 'getentries', + href: entry.absHref, + content: 1 + }, + dataType: 'json', + success: function (json) { + + parseJson(entry, json); + } + }); + + setTimeout(heartbeat, settings.interval); + }, + + init = function () { + + if (!settings.enabled) { + return; + } + + settings.interval = Math.max(1000, settings.interval); + + event.sub('ready', function () { + + setTimeout(heartbeat, settings.interval); + }); + }; + + init(); +}); diff --git a/src/_h5ai/js/inc/ext/crumb.js b/src/_h5ai/js/inc/ext/crumb.js index 07d8ebcb..859154b0 100644 --- a/src/_h5ai/js/inc/ext/crumb.js +++ b/src/_h5ai/js/inc/ext/crumb.js @@ -1,5 +1,5 @@ -modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/entry'], function (_, $, allsettings, resource, entry) { +modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/entry'], function (_, $, allsettings, resource, event, entry) { var defaults = { enabled: false @@ -17,9 +17,9 @@ modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/ statusHintTemplate = '', // updates the crumb for this single entry - update = function (entry) { + update = function (entry, force) { - if (entry.$crumb && entry.$crumb.data('status') === entry.status) { + if (!force && entry.$crumb && entry.$crumb.data('status') === entry.status) { return entry.$crumb; } @@ -59,6 +59,13 @@ modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/ return $html; }, + onContentChanged = function (entry) { + + if (entry.$crumb) { + update(entry, true); + } + }, + // creates the complete crumb from entry down to the root init = function (entry) { @@ -78,6 +85,10 @@ modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/ update(e); }); }); + + event.sub('entry.created', onContentChanged); + event.sub('entry.removed', onContentChanged); + event.sub('entry.changed', onContentChanged); }; init(entry); diff --git a/src/_h5ai/js/inc/ext/sort.js b/src/_h5ai/js/inc/ext/sort.js index 1272bb39..35c0a253 100644 --- a/src/_h5ai/js/inc/ext/sort.js +++ b/src/_h5ai/js/inc/ext/sort.js @@ -1,5 +1,5 @@ -modulejs.define('ext/sort', ['_', '$', 'core/settings', 'core/resource', 'core/store'], function (_, $, allsettings, resource, store) { +modulejs.define('ext/sort', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/store'], function (_, $, allsettings, resource, event, store) { var defaults = { enabled: false, @@ -70,6 +70,11 @@ modulejs.define('ext/sort', ['_', '$', 'core/settings', 'core/resource', 'core/s $('#extended .entry').detach().sort(order.fn).appendTo('#extended > ul'); }, + onContentChanged = function (entry) { + + sortBy(store.get(storekey) || settings.order); + }, + init = function () { if (!settings.enabled) { @@ -139,6 +144,9 @@ modulejs.define('ext/sort', ['_', '$', 'core/settings', 'core/resource', 'core/s sortBy('s' + ($size.hasClass('ascending') ? 'd' : 'a')); event.preventDefault(); }); + + event.sub('entry.changed', onContentChanged); + event.sub('entry.created', onContentChanged); }; init(); diff --git a/src/_h5ai/js/inc/ext/statusbar.js b/src/_h5ai/js/inc/ext/statusbar.js index 112703c3..446eb241 100644 --- a/src/_h5ai/js/inc/ext/statusbar.js +++ b/src/_h5ai/js/inc/ext/statusbar.js @@ -53,7 +53,19 @@ modulejs.define('ext/statusbar', ['_', '$', 'core/settings', 'core/format', 'cor event.sub('statusbar', update); $('#bottombar > .center').append($statusbar); + event.sub('entry.created', function () { + var stats = entry.getStats(); + $folderTotal.text(stats.folders); + $fileTotal.text(stats.files); + }); + + event.sub('entry.removed', function () { + + var stats = entry.getStats(); + $folderTotal.text(stats.folders); + $fileTotal.text(stats.files); + }); event.sub('entry.mouseenter', function (entry) { diff --git a/src/_h5ai/js/inc/ext/tree.js b/src/_h5ai/js/inc/ext/tree.js index 9ea16a40..0d01fcb0 100644 --- a/src/_h5ai/js/inc/ext/tree.js +++ b/src/_h5ai/js/inc/ext/tree.js @@ -186,6 +186,15 @@ modulejs.define('ext/tree', ['_', '$', 'core/settings', 'core/resource', 'core/e $tree.scrollpanel('update'); }, + onContentChanged = function (entry) { + + while (entry.parent) { + entry = entry.parent; + } + + update(entry); + }, + // creates the complete tree from entry down to the root init = function (entry, parser) { @@ -217,6 +226,9 @@ modulejs.define('ext/tree', ['_', '$', 'core/settings', 'core/resource', 'core/e }); event.sub('ready', adjustSpacing); + event.sub('entry.changed', onContentChanged); + event.sub('entry.created', onContentChanged); + event.sub('entry.removed', onContentChanged); $(window).on('resize', function () { diff --git a/src/_h5ai/js/inc/main.js b/src/_h5ai/js/inc/main.js index feacef09..e192f2db 100644 --- a/src/_h5ai/js/inc/main.js +++ b/src/_h5ai/js/inc/main.js @@ -23,6 +23,7 @@ // @include "view/spacing.js" // @include "view/viewmode.js" + // @include "ext/autoupdate.js" // @include "ext/crumb.js" // @include "ext/custom.js" // @include "ext/download.js" diff --git a/src/_h5ai/js/inc/model/entry.js b/src/_h5ai/js/inc/model/entry.js index 4e6539a4..954a3dfb 100644 --- a/src/_h5ai/js/inc/model/entry.js +++ b/src/_h5ai/js/inc/model/entry.js @@ -1,5 +1,5 @@ -modulejs.define('model/entry', ['_', 'core/types', 'core/ajax'], function (_, types, ajax) { +modulejs.define('model/entry', ['_', 'core/types', 'core/ajax', 'core/event'], function (_, types, ajax, event) { var doc = document, domain = doc.domain, @@ -111,24 +111,62 @@ modulejs.define('model/entry', ['_', 'core/types', 'core/ajax'], function (_, ty absHref = forceEncoding(absHref || location); + var created = !cache[absHref], + changed = false; + var self = cache[absHref] || new Entry(absHref); if (_.isNumber(time)) { + if (self.time !== time) { + changed = true; + } self.time = time; } if (_.isNumber(size)) { + if (self.size !== size) { + changed = true; + } self.size = size; } if (status) { + if (self.status !== status) { + changed = true; + } self.status = status; } if (isContentFetched) { self.isContentFetched = true; } + if (created) { + event.pub('entry.created', self); + } else if (changed) { + event.pub('entry.changed', self); + } + return self; }, + removeEntry = function (absHref) { + + absHref = forceEncoding(absHref || location); + + var self = cache[absHref]; + + if (self) { + delete cache[absHref]; + if (self.parent) { + delete self.parent.content[self.absHref]; + } + _.each(self.content, function (entry) { + + removeEntry(entry.absHref); + }); + + event.pub('entry.removed', self); + } + }, + fetchStatus = function (absHref, callback) { var self = getEntry(absHref); @@ -202,6 +240,11 @@ modulejs.define('model/entry', ['_', 'core/types', 'core/ajax'], function (_, ty return this.absHref === location; }, + isInCurrentFolder: function () { + + return !!this.parent && this.parent.isCurrentFolder(); + }, + isDomain: function () { return this.absHref === '/'; @@ -276,9 +319,8 @@ modulejs.define('model/entry', ['_', 'core/types', 'core/ajax'], function (_, ty } }); - - - return { - get: getEntry + return window.ENTRY = { + get: getEntry, + remove: removeEntry }; }); diff --git a/src/_h5ai/js/inc/view/extended.js b/src/_h5ai/js/inc/view/extended.js index 8690f6b5..5f561c2f 100644 --- a/src/_h5ai/js/inc/view/extended.js +++ b/src/_h5ai/js/inc/view/extended.js @@ -29,9 +29,9 @@ modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'c emptyTemplate = '