├── .htaccess ├── images ├── icon-128.png ├── icon-512.png └── battery.svg ├── battery.appcache ├── README.md ├── manifest.webapp ├── index.html ├── scripts ├── install.js └── battery.js ├── style └── style.css └── LICENSE /.htaccess: -------------------------------------------------------------------------------- 1 | AddType application/x-web-app-manifest+json .webapp -------------------------------------------------------------------------------- /images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/battery-quickstart-finished-example/gh-pages/images/icon-128.png -------------------------------------------------------------------------------- /images/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/battery-quickstart-finished-example/gh-pages/images/icon-512.png -------------------------------------------------------------------------------- /battery.appcache: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | # v3 2014-06-24 3 | 4 | CACHE: 5 | 6 | index.html 7 | manifest.webapp 8 | scripts/battery.js 9 | scripts/install.js 10 | style/style.css 11 | images/battery.svg 12 | images/icon-128.png 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | battery-quickstart-finished-example 2 | =================================== 3 | 4 | The finished version of the example built up in the "Your first app" tutorial found in the Mozilla Developer Network [open web app Quickstart](https://developer.mozilla.org/en-US/Apps/Quickstart#Your_first_app) article. 5 | -------------------------------------------------------------------------------- /manifest.webapp: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Battery", 3 | "description": "Battery provides a good template for an in-app battery/charge indicator with different visualization choices, plus ideas of what could be changed once battery level gets low.", 4 | "launch_path": "/index.html", 5 | "icons": { 6 | "128": "/images/icon-128.png", 7 | "512": "/images/icon-512.png" 8 | }, 9 | "developer": { 10 | "name": "Chris Mills", 11 | "url": "http://www.conquestofsteel.co.uk" 12 | }, 13 | "permissions": { 14 | "desktop-notification": { 15 | "description": "Needed for creating system notifications." 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /images/battery.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Lightning Bolt designed by Frontera Taller de Arquitectura from The Noun Project.
30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /scripts/install.js: -------------------------------------------------------------------------------- 1 | // get a reference to the install button 2 | var button = document.getElementById('install'); 3 | 4 | // if browser has support for installable apps, run the install code; it not, hide the install button 5 | if('mozApps' in navigator) { 6 | 7 | // define the manifest URL 8 | var manifest_url = location.href + 'manifest.webapp'; 9 | 10 | function install(ev) { 11 | ev.preventDefault(); 12 | // install the app 13 | var installLocFind = navigator.mozApps.install(manifest_url); 14 | installLocFind.onsuccess = function(data) { 15 | // App is installed, do something if you like 16 | }; 17 | installLocFind.onerror = function() { 18 | // App wasn't installed, info is in 19 | // installapp.error.name 20 | alert(installLocFind.error.name); 21 | }; 22 | }; 23 | 24 | // if app is already installed, hide button. If not, add event listener to call install() on click 25 | var installCheck = navigator.mozApps.checkInstalled(manifest_url); 26 | installCheck.onsuccess = function() { 27 | 28 | if(installCheck.result) { 29 | button.style.display = "none"; 30 | } else { 31 | button.addEventListener('click', install, false); 32 | }; 33 | }; 34 | } else { 35 | button.style.display = "none"; 36 | } -------------------------------------------------------------------------------- /style/style.css: -------------------------------------------------------------------------------- 1 | /* || basic set up + sizing for containers */ 2 | 3 | html, body { 4 | margin: 0; 5 | } 6 | 7 | html { 8 | width: 100%; 9 | height: 100%; 10 | font-size: 20px; 11 | font-family: 'Pathway Gothic One', sans-serif; 12 | background-color: white; 13 | } 14 | 15 | body { 16 | width: 100%; 17 | height: inherit; 18 | } 19 | 20 | .text-indicator { 21 | display: inline-block; 22 | color: white; 23 | background-color: gray; 24 | background: linear-gradient(to bottom, rgba(0,0,0,0.4),rgba(0,0,0,0.75)); 25 | border-radius: 5px; 26 | box-shadow: 1px 1px 1px black; 27 | text-shadow: 1px 1px 1px black; 28 | border: 1px solid gray; 29 | padding: 0.5rem; 30 | margin: 1rem; 31 | } 32 | 33 | .text-indicator p { 34 | margin: 0; 35 | } 36 | 37 | h1, body > p { 38 | margin-left: 1rem; 39 | } 40 | 41 | /* || install button */ 42 | 43 | #install { 44 | font-size: 1rem; 45 | line-height: 1.8rem; 46 | border-radius: 5px; 47 | border: 1px solid black; 48 | background: linear-gradient(to bottom, #7B72D8, #2618B1); 49 | color: white; 50 | text-shadow: 1px 1px 1px black; 51 | border: 1px solid rgba(0,0,0,0.1); 52 | box-shadow: inset 0px 5px 3px rgba(255,255,255,0.2), 53 | inset 0px -5px 3px rgba(0,0,0,0.2); 54 | margin: 1rem; 55 | } 56 | 57 | /* || visual battery indicator */ 58 | 59 | .icon-indicator { 60 | position: relative; 61 | width: 4rem; 62 | height: 3.1rem; 63 | background-color: gray; 64 | background: linear-gradient(to bottom, rgba(0,0,0,0.2),rgba(0,0,0,0.55) 70%); 65 | margin: 1rem; 66 | border-radius: 2px; 67 | } 68 | 69 | #battery-top { 70 | position: absolute; 71 | height: 1.3rem; 72 | width: 0.7rem; 73 | top: 0.9rem; 74 | right: -0.7rem; 75 | background-color: gray; 76 | background: linear-gradient(to bottom, rgba(0,0,0,0.1),rgba(0,0,0,0.55) 70%); 77 | border-radius: 0 2px 2px 0; 78 | } 79 | 80 | #battery-charge { 81 | position: absolute; 82 | left: 0; 83 | height: 3.1rem; 84 | background-color: yellow; 85 | background-image: linear-gradient(to bottom, rgba(0,0,0,0),rgba(0,0,0,0.3) 70%); 86 | } 87 | 88 | #battery-charging { 89 | position: absolute; 90 | left: 0; 91 | height: 3.1rem; 92 | width: 4rem; 93 | background: url(../images/battery.svg) center no-repeat; 94 | background-size: 60% 70%; 95 | } -------------------------------------------------------------------------------- /scripts/battery.js: -------------------------------------------------------------------------------- 1 | // fork the navigator.battery object depending on what prefix the viewing browser uses 2 | var battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery; 3 | 4 | // grab the elements we need, and put them in variables 5 | var indicator1 = document.getElementById('indicator1'); 6 | var indicator2 = document.getElementById('indicator2'); 7 | var batteryCharge = document.getElementById('battery-charge'); 8 | var batteryTop = document.getElementById('battery-top'); 9 | var chargeIcon = document.getElementById('battery-charging'); 10 | 11 | // Flag to check if battery charged/not charged has already been notified once 12 | // 0 for first time of notification, 1 means "charged" has already been notified, 13 | // 1 means "not charged" has already been notified 14 | // This is set to the opposite after each notification, so that you don't keep 15 | // getting repeat notifications about the same charge state. 16 | var chargingState = 0; 17 | 18 | function updateBatteryStatus() { 19 | // battery.level can be used to give us a percentage of bettery charge to report to 20 | // the app's user 21 | var percentage = Math.round(battery.level * 100); 22 | indicator1.innerHTML = "Battery charge at " + percentage + "%"; 23 | batteryCharge.style.width = percentage + '%'; 24 | 25 | if(percentage >= 99) { 26 | // report that the battery is fully charged, more or less ;-) 27 | batteryTop.style.backgroundColor = 'limegreen'; 28 | batteryCharge.style.backgroundColor = 'limegreen'; 29 | 30 | createNotification("Device battery fully charged."); 31 | } 32 | 33 | if(battery.charging) { 34 | // If the battery is charging 35 | if(chargingState == 1 || chargingState == 0) { 36 | // and if our chargingState flag is equal to 0 or 1 37 | 38 | // alter the styling to show the battery charging 39 | batteryTop.style.backgroundColor = 'gold'; 40 | batteryCharge.style.backgroundColor = 'gold'; 41 | indicator2.innerHTML = "Battery is charging"; 42 | chargeIcon.style.visibility = 'visible'; 43 | 44 | // notify the user with a custom notification 45 | createNotification("Device battery now charging."); 46 | 47 | // flip the chargingState flag to 2 48 | chargingState = 2; 49 | } 50 | } else if(!battery.charging) { 51 | // If the battery is NOT charging 52 | if(chargingState == 2 || chargingState == 0) { 53 | // and if our chargingState flag is equal to 0 or 2 54 | 55 | // alter the styling to show the battery NOT charging 56 | batteryTop.style.backgroundColor = '#eee'; 57 | batteryCharge.style.backgroundColor = '#eee'; 58 | indicator2.innerHTML = "Battery not charging"; 59 | chargeIcon.style.visibility = 'hidden'; 60 | 61 | // notify the user with a custom notification 62 | createNotification("Device battery is not charging."); 63 | 64 | // flip the chargingState flag to 1 65 | chargingState = 1; 66 | } 67 | } 68 | } 69 | 70 | function createNotification(message) { 71 | 72 | // Let's check if the browser supports notifications 73 | if (!"Notification" in window) { 74 | console.log("This browser does not support notifications."); 75 | } 76 | 77 | // Let's check if the user is okay to get some notification 78 | else if (Notification.permission === "granted") { 79 | // If it's okay let's create a notification 80 | 81 | // show the notification 82 | var notification = new Notification('Battery status', { body: message }); 83 | 84 | // And vibrate the device if it supports vibration API 85 | window.navigator.vibrate(500); 86 | } 87 | 88 | // Otherwise, we need to ask the user for permission 89 | // Note, Chrome does not implement the permission static property 90 | // So we have to check for NOT 'denied' instead of 'default' 91 | else if (Notification.permission !== 'denied') { 92 | Notification.requestPermission(function (permission) { 93 | 94 | // Whatever the user answers, we make sure Chrome stores the information 95 | if(!('permission' in Notification)) { 96 | Notification.permission = permission; 97 | } 98 | 99 | // If the user is okay, let's create a notification 100 | if (permission === "granted") { 101 | 102 | // show the notification 103 | var notification = new Notification('Battery status', { body: message }); 104 | 105 | // And vibrate the device if it supports vibration API 106 | window.navigator.vibrate(500); 107 | } 108 | }); 109 | } 110 | } 111 | 112 | // Event handler to check whether the battery has started charging or stopped charging 113 | battery.addEventListener("chargingchange", updateBatteryStatus, false); 114 | // Event handler to check whether the battery charge level has changed 115 | battery.addEventListener("levelchange", updateBatteryStatus, false); 116 | 117 | // run the central function once when the app is first loaded 118 | updateBatteryStatus(); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 |