Wir hatten uns in diesem Artikel eine super-simple App mit einer Zeile Source-Code gebaut, die allerdings nur in wenigen Einsatzfällen professionellen Ansprüchen genügt, vielleicht als ePaper-Reader oder als App für ein einfaches News-Medium - zum Beispiel ein Blog - wobei allerdings Responsive Design vorausgesetzt wurde.
Die Lade-Anzeige der Seite wurde mit einfachen CSS-Bord-Mitteln realisiert, was durchaus schon die Usability beträchtlich erhöhen kann. Aber wahrscheinlich will man sehr schnell etwas mehr Komfort und einige spannende Features implementieren.
Ein Spinner für die Lade-Anzeige sieht schon sehr viel professioneller aus und wie wäre es mit einem Kompass für das Impressum, so dass man mobil auf der Anfahrtskarte auch die Richtung erkennen kann, in die man laufen muss? Ich selbst hätte schon häufiger dafür Bedarf gehabt, vor allem, wenn ein Kunde mitten in der Stadt wohnt und das Navi im Parkhaus zurückgelassen werden musste.
Oder man will seinen Nutzern die Möglichkeit geben, ein Photo hochzuladen? Ein solches Feature ist vielleicht der erste Schritt zu einem erfolgreichen Geschäftsmodell.
Aufgabenstellung
In diesem Artikel werden die Kenntnisse aus dem Modul-Pattern-Beitrag verwendet, um eine gut strukturierte App technisch zu realisieren, die folgende Funktionen erfüllt:
- Ein Spinner informiert über den Ladezustand (Abb. 1).
- Der Kompass gibt laufend die aktuelle Richtung des mobilen Endgeräts aus zusammen mit einem Zeitstempel (Abb. 2).
- Ein Button stellt die Kamera bereit, mit der ein Foto geschossen werden kann, welches das Hintergrund-Bild ersetzt (Abb. 3).
Abb. 1: Spinner für den Ladezustand einer Seite
Abb. 2: Kompass und Timestamp werden kontinulierlich aktualisiert.
Abb. 3: Mit der Kamera-Funktion wird das Hintergrund durch ein aktuell geschossenes Foto ersetzt.
Umsetzung
Wir benötigen für unser Projekt, in welchem wir das Modul-Pattern ausnutzen wollen, folgende Projektstruktur (Abb. 4). Es kann nicht schaden, sich diese Projektstruktur mit leeren zusätzlichen Source-Dateien direkt nach der Generierung einer frischen Html5-Cordova-Applikation einzurichten.
Abb. 4: Projektstruktur der Html5-Cordova-Applikation in NetBeans
Auch wenn ich die folgenden Unterkapitel in Schritte unterteilt habe, sollte man doch am besten alle Sourcen auf einen Schlag implementieren, da die App sonst nicht unbedingt funktioniert. Die Schritte dienen nur als Anhaltspunkt für die Reihenfolge, in der man die Aufgabe lösen kann.
Schritt 1: index.html und index.css modifzieren
Als erstes modifizieren wir die index.html-Datei im Root. Ersetzt einfach den Inhalt für index.html durch folgenden Code:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" /> <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 --> <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" /> <link rel="stylesheet" type="text/css" href="css/index.css" /> <title>Hello World</title> </head> <body> <div class="app"> <h1>Apache Cordova</h1> <canvas width="27" height="27" id="spinner"></canvas> <div id="deviceready" class="blink"> <p class="event listening">Connecting to Device</p> <p class="event received">Device is Ready</p> <p class="event status"></p> <p class="takephoto"><button>Take a photo</button></p> </div> </div> <script type="text/javascript" src="cordova.js"></script> <script type="text/javascript" src="js/libs/jquery.js"></script> <script type="text/javascript" src="js/mod/util.js"></script> <script type="text/javascript" src="js/mod/debug.js"></script> <script type="text/javascript" src="js/app/spin.js"></script> <script type="text/javascript" src="js/app/cam.js"></script> <script type="text/javascript" src="js/app/main.js"></script> <script> main.initialize(); </script> </body>
In der Datei index.css benötigen wir einige weinige Modifikationen. Wir ersetzen dort die Regel für .event.received durch dieses Snippet:
.event.received, .event.status, .link.takephoto { background-color:#4B946A; display:none; } h1 { padding: 15px; }
Damit haben wir, zumindest für mein Handy, eine einigermaßen vernünftige Darstellung. Wir machen hier natürlich kein Frontend-Design. Wer ein anderes mobiles Endgerät hat, muss hier halt etwas experimentieren.
Schritt 2: Das Hauptmodul main.js
Unser Hauptmodul verwendet jQuery und implementiert vor allem das DOM-Ready-Event:
var main = (function(util, debug, spin, cam, $) { function _initialize() { spin.init(); } function onDeviceReady() { receivedEvent('deviceready'); $('#spinner').hide(); $('.takephoto').show(); $('.takephoto button').click(function(){ cam.takePhoto(); }); } // Update DOM on a Received Event function receivedEvent(id) { // debug.active(false); var parentElement = document.getElementById(id); var listeningElement = parentElement.querySelector('.listening'); var receivedElement = parentElement.querySelector('.received'); var statusElement = parentElement.querySelector('.status'); listeningElement.setAttribute('style', 'display:none;'); receivedElement.setAttribute('style', 'display:block;'); console.log('Received Event: ' + id); debug.proofCompassSupported(statusElement); } $(document).ready(function() { $('.takephoto').hide(); // Use Corodovas 'deviceready'-event in device-context ever. if (util.runsInNativeApp() || util.runsInRippleEmu()) { document.addEventListener('deviceready', onDeviceReady, false); } else { onDeviceReady(); } if (util.runsInRippleEmu()) { // do something ... } }); return { initialize: function() { _initialize(); } }; }(util, debug, spin, cam, jQuery)); console.log('main.js');
Wir erkennen an der ersten und der letzten Zeile, dass dieses Modul abhängig ist von anderen eigenen Modulen (util, debug, spin, cam) und von jQuery. Diese Art der Deklaration in der letzten Zeile, ermöglicht es, die Modul-Variablen als global verfügbare Funktionsparameter (erste Zeile) zu übergeben.
Schön ist auch, dass wir bei dieser Konstruktion einen Event-Handler onDeviceReady problemlos einbinden können. Das war mit der von Corodova ausgelieferten Architektur in index.js (das wir hoffentlich gelöscht haben) mit dem Objekt-Muster für app nicht möglich.
Außerdem wird der Ablauf abhängig von der Lauf-Umgebung (Device, Ripple-Emulator, Sonstiges) gesteuert durch die neuen Funktionen im Modul util.js.
Schritt 3: Der Spinner
Der Spinner wird mit Canvas realisiert. Dies hat den Vorteil, dass man keine Spinner-Images oder -Icons benötigt. Diese Modul ist sehr einfach und besitzt keine Abhängigkeiten:
var spin = (function() { var cog = new Image(); function _init() { cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path setInterval(draw,10); } var rotation = 0; function draw(){ var ctx = document.getElementById('spinner').getContext('2d'); if (ctx === null) return; ctx.globalCompositeOperation = 'destination-over'; ctx.save(); ctx.clearRect(0,0,27,27); ctx.translate(13.5,13.5); // to get it in the origin rotation +=1; ctx.rotate(rotation*Math.PI/64); //rotate in origin ctx.translate(-13.5,-13.5); //put it back ctx.drawImage(cog,0,0); ctx.restore(); } return { init:function(){_init();} }; }()); console.log('spin.js');
Schritt 4: Helper-Funktionen
Wir benötigen eine Reihe von Helper-Funktionen, die wir im Modul util.js unterbringen. Wir hatten dieses Modul schon im letzten Artikel besprochen. Ich füge es aber trotzdem nocheinmal hier ein:
var util = (function () { // needed for '_replaceAll' function escapeRegExp(string) { return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); } function _replaceAll(string, find, replace) { return string.replace(new RegExp(escapeRegExp(find), 'g'), replace); } // e.g.: var S = new Object(); // S.val='Berlin-Wedding'; // P=shift_word('-', S); // => P='Berlin', S.val='Wedding' function _shiftWord(Separator, S){ var Q = ''; var P = S.val.indexOf(Separator, S.val); var L = Separator.length; if (P==-1) { Q = S.val; S.val = ''; return Q; } if (P==0) { S.val = S.val.substr(L); return ''; } Q = S.val.substr(0,P); S.val = S.val.substr(P+L); return Q; } function _timestamp() { var now = new Date(); var date = [ now.getFullYear(), now.getMonth() + 1, now.getDate()]; var time = [ now.getHours(), now.getMinutes(), now.getSeconds() ]; for ( var i = 1; i < 3; i++ ) { if ( time[i] < 10 ) { time[i] = "0" + time[i]; } } for ( var i = 1; i < 3; i++ ) { if ( date[i] < 10 ) { date[i] = "0" + date[i]; } } return date.join("") + "-" + time.join(""); } // Are we running in native app or in a browser? function _runsInNativeApp() { var res = false; if (document.URL.indexOf("http://") === -1 && document.URL.indexOf("https://") === -1) { res = true; } return res; } // Are we running in Ripple-emulator? function _runsInRippleEmu() { if (_runsInNativeApp()) { return false; } return urlExists('http://localhost:4400/ripple/assets/ripple.css')===true; } function urlExists(url) { var http = new XMLHttpRequest(); http.open('HEAD', url, false); http.send(); // return http.status!=404; return http.status===200; } return { replaceAll: function(aPath, find, replace) { return _replaceAll(aPath, find, replace); }, shiftWord: function(Separator, S) { return _shiftWord(Separator, S); }, timestamp: function(){ return _timestamp(); }, runsInRippleEmu: function() { return _runsInRippleEmu(); }, runsInNativeApp: function() { return _runsInNativeApp(); } }; }()); console.log('util.js');
Schritt 5: Der Kompass
Für den Kompass benötigen wir das Modul util.js sowie jQuery. Ihr wundet Euch, dass der Name debug.js lautet?
Ich habe den Kompass als Test-Funktion implementiert, da es z.B. Sinn macht, mit der Funktion proofCompassSupported() zu überprüfen, ob die Sensorik des mobilen Gerätes zur Verfügung steht oder auch, ob der Ripple-Emulator richtig konfiguriert ist zum Test. Wenn dort nämlich der Kompass nicht funktioniert, die App aber trotzdem zu sehen ist, liegt meistens ein Konfigurationsfehler vor. Da ich dies auch in Projekten prüfen möchte, in denen die Sensorik nicht benötigt wird, habe ich die Funktion in debug.js eingebaut. Dieses Modul wird in späteren Artikeln noch erweitert.
Interessant ist in dem Modul außerdem noch die Eigenschaft active, mit der alle Debug-Funktionen im Programm später abschnittsweise aus- und eingeschaltet werden können durch einfügen von debug.active(true) bzw. debug.active(false).
var debug =(function(util){ var _active = true; function _setActive(how) { _active = how; } function _proofCompassSupported(statusElement) { if (_active===false) {return;}; statusElement.setAttribute('style', 'display:block;'); navigator.compass.watchHeading(function(heading){ // var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU="); // snd.play(); // statusElement.innerHTML = 'hallo'; statusElement.innerHTML = util.timestamp() + '<br/> ' + heading.trueHeading + ' °'; },function(error){ var errorType; switch(error.code){ case CompassError.COMPASS_NOT_SUPPORTED: errorType = "Error: Compass - not supported"; break; case CompassError.COMPASS_INTERNAL_ERR: errorType = "Error: Compass - internal"; break; default: errorType = "Error: Compass - Unknown"; } statusElement.innerHTML = errorType; }); } return { active: function(how) { _setActive(how); return how; }, proofCompassSupported: function(statusElement) { return _proofCompassSupported(statusElement); } }; }(util)); console.log('debug.js');
Wer will, kann natürlich dieses Modul als Ausgangspunkt nehmen für ein komplexeres Kompass-Modul, das dann aber im Ordner mod besser einsortiert ist.
Schritt 6: Die Kamera
Das Cam-Modul setzt wieder fleißig auf jQuery, weshalb wir diese Abhängigkeit angeben. Ansonsten wird nur eine Funktion benötigt, nämlich die, ein Foto zu schießen.
var cam = (function($) { function _takePhoto() { navigator.camera.getPicture(function(imageData) { if (imageData.indexOf("localhost") !== -1) { $('.app').css("background-image", "url(" + imageData + ")"); } else { $('.app').css("background-image", "url(data:image/jpg;base64," + imageData + ")"); } $('.app').css("background-size", "100%"); // stretch }, function(message) { alert(message); }, { quality: 50, destinationType: Camera.DestinationType.DATA_URL, targetWidth: $( '.app' ).width(), targetHeight: $( '.app' ).height() }); } return { takePhoto:function(){ _takePhoto(); } }; }(jQuery)); console.log('cam.js');
So, das war's. Ich wünsche viel Spaß und viele neue Ideen mit dieser Technologie.
Fazit
Wir haben mit dem Modul-Muster eine gut strukturierte App gebaut, die Ausgangspunkt für eine saubere Weiterentwicklung sein kann.
Grundlegend für die Projekt-Struktur war das Modul-Pattern für Javascript.
Damit wurde gegenüber der simplen Blog-App aus einem vorherigen Beitrag die Funktionalität erweitert um den wichtigen Spinner, um den Ladezustand einer Seite anzuzeigen sowie eine einfache Kompass- und Foto-Funktionalität implementiert.
In einem späteren Artikel wird dann gezeigt, wie man Module mittels des Frameworks require.js dynamisch laden kann.