アクセシブルネームを取得するjQueryプラグイン


[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/heppokofrontend/jquery-accessible-name/blob/HEAD/LICENSE) [![Published on NPM](https://img.shields.io/npm/v/@heppokofrontend/jquery-accessible-name.svg)](https://www.npmjs.com/package/@heppokofrontend/jquery-accessible-name)

特にこれといって使うシーンもないですが、夏休みの自由研究的なノリでTypeScriptに書き直して公開しました😂

文中では`label`要素をDOM探索で取得していますが、フォーム関連要素の`labels`というプロパティから`NodeListOf<HTMLLabelElement>`が取得できます👀
恥ずかしながら、このタイミングで改めて`HTMLInputElement`のインターフェース等々を読み返したことで気づきました笑

やっぱりこういう機会を産んでくれるところも、自分が昔書いたコードを見直すのって大切なことだと思います( ˘ω˘ )

<https://www.npmjs.com/package/@heppokofrontend/jquery-accessible-name>

<https://github.com/heppokofrontend/jquery-accessible-name>

追記：2021/07/23 

----

とても久しぶりにjQueryを書くことになったので、
アクセシブルネームを取得するようなものを作ってみたり（何に使うんだ）。

```javascript
/**
 * @see http://jquery.com/
 * @name fn
 * @class jQuery Library
 * @memberOf jQuery
 */

/**
 * 要素のアクセシブルネームを取得します
 * https://qiita.com/heppokofrontend/items/7e5d6d69893828cbf17e#comment-bc346c926f023fc5ac70
 * @return {string} 取得したアクセシブルネーム
 * @memberOf jQuery.fn
 * @license WTFPL　
 */
$.fn.getA11yName = function () {
    /**
     * @param {object} $self - jQueryオブジェクト
     * @return {string} aria-labelledby経由で取得を試みたアクセシブルネーム
     */
    const getAriaLabelledBy = ($self) => {
        const idList = $.trim($self.attr('aria-labelledby')).split(/\s/);
        let result = '';

        for (const id of idList) {
            result += `${$(document.getElementById(id)).text().trim()} `;
        }

        return result.trim();
    };
    /**
     * @param {object} $self - jQueryオブジェクト
     * @return {string} label要素経由で取得を試みたアクセシブルネーム
     */
    const getLabelElementTextContent = ($self) => {
        let result = '';
        const $allElm = $(document.getElementsByTagName('*'));
        const $closestLabel = $self.closest('label');
        const id = $self.attr('id');
        const labels = [];

        // 祖先のlabel要素
        if ($closestLabel.length) {
            labels.push({
                idx: $allElm.index($closestLabel),
                $node: $closestLabel.eq(0)
            });
        }

        // 祖先意外のlabel要素
        if (id) {
            const $labelingByForAttr = $(document.querySelectorAll(`label[for="${id}"]`));

            $labelingByForAttr.each(function () {
                const $label = $(this);

                labels.push({
                    idx: $allElm.index($label),
                    $node: $label
                });
            });
        }

        // 登場順に整理
        labels.sort(({idx: a}, {idx: b}) => a - b);

        for (const obj of labels) {
            result += `${obj.$node.text().trim()} `;
        }

        result = result.trim();

        // 結果的に中身が空でもlabel要素が見つかっていれば、
        // title属性を参照させないように空白文字を返す
        return result || (labels.length ? ' ' : '');
    };
    let result = '';

    this.each(function () {
        const $self = $(this);

        // アクセシブルネームの取得優先順に検証する
        result += (getAriaLabelledBy($self) || $self.attr('aria-label') || getLabelElementTextContent($self) || $self.attr('title') || '');
    });

    return result.trim();
};
```

### 使用方法

```javascript
$('input').getA11yName(); // すべてのinput要素のアクセシブルネームを取得
$('input').eq(0).getA11yName(); // 1つのinput要素のアクセシブルネームを取得
```

### 謝辞

@htsign さんコードレビューありがとうございました！