つくってみよう - FireFox拡張機能でブックマークを一覧表示する（７）ソースコードを読む - 表示について①

# つくってみよう - FireFox拡張機能でブックマークを一覧表示する 記事一覧
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（１）公式サンプルを体験する](https://qiita.com/madaaamj/items/5bf2ed67a2f68b0aa243)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（２）動作を確認する](https://qiita.com/madaaamj/items/3e33b058ad2f13167084)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（３）ソースコードを読む - 構成について]
(https://qiita.com/madaaamj/items/bef7102722da2f249515)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（４）ソースコードを読む - 画面について]
(https://qiita.com/madaaamj/items/27dd820d10fd20c51dee)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（５）ソースコードを読む - 処理の概要について]
(https://qiita.com/madaaamj/items/af88405b30820b19a114)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（６）ソースコードを読む - JSON情報の取得について]
(https://qiita.com/madaaamj/items/d9e7b1c296221218d46a)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（７）ソースコードを読む - 表示について①]
(https://qiita.com/madaaamj/items/68888b5d0fdb8f2af84f)
[つくってみよう - FireFox拡張機能でブックマークを一覧表示する（８）ソースコードを読む - 表示について②]
(https://qiita.com/madaaamj/items/a7e3f764f8177139bf7d)

# ソースコードを読む
「FireFox拡張機能でブックマークを一覧表示する」機能をつくっていきましょう。
今回は`<header>`部分の表示とイベント処理を見ていきます。

# ブックマークリスト（ヘッダー部分）を表示する
[bmlist.html](https://github.com/madaaamj/webextensions/blob/main/FireFox/ex_bm_search/content_scripts/bmlist.html)の`<header>`と`<section>`に表示するhtmlを生成します。

まず再描画のために現在の内容をクリアします。これはすでにブックマークリストがあって、別のブックマークファイルからリストを再生成する場合に直前の内容を削除するために行います。

```javascript:bmlist.js（readFile一部）
...
const header = document.querySelector('header');
const section = document.querySelector('section');
...
// ---------------------------------------------------------------
// 関数定義 
// ---------------------------------------------------------------
// 1.ブックマークファイルを選択して読み込み一覧表を生成する。
function readFile() { 
...
    // ファイル読み込み時：ブックマークファイル（.json）を読み込む
    reader.onload = function(e) {
...
        // 再描画のためのクリア
        header.innerHTML = "";
        section.innerHTML = "";

        // HTML書き出し
        showHeader(jsonObj, dicTags);
        showSection(dicTags);
...
```

`showHeader()`で`<header>`（下の画像のheader）に、`showSection()`で`<section>`（同section）に挿入するタグをセットします。
![gamen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277081/bab3ed6e-3317-6ddc-4410-7b9e6a8ba52e.png)
表示には[Bootstrap](https://getbootstrap.com/docs/5.0/getting-started/introduction/)、[Font Awesome](https://fontawesome.com/how-to-use/on-the-web/referencing-icons/basic-use)、[JQuery](https://learn.jquery.com/about-jquery/)を利用します。

ヘッダーでは、「タイトル表示」にBootstrap の[Jumbotron](https://getbootstrap.com/docs/4.5/components/jumbotron/)を利用しています。

「ブックマーク数表示」には[Font Awesomeのレイヤー機能](https://fontawesome.com/how-to-use/on-the-web/styling/layering)を利用しています。

「更新日時」はJSONのルートにある`dateAdded`と`lastModified`を[`Date`オブジェクト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)と[`Intl.DateTimeFormat`オブジェクト](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)を利用して日時に変換して表示しています。

最後に「タグ検索ボックス」と「ワードハイライトボックス（FireFoxのみ動作）」を追加します。
これらの動作は`readFile()`でイベント処理として定義しています。

```javascript:bmlist.js（showHeader一部）
// 5.readFileから呼び出される。ヘッダー部分（<header>）書き出しを行う。
function showHeader(jsonObj, dicTags) {
    // +++++++++++++++++++++++++++++++
    // タイトル表示
    /* Bootstrap */
    let elemDiv_Jumbo = document.createElement('div');
    elemDiv_Jumbo.setAttribute("class", "jumbotron jumbotron-fluid rounded border border-dark mb-3");
    let elemDiv_Container = document.createElement('div');
    elemDiv_Container.setAttribute("class", "container");

    let elemH1_Title = document.createElement('h1');
    elemH1_Title.setAttribute("class", "display-4 text-center");
    elemH1_Title.textContent = "ブックマーク一覧";

    // +++++++++++++++++++++++++++++++
    // ブックマーク数表示
    /* Font Awesome */
    let elemSpan_Image_layer = document.createElement('span');
    elemSpan_Image_layer.setAttribute("class", "fa-layers fa-fw ml-3");

    let elemI_ImageB = document.createElement('i');
    elemI_ImageB.setAttribute("class", "fas fa-bookmark");
    elemSpan_Image_layer.appendChild(elemI_ImageB);

    let elemSpan_Number = document.createElement('span');
    elemSpan_Number.textContent = g_bookmark_num;
    elemSpan_Number.setAttribute("class", "fa-layers-counter");
    elemSpan_Number.setAttribute("style", "background:Tomato");
    elemSpan_Image_layer.appendChild(elemSpan_Number);

    elemH1_Title.appendChild(elemSpan_Image_layer);
    elemDiv_Container.appendChild(elemH1_Title);

    // +++++++++++++++++++++++++++++++
    // 更新日時表示
    let elemP_Datetime = document.createElement('p');
    elemP_Datetime.setAttribute("class", "lead text-center");
    const dateAdded = new Date(Math.floor(jsonObj['dateAdded']/1000)); //下３桁を切り捨てる
    const lastModified = new Date(Math.floor(jsonObj['lastModified']/1000)); //下３桁を切り捨てる
    let options = {
        year: 'numeric', month: 'numeric', day: 'numeric',
        hour: 'numeric', minute: 'numeric', second: 'numeric',
        hour12: false,
        timeZone: 'Asia/Tokyo' 
    };
    elemP_Datetime.textContent = '作成日時: ' + new Intl.DateTimeFormat('ja-JP', options).format(dateAdded) + ' ／ 更新日時: ' + new Intl.DateTimeFormat('ja-JP', options).format(lastModified);
    elemDiv_Container.appendChild(elemP_Datetime);

    elemDiv_Jumbo.appendChild(elemDiv_Container);
    header.appendChild(elemDiv_Jumbo);

    // +++++++++++++++++++++++++++++++
    // タグ検索ボックスを追加する
    let autocomplete = document.getElementsByTagName("header");
    $(autocomplete).append('<div class="ui-widget"><label class="mx-2 mt-4" for="search">タグ検索:</label><input id="search" placeholder="（例）a" size="30"></div>');

    // +++++++++++++++++++++++++++++++
    // ワードハイライトボックスを追加する（FireFoxのみ動作）
    let highlight = document.getElementsByTagName("header");
    $(highlight).append('<div class="ui-widget"><label class="mx-2 mt-3 mb-4" for="highlight">ワードハイライト:</label><input id="highlight" class="p-1" placeholder="（例）firefox" size="30"></div>');  
}
```

「タグ検索ボックス」はJQueryUIの[Autocomplete](https://jqueryui.com/autocomplete/)を利用しています。今回は部分一致で「タグ」を検索してボックスにリストアップされるようにしました。リストアップされたタグを選択すると該当するタグで登録されたブックマークリストへジャンプします。

「ワードハイライト」ではボックスに入力された文字列を[browser.find](https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/API/find)を使って検索して該当するワードをハイライトします。「ブラウザ実装状況」にあるようにFireFoxでのみ動作する関数です🙇
部分一致するワードがある場合Enterキーを押すと該当するワードに移動していきます。
ボックス内でDeleteキーを押すとボックスの内容が削除されます。

画面の右下にある「フローティングボタン」は押下することで[ページトップ](https://api.jquery.com/scrolltop/)へ[移動する](https://api.jquery.com/animate/)ことができます。

```javascript:bmlist.js（readFile一部）
...
// ---------------------------------------------------------------
// 関数定義 
// ---------------------------------------------------------------
// 1.ブックマークファイルを選択して読み込み一覧表を生成する。
function readFile() { 
...
    // ファイル読み込み時：ブックマークファイル（.json）を読み込む
    reader.onload = function(e) {
...
        // イベント処理
        // タグ検索ボックス・ワードハイライト・フローティングボタン機能
        $( function() {
            // タグ検索ボックス
            $('#search').autocomplete({ // jqueryui
                // オートコンプリート
                source: function(request, response) {
                    //let matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term), "i"); // 先頭が一致
                    let matcher = new RegExp(".*" + $.ui.autocomplete.escapeRegex(request.term) + ".*", "i"); // 部分一致
                    response($.grep(g_arrAutocomplete, function(item) {
                        return matcher.test(item);
                    }));
                },
                // 選択時自動で該当箇所にジャンプ
                select: function(event, ui) { 
                    let data = ui.item.value;
                    let pos = $("#" + data).offset().top;
                    $('html').animate({scrollTop: pos}, 3*1000);
                    return false;
                }
            });
    
            // ワードハイライト FireFoxのみ動作
            $("#highlight").keydown(function(e) {
                if(e.which == 13) { // Enter key
                    let word = $("#highlight").val();
                    if (g_highlight_word !== word) {
                        g_highlight_top = 0;
                        g_highlight_word = word;
                        browser.find.removeHighlighting();
                    }
                    if(word) {
                        browser.find.find(word, {includeRectData: true}).then(goto);    
                    }
                    return false;
                }
                if(e.which == 46) { // Delete key
                    $("#highlight").val("");
                    browser.find.removeHighlighting();
                    g_highlight_top = 0;
                    return false;
                }
                // ワードハイライト位置に飛ぶ
                function goto(results) {
                    console.log(`goto:There were: ${results.count} matches.`);
                    if (results.count > 0) {
                        browser.find.highlightResults();
                        for (rect of results.rectData) {
                            for (rectChild of rect.rectsAndTexts.rectList) {
                                // 検索ボックスには移動しない
                                if (g_highlight_top === 0) {
                                    g_highlight_top = rectChild.top;
                                    continue;
                                }
                                if (Math.floor(rectChild.top) > Math.floor(g_highlight_top)) {
                                    g_highlight_top = rectChild.top;
                                    let pos = rectChild.top;
                                    $('html').animate({scrollTop: pos}, 0.5*1000);
                                    return false;
                                }
                            }
                        }
                    }
                }
            });

            // フローティングボタン（トップへ移動する）
            $(window).on("scroll", function() {
                if ($(this).scrollTop() > 100) $('#fab').show();
                else $('#fab').hide();
            });
            $('#fab').click(function() {
                $('html').animate({scrollTop: 0}, 1*1000);
                return false;
            });
        } );
    }
}
```

次回はいよいよ最終回。ブックマークリスト表示（本体）について解説します。

[[ソースコードを読む](#ソースコードを読む)へもどる]