Blackbing Playground
Blackbing Playground

記錄一些生活與工作的雜事,偶爾會寫一些前端網頁開發的心得


  • 首頁

  • 歸檔
Blackbing Playground

window.open and print problem in Evil IE

發表於 2011-05-20

今天遇到一個奇怪的bug,需求如下:


  • 點選print,跳出新視窗,為了不要再做一次server端的溝通,要將目前的DOM Element傳到新視窗。

  • 新視窗打開要直接跳出print panel


不直接print()是因為列印功能不需要列印目前完整的頁面,只需要列印目前頁面的某一個Element內容。


看起來很簡單的需求,沒想到在IE上踢到了鐵板。測試source code 如下:


1
2
3
4
5
var win = window.open('');
var html = '<div>hello blank </div>';
win.document.write(html);
win.print();
win.focus();


有趣的是,只有IE不會執行print,而且是IE所有系列,更過份的是,連任何message都沒有出現。


測試連結:popup-using-print.html(只有IE無法出現print panel)


有趣了,我決定要好好地測試一下,既然沒辦從外部呼叫print來執行,那就從內部滲透,於是我把程式改成如下:


1
2
3
4
5
var win = window.open('');
var html = '<div>hello blank </div>';
html += ['<scr','ipt ','>','(function(){ window.print();})()','<\/','sc','ript>'].join('');
win.document.write(html);
win.focus();


稍微解釋一下code,我在最後加上一段直接執行的程式,直接做print(),我在本機端執行可以運作,不過會跳出警告視窗,但看起來應該是可以work。於是我放到server端執行,Damn it,it still doesn’t work. 一樣沒有Error message。奇怪的是,按下F5(重新整理),就跳出列印視窗了,啊哈~重新整理還不簡單,天外飛來一行code:


1
2
3
4
5
6
var win = window.open('');
var html = '<div>hello blank </div>';
html += ['<scr','ipt ','>','(function(){ window.print();})()','<\/','sc','ript>'].join('');
win.document.write(html);
win.location.reload();
win.focus();


測試連結:popup and print


竟然可以了,而且在其他瀏覽器也能正常運作,perfect !!,不過等等,那這樣的話跟外部執行和內部滲透搞不好沒關係,於是我將內部滲透再改回外部執行,果然可以正常運作。我想這以後應該可以派得上用場,於是將他寫成一個function。結果搞了半天只需要reload就可以解決了,唉~真是萬惡的IE。


1
2
3
4
5
6
7
8
function openPrint(elm){
var html = typeof elm == 'string' ? elm: elm.innerHTML;
var win = window.open('');
win.document.write(html);
win.print();
win.location.reload();
win.focus();
}


參考連結:



  • quirks mode JavaScript - Popups

Blackbing Playground

Tetris Game(javascript 俄羅斯方塊)

發表於 2011-04-29

今天被問到俄羅斯方塊的作法,於是動手實做了一下,簡單介紹一下大概的概念:

1. css layout 設計

Tetris_layout
利用div建立每一塊Block,這裡重要的屬性是display:inline-block,建立浮動的方塊元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.stage{
border:2px solid #CCC;
padding:5px;
margin:0px;
width:316px;

}
.stage .grid{
display:inline-block;
border: 0px;
width:16px;
height:16px;
outline:1px solid #000;
margin:0px;
padding:0px;
}
.stage .grid.blue{
background-color:blue;
}
.stage .grid.grey{
background-color:grey;
}

2. 資料結構設計

每一個grid的結構

1
2
3
4
5
6
7
8
var blockStructure = function(){
//代表是否填滿,用來判斷是否要著色。
this.fill = false;
//代表是否為堆疊,用來判斷是否可以移動。
this.stacked = false;
//判斷顏色
this.color = '';
};

3. stage Canvas的設計

用一個一維array代表stage矩陣,例如(3, 4) => 4*Xcount + 3

4. shape形狀方塊

shape 用二維array表示,較好理解,例如這是我定義的幾個形狀

1
2
3
4
5
6
7
8
9
10
11
12
Tetris.prototype.getShape = (function(){
var shape = [
[[1,1], [1,1]],
[[0,1,1], [1,1,0]],
[[0,0,1], [1,1,1]],
[[1,1,1,1,1]]
];
return function(){
var rand = Math.floor(Math.random()*shape.length);
return shape[rand];
};
})();

5. 碰撞偵測

碰撞偵測部份是較複雜的部份,我利用兩個檢查函式來做檢查,為了理解容易,底下的判斷程式碼有點重複。

  1. 檢查是否到達邊界
  2. 檢查是否碰到堆積的grid
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var collision = _self.chkCollision(x, y);
    var chkStacked = _self.chkStacked(x, y);
    //collision dectection
    if(collision){
    //若已到達底,則更新狀態為堆積狀態
    if(chkStacked){
    status.stacked = true;
    return;
    }else{

    return;
    }
    }else{
    if(chkStacked){
    //若碰到堆積的grid,先檢查是否可以往下,若可以往下,則退回,若否,則更新為堆積狀態
    var chkStackedDown = _self.chkStacked(status.shapeX, status.shapeY+1);
    if(chkStackedDown){
    status.stacked = true;
    return;
    }else{
    return;
    }
    }
    }

6. 狀態更新

Game 的基本觀念是狀態的更新,每一次重新渲染畫面時都是在更新狀態,因此狀態的表示非常重要,在此我用shape來儲存現在動作的形狀,並紀錄目前shape的x, y,以及是否要進入堆疊狀態。

1
2
3
4
5
6
var status = {
shape:null,
shapeX:0,
shapeY:0,
stacked:false
};

7. refresh 渲染畫面

1
2
3
4
5
6
7
8
9
10
11
12

Tetris.prototype.refresh = function(){
var _self = this;
//取得目前狀態
var status = _self.getStatus();
//清除畫布,判斷是否已經堆積
_self.clear();
//設定shape的狀態
_self.setShape(status.shape, status.shapeX, status.shapeY);
//重新繪製
_self.draw();
};

以上是我的基本概念,實做上其實code有點醜,而且也還有很多bug,不過因為是實驗性質的,也沒打算要產品化,就在這兒野人獻曝了。
DEMO

Update

俄羅斯方塊 Canvas 版本

Blackbing Playground

淺談 MySql geom

發表於 2011-04-21

##MySQL的Geom實在很不成才
MySQL的Geom實在很不成才,OpenGIS規範了這麼多function,就連這麼基本的Distance他都沒實做,跟postgress相比,真的是差了很多,然而系統都是在MySQL上,要移轉資料庫工程實在浩大,還是屈就於MySQL的淫威之下來解決問題。廢話不多說,來看一下如何創建geom欄位。

###建立、修改geom
這裡用到最重要的function是 GeomFromText, 以下例子都是用最常用到的POINT來做說明

1
UPDATE `poi` SET geom = GeomFromText('POINT(X Y)')

查詢落在bounding box裏頭的地標
這裡用到最重要的function是intersects,用來判斷兩個geom是否相集合,我們透過計算將bounding box的轉成polygon來做查詢

1
2
3
4
5
6
7
8
9
10
SELECT id, label, ASTEXT( geom )
FROM poi
WHERE INTERSECTS( geom, GEOMFROMTEXT( 'POLYGON((
121.561531961596 25.0360992913184,
121.56149683801432 25.041444032861694,
121.56846249577495 25.04122795598331,
121.56833620876884 25.036005306093482 ,
121.561531961596 25.0360992913184
))' ) )
LIMIT 0 , 10

###查詢落在bounding box裏的地標, 並計算距離
這裡用到兩點距離公式直接計算距離

1
2
3
4
5
6
7
8
9
10
11
SELECT id, label, ASTEXT( geom ) ,
SQRT( POW( ABS( X( geom ) - 25.037346023922883 ) , 2 ) + POW( ABS( Y( geom ) - 121.55710515578352 ) , 2 ) ) AS Dist
FROM poi
WHERE INTERSECTS( geom, GEOMFROMTEXT( 'POLYGON((
121.561531961596 25.0360992913184,
121.56149683801432 25.041444032861694,
121.56846249577495 25.04122795598331,
121.56833620876884 25.036005306093482 ,
121.561531961596 25.0360992913184
))' ) )
LIMIT 0 , 10

但是單位是經緯度,求出經緯度兩點的點距離人類無法理解,經緯度的座標轉換公式有點繁雜,可以參考經緯度轉換TWD97,在大部分的需求,距離只是一個大概的數字即可。

###神秘的1/111111
在中低緯度的地區(例如台灣),可以用這個參數來做很rough的經緯度/ 公尺轉換,例如:我要計算距離經度121.5 距離1000公尺的經度:121.5 + (1/111111 * 1000) = 121.509

因此,我們將上面的SQL做點小修改,乘上一個111111的參數,即可知道距離,當然也可以做排序囉。

1
2
3
4
5
6
7
8
9
10
11
SELECT id, label, ASTEXT( geom ) ,
ROUND(SQRT( POW( ABS( X( geom ) - 121.5644248807452 ) , 2 ) + POW( ABS( Y( geom ) - 25.033943775454475 ) , 2 ) )*111111) AS DIST
FROM poi
WHERE INTERSECTS( geom, GEOMFROMTEXT( 'POLYGON((
121.5509248807452 25.020443775454474,
121.5509248807452 25.047443775454475,
121.57792488074519 25.047443775454475,
121.57792488074519 25.020443775454474,
121.5509248807452 25.020443775454474
))' ) )
ORDER BY DIST

###參考資料:

  • MySQL中的空間延伸
  • How to use MySQL Spatial Extensions
Blackbing Playground

利用Chrome Extension創造所見即所得的管理工具

發表於 2011-04-15

最近研究Chrome Extension,玩出了一些心得。突發奇想的想到,當我們在做系統的時候,都會需要有「管理」的功能,有些系統將管理功能整合在一起,例如wordpress,當你已經登入時,你就可以直接針對你在瀏覽的文章做「編輯」,不過「編輯」說穿了也是一個連結,其實這只是將這個功能放在所見即所得的地方,讓操作者能夠很快速的執行他所要操作的動作。然而也有些系統的管理需求,需要前後台分開,前台(給使用者看),後台(給管理者操作),如此較可以掌握安全性的問題,例如後台系統鎖IP,你不能從任何地方執行後台功能,也因此前台不會有任何程式漏洞造成使用者可以執行管理者權限的動作。

然而前後台分開,就會有所見不是所得的問題。例如新聞輪播系統,在前台看到新聞輪播,管理者發現某一則新聞的內容有問題,因此要去後台查這一則新聞出來做修改,結果到了後台發現,因為新聞太多,後台又沒有做篩選的功能,所以查起來眼花撩亂。這在管理上就造成一個很大的落差。

企劃:「能不能在做一個搜尋的功能讓我方便搜尋」


RD:「搜尋喔~可以是可以啦,不過現在前台的東西都做不完了,等我有空再做吧!」

檢討一下這個需求,其實這個需求並不是搜尋的需求,而是所見即所得的需求,管理者和使用者看到的畫面其實都一樣,但管理者多了管理的需求,因此需要對使用者看到的畫面做管理,但後台系統通常都做的很隨性,沒有設計,流程僅是工程師導向,因此每個操作後台系統的人永遠會說「這系統真是難用」,要什麼沒什麼。

那麼,「如何設計一個所見即所得的管理工具?」

上述提到,管理功能直接做在前台中,讓管理者登入之後就可以進行操作,這是最理想的方式,但由於安全性的考量,大部分嚴謹的系統都前後台會區分出來,因此造成後台「所見非所得,只能重新整理前台」。Chrome Extension有個特點:透過Extension,可以存取、修改content的DOM物件,因此我可以針對頁面內容做任意修改操作。重點來了,管理功能說穿了就是連結,只要我能將前台的管理功能顯示在畫面上,就能讓管理者「所見即所得」的操作。我們直接來看個範例圖。

index

簡單說明一下這個需求,在前台有很多的廣告顯示,然而廣告管理後台卻僅僅是列出所有廣告,管理者只能依照ID與「肉眼辨識頁面顯示位置」來做篩選,非常的不友善。這種需求非常需要所見即所得的功能來輔助管理者操作,因此我做了一個小工具,將頁面上的廣告顯示出來,並添加一個管理連結,讓管理者可以直接進入該廣告的管理頁面。概念非常簡單,實做也不難,只要能掌握一點javascrtip/ DOM的操作就可以達到這個需求。很簡單,對吧。而安全性的問題同樣也不是問題,因為這個工具只是帶連結過去,後台操作還是要登入才能執行。

雖然這個概念只是解決了管理者所遇到的問題,但我想這樣的方式可以大幅降低管理系統的操作流程,不用再煩惱後台的呈現方式。不過這也這讓我思考到,還有沒有類似的案例可以用這種方式來提供?野人獻曝,歡迎討論。

Blackbing Playground

Download Facebook album's photos

發表於 2011-03-29

https://chrome.google.com/extensions/detail/blbmhonenddnnmbailokbccgmikhkpni

My girl friend want to download her friend’s whole photos on her facebook, so I write a tool for her.


Usage:

  1. Link to the album on your facebook page.
  2. Click the “Download FB phtos” Icon.
  3. You will see all photos on a new tab.
  4. Press “Ctrl+S” and select “Save whole pages”.
  5. Great! You will see a folder including all the photos in this album.

    Cheers!



    聊聊這個小工具的開發心得,首先,我不想花太多時間做這個工具,之前有CCN大大開發了一個抓無名相簿的工具WretchXD,開發的非常好,但一般這種抓圖程式都會遇到被host來源封鎖、擋掉、當成惡意攻擊等奇怪的事情,我不想為了做這種事情,去挑戰臉書的server。其次,我不想做成應用程式,還需要登入、使用graphAPI,為了抓一個相簿,還要挑來挑去,那我乾脆開發一個fb相簿瀏覽器了XD。



    總歸一句就是懶,於是我把腦筋動到google chrome身上,只要我可以parse出縮圖與大圖的規則,就可以拿到一串URL了,稍微測試了一下果然可以。



    縮圖URL:http://photos-c.ak.fbcdn.net/hphotos-ak-ash2/62450_1517231263867_1627073717_1243192_8144805_a.jpg

原始URL:http://photos-c.ak.fbcdn.net/hphotos-ak-ash2/62450_1517231263867_1627073717_1243192_8144805_n.jpg


相當簡單,只差了一個字元而已,於是我開始思考一下這個工具的操作流程:瀏覽FB縮圖,按下按鈕,取得所有連結…..取得所有連結之後咧?使用wget來下載所有連結?windows上還要安裝wget!?而且因為下載的動作已經與瀏覽器的動作分開了,也有可能因為權限問題被擋掉?就在這個moment,我想到了chrome.tabs.create,將所有圖檔load到新分頁裡頭,我就可以利用瀏覽器的「另存新檔」功能來存放所有圖片,非常好,流程不難,「萬事具備,只欠Coding」,最困難的部份在於如何將資料傳入new tab,看起來是安全性的問題不能任意存取tab物件,不過最後我還是繞道解決了,以後再查查看有沒有正規一點的作法來改進。


那麼,使用有什麼bug歡迎回報


Download Facebook album’s photos



2011/04/12 更新日誌:
由於之前懶得查chrome extension API, 在與new tab溝通時,我是用暴力方式將資料塞入window 裡頭,原以為這樣可以正常運作,但發佈出去才發現有眾多的問題存在,因此決定好好survey API, 原來在做message passing時有更好的方式來呼叫,請參考「Message Passing」利用chrome.tabs.sendRequest也可以指定要將參數傳入特定的tab,再該tab裡頭榜入相對應的事件。部份範例code如下:


[sourcecode language=”javascript”]
//=============in click action =====================================
chrome.tabs.create({ url:chrome.extension.getURL(‘./fbphotos.html’), index:(currentTab.index), selected:true }, function(tab){
//指定tab id, 並傳入req
chrome.tabs.sendRequest(tab.id, req);
});

//=============in new tab page====================================
//榜定事件接收資料。
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
loadData(request);
});
[/sourcecode]

2011/7/5 update, 感謝網友更詳細的介紹,相形之下我好懶XD


  • 重灌狂人-按一下,批次下載 Facebook 相簿中的全部照片

  • 以 Google Chrome 下載 Facebook 相簿

  • 香腸烤魷魚-超簡單!一鍵下載Facebook整本相簿照片

Blackbing Playground

匿名函式(Anonymous Function)

發表於 2011-03-04

「我寫過很多javascript了,也用過很多jQuery的plugin,也有套用過一些framework,來做到一些看起來很炫的特效,對於前端工程,我還欠缺什麼呢?」除了經驗,你需要知道一些方法與技巧,來將這些技巧應用在你的實做上。有一件事情你必須意識到,複雜的前端工程,絕對不是你一個人能夠完成,而是共同合作出來的,因此如何共同開發,如何讓人看懂自己的程式,成了更重要的課題。常常看到很多網站做出很絢麗的特效,但看了一下程式碼,一看就覺得是為求目的而湊出來的程式,做出效果,但往後也無法維護了。一個無法維護的網站,註定會被淘汰的。接下來分享在這條路上走過的經驗,並在此做個紀錄。

##Anonymous Function
匿名函式的應用範圍非常的廣,並且也是javascript的特性之一。使用匿名函式,除了可以將你的函式包起來,避免其他變數的影響。也避免暴露你的程式,讓其他程式任意存取。

1
2
3
(function(){
//this is a scope
})()

上述是最基本的匿名函式的例子,你可以利用這種方式將你的程式全部包起來,接下來考考各位一個小問題。

1
2
3
4
(function(){
//this is a scope
this.a = 'a';
})()

OK,這個例子宣告了一個a屬性,指派到this,這是什麼意思?該如何存取他?在這裡this指向window, 也因此你只要呼叫他即可,例如:

1
2
alert(a); // a
alert(window.a); // a

因此,你可以只將你要public的function or variable,即可避免變數污染,或是function被call來call去到最後很難debug。

##接下來再看一點進階的用法。

1
2
3
4
5
6
7
(function(win){
//this is a scope
this.a = 'a';
win.b = 'b'
})(window)
alert(a);// a
alert(b);// b

是的,你可以將變數或物件當作參數傳入,可以擴充物件,這就是最基本的擴充物件的方法。接下來我們來直接看一個實際的範例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var box = {
long: 20,
wide: 30,
high: 40
};
//get area
(function(box){
box.area = box.long*box.wide;
})(box);
console.log(box.area); //600
//get volume
(function(box){
box.volume = box.long*box.wide*box.high;
})(box);
console.log(box.volume); //24000

首先宣告一個box,接著計算他的area與volume,利用匿名函式的特性來將計算與邏輯包裝起來,這種實做方式非常常用到,也可以很容易的共同開發組件。

下集–繼承(待續)

Blackbing Playground

Disable Facebook Theater Mode

發表於 2011-02-25

My girl friend doesn’t like the theater mode in facebook, so I write a small tool for her. um~ Actually, I like it. Then I found this technology is very excellent! Base on the official published :

Finally, to make loading as fast as possible, we attached to every thumbnail an HTML5 data attribute containing the source URL of its full-sized version. This way, when you click a thumbnail we can pull that URL from the data attribute and immediately show you the first image without having to make an AJAX call, dropping the average load time for the Photo Viewer to under half a second.

It means they change the url without AJAX call? I feel so strange. I will check it out .

Disable Facebook Theater Mode

Cheers

Blackbing Playground

Google Spreadsheet Gantt Chart

發表於 2011-02-10

這篇文章只是將最近用到spreadsheet的service做個筆記:

google doc非常的好用,我愛上他很久了,最近想要拿他來做甘特圖,看到Gadget裡頭有Gantt Chart( Google Spreadsheets Tips: Gantt Chart (Microsoft Project-like) using Widget ),還算可以,不過有點不符合我的需求:


  1. 專案切割任務需要估計人月,而不是直接指定起始日與結束日。

  2. 時間是相互影響,我可不希望中間增加或減少天數,則所有的時間點都要重新計算。

  3. 計算工時必須要扣除六日以及假日。

因此我將原本的template改了一下,成為這個版本,到目前為止都還算符合我的需求,相當滿意。除了Gantt chart之外,還加上了假日的設定。如此一來進度就都在我的掌握之中了~(淚奔)~

計算工時的部份,google spreadsheet 提供了一個不錯的function :WORKDAY 。節錄部份說明如下。

WORKDAY(start_date, days, holidays)

Returns a date number that can be formatted as a date. You then see the date of a day that is a certain number of Workdays away from the start_date. Holidays (optional) is a list of holidays. Enter a cell range in which the holidays are listed individually.

DEMO

gantt

有興趣的人可以參考DEMO或者是直接下載。

Blackbing Playground

Browser version detect

發表於 2011-01-25

以往在處理一些特殊事件時,會針對不同瀏覽器來做不同的fix,jQuery建議不要用瀏覽器來做這種判斷

Rather than using $.browser to detect the current user agent and alter the page presentation based on which browser is running, it is a good practice to perform feature detection. This means that prior to executing code which relies on a browser feature, we test to ensure that the feature works properly. To make this process simpler, jQuery performs many such tests and makes the results available to us as properties of the jQuery.support object.

不過今天遇到一個問題,希望使用者用IE6, IE7, FF3.5以下時要做特殊處理,看起來不難的問題,想說用jQuery.browser來解決即可,沒想到竟然遇到一些問題,例如firefox3.5的版本,$.browser.version竟然不一樣,參考Mozilla_Firefox,如:Firefox3.5對應的version為1.9.1,而這讓我想到一個問題,1.9.1這並不是個數字,因此無法做數字的大小比較。因此我寫了一隻小plugin來處理version版本的比較。

[sourcecode language=”javascript”]
/*

  • author: blackbing@gamil.com
  • version: 0.1
  • date: 2011/01/24
  • description: I am confused by browser version detection. What I need is blocking the browsers which are ie6/ie7/ff3 , however, I can’t easily detect browser version. Cause I got the version which is like that "6.0.2900.5512.xpsp_sp3_gdr.100427-1636".
    so I write an easy plugin to check the browser version and you can also use callback to block these kind of old fashion browser or do anything else.

For example:
$.detectBrowserVersion({
filter: {
webkit: ‘535’
},
callback: function(){
alert(‘do you live in stone age?’);
}
});
*/
(function($) {

$.detectBrowserVersion = function(opts) {
    var filter = opts && opts.filter ? opts.filter : {};
    var callback = opts && opts.callback ? opts.callback : null;
    //ready to set stubborn and ignore the setting
    var allcookies = document.cookie;
    var pos = allcookies.indexOf("stubborn=");
    if (pos != -1) {
        var st = pos + 9;
        var end = allcookies.indexOf(";", st);
        if (end == -1) {
            end = allcookies.length;
        }
        var value = allcookies.substring(st, end);
        value = decodeURIComponent(value);
        if (value == '1') {
            return false;
        }
    }
    //these above are ignore the detection
    //filtered browsers and lower version
    var filterBrowsers = {
        'msie': '7',
        'mozilla': '1.9.1'
    };
    filterBrowsers = $.extend(filterBrowsers, filter);
    var default_callback = function() {
        alert('you are using old fashion browser!!');
    };
    callback = callback || default_callback;
    var formatVersion = function(version) {
        //to string
        version += '';
        //get version number
        var versionReg = /[\d]+[\.\d]+/ig;
        var res = versionReg.exec(version);
        if (res && res.length) {
            version = res[0];
        }
        var sp = version.split('.');
        var re = sp[0] + '.';
        for (var i = 1; i < sp.length; i++) {
            re += sp[i];
        }
        return +re;
    };
    $.each($.browser, function(k, w) {
        var filterBrowser = formatVersion(filterBrowsers[k]);
        if ($.browser[k] && filterBrowser) {
            var v = formatVersion($.browser.version);
            if (v <= filterBrowser && callback) {
                //callback and do something
                callback();
            }
        }
    });

};

})(jQuery);
[/sourcecode]

DEMO: http://jsfiddle.net/ynU7Y/

github: https://gist.github.com/793041

Blackbing Playground

HTML5 Placeholder type="password" jQuery Plugin - Final Solution

發表於 2011-01-17

placeholder 是HTML5的新屬性,在做input 的預設值還蠻方便的,但無奈IE8以下不支援,因此需要額外做fix。在實際應用中,卻愈到了很多問題:


例如在官網查到的plugin:http://plugins.jquery.com/project/input-placeholder,就不支援type=”password”的結果。因為僅改變value,對於password的顯示方式


就會有問題。上網查了一下,很多人在討論這個問題,但偏偏我就是找不到根本的解決辦法,最後找到一個看起來是處理掉大部分問題的plugin。


以下是我找到支援度最好地plugin:


DEMO: http://mathiasbynens.be/demo/placeholder


plugin: https://github.com/mathiasbynens/Placeholder-jQuery-Plugin


然而在實做中愈到了一些bug,最後追source code追到plugin本身對於type=”password”還有些bug, 一般的情況可能不會遇到,但偏偏就是讓我遇到了,原因在於這一段程式


[sourcecode language=”javascript”]
if ($input.data(‘placeholder-password’)) {
$input.hide().next().show().focus();
} else {
$input.val(‘’).removeClass(‘placeholder’);
}
[/sourcecode]


當這隻程式在做dom Traversing時,用到了$input.hide().next().show().focus(); ,而bug就是因為在查找.next()時查找錯誤而造成。因此我將這幾段程式做了一點小修改,簡單解釋如下:


[sourcecode language=”javascript”]
if ($input.data(‘placeholder-password’)) {
//$input.hide().next().show().focus();
//avoiding dom traversing by unsure dom structure
$input.hide().data(‘placeholder-src’).show().focus();
} else {
$input.val(‘’).removeClass(‘placeholder’);
}
[/sourcecode]


先用.data儲存要替換的input element,將原本用DOM Traversing查出的Element改用.data取回物件。That’s all.


另外,我也順手修正了一個小bug


[sourcecode language=”javascript”]
$replacement = $input.clone().attr({ type: ‘text’ });
$replacement
.removeAttr(‘id’) //we don’t need id, it will be confused by selector within id
.removeAttr(‘name’)
.data(‘placeholder-password’, true)
.data(‘placeholder-src’, $input)
.bind(‘focus.placeholder’, clearPlaceholder);
[/sourcecode]


我們也不需要複製id,尤其在做一些表單驗證時,很多人會用id 來榜定做檢查,這時這個element就會取得錯誤。




當然,我也commit上去給原作者,不過不曉得他會不會採用就是了。若需要修改後的版本請參考:Download jquery.placeholder.js


這讓我想到在開發API時,如何建立自己的sandbox是很重要的。



  1. 不管你怎麼處理事情,只要畫面不是你能控制的,永遠不要相信被渲染過後的DOM結構,因此盡可能不要用模糊的DOM Travesing來查找元素。

  2. 盡可能不要影響別人的行為,就如同clone Element 之後,你應該要避免複製id 以及name,否則有可能會影想到其他程式。


隨著jQuery越來越強大,plugin的質跟量也開始備受考驗,不重新造輪子,但人家的輪子跑起來就是跑不遠,怎辦?有時候這也是很麻煩的一件事情,上述的例子還只是很單純的事件,若遇到更複雜的專案可就不是簡單trace source code就可以解決的事情。@@

1…567…11
Bingo Yang

Bingo Yang

記錄一些生活與工作的雜事,偶爾會寫一些前端網頁開發的心得

109 文章
61 分類
RSS
© 2018 Bingo Yang
由 Hexo 強力驅動
主題 - NexT.Muse