2012-10-31

ZK-1430 的故事

ZK-1430 真是一個曲折離奇的故事,分上下兩集來講好了 XD

上集:召喚 v/hflex="min",結束這個 issue

起手布局是一個 bandbox,然後 bandpopup 當中塞了一個 listbox。 希望這個 listbox 只顯示 5 個 row 的大小,所以設了 rows="5", 但是 bandpopup 不會跟 listbox 一樣大,自己長自己的大小。

算 bug 嗎?

乍看之下很像 bug,但是如果把 bandpopup 當成普通的 layout 來想, 那麼設定 v/hflex="min" 用小孩的大小來決定自己的大小,就十分合理了。

所以召喚 v/hflex="min",結束這個 issue!

(謎之聲:這上集也太短了吧?)

下集:IE 不能動,還有什麼值得我心痛

隔了兩天,原 po 上來說:

喔喔... 用 v/hfex="min" 這招在 Firefox 上 ok...
但是為什麼 IE7 沒效果?

WTF... 什麼不好炸、偏偏炸在 IE 上啊啊啊啊 <囧>

中間曖昧讓人受盡委屈的劇情就跳過,到外傳再另外賣一次錢,直接跳重點。 問題炸點的 stack trace 大概是:

ComboWidget.open()
    this.presize_()  //實際是跑 Bandbox.presize_(),會回傳 true
        zWatch.fireDown() //參數是 'onFitSize', bandpopup

zWatch.fireDown()
    zWatch.fire()
        _fire()
            _visiChildSubset()  //表象炸點
                _visible()
                    zk.Widget.isWatchable_() //instance 是 Bandpopup

zk.Widget.isWatchable_()
    zk(wgt.$n()).isRealVisiable(true)
        jqzk.isRealVisiable()   //實際炸點

因為 _visiChildSubset() 回傳空的 array,導致 _fire() 的 gun 沒東西可作, 所以 bandpopup 也就沒有真的去作 onFitSize 了。

_visiChildSubset() 會回傳空的 array,是因為他只打算回傳已經 visible 的東西。 所以一路得追到 jqzk.isRealVisiable() 當中。

jqzk.isRealVisiable() 本來是在 dom.js 裡頭,但(還)不知道在哪裡動了手腳, 真正執行的是 domie.js 當中的 jqzk.isRealVisiable()、 而且還是 IE 7 以下的才會這樣搞(所以用 IE9 模擬 IE7 也能重現問題)。 這裡的邏輯是從 bandpopup 開始沿著 DOM tree 一路檢查到 <body>, 必須都要 visible 才回傳 true,否則回傳 false。 至於判斷是不是 visible 的方式,因為 strict 是 true,所以下面兩個都要成立

$n.css('display') != 'none';  //_visi0() 的內容
$n.css('visibility') != 'hidden';

而在 IE6 / IE7 上頭,第二個判斷會回傳 false,原因得回到 ComboWidget.open(), 在呼叫 presize_() 之前,做了這樣的事情:

// throw out
pp.style.visibility = "hidden";
pp.style.left = "-10000px";

這裡的 pp 等於上頭的 $n,所以第二個判斷就爆了。 一路回推回去會讓 _visiChildSubset() 找不到東西→沒東西 fire→bandpopup 沒調 size。

至於解法,目前是在 Bandbox.presize_() 掛上一段

if (zk.ie < 8) {
    var pp = this.getPopupNode_();
    if (pp) pp.style.visibility = "";
}

然後才去作 zWatch.fireDown('onFitSize', bp, {reverse: true});。至少目前看起來沒問題...... [遠目]

外傳:翻譯翻譯,什麼叫做驚喜?

其實整個故事就是一個怪。

從最上層的 ComboWidget.open() 開始看,很難懂為什麼一開始呼叫了一次 this.getPopupNode_(), 得到的值只用來設 pp.style 的 width,height 還是給死成 auto。 然後中間除了呼叫 $pp.makeVParent() 之外好像也沒幹麼, 轉眼又去 call this.presize_() 然後再來一次 this.getPopupSize_()? 那第一次的 getPopupSize_() 到底是要作什麼用的?

為什麼 pp.style.visibility 要設定成 hidden?(寫 pp.style.left="-10000px" 還不夠保險?) 然後在 this.presize_() 之後再設成空字串?

zk.$extends(zul.inp.ComboWidget 當關鍵字去 search 的結果, 發現只有 ComboboxBandbox 是 extends ComboWidget,那蓋這一層 OO 是為了什麼? (讓別人比較不好 trace? XD)為什麼其他行為類似的 class 沒有跟著用? 難道在這裡也中了「未成年就這麼優」的毒嗎?又, 想把 pp.style.visibility = "hidden"; 拿掉,行嗎? 想把 this.presize_() 那段挪到 pp.style.visibility = "hidden"; 前頭去,行嗎?

至於為什麼 jqzk.isRealVisiable() 會在 IE7 以下跑另外一個版本? 當然,在 IE 上發生什麼事情都不意外 [誤],但當初踩到什麼雷、兩邊的邏輯哪裡不一樣? 今天想不判斷 visibility != "hidden",行嗎?

很自然地,越底層的東西就越不太可能錯、或著該說就越不敢去改。 所以在處理 ZK-1430 的時候就只能往後退退退... 退到黃線後頭去了 退到最末端的 Bandbox.presize_() 去硬幹,還好看起來這個 method 沒人想要呼叫。 但是這樣真的好嗎? 真的「對」嗎?

師爺,給我翻譯翻譯,什麼叫做驚喜?
所謂驚喜就是 refactory ComboWidget.open(),接上他的腿!

(To be continue... [完全誤])

No comments:

Post a Comment