🦁

Markdownに貼り付けられるドロップダウンメニュー付きテーブルHTMLを出力するWebツールを作った

に公開

Markdownでドロップダウンメニュー付きテーブルを作成するWebツールを作った話

はじめに

なんとなく、Markdownドキュメントでドロップダウンメニュー付きのテーブルを作成したいと思ったので、READMEや技術文書で、インタラクティブな要素を含むテーブルを表示できるMarkdown用HTML生成ツールを作った。
※GithubやQiita、zenn等ではドロップダウンメニューは表示されない仕様らしい

この記事では、そんな課題を解決するためのWebツール「Markdown Dropdown Generator」について解説する。

img01.png

以下がMarkdownに貼り付けたHTMLコードのTable

img02.png

ツールの概要

Markdown Dropdown Generatorは、以下の特徴を持つWebツール:

主な機能

  • 行数・列数を自由に設定可能なテーブル生成
  • 各セルにドロップダウンメニューを配置
  • 行ヘッダー、列ヘッダー名の設定
  • 選択状態を保持したHTMLコードの生成
  • ブラウザだけで動作するため、インストール不要
  • 直感的なUIで簡単にテーブルを作成可能
  • リアルタイムプレビューで確認しながら表生成が編集可能
  • 各列のドロップダウン選択肢を列ごとに設定可能
  • 行ヘッダー列ヘッダーの有無を切り替え可能

技術的なポイント(ここから先は開発者向けの説明)

1. シンプルな実装

このツールは、純粋なHTML、CSS、JavaScriptのみで実装している。

  • 依存関係がなく、ブラウザだけで動作
  • コードの理解と保守が容易

2. モジュール分割による保守性

機能ごとにJavaScriptファイルを分割した。

  • コードの見通しが良くなる
  • 機能の追加や修正が容易
  • バグの特定と修正が簡単

3. 実装の工夫

シンプルながらも実用的な機能を実現するため、以下の工夫を施した。

  1. セルの選択状態管理
let cellSelections = {
  [cellId]: selectedValue
};
  • セルの選択状態をオブジェクトで管理することで、複雑なデータ構造より簡潔に実装でき、状態の保存と復元をする。
  • セルIDをキーとして使用することで、配列よりも高速にセルの状態にアクセスでき、テーブル再生成時も選択状態を保持できる。
  1. ヘッダー設定の動的更新
// チェックボックスの状態に応じて設定UIの表示/非表示を制御
const showColumnHeaders = document.getElementById('show-column-headers').checked;
const showRowHeaders = document.getElementById('show-row-headers').checked;
const headerSettings = document.getElementById('header-settings');
if (!showColumnHeaders && !showRowHeaders) {
  headerSettings.style.display = 'none';
  return;
}
  • 直接style.displayプロパティを操作することで、CSSクラスの切り替えよりもコードがシンプルになり、即時に反映できます。設定変更の頻度が低いため、この方法が最適だと思われる。
// 既存の設定値を保持しながら、新しい設定を生成
const headerValue = document.getElementById(`header_col_${i}`) ? 
                   document.getElementById(`header_col_${i}`).value : 
                   `${i+1}`;
const optionsValue = document.getElementById(`options_col_${i}`) ? 
                    document.getElementById(`options_col_${i}`).value : 
                    'A,B,C';
  • テーブル再生成時に、ユーザーが入力した設定値を維持するため、既存の入力フィールドの値をチェックしてから新しい設定を生成する。この条件分岐を使用することで、値が存在する場合はその値を使用し、存在しない場合はデフォルト値を使用するという実装にした。
// 入力フィールドのIDを動的に生成し、一意性を確保
columnHeadersHTML += `
  <div style="margin-bottom: 10px;">
    <div>列${i+1}: 
      <input type="text" id="header_col_${i}" value="${headerValue}" style="width: 150px;">
      <input type="text" id="options_col_${i}" value="${optionsValue}" style="width: 250px;" placeholder="プルダウンの選択肢(カンマ区切り)">
    </div>
  </div>`;
  • 入力フィールドにインデックスを含む一意のIDを付与することで、列数が変更されても既存の列の設定が保持される。これにより、テーブル構造を変更してもユーザーの入力データが失われない。
  1. イベント伝播の制御
// ドロップダウンの変更イベントをリスニング
document.querySelector('.dropdown-table').addEventListener('change', function(e) {
  if (e.target.tagName === 'SELECT') {
    // セル選択状態の保存
    const cellId = e.target.id;
    cellSelections[cellId] = e.target.value;
    
    // コード生成の更新
    updateDropdownHTML();
  }
});
  • イベント委譲パターンを使用することで、多数のドロップダウン要素に個別にイベントリスナーを設定する必要がなくなり、テーブルのサイズが大きくなっても、メモリ使用量などパフォーマンスが低下しないよう最適化されるはず。
  1. テーブル生成の効率化
// テーブル生成の最適化
function generateTable() {
  const rows = parseInt(document.getElementById('row-count').value);
  const cols = parseInt(document.getElementById('col-count').value);
  
  // DOMの操作回数を最小限に抑える
  let tableHTML = '<table class="dropdown-table">';
  
  // 一度にまとめてHTMLを生成
  for (let i = 0; i < rows; i++) {
    tableHTML += '<tr>';
    for (let j = 0; j < cols; j++) {
      // セルの生成
    }
    tableHTML += '</tr>';
  }
  
  tableHTML += '</table>';
  
  // DOMの更新は1回だけ
  document.getElementById('table-container').innerHTML = tableHTML;
}
  • 複数回のDOM操作を避け、一度にHTMLを生成してからDOMに追加することで、ページのレンダリングパフォーマンスが向上すると思われる。
  • 特に行数や列数が多い場合に効果的な最適化手法と思われる。

まとめ

Markdown Dropdown Generatorは、シンプルな実装ながらも実用的な機能を提供するWebツールを作成した。ユーザーの視点に立った使いやすさと技術的なシンプルさを両立させた。

参考リンク

Discussion