2015-12-23 00:16:54 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015-2016, Willem Cazander
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
|
|
|
* that the following conditions are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
|
|
|
* following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
|
|
|
* the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
|
|
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2016-01-17 20:57:59 +00:00
|
|
|
/* jslint browser: true */
|
2016-01-24 21:03:24 +00:00
|
|
|
/* global angular,define,sqlitePlugin */
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* FFSpaLoader is an assets loader for single page applications.
|
|
|
|
* Its build around the concept the there is only a single static index.html which
|
2016-03-13 23:26:00 +00:00
|
|
|
* synces all its assets to local cache for offline use and or fast page loads.
|
2016-01-14 21:42:13 +00:00
|
|
|
*
|
|
|
|
* @module FFSpaLoader
|
|
|
|
*/
|
2016-01-17 20:57:59 +00:00
|
|
|
(function (root, factory) {
|
|
|
|
if ( typeof define === 'function' && define.amd ) {
|
2016-04-22 08:34:11 +00:00
|
|
|
define(factory(root));
|
2016-01-17 20:57:59 +00:00
|
|
|
} else if ( typeof exports === 'object' ) {
|
|
|
|
module.exports = factory(root);
|
|
|
|
} else {
|
|
|
|
root.FFSpaLoader = factory(root);
|
|
|
|
}
|
|
|
|
})(this || window, /** @lends module:FFSpaLoader */ function (rootWindow) {
|
|
|
|
'use strict';
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* The options to customize the loader.
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var options = {
|
2016-01-16 17:24:37 +00:00
|
|
|
debug: {
|
|
|
|
enable: false,
|
|
|
|
handler: null, // auto filled
|
|
|
|
prefix: 'FFSpaLoader.'
|
|
|
|
},
|
|
|
|
error: {
|
|
|
|
handler: null, // auto filled
|
2016-02-16 15:09:23 +00:00
|
|
|
title: 'Loader '
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
2016-01-16 17:24:37 +00:00
|
|
|
boot: {
|
|
|
|
cordova: {
|
|
|
|
enable: true,
|
2016-03-16 20:58:27 +00:00
|
|
|
timeout: -1,
|
2016-01-16 17:24:37 +00:00
|
|
|
flag: 'FFCordovaDevice'
|
|
|
|
},
|
|
|
|
angular: {
|
|
|
|
enable: true,
|
|
|
|
modules: []
|
2016-03-16 20:58:27 +00:00
|
|
|
},
|
|
|
|
cleanup: {
|
|
|
|
enable: true,
|
|
|
|
timeout: 1000,
|
|
|
|
tags: []
|
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
server: {
|
2016-01-16 17:24:37 +00:00
|
|
|
url: null,
|
2016-04-20 16:15:23 +00:00
|
|
|
depath: null,
|
2016-01-16 17:24:37 +00:00
|
|
|
assets: null,
|
|
|
|
timeout: 4096,
|
|
|
|
flag: 'FFServerUrl',
|
2016-01-14 21:42:13 +00:00
|
|
|
header: {
|
2016-01-21 21:41:56 +00:00
|
|
|
request: {
|
|
|
|
'X-FFSpaLoader': 'sync'
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
2016-02-26 23:24:43 +00:00
|
|
|
response: {
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2016-01-21 19:42:18 +00:00
|
|
|
question: {
|
|
|
|
transport: 'http://',
|
2016-01-22 12:52:28 +00:00
|
|
|
title: 'Question',
|
2016-01-21 23:02:39 +00:00
|
|
|
submit: 'Start',
|
2016-01-24 17:58:52 +00:00
|
|
|
size: 32,
|
2016-02-16 15:09:23 +00:00
|
|
|
text: 'Please provide the server name',
|
2016-01-21 21:17:22 +00:00
|
|
|
validate: {
|
|
|
|
min: {
|
|
|
|
value: 3,
|
|
|
|
message: 'Server name is to short.'
|
|
|
|
},
|
|
|
|
max: {
|
|
|
|
value: 255,
|
|
|
|
message: 'Server name is to long.'
|
|
|
|
},
|
|
|
|
regex: {
|
|
|
|
value: '^([a-zA-Z0-9\.\:])*$',
|
|
|
|
message: 'Server name is invalid.'
|
|
|
|
}
|
|
|
|
}
|
2016-01-21 19:42:18 +00:00
|
|
|
},
|
2016-02-26 22:40:29 +00:00
|
|
|
loader: {
|
|
|
|
title: 'Loading Application',
|
|
|
|
footer: '© FFSpaLoader',
|
|
|
|
await: 250,
|
|
|
|
progres: {
|
|
|
|
items: {
|
|
|
|
enable: true,
|
|
|
|
size: 50,
|
|
|
|
},
|
|
|
|
bar: {
|
|
|
|
enable: true,
|
|
|
|
percentage: true,
|
|
|
|
}
|
|
|
|
},
|
2016-03-16 21:53:58 +00:00
|
|
|
delayDss: false, // TODO: move to cache type options
|
2016-02-26 22:40:29 +00:00
|
|
|
},
|
2016-01-14 21:42:13 +00:00
|
|
|
cache: {
|
|
|
|
meta: null,
|
|
|
|
js: null,
|
|
|
|
css: null,
|
2016-03-13 23:52:48 +00:00
|
|
|
dss: null
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Use single instance for websql
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var cacheDB = null;
|
|
|
|
|
2016-03-16 21:53:58 +00:00
|
|
|
/**
|
|
|
|
* Use delayed fetch
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var delayedResources = [];
|
2016-04-20 16:15:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Ask Url submit lock.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var askUrlSubmitLock = false;
|
2016-03-16 21:53:58 +00:00
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* The factory which contains detection helpers and cache backend builders.
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var factory = {
|
|
|
|
detect: {
|
|
|
|
localStorage: function() {
|
|
|
|
try {
|
|
|
|
var testData = 'localStorageDetect';
|
2016-01-18 21:41:52 +00:00
|
|
|
rootWindow.localStorage.setItem(testData, testData); // throws err in private browsing mode
|
2016-01-17 20:57:59 +00:00
|
|
|
rootWindow.localStorage.removeItem(testData);
|
2016-01-14 21:42:13 +00:00
|
|
|
return true;
|
|
|
|
} catch(e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
openDatabase: function() {
|
2016-01-17 20:57:59 +00:00
|
|
|
return 'openDatabase' in rootWindow;
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
sqlitePlugin: function() {
|
2016-01-17 20:57:59 +00:00
|
|
|
return 'sqlitePlugin' in rootWindow;
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
cordova: function() {
|
2016-01-17 20:57:59 +00:00
|
|
|
return 'cordova' in rootWindow;
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
cordovaDevice: function() {
|
2016-01-17 20:57:59 +00:00
|
|
|
return options.boot.cordova.flag in rootWindow;
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
cache: {
|
|
|
|
localStorage: function() {
|
|
|
|
return {
|
|
|
|
cacheGetValue: function(key, cb) {
|
|
|
|
try {
|
2016-01-17 20:57:59 +00:00
|
|
|
var dataRaw = rootWindow.localStorage.getItem(key);
|
2016-01-14 21:42:13 +00:00
|
|
|
var data = JSON.parse(dataRaw);
|
|
|
|
cb(null, data);
|
|
|
|
} catch(e) {
|
|
|
|
cb(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
cacheSetValue: function(key, value, cb) {
|
|
|
|
try {
|
2016-01-17 20:57:59 +00:00
|
|
|
rootWindow.localStorage.setItem(key,JSON.stringify(value));
|
2016-01-14 21:42:13 +00:00
|
|
|
cb(null);
|
|
|
|
} catch(e) {
|
|
|
|
cb(e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
cacheDeleteValue: function(key, cb) {
|
|
|
|
try {
|
2016-01-17 20:57:59 +00:00
|
|
|
rootWindow.localStorage.removeItem(key);
|
2016-01-14 21:42:13 +00:00
|
|
|
cb(null);
|
|
|
|
} catch(e) {
|
|
|
|
cb(e);
|
|
|
|
}
|
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
websql: function(opt) {
|
2016-01-24 17:58:52 +00:00
|
|
|
if (opt === undefined) { opt = {}; }
|
|
|
|
if (opt.name === undefined) { opt.name = 'FFSpaLoader'; }
|
|
|
|
if (opt.size === undefined) { opt.size = 4 * 1024 * 1024; } // reg 4MB let user do higher
|
|
|
|
if (opt.version === undefined) { opt.version = '1.0'; }
|
|
|
|
if (opt.table === undefined) { opt.table = 'cache_store'; }
|
|
|
|
if (opt.open === undefined) {
|
|
|
|
opt.open = function(dbOpt) {
|
|
|
|
return rootWindow.openDatabase(dbOpt.name, dbOpt.version, dbOpt.name, dbOpt.size);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var nullDataHandler = function(cb) {
|
2016-01-17 20:57:59 +00:00
|
|
|
return function () {
|
2016-01-14 21:42:13 +00:00
|
|
|
cb(null);
|
|
|
|
};
|
|
|
|
};
|
2016-01-20 20:57:05 +00:00
|
|
|
var executeSql = function(tx, query, values, resultHandler, errorHandler) {
|
2016-01-21 00:40:15 +00:00
|
|
|
utilDebug('websql.executeSql '+query);
|
2016-01-20 20:57:05 +00:00
|
|
|
tx.executeSql(query, values, resultHandler, function(tx,err) {
|
|
|
|
errorHandler(new Error('Code: '+err.code+' '+err.message+' by query: '+query));
|
|
|
|
});
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
2016-01-16 17:24:37 +00:00
|
|
|
var cacheDBInit = function(cb) {
|
|
|
|
cacheDB.transaction(function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
var query = 'CREATE TABLE '+opt.table+'(id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL, value TEXT NOT NULL)';
|
2016-01-20 20:57:05 +00:00
|
|
|
executeSql(tx, query, [], function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
executeSql(tx, 'CREATE UNIQUE INDEX '+opt.table+'__key__udx ON '+opt.table+' (key)', [], nullDataHandler(cb), cb);
|
2016-01-20 20:57:05 +00:00
|
|
|
}, cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
return {
|
2016-01-16 17:24:37 +00:00
|
|
|
cacheOpen: function(cb) {
|
|
|
|
if (cacheDB !== null) {
|
2016-01-18 21:41:52 +00:00
|
|
|
return cb(null); // open once.
|
|
|
|
}
|
2016-01-24 17:58:52 +00:00
|
|
|
utilDebug('websql.cacheOpen '+JSON.stringify(opt));
|
2016-01-18 21:41:52 +00:00
|
|
|
try {
|
2016-01-24 17:58:52 +00:00
|
|
|
cacheDB = opt.open(opt);
|
2016-01-18 21:41:52 +00:00
|
|
|
} catch(e) {
|
|
|
|
return cb(e);
|
2016-01-16 17:24:37 +00:00
|
|
|
}
|
|
|
|
cacheDB.transaction(function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
executeSql(tx,'SELECT value FROM '+opt.table+' WHERE key = \"if-err-init\"', [], function() {
|
2016-01-16 17:24:37 +00:00
|
|
|
cb(null);
|
2016-01-17 20:57:59 +00:00
|
|
|
}, function() {
|
2016-01-16 17:24:37 +00:00
|
|
|
cacheDBInit(cb);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
2016-01-14 21:42:13 +00:00
|
|
|
cacheGetValue: function(key, cb) {
|
|
|
|
cacheDB.transaction(function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
executeSql(tx, 'SELECT value FROM '+opt.table+' WHERE key = ?',[key], function(tx, res) {
|
2016-01-14 21:42:13 +00:00
|
|
|
if (res.rows.length === 0) {
|
|
|
|
cb(null, null);
|
|
|
|
} else {
|
|
|
|
var value = res.rows.item(0).value;
|
|
|
|
cb(null, JSON.parse(value));
|
|
|
|
}
|
2016-01-20 20:57:05 +00:00
|
|
|
}, cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
cacheSetValue: function(key, value, cb) {
|
|
|
|
cacheDB.transaction(function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
executeSql(tx, 'SELECT value FROM '+opt.table+' WHERE key = ?',[key], function(tx, res) {
|
2016-01-14 21:42:13 +00:00
|
|
|
if (res.rows.length === 0) {
|
2016-01-24 17:58:52 +00:00
|
|
|
var queryInsert = 'INSERT INTO '+opt.table+' (key,value) VALUES (?,?)';
|
2016-01-20 20:57:05 +00:00
|
|
|
executeSql(tx, queryInsert, [key,JSON.stringify(value)], nullDataHandler(cb), cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
} else {
|
2016-01-24 17:58:52 +00:00
|
|
|
var queryUpdate = 'UPDATE '+opt.table+' SET value = ? WHERE key = ?';
|
2016-01-20 20:57:05 +00:00
|
|
|
executeSql(tx, queryUpdate, [JSON.stringify(value),key], nullDataHandler(cb), cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-01-20 20:57:05 +00:00
|
|
|
}, cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
cacheDeleteValue: function(key, cb) {
|
|
|
|
cacheDB.transaction(function(tx) {
|
2016-01-24 17:58:52 +00:00
|
|
|
executeSql(tx, 'DELETE FROM '+opt.table+' WHERE key = ?', [key], nullDataHandler(cb), cb);
|
2016-01-22 14:44:43 +00:00
|
|
|
});
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-01-16 17:24:37 +00:00
|
|
|
/**
|
|
|
|
* Prints the debug message with prefix to the options.debug.handler if options.debug.enable is true.
|
|
|
|
* @param {String} message The message to log.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var utilDebug = function (message) {
|
|
|
|
if (options.debug.enable !== true) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
options.debug.handler(options.debug.prefix+message);
|
|
|
|
};
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* The default error handler which renders the error in the browser.
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {Error|String} err The error object or message.
|
2016-01-14 21:42:13 +00:00
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var utilErrorHandler = function(err) {
|
2016-01-20 20:57:05 +00:00
|
|
|
if (!(err instanceof Error)) {
|
|
|
|
err = new Error(err);
|
|
|
|
}
|
|
|
|
utilDebug('utilErrorHandler error '+err.name+' '+err.message);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
var rootTag = document.createElement('div');
|
2016-02-26 22:40:29 +00:00
|
|
|
rootTag.setAttribute('class','ffWrapper');
|
2016-01-20 20:57:05 +00:00
|
|
|
document.getElementsByTagName('body')[0].appendChild(rootTag);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
var titleTag = document.createElement('div');
|
|
|
|
titleTag.setAttribute('class','ffTitle');
|
2016-01-20 20:57:05 +00:00
|
|
|
titleTag.appendChild(document.createTextNode(options.error.title+err.name));
|
2016-01-14 21:42:13 +00:00
|
|
|
rootTag.appendChild(titleTag);
|
2016-02-26 22:40:29 +00:00
|
|
|
|
|
|
|
var dialogTag = document.createElement('div');
|
|
|
|
dialogTag.setAttribute('class','ffError');
|
|
|
|
rootTag.appendChild(dialogTag);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
var questionTag = document.createElement('p');
|
2016-01-20 20:57:05 +00:00
|
|
|
questionTag.appendChild(document.createTextNode(err.message));
|
2016-02-26 22:40:29 +00:00
|
|
|
dialogTag.appendChild(questionTag);
|
2016-01-20 20:57:05 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
var stack = err.stack || '';
|
2016-01-23 18:25:20 +00:00
|
|
|
stack = stack.split('\n').map(function (line) { return line.trim()+'\n'; });
|
2016-01-21 00:40:15 +00:00
|
|
|
var stackText = stack.splice(stack[0] === 'Error' ? 2 : 1);
|
2016-01-20 20:57:05 +00:00
|
|
|
|
2016-01-23 18:25:20 +00:00
|
|
|
var traceTag = document.createElement('pre');
|
2016-01-20 20:57:05 +00:00
|
|
|
traceTag.appendChild(document.createTextNode(stackText));
|
2016-02-26 22:40:29 +00:00
|
|
|
dialogTag.appendChild(traceTag);
|
2016-01-20 20:57:05 +00:00
|
|
|
} catch (stackError) {
|
|
|
|
utilDebug('No stack: '+stackError);
|
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches an url resource with a XMLHttpRequest.
|
|
|
|
* @param {String} url The url to fetch.
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {function} cb Error first callback when done.
|
2016-01-14 21:42:13 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2016-03-13 23:26:00 +00:00
|
|
|
var utilHttpFetch = function (url, cb, onlyJson) {
|
2015-12-23 00:16:54 +00:00
|
|
|
var startTime = new Date().getTime();
|
|
|
|
var httpRequest = new XMLHttpRequest();
|
|
|
|
httpRequest.onreadystatechange = function() {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('utilHttpFetch url \"'+url+'\" done in '+(new Date().getTime()-startTime)+' ms.');
|
2016-02-26 23:24:43 +00:00
|
|
|
var headerResponseKeys = Object.keys(options.server.header.response);
|
|
|
|
for (var headerResponseKeyIdx in headerResponseKeys) {
|
|
|
|
var headerResponseKey = headerResponseKeys[headerResponseKeyIdx];
|
|
|
|
var headerResponseValue = options.server.header.response[headerResponseKey];
|
|
|
|
var value = httpRequest.getResponseHeader(headerResponseKey);
|
|
|
|
if (value === null) {
|
|
|
|
return cb('Header missing: '+headerResponseKey);
|
|
|
|
}
|
|
|
|
if (headerResponseValue === null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (headerResponseValue !== value) {
|
|
|
|
return cb('Header mismatch: '+headerResponseKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
cb(null, httpRequest);
|
2016-01-17 20:57:59 +00:00
|
|
|
} else if (httpRequest.readyState === 4) {
|
2016-03-16 20:58:27 +00:00
|
|
|
cb('Wrong status '+httpRequest.status+' of '+url);
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
httpRequest.open('GET', url, true);
|
2016-01-14 21:42:13 +00:00
|
|
|
httpRequest.timeout = options.server.timeout; // ieX: after open()
|
|
|
|
httpRequest.ontimeout = function() {
|
2016-01-16 17:24:37 +00:00
|
|
|
cb('timeout after '+options.server.timeout+' of url '+url);
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
2016-01-21 21:41:56 +00:00
|
|
|
var headerKeys = Object.keys(options.server.header.request);
|
|
|
|
for (var headerKeyIdx in headerKeys) {
|
|
|
|
var headerKey = headerKeys[headerKeyIdx];
|
|
|
|
var headerValue = options.server.header.request[headerKey];
|
|
|
|
httpRequest.setRequestHeader(headerKey,headerValue);
|
|
|
|
}
|
2016-03-13 23:26:00 +00:00
|
|
|
if (onlyJson === true) {
|
|
|
|
httpRequest.setRequestHeader('Accept','application/json');
|
|
|
|
}
|
2015-12-23 00:16:54 +00:00
|
|
|
httpRequest.send();
|
|
|
|
};
|
2016-01-21 00:40:15 +00:00
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Async helper to run each step from the stack.
|
|
|
|
* @param {String} runType The runType used for debug logging.
|
|
|
|
* @param {Array} stack The stack to run all steps on.
|
|
|
|
* @param {function} step Stack Item + Error first callback when done function callback.
|
|
|
|
* @param {function} cb Error first callback when done.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-21 00:40:15 +00:00
|
|
|
var utilRunStack = function(runType, stack, step, cb) {
|
|
|
|
if (stack.length === 0) {
|
|
|
|
return cb(null);
|
|
|
|
}
|
2016-01-24 17:58:52 +00:00
|
|
|
utilDebug(runType+' start');
|
2016-01-21 00:40:15 +00:00
|
|
|
var startTime = new Date().getTime();
|
|
|
|
var runStack = stack;
|
|
|
|
var runStackStep = function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
runStack = runStack.slice(1);
|
|
|
|
if (runStack.length === 0) {
|
|
|
|
utilDebug(runType+' done '+stack.length+' in '+(new Date().getTime()-startTime)+' ms.');
|
|
|
|
cb(null);
|
|
|
|
} else {
|
|
|
|
step(runStack[0],runStackStep);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
step(runStack[0],runStackStep);
|
|
|
|
};
|
2016-04-20 16:15:23 +00:00
|
|
|
|
|
|
|
var utilCleanServerUrl = function() {
|
|
|
|
var index1 = options.server.url.indexOf('#');
|
|
|
|
if (index1 > 0){
|
|
|
|
options.server.url = options.server.url.substring(0,index1);
|
|
|
|
}
|
|
|
|
var index2 = options.server.url.indexOf('?');
|
|
|
|
if (index2 > 0){
|
|
|
|
options.server.url = options.server.url.substring(0,index2);
|
|
|
|
}
|
|
|
|
if (options.server.depath !== null && options.server.url.indexOf(options.server.depath) > 0) {
|
|
|
|
utilDebug('start server url depathing');
|
|
|
|
options.server.url = options.server.url.substring(0,options.server.url.indexOf(options.server.depath) - 1);
|
|
|
|
}
|
|
|
|
if (options.server.url.indexOf('file://') === 0) {
|
|
|
|
utilDebug('start server url cleared because is file uri');
|
|
|
|
options.server.url = null;
|
|
|
|
}
|
2016-04-20 16:16:50 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
var cacheGetService = function (type) {
|
|
|
|
if (options.cache[type]) {
|
|
|
|
return options.cache[type];
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
return null;
|
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var cacheHasService = function (type) {
|
|
|
|
return cacheGetService(type) !== null;
|
|
|
|
};
|
|
|
|
|
|
|
|
var cacheCheckType = function (type, cb, action) {
|
2016-01-20 20:57:05 +00:00
|
|
|
cacheHasService(type)?action():cb(new Error('No caching for '+type));
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Retreive a cached value.
|
|
|
|
* @param {String} type The cache type to use.
|
|
|
|
* @param {String} key The key to get the value for.
|
|
|
|
* @param {function} cb Error first callback + value callback.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var cacheGetValue = function(type, key , cb) {
|
|
|
|
cacheCheckType(type, cb, function() {
|
|
|
|
var cacheKey = type+'_'+key;
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('cacheGetValue key '+cacheKey);
|
2016-01-14 21:42:13 +00:00
|
|
|
cacheGetService(type).cacheGetValue(cacheKey,cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Store a value in cache.
|
|
|
|
* @param {String} type The cache type to use.
|
|
|
|
* @param {String} key The key to store the value for.
|
|
|
|
* @param {String} value The value to store.
|
|
|
|
* @param {function} cb Error first callback.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var cacheSetValue = function(type, key, value, cb) {
|
|
|
|
cacheCheckType(type, cb, function() {
|
|
|
|
var cacheKey = type+'_'+key;
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('cacheSetValue key '+cacheKey);
|
2016-01-14 21:42:13 +00:00
|
|
|
cacheGetService(type).cacheSetValue(cacheKey,value,cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Deletes an cache value.
|
|
|
|
* @param {String} type The cache type to use.
|
|
|
|
* @param {String} key The key to delete the value.
|
|
|
|
* @param {function} cb Error first callback.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var cacheDeleteValue = function(type, key, cb) {
|
|
|
|
cacheCheckType(type, cb, function() {
|
|
|
|
var cacheKey = type+'_'+key;
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('cacheDeleteValue key '+cacheKey);
|
2016-01-14 21:42:13 +00:00
|
|
|
cacheGetService(type).cacheDeleteValue(cacheKey,cb);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-24 18:44:00 +00:00
|
|
|
var cleanupCache = function (resources, deleteAll, cb) {
|
2016-01-21 00:40:15 +00:00
|
|
|
var typedKeys = {};
|
|
|
|
resources.forEach(function (r) {
|
|
|
|
var typeKey = typedKeys[r.type];
|
|
|
|
if (typeKey === undefined) {
|
|
|
|
typeKey = [];
|
|
|
|
typedKeys[r.type] = typeKey;
|
|
|
|
}
|
|
|
|
typeKey.push(r.hash);
|
|
|
|
});
|
|
|
|
var steps = [];
|
|
|
|
var keys = Object.keys(typedKeys);
|
|
|
|
for (var keyIdx in keys) {
|
|
|
|
var type = keys[keyIdx];
|
|
|
|
if (!cacheHasService(type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
steps.push({keys: typedKeys[type], type: type});
|
|
|
|
}
|
|
|
|
utilRunStack('cleanupCacheKeys',steps, function(typeKey, cb) {
|
|
|
|
cacheGetValue(typeKey.type,'keys',function (err,value) {
|
|
|
|
if (err !== null) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
if (value === null) {
|
2016-01-24 18:44:00 +00:00
|
|
|
return cb(null); // meta has no keys
|
2016-01-21 00:40:15 +00:00
|
|
|
}
|
|
|
|
var diff = [];
|
|
|
|
for (var i=0;i<value.length;i++) {
|
2016-01-24 18:44:00 +00:00
|
|
|
if (deleteAll || typeKey.keys.indexOf(value[i]) === -1) {
|
2016-01-21 00:40:15 +00:00
|
|
|
diff.push(value[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var valueNew = value;
|
|
|
|
for (var i2=0;i2<diff.length;i2++) {
|
|
|
|
var keyIdx = valueNew.indexOf(diff[i2]);
|
|
|
|
if (keyIdx !== -1) {
|
|
|
|
valueNew.splice(keyIdx,1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//utilDebug('cleanupCache value1: '+JSON.stringify(value));
|
|
|
|
//utilDebug('cleanupCache value2: '+JSON.stringify(valueNew));
|
|
|
|
|
|
|
|
utilRunStack('cleanupCacheItems',diff, function(key, cb) {
|
|
|
|
cacheDeleteValue(typeKey.type,key,cb);
|
|
|
|
}, function(err) {
|
|
|
|
if (err !== null) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
if (diff.length === 0) {
|
|
|
|
cb(null);
|
|
|
|
} else {
|
|
|
|
cacheSetValue(typeKey.type,'keys',valueNew ,cb);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}, cb);
|
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var injectResourceData = function(resource, data, cb) {
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('injectResourceData resource '+JSON.stringify(resource)+' data '+data.length);
|
2016-01-14 21:42:13 +00:00
|
|
|
var tag = null;
|
2016-03-13 23:52:48 +00:00
|
|
|
if (resource.type === 'css' || resource.type === 'dss') {
|
2016-01-14 21:42:13 +00:00
|
|
|
tag = document.createElement('style');
|
|
|
|
tag.type = 'text/css';
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
if (resource.type === 'js') {
|
|
|
|
tag = document.createElement('script');
|
|
|
|
tag.type = 'text/javascript';
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-03-14 00:50:47 +00:00
|
|
|
if (tag === null) {
|
|
|
|
return cb('Unknown resource type: '+resource.type);
|
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
tag.appendChild(document.createTextNode(data));
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
document.getElementsByTagName('head')[0].appendChild(tag);
|
|
|
|
//var ref = document.getElementsByTagName('script')[0];
|
|
|
|
//ref.parentNode.insertBefore(tag, ref); // note in reverse order
|
|
|
|
cb(null);
|
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-21 00:40:15 +00:00
|
|
|
/**
|
|
|
|
* Add all cache keys in central list so we can clear the cache item if resources are removed.
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {Object} resource The resource object with the type and hash.
|
|
|
|
* @param {function} cb Error first callback when done.
|
2016-01-21 00:40:15 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2016-01-14 21:42:13 +00:00
|
|
|
var storeResourceKey = function (resource, cb) {
|
2016-01-21 00:40:15 +00:00
|
|
|
var cacheKey = 'keys';
|
|
|
|
cacheGetValue(resource.type,cacheKey,function (err,value) {
|
2016-01-14 21:42:13 +00:00
|
|
|
if (err !== null) {
|
2016-01-21 00:40:15 +00:00
|
|
|
return cb(err);
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
if (value === null) {
|
|
|
|
value = [];
|
|
|
|
}
|
|
|
|
value.push(resource.hash);
|
2016-01-21 00:40:15 +00:00
|
|
|
cacheSetValue(resource.type,cacheKey,value, cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
var storeResource = function (resource, httpRequest, cb) {
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('storeResource url '+resource.url+' hash '+resource.hash);
|
2016-01-14 21:42:13 +00:00
|
|
|
var item = {
|
|
|
|
resource: resource,
|
|
|
|
data: httpRequest.responseText
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
cacheSetValue(resource.type, resource.hash, item , function(err) {
|
|
|
|
if (err !== null) {
|
|
|
|
cb(err);
|
2015-12-23 00:16:54 +00:00
|
|
|
} else {
|
2016-01-14 21:42:13 +00:00
|
|
|
storeResourceKey(resource,cb);
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
|
|
|
});
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-03-16 21:53:58 +00:00
|
|
|
var loadResource = function (resource, cb, loadDelayed) {
|
2016-04-20 16:15:23 +00:00
|
|
|
if (options.loader.delayDss === true && resource.type === 'dss' && loadDelayed === undefined) {
|
2016-03-16 21:53:58 +00:00
|
|
|
utilDebug('loadResource delay '+JSON.stringify(resource));
|
|
|
|
delayedResources.push(resource);
|
|
|
|
return cb(null);
|
|
|
|
}
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var resourceUrl = resource.url;
|
|
|
|
if (resourceUrl.indexOf('http') === -1) {
|
|
|
|
resourceUrl = options.server.url + resourceUrl;
|
|
|
|
}
|
|
|
|
utilDebug('loadResource '+JSON.stringify(resource));
|
|
|
|
if (cacheHasService(resource.type)) {
|
|
|
|
cacheGetValue(resource.type,resource.hash,function(err, value) {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (err !== null) { return cb(err); }
|
2016-01-14 21:42:13 +00:00
|
|
|
if (value === null) {
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('loadResource cache miss'); // + hash mismatch as its the key
|
2016-01-14 21:42:13 +00:00
|
|
|
} else if (value.resource === undefined) {
|
|
|
|
utilDebug('loadResource cache wrong obj');
|
|
|
|
} else {
|
|
|
|
utilDebug('loadResource cache hit');
|
|
|
|
injectResourceData(value.resource,value.data,cb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
utilHttpFetch(resourceUrl, function(err, httpRequest) {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
storeResource(resource, httpRequest, function (err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
injectResourceData(resource,httpRequest.responseText,cb);
|
|
|
|
});
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// note: was links but now download + inject so order stays sequenced
|
|
|
|
utilHttpFetch(resourceUrl, function(err, httpRequest) {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
injectResourceData(resource,httpRequest.responseText,cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
var createLoaderBar = function (resources) {
|
|
|
|
|
|
|
|
var rootTag = null;
|
|
|
|
var prevResource = null;
|
|
|
|
var step = 0;
|
|
|
|
var stepMax = resources.length;
|
|
|
|
var stepProgres = 0;
|
|
|
|
var stepProgres10 = 0;
|
|
|
|
|
|
|
|
var createUITimeout = setTimeout( function () {
|
2016-02-26 23:24:43 +00:00
|
|
|
utilDebug('createLoaderBar after timeout: '+options.loader.await);
|
2016-02-26 22:40:29 +00:00
|
|
|
|
|
|
|
rootTag = document.createElement('div');
|
|
|
|
rootTag.setAttribute('class','ffWrapper');
|
|
|
|
|
|
|
|
var loaderTitleTag = document.createElement('div');
|
|
|
|
loaderTitleTag.setAttribute('class','ffTitle');
|
|
|
|
loaderTitleTag.appendChild(document.createTextNode(options.loader.title));
|
|
|
|
rootTag.appendChild(loaderTitleTag);
|
|
|
|
|
|
|
|
if (options.loader.progres.items.enable) {
|
|
|
|
var loaderItemTag = document.createElement('div');
|
|
|
|
loaderItemTag.setAttribute('class','ffLoaderItem');
|
|
|
|
rootTag.appendChild(loaderItemTag);
|
|
|
|
|
|
|
|
resources.forEach(function(resource) {
|
|
|
|
var shortUrl = resource.url;
|
|
|
|
var shortUrlSize = options.loader.progres.items.size;
|
|
|
|
if (shortUrl.length > shortUrlSize) {
|
|
|
|
shortUrl = '...'+shortUrl.substring(shortUrl.length-shortUrlSize,shortUrl.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
var loaderItemResourceTag = document.createElement('div');
|
|
|
|
loaderItemResourceTag.setAttribute('id',resource.hash);
|
|
|
|
loaderItemResourceTag.setAttribute('class','ffLoaderItemText');
|
|
|
|
loaderItemResourceTag.appendChild(document.createTextNode(shortUrl));
|
|
|
|
|
|
|
|
loaderItemTag.appendChild(loaderItemResourceTag);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.loader.progres.bar.enable) {
|
|
|
|
var loaderBarTag = document.createElement('div');
|
|
|
|
loaderBarTag.setAttribute('class','ffLoaderBar');
|
|
|
|
rootTag.appendChild(loaderBarTag);
|
|
|
|
|
|
|
|
for (var i=1;i<=10;i++) {
|
|
|
|
var loaderBarStepTag = document.createElement('div');
|
|
|
|
loaderBarStepTag.setAttribute('id','barStep'+(i*10));
|
|
|
|
loaderBarStepTag.setAttribute('class','ffLoaderBarStep');
|
|
|
|
if (options.loader.progres.bar.percentage) {
|
|
|
|
loaderBarStepTag.appendChild(document.createTextNode(i*10));
|
|
|
|
}
|
|
|
|
loaderBarTag.appendChild(loaderBarStepTag);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var footerTag = document.createElement('div');
|
|
|
|
footerTag.setAttribute('class','ffFooter');
|
|
|
|
footerTag.appendChild(document.createTextNode(options.loader.footer));
|
|
|
|
rootTag.appendChild(footerTag);
|
|
|
|
|
|
|
|
document.getElementsByTagName('body')[0].appendChild(rootTag);
|
|
|
|
}, options.loader.await);
|
|
|
|
|
|
|
|
return {
|
|
|
|
nextResource: function(resource) {
|
|
|
|
var resourceTag = document.getElementById(resource.hash);
|
|
|
|
if (resourceTag !== null) {
|
|
|
|
resourceTag.setAttribute('class','ffLoaderItemTextStart');
|
|
|
|
}
|
|
|
|
if (prevResource !== null) {
|
|
|
|
var prevResourceTag = document.getElementById(prevResource.hash);
|
|
|
|
if (prevResourceTag !== null) {
|
|
|
|
prevResourceTag.setAttribute('class','ffLoaderItemTextDone');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prevResource = resource;
|
|
|
|
step++;
|
|
|
|
stepProgres = Math.round(step*100/stepMax);
|
|
|
|
|
|
|
|
if (stepProgres > stepProgres10) {
|
|
|
|
stepProgres10 += 10;
|
|
|
|
|
|
|
|
for (var i=1;i<=10;i++) {
|
|
|
|
if ((i*10) > stepProgres10) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var barStepTag = document.getElementById('barStep'+(i*10));
|
|
|
|
if (barStepTag !== null) {
|
|
|
|
barStepTag.setAttribute('class','ffLoaderBarStepDone');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
done: function() {
|
|
|
|
clearTimeout(createUITimeout);
|
|
|
|
if (rootTag !== null) {
|
|
|
|
rootTag.setAttribute('class','ffWrapper ffWrapperFadeOut');
|
|
|
|
setTimeout ( function () {
|
|
|
|
document.getElementsByTagName('body')[0].removeChild(rootTag);
|
|
|
|
}, 500);
|
|
|
|
}
|
|
|
|
}
|
2016-03-14 00:52:26 +00:00
|
|
|
};
|
2016-02-26 22:40:29 +00:00
|
|
|
};
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* Starts loader by downloading resource list or using cache version to
|
|
|
|
* load/refresh/inject the resources.
|
|
|
|
*
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {function} cb Error first callback when done.
|
2016-01-14 21:42:13 +00:00
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var startLoader = function (cb) {
|
|
|
|
if (options.server.url === null) {
|
2016-01-20 20:57:05 +00:00
|
|
|
cb(new Error('No url'));
|
2016-01-14 21:42:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
if (options.server.assets === null) {
|
2016-01-20 20:57:05 +00:00
|
|
|
cb(new Error('No assets'));
|
2016-01-14 21:42:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
rootWindow[options.server.flag] = options.server.url;
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-01-16 17:24:37 +00:00
|
|
|
var resourcesUrl = options.server.url + options.server.assets;
|
|
|
|
utilDebug('startLoader assets \"'+resourcesUrl+'\"');
|
2016-01-14 21:42:13 +00:00
|
|
|
utilHttpFetch(resourcesUrl, function(err, httpRequest) {
|
|
|
|
if (err !== null) {
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('startLoader fetch error '+err);
|
2016-01-14 21:42:13 +00:00
|
|
|
if (cacheHasService('meta')) {
|
|
|
|
cacheGetValue('meta','server_resources',function(err, value) {
|
|
|
|
if (err !== null) {
|
|
|
|
cb(err);
|
|
|
|
} else if (value === null) {
|
2016-01-20 20:57:05 +00:00
|
|
|
cb(new Error('Have no cache of server resouces from '+options.server.url));
|
2016-01-14 21:42:13 +00:00
|
|
|
} else {
|
2016-01-21 00:40:15 +00:00
|
|
|
utilRunStack('injectResources', value, function(resource, cb) {
|
|
|
|
cacheGetValue(resource.type,resource.hash,function(err,item) {
|
|
|
|
injectResourceData(resource,item.data,cb);
|
|
|
|
});
|
|
|
|
} , cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
2016-01-20 20:57:05 +00:00
|
|
|
cb(new Error('Could not fetch server resouces from '+options.server.url));
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
return;
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-03-13 23:42:10 +00:00
|
|
|
var resources = null;
|
|
|
|
try {
|
|
|
|
var responseObject = JSON.parse(httpRequest.responseText);
|
|
|
|
if (responseObject.data === undefined) {
|
|
|
|
return cb('No data in json');
|
|
|
|
}
|
|
|
|
if (responseObject.data.resources === undefined) {
|
|
|
|
return cb('No resources in json');
|
|
|
|
}
|
|
|
|
if (responseObject.data.resources.length === 0) {
|
|
|
|
return cb('Empty resources in json');
|
|
|
|
}
|
|
|
|
resources = responseObject.data.resources;
|
|
|
|
} catch (parseError) {
|
|
|
|
return cb(parseError);
|
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('startLoader resources '+resources.length);
|
2016-02-26 22:40:29 +00:00
|
|
|
|
|
|
|
var progressBar = createLoaderBar(resources);
|
|
|
|
var loadResourceStep = function (resource, cb) {
|
|
|
|
loadResource(resource,cb);
|
|
|
|
progressBar.nextResource(resource);
|
2016-03-14 00:52:26 +00:00
|
|
|
};
|
2016-02-26 22:40:29 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
if (cacheHasService('meta')) {
|
|
|
|
cacheSetValue('meta','server_resources',resources, function (err) {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (err !== null) { return cb(err); }
|
2016-02-26 22:40:29 +00:00
|
|
|
utilRunStack('loadResources', resources, loadResourceStep , function (err) {
|
|
|
|
progressBar.done();
|
2016-03-14 00:50:47 +00:00
|
|
|
if (err === null) {
|
|
|
|
cleanupCache(resources,false,cb); // only clean when fetched + cached
|
|
|
|
} else {
|
|
|
|
cb(err);
|
|
|
|
}
|
2016-01-21 00:40:15 +00:00
|
|
|
});
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
2015-12-23 00:16:54 +00:00
|
|
|
} else {
|
2016-02-26 22:40:29 +00:00
|
|
|
utilRunStack('loadResources', resources, loadResourceStep , function (err) {
|
|
|
|
progressBar.done();
|
2016-03-14 00:50:47 +00:00
|
|
|
cb(err); // done or error
|
2016-02-26 22:40:29 +00:00
|
|
|
});
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-03-13 23:26:00 +00:00
|
|
|
}, true);
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* Validates the user input url by downloading it.
|
|
|
|
*
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {HTMLElement} deleteTag The dom element to remove from the body tag after success.
|
|
|
|
* @param {function} cb Error first callback when done.
|
2016-01-14 21:42:13 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2016-01-22 14:44:43 +00:00
|
|
|
var askUrlValidate = function (deleteTag, cb) {
|
2016-04-20 16:15:23 +00:00
|
|
|
|
|
|
|
if (askUrlSubmitLock === true) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
askUrlSubmitLock = true;
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var inputTag = document.getElementById('serverInput');
|
|
|
|
var inputErrorTag = document.getElementById('serverInputError');
|
2016-01-21 21:17:22 +00:00
|
|
|
var inputValueRaw = inputTag.value;
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
while (inputErrorTag.firstChild) {
|
2016-01-22 12:52:28 +00:00
|
|
|
inputErrorTag.removeChild(inputErrorTag.firstChild);
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-01-21 21:17:22 +00:00
|
|
|
var inputValueHost = null;
|
|
|
|
if (inputValueRaw.indexOf("://") >= 0) {
|
|
|
|
inputValueHost = inputValueRaw.split('/')[2];
|
|
|
|
} else {
|
|
|
|
inputValueHost = inputValueRaw.split('/')[0];
|
|
|
|
}
|
2016-04-20 16:15:23 +00:00
|
|
|
var inputValuePath = inputValueRaw.split(inputValueHost)[1];
|
2016-01-21 21:17:22 +00:00
|
|
|
|
|
|
|
if (options.question.validate.min.value !== false && inputValueHost.length < options.question.validate.min.value) {
|
|
|
|
inputErrorTag.appendChild(document.createTextNode(options.question.validate.min.message));
|
2016-04-20 16:15:23 +00:00
|
|
|
askUrlSubmitLock = false;
|
2016-01-21 21:17:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (options.question.validate.max.value !== false && inputValueHost.length > options.question.validate.max.value) {
|
|
|
|
inputErrorTag.appendChild(document.createTextNode(options.question.validate.max.message));
|
2016-04-20 16:15:23 +00:00
|
|
|
askUrlSubmitLock = false;
|
2016-01-21 21:17:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (options.question.validate.regex.value !== false && options.question.validate.regex.value.length !== 0) {
|
|
|
|
var regex = new RegExp(options.question.validate.regex.value);
|
|
|
|
if (inputValueHost.match(regex) === null) {
|
|
|
|
inputErrorTag.appendChild(document.createTextNode(options.question.validate.regex.message));
|
2016-04-20 16:15:23 +00:00
|
|
|
askUrlSubmitLock = false;
|
2016-01-21 21:17:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inputValueRaw.indexOf('https') === 0) {
|
|
|
|
options.server.url = 'https://' + inputValueHost; // allow user to upgrade to https but not to downgrade to http
|
|
|
|
} else {
|
|
|
|
options.server.url = options.question.transport + inputValueHost;
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-04-20 16:15:23 +00:00
|
|
|
options.server.url = options.server.url + inputValuePath;
|
|
|
|
|
|
|
|
utilCleanServerUrl();
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-01-16 17:24:37 +00:00
|
|
|
var resourcesUrl = options.server.url + options.server.assets;
|
|
|
|
utilDebug('askUrlStart check assets '+resourcesUrl);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-01-17 20:57:59 +00:00
|
|
|
utilHttpFetch(resourcesUrl,function(err, httpRequest) {
|
2016-01-14 21:42:13 +00:00
|
|
|
if (err !== null) {
|
2016-02-26 23:24:43 +00:00
|
|
|
inputErrorTag.appendChild(document.createTextNode('Error '+err));
|
2016-04-20 16:15:23 +00:00
|
|
|
askUrlSubmitLock = false;
|
2016-01-14 21:42:13 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
if (httpRequest.responseText.length === 0) {
|
|
|
|
inputErrorTag.appendChild(document.createTextNode('Error Got empty data.'));
|
2016-04-20 16:15:23 +00:00
|
|
|
askUrlSubmitLock = false;
|
2016-01-17 20:57:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
deleteTag.setAttribute('class','ffWrapper ffWrapperFadeOut');
|
2016-01-22 12:52:28 +00:00
|
|
|
var clearUi = function(err) {
|
2016-01-24 20:38:21 +00:00
|
|
|
document.getElementsByTagName('body')[0].removeChild(deleteTag); // also delete on error
|
|
|
|
cb(err);
|
2016-01-22 12:52:28 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
if (cacheHasService('meta')) {
|
|
|
|
cacheSetValue('meta','server_url',options.server.url, function(err) {
|
2016-01-17 20:57:59 +00:00
|
|
|
if (err !== null) { return cb(err); }
|
2016-01-22 12:52:28 +00:00
|
|
|
startLoader(clearUi);
|
2016-01-14 21:42:13 +00:00
|
|
|
});
|
|
|
|
} else {
|
2016-01-22 12:52:28 +00:00
|
|
|
startLoader(clearUi);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-03-13 23:26:00 +00:00
|
|
|
}, true);
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* Creates the ask url ui.
|
|
|
|
*
|
|
|
|
* @param {function} cb Callback gets called when loader is done.
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var askUrl = function (cb) {
|
|
|
|
utilDebug('askUrl create ui');
|
|
|
|
|
|
|
|
var rootTag = document.createElement('div');
|
2016-02-26 22:40:29 +00:00
|
|
|
rootTag.setAttribute('class','ffWrapper');
|
|
|
|
|
|
|
|
var formTag = document.createElement('div');
|
|
|
|
formTag.setAttribute('class','ffQuestion');
|
|
|
|
rootTag.appendChild(formTag);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
var titleTag = document.createElement('div');
|
|
|
|
titleTag.setAttribute('class','ffQuestionTitle');
|
2016-01-21 19:42:18 +00:00
|
|
|
titleTag.appendChild(document.createTextNode(options.question.title));
|
2016-02-26 22:40:29 +00:00
|
|
|
formTag.appendChild(titleTag);
|
2016-01-16 17:24:37 +00:00
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
var questionTag = document.createElement('div');
|
|
|
|
questionTag.setAttribute('class','ffQuestionText');
|
2016-01-21 19:42:18 +00:00
|
|
|
questionTag.appendChild(document.createTextNode(options.question.text));
|
2016-02-26 22:40:29 +00:00
|
|
|
formTag.appendChild(questionTag);
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
var inputTag = document.createElement('input');
|
2016-02-26 22:40:29 +00:00
|
|
|
inputTag.setAttribute('type','text');
|
|
|
|
inputTag.setAttribute('id','serverInput');
|
2016-01-14 21:42:13 +00:00
|
|
|
inputTag.setAttribute('autofocus','');
|
|
|
|
inputTag.setAttribute('onkeydown','if (event.keyCode == 13) {document.getElementById(\'serverSubmit\').click()}');
|
2016-01-24 17:58:52 +00:00
|
|
|
inputTag.setAttribute('size',options.question.size);
|
2016-01-14 21:42:13 +00:00
|
|
|
formTag.appendChild(inputTag);
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var submitTag = document.createElement('input');
|
2016-02-26 22:40:29 +00:00
|
|
|
submitTag.setAttribute('id','serverSubmit');
|
|
|
|
submitTag.setAttribute('type','submit');
|
|
|
|
submitTag.setAttribute('value',options.question.submit);
|
2016-01-22 14:44:43 +00:00
|
|
|
submitTag.onclick = function() {askUrlValidate(rootTag,cb);};
|
2016-01-14 21:42:13 +00:00
|
|
|
formTag.appendChild(submitTag);
|
2015-12-23 00:16:54 +00:00
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
var serverErrorTag = document.createElement('div');
|
2016-02-26 22:40:29 +00:00
|
|
|
serverErrorTag.setAttribute('id','serverInputError');
|
2016-01-21 23:02:39 +00:00
|
|
|
serverErrorTag.setAttribute('class','ffQuestionError');
|
2016-01-14 21:42:13 +00:00
|
|
|
formTag.appendChild(serverErrorTag);
|
|
|
|
|
2016-02-26 22:40:29 +00:00
|
|
|
var footerTag = document.createElement('div');
|
|
|
|
footerTag.setAttribute('class','ffFooter');
|
|
|
|
footerTag.appendChild(document.createTextNode(options.loader.footer));
|
|
|
|
rootTag.appendChild(footerTag);
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
document.getElementsByTagName('body')[0].appendChild(rootTag);
|
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Starts an cache type by auto selecting if needed and opening it if needed.
|
|
|
|
*
|
|
|
|
* @param {String} type The cache type to start.
|
|
|
|
* @param {function} cb Callback gets called when loader is done.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-16 17:24:37 +00:00
|
|
|
var startCacheType = function (type,cb) {
|
|
|
|
if (options.cache[type] !== null && options.cache[type] === false) {
|
|
|
|
utilDebug('startCacheType '+type+' disabled');
|
|
|
|
options.cache[type] = null;
|
|
|
|
return cb(null);
|
|
|
|
}
|
|
|
|
if (options.cache[type] === null) {
|
|
|
|
if (factory.detect.cordovaDevice() && factory.detect.sqlitePlugin()) {
|
|
|
|
utilDebug('startCacheType auto sqlitePlugin for '+type);
|
2016-01-24 21:03:24 +00:00
|
|
|
options.cache[type] = factory.cache.websql({open: function(dbOpt) { return sqlitePlugin.openDatabase(dbOpt.name, dbOpt.version, dbOpt.name, dbOpt.size);}});
|
2016-01-16 17:24:37 +00:00
|
|
|
} else if (factory.detect.openDatabase()) {
|
|
|
|
utilDebug('startCacheType auto openDatabase for '+type);
|
|
|
|
options.cache[type] = factory.cache.websql();
|
|
|
|
} else if (factory.detect.localStorage()) {
|
|
|
|
utilDebug('startCacheType auto localStorage for '+type);
|
|
|
|
options.cache[type] = factory.cache.localStorage();
|
|
|
|
} else {
|
|
|
|
utilDebug('startCacheType '+type+' none');
|
|
|
|
}
|
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
if (options.cache[type] !== null && typeof options.cache[type].cacheOpen === 'function') {
|
2016-01-16 17:24:37 +00:00
|
|
|
options.cache[type].cacheOpen(cb);
|
|
|
|
} else {
|
|
|
|
cb(null);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Starts all cache types.
|
|
|
|
*
|
|
|
|
* @param {function} cb Callback gets called when loader is done.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-16 17:24:37 +00:00
|
|
|
var startCache = function (cb) {
|
2016-01-24 17:58:52 +00:00
|
|
|
// FIXME: use dynamic loop for user defined types.
|
2016-01-16 17:24:37 +00:00
|
|
|
startCacheType('meta', function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
startCacheType('js', function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
startCacheType('css', function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
2016-03-13 23:52:48 +00:00
|
|
|
startCacheType('dss', cb);
|
2016-01-16 17:24:37 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-03-16 21:53:58 +00:00
|
|
|
var loadDelayedResouces = function() {
|
|
|
|
if (delayedResources.length === 0) {
|
|
|
|
return; // nop
|
|
|
|
}
|
|
|
|
var loadResourceStep = function (resource, cb) {
|
|
|
|
loadResource(resource,cb, true);
|
|
|
|
};
|
|
|
|
utilRunStack('loadResources', delayedResources, loadResourceStep , function (/*err*/) {
|
|
|
|
//cb(err);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-14 21:42:13 +00:00
|
|
|
/**
|
|
|
|
* Starts the loader.
|
|
|
|
*
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {function} cb Optional callback gets called when loader is done.
|
2016-01-14 21:42:13 +00:00
|
|
|
*/
|
|
|
|
var start = function (cbArgu) {
|
|
|
|
var startTime = new Date().getTime();
|
|
|
|
var cb = function(err) {
|
|
|
|
if (err !== null) {
|
2016-01-16 17:24:37 +00:00
|
|
|
options.error.handler(err);
|
2015-12-23 00:16:54 +00:00
|
|
|
} else {
|
2016-03-16 20:58:27 +00:00
|
|
|
utilDebug('start done in '+(new Date().getTime()-startTime)+' ms.'); // last debug line TODO: move bootAngular to onjsloaded
|
|
|
|
bootCleanup(); // move after ang.
|
2016-01-16 17:24:37 +00:00
|
|
|
bootAngular(function(err) {
|
|
|
|
if (err !== null) { return options.error.handler(err); }
|
2016-03-16 21:53:58 +00:00
|
|
|
loadDelayedResouces();
|
2016-01-17 20:57:59 +00:00
|
|
|
if (typeof cbArgu === 'function') {
|
2016-01-16 17:24:37 +00:00
|
|
|
cbArgu();
|
2016-01-20 20:57:05 +00:00
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
});
|
2015-12-23 00:16:54 +00:00
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-24 17:58:52 +00:00
|
|
|
utilDebug('start spa loader'); // first debug line TODO: Add version
|
2016-04-20 16:15:23 +00:00
|
|
|
|
|
|
|
if (options.server.url !== null) {
|
|
|
|
utilCleanServerUrl();
|
|
|
|
}
|
|
|
|
|
2016-01-16 17:24:37 +00:00
|
|
|
if (options.debug.enable === true) {
|
|
|
|
var optionsKeys = Object.keys(options);
|
|
|
|
for (var keyId in optionsKeys) {
|
|
|
|
var key = optionsKeys[keyId];
|
|
|
|
utilDebug('start config '+key+' '+JSON.stringify(options[key]));
|
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
bootCordova(function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
startCache(function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
if (options.server.url !== null) {
|
2016-01-14 21:42:13 +00:00
|
|
|
startLoader(cb);
|
2016-01-16 17:24:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cacheHasService('meta')) {
|
|
|
|
cacheGetValue('meta','server_url',function(err, value) {
|
|
|
|
if (err !== null) {
|
|
|
|
cb(err);
|
|
|
|
} else if (value === undefined || value === null || value === '') {
|
|
|
|
askUrl(cb);
|
|
|
|
} else {
|
|
|
|
options.server.url = value;
|
|
|
|
startLoader(cb);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
askUrl(cb);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
|
|
|
});
|
2016-01-16 17:24:37 +00:00
|
|
|
});
|
2015-12-23 00:16:54 +00:00
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Clears the server url.
|
|
|
|
*
|
|
|
|
* @param {function} cb Optional Error first callback gets called when value is deleted.
|
|
|
|
*/
|
2016-01-16 17:24:37 +00:00
|
|
|
var clearServerUrl = function(cb) {
|
2016-01-14 23:36:10 +00:00
|
|
|
if (cb === undefined) {
|
|
|
|
cb = function() {};
|
|
|
|
}
|
|
|
|
if (cacheHasService('meta')) {
|
2016-01-22 14:44:43 +00:00
|
|
|
cacheDeleteValue('meta','server_url',function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
2016-04-20 16:15:23 +00:00
|
|
|
cacheDeleteValue('meta','server_resources',function(err) {
|
|
|
|
if (err !== null) { return cb(err); }
|
|
|
|
|
|
|
|
setTimeout(function() {cb(null);}); // return next tick so (websql) transaction is flushed before location.reload
|
|
|
|
});
|
2016-01-22 14:44:43 +00:00
|
|
|
});
|
2016-01-14 23:36:10 +00:00
|
|
|
} else {
|
|
|
|
cb(null);
|
|
|
|
}
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 23:36:10 +00:00
|
|
|
|
2016-01-24 18:44:00 +00:00
|
|
|
/**
|
|
|
|
* Clears the cache.
|
|
|
|
*
|
|
|
|
* @param {function} cb Optional Error first callback gets called when cache is cleared.
|
|
|
|
*/
|
|
|
|
var clearCache = function(cb2) {
|
|
|
|
if (cb2 === undefined) {
|
|
|
|
cb2 = function() {};
|
|
|
|
}
|
|
|
|
var cb = function(err) {
|
|
|
|
setTimeout(function() {cb2(err);}); // next tick to flush transactions.
|
|
|
|
};
|
|
|
|
if (cacheHasService('meta')) {
|
|
|
|
cacheGetValue('meta','server_resources',function(err, value) {
|
|
|
|
if (err !== null) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
if (value === null) {
|
|
|
|
return cb(new Error('No cache value')); // TODO: check this or cb(null) or do fetch ?
|
|
|
|
}
|
|
|
|
cleanupCache(value,true,cb);
|
|
|
|
});
|
|
|
|
|
|
|
|
} else {
|
|
|
|
utilHttpFetch(options.server.url + options.server.assets,function(err, httpRequest) {
|
|
|
|
if (err !== null) {
|
|
|
|
return cb(err);
|
|
|
|
}
|
|
|
|
var resources = JSON.parse(httpRequest.responseText).data.resources;
|
|
|
|
cleanupCache(resources,false,cb);
|
2016-03-16 20:58:27 +00:00
|
|
|
}, true); // TODO: create resourcesListFetch();
|
2016-01-24 18:44:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-16 20:58:27 +00:00
|
|
|
/**
|
|
|
|
* Boot cleanup removed the html tags by id after the timeout.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var bootCleanup = function() {
|
|
|
|
if (options.boot.cleanup.enable !== true) {
|
|
|
|
utilDebug('bootCleanup disabled by options');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (options.boot.cleanup.tags.length === 0) {
|
|
|
|
utilDebug('bootCleanup disabled by no tags ids.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
utilDebug('bootCleanup after '+options.boot.cleanup.timeout+' ms.');
|
|
|
|
setTimeout ( function () {
|
|
|
|
for (var tagIdx in options.boot.cleanup.tags) {
|
|
|
|
var tagId = options.boot.cleanup.tags[tagIdx];
|
|
|
|
var tag = document.getElementById(tagId);
|
|
|
|
if (tag !== null) {
|
|
|
|
tag.parentNode.removeChild(tag);
|
|
|
|
utilDebug('bootCleanup removed '+tagId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, options.boot.cleanup.timeout);
|
|
|
|
};
|
|
|
|
|
2016-01-22 14:44:43 +00:00
|
|
|
/**
|
|
|
|
* Boots angular modules if enabled.
|
|
|
|
*
|
|
|
|
* @param {function} cb Error first callback gets called done.
|
|
|
|
* @private
|
|
|
|
*/
|
2016-01-16 17:24:37 +00:00
|
|
|
var bootAngular = function(cb) {
|
|
|
|
if (options.boot.angular.enable !== true) {
|
|
|
|
utilDebug('bootAngular disabled by options');
|
|
|
|
return cb(null);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
if (options.boot.angular.modules.length === 0) {
|
|
|
|
utilDebug('bootAngular disabled by no modules');
|
|
|
|
return cb(null);
|
2016-01-14 21:42:13 +00:00
|
|
|
}
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('bootAngular start '+options.boot.angular.modules);
|
|
|
|
angular.bootstrap(document, options.boot.angular.modules);
|
|
|
|
cb(null);
|
2016-01-17 20:57:59 +00:00
|
|
|
};
|
2016-01-14 21:42:13 +00:00
|
|
|
|
|
|
|
/**
|
2016-01-22 14:44:43 +00:00
|
|
|
* Boots cordova applications which want to use the sqllite plugin as cache.
|
2016-01-14 21:42:13 +00:00
|
|
|
* Note: On none cordova page it will callback directly.
|
2016-01-22 14:44:43 +00:00
|
|
|
* Note: On none cordova device page is will timeout if option is set.
|
2016-01-14 21:42:13 +00:00
|
|
|
*
|
2016-01-22 14:44:43 +00:00
|
|
|
* @param {function} cb Error first callback gets called device is ready.
|
2016-01-16 17:24:37 +00:00
|
|
|
* @private
|
2016-01-14 21:42:13 +00:00
|
|
|
*/
|
2016-01-16 17:24:37 +00:00
|
|
|
var bootCordova = function(cb) {
|
|
|
|
if (options.boot.cordova.enable !== true) {
|
|
|
|
utilDebug('bootCordova disabled by options');
|
|
|
|
return cb(null);
|
|
|
|
}
|
|
|
|
if (factory.detect.cordova() !== true) {
|
|
|
|
utilDebug('bootCordova disabled by detect');
|
|
|
|
return cb(null);
|
|
|
|
}
|
2016-01-14 21:42:13 +00:00
|
|
|
var startTime = new Date().getTime();
|
|
|
|
var bootOnce = function() {
|
2016-01-16 17:24:37 +00:00
|
|
|
var callback = cb;
|
|
|
|
cb = null;
|
|
|
|
utilDebug('bootCordova done in '+(new Date().getTime()-startTime)+' ms.');
|
2016-01-22 12:52:28 +00:00
|
|
|
callback(null);
|
2016-01-14 21:42:13 +00:00
|
|
|
};
|
2016-01-18 21:41:52 +00:00
|
|
|
if (options.boot.cordova.timeout > 0) {
|
|
|
|
utilDebug('bootCordova timeout '+options.boot.cordova.timeout);
|
|
|
|
setTimeout ( function () {
|
|
|
|
utilDebug('bootCordova timeout');
|
|
|
|
bootOnce();
|
|
|
|
}, options.boot.cordova.timeout);
|
|
|
|
}
|
2016-01-20 19:35:43 +00:00
|
|
|
document.addEventListener('deviceready', function () {
|
2016-01-17 20:57:59 +00:00
|
|
|
rootWindow[options.boot.cordova.flag] = true;
|
2016-01-16 17:24:37 +00:00
|
|
|
utilDebug('bootCordova '+options.boot.cordova.flag);
|
2016-01-14 21:42:13 +00:00
|
|
|
bootOnce();
|
|
|
|
}, false);
|
2015-12-23 00:16:54 +00:00
|
|
|
};
|
|
|
|
|
2016-01-16 17:24:37 +00:00
|
|
|
// Auto fill handlers and return public object.
|
|
|
|
options.debug.handler = function(msg) {console.log(msg);};
|
|
|
|
options.error.handler = utilErrorHandler;
|
2015-12-23 00:16:54 +00:00
|
|
|
return {
|
2016-01-14 21:42:13 +00:00
|
|
|
options: options,
|
|
|
|
factory: factory,
|
|
|
|
start: start,
|
2016-01-24 18:44:00 +00:00
|
|
|
clearServerUrl: clearServerUrl,
|
|
|
|
clearCache: clearCache
|
2015-12-23 00:16:54 +00:00
|
|
|
};
|
2016-01-17 20:57:59 +00:00
|
|
|
});
|