DokuWiki/編集ページで画像をペーストする

DokuWiki/編集ページで画像をペーストする

編集のページでクリップボード内の画像をペーストする。 つまり、裏で画像をアップロードして、そのパスをテキストエリア内に記述するということ。

plugin:imgpaste [DokuWiki]

このようなプラグインもあるらしいが、自分の環境ではなんだかちゃんと動かなかったので、そんなに難しくなさそうだったので、グリモンスクリプトで全部実装した。

仕様さえわかれば対して難しい実装ではない。

まずそのファイルを受け付けるソースを読む。 そのコードは dokuwiki/inc/Ajax.php ここにある。

内部はこうなっている。

    protected function call_mediaupload() {
        global $NS, $MSG, $INPUT;
        $id = '';
        if($_FILES['qqfile']['tmp_name']) {
            $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
        } elseif($INPUT->get->has('qqfile')) {
            $id = $INPUT->get->str('qqfile');
        }
        $id = cleanID($id);
        $NS = $INPUT->str('ns');
        $ns = $NS . ':' . getNS($id);
        $AUTH = auth_quickaclcheck("$ns:*");
        if($AUTH >= AUTH_UPLOAD) {
            io_createNamespace("$ns:xxx", 'media');
        }
        if($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
        $res = false;
        if($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
        if($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
        if($res) {
            $result = array(
                'success' => true,
                'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
                'id' => $NS . ':' . $id,
                'ns' => $NS
            );
        } else {
            $error = '';
            if(isset($MSG)) {
                foreach($MSG as $msg) {
                    $error .= $msg['msg'];
                }
            }
            $result = array(
                'error' => $error,
                'ns' => $NS
            );
        }
        $json = new \JSON;
        header('Content-Type: application/json');
        echo $json->encode($result);
    }

詳しいことはわからないが ppfile という名前でファイルを POST してやればいいことがわかる。

あとは、メディアマネージャーという画面でファイルがアップロードできるのでそこでどういうリクエストを投げているかを見る。

ということを踏まえて fetch メソッドで実装するとこうなる。

async function uploadFileDokuWiki(file, namespace, fileName){
    var sectok = document.querySelector('input[name="sectok"]');
    const url = 'https://example.com/lib/exe/ajax.php?sectok=' + sectok.value + '&ns='+ namespace + '&mediaid=&call=mediaupload&ow=false'
    const formData = new FormData();
    formData.append("qqfile", file, fileName);
    let res = await fetch(url, {
        method: 'POST',
        credentials: "include",
        headers: {},
        body: formData
    });
    if(res.status === 200){
        return await res.json();
    }else{
        console.log(await(res.statusText)); // => Error Message
    }
}

sectok というのは CSRF 対策で入れられているモノで画面要素から取得できるのでそれを取っている。 これは純粋にAPIではないので認証を通すために Cookie を送っている(fetch はデフォルトでは送出しない)。

formData を使う場合は第三引数でファイル名指定するので、QueryString 側に qqfile というパラメータは入れる必要がない。

あとはこれでペースト時のメソッドにフックしてクリップボードから画像ファイルを読み出してアップロードすればよい。

JavaScript/イベント/paste

タグの挿入はこのような実装をすればよい JavaScript/DOM操作/テキストエリア操作

function insertTextToCursorPosition(domTextarea, text){
    var curPosi = domTextarea.selectionStart;
    var curPosiTagInserted = curPosi + text.length;
    domTextarea.value =
        domTextarea.value.substr(0, curPosi) +
        text +
        domTextarea.value.substr(domTextarea.selectionStart, domTextarea.value.length);
    domTextarea.setSelectionRange(curPosiTagInserted, curPosiTagInserted);
};
wiki/dokuwiki/paste_image_in_edit_page.txt · 最終更新: 2019-09-16 11:27 by ore