馬拉松需要提前好幾個月前報名,熱門賽事報名又常上演秒殺戲碼,因此全盤掌握未來半年賽事資訊,妥善規劃「檔期」、留意報名時間是愛馬士(愛跑馬人士)的必備功課。我個人則偏愛運動筆記的賽事列表,除了資訊完整,程式部分採用jQuery/AJAX,介面富有濃厚的HTML5風格,甚至還用了Font Awesome呢!(謎之聲:這些跟馬拉松比賽是有什麼關係啦?)

唯一美中不足-運動筆記的賽事網頁沒有距離篩選功能,台灣這幾年路跑賽事多如牛毛,查詢結果項目超過200筆,網頁本身提供地點、類型、年份篩選,卻沒有鎖定特定距離(全馬、半馬)的功能。對我這種鎖定全馬拼業績的人,得在一堆比賽挑出全馬,有點小麻煩。

會寫網頁有一項額外好處:遇到網頁不如己意,動手改到自己開心!

我寫了一個小外掛,為運動筆記賽事網頁偷偷加上自製距離篩選器,篩選器可掃瞄所有賽事加以分類,分成5K、5K+(5K以上,21K以下)、半馬、超半馬、全馬及超馬,預設為全部顯示,點選距離項目右側的小叉叉可排除該分類。如下圖所示,清單可以只顯示有全馬項目的比賽:

如果想使用這個篩選功能,Chrome瀏覽器需先安裝Tampermonkey(Firefox則要安裝Greasemonkey),接著可連Grease Fork點選「安裝腳本」:

以Tampermonkey為例,按下「安裝腳本」後,會進入程式碼檢視頁面,請點選「安裝」:

之後,重新進入運動筆記賽事頁面,Tampermonkey圖示會顯示紅字的1,點選圖示展開選單可見「運動筆記賽事清單路跑距離篩選」,若想停用可點選前方的綠色數字鈕。

這時可以看一下網頁,年份篩選器的下方會默默多出距離選項,Enjoy It!

外掛畢竟還是奇技淫巧,運動筆記直接內建距離篩選功能才是最完美的解決方案。附上程式碼,並將它設成CC0(公眾領域貢獻宣告)授權,對於參考、引用、改寫(且不需加註原作者)均不設限,希望能有一丁點貢獻。


// ==UserScript==
// @name       運動筆記賽事清單路跑距離篩選
// @namespace  http://blog.darkthread.net/
// @version    0.9.2
// @description  為運動筆記之賽事清單加入路跑距離篩選器 by Jeffrey Lee, 黑暗執行緒
// @match      http://tw.running.biji.co/index.php?q=competition*
// @license    http://creativecommons.tw/cc0
// ==/UserScript==
 
//依長度不同區分為六大類
var distCatgs = {
  "5K": "5k", "5K+": "5k-plus", "半馬": "half-ma", 
  "超半馬": "ultra-half-ma", "全馬": "std-ma", "超馬": "ultra-ma" 
};
function scanEvents() {
  //若先前已掃瞄過,略過不處理
  if ($(".com_detail_info:first").hasClass("scan")) return;
  //掃瞄所有賽事,依其距離分類,以class標註於資料列元素
  //場數統計表
  var stats = {}; 
  $(".com_detail_info .competition_event .event_item").each(function() {
    var match = /[0-9.]+K/.exec(this.innerText);
    if (!match) return;
    var dist = match[0];
    var km = parseInt(dist.replace("K", ""));
    // 分類成 5K, 5K+, 半馬, 超半馬, 全馬, 超馬
    var catg = "5K";
    if (km > 5 && km <21) catg = "5K+";
    else if (km == 21) catg = "半馬";
    else if (km > 21 && km < 42) catg = "超半馬";
    else if (km == 42) catg = "全馬";
    else if (km > 42) catg = "超馬";
    // 在資料列元素上以class標示
    $(this).closest(".com_detail_info").addClass(distCatgs[catg]);
    if (stats.hasOwnProperty(catg)) stats[catg]++;
    else stats[catg] = 1;
  });
  console.log("Scanned");
  //更新統計數於篩選鈕後方
  var $fltrBar = $("#distance_filter");
  $.each(Object.keys(distCatgs), function(i, c) {
    $fltrBar.find("." + distCatgs[c] + " .counter").text(stats[c]);
  });
  //在第一筆賽事做記號註記已經掃瞄
  $(".com_detail_info:first").addClass("scanned");
}
// 加入篩選器
$("#distance_filter").remove(); //若已存在先移除之
var h = [];
$.each(Object.keys(distCatgs), function(i, d) {
  h.push(
  '<div class="float_select ' + distCatgs[d] + '" data-catg="' + distCatgs[d] + '">' +
  '<div class="filter_choose_item com_type filter_select_item">' + d + 
  ' <span style="font-size:80%">(<span class="counter"></span>)</span>' +
  '</div>' +
  '<div class="drop_choose fa fa-remove" style="display:block"></div>' +
  '</div>');
});
$("#menu_choose_bar .filter_item:last").before(
  '<div class="filter_item" id="distance_filter">' +
  '<div class="filter_type">距離</div>' +
  '<div class="filter_value">' +
  h.join() +
  '</div></div>');
 
var $filterBar = $("#distance_filter");
$filterBar.on("click", ".filter_choose_item", function() {
  $(this).addClass("filter_select_item").next().show();
  scanEvents();
  filter();
  return false; //防止觸發原始網頁的查詢
}).on("click", ".fa-remove", function() {
  $(this).hide().prev().removeClass("filter_select_item");
  scanEvents();
  filter();
  return false;
});
//執行篩選
function filter() {
  var $all = $(".com_detail_info");
  $all.removeClass("show").hide(); //先全部隱藏
  var selectedCatgs = $.map($filterBar.find(".filter_select_item"), 
    function(elem) { //有選取的距離加上show
      var catgCss = $(elem).parent().attr("data-catg");
      $all.filter("." + catgCss).addClass("show") 
    });
  $all.filter(".show").show(); //顯示有標上show者
}
scanEvents();


Comments

Be the first to post a comment

Post a comment