soiz1 commited on
Commit
d8af696
·
verified ·
1 Parent(s): 4ddb920

Update dev-tools.js

Browse files
Files changed (1) hide show
  1. dev-tools.js +287 -0
dev-tools.js CHANGED
@@ -1731,7 +1731,294 @@ function refreshElementsPanel() {
1731
  }
1732
  }
1733
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1734
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1735
  // 開発者ツール表示/非表示
1736
  function toggleDevTools() {
1737
  const container = document.getElementById('devtools-container');
 
1731
  }
1732
  }
1733
  }
1734
+ // Elementsパネル作成
1735
+ function createElementsPanel() {
1736
+ const panel = document.createElement('div');
1737
+ panel.className = 'devtools-panel';
1738
+ panel.id = 'elements-panel';
1739
+
1740
+ const container = document.createElement('div');
1741
+ container.className = 'elements-container';
1742
+
1743
+ const tree = document.createElement('div');
1744
+ tree.className = 'dom-tree';
1745
+ tree.id = 'dom-tree';
1746
+
1747
+ const cssPanel = document.createElement('div');
1748
+ cssPanel.className = 'css-panel';
1749
+ cssPanel.id = 'css-panel';
1750
+
1751
+ container.appendChild(tree);
1752
+ container.appendChild(cssPanel);
1753
+ panel.appendChild(container);
1754
+
1755
+ // CSSパネル更新関数
1756
+ function updateCSSPanel(element) {
1757
+ const cssPanel = document.getElementById('css-panel');
1758
+ cssPanel.innerHTML = '';
1759
+
1760
+ if (!element) return;
1761
+
1762
+ if (element.style.length > 0) {
1763
+ const inlineRule = document.createElement('div');
1764
+ inlineRule.className = 'css-rule';
1765
+
1766
+ const selector = document.createElement('div');
1767
+ selector.className = 'css-selector';
1768
+ selector.textContent = 'インラインスタイル';
1769
+ inlineRule.appendChild(selector);
1770
+
1771
+ for (let i = 0; i < element.style.length; i++) {
1772
+ const propName = element.style[i];
1773
+ const propValue = element.style[propName];
1774
+
1775
+ const propDiv = document.createElement('div');
1776
+ propDiv.className = 'css-property';
1777
+
1778
+ const nameSpan = document.createElement('span');
1779
+ nameSpan.className = 'css-property-name editable';
1780
+ nameSpan.textContent = propName;
1781
+ nameSpan.onclick = () => editCSSProperty(element, propName, 'style');
1782
+
1783
+ const valueSpan = document.createElement('span');
1784
+ valueSpan.className = 'css-property-value editable';
1785
+ valueSpan.textContent = propValue;
1786
+ valueSpan.onclick = () => editCSSProperty(element, propName, 'style');
1787
+
1788
+ const toggleSpan = document.createElement('span');
1789
+ toggleSpan.className = 'css-toggle';
1790
+ toggleSpan.textContent = '×';
1791
+ toggleSpan.title = 'プロパティを無効化';
1792
+ toggleSpan.onclick = () => {
1793
+ element.style[propName] = '';
1794
+ updateCSSPanel(element);
1795
+ };
1796
+
1797
+ propDiv.appendChild(nameSpan);
1798
+ propDiv.appendChild(valueSpan);
1799
+ propDiv.appendChild(toggleSpan);
1800
+ inlineRule.appendChild(propDiv);
1801
+ }
1802
+
1803
+ cssPanel.appendChild(inlineRule);
1804
+ }
1805
+
1806
+ const computedStyles = window.getComputedStyle(element);
1807
+ const computedRule = document.createElement('div');
1808
+ computedRule.className = 'css-rule';
1809
+
1810
+ const computedSelector = document.createElement('div');
1811
+ computedSelector.className = 'css-selector';
1812
+ computedSelector.textContent = '計算されたスタイル';
1813
+ computedRule.appendChild(computedSelector);
1814
+
1815
+ const importantProps = [
1816
+ 'display', 'position', 'width', 'height', 'margin', 'padding',
1817
+ 'color', 'background', 'border', 'font', 'flex', 'grid'
1818
+ ];
1819
+
1820
+ importantProps.forEach(prop => {
1821
+ const value = computedStyles[prop];
1822
+
1823
+ const propDiv = document.createElement('div');
1824
+ propDiv.className = 'css-property';
1825
+
1826
+ const nameSpan = document.createElement('span');
1827
+ nameSpan.className = 'css-property-name';
1828
+ nameSpan.textContent = prop;
1829
+
1830
+ const valueSpan = document.createElement('span');
1831
+ valueSpan.className = 'css-property-value';
1832
+ valueSpan.textContent = value;
1833
+
1834
+ propDiv.appendChild(nameSpan);
1835
+ propDiv.appendChild(valueSpan);
1836
+ computedRule.appendChild(propDiv);
1837
+ });
1838
+
1839
+ cssPanel.appendChild(computedRule);
1840
+ }
1841
+
1842
+ // DOMツリー構築
1843
+ function buildDOMTree(node, parentElement, depth = 0, isRoot = false) {
1844
+ if (node.nodeType === Node.ELEMENT_NODE) {
1845
+ const element = document.createElement('div');
1846
+ element.className = 'dom-node';
1847
+ element.style.marginLeft = `${depth * 15}px`;
1848
+ element.dataset.elementId = node.id || Math.random().toString(36).substr(2, 9);
1849
+
1850
+ // 右クリックイベント
1851
+ element.oncontextmenu = (e) => {
1852
+ e.preventDefault();
1853
+ selectedElement = node;
1854
+ selectedDOMNode = element;
1855
+
1856
+ document.querySelectorAll('.dom-node').forEach(el => el.classList.remove('selected'));
1857
+ element.classList.add('selected');
1858
+
1859
+ // HTML要素にはコンテキストメニューを表示しない
1860
+ if (node !== document.documentElement) {
1861
+ contextMenu.style.display = 'block';
1862
+ contextMenu.style.left = `${e.pageX}px`;
1863
+ contextMenu.style.top = `${e.pageY}px`;
1864
+ }
1865
+
1866
+ updateCSSPanel(node);
1867
+ };
1868
+
1869
+ // 左クリックで選択
1870
+ element.onclick = (e) => {
1871
+ if (e.target.classList.contains('dom-toggle')) return;
1872
+
1873
+ e.stopPropagation();
1874
+ selectedElement = node;
1875
+ selectedDOMNode = element;
1876
+
1877
+ document.querySelectorAll('.dom-node').forEach(el => el.classList.remove('selected'));
1878
+ element.classList.add('selected');
1879
+
1880
+ updateCSSPanel(node);
1881
+ };
1882
+
1883
+ // 子要素がある場合はトグルボタンを追加
1884
+ const hasChildren = node.childNodes.length > 0 &&
1885
+ !(node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE && !node.childNodes[0].textContent.trim());
1886
+
1887
+ if (hasChildren) {
1888
+ const toggle = document.createElement('div');
1889
+ toggle.className = 'dom-toggle';
1890
+ toggle.onclick = (e) => {
1891
+ e.stopPropagation();
1892
+ const children = element.querySelector('.dom-children');
1893
+ if (children) {
1894
+ if (children.style.maxHeight === '0px') {
1895
+ children.style.maxHeight = children.scrollHeight + 'px';
1896
+ toggle.classList.remove('collapsed');
1897
+ } else {
1898
+ children.style.maxHeight = '0px';
1899
+ toggle.classList.add('collapsed');
1900
+ }
1901
+ }
1902
+ };
1903
+ element.appendChild(toggle);
1904
+ }
1905
+
1906
+ // タグ名(HTML要素は編集不可)
1907
+ const tag = document.createElement('span');
1908
+ tag.className = 'dom-tag';
1909
+ tag.textContent = `<${node.tagName.toLowerCase()}`;
1910
+
1911
+ if (node !== document.documentElement) {
1912
+ tag.classList.add('editable');
1913
+ tag.onclick = (e) => {
1914
+ e.stopPropagation();
1915
+ startInlineEdit(tag, node.tagName.toLowerCase(), (newValue) => {
1916
+ const newElement = document.createElement(newValue);
1917
+ Array.from(node.attributes).forEach(attr => {
1918
+ newElement.setAttribute(attr.name, attr.value);
1919
+ });
1920
+ newElement.innerHTML = node.innerHTML;
1921
+ node.parentNode.replaceChild(newElement, node);
1922
+ selectedElement = newElement;
1923
+ refreshElementsPanel();
1924
+ });
1925
+ };
1926
+ }
1927
+
1928
+ element.appendChild(tag);
1929
+
1930
+ // 属性(HTML要素は編集不可)
1931
+ Array.from(node.attributes).forEach(attr => {
1932
+ const attrSpan = document.createElement('span');
1933
+ attrSpan.className = 'dom-attr';
1934
+ attrSpan.textContent = ` ${attr.name}="${attr.value}"`;
1935
+
1936
+ if (node !== document.documentElement) {
1937
+ attrSpan.classList.add('editable');
1938
+ attrSpan.onclick = (e) => {
1939
+ e.stopPropagation();
1940
+ startInlineEdit(attrSpan, attr.value, (newValue) => {
1941
+ node.setAttribute(attr.name, newValue);
1942
+ refreshElementsPanel();
1943
+ });
1944
+ };
1945
+ }
1946
+
1947
+ element.appendChild(attrSpan);
1948
+ });
1949
 
1950
+ element.appendChild(document.createTextNode('>'));
1951
+
1952
+ if (hasChildren) {
1953
+ const childrenContainer = document.createElement('div');
1954
+ childrenContainer.className = 'dom-children';
1955
+ childrenContainer.style.maxHeight = isRoot ? 'none' : '0px';
1956
+
1957
+ node.childNodes.forEach(child => {
1958
+ buildDOMTree(child, childrenContainer, depth + 1);
1959
+ });
1960
+
1961
+ if (node.tagName.toLowerCase() !== 'br') {
1962
+ const closeTag = document.createElement('div');
1963
+ closeTag.style.marginLeft = `${depth * 15}px`;
1964
+ closeTag.innerHTML = `<span class="dom-tag">&lt;/${node.tagName.toLowerCase()}&gt;</span>`;
1965
+ childrenContainer.appendChild(closeTag);
1966
+ }
1967
+
1968
+ element.appendChild(childrenContainer);
1969
+ }
1970
+
1971
+ parentElement.appendChild(element);
1972
+ } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
1973
+ const text = document.createElement('div');
1974
+ text.style.marginLeft = `${depth * 15}px`;
1975
+ text.className = 'dom-text editable';
1976
+ text.textContent = `"${node.textContent.trim()}"`;
1977
+ text.onclick = (e) => {
1978
+ e.stopPropagation();
1979
+ startInlineEdit(text, node.textContent.trim(), (newValue) => {
1980
+ node.textContent = newValue;
1981
+ refreshElementsPanel();
1982
+ });
1983
+ };
1984
+ parentElement.appendChild(text);
1985
+ }
1986
+ }
1987
+
1988
+ // CSSプロパティ編集
1989
+ function editCSSProperty(element, propName, styleType) {
1990
+ let currentValue = '';
1991
+
1992
+ if (styleType === 'style') {
1993
+ currentValue = element.style[propName];
1994
+ }
1995
+
1996
+ const newValue = prompt(`${propName} の新しい値を入力`, currentValue);
1997
+
1998
+ if (newValue !== null) {
1999
+ if (styleType === 'style') {
2000
+ element.style[propName] = newValue;
2001
+ }
2002
+
2003
+ updateCSSPanel(element);
2004
+ refreshElementsPanel();
2005
+ }
2006
+ }
2007
+
2008
+ // DOM変更を監視
2009
+ observer.observe(document.documentElement, {
2010
+ childList: true,
2011
+ subtree: true,
2012
+ attributes: true,
2013
+ characterData: true
2014
+ });
2015
+
2016
+ setTimeout(() => {
2017
+ refreshElementsPanel();
2018
+ }, 0);
2019
+
2020
+ return panel;
2021
+ }
2022
  // 開発者ツール表示/非表示
2023
  function toggleDevTools() {
2024
  const container = document.getElementById('devtools-container');