izuemon commited on
Commit
54e1152
·
verified ·
1 Parent(s): 5133368

Update p1/index.html

Browse files
Files changed (1) hide show
  1. p1/index.html +167 -169
p1/index.html CHANGED
@@ -116,13 +116,13 @@ h1 {
116
  display: flex;
117
  flex-direction: column;
118
  width: 100%;
119
- max-width: 1200px;
120
- background-color: rgba(17, 34, 64, 0.17);
121
  border-radius: 10px;
122
  padding: 20px;
123
  box-shadow: 0 0 20px rgba(100, 255, 218, 0.2);
124
- backdrop-filter: blur(1.6px);
125
- border: 1.5px solid rgba(100, 255, 218, 0.2);
126
  }
127
 
128
  .viewing-box {
@@ -225,7 +225,7 @@ h1 {
225
  right: 5px;
226
  display: flex;
227
  gap: 5px;
228
- z-index: 200;
229
  background: rgba(0, 0, 0, 0.5);
230
  padding: 5px;
231
  border-radius: 5px;
@@ -545,19 +545,17 @@ select {
545
 
546
  /* 全画面時の操作パネル */
547
  .viewing-box:-webkit-full-screen .video-controls,
548
- .viewing-box:fullscreen .video-controls,
549
- .viewing-box:-moz-full-screen .video-controls {
550
- position: absolute;
551
- bottom: 0;
552
- left: 0;
553
- right: 0;
554
  width: 100%;
555
  border-radius: 0;
556
  background-color: rgba(0, 0, 0, 0.9);
557
  padding: 15px 20px;
558
  z-index: 1000;
559
  flex-shrink: 0;
560
- pointer-events: auto;
561
  }
562
 
563
  /* 全画面時のパネル内要素 */
@@ -1154,6 +1152,10 @@ canvas {
1154
  height: 28px;
1155
  padding: 0 4px;
1156
  font-size: 11px;
 
 
 
 
1157
  }
1158
 
1159
  .pane-controls button svg {
@@ -1469,7 +1471,7 @@ canvas {
1469
  padding: 8px 16px;
1470
  border-radius: 5px;
1471
  cursor: pointer;
1472
- z-index: 1000001;
1473
  font-size: 12px;
1474
  font-weight: bold;
1475
  transition: all 0.3s;
@@ -1820,7 +1822,7 @@ canvas {
1820
  <h1 id="title-name">文化発表会動画プレイヤー</h1>
1821
 
1822
  <div class="details-container">
1823
- <details id="usageDetails" style="max-width:1000px;">
1824
  <summary style="font-size: 25px">使い方</summary>
1825
  <h3>プレイヤーの使い方</h3>
1826
  <p>「▶」や「⏸」ボタンで再生や一時停止ができます。「↺」で再生開始秒数から再生できます。音量スライダーで音量を変更できます。スライダーで再生速度も変更できます。「⇲」で、動画を小さく表示し、他のタブに移動しながら見れるようにします。「⛶」で動画を全画面で表示できます。</p>
@@ -1862,6 +1864,7 @@ canvas {
1862
  <button id="sw-register-btn">Service Worker を登録</button>
1863
  <button id="sw-delete-btn" disabled>Service Worker とデータを削除</button>
1864
  <div id="sw-status"></div>
 
1865
  </div>
1866
  </details><br><br>
1867
  <div class="mode-tabs-container">
@@ -2009,7 +2012,6 @@ canvas {
2009
  audio: 'f/a.mp3',
2010
  mp4: ['f/a.mp4'],
2011
  vrma: ['idle.vrma'],
2012
- startTime: 105,
2013
  timeMarkers: [{
2014
  time: 0,
2015
  label: '0'
@@ -3732,144 +3734,90 @@ function restoreModeState(mode) {
3732
  }
3733
  }
3734
 
3735
- function switchMode(newMode) {
3736
- if (newMode === currentMode) return;
3737
- saveCurrentModeState();
3738
- currentMode = newMode;
3739
- AUDIO_SRC = MODE_DEFINITIONS[currentMode].audio;
3740
- VIDEO_SOURCES = [...MODE_DEFINITIONS[currentMode].mp4];
3741
- VRMA_ANIMATIONS = [...MODE_DEFINITIONS[currentMode].vrma];
3742
-
3743
- document.querySelectorAll('.mode-tab').forEach(tab => {
3744
- tab.classList.toggle('active', tab.dataset.mode === currentMode);
3745
- });
3746
-
3747
- updateTimeMarkers();
3748
- showLoadingOverlay();
3749
-
3750
- if (bgmAudioElement) {
3751
- bgmAudioElement.pause();
3752
- bgmAudioElement.src = '';
3753
- }
3754
-
3755
- const hasSaved = restoreModeState(currentMode);
3756
- if (!hasSaved) {
3757
- const modeDef = MODE_DEFINITIONS[currentMode];
3758
- const defStartTime = modeDef.startTime !== undefined ? modeDef.startTime : 0;
3759
- const defEndTime = modeDef.endTime !== undefined && modeDef.endTime !== null ? modeDef.endTime : 0;
3760
-
3761
- globalTimeline.startTime = defStartTime;
3762
- globalTimeline.endTime = defEndTime;
3763
- globalTimeline.currentTime = defStartTime;
3764
- globalTimeline.loopEnabled = false;
3765
- globalTimeline.loopInterval = 0;
3766
- globalTimeline.isPlaying = false;
3767
- globalTimeline.hasEnded = false;
3768
- document.getElementById('start-time').value = 0;
3769
- document.getElementById('end-time').value = 0;
3770
- document.getElementById('loop').checked = false;
3771
- document.getElementById('loop-interval').value = 0;
3772
- }
3773
-
3774
- if (window.markerManager) {
3775
- if (hasSaved && modeStateStore[currentMode]?.timeline) {
3776
- const savedTimeline = modeStateStore[currentMode].timeline;
3777
- if (savedTimeline.startTime > 0) window.markerManager.setStartMarker(savedTimeline.startTime);
3778
- else window.markerManager.setStartMarker(0);
3779
- if (savedTimeline.endTime > 0 && savedTimeline.endTime < globalTimeline.duration) window.markerManager.setEndMarker(savedTimeline.endTime);
3780
- else window.markerManager.setEndMarker(globalTimeline.duration);
3781
- } else {
3782
- window.markerManager.setStartMarker(0);
3783
- window.markerManager.setEndMarker(globalTimeline.duration);
3784
- }
3785
- }
3786
-
3787
- if (hasSaved && modeStateStore[currentMode].panes) {
3788
- const savedPanes = modeStateStore[currentMode].panes;
3789
- const paneMap = new Map();
3790
- // 既存のパネルをクリーンアップ
3791
- panes.forEach(p => p.cleanup());
3792
- panes = [];
3793
- savedPanes.forEach(pData => {
3794
- const container = document.createElement('div');
3795
- container.className = 'split-pane';
3796
- const pane = new Pane(container, pData.id, pData.type);
3797
- pane.videoSrc = pData.videoSrc;
3798
- pane.vrmSrc = pData.vrmSrc;
3799
- pane.vrmaSrc = pData.vrmaSrc;
3800
- pane.volume = pData.volume;
3801
- pane.isFlipped = pData.isFlipped;
3802
- pane.isMotionFlipped = pData.isMotionFlipped;
3803
- pane.modelBaseScaleX = pData.modelBaseScaleX;
3804
- pane.updateContent();
3805
- pane.applyFlipStates();
3806
- pane.setVolume(pane.volume);
3807
- panes.push(pane);
3808
- paneMap.set(pane.id, pane);
3809
- });
3810
- if (savedPanes[0]?.splitInfo) window.splitTree.deserialize(savedPanes[0].splitInfo, paneMap);
3811
- if (!window.splitTree.root && panes.length > 0) window.splitTree.setRootPane(panes[0]);
3812
- } else {
3813
- // 既存のパネルをクリーンアップ
3814
- panes.forEach(p => p.cleanup());
3815
- panes = [];
3816
- const splitContainer = document.getElementById('split-container');
3817
- if (window.splitTree) {
3818
- // 既存の splitTree をクリア
3819
- splitContainer.innerHTML = '';
3820
  }
3821
- window.splitTree = new SplitTreeManager(splitContainer);
3822
- const defaultPaneContainer = document.createElement('div');
3823
- defaultPaneContainer.className = 'split-pane';
3824
- const pane = new Pane(defaultPaneContainer, 'pane-main', 'video');
3825
- pane.videoSrc = VIDEO_SOURCES[0] || 'm.mp4';
3826
- pane.vrmaSrc = VRMA_ANIMATIONS[0] || 'idle.vrma';
3827
- pane.updateContent();
3828
- panes.push(pane);
3829
- window.splitTree.setRootPane(pane);
3830
- }
3831
-
3832
- panes.forEach(p => p.setGlobalVolumeFactor(globalVolumeFactor));
3833
-
3834
- // 重要: コントロールを再有効化
3835
- setTimeout(() => {
3836
- enableAllControls();
3837
- }, 100);
3838
-
3839
- loadBGMAudio();
3840
- window.seekMedia(globalTimeline.startTime);
3841
- updateProgressBar();
3842
- updateTimeDisplay();
3843
- }
3844
- function enableAllControls() {
3845
- const controlIds = [
3846
- 'play-pause-btn', 'reset-btn', 'volume-btn', 'volume-slider',
3847
- 'fullscreen-btn', 'start-time', 'end-time', 'reset-end-time',
3848
- 'loop', 'loop-interval', 'global-volume', 'set-start-time',
3849
- 'set-end-time', 'playback-speed', 'apply-time-btn', 'pip-btn',
3850
- 'speed-btn'
3851
- ];
3852
-
3853
- controlIds.forEach(id => {
3854
- const el = document.getElementById(id);
3855
- if (el) el.disabled = false;
3856
- });
3857
-
3858
- // ★ すべてのパネル内のセレクトボックスとボタンを有効化
3859
- panes.forEach(pane => {
3860
- const container = pane.container;
3861
- if (!container) return;
3862
-
3863
- const selects = container.querySelectorAll('select, button, input');
3864
- selects.forEach(el => {
3865
- if (el.disabled !== undefined) el.disabled = false;
3866
- });
3867
-
3868
- // 特にタイプセレクトを明示的に有効化
3869
- const typeSelect = container.querySelector('.pane-type-select');
3870
- if (typeSelect) typeSelect.disabled = false;
3871
- });
3872
- }
3873
 
3874
  // ===== ローディングオーバーレイ =====
3875
  function showLoadingOverlay() {
@@ -3886,12 +3834,10 @@ function enableAllControls() {
3886
  isLoadingComplete = true;
3887
  overlay.style.transition = 'opacity 1s ease-out';
3888
  overlay.style.opacity = '0';
3889
- setTimeout(() => {
3890
- overlay.style.display = 'none';
3891
- enableAllControls(); // ローディング完了時にコントロールを有効化
3892
- }, 1000);
3893
  }
3894
  }
 
3895
  function loadBGMAudio() {
3896
  if (bgmAudioElement) { bgmAudioElement.pause();
3897
  bgmAudioElement.src = '';
@@ -3932,21 +3878,15 @@ function enableAllControls() {
3932
  window.markerManager.setEndMarker(globalTimeline.endTime);
3933
  }
3934
  } else {
3935
- // MODE_DEFINITIONSからデフォルト値を取得
3936
- const modeDef = MODE_DEFINITIONS[currentMode];
3937
- const defStartTime = modeDef.startTime !== undefined ? modeDef.startTime : 0;
3938
- const defEndTime = (modeDef.endTime !== undefined && modeDef.endTime !== null) ? modeDef.endTime : globalTimeline.duration;
3939
-
3940
- globalTimeline.startTime = defStartTime;
3941
- globalTimeline.endTime = defEndTime;
3942
-
3943
  if (!isNaN(globalTimeline.duration) && isFinite(globalTimeline.duration)) {
3944
- document.getElementById('end-time').value = globalTimeline.endTime;
3945
- document.getElementById('start-time').value = globalTimeline.startTime;
3946
  }
3947
  if (window.markerManager) {
3948
- window.markerManager.setStartMarker(globalTimeline.startTime);
3949
- window.markerManager.setEndMarker(globalTimeline.endTime);
3950
  }
3951
  }
3952
  updateTimeDisplay();
@@ -4175,7 +4115,7 @@ function applyTimeSettings() {
4175
  initAutoHideControls();
4176
  document.getElementById('speed-btn').addEventListener('click', createSpeedPopup);
4177
  setTimeout(() => {
4178
- enableAllControls();
4179
  }, 1000);
4180
 
4181
  document.querySelectorAll('.mode-tab').forEach(tab => {
@@ -4361,6 +4301,7 @@ function applyTimeSettings() {
4361
  volumeSlider.addEventListener('input', updateVolumeIcon);
4362
  window.addEventListener('beforeunload', () => { saveGlobalState(); });
4363
  setInterval(saveGlobalState, 5000);
 
4364
  }
4365
 
4366
  window.addEventListener('load', () => {
@@ -4373,7 +4314,64 @@ function applyTimeSettings() {
4373
  if (loadingOverlay) { loadingOverlay.style.display = 'flex';
4374
  loadingOverlay.style.opacity = '1'; }
4375
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4376
 
 
 
 
 
 
 
4377
  /*
4378
  // マーカーの状態を確認
4379
  console.log('マーカーマネージャー:', window.markerManager);
 
116
  display: flex;
117
  flex-direction: column;
118
  width: 100%;
119
+ max-width: 1000px;
120
+ background-color: rgba(17, 34, 64, 0.3);
121
  border-radius: 10px;
122
  padding: 20px;
123
  box-shadow: 0 0 20px rgba(100, 255, 218, 0.2);
124
+ backdrop-filter: blur(1.7px);
125
+ border: 1px solid rgba(100, 255, 218, 0.1);
126
  }
127
 
128
  .viewing-box {
 
225
  right: 5px;
226
  display: flex;
227
  gap: 5px;
228
+ z-index: 20;
229
  background: rgba(0, 0, 0, 0.5);
230
  padding: 5px;
231
  border-radius: 5px;
 
545
 
546
  /* 全画面時の操作パネル */
547
  .viewing-box:-webkit-full-screen .video-controls,
548
+ .viewing-box:fullscreen .video-controls {
549
+ position: relative;
550
+ bottom: auto;
551
+ left: auto;
552
+ right: auto;
 
553
  width: 100%;
554
  border-radius: 0;
555
  background-color: rgba(0, 0, 0, 0.9);
556
  padding: 15px 20px;
557
  z-index: 1000;
558
  flex-shrink: 0;
 
559
  }
560
 
561
  /* 全画面時のパネル内要素 */
 
1152
  height: 28px;
1153
  padding: 0 4px;
1154
  font-size: 11px;
1155
+ position: relative;
1156
+ z-index: 100000;
1157
+ transform: translateZ(0);
1158
+ isolation: isolate;
1159
  }
1160
 
1161
  .pane-controls button svg {
 
1471
  padding: 8px 16px;
1472
  border-radius: 5px;
1473
  cursor: pointer;
1474
+ z-index: 10001;
1475
  font-size: 12px;
1476
  font-weight: bold;
1477
  transition: all 0.3s;
 
1822
  <h1 id="title-name">文化発表会動画プレイヤー</h1>
1823
 
1824
  <div class="details-container">
1825
+ <details id="usageDetails">
1826
  <summary style="font-size: 25px">使い方</summary>
1827
  <h3>プレイヤーの使い方</h3>
1828
  <p>「▶」や「⏸」ボタンで再生や一時停止ができます。「↺」で再生開始秒数から再生できます。音量スライダーで音量を変更できます。スライダーで再生速度も変更できます。「⇲」で、動画を小さく表示し、他のタブに移動しながら見れるようにします。「⛶」で動画を全画面で表示できます。</p>
 
1864
  <button id="sw-register-btn">Service Worker を登録</button>
1865
  <button id="sw-delete-btn" disabled>Service Worker とデータを削除</button>
1866
  <div id="sw-status"></div>
1867
+ </div>
1868
  </div>
1869
  </details><br><br>
1870
  <div class="mode-tabs-container">
 
2012
  audio: 'f/a.mp3',
2013
  mp4: ['f/a.mp4'],
2014
  vrma: ['idle.vrma'],
 
2015
  timeMarkers: [{
2016
  time: 0,
2017
  label: '0'
 
3734
  }
3735
  }
3736
 
3737
+ function switchMode(newMode) {
3738
+ if (newMode === currentMode) return;
3739
+ saveCurrentModeState();
3740
+ currentMode = newMode;
3741
+ AUDIO_SRC = MODE_DEFINITIONS[currentMode].audio;
3742
+ VIDEO_SOURCES = [...MODE_DEFINITIONS[currentMode].mp4];
3743
+ VRMA_ANIMATIONS = [...MODE_DEFINITIONS[currentMode].vrma];
3744
+ document.querySelectorAll('.mode-tab').forEach(tab => {
3745
+ tab.classList.toggle('active', tab.dataset.mode === currentMode);
3746
+ });
3747
+ updateTimeMarkers();
3748
+ showLoadingOverlay();
3749
+ if (bgmAudioElement) { bgmAudioElement.pause();
3750
+ bgmAudioElement.src = ''; }
3751
+ const hasSaved = restoreModeState(currentMode);
3752
+ if (!hasSaved) {
3753
+ globalTimeline.startTime = 0;
3754
+ globalTimeline.endTime = 0;
3755
+ globalTimeline.currentTime = 0;
3756
+ globalTimeline.loopEnabled = false;
3757
+ globalTimeline.loopInterval = 0;
3758
+ globalTimeline.isPlaying = false;
3759
+ globalTimeline.hasEnded = false;
3760
+ document.getElementById('start-time').value = 0;
3761
+ document.getElementById('end-time').value = 0;
3762
+ document.getElementById('loop').checked = false;
3763
+ document.getElementById('loop-interval').value = 0;
3764
+ }
3765
+ if (window.markerManager) {
3766
+ if (hasSaved && modeStateStore[currentMode]?.timeline) {
3767
+ const savedTimeline = modeStateStore[currentMode].timeline;
3768
+ if (savedTimeline.startTime > 0) window.markerManager.setStartMarker(savedTimeline.startTime);
3769
+ else window.markerManager.setStartMarker(0);
3770
+ if (savedTimeline.endTime > 0 && savedTimeline.endTime < globalTimeline.duration) window.markerManager.setEndMarker(savedTimeline.endTime);
3771
+ else window.markerManager.setEndMarker(globalTimeline.duration);
3772
+ } else {
3773
+ window.markerManager.setStartMarker(0);
3774
+ window.markerManager.setEndMarker(globalTimeline.duration);
3775
+ }
3776
+ }
3777
+ if (hasSaved && modeStateStore[currentMode].panes) {
3778
+ const savedPanes = modeStateStore[currentMode].panes;
3779
+ const paneMap = new Map();
3780
+ panes.forEach(p => p.cleanup());
3781
+ panes = [];
3782
+ savedPanes.forEach(pData => {
3783
+ const container = document.createElement('div');
3784
+ container.className = 'split-pane';
3785
+ const pane = new Pane(container, pData.id, pData.type);
3786
+ pane.videoSrc = pData.videoSrc;
3787
+ pane.vrmSrc = pData.vrmSrc;
3788
+ pane.vrmaSrc = pData.vrmaSrc;
3789
+ pane.volume = pData.volume;
3790
+ pane.isFlipped = pData.isFlipped;
3791
+ pane.isMotionFlipped = pData.isMotionFlipped;
3792
+ pane.modelBaseScaleX = pData.modelBaseScaleX;
3793
+ pane.updateContent();
3794
+ pane.applyFlipStates();
3795
+ pane.setVolume(pane.volume);
3796
+ panes.push(pane);
3797
+ paneMap.set(pane.id, pane);
3798
+ });
3799
+ window.splitTree.deserialize(savedPanes[0].splitInfo, paneMap);
3800
+ if (!window.splitTree.root && panes.length > 0) window.splitTree.setRootPane(panes[0]);
3801
+ } else {
3802
+ panes.forEach(p => p.cleanup());
3803
+ panes = [];
3804
+ const splitContainer = document.getElementById('split-container');
3805
+ window.splitTree = new SplitTreeManager(splitContainer);
3806
+ const defaultPaneContainer = document.createElement('div');
3807
+ defaultPaneContainer.className = 'split-pane';
3808
+ const pane = new Pane(defaultPaneContainer, 'pane-main', 'video');
3809
+ pane.videoSrc = VIDEO_SOURCES[0] || 'm.mp4';
3810
+ pane.vrmaSrc = VRMA_ANIMATIONS[0] || 'idle.vrma';
3811
+ pane.updateContent();
3812
+ panes.push(pane);
3813
+ window.splitTree.setRootPane(pane);
3814
+ }
3815
+ panes.forEach(p => p.setGlobalVolumeFactor(globalVolumeFactor));
3816
+ loadBGMAudio();
3817
+ window.seekMedia(globalTimeline.startTime);
3818
+ updateProgressBar();
3819
+ updateTimeDisplay();
 
 
3820
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3821
 
3822
  // ===== ローディングオーバーレイ =====
3823
  function showLoadingOverlay() {
 
3834
  isLoadingComplete = true;
3835
  overlay.style.transition = 'opacity 1s ease-out';
3836
  overlay.style.opacity = '0';
3837
+ setTimeout(() => { overlay.style.display = 'none'; }, 1000);
 
 
 
3838
  }
3839
  }
3840
+
3841
  function loadBGMAudio() {
3842
  if (bgmAudioElement) { bgmAudioElement.pause();
3843
  bgmAudioElement.src = '';
 
3878
  window.markerManager.setEndMarker(globalTimeline.endTime);
3879
  }
3880
  } else {
3881
+ globalTimeline.endTime = globalTimeline.duration;
3882
+ globalTimeline.startTime = 0;
 
 
 
 
 
 
3883
  if (!isNaN(globalTimeline.duration) && isFinite(globalTimeline.duration)) {
3884
+ document.getElementById('end-time').value = globalTimeline.duration;
3885
+ document.getElementById('start-time').value = 0;
3886
  }
3887
  if (window.markerManager) {
3888
+ window.markerManager.setStartMarker(0);
3889
+ window.markerManager.setEndMarker(globalTimeline.duration);
3890
  }
3891
  }
3892
  updateTimeDisplay();
 
4115
  initAutoHideControls();
4116
  document.getElementById('speed-btn').addEventListener('click', createSpeedPopup);
4117
  setTimeout(() => {
4118
+ document.querySelectorAll('#play-pause-btn, #reset-btn, #volume-btn, #volume-slider, #fullscreen-btn, #start-time, #end-time, #reset-end-time, #loop, #loop-interval, #global-volume, #set-start-time, #set-end-time, #playback-speed, #apply-time-btn, #pip-btn, #speed-btn').forEach(el => { if (el) el.disabled = false; });
4119
  }, 1000);
4120
 
4121
  document.querySelectorAll('.mode-tab').forEach(tab => {
 
4301
  volumeSlider.addEventListener('input', updateVolumeIcon);
4302
  window.addEventListener('beforeunload', () => { saveGlobalState(); });
4303
  setInterval(saveGlobalState, 5000);
4304
+ initSelectHack();
4305
  }
4306
 
4307
  window.addEventListener('load', () => {
 
4314
  if (loadingOverlay) { loadingOverlay.style.display = 'flex';
4315
  loadingOverlay.style.opacity = '1'; }
4316
  });
4317
+ function applySelectHack() {
4318
+ document.querySelectorAll('.pane-controls select').forEach(original => {
4319
+ if (original.hasAttribute('data-hacked')) return;
4320
+
4321
+ const rect = original.getBoundingClientRect();
4322
+ if (rect.width === 0 || rect.height === 0) return; // 非表示の要素はスキップ
4323
+
4324
+ const clone = original.cloneNode(true);
4325
+ clone.style.position = 'fixed';
4326
+ clone.style.top = rect.top + 'px';
4327
+ clone.style.left = rect.left + 'px';
4328
+ clone.style.width = rect.width + 'px';
4329
+ clone.style.height = rect.height + 'px';
4330
+ clone.style.zIndex = '1000000';
4331
+ clone.style.backgroundColor = '#112240';
4332
+ clone.style.border = '1px solid #64ffda';
4333
+ clone.style.margin = '0';
4334
+ clone.style.padding = '0';
4335
+ clone.style.boxSizing = 'border-box';
4336
+ clone.style.fontSize = window.getComputedStyle(original).fontSize;
4337
+ clone.style.fontFamily = window.getComputedStyle(original).fontFamily;
4338
+
4339
+ // 元のセレクトを透明化
4340
+ original.style.opacity = '0';
4341
+ original.style.pointerEvents = 'none';
4342
+ original.setAttribute('data-hacked', 'true');
4343
+
4344
+ document.body.appendChild(clone);
4345
+
4346
+ // 値の同期
4347
+ clone.addEventListener('change', () => {
4348
+ original.value = clone.value;
4349
+ original.dispatchEvent(new Event('change', { bubbles: true }));
4350
+ });
4351
+
4352
+ // 位置更新(スクロール・リサイズ・親要素の変更に対応)
4353
+ const updatePos = () => {
4354
+ const newRect = original.getBoundingClientRect();
4355
+ clone.style.top = newRect.top + 'px';
4356
+ clone.style.left = newRect.left + 'px';
4357
+ clone.style.width = newRect.width + 'px';
4358
+ };
4359
+ window.addEventListener('scroll', updatePos, { passive: true });
4360
+ window.addEventListener('resize', updatePos);
4361
+ const observer = new ResizeObserver(updatePos);
4362
+ if (original.parentElement) observer.observe(original.parentElement);
4363
+
4364
+ // 全画面表示などでビューポートが変わったときにも対応
4365
+ document.addEventListener('fullscreenchange', updatePos);
4366
+ });
4367
+ }
4368
 
4369
+ // 初期ロード時と動的なパネル追加に対応
4370
+ function initSelectHack() {
4371
+ applySelectHack();
4372
+ const observer = new MutationObserver(() => applySelectHack());
4373
+ observer.observe(document.body, { childList: true, subtree: true });
4374
+ }
4375
  /*
4376
  // マーカーの状態を確認
4377
  console.log('マーカーマネージャー:', window.markerManager);