📜 ⬆️ ⬇️

Developing an application for Firefox OS with a real example

image Mobile applications created using web technologies are gradually capturing the world. But the creation of such applications, under popular platforms, is associated with a bunch of problems - from unknown bug histories, zoo screen sizes, to performance problems that cannot be solved simply by rewriting thin places.

But fortunately, this topic will not be filled with the everyday tragedy of development, similar applications. Since today, I will show with a real example how to develop applications under Firefox OS, which support most of the modern web technologies, and generally speaking, it was created for them and thanks to them.


')

Recipe


For the preparation we need:
0) Api of any service, in our case it is PhotoFania (do not consider it an advertisement).
1) Angular js - as a basis
2) buildingfirefoxos.com/building-blocks - blank ui-blocks
3) jQuery and others to taste

0) Api

Since I want to show the real application, then api should use the real one. Photofania is a website with which you can create funny photos from your boring selfies. So we, a little, will have to work with images on the client (although the main work will take place on the server, of course).

1) Angular js

Angular is good. Of course, I have a touch to it, in terms of performance on mobile devices, but it allows me to move away from the routine code, updates of elements and other things, being only concerned with data. In addition, the application on Angular effortlessly turns out perfectly structured.

2) Building Blocks

Building Blocks are pre-made design elements taken (partially) from Gaia's source code - the Firefox OS UI layer. These blanks do not use js, all the logic that exists there is implemented through pseudo-selectors. In this case, all the code is written using html5 elements, and uses data- * attributes to denote the role of the block.

I also noticed an important thing - the Building Blocks code is faster and smoother than the code I wrote myself, no matter how hard I try. At least it concerns lists. Perhaps certain elements are accelerated natively - not sure how true this is. So if possible, use blanks - they speed up development, make the application look like a native one and make it smoother.

3) jQuery and other

Generally speaking, I would gladly get rid of jQuery, but it is a dependency plugin for pinch zoom github.com/segdeha/jquery-pan-zoom . Putting a plugin on Zepto failed. Fortunately, jQuery can be built from those pieces that you need. Therefore, I ruthlessly got rid of SIzzle and other unnecessary things in everyday life.

Little about the structure



The structure of the application everyone uses what he wants. In my case, it looks like

/build/ /build.js /build.css /scripts/ /vendors/ /controllers/ /services/ /.../ /app.js /dictionary.js /config.js /styles/ /helpers/ /variables.less /mixins.less /main.less /header.less /... /images/ index.html 


Scripts and styles are built using grunt in real time. And grunt release is already minifying everything. I also use grunt-angular-templates which turns all templates into js code, which is also added to build.js

Initial page layout



 <!doctype html> <html ng-app="PhotoFunia" ng-csp> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta charset="UTF-8"> <title>PhotoFunia</title> <link rel="stylesheet" href="build/build.css"/> </head> <body role="application"> <!-- ,    .       ,      --> <section ng-controller="PreloaderController"> <div id="preloader" ng-hide="preloaderHide"> <div class="preloader-content"> <div class="logo"></div> </div> </div> </section> <!--    ()     --> <section data-type="sidebar" ng-include="VIEWS.DRAWER"></section> <!--   .      id="drower"    building blocks --> <section id="drawer" role="region" ng-view ng-class="{'menu-opened': drawerOpened}"></section> <!--   toast  FF OS. http://buildingfirefoxos.com/building-blocks/status.html --> <section role="status" ng-controller="ToastController"> <p ng-if="text" ng-bind="text"></p> </section> <!--       --> <section ng-include="VIEWS.POPUP"></section> <script src="build/build.js"></script> </body> </html> 


Important

I think some have noticed the ng-csp in the element. This directive includes support for the Content Security Policy - and this is required to create an application for Firefox OS. In addition, we need to patch a little angular himself!
We are looking for the angular line window.XMLHttpRequest(); and replace it with window.XMLHttpRequest({mozSystem: true});
And also we need to add with our hands to our styles - angular.js auxiliary styles. Namely - code.angularjs.org/1.2.16/angular-csp.css

Little bit about js



It should be noted that I initially write coffeescript code, but I will show you its javascript counterpart. Perhaps somewhere inaccuracies will emerge - then we will fix them together.
I also hope that you know angular and js well enough so that I don’t stop at every step. Otherwise, nobody ever read this article.

Multilingual

Our application will be multilingual. Therefore, we need a dictionary, its interpreter, and some kind of directive or filter to insert words into the code. Often when it comes to multilingualism with the help of angular - some filters appear that do not look very nice. For example, we are offered to write it this way me a little korezh - why call an extra function every time and write such inconvenient code if you can just use the dictionary in the global skoupe and access it? Like this. For all the time of my work, this method did not let me down. Let us realize it.

I want it to be any nesting, support any number of languages. No problem!
 var DICTIONARY = { header: { search: { title: { ru: '', en: 'Search' }, favorites: { ru: '', en: 'Favorites' } } }, cancel: { ru: '', en: 'Cancel' } }; 


The structure is there, now, in order not to access the variable directly (and not the language), you need to write a small parser.

 App.run(['$rootScope', function ($rootScope) { var lang = 'ru'; //    -  :) $rootScope.m = (function() { var parse = function(obj, result) { result = result || {}; for (var key in obj) { var value = obj[key]; if (typeof value !== "object") return obj[lang]; result[key] = parse(value); } return result; }; return parse(DICTIONARY); })(); }]); 


That is, we simply recursively reach the moment when the value of the variable becomes not an object, and return the value with the desired language. Everything is simple, and now we have the variable m in the root-scopes, to which we can safely refer.
Someone will doubt the performance of such a solution, but I can assure you that this is a drop in the ocean. In general, no one bothers you to write a directive that will not hang a variable hatcher. So everything is fine.

Back to the markup



Let's finish the drawer (Menu). Suppose we already have a base in the form of js. There is a controller that serves our menu, and we have already received using api a list of categories that we will display in the menu. Then the menu code is very simple.

As you can see, in our index.html markup, we have already used part of the code from Building Blocks. Now we take the code of Drawer'a and slightly change for themselves. buildingfirefoxos.com/building-blocks/drawer.html

 <nav ng-controller="DrawerController"> <div class="empty-space"></div> <ul> <li> <a ng-click="go('/favorites'); closeDrawer()"> <span class="text" ng-bind="m.menu.favorite"></span> <span class="counter" ng-bind="favorite.get().length"></span> </a> </li> </ul> <h2 ng-bind="m.category.title"></h2> <ul> <li ng-repeat="cat in categories"> <a ng-click="openCategory(cat.key)"> <span class="text" ng-bind="cat.title"></span> <span class="counter" ng-bind="cat.count"></span> <span class="new-counter" ng-if="cat.new_count" ng-bind="'+'+cat.new_count"></span> </a> </li> </ul> </nav> 


As you can see, we have two lists in the menu, at the very top there is only one link to the favorites (notice that we already use our variable m?), The number of selected photo effects is also displayed on the side. Below we have, in fact, the list of categories.

And for the sake of completeness we will make another page - the list of effects, that is, the category page.
buildingfirefoxos.com/building-blocks/headers.html - here we take headers
buildingfirefoxos.com/building-blocks/lists.html - here are the lists
buildingfirefoxos.com/building-blocks/filters.html - here filters (tabs)
buildingfirefoxos.com/building-blocks/buttons.html - and here are the buttons

And we get, simply, something like this:

 <!--  ,   --> <header> <menu type="toolbar"> <!--    --> <a ng-click="go('/search')"> <span class="icon action-icon search"></span> </a> </menu> <!--     /   (drawer) --> <a ng-click="closeDrawer()"><span class="icon icon-menu"></span></a> <a ng-click="openDrawer()"><span class="icon icon-menu"></span></a> <h1 ng-bind="category.title"></h1> </header> <div role="main" data-type="list" id="category"> <!-- ,     --> <ul role="tablist" data-type="filter" data-items="2"> <li role="tab" aria-selected="{{ sorting === 'new'}}"> <a ng-click="setSorting('new')" text="m.category.new"></a> </li> <li role="tab" aria-selected="{{ sorting === 'popular'}}"> <a ng-click="setSorting('popular')" text="m.category.popular"></a> </li> </ul> <!--      --> <ul class="effects"> <li ng-repeat="effect in effects" ng-click="openEffect(effect.key)"> <aside class="pack-end"> <img ng-src="{{CONFIG.DOMAIN + effect.icon}}"> </aside> <a> <p ng-bind="effect.title"></p> <p ng-if="effect.labels"> <span ng-repeat="label in effect.labels" ng-class="label" class="label"></span> </p> </a> </li> </ul> <!--     --> <div class="load-more" ng-if="isNeedMore && effects.length"> <button ng-click="showMore()" text="m.category.show_more"></button> </div> </div> 


I hope everything is clear. And we need to understand the following: we take the finished blocks and cut out the most necessary of them. They can twist and twist as you like.
All other pages are made in the same way.

About the Firefox OS API



In Firefox OS applications> = 1.3 input [file] will not work, in return, we are offered to use MozActivity. That even simplifies the work.

This is how getting the picture:
 var pick = new MozActivity({ name: "pick", data: { type: ["image/*"], nocrop: true } }); pick.onsuccess = function() { var blob = pick.result.blob; // -    }; 


Here is the sharing:
 new MozActivity({ name: "share", data: { type: "image/*", number: 1, blobs: [blob] } }); 


And something like this - saving:
 var sdcard = navigator.getDeviceStorage("sdcard"); var request = sdcard.addNamed(blob, name); request.onsuccess = function() {}; request.onerror = function() {}; 


After the application is ready, it must be knocked down and tested.

To build - you can use emulators.
I suggest you use the Application Manager, which is built into the newer versions of firefox by default. developer.mozilla.org/ru/docs/Mozilla/Firefox_OS/Using_the_App_Manager . Here you can install different versions of emulators, connect devices and debug! Which is very convenient.

We also need an application manifest. It looks and is written very simply.
I will give an example:
 { "name": "PhotoFunia", "description": "PhotoFunia is the best way to add a spark to your photos, make them special and more original.", "launch_path": "/index.html", "version" : "1", "type": "privileged", "developer": { "name": "", "email" : "" }, "default_locale": "en", "icons": { "256": "/images/app_icon_256.png" }, "permissions": { "device-storage:pictures": { "description": "Save result images", "access": "readwrite" }, "device-storage:sdcard": { "description": "Save result images", "access": "readwrite" }, "mobilenetwork": { "description": "Check for available connection" }, "systemXHR": { "description": "Need for internet connection" } } } 


Strictly speaking, we thrust all the necessary files into a .zip archive and send it to marketplace.firefox.com for review. After a couple of days (and maybe in the evening) the application will appear in the market!

What was it?


I wanted to convey to you that developing under Firefox OS is very simple, interesting and fun! Of course, for now, money cannot be made on this. But you might think, we are here for the money gathered. So, take IDE in hand, and create applications under Firefox OS!

Those, the best of us, who have a device on Firefox OS - ask to the table marketplace.firefox.com/app/photofunia

All wishes, as well as errors and omissions I accept in a personal.

Source: https://habr.com/ru/post/218819/


All Articles