HTML の要素名として解釈される文字2021年12月01日 23時21分

この記事は HTML アドベントカレンダーの 1 日目の分です。


HTML をパースするとき、要素名として扱われる文字の範囲は意外と広大です。最初の 1 文字が ASCII の英字であれば、あとは以下に挙げた文字以外のすべての文字が要素名の一部として扱われます。

  • タブ (U+0009)
  • 改行 (U+000A)
  • フォームフィード (U+000C)
  • 復帰 (U+000D、改行文字の正規化により改行と同じ扱いになる)
  • スペース (U+0020)
  • スラッシュ / (U+002F)
  • 大なり記号 > (U+003E)

日本語文字はもちろん、全角空白まで要素名の一部として扱われるということです。

ただし、これは Web ブラウザがおかしな HTML コードを受け取ったときにどこまでを要素名として扱うかという話であり、Web 製作者がおかしな名前の要素を使ってよいということではありません。カスタム要素の名前にはより厳しい制約が存在し、そこには全角空白は含まれません。

1 文字目だけは ASCII の英字しか使えないと妙に厳しい制約になっていますが、これにより HTML パーサの高速化を図れます。Unicode の文字全体から文字種を判別するのはなかなか大変ですが、ASCII 文字のみ受け付ければよいとなればあらかじめ辞書を作っておくなどの対応が取れるからです。

参考文献

HTML のフォームコントロール要素をフォーム外に置く2021年12月02日 21時47分

この記事は HTML アドベントカレンダーの 2 日目の分です。


HTML のフォームコントロール要素 (input 要素、textarea 要素、select 要素、button 要素など) は、基本的にはその要素の祖先に位置する (その要素を取り囲む) form 要素に紐づいています。しかし、実は祖先にない form 要素に紐づけることもできます。フォームコントロール要素の form 属性の値に、紐づけたい form 要素の ID (id 属性の値) を指定すればよいのです。

この機能を使えば、フォームの一部に別のフォームの送信ボタンを埋め込んだり、

<form id="edit-form" method="post" action="/edit">
  ...
  <p>
    <button type="submit">保存する</button>
    <button type="submit" form="delete-form">削除する</button>
  </p>
</form>
<form id="delete-form" method="post" action="/delete">
</form>

表の行ごとに異なるフォームを配置したりできます。

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>タイトル</th>
      <th>操作</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        1
        <form id="edit-form-1" method="post" action="/edit">
          <input type="hidden" name="id" value="1">
        </form>
      </td>
      <td>
        <input name="title" value="" form="edit-form-1">
      </td>
      <td>
        <button type="submit" form="edit-form-1">保存する</button>
      </td>
    </tr>
    <tr>
      <td>
        2
        <form id="edit-form-2" method="post" action="/edit">
          <input type="hidden" name="id" value="2">
        </form>
      </td>
      <td>
        <input name="title" value="" form="edit-form-2">
      </td>
      <td>
        <button type="submit" form="edit-form-2">保存する</button>
      </td>
    </tr>
    ...
  </tbody>
</table>

Node.js ではイベントから非同期イテレータを生成できる2021年12月02日 23時37分

この記事は JavaScript アドベントカレンダーの 2 日目の分です。


Node.js の Events モジュールでは、events.on メソッドを提供しています (EventEmitter オブジェクトの on メソッドとは別物です)。これは、イベントが列挙されるような非同期イテレータを生成するものです。第 1 引数にイベントを発生させる EventEmitter オブジェクトまたは EventTarget オブジェクトを、第 2 引数に列挙したいイベントの名前を指定します。

以下の例では、実行すると 1 秒後と 3 秒後にそれぞれ「foo イベントが発生しました」と出力されます。

// events-on.mjs

import { on } from 'events';

const target = new EventTarget();
setTimeout(() => {
  target.dispatchEvent(new Event('foo'));
}, 1000);
setTimeout(() => {
  target.dispatchEvent(new Event('foo'));
}, 3000);

(async () => {
  for await (const [event] of on(target, 'foo')) {
      console.log(`${event.type} イベントが発生しました。`)
  }
})();

RxJS の Observable.fromEvent メソッドと機能が似ていますね。

ブラウザ上でも使えると面白い書き方ができるのかもしれませんが、Events モジュールのブラウザ用実装では events.on メソッドに対応していません。issue は立っており、作業ブランチも存在するものの、半年以上動きがなさそうです。

HTML のフォームの送信ボタンごとに挙動を変える2021年12月03日 21時29分

この記事は HTML アドベントカレンダーの 3 日目の分です。


フォームの送信先 URL や送信に使う HTTP メソッドは、基本的には form 要素の属性に記述します。送信先 URL なら action 属性、HTTP メソッドなら method 属性ですね。

しかし、ときには「この送信ボタンを実行したときだけ、通常と違う送信先 URL に送信したい」と思うかもしれません。それを実現するのが送信ボタン (<button type="submit"> 要素や <input type="submit"> 要素など) の formaction 属性です。

以下の例では、「保存する」ボタンを実行すると URL /edit に送信されますが、「削除する」ボタンを実行すると URL /delete に送信されます。

<form method="post" action="/edit">
  ...
  <p>
    <button type="submit">保存する</button>
    <button type="submit" formaction="/delete">削除する</button>
  </p>
</form>

formaction 属性以外にも formmethodformtargetformenctypeformnovalidate 属性が存在し、それぞれ form 要素の methodtargetenctypenovalidate 属性の値を上書きできます。

JavaScript の正規表現で複数文字からなる絵文字を扱えるようにする提案2021年12月04日 23時31分

この記事は JavaScript アドベントカレンダーの 4 日目の分です。


今やあちこちで使われている絵文字ですが、その中には 1 文字に見えるのに複数の文字 (符号位置) から構成されるものがあります。例えば「👨‍👩」という男女が並んだ絵文字は、U+1F468 MAN、U+200D ZERO WIDTH JOINER、U+1F469 WOMAN の 3 つの符号位置からなります。

JavaScript の正規表現でこのような絵文字にマッチさせようとすると正規表現パターンが長大になってしまいます。また、文字クラス [...] 内にこのような絵文字を記述すると、「U+1F468、U+200D、U+1F469 という符号位置の並び」ではなく「U+1F468、U+200D、U+1F469 のいずれかの符号位置」にマッチしてしまいます (/u フラグが有効な場合)。

これを解決するための提案が ECMAScript proposal: support properties of strings (a.k.a. “sequence properties”) in Unicode property escapes です。Unicode において符号位置の並びに対して定義されているプロパティを、正規表現パターンで扱えるようにしようというもので、2021 年 12 月現在は stage 2 となっています。

これが実現すれば、\p{RGI_Emoji} という正規表現パターンが「👨‍👩」という符号位置の並びにマッチするようになります。さらに、このパターンは文字クラス [...] の内部で使うこともできます。ひとつの文字クラスにマッチするのはひとつの符号位置 (/u フラグが無効な場合はひとつの符号単位) というこれまでの常識が覆されるのです。

個人的には、将来的に JavaScript 組み込みの機能で Unicode の書記素クラスタを扱えるようにならないかと期待しています。

参考文献