From 475508baa9f0b21087eb85048d51af342aa09692 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 16 Dec 2015 17:15:43 +0100 Subject: Add the app!!! --- .../widgets/Buttons/SubmitButtons/SubmitButtons.js | 52 ++++++ .../Buttons/SubmitButtons/SubmitButtons.scss | 22 +++ .../app/Frontend/widgets/FormInput/FormInput.scss | 69 ++++++++ .../Frontend/widgets/FormInput/InputPassword.js | 79 +++++++++ .../app/Frontend/widgets/FormInput/InputText.js | 179 +++++++++++++++++++++ .../app/Frontend/widgets/FormInput/UploadFile.js | 113 +++++++++++++ .../app/Frontend/widgets/Navigation/LinkButton.js | 57 +++++++ .../Frontend/widgets/Navigation/Navigation.scss | 26 +++ .../widgets/Notifications/ModalNotification.js | 85 ++++++++++ .../widgets/Notifications/Notifications.scss | 47 ++++++ 10 files changed, 729 insertions(+) create mode 100644 afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js create mode 100644 afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss create mode 100644 afb-client/app/Frontend/widgets/FormInput/FormInput.scss create mode 100644 afb-client/app/Frontend/widgets/FormInput/InputPassword.js create mode 100644 afb-client/app/Frontend/widgets/FormInput/InputText.js create mode 100644 afb-client/app/Frontend/widgets/FormInput/UploadFile.js create mode 100644 afb-client/app/Frontend/widgets/Navigation/LinkButton.js create mode 100644 afb-client/app/Frontend/widgets/Navigation/Navigation.scss create mode 100644 afb-client/app/Frontend/widgets/Notifications/ModalNotification.js create mode 100644 afb-client/app/Frontend/widgets/Notifications/Notifications.scss (limited to 'afb-client/app/Frontend/widgets') 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 . + * + * Bugs: Input with Callback SHOULD BE get 'required' class + */ + +(function () { + 'use strict'; + + var tmpl = '
' + + '' + + '{{label}}' + + '
'; + + 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 . + */ + +@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 = '' + + '' + + ' '+ + ''; + +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 = '' + + ''+ + '{{errmsg}}'; + +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 = '
'+ + ''+ + ' ' + + '
' + + '' ; + +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 . + * + * Bugs: Input with Callback SHOULD BE get 'required' class + */ + +(function () { + 'use strict'; + + var tmpl = '' + + '' + + '{{label}}' + + ''; + + + 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 . + */ + +@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 . + * + * 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 + *
+ * + * + *
+ * + * Note: use CSS.visibility to avoid display flickering at initial display. + */ + +(function () { + 'use strict'; + + var tmpl = '
' + + '' + + '{{tip}}' + + '
' ; + + 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 . + * + * 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; + } +} -- cgit From fbdd26b4a4aa8eb3d83333fe44e93590bc174e11 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 16 Dec 2015 19:17:46 +0100 Subject: Work in Progress --- .../widgets/Notifications/Notifications.scss | 8 ++ .../widgets/Notifications/TokenRefreshSvc.js | 104 +++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/Notifications.scss b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss index 5d42d2a..5a4adc1 100644 --- a/afb-client/app/Frontend/widgets/Notifications/Notifications.scss +++ b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss @@ -45,3 +45,11 @@ tip-modal { display: inline; } } + +token-refresh.online { + color: blue; +} + +token-refresh.offline { + color: red; +} diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js new file mode 100644 index 0000000..1671748 --- /dev/null +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -0,0 +1,104 @@ +/* + alsa-gateway -- provide a REST/HTTP interface to ALSA-Mixer + + Copyright (C) 2015, 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 2 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 scope program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + References: + + */ + +(function () { + 'use strict'; + + var template = + '
' + + 'afb://{{hostname}}:{{httpdport}}' + + '' + + '
' + ; + + +// scope module is load statically before any route is cativated +angular.module('TokenRefresh', []) + + .directive ('tokenRefresh', function($timeout, $http, $location, Notification, ConfigApp) { + + function mymethods(scope, elem, attrs) { + + scope.status; + + scope.online = function () { + elem.addClass ("online"); + elem.removeClass ("offline"); + }; + + scope.offline = function(){ + elem.addClass ("offline"); + elem.removeClass ("online"); + }; + + // Check Binder status + scope.getping = function() { + + var handler = $http.get(ConfigApp.api.ping+'xx?token='+ ConfigApp.session.token); + handler.success(function(response, errcode, headers, config) { + if (!scope.status) { + Notification.success ({message: "AFB Back to Live", delay: 3000}); + scope.online(); + } + scope.status = 1; + }); + + handler.error(function(response, errcode, headers) { + if (scope.status) { + Notification.warning ({message: "AFB Lost", delay: 5000}); + scope.offline(); + } + scope.status = 0; + }); + + // restart a new timer for next ping + $timeout (scope.getping, ConfigApp.session.pingrate*1000); + }; + + // Check Binder status + scope.refresh = function() { + var handler = $http.get(ConfigApp.api.refresh+'?token='+ ConfigApp.session.token); + $timeout (scope.refresh, ConfigApp.session.timeout *800); + }; + + scope.icon = attrs.icon || "fi-lightbulb"; + scope.hostname = $location.host(); + scope.httpdport = $location.port(); + + scope.getping(); + scope.refresh(); + } + + return { + template: template, + scope: { + callback : "=" + }, + restrict: 'E', + link: mymethods + }; +}); + +})(); +console.log ("Token Refresh Loaded"); + -- cgit From 98522d2a6ce7c7a709728872ed892970d0a1df7b Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Wed, 16 Dec 2015 21:38:04 +0100 Subject: Added AFB monitoring and token auto-refresh --- .../widgets/Notifications/Notifications.scss | 12 ++++++++++-- .../widgets/Notifications/TokenRefreshSvc.js | 21 ++++++++++----------- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/Notifications.scss b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss index 5a4adc1..fb740b7 100644 --- a/afb-client/app/Frontend/widgets/Notifications/Notifications.scss +++ b/afb-client/app/Frontend/widgets/Notifications/Notifications.scss @@ -46,10 +46,18 @@ tip-modal { } } +token-refresh { + @include ibz-button(grey,1rem) + i {margin-left: .5rem;} + margin-right: 1rem; +} + token-refresh.online { - color: blue; + color: #0066cc; + i {color: lime;} } token-refresh.offline { - color: red; + color: #ff00ff; + i {color: red;} } diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 1671748..2b1e9db 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -25,11 +25,10 @@ 'use strict'; var template = - '
' - + 'afb://{{hostname}}:{{httpdport}}' - + '' - + '
' - ; + '
' + + 'afb://{{hostname}}:{{httpdport}}' + + '' + + '
'; // scope module is load statically before any route is cativated @@ -39,7 +38,7 @@ angular.module('TokenRefresh', []) function mymethods(scope, elem, attrs) { - scope.status; + scope.status=false; scope.online = function () { elem.addClass ("online"); @@ -54,10 +53,10 @@ angular.module('TokenRefresh', []) // Check Binder status scope.getping = function() { - var handler = $http.get(ConfigApp.api.ping+'xx?token='+ ConfigApp.session.token); + var handler = $http.post(ConfigApp.session.ping+'?token='+ ConfigApp.session.token); handler.success(function(response, errcode, headers, config) { if (!scope.status) { - Notification.success ({message: "AFB Back to Live", delay: 3000}); + Notification.success ({message: "AppFramework Binder Back to Live", delay: 3000}); scope.online(); } scope.status = 1; @@ -65,7 +64,7 @@ angular.module('TokenRefresh', []) handler.error(function(response, errcode, headers) { if (scope.status) { - Notification.warning ({message: "AFB Lost", delay: 5000}); + Notification.warning ({message: "AppFramework Binder Lost", delay: 5000}); scope.offline(); } scope.status = 0; @@ -77,8 +76,8 @@ angular.module('TokenRefresh', []) // Check Binder status scope.refresh = function() { - var handler = $http.get(ConfigApp.api.refresh+'?token='+ ConfigApp.session.token); - $timeout (scope.refresh, ConfigApp.session.timeout *800); + var handler = $http.post(ConfigApp.session.refresh+'?token='+ ConfigApp.session.token); + $timeout (scope.refresh, ConfigApp.session.timeout *250); }; scope.icon = attrs.icon || "fi-lightbulb"; -- cgit From 4136c1506e0c894e604ec069339313987a7e05e7 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sun, 20 Dec 2015 21:04:34 +0100 Subject: Implemented client upload with rangeslider and zip open --- .../app/Frontend/widgets/FormInput/FormInput.scss | 26 +- .../app/Frontend/widgets/FormInput/UploadFile.js | 113 ---- .../app/Frontend/widgets/FormInput/UploadFiles.js | 309 ++++++++++ .../Frontend/widgets/FormInput/newjavascript.js | 55 ++ .../widgets/Notifications/TokenRefreshSvc.js | 2 +- .../widgets/RangeSliders/RangeSliderMod.js | 631 +++++++++++++++++++++ .../Frontend/widgets/RangeSliders/Rangeslider.scss | 67 +++ 7 files changed, 1087 insertions(+), 116 deletions(-) delete mode 100644 afb-client/app/Frontend/widgets/FormInput/UploadFile.js create mode 100644 afb-client/app/Frontend/widgets/FormInput/UploadFiles.js create mode 100644 afb-client/app/Frontend/widgets/FormInput/newjavascript.js create mode 100644 afb-client/app/Frontend/widgets/RangeSliders/RangeSliderMod.js create mode 100644 afb-client/app/Frontend/widgets/RangeSliders/Rangeslider.scss (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/FormInput.scss b/afb-client/app/Frontend/widgets/FormInput/FormInput.scss index 37519fd..77aed6e 100644 --- a/afb-client/app/Frontend/widgets/FormInput/FormInput.scss +++ b/afb-client/app/Frontend/widgets/FormInput/FormInput.scss @@ -7,11 +7,33 @@ @import "app/ibz-mixins"; -upload-file { - height: 5rem; +.upload-file { display: inline-block; float: right; + height : 5rem; + width : 5rem; + margin: 0.5rem; + img { height: inherit;} + + .ibz-range-slider { + height: 10% !important; + border-radius: 5px; + background-color: lightgrey !important; + + .range-slider-handle { + width: 10% !important; + height: 100% !important; + margin-top: .2rem; + background-color: purple !important; + } + + .range-slider-active-segment { + height: 80% !important; + background-color: lightgreen; + } + } + } input-text { diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFile.js b/afb-client/app/Frontend/widgets/FormInput/UploadFile.js deleted file mode 100644 index 9a2f031..0000000 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFile.js +++ /dev/null @@ -1,113 +0,0 @@ - -/* - * 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 = '
'+ - ''+ - ' ' + - '
' + - '' ; - -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/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js new file mode 100644 index 0000000..6c68960 --- /dev/null +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -0,0 +1,309 @@ + +/* + * 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/docs/Web/API/FileReader + * 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 + * https://stuk.github.io/jszip/documentation/howto/read_zip.html + * http://onehungrymind.com/zip-parsing-jszip-angular/ + */ + + +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 = ''+ + '
' + + '' + + '' + + '
'; + + +function Basename(path) { + return path.split('/').reverse()[0]; +} + +// Service Create xform insert files in and Post it to url +function LoadFileSvc (scope, elem, posturl, files, thumbnailCB) { + var xmlReq = new XMLHttpRequest(); + var xform = new FormData(); + + // Update slider during Upload + xmlReq.upload.onprogress = function (event) { + var progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0); + if (scope.slider) scope.slider.setValue (progress); + }; + + // Upload is finish let's notify controler callback + xmlReq.onload = function () { + elem.addClass ("success"); + var response ={ + status : xmlReq.status, + headers: xmlReq.getAllResponseHeaders() + }; + scope.callback (response); + }; + + xmlReq.onerror = function () { + elem.addClass ("error fail"); + var response ={ + status : xmlReq.status, + headers: xmlReq.getAllResponseHeaders() + }; + scope.callback (response); + }; + + xmlReq.onabort = function () { + elem.addClass ("error abort"); + var response ={ + status : xmlReq.status, + headers: xmlReq.getAllResponseHeaders() + }; + scope.callback (response); + }; + + for (var i = 0; i < files.length; i++) { + var file = files[i]; + if (!file.type.match(scope.mimetype)) { + continue; + } + + console.log ("Selected file=" + file.name + " size="+ file.size/1024 + " Type="+ file.type); + + // File to upload is too big + if (file.size > scope.maxsize*1024) { + scope.thumbnail = scope.istoobig; // warning if image path is wrong nothing happen + scope.$apply('thumbnail'); // we short-circuit Angular resync Image + return; + } + + // This is not an uploadable file + if(isNaN(file.size)) { + scope.thumbnail = scope.isnotvalid; + scope.$apply('thumbnail'); + return; + } + + scope.Basename=Basename(file.name); + scope.imgElem[0].file = file; + + // If File is an image let display it now + if (thumbnailCB) { + var reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = thumbnailCB; + } + + // if everything is OK let's add file to xform + xform.append(scope.name, file, file.name); + } + + + // everything looks OK let's Post it + xmlReq.open("POST", posturl , true); + xmlReq.send(xform); +}; + +angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) + +.directive('uploadImage', function(ConfigApp, JQemu, Notification) { + function mymethods(scope, elem, attrs) { + + // get widget image handle from template + scope.imgElem = elem.find('img'); + scope.inputElem = elem.find('input'); + + // Image was ckick let's simulate an input (file) click + scope.imgClicked = function () { + scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!! + }; + + // Slider control handle registration after creation + scope.SliderInitCB=function (slider) { + scope.slider= slider; + }; + + // Upload is delegated to a shared function + scope.UpLoadFile=function (files) { + var readerCB = function (upload) { + // scope.thumbnail = upload.target.result; + scope.imgElem[0].src = window.URL.createObjectURL(new Blob([upload.target.result], {type: "image"})); + scope.$apply('thumbnail'); // we short-circuit Angular resync image + }; + var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + LoadFileSvc (scope, elem, posturl, files, readerCB); + }; + + // Initiallize default values from attributes values + scope.name= attrs.name || 'avatar'; + scope.category= attrs.category || 'image'; + scope.mimetype= (attrs.accept || 'image') + '/*'; + scope.maxsize= attrs.maxsize || 100; // default max size 100KB + scope.regexp = new RegExp (attrs.accept+ '.*','i'); + + if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=ConfigApp.paths[scope.category] + 'tux-bzh.png'; + + if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + + if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; + else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + scope.noslider = attrs.noslider || false; + + if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); + } + return { + restrict: 'E', + template: tmpl, + link: mymethods, + scope: { + callback : '=' + } + }; +}) + +.directive('uploadAudio', function(ConfigApp, JQemu, Notification) { + function mymethods(scope, elem, attrs) { + + // get widget image handle from template + scope.imgElem = elem.find('img'); + scope.inputElem = elem.find('input'); + + // Image was ckick let's simulate an input (file) click + scope.imgClicked = function () { + scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!! + }; + + // Slider control handle registration after creation + scope.SliderInitCB=function (slider) { + scope.slider= slider; + }; + + // Upload is delegated to a shared function + scope.UpLoadFile=function (files) { + var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + LoadFileSvc (scope, elem, posturl, files, false); + }; + + // Initiallize default values from attributes values + scope.name= attrs.name || 'audio'; + scope.category= attrs.category || 'audio'; + scope.mimetype= (attrs.accept || 'audio') + '/*'; + scope.maxsize= attrs.maxsize || 10000; // default max size 10MB + scope.regexp = new RegExp (attrs.accept+ '.*','i'); + + if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=ConfigApp.paths[scope.category] + 'upload-music.png'; + + if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + + if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; + else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + scope.noslider = attrs.noslider || false; + + if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); + } + return { + restrict: 'E', + template: tmpl, + link: mymethods, + scope: { + callback : '=' + } + }; + +}) + +.directive('uploadAppli', function(ConfigApp, JQemu, Notification) { + function mymethods(scope, elem, attrs) { + + // get widget image handle from template + scope.imgElem = elem.find('img'); + scope.inputElem = elem.find('input'); + + // Image was ckick let's simulate an input (file) click + scope.imgClicked = function () { + scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!! + }; + + // Slider control handle registration after creation + scope.SliderInitCB=function (slider) { + scope.slider= slider; + }; + + // Upload is delegated to a shared function + scope.UpLoadFile=function (files) { + + var readerCB = function (upload) { + var zipapp = new JSZip(upload.target.result); + var thumbnail = zipapp.file("afa-pkg/thumbnail.jpg"); + + // Check is we have a thumbnail within loaded Zipfile + if (!thumbnail) { + console.log ("This is not a valid Application Framework APP"); + scope.thumbnail=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + scope.$apply('thumbnail'); // we short-circuit Angular resync image + return; + } + scope.imgElem[0].src = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"})); + scope.$apply('thumbnail'); // we short-circuit Angular resync image + }; + + var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + LoadFileSvc (scope, elem, posturl, files, readerCB); + }; + + // Initiallize default values from attributes values + scope.name= attrs.name || 'appli'; + scope.category= attrs.category || 'appli'; + scope.mimetype= (attrs.accept || '.zip'); + scope.maxsize= attrs.maxsize || 100000; // default max size 100MB + scope.regexp = new RegExp (attrs.accept+ '.*','i'); + + if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=ConfigApp.paths[scope.category] + 'upload-appli.png'; + + if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + + if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; + else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + scope.noslider = attrs.noslider || false; + + if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); + } + return { + restrict: 'E', + template: tmpl, + link: mymethods, + scope: { + callback : '=' + } + }; + +}); + +console.log ("UploadFile Loaded"); +})(); diff --git a/afb-client/app/Frontend/widgets/FormInput/newjavascript.js b/afb-client/app/Frontend/widgets/FormInput/newjavascript.js new file mode 100644 index 0000000..10280c7 --- /dev/null +++ b/afb-client/app/Frontend/widgets/FormInput/newjavascript.js @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 fulup + * + * 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 . + */ + + var reader = new FileReader(); + // Closure to capture the file information. + reader.onload = (function(theFile) { + return function(e) { + var $title = $("

", { + text : theFile.name + }); + $result.append($title); + var $fileContent = $("
    "); + try { + + var dateBefore = new Date(); + // read the content of the file with JSZip + var zip = new JSZip(e.target.result); + var dateAfter = new Date(); + + $title.append($("", { + text:" (parsed in " + (dateAfter - dateBefore) + "ms)" + })); + + // that, or a good ol' for(var entryName in zip.files) + $.each(zip.files, function (index, zipEntry) { + $fileContent.append($("
  • ", { + text : zipEntry.name + })); + // the content is here : zipEntry.asText() + }); + // end of the magic ! + + } catch(e) { + $fileContent = $("
    ", { + "class" : "alert alert-danger", + text : "Error reading " + theFile.name + " : " + e.message + }); + } + $result.append($fileContent); + } + })(f); \ No newline at end of file diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 2b1e9db..0d1cf38 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -32,7 +32,7 @@ // scope module is load statically before any route is cativated -angular.module('TokenRefresh', []) +angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) .directive ('tokenRefresh', function($timeout, $http, $location, Notification, ConfigApp) { diff --git a/afb-client/app/Frontend/widgets/RangeSliders/RangeSliderMod.js b/afb-client/app/Frontend/widgets/RangeSliders/RangeSliderMod.js new file mode 100644 index 0000000..77f0fce --- /dev/null +++ b/afb-client/app/Frontend/widgets/RangeSliders/RangeSliderMod.js @@ -0,0 +1,631 @@ +/* + * 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 . + * + * Bugs: Input with Callback SHOULD BE get 'required' class + * + * ref: https://developer.mozilla.org/en-US/docs/Web/Events/mouseover + * + * usage: +Usage +--------------------- + + class="radius" // check Zurb foundation doc for further info. + class="ibz-handle-display" // increase handle width to hold slider current value + + + callback="myCallBack" // $scope.myCallBack(sliderhandle) is called when ever slider handle blur + formatter="SliderFormatCB" // $scope.myFormatter(value, sliderid) when exist is call when ever slider handle moves. Should return external form of slider value. + ng-model="xxxxxx" // xxx Must be defined, script will store a new RangerObject within provided ng-model variable. + start-at="ScopeVar" // Dynamic limitation when slider is constrains by an external componant [ex: check in/out] + stop-at="ScopeVar" // Idem but for end. + + + not-less="integer" // Fixed starting value for slider [default 0] + not-more="integer" // Fixed end value for sliders [default 100] + by-step="+-integer" // If by-step is >0 then slider use it as step-value, when negative use it for decimal precision + display-target="handle" // display slider external formated value in the handle [requirer calss="ibz-handle-display"] + dual-handles='true' // add a second handle to slider for min/max range + initial='value|[start/stop]' // slider initial value [dual-handles] may have initial values + /> + */ + +(function () { + 'use strict'; + +var RangeSlider = angular.module('RangeSlider',[]); + +function RangeSliderHandle (scope) { + var internals = []; + var externals = []; + + this.getId = function() { + return scope.sliderid; + }; + + this.getCbHandle = function() { + return scope.cbhandle; + }; + + this.getView= function (handle) { + if (!handle) handle = 0; + + // if value did not change return current external representation + if (scope.value[handle] === internals[handle]) return externals[handle]; + + // build external representation and save it for further requests + internals[handle] = scope.value[handle]; + if (scope.formatter) externals[handle] = scope.formatter(scope.value[handle], scope.ctrlhandle); + else externals[handle] = scope.value[handle]; + + return externals[handle]; + }; + + this.updateClass = function (classe, status) { + scope.updateClass (classe, status); + }; + + this.forceRefresh = function (timer) { + scope.forceRefresh(timer); + }; + + this.getValue= function (handle) { + if (!handle) handle = 0; + return scope.value[handle]; + }; + + this.getRelative= function (handle) { + if (!handle) handle = 0; + return scope.relative[handle]; + }; + + this.setValue= function (value, handle) { + if (!handle) handle = 0; + scope.setValue (value, handle); + }; + + this.setDisable= function (flag) { + scope.setDisable(flag); + }; +} + +RangeSlider.directive('rangeSlider', function ($log, $document, $timeout) { + + var template= '
    '+ + ''+ + ''+ + ''+ + ' '+ + ' '+ + ''+ + '
    '; + + + function link (scope, element, attrs, model) { + // full initialisation of slider from a single object + scope.initWidget = function (initvalues) { + + if (initvalues.byStep) scope.byStep = parseInt(initvalues.byStep); + if (initvalues.notMore) scope.notMore = parseInt(initvalues.notMore); + if (initvalues.notLess) scope.notLess = parseInt(initvalues.notLess); + if (initvalues.id) scope.sliderid= initvalues.id; + + // hugely but in some case DOM is not finish when we try to set values !!! + if (initvalues.value !== undefined) { + scope.value = initvalues.value; + scope.forceRefresh (50); // wait 50ms for DOM to be ready + } + }; + + // this function recompute slide positioning + scope.forceRefresh = function (timer) { + var value = scope.value; + scope.value = [undefined,undefined]; + $timeout (function() { + scope.setValue(value[0],0); + if (scope.dual) scope.setValue(value[1],1); + }, timer); + }; + + // handler to change class from slider handle + scope.updateClass = function (classe, status) { + + if (status) element.addClass (classe); + else element.removeClass (classe); + }; + + scope.setDisable = function (disabled) { + + if (disabled) { + element.addClass ("disable"); + scope.handles[0].css ('visibility','hidden'); + if (scope.dual) { + scope.handles[1].css ('visibility','hidden'); + } + } else { + element.removeClass ("disable"); + scope.handles[0].css ('visibility','visible'); + if (scope.dual) scope.handles[1].css ('visibility','visible'); + } + + }; + + scope.normalize = function (value) { + var result; + var range = scope.notMore - scope.notLess; + var point = value * range; + + // if step is positive let's round step by step + if (scope.byStep > 0) { + var mod = (point - (point % scope.byStep)) / scope.byStep; + var rem = point % scope.byStep; + + var round = (rem >= scope.byStep * 0.5 ? scope.byStep : 0); + result= (mod * scope.byStep + round) + scope.notLess; + //console.log ("range=%d value=%d point=%d mod=%d rem=%d round=%d result=%d", range, value, point, mod, rem, round, result) + return result; + } + + // if step is negative return round to asked decimal + if (scope.byStep < 0) { + var power = Math.pow (10,(scope.byStep * -1)); + result = scope.notLess + parseInt (point * power) / power; + return (result); + } + + // if step is null return full value + return point; + }; + + // return current value + scope.getValue = function (offset, handle) { + if (scope.vertical) { + scope.relative[handle] = (offset - scope.bounds.handles[handle].getBoundingClientRect().height) / (scope.bounds.bar.getBoundingClientRect().height - scope.bounds.handles[handle].getBoundingClientRect().height); + } else { + scope.relative[handle] = offset / (scope.bounds.bar.getBoundingClientRect().width - scope.bounds.handles[handle].getBoundingClientRect().width); + } + + var newvalue = scope.normalize (scope.relative[handle]); + + + // if internal value change update or model + if (newvalue !== scope.value[handle]) { + if (newvalue < scope.startValue) newvalue=scope.startValue; + if (newvalue > scope.stopValue) newvalue=scope.stopValue; + + + if (scope.formatter) { + scope.viewValue = scope.formatter (newvalue, scope.ctrlhandle); + } else { + scope.viewValue = newvalue; + } + if (scope.displays[handle]) { + scope.displays[handle].html (scope.viewValue); + } + + // update external representation of the model + scope.value[handle] = newvalue; + if (model) model.$setViewValue (scope.viewValue); + scope.$apply(); + if (newvalue > scope.startValue && newvalue < scope.stopValue) scope.translate(offset, handle); + } + }; + + + scope.setStart = function (value) { + var offset; + + if (value > scope.value[0]) { + if (!scope.dual) scope.setValue (value,0); + else scope.setValue (value,1); + } + + if (scope.vertical) { + offset = scope.bounds.bar.getBoundingClientRect().height * (value - scope.notLess) / (scope.notMore - scope.notLess); + scope.start.css('height',offset + 'px'); + } else { + offset = scope.bounds.bar.getBoundingClientRect().width * (value - scope.notLess) / (scope.notMore - scope.notLess); + scope.start.css('width',offset + 'px'); + } + + scope.startValue= value; + }; + + scope.setStop = function (value) { + var offset; + + if (value < scope.value[0]) { + if (!scope.dual) scope.setValue (value,0); + else scope.setValue (value,1); + } + + if (scope.vertical) { + offset = scope.bounds.bar.getBoundingClientRect().height * (value - scope.notLess) / (scope.notMore - scope.notLess); + scope.start.css('height',offset + 'px'); + } else { + offset = scope.bounds.bar.getBoundingClientRect().width * (value - scope.notLess) / (scope.notMore - scope.notLess); + scope.stop.css({'right': 0, 'width': (scope.bounds.bar.getBoundingClientRect().width - offset) + 'px'}); + } + + scope.stopValue= value; + }; + + scope.translate = function (offset, handle) { + var start; + + if (scope.vertical) { + // take handle size in account to compute middle + var voffset = scope.bounds.bar.getBoundingClientRect().height - offset; + + scope.handles[handle].css({ + '-webkit-transform': 'translateY(' + voffset + 'px)', + '-moz-transform': 'translateY(' + voffset + 'px)', + '-ms-transform': 'translateY(' + voffset + 'px)', + '-o-transform': 'translateY(' + voffset + 'px)', + 'transform': 'translateY(' + voffset + 'px)' + }); + if (!scope.dual) scope.slider.css('height', offset + 'px'); + else if (scope.relative[1] && scope.relative[0]) { + var height = (scope.relative[1] - scope.relative[0]) * scope.bounds.bar.getBoundingClientRect().height; + start = (scope.relative[0] * scope.bounds.bar.getBoundingClientRect().height); + scope.slider.css ({'bottom': start+'px','height': height + 'px'}); + } + } else { + + scope.handles[handle].css({ + '-webkit-transform': 'translateX(' + offset + 'px)', + '-moz-transform': 'translateX(' + offset + 'px)', + '-ms-transform': 'translateX(' + offset + 'px)', + '-o-transform': 'translateX(' + offset + 'px)', + 'transform': 'translateX(' + offset + 'px)' + }); + if (!scope.dual) scope.slider.css('width',offset + 'px'); + else if (scope.relative[1] && scope.relative[0]) { + var width = (scope.relative[1] - scope.relative[0]) * scope.bounds.bar.getBoundingClientRect().width; + start = (scope.relative[0] * scope.bounds.bar.getBoundingClientRect().width); + scope.slider.css ({'left': start+'px','width': width + 'px'}); + } + } + }; + + // position handle on the bar depending a given value + scope.setValue = function (value , handle) { + var offset; + + // if value did not change ignore + if (value === scope.value[handle]) return; + if (value === undefined) value=0; + if (value > scope.notMore) value=scope.notMore; + if (value < scope.notLess) value=scope.notLess; + + if (scope.vertical) { + scope.relative[handle] = (value - scope.notLess) / (scope.notMore - scope.notLess); + if (handle === 0) offset = (scope.relative[handle] * scope.bounds.bar.getBoundingClientRect().height) + scope.bounds.handles[handle].getBoundingClientRect().height/2; + if (handle === 1) offset = scope.relative[handle] * scope.bounds.bar.getBoundingClientRect().height; + + } else { + scope.relative[handle] = (value - scope.notLess) / (scope.notMore - scope.notLess); + offset = scope.relative[handle] * (scope.bounds.bar.getBoundingClientRect().width - scope.bounds.handles[handle].getBoundingClientRect().width); + } + + scope.translate (offset,handle); + scope.value[handle] = value; + + if (scope.formatter) { + // when call through setValue we do not pass cbHandle + scope.viewValue = scope.formatter (value, undefined); + } else { + scope.viewValue = value; + } + + if (model) model.$setViewValue( scope.viewValue); + + if (scope.displays[handle]) { + scope.displays[handle].html (scope.viewValue); + } + }; + + + // Minimal keystroke handling to close picker with ESC [scope.actif is current handle index] + scope.keydown= function(e){ + + switch(e.keyCode){ + case 39: // Right + case 38: // up + if (scope.byStep > 0) scope.$apply(scope.setValue ((scope.value[scope.actif]+scope.byStep), scope.actif)); + if (scope.byStep < 0) scope.$apply(scope.setValue ((scope.value[scope.actif]+(1 / Math.pow(10, scope.byStep*-1))),scope.actif)); + if (scope.callback) scope.callback (scope.value[scope.actif], scope.ctrlhandle); + break; + case 37: // left + case 40: // down + if (scope.byStep > 0) scope.$apply(scope.setValue ((scope.value[scope.actif] - scope.byStep), scope.actif)); + if (scope.byStep < 0) scope.$apply(scope.setValue ((scope.value[scope.actif] - (1 / Math.pow(10, scope.byStep*-1))),scope.actif)); + if (scope.callback) scope.callback (scope.value[scope.actif], scope.ctrlhandle); + break; + case 27: // esc + scope.handles[scope.actif][0].blur(); + } + }; + + scope.moveHandle = function (handle, clientX, clientY) { + var offset; + if (scope.vertical) { + offset = scope.bounds.bar.getBoundingClientRect().bottom - clientY; + if (offset > scope.bounds.bar.getBoundingClientRect().height) offset = scope.bounds.bar.getBoundingClientRect().height; + if (offset < scope.bounds.handles[handle].getBoundingClientRect().height) offset = scope.bounds.handles[handle].getBoundingClientRect().height; + } else { + offset = clientX - scope.bounds.bar.getBoundingClientRect().left; + + if (offset < 0) offset = 0; + if ((clientX + scope.bounds.handles[handle].getBoundingClientRect().width) > scope.bounds.bar.getBoundingClientRect().right) { + offset = scope.bounds.bar.getBoundingClientRect().width - scope.bounds.handles[handle].getBoundingClientRect().width; + } + } + + scope.getValue (offset, handle); + + // prevent dual handle to cross + if (scope.dual && scope.value [0] > scope.value[1]) { + if (handle === 0) scope.setValue (scope.value[0] , 1); + else scope.setValue(scope.value[1],0); + } + }; + + + scope.focusCB = function (inside) { + if (inside) { + $document.on('keydown',scope.keydown); + } else { + $document.unbind('keydown',scope.keydown); + } + }; + + // bar was touch let move handle to this point + scope.touchBarCB = function (event) { + var handle=0; + var relative; + var touches = event.changedTouches; + var oldvalue = scope.value[handle]; + + event.preventDefault(); + + // if we have two handles select closest one from touch point + if (scope.dual) { + if (scope.vertical) relative = (touches[0].pageY - scope.bounds.bar.getBoundingClientRect().bottom) / scope.bounds.bar.getBoundingClientRect().height; + else relative= (touches[0].pageX - scope.bounds.bar.getBoundingClientRect().left) / scope.bounds.bar.getBoundingClientRect().width; + + var distance0 = Math.abs(relative - scope.relative[0]); + var distance1 = Math.abs(relative - scope.relative[1]); + if (distance1 < distance0) handle=1; + } + + // move handle to new place + scope.moveHandle (handle,touches[0].pageX, touches[0].pageY); + if (scope.callback && oldvalue !== scope.value[handle]) scope.callback (scope.value[handle], scope.ctrlhandle); + }; + + // handle was touch and drag + scope.touchHandleCB = function (touchevt, handle) { + var oldvalue = scope.value[handle]; + + touchevt.preventDefault(); + $document.on('touchmove',touchmove); + $document.on('touchend' ,touchend); + element.unbind('touchstart', scope.touchBarCB); + + function touchmove(event) { + event.preventDefault(); + var touches = event.changedTouches; + for (var idx = 0; idx < touches.length; idx++) { + scope.moveHandle (handle,touches[idx].pageX, touches[idx].pageY); + } + } + + function touchend(event) { + $document.unbind('touchmove',touchmove); + $document.unbind('touchend' ,touchend); + element.on('touchstart', scope.touchBarCB); + + // if value change notify application callback + if (scope.callback && oldvalue !== scope.value[handle]) scope.callback (scope.value[handle], scope.ctrlhandle); + } + }; + + scope.handleCB = function (clickevent, handle) { + + if (attrs.automatic) return; + + var oldvalue = scope.value[handle]; + // register mouse event to track handle + clickevent.preventDefault(); + + $document.on('mousemove',mousemove); + $document.on('mouseup', mouseup); + scope.handles[handle][0].focus(); + scope.actif=handle; + + // slider handle is moving + function mousemove(event) { + scope.moveHandle (handle, event.clientX, event.clientY); + } + + // mouse is up dans leave slider send resize events + function mouseup() { + $document.unbind('mousemove', mousemove); + $document.unbind('mouseup', mouseup); + + // if value change notify application callback + if (scope.callback && oldvalue !== scope.value[handle]) scope.callback (scope.value[handle], scope.ctrlhandle); + } + }; + + // simulate jquery find by classes capabilities [warning only return 1st elements] + scope.find = function (select, elem) { + var domelem; + + if (elem) domelem = elem[0].querySelector(select); + else domelem = element[0].querySelector(select); + + var angelem = angular.element(domelem); + return (angelem); + }; + + + + scope.initialSettings = function (initial) { + var decimal_places_match_result; + scope.value=[]; // store low/height value when two handles + scope.relative=[]; + + if (scope.precision === null) { + decimal_places_match_result = ('' + scope.byStep).match(/\.([\d]*)/); + scope.precision = decimal_places_match_result && decimal_places_match_result[1] ? decimal_places_match_result[1].length : 0; + } + + // position handle to initial value(s) + element.on('touchstart', scope.touchBarCB); + scope.handles[0].on('touchstart', function(evt){scope.touchHandleCB(evt,0);}); + + // this slider has two handles low/hight + if (scope.dual) { + scope.handles[1].addClass('range-slider-handle'); + scope.handles[1].on('touchstart', function(evt){scope.touchHandleCB(evt,1);}); + if (!scope.initvalues) scope.setValue (initial[1],1); + } + + // if we have an initstate object apply it + if (scope.initvalues) scope.initWidget (scope.initvalues); + else scope.setValue (initial[0],0); + }; + + scope.init = function () { + scope.sliderid = attrs.id || "slider-" + parseInt (Math.random() * 1000); + scope.startValue = -Infinity; + scope.stopValue = Infinity; + scope.byStep = parseInt(attrs.byStep) || 1; + scope.vertical = attrs.vertical || false; + scope.dual = attrs.dualHandles|| false; + scope.trigger_input_change= false; + scope.notMore = parseInt(attrs.notMore) || 100; + scope.notLess = parseInt(attrs.notLess) || 0; + + if (scope.vertical) element.addClass("vertical-range"); + + scope.handles= [scope.find('.handle-min'), scope.find('.handle-max')]; + scope.bar = element; + scope.slider = scope.find('.range-slider-active-segment'); + scope.start = scope.find('.ibz-range-slider-start'); + scope.stop = scope.find('.ibz-range-slider-stop'); + scope.disable= attrs.disable || false; + + scope.ctrlhandle = new RangeSliderHandle (scope); + + // prepare DOM object pointer to compute size dynamically + scope.bounds = { + bar : element[0], + handles: [scope.handles[0][0], scope.handles[1][0]] + }; + + if (attrs.disable === 'true') scope.setDisable(true); + + if (attrs.displayTarget) { + switch (attrs.displayTarget) { + case true : + case 'handle' : + scope.displays = scope.handles; + scope.handles[0].addClass('ibz-range-slider-display'); + if (scope.dual) scope.handles[1].addClass('ibz-range-slider-display'); + break; + default: + scope.displays = [$document.getElementById (attrs.displayTarget)]; + } + } else scope.displays=[]; + + // extract initial values from attrs and parse into int + if (!attrs.initial) { + scope.initial = [scope.ngModel, scope.ngModel]; // initialize to model values + } else { + var initial = attrs.initial.split(','); + scope.initial = [ + initial[0] !== undefined ? parseInt (initial[0]) : scope.notLess, + initial[1] !== undefined ? parseInt (initial[1]) : scope.notMore + ]; + } + + // Monitor any changes on start/stop dates. + scope.$watch('startAt', function() { + if (scope.value < scope.startAt ) { + //scope.setValue (scope.startAt); + } + if (scope.startAt) scope.setStart (scope.startAt); + }); + + scope.$watch('stopAt' , function() { + if (scope.value > scope.stopAt) { + //scope.setValue (scope.stopAt); + } + if (scope.stopAt) scope.setStop (scope.stopAt); + }); + + // finish widget initialisation + scope.initialSettings (scope.initial); + + }; + + scope.init(); + + // slider is ready provide control handle to application controller + scope.$watch ('inithook', function () { // init Values may arrive late + if (scope.inithook) scope.inithook (scope.ctrlhandle); + }); + + scope.$watch ('initvalues', function () { // init Values may arrive late + if (scope.initvalues) scope.initWidget(scope.initvalues); + }); + + // two-way binding if model value changes + scope.$watch ('ngModel', function (newValue) { + scope.setValue(newValue, 0); + }); + } + +return { + restrict: "E", // restrict to HTML element name + scope: { + startAt :'=', // First acceptable date + stopAt :'=', // Last acceptable date + callback :'=', // Callback to actif when a date is selected + formatter:'=', // Callback for drag event call each time internal value changes + inithook :'=', // Hook point to control slider from API + cbhandle :'=', // Argument added to every callback + initvalues:'=', // Initial values as a single object + ngModel: '=' // the model value + }, + require: '?ngModel', + template: template, // html template is build from JS + replace: true, // replace current directive with template while inheriting of class + link: link // pickadate object's methods +}; +}); + +console.log ("RangeSlider Loaded"); + +})(); \ No newline at end of file diff --git a/afb-client/app/Frontend/widgets/RangeSliders/Rangeslider.scss b/afb-client/app/Frontend/widgets/RangeSliders/Rangeslider.scss new file mode 100644 index 0000000..6717d0e --- /dev/null +++ b/afb-client/app/Frontend/widgets/RangeSliders/Rangeslider.scss @@ -0,0 +1,67 @@ +/* + * ibz-Datepicker for Foundation + * + * Author: Fulup Ar Foll + * Date : March-2015 + * Object: SASS stylesheet, customized to Foundation + * References: https://css-tricks.com/stripes-css/ + * + */ +@import "app/ibz-mixins"; + +.range-slider-handle { + display: inline-block; + position: absolute; + z-index: 1; + top: -0.2rem; + width: 2rem; + height: 1.375rem; + border: 1px solid none; + cursor: pointer; + background: #008cba; +} + +.range-slider.radius, .range-slider-handle { + background: #008cba; + -webkit-border-radius: 3px; + border-radius: 3px; +} + +.range-slider-active-segment { + display: inline-block; + top: 0.07rem; + position: absolute; + height: 0.80rem; + background: #e5e5e5; +} + +.ibz-range-slider { + background-color: rgba(154, 205, 50, 0.6) !important; + height: 1rem; + position: relative; + + .range-slider-active-segment { + background-color: rgba(82, 168, 200, 0.6); + } + + &-display { + background-color: rgba(82, 168, 200, 0.6) !important; + width : 4rem !important; + padding: .25rem; + text-align:center + } + + &-start,&-stop { + display: inline-block; + position: absolute; + padding-top: 2px; + height: 95%; + background: repeating-linear-gradient( + 45deg, + #606dbc, + #606dbc 10px, + #465298 10px, + #465298 20px + );} + +} -- cgit From 6700ae902ee16d9474098c5435e4cdf210962851 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sun, 20 Dec 2015 21:06:07 +0100 Subject: Implemented client upload with rangeslider and zip open --- afb-client/app/Frontend/widgets/FormInput/UploadFiles.js | 1 + 1 file changed, 1 insertion(+) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index 6c68960..65269f3 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -21,6 +21,7 @@ * https://github.com/nervgh/angular-file-upload/blob/master/src/services/FileUploader.js * https://stuk.github.io/jszip/documentation/howto/read_zip.html * http://onehungrymind.com/zip-parsing-jszip-angular/ + * http://stackoverflow.com/questions/15341912/how-to-go-from-blob-to-arraybuffer */ -- cgit From 3b1b2ddc4692776318a135a66c1da8c5dee13f64 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sun, 20 Dec 2015 21:59:32 +0100 Subject: Fixed valid/invalid status for app --- .../app/Frontend/widgets/FormInput/UploadFiles.js | 42 ++++++++--------- .../Frontend/widgets/FormInput/newjavascript.js | 55 ---------------------- 2 files changed, 19 insertions(+), 78 deletions(-) delete mode 100644 afb-client/app/Frontend/widgets/FormInput/newjavascript.js (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index 65269f3..88669a9 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -22,12 +22,11 @@ * https://stuk.github.io/jszip/documentation/howto/read_zip.html * http://onehungrymind.com/zip-parsing-jszip-angular/ * http://stackoverflow.com/questions/15341912/how-to-go-from-blob-to-arraybuffer + * + * Bugs: zip file sent even when flag as invalid */ - -function changeInput() { - console.log ('input imgClicked'); -} + (function() { 'use strict'; @@ -40,10 +39,6 @@ var tmpl = '", { - text : theFile.name - }); - $result.append($title); - var $fileContent = $("
      "); - try { - - var dateBefore = new Date(); - // read the content of the file with JSZip - var zip = new JSZip(e.target.result); - var dateAfter = new Date(); - - $title.append($("", { - text:" (parsed in " + (dateAfter - dateBefore) + "ms)" - })); - - // that, or a good ol' for(var entryName in zip.files) - $.each(zip.files, function (index, zipEntry) { - $fileContent.append($("
    • ", { - text : zipEntry.name - })); - // the content is here : zipEntry.asText() - }); - // end of the magic ! - - } catch(e) { - $fileContent = $("
      ", { - "class" : "alert alert-danger", - text : "Error reading " + theFile.name + " : " + e.message - }); - } - $result.append($fileContent); - } - })(f); \ No newline at end of file -- cgit From 20853066884b9d3cddfa29c9741d625ba625c5f3 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Mon, 21 Dec 2015 01:52:39 +0100 Subject: Few hack for Post --- afb-client/app/Frontend/widgets/FormInput/UploadFiles.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index 88669a9..8bc8eca 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -53,6 +53,7 @@ function LoadFileSvc (scope, elem, posturl, files, thumbnailCB) { // Upload is finish let's notify controler callback xmlReq.onload = function () { elem.addClass ("success"); + elem.removeClass ("error"); var response ={ status : xmlReq.status, headers: xmlReq.getAllResponseHeaders() @@ -61,7 +62,8 @@ function LoadFileSvc (scope, elem, posturl, files, thumbnailCB) { }; xmlReq.onerror = function () { - elem.addClass ("error fail"); + elem.addClass ("error"); + elem.removeClass ("success"); var response ={ status : xmlReq.status, headers: xmlReq.getAllResponseHeaders() @@ -70,7 +72,8 @@ function LoadFileSvc (scope, elem, posturl, files, thumbnailCB) { }; xmlReq.onabort = function () { - elem.addClass ("error abort"); + elem.addClass ("error"); + elem.removeClass ("success"); var response ={ status : xmlReq.status, headers: xmlReq.getAllResponseHeaders() -- cgit From 4c75745c475edfbb6a9258ee80944e655fdf89f6 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Mon, 21 Dec 2015 16:10:40 +0100 Subject: Fixed Warning --- afb-client/app/Frontend/widgets/FormInput/UploadFiles.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index 8bc8eca..8c0a4c2 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -43,8 +43,12 @@ var tmpl = ' Date: Tue, 29 Dec 2015 21:55:10 +0100 Subject: Switch TokenRefresh to HTTP GET We are doing HTTP POST calls with no data in TokenRefresh widget, which is time-consuming and can lead to crashes with libmicrohttpd > 0.9.30. Use HTTP GETs instead. Signed-off-by: Manuel Bachmann --- afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 834aaff..82e43a5 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -73,7 +73,7 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) // Check Binder status scope.getping = function() { - var handler = $http.post(ConfigApp.session.ping+'?token='+ ConfigApp.session.token); + var handler = $http.get(ConfigApp.session.ping+'?token='+ ConfigApp.session.token); // process success and error handler.success(scope.onsuccess); @@ -85,7 +85,7 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) // Check Binder status scope.refresh = function() { - var handler = $http.post(ConfigApp.session.refresh+'?token='+ ConfigApp.session.token); + var handler = $http.get(ConfigApp.session.refresh+'?token='+ ConfigApp.session.token); // process success and error handler.success(scope.onsuccess); @@ -96,7 +96,7 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) // Initial connection scope.tkcreate = function() { - var handler = $http.post(ConfigApp.session.create+'?token='+ ConfigApp.session.initial); + var handler = $http.get(ConfigApp.session.create+'?token='+ ConfigApp.session.initial); // process success and error handler.success(scope.onsuccess); -- cgit From 3d2fda7dd39e2363682f1fa353c951ab0d44ddfa Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Tue, 9 Feb 2016 18:40:49 +0100 Subject: Implemented URL query parsing for initial token /opa/?token=abcde --- afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js index 1b94e25..cba2aeb 100644 --- a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js +++ b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js @@ -24,7 +24,7 @@ var tmpl = '
      ' + '' + '{{label}}' + - '
      '; + '
      '; angular.module('SubmitButton', []) .directive('submitButton', function () { -- cgit From ceafc991147b17a52eab0a26cee5331b647a38f2 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Fri, 12 Feb 2016 17:44:59 +0100 Subject: Fixed Mutiple AutoStart Call and Refresh Token --- .../widgets/Notifications/TokenRefreshSvc.js | 37 +++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 82e43a5..25cb3a4 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -32,26 +32,27 @@ // scope module is load statically before any route is cativated -angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) +angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) - .directive ('tokenRefresh', function($timeout, $http, $location, Notification, ConfigApp) { + .directive ('tokenRefresh', function($timeout, $http, $location, Notification, AppConfig) { function mymethods(scope, elem, attrs) { - scope.status=undefined; // neither thu neither false - - + scope.logged=undefined; // neither thu neither false + scope.online = function () { elem.addClass ("online"); elem.removeClass ("offline"); + scope.logged=true; }; scope.offline = function(){ elem.addClass ("offline"); elem.removeClass ("online"); + scope.logged=false; }; scope.onerror = function(data, errcode, headers) { - if (scope.status !== false) { + if (scope.logged !== false) { Notification.warning ({message: "AppFramework Binder Lost", delay: 5000}); scope.offline(); } @@ -59,13 +60,13 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) }; scope.onsuccess = function(data, errcode, headers, config) { - if (scope.status !== true) { - if (data.request.token) ConfigApp.session.token = data.request.token; - if (data.request.uuid) ConfigApp.session.uuid = data.request.uuid; - if (data.request.timeout) ConfigApp.session.timeout = data.request.timeout; - + if (data.request.token) AppConfig.session.token = data.request.token; + if (data.request.uuid) AppConfig.session.uuid = data.request.uuid; + if (data.request.timeout) AppConfig.session.timeout = data.request.timeout; + if (scope.logged !== true) { Notification.success ({message: "AppFramework Binder Back to Live", delay: 3000}); scope.online(); + if (scope.callback) scope.callback(); } scope.status = 1; }; @@ -73,30 +74,30 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) // Check Binder status scope.getping = function() { - var handler = $http.get(ConfigApp.session.ping+'?token='+ ConfigApp.session.token); + var handler = $http.get(AppConfig.session.ping+'?token='+ AppConfig.session.token); // process success and error handler.success(scope.onsuccess); handler.error(scope.onerror); // restart a new timer for next ping - $timeout (scope.getping, ConfigApp.session.pingrate*1000); + $timeout (scope.getping, AppConfig.session.pingrate*1000); }; // Check Binder status scope.refresh = function() { - var handler = $http.get(ConfigApp.session.refresh+'?token='+ ConfigApp.session.token); + var handler = $http.get(AppConfig.session.refresh+'?token='+ AppConfig.session.token); // process success and error handler.success(scope.onsuccess); handler.error(scope.onerror); // restart a new timer for next refresh to 1/4 of timeout session - $timeout (scope.refresh, ConfigApp.session.timeout *250); + $timeout (scope.refresh, AppConfig.session.timeout *250); }; // Initial connection scope.tkcreate = function() { - var handler = $http.get(ConfigApp.session.create+'?token='+ ConfigApp.session.initial); + var handler = $http.get(AppConfig.session.create+'?token='+ AppConfig.session.initial); // process success and error handler.success(scope.onsuccess); @@ -111,8 +112,8 @@ angular.module('TokenRefresh', ['ConfigApp', 'ModalNotification']) if (scope.autolog) scope.tkcreate(); // Init ping and refresh process - $timeout (scope.getping, ConfigApp.session.pingrate*1000); - $timeout (scope.refresh, ConfigApp.session.timeout *250); + $timeout (scope.getping, AppConfig.session.pingrate*1000); + $timeout (scope.refresh, AppConfig.session.timeout *250); } return { -- cgit From fb1353dbc12ae889c17a6aa1572b917f57de0f9d Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Mon, 15 Feb 2016 15:36:19 +0100 Subject: TokenRefresh added Logout --- .../widgets/Notifications/TokenRefreshSvc.js | 57 ++++++++++++---------- 1 file changed, 31 insertions(+), 26 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 25cb3a4..c4a086e 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -34,11 +34,17 @@ // scope module is load statically before any route is cativated angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) - .directive ('tokenRefresh', function($timeout, $http, $location, Notification, AppConfig) { + .directive ('tokenRefresh', function($window, $timeout, $location, Notification, AppConfig, AppCall) { function mymethods(scope, elem, attrs) { scope.logged=undefined; // neither thu neither false - + + $window.onbeforeunload = function () { + AppCall.get ("token", "reset", {/*query*/}, function () { + console.log("OPA Exit Requested"); + }); + }; + scope.online = function () { elem.addClass ("online"); elem.removeClass ("offline"); @@ -51,7 +57,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) scope.logged=false; }; - scope.onerror = function(data, errcode, headers) { + scope.onerror = function() { if (scope.logged !== false) { Notification.warning ({message: "AppFramework Binder Lost", delay: 5000}); scope.offline(); @@ -59,49 +65,48 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) scope.status = 0; }; - scope.onsuccess = function(data, errcode, headers, config) { - if (data.request.token) AppConfig.session.token = data.request.token; - if (data.request.uuid) AppConfig.session.uuid = data.request.uuid; - if (data.request.timeout) AppConfig.session.timeout = data.request.timeout; + scope.onsuccess = function(jresp) { + if (jresp.request.token) AppConfig.session.token = jresp.request.token; + if (jresp.request.uuid) AppConfig.session.uuid = jresp.request.uuid; + if (jresp.request.timeout) AppConfig.session.timeout = jresp.request.timeout; + if (scope.logged !== true) { Notification.success ({message: "AppFramework Binder Back to Live", delay: 3000}); scope.online(); - if (scope.callback) scope.callback(); + if (scope.callback) scope.callback(jresp); } scope.status = 1; }; // Check Binder status scope.getping = function() { - - var handler = $http.get(AppConfig.session.ping+'?token='+ AppConfig.session.token); - // process success and error - handler.success(scope.onsuccess); - handler.error(scope.onerror); - - // restart a new timer for next ping - $timeout (scope.getping, AppConfig.session.pingrate*1000); + AppCall.get ("token", "ping", {/*query*/},function(result) { + if (result.status === 200) scope.onsuccess (result.data); + else scope.onerror(); + // restart a new timer for next ping + $timeout (scope.getping, AppConfig.session.pingrate*1000); + }); }; // Check Binder status scope.refresh = function() { - var handler = $http.get(AppConfig.session.refresh+'?token='+ AppConfig.session.token); - // process success and error - handler.success(scope.onsuccess); - handler.error(scope.onerror); - // restart a new timer for next refresh to 1/4 of timeout session - $timeout (scope.refresh, AppConfig.session.timeout *250); + AppCall.get ("token", "refresh", {/*query*/},function(result) { + if (result.status === 200) scope.onsuccess (result.data); + else scope.onerror(); + // restart a new timer for next refresh + $timeout (scope.refresh, AppConfig.session.timeout *250); + }); }; // Initial connection scope.tkcreate = function() { - var handler = $http.get(AppConfig.session.create+'?token='+ AppConfig.session.initial); - // process success and error - handler.success(scope.onsuccess); - handler.error(scope.onerror); + AppCall.get ("token", "create", {token: AppConfig.session.initial},function(result) { + if (result.status === 200) scope.onsuccess (result.data); + else scope.onerror(); + }); }; scope.icon = attrs.icon || "fi-lightbulb"; -- cgit From e6d12f74be543056a439259b61ba40a9d0adcf5c Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Mon, 15 Feb 2016 15:56:36 +0100 Subject: Updated TokenRefresh and AppConfig --- .../app/Frontend/widgets/FormInput/UploadFiles.js | 52 +++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index 8c0a4c2..a23809f 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -126,9 +126,9 @@ function LoadFileSvc (scope, elem, posturl, files, thumbnailCB) { xmlReq.send(xform); } -angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) +angular.module('UploadFiles',['AppConfig', 'ModalNotification', 'RangeSlider']) -.directive('uploadImage', function(ConfigApp, JQemu, Notification) { +.directive('uploadImage', function(AppConfig, JQemu, Notification) { function mymethods(scope, elem, attrs) { // get widget image handle from template @@ -152,7 +152,7 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) scope.imgElem[0].src = window.URL.createObjectURL(new Blob([upload.target.result], {type: "image"})); return true; // true activates post }; - var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + var posturl = attrs.posturl + "?token=" + AppConfig.session.token; new LoadFileSvc (scope, elem, posturl, files, readerCB); }; @@ -163,14 +163,14 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) scope.maxsize= attrs.maxsize || 100; // default max size 100KB scope.regexp = new RegExp (attrs.accept+ '.*','i'); - if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; - else scope.thumbnail=ConfigApp.paths[scope.category] + 'tux-bzh.png'; + if (attrs.thumbnail) scope.thumbnail= AppConfig.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=AppConfig.paths[scope.category] + 'tux-bzh.png'; - if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; - else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + if (attrs.thumbnail) scope.isnotvalid= AppConfig.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=AppConfig.paths[scope.category] + 'isnotvalid.png'; - if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; - else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + if (attrs.istoobig) scope.istoobig= AppConfig.paths[scope.category] + attrs.istoobig; + else scope.istoobig=AppConfig.paths[scope.category] + 'istoobig.png'; scope.noslider = attrs.noslider || false; if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); @@ -185,7 +185,7 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) }; }) -.directive('uploadAudio', function(ConfigApp, JQemu, Notification) { +.directive('uploadAudio', function(AppConfig, JQemu, Notification) { function mymethods(scope, elem, attrs) { // get widget image handle from template @@ -204,7 +204,7 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) // Upload is delegated to a shared function scope.UpLoadFile=function (files) { - var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + var posturl = attrs.posturl + "?token=" + AppConfig.session.token; new LoadFileSvc (scope, elem, posturl, files, false); }; @@ -215,14 +215,14 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) scope.maxsize= attrs.maxsize || 10000; // default max size 10MB scope.regexp = new RegExp (attrs.accept+ '.*','i'); - if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; - else scope.thumbnail=ConfigApp.paths[scope.category] + 'upload-music.png'; + if (attrs.thumbnail) scope.thumbnail= AppConfig.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=AppConfig.paths[scope.category] + 'upload-music.png'; - if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; - else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + if (attrs.thumbnail) scope.isnotvalid= AppConfig.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=AppConfig.paths[scope.category] + 'isnotvalid.png'; - if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; - else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + if (attrs.istoobig) scope.istoobig= AppConfig.paths[scope.category] + attrs.istoobig; + else scope.istoobig=AppConfig.paths[scope.category] + 'istoobig.png'; scope.noslider = attrs.noslider || false; if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); @@ -238,7 +238,7 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) }) -.directive('uploadAppli', function(ConfigApp, JQemu, Notification) { +.directive('uploadAppli', function(AppConfig, JQemu, Notification) { function mymethods(scope, elem, attrs) { // get widget image handle from template @@ -265,14 +265,14 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) // Check is we have a thumbnail within loaded Zipfile if (!thumbnail) { console.log ("This is not a valid Application Framework APP"); - scope.thumbnail=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + scope.thumbnail=AppConfig.paths[scope.category] + 'isnotvalid.png'; scope.$apply('thumbnail'); // we short-circuit Angular resync Image return false; // do not post zip on binder } scope.imgElem[0].src = window.URL.createObjectURL(new Blob([thumbnail.asArrayBuffer()], {type: "image"})); return true; // true activates post }; - var posturl = attrs.posturl + "?token=" + ConfigApp.session.token; + var posturl = attrs.posturl + "?token=" + AppConfig.session.token; new LoadFileSvc (scope, elem, posturl, files, readerCB); }; @@ -283,14 +283,14 @@ angular.module('UploadFiles',['ConfigApp', 'ModalNotification', 'RangeSlider']) scope.maxsize= attrs.maxsize || 100000; // default max size 100MB scope.regexp = new RegExp (attrs.accept+ '.*','i'); - if (attrs.thumbnail) scope.thumbnail= ConfigApp.paths[scope.category] + attrs.thumbnail; - else scope.thumbnail=ConfigApp.paths[scope.category] + 'upload-appli.png'; + if (attrs.thumbnail) scope.thumbnail= AppConfig.paths[scope.category] + attrs.thumbnail; + else scope.thumbnail=AppConfig.paths[scope.category] + 'upload-appli.png'; - if (attrs.thumbnail) scope.isnotvalid= ConfigApp.paths[scope.category] + attrs.isnotvalid; - else scope.isnotvalid=ConfigApp.paths[scope.category] + 'isnotvalid.png'; + if (attrs.thumbnail) scope.isnotvalid= AppConfig.paths[scope.category] + attrs.isnotvalid; + else scope.isnotvalid=AppConfig.paths[scope.category] + 'isnotvalid.png'; - if (attrs.istoobig) scope.istoobig= ConfigApp.paths[scope.category] + attrs.istoobig; - else scope.istoobig=ConfigApp.paths[scope.category] + 'istoobig.png'; + if (attrs.istoobig) scope.istoobig= AppConfig.paths[scope.category] + attrs.istoobig; + else scope.istoobig=AppConfig.paths[scope.category] + 'istoobig.png'; scope.noslider = attrs.noslider || false; if (!attrs.posturl) throw new TypeError('file-upload %s posturl=/api/xxxx/xxxx required', scope.attrs); -- cgit From 35698424ab8973d91208df92471d18b1c901220e Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Tue, 16 Feb 2016 18:34:21 +0100 Subject: Fixed BeforeUnload Binder Call in ProdMode --- afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index c4a086e..59fc763 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -34,14 +34,14 @@ // scope module is load statically before any route is cativated angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) - .directive ('tokenRefresh', function($window, $timeout, $location, Notification, AppConfig, AppCall) { + .directive ('tokenRefresh', function($log, $window, $timeout, $location, Notification, AppConfig, AppCall) { function mymethods(scope, elem, attrs) { scope.logged=undefined; // neither thu neither false $window.onbeforeunload = function () { - AppCall.get ("token", "reset", {/*query*/}, function () { - console.log("OPA Exit Requested"); + AppCall.get ("token", "reset", {/*query*/}, function () { + $log.log("OPA exit"); }); }; @@ -133,4 +133,3 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) })(); console.log ("Token Refresh Loaded"); - -- cgit From 7b8fe1b305a36f925fc2757a2c126c88fb0a5137 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Tue, 24 May 2016 09:23:56 +0200 Subject: Started move to new framework version --- .../widgets/Notifications/TokenRefreshSvc.js | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 59fc763..ec29978 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -66,6 +66,13 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) }; scope.onsuccess = function(jresp) { + + if (jresp.request.status !== "success") { + Notification.warning ({message: jresp.request.info, delay: 5000}); + scope.offline(); + return; + } + if (jresp.request.token) AppConfig.session.token = jresp.request.token; if (jresp.request.uuid) AppConfig.session.uuid = jresp.request.uuid; if (jresp.request.timeout) AppConfig.session.timeout = jresp.request.timeout; @@ -81,9 +88,9 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Check Binder status scope.getping = function() { - AppCall.get ("token", "ping", {/*query*/},function(result) { - if (result.status === 200) scope.onsuccess (result.data); - else scope.onerror(); + AppCall.get ("token", "ping", {/*query*/},function(jresp, errcode) { + if (errcode) scope.onerror(); + else scope.onsuccess (jresp); // restart a new timer for next ping $timeout (scope.getping, AppConfig.session.pingrate*1000); }); @@ -92,9 +99,9 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Check Binder status scope.refresh = function() { - AppCall.get ("token", "refresh", {/*query*/},function(result) { - if (result.status === 200) scope.onsuccess (result.data); - else scope.onerror(); + AppCall.get ("token", "refresh", {/*query*/},function(jresp, errcode) { + if (errcode) scope.onerror(); + else scope.onsuccess (jresp); // restart a new timer for next refresh $timeout (scope.refresh, AppConfig.session.timeout *250); }); @@ -103,9 +110,9 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Initial connection scope.tkcreate = function() { - AppCall.get ("token", "create", {token: AppConfig.session.initial},function(result) { - if (result.status === 200) scope.onsuccess (result.data); - else scope.onerror(); + AppCall.get ("token", "create", {token: AppConfig.session.initial},function(jresp, errcode) { + if (errcode) scope.onerror(); + else scope.onsuccess (jresp); }); }; @@ -133,3 +140,4 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) })(); console.log ("Token Refresh Loaded"); + -- cgit From c8a7784c665e1571400853c0c91b9c47be3ce86f Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Tue, 24 May 2016 22:08:43 +0200 Subject: Restore basic functionnalities with new API --- .../widgets/Notifications/TokenRefreshSvc.js | 63 ++++++++++++---------- 1 file changed, 34 insertions(+), 29 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index ec29978..4dff4c9 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -65,67 +65,73 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) scope.status = 0; }; - scope.onsuccess = function(jresp) { + scope.onsuccess = function(jresp, errcode) { - if (jresp.request.status !== "success") { + if (errcode !== 200 || jresp.request.status !== "success") { Notification.warning ({message: jresp.request.info, delay: 5000}); scope.offline(); - return; + return false; } - if (jresp.request.token) AppConfig.session.token = jresp.request.token; - if (jresp.request.uuid) AppConfig.session.uuid = jresp.request.uuid; - if (jresp.request.timeout) AppConfig.session.timeout = jresp.request.timeout; - if (scope.logged !== true) { - Notification.success ({message: "AppFramework Binder Back to Live", delay: 3000}); + Notification.success ({message: "AppFramework Binder Connected", delay: 3000}); scope.online(); if (scope.callback) scope.callback(jresp); } - scope.status = 1; + + scope.status = 1; + return true; }; // Check Binder status scope.getping = function() { AppCall.get ("token", "ping", {/*query*/},function(jresp, errcode) { - if (errcode) scope.onerror(); - else scope.onsuccess (jresp); + if (errcode !== 200 || jresp.request.status !== "success") { + Notification.warning ({message: jresp.request.info, delay: 5000}); + scope.offline(); + return; + } // restart a new timer for next ping $timeout (scope.getping, AppConfig.session.pingrate*1000); - }); + }, scope.onerror); }; // Check Binder status scope.refresh = function() { - AppCall.get ("token", "refresh", {/*query*/},function(jresp, errcode) { - if (errcode) scope.onerror(); - else scope.onsuccess (jresp); + AppCall.get ("token", "refresh", {/*query*/}, function(jresp, errcode) { + + scope.onsuccess (jresp, errcode); + // restart a new timer for next refresh $timeout (scope.refresh, AppConfig.session.timeout *250); - }); + }, scope.onerror); }; // Initial connection - scope.tkcreate = function() { - - AppCall.get ("token", "create", {token: AppConfig.session.initial},function(jresp, errcode) { - if (errcode) scope.onerror(); - else scope.onsuccess (jresp); - }); - }; + scope.loggin = function() { + AppCall.get ("token", "create", {token: AppConfig.session.initial}, function(jresp, errcode) { + + if (!scope.onsuccess (jresp, errcode)) return; + + // Intial token was accepted let's start ping & refresh + $timeout (scope.getping, AppConfig.session.pingrate*1000); + $timeout (scope.refresh, AppConfig.session.timeout *250); + }, scope.onerror); + }; + + + // Parse Widget Parameters scope.icon = attrs.icon || "fi-lightbulb"; scope.hostname = $location.host(); scope.httpdport = $location.port(); scope.autolog = JSON.parse(attrs.autolog || false); - if (scope.autolog) scope.tkcreate(); - - // Init ping and refresh process - $timeout (scope.getping, AppConfig.session.pingrate*1000); - $timeout (scope.refresh, AppConfig.session.timeout *250); + // autostart log if requested + if (scope.autolog) scope.loggin(); + } return { @@ -140,4 +146,3 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) })(); console.log ("Token Refresh Loaded"); - -- cgit From 6d06a2a9a02906ce4c848540d74c3c5798688664 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Thu, 26 May 2016 00:06:57 +0200 Subject: Update to LoginClient Plugin --- afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 4dff4c9..3e5e8d6 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -86,7 +86,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Check Binder status scope.getping = function() { - AppCall.get ("token", "ping", {/*query*/},function(jresp, errcode) { + AppCall.get (scope.plugin, "ping", {/*query*/},function(jresp, errcode) { if (errcode !== 200 || jresp.request.status !== "success") { Notification.warning ({message: jresp.request.info, delay: 5000}); scope.offline(); @@ -100,7 +100,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Check Binder status scope.refresh = function() { - AppCall.get ("token", "refresh", {/*query*/}, function(jresp, errcode) { + AppCall.get (scope.plugin, "refresh", {/*query*/}, function(jresp, errcode) { scope.onsuccess (jresp, errcode); @@ -111,7 +111,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Initial connection scope.loggin = function() { - AppCall.get ("token", "create", {token: AppConfig.session.initial}, function(jresp, errcode) { + AppCall.get (scope.plugin, "login", {token: AppConfig.session.initial}, function(jresp, errcode) { if (!scope.onsuccess (jresp, errcode)) return; @@ -124,6 +124,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Parse Widget Parameters + scope.plugin = attrs.plugin || "auth"; scope.icon = attrs.icon || "fi-lightbulb"; scope.hostname = $location.host(); scope.httpdport = $location.port(); -- cgit From 95a5e12dca0e0e0eb93b3dad69e529d737840d38 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sat, 28 May 2016 12:28:19 +0200 Subject: Clean up and documentation --- .../widgets/ActionButtons/ActionButtons.scss | 40 ++++ .../Frontend/widgets/ActionButtons/AppliButton.js | 205 +++++++++++++++++++++ .../Frontend/widgets/ActionButtons/SubmitButton.js | 52 ++++++ .../widgets/Buttons/SubmitButtons/SubmitButtons.js | 52 ------ .../Buttons/SubmitButtons/SubmitButtons.scss | 22 --- .../Frontend/widgets/FormInput/InputPassword.js | 79 -------- .../app/Frontend/widgets/FormInput/InputText.js | 179 ------------------ .../app/Frontend/widgets/FormInput/UploadFiles.js | 2 +- .../widgets/Notifications/TokenRefreshSvc.js | 4 +- 9 files changed, 300 insertions(+), 335 deletions(-) create mode 100644 afb-client/app/Frontend/widgets/ActionButtons/ActionButtons.scss create mode 100644 afb-client/app/Frontend/widgets/ActionButtons/AppliButton.js create mode 100644 afb-client/app/Frontend/widgets/ActionButtons/SubmitButton.js delete mode 100644 afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js delete mode 100644 afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss delete mode 100644 afb-client/app/Frontend/widgets/FormInput/InputPassword.js delete mode 100644 afb-client/app/Frontend/widgets/FormInput/InputText.js (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/ActionButtons/ActionButtons.scss b/afb-client/app/Frontend/widgets/ActionButtons/ActionButtons.scss new file mode 100644 index 0000000..6cb8338 --- /dev/null +++ b/afb-client/app/Frontend/widgets/ActionButtons/ActionButtons.scss @@ -0,0 +1,40 @@ +/* + * 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 . + */ + +@import "app/ibz-mixins"; + +// place here your submit buttons customization +appli-button { + @include ibz-button(grey,1rem) + img { + height: 3rem; + } + + + .disable>i { + text-decoration:none; // really not needed for the Top Bar, just for general technique + cursor: auto; + color: grey !important; + } +} + +.appli-menu-start { + .start-start, .stop-stop { + i {color: grey;} + } +} diff --git a/afb-client/app/Frontend/widgets/ActionButtons/AppliButton.js b/afb-client/app/Frontend/widgets/ActionButtons/AppliButton.js new file mode 100644 index 0000000..269ee81 --- /dev/null +++ b/afb-client/app/Frontend/widgets/ActionButtons/AppliButton.js @@ -0,0 +1,205 @@ +/* + * 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 . + * + * Bugs: Input with Callback SHOULD BE get 'required' class + */ + +(function () { + 'use strict'; + + var tmplAppli = '
      ' + + '' + + '{{label}}' + + '
      '; + + var tmplModal = + '×' + + '' + + 'Application {{label}}' + + '' + + ''; + + var tmplDetail = + '×' + + '' + + 'Application {{label}}' + + '
        ' + + '
      • Name : {{detail.name}}
      • ' + + '
      • Description {{detail.description}}
      • ' + + '
      • Author : {{detail.author}}
      • ' + + '
      ' + + ''; + + angular.module('AppliButton', []) + .directive('appliButton', function (AppConfig, AppCall, ModalFactory, Notification, $timeout, $window, $location, urlquery) { + + function mymethods(scope, elem, attrs) { + scope.runstatus = "stop"; + scope.runmode = urlquery.runmode || "auto"; + scope.clicked = function () { + + var notifyError = function(action, response) { + Notification.error ({message: "Fail /api/afm-main" + action + "=" + scope.label + " RunID="+ scope.appID, delay: 5000}); + elem.addClass ("fail"); + elem.removeClass ("success"); + scope.callback (scope.appID, action, response); + }; + + var notifySuccess = function (action, response) { + elem.removeClass ("fail"); + scope.runID = response.data.response.runid; + scope.callback (scope.appID, action, response); + }; + + var closeModApp = function() { + scope.modApp.deactivate(); + $timeout (function() {scope.modApp.destroy();}, 1000); + }; + + var closeModInfo = function() { + scope.modInfo.deactivate(); + $timeout (function() {scope.modInfo.destroy();}, 1000); + }; + + var actionModal = function(action) { + console.log ("Modal Action=%s", action); + switch (action) { + + case "start": + if (scope.runstatus !== "stop") return; + AppCall.get ("afm-main", "start", {id: scope.appID, mode: scope.runmode}, function(response) { + if (response.status !== 200 || response.data.jtype !== "afb-reply") { + notifyError ("start", response); + return; + } + scope.runstatus="start"; + notifySuccess (action, response); + if(response.data.response.uri) + scope.winapp= $window.open(response.data.response.uri.replace("%h", $location.host())); + }); + break; + + case "stop": + if (scope.runstatus !== "start") return; + + AppCall.get ("afm-main", "terminate", {runid: scope.runID}, function(response) { + if (response.status !== 200 || response.data.jtype !== "afb-reply") { + notifyError ("stop", response); + return; + } + scope.runstatus="stop"; + + // if a remote window app was open let's close it + if (scope.winapp) { + console.log ("Closing Application Window label=%s id=%s", scope.label, scope.appID); + scope.winapp.close(); + scope.winapp=false; + } + notifySuccess (action, response); + }); + break; + + case "info": + AppCall.get ("afm-main", "detail", {id: scope.appID}, function(response) { + if (response.status !== 200 || response.data.jtype !== "afb-reply") { + notifyError ("detail", response); + return; + } + + // reference http://foundation.zurb.com/apps/docs/#!/angular-modules + var config = { + animationIn: 'slideInFromTop', + contentScope: { + close : closeModInfo, + icon : scope.icon, + label : scope.appID, + detail : response.data.response + }, template : tmplDetail + }; + // Popup Modal to render application data + scope.modInfo = new ModalFactory(config); + scope.modInfo.activate (); + + }); + break; + + case "uninstall": + if (scope.runstatus !== "stop") return; + AppCall.get ("afm-main", "uninstall", {id: scope.appID}, function(response) { + if (response.status !== 200 || response.data.jtype !== "afb-reply") { + notifyError ("uninstall", response); + return; + } + + notifySuccess (action, response); + }); + break; + + default: + console.log ("ActionModal unknown action=[%s]", action); + break; + } + + closeModApp(); + }; + + // reference http://foundation.zurb.com/apps/docs/#!/angular-modules + var config = { + animationIn: 'slideInFromTop', + contentScope: { + action : actionModal, + runstatus: scope.runstatus, + close : closeModApp, + icon : scope.icon, + label : scope.label + }, template : tmplModal + }; + // Popup Modal to render application data + scope.modApp = new ModalFactory(config); + scope.modApp.activate (); + }; + + // extract application information from AppID+Store + if (attrs.handle && scope.store [attrs.handle].name) { + scope.icon = AppConfig.paths.icons + attrs.handle; //scope.store [attrs.handle].name.toLowerCase() + '-ico.png'; + scope.label = scope.store [attrs.handle].name; + scope.appID= attrs.handle; + } else { + scope.icon = AppConfig.paths.icons + 'w3c-ico.png'; + scope.label = attrs.handle; + } + + // 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: tmplAppli, + link: mymethods, + scope: {callback: '=', store: '='} + }; + }); +})(); diff --git a/afb-client/app/Frontend/widgets/ActionButtons/SubmitButton.js b/afb-client/app/Frontend/widgets/ActionButtons/SubmitButton.js new file mode 100644 index 0000000..323cd46 --- /dev/null +++ b/afb-client/app/Frontend/widgets/ActionButtons/SubmitButton.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 . + * + * Bugs: Input with Callback SHOULD BE get 'required' class + */ + +(function () { + 'use strict'; + + var tmpl = '
      ' + + '' + + '{{label}}' + + '
      '; + + 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.js b/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js deleted file mode 100644 index cba2aeb..0000000 --- a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 . - * - * Bugs: Input with Callback SHOULD BE get 'required' class - */ - -(function () { - 'use strict'; - - var tmpl = '
      ' + - '' + - '{{label}}' + - '
      '; - - 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 deleted file mode 100644 index 2150e4d..0000000 --- a/afb-client/app/Frontend/widgets/Buttons/SubmitButtons/SubmitButtons.scss +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 . - */ - -@import "app/ibz-mixins"; - -// place here your submit buttons customization - diff --git a/afb-client/app/Frontend/widgets/FormInput/InputPassword.js b/afb-client/app/Frontend/widgets/FormInput/InputPassword.js deleted file mode 100644 index 157009c..0000000 --- a/afb-client/app/Frontend/widgets/FormInput/InputPassword.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 = '' + - '' + - ' '+ - ''; - -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 deleted file mode 100644 index 2653175..0000000 --- a/afb-client/app/Frontend/widgets/FormInput/InputText.js +++ /dev/null @@ -1,179 +0,0 @@ - -/* - * 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 = '' + - ''+ - '{{errmsg}}'; - -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/UploadFiles.js b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js index a23809f..90110c9 100644 --- a/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js +++ b/afb-client/app/Frontend/widgets/FormInput/UploadFiles.js @@ -157,7 +157,7 @@ angular.module('UploadFiles',['AppConfig', 'ModalNotification', 'RangeSlider']) }; // Initiallize default values from attributes values - scope.name= attrs.name || 'avatar'; + scope.name= attrs.name || 'file'; scope.category= attrs.category || 'image'; scope.mimetype= (attrs.accept || 'image') + '/*'; scope.maxsize= attrs.maxsize || 100; // default max size 100KB diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 3e5e8d6..4dee196 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -68,7 +68,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) scope.onsuccess = function(jresp, errcode) { if (errcode !== 200 || jresp.request.status !== "success") { - Notification.warning ({message: jresp.request.info, delay: 5000}); + Notification.warning ({message: "auto-connect :" + jresp.request.info, delay: 10000}); scope.offline(); return false; } @@ -111,7 +111,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) // Initial connection scope.loggin = function() { - AppCall.get (scope.plugin, "login", {token: AppConfig.session.initial}, function(jresp, errcode) { + AppCall.get (scope.plugin, "connect", {token: AppConfig.session.initial}, function(jresp, errcode) { if (!scope.onsuccess (jresp, errcode)) return; -- cgit From a1c9f0e713b2b6e6cd2469fd34de18507b3290c6 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Sun, 29 May 2016 19:45:13 +0200 Subject: Update client window exit --- afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'afb-client/app/Frontend/widgets') diff --git a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js index 4dee196..2c7c3da 100644 --- a/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js +++ b/afb-client/app/Frontend/widgets/Notifications/TokenRefreshSvc.js @@ -40,7 +40,7 @@ angular.module('TokenRefresh', ['AppConfig', 'ModalNotification']) scope.logged=undefined; // neither thu neither false $window.onbeforeunload = function () { - AppCall.get ("token", "reset", {/*query*/}, function () { + AppCall.get (scope.plugin, "logout", {/*query*/}, function () { $log.log("OPA exit"); }); }; -- cgit