Skip to main content

20 posts tagged with "FirefoxOS"

View All Tags

· 3 min read

This time, its different. The transpilers are build-time polyfills that fill the gap of current browser/server implementation and the newest JS/CSS specs.

Transpilers trans-compile Javascript and CSS to current workable version, so developers could be more productive with JS/CSS latest features and transpilers would translate them into current supported version of code.

From my opinion the most useful es6 feature is arrow functions (=>) which comes from coffeescript. This syntax sugar bind the this value automatically, so developer wont forgot the binding anymore.

The original code is

(function() {
‘use strict’;
document.addEventListener(‘DocumentLocalized’, function() {
// App.init();
}.bind(this));
}());

We can use arrow function to replace function() {}.bind(this) to () => {}

(function() {
‘use strict’;
document.addEventListener(‘DocumentLocalized’, () => {
// App.init();
});
}());

Currently the arrow functions only default enabled on Firefox. So developer could not use this directly on their project. With babel javascript transpiler the js could be translated to current workable version automatically.

(function() {
‘use strict’;
document.addEventListener(‘DocumentLocalized’, function() {
// App.init();
});
}());

The transpiler will know the content does not need 'this' reference and skip the binding. Note the Javascript transpiler still stick into vanilla javascript. It does not invent new syntax, but it make new specs could be used or experiment in current environment.

From CSS perspective, CSS variables brings variables into CSS. Pre-define some color and use everywhere on project is possible.

The origin style is

a {
color: #847AD1;
}

pre {
padding: 10px;
}

It's frustrated when the stylesheets expand larger and we need to change the new color or size everywhere.

We can use CSS variables to predefine the changeable stuff into pseudo ':root' element.

:root {
–maincolor: #847AD1;
–size: 10px;
}

a {
color: var(–maincolor);
}

pre {
padding: var(–size);
}

Looks good. But the same situation occurred. Currently the CSS variables only support on Firefox. So developer could not use this directly on their project. With myth CSS transpiler the CSS could be translated to current workable version automatically.

a {
color: #847AD1;
}

pre {
padding: 10px;
}

Note the CSS transpiler still stick into CSS specs. It does not invent new syntaxes like LESS or SASS does. It just make new CSS specs could be used or experiment in current environment.

Besides the feature polyfill, running transpiler before deploy also help developer catch out the error since transpiler will traverse the source and parsing syntaxes. Transpiler will bark you when any error in your source.

You may wonder setup an environment with above JS/CSS transpiler seems take some time. webapplate 2.3.0 already integrated with babel  and myth grunt tasks to auto transpile your JS/CSS code to current workable version. webapplate jshint/githook also support es6 syntax validation (yes the .jshintrc is exactly borrowed from gaia project), so your project is future proved and keep maintainable.

· 2 min read

Claim: this exercise is for experiment, not for product.

According to wikipedia, f.lux adjusts a computer display's color temperature according to its location and time of day. I always use it on my Mac to make my eyes more comfortable at night.

So, the topic is about if we can bring that experience on Firefox OS. Adjust display's color temperature generally is a system specific issue. But actually it can be categorized as an CSS trick if we like to make it on web (a gist to mimic the f.lux effect).

To quick experiment if it doable or not, the validation steps are:

1. open the WebIDE on Firefox Developer Edition 2. download and open emulator (I choose v2.2) on WebIDE. 3. To debug system app, choose System from top left selector in WebIDE. 4. once connected,  select the html tag and add style **filter: brightness(0.8) sepia(0.9);** into the element.

The live view changed to f.lux like color temperature.

So it works!

To make it persistent on real device, edit [gaia/apps/system/style/system/system.css](https://github.com/mozilla-b2g/gaia/blob/master/apps/system/style/system/system.css#L5), add above style into html tag. Run make reset-gaia then you have the style applied on device.

What's Next

The above experiment will change your device's color temperature permanently, which is not what f.lux do. To make it as option, you can add an option in settings > developer panel and add a observer in system to dynamically add such style into system html tag.

If you feel the strong desire to have such feature happen on Firefox OS device, fire a bug on bugzilla.

· One min read

 

There are several source code visualization tools available for choose. I've tried Code Swarm long time ago and this time I'd like to try something that can be done on web directly. So, here's the Gaia source code visulization rendered by CodeFlower via D3.js.

The prosperity of blossom denotes different

 

Orange is the settings app flower. The upperside are modulized setting panels. We can see good order of them. The downside crowds are things that not that modularized.

 

The purple sparkled flower is gaia web components. The main part is gaia-header, the top left part is gaia-grid.

The system app is a flower with a more concrete shape.

The calendar app (in yellow) looks like a pretty Dandelion.

 What about others? go Gaia source code visulization and check by yourself. (The repo is a digest from 2015/1/7 master)

And you can make your own by forking CodeFlower from github.

· 13 min read

前陣子 Facebook 推出一套名為 FLUX 的前端程式架構,期望能幫過去沒有條理,程式多了結構就亂得像一團麵條的 Javascript 程式寫法找到一個理想的組織方法。

FLUX 簡介

視圖(View)-> 操作(Action)-> 分配器(Dispatcher)-> 資料處理器(Store)-> 繪圖者(Renderer)-> 視圖(View) FLUX 的基本原理有別於常用的 MVC(Model/View/Controller)或 MVVM(Model/View/ViewModel)是在 M,V,C(VM)三者之間互相傳遞或修改資料,

 

MVC (image from fluxxer)

FLUX 重新定義整個組織架構為單向的視圖(View)-> 操作(Action)-> 分配器(Dispatcher)-> 資料處理器(Store)-> 繪圖者(Renderer)->  視圖(View)的運作流程。

FLUX (image from fluxxer)

就我的理解,FLUX 的架構可以拆分為三個重點流程:

  • 跟視圖(View)有關的操作(Action),都透過事件註冊到分配器(Dispatcher)去。
  • 分配器 (Dispatcher)負責將操作(Action)傳遞給需要的資料處理器(Store)。
  • 資料處理器(Store)負責跟資料直接相關的操作。若資料處理器(Store)修改的結果需要反映到視圖(View)上,可以透過發送訊息通知給繪圖者(Renderer)處理。這邊講到了原本 FLUX 概念圖中沒有提到的繪圖者(Renderer)這個角色,在 Facebook 中他們是用 ReactJS 處理。

瞭解其基本架構之後,我發現其實就算不用他們提供的函式庫,用 Javascript 內建的 addEventListener, handleEvent, customEvent 等方法,也可以利用前面所提的三個重點,漸進寫出符合 FLUX 精神的程式。

目前的 JS 組織方式

一個常見的 JS 檔案,一般的架構是

var App = {    init: function app_init() {       // get view       this.view1 = document.getElementById('xxx1');       this.view2 = document.getElementById('xxx2');             // do stuff       this.view1.addEventListener('click', function() {         // do something       });       this.view2.addEventListener('keyup', function() {         // do something       });     } }; 若我們想要將視圖(View)的操作從 init 分離開來,大部分的人會這樣做

 var App = {     init: function app_init() {       // get view       this.view1 = document.getElementById('xxx1');       this.view2 = document.getElementById('xxx2');             // do stuff       this.view1.addEventListener('click', this.clickView1);       this.view2.addEventListener('keyup', this.keyupView2);     },

    clickView1: function app_clickView1() {        // do something     },

    keyupView2: function app_keyupView2() {        // do something     }

}; 如果在 clickView1 或 keyupView2 中要呼叫到 App 裡的參數或方法,那麼我們需要在 addEventListener 時使用 bind (this)

 var App = {     init: function app_init() {       // get view       this.view1 = document.getElementById('xxx1');       this.view2 = document.getElementById('xxx2');             // do stuff       this.view1.addEventListener('click', this.clickView1.bind(this));       this.view2.addEventListener('keyup', this.keyupView2.bind(this));     },

    clickView1: function app_clickView1() {        // do something     },

    keyupView2: function app_keyupView2() {        // do something        this.clickView1();     }

}; 大多數書籍的範例大概就停在這裡,沒有再進一步探討程式的組織架構了。即使是龐大的 Javascript 專案如 Gaia,不少部分的程式碼組織方式也是如此。在這種組織方式裡,若有很多的視圖(View)需要操作或修改,我們的程式碼就會開始亂起來。

下面來試著將以上程式漸進改為 FLUX 架構。

改進建議一:將 handleEvent 當作 Dispatcher 來使用

跟視圖(View)有關的操作(Action),都透過事件註冊到分配器(Dispatcher)去。 (溫馨提示:IE 9 以上版本才有支援 handleEvent 方法,在之前版本上使用要加 polyfill)

我們先來想想看視圖(View)跟操作(Action)在前端 Javascript 程式中分別代表著什麼。 視圖(View)很明顯,就是透過 getElementById 等方法,從 HTML 中取得代表對應節點(Node)的元素(element)。

若想要套用 FLUX 架構,我們可以將附加在各個元素(element)上的事件行為分離,將事件註冊到一個統一的地方(分配器),在這個地方對不同的事件進行操作。

 Javascript 內建的分配器叫做 handleEvent,它可以拿來處理任何事件 Event,寫法如下。

 var App = {     init: function app_init() {       // get view       this.view1 = document.getElementById('xxx1');       this.view2 = document.getElementById('xxx2');             // do stuff       this.view1.addEventListener('click', this);       this.view2.addEventListener('keyup', this);     },

    handleEvent: app_handleEvent(evt) {        switch (evt.type) {          case 'click':            switch (evt.target) {               case this.view1:                 this.clickView1();                 break;            }            break;          case 'keyup':             switch (evt.target) {               case this.view2:                 this.keyupView2();                 break;             }        }     },

    clickView1: function app_clickView1() {        // do something     },

    keyupView2: function app_keyupView2() {        // do something        this.clickView1();     }

}; 這麼做帶來的明顯好處是所有的呼叫都統一在 handleEvent 中,可以更容易地追查到。

這麼寫也可以在 addEventListener/removeEventListener 時不用使用 bind (this),而 bind (this) 經常有些 side effect 需要特別留意。

例如假使我們想要反註冊 view1 上的 click 方法,使用以下寫法

 this.view1.removeEventListener ('click', this.clickView1.bind (this)); 其實並沒有將第一個 event 移除。因為使用了 .bind(this) 後,回傳的其實是一個新的 instance...。 正確的寫法是 this.bindClickView1 = this.clickView1.bind (this) this.view1.addEventListener ('click', this.bindClickView1); ... this.view1.removeEventListener ('click', this.bindClickView1); 用 handleEvent 可以省點事,要反註冊時也傳入 this 即可。 this.view1.removeEventListener ('click', this);

改進建議二:將資料處理的部分分離,使用自訂事件來改變 Store 狀態

分配器 (Dispatcher)負責將操作(Action)傳遞給需要的資料處理器(Store) 資料處理器(Store)負責跟資料直接相關的操作。在稍大的 Web App 中,我們可以另外定一個 Object 來處理資料相關的事宜。一般我們的寫法會是

// Store.js function Store() {   this._data: 0; };

Store.prototype = {   getSomething: function s_getSomething() {     return this._data;   },

  doSomething: function s_doSomething() {     this._data += 1;   },

  setSomething: function s_setSomething(val) {     this._data = val;   } };

// App.js var App = {   this.store = new Store();   this.store.init();   this.store.getSomething();   this.store.doSomething();   this.store.setSomething (2); }; 若想要套用 FLUX 架構,首先我們要避免從資料處理器(Store)外部直接改變資料處理器(Store)。我們可以透過在呼叫端使用 window.DispatchEvent 發送自訂事件(CustomEvent),並在資料處理器(Store)中接收自訂事件來做到。

如此一來,資料處理器(Store)將只留下 get 方法來讓外部取得 Store 想提供的資料。

另外如果程式碼改善進入到下一個重點,在操作(Action)時應該不需要再呼叫 Store.getSomething 了,我們將資料處理器(Store)的 getSomething 方法留著給繪圖者(Renderer)使用 。

// Store.js function Store() {   this._data: 0; };

Store.prototype = {   init: function s_init() {      window.addEventListener('store_do', this);      window.addEventListener('store_set', this);   },

  handleEvent: s_handleEvent(evt) {     switch(evt.type) {       case 'store_do':         this.doSomething();         break;       case 'store_set':         this.setSomething(evt.detail.val);         break;     }   },

  getSomething: function s_getSomething() {     return this._data;   },

  _doSomething: function s_doSomething() {     this._data += 1;   },

  _setSomething: function s_setSomething(val) {     this._data = val;   } };

// App.js var App = {   this.store = new Store();   this.store.init();   //this.store.getSomething();   window..dispatchEvent(new CustomEvent('store_do'));   **window..dispatchEvent(new CustomEvent('store_set',**     {'detail':{'val':2}}   )); }; 這麼做帶來的明顯好處是測試時可以簡單地將 Store 與 App 分開來測試,這對大型 App 是很重要的。

改進建議三:讓 Renderer 來處理視圖

若資料處理器(Store)修改的結果需要反映到視圖(View)上,可以透過發送訊息通知給繪圖者(Renderer)處理 > //  Renderer.js var ClickRenderer = {   init: function s_init(element, Store) {      this.element = element;      this.store = Store;      window.addEventListener('render_view1', this);   },

  handleEvent: s_handleEvent(evt) {     switch(evt.type) {       case 'render_view1':         this.element.textConent = this.store.getSomething();         break;     }   }};

// Store.js function Store() {   this._data: 0; };

Store.prototype = {   init: function s_init() {      window.addEventListener('store_do', this);      window.addEventListener('store_set', this);   },

  handleEvent: s_handleEvent(evt) {     switch(evt.type) {       case 'store_do':         this.doSomething();         break;       case 'store_set':         this.setSomething(evt.detail.val);         break;     }   },

  getSomething: function s_getSomething() {     return this._data;   },

  _doSomething: function s_doSomething() {     this._data += 1;     window..dispatchEvent(new CustomEvent('render_view1'));   },

  _setSomething: function s_setSomething(val) {     this._data = val;   } };

// App.js var App = {   init: function a_init() {     // get view     this.view1 = document.getElementById('xxx1');     this.view2 = document.getElementById('xxx2');     this.store = new Store();     this.store.init();     ClickRenderer.init(this.view1, **this.store);**   },

    handleEvent: a_handleEvent(evt) {     window..dispatchEvent(new CustomEvent('store_do'));     //Store.setSomething(2)     window..dispatchEvent(new CustomEvent('store_set',       {'detail':{'val':2}}     )); }; 上段程式在 App 中註冊了 ClickRenderer,並傳入 Store 與 所需的 View 元件。所有的介面更新全交由 ClickRenderer 處理。

(另一個方法是讓繪圖者(Renderer)監看資料處理器(Store)的狀態,然後去改變視圖(View))  http://fluxxor.com/documentation/store-watch-mixin.html

總結

整理完後,一般 javascript 套用 flux 架構的運作流程如下:

簡而言之,上面的各種建議是鼓勵大家多使用 Javascript 內建的 addEventListener, handleEvent, customEvent 等方法。透過大量使用 event,我們可以改善 Javascript 程式邏輯,資料,與介面元件之間的關聯程度。

將 FLUX 架構拆分為三個重點流程來理解或實踐的好處,是我們能漸進地遵循其中一些方法來改善我們現有的程式架構。

以上是我關於如何使用 FLUX 架構在一般 Javascript 組織方式的第三個版本,可能有些錯謬之處,還迎大家討論或給予建議。

· 2 min read

FoxBox is the project that intent to provide a battery included Firefox OS build environment.

The goal of foxbox is to try any approach that make new user can do as less as possible to start the FirefoxOS development

Our first take is use vagrant with virtualbox to make major platform users can try FirefoxOS dev in VM.

It will be great to setup the current version of foxbox in your desktop environment

http://github.com/gasolin/foxbox

And record obstacles you encountered here https://github.com/gasolin/foxbox/issues?state=open. There are some issues (but not the limit) that might be worth to do in the future version of foxbox.

Note that you require a desktop with INTEL VT-x/AMD-V hardware virtualization support(Windows8 or Mac already enabled it), at least 4GB RAM and about 10~40GB disk space(for gaia or full B2G development).

FoxBox has been approved by the Google Summer of Code administrator http://wiki.mozilla.org/Community:SummerOfCode14 , so its perfect time to step up, try FoxBox, fix issues that every others will encounter, save everybody's time and start make your own Firefox OS phone.

If you'd like to contribute FoxBox for SummerOfCode14. We expect you could find out the interesting topic you want to contribute or any other way that can better achieve FoxBox's goal.