目次(見出し)のボタンを右のメニューに作成(強調と絵文字がついたもの)
強調と絵文字がついたものに関して、目次(見出し)を表示するボタンを右のメニューに作成するコード
絵文字は特定のものしか反応しないかも
https://gyazo.com/023fa9032102d60dac111779861b93c2
code:script.js
(function () {
// ボタンクリック時の処理
cosense.PageMenu.addMenu({
title: '見出し',
icon: 'fas fa-list',
onClick: generateHeadingMenu
})
// 見出しメニューを生成する関数
function generateHeadingMenu() {
try {
const menu = cosense.PageMenu('見出し')
menu.removeAllItems()
console.log('Generating heading menu...')
// すべての行をループ
for (let i = 0; i < cosense.Page.lines.length; i++) {
const line = cosense.Page.linesi
// セクション開始でなければスキップ
if (!line.section || !line.section.start) continue
// 行のテキストを取得
const text = line.text || ''
// デバッグ: 各行のテキストを出力
if (text.length > 0) {
console.log(Checking line: "${text}")
}
let headingText = null
let headingLevel = 0
let prefixEmoji = null
// 1. 強調マークアップを探す
const strongRegex = /\\*+\s+(.*?)\s*\/
const strongMatch = text.match(strongRegex)
if (strongMatch && strongMatch1) {
headingText = strongMatch1.trim()
headingLevel = strongMatch0.match(/\*+/)0.length
console.log(Found strong heading: "${headingText}" with level ${headingLevel})
}
// 2. 絵文字から始まる行を探す
else {
// 最初の文字を取得(トリムして空白を除去)
const trimmedText = text.trim()
if (trimmedText.length === 0) continue
// 最初の文字が絵文字かどうかをチェックする関数
function isFirstCharEmoji(text) {
// 指定された絵文字リスト(特に使用される絵文字)
const specificEmojis = ['📄', '📋', '✉️', '🤔', '🛒', '🗓️', '💡', '✅',
'☑️', '✓', '✔️', '📌', '📍', '🔍', '⭐', '★',
'☆', '⚡', '🔴', '🟠', '🟡', '🟢', '🔵', '🟣',
'⚫', '⚪', '📝', '📔', '📒', '📕', '📗', '📘',
'📙', '🔑', '🗝️', '👉', '👆', '☝️', '👇', '👈',
'❗', '❓', '‼️', '⁉️', '❕', '❔', '🚩', '🏁',
'🎯', '🔔', '🔖', '📑', '🛠️', '🔧', '🔨', '🗂️',
'📁', '📂', '💬', '🗣️', '📢', '📣'];
// テキストの最初の文字(絵文字は複数のコードポイントで構成されている可能性がある)
const firstTwoChars = text.slice(0, 2);
const firstThreeChars = text.slice(0, 3);
const firstFourChars = text.slice(0, 4);
// 明示的なリストチェック(最大4文字まで)
for (const emoji of specificEmojis) {
if (text.startsWith(emoji)) {
return emoji;
}
}
// 一般的な絵文字の範囲チェック(バックアップ)
const firstCharCode = text.codePointAt(0);
if ((firstCharCode >= 0x1F300 && firstCharCode <= 0x1F6FF) || // Miscellaneous Symbols and Pictographs
(firstCharCode >= 0x1F900 && firstCharCode <= 0x1F9FF) || // Supplemental Symbols and Pictographs
(firstCharCode >= 0x2600 && firstCharCode <= 0x26FF) || // Miscellaneous Symbols
(firstCharCode >= 0x2700 && firstCharCode <= 0x27BF) || // Dingbats
(firstCharCode >= 0x1F1E6 && firstCharCode <= 0x1F1FF) || // Flags
(firstCharCode >= 0x1F000 && firstCharCode <= 0x1F02F) || // Mahjong Tiles
(firstCharCode >= 0x1F0A0 && firstCharCode <= 0x1F0FF)) { // Playing Cards
// 絵文字の長さを判定
const firstCodePoint = String.fromCodePoint(firstCharCode);
return firstCodePoint;
}
return null; // 絵文字ではない
}
// 最初の文字が絵文字かチェック
const emoji = isFirstCharEmoji(trimmedText);
if (emoji) {
prefixEmoji = emoji;
// 絵文字の後のテキストを取得
const emojiLength = emoji.length;
let remainingText = trimmedText.slice(emojiLength).trim();
if (remainingText) {
headingText = remainingText;
headingLevel = 1; // 絵文字見出しは基本レベル1とする
console.log(Found emoji heading: "${headingText}" with emoji ${prefixEmoji});
}
}
}
// 見出しテキストが見つかった場合、メニューに追加
if (headingText) {
// クリックハンドラを定義
const lineId = line.id;
function jumpToLine() {
console.log('Jumping to line id:', lineId);
window.location.hash = lineId;
return false;
}
// メニュータイトルを作成
const menuTitle = prefixEmoji ? ${prefixEmoji} ${headingText} : headingText;
// メニューアイテムを追加
menu.addItem({
title: menuTitle,
onClick: jumpToLine
});
}
}
console.log('Heading menu generated successfully');
} catch (error) {
console.error('Error generating heading menu:', error);
}
}
})();