akhaliq HF Staff commited on
Commit
2e50f11
·
1 Parent(s): 4d7b624

Implement defensive DOM operations in app.js to fix startup crashes

Browse files
Files changed (1) hide show
  1. static/app.js +107 -81
static/app.js CHANGED
@@ -72,7 +72,7 @@ marked.setOptions({
72
  // Setup Initial State & Event Handlers
73
  async function initializeApp() {
74
  // 1. Restore Credentials
75
- if (STATE.apiKey) {
76
  dom.apiKeyInput.value = STATE.apiKey;
77
  }
78
 
@@ -87,111 +87,137 @@ async function initializeApp() {
87
  });
88
 
89
  // 3. Register Sidebar Drawer Slide Events (Drawer + Overlay)
90
- dom.btnToggleRight.addEventListener("click", () => toggleSettingsDrawer(true));
91
- dom.btnCloseDrawer.addEventListener("click", () => toggleSettingsDrawer(false));
92
- dom.sidebarOverlay.addEventListener("click", () => toggleSettingsDrawer(false));
93
 
94
  // 4. Register Settings Listeners
95
- dom.apiKeyInput.addEventListener("input", (e) => {
96
- STATE.apiKey = e.target.value;
97
- localStorage.setItem("step_api_key", STATE.apiKey);
98
- });
 
 
99
 
100
- dom.toggleKeyVisibility.addEventListener("click", () => {
101
- const type = dom.apiKeyInput.type === "password" ? "text" : "password";
102
- dom.apiKeyInput.type = type;
103
- });
 
 
 
 
104
 
105
- dom.effortRadioButtons.forEach(radio => {
106
- radio.addEventListener("change", (e) => {
107
- STATE.reasoningEffort = e.target.value;
 
 
108
  });
109
- });
110
 
111
- dom.maxTokensSlider.addEventListener("input", (e) => {
112
- STATE.maxTokens = parseInt(e.target.value);
113
- dom.maxTokensVal.textContent = STATE.maxTokens;
114
- });
 
 
115
 
116
- dom.temperatureSlider.addEventListener("input", (e) => {
117
- STATE.temperature = parseFloat(e.target.value);
118
- dom.temperatureVal.textContent = STATE.temperature.toFixed(1);
119
- });
 
 
120
 
121
  // 5. Register File Upload Actions
122
- dom.studioUploadTrigger.addEventListener("click", () => dom.fileUploader.click());
123
- dom.miniUploadTrigger.addEventListener("click", () => dom.fileUploader.click());
124
- dom.dropZone.addEventListener("click", () => dom.fileUploader.click());
125
- dom.fileUploader.addEventListener("change", handleFileSelection);
126
 
127
  // Dropzone Drag-and-Drop animations
128
- ["dragenter", "dragover"].forEach(eventName => {
129
- dom.dropZone.addEventListener(eventName, (e) => {
130
- e.preventDefault();
131
- dom.dropZone.classList.add("drag-active");
132
- }, false);
133
- });
 
134
 
135
- ["dragleave", "drop"].forEach(eventName => {
136
- dom.dropZone.addEventListener(eventName, (e) => {
137
- e.preventDefault();
138
- dom.dropZone.classList.remove("drag-active");
139
- }, false);
140
- });
141
 
142
- dom.dropZone.addEventListener("drop", (e) => {
143
- const dt = e.dataTransfer;
144
- const files = dt.files;
145
- processFiles(files);
146
- });
 
147
 
148
  // 6. Submit Triggers
149
- dom.studioSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.studioPromptInput));
150
- dom.miniSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.miniPromptInput));
 
 
 
 
151
 
152
- dom.studioPromptInput.addEventListener("keydown", (e) => {
153
- if (e.key === "Enter" && !e.shiftKey) {
154
- e.preventDefault();
155
- triggerPromptSubmission(dom.studioPromptInput);
156
- }
157
- });
 
 
158
 
159
- dom.miniPromptInput.addEventListener("keydown", (e) => {
160
- if (e.key === "Enter" && !e.shiftKey) {
161
- e.preventDefault();
162
- triggerPromptSubmission(dom.miniPromptInput);
163
- }
164
- });
 
 
165
 
166
  // 7. Resets
167
- dom.menuNewChat.addEventListener("click", resetSandbox);
168
- dom.clearChatBtn.addEventListener("click", resetSandbox);
169
 
170
  // 8. Recipe Chips Console Setup
171
- dom.recipeChips.forEach(chip => {
172
- chip.addEventListener("click", () => {
173
- const recipeType = chip.getAttribute("data-recipe");
174
- loadRecipe(recipeType);
 
 
175
  });
176
- });
177
 
178
  // Auto-expand input textareas
179
  [dom.studioPromptInput, dom.miniPromptInput].forEach(textarea => {
180
- textarea.addEventListener("input", () => {
181
- textarea.style.height = "auto";
182
- textarea.style.height = (textarea.scrollHeight) + "px";
183
- });
 
 
184
  });
185
  }
186
 
187
  // Drawer Toggler Action
188
  function toggleSettingsDrawer(open) {
189
  if (open) {
190
- dom.sidebarRight.classList.remove("collapsed");
191
- dom.sidebarOverlay.classList.add("active");
192
  } else {
193
- dom.sidebarRight.classList.add("collapsed");
194
- dom.sidebarOverlay.classList.remove("active");
195
  }
196
  }
197
 
@@ -223,12 +249,12 @@ function processFiles(files) {
223
 
224
  // Update UI Attachment Previews
225
  function updateShelfUI() {
226
- dom.shelfList.innerHTML = "";
227
- dom.innerShelfPreview.innerHTML = "";
228
- dom.miniShelfPreview.innerHTML = "";
229
 
230
  if (STATE.uploadedFiles.length === 0) {
231
- dom.shelfList.innerHTML = `<div class="empty-shelf-text">No active attachments loaded. Upload images or video clips.</div>`;
232
  return;
233
  }
234
 
@@ -264,15 +290,15 @@ function updateShelfUI() {
264
  removeFile(file.id);
265
  });
266
 
267
- dom.shelfList.appendChild(chip);
268
 
269
  // 2. Dashboard Inner Console Preview
270
  const previewItemDash = createPreviewThumb(file);
271
- dom.innerShelfPreview.appendChild(previewItemDash);
272
 
273
  // 3. Mini Input Preview
274
  const previewItemMini = createPreviewThumb(file);
275
- dom.miniShelfPreview.appendChild(previewItemMini);
276
  });
277
  }
278
 
 
72
  // Setup Initial State & Event Handlers
73
  async function initializeApp() {
74
  // 1. Restore Credentials
75
+ if (STATE.apiKey && dom.apiKeyInput) {
76
  dom.apiKeyInput.value = STATE.apiKey;
77
  }
78
 
 
87
  });
88
 
89
  // 3. Register Sidebar Drawer Slide Events (Drawer + Overlay)
90
+ if (dom.btnToggleRight) dom.btnToggleRight.addEventListener("click", () => toggleSettingsDrawer(true));
91
+ if (dom.btnCloseDrawer) dom.btnCloseDrawer.addEventListener("click", () => toggleSettingsDrawer(false));
92
+ if (dom.sidebarOverlay) dom.sidebarOverlay.addEventListener("click", () => toggleSettingsDrawer(false));
93
 
94
  // 4. Register Settings Listeners
95
+ if (dom.apiKeyInput) {
96
+ dom.apiKeyInput.addEventListener("input", (e) => {
97
+ STATE.apiKey = e.target.value;
98
+ localStorage.setItem("step_api_key", STATE.apiKey);
99
+ });
100
+ }
101
 
102
+ if (dom.toggleKeyVisibility) {
103
+ dom.toggleKeyVisibility.addEventListener("click", () => {
104
+ if (dom.apiKeyInput) {
105
+ const type = dom.apiKeyInput.type === "password" ? "text" : "password";
106
+ dom.apiKeyInput.type = type;
107
+ }
108
+ });
109
+ }
110
 
111
+ if (dom.effortRadioButtons) {
112
+ dom.effortRadioButtons.forEach(radio => {
113
+ radio.addEventListener("change", (e) => {
114
+ STATE.reasoningEffort = e.target.value;
115
+ });
116
  });
117
+ }
118
 
119
+ if (dom.maxTokensSlider && dom.maxTokensVal) {
120
+ dom.maxTokensSlider.addEventListener("input", (e) => {
121
+ STATE.maxTokens = parseInt(e.target.value);
122
+ dom.maxTokensVal.textContent = STATE.maxTokens;
123
+ });
124
+ }
125
 
126
+ if (dom.temperatureSlider && dom.temperatureVal) {
127
+ dom.temperatureSlider.addEventListener("input", (e) => {
128
+ STATE.temperature = parseFloat(e.target.value);
129
+ dom.temperatureVal.textContent = STATE.temperature.toFixed(1);
130
+ });
131
+ }
132
 
133
  // 5. Register File Upload Actions
134
+ if (dom.studioUploadTrigger) dom.studioUploadTrigger.addEventListener("click", () => dom.fileUploader.click());
135
+ if (dom.miniUploadTrigger) dom.miniUploadTrigger.addEventListener("click", () => dom.fileUploader.click());
136
+ if (dom.dropZone) dom.dropZone.addEventListener("click", () => dom.fileUploader.click());
137
+ if (dom.fileUploader) dom.fileUploader.addEventListener("change", handleFileSelection);
138
 
139
  // Dropzone Drag-and-Drop animations
140
+ if (dom.dropZone) {
141
+ ["dragenter", "dragover"].forEach(eventName => {
142
+ dom.dropZone.addEventListener(eventName, (e) => {
143
+ e.preventDefault();
144
+ dom.dropZone.classList.add("drag-active");
145
+ }, false);
146
+ });
147
 
148
+ ["dragleave", "drop"].forEach(eventName => {
149
+ dom.dropZone.addEventListener(eventName, (e) => {
150
+ e.preventDefault();
151
+ dom.dropZone.classList.remove("drag-active");
152
+ }, false);
153
+ });
154
 
155
+ dom.dropZone.addEventListener("drop", (e) => {
156
+ const dt = e.dataTransfer;
157
+ const files = dt.files;
158
+ processFiles(files);
159
+ });
160
+ }
161
 
162
  // 6. Submit Triggers
163
+ if (dom.studioSendBtn) {
164
+ dom.studioSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.studioPromptInput));
165
+ }
166
+ if (dom.miniSendBtn) {
167
+ dom.miniSendBtn.addEventListener("click", () => triggerPromptSubmission(dom.miniPromptInput));
168
+ }
169
 
170
+ if (dom.studioPromptInput) {
171
+ dom.studioPromptInput.addEventListener("keydown", (e) => {
172
+ if (e.key === "Enter" && !e.shiftKey) {
173
+ e.preventDefault();
174
+ triggerPromptSubmission(dom.studioPromptInput);
175
+ }
176
+ });
177
+ }
178
 
179
+ if (dom.miniPromptInput) {
180
+ dom.miniPromptInput.addEventListener("keydown", (e) => {
181
+ if (e.key === "Enter" && !e.shiftKey) {
182
+ e.preventDefault();
183
+ triggerPromptSubmission(dom.miniPromptInput);
184
+ }
185
+ });
186
+ }
187
 
188
  // 7. Resets
189
+ if (dom.menuNewChat) dom.menuNewChat.addEventListener("click", resetSandbox);
190
+ if (dom.clearChatBtn) dom.clearChatBtn.addEventListener("click", resetSandbox);
191
 
192
  // 8. Recipe Chips Console Setup
193
+ if (dom.recipeChips) {
194
+ dom.recipeChips.forEach(chip => {
195
+ chip.addEventListener("click", () => {
196
+ const recipeType = chip.getAttribute("data-recipe");
197
+ loadRecipe(recipeType);
198
+ });
199
  });
200
+ }
201
 
202
  // Auto-expand input textareas
203
  [dom.studioPromptInput, dom.miniPromptInput].forEach(textarea => {
204
+ if (textarea) {
205
+ textarea.addEventListener("input", () => {
206
+ textarea.style.height = "auto";
207
+ textarea.style.height = (textarea.scrollHeight) + "px";
208
+ });
209
+ }
210
  });
211
  }
212
 
213
  // Drawer Toggler Action
214
  function toggleSettingsDrawer(open) {
215
  if (open) {
216
+ if (dom.sidebarRight) dom.sidebarRight.classList.remove("collapsed");
217
+ if (dom.sidebarOverlay) dom.sidebarOverlay.classList.add("active");
218
  } else {
219
+ if (dom.sidebarRight) dom.sidebarRight.classList.add("collapsed");
220
+ if (dom.sidebarOverlay) dom.sidebarOverlay.classList.remove("active");
221
  }
222
  }
223
 
 
249
 
250
  // Update UI Attachment Previews
251
  function updateShelfUI() {
252
+ if (dom.shelfList) dom.shelfList.innerHTML = "";
253
+ if (dom.innerShelfPreview) dom.innerShelfPreview.innerHTML = "";
254
+ if (dom.miniShelfPreview) dom.miniShelfPreview.innerHTML = "";
255
 
256
  if (STATE.uploadedFiles.length === 0) {
257
+ if (dom.shelfList) dom.shelfList.innerHTML = `<div class="empty-shelf-text">No active attachments loaded. Upload images or video clips.</div>`;
258
  return;
259
  }
260
 
 
290
  removeFile(file.id);
291
  });
292
 
293
+ if (dom.shelfList) dom.shelfList.appendChild(chip);
294
 
295
  // 2. Dashboard Inner Console Preview
296
  const previewItemDash = createPreviewThumb(file);
297
+ if (dom.innerShelfPreview) dom.innerShelfPreview.appendChild(previewItemDash);
298
 
299
  // 3. Mini Input Preview
300
  const previewItemMini = createPreviewThumb(file);
301
+ if (dom.miniShelfPreview) dom.miniShelfPreview.appendChild(previewItemMini);
302
  });
303
  }
304