refactor: share instant action binding
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
setTextIfChanged,
|
||||
syncElementAttributes,
|
||||
} from '../web/resolver/utils/dom_patch_utils.js';
|
||||
import * as domPatchUtils from '../web/resolver/utils/dom_patch_utils.js';
|
||||
|
||||
const projectRoot = path.resolve(import.meta.dirname, '..');
|
||||
const resolveDownloadMethodsSource = fs.readFileSync(
|
||||
@@ -92,6 +93,29 @@ test('shared DOM helpers synchronize attributes, text, and one-time listeners',
|
||||
assert.equal(clicks, 1);
|
||||
});
|
||||
|
||||
test('instant actions handle pointer and click as one idempotent action', () => {
|
||||
assert.equal(typeof domPatchUtils.bindInstantAction, 'function');
|
||||
|
||||
const window = new Window();
|
||||
const button = window.document.createElement('button');
|
||||
let calls = 0;
|
||||
const events = [];
|
||||
|
||||
assert.equal(domPatchUtils.bindInstantAction(button, event => {
|
||||
calls += 1;
|
||||
events.push(event.type);
|
||||
}), true);
|
||||
assert.equal(domPatchUtils.bindInstantAction(button, () => {
|
||||
calls += 100;
|
||||
}), false);
|
||||
|
||||
button.dispatchEvent(new window.Event('pointerdown', { bubbles: true, cancelable: true }));
|
||||
button.dispatchEvent(new window.Event('click', { bubbles: true, cancelable: true }));
|
||||
|
||||
assert.equal(calls, 1);
|
||||
assert.deepEqual(events, ['pointerdown']);
|
||||
});
|
||||
|
||||
function createDialog(window) {
|
||||
return {
|
||||
syncSearchElementAttributes,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { app } from "../../../../../scripts/app.js";
|
||||
import { $el } from "../../../../../scripts/ui.js";
|
||||
import { getSvgIcon } from "../../utils/icon_utils.js";
|
||||
import { startSplitterDrag } from "../utils/splitter_drag.js";
|
||||
import { syncElementAttributes } from "../utils/dom_patch_utils.js";
|
||||
import { bindInstantAction, syncElementAttributes } from "../utils/dom_patch_utils.js";
|
||||
const FOOTER_VERSION_REFRESH_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
||||
const FOOTER_VERSION_FAILURE_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
|
||||
|
||||
@@ -1115,26 +1115,6 @@ export const queueMethods = {
|
||||
},
|
||||
|
||||
wireDownloadsPanelControls() {
|
||||
const bindInstantAction = (button, handler) => {
|
||||
if (!button || button._hasListener) return;
|
||||
button._hasListener = true;
|
||||
const run = (event) => {
|
||||
event?.preventDefault?.();
|
||||
event?.stopPropagation?.();
|
||||
if (button.disabled) return;
|
||||
if (event?.type === 'click' && button._handledPointerAction) {
|
||||
button._handledPointerAction = false;
|
||||
return;
|
||||
}
|
||||
if (event?.type === 'pointerdown') {
|
||||
button._handledPointerAction = true;
|
||||
}
|
||||
handler();
|
||||
};
|
||||
button.addEventListener('pointerdown', run);
|
||||
button.addEventListener('click', run);
|
||||
};
|
||||
|
||||
const getDownloadContext = (button) => {
|
||||
const downloadId = button?.dataset?.downloadId || '';
|
||||
const info = this.activeDownloads?.[downloadId];
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getModelCardUrl, parseHuggingFaceFileUrl } from "../utils/url_utils.js"
|
||||
import { getCivitaiModelUrl } from "../globals.js";
|
||||
import { normalizeSha256 } from "../utils/hash_utils.js";
|
||||
import { normalizePathIdentity } from "../utils/html_utils.js";
|
||||
import { bindEventOnce, syncElementAttributes } from "../utils/dom_patch_utils.js";
|
||||
import { bindEventOnce, bindInstantAction, syncElementAttributes } from "../utils/dom_patch_utils.js";
|
||||
const log = createModuleLogger('resolve_download_methods');
|
||||
|
||||
export const resolveDownloadMethods = {
|
||||
@@ -1108,25 +1108,6 @@ export const resolveDownloadMethods = {
|
||||
|
||||
attachDownloadActionHandlers(progressDiv, downloadId) {
|
||||
if (!progressDiv) return;
|
||||
const bindInstantAction = (button, handler) => {
|
||||
if (!button || button._hasListener) return;
|
||||
button._hasListener = true;
|
||||
const run = (event) => {
|
||||
event?.preventDefault?.();
|
||||
event?.stopPropagation?.();
|
||||
if (button.disabled) return;
|
||||
if (event?.type === 'click' && button._handledPointerAction) {
|
||||
button._handledPointerAction = false;
|
||||
return;
|
||||
}
|
||||
if (event?.type === 'pointerdown') {
|
||||
button._handledPointerAction = true;
|
||||
}
|
||||
handler(event);
|
||||
};
|
||||
button.addEventListener('pointerdown', run);
|
||||
button.addEventListener('click', run);
|
||||
};
|
||||
progressDiv.querySelectorAll('.cancel-download-btn, .cancel-download-btn-pending, .mr-download-queue-cancel').forEach(cancelBtn => {
|
||||
bindInstantAction(cancelBtn, () => {
|
||||
const targetDownloadId = cancelBtn.dataset.downloadId || downloadId;
|
||||
|
||||
@@ -42,3 +42,24 @@ export function bindEventOnce(element, eventName, handler, key = eventName) {
|
||||
element.addEventListener(eventName, handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function bindInstantAction(button, handler) {
|
||||
if (!button || button._hasListener) return false;
|
||||
button._hasListener = true;
|
||||
const run = (event) => {
|
||||
event?.preventDefault?.();
|
||||
event?.stopPropagation?.();
|
||||
if (button.disabled) return;
|
||||
if (event?.type === 'click' && button._handledPointerAction) {
|
||||
button._handledPointerAction = false;
|
||||
return;
|
||||
}
|
||||
if (event?.type === 'pointerdown') {
|
||||
button._handledPointerAction = true;
|
||||
}
|
||||
handler(event);
|
||||
};
|
||||
button.addEventListener('pointerdown', run);
|
||||
button.addEventListener('click', run);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user