2
0
Fork 0

Fixed offline injection and added Error support

This commit is contained in:
Willem 2016-01-20 21:57:05 +01:00
parent 1679782085
commit 2010e420d8
3 changed files with 70 additions and 56 deletions

View file

@ -77,7 +77,7 @@ A javascript library providing server defined loading of assets for a single pag
* debug.handler = Prints/log debug message. (default: console.log) * debug.handler = Prints/log debug message. (default: console.log)
* debug.prefix = Debug message prefix. (default: 'FFSpaLoader.') * debug.prefix = Debug message prefix. (default: 'FFSpaLoader.')
* error.handler = The error handler. (default: internal error handler ui) * error.handler = The error handler. (default: internal error handler ui)
* error.title = The error title. (default: 'Loader Error'); * error.title = The error title. (default: 'Loader ');
* error.style = The error ui css style. (default: red border box) * error.style = The error ui css style. (default: red border box)
* boot.cordova.enable = Use deviceready event to boot when cordova is detected. (default: true) * boot.cordova.enable = Use deviceready event to boot when cordova is detected. (default: true)
* boot.cordova.timeout = Boot after (if<0=no-)timeout when deviceready event is not received. (default: -1) * boot.cordova.timeout = Boot after (if<0=no-)timeout when deviceready event is not received. (default: -1)
@ -143,6 +143,7 @@ A javascript library providing server defined loading of assets for a single pag
* Chromium 46 * Chromium 46
* Iceweasel 43 * Iceweasel 43
* Opera 12 Presto * Opera 12 Presto
* IE 11 Edge
* Android 5 in Cordova * Android 5 in Cordova
## Todo ## Todo
@ -167,6 +168,7 @@ Add unit tests for any new or changed functionality. Lint and test your code.
### 0.0.4 ### 0.0.4
* Disable cordova timeout per default. * Disable cordova timeout per default.
* Remove unused mobileAgent detect. * Remove unused mobileAgent detect.
* Fixed cached resources loading.
### 0.0.3 ### 0.0.3

View file

@ -49,7 +49,7 @@
}, },
error: { error: {
handler: null, // auto filled handler: null, // auto filled
title: 'Loader Error', title: 'Loader ',
style: '.ffError { margin: auto;width: 90%;border: 3px solid red;padding-left: 1em;padding-bottom: 1em;}' style: '.ffError { margin: auto;width: 90%;border: 3px solid red;padding-left: 1em;padding-bottom: 1em;}'
}, },
boot: { boot: {
@ -158,20 +158,20 @@
cb(null); cb(null);
}; };
}; };
var sqlErrorHandler = function(cb) { var executeSql = function(tx, query, values, resultHandler, errorHandler) {
return function (tx, err) { tx.executeSql(query, values, resultHandler, function(tx,err) {
cb(err.message+' code: '+err.code); errorHandler(new Error('Code: '+err.code+' '+err.message+' by query: '+query));
}; });
}; };
var cacheDBInit = function(cb) { var cacheDBInit = function(cb) {
cacheDB.transaction(function(tx) { cacheDB.transaction(function(tx) {
var query = 'CREATE TABLE cache_store(id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL, value TEXT NOT NULL)'; var query = 'CREATE TABLE cache_store(id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL, value TEXT NOT NULL)';
utilDebug('websql.init query '+query); utilDebug('websql.init query '+query);
tx.executeSql(query, [], function(tx) { executeSql(tx, query, [], function(tx) {
var query = 'CREATE UNIQUE INDEX cache_store__key__udx ON cache_store (key)'; var query = 'CREATE UNIQUE INDEX cache_store__key__udx ON cache_store (key)';
utilDebug('websql.init query '+query); utilDebug('websql.init query '+query);
tx.executeSql(query, [], function() {cb(null);}, sqlErrorHandler(cb)); executeSql(tx, query, [], nullDataHandler(cb), cb);
}, sqlErrorHandler(cb)); }, cb);
}); });
}; };
return { return {
@ -187,7 +187,7 @@
cacheDB.transaction(function(tx) { cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = \"test-for-table\"'; var query = 'SELECT value FROM cache_store WHERE key = \"test-for-table\"';
utilDebug('websql.cacheOpen query '+query); utilDebug('websql.cacheOpen query '+query);
tx.executeSql(query, [], function() { executeSql(tx, query, [], function() {
cb(null); cb(null);
}, function() { }, function() {
cacheDBInit(cb); cacheDBInit(cb);
@ -198,40 +198,40 @@
cacheDB.transaction(function(tx) { cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = ?'; var query = 'SELECT value FROM cache_store WHERE key = ?';
utilDebug('websql.cacheGetValue query '+query); utilDebug('websql.cacheGetValue query '+query);
tx.executeSql(query,[key], function(tx, res) { executeSql(tx, query,[key], function(tx, res) {
if (res.rows.length === 0) { if (res.rows.length === 0) {
cb(null, null); cb(null, null);
} else { } else {
var value = res.rows.item(0).value; var value = res.rows.item(0).value;
cb(null, JSON.parse(value)); cb(null, JSON.parse(value));
} }
}, sqlErrorHandler(cb)); }, cb);
}); });
}, },
cacheSetValue: function(key, value, cb) { cacheSetValue: function(key, value, cb) {
cacheDB.transaction(function(tx) { cacheDB.transaction(function(tx) {
var query = 'SELECT value FROM cache_store WHERE key = ?'; var query = 'SELECT value FROM cache_store WHERE key = ?';
utilDebug('websql.cacheSetValue query '+query); utilDebug('websql.cacheSetValue query '+query);
tx.executeSql(query,[key], function(tx, res) { executeSql(tx, query,[key], function(tx, res) {
if (res.rows.length === 0) { if (res.rows.length === 0) {
var queryInsert = 'INSERT INTO cache_store (key,value) VALUES (?,?)'; var queryInsert = 'INSERT INTO cache_store (key,value) VALUES (?,?)';
utilDebug('websql.cacheSetValue query '+queryInsert); utilDebug('websql.cacheSetValue query '+queryInsert);
tx.executeSql(queryInsert, [key,JSON.stringify(value)], nullDataHandler(cb), sqlErrorHandler(cb)); executeSql(tx, queryInsert, [key,JSON.stringify(value)], nullDataHandler(cb), cb);
} else { } else {
var queryUpdate = 'UPDATE cache_store SET value = ? WHERE key = ?'; var queryUpdate = 'UPDATE cache_store SET value = ? WHERE key = ?';
utilDebug('websql.cacheSetValue query '+queryUpdate); utilDebug('websql.cacheSetValue query '+queryUpdate);
tx.executeSql(queryUpdate, [JSON.stringify(value),key], nullDataHandler(cb), sqlErrorHandler(cb)); executeSql(tx, queryUpdate, [JSON.stringify(value),key], nullDataHandler(cb), cb);
} }
}, sqlErrorHandler(cb)); }, cb);
}); });
}, },
cacheDeleteValue: function(key, cb) { cacheDeleteValue: function(key, cb) {
cacheDB.transaction(function(tx) { cacheDB.transaction(function(tx) {
var query = 'DELETE FROM cache_store WHERE key = ?'; var query = 'DELETE FROM cache_store WHERE key = ?';
utilDebug('websql.cacheDeleteValue query '+query); utilDebug('websql.cacheDeleteValue query '+query);
tx.executeSql(query, [key], function () { executeSql(tx, query, [key], function () {
setTimeout(function() {cb(null);}); // return next tick so transaction is flushed before location.reload setTimeout(nullDataHandler(cb)); // return next tick so transaction is flushed before location.reload
}, sqlErrorHandler(cb)); }, cb);
}); });
} }
}; };
@ -257,10 +257,14 @@
* @private * @private
*/ */
var utilErrorHandler = function(err) { var utilErrorHandler = function(err) {
utilDebug('utilErrorHandler error '+err); // TODO: Add Error object support if (!(err instanceof Error)) {
err = new Error(err);
}
utilDebug('utilErrorHandler error '+err.name+' '+err.message);
var rootTag = document.createElement('div'); var rootTag = document.createElement('div');
rootTag.setAttribute('class','ffError'); rootTag.setAttribute('class','ffError');
document.getElementsByTagName('body')[0].appendChild(rootTag);
var cssTag = document.createElement('style'); var cssTag = document.createElement('style');
cssTag.type = 'text/css'; cssTag.type = 'text/css';
@ -268,14 +272,24 @@
rootTag.appendChild(cssTag); rootTag.appendChild(cssTag);
var titleTag = document.createElement('h1'); var titleTag = document.createElement('h1');
titleTag.appendChild(document.createTextNode(options.error.title)); titleTag.appendChild(document.createTextNode(options.error.title+err.name));
rootTag.appendChild(titleTag); rootTag.appendChild(titleTag);
var questionTag = document.createElement('p'); var questionTag = document.createElement('p');
questionTag.appendChild(document.createTextNode(err)); questionTag.appendChild(document.createTextNode(err.message));
rootTag.appendChild(questionTag); rootTag.appendChild(questionTag);
document.getElementsByTagName('body')[0].appendChild(rootTag); try {
var stack = err.stack || '';
stack = stack.split('\n').map(function (line) { return line.trim(); });
var stackText = stack.splice(stack[0] == 'Error' ? 2 : 1);
var traceTag = document.createElement('div');
traceTag.appendChild(document.createTextNode(stackText));
rootTag.appendChild(traceTag);
} catch (stackError) {
utilDebug('No stack: '+stackError);
}
}; };
/** /**
@ -315,7 +329,7 @@
}; };
var cacheCheckType = function (type, cb, action) { var cacheCheckType = function (type, cb, action) {
cacheHasService(type)?action():cb('No caching for '+type); cacheHasService(type)?action():cb(new Error('No caching for '+type));
}; };
var cacheGetValue = function(type, key , cb) { var cacheGetValue = function(type, key , cb) {
@ -450,33 +464,27 @@
loadResource(resourceStack[0],resourceLoader); loadResource(resourceStack[0],resourceLoader);
}; };
var injectResource = function(resource, cb) {
cacheGetValue(resource.type,resource.hash,function(err,item) {
injectResourceData(resource,item.data,cb);
});
}
var injectResources = function(resources, cb) { var injectResources = function(resources, cb) {
var startTime = new Date().getTime(); var startTime = new Date().getTime();
utilDebug('injectResources'); utilDebug('injectResources');
resources.forEach(function (resource) { var resourceStack = resources;
cacheGetValue(resource.type,resource.hash,function(err,item) { var resourceLoader = function(err) {
// TODO reuse injectResourceData if (err !== null) { return cb(err); }
resourceStack = resourceStack.slice(1);
var tag = null; if (resourceStack.length === 0) {
if (resource.type === 'css' || resource.type === 'cssData') { utilDebug('injectResources done in '+(new Date().getTime()-startTime)+' ms.');
tag = document.createElement('style'); cb(null);
tag.type = 'text/css'; } else {
} injectResource(resourceStack[0],resourceLoader);
if (resource.type === 'js') { }
tag = document.createElement('script'); };
tag.type = 'text/javascript'; injectResource(resourceStack[0],resourceLoader);
}
utilDebug('injectResources from '+JSON.stringify(resource));
tag.appendChild(document.createTextNode(item.data));
//document.getElementsByTagName('head')[0].appendChild(tag);
var ref = document.getElementsByTagName('script')[0];
ref.parentNode.insertBefore(tag, ref); // note in reverse order
});
});
utilDebug('injectResources done in '+(new Date().getTime()-startTime)+' ms.');
cb(null); // FIXME async
}; };
/** /**
@ -488,11 +496,11 @@
*/ */
var startLoader = function (cb) { var startLoader = function (cb) {
if (options.server.url === null) { if (options.server.url === null) {
cb('Missing options.server.url'); cb(new Error('No url'));
return; return;
} }
if (options.server.assets === null) { if (options.server.assets === null) {
cb('Missing options.server.assets'); cb(new Error('No assets'));
return; return;
} }
rootWindow[options.server.flag] = options.server.url; rootWindow[options.server.flag] = options.server.url;
@ -507,13 +515,13 @@
if (err !== null) { if (err !== null) {
cb(err); cb(err);
} else if (value === null) { } else if (value === null) {
cb('Have no cache of server resouces from '+options.server.url); cb(new Error('Have no cache of server resouces from '+options.server.url));
} else { } else {
injectResources(value, cb); injectResources(value, cb);
} }
}); });
} else { } else {
cb('Could not fetch server resouces from '+options.server.url); cb(new Error('Could not fetch server resouces from '+options.server.url));
} }
return; return;
} }
@ -695,7 +703,7 @@
if (err !== null) { return options.error.handler(err); } if (err !== null) { return options.error.handler(err); }
if (typeof cbArgu === 'function') { if (typeof cbArgu === 'function') {
cbArgu(); cbArgu();
} }
}); });
} }
}; };

View file

@ -9,7 +9,7 @@ var morgan = require('morgan');
// example options; // example options;
var serverUrl = 'http://localhost:8080'; var serverUrl = 'http://localhost:8080';
var useInline = true; // or false var useInline = false; // or false
var clientResourcesWeb = []; var clientResourcesWeb = [];
var clientResources = { var clientResources = {
@ -123,7 +123,11 @@ server.use('/static/module/angular', express.static(path.join(__dirname,'n
server.use('/static/module/angular-route', express.static(path.join(__dirname,'node_modules/angular-route'))); server.use('/static/module/angular-route', express.static(path.join(__dirname,'node_modules/angular-route')));
server.get('/static/es5-ff-spa-loader.js', function (req,res) { server.get('/static/es5-ff-spa-loader.js', function (req,res) {
res.write(fs.readFileSync(__dirname+'/../dist/es5-ff-spa-loader.js', 'utf8')); if (fs.existsSync(__dirname+'/../es5-ff-spa-loader.js')) {
res.write(fs.readFileSync(__dirname+'/../es5-ff-spa-loader.js', 'utf8'));
} else {
res.write(fs.readFileSync(__dirname+'/../dist/es5-ff-spa-loader.js', 'utf8'));
}
res.end(); res.end();
}); });
server.get('/static/spa-client-resources', function (req,res) { server.get('/static/spa-client-resources', function (req,res) {