2
0
Fork 0

Added mobile example app

This commit is contained in:
Willem 2016-01-24 21:38:21 +01:00
parent 4fbf705ae5
commit cf364fc418
26 changed files with 187 additions and 61 deletions

11
.gitignore vendored
View file

@ -10,12 +10,19 @@ node_modules
npm-debug.log
# Ignore mocha test data
test/data
test/data
# Ignore example data
example/node_modules
example/npm-debug.log
example/mobile_app
# Ignore example cordova data
example/app_mobile/platforms/*
!example/app_mobile/platforms/platforms.json
example/app_mobile/plugins/*
!example/app_mobile/plugins/android.json
!example/app_mobile/plugins/fetch.json
example/app_mobile/www/es5-ff-spa-loader.js
# Ignore binary files
*.o

View file

@ -161,8 +161,24 @@ A javascript library providing server defined loading of assets for a single pag
## Example Application
There is a fully working nodejs example application in the example folder.
There is a fully working nodejs example application in the example folder;
* git clone <repro-url>
* cd es5-ff-spa-loader
* cd example
* npm install
* npm start
For the mobile example install+build steps are;
* export ANDROID_HOME=/my/android-sdk/path
* npm install cordova -g
* cd es5-ff-spa-loader
* cd example
* cd app_mobile
* cordova platform add android
* cordova build
## Tested Browsers
* Chromium 46
@ -203,7 +219,9 @@ Add unit tests for any new or changed functionality. Lint and test your code.
* Fixed sqlitePlugin open function was typo on openDatabase.
* Added websql table option. (defaults to 'cache_store')
* Added clearCache function.
* Fixed removed question div on loader error.
* Updated example and removed it from npm.
### 0.1.0
* Moved options.server.question to options.question.
* Added question.validate.[min|max|regex].value|message options.

View file

@ -698,9 +698,8 @@
deleteTag.setAttribute('class','ffQuestion ffQuestionLoad');
var clearUi = function(err) {
if (err !== null) { return cb(err); }
document.getElementsByTagName('body')[0].removeChild(deleteTag);
cb(null);
document.getElementsByTagName('body')[0].removeChild(deleteTag); // also delete on error
cb(err);
};
if (cacheHasService('meta')) {
cacheSetValue('meta','server_url',options.server.url, function(err) {

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<widget id="net.forwardfire.spa.loader" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>FFSpaLoaderExample</name>
<description>
A sample FFSpaLoader example application.
</description>
<author email="ffspaloader.example.2016@forwardfire.net" href="http://forwardfire.net">
FFSpaLoaderExample
</author>
<content src="index.html" />
<plugin name="cordova-plugin-whitelist" spec="1" />
<plugin name="cordova-sqlite-storage" spec="1" />
<access origin="*" />
<icon src="www/img/ic_launcher_mdpi.png" />
<icon src="www/img/ic_launcher_mdpi.png" platform="android" density="ldpi" />
<icon src="www/img/ic_launcher_mdpi.png" platform="android" density="mdpi" />
<icon src="www/img/ic_launcher_hdpi.png" platform="android" density="hdpi" />
<icon src="www/img/ic_launcher_xhdpi.png" platform="android" density="xhdpi" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
<!-- Build for lowest version of cordova 5.x -->
<preference name="android-minSdkVersion" value="14" />
</platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
<!-- disable backup to ICloud of db file -->
<preference name="BackupWebStorage" value="none"/>
</platform>
<hook type="before_build" src="scripts/copy-ff-spa-loader.js" />
<hook type="after_build" src="scripts/rename-android-apk.js" />
</widget>

View file

@ -0,0 +1,3 @@
{
"android": "4.1.1"
}

View file

@ -0,0 +1,18 @@
{
"prepare_queue": {
"installed": [],
"uninstalled": []
},
"config_munge": {
"files": {}
},
"installed_plugins": {
"cordova-plugin-whitelist": {
"PACKAGE_NAME": "net.forwardfire.spa.loader"
},
"cordova-sqlite-storage": {
"PACKAGE_NAME": "net.forwardfire.spa.loader"
}
},
"dependent_plugins": {}
}

View file

@ -0,0 +1,18 @@
{
"cordova-sqlite-storage": {
"source": {
"type": "registry",
"id": "cordova-sqlite-storage"
},
"is_top_level": true,
"variables": {}
},
"cordova-plugin-whitelist": {
"source": {
"type": "registry",
"id": "cordova-plugin-whitelist@1"
},
"is_top_level": true,
"variables": {}
}
}

View file

@ -0,0 +1,16 @@
var fs = require('fs');
module.exports = function(context) {
var Q = context.requireCordovaModule('q');
var deferral = new Q.defer();
console.log('copy-ff-spa-loader start');
fs.readFile('../../es5-ff-spa-loader.js',function(err,data) {
if (err) return deferral.reject(err);
fs.writeFile('www/es5-ff-spa-loader.js',data,function(err) {
if (err) return deferral.reject(err);
console.log('copy-ff-spa-loader done');
deferral.resolve();
})
});
return deferral.promise;
}

View file

@ -0,0 +1,15 @@
var fs = require('fs');
module.exports = function(context) {
var Q = context.requireCordovaModule('q');
var deferral = new Q.defer();
var nameOld = 'platforms/android/build/outputs/apk/android-debug.apk';
var nameNew = 'platforms/android/build/outputs/apk/FFSpaLoaderExample.apk';
console.log('rename-android-apk start old: '+nameOld);
fs.rename(nameOld,nameNew,function(err) {
if (err) return deferral.reject(err);
console.log('rename-android-apk done new: '+nameNew);
deferral.resolve();
});
return deferral.promise;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap:">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
</head>
<body>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="es5-ff-spa-loader.js"></script>
<script>
FFSpaLoader.options.debug.enable = true;
FFSpaLoader.options.boot.angular.modules.push('exampleUI');
FFSpaLoader.options.server.assets = '/static/spa-client-resources';
FFSpaLoader.start();
</script>
</body>
</html>

View file

@ -1,15 +1,14 @@
'use strict';
var httpPort = 9090;
var express = require('express');
var path = require('path');
var fs = require('fs');
var fetch = require('fetch');
var cors = require('cors');
var morgan = require('morgan');
// example options;
var serverUrl = 'http://localhost:8080';
var useInline = true; // or false
var UglifyJS = require("uglify-js");
var Hashes = require('jshashes');
var clientResourcesWeb = [];
var clientResources = {
@ -22,21 +21,12 @@ var addClientResource = function(clientResource, resourceType) {
clientResources[resourceType].push(clientResource);
};
var stringHash = function (str) {
/* jslint bitwise: true */
var hash = 31; // prime
for (var i = 0; i < str.length; i++) {
hash = ((hash<<5)-hash)+str.charCodeAt(i);
hash = hash & hash; // keep 32b
}
return hash;
/* jslint bitwise: false */
};
var fetchHashResource = function(fetchEntry,cb) {
var serverUrl = 'http://localhost:'+httpPort;
var hashDigest = new Hashes.SHA1;
fetch.fetchUrl(serverUrl + fetchEntry.url,function(err, meta, data) {
if (err !== null) { return cb(err); }
var assetHash = stringHash(''+data);
var assetHash = hashDigest.hex(''+data);
clientResourcesWeb.push({
url: fetchEntry.url,
type: fetchEntry.type,
@ -88,17 +78,15 @@ function renderTemplatePath(viewPath) {
}
function renderIndex() {
var inlineData = fs.readFileSync(__dirname+'/../dist/es5-ff-spa-loader.min.js');
var inline = '\n\t\t<script>'+inlineData+'</script>';
var inlineNot = '\n\t\t<script src=\"/static/es5-ff-spa-loader.js\"></script>';
return function (req, res) {
var inlineScript = UglifyJS.minify(__dirname+'/../../es5-ff-spa-loader.js');
res.render('index', {
inlineNot: useInline?'':inlineNot,
inline: useInline?inline:''
inlineScript: inlineScript.code
});
};
}
// Add resources ORDERED per type
addClientResource('/static/module/jquery/jquery.js','js');
addClientResource('/static/module/angular/angular.js','js');
addClientResource('/static/module/angular-route/angular-route.js','js');
@ -106,8 +94,8 @@ addClientResource('/static/module/bootstrap/css/bootstrap.css','css');
addClientResource('/static/module/bootstrap/js/bootstrap.js','js');
addClientResource('/static/css/boot.css','css');
addClientResource('/static/css/style.css','css');
addClientResource('/static/js/example-app.js','js');
addClientResource('/static/js/controller/page-bar.js','js');
addClientResource('/static/js/example-app.js','js'); // deps: jquery,angular
addClientResource('/static/js/controller/page-bar.js','js'); // deps: example-app.js
addClientResource('/static/js/controller/page-foo.js','js');
addClientResource('/static/js/controller/page-index.js','js');
@ -117,30 +105,17 @@ server.use(cors({credentials: true, origin: '*'}));
server.set('view engine', 'ejs');
server.set('views', path.join(__dirname,'www_views'));
server.use('/static', express.static(path.join(__dirname,'www_static')));
server.use('/static/module/bootstrap', express.static(path.join(__dirname,'node_modules/bootstrap/dist')));
server.use('/static/module/jquery', express.static(path.join(__dirname,'node_modules/jquery/dist')));
server.use('/static/module/angular', express.static(path.join(__dirname,'node_modules/angular')));
server.use('/static/module/angular-route', express.static(path.join(__dirname,'node_modules/angular-route')));
server.use('/static/module/bootstrap', express.static(path.join(__dirname,'../node_modules/bootstrap/dist')));
server.use('/static/module/jquery', express.static(path.join(__dirname,'../node_modules/jquery/dist')));
server.use('/static/module/angular', express.static(path.join(__dirname,'../node_modules/angular')));
server.use('/static/module/angular-route', express.static(path.join(__dirname,'../node_modules/angular-route')));
server.get('/static/spa-client-resources', function (req,res) {res.json({data: {resources: clientResourcesWeb}});});
server.get('/', function (req, res) {res.redirect('/example-ui');});
server.get('/example-ui/thtml/*', renderTemplatePath('thtml/'));
server.get('/example-ui', renderIndex());
server.get('/static/es5-ff-spa-loader.js', function (req,res) {
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) {
res.json({data: {resources: clientResourcesWeb}});
});
server.get('/', function (req, res) {res.redirect('/example-ui');});
server.get('/example-ui/thtml/*', renderTemplatePath('thtml/'));
server.get('/example-ui', renderIndex());
console.info('Server config done.');
server.listen(8080);
console.info('Server started on port 8080');
server.listen(httpPort);
console.info('Server started on port '+httpPort);
var res = createClientResourceFetchList();
fetchHashResources(res, function(err) {

View file

@ -2,9 +2,10 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Loading</title><%- inlineNot %>
<title>Loading</title>
</head>
<body><%- inline %>
<body>
<script><%- inlineScript %></script>
<script>
FFSpaLoader.options.debug.enable = true;
FFSpaLoader.options.boot.angular.modules.push('exampleUI');

View file

@ -4,7 +4,7 @@
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node example.js"
"start": "node app_server/example.js"
},
"dependencies": {
"angular": "^1.4.8",
@ -15,6 +15,8 @@
"express": "4.11.x",
"fetch": "0.3.x",
"jquery": "^2.1.4",
"morgan": "^1.6.1"
"jshashes": "^1.0.5",
"morgan": "^1.6.1",
"uglify-js": "^2.6.1"
}
}

View file

@ -48,10 +48,6 @@
"dependencies": {},
"files": [
"README.md",
"example/www_static/",
"example/www_views/",
"example/example.js",
"example/package.json",
"dist/"
]
}