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('

Settings
'); + buf.push('

Update available!

Settings
'); } 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');