mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-31 19:38:23 +00:00 
			
		
		
		
	Fix form property assignment edge case (#35073)
"form" has an edge case: its `<input name=action>` element overwrites the `action` property, we can only set attribute. This PR makes `assignElementProperty` can handle such case, and add more tests
This commit is contained in:
		| @@ -1,12 +1,23 @@ | |||||||
| import {assignElementProperty} from './common-button.ts'; | import {assignElementProperty, type ElementWithAssignableProperties} from './common-button.ts'; | ||||||
|  |  | ||||||
| test('assignElementProperty', () => { | test('assignElementProperty', () => { | ||||||
|   const elForm = document.createElement('form'); |   const elForm = document.createElement('form'); | ||||||
|   assignElementProperty(elForm, 'action', '/test-link'); |   assignElementProperty(elForm, 'action', '/test-link'); | ||||||
|   expect(elForm.action).contains('/test-link'); // the DOM always returns absolute URL |   expect(elForm.action).contains('/test-link'); // the DOM always returns absolute URL | ||||||
|  |   expect(elForm.getAttribute('action')).eq('/test-link'); | ||||||
|   assignElementProperty(elForm, 'text-content', 'dummy'); |   assignElementProperty(elForm, 'text-content', 'dummy'); | ||||||
|   expect(elForm.textContent).toBe('dummy'); |   expect(elForm.textContent).toBe('dummy'); | ||||||
|  |  | ||||||
|  |   // mock a form with its property "action" overwritten by an input element | ||||||
|  |   const elFormWithAction = new class implements ElementWithAssignableProperties { | ||||||
|  |     action = document.createElement('input'); // now "form.action" is not string, but an input element | ||||||
|  |     _attrs: Record<string, string> = {}; | ||||||
|  |     setAttribute(name: string, value: string) { this._attrs[name] = value } | ||||||
|  |     getAttribute(name: string): string | null { return this._attrs[name] } | ||||||
|  |   }(); | ||||||
|  |   assignElementProperty(elFormWithAction, 'action', '/bar'); | ||||||
|  |   expect(elFormWithAction.getAttribute('action')).eq('/bar'); | ||||||
|  |  | ||||||
|   const elInput = document.createElement('input'); |   const elInput = document.createElement('input'); | ||||||
|   expect(elInput.readOnly).toBe(false); |   expect(elInput.readOnly).toBe(false); | ||||||
|   assignElementProperty(elInput, 'read-only', 'true'); |   assignElementProperty(elInput, 'read-only', 'true'); | ||||||
|   | |||||||
| @@ -109,18 +109,26 @@ function onHidePanelClick(el: HTMLElement, e: MouseEvent) { | |||||||
|   throw new Error('no panel to hide'); // should never happen, otherwise there is a bug in code |   throw new Error('no panel to hide'); // should never happen, otherwise there is a bug in code | ||||||
| } | } | ||||||
|  |  | ||||||
| export function assignElementProperty(el: any, name: string, val: string) { | export type ElementWithAssignableProperties = { | ||||||
|   name = camelize(name); |   getAttribute: (name: string) => string | null; | ||||||
|   const old = el[name]; |   setAttribute: (name: string, value: string) => void; | ||||||
|  | } & Record<string, any> | ||||||
|  |  | ||||||
|  | export function assignElementProperty(el: ElementWithAssignableProperties, kebabName: string, val: string) { | ||||||
|  |   const camelizedName = camelize(kebabName); | ||||||
|  |   const old = el[camelizedName]; | ||||||
|   if (typeof old === 'boolean') { |   if (typeof old === 'boolean') { | ||||||
|     el[name] = val === 'true'; |     el[camelizedName] = val === 'true'; | ||||||
|   } else if (typeof old === 'number') { |   } else if (typeof old === 'number') { | ||||||
|     el[name] = parseFloat(val); |     el[camelizedName] = parseFloat(val); | ||||||
|   } else if (typeof old === 'string') { |   } else if (typeof old === 'string') { | ||||||
|     el[name] = val; |     el[camelizedName] = val; | ||||||
|  |   } else if (old?.nodeName) { | ||||||
|  |     // "form" has an edge case: its "<input name=action>" element overwrites the "action" property, we can only set attribute | ||||||
|  |     el.setAttribute(kebabName, val); | ||||||
|   } else { |   } else { | ||||||
|     // in the future, we could introduce a better typing system like `data-modal-form.action:string="..."` |     // in the future, we could introduce a better typing system like `data-modal-form.action:string="..."` | ||||||
|     throw new Error(`cannot assign element property ${name} by value ${val}`); |     throw new Error(`cannot assign element property "${camelizedName}" by value "${val}"`); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user