diff --git a/README.md b/README.md index ed60d94..0a36384 100644 --- a/README.md +++ b/README.md @@ -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.prefix = Debug message prefix. (default: 'FFSpaLoader.') * 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) * 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) @@ -143,6 +143,7 @@ A javascript library providing server defined loading of assets for a single pag * Chromium 46 * Iceweasel 43 * Opera 12 Presto + * IE 11 Edge * Android 5 in Cordova ## Todo @@ -167,6 +168,7 @@ Add unit tests for any new or changed functionality. Lint and test your code. ### 0.0.4 * Disable cordova timeout per default. * Remove unused mobileAgent detect. +* Fixed cached resources loading. ### 0.0.3 diff --git a/es5-ff-spa-loader.js b/es5-ff-spa-loader.js index 813f407..9a77688 100644 --- a/es5-ff-spa-loader.js +++ b/es5-ff-spa-loader.js @@ -49,7 +49,7 @@ }, error: { 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;}' }, boot: { @@ -158,20 +158,20 @@ cb(null); }; }; - var sqlErrorHandler = function(cb) { - return function (tx, err) { - cb(err.message+' code: '+err.code); - }; + var executeSql = function(tx, query, values, resultHandler, errorHandler) { + tx.executeSql(query, values, resultHandler, function(tx,err) { + errorHandler(new Error('Code: '+err.code+' '+err.message+' by query: '+query)); + }); }; var cacheDBInit = function(cb) { cacheDB.transaction(function(tx) { var query = 'CREATE TABLE cache_store(id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL, value TEXT NOT NULL)'; 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)'; utilDebug('websql.init query '+query); - tx.executeSql(query, [], function() {cb(null);}, sqlErrorHandler(cb)); - }, sqlErrorHandler(cb)); + executeSql(tx, query, [], nullDataHandler(cb), cb); + }, cb); }); }; return { @@ -187,7 +187,7 @@ cacheDB.transaction(function(tx) { var query = 'SELECT value FROM cache_store WHERE key = \"test-for-table\"'; utilDebug('websql.cacheOpen query '+query); - tx.executeSql(query, [], function() { + executeSql(tx, query, [], function() { cb(null); }, function() { cacheDBInit(cb); @@ -198,40 +198,40 @@ cacheDB.transaction(function(tx) { var query = 'SELECT value FROM cache_store WHERE key = ?'; utilDebug('websql.cacheGetValue query '+query); - tx.executeSql(query,[key], function(tx, res) { + executeSql(tx, query,[key], function(tx, res) { if (res.rows.length === 0) { cb(null, null); } else { var value = res.rows.item(0).value; cb(null, JSON.parse(value)); } - }, sqlErrorHandler(cb)); + }, cb); }); }, cacheSetValue: function(key, value, cb) { cacheDB.transaction(function(tx) { var query = 'SELECT value FROM cache_store WHERE key = ?'; utilDebug('websql.cacheSetValue query '+query); - tx.executeSql(query,[key], function(tx, res) { + executeSql(tx, query,[key], function(tx, res) { if (res.rows.length === 0) { var queryInsert = 'INSERT INTO cache_store (key,value) VALUES (?,?)'; 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 { var queryUpdate = 'UPDATE cache_store SET value = ? WHERE key = ?'; 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) { cacheDB.transaction(function(tx) { var query = 'DELETE FROM cache_store WHERE key = ?'; utilDebug('websql.cacheDeleteValue query '+query); - tx.executeSql(query, [key], function () { - setTimeout(function() {cb(null);}); // return next tick so transaction is flushed before location.reload - }, sqlErrorHandler(cb)); + executeSql(tx, query, [key], function () { + setTimeout(nullDataHandler(cb)); // return next tick so transaction is flushed before location.reload + }, cb); }); } }; @@ -257,10 +257,14 @@ * @private */ 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'); rootTag.setAttribute('class','ffError'); + document.getElementsByTagName('body')[0].appendChild(rootTag); var cssTag = document.createElement('style'); cssTag.type = 'text/css'; @@ -268,14 +272,24 @@ rootTag.appendChild(cssTag); var titleTag = document.createElement('h1'); - titleTag.appendChild(document.createTextNode(options.error.title)); + titleTag.appendChild(document.createTextNode(options.error.title+err.name)); rootTag.appendChild(titleTag); var questionTag = document.createElement('p'); - questionTag.appendChild(document.createTextNode(err)); + questionTag.appendChild(document.createTextNode(err.message)); 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) { - cacheHasService(type)?action():cb('No caching for '+type); + cacheHasService(type)?action():cb(new Error('No caching for '+type)); }; var cacheGetValue = function(type, key , cb) { @@ -450,33 +464,27 @@ 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 startTime = new Date().getTime(); utilDebug('injectResources'); - resources.forEach(function (resource) { - cacheGetValue(resource.type,resource.hash,function(err,item) { - // TODO reuse injectResourceData - - var tag = null; - if (resource.type === 'css' || resource.type === 'cssData') { - tag = document.createElement('style'); - tag.type = 'text/css'; - } - if (resource.type === 'js') { - tag = document.createElement('script'); - tag.type = 'text/javascript'; - } - 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 + var resourceStack = resources; + var resourceLoader = function(err) { + if (err !== null) { return cb(err); } + resourceStack = resourceStack.slice(1); + if (resourceStack.length === 0) { + utilDebug('injectResources done in '+(new Date().getTime()-startTime)+' ms.'); + cb(null); + } else { + injectResource(resourceStack[0],resourceLoader); + } + }; + injectResource(resourceStack[0],resourceLoader); }; /** @@ -488,11 +496,11 @@ */ var startLoader = function (cb) { if (options.server.url === null) { - cb('Missing options.server.url'); + cb(new Error('No url')); return; } if (options.server.assets === null) { - cb('Missing options.server.assets'); + cb(new Error('No assets')); return; } rootWindow[options.server.flag] = options.server.url; @@ -507,13 +515,13 @@ if (err !== null) { cb(err); } 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 { injectResources(value, cb); } }); } else { - cb('Could not fetch server resouces from '+options.server.url); + cb(new Error('Could not fetch server resouces from '+options.server.url)); } return; } @@ -695,7 +703,7 @@ if (err !== null) { return options.error.handler(err); } if (typeof cbArgu === 'function') { cbArgu(); - } + } }); } }; diff --git a/example/example.js b/example/example.js index 9b19559..f3c910f 100644 --- a/example/example.js +++ b/example/example.js @@ -9,7 +9,7 @@ var morgan = require('morgan'); // example options; var serverUrl = 'http://localhost:8080'; -var useInline = true; // or false +var useInline = false; // or false var clientResourcesWeb = []; 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.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(); }); server.get('/static/spa-client-resources', function (req,res) {