🎆

投稿記事の画像の処理

2024/01/29に公開

zennは画像をクリップボードからコピペすると

![](https://storage.googleapis.com/zenn-user-upload/26aa03bb83d3-20240122.png)

自動で形を変換して保存してくれる
こいつを実装していきたい
マークダウンで画像を読み込む機能はParsedownにある
jQueryでできるみたいだからやってみよう

npm install jquery --save

npmでインストールしたらnode_modules下にファイルがあるからそれをwebroot/jsに移動

script.js
$(document).ready(function() {
    $('#body').on('paste', function(event) { // '#body'は投稿フォームに合わせる
        var items = (event.originalEvent || event).clipboardData.items;
        for (var index in items) {
            var item = items[index];
            if (item.kind === 'file') {
                var blob = item.getAsFile();

                var formData = new FormData();
                formData.append('image', blob);

                $.ajax({
                    url: '/posts/uploadImage',
                    type: 'POST',
                    data: formData,
                    processData: false,
                    contentType: false,
		    headers: {
                        'X-CSRF-Token': window.CakephpCsrfToken
            	    },
                    success: function(response) {
                        if(response.url) {
                            var markdownImageText = `![alt](${response.url})`;
                            insertAtCursor($('#body'), markdownImageText);
                        }
                    },
                    error: function() {
                        console.error('Failed to upload image');
                    }
                });
            }
        }
    });
});

function insertAtCursor($field, text) {
    var cursorPos = $field.prop('selectionStart');
    var v = $field.val();
    var textBefore = v.substring(0, cursorPos);
    var textAfter = v.substring(cursorPos, v.length);

    $field.val(textBefore + text + textAfter);
}

jsとやりとりしてくれるやつをコントローラに記述

PostsController.php
use Cake\Http\Response;
use Cake\Routing\Router;

   public function uploadImage(): Response
    {
        $this->request->allowMethod(['post']);
        $image = $this->request->getData('image');

        if ($image && $image->getError() === UPLOAD_ERR_OK) {
            $ext = strtolower(pathinfo($image->getClientFilename(), PATHINFO_EXTENSION));
            $allowedExtensions = ['jpg', 'jpeg', 'gif', 'png', 'webp'];

            if (in_array($ext, $allowedExtensions)) {
                $fileName = time() . '_' . $image->getClientFilename();
                $filePath = WWW_ROOT . 'img' . DS . 'post_body_img' . DS . $fileName;
                $image->moveTo($filePath);

                // 画像のURLを生成
                $imageUrl = Router::url('/img/post_body_img/' . $fileName, true);

                return $this->response->withType('application/json')
                                      ->withStringBody(json_encode(['url' => $imageUrl]));
            }
        }

        return $this->response->withStatus(400)
                              ->withType('application/json')
                              ->withStringBody(json_encode(['error' => 'Invalid image']));
    }

最後にビューでCSRFトークンを準備する

edit.php
<!-- 一番ケツに書く -->
<script>
    window.CakephpCsrfToken = <?= json_encode($this->request->getAttribute('csrfToken')); ?>;
</script>

コピペで画像を貼れるようになった
保存してあるファイルをアップできるようにしたほうがいいんだろうけど面倒だからやらない
編集画面

詳細画面

Discussion