DeepLearning101 commited on
Commit
212391b
·
verified ·
1 Parent(s): 0fdf933

由內而外鎖定法 (Inside-Out Locking)

Browse files

抓到表格本人:設定寬度 1500px。
抓表格的爸爸 (直接容器):強制 overflow-x: auto (只有這裡要有捲軸)。
抓表格的爺爺、曾爺爺 (外層容器):強制 overflow-x: hidden (全部殺死,不准有捲軸)

Files changed (1) hide show
  1. app.py +60 -57
app.py CHANGED
@@ -131,67 +131,70 @@ def check_login(user, password):
131
  error_msg: "<span style='color: red'>❌ 帳號或密碼錯誤</span>"
132
  }
133
 
134
- # --- 🟢 [JavaScript] 用來強殺死外層捲軸 ---
135
- # 這 JS 會在頁面載入後,每 0.5 秒檢查一次,強制把那些不受控的 wrapper 鎖死
136
- kill_scroll_js = """
 
 
 
137
  function() {
138
- // 定義一個修復函數
139
  const fixScroll = () => {
140
- const tableComponent = document.querySelector('#booking_table');
141
- if (!tableComponent) return;
 
142
 
143
- // 1. 找到所有中間層 (wrapper)
144
- // 這些 div 通常是 Gradio 自動生成的,就是它們在搞鬼
145
- const wrappers = tableComponent.querySelectorAll('div');
146
-
147
- wrappers.forEach(div => {
148
- // 如果這個 div 不是真正包著 table 的那個 (table-wrap)
149
- // 而且它有水平捲軸,就強制殺掉它
150
- if (!div.classList.contains('table-wrap') && div.scrollWidth > div.clientWidth) {
151
- div.style.overflowX = 'hidden';
152
- div.style.maxWidth = '100vw'; // 強制不准超過螢幕
153
- }
154
- });
155
-
156
- // 2. 確保最內層可以捲動
157
- const innerScroller = tableComponent.querySelector('.table-wrap');
158
- if (innerScroller) {
159
- innerScroller.style.overflowX = 'auto';
160
- innerScroller.style.maxWidth = '100vw'; // 確保捲動容器本身也不超過螢幕
 
 
 
 
 
 
 
161
  }
 
 
 
162
  };
163
 
164
- // 立即執行一次
165
  fixScroll();
166
-
167
- // 每 500ms 執行一次,以防 Gradio 重新渲染後失效
168
- setInterval(fixScroll, 500);
169
  }
170
  """
171
 
172
- # --- 🔥 [CSS] 定寬 + 換行設定 ---
173
  custom_css = """
174
- /* 1. 元件外框鎖死 */
175
- #booking_table {
 
176
  max-width: 100vw !important;
177
- overflow: hidden !important;
178
- border: none !important;
179
  }
180
 
181
  /* 2. 表格內容設定 */
182
- #booking_table table {
183
- table-layout: fixed !important;
184
- width: 1500px !important;
185
- min-width: 1500px !important;
186
- border-collapse: collapse !important;
187
- margin: 0 !important;
188
- }
189
-
190
- /* 3. 欄位設定:允許換行 */
191
  #booking_table th, #booking_table td {
192
- white-space: normal !important;
193
- word-break: break-all !important;
194
  overflow-wrap: break-word !important;
 
195
  vertical-align: top !important;
196
  box-sizing: border-box !important;
197
  padding: 8px 5px !important;
@@ -200,17 +203,17 @@ custom_css = """
200
  line-height: 1.4 !important;
201
  }
202
 
203
- /* 4. 🔥 個別欄位寬度 (您指) */
204
- #booking_table th:nth-child(1), #booking_table td:nth-child(1) { width: 60px !important; }
205
- #booking_table th:nth-child(2), #booking_table td:nth-child(2) { width: 170px !important; }
206
- #booking_table th:nth-child(3), #booking_table td:nth-child(3) { width: 80px !important; }
207
- #booking_table th:nth-child(4), #booking_table td:nth-child(4) { width: 120px !important; }
208
- #booking_table th:nth-child(5), #booking_table td:nth-child(5) { width: 120px !important; }
209
- #booking_table th:nth-child(6), #booking_table td:nth-child(6) { width: 250px !important; }
210
- #booking_table th:nth-child(7), #booking_table td:nth-child(7) { width: 50px !important; }
211
- #booking_table th:nth-child(8), #booking_table td:nth-child(8) { width: 180px !important; }
212
- #booking_table th:nth-child(9), #booking_table td:nth-child(9) { width: 120px !important; }
213
- #booking_table th:nth-child(10), #booking_table td:nth-child(10) { width: 320px !important; }
214
  """
215
 
216
  # --- 介面開始 ---
@@ -248,8 +251,8 @@ with gr.Blocks(title="Admin", css=custom_css) as demo:
248
  outputs=[login_row, admin_row, error_msg]
249
  )
250
 
251
- # 🔥🔥🔥 關鍵:頁面載入時執行 JS 修復捲軸 🔥🔥🔥
252
- demo.load(None, js=kill_scroll_js)
253
 
254
  if __name__ == "__main__":
255
  demo.launch()
 
131
  error_msg: "<span style='color: red'>❌ 帳號或密碼錯誤</span>"
132
  }
133
 
134
+ # --- 🟢 [JavaScript] 精準控制捲軸 ---
135
+ # 這 JS 負責:
136
+ # 1. 找到表格本體 (table)
137
+ # 2. 找到包著表格的「那一層」div (parent),強制它顯示捲軸
138
+ # 3. 找到更外層的所有 div (grandparents),強制它們「不准」顯示捲軸
139
+ force_scroll_js = """
140
  function() {
 
141
  const fixScroll = () => {
142
+ // 1. 找到表格元件
143
+ const comp = document.querySelector('#booking_table');
144
+ if (!comp) return;
145
 
146
+ // 2. 找到裡面的 table
147
+ const table = comp.querySelector('table');
148
+ if (!table) return;
149
+
150
+ // 強制表格寬度 (確保內容撐開)
151
+ table.style.width = '1500px';
152
+ table.style.minWidth = '1500px';
153
+ table.style.tableLayout = 'fixed';
154
+
155
+ // 3. 找到直接包著 table 的那一層 div (這是我們要保留捲軸的地方)
156
+ const innerWrapper = table.parentElement;
157
+ if (innerWrapper) {
158
+ innerWrapper.style.overflowX = 'auto'; // 開啟捲軸
159
+ innerWrapper.style.width = '100%';
160
+ innerWrapper.style.maxWidth = '100vw';
161
+ innerWrapper.style.display = 'block';
162
+ }
163
+
164
+ // 4. 往上找所有祖先容器,全部殺死捲軸
165
+ // 這是解決「錯誤捲軸」或「雙重捲軸」的關鍵
166
+ let parent = innerWrapper.parentElement;
167
+ while (parent && parent.id !== 'booking_table') {
168
+ parent.style.overflowX = 'hidden'; // 隱藏外層捲軸
169
+ parent.style.width = '100%';
170
+ parent = parent.parentElement;
171
  }
172
+
173
+ // 確保最外層也沒有捲軸
174
+ if(comp) comp.style.overflowX = 'hidden';
175
  };
176
 
177
+ // 執行邏輯
178
  fixScroll();
179
+ setInterval(fixScroll, 500); // 防止 Gradio 重繪後失效
 
 
180
  }
181
  """
182
 
183
+ # --- 🔥 [CSS] 定寬 + 換行 + 隱藏全域捲軸 ---
184
  custom_css = """
185
+ /* 1. 全域設定:防止網頁被撐開 */
186
+ body, .gradio-container {
187
+ overflow-x: hidden !important;
188
  max-width: 100vw !important;
 
 
189
  }
190
 
191
  /* 2. 表格內容設定 */
192
+ /* 這裡只負責欄位的樣式,捲軸交給 JS 控制 */
 
 
 
 
 
 
 
 
193
  #booking_table th, #booking_table td {
194
+ white-space: normal !important; /* 允許換行 */
195
+ word-break: break-all !important; /* 強制換行 */
196
  overflow-wrap: break-word !important;
197
+
198
  vertical-align: top !important;
199
  box-sizing: border-box !important;
200
  padding: 8px 5px !important;
 
203
  line-height: 1.4 !important;
204
  }
205
 
206
+ /* 3. 🔥 個別欄位寬度 (同時設 width, min-width, max-width 確保不動如山) */
207
+ #booking_table th:nth-child(1), #booking_table td:nth-child(1) { width: 60px !important; min-width: 60px !important; max-width: 60px !important; }
208
+ #booking_table th:nth-child(2), #booking_table td:nth-child(2) { width: 170px !important; min-width: 170px !important; max-width: 170px !important; }
209
+ #booking_table th:nth-child(3), #booking_table td:nth-child(3) { width: 80px !important; min-width: 80px !important; max-width: 80px !important; }
210
+ #booking_table th:nth-child(4), #booking_table td:nth-child(4) { width: 120px !important; min-width: 120px !important; max-width: 120px !important; }
211
+ #booking_table th:nth-child(5), #booking_table td:nth-child(5) { width: 120px !important; min-width: 120px !important; max-width: 120px !important; }
212
+ #booking_table th:nth-child(6), #booking_table td:nth-child(6) { width: 250px !important; min-width: 250px !important; max-width: 250px !important; }
213
+ #booking_table th:nth-child(7), #booking_table td:nth-child(7) { width: 50px !important; min-width: 50px !important; max-width: 50px !important; }
214
+ #booking_table th:nth-child(8), #booking_table td:nth-child(8) { width: 180px !important; min-width: 180px !important; max-width: 180px !important; }
215
+ #booking_table th:nth-child(9), #booking_table td:nth-child(9) { width: 120px !important; min-width: 120px !important; max-width: 120px !important; }
216
+ #booking_table th:nth-child(10), #booking_table td:nth-child(10) { width: 320px !important; min-width: 320px !important; max-width: 320px !important; }
217
  """
218
 
219
  # --- 介面開始 ---
 
251
  outputs=[login_row, admin_row, error_msg]
252
  )
253
 
254
+ # 🔥🔥🔥 啟動 JS 修復程式 🔥🔥🔥
255
+ demo.load(None, js=force_scroll_js)
256
 
257
  if __name__ == "__main__":
258
  demo.launch()