[Javascript] Something about pinch gestures

Image Credit

pinch-gesture

最近一直在研究如何在 Browser 上支援 Mac touchpad 的 Pinch 手勢,所以有一些心得想要記錄一下。

3rd party libraries

一開始的想法就覺得這種事情應該有什麼 3rd party 套件有支援了,只要簡單的把 event 和現有的程式接上就可以了。不過找了一陣子後,實在是沒有找到什麼好東西,通常大家推的都是 Hammer.js,不過其實這個 library 是專門設計給 mobile app 使用的,看了一下程式碼發現是組合 touch 相關的 event 後再經過數學運算後提供客製化的 gesture event 像是 pinchpan … 之類的。

不過這個和我的使用情境不太一樣,因為 gesture 相關的 event 只有在 mobile 的 browser 上才會存在,因此只能再找找別的方法。

Solutions

之後很幸運的找到了 Chromium 開發者們的討論串,主要在討論的內容就是要如何把 touchpad 上的 pinch 手勢透過 wheel 這個 event 傳出去!那個討論串主要的重點就是在於 2014 年五月之後,Chromium 開發者們上了一個 patch,讓前端開發者可以透過正規的 wheel event (對了,wheelmousewheel 有點不太一樣,前者才是大家公認的標準,後者則是非標準,只有少部分的 browser 有支援,要注意一下)去偵測 pinch gesture 的觸發。當 wheel event 是透過 pinch 觸發的話,那傳進來的 event 的 ctrlKey 這個屬性則會被設成 true,所以開發者們就可以用這個值來做判斷。

而在我們公司裡,因為我們要監聽這個手勢的發生做客製化的視覺處理,而且我們不希望 Mac 上預設的 zoom in / zoom out 還被觸發,所以要記得透過 event.preventDefault() 來避免 Browser 做 zoom in / zoom out 的動作。

Limitations

當然世界沒這麼美好,所以我最後還是整理了一些目前的限制(以後說不定就沒這個問題)

  • Safari
    1. 目前我手上最新的 Safari 9.0.x 版(Mac OS X 10.11.x)是沒辦法透過上面的方法來偵測手勢及取消預設的 zoom in / zoom out 觸發。
    2. 好消息是在未來的 Safari 9.1.x 版後,他們提供了新的 gesture event 讓開發者們可以去偵測手勢,不過這個版本目前也還沒釋出所以也沒辦法測試,如果官方文件沒有唬爛的話那就應該是可以支援,只是這個 event 目前應該也是 Safari only 的客製化 event 就是了,會不會變成 standard 也不知道。
  • Chrome
    1. 在 2014 年五月後的 Chrome 就支援上述做法來偵測 pinch 手勢了!(我很想查 Chrome 的版本號只是不知道怎麼找,如果有人知道那個 patch 實際被 land 到哪個版本的話,請和我說一下)
    2. 個人 Chrome 48+ 實測是 ok 的。
  • IE / Edge
    1. 如果討論串上的資訊正確的話,那 IE / Edge 應該和 Chrome 一樣有支援 ctrlKey 可以讓開發者去做偵測。
  • Firefox
    1. 無解 …
  • Electron
    1. 我有測試過 Electron 0.36.x+,因為他的核心也是 Chromium,所以這個做法也是可以支援的!
    2. 如果你是用 <webview> 的方式來載入你的 web app 的話,那你特別需要先在 render view 的地方聽  wheel event 但是不需要做任何事(超怪,無法理解),這樣這個 wheel event 就會正確的被傳進你的 <webview>,然後你的 webview 裡面如果有實作 event.preventDefault() 的話,那預設的 zoom in / zoom out 行為就會被取消,這樣你就可以在 webview (也就是你的網站裡面處理這件事情就好)

References

附上所有我找到的有用資源如下:

  1. http://jsbin.com/qiyaseza/8/edit?html,css,js,output
  2. https://bugs.chromium.org/p/chromium/issues/detail?id=289887
  3. http://stackoverflow.com/questions/15416851/catching-mac-trackpad-zoom
  4. http://stackoverflow.com/questions/29929411/disable-pinch-zoom-in-webkit-or-electron
  5. https://gist.github.com/NekR/9a80ebe73573e11f0351

[Javascript] TwZip.js

twzip

Github Link

最近因為 Hax4 有 project 需要用到台灣郵遞區號,所以就花了一點時間做了一個簡單的 js (jQuery) plugin – TwZip.js。不過身為一個前端工程師當然想把事情都留在前端處理就好,因此當初在設計這個 plugin 的時候就打算把所有的資料都放在前端,然後以 lazyload 的方式把資料載進來而不需要後端的支援(超懶)。

而說到資料,TwZip.js 的資料是從中華郵政全球資訊網下載來的,然後簡單寫了一個 makefile 搭配 node.js 自動產生數百個鄉鎮市區的 metadata 供前端使用。

這邊要提一個我一直被卡住的白痴問題(OS 老師當初應該把我當掉),因為原本我的設計是三層式架構(像是 台北市/信義區/信義路),但是這會造成資料過度碎片化的問題。之所以會這樣是因為在 file system 裡面最小單位的 block or Cluster 有一個最小容量,像我電腦就是 4 KB,所以如果資料小於 4KB 就還是以 4KB 計,因此這個三層式設計最後就產生出 16X MB 的資料(因為產生出太多 metadata 了)… 整個比原本的專案大上好幾十倍呀 …

為了解決這個問題,最後就改成兩層式架構(像是 台北市/信義區,也因為層數變少的關係所以最後就變成約 4 MB 的資料了,整個就是皆大歡喜。

還記得以前的前輩曾經教過我在寫程式的時候要先把 API 想好,確定使用者使用的介面再開始寫細節,透過這樣的決定來讓整個專案照著預期的方向前進才是比較好的,這樣才可以提前知道這個設計上的缺陷及問題,算是又多了一點體悟吧!

儘管如此,目前這個 plugin 還只能算是一個 prototype ,未來應該會再把 zipcode 的資訊透過 callback 傳回去。其他的功能就再說吧。

DogFooding ++

[Node.js] Difference between module.exports and exports

Image Credit

This simplified Chinese blog tells the details about the difference between module.exports and exports.

The most surprising part of the difference is that you can not use them together at the same time. (I know no one would use it in this way, because you have to make sure the coding style is the same anywhere.)

After testing, if you use these two ways to export modules, defined methods or properties in exports will be discarded directly and only export the ones defined in module.exports.

So I think the best practice here is to use module.exports instead of exports to define your stuffs.

Read More on : Here

[Javascript] performance issues when appending in DOM tree

Image Credit

According to John Resig’s blog, you can see that there is 2x-3x performance better when using fragments.

Take his code for example :

https://gist.github.com/EragonJ/6111312.js

If you use original append to append divs one by one, then you will see the blink on the screen especially when you are going to append a huge list. But, when using fragments, it is another kind of structure to hold these temporary divs and will be appended to the target all together at the same time.

So if one day you have to deal with massive DOM manipulation problems without 3rd party libraries’ help, remember to use it.

Cheeers 😛

Read More on : http://ejohn.org/blog/dom-documentfragments/

[Javascript] Build your own Trip with Trip.js

Image Credit

Demo : http://eragonj.github.io/Trip.js/
Repository : https://github.com/EragonJ/Trip.js

太久沒寫網誌了,所以想說來寫一篇最近比較值得記錄的事情,那就是 Trip.js

什麼是 Trip.js ? 一言以敝之就是「Trip.js is a useful plugin that can help you customize a tutorial trip easily. ( Based on jQuery )」,通常對於 landing page 或是一些需要做  step by step 指導的網站,都會需要這類型的 plugin 來幫助 developer 快速上手,做出需要的效果 ,而剛好之前在公司的時候有類似的需求,所以我就在其他時間自己先行開發了 Trip.js 的初始版,然後分享在網路上。

就目前看來感覺效果還蠻出眾的(在 hackernews & github 上都有一些回響),雖然市面上還有很多類似的 plugin,但是東西是自己寫的那種感覺就是很不一樣,有興趣的 developer 不妨參考一下吧 😛

[Javascript] Some good/bad parts learned from Chrome Extension

Image Credit

Just update my FBBK from version 1.0 to 1.2.1 and think there are some nice features/designs to be noted about Chrome extension.

  1. chrome.storage API

    When using manifest 1, we have to set up a background page  as middleware to communicate between content scripts and localStorage ( used to store users’ selected options ) because the localStorage used in content scripts will be referred to the page localStorage instead of extension localStorage.In this way, developers have to make build up a fake background page to transfer data. But this problem has been solved by chrome.storage API. With this API, we can easily set/get data for content scripts without the help of background page.Better than that, this API can also synchronize data from local to the cloud to solve problems when users using different computers. The most awesome part is that the API would automatically fallback to store data in local if the internet connection breaks !
  2. chrome.i18n API

    It is really important to i18n your extensions/apps if you want to reach the global market ( users ). For FBBK 1.2.0+, I just implemented two locales ( en / zh ). I really like the design that Chrome can automatically detect the right locale to be used  and even falls back to default locale.This API is really smart enough for basic projects but can’t meet more complicated needs. Take FBBK for example, There are many models with i18n needs ( to describe models’ usage, intro … blah ). Because Chrome doesn’t support a good way for me to get the current locale ( can use predefined variable like @@ui_locale in CSS but not in JS  ) , I have to proxy the models descriptions to  use chrome.i18n.getMessage() to get the right locale and match the right message.json ( see the above figure ).

    This is how I do in FBBK :

    https://gist.github.com/4259985.js?file=gistfile1.js

    If you have better ideas to extract models with i18n json, plz comment to let me know !

That’s it ! Have fun on developing chrome extension 😉

[Javascript] Facebook Blocker (FBBK) Still Rocks On

Check : FBBK 的主介紹頁

改變

也許有點老梗,但是最近因為情緒低落,想要參考學徒模式的作法,回到自己的舒適圈,試著找回一些原本稱之為熱情的東西。

其實也是這麼的剛好,因為 Chrome 在版本號 >= 18 後會逐漸遺棄 Manifest V1 的部份實作,提供了更多方便好用的 API 在 Manifest V2(例如說 Content-Script 在 Manifest V1 時,存取 LocalStorage 的限制需要透過 background page 的幫助),其實我覺得是種陰謀啦,畢竟 Extensions 就和 Apps 多如牛毛,所以透過這種手段還可以順便幹掉那些沒在更新的 Extensions … XD

以下是從  Google 那邊擷取的時程說明:

  1. 2013 Q1

    • The Web Store will remove manifest version 1 items from the wall, search results, and category pages.
    • Notice emails will be sent to all developers with manifest version 1 items still in the store reminding them that these items will be unpublished and providing update instructions.
  2. 2013 Q2

    • The Web Store will unpublish all manifest version 1 items.
    • Final notice emails will be sent to developers with manifest version 1 items still in the Web Store.
    • Chrome will continue to load and run installed manifest version 1 items.
  3. 2013 Q3

    • Chrome will stop loading or running manifest version 1 items.

動機

除此之外,還差一些讓我捲起袖子實作的動機 … 想著想著,我就想到我在使用 Facebook 長久以來的困擾,那就是這個:

沒錯,就是那個該死的「Seen」,這個 Feature 真的是我最痛恨的一點,有的時候就是想假裝沒有看到某個人的留言,但是 Facebook 卻會在特定的情況下 Trigger 「讓別人知道你已經看過留言的事件」,這種行為我真的沒辦法接受 … 隱私這種東西在這個設計之下幾乎是蕩然無存呀!

所以我就參考了一些文章還有 Chrome Extension Request 的機制,為 FBBK 加上全新的 Unseen Feature,可以參考選項設定的擷圖:

結果

經過幾位好友的友情測試之後,Unseen 運作的非常良好,終於可以(和別人站在不同的起跑點了) 在聊天的時候暫時找回那一點點曾經屬於自己的隱私了 xD。

以上就是這一次 FBBK 的更新,歡迎大家提供 feedback !

 

立馬安裝 Facebook Blocker – FBBK Chrome Extension

Updated on 2012/08/11,目前審核通過!

P.S. 其實這一篇是 2012/08/07 的時候就寫好了… 但是因為 Chrome Extension 在做版本更新的時候出了一點問題,所以這個版本的更新要等待工人智慧審核通過之後才會發佈,囧。

原本是想要等更新通過再發這一篇文章的啦,但是因為不知道要等多久(可靠消息指出會到兩三天),所以就先放出這個消息來啦!過幾天會把 FBBK 的更新消息統一到一個 Page ,這樣相關的資訊就可以在那邊一目了然啦!

Thanks All ~ FBBK Still Rocks on !

[Javascript] NCKU-GPA calculator

Image Credit

前幾天有個朋友在社團提出了一個有趣的問題:

成大現在成績查詢那邊都沒有GPA的自動計算。要不要來簡單做一個,然後賣回給成大~~~

因為那個時候剛好自己也無聊沒什麼事,又想說很久沒有寫 Chrome Extension 了,就把以前做 FBBK 的東西翻了出來做了些調整,改採 PageAction 的方式去寫這個 Extension,主要的功能就是可以自動幫你把百分制的成績自動計算成 GPA。

NCKU-GPA calculator on Chrome Web Store: Here

不過,原本想說只是快速 Hack 一個 alpha 版本拿來自己用爽就好了,結果誰知道卻遇上了一些問題,多是我以前沒有遇過的有趣問題,所以特別想要在這邊記錄一下。

BTW, Checkout the repository first :]

git checkout git://github.com/EragonJ/NCKU-GPA-calculator.git

Problem – Encoding conflicts

我從來沒有想過我在這個世界還會遇到 big5 編碼的網頁,Well,成功大學的成績查詢網頁就是用 big5 編碼的,除此之外,透過 Inspector 的觀察之後,發現它的頁面是透過 POST 的方式,判斷 Client 回傳的 submit1 值來決定是要 Render 哪一個上/下學期的成績資訊。

但是,問題就在這邊,如果觀察它的 submit1 值,從 Inspector 上會看到unable to decode value。舉兩個實際的例子,如果是「0096上」,則它編碼後的結果是「0096%A4W」,如果是「0096下」,則它編碼後的結果會是「0096%A4U」。

問題來了,如果透過 $.ajax 來傳「0096上」這個值回去的話,會發現它編碼後的結果不會是「0096%A4W」,結果我去查了一下 $.ajax的原始碼後,發現它會呼叫 javascript 內的 encodeURIComponent 來做編碼的動作,所以不管如何,單純把值丟入 $.ajax 是一定不會得到期望的結果!

所以…需要在 $.ajax 的 options 做一些調整,那就是設定 processData 這個屬性,這樣不管我們傳什麼值給他,他都不會幫我們再其它額外的動作(例如 encodeURIComponent ),直接把值傳過去。因此,既然我們可以透過這個設定做到我們想要的效果,就要先把「上」、「下」這兩個字做 Replace 的動作,再傳入設定過的 $.ajax 直接把值傳過去,就可以解決這個問題了。

Well,比較值得記錄的就是這個部分。

有點累了,有沒有收假前一晚還在熬夜寫 Blog 的八卦…改天再回來修文字還有補充資訊,先睡了。

[Javascript] Solve conflicts when using jQuery blockUI and datepicker

Image Credit

最近在開發專案的時候,因為大量用到 blockUI 及 datepicker,所以好死不死終於遇到了一個很神奇的 bug,這個 bug 會發生在你使用 modal dialog ,而該 dialog 內還包含一個 datepicker 的元素,這樣就會造成那個 datepicker 在選取年、月的下拉式選單(dropdown)時無法觸發。

但是這個很怪,沒有道理 DOM 都是正確的(年、月的 option 數目都是對的)但是卻打不開 dropdown,不過當我設定 option 內的 showOverlay 為 true 的時候,一切都正常了,因此判斷一切都和那個 showOverlay 的參數有關,所以去 Trace 了blockUI 的 source code ,最後終於發現了問題所在 …

https://gist.github.com/1058564.js?file=gistfile1.js

原來在 blockUI 運行的過程中,有這麼一段程式碼會綁定 mousedown / mouseup / keydown / keypress 的事件,這樣就會使得 datepicker 的點擊行為無法發生,這就是為什麼會有這個 bug 的出現。

所以目前比較好的做法,一個是設定 showOverlay : false (這會拿掉漸層背景,不過這通常都不會是我們想要的解法),另一個就是設定 bindEvents : false (讓 blockUI 不要 suppress 我們的點擊 event ),這樣就可以解決這個問題了。

[JS] Facebook Blocker

Check : FBBK 的主介紹頁

應該有很多人像我一樣已經厭倦了 Facebook 上面一堆無聊的心理測驗或是騙人氣的按讚論壇,所以身為 Chrome 的愛好者及 Javascript 的初心者,我就為 Chrome 寫了一個小小的擴充功能,名為「Facebook Blocker」。

Facebook Blocker 可以讓你設定自己的「樣式」,然後它會自動在你下次進入 Facebook 的時候讀取樣式並分析當下的頁面,凡是符合該「樣式」的訊息就會自動被隱藏起來,讓你以後再也不用看到那些惱人的廣告。

其實如果你上 Chrome Extensions 看的話,已經有很多名為 「Facebook Blocker」的 Extension 了,但是經過一陣搜尋之後,發現那些 Extension 大多和我想要做的事情都不太一樣,不是太過痴肥要不然就是功能不同,讓我久久不能自己。

所以經過幾天的研究之後,已經寫好了 Facebook Blocker 的雛型了,而且基本的 Hot Key 也在剛剛 1.0.2 版的時候新增上去了。心中還有很多有趣的功能還沒實作,雖然 UI 也有點難看,不過至少在使用上沒有太大的問題,總要留些東西放在後面更新,才不會有人說我在打混(好的不學都在學這個 …)

如果有什麼想要增加的功能或是意見都可以留言給我(在這或是在 Extension 的頁面都可以),我會一一回覆的。

Enjoy blocking 😉

δ Facebook Blocker 在 Chrome Extension 上的載點與步設定步驟的教學圖