2007-07-14

以年月份做分類的導覽連結列 (Year & Month Breadcrumbs)

如果像我用 Daily Archive 來做日曆的 Hack,會發現一個問題:要怎麼找當月份或是當年份的備份文章呢?之前很多朋友都發現 Archive 其實只有一個能生效,即使手動 Hack 塞了兩個,還是會不大正常。其實目前為止這個問題並沒有好的解法(除非不用那個日曆的 Hack),能夠做的就是在一些小地方加上連結,讓讀者可以看到當年份或是當月份的文章。這裡介紹的 Hack 是文章上方的導覽列(要點進特定文章才會出現),這個導覽列英文叫 Breadcrumbs,是「覆蓋在麵包上的小屑屑」,英文用得其實比中文「導覽列」 (NavBar) 更貼切(我也不知道中文怎麼翻,總不能真的叫麵包屑吧),Hack 完或實際特定文章連結看範例就知道是怎麼回事了。

原作者做的 Hack 是導覽連結列是 首頁 -> 標籤 -> 文章標題,不過眼尖的人會發現兩個問題:第一,如果有多個標籤該怎麼辦?第二,進到單篇文章裡面,文章一開始就有文章標題、最後面會列出該文章所有標籤,這個導覽連結列完全沒有可用性啊!因此有了改良,改成以時間來導覽連結,變成像是 首頁 -> 年份 -> 月份 -> 文章標題,嗯嗯!就樣也算是有了該篇文章當月或當年的 Archive 作用了。但是我發現這份改良還是有問題,作者當月的 Archive 還是借用 Monthly Archive 的連結來做的,像我用 Daily Archive 還是會不正常啊!研究了一下,原來 Archive 是用 Blogger 自己搜尋引擎的語法,帶入時間範圍當變數達成的,所以我就又修改了一下,當月的 Archive 一樣比照辦理,做出來文首的導覽列連結就不受 Archive 的型態和設定影響了!

一樣打開範本->修改 HTML->勾選「展開小裝置範本」,在 Blog 文章的這個 widget 區段內(<b:widget id='Blog1' ....> </b:widget>),找到顯示文章的那一個子區段,應該是下面這一行開始:

<b:includable id='main' var='top'>

這行下面表示的是在產生文章的完整內容,由於我們這個文首的導覽列要放在文章內容的前面,因此在產生的文章迴圈後、產生發表日期和標題前塞入下面紅色那一行:

<b:loop values='data:posts' var='post'>
<b:include data='post' name='breadcrumbs'/>
<b:if cond='data:post.dateHeader'>

而這個新加進來的 include 定義 breadcrumbs,我們也要宣告,因此下面的程式碼請加在 <b:includable id='main' var='top'> 這行的前面:

<b:includable id='breadcrumbs' var='post'>
<!-- Year & Month Breadcrumbs -->
  <b:if cond='data:blog.pageType == "item"'>
    <p class='breadcrumbs'>
      導覽連結:  <a expr:href='data:blog.homepageUrl' rel='tag'>首頁</a>
      <script type='text/javascript'>
        generateBreadcrumbs();
      </script>
      <b:if cond='data:post.title'>
        -&gt;  標題: <data:post.title/>
      </b:if>
    </p>
  </b:if>
<!-- End of Breadcrumbs Hack -->
</b:includable>

而上面的程式碼裡,有用到一段 Javascript 的函式 generateBreadcrumbs(),因此接著要把這個函式的宣告和定義放到樣版裡面。和之前的 Hack 一樣,把下面的 Javascript 程式放到樣版 </head> 標籤前面,或是自己定義的 Javascript 區段:

<script type='text/javascript'>
//<![CDATA[
<!-- Functions used for generating Year & Month Breadcrumbs: generateBreadcrumbs() -->
function generateBreadcrumbs() {
  var strHref = location.href.toLowerCase();
  var intWhereAt = strHref.lastIndexOf('/', strHref.indexOf('.html'));
  var intYear = parseInt(strHref.substr(intWhereAt - 7, 4),10);
  var strCrumbOutput = ' -&gt; 年份: <a href="/search?updated-min=' + intYear;
  strCrumbOutput += '-01-01T00%3A00%3A00-08%3A00&updated-max=' + (intYear + 1);
  strCrumbOutput += '-01-01T00%3A00%3A00-08%3A00">' + intYear + '</a>';
  var intMonth = parseInt(strHref.substr(intWhereAt - 2, 2),10);
  var intNextMonthYear = intYear;
  var intNextMonth = intMonth + 1;
  if (intNextMonth > 11) {
    intNextMonth = 1;
    intNextMonthYear += 1;
  }
  var strMonth = intMonth;
  if (intMonth < 10) strMonth = "0" + intMonth;
  var strNextMonth = intNextMonth;
  if (intNextMonth < 10) strNextMonth = "0" + intNextMonth;
  strCrumbOutput += ' -&gt; 月份: <a href="/search?updated-min=' + intYear;
  strCrumbOutput += '-' + strMonth + '-01T00%3A00%3A00-08%3A00&updated-max=' + intNextMonthYear;
  strCrumbOutput += '-' + strNextMonth + '-01T00%3A00%3A00-08%3A00">' + strMonth + '</a>';
  document.write(strCrumbOutput);
}
//]]>
</script>

最後就是外觀了。原始碼裡面用到了一個新定義的 CSS 變數:breadcrumbs,這是用來顯示這個導覽連結區段的 Style,所以在 CSS 定義的區段 <head> 標籤後面、<style>區段裡加入以下的 CSS (樣式請自行根據自己的樣版調整顏色、字型大小和分隔線):

/* Style for Year & Month Breadcrumbs */
.breadcrumbs {
 color: $sidebarcolor;
 letter-spacing: .1em;
 font: $postfooterfont;
 border-bottom:1px dotted $bordercolor;
 margin:0 0 0.5em;
 padding:0 0 0.5em;
}

存檔搞定!檢視首頁的時候好像沒什麼改變,因為顯示這個連結列的條件是:

<b:if cond='data:blog.pageType == "item"'>

也就是要點入單篇文章的時候,效果才會出來,顯示在文章標題的上面,我想在其他地方應該沒有導覽的必要吧~

參考文章:
Adding a Breadcrumb Trail to your Blogger Post
Year & Month Breadcrumbs

註:已修正 8, 9 月文章月份導覽會變成 0 的問題,原因是 Javascript parseInt(08) 的問題,改成 parseInt(08, 10) 就沒事了。

回應: 22

Sam H. 提到...

Abin您好,我有使用您這個Hack,不過使用之後會變成月份顯示是變成"00",像是這裡所示,我猜有可能是
var intMonth = parseInt(strHref.substr(intWhereAt - 2, 2));
這邊的問題,
修改之後就像這邊一樣正常顯示為"09"了,可是看您的是顯示正確的,所以想問問看會是什麼樣問題(說不定也有可能是我模板的問題 :P)。
謝謝您了 ^^

fumiko 提到...

我也有一樣的問題,9月的部分顯示會變成00
var intMonth = parseInt(strHref.substr(intWhereAt - 2, 2));改成-1, 2後,變成10、11、12月顯示為00(其實我不知道該怎麼改就亂填數字)
而且不知道為什麼3/20的文章顯示的月份導覽是7月
我反覆看這些程式碼,猜測好像是變數設定的問題,不過我不懂,胡亂修改測試也得不到任何結論
如果可以的話,希望可以明白修正的方法

不好意思勞煩您了^^
祝 新年快樂

Abin 提到...

To Sam h. & funiko:

這個 hack 的動作,主要是 parse 該文章的網址,因為網址裡分類方式是依年、月來分路徑,所以程式碼是先抓文章網址、找到最後一個"斜線"位置 (intWhereAt)、往前推兩個字元、把這兩個字元轉換成 int 就變成月份變數了。除非命名規則改了,我不知道這還會有什麼問題,也不知道怎麼修正起。
(看來兩位都正常了,說不定是 BlogSpot 自己的問題)

nobody 提到...

Hello Abin,小弟按照您的說明將CODE分別拷貝進我的BLOG頁面碼的相關位置,但卻出現了以下訊息,

我們無法儲存您的模版
請修正下列錯誤,再重新提交您的模版。
我們無法剖析您的範本,因為它的結構不完整。 請確定所有的 XML 元素均已正確關閉。
XML 錯誤訊息: The entity name must immediately follow the '&' in the entity reference.

找了好久都不知道到底該如何修正,請幫我看看,多謝!
My blog

Abin 提到...

To nobody:
錯誤訊息不是告訴你問題關鍵在哪裡了嗎:「XML 錯誤訊息: The entity name must immediately follow the '&' in the entity reference.」
你找一下原始碼裡面、有用到 '&' 這個符號的部份,如果在註解裡,你就刪掉他試試看,如果不是,可以暫時用其他字元替代,這樣光看你的 Blog 我是沒辦法幫你 debug 的。要有你改過、不能存檔 XML 的原始檔才能知道哪裡有問題。

通達人 提到...

Abin您好,我有使用您這個Hack,不過使用之後發現位置是頂左的,看起來真的有點怪。想請教一下如果我要調往右一些的話,是要改那個部份呢?謝謝!我的網址:http://prudentman.idv.tw/2008/07/cancer-updates-from-john-hopkins.html

Abin 提到...

To 通達人:
要靠左靠右、因應版面的需求你應該自己調整樣板的 CSS,直接複製我的程式碼使用,不一定能滿足滿個樣板不同的人的需求。
像你的版面,預設樣板本來就有稍稍平移向右,因此要改動這個 breadcrumbs 的位置,你可以調整自己的樣板,或是這個 breadcrumbs 的樣式設定。前者我幫不了你,後者的調法我試了一下,只要改 padding 就行了。原來是:
padding:0 0 0.5em;
改成這樣(向左 padding 多一點):
padding:0 1.5em 0.5em;
是不是就是你要的樣子哩?

通達人 提到...

果然,一改了之後就是我要的樣子了!多謝!不好意思,請教一個和這個bloghack沒有直接關係的問題,你是怎麼「變」得很會用blogger的?有沒有什麼學習的路徑可供分享呢?謝謝!

Abin 提到...

To 通達人:
Blogger 提供很多彈性,讓你能夠自訂樣板和模組功能,關鍵不是在很會用 Blogger,而是能延伸 Javascript 和 CSS,把這些技術配合 Blogger 環境使用。我一點也沒「很會用」,只是參考了很多人的文章,用自己的一點點程式基礎稍微改了一下,如果要學習的話,最簡單還是從參考人家的文章和程式碼開始,然後加強自己對 CSS 和 Javascript 的知識,漸漸地你就會變很會用了。

匿名 提到...

Hello, 你好

到了八月發現這個導覽列有個 Bug,每篇在八月的舊文章,日期導覽中的月份顯示都是 00,我點選了其他年份的,好像 2007 年的九月份舊文,導覽列月份也是顯示 00,不知道應該怎麼修改才好呢?謝謝喔!

匿名 提到...

真不好意思,我看到上面有人問了同樣的問題了,請刪留言吧,謝啦!

鯰魚 提到...

似乎每年的八月九月都有問題...剛剛測試發現的

Abin 提到...

To 鯰魚:
以上提到月份變成 0 的 Bug 原因我找到了,那是 Javascript parseInt() 函式常見的錯誤,只要 parse 到 08 或 09 就會變成 0,問題已經修正,只要使用這個函式時指定是十進位專用 (parseInt(08,10)),就不會發生這個錯誤。(以上範例程式也已修正,只要修改 parseInt 後面加一個指定十進位的參數即可)

so ist es 提到...

非常謝謝你找到方法修改它~~~現在用起來很順喔!

阿厝 提到...

您好,使用您的hack之後出現:「ID 為 Blog1 的小裝置不可包含此元素: "#comment". 小裝置只能包含 b:includable 元素。」但小弟不知道這段話要怎麼修改以致能符合我的模版。

附上修改之後無法儲存的模版,請按這裡
感謝您的回覆。

Abin 提到...

To 阿厝:
我想你可能沒有先看這篇文章。我看了一下,您問的問題和碰到的狀況,和我的這個 Hack 無關(看您碰到的錯誤訊息,關鍵字我這篇文章也沒用過),每個人的樣板樣式都不一樣,我是沒辦法幫每個人 trace bug 的。

阿厝 提到...

其實我看過那篇:P。
只能說還有一點期待(希望能碰到您剛好覺得無聊的時候),畢竟自己想說是不是哪個小地方沒注意到所以不行(沒想到是無關啊)。

很感謝您的回覆,抱歉佔用您的時間。

Down To Earth 提到...

Abin你好...我用了這個HACK之後,顯示上是沒問題,但是最後要貼上調整字體的CODE時,卻出了問題,貼上去的CODE反而會出現在HEADER上方,能否幫我看看?

http://www.badongo.com/pic/4599713

Abin 提到...

To Down To Earth:
你調整字體的 CSS 樣式貼錯地方了。CSS 樣式是貼在 <head> 後面沒錯,但是,請放在「樣式定義的區段」,還要在<style> 的區段裡面。

黑兄 提到...

個人覺得導覽連結最後再加上標題好像有點多餘,畢竟下方已經有標題了。不過這個導覽列實在不錯,感謝分享

Abin 提到...

To 黑兄:
是啊!現在看是挺多餘的,只要把下面三行拿掉,就不會顯示標題了:
<b:if cond='data:post.title'>
-> 標題: <data:post.title/>
</b:if>
我自己的也順便改掉了 :P

jijiong 提到...

abin兄你好:剛無意間發現,當我發了一篇文後,再去更改它的發文時間,譬如:2/26發文後,更改為1/20後,這個導覽列內的月份,好像還是維持在2月份! 是因為blogger還來不及將時間抓進去顯示的關係嗎? 還是??

張貼留言

歡迎留言或發表意見,不過要理性不做人身攻擊。匿名的朋友得到回應的速度會比較慢喔~
發問相關的禮貌和規矩請先參考這篇文章,不當留言、和本文無關的回應可能會被直接刪除無視喔!