Android App voor havenbedrijven om schadegevallen te registreren in een Digitaal Informatie Systeem.

Maat: px
Weergave met pagina beginnen:

Download "Android App voor havenbedrijven om schadegevallen te registreren in een Digitaal Informatie Systeem."

Transcriptie

1 Scriptie ingediend tot het behalen van de graad van PROFESSIONELE BACHELOR IN DE ELEKTRONICA-ICT Android App voor havenbedrijven om schadegevallen te registreren in een Digitaal Informatie Systeem. Matthias Debaere Departement Wetenschappen en Techniek Opleiding Elektronica-ICT Academiejaar Interne promotor: Docent Tim Dams Externe promotor: Bernard De Vriese en Martijn Van Oosterhout Versie: 12 juni 2015

2 Dankwoord In eerste instantie gaat mijn welgemeende dank uit naar de directie en de medewerkers van Molenbergnatie / Ilomar Holding te Antwerpen, om mij via een stageplaats de kans te geven dit scriptie-project uit te werken. Specifiek bedank ik daarbij de heren Bernard De Vriese, ICT Manager, en Martijn Van Oosterhout, IT Software Coördinator. Verder bedank ik oprecht mijn docent en interne promotor, de heer Tim Dams voor zijn begeleiding. Ik waardeer ten zeerste hoe hij studenten weet te stimuleren en hen in contact brengt met het bedrijfsleven. Tenslotte een woordje van dank voor iedereen die op een of andere manier heeft bijgedragen tot het welslagen van mijn studies en van dit project. Antwerpen, 12 juni 2015 Matthias Debaere i

3 Abstract Molenbergnatie is met een omzet van bijna 40 miljoen euro in 2013, en met een opslagcapaciteit van ruim m² een belangrijke speler in de logistieke sector. In het kader van die activiteiten is het evident dat schadegevallen niet uit te sluiten zijn. Tot hiertoe worden data hierover manueel vergaard en tot bij de dossierbeheerders gebracht, hetzij via persoonlijk gerichte mails, hetzij via het persoonlijk overhandigen van digitale opslagmedia zoals USB-sticks. De opdracht van de stage bestond er in om een applicatie te ontwikkelen zodat de betrokken gegevens op een uniforme, gestandaardiseerde, eenvoudige en gebruiksvriendelijke manier door de medewerkers kunnen worden verzameld en vervolgens tot bij de beheerders geraken voor verdere verwerking. Dit hield in dat de applicatie foto s, barcodes en notities moet kunnen bundelen tot een geheel van data, die vervolgens kunnen worden doorgestuurd naar een Digitaal Informatie Systeem (DIS). Het was de intentie om deze applicatie voor Android te maken, doch er werd geopteerd om er een hybride applicatie van te maken. Dit in eerste instantie omdat het eenvoudiger is om te ontwikkelen in een combinatie van HTML5 en CSS3 met het front-end framework Ionic dat beroep doet op Angular JavaScript v1, dan in de native codetaal Java van Android. Een bijkomend voordeel is dat aanpassingen achteraf zeer eenvoudig implementeerbaar zijn. Het project is uitgemond in de ontwikkeling van WareHouseSnaps, een applicatie voor Android smartphones. De testresultaten en de reacties van op de vloer zijn positief en bemoedigend. Als eerste mobiele en tevens multi-language applicatie zal WareHouseSnaps, na een testperiode en de nodige investeringen in de hardware, worden geïmplementeerd in Antwerpen, en in een latere fase in de Spaanse vestigingen. Het management gelooft in de kostenbesparing en de kwaliteitsverbetering die kan worden gerealiseerd dankzij WareHouseSnaps. ii

4 Inhoudsopgave Dankwoord Abstract i ii 1 Situering 1 2 Bespreking Architectuur Van opdracht tot keuze architectuur Basiskenmerken Ionic framework Vergelijking met Model View Presenter-patroon Specifieke kenmerken Ionic framework Compenenten / Modules Configs Views Directives CSS Controllers Services en Factories Libraries ngcordova plugins Resultaten 65 4 Besluit 69 A Handleidingen 70 A.1 Een Ionic project: van A tot Z A.1.1 Te downloaden en te installeren A.1.2 Omgevingsvariabelen iii

5 INHOUDSOPGAVE iv A.1.3 Android SDK Manager A.1.4 Node Package Manager A.1.5 Ionic project starten A.1.6 Applicatie builden en emulaten A.1.7 Applicatie releasen A.1.8 Applicatie debuggen A.2 Smartphone voorbereiden op de installatie van een applicatie A.2.1 Smartphone Drivers A.2.2 Smartphone als emulator A.3 Installatie van een applicatie op een smartphone B Bugs en oplossingen 77 B.1 Bug: Ionicons manueel update B.1.1 Probleem B.1.2 Oplossing B.2 Bug: HTML5 File Input B.2.1 Probleem B.3 Bug: Cordova camera plugin v B.3.1 Probleem B.3.2 Oplossing B.4 Bug: Footer bar bij keyboard-open B.4.1 Probleem B.4.2 Oplossing C Mails 79 C.1 Mails met interne promoter T. Dams om HTML5 file input probleem aan te pakken C.2 Mails met N. Hoet, M. Van Oosterhout, R. Van Ruijssevelt en B. De Vriese om applicatie te bespreken D Opzetten van multi-language applicatie 84 D.1 Stappenplan E Licenties 89 E.1 The MIT License

6 Lijst van figuren 2.1 Schematische voorstelling van de gebruikte architectuur Screenshot van het menu van WareHouseSnaps Screenshot van de DMG-OPS pagina in actie Verschil tussen sent Verschil tussen sent Screenshots van de settings pagina in WareHouseSnaps aanpasbare ordertypes Screenshots van het zwart-witschema in WareHouseSnaps CSS stijl voor de footer Een thumbnail van een foto in de fotolijst De slideshow in actie Screenshots van de applicatie WareHouseSnaps v

7 Hoofdstuk1 Situering In de haven van Antwerpen zijn sinds de 19de eeuw meerdere naties of natiebedrijven actief. Het betreft vennootschappen die destijds werden opgericht om de behandeling en het vervoer van de goederen tussen de kade en de magazijnen of pakhuizen te verzorgen. De Molenbergnatie werd officieel opgericht in 1867 en concentreerde zich van meet af aan op de opslag van koffie, cacao bonen, noten, kruiden, specerijen e.d. Net zoals andere naties heeft Molenbergnatie haar activiteiten door de jaren heen gevoelig uitgebreid, zowel naar inhoud als naar geografische spreiding. Reeds voor de Tweede Wereldoorlog werd een douanegarantie bekomen zodat het bedrijf sinds dan haar klanten ook kan helpen met het vervullen van alle formaliteiten m.b.t. de dedouanering van goederen. Sinds 2014 maakt de Molenbergnatie deel uit van de holding Ilomar N.V. Met hubs in Spanje en recent ook in Vietnam (sinds januari 2015), beschikt de Molenbergnatie wereldwijd over een opslagcapaciteit van meer dan m². In 2013 werd een omzet van bijna 40 miljoen euro gerealiseerd. Een uitgebreid en gesofisticeerd informaticasysteem kan en mag niet ontbreken bij de efficiënte leiding van een dergelijk groot en gereputeerd bedrijf in de logistieke sector. Het is evident dat schade aan goederen en aan de infrastructuur niet uit te sluiten valt. Aangezien het bedrijf zich uitstrekt over een immense oppervlakte, gelegen in meerdere landen en/of continenten, zocht Molenbergnatie o.a. naar een manier om haar medewerkers op een uniforme, gestandaardiseerde, geïnformatiseerde en gebruiksvriendelijke manier alle schade, waar ook ter wereld, te kunnen laten registreren. In eerste instantie werd daarbij de schade ten gevolge van een logistieke handeling beoogd, maar ook andere schade moet worden gerapporteerd. Tijdens mijn stage heb ik aan deze digitalisering kunnen meewerken door de ontwikkeling van de applicatie WareHouseSnaps (WHS) voor Android smartphones. 1

8 Hoofdstuk2 Bespreking 2.1 Korte bespreking van de gekozen architectuur Van opdracht tot keuze architectuur Tot hiertoe worden data manueel vergaard en tot bij de dossierbeheerders gebracht, hetzij via persoonlijk gerichte mails, hetzij via het persoonlijk overhandigen van digitale opslagmedia zoals USB-sticks. De opdracht bestond er in om een applicatie te ontwikkelen zodat de betrokken gegevens op een uniforme, gestandaardiseerde, eenvoudige en gebruiksvriendelijke manier door de medewerkers kunnen worden verzameld en vervolgens tot bij de beheerders geraken voor verdere verwerking. Dit hield in dat de applicatie foto s, barcodes en notities moest kunnen bundelen tot een geheel van data, die vervolgens kunnen worden doorgestuurd naar een Digitaal Informatie Systeem (DIS). Het was de intentie om deze applicatie voor Android te maken, doch er werd geopteerd om er een hybride applicatie van te maken. Dit in eerste instantie omdat het eenvoudiger is om te ontwikkelen in een combinatie van HTML5 en CSS3 met het front-end framework Ionic dat beroep doet op Angular JavaScript v1 (Angular JS), dan in de native codetaal Java van Android. Een bijkomend voordeel is dat aanpassingen achteraf zeer eenvoudig implementeerbaar zijn Basiskenmerken Ionic framework De architectuur van een applicatie in het Ionic framework bestaat uit een aantal modules, waarvan de meeste Angular JS modules. Deze modules hebben elk hun eigen functie in de architectuur, maar bereiken pas hun volledig potentieel wanneer ze met elkaar worden 2

9 HOOFDSTUK 2. BESPREKING 3 gecombineerd. Deze modules staan bekend als views, controllers, services en factories, directives en configs. Een korte samenvatting: Views: De pagina s van de applicatie die aan de gebruiker worden getoond noemen Views. Ze worden opgebouwd in HTML5 bestanden. Ze bevatten een minimum aan logica, al kan het zijn dat ze op vele verschillende manier worden gebruikt door, of gebruik maken van, de controllers en directives; Controllers: In een Angular JS bestand staan controllers die in views toegepast worden. Ze hebben hun eigen functies, of ze roepen algemene functies op in services of factories. Controllers hebben hun eigen functies als ze direct een eigen logica implementeren, bijvoorbeeld het monitoren van een input in een HTML pagina en hier iets mee doen. Maar Controllers kunnen ook algemene functies aanspreken in services, bijvoorbeeld een service die een object ontvangt uit de controller en dit aanvult met data en terugstuurt; Services en Factories: Dit Angular JS bestand definieert functies met vaak voorkomende code van controllers. In een service of factories worden functies met de code ingevuld en kunnen data worden behandeld; Directives: Dit Angular JS bestand wordt eveneens gebruikt om eigen HTML elementen en/of attributen te maken. Hier kan men dus een volledig andere invulling geven aan reeds bestaande of nieuwe elementen en/of attributen geven, met als doel een deel van de logica al in de views en de respectievelijke directive te laten gebeuren. Een voorbeeld hiervan is het automatisch laten aanpassen van de grootte van een tekstkader aan de hoeveelheid tekst die er in getypt wordt; Configs: In dit laatste Angular JS bestand worden regels met betrekking op de applicatie afgesproken. Het kan gaan van het linken van controllers met views om een boomstructuur in de pagina s van de applicatie te definiëren, tot het bepalen van hoe een titel van een pagina er uit moet zien of hoeveel pagina s in tijdelijk geheugen (cache) mogen worden opgenomen Vergelijking met Model View Presenter-patroon Dit alles doet heel veel denken aan een Model View Presenter (MVP) patroon en dat is het bijna ook, met als verschil dat we de models vervangen door services en de views een connectie met directives kunnen hebben. Elke view heeft wel nog altijd zijn eigen controller zoals bij het MVP patroon en controllers spreken een algemeen model aan wat services en factories bevat. Figuur 2.1 toont een schematische voorstelling. Door deze opsplitsing van Angular JS modules vinden we enkele voordelen van het MVP patroon terug in het gebruikte Ionic framework. We kunnen in algemene functies herbruikbare code schrijven die door andere modules gebruikt wordt, wat resulteert in minder code en een duidelijkere structuur. Er kunnen aldus eenvoudig pagina s toegevoegd worden.

10 HOOFDSTUK 2. BESPREKING 4 Figuur 2.1: Schematische voorstelling van de gebruikte architectuur Specifieke kenmerken Ionic framework Wat maakt Ionic framework nu Ionic framework: Het gebruikt Cordova plugins om bepaalde native functionaliteit van de smartphone aan te spreken, zoals de camera. Deze plugin roept men dan aan in de controllers of services met behulp van de ngcordova library, zodat men bijvoorbeeld de camera in functies kan gebruiken en manipuleren; Het bundelt HTML en CSS (of Sass) bestanden om het uiterlijk van de app te bouwen. Met Angular JS kan men in de controllers, of in de views zelf, logica in de HTML templates implementeren; Het compileert naar een native app voor een geselecteerd platform. Ionic ondersteunt compilatie voor ios 6+, en Android 4.0+, en ook Windows Phone in de nabije toekomst; Het kan extra libraries toevoegen en gebruiken.

11 HOOFDSTUK 2. BESPREKING Componenten / Modules Configs Het doel van Configs is om bepaalde regels, definities en algemene opstartcode vast te leggen die gebruikt worden over de hele applicatie. Aan de hand van de injectie van delegates in de config kan men functies uit libraries gebruiken. We bespreken enkele delegates die we gebruikt hebben in configs $lockerprovider Om in de applicatie WareHouseSnaps settings te implementeren was er nood aan een configuratie van een zogenaamde kluis, oftewel Angular Locker. Angular Locker (locker) is een library in Angular JS code die kan worden gebruikt om waarden op te slaan in variabelen. Alvorens de locker in controllers, services, factories, directives of andere configs kan worden gebruikt is een definiëring en configuratie in een config vereist. Aldus hebben we volgende config verklaard: 1. c o n f i g ( [ l o c k e r P r o v i d e r, function ( l o c k e r P r o v i d e r ) { 2 l o c k e r P r o v i d e r. s e t D e f a u l t D r i v e r ( l o c a l ) 3. setdefaultnamespace ( WHS ) 4. s e t S e p a r a t o r (. ) 5. s e t E v e n t s E n a b l e d ( f a l s e ) ; 6 } ] ) Listing 2.1: app.js: config met $lockerprovider Aangezien de volgorde van configs belangrijk is hebben we de configuratie van de locker bovenaan in het bestand geplaatst. Vanaf dan kan de locker direct worden gebruikt $translateprovider Naar het einde van het project toe hebben we er op vraag van de verantwoordelijke voor gekozen om de taal in de interface van de applicatie te veranderen. In plaats van alles te vertalen in het Nederlands hebben we van WareHouseSnaps een multi-language applicatie gemaakt. Daarvoor waren echter meerdere stappen vereist, die we uitgewerkt en gedocumenteerd hebben. In eerste instantie was er behoefte aan een config. De config in kwestie moest bepalen waar de taalbestanden door de applicatie kunnen worden gevonden en geladen, en tevens voorzien in een beveiliging tegen Cross-Site Scripting (XSS) door middel van een sanering van de bron van deze bestanden (url) en ten slotte een geprefereerde en terugval taal verklaren.

12 HOOFDSTUK 2. BESPREKING c o n f i g ( [ $ s t a t e P r o v i d e r, $urlrouterprovider, $compileprovider, $ t r a n s l a t e P r o v i d e r, function ( $ s t a t e P r o v i d e r, $ u r l R o u t e r P r o v i d e r, $ c o m p i l e P r o v i d e r, $ t r a n s l a t e P r o v i d e r ) { // so Angular can work with f i l e : / / - u r i s ( aka l o c a l data ) : 25 $ c o m p i l e P r o v i d e r. i m g S r c S a n i t i z a t i o n W h i t e l i s t (/\ s *( h t t p s? f t p m a i l t o f i l e t e l ) : / ) ; $ t r a n s l a t e P r o v i d e r. u s e S a n i t i z e V a l u e S t r a t e g y ( escaped ) ; // p r o t e c t a g a i n s t XSS- a t t a c k s 28 $ t r a n s l a t e P r o v i d e r. u s e S t a t i c F i l e s L o a d e r ( { // use s t a t i c f i l e s and d e f i n e where to get them 29 p r e f i x : j s / languages /, 30 s u f f i x :. j s o n 31 } ) ; 32 $ t r a n s l a t e P r o v i d e r. p r e f e r r e d L a n g u a g e ( en ) ; // use e n g l i s h by d e f a u l t 33 $ t r a n s l a t e P r o v i d e r. f a l l b a c k L a n g u a g e ( en ) ; // use e n g l i s h by d e f a u l t i f t h e r e s no match in t a r g e t s d e v i c e. Listing 2.2: app.js: config met $translateprovider Om in Angular JS url s te saneren wordt $compileprovider gebruikt. De configs van de $translateprovider en de $lockerprovider werken al direct samen bij een Runcomponent die we na alle configs hebben gedefinieerd. Hierin wordt nagegaan of een gebruiker de applicatie voor de eerste keer opstart. Dit doet men door te zien of een bepaalde taalkeuzesetting geen lege waarde heeft. Indien dit wel het geval is wordt de taal overgenomen in de applicatie run ( [ $ i o n i c P l a t f o r m, $ t r a n s l a t e, l o c k e r, function ( $ i o n i c P l a t f o r m, $ t r a n s l a t e, l o c k e r ) { 109 $ i o n i c P l a t f o r m. r e a d y ( function ( ) { 110 //.. i f t h i s i s the f i r s t time the app i s being used, 111 // try and get the t a r g e t s d e f a u l t language and s e l e c t i t. 112 i f ( l o c k e r. get ( s e t t i n g s. chosenlanguage ) === ) { 113 i f ( typeof n a v i g a t o r. g l o b a l i z a t i o n!== undefined ) { // Found the language o f user s o p e r a t i n g system. 114 n a v i g a t o r. g l o b a l i z a t i o n. g e t P r e f e r r e d L a n g u a g e ( function ( d e t e c t e d L a n g ) { 115 // Format value to s u b s t r a c t l a t e r 116 d e t e c t e d L a n g = d e tectedlang. v a l u e. r e p l a c e (, - ) ; 117 c o n s o l e. l o g ( Detected language i s : + d etectedlang ) 118 // Use value to try to load user s o p e r a t i n g system - language in a p p l i c a t i o n 119 $ t r a n s l a t e. use ( ( d e tectedlang ). s p l i t ( - ) [ 0 ] ). then ( function ( data ) { 120 c o n s o l e. l o g ( S u c c e s f u l l y found t a r g e t s d e f a u l t language - + data ) ; 121 }, function ( e r r o r ) { 122 c o n s o l e. l o g ( Error in f i n d i n g the t a r g e t s d e f a u l t language - + e r r o r ) ;

13 HOOFDSTUK 2. BESPREKING } ) ; 124 }, n u l l ) ; 125 } 126 } 127 // Hide the a c c e s s o r y bar by d e f a u l t 128 i f ( window. cordova && window. cordova. p l u g i n s. Keyboard ) { 129 cordova. p l u g i n s. Keyboard. h i d e K e y b o a r d A c c e s s o r y B a r ( true ) ; } 130 // Use d e f a u l t s t a t u s bar 131 i f ( window. S t a t u s B a r ) { 132 S t a t u s B a r. s t y l e D e f a u l t ( ) ; } 133 } ) ; 134 } ] ) ; Listing 2.3: app.js: run-component met $translateprovider en $lockerprovider Gezien de geografische ligging van de vestigingen van Ilomar (België (Antwerpen), Spanje en Vietnam) hebben we de taalkeuze beperkt tot het Nederlands, het Engels of het Spaans $stateprovider en $urlrouterprovider Gebruikmakende van een $stateprovider kan een (boom)structuur van pagina s (lees: views) worden gedefinieerd. Deze $stateprovider houdt letterlijk de staat van de applicatie bij: op welke pagina de gebruiker zich bevindt en met welke controller deze in verband staat. Uiteindelijk hebben we alle navigatie mogelijkheden voorzien en door de menu-pagina met de $urlrouterprovider als default te definiëren worden errors voorkomen. 35 // a l l p o s s i b l e s t a t e s 36 $ s t a t e P r o v i d e r 37. s t a t e ( app, { 38 u r l : /app, 39 a b s t r a c t : true, 40 t e m p l a t e U r l : templates /main. html, 41 c o n t r o l l e r : mainctrl 42 } ) s t a t e ( app. menu, { 45 u r l : /menu, 46 v i e w s : { 47 content view : { 48 t e m p l a t e U r l : templates /menu. html, 49 c o n t r o l l e r : menuctrl 50 } 51 } 52 } ) s t a t e ( app. ops, { 55 u r l : / ops,

14 HOOFDSTUK 2. BESPREKING 8 56 v i e w s : { 57 content view : { 58 t e m p l a t e U r l : templates / ops. html, 59 c o n t r o l l e r : opsctrl 60 } 61 } 62 } ) s t a t e ( app. wh, { 65 u r l : /wh, 66 v i e w s : { 67 content view : { 68 t e m p l a t e U r l : templates /wh. html, 69 c o n t r o l l e r : whctrl 70 } 71 } 72 } ) s t a t e ( app. garage, { 75 u r l : / garage, 76 v i e w s : { 77 content view : { 78 t e m p l a t e U r l : templates / garage. html, 79 c o n t r o l l e r : g a r a g e C trl 80 } 81 } 82 } ) s t a t e ( app. v a r i a, { 85 u r l : / v a r i a, 86 v i e w s : { 87 content view : { 88 t e m p l a t e U r l : templates / v a r i a. html, 89 c o n t r o l l e r : v a r i a C t r l 90 } 91 } 92 } ) s t a t e ( app. s e t t i n g s, { 95 u r l : / s e t t i n g s, 96 v i e w s : { 97 content view : { 98 t e m p l a t e U r l : templates / s e t t i n g s. html, 99 c o n t r o l l e r : s e t t i n g s C t r l 100 } 101 } 102 } ) ; // I f none o f the above s t a t e s are matched, use t h i s as the f a l l b a c k 105 $ u r l R o u t e r P r o v i d e r. o t h e r w i s e ( /app/menu ) ;

15 HOOFDSTUK 2. BESPREKING } ] ) Listing 2.4: app.js: config met $stateprovider en $urlrouterprovider $ionicconfigprovider Met behulp van de $ionicconfigprovider kan men eigenschappen van de applicatie aanpassen. Bijvoorbeeld om een maximum van tien pagina s in de cache door de applicatie te laten bijhouden, of om de stijl van de terug -knop, van de navigatiebar in een pagina, van tabs, van HTML forms of van animaties tussen pagina s te veranderen. 13. c o n f i g ( [ $ i o n i c C o n f i g P r o v i d e r, function ( $ i o n i c C o n f i g P r o v i d e r ) { 14 // we w i l l need to cache pages, in case we go back to menu and return l a t e r, so we don t l o s e data, photo s, input - text, $ i o n i c C o n f i g P r o v i d e r. v i e w s. maxcache (10). forwardcache ( true ) ; 16 // the f o l l o w i n g code w i l l r e s u l t in a backbutton as such : back. 17 $ i o n i c C o n f i g P r o v i d e r. backbutton. t e x t ( Back ). i c o n ( ion - chevron - l e f t ). p r e v i o u s T i t l e T e x t ( f a l s e ) ; 18 // c e n t e r the t i t l e o f the navigation - bar : 19 $ i o n i c C o n f i g P r o v i d e r. navbar. a l i g n T i t l e ( c e n t e r ) ; 20 } ] ) Listing 2.5: app.js: config met $ionicconfigprovider De belangrijke variabele die we hier hebben aangepast is $ionicconfigproviders.views.forwardcache die we de waarde true hebben gegeven. Dit zorgt ervoor dat als er na een data verzameling van pagina wordt veranderd, de data bij het opnieuw openen van de betreffende pagina waarop de data staan niet verloren gaan Views Views zijn zoals eerder vermeld in hoofdstuk Architectuur de pagina s die aan de gebruiker worden getoond. De voornaamste codetaal is hier HTML5 en CSS Main Deze pagina dient als plaatshouder voor bepaalde elementen. In vaktermen noemt men dit de parent-pagina en zijn alle andere child-pagina s. Vandaar dat we deze pagina in de $stateprovider als abstract: true hebben verklaard. Volgende elementen vinden we hier terug (in volgorde): de header die de titel en de terug -knop bevat; het element <ion-nav-view/> dat door onderstaande pagina s wordt ingevuld;

16 Figuur 2.2: Screenshot van het menu van HOOFDSTUK 2. BESPREKING 10 de footer die de naam van de applicatie, de versie ervan en de settings -knop bevat. Voor de settings -knop in de footer hebben we er voor gekozen om een icoon van het icoonpak Ionicons te gebruiken. Aanvankelijk ondervonden we problemen met het gebruik van deze iconen. We hadden al een oplossing uitgewerkt, maar inmiddels is een update van het Ionic framework beschikbaar waarin het probleem in kwestie zich niet meer voordoet. In de footer staat er al een stukje code (lijn 11) waarmee de kleur van de footer kan worden veranderd. Deze mogelijkheid tot kleurverandering hadden we o.a. in gedachten ten behoeve van kleurenblinden (belang van een zwart-wit thema). 10 <div class= bar b a r - f o o t e r hide-on-keyboard-open 11 ng class= c o l o r mode? bar-balanced : b a r - s t a b l e > 12 <div class= t i t l e f o o t e r - t i t l e style= >WareHouseSnaps v1. 3</ div> 13 <div class= f o o t e r - s e t t i n g s > 14 <a class= button b u t t o n - i c o n icon i o n - g e a r - a href= #/app/ s e t t i n g s >< /a> 15 </ div> 16 </ div> Listing 2.6: main.html: ng-class in footer De directive ng-class hebben we te danken aan Angular JS en zorgt ervoor dat classes afhankelijk van een expressie aan een HTML element kunnen worden verwijderd of toegevoegd. Afhankelijk van de locker variabele color mode, die door de gebruiker in de settings -pagina kan worden aangepast, wordt er bepaald of bar-balanced of bar-stable aan de class moet worden toegevoegd. Dit resulteert in een kleurverandering van de footer. kleuren kunnen overigens onderling worden veranderd in de CSS files van Ionic of door Sass te gebruiken Menu Dit is de hoofdpagina van de applicatie. Van hieruit kan de gebruiker naar alle andere pagina s navigeren. Dankzij de $urlrouterprovider vormt deze menu -pagina de default pagina van de applicatie. Doordat we de locatie van menu.html in een config met de $stateprovider hebben gedefinieerd, kan Ionic dit in het <ion-nav-view> -element van main.html invullen. Aangezien we in main.html al een footer hadden gedefinieerd moest dat in dit HTML bestand worden gemeld en plaats voor worden voorzien, dit

17 HOOFDSTUK 2. BESPREKING 11 door in het <ion-content> -element een CSS class has-footer op te nemen. In dit <ion-content> - element plaatst Ionic, zoals de naam het zegt, de inhoud van de pagina. In het bovenliggende element <ion-view> bestaat de optie om een titel in te voeren (MENU) door de Ionic directive view-title te gebruiken en het de desbetreffende titel als waarde te geven. Vervolgens kan men de header verder aanpassen door in de <ion-view> gebruik te maken van een <ion-nav-buttons> -element, iets wat hier nog niet hebben toegepast maar echter wel in de pagina s van DMG-OPS, DMG-WH, DMG-GRG en VARIA. Vervolgens wensten we het logo van Ilomar in het midden van de vier knoppen te plaatsen, waarbij de hoeken worden afgerond. Hiervoor waren enkele CSS3-variabelen nodig. Allereerst hebben we een overliggend kader in de linkerbovenhoek van de VARIA -knop getekend en op de juiste plaats gezet door position: relative;, top: -178px; en right: 77px; te gebruiken. Vervolgens hebben we de hoeken afgerond met border-radius: 25px; en hebben we als inhoud het bedrijfslogo van Ilomar ingevuld door content: url($logo) te gebruiken. $logo is een Sass -variabele die we eerder als de url van de afbeelding hebben verklaard. Ten slotte hebben we de CSS stijl van de knoppen overschreven zodat de margin en padding tot nul wordt gereduceerd. Dit hebben we rechtstreeks in de HTML en niet met Sass gedaan omdat dat daar geen effect zou hebben. Een nieuwe class afleiden uit de Ionic classes had ook een optie kunnen zijn, maar dat zou meer werk en code hebben gevergd dan het in HTML aan te passen. Door gebruik te maken van de door Ionic gedefinieerde CSS-classes hebben we niet meer CSS moeten schrijven dan nodig was. Voor zowat elk element, zoals bijvoorbeeld knoppen, kan men op hun website veel informatie vinden, zodat men efficiënt de stijl van deze elementen kan aanpassen.

18 HOOFDSTUK 2. BESPREKING DMG-OPS: Registratie van schade bij operations Algemeen Via deze pagina wordt concreet de schade bij handelingen (operations) doorgegeven. Voor de gebruiker vormt dit de belangrijkste pagina van WareHouseSnaps. De meeste functionaliteit bevindt zich hier en op de settings -pagina na, hebben we hier de meeste HTML in moeten verwerken. De pagina dient, zoals DMG-WH, DMG-GRG en VARIA, ter verzameling van data. Dit kan het scannen of invullen van een barcode die een order voorstelt, het nemen van foto s en/of het invullen van notities zijn. Ten slotte kan de gebruiker kiezen of Terminal Management in CC wordt g d. Allereerst hebben we een icoon in de header geplaatst zodat na gebruik de verzamelde gegevens gewist worden. Dit hebben we gedaan door een <ion-nav-buttons> -element te gebruiken na het definiëren van het <ionview> -element, maar vóór het definiëren van Figuur 2.3: Screenshot van de DMG-OPS het <ion-content> -element. pagina in actie. Daarin hebben we een button met een Ionicon icoon aan de rechterkant geplaatst zodat de pagina als het ware kan worden ververst (refresh) als de gebruiker er op drukt. Opdat er effectief iets met de inhoud van de pagina zou gebeuren, moet de knop door de Angular directive ng-click te gebruiken een functie aanspreken in zijn respectievelijke controller. Bijvoorbeeld hebben we de functie cleardata die we in de controller van de DMG-OPS -pagina hebben verklaard. Vervolgens hebben we aan de hand van een <ion-content> -element de pagina met inhoud gevuld. Het eerste onderdeel betreft de plaats waar data in verband met het order worden ingevuld. Het order (Task) Een order wordt geïdentificeerd door het ordertype en het ordernummer. De gebruiker kan het order ofwel scannen door de scan -knop te gebruiken ofwel het manueel invoeren. In dat laatste

19 HOOFDSTUK 2. BESPREKING 13 geval moet men een dropdown-selectie gebruiken voor het ordertype en een simpele tekst-input voor de ordernummer. Ook hier verwijst de scan -knop naar een functie in de controller. De input hebben we gelinkt aan de controller door de Angular directives ng-model of ng-bind te gebruiken. Het verschil tussen deze twee directives ligt vervat in de manier waarop men bind: ng-bind voor One-way binding (van controller naar view) of ng-model voor Two-waybinding. Aangezien de input een waarde naar de controller moet versturen volgt daaruit dat ng-model dé manier is om te binden. Dit hebben we overigens toegepast op alle andere input en optie-knoppen, tenzij anders vermeld. 22 <l a b e l class= item i t e m - i n p u t i t e m - s t a c k e d - l a b e l > 23 <s pan>{{ lang. t a s k h i n t }}</s pan> 24 <i nput id= input-tasknumber type= t e l 25 placeholder= {{ lang. empty p l a c e h o l d e r }} 26 ng style= { c o l o r : ( c o l o r mode? # : #444 ) } 27 ng model= tasknumber. value > 28 </ l a b e l> Listing 2.7: ops.html: input met ng-style Opdat de kleur van de tekst in de input naar het kleurenthema zich zou aanpassen hebben we de Angular directive ng-style gebruikt. Met dergelijke directive kan in functie van een expressie die we ter plaatste hebben bepaald, de CSS stijl worden aangepast. De waarden van de opties in de dropdown voor het ordertype worden ingevuld met waarden die uit de controller komen. Deze waarden kunnen worden aangepast in de settings -pagina. Opdat de dropdown waardes aan de rechterkant uitgelijnd zouden worden, hebben we in de CSS class dropdown-tasknumber een variabele direction met waarde rtl (Right To Left) gebruikt. Door in een HTML <select> -element de Angular directive ng-options te gebruiken kunnen afhankelijk van een expressie de waarden uit de controller als effectieve opties worden geladen. 15 <s e l e c t id= dropdown-tasknumber 16 class= item i t e m - s e l e c t padding-top-and-bottom-only 17 ng class= c o l o r mode? balanced : dark 18 ng model= tasknumber. type 19 ng options= item as item f o r item in s e t t i n g s. t a s k t y p e s > 20 <option></ option> <! empty o p t i o n > 21 </s e l e c t> Listing 2.8: ops.html: dropdown vullen met ng-options Ten slotte hebben we een extra lege optie bijgevoegd zodat de dropdown default op een lege waarde geselecteerd staat. Foto s (Photos) Daarna hebben we het foto-gedeelte geplaatst. Mits een eenvoudige duw op de knop kan

20 HOOFDSTUK 2. BESPREKING 14 de gebruiker een foto nemen. De details van de foto worden nadien automatisch ingevuld in een dropdown lijst onder de knop dankzij de Angular directive ng-repeat die de data uit de controller haalt. Deze lijst heeft een titelbalk met daarin twee getallen waarvan het linkse getal het aantal geselecteerde foto s en het rechtste getal het aantal genomen foto s representeert. Door op deze titelbalk te drukken opent de lijst zich en wordt er automatisch naar gescrolled door een functie in de controller die de Toggle -functie uit de factory Scroll aanspreekt. Figuur 2.4: Het verschil na het verzenden van een foto. Afhankelijk van de geselecteerde foto s en hun grootte verandert de achtergrondkleur van het linkse getal: Groen om aan te tonen dat de selectie zich onder de attachment-limiet bevindt; Geel als de selectie in de buurt van de limiet komt (met 1 MB marge); Rood bij een overschrijding van de limiet. Hiertoe hebben we een vrij uitgebreide expressie geschreven, waarbij we eveneens de filter voor het linkse getal om het aantal gekozen foto s te tonen in de content hebben opgenomen: 49 <s pan class= badge 50 ng class= c o l o r mode? b a d g e - p o s i t i v e : badge-dark >{{ photos. l e n g t h }}</s pan> 51 <s pan style= m a r g i n - r i g h t : 35px ; 52 class= badge 53 ng class= c o l o r mode? ( attachments s i z e >= s e t t i n g s. attachment s e t t i n g? b a d g e - a s s e r t i v e : 54 ( attachments s i z e >= ( s e t t i n g s. attachment s e t t i n g - 1) && attachments s i z e < 55 s e t t i n g s. attachment s e t t i n g? badge-energized : 56 badge-balanced ) ) : 57 b a d g e - l i g h t >{{ ( photos f i l t e r : {checked : true } ). l e n g t h }}</s pan> Listing 2.9: ops.html: expressie voor kleurverandering van labels in een fotolijst Nieuw genomen foto s worden default geselecteerd om te verzenden, maar kunnen gedeselecteerd worden door op hun optie-knop in de lijst te drukken. Ze worden ook default gedeselecteerd na het verzenden ervan en krijgen daarbij een extra verzonden -label. Dit label wordt getoond met behulp van Angular Directive ng-show. Deze directive toont of verbergt afhankelijk van een expressie het bepaalde HTML element.

21 HOOFDSTUK 2. BESPREKING 15 Indien de gebruiker niet zeker is over de genomen foto kan hij de foto herbekijken door op de thumbnail van de foto te drukken. Aldus opent zich een pop-up galerij van de genomen foto s. De gebruiker kan dan tussen de genomen foto s swypen en uiteindelijk de galerij doen verdwijnen door op deze galerij te tappen. Om deze galerij te kunnen oproepen hebben we een template moeten aanmaken die er uit ziet als een slideshow en ook zo werkt. Daartoe hebben we met de directive ng-repeat <ion-slide> -elementen aan een <ion-slide-box> -element toegevoegd. De logica voor de slideshow hebben volledig in de controller verklaard zodat de juiste slide wordt geopend bij de uitgekozen foto. 79 <! t e m p l a t e o f a s l i d e s h o w to show the photos > 80 <s c r i p t id= image-modal. html type= t e x t / ng-template > 81 <div class= modal image-modal t r a n s p a r e n t 82 ng click= closemodal ( ) > 83 <i on slide box on slide changed= slidechanged ( index ) 84 show pager= f a l s e > 85 <i o n s l i d e ng repeat= photo in photos > 86 <img ng src= {{ photo. s r c }} class= f u l l s c r e e n - i m a g e /> 87 </ i o n s l i d e> 88 </ i on slide box> 89 </ div> 90 </s c r i p t> Listing 2.10: ops.html: template voor de slideshow Notities (Notes) Vervolgens heeft de gebruiker de mogelijkheid om aantekeningen te typen in een <textarea> - element. Opdat deze eenvoudig en afzonderlijk van de overige data zou kunnen worden leeg gemaakt hebben we een reset -button in de titel verborgen, die dankzij ng-show pas tevoorschijn komt als er inhoud in deze textarea staat. Om de logica om het tonen of verbergen en het leegmaken ter plaatse te laten gebeuren, hebben we expressies met $parent.notes geschreven. 92 <! To add e x t r a n o t e s > 93 <div class= card > 94 <div class= item i t e m - d i v i d e r t e x t - c e n t e r > 95 <h2><b>{{ lang. n o t e s s u b t i t l e }}</b></h2> 96 <s pan>{{ lang. n o t e s h i n t }}</s pan> 97 <button style= p o s i t i o n : a b s o l u t e ; top : 0px ; r i g h t : 0px ; 98 class= button b u t t o n - s m a l l 99 ng class= c o l o r mode? b u t t o n - p o s i t i v e : button-dark 100 ng show= $parent. notes!= n u l l 101 ng click= $parent. notes = n u l l > 102 {{ lang. n o t e s c l e a r }} 103 </b utton> 104 </ div> 105 <l a b e l class= item i t e m - i n p u t t e x t > 106 <! t e x t a r e a with a d i r e c t i v e, so use $ p a r e n t.<var> i n ng model

22 HOOFDSTUK 2. BESPREKING to e f f e c t i v e l y get value to c o n t r o l l e r s scope. > 108 <textarea id= notepad 109 ng style= { c o l o r : ( s e t t i n g s. c o l o r mode? # : #444 ) } 110 ng model= $parent. notes 111 placeholder= {{ lang. notes p l a c e h o l d e r }} ></ textarea> 112 </ l a b e l> 113 </ div> Listing 2.11: ops.html: een textarea met gebruik van $parent $parent hebben we nogmaals moeten aanwenden, namelijk in de bind tussen de inhoud en de controller. Omdat we van het <textarea> -element een directive hebben gemaakt, kunnen we ng-model alleen gebruiken worden als we $parent. voor de bepaalde variabele, die in de controller gedefinieerd wordt, verklaren. Dit komt doordat Angular een eigen <textarea> - element als directive heeft en we dat hebben overschreven. Hier kunnen we nog aan toevoegen dat als de gebruiker input geeft aan een textarea, Angular JS die inhoud normaal gezien automatisch in een voor de controller onbekende, nieuwe variabele plaatst. Daarom hebben we Angular JS de instructie moeten geven om geen eigen variabelen te maken: dit hebben we bereikt door ng-model aan $parent.notes te binden. Mail (Mail) Na het verzamelen van het ordernummer, foto s en/of notities, krijgt de gebruiker de mogelijkheid om alles door te sturen via mail. Daarbij haalt de controller het mailadres van de betrokken beheerder uit de settings-pagina. Afhankelijk van een CC optie die we in de settings default op uit hebben verklaard wordt Terminal Management in CC geplaatst. Aldus opent zich de native mail applicatie van de smartphone wanneer de gebruiker op de mailknop duwt. Alle vergaarde data worden dan als attachments met een nieuwe bestandsnaam gebaseerd op het order, de datum en een unieke identifier in de mail geplaatst. Bij het terugkomen in de applicatie, na het verzenden of weggooien van de mail, krijgt de gebruiker een pop-up te zien waarin wordt gevraagd of de pagina mag worden ververst. Indien er toegestemd wordt, ververst de pagina zich en worden alle data verwijderd. Indien er geweigerd wordt blijven de data beschikbaar, maar krijgen gekozen foto-elementen een extra verzonden -label ( sent ). In verband met deze HTML vermelden we nog dat we een CSS-class padding-left-and-rightonly hebben geschreven, die in de mail-knop wordt gebruikt. Ionic heeft namelijk de neiging om overal padding (extra ruimte tussen elementen) te plaatsen. Door meerdere extra classes in het CSS-bestand te verklaren, kan makkelijk padding worden verwijderd of op verschillende kanten worden toegevoegd. Overigens doen alle elementen met een kleur beroep op een ng-class die naar de color mode - variabele luistert. Daarentegen maakt alles met een tekst-input gebruik van ng-style, zoals bij de input van het order.

23 HOOFDSTUK 2. BESPREKING DMG-WH, DMG-GRG en VARIA: Registratie van andere schade Een medewerker kan ook andere schade melden: DMG-WH voor schade aan magazijnen ( warehouses ); DMG-GRG voor schade aan garages of voertuigen ( garage ); VARIA voor overige schade. Een gebruiker van WareHouseSnaps kan ook hiervan foto s en notities nemen en vervolgens mailen, met Terminal Management al of niet in CC. Om ook visueel makkelijk een onderscheid te kunnen maken tussen deze verschillende pagina s, hebben we voor elke optie een verschillende kleur gedefinieerd. De kleuren van deze elementen komen overeen met de kleur van de knoppen op de menu-pagina zodat dit voor de gebruiker makkelijk herkenbaar is. Figuur 2.5: Kleurverschil tussen pagina s.

24 HOOFDSTUK 2. BESPREKING 18 (a) Invoer van het paswoord op de settings -pagina. (b) Screenshot van de pagina settings. Figuur 2.6: Screenshots van de settings pagina in WareHouseSnaps SETTINGS (settings.html) Voor de beheerder van WareHouseSnaps is de settings-pagina de belangrijkste pagina. Hierop staan immers instellingen die voor alle pagina s belangrijk zijn, gaande van het kleurenschema tot het verklaren van de mailadressen en opties voor foto s te nemen. Alvorens er instellingen kunnen worden aangepast moet het juiste paswoord worden ingevuld. Dit is default abc123 maar dit kan door de beheerder worden veranderd. De pop-up is een Ionic element dat bij elke opening van deze pagina uit de controller wordt opgeroepen en de pagina aldus blokkeert. Al snel werd duidelijk dat dit niet waterdicht is: daarom hebben we in de checkbox-elementen de Angular JS directive ng-disabled gebruikt, die we naar een variabele uit de controller laten luisteren. Allereerst wordt tekst-input voor de mailadressen getoond. Deze adressen worden gebruikt door

25 HOOFDSTUK 2. BESPREKING 19 de respectievelijke controllers van DMG-OPS, DMG-WH, DMG-GRG en VARIA. Voor de stijl van deze inputs en hun labels hebben we een CSS class inputalic geschreven. 82 /* i n p u t a l i c c l a s s f o r s e t t i n g s p a g e m a i l - i n p u t */ 83. i n p u t a l i c input, #notepad { 84 f o n t s t y l e : i t a l i c ; } /* l a b e l s f o r m a i l - a d d r e s s e s */ 87. i n p u t a l i c span { 88 t e x t d e c o r a t i o n : u n d e r l i n e ; 89 w hite space: normal ; 90 word wrap: break word ; 91 w i d t h : 100%; 92 } Listing 2.12: ionic.app.scss: CSS code voor de input van adressen op de settings - pagina Data Vervolgens hebben we instellingen geplaatst die betrekking hebben op de data-verzameling. De gebruiker kan aldus bijvoorbeeld kiezen om foto s automatisch op te slaan op de smartphone. Aangezien dit belastend voor het geheugen is, hebben we deze optie default op uit gezet. Bepaalde van deze instellingen worden getoond met een toggle -optie. Er bestaan twee manieren om dergelijke toggle -optie in de HTML van de pagina te plaatsen. Men zou het <ion-toggle> -element van Ionic kunnen gebruiken met de directives ng-model om te binden en toggle-class om een Ionic stijl toe te voegen, maar dan kan er geen ng-class directive van Angular JS worden gebruikt (zodat de class afhankelijk van de kleurvariabele zou worden bepaald). Daarom hebben we een uitgebreide HTML met meer code, maar met meer functionaliteit, gebruikt: 137 < l i class= item i t e m - t o g g l e > 138 {{ lang. s e t t i n g s use c o l o r s }} 139 <l a b e l class= t o g g l e 140 ng class= s e t t i n g s. c o l o r mode? t o g g l e - b a l a n c e d : t o g g l e - d a r k > 141 <i nput type= checkbox 142 ng disabled= d i s a b l e d t o g g l e 143 ng model= s e t t i n g s. c o l o r mode > 144 <div class= track > 145 <div class= handle ></ div> 146 </ div> 147 </ l a b e l> 148 </ l i > Listing 2.13: settings.html: een toggle-optie met meer html maar met meer functionaliteit

26 HOOFDSTUK 2. BESPREKING 20 Die code komt terug bij de andere toggle -opties zoals bij de optie om terminal management in pagina s standaard aan te vinken en in CC te willen zetten, de kleurenoptie en de optie om de debug mode in te schakelen. Daarna volgt een input die de limiet van de attachments bepaalt. Een account heeft standaard al een attachment limiet maar dankzij onze extra setting kan een beheerder in WareHouseSnaps een lagere limiet instellen. Er wordt overigens ook in pagina s met fotolijsten naar deze variabele geluisterd om bij de fotolijst de kleurwaarde van het label van het gekozen aantal foto s aan te passen. Standaard hebben we de limiet op 10 MB ingesteld. De task line delimiter oftewel orderlijn delimiter zorgt ervoor dat bij het scannen van barcodes de overige data die van de orderlijn van de nuttige data worden gescheiden. Hier is default de delimiter een forward slash maar kan dankzij deze input worden aangepast. Opdat er maar één karakter in de input zou worden aanvaard, hebben we de HTML directive maxlength gedefinieerd met waarde als 1. Uiteindelijk hebben we in dit deel van de instellingen een lijst van ordertypes (task types) opgenomen. Deze ordertypes zijn de default waardes die een gebruiker in een dropdown op de OPS-pagina kan kiezen. Door functies uit de controller hierin te verwerken kan een gebruiker een default waarde verwijderen of er een nieuwe toevoegen. Bij het toevoegen opent zich een Ionic pop-up die een waarde voor het nieuwe type aanvaart, waarna de controller de rest doet en de Angular directive ng-repeat automatisch de lijst aanvult. Figuur 2.7: aanpasbare ordertypes. Overige (Other) Ten slotte is er nog het onderdeel waarin overige instellingen, zoals bijvoorbeeld de taalkeuze, kunnen worden veranderd. Voor deze taalkeuze hebben we een dropdown gedefinieerd die bij een eerste opstart van WareHouseSnaps door de controller default op de taal van het Operating System (OS) van de smartphone wordt gezet. De gebruiker heeft de keuze tussen Nederlands, Engels en Spaans. Opdat er bij het selecteren van een optie effectief een verandering in taal zou gebeuren, hebben we een directive geschreven en als attribuut in het element gebruikt.

27 HOOFDSTUK 2. BESPREKING < l i class= item style= p a d d i n g - r i g h t : 100px ; > 120 {{ lang. s e t t i n g s choose language }} 121 <s e l e c t id= l a n g u a g e S e l e c t o r 122 languageselecter 123 ng change= s e t L o c a l e ( ) ng model= l o c a l e 124 ng class= c o l o r mode? balanced : dark > 125 <option style= d i s p l a y : none ; value= ></ option> 126 <option value= en ng selected= l o c a l e == en > 127 {{ lang. languagenames. en }} 128 </ option> 129 <option value= nl ng selected= l o c a l e == nl > 130 {{ lang. languagenames. n l }} 131 </ option> 132 <option value= es ng selected= l o c a l e == es > 133 {{ lang. languagenames. es }} 134 </ option> 135 </s e l e c t> 136 </ l i > Listing 2.14: settings.html: dropdown van language met directive languageselecter In samenwerking met de Angular directive ng-change wordt er dan een taalkeuze doorgevoerd. De gebruiker kan tevens het kleurenschema veranderen naar een zwart-wit schema alsook de debug mode in- of uitschakelen. (a) Zwart-witschema in settings (b) Zwart-witschema in DMG-GRG. Figuur 2.8: Screenshots van het zwart-witschema in WareHouseSnaps De debug mode verandert niets aan de werking van de applicatie, er wordt alleen maar

28 HOOFDSTUK 2. BESPREKING 22 extra informatie voor de developer in de Dalvik Debug Monitor dankzij console.log-messages zichtbaar. En als laatste bestaat er voor de beheerder de mogelijkheid om het paswoord van deze settings - pagina te veranderen. Deze knop opent ten eerste een Ionic pop-up die om de confirmatie van het huidig paswoord vraagt. Indien dit juist wordt ingevuld, opent zich een volgende popup die om het nieuwe paswoord vraagt. Uiteindelijk opent zich een laatste pop-up die om een confirmatie van dit nieuwe paswoord vraagt. Hiervoor hebben we in de controller van de settings -pagina de nodige functies geschreven Directives textarea Directives kunnen worden gebruikt om een volledig andere invulling te geven aan reeds bestaande of zelf toegevoegde elementen en/of attributen te geven, zodat (een deel van) de logica kan worden overgenomen. 4 a n g u l a r. module ( WHS. d i r e c t i v e s, [ ] ) 5. d i r e c t i v e ( t e x t a r e a, function ( ) { 6 return { 7 r e s t r i c t : E, 8 c o n t r o l l e r : [ $element, function ( $element ) { 9 $element. c s s ( overflow - y, hidden ) ; 10 $element. c s s ( r e s i z e, none ) ; 11 a d j u s t H e i g h t ( ) ; function a d j u s t H e i g h t ( ) { 14 $element. c s s ( height, 0 + px ) ; var h e i g h t = a n g u l a r. element ( $element ) [ 0 ]. s c r o l l H e i g h t ; $element. c s s ( height, h e i g h t + px ) ; 19 $element. c s s ( max- h eight, h e i g h t + px ) ; 20 } ; function k e y P r e s s ( ) { 23 a d j u s t H e i g h t ( ) ; 24 } ; $element. bind ( keyup change blur, k e y P r e s s ) ; 27 } ] 28 } ; 29 } ) Listing 2.15: directives.js: de directive textarea

29 HOOFDSTUK 2. BESPREKING 23 De directive textarea heeft als doel de grootte van het element aan te passen aan de inhoud. Zo zal de gebruiker die meerdere zinnen typt niet meer in dit element moeten scrollen, maar is alle tekst ten allen tijde zichtbaar. Omgekeerd zal ook het element kleiner worden naarmate er tekst wordt verwijderd. Door restrict: E in de code te plaatsen laten we de directive het bestaande textarea element overnemen. In de volgende directive daarentegen hebben we restrict: A geplaatst zodat de directive als attribuut aan een element kan worden toegevoegd. We hebben de functie keypress() aan een toetsaanslag gebonden en laten we de functie adjustheight() oproepen. Na een initiële reset van de hoogte naar nul hebben we de hoogte van het element gelijk gesteld aan de waarde van de variabele scrollheight. Dit is anders dan de bron aantoont, wat voor ons een moeizame verkleining van het tekstkader voorkomt en tegelijkertijd code bespaart languageselecter Op deze directive hebben we beroep gedaan om de taal op de settings -pagina effectief te kunnen laten veranderen wanneer de gebruiker een andere optie in de dropdown kiest. Bij een eerste opstart van WareHouseSnaps wordt afhankelijk van de systeemtaal een voorgestelde taal ingevuld in de variabele $scope.locale en in de dropdown-optie van de settingspagina. Deze waarde laten we door een injectorfunctie ( $translate.proposedlanguage() ) van de ngtranslate -library ophalen. Als de gebruiker nadien op de settings-pagina een andere taal kiest, dan laten we die taal in proposedlanguage ophalen door in de HTML in het input -element met ng-model naar $scope.locale te binden. 44. d i r e c t i v e ( l a n g u a g e s e l e c t e r, function ( $ t r a n s l a t e ) { 45 return { 46 r e s t r i c t : A, 47 c o n t r o l l e r : [ $scope, $ t r a n s l a t e, function ( $scope, $ t r a n s l a t e ) { 48 // Get a c t i v e l o c a l e even i f not loaded yet : 49 $scope. l o c a l e = $ t r a n s l a t e. proposedlanguage ( ) ; $scope. s e t L o c a l e = function ( ) { 52 $ t r a n s l a t e. use ( $scope. l o c a l e ) ; 53 $scope. s e t t i n g s. c h o s e n l a n g u a g e = $scope. l o c a l e ; 54 } ; } ] 57 } ; 58 } ) ; Listing 2.16: directives.js: de directive languageselecter

30 HOOFDSTUK 2. BESPREKING 24 Uiteindelijk wordt de opgeroepen taal in de applicatie geïmplementeerd, door deze in de injectorfunctie $translate.use() van de ngtranslate -library te gebruiken. Een uitgebreid stappenplan om een multi-language applicatie te maken hebben we opgenomen in appendix D CSS CSS3 biedt een groot aanbod aan om de stijl van HTML aan te passen. Uiteindelijk hebben we er toch voor geopteerd om Sass te gebruiken. Sass lijkt erg op CSS en hergebruikt vele variabelen, maar kan eigen variabelen definiëren en, bovenal, hergebruiken. Dit maakt het bijvoorbeeld gemakkelijk om een url van een logo één keer te verklaren en vervolgens in andere classes te hergebruiken. 31 $ l o g o :.. / img/ logo i l o m a r - t r a n s p a r a n t. png ; Listing 2.17: ionic.app.scss: de url van het logo in Sass verklaard Kleuren Allereerst hebben we de default kleuren van Ionic overschreven met nieuwe hexadecimale kleurenwaardes. Deze variabelen worden ook in het Ionic CSS bestand gebruikt, dus aanpassingen hebben ook daar effect. Het logo van het bedrijf (Ilomar) hebben we in een variabele $logo gestoken en kan aldus worden hergebruikt om als statische achtergrond te dienen. 33. s c r o l l b g { 34 background: u r l ( $ l o g o ) no repeat c e n t e r 90% f i x e d ; 35 } Listing 2.18: ionic.app.scss: $logo in Sass gebruiken Of zoals bijvoorbeeld al aangetoond is in het hoofdstuk Views, op de menu -pagina tussen de 4 knoppen. 38 d i v. l o g o : a f t e r { 39 c o n t e n t : u r l ( $ l o g o ) ; 40 p o s i t i o n : r e l a t i v e ; 41 t o p : 178px ; r i g h t : 77 px ; 42 border top: 80 px s o l i d rgba ( 2 0 4, 0, 0, 0 ) ; 43 b o r d e r l e f t : 5 px s o l i d rgba ( 2 0 4, 0, 0, 0 ) ; 44 b o r d e r r i g h t : 5px s o l i d rgba ( 2 0 4, 0, 0, 0 ) ; 45 w i d t h : 0 ; 46 background:#f f f ; 47 b o r d e r r a d i u s : 2 5 p x ;

31 HOOFDSTUK 2. BESPREKING } Listing 2.19: ionic.app.scss: $logo in Sass gebruiken Footer Om de standaard Ionic rand op de footer te verwijderen hebben we deze klasse overschreven zodat die rand niet meer zichtbaar is. Mits het aanpassen van enkele CSS variabelen hebben we dan kunnen bereiken dat de titel in de footer links wordt uitgelijnd en het settings -icoon rechts wordt uitgelijnd. Vervolgens wensten we een duidelijke afscheiding tussen de titel en het settings -icoon zoals aangegeven op volgende figuur (merk grijze scheiding op): Figuur 2.9: CSS stijl voor de footer Ook dit hebben we kunnen realiseren via enkele CSS3 variabelen die de eerste achtergrond ( :before ) van het icoon een lichtgroene kleur geven, terwijl daarachter ( :after ) de tweede achtergrond lichtgrijs wordt gekleurd. 61 d i v. f o o t e r t i t l e : a f t e r { 62 c o n t e n t : ; 63 p o s i t i o n : a b s o l u t e ; 64 t o p : 0 px ; r i g h t : 0px ; 65 border top: 205 px s o l i d #ebebeb ; 66 b o r d e r l e f t : 80 px s o l i d rgba ( 2 0 0, 0, 0, 0 ) ; 67 w i d t h : 0 ; 68 } 69 d i v. f o o t e r s e t t i n g s : b e f o r e { 70 c o n t e n t : ; 71 p o s i t i o n : a b s o l u t e ; 72 t o p : 1 px ; r i g h t : 0 ; 73 border top: 180 px s o l i d #A2D064 ; 74 b o r d e r l e f t : 70 px s o l i d rgba ( 0, 0, 0, 0 ) ; /* t r a n s p a r e n t area under the d i a g o n a l edge */ 75 w i d t h : 0 ; 76 } Listing 2.20: ionic.app.scss: footer stijl geven met CSS3 variabelen In de HTML hebben we het footer-element met de class bar-balanced aangevuld, wat de donkergroene kleur oplevert. Deze wordt aangevuld met behulp van een expressie afhankelijk van de color mode -optie in ng-class.

32 HOOFDSTUK 2. BESPREKING #dropdown-tasknumber Om de dropdown op de OPS-pagina rechts uit te lijnen en te laten aansluiten op de input die ernaast staat, hebben we een andere waarde aan CSS variabele direction moeten gegeven. Namelijk rtl wat Right To Left betekent #settings-typeslist Deze hebben we aangemaakt om de lijst van de typeslist in de settings -pagina een lichtgrijze rand te geven Padding classes Deze classes hebben we aangemaakt omdat Ionic al te graag een standaard padding geeft aan elementen. Deze classes kunnen deze padding aan een bepaalde kant of alle kanten naar nul overschrijven, of verklaren de padding op tien pixels Fotolijsten Opdat de fotolijsten geen ruimte zouden innemen als ze niet worden getoond, en om een vlotte overgang te bewerkstelligen als de gebruiker kiest om deze wél te tonen, hebben we volgende classes aangemaakt: 192 /* accordion */ 193. item. item accordion. img { 194 l i n e h e i g h t : 38 px ; 195 padding top: 0 ; 196 padding bottom: 0 ; 197 t r a n s i t i o n : 0.09 s a l l l i n e a r ; } item. item accordion. ng hide { 200 l i n e h e i g h t : 0px ; } item. item accordion. ng hide add,. item. item accordion. ng hide remove { 203 d i s p l a y : b l o c k! i m p o r t a n t ; } Listing 2.21: ionic.app.scss: fotolijsten stijlen met CSS3 variabelen Daartoe laten we de hoogte van de items in deze lijst naar nul reduceren zodat ze niet zichtbaar zijn als ze niet worden getoond. Wanneer deze wél worden getoond, hebben ze een hoogte van 38 pixels terwijl ze zich binnen een tijdsspanne van 9 milliseconden openen. Dankzij de class hieronder wordt hun grootte uiteindelijk groter als 38 pixels, dit is dus maar een back-up die bijvoorbeeld bij de lijst van ordertypes in de settings -pagina wel van pas kwam.

33 HOOFDSTUK 2. BESPREKING avatar Zodat foto s in de fotolijst als een thumbnail worden getoond, hebben we een nieuwe class avatar geschreven met volgend effect: Figuur 2.10: Een thumbnail van een foto in de fotolijst Foto-slideshow Voor de slideshow van de foto s hadden we al een template in <script> -tags in de HTML van de pagina s geschreven. Na deze met enkele classes te stijlen zodat de achtergrond een donkere schijn geeft en de foto zich naar de grootte van het scherm aanpast zijn we volgend resultaat bekomen: Figuur 2.11: De slideshow in actie

34 HOOFDSTUK 2. BESPREKING Overige Ten slotte hebben we de classes languageselector, inputalic, inputnumb, button-scan en input-tasknumber aangemaakt om bij hun respectievelijke elementen de grootte, plaats in de layout en/of font-stijl aan te passen Controllers De controllers bevatten de logica van de views. Zij kunnen tevens beroep doen op services of factories. Elke view heeft zijn eigen controller die we in de $stateprovider in een config hebben bepaald. Vermeldenswaard is dat bij Angular JS men standaard met variabelen uit de parent -variabele $scope werkt. Dit geeft de mogelijkheid om allerlei variabelen in de views aan te roepen. Men kan dus ook JavaScript variabelen zoals var gebruiken, maar hun gebruik is beperkter. Bovendien worden libraries zoals locker of plugins zoals $cordova composer vóór hun gebruik geïnjecteerd in de controller. Dit doet men als volgt: 8. c o n t r o l l e r ( mainctrl, [ $scope, l o c k e r, $cordova composer, $ c o r d o v a F i l e, $ t r a n s l a t e, function ( $scope, l o c k e r, $cordova composer, $ c o r d o v a F i l e, $ t r a n s l a t e ) { Listing 2.22: controllers.js: injectie van plugins en libraries Dit is noodzakelijk om plugins, libraries, services en dergelijke te kunnen gebruiken mainctrl mainctrl is de controller van de main -pagina. Daarin hebben we code geschreven die in werking treed elke keer de applicatie wordt opgestart. Zo hebben we bijvoorbeeld het laden van de instellingen die in de settings -pagina kunnen worden aangepast. De locker -library werkt door variabelen van de controller te binden aan locker -variabelen. Deze locker -variabelen kunnen dan later in andere controllers worden opgeroepen en/of aangepast. Ten eerste hebben we code geschreven die wordt overlopen telkens de WareHouseSnapsapplicatie wordt geopend. Om te bepalen wanneer dit moest gebeuren hebben we Ionic events gebruikt. Aan de hand van het event beforeenter van de geïnjecteerde delegate $ionicview hebben we gedefinieerd dat de code wordt geladen alvorens het tonen van deze eerste pagina. 10 var debug ; 11 // F i r e s each time we e n t e r the page, whether i t s c r e a t e d or loaded a f t e r w a r d s when cached. 12 $scope. $on ( $ionicview. beforeenter, function ( ) {

35 HOOFDSTUK 2. BESPREKING i f ( l o c k e r. has ( s e t t i n g s. debug mode ) ) { // simple check i f s e t t i n g s have been loaded in l o c k e r. 14 // we load t h e s e s e t t i n g s in d i f f e r e n t v a r i a b l e s where 2 - way binding i s n t enabled, 15 // so that user - i n t e r a c t i o n on t h i s page won t have e f f e c t on the a c t u a l s e t t i n g s. 16 debug = l o c k e r. get ( s e t t i n g s. debug mode ) ; 17 $scope. c o l o r mode = l o c k e r. get ( s e t t i n g s. c o l o r mode ) ; 18 } 19 } ) ; 20 i f ( debug ) { c o n s o l e. l o g ( MAIN Page entered. ) ; } Listing 2.23: controllers.js: settings laden in mainctrl In de code hierboven wordt nagegaan of de color-mode en / of de debug-mode aan of uit staan. Ze worden, indien ze bestaan, uit de locker in aparte variabelen geladen. En zo kan men zich ervan verzekeren dat er zich geen relaties en ongewenste effecten bij de locker -settings voordoen. Afhankelijk van de color-mode wordt de footer wel of niet ingekleurd. Ten tweede hebben we code geschreven om settings voor te bereiden door bepaalde $scope - variabelen in de locker te binden. 22 // I n t e r e s t i n g to know : when $scope changes because o f user - i n t e r a c t i o n, i t w i l l be l o c k e r who adapts to i t. 23 /* Use l o c k e r. empty ( ) ; to d e l e t e a l l e n t r i e s. This i s u s e f u l l to use during development, but we comment i t out at deployment 24 because i t would r e s e t the s e t t i n g s each time you s t a r t the app. */ 25 /* Bind l o c k e r - e n t r i e s to $scope.<s omething> with an ( empty ) d e f a u l t value, to load as soon as the app s t a r t s up. 26 These w i l l be used in the s e t t i n g s - page and are 2 -way binded t h e r e. 27 This means they w i l l be saved to the l o c k e r - entry a f t e r change there, and a f t e r s h u t t i n g down the app. */ 28 l o c k e r. bind ( $scope, s e t t i n g s. to ops, ) ; // entry to hold ops s mail - address 29 l o c k e r. bind ( $scope, s e t t i n g s. to wh, ) ; // entry to hold wh s mail - address 30 l o c k e r. bind ( $scope, s e t t i n g s. to grg, ) ; // entry to hold garage s mail - address 31 l o c k e r. bind ( $scope, s e t t i n g s. to terminalmgmt, ) ; // entry to hold t e r m i n a l management s mail - address 32 l o c k e r. bind ( $scope, s e t t i n g s. save photos, f a l s e ) ; // to save photos to phone or not, d e f a u l t on f a l s e s i n c e we don t 33 // want to save the photos, we want to send them to the s e r v e r. 34 l o c k e r. bind ( $scope, s e t t i n g s. cc s e t t i n g, f a l s e ) ; // put t e r m i n a l management in cc 35 l o c k e r. bind ( $scope, s e t t i n g s. attachment s e t t i n g, 10) ; // allowed s i z e o f attachments in MB 36 l o c k e r. bind ( $scope, s e t t i n g s. t a s k t y p e s, [ INBO-, OUTBO-, TRO- ] ) ; // entry to hold array o f t a s k t y p e s

36 HOOFDSTUK 2. BESPREKING l o c k e r. bind ( $scope, s e t t i n g s. c o l o r mode, true ) ; // use c o l o r s in d esign 38 l o c k e r. bind ( $scope, s e t t i n g s. debug mode, true ) ; // i f debug mode i s enabled, c o n s o l e. l o g - messages 39 // w i l l be a c t i v a t e d a l l over the app. 40 l o c k e r. bind ( $scope, s e t t i n g s. password, abc123 ) ; // password used to get to s e t t i n g s - page. 41 l o c k e r. bind ( $scope, s e t t i n g s. o r d e r d e l i m i t e r, / ) ; // use / as a text - s e p a r a t o r in a scanned ordernumber. 42 l o c k e r. bind ( $scope, s e t t i n g s. chosenlanguage, ) ; // s e t up a v a r i a b l e in l o c k e r to save the user s chosen language to. 43 i f ( debug ) { c o n s o l e. l o g ( There are + l o c k e r. count ( ) + v a r i a b e l e s in l o c a l s t o r a g e d e f i n e d. ) ; } Listing 2.24: controllers.js: settings voorbereiden in mainctrl Deze worden dan achteraf opgehaald met de functies locker.get(). Om de locker -variabelen aan te passen is het voldoende om de gebonden $scope -variabele aan te passen. Ten derde wordt nagegaan of de gebruiker zijn eigen taal in de settings -pagina voordien al had gekozen. Indien dit het geval is wordt deze uitgelezen uit de locker en met behulp van de ngtranslate -library $translate -injector in WareHouseSnaps ingevuld. 43 i f ( debug ) { c o n s o l e. l o g ( There are + l o c k e r. count ( ) + v a r i a b e l e s in l o c a l s t o r a g e d e f i n e d. ) ; } 44 i f ( l o c k e r. get ( s e t t i n g s. chosenlanguage )!== ) { // i f a language was chosen by the user on p r e v i o u s use, 45 $ t r a n s l a t e. use ( l o c k e r. get ( s e t t i n g s. chosenlanguage ) ) ; // load t h i s language in the a p p l i c a t i o n. 46 i f ( debug ) { c o n s o l e. l o g ( Predefined language s e l e c t e d + l o c k e r. get ( s e t t i n g s. chosenlanguage ) ) ; } 47 } Listing 2.25: controllers.js: taal laden uit locker in mainctrl Ten slotte hebben we ngcordova plugins gebruikt om de cache van de applicatie leeg te maken en een mail-functie voor te bereiden. We hebben er bewust voor gekozen om de cache leeg te maken bij het opstarten en niet bij het afsluiten. Op die manier kunnen er na het afsluiten nog data uit de cache worden gehaald. 48 document. a d d E v e n t L i s t e n e r ( deviceready, function ( ) { 49 i f ( debug ) { c o n s o l e. l o g ( d e v i c e ready! ) ; } 50 // check i f a n a t i v e e - mail app i s i n s t a l l e d, such as exchange or gmail.. 51 $cordova composer. i s A v a i l a b l e ( ). then ( function ( ) { 52 i f ( debug ) { c o n s o l e. l o g ( - f u n c t i o n a v a i l a b l e ) ; } 53 /* a v a i l a b l e, though not r e a l l y trustworthy as i t could be a gmail account that i s a v a i l a b l e. 54 Unfortunately t h e r e s no way to know, so we try t h i s code anyway. */ 55 $cordova composer. a d d A l i a s ( exchange, com. android. ) ;

37 HOOFDSTUK 2. BESPREKING }, function ( ) { 57 i f ( debug ) { c o n s o l e. l o g ( - f u n c t i o n not a v a i l a b l e. Please i n s t a l l an app on the d e v i c e. ) ; } // not a v a i l a b l e 58 } ) ; 59 // Delete a l l p r e v i o u s cache memory on a f i r s t load o f t h i s app. 60 $ c o r d o v a F i l e. c h e c k D i r ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y, cache ) 61. then ( function ( s u c c e s s ) { 62 // s u c c e s s 63 i f ( debug ) { c o n s o l e. l o g ( Cache f o l d e r found, w i l l be emptied by d e l e t i n g i t. ) ; } 64 // Delete a l l p r e v i o u s cache memory on a f i r s t load o f t h i s app. 65 $ c o r d o v a F i l e. r e m o v e R e c u r s i v e l y ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y, cache ) 66. then ( function ( s u c c e s s ) { 67 // s u c c e s s 68 i f ( debug ) { c o n s o l e. l o g ( Cache d e l e t e d ) ; } 69 }, function ( e r r o r ) { 70 // e r r o r 71 i f ( debug ) { c o n s o l e. l o g ( Could not d e l e t e cache. + JSON. s t r i n g i f y ( e r r o r ) ) ; } 72 } ) ; 73 }, function ( e r r o r ) { 74 // e r r o r 75 i f ( debug ) { c o n s o l e. l o g ( Could not f i n d cache. + JSON. s t r i n g i f y ( e r r o r ) ) ; } 76 } ) ; 77 } ) ; Listing 2.26: controllers.js: cache leegmaken in mainctrl met behulp van ngcordova plugins Opdat ngcordova plugins gebruikt zouden kunnen worden gebruikt, moet bepaalde code in een wrapper worden geschreven. De wrapper document.addevenlistener( deviceready, function()) luistert naar het event deviceready, dat zich voordoet vanaf de applicatie klaar is met het laden van de pagina, zodat de plugins effectief kunnen worden gebruikt en geen errors zouden kunnen geven. Zo hebben we de mail-functie kunnen voorbereiden door na te gaan of er een mail-applicatie op de smartphone staat. Vervolgens hebben we deze native mail applicatie aan de ngcordova mail-plugin $cordova composer verklaard. De cache wordt leeggemaakt door na te gaan of er een map cache in de applicatie aanwezig is en indien zo, deze te verwijderen. Hiervoor hebben we de ngcordova plugin $cordovafile gebruikt. Het succesvol vinden van de locatie van de cache bleek in de praktijk niet zo eenvoudig. De plugin voorziet enkele locaties dankzij variabelen, waaronder de cache-folder, maar nét die

38 HOOFDSTUK 2. BESPREKING 32 blijkt niet te werken. Daarom hebben we cordova.file.cachedirectory niet gebruikt, maar wel cordova.file.externalapplicationstoragedirectory in combinatie met cache menuctrl Deze controller hebben we gebonden aan de menu -pagina. De geschreven code dient alleen maar om na te gaan of de color-mode en/of de debug-mode aan of uit staat, zoals bij menuctrl. Zo hebben we ervoor gezorgd dat de kleuren van de menu-buttons worden aangepast opsctrl Algemeen Deze controller bevat de meeste code en functies. Dit komt omdat in tegenstelling tot de andere pagina s DMG-WH, DMG-GRG en VARIA de DMG-OPS -pagina ook de functionaliteit van het scannen van barcodes en aanvaarden van input voor het ordernummer bevat. Vooraleer we voor de OPS-pagina specifieke functies hebben kunnen schrijven, hebben we zoals bij de vorige controllers de settings uit de locker geladen. We hebben bij het beforeenter -event extra code geschreven om de taal in de controller, en bijgevolg in de view, te laden. 109 $scope. $on ( $ionicview. beforeenter, function ( ) { 110 /* we load t h e s e s e t t i n g s in d i f f e r e n t v a r i a b l e s where 2 -way binding i s n t enabled, 111 so that user - i n t e r a c t i o n on t h i s page won t have e f f e c t on the a c t u a l s e t t i n g s. */ 112 // Get s e t t i n g s from l o c k e r and load them i n t o the page. 113 debug = l o c k e r. get ( s e t t i n g s. debug mode ) ; 114 $scope. s e t t i n g s. cc mgmt = l o c k e r. get ( s e t t i n g s. cc s e t t i n g ) ; 115 $scope. c o l o r mode = l o c k e r. get ( s e t t i n g s. c o l o r mode ) ; // Get language t r a n s l a t i o n s from s e r v i c e and load in $scope. lang, to be used in the view. 118 Language. g e t T r a n s l a t i o n s ( ). then ( function ( data ) { 119 $scope. l a n g = data. data ; 120 i f ( debug ) { c o n s o l e. l o g ( Language s u c c e s f u l l y loaded i n t o page s code - behind. ) ; } 121 } ) ; i f ( debug ) { c o n s o l e. l o g ( OPS Page entered. ) ; } 124 } ) ; Listing 2.27: controllers.js: settings en taal in de opsctrl laden

39 HOOFDSTUK 2. BESPREKING 33 De variabelen uit de view zoals {{ lang.task subtitle }}, die we aan hun respectievelijke $scope -variabelen in de controller hebben gebonden, krijgen de juiste info van vertalingen door dankzij de functie gettranslation() van de factory Language. Om de fotolijst te openen en te tonen hebben we de functie togglelist geschreven, die uit de view wordt aangeroepen: 126 // show or hide the p h o t o l i s t 127 $scope. t o g g l e L i s t = function ( bool, element ) { 128 // Show the p h o t o l i s t and s c r o l l to i t 129 S c r o l l. Toggle ( bool, element, 50) 130. then ( function ( data ) { $scope. ArePhotosShown = data ; } ) ; 131 // update the v a r i a b l e to the view 132 } ; Listing 2.28: controllers.js: functie togglelist om de fotolijst te openen Het aanvaardt de huidige status van de lijst of die al of niet wordt getoond en het ID van het element. De achterliggende reden is dat een functie Toggle van de service Scroll wordt aangeroepen: deze functie zorgt ervoor dat er automatisch naar het element wordt gescrolled. Opdat die functie zou weten naar waar er moet worden gescrolled, laten we het ID meegeven inclusief een offset zodat er rekening wordt gehouden met de margin of padding van het bepaalde element en de header. In de titelbalk van de fotolijst worden rechts het aantal gekozen en aantal genomen foto s vermeld. Vermits dit aantal gelimiteerd is hebben we een watch in de controller geschreven zodat de gebruiker via een wijziging van de achtergrond kleur van het label op de hoogte wordt gebracht van het benaderen van deze verzendlimiet. Een watch bekijkt een variabele, in dit geval de array (lijst) van foto s, en voert code uit als de waarde van de variabele in kwestie verandert. Daarom hebben we volgende watch geschreven die bij een verandering van de karaktereigenschap checked van een foto in de foto-lijst, telkens een nieuwe som maakt van de grootte van alle gekozen foto s. Het resultaat wordt dan in een nieuwe variabele geplaatst die in de view wordt gebruikt. 134 /* Watch the photos - array s p e c i f i c a l l y on the checked - property to know which are s e l e c t e d as attachments. 135 Then v a l i d a t e i f the s i z e o f attachments i s below the l i m i t. */ 136 $scope. $watch ( function ( $scope ) { 137 return $scope. photos. map( function ( photo ) { 138 return photo. checked ; 139 } ) ; 140 }, function ( ) { 141 // C a l c u l a t e the s i z e using the f u n c t i o n getsizeofattachments ( ) 142 attachments. g e t S i z e O f A t t a c h m e n t s ( $scope. photos ) 143. then ( function ( data ) { $scope. attachments s i z e = data ; } ) ; // update the r e s u l t to the view. 144 }, true ) ; Listing 2.29: controllers.js: een watch -functie die eigenschappen van foto s opvolgt

40 HOOFDSTUK 2. BESPREKING 34 Wanneer de gebruiker op een thumbnail in de fotolijst drukt, wordt een slideshowbox geopend. Deze wordt geladen uit een template dat in de HTML in <script> -tags wordt opgemaakt en in de controller aan de variabele $scope.modal gebonden is. Het drukken op de thumbnail roept de functie $scope.openmodal aan: 146 // Load a template f o r the s l i d e s h o w and bind i t to $scope. modal 147 $ i o n i c M o d a l. fromtemplateurl ( image - modal. html, { scope : $scope, a n i m a t i o n : s l i d e - in - up } ) 148. then ( function ( modal ) { $scope. modal = modal ; } ) ; 149 // When the s l i d e s h o w template i s loaded bind i t to $scope. modal // When a photo i n s i d e the p h o t o l i s t i s c l i c k e d, t h i s f u n c t i o n w i l l be c a l l e d 152 $scope. openmodal = function (new i n d e x ) { 153 // Before opening the slideshow, we change the index to show the c l i c k e d photo $ i o n i c S l i d e B o x D e l e g a t e. s l i d e (new index, 300) ; 155 i f ( debug ) { c o n s o l e. l o g ( Opening s l i d e s h o w on index + new i n d e x +, with f i l e - source : + $scope. photos [ new i n d e x ]. s r c +. ) ; } 156 //.. and then we open the s l i d e s h o w. 157 $scope. modal. show ( ) ; 158 // Important : The l i n e below i s needed to update the c u r r e n t ion - s l i d e s when using ng - repeat, and w i l l not work without 159 $ i o n i c S l i d e B o x D e l e g a t e. update ( ) ; 160 } ; Listing 2.30: controllers.js: functie $scope.openmodal die de slideshow opent Nadat de juiste index van de foto waarop de gebruiker drukt wordt geladen, opent zich de slideshowbox via de functie $scope.modal.show(). De code $ionicslideboxdelegate.update() is vereist omdat we ng-repeat gebruiken om de foto s in de slidebox te laden. Zonder deze code zou er alleen maar de eerste foto kunnen worden geopend. De slideshowbox komt voort uit de Ionic delegate $ionicslideboxdelegate die over meerdere functies beschikt zoals het swypen tussen foto s, het instellen van de snelheid van het sliden, het verbergen van de slideshowbox, en meer. Om te voorzien in het manueel sliden en het manueel sluiten van de slideshowbox hebben we volgende functies gebruikt: 161 // Closing the s l i d e s h o w 162 $scope. c l o s e M o d a l = function ( ) { 163 $scope. modal. h i d e ( ) ; 164 } ; 165 // Cleaning up the modal when we re done with i t. 166 $scope. $on ( $destroy, function ( ) { 167 $scope. modal. remove ( ) ; 168 } ) ;

41 HOOFDSTUK 2. BESPREKING // Call t h e s e f u n c t i o n s i f you need to manually c o n t r o l the s l i d e s 170 $scope. next = function ( ) { 171 $ i o n i c S l i d e B o x D e l e g a t e. next ( ) ; 172 } ; 173 $scope. p r e v i o u s = function ( ) { 174 $ i o n i c S l i d e B o x D e l e g a t e. p r e v i o u s ( ) ; 175 } ; 176 // Called each time the s l i d e changes 177 $scope. s l i d e C h a n g e d = function ( i n d e x ) { 178 i f ( debug ) { c o n s o l e. l o g ( Showing p i c t u r e in s l i d e b o x on index : + i n d e x + with f i l e - source : + $scope. photos [ i n d e x ]. s r c ) ; } 179 } ; Listing 2.31: controllers.js: functies om te sliden in de slideshow De code die we vervolgens hebben geschreven bevat de vier functies van de DMG-OPS -pagina namelijk scannen, foto s nemen, notities nemen en mailen. Barcodes scannen Om code te schrijven die een barcode scanner kan opstarten hebben we ten eerste de ngcordova plugin $cordovabarcodescanner in de controller geïnjecteerd en ten tweede een wrapper, die zoals bij mainctrl naar het deviceready event luistert, opgeroepen. Daarna hebben we functie scan(<mail-variabele>) geschreven die in de view wordt aangeroepen. Er wordt gekeken naar de mogelijkheden van een scan: ofwel scant de gebruiker een barcode, ofwel stopt de gebruiker met scannen door op de terugknop van de smartphone te duwen, of er doet zich een fout. Indien de scan wordt afgelast, wordt een pop-up aan de gebruiker getoond. Dit is eigenlijk eerder om een bug op te vangen dan om de gebruiker op ervan te informeren dat het scannen wordt geannuleerd. Die bug zou immers een tweede back-button afvuren. 181 // I t s important to wrap cordova - f u n c t i o n s i n s i d e document. addeventlistener to avoid c r a s h e s 182 document. a d d E v e n t L i s t e n e r ( deviceready, function ( ) { 183 i f ( debug ) { c o n s o l e. l o g ( d e v i c e ready! ) ; } /* SCAN A BARCODE */ 186 $scope. scanbarcode = function ( m a i l ) { /* v a r i a b l e mail i s to know whether or not the f u n c t i o n was 187 c a l l e d from the a l e r t - popup when mailing w/o tasknumber. */ 188 $cordovabarcodescanner. scan ( ) // s t a r t scanner then ( function ( scandata ) { // a f t e r scanning use the data. 190 i f ( scandata. c a n c e l l e d ) { // scanning was aborted by user. 191 i f ( debug ) { c o n s o l e. l o g ( Cancelled scanning ) ; }

42 HOOFDSTUK 2. BESPREKING /* We need to w r i t e something to handle the cancel, because the back - button f i r e s 2 times. 193 So we show an empty template that c a t c h e s the 2nd back - button. */ 194 $ i o n i c M o d a l. fromtemplate ( ). show ( ). then ( function ( ) { 195 // i n c l u d i n g an a l e r t 196 $ionicpopup. a l e r t ( { 197 t i t l e : $scope. l a n g. scan c a n c e l l e d, 198 t e m p l a t e : 199 } ). then ( function ( ) { 200 $ i o n i c M o d a l. fromtemplate ( ). h i d e ( ) ; } ) ; // and hide the empty template, i f i t s s t i l l t h e r e. 201 } ) ; 202 } Listing 2.32: controllers.js: scan -functie in opsctrl Die pop-up s hebben we uit de Ionic delegate $ionicpopup gehaald. Ze kunnen onder andere tekst tonen, knoppen met functies implementeren, om input vragen en deze verder gebruiken. Bij de ontwikkeling van WareHouseSnaps zijn deze mogelijkheden meermaals aan bod gekomen. Als de gebruiker succesvol een barcode scant wordt er gekeken of deze barcode een orderline delimiter (default / ) bevat. Deze delimiter kunnen we dankzij de locker -variabelen uit de settings laten oproepen. In dit geval moeten de data die voor de delimiter staan worden gescheiden van de data die erna komen. 203 e l s e i f ( scandata. t e x t!== ) { // scanning succeeded 204 i f ( debug ) { c o n s o l e. l o g ( Barcode Format : + scandata. format + Barcode Text : + scandata. t e x t ) ; } 205 var foundtype = f a l s e ; // d e f a u l t value o f f a l s e we l l use in f u t u r e code when matching the type. 206 i f ( debug ) { c o n s o l e. l o g ( Searching f o r d e l i m i t e r : + l o c k e r. get ( s e t t i n g s. o r d e r d e l i m i t e r ) + in scanned t e x t ) ; } 207 // try and get l a s t index o f d e l i m i t e r in the scanned code 208 var d e l = scandata. t e x t. l a s t I n d e x O f ( l o c k e r. get ( s e t t i n g s. o r d e r d e l i m i t e r ) ) ; 209 // i f the d e l i m i t e r i s found in de scanned data 210 i f ( debug && d e l!= 1){ 211 c o n s o l e. l o g ( Found d e l i m i t e r : + l o c k e r. get ( s e t t i n g s. o r d e r d e l i m i t e r ) +, d e l e t i n g e v e r y t h i n g a f t e r i t. ) ; 212 } // save e v e r y t h i n g b e f o r e that d e l i m i t e r 213 scandata. t e x t = scandata. t e x t. s u b s t r i n g ( 0, d e l!= 1? d e l : scandata. t e x t. l e n g t h ) ; Listing 2.33: controllers.js: succes in scan -functie in opsctrl

43 HOOFDSTUK 2. BESPREKING 37 Nadien kunnen we verder zien of de scan een ordertype bevat. Door te vergelijken met de waardes van de lijst van ordertypes, verklaard in de settings, kan er al dan niet beslist worden om dit ook uit de data te filteren wat in de dropdown wordt ingevuld. De restgegevens wordt in de input gezet. 215 // search f o r the tasktype in the l i s t o f t a s k t y p e s d e f i n e d in the s e t t i n g s. 216 f o r ( var i = 0 ; i < $scope. s e t t i n g s. t a s k t y p e s. l e n g t h ; i ++) { 217 i f ( debug ) { c o n s o l e. l o g ( checking i f + $scope. s e t t i n g s. t a s k t y p e s [ i ] + matches an option. ) ; } 218 i f ( scandata. t e x t. indexof ( $scope. s e t t i n g s. t a s k t y p e s [ i ] ) > 1) { // found a match. 219 i f ( debug ) { c o n s o l e. l o g ( Found type in tasktype - l i s t. S e l e c t i n g according option in dropdown. ) ; } 220 // s e l e c t match in dropdown. 221 $scope. tasknumber. type = $scope. s e t t i n g s. t a s k t y p e s [ i ] ; 222 // save e v e r y t h i n g a f t e r the tasktype as a value f o r the input. 223 $scope. tasknumber. v a l u e = scandata. t e x t. s l i c e ( $scope. s e t t i n g s. t a s k t y p e s [ i ]. l e n g t h ) ; 224 // Let f u t u r e code know that a type was found with the foundtype v a r i a b l e. 225 foundtype = true ; 226 i f ( debug ) { c o n s o l e. l o g ( Tasknumber i s + $scope. tasknumber. v a l u e ) ; } 227 // c a l l o f f i t e r a t i o n s i n c e we found our tasknumber 228 break ; 229 } 230 } Listing 2.34: controllers.js: vergelijken van ordertypes in de scan -functie in opsctrl Indien er geen ordertype wordt gevonden plaatsen we alles in de input en blijft dropdown van de ordertypes op een lege selectie staan. Deze moet echter wel ingevuld worden vooraleer er kan worden g d. 232 // type was not found in tasktype - l i s t 233 i f ( foundtype === f a l s e ) { 234 i f ( debug ) { c o n s o l e. l o g ( No type match found, putting whole value in i n p u t f i e l d. ) ; } 235 // So move e v e rything in the input. 236 $scope. tasknumber. v a l u e = scandata. t e x t ; 237 } Listing 2.35: controllers.js: wanneer er geen ordertype in de scan -functie wordt gevonden

44 HOOFDSTUK 2. BESPREKING 38 Ten slotte wordt gekeken of de functie na een mail-poging wordt aangeroepen. Indien de gebruiker op dat moment nog geen ordertype zou hebben gekozen dan zou de mail-functie aan de hand van een pop-up melden dat dat nog moet gebeuren. In die pop-up staat een knop die de gebruiker direct kan doen scannen. In dat geval zou de functie scan() een variabele mail met waarde true meekrijgen. Afhankelijk van die variabele laten we nagaan of de mail-poging moet worden verder gezet. 239 // v a r i a b l e mail i s used to check i f we should continue / r e t r y mailing. 240 i f ( m a i l ) { $scope. sendmail ( ) ; } 241 } Listing 2.36: controllers.js: poging tot mailen hervatten Foto s nemen De wijze waarop de gebruiker een foto neemt kunnen we beïnvloeden via opties meegegeven aan de functie getpicture van de ngcordova plugin $cordovacamera. Die opties hebben we in een array-variabele options geplaatst. 254 var o p t i o n s = { 255 q u a l i t y : 50, 256 d e s t i n a t i o n T y p e : Camera. D e s t i n a t i o n T y p e. FILE URI, 257 sourcetype : Camera. P i c t u r e S o u r c e T y p e.camera, 258 a l l o w E d i t : f a l s e, 259 // we use JPEG because i t s harder to read e x i f data from PNG 260 encodingtype : Camera. EncodingType. JPEG, 261 // whether or not to save the p i c t u r e s depends on s e l e c t e d s e t t i n g. 262 savetophotoalbum : l o c k e r. get ( s e t t i n g s. save photos ) 263 } ; Listing 2.37: controllers.js: opties voor de takepic -functie Ze bevatten informatie zoals de kwaliteit van de foto, de bron van de foto, in welke extensie het moet worden opgeslagen en of het naar het geheugen van de smartphone moet worden opslagen. Deze laatste variabele is afhankelijk van de setting die we uit de locker laten oproepen. Niet alle beschikbare opties van de plugin lijken te werken, zoals bijvoorbeeld cameradirection. Die moet bepalen of de camera aan de voorkant of van de achterkant van de smartphone wordt gebruikt. Voor WareHouseSnaps belangrijke opties zoals het nemen van foto s in JPEG extensie hebben we wel succesvol kunnen implementeren. Dit maakt dat EXIF-data kunnen worden gelezen. De functie takepic, die we in de view laten aanroepen, bevat de code om effectief met de camera een foto te nemen. Na de options -variabele mee te geven in deze functie, krijgen we een variabele terug die als waarde de bron van de foto bevat. Deze gebruiken we om exif-data uit de foto te halen, waarna we deze inclusief de bron van de foto in een foto-object invullen.

45 HOOFDSTUK 2. BESPREKING $scope. t a k e P i c = function ( ) { 265 $cordovacamera. g e t P i c t u r e ( o p t i o n s ). then ( function ( imageuri ) { // After s u c c e s f u l l y taking the photo 266 i f ( debug ) { c o n s o l e. l o g ( Taken a photo : + imageuri ) ; } 267 // f i r s t s t r i p the e x i f data 268 e x i f f e r. g e t E x i f ( imageuri ). then ( function ( e x i f d a t a ) { 269 i f ( debug ) { c o n s o l e. l o g ( Create Photo - o b j e c t and push to photo - array when c r e a t i o n completed. ) ; } 270 // then c r e a t e a photo - o b j e c t with the e x i f d a t a 271 f i l e s. c r e a t e P h o t o ( $scope. photos. l e n g t h, imageuri, e x i f d a t a ). then ( function ( data ) { 272 // and f i n a l l y push the photo - o b j e c t to the array, i n c l u d i n g a l l important data 273 $scope. photos. push ( data ) ; 274 i f ( debug ) { c o n s o l e. l o g ( Pushed + JSON. s t r i n g i f y ( data ) + to p h o t o s l i s t. ) ; } 275 } ) ; 276 } ) ; Listing 2.38: controllers.js: de takepic -functie bij succes Het maken van een foto-object gebeurt met dezelfde factory als om een notitie-object te maken, maar dan met een andere functie namelijk createphoto. Nadat een foto-object terug wordt ontvangen, wordt het toegevoegd aan de fotolijst. Tijdens het ontwikkelen van deze functie werd ons na enkele testen duidelijk dat er soms geen foto s kunnen worden gemaakt. Dit blijkt een bug te zijn met als oorzaak de optie om de foto op te slagen. Sommige smartphones hebben een eigen OS dat niet toelaat om het geheugen buiten de applicatie aan te spreken, zodat bijgevolg foto s niet kunnen worden opgeslagen. Om hieraan te verhelpen hebben we een stuk code herhaald, maar dan zonder het gebruiken van de optie om de foto op te slaan. 277 }, function ( e r r ) { 278 i f ( debug ) { c o n s o l e. l o g ( Error occurred when taking a p i c t u r e -> + e r r ) ; } 279 i f ( e r r!= Camera c a n c e l l e d. ) { 280 // try again but not saving to photoalbum, as t h i s i s the bug that may be r e s p o n s i b l e. 281 o p t i o n s. savetophotoalbum = f a l s e ; 282 $cordovacamera. g e t P i c t u r e ( o p t i o n s ). then ( function ( imageuri ) { // After taking the photo 283 i f ( debug ) { c o n s o l e. l o g ( Taken a photo : + imageuri ) ; } 284 // f i r s t s t r i p the e x i f data 285 e x i f f e r. g e t E x i f ( imageuri ). then ( function ( e x i f d a t a ) { 286 i f ( debug ) { c o n s o l e. l o g ( Create Photo - o b j e c t and push to photo - array when c r e a t i o n completed. ) ; }

46 HOOFDSTUK 2. BESPREKING // then c r e a t e a photo - o b j e c t with the e x i f d a t a 288 f i l e s. c r e a t e P h o t o ( $scope. photos. l e n g t h, imageuri, e x i f d a t a ). then ( function ( data ) { 289 // and f i n a l l y push the photo - o b j e c t to the array, i n c l u d i n g a l l important data 290 $scope. photos. push ( data ) ; 291 i f ( debug ) { c o n s o l e. l o g ( Pushed + JSON. s t r i n g i f y ( data ) + to p h o t o s l i s t. ) ; } 292 } ) ; 293 } ) ; 294 }, function ( e r r ) { 295 i f ( debug ) { c o n s o l e. l o g ( Error occurred when taking a p i c t u r e -> + e r r ) ; } 296 } ) ; 297 } 298 } ) ; 299 } ; Listing 2.39: controllers.js: de takepic -functie bij error Bij blijvende problemen laten we dit via een message in de console in de logfiles opnemen en aan de developer melden. Notities maken Om de notities in de array van attachments te plaatsen hebben we met behulp van de createnote functie uit de files factory een object gemaakt van de notities. 318 /* NOTES */ 319 // c r e a t e. txt - f i l e from notes and continue making mail o b j e c t 320 f i l e s. c r e a t e N o t e ( $scope. notes, debug ) 321. then ( function ( r e t u r n e d note o b j e c t ) { 322 // d u p l i c a t e the photoarray. 323 var to a t t a c h = $scope. photos. s l i c e ( 0 ) ; 324 i f ( r e t u r n e d note o b j e c t!== n u l l ) { 325 i f ( debug ) { c o n s o l e. l o g ( Retrieved note o b j e c t : + JSON. s t r i n g i f y ( r e t u r n e d note o b j e c t ) ) ; } 326 // append the to attach array with t h i s note - o b j e c t 327 to a t t a c h [ to a t t a c h. l e n g t h ] = r e t u r n e d note o b j e c t ; 328 } Listing 2.40: controllers.js: notities maken met behulp van de createnote functie uit de files factory

47 HOOFDSTUK 2. BESPREKING 41 Mailen Het mailen zelf in de mail-functie sendmail() wordt pas gestart na een serie van checks. Deze checks worden uitgevoerd dankzij de functie checkrequirements die zich in de factory mail bevindt. 302 $scope. sendmail = function ( ) { 303 i f ( debug ) { c o n s o l e. l o g ( Preparing mail, performing checks. ) ; } 304 // check a l l requirements and decide i f we can mail or not. 305 m a i l. checkrequirements ( $scope. lang, 306 $scope. notes, 307 $scope. attachments s i z e, $scope. s e t t i n g s. attachment s e t t i n g, 308 debug, 309 true, /* l e t the s e r v i c e know i t s 310 being c a l l e d on the ops - page and i t l l need the extra v a r i a b l e s : tasknumber & tasktype */ 311 $scope. tasknumber. value, $scope. tasknumber. type, 312 $scope. scanbarcode ) // scanbarcode f u n c t i o n to use i f user want s to scan from popup Listing 2.41: controllers.js: functie sendmail() start met een serie checks aan de hand van functie checkrequirements uit mail factory Die functie aanvaardt verschillende objecten van data die op de pagina kunnen worden verzameld, en meer: de taal, de grootte van de attachments en de waarde uit de settings om deze grootte aan te weerspiegelen, de debug variabele, een waarde true om te zien of orderdata nodig is, de orderdata zelf en de functie om barcodes te scannen. De checks gebeuren serieel en creëren een pop-up object (error popup) met een relevante boodschap bij problemen. Error popup wordt dan aan de gebruiker getoond dankzij een functie van de $ionicpopup injector: 380 }, function ( e r r o r popup ) { 381 // I f requirements were not met, send a popup to the view to a l e r t the user. 382 $ionicpopup. a l e r t ( e r r o r popup ) ; 383 } ) ; Listing 2.42: controllers.js: pop-up tonen bij error van checks Als er zich geen problemen stellen, wordt code overlopen die beschikbare notities in een.txt-bestand plaatst. Dit bestand wordt samen met de door de gebruiker gekozen foto s in een attachment-array geplaatst. Vervolgens laten we deze attachments met behulp van een formatfilenames -functie uit de attachment factory van naam veranderen, dit in functie van de waardes van de voorliggende data. 329 /* I t e r a t e each photo and check i f i t should be placed i n s i d e the attachments array

48 HOOFDSTUK 2. BESPREKING while a d j u s t i n g the f i l e n a m e. */ 331 attachments. formatfilenames ( to attach, 332 true, /* to l e t the s e r v i c e know i t s 333 coming from the ops page and i t w i l l be needing extra var s : tasknumber & - type */ 334 $scope. tasknumber. value, 335 $scope. tasknumber. type ) Listing 2.43: controllers.js: bestandsnamen bepalen met formatfilenames -functie uit de attachment -factory Dit geeft als resultaat bestandsnamen met als structuur <ordernummer> <timestamp> <unieke id>.<extensie>. Wanneer er geen orderdata beschikbaar zijn, laten we dit uit de bestandnaam en behouden we <timestamp> <unieke id>.<extensie>. Na een succesvolle herbenoeming van de bestanden wordt het mail-object aangemaakt en met data ingevuld. Afhankelijk van de optie om terminal management in CC te zetten wordt het adres hiervan toegevoegd aan het mail-object en vervolgens door middel van de ngcordova delegate $cordova composer verstuurd then ( function ( r e t u r n e d i t e m s ) { 337 // Push t h i s returned array to the attachments array. 338 $scope. e m a i l attachments = r e t u r n e d i t e m s ; 339 // Make mail o b j e c t 340 e m a i l = { 341 app : exchange, 342 to : l o c k e r. get ( s e t t i n g s. to ops ), 343 attachments : $scope. e m a i l attachments, 344 s u b j e c t : $scope. tasknumber. type + $scope. tasknumber. value, 345 body : $scope. notes, 346 ishtml : true 347 } ; 348 // put the t erminal management s mail - address in CC i f option i s checked 349 i f ( $scope. s e t t i n g s. cc mgmt === true ) { 350 var t e r m i n a l mgmt = l o c k e r. get ( s e t t i n g s. to terminalmgmt ) ; 351 i f ( debug ) { c o n s o l e. l o g ( Adding + t e r m i n a l mgmt + to cc. ) ; } 352 e m a i l. cc = t e r m i n a l mgmt ; // put the mail - address in cc 353 } 354 // a c t u a l l y send the mail by opening the n a t i v e e - mail app (we use exchange ) 355 i f ( debug ) { c o n s o l e. l o g ( Sending mail ) ; }

49 HOOFDSTUK 2. BESPREKING $cordova composer. open ( e m a i l ). then ( n u l l, function ( ) { Listing 2.44: controllers.js: mail-object aanmaken na succesvolle herbenoeming van bestandsnamen Aangezien het moeilijk is om te weten wat er zich afspeelt in andere applicaties, vanwege Android veiligheidsrestricties, kan niet worden nagegaan of de mail effectief wordt verstuurd. Er zijn echter wel push notifications van de mail-applicatie die de gebruiker op de hoogte kunnen brengen van de status van de mail-applicatie. Daarom hebben we besloten om de gebruiker een pop-up te tonen waarin wordt gevraagd of de data die al dan niet verzonden zijn moeten worden verwijderd of bijgehouden. 362 $ionicpopup. a l e r t ( { 363 t i t l e : $scope. l a n g. c l e a n data, 364 t e m p l a t e : $scope. l a n g. c l e a n data h i n t, 365 b u t t o n s : [ { 366 t e x t : $scope. l a n g. c l e a n data keep, 367 type : button - d e f a u l t 368 }, { 369 t e x t : $scope. l a n g. c l e a n data d e l e t e, 370 type : button - p o s i t i v e, 371 ontap : function ( ) { 372 // c a l l cleardata ( ) to remove data. 373 $scope. c l e a r D a t a ( ) ; 374 } 375 } ] 376 } ) ; Listing 2.45: controllers.js: pop-up tonen of data moet worden bijgehouden of verwijderd Indien de gebruiker kiest om de data te verwijderen, wordt de functie cleardata() aangesproken. Als volgt maakt deze alle variabelen leeg en geeft het gevoel alsof de pagina wordt ververst. 386 /* CLEAN VIEW */ 387 $scope. c l e a r D a t a = function ( ) { // r e s e t data on OPS- page 388 $scope. tasknumber = [ ] ; 389 $scope. photos = [ ] ; 390 $scope. ArePhotosShown = f a l s e ; 391 $scope. tasknumber. type = ; 392 $scope. tasknumber. v a l u e = ; 393 $scope. s e t t i n g s. cc mgmt = l o c k e r. get ( s e t t i n g s. cc s e t t i n g ) ; 394 $scope. n o t e s = n u l l ; 395 // r e s i z e the s c r o l l i n g area on the page.

50 HOOFDSTUK 2. BESPREKING $ i o n i c S c r o l l D e l e g a t e. r e s i z e ( ) ; 397 // only needed when destinationtype in the camera option i s FILE URI 398 $cordovacamera. c l e a n u p ( ) ; Listing 2.46: controllers.js: pagina verversen met de cleardata -functie whctrl De controller whctrl die gelinkt is aan de view van de DMG-WH -pagina, bevat minder functionaliteit als de opsctrl omdat er geen barcodes gescand of ordernummers moeten worden ingevuld. Aangezien dit qua functionaliteit het enige verschil tussen de twee pagina inhoudt, vertoont de code van deze controller verder veel gelijkenissen met die van opsctrl. Vermits er hier minder data in functies zoals checkrequirements, formatfilenames en cleardata worden gebruikt, en er geen orderdata bestaan, hebben we wel enkele aanpassingen moeten aanbrengen: 492 $scope. sendmail = function ( ) { 493 i f ( debug ) { c o n s o l e. l o g ( Preparing mail, performing checks. ) ; } 494 // check a l l requirements and decide i f we can mail or not. 495 m a i l. checkrequirements ( $scope. lang, 496 $scope. notes, 497 $scope. attachments s i z e, 498 $scope. s e t t i n g s. attachment s e t t i n g, 499 debug ) 500. then ( function ( s u c c e s s ) { Listing 2.47: controllers.js: minder data doorsturen naar checkrequirements -functie 515 attachments. formatfilenames ( to a t t a c h ). then ( function ( r e t u r n e d i t e m s ) { 516 // Push t h i s returned array to the attachments. 517 $scope. e m a i l attachments = r e t u r n e d i t e m s ; 518 // Make mail o b j e c t 519 e m a i l = { 520 app : exchange, 521 to : l o c k e r. get ( s e t t i n g s. to wh ), 522 attachments : $scope. e m a i l attachments, 523 s u b j e c t : Damages to warehouse, 524 body : $scope. notes, 525 ishtml : true 526 } ; Listing 2.48: controllers.js: minder data doorsturen naar formatfilenames -functie 617 /* CLEAN VIEW */ 618 $scope. c l e a r D a t a = function ( ) { // r e s e t data on WH- page 619 $scope. photos = [ ] ;

51 HOOFDSTUK 2. BESPREKING $scope. ArePhotosShown = f a l s e ; 621 $scope. s e t t i n g s. cc mgmt = l o c k e r. get ( s e t t i n g s. cc s e t t i n g ) ; 622 $scope. n o t e s = n u l l ; 623 // r e s i z e the s c r o l l i n g area on the page. 624 $ i o n i c S c r o l l D e l e g a t e. r e s i z e ( ) ; 625 // only needed when destinationtype in the camera option i s FILE URI 626 $cordovacamera. c l e a n u p ( ) ; 627 } ; Listing 2.49: controllers.js: minder data doorsturen naar cleardata -functie grgctrl en variactrl Idem zoals bij whctrl settingsctrl Algemeen Op de settings-pagina kan de gebruiker instellingen veranderen met effect op andere pagina s en dus ook op andere controllers. Bijgevolg hebben we frequent gebruik gemaakt van de locker -library. Allereerst hebben we de instellingen uit de locker geladen voor gebruik in de code van de settings-controller. De instellingen in de view luisteren per definitie naar de locker -variabelen aangezien we die aan bepaalde $scope -variabelen hebben gebonden en moeten dus niet worden geladen // get debug mode from l o c k e r 1091 var debug = l o c k e r. get ( s e t t i n g s. debug mode ) ; 1092 // t a s k t y p e s are not shown by d e f a u l t 1093 $scope. AreTaskTypesShown = f a l s e ; 1094 // Array to hold the t r a n s l a t i o n - data 1095 $scope. l a n g = [ ] ; 1096 // F i r e s each time we e n t e r the page, whether i t s c r e a t e d or loaded a f t e r w a r d s when cached $scope. $on ( $ionicview. beforeenter, function ( ) { 1098 Language. g e t T r a n s l a t i o n s ( ). then ( function ( data ) { 1099 $scope. l a n g = data. data ; 1100 switch ( $scope. l a n g. language ) { 1101 case EN : 1102 document. getelementbyid ( l a n g u a g e S e l e c t o r ). s e l e c t e d I n d e x = 1 ; 1103 break ; 1104 case NL : 1105 document. getelementbyid ( l a n g u a g e S e l e c t o r ). s e l e c t e d I n d e x = 2 ;

52 HOOFDSTUK 2. BESPREKING break ; 1107 case ES : 1108 document. getelementbyid ( l a n g u a g e S e l e c t o r ). s e l e c t e d I n d e x = 3 ; 1109 break ; 1110 } 1111 i f ( debug ) { c o n s o l e. l o g ( Language + $scope. l a n g. language + s u c c e s f u l l y loaded i n t o page s code - behind. ) ; } 1112 } ) ; 1113 } ) ; Listing 2.50: controllers.js: variabelen uit de locker laden Paswoord Om die instellingen te beschermen wordt telkens een gebruiker zich op de settings -pagina begeeft een paswoord gevraagd // F i r e s each time we entered the page, whether i t s c r e a t e d or loaded a f t e r w a r d s when cached $scope. $on ( $ionicview. e n t e r, function ( ) { 1117 // d i s a b l e toggle - o p t i o n s b e f o r e user e n t e r s r i g h t password $scope. d i s a b l e d t o g g l e = true ; 1119 // prompt f o r user input 1120 $ionicpopup. prompt ( { 1121 t i t l e : $scope. l a n g. password r e q u i r e d, 1122 t e m p l a t e : $scope. l a n g. password r e q u i r e d h i n t, 1123 inputtype : password, 1124 i n p u t P l a c e h o l d e r : ******* 1125 } ). then ( function ( password ) { 1126 // i f c o r r e c t password was entered 1127 i f ( password == l o c k e r. get ( s e t t i n g s. password ) ) { 1128 i f ( debug ) { c o n s o l e. l o g ( Correct password entered. ) ; } 1129 // unlock toggle - o p t i o n s $scope. d i s a b l e d t o g g l e = f a l s e ; 1131 i f ( debug ) { c o n s o l e. l o g ( entered s e t t i n g s page ) ; } 1132 } e l s e { // i f password was i n c o r r e c t 1133 i f ( debug ) { c o n s o l e. l o g ( Wrong password entered. ) ; } 1134 // n o t i f y user i n c o r r e c t password was entered 1135 $ionicpopup. a l e r t ( { 1136 t i t l e : $scope. l a n g. password e r r o r, 1137 t e m p l a t e : $scope. l a n g. password e r r o r h i n t 1138 } ). then ( function ( ) { 1139 // and return to p r e v i o u s page $ i o n i c H i s t o r y. goback ( ) ; 1141 } ) ; 1142 } 1143 } ) ; 1144 } ) ; Listing 2.51: controllers.js: paswoord-controle via pop-ups

53 HOOFDSTUK 2. BESPREKING 47 Via een pop-up waarin het paswoord wordt gevraagd, wordt een gebruiker al of niet toegelaten op de settingspagina. Wanneer een gebruiker het juiste paswoord invoert wordt de variabele $scope.disabled toggle op waarde false gezet, zodat toggle -opties zoals bij de color-mode optie kunnen worden aangepast. Anderzijds wordt een gebruiker die een incorrect paswoord invoert teruggestuurd naar de vorige pagina, dit met behulp van de Ionic delegate $IonicHistory. Wanneer de gebruiker het paswoord wilt veranderen worden er eveneens een serie pop-ups gegenereerd. Vooreerst wordt dan een confirmatie van het huidige paswoord gevraagd: 1158 $scope. changepassword = function ( ) { 1159 i f ( debug ) { c o n s o l e. l o g ( Changing password, asking f o r p r e v i o u s password. ) ; } 1160 // prompt f o r user input f o r v a l i d a t i n g p r e v i o u s pasword 1161 $ionicpopup. prompt ( { 1162 t i t l e : $scope. l a n g. password change, 1163 t e m p l a t e : $scope. l a n g. password change p r e v i o u s, 1164 inputtype : password, 1165 i n p u t P l a c e h o l d e r : ******* 1166 } ). then ( function ( password ) { Listing 2.52: controllers.js: oud paswoord bevestigen alvorens een nieuw in te stellen Daarna wordt een pop-up opgeroepen waarin de gebruiker een nieuw paswoord kan opgeven. Om veiligheidsredenen wordt aan de gebruiker dit nieuwe paswoord te bevestigen // i f c o r r e c t password was entered 1168 i f ( password == l o c k e r. get ( s e t t i n g s. password ) ) { 1169 i f ( debug ) { c o n s o l e. l o g ( Correct password entered, asking f o r new password. ) ; } 1170 // prompt f o r user input to ask f o r new password 1171 $ionicpopup. prompt ( { 1172 t i t l e : $scope. l a n g. password new, 1173 t e m p l a t e : $scope. l a n g. password new h i n t, 1174 inputtype : password, 1175 i n p u t P l a c e h o l d e r : ******* 1176 } ). then ( function ( password ) { 1177 // prompt f o r user input to confirm new password 1178 $ionicpopup. prompt ( { 1179 t i t l e : $scope. l a n g. password confirm, 1180 t e m p l a t e : $scope. l a n g. password c o n f i r m h i n t, 1181 inputtype : password, 1182 i n p u t P l a c e h o l d e r : ******* 1183 } ). then ( function ( c o n f i r m password ) { Listing 2.53: controllers.js: nieuw paswoord invoeren en confirmeren Na een succesvolle wijziging van het paswoord wordt dit aan de gebruiker meegedeeld.

54 HOOFDSTUK 2. BESPREKING // i f password i s confirmed 1185 i f ( c o n f i r m password == password ) { 1186 // change password 1187 $scope. s e t t i n g s. password = password ; 1188 i f ( debug ) { c o n s o l e. l o g ( New password confirmed. ) ; } 1189 // n o t i f y user has s u c c e s f u l l y changed password 1190 $ionicpopup. a l e r t ( { 1191 t i t l e : $scope. l a n g. password changed, 1192 t e m p l a t e : $scope. l a n g. password changed h i n t 1193 } ) ; Listing 2.54: controllers.js: pop-up tonen dat het paswoord succesvol is veranderd De gebruiker wordt eveneens verwittigd mocht zich een fout voordien tijdens deze procedure. De poging tot wijziging wordt dan ook gestaakt } e l s e { // i f c o n f i r m a t i o n f a i l e d 1195 i f ( debug ) { c o n s o l e. l o g ( Password not confirmed, changing password aborted. ) ; } 1196 // n o t i f y user has f a i l e d to confirm and abort changing the password 1197 $ionicpopup. a l e r t ( { 1198 t i t l e : $scope. l a n g. password c o n f i r m e r r o r, 1199 t e m p l a t e : $scope. l a n g. password c o n f i r m e r r o r h i n t 1200 } ) ; 1201 } 1202 } ) ; 1203 } ) ; 1204 } e l s e { 1205 // i f i n c o r r e c t password was entered 1206 i f ( debug ) { c o n s o l e. l o g ( Wrong password entered, a borting password change. ) ; } 1207 // n o t i f y user f a i l e d to e n t e r p r e v i o u s password and abort changing the password 1208 $ionicpopup. a l e r t ( { 1209 t i t l e : $scope. l a n g. password p r e v i o u s e r r o r, 1210 t e m p l a t e : $scope. l a n g. password p r e v i o u s e r r o r h i n t 1211 } ) ; 1212 } 1213 } ) ; 1214 } ; Listing 2.55: controllers.js: pop-ups bij een fout tijdens het veranderen van paswoord

55 HOOFDSTUK 2. BESPREKING 49 Taalkeuze In dit verband hebben we een instructie gebruikt die op het event $translatechangeend reageert, dat vanuit de ngtranslate -library op $rootscope -niveau wordt verzonden. Dit niveau strekt zich over alle controllers, en is dus zoals $scope niet beperkt tot één controller // l i s t e n to changes o f s e l e c t e d language 1147 $rootscope. $on ( $translatechangeend, function ( event, a r g s ) { 1148 i f ( debug ) { c o n s o l e. l o g ( New language s e l e c t e d : + a r g s. l anguage ) ; } 1149 Language. g e t T r a n s l a t i o n s ( a r g s. language ). then ( function ( data ) { 1150 $scope. l a n g = data. data ; 1151 } ) ; 1152 } ) ; Listing 2.56: controllers.js: taal veranderen bij nieuwe keuze in de settings Vervolgens wordt de taal opnieuw geladen dankzij de functie gettranslations uit de Language - factory. Ordertypes In de settings kan de gebruiker ook ordertypes toevoegen of verwijderen. Na de functie die de lijst van ordertypes kan tonen of verbergen, hebben we functies geschreven die het verwijderen of het toevoegen ervan behandelen. Om een type te verwijderen ontvangt de controller de index van het aangeklikte item dat moet worden verwijderd. Vervolgens wordt deze index met javascript functie splice gebruikt om het type uit de lijst te halen // D e l e t i n g a type from the tasktypes - l i s t $scope. d e l e t e T y p e = function ( i n d e x ) { 1224 i f ( debug ) { c o n s o l e. l o g ( D e l e t i n g item : + $scope. s e t t i n g s. t a s k t y p e s [ i n d e x ] ) ; } 1225 // Delete from array o f t a s k t y p e s $scope. s e t t i n g s. t a s k t y p e s. s p l i c e ( index, 1) ; 1227 } ; Listing 2.57: controllers.js: ordertype uit de lijst verwijderen Om een type toe te voegen aan de lijst moet de gebruiker, eveneens met behulp van een pop-up, de waarde van een nieuw type invullen. Alvorens het type effectief wordt toegevoegd, wordt er nagegaan of het type al wel of niet in de lijst bestaat. Bij een match wordt dit via een pop-up aan de gebruiker gemeld // Add a new type to tasktypes - l i s t 1230 $scope. addtype = function ( ) { 1231 // prompt f o r user input f o r new type 1232 $ionicpopup. prompt ( { 1233 t i t l e : $scope. l a n g. t a s k t y p e new, 1234 t e m p l a t e : $scope. l a n g. t a s k t y p e new h i n t, 1235 inputtype : t e x t,

56 HOOFDSTUK 2. BESPREKING i n p u t P l a c e h o l d e r : } ). then ( function (new type ) { 1238 // i f something i s entered in the input box 1239 i f (new type!= && new type!= n u l l ) { 1240 var a l r e a d y e x i s t s = f a l s e ; 1241 // check i f i t al ready e x i s t s 1242 f o r ( var j = 0 ; j < $scope. s e t t i n g s. t a s k t y p e s. l e n g t h ; j ++){ 1243 i f ( $scope. s e t t i n g s. t a s k t y p e s [ j ] == new type ) { 1244 // i f i t does, n o t i f y user and change the already e x i s t s - v a r i a b l e to true 1245 a l r e a d y e x i s t s = true ; 1246 i f ( debug ) { 1247 c o n s o l e. l o g ( Tasktype + new type + already e x i s t s. ) ; 1248 c o n s o l e. l o g ( Adding t h i s to the l i s t c a n c e l l e d. ) ; } 1249 break ; 1250 } 1251 } Listing 2.58: controllers.js: ordertype aan de lijst toevoegen Indien het nieuwe type nog niet bestaat wordt het aan de lijst toegevoegd i f ( a l r e a d y e x i s t s === f a l s e ) { 1253 // i f i t s a new type we push i t to the array 1254 i f ( debug ) { c o n s o l e. l o g ( Adding new type + new type ) ; } 1255 $scope. s e t t i n g s. t a s k t y p e s. push (new type ) ; // push new type to the array 1256 } 1257 } e l s e { 1258 i f ( debug ) { c o n s o l e. l o g ( Adding new type c a n c e l l e d. ) ; } 1259 } 1260 } ) ; 1261 } ; Listing 2.59: controllers.js: effectief toevoegen indien het type nog niet bestaat Het toevoegen of verwijderen van een type is zichtbaar in de HTML, maar moet dan nog worden opgeslagen in de locker -variabelen. Vermits we in de HTML niet met Angular JS directive ngmodel maar met ng-repeat hebben gebind, hebben we dit manueel in code moeten definiëren. Dit manueel updaten wordt gerealiseerd door de hele lijst in een watch te laten opvolgen. Op het moment dat er zich een wijziging voordoet in de lijst van ordertypes, wordt de hele lijst uit de relevante locker -variabele verwijderd en door de nieuwe lijst vervangen // Watch the t a s k t y p e s change in the HTML- template to update manually to the l o c k e r..

57 HOOFDSTUK 2. BESPREKING $scope. $watch ( [ $scope, function ( $scope ) { 1265 return $scope. s e t t i n g s. t a s k t y p e s ; 1266 } ], function (new t a s k t y p e s ) { 1267 //.. because they are not binded with ng - model, so we update i t manually by p u l l i n g l o c k e r. p u l l ( s e t t i n g s. t a s k t y p e s ) ; 1269 //.. and by re - pushing the array we r e c e i v e from watching the scope l o c k e r. put ( s e t t i n g s. t a s k t y p e s, new t a s k t y p e s ) ; 1271 // r e s i z e the s c r o l l i n g area on the page $ i o n i c S c r o l l D e l e g a t e. r e s i z e ( ) ; i f ( debug ) { c o n s o l e. l o g ( New array o f t a s k t y p e s : + l o c k e r. get ( s e t t i n g s. t a s k t y p e s ) ) ; } 1275 }, true ) ; Listing 2.60: controllers.js: ordertypes toevoegen of verwijderen in de locker Console.log messages Uiteindelijk hebben we dan nog twee watches geschreven die een message naar de console.log sturen. Een eerste wanneer de gebruiker de attachment limiet veranderd, een tweede wanneer de orderlijn-delimiter wordt veranderd Services en Factories Met services en factories kunnen vaak voorkomende functies in één algemene functie worden gebundeld. Indien nodig ontvangen en versturen deze algemene functies data van of naar de controller die hen aanroept. Dit bespaart code en vergemakkelijkt daarbij de flow/structuur van de logica in de code. We hebben verschillende factories gebruikt zodat er bijvoorbeeld gemakkelijk exif-data uit een foto kunnen worden gehaald, objecten van foto s en notities kunnen worden aangemaakt, namen van bestanden kunnen worden bewerkt, de grootte van bestanden kan worden berekend, automatisch naar HTML elementen kan worden gescrolled, taalbestanden kunnen worden geladen en een serie checks voor het versturen van mails kunnen worden uitgevoerd. Services, factories en providers kunnen gebruik maken van een Angular JS service $q. $q is een constructor die bepaalde functies heeft zoals defer(), resolve(), en reject(). Deze drie functies beïnvloeden de flow van de code: defer() gebruikt men om het $q object open te stellen voor gebruik, en is dus altijd nodig; resolve() wordt gebruikt wanneer er iets succesvol gelukt is. Het kan data aanvaarden en neemt deze op in een object. Deze data worden dan later aan de hand van dat object mee teruggestuurd naar de controller;

58 HOOFDSTUK 2. BESPREKING 52 reject() wordt gebruikt wanneer er iets niet succesvol is. Dit kan ook objecten aanvaarden, die dan mee naar de controller worden verstuurd. Om ten slotte aan te tonen dat de functie ten einde loopt en mag worden afgerond, wordt q.promise gebruikt. Meer bepaald schrijft men return q.promise. Afhankelijk van wat er vooraf in de code gebeurt zullen er error-data of success-data naar de controller worden verstuurd. Een extra voordeel van de $q constructor is dat deze asynchroon werkt. Terwijl een functie uit de service of factory bezig is loopt de code van de controller verder, dit tot de functie klaar is en iets meldt aan de controller. Aldus kan een applicatie sneller werken. Eigenlijk kan men dit voorstellen als volgt: in het perspectief van error-behandling betekenen defer, resolve en reject voor asynchrone code hetzelfde als wat try, catch en throw betekenen voor synchrone code exiffer getexif Exiffer is een factory waarin we een functie getexif hebben bepaald. De functie krijgt een bron van een foto uit de controller mee en gebruikt deze om met de exif -library de EXIF-data uit te lezen. In deze data bevindt zich informatie zoals het tijdstip waarop de foto is genomen, de afmetingen van de foto, de GPS-coördinaten en nog veel meer. 3 a n g u l a r. module ( WHS. s e r v i c e s, [ ] ) 4. f a c t o r y ( e x i f f e r, [ $q, $window, function ( $q, $window ) { 5 return { 6 g e t E x i f : function ( imgurl ) { 7 var q = $q. d e f e r ( ) ; 8 var f i l e s i z e ; 9 $window. r e s o l v e L o c a l F i l e S y s t e m U R L ( imgurl, function ( f i l e E n t r y ) { 10 // use FileReader to get binary data. 11 var r e a d e r = new F i l e R e a d e r ( ) ; // a f t e r the FileReader was loaded, get the EXIF from the binary data 14 r e a d e r. onload = function ( e v t ) { 15 var r e s u l t = e v t. t a r g e t. r e s u l t ; 16 var e x i f = EXIF. r e a d F r o m B i n a r y F i l e ( r e s u l t ) ; 17 // do something on the e x i f data 18 e x i f. f i l e s i z e = f i l e s i z e ; 19 c o n s o l e. l o g ( e x i f. f i l e s i z e + MB, taken on + e x i f. DateTime ) ; 20 q. r e s o l v e ( e x i f ) ;

59 HOOFDSTUK 2. BESPREKING } ; Listing 2.61: services.js: EXIF-data uitlezen in de getexif -functie van de exiffer factory Uiteindelijk gebruiken we alleen het tijdstip maar tijdens het uitlezen kunnen we ook wel de grootte van het bestand bepalen dankzij het JavaScript object FileReader. 22 // i f t h e r e s an e r r o r in reading the binary data 23 r e a d e r. o n e r r o r = function ( ) { 24 c o n s o l e. l o g ( Unexpected e r r o r in reading f i l e. ) ; 25 q. r e j e c t ( ) ; 26 } ; 27 // when e n t e r i n g the f i l e to read the data.. 28 f i l e E n t r y. f i l e ( function ( f i l e ) { 29 //.. get s i z e in k i l o b y t e s.. 30 r e a d e r. r e a d A s A r r a y B u f f e r ( f i l e ) ; 31 //.. c a l c u l a t e the s i z e in megabytes. 32 f i l e s i z e = f i l e. s i z e /1024/1024; 33 f i l e s i z e = f i l e s i z e. t o F i x e d ( 2 ) ; // round i t to two decimals. 34 c o n s o l e. l o g ( S i z e in bytes : + f i l e s i z e + MB ) ; 35 }, function ( ) { 36 c o n s o l e. l o g ( Unexpected e r r o r in reading f i l e. ) ; 37 q. r e j e c t ( ) ; 38 } ) ; 39 }, 40 function ( ) { 41 c o n s o l e. l o g ( Unexpected e r r o r in using $window. resolvelocalfilesystemurl. ) ; 42 q. r e j e c t ( ) ; 43 } ) ; 44 return q. promise ; 45 } 46 } ; 47 } ] ) Listing 2.62: services.js: errors opvangen en grootte van foto s bepalen in de getexif - functie Dit plaatsen we in een array met alle EXIF-data die naar de controller wordt teruggestuurd, door middel van q.resolve(exif) files createphoto Nadat de controller de EXIF-data van de exiffer -factory functie getexif terugkrijgt, worden die data verstuurd naar de functie createphoto van de files factory. Via de functie createphoto kan er een object van een foto worden aangemaakt, waarin de EXIF-data worden geplaatst.

60 HOOFDSTUK 2. BESPREKING f a c t o r y ( f i l e s, [ $q, $ cordovafile, function ( $q, $ c o r d o v a F i l e ) { 49 return { 50 c r e a t e P h o t o : function ( g i v e n id, imagesrc, e x i f d a t a ) { 51 var q = $q. d e f e r ( ) ; 52 // i f we r e c e i v e d a l l n e c e s s a r y data.. 53 i f ( g i v e n i d!== n u l l && imagesrc!== n u l l && e x i f d a t a!== n u l l ) { 54 //.. put the data in an o b j e c t. 55 var photo o b j e c t = { 56 i d : g i v e n id, 57 t i t l e : e x i f d a t a. DateTime, 58 s r c : imagesrc, 59 s i z e : e x i f d a t a. f i l e s i z e, 60 checked : true, // check the o b j e c t to send with the mail 61 s e n t : f a l s e // the o b j e c t has not yet been sent 62 } ; 63 q. r e s o l v e ( photo o b j e c t ) ; 64 } e l s e { 65 c o n s o l e. l o g ( No v a l i d parameters passed : given id = + g i v e n i d + imagesrc = + imagesrc + e x i f d a t a = + e x i f d a t a ) ; 66 q. r e j e c t ( ) ; 67 } 68 return q. promise ; 69 }, Listing 2.63: services.js: de createphoto -functie in de files factory dat objecten van foto s kan maken Indien de functie alle benodigde data krijgt worden de verkregen data samen met nog nieuwe extra variabelen id, checked en sent in het foto-object opgenomen. Indien er niet voldoende data in de functie beschikbaar zijn, wordt met q.reject() de controller op de hoogte gesteld dat er zich een error voordoet. createnote De tweede factory-functie van files is createnote. In eerste instantie hebben we de functie makenote die een.txt-bestand voor notities en een notities-object kan aanmaken verklaard, dit voor later gebruik. 70 c r e a t e N o t e : function ( notes, debug ) { 71 var q = $q. d e f e r ( ) ; 72 function makenote ( ) { 73 $ c o r d o v a F i l e. c r e a t e F i l e ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y, cache, true ) ; 74 $ c o r d o v a F i l e. w r i t e F i l e ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y,, notes, true ) 75. then ( function ( ) { cache / notes. txt

61 HOOFDSTUK 2. BESPREKING // s u c c e s s 77 i f ( debug ) { c o n s o l e. l o g ( Created f i l e with notes. ) ; } 78 var note o b j e c t = { 79 s r c : cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y + cache / notes. txt, 80 checked : true, 81 s e n t : f a l s e 82 } ; 83 q. r e s o l v e ( note o b j e c t ) ; 84 }, function ( e r r o r ) { 85 // e r r o r 86 i f ( debug ) { c o n s o l e. l o g ( Could not c r e a t e f i l e with notes. -> + JSON. s t r i n g i f y ( e r r o r ) ) ; } 87 q. r e j e c t ( ) ; 88 } ) ; 89 } Listing 2.64: services.js:.txt-bestand en notities-object aanmaken in de createnotes - functie van de files factory In createnote wordt immers nagekeken of er al dan niet notities zijn aangekomen, alsook of er een cache folder aanwezig is waarin bestanden kunnen worden aangemaakt. Dan wordt makenote opgeroepen. 91 i f ( n o t e s!== n u l l ) { 92 i f ( debug ) { c o n s o l e. l o g ( Notes r e c e i v e d in s e r v i c e, c r e a t i o n t e x t f i l e in cache d i r e c t o r y. ) ; } 93 $ c o r d o v a F i l e. c h e c k D i r ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y, cache ) 94. then ( function ( ) { 95 // Found a cache f o l d e r to s t o r e the n o t e f i l e in. 96 i f ( debug ) { c o n s o l e. l o g ( Cache f o l d e r found. ) ; } 97 // Make a n o t e f i l e, with the content from text - pad from the view. 98 makenote ( ) ; 99 }, function ( e r r o r ) { Listing 2.65: services.js: nagaan of er notities aanwezig zijn en of de cache folder beschikbaar is Indien blijkt dat er geen cache folder bestaat, dan zal er een cache folder worden aangemaakt door volgende functie, zodat uiteindelijk ook de functie makenote kan worden opgeroepen. 99 }, function ( e r r o r ) { 100 // Did not f i n d a cache f o l d e r, so we make one. 101 i f ( debug ) { c o n s o l e. l o g ( Could not f i n d cache. + JSON. s t r i n g i f y ( e r r o r ) ) ; 102 c o n s o l e. l o g ( Attempting to c r e a t e cache f o l d e r ) ; }

62 HOOFDSTUK 2. BESPREKING $ c o r d o v a F i l e. c r e a t e D i r ( cordova. f i l e. e x t e r n a l A p p l i c a t i o n S t o r a g e D i r e c t o r y, cache, f a l s e ) 104. then ( function ( ) { 105 // S u c c e s f u l l y c r e a t e d a cache f o l d e r. 106 i f ( debug ) { c o n s o l e. l o g ( Cache f o l d e r c r e a t e d. ) ; } 107 // Make a n o t e f i l e, with the content from text - pad from the view. 108 makenote ( ) ; 109 }, function ( e r r o r ) { 110 // Could not make a cache f o l d e r, r e p o r t to l o g and to user. 111 i f ( debug ) { c o n s o l e. l o g ( Could not make cache f o l d e r. + JSON. s t r i n g i f y ( e r r o r ) ) ; } 112 q. r e j e c t ( ) ; 113 } ) ; 114 } ) ; 115 } 116 e l s e { 117 i f ( debug ) { c o n s o l e. l o g ( No notes r e c e i v e d in s e r v i c e. ) ; } 118 q. r e s o l v e ( n u l l ) ; 119 } 120 return q. promise ; 121 } Listing 2.66: services.js: indien er geen cache folder aanwezig is dan wordt die in de createnote -functie aangemaakt Scroll Om automatisch naar HTML elementen te scrollen hebben we de twee factory-functies To en Toggle geschreven. Het verschil tussen deze twee blijkt miniem maar toch relevant: Toggle kon ook lijsten openen of sluiten, waar To alleen maar kan scrollen. To To hebben we gebruikt om de gebruiker naar de input van het ordernummer te brengen. Indien het ordernummer tijdens de checkmailrequirements -functie nog niet aanwezig zou zijn, dan wordt er een bepaalde pop-up opgeroepen met daarop een Vul nu in -knop. Indien de gebruiker hierop duwt, wordt deze To functie geactiveerd f a c t o r y ( S c r o l l, [ $q, $ i o n i c S c r o l l D e l e g a t e, $timeout, function ( $q, $ i o n i c S c r o l l D e l e g a t e, $timeout ) { 125 return { 126 To : function ( element, o f f s e t ) { 127 var q = $q. d e f e r ( ) ;

63 HOOFDSTUK 2. BESPREKING // i f parameters are v a l i d i f ( element!== n u l l && o f f s e t!== n u l l ) { 130 //.. get the p o s i t i o n to s c r o l l to : 131 var d i f f = document. getelementbyid ( element ). g e t B o u n d i n g C l i e n t R e c t ( ). top $ i o n i c S c r o l l D e l e g a t e. g e t S c r o l l P o s i t i o n ( ). top + o f f s e t ; 133 c o n s o l e. l o g ( S c r o l l i n g to + element + at y - p o s i t i o n : + d i f f ) ; 134 $ i o n i c S c r o l l D e l e g a t e. r e s i z e ( ) ; //.. re - d e f i n e the s c r o l l i n g - area. 135 $ i o n i c S c r o l l D e l e g a t e. s c r o l l T o ( 0, d i f f, true ) ; // and s c r o l l to the element 136 } e l s e { // i f parameters are not v a l i d 137 c o n s o l e. l o g ( No v a l i d parameters passed : element = + element + o f f s e t = + o f f s e t ) ; 138 q. r e j e c t ( ) ; 139 } 140 return q. promise ; 141 }, Listing 2.67: services.js: de To -functie uit de Scroll factory om naar een element te scrollen Door we de Ionic delegate $ionicscrolldelegate gebruikt hebben kan er, na het bepalen van de verticale positie van het element, effectief worden gescrolled. Toggle De functie Toggle van factory Scroll hebben we geschreven om lijsten te kunnen openen of te kunnen sluiten, en indien ze worden geopend er naar te scrollen. Bijvoorbeeld bij het openen van een fotolijst op een DMG-pagina. Of de lijst van de ordertypes op de settings -pagina. 142 Toggle : function ( isshown, element, o f f s e t ) { 143 var q = $q. d e f e r ( ) ; 144 // prepare v a r i a b l e to pass back 145 var show r e s u l t ; 146 i f ( isshown!== n u l l && element!== n u l l && o f f s e t!== n u l l ) { 147 // i f l i s t i s shown we hide i t : 148 i f ( isshown ) { 149 show r e s u l t = f a l s e ; 150 c o n s o l e. l o g ( Hiding + element ) ; 151 $timeout ( function ( ) { $ i o n i c S c r o l l D e l e g a t e. r e s i z e ( ) ; } ) ; 152 } e l s e { // i f l i s t i s hidden we show and s c r o l l to i t 153 show r e s u l t = true ; 154 c o n s o l e. l o g ( Showing and s c r o l l i n g to + element ) ; 155 t h i s. To( element, o f f s e t ) ; // s c r o l l to i t 156 } 157 // pass back r e s u l t to c o n t r o l l e r 158 q. r e s o l v e ( show r e s u l t ) ;

64 HOOFDSTUK 2. BESPREKING } e l s e { // i f parameters are i n v a l i d 160 c o n s o l e. l o g ( No v a l i d parameters passed : isshown = + isshown element = + element + o f f s e t = + o f f s e t ) ; 162 q. r e j e c t ( ) ; 163 } 164 return q. promise ; 165 } 166 } ; Listing 2.68: services.js: de Toggle -functie om een lijst te openen of te sluiten en vervolgens naar te scrollen attachments Om de namen van de bestanden die als attachments gekozen zijn te veranderen, of om de grootte ervan te berekenen, hebben we in deze factory de twee functies getsizeofattachments en formatfilenames geschreven. getsizeofattachments Deze functie wordt aangeroepen in een watch die de lijst van foto s opvolgt. Dankzij het kenmerk size, dat we met de factory-functie createphoto met data uit de factory-functie getexif hebben toegevoegd, kan een som worden gemaakt om de totale grootte te bepalen en terug te sturen naar de controller f a c t o r y ( attachments, [ $q, $ cordovafile, function ( $q, $ c o r d o v a F i l e ) { 169 return { 170 // c a l c u l a t e t o t a l s i z e o f s e l e c t e d attachments 171 g e t S i z e O f A t t a c h m e n t s : function ( i t e m s ) { 172 var q = $q. d e f e r ( ) ; 173 // prepare v a r i a b l e to send back to c o n t r o l l e r 174 var som = 0 ; 175 // i t e r a t e over each photo and add the s i z e when i t s checked a s an attachment 176 f o r ( var i = 0 ; i < i t e m s. l e n g t h ; i ++){ 177 i f ( i t e m s [ i ]. checked === true ) { 178 c o n s o l e. l o g ( S e l e c t e d item s i z e = + i t e m s [ i ]. s i z e ) ; 179 som = p a r s e F l o a t ( som ) + p a r s e F l o a t ( i t e m s [ i ]. s i z e ) ; 180 c o n t i n u e ; 181 } 182 } 183 c o n s o l e. l o g ( Total s i z e o f a l l attachments = + som ) ; 184 q. r e s o l v e ( som ) ;

65 HOOFDSTUK 2. BESPREKING return q. promise ; 186 }, Listing 2.69: services.js: getsizeofattachments -functie uit de attachments factory om de totale grootte van bestanden te berekenen formatfilenames formatfilenames wordt aangeroepen wanneer de gebruiker de verzamelde data wilt versturen via mail. De bestandsnamen van de gekozen foto s en/of notities worden aangepast zodat de ontvanger deze bestanden juist kan interpreteren. Die bestandsnamen hebben we overigens volgens afspraken binnen het bedrijf bepaald. Afhankelijk vanuit welke controller deze factory-functie wordt aangeroepen zullen er extra data, meer bepaald de orderdata, nodig zijn. In het geval van de DMG-OPS -controller worden deze data gebruikt om mee in de nieuwe naam van bestanden te plaatsen. 187 formatfilenames : function ( f i l e s, ops, tasknumber, t a s k t y p e ) { 188 /* i f ops i s true then i t means that the f u n c t i o n was c a l l e d from the ops - page and 189 that the f u n c t i o n needs extra code and data. */ 190 var q = $q. d e f e r ( ) ; 191 // prepare array which w i l l be sent back to the c o n t r o l l e r 192 var new attachments = [ ] ; 193 // loop over every item to v a l i d a t e i f i t s marked as attachment 194 f i l e s. f o r E a c h ( function ( item ) { 195 i f ( item. checked ) { 196 // change value to true so that view w i l l be updated with a sent - tag at t h i s item. 197 item. s e n t = true ; 198 // r e s e t checked value to f a l s e, as i t i s being sent now and probably won t be sent again. 199 item. checked = f a l s e ; 200 // t e m p o r a r i l y save the path o f the f i l e 201 var f i l e path = item. s r c. s l i c e ( 0, item. s r c. l a s t I n d e x O f ( / ) +1 ) ; 202 // t e m p o r a r i l y save the name o f the f i l e 203 var f i l e name = item. s r c. s l i c e ( item. s r c. l a s t I n d e x O f ( / ) + 1) ; 204 // prepare new name 205 var new name = ; 206 /* i f f u n c t i o n was c a l l e d in ops page, then make a new name i n c l u d i n g 207 the date, the tasktype, the tasknumber and an unique i d e n t i f i e r */ 208 i f ( ops ) { 209 new name = new Date ( ). tojson ( ). s l i c e ( 0, 10) + + t a s k t y p e + tasknumber + + f i l e name ; } 210 e l s e { // i f not, then make a new name i n c l u d i n g only the date and an unique i d e n t i f i e r

66 HOOFDSTUK 2. BESPREKING new name = new Date ( ). tojson ( ). s l i c e ( 0, 10) + + f i l e name ; } Listing 2.70: services.js: formatfilesnames -functie om bestanden een bepaalde naam te geven alvorens in een mail te versturen Om bestanden na de naamverandering als attachment in een mail te kunnen gebruiken, wordt het bestand ook effectief in de cache aangemaakt. Dit is omdat Android strikte veiligheidsregels hanteert voor applicaties. Zo mogen bijvoorbeeld bestanden op het geheugen van de smartphone niet zomaar worden gemanipuleerd, wat overigens tot andere problemen leidt. Zie appendix C voor correspondentie waarin meer info wordt besproken. 212 // rename the whole f i l e by moving i t to i t s new name. 213 $ c o r d o v a F i l e. movefile ( f i l e path, f i l e name, f i l e path, new name ) ; 214 /* m o v e f i l e only works when the f i l e i s l o c a t e d in the app s l o c a l d i r e c t o r y, f o r example notes. 215 When i t s not, f o r example with p i c t u r e s taken by the camera, they l l only be temporarely moved, 216 and a f t e r w a r d s s t i l l l o c a t e d on t h e i r o r i g i n a l l o c a t i o n. This i s because o f s e c u r i t y p o l i c y in Android. 217 Though t h i s i s n t p r a c t i c a l, i t s not a problem. */ 218 // f i n a l y, add the source to the new l i s t o f attachments 219 new attachments. push ( f i l e path + new name ) ; 220 } 221 } ) ; 222 // r eturn the attachments to the c o n t r o l l e r. 223 q. r e s o l v e (new attachments ) ; 224 return q. promise ; 225 } Listing 2.71: services.js: bestanden met nieuwe naam in cache plaatsen Language In de factory Language hebben we een functie gettranslations geschreven om vertalingen op te halen uit de respectievelijke taalbestanden. Deze taalbestanden bevatten JSON data die we in de controller aan een $scope variabele hebben gebonden. gettranslations De factory-functie neemt een variabele aan waarin de benodigde taal staat verklaard. Indien deze variabele geen benodigde taal zou hebben verklaard, bijvoorbeeld bij een eerste opstart van WareHouseSnaps, wordt aan de hand van functies uit de ngtranslate -library een zo goed mogelijke keuze gemaakt.

67 HOOFDSTUK 2. BESPREKING f a c t o r y ( Language, [ $q, $http, $ t r a n s l a t e, function ( $q, $http, $ t r a n s l a t e ) { 231 return { 232 g e t T r a n s l a t i o n s : function ( language ) { 233 var q = $q. d e f e r ( ) ; 234 // get c u r r e n t language 235 var a c t i v e L a n g u a g e = language ; 236 // i f c u r r e n t language i s not a v a i l a b l e because i t s not d e f i n e d in the s e t t i n g s - page 237 i f ( l a nguage === u n d e f i n e d ) { 238 c o n s o l e. l o g ( Undefined language so load p r e f e r r e d language. ) ; 239 // use the p r e f e r r e d language from the c o n f i g in app. j s 240 a c t i v e L a n g u a g e = $ t r a n s l a t e. use ( ) $ t r a n s l a t e. s t o r a g e ( ). get ( $ t r a n s l a t e. s t o r a g e K e y ( ) ) $ t r a n s l a t e. p r e f e r r e d L a n g u a g e ( ) ; 241 } 242 c o n s o l e. l o g ( Used language i s + a c t i v e L a n g u a g e ) ; Listing 2.72: services.js: gekozen taal bepalen in de gettranslations -functie van de Language factory Finaal worden de data effectief uit het geselecteerde taalbestand gehaald met een functie uit de Angular injector $http. Deze data worden dan terug gestuurd naar de controller. 241 // get the data f o r t h i s language from the language - f i l e 242 $ http. get ( j s / languages / + a c t i v e L a n g u a g e +. j s o n ). then ( function ( data ) { 243 q. r e s o l v e ( data ) ; 244 c o n s o l e. l o g ( Language - pack r e c e i v e d. ) ; 245 } ) ; 246 return q. promise ; 247 } 248 } ; 249 } ] ) Listing 2.73: services.js: met behulp van een $http functie de JSON-data uit de taalbestanden halen mail Met betrekking tot het mailen in WareHouseSnaps hebben we meerdere checks voorzien zodat een gebruiker tijdig wordt gewaarschuwd, bv. als de attachment-limiet wordt overschreden of wanneer er niet genoeg data worden verzameld. In de functie checkrequirements worden alle voorwaarden overlopen. Ofwel wordt dan groen licht gegeven aan de controller, ofwel wordt een pop-up met een relevante boodschap aan de gebruiker getoond.

68 HOOFDSTUK 2. BESPREKING 62 checkrequirements Afhankelijk van de controller waaruit deze functie wordt opgeroepen, moeten er meer of minder data naar deze factory-functie worden verstuurd. Meer bepaald worden er orderdata verwacht wanneer de functie in de DMG-OPS -pagina wordt opgeroepen. Indien de functie niet uit de DMG-OPS -pagina wordt opgeroepen, laten we de orderdata-variabelen tijdelijk valse waardes aannemen. 252 checkrequirements : function ( languagedata, 253 notes, 254 attachments s i z e, 255 attachment s e t t i n g, 256 debug, 257 ops, 258 tasknumber, 259 t a s k t y p e, 260 scanbarcode ) { 261 var q = $q. d e f e r ( ) ; 262 v ar popup ; 263 var l a n g = l a n g u a g e d a t a ; 264 /* i f t h i s f u n c t i o n i s NOT c a l l e d from the OPS page, 265 we l l put in some dummy value s to pass along in the checks. 266 They won t be used a f t e r w a r d s or f o r o p e r a t i o n s on content. */ 267 i f (! ops ) { 268 tasknumber = dummy ; 269 t a s k t y p e = dummy ; 270 } Listing 2.74: services.js: data ontvangen in de checkrequirements -functie van de factory mail Vervolgens voert de checkrequirements -functie een volledige verificatie van alle voorwaarden uit. Indien voldaan blijkt aan alle voorwaarden wordt aan de controller onmiddellijk groen licht gegeven. Bij problemen wordt er dan systematisch van de belangrijkste naar de minst belangrijke voorwaarde individueel gekeken. In rangorde: of er notities of foto s zijn meegegeven > of er een ordernummer aanwezig is > of er een ordertype aanwezig is > of de attachment-limiet niet overschreden is. De controller krijgt dan een pop-up object toegestuurd dat aan de gebruiker een relevante boodschap toont. Daarop kan de gebruiker reageren en aan het probleem remediëren Libraries Libraries zijn een verzameling van vaak voorkomende functies die in een applicatie kunnen worden aangeroepen. Libraries worden zo goed als altijd voor een bepaald doel geschreven, bijvoorbeeld om EXIF-data uit een foto-object te halen. Aldus kunnen ze de developer tijd en werk besparen.

69 HOOFDSTUK 2. BESPREKING Exif.js Om gemakkelijk aan de EXIF-data van foto s te geraken hebben we deze library toegevoegd. Copyright (c) 2008 Jacob Seidelin The MIT License (MIT) locker Een library om variabelen op te slaan in local en session storage. Copyright (c) 2014 Sean Tymon The MIT License (MIT) ngcordova Een library van Angular JS wrappers van Cordova en PhoneGap plugins die bepaalde functionaliteit van een Android smartphone kunnen voorzien. Om deze library te gebruiken moet men allereerst de library aan het project toevoegen, deze injecteren in de module van de applicatie waarin men plugins wilt gebruiken en ten slotte met de cordova command-line interface de plugin aan de applicatie toevoegen. Copyright (c) 2014 Drifty The MIT License (MIT) ngtranslate Om de applicatie met Angular JS van meerdere talen te voorzien hebben we de ngtranslate library gebruikt. Copyright (c) 2014 pascal.precht@gmail.com The MIT License (MIT) Ionic Bij het opstarten van een Ionic project wordt er automatisch de Ionic library toegevoegd. Hierin zit alle functionaliteit van alle componenten verwerkt. Copyright 2014 Drifty Co. The MIT License (MIT) ngcordova plugins $cordovabarcodescanner De Barcode Scanner Plugin opent de camera en scant automatisch een barcode. wordt de data beschikbaar gesteld. Achteraf

70 HOOFDSTUK 2. BESPREKING $cordovacamera Met de camera plugin kan men foto s en video s nemen. Met behulp van de opties kan men het nemen ervan manipuleren. Bijvoorbeeld om de extensie, de kwaliteit, de bron en dergelijke te veranderen $cordova composer Deze plugin biedt toegang tot een native mail-applicatie, zoals Gmail of Exchange, die het bewerken en verzenden van een bericht beheert. Men kan deze plugin gebruiken om een in de applicatie op voorhand op te maken, door mail-eigenschappen zoals het onderwerp, ontvangers, body-tekst en bijlagen in te vullen. Maar de gebruiker krijgt nog altijd de kans om deze te bewerken alvorens te kiezen om de te versturen of te annuleren. De plugin is geen garantie dat de mail wordt verzonden. Indien er geen internetverbinding is wordt de mail in de outbox geplaatst en verzonden vanaf er wel een verbinding is. Er is ook geen mogelijkheid om na te gaan of de mail verzonden of geannuleerd is, al geeft een native mail-applicatie push notifications $cordovafile Via deze plugin kan men toegang te krijgen tot folders en bestanden op een smartphone. De plugin wordt bijvoorbeeld gebruikt om bestanden te herbenoemen, bestanden in de cache te plaatsen of bij het opstarten de cache van een applicatie leeg te maken.

71 Hoofdstuk3 Resultaten Als groot en gereputeerd bedrijf in de logistieke sector beschikt de Molenbergnatie, behorende tot de Ilomar Holding N.V., wereldwijd over een opslagcapaciteit van ruim m². Onvermijdelijk doen zich hier schadegevallen voor, al of niet ten gevolge van logistieke handelingen. Deze schadegevallen moeten uiteraard worden gerapporteerd en opgevolgd. Tot hiertoe worden data manueel vergaard en tot bij de dossierbeheerders gebracht, hetzij via persoonlijk gerichte mails, hetzij via het persoonlijk overhandigen van digitale opslagmedia zoals USB-sticks. Gezocht wordt naar een uniforme, geïnformatiseerde en gebruiksvriendelijke manier om waar ook ter wereld alles om alle schade te kunnen laten registreren. Daarbij werd gedacht aan een applicatie voor smartphones. Het project is uitgemond in de ontwikkeling van WareHouseSnaps, een applicatie voor Android smartphones. Medewerkers, waar ze zich ook op het terrein bevinden, zullen dankzij WareHouseSnaps incidenten kunnen melden, zowel bij schade in het kader van een logistieke handeling (DMG- OPS) als voor schade aan gebouwen/garages/e.a. Dit houdt in: Ordernummers in barcodes scannen of intikken (alleen voor DMG-OPS); Foto s nemen; Notities invullen; Bundelen en doorsturen via mail. Aldus zullen de gegevens van allerlei schadegevallen volledig digitaal kunnen worden geregistreerd en beheerd. Ongetwijfeld zal dit resulteren in een gevoelige besparing van tijd en kosten, zowel bij de medewerkers op het terrein als bij de dossierbeheerders, alsook leiden tot een kwaliteitsverbetering van bedrijfsprocessen. 65

72 HOOFDSTUK 3. RESULTATEN 66 De kostenbesparing is besproken tijdens de meetings maar wordt om redenen van confidentialiteit hier niet gepubliceerd. De kwaliteitsverbetering in de processen is voor het management duidelijk: bv. foto s worden direct gesaved op de juiste plaats, de betrokken personen (dossierbeheerders) worden direct op de hoogte gebracht, de communicatieflow verbetert omdat de informatie niet meer via tussenpersonen (de terminal managers) verloopt. Begin juni 2015 heeft het bedrijf een eerste formele test uitgevoerd op enkele smartphones. De eerste respons is alvast positief, en bugs zijn uitgebleven Het werkt goed en de mensen vinden het ook ok! (mail ontvangen van de heer N. Hoet op 5 juni 2015). Concreet zal op korte termijn WareHouseSnaps gedurende twee à drie maanden uitvoerig worden getest door een tiental medewerkers in Antwerpen. Voor Molenbergnatie is het de eerste mobiele app die naar de terminals gaat. Bijgevolg moet voorafgaand worden geïnvesteerd in hardware voor de magazijniers/terminal managers (voorzien binnen 12 maanden). Het aantal gebruikers per terminal is bepaald en gekend, en voorzien is dat alle dossierbeheerders toegang krijgen. Op middellange/ lange termijn wordt niet alleen gedacht aan het uitrollen van WareHouseSnaps in Antwerpen, maar tevens in de Spaanse vestigingen. In die optiek hebben we dan ook aan het management voorgesteld om WareHouseSnaps ineens als een multi-language applicatie te ontwikkelen. Die multi-language faciliteit hebben we met resultaat kunnen implementeren. Zelf zien we nog mogelijkheden om aan WareHouseSnaps functionaliteit toe te voegen. Specifiek denken we dan o.a. aan het opnemen van de GPS locatie, het voorzien in een timer-functie die de facturatie vergemakkelijkt, statistieken van schadegevallen en push notifications en/of een afzonderlijke, overzichtelijke pagina voor beheerders.

73 HOOFDSTUK 3. RESULTATEN 67 (a) Het menu van WareHouseSnaps. (b) De pagina DMG-OPS in actie. (c) De pagina DMG-WH. (d) Screenshot van de pagina DMG-GRG.

74 HOOFDSTUK 3. RESULTATEN 68 (e) Screenshot van de pagina VARIA. (f) Screenshot van de pagina Settings. Figuur 3.1: Screenshots van de applicatie WareHouseSnaps

Priva Blue ID Network scanner / Syslog Tool

Priva Blue ID Network scanner / Syslog Tool Priva Blue ID Network scanner / Syslog Tool Versie 1.3.15.0 Bladzijde 1 Inhoudsopgave Inhoudsopgave... 2 Introductie:... 3 Systeemeisen:... 4 Installeren op een SX100:... 5 De Werking:... 6 Scannen van

Nadere informatie

Shipment Centre EU Quick Print Client handleiding [NL]

Shipment Centre EU Quick Print Client handleiding [NL] Shipment Centre EU Quick Print Client handleiding [NL] Please scroll down for English. Met de Quick Print Client kunt u printers in Shipment Centre EU configureren. De Quick Print Client kan alleen op

Nadere informatie

MyDHL+ ProView activeren in MyDHL+

MyDHL+ ProView activeren in MyDHL+ MyDHL+ ProView activeren in MyDHL+ ProView activeren in MyDHL+ In MyDHL+ is het mogelijk om van uw zendingen, die op uw accountnummer zijn aangemaakt, de status te zien. Daarnaast is het ook mogelijk om

Nadere informatie

Leeftijdcheck (NL) Age Check (EN)

Leeftijdcheck (NL) Age Check (EN) Leeftijdcheck (NL) Age Check (EN) [Type text] NL: Verkoopt u producten die niet aan jonge bezoekers verkocht mogen worden of heeft uw webwinkel andere (wettige) toelatingscriteria? De Webshophelpers.nl

Nadere informatie

MyDHL+ Van Non-Corporate naar Corporate

MyDHL+ Van Non-Corporate naar Corporate MyDHL+ Van Non-Corporate naar Corporate Van Non-Corporate naar Corporate In MyDHL+ is het mogelijk om meerdere gebruikers aan uw set-up toe te voegen. Wanneer er bijvoorbeeld meerdere collega s van dezelfde

Nadere informatie

Firewall van de Speedtouch 789wl volledig uitschakelen?

Firewall van de Speedtouch 789wl volledig uitschakelen? Firewall van de Speedtouch 789wl volledig uitschakelen? De firewall van de Speedtouch 789 (wl) kan niet volledig uitgeschakeld worden via de Web interface: De firewall blijft namelijk op stateful staan

Nadere informatie

2019 SUNEXCHANGE USER GUIDE LAST UPDATED

2019 SUNEXCHANGE USER GUIDE LAST UPDATED 2019 SUNEXCHANGE USER GUIDE LAST UPDATED 0 - -19 1 WELCOME TO SUNEX DISTRIBUTOR PORTAL This user manual will cover all the screens and functions of our site. MAIN SCREEN: Welcome message. 2 LOGIN SCREEN:

Nadere informatie

Handleiding helpdesk. Datum: 08-10-2014 Versie: 1.0 Auteur: Inge van Sark

Handleiding helpdesk. Datum: 08-10-2014 Versie: 1.0 Auteur: Inge van Sark Datum: 08-10-2014 Versie: 1.0 Auteur: Inge van Sark Inhoudsopgave Inhoudsopgave... 2 1. Beheer helpdesk... 3 1.1. Settings... 3 1.2. Applicaties... 4 1.3. Prioriteiten... 5 1.4. Gebruik mailtemplates...

Nadere informatie

Les 15 : updaten van gegevens in de database (deel2).

Les 15 : updaten van gegevens in de database (deel2). Les 15 : updaten van gegevens in de database (deel2). In de volgende reeks lessen zal alle vorige leerstof uitgebreid aan het bod komen. Zie ook de vorige lessen en documenten om informatie op te zoeken

Nadere informatie

Om het Elektronica thema te installeren gaat u naar "Theme Store" in Design. Hier kunt u het Elektronica thema in 4 kleurvarianten vinden.

Om het Elektronica thema te installeren gaat u naar Theme Store in Design. Hier kunt u het Elektronica thema in 4 kleurvarianten vinden. Inhoud: 1. Installatie 2. FAQ 3. Thema instellingen 4. Meer hulp nodig? 1.Installatie: Om het Elektronica thema te installeren gaat u naar "Theme Store" in Design. Hier kunt u het Elektronica thema in

Nadere informatie

Het beheren van mijn Tungsten Network Portal account NL 1 Manage my Tungsten Network Portal account EN 14

Het beheren van mijn Tungsten Network Portal account NL 1 Manage my Tungsten Network Portal account EN 14 QUICK GUIDE C Het beheren van mijn Tungsten Network Portal account NL 1 Manage my Tungsten Network Portal account EN 14 Version 0.9 (June 2014) Per May 2014 OB10 has changed its name to Tungsten Network

Nadere informatie

MyDHL+ Uw accountnummer(s) delen

MyDHL+ Uw accountnummer(s) delen MyDHL+ Uw accountnummer(s) delen met anderen Uw accountnummer(s) delen met anderen in MyDHL+ In MyDHL+ is het mogelijk om uw accountnummer(s) te delen met anderen om op uw accountnummer een zending te

Nadere informatie

HANDLEIDING DMS Plugin Installatie, configuratie & werking

HANDLEIDING DMS Plugin Installatie, configuratie & werking HANDLEIDING DMS Plugin Installatie, configuratie & werking Dit document is de handleiding voor de installatie, configuratie en werking van de DMS Plugin. Versie 1-12/09/2005 Inhoudstafel 1 Installatie...

Nadere informatie

Inhoud. Installatie. Functies

Inhoud. Installatie. Functies Inhoud Installatie Functies Instellingen Achtergrond Blokken, knoppen Korting Footer Header, left column Main navigation Modules Price categories, Producten Text Contact 3 4 5 5 6 7 8 9 10 11 12 13 14

Nadere informatie

Handleiding CMS Online Identity Webontwikkeling. Handleiding CMS

Handleiding CMS Online Identity Webontwikkeling. Handleiding CMS Handleiding CMS 1 Inhoudsopgave 1. Inloggen... 3 2. Het CMS... 3 3. Websitecontent... 4 3.1 Een nieuwe pagina toevoegen... 4 3.2 Een pagina wijzigen... 4 3.3 Een pagina verwijderen... 5 4. De WYSIWYG editor...

Nadere informatie

Handleiding RS Form! 1.0.4

Handleiding RS Form! 1.0.4 Handleiding RS Form! 1.0.4 Inhoud 1. Controlepaneel... 3 2. Forms Manager... 4 2.1 Nieuwe form aanmaken... 4 2.2 Nieuwe fields toevoegen... 7 2.3 Wijzigen/verwijderen bestaande Forms, Fields... 10 Versie

Nadere informatie

Veel gestelde vragen nieuwe webloginpagina

Veel gestelde vragen nieuwe webloginpagina Veel gestelde vragen nieuwe webloginpagina Op deze pagina treft u een aantal veel gestelde vragen aan over het opstarten van de nieuwe webloginpagina http://weblogin.tudelft.nl: 1. Ik krijg de melding

Nadere informatie

De Kleine WordPress Handleiding

De Kleine WordPress Handleiding Introductie Dit is geen uitgebreide handleiding om een WordPress website of blog mee te bouwen. Het is ook geen overzicht van alle aspecten die een WordPress website zo bijzonder maken en geen verhandeling

Nadere informatie

Toelichting release notes. 23 oktober 2014

Toelichting release notes. 23 oktober 2014 Toelichting release notes 23 oktober 2014 2 Toelichting release notes 23 oktober 2014 Inleiding release notes Deze week ontvangen jullie de release notes waarin onder meer twee nieuwe Paddlets, verschillende

Nadere informatie

2.ouderbeleid.3.plaatsingsprocedure werk admini Pagina 1 van 14

2.ouderbeleid.3.plaatsingsprocedure werk admini Pagina 1 van 14 2.ouderbeleid.3.plaatsingsprocedure werk admini Pagina 1 van 14 In deze werkinstructies kan alles vinden wat te maken heeft met het onderhoud van het kdadmin programma. Je kunt deze onderdelen vinden in

Nadere informatie

DHL KOPPELING GEBRUIKERSHANDLEIDING

DHL KOPPELING GEBRUIKERSHANDLEIDING GEBRUIKERSHANDLEIDING DHL KOPPELING DHL biedt Magento webshops een handige koppeling, genaamd plug-in. Hiermee biedt u bezorgopties direct aan in uw webshop en daarmee vergroot u uw service voor uw klanten.

Nadere informatie

Icoon/Icon Betekenis Description. Change scheduling Online. Gaat offline op (datum/tijd) Online. Going offline on (date/time)

Icoon/Icon Betekenis Description. Change scheduling Online. Gaat offline op (datum/tijd) Online. Going offline on (date/time) Algemeen/General Gepubliceerd maar gewijzigd Published but changed Meer acties op geselecteerde content More actions on selected content Gepubliceerd en niet gewijzigd Published and not changed Terugdraaien

Nadere informatie

ICARUS Illumina E653BK on Windows 8 (upgraded) how to install USB drivers

ICARUS Illumina E653BK on Windows 8 (upgraded) how to install USB drivers ICARUS Illumina E653BK on Windows 8 (upgraded) how to install USB drivers English Instructions Windows 8 out-of-the-box supports the ICARUS Illumina (E653) e-reader. However, when users upgrade their Windows

Nadere informatie

Inhoud. MySite Handleiding 1

Inhoud. MySite Handleiding 1 Inhoud Een module bewerken: Een module toevoegen...2 Een module kopiëren...4 Een module verplaatsen...5 Een module verbergen...6 Een module verwijderen...6 Openingsuren wijzigen...7 Een pagina bewerken:

Nadere informatie

REDACTEUREN HANDLEIDING

REDACTEUREN HANDLEIDING V1.2 8/5/2009 Vertaling: John Sim 2 Inhoudsopgave De inhoud van een document bewerken... 11 Een nieuwe document aanmaken... 12 Het aanmaken van een nieuwe document gaat als volgt:... 12 Een pagina publiceren...

Nadere informatie

Handleiding: Whitelabel Customersite

Handleiding: Whitelabel Customersite ARGEWEB B.V. Handleiding: Whitelabel Customersite Controlportal.nl Argeweb Support 8-1-2009 Handleiding voor het gebruik maken van de Whitelabel Customersite op controlportal.nl, door Resellers van Argeweb.

Nadere informatie

Handleiding Wordpress

Handleiding Wordpress Handleiding Wordpress Inhoudsopgave 1. Inloggen 2. Berichten en Pagina s 3. Afbeeldingen en video s 4. Weblinks 1. Inloggen 1.1 Inloggen bij Wordpress We starten met het inloggen op je WordPress gebaseerde

Nadere informatie

Hoe te verbinden met NDI Remote Office (NDIRO): Apple OS X How to connect to NDI Remote Office (NDIRO): Apple OS X

Hoe te verbinden met NDI Remote Office (NDIRO): Apple OS X How to connect to NDI Remote Office (NDIRO): Apple OS X Handleiding/Manual Hoe te verbinden met (NDIRO): Apple OS X How to connect to (NDIRO): Apple OS X Inhoudsopgave / Table of Contents 1 Verbinden met het gebruik van Apple OS X (Nederlands)... 3 2 Connect

Nadere informatie

2 Pagina s binnen TYPO3

2 Pagina s binnen TYPO3 2 Pagina s binnen TYPO3 Als u links onder de module Web klikt op de submodule Pagina krijgt u aan de rechterzijde het volgende scherm: Afbeelding 2.2 (frontend) Afbeelding 2.1 (backend) De gele, blauwe

Nadere informatie

Handleiding voor Zotero versie 2.0

Handleiding voor Zotero versie 2.0 Handleiding voor Zotero versie 2.0 Michiel Wolda De handleiding voor Zetero is geschreven voor de lezers van het boek Deskresearch: Informatie selecteren, beoordelen en verwerken: tweede editie (Van Veen

Nadere informatie

Handleiding Basecamp

Handleiding Basecamp Handleiding Basecamp PlusPort b.v. PlusPort 2013 Pagina 1 van 24 1 Inhoudsopgave. 1 Inhoudsopgave.... 2 2 Wat is Basecamp?... 3 3 Aan de slag met Basecamp... 4 3.1 Inloggen... 4 4 Projects... 6 4.1 Projectoverzicht...

Nadere informatie

Meehelpen met de ontwikkeling van nieuwe of verbetering van bestaande spellen. Pag. 1 www.edubas.nl

Meehelpen met de ontwikkeling van nieuwe of verbetering van bestaande spellen. Pag. 1 www.edubas.nl Meehelpen met de ontwikkeling van nieuwe of verbetering van bestaande spellen. Pag. 1 Versie 1.0 februari 2015 Start-versie Over dit document In dit document probeer is duidelijk te maken hoe de spellen

Nadere informatie

Je kan vanuit de RV SiteBuilder steeds terugkeren naar het controlepaneel, via de knop rechts bovenaan.

Je kan vanuit de RV SiteBuilder steeds terugkeren naar het controlepaneel, via de knop rechts bovenaan. RV SiteBuilder openen Log in op je controlepaneel met de gegevens die je van ons hebt ontvangen. Eens ingelogd, klik je helemaal onderaan, in de sectie Software/Services, op het RV SiteBuilder icoontje.

Nadere informatie

Fotografie Sophie Berten Zeelaan 74 8660 De Panne 058/62 45 46 www.fotogeniek.net sophie@fotogeniek.net. Fotogeniek - Creative photos Handleiding

Fotografie Sophie Berten Zeelaan 74 8660 De Panne 058/62 45 46 www.fotogeniek.net sophie@fotogeniek.net. Fotogeniek - Creative photos Handleiding Fotografie Sophie Berten Zeelaan 74 8660 De Panne 058/62 45 46 www.fotogeniek.net sophie@fotogeniek.net Fotogeniek - Creative photos Handleiding Inhoudsopgave FOTOGENIEK - CREATIVE PHOTOS HANDLEIDING...

Nadere informatie

Handleiding ESS na de upgrade People Inc. versie 3.5.0

Handleiding ESS na de upgrade People Inc. versie 3.5.0 Handleiding ESS na de upgrade People Inc. versie 3.5.0 I Handleiding ESS na de upgrade People Inc. versie 3.5.0 Inhoudsopgave Hoofdstuk 1 1 1.1 ESS... Iconen selecteren 1 1.2 ESS... Inlog scherm tekst

Nadere informatie

Automatisering voor Financiële Dienstverleners. Werken met Queries en Merge Documenten. For more information visit our website at www.pyrrho.

Automatisering voor Financiële Dienstverleners. Werken met Queries en Merge Documenten. For more information visit our website at www.pyrrho. Automatisering voor Financiële Dienstverleners Werken met Queries en Merge Documenten For more information visit our website at www.pyrrho.com Date: Document Nr: 30 maart, 2007 UBizzMerge, Versie 4.0 Status:

Nadere informatie

Klachtenbeheer (Intranet)

Klachtenbeheer (Intranet) Klachtenbeheer (Intranet) Versie:1 1/17 1 INLEIDING...3 2 NAVIGATIE VAN DE APPLICATIE...3 3 FRONT-END (OP DE WEBSITE)...4 3.1 Het online melden van klachten... 4 3.2 Mijn meldingen... 5 4 BACK-END...6

Nadere informatie

Handleiding integratie CF iviewer CT-iViewer

Handleiding integratie CF iviewer CT-iViewer Domotechnology BVBA Dikberd 34 unit 1a 2200 HERENTALS België Handleiding integratie CF iviewer CT-iViewer TEL: 014/72.00.30 MAIL: info@domotechnology.be SITE: www.domotechnology.be CT-iViewer Inhoudstabel

Nadere informatie

Datum: Gemaakt door: Berend de Groot Voor: ComSi, ROC Friese Poort

Datum: Gemaakt door: Berend de Groot Voor: ComSi, ROC Friese Poort Datum: Gemaakt door: Berend de Groot Voor: ComSi, ROC Friese Poort Contents 1. Introductie... 3 1.1. Hoe werkt het?... 3 2. Eerste Contact als gebruiker... 4 3. Ticket Acties... 5 4. Tickets Pagina...

Nadere informatie

Voor vragen: http://www.richard3332.nl/ of mail naar Richard3332@gmail.com

Voor vragen: http://www.richard3332.nl/ of mail naar Richard3332@gmail.com Welkom bij mijn website tutorial (Deel 5) Ik ga uit van Microsoft XP voor de duidelijkheid. Ik heb dus geen idee of de programma s die ik gebruik ook op Vista werken. Notepad++ werkt zowieso op xp en Vista.

Nadere informatie

Voor vragen: http://www.richard3332.nl/ of mail naar Richard3332@gmail.com

Voor vragen: http://www.richard3332.nl/ of mail naar Richard3332@gmail.com Welkom bij mijn website tutorial (Deel 3) Ik ga uit van Microsoft XP voor de duidelijkheid. Ik heb dus geen idee of de programma s die ik gebruik ook op Vista werken. Notepad++ werkt zowieso op xp en Vista.

Nadere informatie

SBGuidance Machine Manager. SBGuidance Machine Manager. Versie 2.0. Handleiding. 24 november 2009

SBGuidance Machine Manager. SBGuidance Machine Manager. Versie 2.0. Handleiding. 24 november 2009 SBGuidance Machine Manager Handleiding 24 november 2009 Versie 2.0 Service Handleiding - 1 - November 2009 SBGuidance Machine Manager Service Handleiding (Herziening 0) Copyright 2009 SBG Innovatie. Alle

Nadere informatie

Siemens workpoints en DHCP options

Siemens workpoints en DHCP options Siemens workpoints en DHCP options Dit document beschrijft de configuratie en werking van een Windows 2003 DHCP server in combinatie met Siemens optipoint en Siemens OpenStage toestellen (aangemeld op

Nadere informatie

Versie 0.4. Documentatie Onsweb Club plugin voor KNKV verenigingen. Laatste wijziging: 19 juli 2012 Auteurs: Marien Dongstra, Sebastian Huisman

Versie 0.4. Documentatie Onsweb Club plugin voor KNKV verenigingen. Laatste wijziging: 19 juli 2012 Auteurs: Marien Dongstra, Sebastian Huisman Documentatie Onsweb Club plugin voor KNKV verenigingen Versie 0.4 Laatste wijziging: 19 juli 2012 Auteurs: Marien Dongstra, Sebastian Huisman Alle rechten in dit document zijn voorbehouden. www.onsweb.nl,

Nadere informatie

Mach3Framework 5.0 / Website

Mach3Framework 5.0 / Website Mach3Framework 5.0 / Website Handleiding Mach3Builders Inhoudsopgave 1 Inloggen...5 1.1 Ingelogd blijven...6 1.2 Wachtwoord vergeten...7 2 Applicatie keuzescherm...8 2.1 De beheeromgeving openen...9 3

Nadere informatie

Handleiding DIAS scanning. 1. Opstarten. Start eerst DIAS op en daarna het DIAS scanprogramma.

Handleiding DIAS scanning. 1. Opstarten. Start eerst DIAS op en daarna het DIAS scanprogramma. Handleiding DIAS scanning 1. Opstarten Start eerst DIAS op en daarna het DIAS scanprogramma. Indien u het scanprogramma toch probeert te gebruiken zonder dat DIAS is opgestart zult u zien dat het DIAS

Nadere informatie

Handleiding voor installatie en gebruik van

Handleiding voor installatie en gebruik van Handleiding voor installatie en gebruik van Opticon OPN-2001 Data Collector Inhoud pakket: - OPN-2001 - USB Communicatie kabel - Neckstrap Voordat u kunt communiceren met de OPN-2001 dient u de volgende

Nadere informatie

Mobile Connect & Apple

Mobile Connect & Apple Mobile Connect & Apple Software versie 4.05.01.00 - Always Best Connected - Hoe Installeert U de Vodafone Mobile Broadband software op uw Apple computer. Index van deze handleiding: Inleiding Het installeren

Nadere informatie

SAP Mobile Documents SP 05 Hoe het werken met de nieuwste versie nog makkelijker is geworden.

SAP Mobile Documents SP 05 Hoe het werken met de nieuwste versie nog makkelijker is geworden. SAP Mobile Documents SP 05 Hoe het werken met de nieuwste versie nog makkelijker is geworden. Documentnummer: 1.0 Datum: 4-1-2016 Auteur: SANDER MAES Rompertdreef 1b 5233 ED s-hertogenbosch Postbus 86

Nadere informatie

1 BUSINESS INTERNET SUPPORT

1 BUSINESS INTERNET SUPPORT Versie 1 BUSINESS INTERNET SUPPORT Yoron Dot Net Stap voor stap Handleiding YORON DOT NET BEHEER V1.X Stap voor stap handleiding YORON Het Wielsem 10 s-hertogenbosch Inhoudsopgave Opstarten Yoron DotNet

Nadere informatie

Midi PDF Bladmuziek lezer

Midi PDF Bladmuziek lezer Inleiding. Ruim 20 ordners aan bladmuziek, meeste daarvan uitgeprint van een PDF. Even snel een nummer opzoeken wil dan ook niet, terwijl ik alles wel op alfabetische volgorde heb. Dat was het niet helemaal

Nadere informatie

Werkomgeving. Android Studio. Android - werkomgeving 1/6

Werkomgeving. Android Studio. Android - werkomgeving 1/6 Android - werkomgeving 1/6 Werkomgeving Android Studio Installatie Ga naar de volgende URL: http://developer.android.com/sdk/index.html Klik op de knop "Download Android Studio for Windows" om het programma

Nadere informatie

Les 9: formulier controle met javascript.

Les 9: formulier controle met javascript. Les 9: formulier controle met javascript. Javascript is erg veel gebruikt bij internet toepassingen. In tegenstelling tot PHP, wat een server side scripting is, is java client side scripting. Dwz, niet

Nadere informatie

Bewerk uw eigen Digibordbij boek

Bewerk uw eigen Digibordbij boek Bewerk uw eigen Digibordbij boek Naast de presentatie van schoolboeken in het Digibordbij systeem is het voor leraren ook mogelijk aanpassingen te maken in de digitale boeken. De leraar kan via een aparte

Nadere informatie

DHL PARCEL INTRODUCTIE. *Bron: Metapack

DHL PARCEL INTRODUCTIE. *Bron: Metapack DHL PARCEL INTRODUCTIE DHL biedt Magento webshops een handige koppeling, genaamd plug-in. Hiermee biedt u bezorgopties direct aan in uw webshop en daarmee vergroot u uw service voor uw klanten. Daar profiteert

Nadere informatie

Mobile Watch Snelle Handleiding. Bezoek voor meer informatie

Mobile Watch Snelle Handleiding. Bezoek  voor meer informatie Mobile Watch Snelle Handleiding Ⅰ. Software installatie - Software download: Zoek voor "360Eye"in de Iphone App Store en installeer de applicatie. Of scan de QR Code aan de rechterzeide. Voor meer details

Nadere informatie

PayCheckout Magento module

PayCheckout Magento module PayCheckout Magento module 1 Inhoudsopgave Installatie... 3 Compatibiliteit... 3 Best practice... 3 Installeren van de module... 3 Configuratie... 4 Webshop... 4 Webshop toevoegen... 4 Webshop Identifier

Nadere informatie

TeD Tekst en Design. Basisinformatie voor klein gebruik van het cms Made Simple

TeD Tekst en Design. Basisinformatie voor klein gebruik van het cms Made Simple Basisinformatie voor klein gebruik van het cms Made Simple 1 Inhoud Inhoud 2 Inleiding 3 Inloggen in het CMS 3 Teksten plaatsen/aanpassen 4 Een link aanmaken 4 Gebruikers toevoegen/ verwijderen 5 Werken

Nadere informatie

Bitrix Site Manager gebruikershandleiding BureauZuid

Bitrix Site Manager gebruikershandleiding BureauZuid Bitrix Site Manager gebruikershandleiding BureauZuid Introductie Deze gebruikershandleiding geeft gedetailleerde basisinformatie over hoe te werken met Bitrix Site Manager. Deze handleiding is bedoeld

Nadere informatie

EM6250 Firmware update V030507

EM6250 Firmware update V030507 EM6250 Firmware update V030507 EM6250 Firmware update 2 NEDERLANDS/ENGLISH Table of contents 1.0 (NL) Introductie... 3 2.0 (NL) Firmware installeren... 3 3.0 (NL) Release notes:... 5 1.0 (UK) Introduction...

Nadere informatie

EM7680 Firmware Update by OTA

EM7680 Firmware Update by OTA EM7680 Firmware Update by OTA 2 NEDERLANDS/ENGLISH EM7680 Firmware update by OTA Table of contents 1.0 (NL) Introductie... 3 2.0 (NL) Firmware installeren... 3 3.0 (NL) Release notes:... 3 4.0 (NL) Overige

Nadere informatie

1. Inloggen 2. 2. Uw account 3 2.1 Wachtwoord veranderen 3 2.2 Alle gegevens bekijken 3 2.3 Credits (mail-bundels) kopen 3

1. Inloggen 2. 2. Uw account 3 2.1 Wachtwoord veranderen 3 2.2 Alle gegevens bekijken 3 2.3 Credits (mail-bundels) kopen 3 Inhoudsopgave Hoofdstuk Bladzijde 1. Inloggen 2 2. Uw account 3 2.1 Wachtwoord veranderen 3 2.2 Alle gegevens bekijken 3 2.3 Credits (mail-bundels) kopen 3 3. Nieuwsbrieven 4 stap 1: voeg een nieuwsbrief

Nadere informatie

Lab Webdesign: Javascript 7 april 2008

Lab Webdesign: Javascript 7 april 2008 H8: FORMULIEREN In dit hoofdstuk komt het "form"-object aan de orde: we zullen zien hoe we JavaScript kunnen gebruiken voor het manipuleren en valideren van de gegevens die een eindgebruiker invult in

Nadere informatie

HORECA HANDLEIDING 1

HORECA HANDLEIDING 1 HORECA HANDLEIDING 1 Inhoud Algemeen menu... 4 Dashboard of Overzicht... 4 Beheerder (Manager) -> Profiel (Profile)... 5 Dashboard of Overzicht... 6 Ticket details:... 7 User Management of gebruikersbeheer...

Nadere informatie

Handleiding CMS. Auteur: J. Bijl Coldfusion Consultant

Handleiding CMS. Auteur: J. Bijl Coldfusion Consultant Handleiding CMS Auteur: J. Bijl Coldfusion Consultant Inhoudsopgave 1.0 Inleiding 3 2.0 Introductie CMS en websites 4 3.0 Inloggen in beheer 5 4.0 Dashboard 6 4.1 Bezoekers totalen 6 4.2 Bezoekers 7 4.3

Nadere informatie

Handleiding WiFi. RR Trading B.V.

Handleiding WiFi. RR Trading B.V. Handleiding WiFi RR Trading B.V. Rev.05 Inhoudsopgave 1. Voorbeeld van de werking... 3 2. Benodigde materialen en informatie... 3 3. Mededeling... 4 4. Gebruiksvoorwaarden... 4 5. Registreren... 5 6. Externe

Nadere informatie

Uitleg 1mail E mailingmodule

Uitleg 1mail E mailingmodule Uitleg 1mail E mailingmodule Wat is het? Een online programma om nieuwsbrieven/e-zines te versturen, met personalisatiemogelijkheden en met een gedetailleerd rapporteringssysteem. Dit alles via een externe

Nadere informatie

ATOS Viewer for Dental Frameworks User Manual

ATOS Viewer for Dental Frameworks User Manual ATOS Viewer for Dental Frameworks User Manual www.dentwise.eu Inhoud Content NEDERLANDS... 2 1. Installatie... 2 2. Algemene Functies... 2 3. Afstanden Meten... 3 4. Doorsneden Maken... 4 5. Weergave Aanpassen...

Nadere informatie

Documentatie Nederlands v1

Documentatie Nederlands v1 Documentatie Nederlands v1 Getting started Navigation menu Theme settings General Features Background Typography Banners Contact details Social Unique selling points Image Sizes Frequently asked questions

Nadere informatie

U gaat naar de site van Dropbox. Klik nu op de grote knop Download Dropbox.

U gaat naar de site van Dropbox. Klik nu op de grote knop Download Dropbox. Dropbox Weg met USB-sticks, leve Dropbox! Met het programma wisselt u eenvoudig bestanden (foto's, documenten, muziek) uit tussen verschillende gebruikers en apparaten. Stap 1: Downloaden Klik hierboven

Nadere informatie

License Management Tool: Lokaal beheer software licenties

License Management Tool: Lokaal beheer software licenties License Management Tool: Lokaal beheer software licenties De License Management Tool biedt de ondersteuning voor het beheer van software die via ICTS wordt verdeeld: Installatiecodes en download vanop

Nadere informatie

DE MODULE FOTOGALERIJ

DE MODULE FOTOGALERIJ DE MODULE FOTOGALERIJ Inhoudsopgave Inhoud Pagina 1. INLEIDING... 2 2. PROCEDURE... 3 2.1. De module Fotogalerij openen... 3 2.2. Een galerij creëren.....4 2.2.1 Een galerij openen....4 2.2.2 Een galerij

Nadere informatie

Installatiehandleiding 2.x

Installatiehandleiding 2.x Installatiehandleiding 2.x Voorwoord Hierbij de installatiehandleiding voor onze plugin met Magento 2.x. Bij vragen kunt u support aanvragen via een e-mail naar ict@parcelpro.nl of bellen naar 085 273

Nadere informatie

General info on using shopping carts with Ingenico epayments

General info on using shopping carts with Ingenico epayments Inhoudsopgave 1. Disclaimer 2. What is a PSPID? 3. What is an API user? How is it different from other users? 4. What is an operation code? And should I choose "Authorisation" or "Sale"? 5. What is an

Nadere informatie

Studenthandleiding Portfolio in Blackboard Learn

Studenthandleiding Portfolio in Blackboard Learn Studenthandleiding Stafbureau onderwijs & onderzoek Functioneel beheer Blackboard Learn. T.b.v. October 2014 release. Versie: 02-12-2014. Handleiding portfolio studenten In deze handleiding wordt het aanmaken

Nadere informatie

Op basis van klanten-,product-,barcodegegevens wordt automatisch een barcode document aangemaakt

Op basis van klanten-,product-,barcodegegevens wordt automatisch een barcode document aangemaakt Op basis van klanten-,product-,barcodegegevens wordt automatisch een barcode document aangemaakt Pagina 1 van 56 Inhoud van deze help 1. Algemeen 1.1 Inhoud van deze box. 1.2 Minimum systeemvereisten 2.

Nadere informatie

Snel op weg met Solid Edge ST5

Snel op weg met Solid Edge ST5 Snel op weg met Solid Edge ST5 Dit document helpt u, om na installatie van Solid Edge ST5, snel aan de slag te kunnen met de software. Beschreven staat welke instellingen u kunt aanpassen om een betere

Nadere informatie

Release notes:

Release notes: Applicatie: Alle Module: Algemeen (geen specifieke module) 64098 Auto resize image geeft zwarte randen indien de achtergrond transparant is Gecorrigeerde functionaliteit Als bepaalde types afbeeldingen

Nadere informatie

Versie 6.4 van de Photomatic software is nu beschikbaar als download op www.idstation.eu/downloads.

Versie 6.4 van de Photomatic software is nu beschikbaar als download op www.idstation.eu/downloads. Release Notes versie 6.4 Versie 6.4 van de Photomatic software is nu beschikbaar als download op www.idstation.eu/downloads. Updates zijn natuurlijk ook beschikbaar. Kies de update op basis van uw printer:

Nadere informatie

Inhoud. Handleiding Dododent. Beste tandarts of praktijkmanager,

Inhoud. Handleiding Dododent. Beste tandarts of praktijkmanager, Handleiding Dododent Beste tandarts of praktijkmanager, Hartelijk dank voor de aanschaf van een website bij Dodoworks. Hieronder volgt een uitgebreide handleiding van het Dododent systeem waarmee de website

Nadere informatie

Werkwijze Maandelijkse Nieuwsbrief

Werkwijze Maandelijkse Nieuwsbrief Werkwijze Maandelijkse Nieuwsbrief Inhoud 1 Mensen aanschrijven om hen bewust te maken van de deadline 2 Eerdere content (zoals oproepen) opvolgen en mail verwerken 3 Content bewerken in html 4 Nieuwsbrief

Nadere informatie

Inventus Software. Antum Secured Mail / Message System. Gebruikershandleiding

Inventus Software. Antum Secured Mail / Message System. Gebruikershandleiding Inventus Software Antum Secured Mail / Message System Gebruikershandleiding 1 Hoe begin ik? 3 2 Wat is er zoal aanwezig in het hoofdprogramma? 3 3 Hoe decoder ik e-mails of tekstberichten? 4 3.1 Decoderen

Nadere informatie

Quick Guide VivianCMS

Quick Guide VivianCMS Quick Guide VivianCMS Contactformulier creëren Versie: 1.0 Startdatum: 24 juli 2006 Datum laatste wijziging: 24 juli 2006 Opmerking: Gepubliceerd op http://www.viviancms.nl Inhoud 1 Inleiding...3 1.1 Contactformulier

Nadere informatie

WEBSITE-DESIGN CHRIS VERMAAS & FJODOR VAN SLOOTEN 2014-201000018-1B

WEBSITE-DESIGN CHRIS VERMAAS & FJODOR VAN SLOOTEN 2014-201000018-1B WEBSITE-DESIGN CHRIS VERMAAS & FJODOR VAN SLOOTEN 2014-201000018-1B WEBSITE-DESIGN INHOUD COLLEGE Afronding vak JQuery, mail(formulieren) en social media Testen Website-design 5-1-2015 2 AFRONDING VAK

Nadere informatie

Hoe maak je een nieuwbrief template met MailChimp? In dit document leg ik je stap voor stap uit hoe je met het drag and drop systeem van MailChimp jouw eigen layout bij elkaar sleept. Je geeft jouw template

Nadere informatie

Mei. Handleiding - Publisher Tool 1

Mei. Handleiding - Publisher Tool 1 Mei 15 Handleiding - Publisher Tool 1 Inhoudsopgave 1. Welkom... 3 1.1 Inloggen... 3 1.2 Dashboard... 4 2. Boeken... 5 2.1 Boeken aanmaken... 5 2.2 Het bewerken van boekinformatie.... 7 3. Verrijkingen...

Nadere informatie

Tips en tricks. Hoe te werken met Qualtrics. Ilonka van Meenen

Tips en tricks. Hoe te werken met Qualtrics. Ilonka van Meenen Tips en tricks Hoe te werken met Qualtrics Ilonka van Meenen Inhoud Handigheidjes... 2 Menu: Edit survey survey options... 3 Display logic... 5 Vragen kopiëren uit andere vragenlijsten... 6 Translate...

Nadere informatie

INSTALLATIE EXCHANGE CONNECTOR

INSTALLATIE EXCHANGE CONNECTOR HANDLEIDING INSTALLATIE EXCHANGE CONNECTOR INSTALLATIE EXCHANGE CONNECTOR 0 0 HANDLEIDING INSTALLATIE EXCHANGE CONNECTOR INSTALLATIE EXCHANGE CONNECTOR HANDLEIDING datum: 10-08-2018 1 Inleiding... 1 2

Nadere informatie

Web Handleiding. semper vigilant Fall 2014 LOCALBOX 1.1.3

Web Handleiding. semper vigilant Fall 2014 LOCALBOX 1.1.3 Web Handleiding semper vigilant Fall 2014 Functionaliteiten web-based 2 Inloggen 2 Home 3 Uploaden: 4 Opties: 6 Map Delen: 6 Beheer Links 8 Functionaliteiten App-based 12 Hoger niveau 16 Acties op bestanden

Nadere informatie

NIEUWSBRIEVEN VIA MAILCHIMP. Handleiding voor de beheerder

NIEUWSBRIEVEN VIA MAILCHIMP. Handleiding voor de beheerder NIEUWSBRIEVEN VIA MAILCHIMP Handleiding voor de beheerder Inhoud 1. Inloggen 2 2. Mailadressen beheren 2 2.1 Een nieuwe adressenlijst aanmaken 2 2.2 Een bestaande adressenlijst beheren 3 2.3 Een gebruiker

Nadere informatie

Selenium IDE Webdriver. Introductie

Selenium IDE Webdriver. Introductie Selenium IDE Webdriver Het Wielsem 10, 5231 BW s- Hertogenbosch, telefoon 073-6409311 e- mail info@testwork.nl internet http://www.testwork.nl 1 Inhoudsopgave 1 Inhoudsopgave... 2 2 Selenium IDE... 3 3

Nadere informatie

Gebruikersgids. 2010,Sitewriter All Rights Reserved. Gebruikersgids

Gebruikersgids. 2010,Sitewriter All Rights Reserved. Gebruikersgids 2010,Sitewriter All Rights Reserved. 0 Contents 2 Pagina toevoegen 5 Pagina bewerken 7 Media-inhoud 7 9 10 11 12 Invoegen afbeelding Invoegen muziek fragment Invoegen van een video Invoegen van Flash invoegen

Nadere informatie

Report generator Gegevens zoeken en kolommen selecteren Rapporten opslaan en beheren... 6

Report generator Gegevens zoeken en kolommen selecteren Rapporten opslaan en beheren... 6 Report generator... 3 1 Gegevens zoeken en kolommen selecteren... 4 2 Rapporten opslaan en beheren... 6 3 Rapporten automatisch laten genereren en versturen... 8 Zoeken binnen resultaten... 11 Report generator

Nadere informatie

Stappenplan Werken met Popplet

Stappenplan Werken met Popplet WAT IS POPPLET? Popplet is een handige site voor het maken van mindmaps of stroomdiagrammen. De blokjes zijn herkenbaar en het plaatsen gaat erg eenvoudig. Het maken van een eigen uitstraling is daardoor

Nadere informatie

Release nieuwe versie 1.9.3

Release nieuwe versie 1.9.3 Release nieuwe versie 1.9.3 November 2013 www.siteop.mobi www.siteop.mobi - Kingsfordweg 151-1043 GR Amsterdam Tel: 085 40 123 92 - support.siteop.mob Release Versie Item Versie Datum SiteOpMobi Platform

Nadere informatie

Deel 5: Ontleding van een thema en subtheming. 20. YML-bestanden en subtheming

Deel 5: Ontleding van een thema en subtheming. 20. YML-bestanden en subtheming Deel 5: Ontleding van een thema en subtheming 20. YML-bestanden en subtheming Een thema moet voldoen aan bepaalde standaarden. Wat moet een thema zoal bevatten en kunnen we beroep doen op andere basisthema

Nadere informatie

Informatica Wiki. Hoe ontwerp en beheer je je eigen wiki met wikispaces

Informatica Wiki. Hoe ontwerp en beheer je je eigen wiki met wikispaces 1. Registeren Informatica Hoe ontwerp en beheer je je eigen wiki met wikispaces surf naar www.wikispaces.com Indien je nog geen wiki-member bent kies je een gebruikersnaam en paswoord en vul je je e-mailadres

Nadere informatie

Basis handleiding CMS

Basis handleiding CMS Basis handleiding CMS Inhoud Basis handleiding CMS... 1 Inloggen... 3 Pagina beheren... 4 Pagina toevoegen/wijzigen... 6 WYSIWYG editor... 8 externe / interne link toevoegen... 9 Plaatjes toevoegen...

Nadere informatie

Met onderstaand stappenplan kunt u in korte tijd kennismaken met ICEmailer en uw eerste nieuwsbrief versturen.

Met onderstaand stappenplan kunt u in korte tijd kennismaken met ICEmailer en uw eerste nieuwsbrief versturen. Introductie ICEmailer 1.02 URL en inloggegevens: url: www.icemailer.nl organisatie: user: password: Eerste stappen: Indien u ICEmailer gebruikt om mailings te sturen naar klanten van uw online webshop,

Nadere informatie

Handleiding beheer lijst.hva.nl. See page 11 for Instruction in English

Handleiding beheer lijst.hva.nl. See page 11 for Instruction in English Handleiding beheer lijst.hva.nl See page 11 for Instruction in English Maillijsten voor medewerkers van de Hogeschool van Amsterdam Iedereen met een HvA-ID kan maillijsten aanmaken bij lijst.hva.nl. Het

Nadere informatie