Update dev-tools.js
Browse files- dev-tools.js +68 -80
dev-tools.js
CHANGED
@@ -1,8 +1,35 @@
|
|
1 |
(function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
// Web Vitalsスクリプトを動的に読み込み
|
3 |
-
const
|
4 |
-
|
5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
// スタイルの動的追加 (ダークテーマ)
|
8 |
const style = document.createElement('style');
|
@@ -35,6 +62,7 @@
|
|
35 |
--dom-attr: #9cdcfe;
|
36 |
--dom-text: #d4d4d4;
|
37 |
}
|
|
|
38 |
.devtools-container {
|
39 |
position: fixed;
|
40 |
bottom: 0;
|
@@ -548,28 +576,11 @@
|
|
548 |
.json-null {
|
549 |
color: var(--json-null);
|
550 |
}
|
551 |
-
`;
|
552 |
document.head.appendChild(style);
|
553 |
|
554 |
-
// グローバル変数
|
555 |
-
let contextMenu = null;
|
556 |
-
let selectedElement = null;
|
557 |
-
let selectedDOMNode = null;
|
558 |
-
let activeEditElement = null;
|
559 |
-
let networkRequests = [];
|
560 |
-
let selectedRequest = null;
|
561 |
-
let vitalsData = {
|
562 |
-
CLS: null,
|
563 |
-
FCP: null,
|
564 |
-
FID: null,
|
565 |
-
LCP: null,
|
566 |
-
TTFB: null
|
567 |
-
};
|
568 |
-
let observer = null;
|
569 |
-
let refreshElementsPanel = null;
|
570 |
-
|
571 |
// DOM変更を監視するMutationObserver
|
572 |
-
|
573 |
observer = new MutationObserver((mutations) => {
|
574 |
mutations.forEach((mutation) => {
|
575 |
if (mutation.type === 'childList') {
|
@@ -591,7 +602,7 @@
|
|
591 |
attributes: true,
|
592 |
characterData: true
|
593 |
});
|
594 |
-
}
|
595 |
|
596 |
// ノードをハイライト表示
|
597 |
function highlightNode(node) {
|
@@ -686,7 +697,7 @@
|
|
686 |
}
|
687 |
|
688 |
elementsTab.click();
|
689 |
-
}
|
690 |
|
691 |
// Web Vitalsパネル作成
|
692 |
function createVitalsPanel() {
|
@@ -769,20 +780,6 @@
|
|
769 |
container.appendChild(ttfbCard);
|
770 |
|
771 |
// Web Vitalsの計測を開始
|
772 |
-
const loadWebVitals = () => {
|
773 |
-
return new Promise((resolve) => {
|
774 |
-
if (window.webVitals) {
|
775 |
-
resolve();
|
776 |
-
return;
|
777 |
-
}
|
778 |
-
|
779 |
-
const script = document.createElement('script');
|
780 |
-
script.src = 'https://unpkg.com/[email protected]/dist/web-vitals.iife.js';
|
781 |
-
script.onload = resolve;
|
782 |
-
document.head.appendChild(script);
|
783 |
-
});
|
784 |
-
};
|
785 |
-
|
786 |
loadWebVitals().then(() => {
|
787 |
if (window.webVitals) {
|
788 |
try {
|
@@ -876,14 +873,17 @@
|
|
876 |
container.className = 'network-container';
|
877 |
panel.appendChild(container);
|
878 |
|
|
|
879 |
const requestsList = document.createElement('div');
|
880 |
requestsList.className = 'network-requests';
|
881 |
container.appendChild(requestsList);
|
882 |
|
|
|
883 |
const detailsPanel = document.createElement('div');
|
884 |
detailsPanel.className = 'network-details';
|
885 |
container.appendChild(detailsPanel);
|
886 |
|
|
|
887 |
setupNetworkMonitoring();
|
888 |
|
889 |
return panel;
|
@@ -1092,6 +1092,7 @@
|
|
1092 |
const detailsPanel = panel.querySelector('.network-details');
|
1093 |
detailsPanel.innerHTML = '';
|
1094 |
|
|
|
1095 |
const generalSection = document.createElement('div');
|
1096 |
generalSection.className = 'network-detail-section';
|
1097 |
generalSection.innerHTML = `
|
@@ -1105,6 +1106,7 @@
|
|
1105 |
`;
|
1106 |
detailsPanel.appendChild(generalSection);
|
1107 |
|
|
|
1108 |
if (selectedRequest.requestHeaders) {
|
1109 |
const headersSection = document.createElement('div');
|
1110 |
headersSection.className = 'network-detail-section';
|
@@ -1131,6 +1133,7 @@
|
|
1131 |
detailsPanel.appendChild(headersSection);
|
1132 |
}
|
1133 |
|
|
|
1134 |
if (selectedRequest.requestBody) {
|
1135 |
const bodySection = document.createElement('div');
|
1136 |
bodySection.className = 'network-detail-section';
|
@@ -1157,6 +1160,7 @@
|
|
1157 |
detailsPanel.appendChild(bodySection);
|
1158 |
}
|
1159 |
|
|
|
1160 |
if (selectedRequest.response) {
|
1161 |
const responseSection = document.createElement('div');
|
1162 |
responseSection.className = 'network-detail-section';
|
@@ -1183,6 +1187,7 @@
|
|
1183 |
detailsPanel.appendChild(responseSection);
|
1184 |
}
|
1185 |
|
|
|
1186 |
if (selectedRequest.error) {
|
1187 |
const errorSection = document.createElement('div');
|
1188 |
errorSection.className = 'network-detail-section';
|
@@ -1241,6 +1246,7 @@
|
|
1241 |
panel.className = 'devtools-panel';
|
1242 |
panel.id = 'storage-panel';
|
1243 |
|
|
|
1244 |
const localStorageTitle = document.createElement('h3');
|
1245 |
localStorageTitle.textContent = 'Local Storage';
|
1246 |
panel.appendChild(localStorageTitle);
|
@@ -1262,6 +1268,7 @@
|
|
1262 |
};
|
1263 |
panel.appendChild(addLocalStorageBtn);
|
1264 |
|
|
|
1265 |
const sessionStorageTitle = document.createElement('h3');
|
1266 |
sessionStorageTitle.style.marginTop = '20px';
|
1267 |
sessionStorageTitle.textContent = 'Session Storage';
|
@@ -1284,6 +1291,7 @@
|
|
1284 |
};
|
1285 |
panel.appendChild(addSessionStorageBtn);
|
1286 |
|
|
|
1287 |
const cookiesTitle = document.createElement('h3');
|
1288 |
cookiesTitle.style.marginTop = '20px';
|
1289 |
cookiesTitle.textContent = 'Cookies';
|
@@ -1306,6 +1314,7 @@
|
|
1306 |
};
|
1307 |
panel.appendChild(addCookieBtn);
|
1308 |
|
|
|
1309 |
function renderStorage() {
|
1310 |
renderTable(localStorageTable, localStorage, 'local');
|
1311 |
renderTable(sessionStorageTable, sessionStorage, 'session');
|
@@ -1454,6 +1463,7 @@
|
|
1454 |
});
|
1455 |
}
|
1456 |
|
|
|
1457 |
renderStorage();
|
1458 |
|
1459 |
return panel;
|
@@ -1625,6 +1635,7 @@
|
|
1625 |
panel.appendChild(log);
|
1626 |
panel.appendChild(input);
|
1627 |
|
|
|
1628 |
const originalConsole = {
|
1629 |
log: console.log,
|
1630 |
error: console.error,
|
@@ -1802,6 +1813,7 @@
|
|
1802 |
element.style.marginLeft = `${depth * 15}px`;
|
1803 |
element.dataset.elementId = node.id || Math.random().toString(36).substr(2, 9);
|
1804 |
|
|
|
1805 |
element.oncontextmenu = (e) => {
|
1806 |
e.preventDefault();
|
1807 |
selectedElement = node;
|
@@ -1819,6 +1831,7 @@
|
|
1819 |
updateCSSPanel(node);
|
1820 |
};
|
1821 |
|
|
|
1822 |
element.onclick = (e) => {
|
1823 |
if (e.target.classList.contains('dom-toggle')) return;
|
1824 |
|
@@ -1832,6 +1845,7 @@
|
|
1832 |
updateCSSPanel(node);
|
1833 |
};
|
1834 |
|
|
|
1835 |
const hasChildren = node.childNodes.length > 0 &&
|
1836 |
!(node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE && !node.childNodes[0].textContent.trim());
|
1837 |
|
@@ -1854,6 +1868,7 @@
|
|
1854 |
element.appendChild(toggle);
|
1855 |
}
|
1856 |
|
|
|
1857 |
const tag = document.createElement('span');
|
1858 |
tag.className = 'dom-tag';
|
1859 |
tag.textContent = `<${node.tagName.toLowerCase()}`;
|
@@ -1877,6 +1892,7 @@
|
|
1877 |
|
1878 |
element.appendChild(tag);
|
1879 |
|
|
|
1880 |
Array.from(node.attributes).forEach(attr => {
|
1881 |
const attrSpan = document.createElement('span');
|
1882 |
attrSpan.className = 'dom-attr';
|
@@ -1954,7 +1970,7 @@
|
|
1954 |
}
|
1955 |
}
|
1956 |
|
1957 |
-
// refreshElementsPanel
|
1958 |
refreshElementsPanel = function() {
|
1959 |
let tree = document.getElementById('dom-tree');
|
1960 |
|
@@ -1990,7 +2006,7 @@
|
|
1990 |
}
|
1991 |
};
|
1992 |
|
1993 |
-
// MutationObserver
|
1994 |
setupMutationObserver();
|
1995 |
|
1996 |
// 初期表示
|
@@ -2016,54 +2032,26 @@
|
|
2016 |
const button = document.createElement('button');
|
2017 |
button.id = 'open-devtools-btn';
|
2018 |
button.textContent = '開発者ツールを開く';
|
2019 |
-
|
2020 |
-
// スタイルを直接設定(動的CSSに依存しない)
|
2021 |
button.style.position = 'fixed';
|
2022 |
-
button.style.bottom = '
|
2023 |
-
button.style.right = '
|
2024 |
button.style.padding = '8px 16px';
|
2025 |
-
button.style.
|
2026 |
button.style.color = '#000';
|
2027 |
button.style.border = 'none';
|
2028 |
button.style.borderRadius = '4px';
|
2029 |
button.style.cursor = 'pointer';
|
2030 |
-
button.style.zIndex = '
|
2031 |
-
button.style.fontFamily = 'sans-serif';
|
2032 |
-
button.style.fontSize = '14px';
|
2033 |
-
button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
2034 |
-
|
2035 |
button.onclick = toggleDevTools;
|
2036 |
-
document.body.appendChild(button);
|
2037 |
-
|
2038 |
-
console.log('開発者ツールボタンが作成されました'); // デバッグ用
|
2039 |
-
}
|
2040 |
|
2041 |
-
|
2042 |
-
function initializeDevTools() {
|
2043 |
-
try {
|
2044 |
-
// 1. スタイルを最初に追加
|
2045 |
-
const style = document.createElement('style');
|
2046 |
-
style.textContent = `...`; // 前述のスタイル定義
|
2047 |
-
document.head.appendChild(style);
|
2048 |
-
|
2049 |
-
// 2. メインコンテナ作成
|
2050 |
-
createDevTools();
|
2051 |
-
|
2052 |
-
// 3. ボタン作成(setTimeoutで少し遅らせる)
|
2053 |
-
setTimeout(() => {
|
2054 |
-
createOpenButton();
|
2055 |
-
console.log('初期化完了');
|
2056 |
-
}, 100);
|
2057 |
-
|
2058 |
-
} catch (error) {
|
2059 |
-
console.error('初期化エラー:', error);
|
2060 |
-
}
|
2061 |
}
|
2062 |
|
2063 |
-
//
|
2064 |
-
|
2065 |
-
|
2066 |
-
|
2067 |
-
|
2068 |
-
|
|
|
2069 |
})();
|
|
|
1 |
(function() {
|
2 |
+
// グローバル変数宣言
|
3 |
+
let contextMenu = null;
|
4 |
+
let selectedElement = null;
|
5 |
+
let selectedDOMNode = null;
|
6 |
+
let activeEditElement = null;
|
7 |
+
let networkRequests = [];
|
8 |
+
let selectedRequest = null;
|
9 |
+
let vitalsData = {
|
10 |
+
CLS: null,
|
11 |
+
FCP: null,
|
12 |
+
FID: null,
|
13 |
+
LCP: null,
|
14 |
+
TTFB: null
|
15 |
+
};
|
16 |
+
let observer = null;
|
17 |
+
let refreshElementsPanel = null;
|
18 |
+
|
19 |
// Web Vitalsスクリプトを動的に読み込み
|
20 |
+
const loadWebVitals = () => {
|
21 |
+
return new Promise((resolve) => {
|
22 |
+
if (window.webVitals) {
|
23 |
+
resolve();
|
24 |
+
return;
|
25 |
+
}
|
26 |
+
|
27 |
+
const webVitalsScript = document.createElement('script');
|
28 |
+
webVitalsScript.src = 'https://unpkg.com/[email protected]/dist/web-vitals.iife.js';
|
29 |
+
webVitalsScript.onload = resolve;
|
30 |
+
document.head.appendChild(webVitalsScript);
|
31 |
+
});
|
32 |
+
};
|
33 |
|
34 |
// スタイルの動的追加 (ダークテーマ)
|
35 |
const style = document.createElement('style');
|
|
|
62 |
--dom-attr: #9cdcfe;
|
63 |
--dom-text: #d4d4d4;
|
64 |
}
|
65 |
+
|
66 |
.devtools-container {
|
67 |
position: fixed;
|
68 |
bottom: 0;
|
|
|
576 |
.json-null {
|
577 |
color: var(--json-null);
|
578 |
}
|
579 |
+
`;
|
580 |
document.head.appendChild(style);
|
581 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
582 |
// DOM変更を監視するMutationObserver
|
583 |
+
const setupMutationObserver = () => {
|
584 |
observer = new MutationObserver((mutations) => {
|
585 |
mutations.forEach((mutation) => {
|
586 |
if (mutation.type === 'childList') {
|
|
|
602 |
attributes: true,
|
603 |
characterData: true
|
604 |
});
|
605 |
+
};
|
606 |
|
607 |
// ノードをハイライト表示
|
608 |
function highlightNode(node) {
|
|
|
697 |
}
|
698 |
|
699 |
elementsTab.click();
|
700 |
+
};
|
701 |
|
702 |
// Web Vitalsパネル作成
|
703 |
function createVitalsPanel() {
|
|
|
780 |
container.appendChild(ttfbCard);
|
781 |
|
782 |
// Web Vitalsの計測を開始
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
783 |
loadWebVitals().then(() => {
|
784 |
if (window.webVitals) {
|
785 |
try {
|
|
|
873 |
container.className = 'network-container';
|
874 |
panel.appendChild(container);
|
875 |
|
876 |
+
// リクエストリスト
|
877 |
const requestsList = document.createElement('div');
|
878 |
requestsList.className = 'network-requests';
|
879 |
container.appendChild(requestsList);
|
880 |
|
881 |
+
// 詳細パネル
|
882 |
const detailsPanel = document.createElement('div');
|
883 |
detailsPanel.className = 'network-details';
|
884 |
container.appendChild(detailsPanel);
|
885 |
|
886 |
+
// ネットワークリクエストを監視
|
887 |
setupNetworkMonitoring();
|
888 |
|
889 |
return panel;
|
|
|
1092 |
const detailsPanel = panel.querySelector('.network-details');
|
1093 |
detailsPanel.innerHTML = '';
|
1094 |
|
1095 |
+
// 一般情報
|
1096 |
const generalSection = document.createElement('div');
|
1097 |
generalSection.className = 'network-detail-section';
|
1098 |
generalSection.innerHTML = `
|
|
|
1106 |
`;
|
1107 |
detailsPanel.appendChild(generalSection);
|
1108 |
|
1109 |
+
// リクエストヘッダー
|
1110 |
if (selectedRequest.requestHeaders) {
|
1111 |
const headersSection = document.createElement('div');
|
1112 |
headersSection.className = 'network-detail-section';
|
|
|
1133 |
detailsPanel.appendChild(headersSection);
|
1134 |
}
|
1135 |
|
1136 |
+
// リクエストボディ
|
1137 |
if (selectedRequest.requestBody) {
|
1138 |
const bodySection = document.createElement('div');
|
1139 |
bodySection.className = 'network-detail-section';
|
|
|
1160 |
detailsPanel.appendChild(bodySection);
|
1161 |
}
|
1162 |
|
1163 |
+
// レスポンス
|
1164 |
if (selectedRequest.response) {
|
1165 |
const responseSection = document.createElement('div');
|
1166 |
responseSection.className = 'network-detail-section';
|
|
|
1187 |
detailsPanel.appendChild(responseSection);
|
1188 |
}
|
1189 |
|
1190 |
+
// エラー
|
1191 |
if (selectedRequest.error) {
|
1192 |
const errorSection = document.createElement('div');
|
1193 |
errorSection.className = 'network-detail-section';
|
|
|
1246 |
panel.className = 'devtools-panel';
|
1247 |
panel.id = 'storage-panel';
|
1248 |
|
1249 |
+
// LocalStorage表示
|
1250 |
const localStorageTitle = document.createElement('h3');
|
1251 |
localStorageTitle.textContent = 'Local Storage';
|
1252 |
panel.appendChild(localStorageTitle);
|
|
|
1268 |
};
|
1269 |
panel.appendChild(addLocalStorageBtn);
|
1270 |
|
1271 |
+
// SessionStorage表示
|
1272 |
const sessionStorageTitle = document.createElement('h3');
|
1273 |
sessionStorageTitle.style.marginTop = '20px';
|
1274 |
sessionStorageTitle.textContent = 'Session Storage';
|
|
|
1291 |
};
|
1292 |
panel.appendChild(addSessionStorageBtn);
|
1293 |
|
1294 |
+
// Cookie表示
|
1295 |
const cookiesTitle = document.createElement('h3');
|
1296 |
cookiesTitle.style.marginTop = '20px';
|
1297 |
cookiesTitle.textContent = 'Cookies';
|
|
|
1314 |
};
|
1315 |
panel.appendChild(addCookieBtn);
|
1316 |
|
1317 |
+
// ストレージを表示する関数
|
1318 |
function renderStorage() {
|
1319 |
renderTable(localStorageTable, localStorage, 'local');
|
1320 |
renderTable(sessionStorageTable, sessionStorage, 'session');
|
|
|
1463 |
});
|
1464 |
}
|
1465 |
|
1466 |
+
// 初期表示
|
1467 |
renderStorage();
|
1468 |
|
1469 |
return panel;
|
|
|
1635 |
panel.appendChild(log);
|
1636 |
panel.appendChild(input);
|
1637 |
|
1638 |
+
// コンソールメソッドをオーバーライド
|
1639 |
const originalConsole = {
|
1640 |
log: console.log,
|
1641 |
error: console.error,
|
|
|
1813 |
element.style.marginLeft = `${depth * 15}px`;
|
1814 |
element.dataset.elementId = node.id || Math.random().toString(36).substr(2, 9);
|
1815 |
|
1816 |
+
// 右クリックイベント
|
1817 |
element.oncontextmenu = (e) => {
|
1818 |
e.preventDefault();
|
1819 |
selectedElement = node;
|
|
|
1831 |
updateCSSPanel(node);
|
1832 |
};
|
1833 |
|
1834 |
+
// 左クリックで選択
|
1835 |
element.onclick = (e) => {
|
1836 |
if (e.target.classList.contains('dom-toggle')) return;
|
1837 |
|
|
|
1845 |
updateCSSPanel(node);
|
1846 |
};
|
1847 |
|
1848 |
+
// 子要素がある場合はトグルボタンを追加
|
1849 |
const hasChildren = node.childNodes.length > 0 &&
|
1850 |
!(node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE && !node.childNodes[0].textContent.trim());
|
1851 |
|
|
|
1868 |
element.appendChild(toggle);
|
1869 |
}
|
1870 |
|
1871 |
+
// タグ名(HTML要素は編集不可)
|
1872 |
const tag = document.createElement('span');
|
1873 |
tag.className = 'dom-tag';
|
1874 |
tag.textContent = `<${node.tagName.toLowerCase()}`;
|
|
|
1892 |
|
1893 |
element.appendChild(tag);
|
1894 |
|
1895 |
+
// 属性(HTML要素は編集不可)
|
1896 |
Array.from(node.attributes).forEach(attr => {
|
1897 |
const attrSpan = document.createElement('span');
|
1898 |
attrSpan.className = 'dom-attr';
|
|
|
1970 |
}
|
1971 |
}
|
1972 |
|
1973 |
+
// refreshElementsPanel関数の定義
|
1974 |
refreshElementsPanel = function() {
|
1975 |
let tree = document.getElementById('dom-tree');
|
1976 |
|
|
|
2006 |
}
|
2007 |
};
|
2008 |
|
2009 |
+
// MutationObserverの設定
|
2010 |
setupMutationObserver();
|
2011 |
|
2012 |
// 初期表示
|
|
|
2032 |
const button = document.createElement('button');
|
2033 |
button.id = 'open-devtools-btn';
|
2034 |
button.textContent = '開発者ツールを開く';
|
|
|
|
|
2035 |
button.style.position = 'fixed';
|
2036 |
+
button.style.bottom = '10px';
|
2037 |
+
button.style.right = '10px';
|
2038 |
button.style.padding = '8px 16px';
|
2039 |
+
button.style.background = 'var(--primary-color)';
|
2040 |
button.style.color = '#000';
|
2041 |
button.style.border = 'none';
|
2042 |
button.style.borderRadius = '4px';
|
2043 |
button.style.cursor = 'pointer';
|
2044 |
+
button.style.zIndex = '9998';
|
|
|
|
|
|
|
|
|
2045 |
button.onclick = toggleDevTools;
|
|
|
|
|
|
|
|
|
2046 |
|
2047 |
+
document.body.appendChild(button);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2048 |
}
|
2049 |
|
2050 |
+
// 初期化
|
2051 |
+
document.addEventListener('DOMContentLoaded', function() {
|
2052 |
+
createDevTools();
|
2053 |
+
createOpenButton();
|
2054 |
+
console.log('開発者ツールが初期化されました');
|
2055 |
+
console.log('このコンソールでJavaScriptを実行できます');
|
2056 |
+
});
|
2057 |
})();
|