summaryrefslogtreecommitdiffstats
path: root/afb-client/app
diff options
context:
space:
mode:
Diffstat (limited to 'afb-client/app')
-rw-r--r--afb-client/app/Backend/RestApis/PostMockApi.js37
-rw-r--r--afb-client/app/Backend/RestApis/TokenMockApi.js114
-rw-r--r--afb-client/app/Backend/RestApis/_all.js29
-rw-r--r--afb-client/app/Backend/server.js58
-rw-r--r--afb-client/app/Frontend/app.js44
-rw-r--r--afb-client/app/Frontend/favicon.icobin0 -> 1150 bytes
-rw-r--r--afb-client/app/Frontend/images/avatars/istoobig.jpgbin0 -> 7204 bytes
-rw-r--r--afb-client/app/Frontend/images/avatars/tux-admin.pngbin0 -> 58558 bytes
-rw-r--r--afb-client/app/Frontend/images/avatars/tux-bzh.pngbin0 -> 65172 bytes
-rw-r--r--afb-client/app/Frontend/images/avatars/tux-visitor.pngbin0 -> 84573 bytes
-rw-r--r--afb-client/app/Frontend/images/login/fb-logo.pngbin0 -> 2482 bytes
-rw-r--r--afb-client/app/Frontend/images/login/gg-logo.pngbin0 -> 3554 bytes
-rw-r--r--afb-client/app/Frontend/images/login/gh-logo.pngbin0 -> 4946 bytes
-rw-r--r--afb-client/app/Frontend/images/login/iot-logo.pngbin0 -> 3471 bytes
-rw-r--r--afb-client/app/Frontend/images/login/lk-logo.pngbin0 -> 4579 bytes
-rw-r--r--afb-client/app/Frontend/images/login/ms-logo.pngbin0 -> 6036 bytes
-rw-r--r--afb-client/app/Frontend/images/login/og-logo.pngbin0 -> 2706 bytes
-rw-r--r--afb-client/app/Frontend/images/login/pp-logo.pngbin0 -> 3222 bytes
-rw-r--r--afb-client/app/Frontend/images/login/yh-logo.pngbin0 -> 5491 bytes
-rw-r--r--afb-client/app/Frontend/images/logo/logo_iot_bzh.svg139
-rw-r--r--afb-client/app/Frontend/images/logo/logo_iot_bzhx350.pngbin0 -> 14449 bytes
-rw-r--r--afb-client/app/Frontend/images/logo/tampon-iot-bzhx450.pngbin0 -> 44996 bytes
-rw-r--r--afb-client/app/Frontend/images/logo/triskel_iot_bzh.pngbin0 -> 55940 bytes
-rw-r--r--afb-client/app/Frontend/images/logo/triskel_iot_bzh.svg110
-rw-r--r--afb-client/app/Frontend/images/logo/triskel_iot_bzhx250.pngbin0 -> 18787 bytes
-rw-r--r--afb-client/app/Frontend/index.html41
-rw-r--r--afb-client/app/Frontend/pages/Home/Home.html33
-rw-r--r--afb-client/app/Frontend/pages/Home/HomeModule.js90
-rw-r--r--afb-client/app/Frontend/pages/Home/HomeModule.scss65
-rw-r--r--afb-client/app/Frontend/pages/Sample/Sample.html22
-rw-r--r--afb-client/app/Frontend/pages/Sample/SampleModule.js48
-rw-r--r--afb-client/app/Frontend/pages/Sample/SampleModule.scss41
-rw-r--r--afb-client/app/Frontend/services/ConfigApp.js25
-rw-r--r--afb-client/app/Frontend/services/JQueryEmu.js42
-rw-r--r--afb-client/app/Frontend/styles/README.md28
-rw-r--r--afb-client/app/Frontend/styles/app/_ibz-mixins.scss52
-rw-r--r--afb-client/app/Frontend/styles/app/ibz-global.scss43
-rw-r--r--afb-client/app/Frontend/styles/foundation/_foundation-icons.scss591
-rw-r--r--afb-client/app/Frontend/styles/foundation/_foundation-settings.scss605
-rw-r--r--afb-client/app/Frontend/styles/foundation/foundation-conf.scss19
-rw-r--r--afb-client/app/Frontend/tmp/routes.js1
-rw-r--r--afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js52
-rw-r--r--afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss22
-rw-r--r--afb-client/app/Frontend/widgets/FormInput/FormInput.scss69
-rw-r--r--afb-client/app/Frontend/widgets/FormInput/InputPassword.js79
-rw-r--r--afb-client/app/Frontend/widgets/FormInput/InputText.js179
-rw-r--r--afb-client/app/Frontend/widgets/FormInput/UploadFile.js113
-rw-r--r--afb-client/app/Frontend/widgets/Navigation/LinkButton.js57
-rw-r--r--afb-client/app/Frontend/widgets/Navigation/Navigation.scss26
-rw-r--r--afb-client/app/Frontend/widgets/Notifications/ModalNotification.js85
-rw-r--r--afb-client/app/Frontend/widgets/Notifications/Notifications.scss47
-rw-r--r--afb-client/app/etc/AppDefaults.js41
-rw-r--r--afb-client/app/etc/_Config.js44
-rw-r--r--afb-client/app/etc/_Trace.js55
54 files changed, 3146 insertions, 0 deletions
diff --git a/afb-client/app/Backend/RestApis/PostMockApi.js b/afb-client/app/Backend/RestApis/PostMockApi.js
new file mode 100644
index 0000000..6299f39
--- /dev/null
+++ b/afb-client/app/Backend/RestApis/PostMockApi.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var fs = require('fs');
+var multer = require('multer');
+
+function NewApi(handle, prefix) {
+ var self=this;
+ handle.trace (this,1, "Mock PostApi url=%s", prefix +'/ping');
+ var upload = multer({ dest: '/tmp/uploads/' });
+
+ handle.app.post(prefix +'/upload', upload.single('avatar'), function (req, res) {
+ handle.trace (self, 1, "%s/upload file=", prefix, req.file.originalname);
+ var upload = multer({ dest: '/tmp/uploads/' });
+
+ res.send({"jtype": "TEST_message", "status": "success", "info": "done"});
+ });
+
+}
+
+// Export Class
+module.exports = NewApi; \ No newline at end of file
diff --git a/afb-client/app/Backend/RestApis/TokenMockApi.js b/afb-client/app/Backend/RestApis/TokenMockApi.js
new file mode 100644
index 0000000..74b565a
--- /dev/null
+++ b/afb-client/app/Backend/RestApis/TokenMockApi.js
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* ----------------------------------------------------------------------
+ * This module simulate Application Framework Binder
+ *
+ * /api/afbs/create
+ * /api/afbs/check?token=123456789
+ * /api/afbs/refresh?token=123456789-xxxxx
+ * /api/afbs/reset?123456789-xxxxx
+ *
+ * Note: this MOCK api does not handle any session login. It only returns
+ * a fake valid or false message depending on call order.
+ * Its goal is to get a quick way to check you HTML5 client rendering & behaviour.
+ *
+ * When you're happy with you HTML5 client OnePageApp check it with afb-daemon
+ * ----------------------------------------------------------------------*/
+
+
+function NewApi(handle, prefix) {
+ var scope=this; // I hate JavaScript
+ scope.connected=false;
+
+ // Simulate Client Context Session Creation
+ handle.app.post(prefix +'/create', function (req, res) {
+ handle.trace (scope, 1, "%s/create body=%s", prefix, req.body.action);
+ var okResponse= '{ "jtype": "AJB_reply"' +
+ ', "request": { "prefix": "afbs", "api": "create", "uuid": "e4ef5e66-xxxx", "token": "123456789-xxxxx", "status": "processed" }'+
+ ', "response": { "token": "Token was refreshed" }'+
+ '}';
+
+ var fxResponse= '{ "jtype": "AJB_reply" ' +
+ ', "request": { "prefix": "afbs", "api": "create", "status": "fail", "info": "AFB_SESSION_REFRESH Not Initial Token Chain" }'+
+ '}';
+
+ if (scope.connected) res.status(401).send(fxResponse);
+ else {
+ res.send(okResponse);
+ scope.connected=true;
+ }
+ });
+
+
+ // Simulate Client Context Check
+ handle.app.post(prefix +'/check', function (req, res) {
+ handle.trace (scope, 1, "%s/check query=%s", prefix, req.query.token);
+ var okResponse= '{"jtype":"AJB_reply"'+
+ ',"request":{"prefix":"afbs","api":"check", "status":"processed"}'+
+ ',"response":{"isvalid":true}'+
+ '}';
+
+ var fxResponse= '{"jtype":"AJB_reply",'+
+ '"request":{"prefix":"afbs","api":"check","status":"empty","info":"AFB_SESSION_CHECK Not a Valid Active Token"}'+
+ '}';
+
+ if (!scope.connected) res.status(401).send(fxResponse);
+ else res.send(okResponse);
+ });
+
+ // Simulate Client Context Check
+ handle.app.post(prefix +'/refresh', function (req, res) {
+ handle.trace (scope, 1, "%s/refresh query=%s", prefix, req.query.token);
+ var okResponse= '{"jtype":"AJB_reply"'+
+ ',"request":{"prefix":"afbs","api":"refresh","uuid": "e4ef5e66-xxxx", "token": "123456789-xxxxx","status":"processed"}'+
+ ',"response":{"isvalid":true}'+
+ '}';
+
+ var fxResponse= '{"jtype":"AJB_reply",'+
+ '"request":{"prefix":"afbs","api":"refresh","status":"empty","info":"AFB_SESSION_REFRESH Not a Valid Active Token"}'+
+ '}';
+
+ if (!scope.connected) res.status(401).send(fxResponse);
+ else res.send(okResponse);
+ });
+
+ // Simulate Client Context Session Closing
+ handle.app.post(prefix +'/reset', function (req, res) {
+ handle.trace (scope, 1, "%s/reset query=%s", prefix, req.query.token);
+ var okResponse= '{"jtype":"AJB_reply"'+
+ ',"request":{"prefix":"afbs","api":"reset","uuid": "e4ef5e66-xxxx","status":"processed"}'+
+ ',"response":{"uuid":"b028b883-8b47-4c6d-9c6e-e79b9e2b81b9"}'+
+ '}';
+
+ var fxResponse= '{"jtype":"AJB_reply",'+
+ '"request":{"prefix":"afbs","api":"reset","status":"empty","info":"AFB_SESSION_CLOSE Not a Valid Access Token"}'+
+ '}';
+
+ if (!scope.connected) res.status(401).send(fxResponse);
+ else {
+ res.send(okResponse);
+ scope.connected=false;
+ }
+ });
+
+
+}
+
+// Export Class
+module.exports = NewApi; \ No newline at end of file
diff --git a/afb-client/app/Backend/RestApis/_all.js b/afb-client/app/Backend/RestApis/_all.js
new file mode 100644
index 0000000..aacf19e
--- /dev/null
+++ b/afb-client/app/Backend/RestApis/_all.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+PostMockApi = require ('./PostMockApi');
+TokenMockApi = require ('./TokenMockApi');
+
+// Include here every application APIs routes modules.
+function Initialise (handle) {
+
+ this.sample= new TokenMockApi (handle, config.APIBASE + 'token');
+ this.sample= new PostMockApi (handle, config.APIBASE + 'post');
+}
+
+module.exports = Initialise;
+
diff --git a/afb-client/app/Backend/server.js b/afb-client/app/Backend/server.js
new file mode 100644
index 0000000..11c5486
--- /dev/null
+++ b/afb-client/app/Backend/server.js
@@ -0,0 +1,58 @@
+var config = require('../etc/_Config');
+var trace = require('../etc/_Trace');
+var RestAPI = require('./RestApis/_all');
+var fs = require('fs');
+
+var express = require('express');
+var session = require('express-session');
+var bodyParser = require('body-parser');
+var methodOverride = require('method-override');
+
+// instanciate express HTTP server
+var app = express();
+
+// chose dev or prod rootdir
+var staticdir = 'dist.dev';
+if (process.env.MODE) staticdir = process.env.MODE === 'prod' ? 'dist.prod' : 'dist.dev';
+else staticdir = config.MODE === 'prod' ? 'dist.prod' : 'dist.dev';
+
+var rootdir = __dirname + '/../../' + staticdir;
+if (!fs.existsSync(rootdir)) {
+ console.log("### HOOPS Rootdir not found rootdir=%s\n", rootdir);
+ process.exit();
+}
+
+// get all data/stuff of the body (POST) parameters
+app.use(bodyParser.json()); // parse application/json
+app.use(methodOverride('X-HTTP-Method-Override')); // override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
+
+// This handle should contain enough for application logic
+var serverHandle = {
+ app : app, // Express server
+ config: config,
+ trace: config.DBG_LVL > 0 ? trace : function(){/*empty function */}
+};
+
+// set the static files location /public/img will be /img for users
+app.use(express.static(rootdir));
+
+// Load Mock APIs
+var apirest = new RestAPI(serverHandle);
+
+app.get(config.URLBASE, function (req, res) {
+ console.log ("Angular OPA %s", req.originalUrl);
+ res.sendfile(config.URLBASE +"index.html", {root: rootdir});
+});
+
+// rewrite requested URL to include Angular hashPrompt and set session flag for RestAPI
+app.get(config.URLBASE + '*', function(req, res) {
+ // Warning redirect should be under exact "/opa/#!page" or a redirect to home will be done
+ var redirect=config.URLBASE + '#!' + req.originalUrl.substring(config.URLBASE.length);
+ res.redirect(redirect);
+ console.log ("Redirect to: ", redirect);
+});
+
+
+// start app ===============================================
+app.listen(config.EXPRESS_PORT, config.EXPRESS_HOST);
+console.log('Server Listening http://%s:%d (rootdir=%s)', config.EXPRESS_HOST, config.EXPRESS_PORT, rootdir); \ No newline at end of file
diff --git a/afb-client/app/Frontend/app.js b/afb-client/app/Frontend/app.js
new file mode 100644
index 0000000..dc1d489
--- /dev/null
+++ b/afb-client/app/Frontend/app.js
@@ -0,0 +1,44 @@
+(function() {
+ 'use strict';
+
+ angular.module('@@APPNAME@@', [ // Warning: Appname should fit with gulpfile.js & index.html
+ 'ui.router',
+ 'ngAnimate',
+
+ //foundation
+ 'foundation',
+ 'foundation.dynamicRouting',
+ 'foundation.dynamicRouting.animations',
+
+ // external components
+ 'ui-notification',
+
+ // Application Components
+ 'ConfigApp',
+ 'JQueryEmu',
+ 'HomeModule',
+ 'SampleModule',
+ 'UploadFile',
+ 'LinkButton',
+ 'ModalNotification'
+ ])
+ .config(config)
+ .run(run)
+ ;
+
+ config.$inject = ['$urlRouterProvider', '$locationProvider'];
+
+ function config($urlProvider, $locationProvider) {
+ $urlProvider.otherwise('/home');
+
+ // https://docs.angularjs.org/error/$location/nobase
+ $locationProvider.html5Mode(true).hashPrefix('!');
+
+ }
+
+ function run() {
+ FastClick.attach(document.body);
+ }
+
+console.log ("@@APPNAME@@ Loaded");
+})();
diff --git a/afb-client/app/Frontend/favicon.ico b/afb-client/app/Frontend/favicon.ico
new file mode 100644
index 0000000..eeb7ab7
--- /dev/null
+++ b/afb-client/app/Frontend/favicon.ico
Binary files differ
diff --git a/afb-client/app/Frontend/images/avatars/istoobig.jpg b/afb-client/app/Frontend/images/avatars/istoobig.jpg
new file mode 100644
index 0000000..da0f255
--- /dev/null
+++ b/afb-client/app/Frontend/images/avatars/istoobig.jpg
Binary files differ
diff --git a/afb-client/app/Frontend/images/avatars/tux-admin.png b/afb-client/app/Frontend/images/avatars/tux-admin.png
new file mode 100644
index 0000000..ee40d2a
--- /dev/null
+++ b/afb-client/app/Frontend/images/avatars/tux-admin.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/avatars/tux-bzh.png b/afb-client/app/Frontend/images/avatars/tux-bzh.png
new file mode 100644
index 0000000..16e001b
--- /dev/null
+++ b/afb-client/app/Frontend/images/avatars/tux-bzh.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/avatars/tux-visitor.png b/afb-client/app/Frontend/images/avatars/tux-visitor.png
new file mode 100644
index 0000000..bd491b0
--- /dev/null
+++ b/afb-client/app/Frontend/images/avatars/tux-visitor.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/fb-logo.png b/afb-client/app/Frontend/images/login/fb-logo.png
new file mode 100644
index 0000000..fcf7847
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/fb-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/gg-logo.png b/afb-client/app/Frontend/images/login/gg-logo.png
new file mode 100644
index 0000000..0c372eb
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/gg-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/gh-logo.png b/afb-client/app/Frontend/images/login/gh-logo.png
new file mode 100644
index 0000000..ff856fc
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/gh-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/iot-logo.png b/afb-client/app/Frontend/images/login/iot-logo.png
new file mode 100644
index 0000000..ca594d7
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/iot-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/lk-logo.png b/afb-client/app/Frontend/images/login/lk-logo.png
new file mode 100644
index 0000000..d9bc51f
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/lk-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/ms-logo.png b/afb-client/app/Frontend/images/login/ms-logo.png
new file mode 100644
index 0000000..d4f23eb
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/ms-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/og-logo.png b/afb-client/app/Frontend/images/login/og-logo.png
new file mode 100644
index 0000000..a6f6e9a
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/og-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/pp-logo.png b/afb-client/app/Frontend/images/login/pp-logo.png
new file mode 100644
index 0000000..dbb8866
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/pp-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/login/yh-logo.png b/afb-client/app/Frontend/images/login/yh-logo.png
new file mode 100644
index 0000000..6ab90cf
--- /dev/null
+++ b/afb-client/app/Frontend/images/login/yh-logo.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/logo/logo_iot_bzh.svg b/afb-client/app/Frontend/images/logo/logo_iot_bzh.svg
new file mode 100644
index 0000000..6e60c95
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/logo_iot_bzh.svg
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="597.39423"
+ height="162.54224"
+ id="svg4035"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="New document 5">
+ <defs
+ id="defs4037">
+ <filter
+ color-interpolation-filters="sRGB"
+ id="filter4000"
+ inkscape:label="Drop Shadow">
+ <feFlood
+ id="feFlood4002"
+ flood-opacity="0.475"
+ flood-color="rgb(0,0,0)"
+ result="flood" />
+ <feComposite
+ id="feComposite4004"
+ in2="SourceGraphic"
+ in="flood"
+ operator="in"
+ result="composite1" />
+ <feGaussianBlur
+ id="feGaussianBlur4006"
+ stdDeviation="5"
+ result="blur" />
+ <feOffset
+ id="feOffset4008"
+ dx="8"
+ dy="8"
+ result="offset" />
+ <feComposite
+ id="feComposite4010"
+ in2="offset"
+ in="SourceGraphic"
+ operator="over"
+ result="composite2" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="339.36637"
+ inkscape:cy="3.4393101"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1108"
+ inkscape:window-height="862"
+ inkscape:window-x="321"
+ inkscape:window-y="159"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata4040">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-49.874326,-433.94821)">
+ <g
+ id="g3091"
+ transform="translate(62.857151,24.927697)"
+ inkscape:export-filename="/home/sdx/Pictures/Logo/logo_iot_bzh_100dpi.png"
+ inkscape:export-xdpi="100.22011"
+ inkscape:export-ydpi="100.22011"
+ style="display:inline;filter:url(#filter4000)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text3557-5-3-7-0-7-3"
+ y="519.50671"
+ x="27.886671"
+ style="font-size:97.09867096px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
+ xml:space="preserve"><tspan
+ style="font-size:97.09867096px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:FreeEuro;-inkscape-font-specification:FreeEuro Bold"
+ y="519.50671"
+ x="27.886671"
+ id="tspan3559-5-4-1-5-0-6"
+ sodipodi:role="line">IOT</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ d="m 296.73007,473.23356 c 28.21686,16.29102 28.75566,58.73779 0.99693,78.53831 -7.67688,5.47598 -8.77935,4.91028 -1.99529,-1.0238 17.47377,-15.28453 17.98492,-42.17775 1.08522,-57.09786 l -3.91266,-3.45435 0.72312,-3.71053 c 0.39771,-2.04076 0.5997,-5.73115 0.44885,-8.20083 -0.33876,-5.54623 0.15803,-6.49185 2.65383,-5.05094 z m -64.76568,11.40332 c 7.06047,-7.74198 18.64659,-14.16089 29.04027,-16.08874 l 6.87489,-1.27521 0.87404,2.89709 c 0.4807,1.59343 0.67439,5.2245 0.43037,8.06906 l -0.44364,5.17195 -6.13887,1.6918 c -10.91241,3.00731 -20.4022,10.85909 -25.4533,21.05979 l -2.41633,4.87984 -2.74281,-0.41238 c -5.14252,-0.77316 -12.72985,-3.97645 -12.79123,-5.40033 -0.092,-2.13451 8.34659,-15.74625 12.76661,-20.59287 z m 33.20546,36.39493 c -28.21687,16.29101 -65.24624,-4.46574 -68.51461,-38.40577 -0.9039,-9.38637 0.13723,-10.0583 1.88428,-1.21608 4.49989,22.77499 27.53453,36.66428 48.90556,29.48876 l 4.94788,-1.66128 2.85184,2.48149 c 1.56852,1.36481 4.66349,3.38493 6.87772,4.48914 4.97257,2.47973 5.54308,3.38282 3.04733,4.82374 z m 22.50729,-61.79039 c 3.17451,9.98553 2.94038,23.22889 -0.58688,33.19399 l -2.33309,6.59143 -2.94597,-0.69161 c -1.6203,-0.38041 -4.86173,-2.02821 -7.2032,-3.6618 l -4.25721,-2.97018 1.60429,-6.16234 c 2.85178,-10.95404 0.79685,-23.09833 -5.51167,-32.57307 l -3.01788,-4.53253 1.72854,-2.16916 c 3.24083,-4.06698 9.80863,-9.03614 11.07242,-8.37738 1.89457,0.98756 9.46336,15.1015 11.45065,21.35265 z m -48.80223,10.31437 c 0,-32.58201 36.49058,-54.27201 67.51771,-40.1325 8.58077,3.9104 8.6421,5.148 0.11108,2.23988 -21.97368,-7.49048 -45.51946,5.51348 -49.99082,27.6091 l -1.03521,5.11561 -3.57498,1.22902 c -1.96621,0.67596 -5.26316,2.34622 -7.32655,3.71171 -4.63379,3.06649 -5.70115,3.10904 -5.70115,0.22718 z m 42.25842,50.3871 c -10.23499,-2.24356 -21.58699,-9.06801 -28.45341,-17.10525 l -4.5418,-5.31622 2.07194,-2.20549 c 1.13957,-1.21302 4.18733,-3.19628 6.77282,-4.40726 l 4.70085,-2.20176 4.53458,4.47053 c 8.06061,7.94674 19.60535,12.23927 30.96496,11.51329 l 5.43422,-0.34731 1.01427,2.58154 c 1.90169,4.84014 2.92124,13.01261 1.71883,13.77769 -1.80254,1.14695 -17.80995,0.64475 -24.21726,-0.75976 z"
+ style="fill:#5a2ca0;display:inline"
+ id="path3415-4-2-2-5-0-3-7-4-4-1-5" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text3557-5-3-7-46-7-3-7"
+ y="519.50671"
+ x="317.95816"
+ style="font-size:97.09867096px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
+ xml:space="preserve"><tspan
+ style="font-size:97.09867096px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:FreeEuro;-inkscape-font-specification:FreeEuro Bold"
+ y="519.50671"
+ x="317.95816"
+ id="tspan3559-5-4-1-90-0-2-9"
+ sodipodi:role="line">BZH</tspan></text>
+ </g>
+ <rect
+ style="fill:none;stroke:none;display:inline"
+ id="rect3098"
+ width="577.14288"
+ height="162.54224"
+ x="59.999989"
+ y="433.94821"
+ inkscape:export-filename="/home/sdx/Pictures/Logo/logo_iot_bzh_100dpi.png"
+ inkscape:export-xdpi="100.22011"
+ inkscape:export-ydpi="100.22011" />
+ </g>
+</svg>
diff --git a/afb-client/app/Frontend/images/logo/logo_iot_bzhx350.png b/afb-client/app/Frontend/images/logo/logo_iot_bzhx350.png
new file mode 100644
index 0000000..2c3b2ae
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/logo_iot_bzhx350.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/logo/tampon-iot-bzhx450.png b/afb-client/app/Frontend/images/logo/tampon-iot-bzhx450.png
new file mode 100644
index 0000000..f365e19
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/tampon-iot-bzhx450.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/logo/triskel_iot_bzh.png b/afb-client/app/Frontend/images/logo/triskel_iot_bzh.png
new file mode 100644
index 0000000..832dc1f
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/triskel_iot_bzh.png
Binary files differ
diff --git a/afb-client/app/Frontend/images/logo/triskel_iot_bzh.svg b/afb-client/app/Frontend/images/logo/triskel_iot_bzh.svg
new file mode 100644
index 0000000..096f424
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/triskel_iot_bzh.svg
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="205.71426"
+ height="197.14285"
+ id="svg4199"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="triskel_iot_bzh.svg">
+ <defs
+ id="defs4201">
+ <filter
+ color-interpolation-filters="sRGB"
+ id="filter4111"
+ inkscape:label="Drop Shadow">
+ <feFlood
+ id="feFlood4113"
+ flood-opacity="0.475"
+ flood-color="rgb(0,0,0)"
+ result="flood" />
+ <feComposite
+ id="feComposite4115"
+ in2="SourceGraphic"
+ in="flood"
+ operator="in"
+ result="composite1" />
+ <feGaussianBlur
+ id="feGaussianBlur4117"
+ stdDeviation="5"
+ result="blur" />
+ <feOffset
+ id="feOffset4119"
+ dx="8"
+ dy="8"
+ result="offset" />
+ <feComposite
+ id="feComposite4121"
+ in2="offset"
+ in="SourceGraphic"
+ operator="over"
+ result="composite2" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.35"
+ inkscape:cx="46.428557"
+ inkscape:cy="178.57144"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="500"
+ inkscape:window-height="435"
+ inkscape:window-x="1087"
+ inkscape:window-y="400"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata4204">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-328.57144,-513.79077)">
+ <path
+ id="path3415-4-2-2-5-0-3-7-4-4-1-9"
+ style="fill:#5a2ca0;display:inline;filter:url(#filter4111)"
+ d="m 470.88567,595.30412 c 28.21686,16.29102 28.75566,58.73778 0.99693,78.5383 -7.67688,5.47598 -8.77935,4.91028 -1.99529,-1.0238 17.47377,-15.28453 17.98492,-42.17774 1.08522,-57.09785 l -3.91266,-3.45435 0.72312,-3.71053 c 0.39771,-2.04076 0.5997,-5.73115 0.44885,-8.20083 -0.33876,-5.54623 0.15803,-6.49185 2.65383,-5.05094 z m -64.76568,11.40332 c 7.06047,-7.74198 18.64659,-14.16089 29.04027,-16.08874 l 6.87489,-1.27521 0.87404,2.89709 c 0.4807,1.59343 0.67439,5.2245 0.43037,8.06906 l -0.44364,5.17195 -6.13887,1.6918 c -10.91241,3.00731 -20.4022,10.85909 -25.4533,21.05979 l -2.41633,4.87984 -2.74281,-0.41238 c -5.14252,-0.77316 -12.72985,-3.97645 -12.79123,-5.40033 -0.092,-2.13451 8.34659,-15.74625 12.76661,-20.59287 z m 33.20546,36.39493 c -28.21687,16.291 -65.24624,-4.46574 -68.51461,-38.40577 -0.9039,-9.38637 0.13723,-10.0583 1.88428,-1.21608 4.49989,22.77499 27.53453,36.66428 48.90556,29.48876 l 4.94788,-1.66128 2.85184,2.48149 c 1.56852,1.36481 4.66349,3.38493 6.87772,4.48914 4.97257,2.47973 5.54308,3.38282 3.04733,4.82374 z m 22.50729,-61.7904 c 3.17451,9.98554 2.94038,23.2289 -0.58688,33.194 l -2.33309,6.59143 -2.94597,-0.69161 c -1.6203,-0.38041 -4.86173,-2.02821 -7.2032,-3.6618 l -4.25721,-2.97018 1.60429,-6.16234 c 2.85178,-10.95404 0.79685,-23.09834 -5.51167,-32.57308 l -3.01788,-4.53253 1.72854,-2.16916 c 3.24083,-4.06698 9.80863,-9.03614 11.07242,-8.37738 1.89457,0.98756 9.46336,15.1015 11.45065,21.35265 z m -48.80223,10.31438 c 0,-32.58202 36.49058,-54.27202 67.51771,-40.13251 8.58077,3.9104 8.6421,5.148 0.11108,2.23988 -21.97368,-7.49048 -45.51946,5.51348 -49.99082,27.6091 l -1.03521,5.11562 -3.57498,1.22902 c -1.96621,0.67596 -5.26316,2.34622 -7.32655,3.71171 -4.63379,3.06649 -5.70115,3.10904 -5.70115,0.22718 z m 42.25842,50.3871 c -10.23499,-2.24356 -21.58699,-9.06801 -28.45341,-17.10525 l -4.5418,-5.31622 2.07194,-2.20549 c 1.13957,-1.21302 4.18733,-3.19628 6.77282,-4.40726 l 4.70085,-2.20176 4.53458,4.47053 c 8.06061,7.94674 19.60535,12.23927 30.96496,11.51329 l 5.43422,-0.34731 1.01427,2.58154 c 1.90169,4.84014 2.92124,13.01261 1.71883,13.77769 -1.80254,1.14695 -17.80995,0.64475 -24.21726,-0.75976 z"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="/home/sdx/Pictures/Logo/triskel_iot_bzh_300dpi.png"
+ inkscape:export-xdpi="300"
+ inkscape:export-ydpi="300" />
+ <rect
+ style="fill:none;stroke:none;display:inline"
+ id="rect4179"
+ width="205.71426"
+ height="197.14285"
+ x="328.57144"
+ y="513.79077"
+ inkscape:export-filename="/home/sdx/Pictures/Logo/triskel_iot_bzh_300dpi.png"
+ inkscape:export-xdpi="300"
+ inkscape:export-ydpi="300" />
+ </g>
+</svg>
diff --git a/afb-client/app/Frontend/images/logo/triskel_iot_bzhx250.png b/afb-client/app/Frontend/images/logo/triskel_iot_bzhx250.png
new file mode 100644
index 0000000..f4e41ae
--- /dev/null
+++ b/afb-client/app/Frontend/images/logo/triskel_iot_bzhx250.png
Binary files differ
diff --git a/afb-client/app/Frontend/index.html b/afb-client/app/Frontend/index.html
new file mode 100644
index 0000000..0d55267
--- /dev/null
+++ b/afb-client/app/Frontend/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<!--[if lt IE 7]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+<!--[if IE 7]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9 lt-ie8"> <![endif]-->
+<!--[if IE 8]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9"> <![endif]-->
+<!--[if gt IE 8]><!--> <html lang="en" ng-app="@@APPNAME@@" class="no-js"> <!--<![endif]-->
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>Simple Sample Application</title>
+ <meta name="description" content="">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <!-- bower:css -->
+ <!-- endinject -->
+ <!--vendor:css -->
+ <!-- endinject -->
+ <!-- appli:css -->
+ <!-- endinject -->
+ <!-- inject:css -->
+ <!-- endinject -->
+ <base href="@@URLBASE@@"> <!-- https://docs.angularjs.org/error/$location/nobase -->
+
+</head>
+<body>
+<!--[if lt IE 7]>
+<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+<![endif]-->
+<div ui-view></div>
+<!-- bower:js -->
+<!-- endinject -->
+<!-- inject:js -->
+<!-- endinject -->
+
+<!-- Generic Foundation Modal Template -->
+<script id="components/modal/modal.html" type="text/ng-template">
+ <div class="modal-overlay" ng-click="hideOverlay()">
+ <aside class="modal" ng-click="$event.stopPropagation();" ng-transclude></aside>
+ </div>
+</script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/afb-client/app/Frontend/pages/Home/Home.html b/afb-client/app/Frontend/pages/Home/Home.html
new file mode 100644
index 0000000..9803b63
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Home/Home.html
@@ -0,0 +1,33 @@
+<!-- comment -->
+
+---
+name: myhome
+url: /home
+controller: HomeController as ctrl
+animationIn: slideInRight
+---
+
+<h3>
+<img class="logo" src="images/logo/triskel_iot_bzhx250.png" alt="IoT.bzh Logo" style="height:150px;">
+ App Framework Binder Simple Client
+</h3>
+
+
+
+<div class="button-box box-content ">
+
+ <submit-button class="session-button {{ctrl.APIcreate}}" icon="fi-unlock" label="Open" clicked="ctrl.OpenSession" ></submit-button>
+ <submit-button class="session-button {{ctrl.APIcheck}}" icon="fi-checkbox" label="Check" clicked="ctrl.CheckSession" ></submit-button>
+ <submit-button class="session-button {{ctrl.APIrefresh}}" icon="fi-arrows-compress" label="Refresh" clicked="ctrl.RefreshSession" ></submit-button>
+ <submit-button class="session-button {{ctrl.APIreset}}" icon="fi-lock" label="Close" clicked="ctrl.ResetSession" ></submit-button>
+
+</div>
+<div class="message-box box-content vertical grid-frame">
+ <div class="response">
+ <span class="grid-content noscroll req {{ctrl.status}} ">req= {{ctrl.request}}</span>
+ <span class="grid-content noscroll res {{ctrl.status}} ">res= {{ctrl.response}}</span>
+ <span class="grid-content noscroll status {{ctrl.status}}">status= {{ctrl.errcode}}</span>
+ </div>
+</div>
+
+<link-button href="sample" icon="fi-home" label="sample"></link-button>
diff --git a/afb-client/app/Frontend/pages/Home/HomeModule.js b/afb-client/app/Frontend/pages/Home/HomeModule.js
new file mode 100644
index 0000000..11b3882
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Home/HomeModule.js
@@ -0,0 +1,90 @@
+(function() {
+'use strict';
+
+ var INITIAL_TOKEN=123456789; // should match with --token=xxxx binder command line
+
+// list all rependencies within the page + controler if needed
+angular.module('HomeModule', ['SubmitButton'])
+
+ .controller('HomeController', function ($http, ConfigApp) {
+ var scope = this; // I hate JavaScript
+ scope.uuid ="none";
+ scope.token ="none";
+ scope.session="none";
+ scope.status ="err-no";
+
+ console.log ("Home Controller");
+
+ scope.ProcessResponse= function(data, errcode, headers, config) {
+ var apiname= 'API'+ data.request.api.replace('-','_');
+ scope.status = "err-ok";
+ scope.errcode= errcode;
+ scope.request = data.request;
+ scope.response = data.response;
+
+ // Make sure we clean everything when Open/Close is called
+ if (apiname === "APIcreate" || apiname === "APIreset") {
+ scope["APIreset"]='';
+ scope["APIcreate"]='';
+ scope["APIrefresh"]='';
+ scope["APIcheck"]='';
+ }
+ scope[apiname]="success";
+
+ // If we have a new token let's update it
+ if (data.request.token) scope.token=data.request.token;
+
+ console.log ("OK: "+ JSON.stringify(data));
+ };
+
+ scope.ProcessError= function(data, errcode, headers, config) {
+ var apiname= 'API'+data.request.api.replace('-','_');
+ scope.status = "err-fx";
+ scope.errcode = errcode;
+ scope.request = data.request;
+ scope.response = "";
+ scope[apiname]="fail";
+
+ console.log ("FX: "+ JSON.stringify(data));
+ };
+
+ scope.OpenSession = function() {
+ console.log ("OpenSession");
+ var postdata= {/* any json your application may need */};
+ var handler = $http.post(ConfigApp.api.token + 'create?token='+INITIAL_TOKEN, postdata);
+
+ handler.success(scope.ProcessResponse);
+ handler.error(scope.ProcessError);
+ };
+
+ scope.CheckSession = function() {
+ console.log ("CloseSession");
+ var postdata= {/* any json your application may need */};
+ var handler = $http.post(ConfigApp.api.token + 'check?token='+scope.token, postdata);
+
+ handler.success(scope.ProcessResponse);
+ handler.error(scope.ProcessError);
+ };
+
+ scope.RefreshSession = function() {
+ console.log ("RefreshSession");
+ var postdata= {/* any json your application may need */};
+ var handler = $http.post(ConfigApp.api.token + 'refresh?token='+scope.token, postdata);
+
+ handler.success(scope.ProcessResponse);
+ handler.error(scope.ProcessError);
+ };
+
+ scope.ResetSession = function() {
+ console.log ("ResetSession");
+ var postdata= {/* any json your application may need */};
+ var handler = $http.post(ConfigApp.api.token + 'reset?token='+scope.token, postdata);
+
+ handler.success(scope.ProcessResponse);
+ handler.error(scope.ProcessError);
+ };
+
+ });
+
+console.log ("SampleControler Loaded");
+})(); \ No newline at end of file
diff --git a/afb-client/app/Frontend/pages/Home/HomeModule.scss b/afb-client/app/Frontend/pages/Home/HomeModule.scss
new file mode 100644
index 0000000..34e1181
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Home/HomeModule.scss
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "app/ibz-mixins";
+
+$COLOR_SUCCESS: green;
+$COLOR_FAIL: red;
+
+.button-box {
+ height : 4.5rem;
+
+ .session-button {
+ float: left;
+ width: 5rem;
+ };
+
+ .response > span{
+ display: block;
+ margin: .3rem .5rem .3rem .5rem;
+ }
+
+ .fail {
+ color:$COLOR_FAIL;
+ border: 1px solid darken($COLOR_FAIL,10%);
+ }
+ .success {
+ color:$COLOR_SUCCESS;
+ border: 1px solid darken($COLOR_SUCCESS,10%);
+ }
+
+};
+
+.message-box {
+ height : auto;
+ width: 100%;
+ font-size: .75rem;
+
+ .response {
+ .err-no { color:grey; }
+ .res.err-ok { color: blue; }
+ .req.err-ok { color:blueviolet; }
+ .status.err-ok { color:green; }
+ .status.err-fx { color:red; }
+ }
+
+
+};
+
+
+
diff --git a/afb-client/app/Frontend/pages/Sample/Sample.html b/afb-client/app/Frontend/pages/Sample/Sample.html
new file mode 100644
index 0000000..00a6f3b
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Sample/Sample.html
@@ -0,0 +1,22 @@
+<!-- comment -->
+
+---
+name: mysample
+url: /sample
+controller: SampleController as ctrl
+animationIn: slideInRight
+---
+
+<h1><img class="logo" src="images/logo/triskel_iot_bzhx250.png" alt="IoT.bzh Logo" style="height:150px;"> Sample Page</h1>
+
+<div class="sample-box box-content">
+
+ <upload-file name="avatar" category="avatars" icon="tux-visitor.png"></upload-file>
+
+ <submit-button class="sample-button" icon="fi-zoom-in" label="Vol+" clicked="ctrl.MuteOn" ></submit-button>
+ <submit-button class="sample-button" icon="fi-zoom-out" label="Vol-" clicked="ctrl.MuteOff" ></submit-button>
+ <submit-button class="home-button" icon="fi-upload" label="Refresh" clicked="ctrl.UploadFile" ></submit-button>
+
+</div>
+
+<link-button href="home" icon="fi-home" label="home"></link-button>
diff --git a/afb-client/app/Frontend/pages/Sample/SampleModule.js b/afb-client/app/Frontend/pages/Sample/SampleModule.js
new file mode 100644
index 0000000..2a2e777
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Sample/SampleModule.js
@@ -0,0 +1,48 @@
+(function() {
+'use strict';
+
+// list all rependencies within the page + controler if needed
+angular.module('SampleModule', ['SubmitButton','UploadFile'])
+
+ .controller('SampleController', function ($http) {
+ var self = this; // I hate JavaScript
+ this.status='muted-off';
+
+ console.log ("sample controller");
+
+ this.MuteOn = function() {
+ console.log ("Muted");
+ // send AJAX request to server
+ var handler = $http.post('/api/dbus/ping', {type:'mute', action: "on"});
+
+ handler.success(function(response, errcode, headers, config) {
+ self.status = 'muted-on';
+ });
+
+ handler.error(function(status, errcode, headers) {
+ console.log ("Oops /api/dbus/pring err=" + errcode);
+ self.status = 'muted-error';
+ });
+ };
+
+ this.MuteOff = function() {
+ console.log ("UnMuted");
+ // send AJAX request to server
+ var handler = $http.post('/api/dbus/ping', {type:'mute', action: "off"});
+
+ handler.success(function(response, errcode, headers, config) {
+ self.status = 'muted-off';
+ });
+
+ handler.error(function(status, errcode, headers) {
+ console.log ("Oops /api/dbus/ping err=" + errcode);
+ self.status = 'muted-error';
+ });
+
+ };
+
+
+ });
+
+console.log ("SampleControler Loaded");
+})(); \ No newline at end of file
diff --git a/afb-client/app/Frontend/pages/Sample/SampleModule.scss b/afb-client/app/Frontend/pages/Sample/SampleModule.scss
new file mode 100644
index 0000000..2e54c53
--- /dev/null
+++ b/afb-client/app/Frontend/pages/Sample/SampleModule.scss
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "app/ibz-mixins";
+
+
+.sample-box {
+ display: block;
+ height : 4.5rem;
+
+ .sample-button {
+ float: left;
+ width: 5rem;
+ };
+
+ .muted-on-on,.muted-off-off{
+ background: blueviolet;
+ };
+
+ .muted-error{
+ background: red;
+ };
+};
+
+
+
diff --git a/afb-client/app/Frontend/services/ConfigApp.js b/afb-client/app/Frontend/services/ConfigApp.js
new file mode 100644
index 0000000..f36d79b
--- /dev/null
+++ b/afb-client/app/Frontend/services/ConfigApp.js
@@ -0,0 +1,25 @@
+(function () {
+ 'use strict';
+
+ // _all modules only reference dependencies
+ angular.module('ConfigApp', [])
+
+ // Factory is a singleton and share its context within all instances.
+ .factory('ConfigApp', function () {
+
+
+ var myConfig = {
+ paths: { // Warning paths should end with /
+ images : 'images/',
+ avatars: 'images/avatars/'
+ },
+
+ api: { // Warning paths should end with /
+ token : '/api/token/'
+ }
+ };
+
+ return myConfig;
+ });
+
+})(); \ No newline at end of file
diff --git a/afb-client/app/Frontend/services/JQueryEmu.js b/afb-client/app/Frontend/services/JQueryEmu.js
new file mode 100644
index 0000000..5112052
--- /dev/null
+++ b/afb-client/app/Frontend/services/JQueryEmu.js
@@ -0,0 +1,42 @@
+(function () {
+ 'use strict';
+
+ // _all modules only reference dependencies
+ angular.module('JQueryEmu', [])
+
+ // Factory is a singleton and share its context within all instances.
+ .factory('JQemu', function () {
+
+ // JQueryLight cannot search a tag within ancestrors
+ var parent = function (element, selector) {
+ var parent = element;
+ var search = selector.toUpperCase();
+ while (parent[0]) {
+ if (search === parent[0].tagName) {
+ return parent;
+ } // HTMLDivElement properties
+ parent = parent.parent();
+ }
+ };
+
+ // JQueryLight cannot search by type
+ var findByType= function (element, selector) {
+ var search = selector.toLowerCase();
+ var children = element.children();
+ while (children[0]) {
+ if (search === children[0].type) {
+ return children;
+ } // HTMLDivElement properties
+ children = children.next();
+ }
+ };
+
+ var myMethods = {
+ parent: parent,
+ findByType: findByType
+ };
+
+ return myMethods;
+ });
+
+})(); \ No newline at end of file
diff --git a/afb-client/app/Frontend/styles/README.md b/afb-client/app/Frontend/styles/README.md
new file mode 100644
index 0000000..dc50ced
--- /dev/null
+++ b/afb-client/app/Frontend/styles/README.md
@@ -0,0 +1,28 @@
+WARNING note about global style dir
+-------------------------------------
+
+ - styles placed in Frontend/styles is global and will be posted in dist.prod/styles
+ - styles defined within widget or page directory will be place in dist.prof/opa/styles
+
+This model allows to share global styles by multiple applications.
+
+To change this behaviour just rename styles directory on something else [eg: appstyles]
+
+
+ |---- /Frontend
+ | |
+ | |---- /styles
+ | | |
+ | | |---- _settings.scss
+ | | |---- app.scss
+ | |
+ | |---- /Widgets
+ | | |
+ | | |--- widget.js
+ | | |--- widget.sccs
+ | |
+ | |-----/Pages
+ | |--- page-partial.html
+ | |--- page-cntrl.js
+ | |--- page-style.scss
+ |
diff --git a/afb-client/app/Frontend/styles/app/_ibz-mixins.scss b/afb-client/app/Frontend/styles/app/_ibz-mixins.scss
new file mode 100644
index 0000000..ed9dba8
--- /dev/null
+++ b/afb-client/app/Frontend/styles/app/_ibz-mixins.scss
@@ -0,0 +1,52 @@
+/*
+ Every SCSS files will be injected into main HTML page
+*/
+%shadow-transition {
+ transition: border 0.2s linear 0s, box-shadow 0.2s linear 0s;
+ border-radius: 5px;
+}
+
+@mixin ibz-box-content {
+ border: 2px solid gainsboro !important;
+ border-radius: 5px;
+
+ margin-left: auto;
+ margin-right: auto;
+ min-width: 98% !important;
+ margin: .5rem .5rem .5rem .5rem;
+ background: rgba(200,205,200,.3);
+}
+
+@mixin ibz-button ($color, $size:2rem) {
+ display: inline-block;
+ border: 1px solid darken($color,10%);
+ box-shadow: 2px 2px 1px adjust-hue($color,20deg);
+ color: $color;
+ border-radius: 5px;
+ font-style: italic;
+ padding: 0rem .5rem 0rem .5rem;
+ margin:.5rem;
+ background: lighten(#9494b7, 20%);
+ i {
+ padding-right: 0.3rem;
+ font-size: $size;
+ }
+ span {font-size: 1rem}
+
+ &:hover {
+ background: lighten($color, 45%);
+ border: 2px solid darken($color,20%);
+
+ }
+}
+
+@mixin ibz-input-alert ($color, $background) {
+ position :fixed;
+ margin: -2.2rem 0 0 15rem;
+ border-radius: 5px;
+ font-style: italic;
+ border-color: darken($background,10%);
+ color: $color;
+ background-color: $background !important;
+ padding: 0.2rem !important;
+}
diff --git a/afb-client/app/Frontend/styles/app/ibz-global.scss b/afb-client/app/Frontend/styles/app/ibz-global.scss
new file mode 100644
index 0000000..1f5017e
--- /dev/null
+++ b/afb-client/app/Frontend/styles/app/ibz-global.scss
@@ -0,0 +1,43 @@
+/*
+Copyright (C) 2015 "IoT.bzh"
+Author "Fulup Ar Foll"
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+@import "app/ibz-mixins";
+
+submit-button {
+ float: right;
+ @include ibz-button(grey);
+}
+
+zf-modal {
+ background-color: rgba(180,180,180,.5);
+}
+
+.box-content {
+ @include ibz-box-content;
+
+ .box-title {
+ display: block;
+ font-size: 1.3rem;
+ }
+}
+
+// Change Notifications default size
+.ui-notification {
+ width: auto;
+ border-radius: 5px;
+} \ No newline at end of file
diff --git a/afb-client/app/Frontend/styles/foundation/_foundation-icons.scss b/afb-client/app/Frontend/styles/foundation/_foundation-icons.scss
new file mode 100644
index 0000000..d401f3c
--- /dev/null
+++ b/afb-client/app/Frontend/styles/foundation/_foundation-icons.scss
@@ -0,0 +1,591 @@
+/*
+ * Foundation Icons v 3.0
+ * Made by ZURB 2013 http://zurb.com/playground/foundation-icon-fonts-3
+ * MIT License
+ */
+
+@font-face {
+ font-family: "foundation-icons";
+ src: url("/bower_components/foundation-icons.woff") format("woff");
+ font-weight: normal;
+ font-style: normal;
+}
+
+
+.fi-address-book:before,
+.fi-alert:before,
+.fi-align-center:before,
+.fi-align-justify:before,
+.fi-align-left:before,
+.fi-align-right:before,
+.fi-anchor:before,
+.fi-annotate:before,
+.fi-archive:before,
+.fi-arrow-down:before,
+.fi-arrow-left:before,
+.fi-arrow-right:before,
+.fi-arrow-up:before,
+.fi-arrows-compress:before,
+.fi-arrows-expand:before,
+.fi-arrows-in:before,
+.fi-arrows-out:before,
+.fi-asl:before,
+.fi-asterisk:before,
+.fi-at-sign:before,
+.fi-background-color:before,
+.fi-battery-empty:before,
+.fi-battery-full:before,
+.fi-battery-half:before,
+.fi-bitcoin-circle:before,
+.fi-bitcoin:before,
+.fi-blind:before,
+.fi-bluetooth:before,
+.fi-bold:before,
+.fi-book-bookmark:before,
+.fi-book:before,
+.fi-bookmark:before,
+.fi-braille:before,
+.fi-burst-new:before,
+.fi-burst-sale:before,
+.fi-burst:before,
+.fi-calendar:before,
+.fi-camera:before,
+.fi-check:before,
+.fi-checkbox:before,
+.fi-clipboard-notes:before,
+.fi-clipboard-pencil:before,
+.fi-clipboard:before,
+.fi-clock:before,
+.fi-closed-caption:before,
+.fi-cloud:before,
+.fi-comment-minus:before,
+.fi-comment-quotes:before,
+.fi-comment-video:before,
+.fi-comment:before,
+.fi-comments:before,
+.fi-compass:before,
+.fi-contrast:before,
+.fi-credit-card:before,
+.fi-crop:before,
+.fi-crown:before,
+.fi-css3:before,
+.fi-database:before,
+.fi-die-five:before,
+.fi-die-four:before,
+.fi-die-one:before,
+.fi-die-six:before,
+.fi-die-three:before,
+.fi-die-two:before,
+.fi-dislike:before,
+.fi-dollar-bill:before,
+.fi-dollar:before,
+.fi-download:before,
+.fi-eject:before,
+.fi-elevator:before,
+.fi-euro:before,
+.fi-eye:before,
+.fi-fast-forward:before,
+.fi-female-symbol:before,
+.fi-female:before,
+.fi-filter:before,
+.fi-first-aid:before,
+.fi-flag:before,
+.fi-folder-add:before,
+.fi-folder-lock:before,
+.fi-folder:before,
+.fi-foot:before,
+.fi-foundation:before,
+.fi-graph-bar:before,
+.fi-graph-horizontal:before,
+.fi-graph-pie:before,
+.fi-graph-trend:before,
+.fi-guide-dog:before,
+.fi-hearing-aid:before,
+.fi-heart:before,
+.fi-home:before,
+.fi-html5:before,
+.fi-indent-less:before,
+.fi-indent-more:before,
+.fi-info:before,
+.fi-italic:before,
+.fi-key:before,
+.fi-laptop:before,
+.fi-layout:before,
+.fi-lightbulb:before,
+.fi-like:before,
+.fi-link:before,
+.fi-list-bullet:before,
+.fi-list-number:before,
+.fi-list-thumbnails:before,
+.fi-list:before,
+.fi-lock:before,
+.fi-loop:before,
+.fi-magnifying-glass:before,
+.fi-mail:before,
+.fi-male-female:before,
+.fi-male-symbol:before,
+.fi-male:before,
+.fi-map:before,
+.fi-marker:before,
+.fi-megaphone:before,
+.fi-microphone:before,
+.fi-minus-circle:before,
+.fi-minus:before,
+.fi-mobile-signal:before,
+.fi-mobile:before,
+.fi-monitor:before,
+.fi-mountains:before,
+.fi-music:before,
+.fi-next:before,
+.fi-no-dogs:before,
+.fi-no-smoking:before,
+.fi-page-add:before,
+.fi-page-copy:before,
+.fi-page-csv:before,
+.fi-page-delete:before,
+.fi-page-doc:before,
+.fi-page-edit:before,
+.fi-page-export-csv:before,
+.fi-page-export-doc:before,
+.fi-page-export-pdf:before,
+.fi-page-export:before,
+.fi-page-filled:before,
+.fi-page-multiple:before,
+.fi-page-pdf:before,
+.fi-page-remove:before,
+.fi-page-search:before,
+.fi-page:before,
+.fi-paint-bucket:before,
+.fi-paperclip:before,
+.fi-pause:before,
+.fi-paw:before,
+.fi-paypal:before,
+.fi-pencil:before,
+.fi-photo:before,
+.fi-play-circle:before,
+.fi-play-video:before,
+.fi-play:before,
+.fi-plus:before,
+.fi-pound:before,
+.fi-power:before,
+.fi-previous:before,
+.fi-price-tag:before,
+.fi-pricetag-multiple:before,
+.fi-print:before,
+.fi-prohibited:before,
+.fi-projection-screen:before,
+.fi-puzzle:before,
+.fi-quote:before,
+.fi-record:before,
+.fi-refresh:before,
+.fi-results-demographics:before,
+.fi-results:before,
+.fi-rewind-ten:before,
+.fi-rewind:before,
+.fi-rss:before,
+.fi-safety-cone:before,
+.fi-save:before,
+.fi-share:before,
+.fi-sheriff-badge:before,
+.fi-shield:before,
+.fi-shopping-bag:before,
+.fi-shopping-cart:before,
+.fi-shuffle:before,
+.fi-skull:before,
+.fi-social-500px:before,
+.fi-social-adobe:before,
+.fi-social-amazon:before,
+.fi-social-android:before,
+.fi-social-apple:before,
+.fi-social-behance:before,
+.fi-social-bing:before,
+.fi-social-blogger:before,
+.fi-social-delicious:before,
+.fi-social-designer-news:before,
+.fi-social-deviant-art:before,
+.fi-social-digg:before,
+.fi-social-dribbble:before,
+.fi-social-drive:before,
+.fi-social-dropbox:before,
+.fi-social-evernote:before,
+.fi-social-facebook:before,
+.fi-social-flickr:before,
+.fi-social-forrst:before,
+.fi-social-foursquare:before,
+.fi-social-game-center:before,
+.fi-social-github:before,
+.fi-social-google-plus:before,
+.fi-social-hacker-news:before,
+.fi-social-hi5:before,
+.fi-social-instagram:before,
+.fi-social-joomla:before,
+.fi-social-lastfm:before,
+.fi-social-linkedin:before,
+.fi-social-medium:before,
+.fi-social-myspace:before,
+.fi-social-orkut:before,
+.fi-social-path:before,
+.fi-social-picasa:before,
+.fi-social-pinterest:before,
+.fi-social-rdio:before,
+.fi-social-reddit:before,
+.fi-social-skillshare:before,
+.fi-social-skype:before,
+.fi-social-smashing-mag:before,
+.fi-social-snapchat:before,
+.fi-social-spotify:before,
+.fi-social-squidoo:before,
+.fi-social-stack-overflow:before,
+.fi-social-steam:before,
+.fi-social-stumbleupon:before,
+.fi-social-treehouse:before,
+.fi-social-tumblr:before,
+.fi-social-twitter:before,
+.fi-social-vimeo:before,
+.fi-social-windows:before,
+.fi-social-xbox:before,
+.fi-social-yahoo:before,
+.fi-social-yelp:before,
+.fi-social-youtube:before,
+.fi-social-zerply:before,
+.fi-social-zurb:before,
+.fi-sound:before,
+.fi-star:before,
+.fi-stop:before,
+.fi-strikethrough:before,
+.fi-subscript:before,
+.fi-superscript:before,
+.fi-tablet-landscape:before,
+.fi-tablet-portrait:before,
+.fi-target-two:before,
+.fi-target:before,
+.fi-telephone-accessible:before,
+.fi-telephone:before,
+.fi-text-color:before,
+.fi-thumbnails:before,
+.fi-ticket:before,
+.fi-torso-business:before,
+.fi-torso-female:before,
+.fi-torso:before,
+.fi-torsos-all-female:before,
+.fi-torsos-all:before,
+.fi-torsos-female-male:before,
+.fi-torsos-male-female:before,
+.fi-torsos:before,
+.fi-trash:before,
+.fi-trees:before,
+.fi-trophy:before,
+.fi-underline:before,
+.fi-universal-access:before,
+.fi-unlink:before,
+.fi-unlock:before,
+.fi-upload-cloud:before,
+.fi-upload:before,
+.fi-usb:before,
+.fi-video:before,
+.fi-volume-none:before,
+.fi-volume-strike:before,
+.fi-volume:before,
+.fi-web:before,
+.fi-wheelchair:before,
+.fi-widget:before,
+.fi-wrench:before,
+.fi-x-circle:before,
+.fi-x:before,
+.fi-yen:before,
+.fi-zoom-in:before,
+.fi-zoom-out:before {
+ font-family: "foundation-icons";
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ display: inline-block;
+ text-decoration: inherit;
+}
+
+.fi-address-book:before { content: "\f100"; }
+.fi-alert:before { content: "\f101"; }
+.fi-align-center:before { content: "\f102"; }
+.fi-align-justify:before { content: "\f103"; }
+.fi-align-left:before { content: "\f104"; }
+.fi-align-right:before { content: "\f105"; }
+.fi-anchor:before { content: "\f106"; }
+.fi-annotate:before { content: "\f107"; }
+.fi-archive:before { content: "\f108"; }
+.fi-arrow-down:before { content: "\f109"; }
+.fi-arrow-left:before { content: "\f10a"; }
+.fi-arrow-right:before { content: "\f10b"; }
+.fi-arrow-up:before { content: "\f10c"; }
+.fi-arrows-compress:before { content: "\f10d"; }
+.fi-arrows-expand:before { content: "\f10e"; }
+.fi-arrows-in:before { content: "\f10f"; }
+.fi-arrows-out:before { content: "\f110"; }
+.fi-asl:before { content: "\f111"; }
+.fi-asterisk:before { content: "\f112"; }
+.fi-at-sign:before { content: "\f113"; }
+.fi-background-color:before { content: "\f114"; }
+.fi-battery-empty:before { content: "\f115"; }
+.fi-battery-full:before { content: "\f116"; }
+.fi-battery-half:before { content: "\f117"; }
+.fi-bitcoin-circle:before { content: "\f118"; }
+.fi-bitcoin:before { content: "\f119"; }
+.fi-blind:before { content: "\f11a"; }
+.fi-bluetooth:before { content: "\f11b"; }
+.fi-bold:before { content: "\f11c"; }
+.fi-book-bookmark:before { content: "\f11d"; }
+.fi-book:before { content: "\f11e"; }
+.fi-bookmark:before { content: "\f11f"; }
+.fi-braille:before { content: "\f120"; }
+.fi-burst-new:before { content: "\f121"; }
+.fi-burst-sale:before { content: "\f122"; }
+.fi-burst:before { content: "\f123"; }
+.fi-calendar:before { content: "\f124"; }
+.fi-camera:before { content: "\f125"; }
+.fi-check:before { content: "\f126"; }
+.fi-checkbox:before { content: "\f127"; }
+.fi-clipboard-notes:before { content: "\f128"; }
+.fi-clipboard-pencil:before { content: "\f129"; }
+.fi-clipboard:before { content: "\f12a"; }
+.fi-clock:before { content: "\f12b"; }
+.fi-closed-caption:before { content: "\f12c"; }
+.fi-cloud:before { content: "\f12d"; }
+.fi-comment-minus:before { content: "\f12e"; }
+.fi-comment-quotes:before { content: "\f12f"; }
+.fi-comment-video:before { content: "\f130"; }
+.fi-comment:before { content: "\f131"; }
+.fi-comments:before { content: "\f132"; }
+.fi-compass:before { content: "\f133"; }
+.fi-contrast:before { content: "\f134"; }
+.fi-credit-card:before { content: "\f135"; }
+.fi-crop:before { content: "\f136"; }
+.fi-crown:before { content: "\f137"; }
+.fi-css3:before { content: "\f138"; }
+.fi-database:before { content: "\f139"; }
+.fi-die-five:before { content: "\f13a"; }
+.fi-die-four:before { content: "\f13b"; }
+.fi-die-one:before { content: "\f13c"; }
+.fi-die-six:before { content: "\f13d"; }
+.fi-die-three:before { content: "\f13e"; }
+.fi-die-two:before { content: "\f13f"; }
+.fi-dislike:before { content: "\f140"; }
+.fi-dollar-bill:before { content: "\f141"; }
+.fi-dollar:before { content: "\f142"; }
+.fi-download:before { content: "\f143"; }
+.fi-eject:before { content: "\f144"; }
+.fi-elevator:before { content: "\f145"; }
+.fi-euro:before { content: "\f146"; }
+.fi-eye:before { content: "\f147"; }
+.fi-fast-forward:before { content: "\f148"; }
+.fi-female-symbol:before { content: "\f149"; }
+.fi-female:before { content: "\f14a"; }
+.fi-filter:before { content: "\f14b"; }
+.fi-first-aid:before { content: "\f14c"; }
+.fi-flag:before { content: "\f14d"; }
+.fi-folder-add:before { content: "\f14e"; }
+.fi-folder-lock:before { content: "\f14f"; }
+.fi-folder:before { content: "\f150"; }
+.fi-foot:before { content: "\f151"; }
+.fi-foundation:before { content: "\f152"; }
+.fi-graph-bar:before { content: "\f153"; }
+.fi-graph-horizontal:before { content: "\f154"; }
+.fi-graph-pie:before { content: "\f155"; }
+.fi-graph-trend:before { content: "\f156"; }
+.fi-guide-dog:before { content: "\f157"; }
+.fi-hearing-aid:before { content: "\f158"; }
+.fi-heart:before { content: "\f159"; }
+.fi-home:before { content: "\f15a"; }
+.fi-html5:before { content: "\f15b"; }
+.fi-indent-less:before { content: "\f15c"; }
+.fi-indent-more:before { content: "\f15d"; }
+.fi-info:before { content: "\f15e"; }
+.fi-italic:before { content: "\f15f"; }
+.fi-key:before { content: "\f160"; }
+.fi-laptop:before { content: "\f161"; }
+.fi-layout:before { content: "\f162"; }
+.fi-lightbulb:before { content: "\f163"; }
+.fi-like:before { content: "\f164"; }
+.fi-link:before { content: "\f165"; }
+.fi-list-bullet:before { content: "\f166"; }
+.fi-list-number:before { content: "\f167"; }
+.fi-list-thumbnails:before { content: "\f168"; }
+.fi-list:before { content: "\f169"; }
+.fi-lock:before { content: "\f16a"; }
+.fi-loop:before { content: "\f16b"; }
+.fi-magnifying-glass:before { content: "\f16c"; }
+.fi-mail:before { content: "\f16d"; }
+.fi-male-female:before { content: "\f16e"; }
+.fi-male-symbol:before { content: "\f16f"; }
+.fi-male:before { content: "\f170"; }
+.fi-map:before { content: "\f171"; }
+.fi-marker:before { content: "\f172"; }
+.fi-megaphone:before { content: "\f173"; }
+.fi-microphone:before { content: "\f174"; }
+.fi-minus-circle:before { content: "\f175"; }
+.fi-minus:before { content: "\f176"; }
+.fi-mobile-signal:before { content: "\f177"; }
+.fi-mobile:before { content: "\f178"; }
+.fi-monitor:before { content: "\f179"; }
+.fi-mountains:before { content: "\f17a"; }
+.fi-music:before { content: "\f17b"; }
+.fi-next:before { content: "\f17c"; }
+.fi-no-dogs:before { content: "\f17d"; }
+.fi-no-smoking:before { content: "\f17e"; }
+.fi-page-add:before { content: "\f17f"; }
+.fi-page-copy:before { content: "\f180"; }
+.fi-page-csv:before { content: "\f181"; }
+.fi-page-delete:before { content: "\f182"; }
+.fi-page-doc:before { content: "\f183"; }
+.fi-page-edit:before { content: "\f184"; }
+.fi-page-export-csv:before { content: "\f185"; }
+.fi-page-export-doc:before { content: "\f186"; }
+.fi-page-export-pdf:before { content: "\f187"; }
+.fi-page-export:before { content: "\f188"; }
+.fi-page-filled:before { content: "\f189"; }
+.fi-page-multiple:before { content: "\f18a"; }
+.fi-page-pdf:before { content: "\f18b"; }
+.fi-page-remove:before { content: "\f18c"; }
+.fi-page-search:before { content: "\f18d"; }
+.fi-page:before { content: "\f18e"; }
+.fi-paint-bucket:before { content: "\f18f"; }
+.fi-paperclip:before { content: "\f190"; }
+.fi-pause:before { content: "\f191"; }
+.fi-paw:before { content: "\f192"; }
+.fi-paypal:before { content: "\f193"; }
+.fi-pencil:before { content: "\f194"; }
+.fi-photo:before { content: "\f195"; }
+.fi-play-circle:before { content: "\f196"; }
+.fi-play-video:before { content: "\f197"; }
+.fi-play:before { content: "\f198"; }
+.fi-plus:before { content: "\f199"; }
+.fi-pound:before { content: "\f19a"; }
+.fi-power:before { content: "\f19b"; }
+.fi-previous:before { content: "\f19c"; }
+.fi-price-tag:before { content: "\f19d"; }
+.fi-pricetag-multiple:before { content: "\f19e"; }
+.fi-print:before { content: "\f19f"; }
+.fi-prohibited:before { content: "\f1a0"; }
+.fi-projection-screen:before { content: "\f1a1"; }
+.fi-puzzle:before { content: "\f1a2"; }
+.fi-quote:before { content: "\f1a3"; }
+.fi-record:before { content: "\f1a4"; }
+.fi-refresh:before { content: "\f1a5"; }
+.fi-results-demographics:before { content: "\f1a6"; }
+.fi-results:before { content: "\f1a7"; }
+.fi-rewind-ten:before { content: "\f1a8"; }
+.fi-rewind:before { content: "\f1a9"; }
+.fi-rss:before { content: "\f1aa"; }
+.fi-safety-cone:before { content: "\f1ab"; }
+.fi-save:before { content: "\f1ac"; }
+.fi-share:before { content: "\f1ad"; }
+.fi-sheriff-badge:before { content: "\f1ae"; }
+.fi-shield:before { content: "\f1af"; }
+.fi-shopping-bag:before { content: "\f1b0"; }
+.fi-shopping-cart:before { content: "\f1b1"; }
+.fi-shuffle:before { content: "\f1b2"; }
+.fi-skull:before { content: "\f1b3"; }
+.fi-social-500px:before { content: "\f1b4"; }
+.fi-social-adobe:before { content: "\f1b5"; }
+.fi-social-amazon:before { content: "\f1b6"; }
+.fi-social-android:before { content: "\f1b7"; }
+.fi-social-apple:before { content: "\f1b8"; }
+.fi-social-behance:before { content: "\f1b9"; }
+.fi-social-bing:before { content: "\f1ba"; }
+.fi-social-blogger:before { content: "\f1bb"; }
+.fi-social-delicious:before { content: "\f1bc"; }
+.fi-social-designer-news:before { content: "\f1bd"; }
+.fi-social-deviant-art:before { content: "\f1be"; }
+.fi-social-digg:before { content: "\f1bf"; }
+.fi-social-dribbble:before { content: "\f1c0"; }
+.fi-social-drive:before { content: "\f1c1"; }
+.fi-social-dropbox:before { content: "\f1c2"; }
+.fi-social-evernote:before { content: "\f1c3"; }
+.fi-social-facebook:before { content: "\f1c4"; }
+.fi-social-flickr:before { content: "\f1c5"; }
+.fi-social-forrst:before { content: "\f1c6"; }
+.fi-social-foursquare:before { content: "\f1c7"; }
+.fi-social-game-center:before { content: "\f1c8"; }
+.fi-social-github:before { content: "\f1c9"; }
+.fi-social-google-plus:before { content: "\f1ca"; }
+.fi-social-hacker-news:before { content: "\f1cb"; }
+.fi-social-hi5:before { content: "\f1cc"; }
+.fi-social-instagram:before { content: "\f1cd"; }
+.fi-social-joomla:before { content: "\f1ce"; }
+.fi-social-lastfm:before { content: "\f1cf"; }
+.fi-social-linkedin:before { content: "\f1d0"; }
+.fi-social-medium:before { content: "\f1d1"; }
+.fi-social-myspace:before { content: "\f1d2"; }
+.fi-social-orkut:before { content: "\f1d3"; }
+.fi-social-path:before { content: "\f1d4"; }
+.fi-social-picasa:before { content: "\f1d5"; }
+.fi-social-pinterest:before { content: "\f1d6"; }
+.fi-social-rdio:before { content: "\f1d7"; }
+.fi-social-reddit:before { content: "\f1d8"; }
+.fi-social-skillshare:before { content: "\f1d9"; }
+.fi-social-skype:before { content: "\f1da"; }
+.fi-social-smashing-mag:before { content: "\f1db"; }
+.fi-social-snapchat:before { content: "\f1dc"; }
+.fi-social-spotify:before { content: "\f1dd"; }
+.fi-social-squidoo:before { content: "\f1de"; }
+.fi-social-stack-overflow:before { content: "\f1df"; }
+.fi-social-steam:before { content: "\f1e0"; }
+.fi-social-stumbleupon:before { content: "\f1e1"; }
+.fi-social-treehouse:before { content: "\f1e2"; }
+.fi-social-tumblr:before { content: "\f1e3"; }
+.fi-social-twitter:before { content: "\f1e4"; }
+.fi-social-vimeo:before { content: "\f1e5"; }
+.fi-social-windows:before { content: "\f1e6"; }
+.fi-social-xbox:before { content: "\f1e7"; }
+.fi-social-yahoo:before { content: "\f1e8"; }
+.fi-social-yelp:before { content: "\f1e9"; }
+.fi-social-youtube:before { content: "\f1ea"; }
+.fi-social-zerply:before { content: "\f1eb"; }
+.fi-social-zurb:before { content: "\f1ec"; }
+.fi-sound:before { content: "\f1ed"; }
+.fi-star:before { content: "\f1ee"; }
+.fi-stop:before { content: "\f1ef"; }
+.fi-strikethrough:before { content: "\f1f0"; }
+.fi-subscript:before { content: "\f1f1"; }
+.fi-superscript:before { content: "\f1f2"; }
+.fi-tablet-landscape:before { content: "\f1f3"; }
+.fi-tablet-portrait:before { content: "\f1f4"; }
+.fi-target-two:before { content: "\f1f5"; }
+.fi-target:before { content: "\f1f6"; }
+.fi-telephone-accessible:before { content: "\f1f7"; }
+.fi-telephone:before { content: "\f1f8"; }
+.fi-text-color:before { content: "\f1f9"; }
+.fi-thumbnails:before { content: "\f1fa"; }
+.fi-ticket:before { content: "\f1fb"; }
+.fi-torso-business:before { content: "\f1fc"; }
+.fi-torso-female:before { content: "\f1fd"; }
+.fi-torso:before { content: "\f1fe"; }
+.fi-torsos-all-female:before { content: "\f1ff"; }
+.fi-torsos-all:before { content: "\f200"; }
+.fi-torsos-female-male:before { content: "\f201"; }
+.fi-torsos-male-female:before { content: "\f202"; }
+.fi-torsos:before { content: "\f203"; }
+.fi-trash:before { content: "\f204"; }
+.fi-trees:before { content: "\f205"; }
+.fi-trophy:before { content: "\f206"; }
+.fi-underline:before { content: "\f207"; }
+.fi-universal-access:before { content: "\f208"; }
+.fi-unlink:before { content: "\f209"; }
+.fi-unlock:before { content: "\f20a"; }
+.fi-upload-cloud:before { content: "\f20b"; }
+.fi-upload:before { content: "\f20c"; }
+.fi-usb:before { content: "\f20d"; }
+.fi-video:before { content: "\f20e"; }
+.fi-volume-none:before { content: "\f20f"; }
+.fi-volume-strike:before { content: "\f210"; }
+.fi-volume:before { content: "\f211"; }
+.fi-web:before { content: "\f212"; }
+.fi-wheelchair:before { content: "\f213"; }
+.fi-widget:before { content: "\f214"; }
+.fi-wrench:before { content: "\f215"; }
+.fi-x-circle:before { content: "\f216"; }
+.fi-x:before { content: "\f217"; }
+.fi-yen:before { content: "\f218"; }
+.fi-zoom-in:before { content: "\f219"; }
+.fi-zoom-out:before { content: "\f21a"; }
diff --git a/afb-client/app/Frontend/styles/foundation/_foundation-settings.scss b/afb-client/app/Frontend/styles/foundation/_foundation-settings.scss
new file mode 100644
index 0000000..d4c6415
--- /dev/null
+++ b/afb-client/app/Frontend/styles/foundation/_foundation-settings.scss
@@ -0,0 +1,605 @@
+// FOUNDATION FOR APPS SETTINGS
+// ----------------------------
+//
+// Table of Contents:
+//
+// 1. CSS Exports
+// 2. Global Styles
+// 3. Breakpoints
+// 4. Typography
+// 5. Grid
+// 6. Button
+// 7. Accordion
+// 8. Action Sheet
+// 9. Block List
+// 10. Button Group
+// 11. Card
+// 12. Extras
+// 13. Forms
+// 14. Iconic
+// 15. Label
+// 16. Menu Bar
+// 17. Modal
+// 18. Motion UI
+// 19. Notification
+// 20. Off-canvas
+// 21. Panel
+// 22. Popup
+// 23. Switch
+// 24. Tabs
+// 25. Title Bar
+
+@import "helpers/functions";
+
+// 1. CSS Exports
+// - - - - - - - - - - - - - - -
+
+// Change any value in this map from "true" to "false" to disable that component's CSS class output. You'll still be able to use the component's mixins, but none of our pre-written classes will be in your CSS.
+
+ $include-css: (
+ accordion: true,
+ action-sheet: true,
+ block-list: true,
+ button: true,
+ button-group: true,
+ card: true,
+ coloring: true,
+ extras: true,
+ forms: true,
+ grid: true,
+ iconic: true,
+ label: true,
+ badge: true,
+ list: true,
+ menu-bar: true,
+ modal: true,
+ motion: true,
+ notification: true,
+ off-canvas: true,
+ panel: true,
+ popup: true,
+ switch: true,
+ tabs: true,
+ title-bar: true,
+ typography: true,
+ utilities: true,
+ );
+
+// 2. Global Styles
+// - - - - - - - - - - - - - - -
+
+// This sets 1rem to be 16px
+// $rem-base: 16px;
+
+// The default font-size is set to 100% of the browser style sheet (usually 16px)
+// for compatibility with browser-based text zoom or user-set defaults.
+
+// Since the typical default browser font-size is 16px, that makes the calculation for grid size.
+// If you want your base font-size to be different and not have it affect the grid breakpoints,
+// set $rem-base to $base-font-size and make sure $base-font-size is a px value.
+// $base-font-size: 100%;
+
+// $base-line-height is 24px while $base-font-size is 16px
+// $base-line-height: 1.5;
+
+// Text selector helpers
+// $headers: "h1,h2,h3,h4,h5,h6";
+
+// We use these to define default font weights
+// $font-weight-normal: normal;
+// $font-weight-bold: bold;
+
+// We use these to control various global styles
+// $body-background: #fff;
+// $body-font-color: #222;
+// $body-font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
+// $body-font-weight: $font-weight-normal;
+// $body-font-style: normal;
+// $body-antialiased: true;
+
+// Application Colors
+// $primary-color: #00558b;
+// $secondary-color: #f1f1f1;
+// $alert-color: #F04124;
+// $info-color: #A0D3E8;
+// $success-color: #43AC6A;
+// $warning-color: #F08A24;
+// $dark-color: #232323;
+// $gray: #dfdfdf;
+// $gray-dark: darken($gray, 8);
+// $gray-light: lighten($gray, 8);
+
+// We use these to make sure border radius matches unless we want it different.
+// $global-radius: 4px;
+// $global-rounded: 1000px;
+
+// We use this for default spacing
+// $global-padding: 1rem;
+// $global-spacing: rem-calc(15);
+
+// 3. Breakpoints
+// - - - - - - - - - - - - - - -
+
+// These are our named breakpoints. You can use them in our breakpoint function like this: @include breakpoint(medium) { // Medium and larger styles }
+// $breakpoints: (
+// small: rem-calc(0),
+// medium: rem-calc(640),
+// large: rem-calc(1200),
+// xlarge: rem-calc(1440),
+// xxlarge: rem-calc(1920),
+// );
+
+// All of the names in this list will be output as classes in your CSS, like small-12, medium-6, and so on.
+// $breakpoint-classes: (small medium large);
+
+// 4. Typography
+// - - - - - - - - - - - - - - -
+
+// We use these to control header font styles
+// $header-font-family: $body-font-family;
+// $header-font-weight: $font-weight-normal;
+// $header-font-style: $font-weight-normal;
+// $header-font-color: #222;
+// $header-line-height: 1.4;
+// $header-top-margin: .2rem;
+// $header-bottom-margin: .5rem;
+// $header-text-rendering: optimizeLegibility;
+
+// We use these to control header font sizes
+// $h1-font-size: rem-calc(44);
+// $h2-font-size: rem-calc(37);
+// $h3-font-size: rem-calc(27);
+// $h4-font-size: rem-calc(23);
+// $h5-font-size: rem-calc(18);
+// $h6-font-size: 1rem;
+
+// We use these to control header size reduction on small screens
+// $h1-font-reduction: rem-calc(10);
+// $h2-font-reduction: rem-calc(10);
+// $h3-font-reduction: rem-calc(5);
+// $h4-font-reduction: rem-calc(5);
+// $h5-font-reduction: 0;
+// $h6-font-reduction: 0;
+
+// These control how subheaders are styled.
+// $subheader-line-height: 1.4;
+// $subheader-font-color: scale-color($header-font-color, $lightness: 35%);
+// $subheader-font-weight: $font-weight-normal;
+// $subheader-top-margin: .2rem;
+// $subheader-bottom-margin: .5rem;
+
+// A general <small> styling
+// $small-font-size: 60%;
+// $small-font-color: scale-color($header-font-color, $lightness: 35%);
+
+// We use these to style paragraphs
+// $paragraph-font-family: inherit;
+// $paragraph-font-weight: $font-weight-normal;
+// $paragraph-font-size: 1rem;
+// $paragraph-line-height: 1.6;
+// $paragraph-margin-bottom: rem-calc(20);
+// $paragraph-aside-font-size: rem-calc(14);
+// $paragraph-aside-line-height: 1.35;
+// $paragraph-aside-font-style: italic;
+// $paragraph-text-rendering: optimizeLegibility;
+
+// We use these to style <code> tags
+// $code-color: grayscale($primary-color);
+// $code-font-family: Consolas, 'Liberation Mono', Courier, monospace;
+// $code-font-weight: $font-weight-normal;
+// $code-background-color: scale-color($secondary-color, $lightness: 70%);
+// $code-border-size: 1px;
+// $code-border-style: solid;
+// $code-border-color: scale-color($code-background-color, $lightness: -10%);
+// $code-padding: rem-calc(2) rem-calc(5) rem-calc(1);
+
+// We use these to style anchors
+// $anchor-text-decoration: none;
+// $anchor-text-decoration-hover: none;
+// $anchor-font-color: $primary-color;
+// $anchor-font-color-hover: scale-color($anchor-font-color, $lightness: -14%);
+
+// We use these to style the <hr> element
+// $hr-border-width: 1px;
+// $hr-border-style: solid;
+// $hr-border-color: #ddd;
+// $hr-margin: rem-calc(20);
+
+// We use these to style lists
+// $list-font-family: $paragraph-font-family;
+// $list-font-size: $paragraph-font-size;
+// $list-line-height: $paragraph-line-height;
+// $list-margin-bottom: $paragraph-margin-bottom;
+// $list-style-position: outside;
+// $list-side-margin: 1.1rem;
+// $list-ordered-side-margin: 1.4rem;
+// $list-side-margin-no-bullet: 0;
+// $list-nested-margin: rem-calc(20);
+// $definition-list-header-weight: $font-weight-bold;
+// $definition-list-header-margin-bottom: .3rem;
+// $definition-list-margin-bottom: rem-calc(12);
+
+// We use these to style blockquotes
+// $blockquote-font-color: scale-color($header-font-color, $lightness: 35%);
+// $blockquote-padding: rem-calc(9 20 0 19);
+// $blockquote-border: 1px solid #ddd;
+// $blockquote-cite-font-size: rem-calc(13);
+// $blockquote-cite-font-color: scale-color($header-font-color, $lightness: 23%);
+// $blockquote-cite-link-color: $blockquote-cite-font-color;
+
+// Acronym styles
+// $acronym-underline: 1px dotted #ddd;
+
+// 5. Grid
+// - - - - - - - - - - - - - - -
+
+// $container-width: rem-calc(900);
+// $block-padding: $global-padding;
+// $total-columns: 12;
+// $block-grid-max-size: 6;
+
+// 6. Button
+// - - - - - - - - - - - - - - -
+
+// $button-padding: 0.85em 1em;
+// $button-margin: 0 $global-padding $global-padding 0;
+// $button-style: solid;
+// $button-background: $primary-color;
+// $button-color: auto;
+// $button-radius: 0;
+// $button-sizes: (
+// tiny: 0.7,
+// small: 0.8,
+// medium: 1,
+// large: 1.3,
+// );
+// $button-font-size: 0.9rem;
+// $button-opacity-disabled: 0.5;
+// $button-tag-selector: false;
+
+// 7. Accordion
+// - - - - - - - - - - - - - - -
+
+// $accordion-border: 1px solid $gray-dark;
+
+// $accordion-title-background: $gray-light;
+// $accordion-title-background-hover: smartscale($accordion-title-background, 5%);
+// $accordion-title-background-active: smartscale($accordion-title-background, 3%);
+// $accordion-title-color: isitlight($accordion-title-background);
+// $accordion-title-color-active: isitlight($accordion-title-background);
+
+// $accordion-title-padding: $global-padding;
+// $accordion-content-padding: $global-padding;
+
+// 8. Action Sheet
+// - - - - - - - - - - - - - - -
+
+// $actionsheet-background: white;
+// $actionsheet-border-color: #ccc;
+// $actionsheet-animate: transform opacity;
+// $actionsheet-animation-speed: 0.25s;
+// $actionsheet-width: 300px;
+// $actionsheet-radius: 4px;
+// $actionsheet-shadow: 0 -3px 10px rgba(black, 0.25);
+// $actionsheet-padding: $global-padding;
+// $actionsheet-tail-size: 10px;
+
+// $actionsheet-popup-shadow: 0 0 10px rgba(black, 0.25);
+
+// $actionsheet-link-color: #000;
+// $actionsheet-link-background-hover: smartscale($actionsheet-background);
+
+// 9. Block List
+// - - - - - - - - - - - - - - -
+
+// $blocklist-background: #fff;
+// $blocklist-fullbleed: true;
+// $blocklist-fontsize: 1rem;
+
+// $blocklist-item-padding: 0.8rem 1rem;
+// $blocklist-item-color: isitlight($blocklist-background, #000, #fff);
+// $blocklist-item-background-hover: smartscale($blocklist-background, 4.5%);
+// $blocklist-item-color-disabled: #999;
+// $blocklist-item-border: 1px solid smartscale($blocklist-background, 18.5%);
+
+// $blocklist-item-label-color: scale-color($blocklist-item-color, $lightness: 60%);
+// $blocklist-item-icon-size: 0.8;
+
+// $blocklist-header-fontsize: 0.8em;
+// $blocklist-header-color: smartscale($blocklist-item-color, 40%);
+// $blocklist-header-uppercase: true;
+
+// $blocklist-check-icons: true;
+
+// 10. Button Group
+// - - - - - - - - - - - - - - -
+
+// $btngroup-background: $primary-color;
+// $btngroup-color: #fff;
+// $btngroup-radius: $button-radius;
+
+// 11. Card
+// - - - - - - - - - - - - - - -
+
+// $card-background: #fff;
+// $card-color: isitlight($card-background);
+// $card-border: 1px solid smartscale($card-background, 7%);
+// $card-radius: $global-radius;
+// $card-shadow: 0 1px 2px rgba(#000, 0.2);
+// $card-padding: $global-padding;
+// $card-margin: 0.5rem;
+
+// $card-divider-background: smartscale($card-background, 7%);
+
+// 12. Extras
+// - - - - - - - - - - - - - - -
+
+// $closebutton-position: (top right);
+// $closebutton-size: 2em;
+// $closebutton-lineheight: 0.5;
+// $closebutton-color: #999;
+// $closebutton-color-hover: #333;
+
+// $thumbnail-padding: 0.5rem;
+// $thumbnail-shadow: 0 3px 15px rgba(black, 0.25);
+
+// 13. Forms
+// - - - - - - - - - - - - - - -
+
+// Basic form variables
+// $form-fontsize: 1rem;
+// $form-padding: 0.5rem;
+
+// Text fields
+// $input-color: #000;
+// $input-color-hover: $input-color;
+// $input-color-focus: $input-color;
+// $input-background: #fff;
+// $input-background-hover: $input-background;
+// $input-background-focus: $input-background;
+// $input-border: 1px solid #ccc;
+// $input-border-hover: 1px solid #bbb;
+// $input-border-focus: 1px solid #999;
+
+// Select menus
+// $select-color: #000;
+// $select-background: #fafafa;
+// $select-background-hover: smartscale($select-background, 4%);
+// $select-arrow: true;
+// $select-arrow-color: $select-color;
+
+// Labels
+// $form-label-fontsize: 0.9rem;
+// $form-label-margin: 0.5rem;
+// $form-label-color: #333;
+
+// Inline labels
+// $inlinelabel-color: #333;
+// $inlinelabel-background: #eee;
+// $inlinelabel-border: $input-border;
+
+// Range slider
+// $slider-background: #ddd;
+// $slider-height: 1rem;
+// $slider-radius: 0px;
+// $slider-thumb-height: 1.5rem;
+// $slider-thumb-color: $primary-color;
+// $slider-thumb-radius: 0px;
+
+// Progress and meter
+// $meter-height: 1.5rem;
+// $meter-background: #ccc;
+// $meter-fill: $primary-color;
+// $meter-fill-high: $success-color;
+// $meter-fill-medium: #e7cf00;
+// $meter-fill-low: $alert-color;
+// $meter-radius: 0;
+
+// 14. Iconic
+// - - - - - - - - - - - - - - -
+
+// $iconic-primary-fill: $primary-color;
+// $iconic-primary-stroke: $primary-color;
+// $iconic-accent-fill: $iconic-primary-fill;
+// $iconic-accent-stroke: $iconic-accent-fill;
+
+// 15. Label
+// - - - - - - - - - - - - - - -
+
+// $label-fontsize: 0.8rem;
+// $label-padding: ($global-padding / 3) ($global-padding / 2);
+// $label-radius: 0;
+// $label-background: $primary-color;
+// $label-color: isitlight($primary-color);
+
+// $badge-fontsize: 0.8em;
+// $badge-diameter: 1.5rem;
+// $badge-background: $primary-color;
+// $badge-color: #fff;
+
+// DEPRECATED: these variables will be removed in v1.1.
+// $badge-padding: .1em .61em;
+// $badge-radius: $global-rounded;
+// $badge-font-color: #fff;
+
+// 16. Menu Bar
+// - - - - - - - - - - - - - - -
+
+// $menubar-fontsize: 1rem;
+// $menubar-background: #fff;
+// $menubar-background-hover: smartscale($menubar-background, 7%);
+// $menubar-background-active: $menubar-background-hover;
+// $menubar-color: isitlight($menubar-background);
+// $menubar-color-hover: $menubar-color;
+// $menubar-color-active: $menubar-color-hover;
+
+// $menubar-item-padding: $global-padding;
+// $menubar-icon-size: 25px;
+// $menubar-icon-spacing: $menubar-item-padding;
+
+// 17. Modal
+// - - - - - - - - - - - - - - -
+
+// $modal-background: #fff;
+// $modal-border: 0;
+// $modal-radius: 0px;
+// $modal-shadow: none;
+// $modal-zindex: 1000;
+// $modal-sizes: (
+// tiny: 300px,
+// small: 500px,
+// medium: 600px,
+// large: 800px,
+// );
+
+// $modal-overlay-class: 'modal-overlay';
+// $modal-overlay-background: rgba(#333, 0.7);
+
+// 18. Motion UI
+// - - - - - - - - - - - - - - -
+
+// Classes to use when triggering in/out animations
+// $motion-class: (
+// in: "ng-enter",
+// out: "ng-leave",
+// );
+// $motion-class-active: (
+// in: "ng-enter-active",
+// out: "ng-leave-active",
+// );
+// $motion-class-stagger: (
+// in: "ng-enter-stagger",
+// out: "ng-leave-stagger",
+// );
+
+// Set if movement-based transitions should also fade the element in and out
+// $motion-slide-and-fade: false;
+// $motion-hinge-and-fade: true;
+// $motion-scale-and-fade: true;
+// $motion-spin-and-fade: true;
+
+// Default speed for transitions and animations
+// $motion-duration-default: 500ms;
+// Slow and fast modifiders
+// $motion-duration-slow: 750ms;
+// $motion-duration-fast: 250ms;
+// $motion-stagger-duration-default: 150ms;
+// $motion-stagger-duration-short: 50ms;
+// $motion-stagger-duration-long: 300ms;
+
+// Default timing function for transitions and animations
+// $motion-timing-default: ease;
+// Built-in and custom easing functions
+// Every item in this map becomes a CSS class
+// $motion-timings: (
+// linear: linear,
+// ease: ease,
+// easeIn: ease-in,
+// easeOut: ease-out,
+// easeInOut: ease-in-out,
+// bounceIn: cubic-bezier(0.485, 0.155, 0.240, 1.245),
+// bounceOut: cubic-bezier(0.485, 0.155, 0.515, 0.845),
+// bounceInOut: cubic-bezier(0.760, -0.245, 0.240, 1.245),
+// );
+
+// Default delay for all transitions and animations
+// $motion-delay-default: 0;
+// Short and long delay modifiers
+// $motion-delay-short: 300ms;
+// $motion-delay-long: 700ms;
+
+// 19. Notification
+// - - - - - - - - - - - - - - -
+
+// $notification-default-position: right top;
+// $notification-width: rem-calc(400);
+// $notification-offset: $global-padding;
+
+// $notification-background: $primary-color;
+// $notification-color: white;
+// $notification-padding: $global-padding;
+// $notification-radius: 4px;
+
+// $notification-icon-size: 60px;
+// $notification-icon-margin: $global-padding;
+// $notification-icon-align: top;
+
+
+// 20. Off-canvas
+// - - - - - - - - - - - - - - -
+
+// $offcanvas-size-horizontal: 250px;
+// $offcanvas-size-vertical: 250px;
+
+// $offcanvas-background: #fff;
+// $offcanvas-color: isitlight($offcanvas-background);
+// $offcanvas-padding: 0;
+// $offcanvas-shadow: 3px 0 10px rgba(black, 0.25);
+// $offcanvas-animation-speed: 0.25s;
+
+// $offcanvas-frame-selector: '.grid-frame';
+
+// 21. Panel
+// - - - - - - - - - - - - - - -
+
+// $panel-size-horizontal: 300px;
+// $panel-size-vertical: 300px;
+// $panel-padding: 0;
+
+// $panel-background: #fff;
+// $panel-shadow: 3px 0 10px rgba(black, 0.25);
+// $panel-animation-speed: 0.25s;
+
+// 22. Popup
+// - - - - - - - - - - - - - - -
+
+// $popup-width: rem-calc(300);
+// $popup-background: #fff;
+// $popup-border: 0;
+// $popup-radius: 0;
+// $popup-shadow: 0 0 10px rgba(#000, 0.25);
+
+// 23. Switch
+// - - - - - - - - - - - - - - -
+
+// $switch-width: rem-calc(50);
+// $switch-height: rem-calc(32);
+// $switch-background: #ccc;
+// $switch-background-active: $primary-color;
+// $switch-border: 0;
+// $switch-radius: 9999px;
+// $switch-animation-speed: 0.15s;
+
+// $switch-paddle-color: white;
+// $switch-paddle-offset: 4px;
+
+// 24. Tabs
+// - - - - - - - - - - - - - - -
+
+// $tabstrip-background: transparent;
+
+// $tab-title-background: $gray-light;
+// $tab-title-background-hover: smartscale($tab-title-background, 5%);
+// $tab-title-background-active: smartscale($tab-title-background, 3%);
+// $tab-title-color: isitlight($tab-title-background);
+// $tab-title-color-active: $tab-title-color;
+
+// $tab-title-padding: $global-padding;
+// $tab-content-padding: $global-padding;
+
+// 25. Title Bar
+// - - - - - - - - - - - - - - -
+
+// $titlebar-center-width: 50%;
+// $titlebar-side-width: (100% - $titlebar-center-width) / 2;
+// $titlebar-background: #eee;
+// $titlebar-color: #000;
+// $titlebar-border: 1px solid #ccc;
+// $titlebar-padding: $global-padding;
+// $titlebar-item-classes: (
+// center: 'center',
+// left: 'left',
+// right: 'right',
+// title: 'title',
+// );
+
diff --git a/afb-client/app/Frontend/styles/foundation/foundation-conf.scss b/afb-client/app/Frontend/styles/foundation/foundation-conf.scss
new file mode 100644
index 0000000..bdcfe1f
--- /dev/null
+++ b/afb-client/app/Frontend/styles/foundation/foundation-conf.scss
@@ -0,0 +1,19 @@
+@import "foundation-settings";
+@import "foundation-icons";
+@import "foundation";
+
+
+/*.sidebar {
+ // Panel on small screens
+ @extend %panel-base;
+ @include panel-position(left);
+ // Override styles to become a block on medium screens
+ @include breakpoint(medium) {
+ @include grid-panel-reset;
+ @include grid-block(4);
+ }
+ // Change size to 3 columns on large screens
+ @include breakpoint(large) {
+ @include grid-size(3);
+ }
+}*/ \ No newline at end of file
diff --git a/afb-client/app/Frontend/tmp/routes.js b/afb-client/app/Frontend/tmp/routes.js
new file mode 100644
index 0000000..c3c5ba4
--- /dev/null
+++ b/afb-client/app/Frontend/tmp/routes.js
@@ -0,0 +1 @@
+var foundationRoutes = [{"name":"mysample","url":"/sample","controller":"SampleController as ctrl","animationIn":"slideInRight","path":"pages/Sample/Sample.html"},{"name":"myhome","url":"/home","controller":"HomeController as ctrl","animationIn":"slideInRight","path":"pages/Home/Home.html"}];
diff --git a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js
new file mode 100644
index 0000000..1b94e25
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Bugs: Input with Callback SHOULD BE get 'required' class
+ */
+
+(function () {
+ 'use strict';
+
+ var tmpl = '<div ng-click="clicked()"> <span>' +
+ '<i class="{{icon}}"></i>' +
+ '<span>{{label}}</span>' +
+ '</span></div>';
+
+ angular.module('SubmitButton', [])
+ .directive('submitButton', function () {
+
+ function mymethods(scope, elem, attrs) {
+
+ // ajust icon or use default
+ scope.icon = attrs.icon || 'fi-foot';
+ scope.label = attrs.label || 'Next';
+
+ // add label as class
+ elem.addClass (scope.label.toLowerCase());
+
+ // note: clicked in imported and when template is clicked
+ // it will call clicked method passed in param.
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {clicked : '='}
+ };
+ });
+})();
diff --git a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss
new file mode 100644
index 0000000..2150e4d
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "app/ibz-mixins";
+
+// place here your submit buttons customization
+
diff --git a/afb-client/app/Frontend/widgets/FormInput/FormInput.scss b/afb-client/app/Frontend/widgets/FormInput/FormInput.scss
new file mode 100644
index 0000000..37519fd
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/FormInput/FormInput.scss
@@ -0,0 +1,69 @@
+/*
+ Sample of style overload for a specific widget
+
+ Note: this SCSS is injected with main HTML page, it scope should be reduce
+ to a specific widget or it value will be propagated at a global level.
+*/
+
+@import "app/ibz-mixins";
+
+upload-file {
+ height: 5rem;
+ display: inline-block;
+ float: right;
+ img { height: inherit;}
+}
+
+input-text {
+
+ alert {@include ibz-input-alert(darkblue, rgba(200, 200, 200, 0.6))};
+
+ input {
+ margin-bottom: .5rem !important;
+ }
+
+ label {
+ margin-top: 1rem !important;
+ }
+
+ .required {
+ color: blue;
+ float: right;
+ color: lightskyblue;
+ }
+ .required.valid {
+ color: green;
+ }
+
+ .required.invalid {
+ color: plum;
+ }
+
+ .status-untouch {
+ border-color: rgba(200, 200, 200, 0.6) !important;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(200, 200, 200, 0.6) !important;
+ color: #696969 !important;
+ }
+
+ input:focus {
+ border-color: rgba(82,168,236,0.8) ;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(82,168,236,0.8) !important;
+ transition: border 0.2s linear 0s, box-shadow 0.2s linear 0s;
+ color: darkslateblue !important;
+ @extend shadow-transition;
+ }
+
+ .status-valid {
+ border-color: rgba(154, 205, 50, 0.6)!important;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(154, 205, 50, 0.6)!important;
+ @extend shadow-transition;
+ }
+
+ .status-invalid {
+ border-color: rgba(154, 17, 69, 0.6);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(154, 17, 69, 0.6)!important;
+ color: rgb(154, 17, 69);
+ @extend shadow-transition;
+ }
+
+}
diff --git a/afb-client/app/Frontend/widgets/FormInput/InputPassword.js b/afb-client/app/Frontend/widgets/FormInput/InputPassword.js
new file mode 100644
index 0000000..157009c
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/FormInput/InputPassword.js
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+(function() {
+'use strict';
+
+var tmpl = '<input-text class="password" tip="{{tip1}}" placeholder="{{place1}}"' +
+ 'label="{{label1}}" callback="valid1" name="{{name}}-1" value="pass1" required minlen="{{minlen}}" type="password" >' +
+ '</input-text>' +
+ '<input-text class="password" tip="tip2" placeholder="{{place2}}"' +
+ 'label="{{label2}}" callback="valid2" name="{{name}}-2" value="pass2" required minlen="{{minlen}}" type="password" > '+
+ '</input-text>';
+
+angular.module('InputPassword',[])
+
+.directive('inputPassword', function() {
+ function mymethods(scope, elem, attrs) {
+
+ scope.valid1 = function (name, value) {
+ console.log ("Clicked InputPassword1 name=%s value=%s", name, value);
+ scope.firstpwd = value;
+ };
+
+ scope.valid2 = function (name, value, done) {
+ console.log ("Clicked InputPassword2 name=%s value=%s", name, value);
+
+ // if both passwd equal then call form CB
+ if (scope.firstpwd !== value) {
+ done({valid: false, status: 'invalid', errmsg: "both password should match"});
+ } else {
+ scope.callback (attrs.name, value);
+ }
+
+ };
+
+ // this method can be called from controller to update widget status
+ scope.done=function (data) {
+ console.log ("Text-Input Callback ID="+ attrs.name + " data=", data);
+ for (var i in data) scope[i] = data[i];
+ };
+
+ // Export some attributes within directive scope for template
+ scope.name = attrs.name;
+ scope.label1 = attrs.label || 'Password';
+ scope.label2 = attrs.label || 'Password Verification';
+ scope.place1 = attrs.placeholder1 || 'User Password';
+ scope.tip1 = attrs.tip || 'Choose a Password';
+ scope.place2 = attrs.placeholder1 || 'Password Verification';
+ scope.tip2 = attrs.tip || 'Confirme your Password';
+ scope.minlen = attrs.minlen || 10;
+
+ if ("required" in attrs) scope.required = 'required';
+
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {
+ callback : '=',
+ }
+ };
+});
+
+console.log ("InputPassword Loaded");
+})();
diff --git a/afb-client/app/Frontend/widgets/FormInput/InputText.js b/afb-client/app/Frontend/widgets/FormInput/InputText.js
new file mode 100644
index 0000000..2653175
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/FormInput/InputText.js
@@ -0,0 +1,179 @@
+
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details..
+ */
+
+
+
+(function() {
+'use strict';
+
+var tmpl = '<tip-modal tip="tip"></tip-modal>' +
+ '<label for="{{name}}-intext">{{label}} <i ng-show="required" ng-click="ToBeDefined" ' +
+ 'class="required {{status}} fi-checkbox" title="Free Value But Mandatory Argument" alt="?"> &nbsp; </i></label>'+
+ '<input '+
+ ' type="{{type}}" id="{{name}}-intext" placeholder="{{placeholder}}" class="status-{{status}}"'+
+ ' ng-model="value" ng-blur="validate()" ng-focus="selected()" '+
+ ' ng-model-options="{ updateOn: \'default blur\', debounce: {default: 500, blur: 0} }"' +
+ '><alert data-ng-show="!valid&&errmsg">{{errmsg}}</alert>';
+
+var emailpatern = /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
+
+angular.module('InputText',['JQueryEmu'])
+
+.directive('inputText', function(JQemu) {
+ function mymethods(scope, elem, attrs) {
+
+ // default value at 1st rendering
+ scope.error = false;
+ scope.valid = false;
+ scope.status = 'untouch';
+
+ scope.input = elem.find ("input");
+ scope.required = 0;
+
+ // requirer is use to increment requested counter
+ if ("required" in attrs) {
+ scope.required = 1;
+ elem.addClass ("required");
+ }
+
+ // user enter input reset error status
+ scope.selected = function () {
+ scope.error=false;
+ scope.errmsg=false;
+ scope.status = 'touch';
+ };
+
+ scope.validate = function () {
+
+ // get value from input field bypassing Angular ng-model
+ console.log ("Clicked InputText name=%s value=%s valid=%s", scope.name, scope.value, scope.valid);
+
+ // form is not untouched anymore
+ scope.parent.removeClass ("ng-pristine");
+
+ // if value not null clean up string
+ if (scope.value) {
+ scope.error=false;
+ // remove leading and trailling space
+ scope.value = scope.value.trim();
+
+ // remove any space is not allowed
+ if ('nospace' in attrs) {
+ scope.value=scope.value.replace(/\s/g, '');
+ }
+
+ if ('lowercase' in attrs) {
+ scope.value = scope.value.toLowerCase();
+ }
+
+ // check minimum lenght
+ if ("minlen" in attrs) {
+ if (scope.value.length < attrs.minlen) {
+ scope.status='invalid';
+ scope.errmsg=scope.name + ': Mininum Lengh= ' + attrs.minlen + ' Characters';
+ scope.error=true;
+ }
+ }
+
+ if ('email' in attrs) {
+ if (!emailpatern.test (scope.value)) {
+ scope.status='invalid';
+ scope.errmsg='invalid email address';
+ scope.error=true;
+ }
+ }
+
+ } else {
+ if (scope.required) {
+ scope.status='invalid';
+ scope.errmsg=scope.name + ': Required Attribute';
+ scope.error=true;
+ }
+ }
+
+ // If local control fail let's refuse input
+ if (scope.error) {
+ if (scope.required && scope.valid) {
+ scope.valid = false;
+ if (scope.l4acounter.validated > 0) scope.l4acounter.validated --;
+ }
+ // use call to update form scope on form completeness
+ scope.callback (attrs.name, null, scope.done);
+ } else {
+ // localcheck is OK backup may nevertheless change status to false
+ if (scope.required && !scope.valid) scope.l4acounter.validated ++;
+ scope.status='valid';
+ scope.valid=true;
+ scope.callback (attrs.name, scope.value, scope.done);
+ }
+
+ };
+
+ // this method can be called from controller to update widget status
+ scope.done=function (data) {
+ console.log ("Text-Input Callback ID="+ attrs.name + " data=", data);
+ for (var i in data) scope[i] = data[i];
+ };
+
+ // Export some attributes within directive scope for template
+ scope.label = attrs.label;
+ scope.name = attrs.name;
+ scope.placeholder = attrs.placeholder;
+ scope.type = attrs.type || "text";
+ scope.tip = attrs.tip;
+
+ // search for form within parent elemnts
+ scope.parent = JQemu.parent (elem, "FORM");
+
+ // email enforce lowercase and nospace
+ if ("email" in attrs) {
+ attrs.lowercase=true;
+ attrs.nospace=true;
+ attrs.minlen=6;
+ }
+
+ if (scope.required) {
+ scope.l4acounter = scope.parent.data ("l4acounter");
+ if (!scope.l4acounter) {
+ scope.l4acounter = {required:1, validated:0};
+ console.log("Field "+scope.name+" is required (1st)");
+ scope.parent.data ("l4acounter", scope.l4acounter);
+ } else {
+ console.log("Field "+scope.name+" is required");
+ scope.l4acounter.required ++;
+ }
+ }
+
+ // refresh validation each time controler update value
+ scope.$watch ('value', function(){
+ if(scope.value) scope.validate(); }
+ );
+
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {
+ callback : '=',
+ value: '='
+ }
+ };
+});
+
+console.log ("InputText Loaded");
+})();
diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFile.js b/afb-client/app/Frontend/widgets/FormInput/UploadFile.js
new file mode 100644
index 0000000..9a2f031
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/FormInput/UploadFile.js
@@ -0,0 +1,113 @@
+
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details..
+ *
+ * Reference:
+ * https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications#Using_hidden_file_input_elements_using_the_click%28%29_method
+ * https://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs
+ * https://www.terlici.com/2015/05/16/uploading-files-locally.html
+ * https://github.com/nervgh/angular-file-upload/blob/master/src/services/FileUploader.js
+ */
+
+
+function changeInput() {
+ console.log ('input imgClicked');
+}
+
+(function() {
+'use strict';
+
+// WARNING: Angular ng-change does not work on input/file. Let's hook our callback through standard JS function
+var tmpl = '<form target="null" action="/api/afbs/file-upload" method="post" enctype="multipart/form-data" >'+
+ '<input type="file" name="{{name}}" onchange="angular.element(this).scope().UpLoadFile(this.files)" accept="{{mime}}/*" style="display" >'+
+ '<input type="submit" class="submit" style="display" > ' +
+ '</form>' +
+ '<img id="{{name}}-img" src="{{imagepath}}" ng-click="imgClicked()">' ;
+
+function basename(path) {
+ return path.split('/').reverse()[0];
+}
+
+angular.module('UploadFile',['ConfigApp'])
+
+.directive('uploadFile', function(ConfigApp, $http, JQemu) {
+ function mymethods(scope, elem, attrs) {
+
+ // get widget image handle from template
+ scope.imgElem = elem.find('img');
+ scope.inputElem = elem.find('input');
+ scope.submitElem = JQemu.findByType (elem.children(), "submit");
+
+
+ // Image was ckick let's simulate an input (file) click
+ scope.imgClicked = function () {
+ scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!!
+ };
+
+ // upload file to server
+ scope.UpLoadFile= function(files) {
+
+
+ for (var i = 0; i < files.length; i++) {
+ var file = files[i];
+ console.log ("Selected file=" + file.name + " size="+ file.size/1024);
+ var mimeType = /image.*/; // build regular expression from Mime
+ if (!file.type.match(mimeType)) {
+ continue;
+ }
+
+ if (file.size > scope.sizemax*1024) {
+ scope.imagepath = scope.istoobig; // warning is path is wrong nothing happen
+ scope.$apply('imagepath'); // we short-circuit Angular resync Image
+ } else {
+
+ scope.basename=basename(file.name);
+ scope.imgElem[0].file = file;
+
+ var reader = new FileReader();
+ reader.readAsDataURL(file);
+ reader.onload = function (upload) {
+ scope.imagepath = upload.target.result;
+ scope.$apply('imagepath'); // we short-circuit Angular resync image
+ scope.submitElem[0].click(); // Warning Angular TriggerEvent does not work!!!
+ };
+ }
+ }
+ };
+
+ // Initiallize default values from attributes values
+ if (attrs.icon) scope.imagepath= ConfigApp.paths[attrs.category] + attrs.icon;
+ else scope.imagepath=ConfigApp.paths.avatars + 'tux-bzh.png';
+
+ if (attrs.istoobig) scope.istoobig= ConfigApp.paths[attrs.category] + attrs.istoobig;
+ else scope.istoobig=ConfigApp.paths.avatars + 'istoobig.jpg';
+
+ scope.name= attrs.name || 'avatar';
+ scope.mime= attrs.mime || 'image';
+ scope.sizemax= attrs.sizemax || 100; // default max size 100KB
+
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {
+ callback : '='
+ }
+ };
+});
+
+console.log ("UploadFile Loaded");
+})();
diff --git a/afb-client/app/Frontend/widgets/Navigation/LinkButton.js b/afb-client/app/Frontend/widgets/Navigation/LinkButton.js
new file mode 100644
index 0000000..3e83425
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Navigation/LinkButton.js
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Bugs: Input with Callback SHOULD BE get 'required' class
+ */
+
+(function () {
+ 'use strict';
+
+ var tmpl = '<span title="Goto: {{href}}" ng-click="clicked()">' +
+ '<i class="{{icon}}"></i>' +
+ '<span>{{label}}</span>' +
+ '</span>';
+
+
+ angular.module('LinkButton', [])
+ .directive('linkButton', function ($location) {
+
+ function mymethods(scope, elem, attrs) {
+
+ scope.clicked = function () {
+
+ if (!attrs.query) $location.path(attrs.href);
+ else $location.path(attrs.href).search(attrs.query);
+ };
+
+ // ajust icon or use default
+ scope.icon = attrs.icon || 'fi-link';
+ scope.label = attrs.label || 'Jump';
+ scope.href = attrs.href || '/home';
+
+ // add label as class
+ elem.addClass (scope.label.toLowerCase());
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {}
+ };
+ });
+})();
diff --git a/afb-client/app/Frontend/widgets/Navigation/Navigation.scss b/afb-client/app/Frontend/widgets/Navigation/Navigation.scss
new file mode 100644
index 0000000..2babf24
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Navigation/Navigation.scss
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "app/ibz-mixins";
+
+
+link-button {@include ibz-button(#3366ff,1rem)};
+
+//pale blue for secondaty link
+link-button.secondary {@include ibz-button(#99b3ff,1rem)};
+
diff --git a/afb-client/app/Frontend/widgets/Notifications/ModalNotification.js b/afb-client/app/Frontend/widgets/Notifications/ModalNotification.js
new file mode 100644
index 0000000..37ba047
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Notifications/ModalNotification.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Bugs: Input with Callback SHOULD BE get 'required' class
+ *
+ * ref: https://developer.mozilla.org/en-US/docs/Web/Events/mouseover
+ *
+ * usage:
+ *
+ * tipModal: listen event from elem.parent() to display tip-modal
+ * <div class="xxxx">
+ * <tip-modal tip=xxxx></tip-modal>
+ * <input-text ....></input-text>
+ * </div>
+ *
+ * Note: use CSS.visibility to avoid display flickering at initial display.
+ */
+
+(function () {
+ 'use strict';
+
+ var tmpl = '<div class="tip-modal-popup">' +
+ '<i class="{{icon}}"></i>' +
+ '<span>{{tip}}</span>' +
+ '</span></div>' ;
+
+ angular.module('ModalNotification', [])
+ .directive('tipModal', function ($timeout) {
+
+ function mymethods(scope, elem, attrs) {
+ scope.parent = elem.parent();
+ scope.modal = elem.find("div");
+
+
+ // delay tip display to avoid blinking when moving mouse fast
+ function display () {
+ function action() {
+ if (scope.show) scope.modal.css({opacity: 1, visibility:'visible'});
+ }
+ scope.show = true;
+ scope.timeout = $timeout(action, scope.delay);
+ }
+
+ function close () {
+ scope.show = false;
+ scope.modal.css({opacity: 0, visibility:'hidden'});
+ }
+
+
+ // ajust icon or use default
+ scope.icon = attrs.icon || 'fi-lightbulb';
+
+ // Update Parent element to get mouse event
+ scope.parent.addClass ('as-modal-tip');
+ scope.parent.bind('click', close);
+ scope.parent.bind('focus', display);
+ scope.parent.bind('mouseover', display);
+ scope.parent.bind('mouseleave', close);
+ scope.parent.bind('blur', close);
+
+ scope.delay = attrs.delay || 1000; // wait 1s before displaying tip
+ }
+
+ return {
+ restrict: 'E',
+ template: tmpl,
+ link: mymethods,
+ scope: {tip: "="} // tip may not be defined when widget is display
+ };
+ });
+})();
diff --git a/afb-client/app/Frontend/widgets/Notifications/Notifications.scss b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss
new file mode 100644
index 0000000..5d42d2a
--- /dev/null
+++ b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Reference: http://www.greywyvern.com/?post=337
+ */
+
+@import "app/ibz-mixins";
+
+
+link-button {@include ibz-button(#3366ff,1rem)};
+
+// Modal should be relative and tip-modal-popup absolute
+tip-modal {
+ position:relative;
+}
+
+.tip-modal-popup {
+ //visibility: hidden;
+ width: 20rem;
+ position:absolute;
+ top:1em;
+ padding: 0.2em 0.6em;
+ border:1px solid #996633;
+ background-color:#e5ffff;
+ color:#000;
+ opacity:0;
+ transition:visibility .5s linear 1s,opacity 1s linear;
+ border-radius: 5px;
+ i {
+ margin: 0 .3rem 0 0;
+ display: inline;
+ }
+}
diff --git a/afb-client/app/etc/AppDefaults.js b/afb-client/app/etc/AppDefaults.js
new file mode 100644
index 0000000..7b5326a
--- /dev/null
+++ b/afb-client/app/etc/AppDefaults.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var SESSION_TIMEOUT= 3600000; // default is 1h loggin session
+
+// Default config will be superseaded by ProjectRoot/.config-l4a.js $HOME/.config-l4a.js /etc/default/config-l4a.js
+config = {
+
+ APPNAME : 'AFBclient', // AppName is use as main Angular Module name
+ FRONTEND: "Frontend", // HTML5 frontend [no leading ./]
+ BACKEND : "Backend", // NodeJS Rest API [no leading ./]
+ URLBASE : '/opa/', // HTML basedir when running in production [should end with a /]
+ APIBASE : '/api/', // Api url base dir [should end with a /]
+ DEBUG : 4001, // Node Debug Port
+ DBG_LVL : 5, // Debug Trace Level 0=no trace.
+
+ // EXPRESS WEB server config [note: URLBASE generate rewriting rules]
+ EXPRESS_HOST : 'localhost', // HTTP will only listen on related Internet interface
+ EXPRESS_PORT : 4000, // HTTP port
+ EXPRESS_LOGDIR : __dirname + '/../../log', // httpd log file
+ EXPRESS_SECRET : Math.random().toString(36).slice(2), // [default cookie session]
+ EXPRESS_SESSION : SESSION_TIMEOUT
+};
+
+module.exports = config;
+
diff --git a/afb-client/app/etc/_Config.js b/afb-client/app/etc/_Config.js
new file mode 100644
index 0000000..ce93d43
--- /dev/null
+++ b/afb-client/app/etc/_Config.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Fulup Ar Foll
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var fs = require('fs');
+
+function Config () {
+ 'use strict';
+ var values=[];
+ var extention='-l4a.js';
+ var conf;
+
+ // Configs file path last one supersead first one.
+ var files= [__dirname + "/AppDefaults.js", "/etc/default/noderc"+ extention, process.env.NODERC, process.env.HOME + "/.noderc"+ extention , __dirname +"/../../.noderc.js" ];
+
+ // Parse any existing files within config list & merge them
+ for (var idx in files) {
+ if (files[idx]) {
+ //console.log ("files=", files[idx]);
+ if (fs.existsSync (files[idx])) conf=require (files[idx]);
+ for (var i in conf) values[i] = conf[i];
+ }
+ }
+
+ // set path to search for node_module within parent directory
+ process.env.NODE_PATH= process.env.NODE_PATH + '../node_modules';
+
+ // console.log ("values=", values);
+ return values;
+}
+
+module.exports = Config();
diff --git a/afb-client/app/etc/_Trace.js b/afb-client/app/etc/_Trace.js
new file mode 100644
index 0000000..79ef4f5
--- /dev/null
+++ b/afb-client/app/etc/_Trace.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Fulup Ar Foll
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var util = require("util");
+var path = require("path");
+var config= require('./_Config');
+
+function TracePoint () {
+ var saved = Error.prepareStackTrace; // save default prepareStack function
+ Error.prepareStackTrace = function(_, stack){ return stack; }; // overload err stack handling
+ Error.captureStackTrace(this, arguments.callee); // request a stack
+ this.trace = this.stack; // effectively build trace
+ Error.prepareStackTrace = saved; // restore original nodejs function
+}
+
+// ------- Public Methods --------------
+var dbgLevel = function(target, level, format) { //+ arguments
+ // try to get debugLevel from calling object or global config
+ if (target && target.dbgLevel) dbgLevel = target.dbgLevel;
+ else dbgLevel = config.DBG_LVL || 1;
+
+ if (dbgLevel >= level ) {
+
+ var args = [].slice.call(arguments, 2); // copy argument in a real array leaving out level
+ var message = util.format.apply(null, args);
+
+ var trace = new TracePoint().trace;
+ var info = {
+ fullpath : trace[1].getFileName(),
+ linenum : trace[1].getLineNumber(),
+ basename : path.basename (trace[1].getFileName())
+ };
+
+ if (dbgLevel >= 5) {
+ console.log("%s:%d", info.fullpath, info.linenum);
+ console.log("\t[%d] %j", dbgLevel, message);
+ }
+ else console.log("--%d-- [%s:%d] -- %j", dbgLevel, info.basename, info.linenum, message);
+ }
+};
+
+module.exports = dbgLevel;