Skip to content

Commit d05bc3a

Browse files
committed
refactor: centralize modal creation and reduce canvas duplication
1 parent 2b2278b commit d05bc3a

8 files changed

Lines changed: 275 additions & 119 deletions

js/canvas/resolution_master_canvas_methods.js

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -194,56 +194,55 @@ export const canvasMethods = {
194194
);
195195
},
196196

197-
updateCanvasValueWidth(x, w, ctrlKey) {
198-
const diagnosticsToken = performanceDiagnostics.start("updateCanvasValueWidth");
197+
updateCanvasValueDimension(axis, coord, size, ctrlKey) {
198+
const axisUpper = axis.toUpperCase();
199+
const diagnosticsToken = performanceDiagnostics.start(`updateCanvasValueDimension${axisUpper}`);
199200
try {
200201
const node = this.node;
201202
const props = node.properties;
203+
const isX = axis === 'x';
204+
205+
let val = isX ? coord / size : 1 - coord / size;
206+
val = Math.max(0, Math.min(1, val));
202207

203-
let vX = Math.max(0, Math.min(1, x / w));
204208
if (!ctrlKey) {
205-
let sX = props.canvas_step_x / (props.canvas_max_x - props.canvas_min_x);
206-
vX = Math.round(vX / sX) * sX;
209+
const step = props[`canvas_step_${axis}`];
210+
const min = props[`canvas_min_${axis}`];
211+
const max = props[`canvas_max_${axis}`];
212+
const range = max - min;
213+
const stepScale = step / range;
214+
val = Math.round(val / stepScale) * stepScale;
207215
}
208216

209-
node.intpos.x = vX;
217+
node.intpos[axis] = val;
210218

211-
let newX = props.canvas_min_x + (props.canvas_max_x - props.canvas_min_x) * vX;
219+
const min = props[`canvas_min_${axis}`];
220+
const max = props[`canvas_max_${axis}`];
221+
let newVal = min + (max - min) * val;
212222

213-
const rnX = Math.pow(10, props.canvas_decimals_x);
214-
newX = Math.round(rnX * newX) / rnX;
215-
if (props.valueX !== newX) {
216-
this.setDimensions(newX, this.heightWidget.value, { syncPosition: false });
223+
const decimals = props[`canvas_decimals_${axis}`];
224+
const rn = Math.pow(10, decimals);
225+
newVal = Math.round(rn * newVal) / rn;
226+
227+
const propName = isX ? 'valueX' : 'valueY';
228+
if (props[propName] !== newVal) {
229+
if (isX) {
230+
this.setDimensions(newVal, this.heightWidget.value, { syncPosition: false });
231+
} else {
232+
this.setDimensions(this.widthWidget.value, newVal, { syncPosition: false });
233+
}
217234
}
218235
} finally {
219236
performanceDiagnostics.end(diagnosticsToken);
220237
}
221238
},
222239

223-
updateCanvasValueHeight(y, h, ctrlKey) {
224-
const diagnosticsToken = performanceDiagnostics.start("updateCanvasValueHeight");
225-
try {
226-
const node = this.node;
227-
const props = node.properties;
228-
229-
let vY = Math.max(0, Math.min(1, 1 - y / h));
230-
if (!ctrlKey) {
231-
let sY = props.canvas_step_y / (props.canvas_max_y - props.canvas_min_y);
232-
vY = Math.round(vY / sY) * sY;
233-
}
234-
235-
node.intpos.y = vY;
236-
237-
let newY = props.canvas_min_y + (props.canvas_max_y - props.canvas_min_y) * vY;
240+
updateCanvasValueWidth(x, w, ctrlKey) {
241+
this.updateCanvasValueDimension('x', x, w, ctrlKey);
242+
},
238243

239-
const rnY = Math.pow(10, props.canvas_decimals_y);
240-
newY = Math.round(rnY * newY) / rnY;
241-
if (props.valueY !== newY) {
242-
this.setDimensions(this.widthWidget.value, newY, { syncPosition: false });
243-
}
244-
} finally {
245-
performanceDiagnostics.end(diagnosticsToken);
246-
}
244+
updateCanvasValueHeight(y, h, ctrlKey) {
245+
this.updateCanvasValueDimension('y', y, h, ctrlKey);
247246
},
248247

249248
isPointInControl(x, y, control) {

js/dialogs/custom_value_dialog_manager.js

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// custom_value_dialog_manager.js - Manages custom value input dialogs for ResolutionMaster
22
import { createModuleLogger } from "../log_system/log_funcs.js";
3+
import { createModalWrapper } from "../utils/dialog_helper.js";
34

45
const log = createModuleLogger('custom_value_dialog_manager');
56

@@ -10,6 +11,7 @@ export class CustomValueDialogManager {
1011
this.customInputDialog = null;
1112
this.customInputOverlay = null;
1213
this.inputDialogActive = false;
14+
this.closeWrapper = null;
1315
}
1416

1517
/**
@@ -83,28 +85,32 @@ export class CustomValueDialogManager {
8385
this.inputDialogActive = true;
8486
log.debug(`Creating dialog for ${valueType}, current: ${currentValue}`);
8587

86-
// Create overlay
87-
const overlay = document.createElement('div');
88-
this.customInputOverlay = overlay;
89-
overlay.style.cssText = `
90-
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
91-
background: rgba(0,0,0,0.5); z-index: 9999;
92-
`;
93-
overlay.addEventListener('mousedown', () => this.closeCustomInputDialog());
94-
document.body.appendChild(overlay);
88+
// Create overlay and dialog container via dialog_helper
89+
const wrapper = createModalWrapper({
90+
className: 'litegraph-custom-input-dialog',
91+
overlayStyle: `
92+
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
93+
background: rgba(0,0,0,0.5); z-index: 9999;
94+
`,
95+
dialogStyle: `
96+
position: fixed;
97+
background: linear-gradient(135deg, #2a2a2a 0%, #1e1e1e 100%);
98+
border: 2px solid #555; border-radius: 8px; padding: 20px;
99+
box-shadow: 0 8px 32px rgba(0,0,0,0.8); z-index: 10000;
100+
font-family: Arial, sans-serif; min-width: 280px;
101+
`,
102+
onClose: () => {
103+
this.customInputDialog = null;
104+
this.customInputOverlay = null;
105+
this.inputDialogActive = false;
106+
this.closeWrapper = null;
107+
}
108+
});
95109

96-
// Create dialog container
97-
const dialog = document.createElement('div');
98-
this.customInputDialog = dialog;
99-
dialog.className = 'litegraph-custom-input-dialog';
100-
dialog.addEventListener('mousedown', (e) => e.stopPropagation()); // Prevent clicks inside from closing
101-
dialog.style.cssText = `
102-
position: fixed;
103-
background: linear-gradient(135deg, #2a2a2a 0%, #1e1e1e 100%);
104-
border: 2px solid #555; border-radius: 8px; padding: 20px;
105-
box-shadow: 0 8px 32px rgba(0,0,0,0.8); z-index: 10000;
106-
font-family: Arial, sans-serif; min-width: 280px;
107-
`;
110+
this.customInputOverlay = wrapper.overlay;
111+
this.customInputDialog = wrapper.dialog;
112+
this.closeWrapper = wrapper.close;
113+
const dialog = wrapper.dialog;
108114

109115
// Position dialog
110116
const x = e.clientX ? e.clientX + 20 : (window.innerWidth - 280) / 2;
@@ -129,8 +135,6 @@ export class CustomValueDialogManager {
129135
</div>
130136
`;
131137

132-
document.body.appendChild(dialog);
133-
134138
// Get elements
135139
const input = dialog.querySelector('#customValueInput');
136140
const validationMsg = dialog.querySelector('#validationMessage');
@@ -222,15 +226,20 @@ export class CustomValueDialogManager {
222226
* Closes and cleans up the custom input dialog
223227
*/
224228
closeCustomInputDialog() {
225-
if (this.customInputDialog) {
226-
document.body.removeChild(this.customInputDialog);
227-
this.customInputDialog = null;
228-
}
229-
if (this.customInputOverlay) {
230-
document.body.removeChild(this.customInputOverlay);
231-
this.customInputOverlay = null;
229+
if (this.closeWrapper) {
230+
this.closeWrapper();
231+
this.closeWrapper = null;
232+
} else {
233+
if (this.customInputDialog) {
234+
document.body.removeChild(this.customInputDialog);
235+
this.customInputDialog = null;
236+
}
237+
if (this.customInputOverlay) {
238+
document.body.removeChild(this.customInputOverlay);
239+
this.customInputOverlay = null;
240+
}
241+
this.inputDialogActive = false;
232242
}
233-
this.inputDialogActive = false;
234243
}
235244

236245
/**

js/presets/preset_manager/json_editor_dialog.js

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { TooltipManager } from './tooltip_manager.js';
44
import { presetManagerTooltips } from '../../config/resolution_master_tooltips.js';
55
import { createModuleLogger } from "../../log_system/log_funcs.js";
6+
import { createModalWrapper } from "../../utils/dialog_helper.js";
67

78
const log = createModuleLogger('json_editor_dialog');
89

@@ -25,13 +26,14 @@ export class JSONEditorDialog {
2526
jsonLength: currentJSON.length
2627
});
2728

28-
// Create overlay
29-
const overlay = document.createElement('div');
30-
overlay.className = 'resolution-master-json-editor-overlay';
31-
32-
// Create dialog container
33-
const dialog = document.createElement('div');
34-
dialog.className = 'resolution-master-json-editor-dialog';
29+
// Create overlay and dialog container via dialog_helper
30+
const wrapper = createModalWrapper({
31+
className: 'resolution-master-json-editor-dialog',
32+
overlayClassName: 'resolution-master-json-editor-overlay',
33+
clickAwayToClose: false
34+
});
35+
const overlay = wrapper.overlay;
36+
const dialog = wrapper.dialog;
3537

3638
// Create tooltip manager
3739
const tooltipManager = new TooltipManager({
@@ -50,8 +52,7 @@ export class JSONEditorDialog {
5052
this.editor = null;
5153
}
5254
tooltipManager.destroy();
53-
document.body.removeChild(overlay);
54-
document.body.removeChild(dialog);
55+
wrapper.close();
5556
});
5657
dialog.appendChild(header);
5758

@@ -151,15 +152,10 @@ export class JSONEditorDialog {
151152
this.editor = null;
152153
}
153154
tooltipManager.destroy();
154-
document.body.removeChild(overlay);
155-
document.body.removeChild(dialog);
155+
wrapper.close();
156156
});
157157
dialog.appendChild(footer);
158158

159-
// Add to DOM
160-
document.body.appendChild(overlay);
161-
document.body.appendChild(dialog);
162-
163159
// Attach tooltips to buttons (after adding to DOM)
164160
const closeBtn = dialog.querySelector('#json-editor-close-btn');
165161
const cancelBtn = dialog.querySelector('#json-editor-cancel-btn');

js/presets/preset_manager/preset_add_view_renderer.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { AspectRatioUtils } from "../aspect_ratio_utils.js";
44
import { getIconHtml } from "../../utils/icon_utils.js";
5+
import { aspectRatioString } from "../../canvas/aspect_ratio_math.js";
56

67
/**
78
* Renderer for the add/edit preset view
@@ -386,14 +387,11 @@ export class PresetAddViewRenderer {
386387
previewShape.style.border = `2px solid ${borderColor}`;
387388
previewShape.style.background = bgColor;
388389

389-
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
390-
const divisor = gcd(width, height);
391-
const ratioW = width / divisor;
392-
const ratioH = height / divisor;
390+
const ratioStr = aspectRatioString(width, height);
393391

394392
previewText.innerHTML = `
395393
<div style="color: ${textColor};">${width}×${height}</div>
396-
<div style="font-size: 10px; color: #888;">${ratioW}:${ratioH}</div>
394+
<div style="font-size: 10px; color: #888;">${ratioStr}</div>
397395
`;
398396

399397
if (previewCanvas.parentElement) {

js/presets/preset_manager/preset_manager_dialog.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { JSONEditorDialog } from './json_editor_dialog.js';
1818
import { PresetListRenderer } from './preset_list_renderer.js';
1919
import { PresetAddViewRenderer } from './preset_add_view_renderer.js';
2020
import { TooltipManager } from './tooltip_manager.js';
21+
import { createModalWrapper } from "../../utils/dialog_helper.js";
2122

2223
const log = createModuleLogger('preset_manager_dialog');
2324

@@ -146,18 +147,19 @@ export class PresetManagerDialog {
146147
this.selectedPresetsForDeletion.clear(); // Clear selection when opening dialog
147148
this.lastClickedPresetKey = null; // Reset last clicked for shift-click
148149

149-
// Create overlay
150-
this.overlay = document.createElement('div');
151-
this.overlay.className = 'resolution-master-preset-manager-overlay';
150+
// Create overlay and container via dialog_helper
151+
const wrapper = createModalWrapper({
152+
className: 'resolution-master-preset-manager-dialog',
153+
overlayClassName: 'resolution-master-preset-manager-overlay',
154+
clickAwayToClose: false // Manual overlay click check below
155+
});
156+
this.overlay = wrapper.overlay;
157+
this.container = wrapper.dialog;
158+
this.closeWrapper = wrapper.close;
159+
152160
this.overlay.addEventListener('mousedown', (e) => {
153161
if (e.target === this.overlay) this.hide();
154162
});
155-
document.body.appendChild(this.overlay);
156-
157-
// Create container
158-
this.container = document.createElement('div');
159-
this.container.className = 'resolution-master-preset-manager-dialog';
160-
document.body.appendChild(this.container);
161163

162164
this.renderDialog();
163165
}
@@ -846,11 +848,16 @@ export class PresetManagerDialog {
846848
this.registerTooltips();
847849
}
848850

849-
if (this.container && this.container.parentNode) {
850-
document.body.removeChild(this.container);
851-
}
852-
if (this.overlay && this.overlay.parentNode) {
853-
document.body.removeChild(this.overlay);
851+
if (this.closeWrapper) {
852+
this.closeWrapper();
853+
this.closeWrapper = null;
854+
} else {
855+
if (this.container && this.container.parentNode) {
856+
document.body.removeChild(this.container);
857+
}
858+
if (this.overlay && this.overlay.parentNode) {
859+
document.body.removeChild(this.overlay);
860+
}
854861
}
855862

856863
this.container = null;

0 commit comments

Comments
 (0)