hadadrjt commited on
Commit
e925412
·
1 Parent(s): 358710a

image: Refac B/F. #2

Browse files
Files changed (1) hide show
  1. assets/plugins/imageGenerator.js +229 -169
assets/plugins/imageGenerator.js CHANGED
@@ -22,8 +22,7 @@
22
  isConnecting = true;
23
  var protocol = window.location.protocol === 'https:'
24
  ? 'wss:' : 'ws:';
25
- var wsUrl = protocol + '//' +
26
- window.location.host;
27
 
28
  ws = new WebSocket(wsUrl);
29
 
@@ -76,36 +75,35 @@
76
  var handleWebSocketMessage = function(data) {
77
  if (!data || !data.type) return;
78
 
79
- switch(data.type) {
80
- case 'progressUpdate':
81
- updateProgressUI(data.progress);
82
- break;
83
-
84
- case 'generationStarted':
85
- showGeneratingUI();
86
- break;
87
-
88
- case 'generationComplete':
89
- handleGenerationComplete(data.images);
90
- break;
91
-
92
- case 'generationError':
93
- handleGenerationError(data.error);
94
- break;
95
-
96
- case 'generationCancelled':
97
- handleGenerationCancelled();
98
- break;
99
-
100
- case 'imageDeleted':
101
- handleImageDeleted(data.images);
102
- break;
103
  }
104
  };
105
 
106
  var updateProgressUI = function(progress) {
107
- var progressFill = document.querySelector('.progress-fill');
108
- var progressText = document.querySelector('.progress-text');
 
 
 
 
109
 
110
  if (progressFill) {
111
  progressFill.style.width = progress + '%';
@@ -117,46 +115,51 @@
117
  }
118
  };
119
 
 
 
 
 
 
 
 
 
 
 
 
120
  var showGeneratingUI = function() {
121
  var outputSection = document.querySelector(
122
  '.image-output-section'
123
  );
124
- var form = document.getElementById('generateForm');
125
- var inputs = form ?
126
- form.querySelectorAll('input, select, textarea') : [];
127
 
128
- Array.prototype.forEach.call(inputs, function(input) {
129
- input.disabled = true;
130
- });
131
 
132
  if (outputSection) {
133
  outputSection.classList.remove('has-images');
134
- outputSection.innerHTML =
135
- '<div class="loading-container">' +
136
- '<div class="loading-spinner" ' +
137
- 'style="margin: 0 auto 20px;"></div>' +
138
- '<p class="loading-text">Generating your image...</p>' +
139
- '<div class="progress-bar">' +
140
- '<div class="progress-fill" style="width: 0%;"></div>' +
141
- '</div>' +
142
- '<p class="progress-text">0% Complete</p>' +
143
- '</div>';
 
 
 
144
  }
145
 
146
  updateButtonsForGeneration(true);
147
  };
148
 
149
  var hideGeneratingUI = function() {
150
- var form = document.getElementById('generateForm');
151
- var inputs = form ?
152
- form.querySelectorAll('input, select, textarea') : [];
153
-
154
- Array.prototype.forEach.call(inputs, function(input) {
155
- input.disabled = false;
156
- });
157
-
158
  updateButtonsForGeneration(false);
159
- window.validateInputs && window.validateInputs();
 
 
 
160
  };
161
 
162
  var resetToInitialState = function() {
@@ -177,20 +180,59 @@
177
  if (!outputSection) return;
178
 
179
  outputSection.classList.remove('has-images');
180
- outputSection.innerHTML =
181
- '<svg class="placeholder-icon" width="80" height="80" ' +
182
- 'viewBox="0 0 24 24" fill="none">' +
183
- '<path d="M21 3H3C2 3 1 4 1 5V19C1 20 2 21 3 21H21C22 ' +
184
- '21 23 20 23 19V5C23 4 22 3 21 3ZM21 19H3V5H21V19Z" ' +
185
- 'fill="currentColor"/>' +
186
- '<path d="M4.5 16.5L9 12L11.5 14.5L16 10L19.5 13.5" ' +
187
- 'stroke="currentColor" stroke-width="1.5" ' +
188
- 'stroke-linecap="round"/>' +
189
- '<circle cx="8" cy="8.5" r="1.5" fill="currentColor"/>' +
190
- '</svg>' +
191
- '<p class="placeholder-text">' +
192
- 'No images generated yet. Start creating amazing visuals!' +
193
- '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  };
195
 
196
  var updateButtonsForGeneration = function(isGenerating) {
@@ -200,29 +242,10 @@
200
 
201
  if (!buttonsContainer) return;
202
 
203
- if (isGenerating) {
204
- buttonsContainer.innerHTML =
205
- '<button type="button" onclick="cancelGeneration()" ' +
206
- 'class="btn btn-danger">' +
207
- '<svg class="button-icon" viewBox="0 0 24 24" ' +
208
- 'fill="none">' +
209
- '<rect x="4" y="4" width="16" height="16" rx="3" ' +
210
- 'fill="currentColor"/>' +
211
- '</svg>' +
212
- 'Stop Generation' +
213
- '</button>';
214
- } else {
215
- buttonsContainer.innerHTML =
216
- '<button type="submit" id="submitBtn" disabled ' +
217
- 'class="btn btn-primary">' +
218
- '<svg class="button-icon" viewBox="0 0 24 24" ' +
219
- 'fill="none">' +
220
- '<path d="M3 20V4L22 12L3 20ZM5 17L16.85 12L5 7V10.5' +
221
- 'L11 12L5 13.5V17Z" fill="currentColor"/>' +
222
- '</svg>' +
223
- 'Generate Image' +
224
- '</button>';
225
- }
226
  };
227
 
228
  var handleGenerationComplete = function(images) {
@@ -245,6 +268,66 @@
245
  displayImages(currentImages);
246
  };
247
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
  var displayImages = function(images) {
249
  var outputSection = document.querySelector(
250
  '.image-output-section'
@@ -256,73 +339,38 @@
256
  showPlaceholder();
257
  } else {
258
  outputSection.classList.add('has-images');
259
- var html = '<div class="image-grid">';
260
 
261
  images.forEach(function(image, index) {
262
- html +=
263
- '<div class="image-card">' +
264
- '<img src="data:image/png;base64,' + image.base64 +
265
- '" alt="' + image.prompt + '">' +
266
- '<div class="image-actions">' +
267
- '<a href="data:image/png;base64,' + image.base64 +
268
- '" download="generated-' + image.id + '.png" ' +
269
- 'class="action-btn">' +
270
- '<svg class="action-icon" viewBox="0 0 24 24" ' +
271
- 'fill="none">' +
272
- '<path d="M12 16L7 11L8.4 9.55L11 12.15V4H13V12.15' +
273
- 'L15.6 9.55L17 11L12 16Z" fill="currentColor"/>' +
274
- '<path d="M4 20C3.45 20 2.98 19.8 2.59 19.41C2.2 ' +
275
- '19.02 2 18.55 2 18V15H4V18H20V15H22V18C22 18.55 ' +
276
- '21.8 19.02 21.41 19.41C21.02 19.8 20.55 20 20 20H4Z" ' +
277
- 'fill="currentColor"/>' +
278
- '</svg>' +
279
- '</a>' +
280
- '<button type="button" onclick="deleteImage(' +
281
- index + ')" class="action-btn">' +
282
- '<svg class="action-icon" viewBox="0 0 24 24" ' +
283
- 'fill="none">' +
284
- '<path d="M18.3 5.71C17.91 5.32 17.28 5.32 16.89 ' +
285
- '5.71L12 10.59L7.11 5.7C6.72 5.31 6.09 5.31 5.7 ' +
286
- '5.7C5.31 6.09 5.31 6.72 5.7 7.11L10.59 12L5.7 ' +
287
- '16.89C5.31 17.28 5.31 17.91 5.7 18.3C6.09 18.69 ' +
288
- '6.72 18.69 7.11 18.3L12 13.41L16.89 18.3C17.28 ' +
289
- '18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 ' +
290
- '17.28 18.3 16.89L13.41 12L18.3 7.11C18.68 6.73 ' +
291
- '18.68 6.09 18.3 5.71Z" fill="currentColor"/>' +
292
- '</svg>' +
293
- '</button>' +
294
- '</div>' +
295
- '<div class="image-info">' +
296
- '<p class="image-prompt">' + image.prompt + '</p>' +
297
- '<p class="image-meta">' +
298
- '<span class="image-model">' +
299
- image.model.toUpperCase() + '</span> | ' +
300
- image.size + '</p>' +
301
- '</div>' +
302
- '</div>';
303
  });
304
 
305
- html += '</div>';
306
- outputSection.innerHTML = html;
307
  }
308
  };
309
 
310
  var showErrorModal = function(error) {
311
- var existingModal = document.getElementById('errorModal');
 
 
 
312
  if (existingModal) existingModal.remove();
313
 
314
  var modal = document.createElement('div');
315
  modal.id = 'errorModal';
316
  modal.className = 'modal-overlay';
317
- modal.innerHTML =
318
- '<div class="modal-content modal-error-content">' +
319
- '<div class="modal-inner">' +
320
- '<h3 class="modal-error-title">Error</h3>' +
321
- '<p class="modal-error-text">' + error + '</p>' +
322
- '<button onclick="closeErrorModal()" ' +
323
- 'class="btn btn-primary w-full">OK</button>' +
324
- '</div>' +
325
- '</div>';
 
 
326
 
327
  document.body.appendChild(modal);
328
  };
@@ -338,9 +386,8 @@
338
  xhr.onload = function() {
339
  try {
340
  var response = JSON.parse(xhr.responseText);
341
- if (response.success) {
342
- currentImages = response.images || [];
343
- displayImages(currentImages);
344
  }
345
  } catch (e) {}
346
  };
@@ -357,30 +404,43 @@
357
  '.image-output-section'
358
  );
359
 
360
- if (outputSection && outputSection.classList.contains('has-images')) {
361
- var imageCards = outputSection.querySelectorAll('.image-card');
362
- if (imageCards && imageCards.length > 0) {
363
- currentImages = [];
364
- imageCards.forEach(function(card) {
365
- var img = card.querySelector('img');
366
- var prompt = card.querySelector('.image-prompt');
367
- var model = card.querySelector('.image-model');
368
- var meta = card.querySelector('.image-meta');
369
-
370
- if (img && img.src && img.src.includes('base64,')) {
371
- var base64 = img.src.split('base64,')[1];
372
- var size = meta ? meta.textContent.split('|')[1] : '';
373
- currentImages.push({
374
- id: 'existing-' + Math.random().toString(36).substring(2, 15),
375
- base64: base64,
376
- prompt: prompt ? prompt.textContent : '',
377
- model: model ? model.textContent.toLowerCase() : '',
378
- size: size ? size.trim() : ''
379
- });
380
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  });
382
  }
383
- }
384
  };
385
 
386
  connectWebSocket();
 
22
  isConnecting = true;
23
  var protocol = window.location.protocol === 'https:'
24
  ? 'wss:' : 'ws:';
25
+ var wsUrl = protocol + '//' + window.location.host;
 
26
 
27
  ws = new WebSocket(wsUrl);
28
 
 
75
  var handleWebSocketMessage = function(data) {
76
  if (!data || !data.type) return;
77
 
78
+ var handlers = {
79
+ 'progressUpdate': function() {
80
+ updateProgressUI(data.progress);
81
+ },
82
+ 'generationStarted': showGeneratingUI,
83
+ 'generationComplete': function() {
84
+ handleGenerationComplete(data.images);
85
+ },
86
+ 'generationError': function() {
87
+ handleGenerationError(data.error);
88
+ },
89
+ 'generationCancelled': handleGenerationCancelled,
90
+ 'imageDeleted': function() {
91
+ handleImageDeleted(data.images);
92
+ }
93
+ };
94
+
95
+ if (handlers[data.type]) {
96
+ handlers[data.type]();
 
 
 
 
 
97
  }
98
  };
99
 
100
  var updateProgressUI = function(progress) {
101
+ var progressFill = document.querySelector(
102
+ '.progress-fill'
103
+ );
104
+ var progressText = document.querySelector(
105
+ '.progress-text'
106
+ );
107
 
108
  if (progressFill) {
109
  progressFill.style.width = progress + '%';
 
115
  }
116
  };
117
 
118
+ var toggleFormInputs = function(disabled) {
119
+ var form = document.getElementById('generateForm');
120
+ var inputs = form ? form.querySelectorAll(
121
+ 'input, select, textarea'
122
+ ) : [];
123
+
124
+ Array.prototype.forEach.call(inputs, function(input) {
125
+ input.disabled = disabled;
126
+ });
127
+ };
128
+
129
  var showGeneratingUI = function() {
130
  var outputSection = document.querySelector(
131
  '.image-output-section'
132
  );
 
 
 
133
 
134
+ toggleFormInputs(true);
 
 
135
 
136
  if (outputSection) {
137
  outputSection.classList.remove('has-images');
138
+ outputSection.innerHTML = [
139
+ '<div class="loading-container">',
140
+ '<div class="loading-spinner" ',
141
+ 'style="margin: 0 auto 20px;"></div>',
142
+ '<p class="loading-text">',
143
+ 'Generating your image...</p>',
144
+ '<div class="progress-bar">',
145
+ '<div class="progress-fill" ',
146
+ 'style="width: 0%;"></div>',
147
+ '</div>',
148
+ '<p class="progress-text">0% Complete</p>',
149
+ '</div>'
150
+ ].join('');
151
  }
152
 
153
  updateButtonsForGeneration(true);
154
  };
155
 
156
  var hideGeneratingUI = function() {
157
+ toggleFormInputs(false);
 
 
 
 
 
 
 
158
  updateButtonsForGeneration(false);
159
+
160
+ if (window.validateInputs) {
161
+ window.validateInputs();
162
+ }
163
  };
164
 
165
  var resetToInitialState = function() {
 
180
  if (!outputSection) return;
181
 
182
  outputSection.classList.remove('has-images');
183
+ outputSection.innerHTML = [
184
+ '<svg class="placeholder-icon" ',
185
+ 'width="80" height="80" ',
186
+ 'viewBox="0 0 24 24" fill="none">',
187
+ '<path d="M21 3H3C2 3 1 4 1 5V19C1 20 2 21 ',
188
+ '3 21H21C22 21 23 20 23 19V5C23 4 22 3 21 3Z',
189
+ 'M21 19H3V5H21V19Z" fill="currentColor"/>',
190
+ '<path d="M4.5 16.5L9 12L11.5 14.5L16 10L',
191
+ '19.5 13.5" stroke="currentColor" ',
192
+ 'stroke-width="1.5" stroke-linecap="round"/>',
193
+ '<circle cx="8" cy="8.5" r="1.5" ',
194
+ 'fill="currentColor"/>',
195
+ '</svg>',
196
+ '<p class="placeholder-text">',
197
+ 'No images generated yet. ',
198
+ 'Start creating amazing visuals!',
199
+ '</p>'
200
+ ].join('');
201
+ };
202
+
203
+ var createButton = function(type, isGenerating) {
204
+ var icons = {
205
+ stop: '<rect x="4" y="4" width="16" height="16" ' +
206
+ 'rx="3" fill="currentColor"/>',
207
+ play: '<path d="M3 20V4L22 12L3 20ZM5 17L16.85 ' +
208
+ '12L5 7V10.5L11 12L5 13.5V17Z" ' +
209
+ 'fill="currentColor"/>'
210
+ };
211
+
212
+ if (isGenerating) {
213
+ return [
214
+ '<button type="button" ',
215
+ 'onclick="cancelGeneration()" ',
216
+ 'class="btn btn-danger">',
217
+ '<svg class="button-icon" viewBox="0 0 24 24" ',
218
+ 'fill="none">',
219
+ icons.stop,
220
+ '</svg>',
221
+ 'Stop Generation',
222
+ '</button>'
223
+ ].join('');
224
+ }
225
+
226
+ return [
227
+ '<button type="submit" id="submitBtn" disabled ',
228
+ 'class="btn btn-primary">',
229
+ '<svg class="button-icon" viewBox="0 0 24 24" ',
230
+ 'fill="none">',
231
+ icons.play,
232
+ '</svg>',
233
+ 'Generate Image',
234
+ '</button>'
235
+ ].join('');
236
  };
237
 
238
  var updateButtonsForGeneration = function(isGenerating) {
 
242
 
243
  if (!buttonsContainer) return;
244
 
245
+ buttonsContainer.innerHTML = createButton(
246
+ isGenerating ? 'stop' : 'play',
247
+ isGenerating
248
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  };
250
 
251
  var handleGenerationComplete = function(images) {
 
268
  displayImages(currentImages);
269
  };
270
 
271
+ var createImageCard = function(image, index) {
272
+ var downloadIcon = [
273
+ '<path d="M12 16L7 11L8.4 9.55L11 12.15V4H13',
274
+ 'V12.15L15.6 9.55L17 11L12 16Z" ',
275
+ 'fill="currentColor"/>',
276
+ '<path d="M4 20C3.45 20 2.98 19.8 2.59 19.41',
277
+ 'C2.2 19.02 2 18.55 2 18V15H4V18H20V15H22V18',
278
+ 'C22 18.55 21.8 19.02 21.41 19.41C21.02 19.8 ',
279
+ '20.55 20 20 20H4Z" fill="currentColor"/>'
280
+ ].join('');
281
+
282
+ var deleteIcon = [
283
+ '<path d="M18.3 5.71C17.91 5.32 17.28 5.32 ',
284
+ '16.89 5.71L12 10.59L7.11 5.7C6.72 5.31 6.09 ',
285
+ '5.31 5.7 5.7C5.31 6.09 5.31 6.72 5.7 7.11',
286
+ 'L10.59 12L5.7 16.89C5.31 17.28 5.31 17.91 ',
287
+ '5.7 18.3C6.09 18.69 6.72 18.69 7.11 18.3L12 ',
288
+ '13.41L16.89 18.3C17.28 18.69 17.91 18.69 ',
289
+ '18.3 18.3C18.69 17.91 18.69 17.28 18.3 ',
290
+ '16.89L13.41 12L18.3 7.11C18.68 6.73 18.68 ',
291
+ '6.09 18.3 5.71Z" fill="currentColor"/>'
292
+ ].join('');
293
+
294
+ return [
295
+ '<div class="image-card">',
296
+ '<img src="data:image/png;base64,',
297
+ image.base64,
298
+ '" alt="', image.prompt, '">',
299
+ '<div class="image-actions">',
300
+ '<a href="data:image/png;base64,',
301
+ image.base64,
302
+ '" download="generated-', image.id, '.png" ',
303
+ 'class="action-btn">',
304
+ '<svg class="action-icon" viewBox="0 0 24 24" ',
305
+ 'fill="none">',
306
+ downloadIcon,
307
+ '</svg>',
308
+ '</a>',
309
+ '<button type="button" onclick="deleteImage(',
310
+ index,
311
+ ')" class="action-btn">',
312
+ '<svg class="action-icon" viewBox="0 0 24 24" ',
313
+ 'fill="none">',
314
+ deleteIcon,
315
+ '</svg>',
316
+ '</button>',
317
+ '</div>',
318
+ '<div class="image-info">',
319
+ '<p class="image-prompt">', image.prompt, '</p>',
320
+ '<p class="image-meta">',
321
+ '<span class="image-model">',
322
+ image.model.toUpperCase(),
323
+ '</span> | ',
324
+ image.size,
325
+ '</p>',
326
+ '</div>',
327
+ '</div>'
328
+ ].join('');
329
+ };
330
+
331
  var displayImages = function(images) {
332
  var outputSection = document.querySelector(
333
  '.image-output-section'
 
339
  showPlaceholder();
340
  } else {
341
  outputSection.classList.add('has-images');
342
+ var html = ['<div class="image-grid">'];
343
 
344
  images.forEach(function(image, index) {
345
+ html.push(createImageCard(image, index));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  });
347
 
348
+ html.push('</div>');
349
+ outputSection.innerHTML = html.join('');
350
  }
351
  };
352
 
353
  var showErrorModal = function(error) {
354
+ var existingModal = document.getElementById(
355
+ 'errorModal'
356
+ );
357
+
358
  if (existingModal) existingModal.remove();
359
 
360
  var modal = document.createElement('div');
361
  modal.id = 'errorModal';
362
  modal.className = 'modal-overlay';
363
+ modal.innerHTML = [
364
+ '<div class="modal-content ',
365
+ 'modal-error-content">',
366
+ '<div class="modal-inner">',
367
+ '<h3 class="modal-error-title">Error</h3>',
368
+ '<p class="modal-error-text">', error, '</p>',
369
+ '<button onclick="closeErrorModal()" ',
370
+ 'class="btn btn-primary w-full">OK</button>',
371
+ '</div>',
372
+ '</div>'
373
+ ].join('');
374
 
375
  document.body.appendChild(modal);
376
  };
 
386
  xhr.onload = function() {
387
  try {
388
  var response = JSON.parse(xhr.responseText);
389
+ if (!response.success && response.error) {
390
+ showErrorModal(response.error);
 
391
  }
392
  } catch (e) {}
393
  };
 
404
  '.image-output-section'
405
  );
406
 
407
+ if (!outputSection ||
408
+ !outputSection.classList.contains('has-images')) {
409
+ return;
410
+ }
411
+
412
+ var imageCards = outputSection.querySelectorAll(
413
+ '.image-card'
414
+ );
415
+
416
+ if (!imageCards || imageCards.length === 0) return;
417
+
418
+ currentImages = [];
419
+
420
+ imageCards.forEach(function(card) {
421
+ var img = card.querySelector('img');
422
+ var prompt = card.querySelector('.image-prompt');
423
+ var model = card.querySelector('.image-model');
424
+ var meta = card.querySelector('.image-meta');
425
+
426
+ if (img && img.src && img.src.includes('base64,')) {
427
+ var base64 = img.src.split('base64,')[1];
428
+ var size = meta
429
+ ? meta.textContent.split('|')[1]
430
+ : '';
431
+
432
+ currentImages.push({
433
+ id: 'existing-' + Math.random()
434
+ .toString(36).substring(2, 15),
435
+ base64: base64,
436
+ prompt: prompt ? prompt.textContent : '',
437
+ model: model
438
+ ? model.textContent.toLowerCase()
439
+ : '',
440
+ size: size ? size.trim() : ''
441
  });
442
  }
443
+ });
444
  };
445
 
446
  connectWebSocket();