今天犯了一個常見的錯誤:

window.addEventListener('homescreenopened', function onhomeopen() {
  window.removeEventListener('homescreenopened', onhomescreen);
  this.publish('closedbykilling');
}.bind(this));

大意:註冊一次 homescreenopened 事件,等他發生後發出 closedbykilling 事件給管理者移除自己。

結果發現每次 homescreenopened 發生時這邊都會再執行一次,造成 memory leak...

原因

function 被 bind 之後就會變成另一個新的 function,原來 function name 已經不能代表這個新的 function 了。
所以第二行的 removeEventListener 會失效。

解決方法

  1. 用 closure 把 this 變成 self
    var self = this;
    window.addEventListener('homescreenopened', function onhomeopen() {
    window.removeEventListener('homescreenopened', onhomescreen);
    self.publish('closedbykilling');
    });
    
  2. 給新的 function 名字再拿去作 addEventListener。
    var onhomeopen = function () {
    window.removeEventListener('homescreenopened', onhomescreen);
    this.publish('closedbykilling');
    }.bind(this);
    window.addEventListener('homescreenopened', onhomeopen);
    

Bugzilla 是 Mozilla 的 issue tracker,在使用上有些不方便的地方,
比如十年沒改的版面 -- 雖然現在有 preference 看起來現代化了一些,不過當跟自己有牽扯的 bug 變多,
想要回顧的時候實在不是很方便。

幸運的是 bugzilla 有 expose 一些 API 出來可以用。
九月底的週末,為了寫第三季的 Report,不小心就做了一個接口網頁,推給同事之後還獲得不少好評。
https://github.com/alivedise/bugzilla-report-helper

目前會顯示所有 official 在 FirefoxOS project 工作的 employee 的所有追蹤 bug 狀況。
本來還想多弄一些 UI 變化的,不過既然是 weekend project,就讓他停留在這個狀況吧。

寫給某人看的DOM事件傳遞模型

  • 用 fileset/legend 模擬 DOM structure
  • 用數字表示發生的順序
  • IE 使用者請下載支援 addEventListener / removeEventListener 的瀏覽器。(其實是我懶得寫支援 IE 的部份...)

http://jsfiddle.net/alivedise/bNqm6/

(function() {
    var count = 0;
    var phase = ['none', 'capture', 'at_target', 'bubble'];
    
    function eventHandler(evt) {
      document.querySelector('[name='+evt.currentTarget.id+']').innerHTML =  document.querySelector('[name='+evt.currentTarget.id+']').innerHTML + '<br/>' +
          + ++count + '.' + evt.currentTarget.id + ' caught the ball in phase: ' + phase[evt.eventPhase] + '.';
        
      if (document.getElementById('intercept').checked)
          evt.stopPropagation();
    }
    
    function clear() {
        var c = document.querySelectorAll('.caught');
        for (var i = 0, element; element = c[i]; i++) {
            element.textContent = '';
        }
        count = 0;
    }
    
    function unregisterEvents(capture) {
        document.getElementById('bug').removeEventListener('click', eventHandler, capture);
        document.getElementById('alive').removeEventListener('click', eventHandler, capture);
        document.getElementById('dolphin').removeEventListener('click', eventHandler, capture);
    }
    
    function registerEvents(capture) {
        document.getElementById('bug').addEventListener('click', eventHandler, capture);
        document.getElementById('alive').addEventListener('click', eventHandler, capture);
        document.getElementById('dolphin').addEventListener('click', eventHandler, capture);
    }
    
    document.getElementById('intercept').addEventListener('change', function() {
        clear();
    });
    
    document.getElementById('bubble').addEventListener('change', function() {
        clear();
        
        if (document.getElementById('bubble').checked) {
            unregisterEvents(true);
        } else {
            registerEvents(true);
        }
    });
    
    registerEvents(true);
    registerEvents(false);
}());

原文出自PTT Web_design版:
http://www.ptt.cc/bbs/Web_Design/M.1377320015.A.5E6.html

原po想要整理如下的code:

window.onload = function() {
   bind('.delete_button_1').(function() {});
   bind('.delete_button_2').(function() {});
   ...etc

   bind('.add_button_1').(function() {});
   bind('.add_button_2').(function() {});
   ...etc
}

其實這問題對於支援handleEvent以及addEventListener的瀏覽器來說並非難事,

var App = {
    init: function app_init() {
    this.getAllElements();
    
    this.addButton1.addEventListener('click', this);
    this.addButton2.addEventListener('click', this);
    this.deleteButton1.addEventListener('click', this);
    this.deleteButton2.addEventListener('click', this);
  },
  getAllElements: function app_getAllElements() {
    // Fetch elements to this object here.

  },
  handleEvent: function app_handleEvent(evt) {
    // According to evt.target do something here.

  }
};
window.onload = function() {
    App.init();
};

不意外的IE9之後才有機會支援「把內含handleEvent函數的物件當成EventListener」。

一般MVC framework應該都有解決這個問題的方法,
之前在trace CanJS的時候看到它的作法如下:

var App = {
  init: function app_init() {
    this.bindEvents();
  },

  bindEvents: function app_bindEvents() {
    for (var prop in this) {
      var a = prop.split(' ');
      if (a.length > 1) {
        // Pseudo code: Delegate element a[0] with a[1] event
        $(a[0]).on(a[1], this[prop].bind(this));
      }
    }
  },

  '.delete_button_1 click': function on_delete_button_1_click() {
    // do sth...
  },

  '.delete_button_2 click': function on_delete_button_2_click() {
    // do sth...
  },

  '.delete_button_3 click': function on_delete_button_3_click() {
    // do sth...
  },

  'form submit': function on_form_submit() {
    // do sth...
  }
};

簡言之用約定俗成的方式將"selector event"當成key, callback當成value,
寫在object裡面然後在初始階段去過濾有這樣的property的話就自動做delegate的動作。

Following are the plan about why and how to split current Gaia:System:Window Manager.

Sources/Links

Current main functions in Window Manager

  • App Window Management
  • Wrapper Window Management
  • Inline Activity Management
  • Homescreen Management
  • MozBrowser Element Generation
  • Orientation Management
  • Visibility Management
  • Resize Management
  • App Screenshots Management [deprecated]
  • System Message Handler
  • Open app transition
  • Close app transition
  • FTU Management [deprecated! Become standalone FTU Launcher already!]

So which could be pulled out to reduce the heavy weight?

Continue Reading →

在桌面版本的網頁開發中,我們可以透過 HTML5 的 page visibility API 來知道目前的網頁是否為使用者焦點,或者目前不可為使用者所見,來達成某些目的:如停止 UI 更新,資料交換...等,範例程式如下:

function handleVisibilityChange() {
  if (document.hidden) {
  // Pause UI update
  } else {
  // Begin UI update
  }
}

document.addEventListener("visibilitychange",
  handleVisibilityChange, false);

我們將這個 API 帶到 Firefox OS 中,並賦予了它更深一層的意義:

Continue Reading →