ken_nogi/pleasanter/develop/MDエディタ/sites/scripts/mermaid_Editor.js
Kenichiro NOGI 7176dc33ec pleasanter
2025-07-10 10:15:35 +09:00

215 lines
6.7 KiB
JavaScript

/*
@config : next999.json
@filename : ${psFileBasename}
@title : mermaid_Editor
@name :
@siteIds : 326341
@siteTitles : MD作成
@disabled: false
*/
let pageLoading = 0; //ページのロード状態を管理する変数
//----------------------------------------------------------------------
//初期処理
window.addEventListener('load', function () {
if (pageLoading == 0) {
console.log('Window load Event');
$p.ex.onLoad();
}
});
$p.events.on_editor_load = function () {
if (pageLoading == 0) {
console.log('on Editor Load');
$p.ex.onLoad();
}
}
//----------------------------------------------------------------------
$p.ex.onLoad = function () {
//ロード開始
pageLoading = 1;
//初期処理
$p.ex.init();
}
//初期処理
$p.ex.init = function () {
//初期化
const mermaidContent = $('#Results_Body').val(); //値を取得
if ($('#mermaidWindow').length) {
$('#mermaidWindow').remove(); //既存のMermaidウインドウを削除
}
//Mermaidウインドウ
let mermaidWindow = document.createElement('div');
mermaidWindow.id = 'mermaidWindow'; //任意のIDを指定
mermaidWindow.className = 'mermaidWindow'; //任意のクラスを指定
let h1 = document.createElement('h1');
h1.innerHTML = 'Mermaid Viewer';
mermaidWindow.appendChild(h1);
let h2 = document.createElement('h2');
h2.innerHTML = 'Mermaid記法で記述された図がプレビューされます。';
mermaidWindow.appendChild(h2);
//Preview用Preタグを作成
const pre = document.createElement('pre');
pre.id = 'mermaidPreview';
pre.className = 'mermaid'; //Mermaid描画用のクラスを設定
pre.textContent = mermaidContent; //Mermaid記法を設定
//描画エリアに追加
mermaidWindow.appendChild(pre);
$('#Editor').after(mermaidWindow);
//Mermaidを再レンダリング
if (window.mermaid) {
mermaid.init(undefined, '#mermaidPreview');
} else {
console.error('Mermaidライブラリが読み込まれていません。');
}
//PNG出力ボタンを作成
createExportButton();
};
//Mermaid図をPNG形式で出力するボタンを作成
function createExportButton() {
const exportButton = document.createElement('button');
exportButton.id = 'exportMermaid';
exportButton.textContent = 'PNGとして保存';
exportButton.style.marginTop = '10px';
//ボタンのクリックイベント
exportButton.addEventListener('click', function () {
const mermaidPreview = document.getElementById('mermaidPreview');
if (mermaidPreview) {
html2canvas(mermaidPreview).then(canvas => {
const link = document.createElement('a');
link.download = 'mermaid-diagram.png';
link.href = canvas.toDataURL('image/png');
link.click();
}).catch(error => {
console.error('PNG出力中にエラーが発生しました:', error);
});
} else {
console.error('Mermaidプレビューエリアが見つかりません。');
}
});
//Mermaidウインドウにボタンを追加
const mermaidWindow = document.getElementById('mermaidWindow');
if (mermaidWindow) {
mermaidWindow.appendChild(exportButton);
$(exportButton).button({
icon: "ui-icon-image",
showLabel: true
});
} else {
console.error('Mermaidウインドウが見つかりません。');
}
}
//#Results_Body の中身が変更されたら処理を実行
$p.on('change', 'Body', function () {
$p.ex.init();
});
$p.events.after_set = function (args) {
$p.ex.init();
}
$p.events.before_validate_Update = async function (args) {
console.log('Mermaid画像の保存を開始します。');
// saveMermaidImage() の完了を待つ
const result = await saveMermaidImage();
if (result) {
console.log('Mermaid画像の保存が成功しました。次の処理を実行します。');
// 次の処理をここに記述
} else {
console.error('Mermaid画像の保存に失敗しました。処理を中断します。');
return false; // 処理を中断
}
// 必要に応じて次の処理を続行
console.log('次の処理を実行中...');
return false; // 処理を続行
};
async function saveMermaidImage() {
const mermaidPreview = document.getElementById('mermaidPreview');
if (mermaidPreview) {
try {
const canvas = await html2canvas(mermaidPreview);
const pngBase64 = canvas.toDataURL('image/png').replace(/^data:image\/png;base64,/, '');
// uploadImage関数のレスポンスを待つ
const res = await uploadImage(pngBase64);
console.log('アップロード結果:', res);
if (res && res.StatusCode === 200) {
console.log('アップロードが成功しました。');
return true; // 成功
} else {
console.error('アップロードに失敗しました。');
return false; // 失敗
}
} catch (error) {
console.error('PNG変換またはアップロード中にエラーが発生しました:', error);
return false; // エラー
}
} else {
console.error('Mermaidプレビューエリアが見つかりません。');
return false; // プレビューエリアがない
}
}
async function uploadImage(pngBase64) {
const url = 'https://' + location.hostname + '/pleasanter/api/items/' + $p.id() + '/update'
const json = {
'ApiVersion': 1.1,
'DescriptionHash': {
'DescriptionA': '' // Mermaid記法を設定
},
'ImageHash': {
'DescriptionA': {
'Base64': pngBase64,
}
}
}
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(json)
});
return res.json();
}
//要素が読み込まれるまで待機し、返す
function waitForElement(selector, callback, interval = 100, timeout = 5000) {
const startTime = Date.now();
const checkExist = setInterval(function () {
if ($(selector).length) {
clearInterval(checkExist); //要素が見つかったら停止
callback();
} else if (Date.now() - startTime > timeout) {
clearInterval(checkExist); //タイムアウト処理
console.warn(`指定した要素 '${selector}' が ${timeout / 1000} 秒以内に見つかりませんでした。`);
}
}, interval);
}