soiz1 commited on
Commit
6fa3b2e
·
verified ·
1 Parent(s): 12286b2

Update dev-tools.js

Browse files
Files changed (1) hide show
  1. dev-tools.js +99 -17
dev-tools.js CHANGED
@@ -140,6 +140,15 @@
140
  color: #333;
141
  }
142
 
 
 
 
 
 
 
 
 
 
143
  .css-panel {
144
  flex: 1;
145
  overflow: auto;
@@ -278,6 +287,7 @@
278
  let contextMenu = null;
279
  let selectedElement = null;
280
  let selectedDOMNode = null;
 
281
 
282
  // 開発者ツールのUI構築
283
  function createDevTools() {
@@ -385,11 +395,10 @@
385
 
386
  switch (action) {
387
  case 'edit-html':
388
- const html = prompt('HTMLを編集', selectedElement.outerHTML);
389
- if (html) {
390
- selectedElement.outerHTML = html;
391
  refreshElementsPanel();
392
- }
393
  break;
394
 
395
  case 'add-attribute':
@@ -402,9 +411,8 @@
402
  break;
403
 
404
  case 'edit-element':
405
- const tagName = prompt('タグ名を編集', selectedElement.tagName.toLowerCase());
406
- if (tagName) {
407
- const newElement = document.createElement(tagName);
408
  Array.from(selectedElement.attributes).forEach(attr => {
409
  newElement.setAttribute(attr.name, attr.value);
410
  });
@@ -412,7 +420,7 @@
412
  selectedElement.parentNode.replaceChild(newElement, selectedElement);
413
  selectedElement = newElement;
414
  refreshElementsPanel();
415
- }
416
  break;
417
 
418
  case 'duplicate':
@@ -452,6 +460,69 @@
452
  }
453
  }
454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  // Consoleパネルの作成
456
  function createConsolePanel() {
457
  const panel = document.createElement('div');
@@ -579,8 +650,21 @@
579
 
580
  // タグ名
581
  const tag = document.createElement('span');
582
- tag.className = 'dom-tag';
583
  tag.textContent = `<${node.tagName.toLowerCase()}`;
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  element.appendChild(tag);
585
 
586
  // 属性
@@ -590,11 +674,10 @@
590
  attrSpan.textContent = ` ${attr.name}="${attr.value}"`;
591
  attrSpan.onclick = (e) => {
592
  e.stopPropagation();
593
- const newValue = prompt(`属性 ${attr.name} の値を編集`, attr.value);
594
- if (newValue !== null) {
595
  node.setAttribute(attr.name, newValue);
596
  refreshElementsPanel();
597
- }
598
  };
599
  element.appendChild(attrSpan);
600
  });
@@ -620,15 +703,14 @@
620
  } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
621
  const text = document.createElement('div');
622
  text.style.marginLeft = `${depth * 15}px`;
623
- text.className = 'dom-text';
624
  text.textContent = `"${node.textContent.trim()}"`;
625
  text.onclick = (e) => {
626
  e.stopPropagation();
627
- const newText = prompt('テキストを編集', node.textContent.trim());
628
- if (newText !== null) {
629
- node.textContent = newText;
630
  refreshElementsPanel();
631
- }
632
  };
633
  parentElement.appendChild(text);
634
  }
 
140
  color: #333;
141
  }
142
 
143
+ .dom-edit-input {
144
+ background: #fff;
145
+ border: 1px solid #4fc3f7;
146
+ padding: 0 2px;
147
+ margin: -1px 0;
148
+ font-family: monospace;
149
+ min-width: 50px;
150
+ }
151
+
152
  .css-panel {
153
  flex: 1;
154
  overflow: auto;
 
287
  let contextMenu = null;
288
  let selectedElement = null;
289
  let selectedDOMNode = null;
290
+ let activeEditElement = null;
291
 
292
  // 開発者ツールのUI構築
293
  function createDevTools() {
 
395
 
396
  switch (action) {
397
  case 'edit-html':
398
+ startInlineEdit(selectedDOMNode, selectedElement.outerHTML, (newValue) => {
399
+ selectedElement.outerHTML = newValue;
 
400
  refreshElementsPanel();
401
+ });
402
  break;
403
 
404
  case 'add-attribute':
 
411
  break;
412
 
413
  case 'edit-element':
414
+ startInlineEdit(selectedDOMNode.querySelector('.dom-tag'), selectedElement.tagName.toLowerCase(), (newValue) => {
415
+ const newElement = document.createElement(newValue);
 
416
  Array.from(selectedElement.attributes).forEach(attr => {
417
  newElement.setAttribute(attr.name, attr.value);
418
  });
 
420
  selectedElement.parentNode.replaceChild(newElement, selectedElement);
421
  selectedElement = newElement;
422
  refreshElementsPanel();
423
+ });
424
  break;
425
 
426
  case 'duplicate':
 
460
  }
461
  }
462
 
463
+ // インライン編集を開始する関数
464
+ function startInlineEdit(element, initialValue, callback) {
465
+ if (activeEditElement) return;
466
+
467
+ const originalValue = element.textContent;
468
+ const rect = element.getBoundingClientRect();
469
+
470
+ const input = document.createElement('input');
471
+ input.className = 'dom-edit-input';
472
+ input.value = initialValue || originalValue;
473
+ input.style.position = 'absolute';
474
+ input.style.left = `${rect.left}px`;
475
+ input.style.top = `${rect.top}px`;
476
+ input.style.width = `${rect.width + 20}px`;
477
+
478
+ document.body.appendChild(input);
479
+ input.focus();
480
+ input.select();
481
+
482
+ activeEditElement = {
483
+ element: element,
484
+ input: input,
485
+ callback: callback
486
+ };
487
+
488
+ // 入力フィールド外をクリックしたら編集を終了
489
+ const clickOutsideHandler = (e) => {
490
+ if (!input.contains(e.target)) {
491
+ finishInlineEdit();
492
+ }
493
+ };
494
+
495
+ // Enterキーで編集を終了
496
+ input.addEventListener('keydown', (e) => {
497
+ if (e.key === 'Enter') {
498
+ finishInlineEdit();
499
+ } else if (e.key === 'Escape') {
500
+ cancelInlineEdit();
501
+ }
502
+ });
503
+
504
+ setTimeout(() => {
505
+ document.addEventListener('click', clickOutsideHandler);
506
+ }, 0);
507
+
508
+ function finishInlineEdit() {
509
+ if (input.value !== originalValue && callback) {
510
+ callback(input.value);
511
+ }
512
+ cleanup();
513
+ }
514
+
515
+ function cancelInlineEdit() {
516
+ cleanup();
517
+ }
518
+
519
+ function cleanup() {
520
+ document.removeEventListener('click', clickOutsideHandler);
521
+ input.remove();
522
+ activeEditElement = null;
523
+ }
524
+ }
525
+
526
  // Consoleパネルの作成
527
  function createConsolePanel() {
528
  const panel = document.createElement('div');
 
650
 
651
  // タグ名
652
  const tag = document.createElement('span');
653
+ tag.className = 'dom-tag editable';
654
  tag.textContent = `<${node.tagName.toLowerCase()}`;
655
+ tag.onclick = (e) => {
656
+ e.stopPropagation();
657
+ startInlineEdit(tag, node.tagName.toLowerCase(), (newValue) => {
658
+ const newElement = document.createElement(newValue);
659
+ Array.from(node.attributes).forEach(attr => {
660
+ newElement.setAttribute(attr.name, attr.value);
661
+ });
662
+ newElement.innerHTML = node.innerHTML;
663
+ node.parentNode.replaceChild(newElement, node);
664
+ selectedElement = newElement;
665
+ refreshElementsPanel();
666
+ });
667
+ };
668
  element.appendChild(tag);
669
 
670
  // 属性
 
674
  attrSpan.textContent = ` ${attr.name}="${attr.value}"`;
675
  attrSpan.onclick = (e) => {
676
  e.stopPropagation();
677
+ startInlineEdit(attrSpan, attr.value, (newValue) => {
 
678
  node.setAttribute(attr.name, newValue);
679
  refreshElementsPanel();
680
+ });
681
  };
682
  element.appendChild(attrSpan);
683
  });
 
703
  } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {
704
  const text = document.createElement('div');
705
  text.style.marginLeft = `${depth * 15}px`;
706
+ text.className = 'dom-text editable';
707
  text.textContent = `"${node.textContent.trim()}"`;
708
  text.onclick = (e) => {
709
  e.stopPropagation();
710
+ startInlineEdit(text, node.textContent.trim(), (newValue) => {
711
+ node.textContent = newValue;
 
712
  refreshElementsPanel();
713
+ });
714
  };
715
  parentElement.appendChild(text);
716
  }