|
(function() { |
|
|
|
const style = document.createElement('style'); |
|
style.textContent = ` |
|
.devtools-container { |
|
position: fixed; |
|
bottom: 0; |
|
left: 0; |
|
right: 0; |
|
height: 300px; |
|
background: #1a1e24; |
|
color: #e0e0e0; |
|
font-family: 'Consolas', 'Courier New', monospace; |
|
border-top: 2px solid #4fc3f7; |
|
display: flex; |
|
flex-direction: column; |
|
z-index: 9999; |
|
box-shadow: 0 -5px 15px rgba(0, 0, 0, 0.5); |
|
} |
|
|
|
.devtools-header { |
|
background: #252a33; |
|
padding: 8px 15px; |
|
display: flex; |
|
justify-content: space-between; |
|
border-bottom: 1px solid #4fc3f7; |
|
} |
|
|
|
.devtools-tabs { |
|
display: flex; |
|
gap: 10px; |
|
} |
|
|
|
.devtools-tab { |
|
padding: 5px 10px; |
|
background: #2c313a; |
|
border: 1px solid #4fc3f7; |
|
border-radius: 3px 3px 0 0; |
|
cursor: pointer; |
|
transition: all 0.2s; |
|
} |
|
|
|
.devtools-tab.active { |
|
background: #4fc3f7; |
|
color: #000; |
|
} |
|
|
|
.devtools-close { |
|
background: transparent; |
|
border: none; |
|
color: #e0e0e0; |
|
cursor: pointer; |
|
} |
|
|
|
.devtools-content { |
|
flex: 1; |
|
display: flex; |
|
overflow: hidden; |
|
} |
|
|
|
.devtools-panel { |
|
flex: 1; |
|
padding: 10px; |
|
overflow: auto; |
|
display: none; |
|
} |
|
|
|
.devtools-panel.active { |
|
display: block; |
|
} |
|
|
|
/* Console スタイル */ |
|
#console-log { |
|
white-space: pre-wrap; |
|
margin: 0; |
|
line-height: 1.4; |
|
} |
|
|
|
.console-input { |
|
width: 100%; |
|
background: #252a33; |
|
border: 1px solid #4fc3f7; |
|
color: #e0e0e0; |
|
padding: 8px; |
|
margin-top: 10px; |
|
} |
|
|
|
/* Elements スタイル */ |
|
.dom-tree { |
|
font-family: monospace; |
|
} |
|
|
|
.dom-node { |
|
margin-left: 15px; |
|
} |
|
|
|
.dom-tag { |
|
color: #4fc3f7; |
|
} |
|
|
|
.dom-attr { |
|
color: #ff7043; |
|
} |
|
|
|
/* Storage スタイル */ |
|
.storage-table { |
|
width: 100%; |
|
border-collapse: collapse; |
|
} |
|
|
|
.storage-table th, .storage-table td { |
|
border: 1px solid #4fc3f7; |
|
padding: 5px; |
|
text-align: left; |
|
} |
|
|
|
.storage-table th { |
|
background: #252a33; |
|
} |
|
|
|
.storage-actions { |
|
display: flex; |
|
gap: 5px; |
|
} |
|
|
|
.storage-btn { |
|
background: #4fc3f7; |
|
border: none; |
|
padding: 2px 5px; |
|
cursor: pointer; |
|
} |
|
`; |
|
document.head.appendChild(style); |
|
|
|
|
|
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); |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
consoleTab.click(); |
|
} |
|
|
|
|
|
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, '#4fc3f7'); |
|
logMessage('← ' + result, '#69f0ae'); |
|
} |
|
} catch (err) { |
|
logMessage(err.message, '#ff5252'); |
|
} |
|
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' ? '#ff5252' : method === 'warn' ? '#ffab40' : '#e0e0e0'; |
|
logMessage(args.join(' '), color); |
|
}; |
|
}); |
|
|
|
function logMessage(message, color) { |
|
const line = document.createElement('div'); |
|
line.style.color = color; |
|
line.textContent = message; |
|
log.appendChild(line); |
|
log.scrollTop = log.scrollHeight; |
|
} |
|
|
|
return panel; |
|
} |
|
|
|
|
|
function createElementsPanel() { |
|
const panel = document.createElement('div'); |
|
panel.className = 'devtools-panel'; |
|
panel.id = 'elements-panel'; |
|
|
|
const tree = document.createElement('div'); |
|
tree.className = 'dom-tree'; |
|
tree.id = 'dom-tree'; |
|
|
|
panel.appendChild(tree); |
|
|
|
|
|
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`; |
|
|
|
|
|
const tag = document.createElement('span'); |
|
tag.className = 'dom-tag'; |
|
tag.textContent = `<${node.tagName.toLowerCase()}`; |
|
element.appendChild(tag); |
|
|
|
|
|
Array.from(node.attributes).forEach(attr => { |
|
const attrSpan = document.createElement('span'); |
|
attrSpan.className = 'dom-attr'; |
|
attrSpan.textContent = ` ${attr.name}="${attr.value}"`; |
|
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 = `<span class="dom-tag"></${node.tagName.toLowerCase()}></span>`; |
|
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.style.color = '#e0e0e0'; |
|
text.textContent = `"${node.textContent.trim()}"`; |
|
parentElement.appendChild(text); |
|
} |
|
} |
|
|
|
|
|
buildDOMTree(document.documentElement, tree); |
|
|
|
return panel; |
|
} |
|
|
|
|
|
function createStoragePanel() { |
|
const panel = document.createElement('div'); |
|
panel.className = 'devtools-panel'; |
|
panel.id = 'storage-panel'; |
|
|
|
|
|
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 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 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); |
|
|
|
|
|
function renderStorage() { |
|
renderTable(localStorageTable, localStorage); |
|
renderTable(sessionStorageTable, sessionStorage); |
|
renderCookiesTable(cookiesTable); |
|
} |
|
|
|
function renderTable(tableElement, storage) { |
|
tableElement.innerHTML = ` |
|
<thead> |
|
<tr> |
|
<th>Key</th> |
|
<th>Value</th> |
|
<th>Actions</th> |
|
</tr> |
|
</thead> |
|
<tbody></tbody> |
|
`; |
|
|
|
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'); |
|
keyCell.textContent = key; |
|
|
|
const valueCell = document.createElement('td'); |
|
valueCell.textContent = value; |
|
|
|
const actionsCell = document.createElement('td'); |
|
actionsCell.className = 'storage-actions'; |
|
|
|
const editBtn = document.createElement('button'); |
|
editBtn.className = 'storage-btn'; |
|
editBtn.textContent = 'Edit'; |
|
editBtn.onclick = () => { |
|
const newValue = prompt('Enter new value:', value); |
|
if (newValue !== null) { |
|
storage.setItem(key, newValue); |
|
renderStorage(); |
|
} |
|
}; |
|
|
|
const deleteBtn = document.createElement('button'); |
|
deleteBtn.className = 'storage-btn'; |
|
deleteBtn.textContent = 'Delete'; |
|
deleteBtn.onclick = () => { |
|
storage.removeItem(key); |
|
renderStorage(); |
|
}; |
|
|
|
actionsCell.appendChild(editBtn); |
|
actionsCell.appendChild(deleteBtn); |
|
|
|
row.appendChild(keyCell); |
|
row.appendChild(valueCell); |
|
row.appendChild(actionsCell); |
|
|
|
tbody.appendChild(row); |
|
} |
|
} |
|
|
|
function renderCookiesTable(tableElement) { |
|
tableElement.innerHTML = ` |
|
<thead> |
|
<tr> |
|
<th>Name</th> |
|
<th>Value</th> |
|
<th>Actions</th> |
|
</tr> |
|
</thead> |
|
<tbody></tbody> |
|
`; |
|
|
|
const tbody = tableElement.querySelector('tbody'); |
|
|
|
document.cookie.split(';').forEach(cookie => { |
|
if (!cookie.trim()) return; |
|
|
|
const [name, ...valueParts] = cookie.split('='); |
|
const value = valueParts.join('=').trim(); |
|
|
|
const row = document.createElement('tr'); |
|
|
|
const nameCell = document.createElement('td'); |
|
nameCell.textContent = name.trim(); |
|
|
|
const valueCell = document.createElement('td'); |
|
valueCell.textContent = decodeURIComponent(value); |
|
|
|
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 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を実行できます'); |
|
} |
|
})(); |