ChatGPTで最近”書いた”javascriptの紹介

専業のエンジニアではアリマセン。

## 要件
- wordpressで構築しているマニュアルページ内に設置
- tableタグの中のテキストをクリックでクリップボードにコピー
- コピーしたらクリックした場所に「コピーしました」を表示する

## ChatGPTプロンプト
```diff_html
<div id="">
<figure class="wp-block-table">
<table><tbody>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
</figure>
</div>
```
> 上記のhtmlの各セルの文言をクリックするとクリップボードにコピーされるようにしたいです。

## プロンプトの追加
思った動きではなかったので追加しました。

> ブラウザのメッセージは出さずにテキストのすぐ近くに「コピーしました」というメッセージを出したい。メッセージの背景はブルーで文字は白です。1秒後にこのメッセージは自動で消えます。

これでイメージ通りになりました😃

## 最終結果
### CSS
```diff_css
<style>
    .copy-cell {
        cursor: pointer;
    }
    .copy-cell:hover {
        background-color: #f0f0f0; /* Optional hover effect */
    }
</style>
```
### Javascript
```diff_javascript
<script>
    // Function to copy text to clipboard
    function copyToClipboard(text) {
        // Create a temporary textarea element to hold the text
        const textarea = document.createElement('textarea');
        textarea.value = text;
        // Append the textarea to the body (required for clipboard API)
        document.body.appendChild(textarea);
        // Select the text in the textarea
        textarea.select();
        // Execute the copy command
        document.execCommand('copy');
        // Remove the temporary textarea element
        document.body.removeChild(textarea);
        // Alert the user that the text has been copied (optional)
        alert('Copied to clipboard: ' + text);
    }

    // Add click event listeners to all table cells with the 'copy-cell' class
    document.querySelectorAll('.copy-cell').forEach(cell => {
        cell.addEventListener('click', () => {
            // Get the text content of the clicked cell
            const text = cell.textContent;
            // Call the copy function with the cell text
            copyToClipboard(text);
        });
    });
</script>
```
### HTML（class="copy-cell"追加）
```diff_html
<div id="">
    <figure class="wp-block-table">
        <table>
            <tbody>
                <tr>
                    <td class="copy-cell"></td>
                    <td class="copy-cell"></td>
                    <td class="copy-cell"></td>
                </tr>
            </tbody>
        </table>
    </figure>
</div>
```
## 検証
![202408051320.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3805817/7f54e09c-f8b9-7a22-53ee-929499b54ef5.gif)

## 振り返り
### 掛かった時間
- 一回目の試行錯誤（失敗）10分
- プロンプト再作成　5分
- 出力　1分
- 実装確認　5分

### 今まで
今までですと自分で書くのは絶対無理で社内の開発に依頼するかランサーズなどに依頼をするしか手がありませんでした。

社内で依頼するにも社内工数（コスト）が掛かるわけですしプロダクトの開発の手を止めてまでやっていただくものでもありません。ランサーズ依頼では安価かつ即日完了が可能かもしれませんが、それでも全体としては「依頼登録」「ランサーズ選定」「質疑応答対応」「確認と支払い処理」などと全体では丸1日～数日がかかってしまいそうです。

### 今回
ChatGPTを使うことで確認作業なども含めてトータル30分も掛からずできてしまうのはありがたいですね。

### 少し工夫
当初テキスト部分を検出させようとしてミスってました。tdをターゲットに動作させることはできそうでは？と思いその方向性で指示出ししたのが良かったような気はします。

### 今後
自分でも少しプログラミングを勉強することで勘所の良い指示を出せるようになる気がしてます。なお、出来上がったコードがイケてるコードかどうかは分かりません😇

## 追記（2024/8/5）
@juner様にご指摘いただき`document.execCommand()`が非推奨メソッドとのことで修正依頼をしました。
> 上記のソースでdocument.execCommand()が非推奨のようですので修正をお願い致します。

更に出てきたコードに対して別スレッドで検証（改良依頼）

> 上記コードになにか問題点はありますか？よりスマートでモダンな記述に修正できることがあれば指摘してください。

これでCSSとJS部分が以下のように修正されました。
動作確認はOKでした。CSSに少しアニメーションを付けたようです（モダンを解釈した結果でしょうか？）

### 修正後のCSS
```diff_html
<style>
    .copy-cell {
        cursor: pointer;
        position: relative;
    }
    .copy-cell:hover {
        background-color: #f0f0f0;
    }
    .copy-message {
        position: absolute;
        top: 0;
        right: 0;
        background-color: #007BFF;
        color: white;
        padding: 5px 10px;
        border-radius: 5px;
        font-size: 12px;
        z-index: 10;
        white-space: nowrap;
        opacity: 0; /* 初期状態でメッセージを非表示 */
        transition: opacity 0.3s ease; /* フェードイン/アウトのスムーズなトランジション */
    }
    .even-width-table {
        width: 100%;
        table-layout: fixed;
    }
    .even-width-table td {
        width: 33.33%;
    }
</style>
```
### 修正後のJavaSCRIPT
```diff_javascript
<script>
    // クリックイベントを処理するためにイベントデリゲーションを使用
    document.querySelector('.even-width-table').addEventListener('click', (event) => {
        if (event.target.classList.contains('copy-cell')) {
            const cell = event.target;
            const text = cell.textContent.trim(); // 余分な空白を削除

            // テキストをクリップボードにコピー
            navigator.clipboard.writeText(text).then(() => {
                showCopyMessage(cell); // 成功メッセージを表示
            }).catch(err => {
                console.error('Error copying text: ', err);
                alert('コピーに失敗しました'); // 失敗時にユーザーにアラートを表示
            });
        }
    });

    // "コピーしました"メッセージを表示する関数
    const showCopyMessage = (cell) => {
        let message = cell.querySelector('.copy-message');

        // メッセージ要素がすでに存在するか確認
        if (!message) {
            message = document.createElement('div');
            message.className = 'copy-message';
            message.textContent = 'コピーしました';
            cell.appendChild(message);
        }

        // メッセージを表示
        message.style.opacity = 1;

        // 1秒後にメッセージを非表示
        setTimeout(() => {
            message.style.opacity = 0;
        }, 1000);
    };
</script>
```
### ChatGPTによる解説
#### 主な改善点の説明
1. イベントデリゲーション: 
イベントリスナーをテーブルに付け、クリックされた要素が.copy-cellかどうかをチェックします。このアプローチにより、DOM内のイベントリスナーの数を減らすことができ、多くの行がある場合にパフォーマンスが向上します。
1. CSSトランジション: 
不透明度のトランジションを使用して、コピーのメッセージにスムーズなフェードインとフェードアウト効果を提供します。
1. エラーハンドリング: 
コピーが失敗した場合にユーザーに通知するアラートを追加し、即時フィードバックを提供します。
1. モダンなJavaScriptプラクティス: 
constとletを使用し、アロー関数を利用することで、より明確で簡潔なコードを実現しています。
1. 空白処理: 
trim()を使用して、セルテキストの余分な空白をコピー前に削除します。

この改善されたコードは、より良いパフォーマンス、ユーザーへのフィードバック、およびスムーズなユーザー体験を提供し、よりメンテナブルでモダンな開発基準に合わせられています。

### 次回からは
プロンプトする時に「非推奨メソッドを使用しない」という制約事項は付けてみようかと思います。時間があれば（意欲があれば）一度作成してから改善余地を再度検証依頼するというのも良さそうです。

今回やってませんがGemini Advancedも課金しているのでChatGPTで作成してGEMINIで検証（或いは逆）などもありかもと思いました。

ただAIガチャに永遠には付き合ってられないのでほどほどにでしょうか。