'use strict'; /* * 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. */ // TODO: // set tag.media = 'only you'; // add media in resouces // check supported browsers /** * FFSpaLoader is an assets loader for single page applications. * Its build around the concept the there is only a single static index.html which * synces all its assets to local cache for offline and or fast page loads. * * Features: * - Assets caching for offline use. * - Assets hashing for fast syncing. * - Assets types: js,css,cssData * - Caching backends: null,localStorage,webSqlDB,sqllite * - Optional ask and cache server assets url. * - Cordova deviceready event booting. * * @module FFSpaLoader */ var FFSpaLoader = (/** @lends module:FFSpaLoader */function () { var options = { debug: false, errorHandler: null, bootDevice: { timeout: 4096, windowFlag: 'FFCordovaDevice' }, askUrl: { urlTransport: 'http://', questionText: 'Please provide the server name;', cssText: '.ffAskUrl { font-size: 1em;margin: auto;width: 50%;border: 3px solid #73AD21;padding: 1em;} .ffAskUrl > div {font-size: 0.8em;color: #ccc;} .ffAskUrl > div > * {} .ffAskUrl > div > input {} .ffAskUrlError{ color: red}', }, server: { url: null, urlPath: null, timeout: 4096, windowFlag: 'FFServerUrl', header: { request: { 'X-FFSpaLoader': '42' }, response: { } } }, cache: { factory: null, meta: null, js: null, css: null, cssData: null } }; /** * Prints debug message to the console if options.debug is true. * @param {String} message The message to log. * @private */ var utilDebug = function (message) { if (options.debug !== true) { return; } console.log('FFSpaLoader.'+message); }; var factory = { detect: { localStorage: function() { try { var testData = 'localStorageDetect'; localStorage.setItem(testData, testData); localStorage.removeItem(testData); return true; } catch(e) { return false; } }, openDatabase: function() { return 'openDatabase' in window; }, sqlitePlugin: function() { return 'sqlitePlugin' in window; }, cordova: function() { return 'cordova' in window; }, cordovaDevice: function() { return options.bootDevice.windowFlag in window; }, mobileAgent: function() { return navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|IEMobile)/); } }, cache: { localStorage: function() { return { cacheGetValue: function(key, cb) { try { var dataRaw = localStorage.getItem(key); var data = JSON.parse(dataRaw); cb(null, data); } catch(e) { cb(e); } }, cacheSetValue: function(key, value, cb) { try { localStorage.setItem(key,JSON.stringify(value)); cb(null); } catch(e) { cb(e); } }, cacheDeleteValue: function(key, cb) { try { localStorage.removeItem(key); cb(null); } catch(e) { cb(e); } } } }, websql: function(opt) { if (opt === undefined) { opt = {}; } if (opt.name === undefined) { opt.name = 'ffSpaLoader.db'; } if (opt.size === undefined) { opt.size = -1; } if (opt.version === undefined) { opt.version = '1.0'; } if (opt.openDatabase === undefined) { opt.openDatabase = window.openDatabase; } var nullDataHandler = function(cb) { return function (tx, results) { cb(null); }; }; var sqlErrorHandler = function(cb) { return function (tx, err) { cb(err.message+' code: '+err.code); }; }; var cacheDB = window.openDatabase(opt.name, opt.version, opt.name, opt.size); cacheDB.transaction(function(tx) { var query = 'SELECT value FROM cache_store WHERE key = \"test-for-table\"'; utilDebug('websql.init query: '+query); tx.executeSql(query, [], function(tx,res) {}, function(tx,errorNoTable) { 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,res) { var query = 'CREATE UNIQUE INDEX cache_store__key__udx ON cache_store (key)'; utilDebug('websql.init query: '+query); tx.executeSql(query, [], function(tx,res) {}, sqlErrorHandler(options.errorHandler)); // FIX