Skip to content

Commit ab3d2a9

Browse files
GiteaBotwxiaoguang
andauthored
Fix form property assignment edge case (#35073) (#35078)
Backport #35073 by wxiaoguang Co-authored-by: wxiaoguang <[email protected]>
1 parent 12bfa9e commit ab3d2a9

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

web_src/js/features/common-button.test.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
1-
import {assignElementProperty} from './common-button.ts';
1+
import {assignElementProperty, type ElementWithAssignableProperties} from './common-button.ts';
22

33
test('assignElementProperty', () => {
44
const elForm = document.createElement('form');
55
assignElementProperty(elForm, 'action', '/test-link');
66
expect(elForm.action).contains('/test-link'); // the DOM always returns absolute URL
7+
expect(elForm.getAttribute('action')).eq('/test-link');
78
assignElementProperty(elForm, 'text-content', 'dummy');
89
expect(elForm.textContent).toBe('dummy');
910

11+
// mock a form with its property "action" overwritten by an input element
12+
const elFormWithAction = new class implements ElementWithAssignableProperties {
13+
action = document.createElement('input'); // now "form.action" is not string, but an input element
14+
_attrs: Record<string, string> = {};
15+
setAttribute(name: string, value: string) { this._attrs[name] = value }
16+
getAttribute(name: string): string | null { return this._attrs[name] }
17+
}();
18+
assignElementProperty(elFormWithAction, 'action', '/bar');
19+
expect(elFormWithAction.getAttribute('action')).eq('/bar');
20+
1021
const elInput = document.createElement('input');
1122
expect(elInput.readOnly).toBe(false);
1223
assignElementProperty(elInput, 'read-only', 'true');

web_src/js/features/common-button.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,26 @@ function onHidePanelClick(el: HTMLElement, e: MouseEvent) {
102102
throw new Error('no panel to hide'); // should never happen, otherwise there is a bug in code
103103
}
104104

105-
export function assignElementProperty(el: any, name: string, val: string) {
106-
name = camelize(name);
107-
const old = el[name];
105+
export type ElementWithAssignableProperties = {
106+
getAttribute: (name: string) => string | null;
107+
setAttribute: (name: string, value: string) => void;
108+
} & Record<string, any>
109+
110+
export function assignElementProperty(el: ElementWithAssignableProperties, kebabName: string, val: string) {
111+
const camelizedName = camelize(kebabName);
112+
const old = el[camelizedName];
108113
if (typeof old === 'boolean') {
109-
el[name] = val === 'true';
114+
el[camelizedName] = val === 'true';
110115
} else if (typeof old === 'number') {
111-
el[name] = parseFloat(val);
116+
el[camelizedName] = parseFloat(val);
112117
} else if (typeof old === 'string') {
113-
el[name] = val;
118+
el[camelizedName] = val;
119+
} else if (old?.nodeName) {
120+
// "form" has an edge case: its "<input name=action>" element overwrites the "action" property, we can only set attribute
121+
el.setAttribute(kebabName, val);
114122
} else {
115123
// in the future, we could introduce a better typing system like `data-modal-form.action:string="..."`
116-
throw new Error(`cannot assign element property ${name} by value ${val}`);
124+
throw new Error(`cannot assign element property "${camelizedName}" by value "${val}"`);
117125
}
118126
}
119127

0 commit comments

Comments
 (0)