diff --git a/clientapp/app.js b/clientapp/app.js
index 9ba5029..b3945a1 100644
--- a/clientapp/app.js
+++ b/clientapp/app.js
@@ -14,6 +14,7 @@ var Storage = require('./storage');
var xmppEventHandlers = require('./helpers/xmppEventHandlers');
var Notify = require('notify.js');
var Desktop = require('./helpers/desktop');
+var AppCache = require('./helpers/cache');
module.exports = {
@@ -38,6 +39,7 @@ module.exports = {
function (cb) {
app.notifications = new Notify();
app.desktop = new Desktop();
+ app.cache = new AppCache();
app.storage = new Storage();
app.storage.open(cb);
},
diff --git a/clientapp/helpers/cache.js b/clientapp/helpers/cache.js
new file mode 100644
index 0000000..2afd0fe
--- /dev/null
+++ b/clientapp/helpers/cache.js
@@ -0,0 +1,50 @@
+var WildEmitter = require('wildemitter');
+var STATES = [
+ 'uncached',
+ 'idle',
+ 'checking',
+ 'downloading',
+ 'updateReady',
+ 'obsolete'
+];
+
+function AppCache() {
+ WildEmitter.call(this);
+
+ var self = this;
+ this.cache = window.applicationCache;
+ this.state = STATES[this.cache.status];
+ this.emit('change', this.state);
+
+ function mapevent(name, altName) {
+ self.cache.addEventListener(name, function (e) {
+ var newState = STATES[self.cache.status];
+ if (newState !== self.state) {
+ self.state = newState;
+ self.emit('change', newState);
+ }
+ self.emit(altName || name, e);
+ }, false);
+ }
+ mapevent('cached');
+ mapevent('checking');
+ mapevent('downloading');
+ mapevent('error');
+ mapevent('noupdate', 'noUpdate');
+ mapevent('obsolete');
+ mapevent('progress');
+ mapevent('updateready', 'updateReady');
+}
+
+AppCache.prototype = Object.create(WildEmitter.prototype, {
+ constructor: {
+ value: AppCache
+ }
+});
+
+AppCache.prototype.update = function () {
+ this.cache.update();
+};
+
+
+module.exports = AppCache;
diff --git a/clientapp/models/state.js b/clientapp/models/state.js
index fbb4e2b..907ac18 100644
--- a/clientapp/models/state.js
+++ b/clientapp/models/state.js
@@ -23,6 +23,11 @@ module.exports = HumanModel.define({
self.markInactive();
});
+ self.cacheStatus = app.cache.state;
+ app.cache.on('change', function (state) {
+ self.cacheStatus = state;
+ });
+
this.markActive();
},
session: {
@@ -35,7 +40,8 @@ module.exports = HumanModel.define({
allowAlerts: ['bool', false, false],
badge: 'string',
pageTitle: 'string',
- hasActiveCall: ['boolean', false, false]
+ hasActiveCall: ['boolean', false, false],
+ cacheStatus: 'string'
},
derived: {
title: {
diff --git a/clientapp/templates.js b/clientapp/templates.js
index bc2eff7..f91e8e8 100644
--- a/clientapp/templates.js
+++ b/clientapp/templates.js
@@ -13,7 +13,7 @@ exports.pages = {};
exports.body = function anonymous(locals) {
var buf = [];
with (locals || {}) {
- buf.push('
');
+ buf.push('');
}
return buf.join("");
};
diff --git a/clientapp/templates/body.jade b/clientapp/templates/body.jade
index fe198a6..85babf2 100644
--- a/clientapp/templates/body.jade
+++ b/clientapp/templates/body.jade
@@ -1,10 +1,13 @@
body
#connectionOverlay
aside#connectionStatus.box
- p
+ p
| You're currently
strong disconnected
button.primary.reconnect Reconnect
+ #updateBar
+ p Update available!
+ button.primary.upgrade Upgrade
#wrapper
aside#menu
section#roster
diff --git a/clientapp/views/main.js b/clientapp/views/main.js
index f1af89e..8df7302 100644
--- a/clientapp/views/main.js
+++ b/clientapp/views/main.js
@@ -23,6 +23,7 @@ module.exports = HumanView.extend({
},
classBindings: {
connected: '#connectionOverlay',
+ cacheStatus: '#updateBar',
hasActiveCall: '#wrapper'
},
render: function () {
diff --git a/public/css/otalk.css b/public/css/otalk.css
index 4b843c6..c2ce759 100644
--- a/public/css/otalk.css
+++ b/public/css/otalk.css
@@ -551,6 +551,19 @@ button.secondary:hover:not(:disabled) {
position: relative;
top: -1px;
}
+#updateBar {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 30px;
+ background: rgba(0,0,0,0.8);
+ z-index: 900;
+ transition: all 0.25s linear 0;
+ border-bottom: 1px solid #222;
+ text-align: center;
+ display: none;
+}
#menu {
position: fixed;
top: 0px;
diff --git a/public/css/otalk.styl b/public/css/otalk.styl
index 595edd6..e1c7718 100644
--- a/public/css/otalk.styl
+++ b/public/css/otalk.styl
@@ -7,6 +7,7 @@
@import 'components/buttons'
@import 'pages/connectionStatus'
+@import 'pages/updateBar'
@import 'pages/roster'
@import 'pages/chat'
@import 'pages/settings'
diff --git a/public/css/pages/connectionStatus.styl b/public/css/pages/connectionStatus.styl
index 723a8ff..dc5ef32 100644
--- a/public/css/pages/connectionStatus.styl
+++ b/public/css/pages/connectionStatus.styl
@@ -13,7 +13,7 @@
&.connected
height: 0px
-
+
#connectionStatus
top: -200px
diff --git a/public/css/pages/updateBar.styl b/public/css/pages/updateBar.styl
new file mode 100644
index 0000000..0f226df
--- /dev/null
+++ b/public/css/pages/updateBar.styl
@@ -0,0 +1,15 @@
+@import '../_variables'
+@import '../_mixins'
+
+#updateBar
+ position: fixed
+ top: 0px
+ left: 0px
+ width: 100%
+ height: 30px
+ background: rgba(0, 0, 0, 0.8)
+ z-index: 900
+ transition: all .25s linear 0
+ border-bottom: 1px solid #222
+ text-align: center
+ display: none
diff --git a/server.js b/server.js
index ad72813..a169796 100644
--- a/server.js
+++ b/server.js
@@ -55,7 +55,7 @@ clientApp.on('ready', function () {
var manifestTemplate = fs.readFileSync(__dirname + '/clientapp/templates/misc/manifest.cache', 'utf-8');
var cacheManifest = manifestTemplate
- .replace('#{version}', pkginfo.version)
+ .replace('#{version}', pkginfo.version + config.isDev ? ' ' + Date.now() : '')
.replace('#{jsFileName}', clientApp.jsFileName())
.replace('#{cssFileName}', clientApp.cssFileName());
console.log('Cache manifest generated');