(function() { // スタイルの動的追加 const style = document.createElement('style'); style.textContent = ` .devtools-container { position: fixed; bottom: 0; left: 0; width: 100%; height: 300px; background-color: #fff; border-top: 1px solid #ddd; box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); z-index: 9999; display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } .devtools-header { display: flex; justify-content: space-between; align-items: center; padding: 5px 10px; background-color: #f5f5f5; border-bottom: 1px solid #ddd; } .devtools-tabs { display: flex; gap: 10px; } .devtools-tab { padding: 5px 10px; cursor: pointer; border-radius: 3px 3px 0 0; background-color: #e0e0e0; border: 1px solid #ccc; border-bottom: none; font-size: 12px; } .devtools-tab.active { background-color: #fff; border-bottom: 1px solid #fff; margin-bottom: -1px; font-weight: bold; } .devtools-close { background: none; border: none; font-size: 16px; cursor: pointer; padding: 0 5px; } .devtools-content { flex: 1; overflow: auto; position: relative; } .devtools-panel { position: absolute; top: 0; left: 0; width: 100%; height: 100%; padding: 10px; overflow: auto; display: none; } .devtools-panel.active { display: block; } /* Console スタイル */ #console-log { white-space: pre-wrap; margin: 0; line-height: 1.4; flex: 1; color: #333; } .console-input { width: 100%; background: #f5f5f5; border: 1px solid #ddd; color: #333; padding: 8px; margin-top: 10px; font-family: monospace; } /* Elements スタイル */ .elements-container { display: flex; flex: 1; overflow: hidden; } .dom-tree { font-family: monospace; flex: 1; overflow: auto; border-right: 1px solid #ddd; padding-right: 10px; color: #333; } .dom-node { margin-left: 15px; position: relative; line-height: 1.4; } .dom-node.selected { background: rgba(79, 195, 247, 0.2); } .dom-tag { color: #0066cc; font-weight: bold; } .dom-attr { color: #d33682; } .dom-attr.editable:hover { text-decoration: underline; cursor: pointer; } .dom-text { color: #333; } .dom-edit-input { background: #fff; border: 1px solid #4fc3f7; padding: 0 2px; margin: -1px 0; font-family: monospace; min-width: 50px; } .css-panel { flex: 1; overflow: auto; padding-left: 10px; } .css-rule { margin-bottom: 15px; border: 1px solid #ddd; padding: 8px; background-color: #f9f9f9; } .css-selector { color: #0066cc; margin-bottom: 5px; font-weight: bold; } .css-property { display: flex; margin-bottom: 3px; } .css-property-name { color: #d33682; min-width: 120px; } .css-property-value { color: #333; flex: 1; } .css-toggle { margin-left: 10px; color: #dc322f; cursor: pointer; } /* Context Menu */ .context-menu { position: absolute; background: #fff; border: 1px solid #ddd; z-index: 10000; min-width: 200px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); display: none; } .context-menu-item { padding: 8px 15px; cursor: pointer; color: #333; } .context-menu-item:hover { background: #4fc3f7; color: #000; } /* Storage スタイル */ .storage-table { width: 100%; border-collapse: collapse; margin-bottom: 10px; } .storage-table th, .storage-table td { border: 1px solid #ddd; padding: 5px; text-align: left; } .storage-table th { background: #f5f5f5; } .storage-actions { display: flex; gap: 5px; } .storage-btn { background: #4fc3f7; border: none; padding: 2px 5px; cursor: pointer; border-radius: 3px; } .editable { cursor: pointer; padding: 2px 5px; border: 1px dashed transparent; } .editable:hover { border-color: #4fc3f7; } .add-btn { background: #4fc3f7; color: #000; border: none; padding: 5px 10px; margin-top: 10px; cursor: pointer; border-radius: 3px; } .json-object { color: #268bd2; } .json-string { color: #2aa198; } .json-number { color: #d33682; } .json-boolean { color: #b58900; } .json-null { color: #6c71c4; } `; document.head.appendChild(style); // グローバル変数 let contextMenu = null; let selectedElement = null; let selectedDOMNode = null; let activeEditElement = null; // 開発者ツールのメイン関数 function createDevTools() { const container = document.createElement('div'); container.className = 'devtools-container'; container.id = 'devtools-container'; container.style.display = 'none'; // ヘッダー部分 const header = document.createElement('div'); header.className = 'devtools-header'; const tabs = document.createElement('div'); tabs.className = 'devtools-tabs'; const consoleTab = createTab('Console', 'console'); const elementsTab = createTab('Elements', 'elements'); const storageTab = createTab('Storage', 'storage'); tabs.appendChild(consoleTab); tabs.appendChild(elementsTab); tabs.appendChild(storageTab); const closeBtn = document.createElement('button'); closeBtn.className = 'devtools-close'; closeBtn.textContent = '×'; closeBtn.onclick = toggleDevTools; header.appendChild(tabs); header.appendChild(closeBtn); // コンテンツ部分 const content = document.createElement('div'); content.className = 'devtools-content'; const consolePanel = createConsolePanel(); const elementsPanel = createElementsPanel(); const storagePanel = createStoragePanel(); content.appendChild(consolePanel); content.appendChild(elementsPanel); content.appendChild(storagePanel); container.appendChild(header); container.appendChild(content); document.body.appendChild(container); // コンテキストメニュー作成 createContextMenu(); // タブ切り替え機能 function createTab(name, panelId) { const tab = document.createElement('div'); tab.className = 'devtools-tab'; tab.textContent = name; tab.onclick = () => { document.querySelectorAll('.devtools-tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.devtools-panel').forEach(p => p.classList.remove('active')); tab.classList.add('active'); document.getElementById(panelId + '-panel').classList.add('active'); }; return tab; } elementsTab.click(); } // コンテキストメニュー作成 function createContextMenu() { contextMenu = document.createElement('div'); contextMenu.className = 'context-menu'; contextMenu.innerHTML = `
HTMLとして編集
属性を追加
要素を編集
要素を複製
要素を削除
要素を非表示
状態を強制
`; document.body.appendChild(contextMenu); contextMenu.querySelectorAll('.context-menu-item').forEach(item => { item.addEventListener('click', (e) => { const action = e.target.getAttribute('data-action'); handleContextMenuAction(action); contextMenu.style.display = 'none'; }); }); document.addEventListener('click', (e) => { if (e.target !== contextMenu && !contextMenu.contains(e.target)) { contextMenu.style.display = 'none'; } }); } function createStoragePanel() { const panel = document.createElement('div'); panel.className = 'devtools-panel'; panel.id = 'storage-panel'; // LocalStorage表示 const localStorageTitle = document.createElement('h3'); localStorageTitle.textContent = 'Local Storage'; panel.appendChild(localStorageTitle); const localStorageTable = document.createElement('table'); localStorageTable.className = 'storage-table'; panel.appendChild(localStorageTable); const addLocalStorageBtn = document.createElement('button'); addLocalStorageBtn.className = 'add-btn'; addLocalStorageBtn.textContent = '+ Local Storageに追加'; addLocalStorageBtn.onclick = () => { const key = prompt('キー名を入力'); if (key) { const value = prompt('値を入力'); localStorage.setItem(key, value); renderStorage(); } }; panel.appendChild(addLocalStorageBtn); // SessionStorage表示 const sessionStorageTitle = document.createElement('h3'); sessionStorageTitle.style.marginTop = '20px'; sessionStorageTitle.textContent = 'Session Storage'; panel.appendChild(sessionStorageTitle); const sessionStorageTable = document.createElement('table'); sessionStorageTable.className = 'storage-table'; panel.appendChild(sessionStorageTable); const addSessionStorageBtn = document.createElement('button'); addSessionStorageBtn.className = 'add-btn'; addSessionStorageBtn.textContent = '+ Session Storageに追加'; addSessionStorageBtn.onclick = () => { const key = prompt('キー名を入力'); if (key) { const value = prompt('値を入力'); sessionStorage.setItem(key, value); renderStorage(); } }; panel.appendChild(addSessionStorageBtn); // Cookie表示 const cookiesTitle = document.createElement('h3'); cookiesTitle.style.marginTop = '20px'; cookiesTitle.textContent = 'Cookies'; panel.appendChild(cookiesTitle); const cookiesTable = document.createElement('table'); cookiesTable.className = 'storage-table'; panel.appendChild(cookiesTable); const addCookieBtn = document.createElement('button'); addCookieBtn.className = 'add-btn'; addCookieBtn.textContent = '+ Cookieに追加'; addCookieBtn.onclick = () => { const name = prompt('Cookie名を入力'); if (name) { const value = prompt('値を入力'); document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; path=/`; renderStorage(); } }; panel.appendChild(addCookieBtn); // ストレージを表示する関数 function renderStorage() { renderTable(localStorageTable, localStorage, 'local'); renderTable(sessionStorageTable, sessionStorage, 'session'); renderCookiesTable(cookiesTable); } function renderTable(tableElement, storage, type) { tableElement.innerHTML = ` Key Value Actions `; const tbody = tableElement.querySelector('tbody'); for (let i = 0; i < storage.length; i++) { const key = storage.key(i); const value = storage.getItem(key); const row = document.createElement('tr'); const keyCell = document.createElement('td'); const keySpan = document.createElement('span'); keySpan.className = 'editable'; keySpan.textContent = key; keySpan.onclick = () => { const newKey = prompt('新しいキー名を入力', key); if (newKey && newKey !== key) { storage.setItem(newKey, value); storage.removeItem(key); renderStorage(); } }; keyCell.appendChild(keySpan); const valueCell = document.createElement('td'); const valueSpan = document.createElement('span'); valueSpan.className = 'editable'; valueSpan.textContent = value; valueSpan.onclick = () => { const newValue = prompt('新しい値を入力', value); if (newValue !== null) { storage.setItem(key, newValue); renderStorage(); } }; valueCell.appendChild(valueSpan); const actionsCell = document.createElement('td'); actionsCell.className = 'storage-actions'; const deleteBtn = document.createElement('button'); deleteBtn.className = 'storage-btn'; deleteBtn.textContent = 'Delete'; deleteBtn.onclick = () => { storage.removeItem(key); renderStorage(); }; actionsCell.appendChild(deleteBtn); row.appendChild(keyCell); row.appendChild(valueCell); row.appendChild(actionsCell); tbody.appendChild(row); } } function renderCookiesTable(tableElement) { tableElement.innerHTML = ` Name Value Actions `; const tbody = tableElement.querySelector('tbody'); document.cookie.split(';').forEach(cookie => { if (!cookie.trim()) return; const [name, ...valueParts] = cookie.split('='); const decodedName = decodeURIComponent(name.trim()); const value = valueParts.join('=').trim(); const row = document.createElement('tr'); const nameCell = document.createElement('td'); const nameSpan = document.createElement('span'); nameSpan.className = 'editable'; nameSpan.textContent = decodedName; nameSpan.onclick = () => { const newName = prompt('新しい名前を入力', decodedName); if (newName && newName !== decodedName) { const newValue = prompt('新しい値を入力', decodeURIComponent(value)); if (newValue !== null) { document.cookie = `${encodeURIComponent(newName)}=${encodeURIComponent(newValue)}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`; document.cookie = `${name.trim()}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`; renderStorage(); } } }; nameCell.appendChild(nameSpan); const valueCell = document.createElement('td'); const valueSpan = document.createElement('span'); valueSpan.className = 'editable'; valueSpan.textContent = decodeURIComponent(value); valueSpan.onclick = () => { const newValue = prompt('新しい値を入力', decodeURIComponent(value)); if (newValue !== null) { document.cookie = `${name.trim()}=${encodeURIComponent(newValue)}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`; renderStorage(); } }; valueCell.appendChild(valueSpan); const actionsCell = document.createElement('td'); actionsCell.className = 'storage-actions'; const deleteBtn = document.createElement('button'); deleteBtn.className = 'storage-btn'; deleteBtn.textContent = 'Delete'; deleteBtn.onclick = () => { document.cookie = `${name.trim()}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`; renderStorage(); }; actionsCell.appendChild(deleteBtn); row.appendChild(nameCell); row.appendChild(valueCell); row.appendChild(actionsCell); tbody.appendChild(row); }); } // 初期表示 renderStorage(); return panel; } // コンテキストメニューアクション処理 function handleContextMenuAction(action) { if (!selectedElement) return; switch (action) { case 'edit-html': // document.documentElement(html要素)は編集不可 if (selectedElement === document.documentElement) { alert('ルートHTML要素は直接編集できません'); return; } startInlineEdit(selectedDOMNode, selectedElement.outerHTML, (newValue) => { try { selectedElement.outerHTML = newValue; refreshElementsPanel(); } catch (e) { alert('この要素は編集できません: ' + e.message); } }); break; case 'add-attribute': const attrName = prompt('属性名を入力'); if (attrName) { const attrValue = prompt('属性値を入力'); selectedElement.setAttribute(attrName, attrValue || ''); refreshElementsPanel(); } break; case 'edit-element': startInlineEdit(selectedDOMNode.querySelector('.dom-tag'), selectedElement.tagName.toLowerCase(), (newValue) => { const newElement = document.createElement(newValue); Array.from(selectedElement.attributes).forEach(attr => { newElement.setAttribute(attr.name, attr.value); }); newElement.innerHTML = selectedElement.innerHTML; selectedElement.parentNode.replaceChild(newElement, selectedElement); selectedElement = newElement; refreshElementsPanel(); }); break; case 'duplicate': const clone = selectedElement.cloneNode(true); selectedElement.parentNode.insertBefore(clone, selectedElement.nextSibling); refreshElementsPanel(); break; case 'remove': if (confirm('要素を削除しますか?')) { selectedElement.parentNode.removeChild(selectedElement); refreshElementsPanel(); } break; case 'toggle-visibility': if (selectedElement.style.display === 'none') { selectedElement.style.display = ''; } else { selectedElement.style.display = 'none'; } refreshElementsPanel(); break; case 'force-state': const state = prompt('強制する状態を入力 (例: hover, active, focus)', 'hover'); if (state) { selectedElement.classList.remove('force-hover', 'force-active', 'force-focus', 'force-focus-within', 'force-focus-visible', 'force-target'); selectedElement.classList.add(`force-${state}`); refreshElementsPanel(); } break; } } // インライン編集関数 function startInlineEdit(element, initialValue, callback) { if (activeEditElement) return; const originalValue = element.textContent; const rect = element.getBoundingClientRect(); const input = document.createElement('input'); input.className = 'dom-edit-input'; input.value = initialValue || originalValue; input.style.position = 'absolute'; input.style.left = `${rect.left}px`; input.style.top = `${rect.top}px`; input.style.width = `${rect.width + 20}px`; document.body.appendChild(input); input.focus(); input.select(); activeEditElement = { element: element, input: input, callback: callback }; const clickOutsideHandler = (e) => { if (!input.contains(e.target)) { finishInlineEdit(); } }; input.addEventListener('keydown', (e) => { if (e.key === 'Enter') { finishInlineEdit(); } else if (e.key === 'Escape') { cancelInlineEdit(); } }); setTimeout(() => { document.addEventListener('click', clickOutsideHandler); }, 0); function finishInlineEdit() { try { if (input.value !== originalValue && callback) { callback(input.value); } } catch (e) { alert('編集に失敗しました: ' + e.message); } finally { cleanup(); } } function cancelInlineEdit() { cleanup(); } function cleanup() { document.removeEventListener('click', clickOutsideHandler); input.remove(); activeEditElement = null; } } // Consoleパネル作成 function createConsolePanel() { const panel = document.createElement('div'); panel.className = 'devtools-panel'; panel.id = 'console-panel'; const log = document.createElement('div'); log.id = 'console-log'; const input = document.createElement('input'); input.className = 'console-input'; input.placeholder = 'ここにJavaScriptを入力... (Enterで実行)'; input.onkeypress = (e) => { if (e.key === 'Enter') { try { const result = eval(e.target.value); if (result !== undefined) { logMessage('> ' + e.target.value, '#0066cc'); logMessage('← ' + formatOutput(result), '#2aa198'); } } catch (err) { logMessage(err.message, '#dc322f'); } e.target.value = ''; } }; panel.appendChild(log); panel.appendChild(input); ['log', 'error', 'warn'].forEach(method => { const original = console[method]; console[method] = (...args) => { original.apply(console, args); const color = method === 'error' ? '#dc322f' : method === 'warn' ? '#b58900' : '#586e75'; logMessage(args.map(arg => formatOutput(arg)).join(' '), color); }; }); function logMessage(message, color) { const line = document.createElement('div'); line.style.color = color; line.innerHTML = message; log.appendChild(line); log.scrollTop = log.scrollHeight; } function formatOutput(output) { if (output === null) return 'null'; if (output === undefined) return 'undefined'; if (typeof output === 'boolean') return `${output}`; if (typeof output === 'number') return `${output}`; if (typeof output === 'string') return `"${output}"`; if (typeof output === 'function') return `function ${output.name}() { ... }`; if (Array.isArray(output)) return `[${output.map(formatOutput).join(', ')}]`; if (typeof output === 'object') { try { return `${JSON.stringify(output, null, 2) .replace(/"([^"]+)":/g, '"$1":') .replace(/"([^"]+)"/g, '"$1"') .replace(/\b(true|false)\b/g, '$1') .replace(/\b(null)\b/g, '$1') .replace(/\b(\d+)\b/g, '$1')}`; } catch (e) { return `${output.toString()}`; } } return output; } return panel; } // Elementsパネル作成 function createElementsPanel() { const panel = document.createElement('div'); panel.className = 'devtools-panel'; panel.id = 'elements-panel'; const container = document.createElement('div'); container.className = 'elements-container'; const tree = document.createElement('div'); tree.className = 'dom-tree'; tree.id = 'dom-tree'; const cssPanel = document.createElement('div'); cssPanel.className = 'css-panel'; cssPanel.id = 'css-panel'; container.appendChild(tree); container.appendChild(cssPanel); panel.appendChild(container); // CSSパネル更新関数 function updateCSSPanel(element) { const cssPanel = document.getElementById('css-panel'); cssPanel.innerHTML = ''; if (!element) return; if (element.style.length > 0) { const inlineRule = document.createElement('div'); inlineRule.className = 'css-rule'; const selector = document.createElement('div'); selector.className = 'css-selector'; selector.textContent = 'インラインスタイル'; inlineRule.appendChild(selector); for (let i = 0; i < element.style.length; i++) { const propName = element.style[i]; const propValue = element.style[propName]; const propDiv = document.createElement('div'); propDiv.className = 'css-property'; const nameSpan = document.createElement('span'); nameSpan.className = 'css-property-name editable'; nameSpan.textContent = propName; nameSpan.onclick = () => editCSSProperty(element, propName, 'style'); const valueSpan = document.createElement('span'); valueSpan.className = 'css-property-value editable'; valueSpan.textContent = propValue; valueSpan.onclick = () => editCSSProperty(element, propName, 'style'); const toggleSpan = document.createElement('span'); toggleSpan.className = 'css-toggle'; toggleSpan.textContent = '×'; toggleSpan.title = 'プロパティを無効化'; toggleSpan.onclick = () => { element.style[propName] = ''; updateCSSPanel(element); }; propDiv.appendChild(nameSpan); propDiv.appendChild(valueSpan); propDiv.appendChild(toggleSpan); inlineRule.appendChild(propDiv); } cssPanel.appendChild(inlineRule); } const computedStyles = window.getComputedStyle(element); const computedRule = document.createElement('div'); computedRule.className = 'css-rule'; const computedSelector = document.createElement('div'); computedSelector.className = 'css-selector'; computedSelector.textContent = '計算されたスタイル'; computedRule.appendChild(computedSelector); const importantProps = [ 'display', 'position', 'width', 'height', 'margin', 'padding', 'color', 'background', 'border', 'font', 'flex', 'grid' ]; importantProps.forEach(prop => { const value = computedStyles[prop]; const propDiv = document.createElement('div'); propDiv.className = 'css-property'; const nameSpan = document.createElement('span'); nameSpan.className = 'css-property-name'; nameSpan.textContent = prop; const valueSpan = document.createElement('span'); valueSpan.className = 'css-property-value'; valueSpan.textContent = value; propDiv.appendChild(nameSpan); propDiv.appendChild(valueSpan); computedRule.appendChild(propDiv); }); cssPanel.appendChild(computedRule); } // DOMツリー構築 function buildDOMTree(node, parentElement, depth = 0) { if (node.nodeType === Node.ELEMENT_NODE) { const element = document.createElement('div'); element.className = 'dom-node'; element.style.marginLeft = `${depth * 15}px`; element.dataset.elementId = node.id || Math.random().toString(36).substr(2, 9); // 右クリックイベント element.oncontextmenu = (e) => { e.preventDefault(); selectedElement = node; selectedDOMNode = element; document.querySelectorAll('.dom-node').forEach(el => el.classList.remove('selected')); element.classList.add('selected'); // HTML要素にはコンテキストメニューを表示しない if (node !== document.documentElement) { contextMenu.style.display = 'block'; contextMenu.style.left = `${e.pageX}px`; contextMenu.style.top = `${e.pageY}px`; } updateCSSPanel(node); }; // タグ名(HTML要素は編集不可) const tag = document.createElement('span'); tag.className = 'dom-tag'; tag.textContent = `<${node.tagName.toLowerCase()}`; if (node !== document.documentElement) { tag.classList.add('editable'); tag.onclick = (e) => { e.stopPropagation(); startInlineEdit(tag, node.tagName.toLowerCase(), (newValue) => { const newElement = document.createElement(newValue); Array.from(node.attributes).forEach(attr => { newElement.setAttribute(attr.name, attr.value); }); newElement.innerHTML = node.innerHTML; node.parentNode.replaceChild(newElement, node); selectedElement = newElement; refreshElementsPanel(); }); }; } element.appendChild(tag); // 属性(HTML要素は編集不可) Array.from(node.attributes).forEach(attr => { const attrSpan = document.createElement('span'); attrSpan.className = 'dom-attr'; attrSpan.textContent = ` ${attr.name}="${attr.value}"`; if (node !== document.documentElement) { attrSpan.classList.add('editable'); attrSpan.onclick = (e) => { e.stopPropagation(); startInlineEdit(attrSpan, attr.value, (newValue) => { node.setAttribute(attr.name, newValue); refreshElementsPanel(); }); }; } element.appendChild(attrSpan); }); element.appendChild(document.createTextNode('>')); if (node.childNodes.length > 0) { node.childNodes.forEach(child => { buildDOMTree(child, element, depth + 1); }); } if (node.childNodes.length > 0 || node.tagName.toLowerCase() !== 'br') { const closeTag = document.createElement('div'); closeTag.style.marginLeft = `${depth * 15}px`; closeTag.innerHTML = `</${node.tagName.toLowerCase()}>`; element.appendChild(closeTag); } parentElement.appendChild(element); } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) { const text = document.createElement('div'); text.style.marginLeft = `${depth * 15}px`; text.className = 'dom-text editable'; text.textContent = `"${node.textContent.trim()}"`; text.onclick = (e) => { e.stopPropagation(); startInlineEdit(text, node.textContent.trim(), (newValue) => { node.textContent = newValue; refreshElementsPanel(); }); }; parentElement.appendChild(text); } } // CSSプロパティ編集 function editCSSProperty(element, propName, styleType) { let currentValue = ''; if (styleType === 'style') { currentValue = element.style[propName]; } const newValue = prompt(`${propName} の新しい値を入力`, currentValue); if (newValue !== null) { if (styleType === 'style') { element.style[propName] = newValue; } updateCSSPanel(element); refreshElementsPanel(); } } // 要素パネル更新 function refreshElementsPanel() { let tree = document.getElementById('dom-tree'); if (!tree) { const panel = document.getElementById('elements-panel'); if (panel) { const container = panel.querySelector('.elements-container'); if (container) { tree = document.createElement('div'); tree.className = 'dom-tree'; tree.id = 'dom-tree'; container.insertBefore(tree, container.querySelector('.css-panel')); } } } if (!tree) return; tree.innerHTML = ''; buildDOMTree(document.documentElement, tree); if (selectedElement) { const elementId = selectedElement.id || Array.from(selectedElement.attributes) .find(attr => attr.name.startsWith('data-element-id'))?.value; if (elementId) { const node = document.querySelector(`[data-element-id="${elementId}"]`); if (node) { node.classList.add('selected'); updateCSSPanel(selectedElement); } } } } setTimeout(() => { refreshElementsPanel(); }, 0); return panel; } // Storageパネル作成 (前回と同じなので省略) // 開発者ツール表示/非表示 function toggleDevTools() { const container = document.getElementById('devtools-container'); if (container.style.display === 'none') { container.style.display = 'flex'; } else { container.style.display = 'none'; } } // 開くボタン作成 function createOpenButton() { const button = document.createElement('button'); button.id = 'open-devtools-btn'; button.textContent = '開発者ツールを開く'; button.style.position = 'fixed'; button.style.bottom = '10px'; button.style.right = '10px'; button.style.padding = '8px 16px'; button.style.background = '#4fc3f7'; button.style.color = '#000'; button.style.border = 'none'; button.style.borderRadius = '4px'; button.style.cursor = 'pointer'; button.style.zIndex = '9998'; button.onclick = toggleDevTools; document.body.appendChild(button); } // 初期化 document.addEventListener('DOMContentLoaded', function() { createDevTools(); createOpenButton(); console.log('開発者ツールが初期化されました'); console.log('このコンソールでJavaScriptを実行できます'); }); })();