十一月 13, 2015
» Setup Firefox OS (Gaia) on Ubuntu 15.10

I got my Dell XPS 13 (9343) for a while and decide to install Ubuntu 15.10 as duel boot.

By following the guide its pretty easy to get a Ubuntu environment.
To setup my daily develop environment, I take the foxbox setup script for 14.04 and everything works fine.

So for windows user who want develop FirefoxOS gaia with real device, I recommend you try foxbox first. If you have more commitment, install the Ubuntu. With duel boot you can keep windows and have a more developer friendly environment to develop connecting devices.

十月 15, 2015
» Quick Settings Enhancement Addon

As the Firefox OS Settings Peer, I still feel its not efficient to toggle everything in Settings, because it needs too many steps such as: 1. Open Settings app, 2. Find proper item, which may located in sub panels, 3. Do the action with that setting.


During hackthon in Taipei last month, Yifan and I made the Quick Settings Enhancement Addon, and now its available on marketplace (within the :debug mode).

How it looks like?



The addon add plenty of Settings switch(NFC, Internet Sharing, Lock Orientation, Battery Saving Mode, Geolocation, Enable USB Storage), Settings shortcut (Developer panel configs), Power menu shortcut (Silence Incomming Calls) and.....the Flashlight to quick settings menu!


We also found it will take a lot of estate of your utility tray, so FYR we'd propose a `at most 2 clicks` mockup to handle those quick settings.


The codebase is at https://github.com/gasolin/fxos-quick-settings
Welcome to contribute.

八月 24, 2015
» FoxBox 1.0, 讓你在一個小時內不痛安裝 Firefox OS 開發環境的設定工具

Here she is!!

要開始開發 Firefox OS 的 Web 端(Gaia),並不像開發一般網站一樣那麼容易。在開始改網頁之前,通常要把相關的開發文件讀一遍/試一遍,才能順利把開發環境設定好。
而把環境設定好可能已經花了半天時間,這時原本想要改程式的精力也所剩不多了。

去年有感於此,花了些時間整合了一套快速設定 Firefox OS 開發環境的工具「FoxBox」,透過 Virtualbox 虛擬機與 vagrant 自動化工具來達成自動部署 Gaia 的開發環境。最近把 FoxBox 基礎作業系統版本升級了一下(使用 Ubuntu 14.04LTS),在 Macbook 或 Ubuntu 桌面電腦上,只需用一個小時左右的時間,就可以自動安裝好整套開發環境。

Vagrant + VM 的優點

使用Vagrant搭配虛擬機(VMWare或免費的Virtualbox)的好處多多,其一是簡化了開發環境的需求,由於主流的作業系統(Windows,Mac,Ubuntu/RedHat)都支援虛擬機,透過在虛擬機上使用單一的作業系統,可以大幅簡化安裝指令。
其二則是自動化安裝,透過 Vagrantfile 指定要執行的指令 (放在scripts資料夾下),最後跑出來的結果只有安裝成功一種。如果失敗了表示自動安裝的指令沒寫好,初級開發者不用在環境安裝時就強迫得學太多細節。
其三是開發環境隔離,命令都跑在VM中,在之後開發或升級的過程中出現任何問題,隨時都可以重新建立一個乾淨的開發環境。

使用 FoxBox 這套開發環境設定工具,當其他人碰到問題時,也可以更容易地重現問題。


透過 Vagrant 設定,FoxBox 提供實體機與虛擬機共享檔案夾,並支援USB實機偵錯。

雖然開發環境隔離,但是 FoxBox 預設的設定即提供實體機與虛擬機共享檔案夾。裝好開發環境後,你依然可以使用目前作業系統上自己習慣的編輯器來修改程式碼,然後在VM中執行命令。

FoxBox 預設也將 USB port 串接到 VM 中,所以在 VM 中也可以直接接收到實機的偵錯訊息 。

設定的流程


連上網路,在主機上執行以下命令

$ git clone https://github.com/gasolin/foxbox.git
$ cd foxbox
$ ./configure.sh

除了開始時需要指定網路介面卡,並輸入主機的密碼(用來和虛擬機共享檔案夾)外,其中大部分的流程都是自動化的。

當VM跑起來後,登入VM(帳號/密碼為 vagrant/vagrant)並執行以下命令:

$ gaia_init.sh
$ cd gaia
$ make

即可順利編譯好Firefox OS 的 Web 端(Gaia)程式碼囉!

六月 8, 2015
» JSDoc generator in Gaia



Last week I've post on dev-gaia to notice the change of JSDoc generator.

Now gaia's jsdoc generator takes standard jsdoc config format from each app's jsdoc.json file. And app owner could customize its look and feel if they prefer to do so.
http://usejsdoc.org/about-configuring-jsdoc.html

Here's the working jsdoc for Firefox OS settings app http://gasolin.github.io/gaia/settings/ .



The trick is done by gulp and shell commands, which can be apply on any other projects. Here's how I did it.


First of all is install required packages

$ npm install gulp gulp-shell jsdoc --save-dev

Then open `gulpfile.js` and add following scripts:

var gulp = require('gulp');
var shell = require('gulp-shell');

gulp.task('jsdoc', shell.task([
  './node_modules/jsdoc/jsdoc.js -c jsdoc.json'
]));

(It's an simplified version because gaia contains 20+ web apps in it, so I add some tree-walking code to create bunch of gulp tasks. But basically its the same)
The simplified version is now available for reuse in webapplate.


Bonus section:

Here's how I upload jsdoc (http://gasolin.github.io/gaia/settings/ , http://gasolin.github.io/gaia/system/) to github gh pages.

Add another section in gulpfile.js with following script

var gulp = require('gulp');
var ghPages = require('gulp-gh-pages');

...

gulp.task('github', ['jsdoc'], function() {
  return gulp.src('./docs/**/*')
    .pipe(ghPages());
});

Run `gulp github` command and the build tool will generate jsdoc and upload to github page automatically.


三月 11, 2015
» Dogfooding FxOS 2.2 one more month



I've finished another iteration of dogfooding with Firefox OS 2.2. This is the version by far I'm pretty enjoy to use in daily base, without a backup Android phone.

Since my main usage of smart phone is browsing news and web sites, the new Browser frame serves me well.

The edge swiping is still awesome. Swipe left to right or vice versa from the off screen is more efficient than task manager.

In task manager, a small `close` button in bottom left of each card, make a more intuitive way to clean a web app.

Some web app made the dogfood more easier.

  • FeedSpider: The news feed via feedly
  • Social
    • Facebook and Twitter: Browse their web site, then add them on Homescreen
  • Map
    • Google Map:  Browse the web site, then add it on Homescreen
  • Note taking
    • Google Keep:  Browse the web site, then add it on Homescreen

The last thing I want to have is the bookmark sync.

Since the dogfooding experience is so positive, I'll challenge with dogfooding nightly build in next month.

三月 1, 2015
» Future proved Javascript and CSS



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.

二月 24, 2015
» Single line of style to bring (keypart of) f.lux on FirefoxOS

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`, 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.

二月 22, 2015
» 2015 年的 4 個 Web 技術趨勢

要預測未來不容易,但根據已經發生的一些蛛絲馬跡,來推測看看一年半載內可能會發生什麼,還是勉力可以為之。

1. Javascript 語法的改進

ECMAScript6 (ES6) 規格已經底定,主流的瀏覽器也已紛紛支援 ES6 的各種特性。好用的諸如 arrow functionpromises 等特性,都已在 Gaia 專案中大量被使用。

要追求專案與舊瀏覽器的相容性,有 Babeltraceur 等轉譯器可供使用。中文英文教學文件也已不少,就安心地用吧。


2. DOM 的改進

去年最紅的前端函式庫當推Facebook提出的 react.js。react.js 提出使用 Virtual DOM 來管理更新與繪製畫面,在不修改現有瀏覽器實作的現況下,提升操作DOM的效能。

Web Component 則是提供了多種新的瀏覽器特性,Gaia 專案裡也已經使用 Web Component 來設計新一代共用的介面元件。Custom Element 特性讓每個開發者可以自行定義新的 HTML 標籤,Shadow DOM 特性則讓每個 HTML 標籤的實作獨立,不會輕易被其他網頁內容改變。

好消息是這些改進是可以共用的




3. HTTPS 大量被採用

(離線存取的改進)


Service Worker 是規劃了多年的重頭戲。Service Worker 提供更完備的離線存取功能。在第一次使用 Web App 時會快取內容,之後再次使用 Web App 時只需更新不同的部分。由於這功能在各瀏覽器中都還在實驗或Beta階段,最快可能是年底上線。因此開發者能大量投入使用的時間點應該是2016年。

無論是 Service worker 或是也剛底定的 HTTP 2.0 草案,都需要運行在加密過的 HTTPS 上。Google 更是為使用 HTTPS 連線的網站提升搜索排序。過去由於證書取得不易,限制了 HTTPS 的使用率。Mozilla 與 Cisco 等廠商今年將合作提供免費的CA證書。當然,也可以透過現在已經存在的 StartSSL服務 來取得免費證書。


4. 預編譯網站

現在比較大型的網站或 web app 都是透過 build script 預做一些 packaging,optimize,或 trans compile 等動作後才部署上線。除了可以壓縮網頁大小以減少載入時間,同時也起到部分保護原始碼的效果。由於 GruntGulp 等工具的流行,預編譯這方面的門檻降低不少。中、小型,甚至個人網站,也可以很容易地使用這些技術來建構網站或Web App。


最後賣瓜一下:webapplate 這個範本已經整合好 grunt based packaging,optimize,trans compile 等動作,新版本也加進了 Babel trans compiler,可以直接使用 ES6 語法開發 web app。要開新 web 專案時歡迎取用。

二月 13, 2015
» webapplate on jsfiddle


In short, here is the jsfiddle link.

In recent article on moztech (in Chinese) I've introduce ghapplate to develop and host web app directly on github. After the post is published, I'm still seeking for a more easier approach. Since github does not provide web preview while editing, you have to save your current work then view it later on browser to see if it's the expect result.

So jsfiddle comes to my mind. Here is a playground that preload the libraries used by ghapplate and webapplate.


It's possible to use jsfiddle to prototype web app as well. What you need is attach `/manifest.webapp` postfix after your jsfiddle link.

jsfiddle and ghapplate are good for quick experiment. If you want to get benefit from optimizer, lint check and more during serious web development, webapplate is still the more maintainable choice.

一月 7, 2015
» Code Flower of Gaia - The firefox OS front end




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.

十二月 4, 2014
» 使用 FLUX 架構的概念,漸進改善一般 Javascript 程式碼的組織方式

前陣子 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 組織方式的第三個版本,可能有些錯謬之處,還迎大家討論或給予建議。


八月 24, 2014
» 一個 WebApp,各自表述

前陣子寫了一篇「像原生應用程式一樣的 WebApp?趕快學起來!」,稍微提到現在 WebApp 在桌面和移動端上已經可以像一般應用程式一樣安裝、移除、離線使用。

再進一步觀之,webapp 至今尚未有統一的標準,但Adobe、Google、Mozilla已分別為此推出 Cordova (PhoneGap)、Chrome Apps、WebApp等多種方式來達成此目標。


Cordova (PhoneGap)

Cordova 其實是在各個智慧手機平台上實作共用的Native Adapter,透過 Javascript Interface 來存取設備功能。所以得以使用同一套 web API,而能在不同的平台上執行。

因此 Cordova App 在各平台上執行的效果取決於該平台的 WebView 支援程度。所幸近期兩大 OS 的 WebView 都已隨自家瀏覽器更新,在新版 OS 上 Webapp 的效能已漸漸不再是太大的問題。


Chrome Apps

Chrome Apps 可以在 Chrome 桌面瀏覽器上執行,並提供修改版的 Cordova,Chrome App 可以使用相同的 API 移植到 Android App 上。

近期 Chrome 也進一步釋出 Chrome Dev Editor 與 App Dev Tool,提供在瀏覽器上即可編輯網頁App 與即時在 Android 手機上預覽的功能。


Mozilla Webapp

Mozilla Webapp 可以在「像原生應用程式一樣的 WebApp?趕快學起來!」這篇中找到比較詳細的解釋。

開發工具的部分,近期 Mozilla 亦將 WebIDE 整合進瀏覽器中。除HTML/JS/CSS編輯器外,也附帶Firefox OS 模擬器與 adb 工具,所以在桌面安裝了 Firefox 後可直接在 Firefox 中開發 Web app。開發的 Web app 除了在瀏覽器或模擬器中測試外,亦可以直接傳送到 Firefox OS裝置或 Android 裝置(需要裝 Firefox for Android)上測試。


以上三者之間各自有些異同之處,但並非不可調和。Cordova 已正式支援輸出 Firefox OS webApp,Chrome App 與 Mozilla Webapp 也已共用大部份的 manifest 格式。Chrome Apps 也透過修改 Cordova,來讓 Chrome Apps 的特有 web API能運行在 Android 手機上。


若想開始嘗試寫 Webapp,我寫的 Webapplate 除了可以幫你處理掉開新專案、封裝App、整合測試框架、程式碼風格檢查等問題,也已經同時支援 Mozilla WebApp 、 Chrome Apps,可以參考看看。


五月 6, 2014
» 來自未來的CSS - media 查詢

注意本篇提到的技巧僅適合用在特定平台的Webapp中,透過預處理器來針對特定使用平台做最佳化。但是在撰寫時仍然可以是完全跨平台的。


接續上一篇,我們繼續來重新發現一些對於有助於撰寫結構化CSS的一些CSS標準語法。


Media Query 是撰寫 Responsive design web 響應式網頁的重要元素之一。透過諸如

@media (min-width: 768px) {
...
}

這樣的語法, 瀏覽器可以根據條件,刪選並套用特定的規則來顯示。這邊需要注意的是桌面瀏覽器與移動設備瀏覽器/webapp的不同之處:在移動設備上看webapp時,除了基本Orientation之外,並不太需要調整螢幕大小。但是瀏覽器並不知道這之間的不同。瀏覽器看到@media 標簽時的運作模式,並不像一般條件式程式一般,若條件不符合時就不執行,而是一律讀進來並預先解析進 rendering tree。

在最近針對Gaia的一些load time performance measuring中,我們發現在Settings App中,每加入一行 @media 語句就會增加 100ms 左右的啟動延遲,很可能的原因就是每次瀏覽器看到@media標簽時就需要跑一次預先解析過程。因此在瀏覽器引擎本身有提供更好的方案之前,我們勢必得尋找中短期的解決方法來克服遇到的問題。


provecss 中我們嘗試提供了幾種預處理 media query 的方法。一種是搭配「Import」語法提供 filter,根據檔案名稱在 Import inlining 時將不符合條件的檔案拿掉。

例如上一篇中使用到的範例


@import url("app_mobile.css");
@import url("app_tablet.css");



我們傳入 import_filter = ["mobile"] ,則 Import Inlining 結果將只傳回「app_mobile.css」檔案中的內容:

headers {
background-color: orange;
}

「app_tablet.css」檔案中的內容就被濾掉了。這種方式可以部分解決問題,但使用上的彈性並不是很好。

另一個方式是使用標準CSS語法預處理器(Pre-processor)來查詢 CSS 檔案中的內容,只將符合條件的@media 查詢結果留下。

 我們傳入 { width: '240px', height: '320px' },則
@media (min-width: 768px)並不符合查詢條件,所以輸出的結果也會是 

headers {
background-color: orange;
}
這個方法能應對更複雜的情境。我們還能進一步 傳入「media_extract」參數,將輸出的 @media 標簽去除。

headers {
background-color: orange;
}
// was-@media condition
headers {
background-color: red;
}
於是原本@media標簽中的樣式將覆寫過原來的樣式,在特定機型中達成一樣的顯示效果。(目前主要目標是拿來用在Gaia內建App的編譯上)


如何安裝provecss
npm install -g provecss

使用命令行操作
provecss imprt.css imprt.out.css --import

加入「--import」參數即可啟用 import inlining 功能。

此外 provecss 還可以作為 node 函式庫或是 Grunt plugin 呼叫,更詳細的使用說明請參考 provecss 的 README。

» 來自未來的CSS - 匯入(Import)

接續上一篇,我們繼續來重新發現一些對於有助於撰寫結構化CSS的一些CSS標準語法。

對於比較複雜的CSS樣式,其實在CSS標準語法中,早已提供使用「import」語法來結構化地組織 CSS 樣式表。

語法如下:


@import url("app_mobile.css");
@import url("app_tablet.css");

瀏覽器在載入時會自動去「app_mobile.css」和「app_tablet.css」檔案中載入相應的CSS樣式。

有經驗的使用者在此會提出質疑:在CSS檔案中使用 import 語法將會拖慢載入速度,千萬別用!

是的,由於瀏覽器須先完全載入這個包含「import」語句的CSS檔案,然後才能再載入「import」語句中的檔案,整個載入流程會被阻塞住,需等待所有CSS檔案載入完成後才能繼續渲染(Render)過程,所以將比直接在檔案中平鋪CSS樣式的載入時間更長。

解決方法一樣是使用標準CSS語法預處理器(Pre-processor)來將使用到「import」語法的CSS檔案「扁平化」。即將「import」語法中讀到的檔案直接嵌入到原檔案中,以達到平鋪的目的。

如果 app_mobile.css 檔案的內容為

headers {
background-color: orange;
}
 
app_tablet.css 檔案的內容為
 
@media (min-width: 768px) {
headers {
background-color: black;
}
}
經過「Import Inlining」處理的檔案將變成如下
headers {
background-color: orange;
}

@media (min-width: 768px) {
headers {
background-color: black;
}
}
 
處理後原來共三個檔案會縮減為一個檔案,達成一樣使用效果的同時,還避免了效能上的疑慮。
 
在 provecss 專案,「Import Inlining」是其中一個主要與 myth 不同的特性。
如何安裝provecss
npm install -g provecss

使用命令行操作
provecss imprt.css imprt.out.css --import

加入「--import」參數即可啟用 import inlining 功能。

此外 provecss 還可以作為 node 函式庫或是 Grunt plugin 呼叫,更詳細的使用說明請參考 provecss 的 README。

五月 5, 2014
» 來自未來的CSS - CSS 變量

 CSS變量(CSS Variable)是我最近才注意到的新玩意。它要解決的問題其實跟已經行之有年的LESS或SASS相似,即讓 CSS 能用上變量(變數)。

語法像是這樣


:root {
  --main-color: orange;
}

body {
color: var(--main-color);
}
 
在一個 CSS 根元素中以「--」開頭定義CSS變量,在一般的CSS 樣式中使用「var(--)」來使用變量。

就如範例所示,只要改變一個變量的值,就可以改變整份CSS的參數。例如將「--main-color」變量的值改為「red」,則整個Body的color就會變成紅色。

這參考標準草案有多新?在目前所有的瀏覽器中,只有剛發佈的Firefox 29才有正式支援。

...對於暫時只有在特定瀏覽器上能運作的新功能,一般網頁開發者都是抱著敬謝不敏的態度。就算不提瀏覽器跨平台的支援不足,「CSS變量」一聽起來,跟原本的靜態CSS比起來,感覺就會有效能上的疑慮。

但是前陣子發現了 mythrework-vars工具,這些工具的作用是對使用標準/新 CSS 語法的 CSS 檔案預處理(pre-processing),將新的CSS變量語法轉換成向前相容的靜態語法。透過這樣的方式,開發者在開發時可以使用最新的CSS語法來撰寫更加結構化的CSS,而不需要使用額外的函式庫。同時在部署時可以透過標準CSS語法預處理器(Pre-processor)來將有瀏覽器相容/效能疑慮的 CSS 轉換成「現實版」的 CSS 語法,好讓現在的所有瀏覽器能識別來自未來的 CSS。

經過預處理後,CSS樣式表變成如下
body {
color: orange;
}
可以看見變量宣告與賦值的部分都直接被整合成靜態CSS了。

在開發 Gaia/webapp 的過程中,我們正遇到了類似的狀況:對於在 FIrefoxOS 平台上執行的 webapp 而言,1.4 版(對應Firefox 28)和以前的 FirefoxOS 版本也無法使用 CSS 變量,但是在未來的版本上卻肯定應該試試這些新網頁技術。對於一般的webapp開發者而言亦然。

於是我建立了 provecss 專案,provecss 專案吸收了 myth 的特性,但為 gaia 和 webapp 做了更多的調整。就 CSS 變量這特性而言,與 myth 不同的地方是 provecss 預設並不處理 CSS 變量。provecss 其他的功能,將在接下來的文章中進一步做說明。





如何安裝provecss

npm install -g provecss

使用命令行操作

provecss vars.css vars.out.css --vars

加入「--vars」參數即可啟用 CSS 變量取代功能。

此外 provecss 還可以作為 node 函式庫或是 Grunt plugin 呼叫,更詳細的使用說明請參考 provecss 的 README。

三月 19, 2014
» FoxBox and SummerOfCode14

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.
 

二月 10, 2014
» Auto-configured FirefoxOS Build Environment in a VM

I'm pleased to release first FoxBox version that may save a lot of time for people who wants to give FirefoxOS development a try.

For web developer who wants to contribute to gaia might meet a serious problem that they might have limit knowledge of *nix system. But to build gaia, the command line and make script is essential.

For developer who wants to contribute to B2G project, a bunch of per-requisite settings must be configured well before really digging into the code.

FoxBox could help (currently I mainly focus on) B2G/gaia developer quickly setup a working environment in VM.

Generally FoxBox 0.4 provide a Vagrantfile which automatically configure a VM with bunch of tools you need for building FirefoxOS and gaia development.

FoxBox have put a comprehend list of USB vendors, so any Android/FirefoxOS smartphone plugged can be identified.

With vagrant's NFS shared folder, developer can use their favorite editor to code.

FoxBox also bundled with a minimum GUI environment that enable you to test FirefoxOS in VM. Firefox Nightly will be pre-installed for you as well!

Read README for more detail.

Happy Hacking!


Disclaim: Though I work for mozilla, FoxBox is not an official project of Mozilla. Currently its just my side project create around Chinese New Year's holiday.

一月 13, 2014
» template.js

From Template library from Messages app now available in shared/js

Rick Waldron post the new template.js library that works originally for gaia/cummunication apps. Now it's widely adopted for other apps such as settings.

The template.js library is pretty small and stable for general use. just copy it and put in your library to use it.

The syntax is no magic, just inject an single id tag into main html file. And the 'template' is just the commented code. It allows general parameters replacement and prevent innerHTML pollution.

Here's the post from Rick:


Using the Template library is simple:

1. Add <script src="shared/js/template.js"></script> to your index.html

2. Create your template as a comment node inside of any type of element,
place in index.html:

  <span id="emphasis-template">
  <!-- <${tag}>${value}</${tag}> -->
  </span>

  <span id="greeting-template">
  <!-- Hello ${name}! -->
  </span>

3. In your JavaScript code, initialize an instance of this template:

  // Template will accept either an id string or a node!
  var emphasis = new Template('emphasis-template');
  var greeting = new Template(document.getElementById('greeting-template'));


4. Generate a safe markup string with specified values by calling the `interpolate` method of the template object:

  greeting.interpolate({
    name: 'World'
  });

  // Hello World!

Simple partial nesting is supported, just tell `interpolate` which properties are "safe":

  var name = emphasis.interpolate({
    tag: 'b',
    value: 'World'
  });

  // we know that the value of 'name' has already been escaped :)
  greeting.interpolate({ name: name }, { safe: ['name'] });

  // Hello <b>World</b>!


Markup strings produced by Template are innerHTML safe (unless explicitly
marked otherwise, as shown above):

  greeting.interpolate({
    name: '<script>alert("hi!")' + '</script>'
  });

  // &lt;script&gt;alert(&quot;hi!&quot;)&lt;/script&gt;


Template instances disallow modification of the template string once the
object is initialized, but the toString() method will return the raw
template as a string:

  greeting.toString();

  // Hello ${name}!

  emphasis.toString();

  // <${tag}>${value}</${tag}>



It's important to remember that Template and WebComponent are not at odds
with each other and exist to serve to different purposes; read more here:
https://bugzilla.mozilla.org/show_bug.cgi?id=908950#c6

» UI Demos and reuse Gaia UI elements with Building Blocks

List of UI elements

Though what FirefoxOS encourage developers to develop for the (general) Web, but not for FirefoxOS only. There's still a portion of developers would prefer to start their very first mobile web app with FirefoxOS native look and feel.


From Feb 2013, I've made my first Firefox/OS marketplace webapp: UI Demos , which demonstrate FirefoxOS (gaia) UI Building-Blocks elements and provide correspondent code blocks for reference.
 (The wrapper version of UI Demos is also available in Android Play Store)

Basically those FirefoxOS(gaia) UI Building-Blocks are a set of UI elements defined purely in CSS. So you can include correspondent styles and see your web changed to a 'mobile' looking.

Custom headers

Since these UI are intended to serve the need of FirefoxOS(gaia) presence, they looks not well in other browser. (update: Include cross_browser.css if you want your webapp can run on other browsers.)


Recently FirefoxOS UI related developers starting a project called "Building-Blocks" to make developers outside of FirefoxOS (gaia) can reuse the same UI more easily.

https://github.com/buildingfirefoxos/Building-Blocks/

 
1. Currently you can git clone the code from git https://github.com/buildingfirefoxos/Building-Blocks.git

2. I also register 'building-blocks' to bower list so my webapplate project or yeoman generators can reuse it with bower.
Use bower (need ran 'npm install -g bower' first) to install 'building-blocks' into your project is easy
$ bower install building-blocks

Or you can predefined required libraries in 'bower.json' file. then run 'bower install' directly.

For code and demos, please install UI Demos by your Desktop Firefox browser or FirefoxOS devices.

Reusable code samples

十一月 21, 2013
» 讓網頁應用支援多樣設備

Firefox OS 剛出品的設備解析度都是 320x480,但將來當然會支援更多種類的設備。這些設備的螢幕大小和所使用的解析度可能差異較大,所以我們也在思考要如何做才能善用Web技術,做到讓網頁應用/系統支援多重解析度設備。

前陣子將最近在支援較大螢幕設備的實作經驗整理一下,於謀智台客上發表了幾篇文章:


總而言之,開發者需要根據設備的「像素密度」(Pixel Density)與「螢幕大小」(Screen Size),處理相對應的「排版」與「圖片」問題。

即使是Web App,要支援多樣設備仍然要花上不少心力哩。

biggo.com.tw

A Django site.