mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 11:41:20 +08:00
fix(input): title attribute is automatically inherited (#22493)
resolves #22055
This commit is contained in:
@ -2,7 +2,7 @@ import { Build, Component, ComponentInterface, Element, Event, EventEmitter, Hos
|
|||||||
|
|
||||||
import { getIonMode } from '../../global/ionic-global';
|
import { getIonMode } from '../../global/ionic-global';
|
||||||
import { AutocompleteTypes, Color, InputChangeEventDetail, StyleEventDetail, TextFieldTypes } from '../../interface';
|
import { AutocompleteTypes, Color, InputChangeEventDetail, StyleEventDetail, TextFieldTypes } from '../../interface';
|
||||||
import { debounceEvent, findItemLabel } from '../../utils/helpers';
|
import { debounceEvent, findItemLabel, inheritAttributes } from '../../utils/helpers';
|
||||||
import { createColorClasses } from '../../utils/theme';
|
import { createColorClasses } from '../../utils/theme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +21,7 @@ export class Input implements ComponentInterface {
|
|||||||
private nativeInput?: HTMLInputElement;
|
private nativeInput?: HTMLInputElement;
|
||||||
private inputId = `ion-input-${inputIds++}`;
|
private inputId = `ion-input-${inputIds++}`;
|
||||||
private didBlurAfterEdit = false;
|
private didBlurAfterEdit = false;
|
||||||
private tabindex?: string | number;
|
private inheritedAttributes: { [k: string]: any } = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is required for a WebKit bug which requires us to
|
* This is required for a WebKit bug which requires us to
|
||||||
@ -225,14 +225,7 @@ export class Input implements ComponentInterface {
|
|||||||
@Event() ionStyle!: EventEmitter<StyleEventDetail>;
|
@Event() ionStyle!: EventEmitter<StyleEventDetail>;
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
// If the ion-input has a tabindex attribute we get the value
|
this.inheritedAttributes = inheritAttributes(this.el, ['tabindex', 'title']);
|
||||||
// and pass it down to the native input, then remove it from the
|
|
||||||
// ion-input to avoid causing tabbing twice on the same element
|
|
||||||
if (this.el.hasAttribute('tabindex')) {
|
|
||||||
const tabindex = this.el.getAttribute('tabindex');
|
|
||||||
this.tabindex = tabindex !== null ? tabindex : undefined;
|
|
||||||
this.el.removeAttribute('tabindex');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@ -428,13 +421,13 @@ export class Input implements ComponentInterface {
|
|||||||
spellcheck={this.spellcheck}
|
spellcheck={this.spellcheck}
|
||||||
step={this.step}
|
step={this.step}
|
||||||
size={this.size}
|
size={this.size}
|
||||||
tabindex={this.tabindex}
|
|
||||||
type={this.type}
|
type={this.type}
|
||||||
value={value}
|
value={value}
|
||||||
onInput={this.onInput}
|
onInput={this.onInput}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onKeyDown={this.onKeydown}
|
onKeyDown={this.onKeydown}
|
||||||
|
{...this.inheritedAttributes}
|
||||||
/>
|
/>
|
||||||
{(this.clearInput && !this.readonly && !this.disabled) && <button
|
{(this.clearInput && !this.readonly && !this.disabled) && <button
|
||||||
aria-label="reset"
|
aria-label="reset"
|
||||||
|
@ -2,7 +2,7 @@ import { Build, Component, ComponentInterface, Element, Event, EventEmitter, Hos
|
|||||||
|
|
||||||
import { getIonMode } from '../../global/ionic-global';
|
import { getIonMode } from '../../global/ionic-global';
|
||||||
import { Color, StyleEventDetail, TextareaChangeEventDetail } from '../../interface';
|
import { Color, StyleEventDetail, TextareaChangeEventDetail } from '../../interface';
|
||||||
import { debounceEvent, findItemLabel, raf } from '../../utils/helpers';
|
import { debounceEvent, findItemLabel, inheritAttributes, raf } from '../../utils/helpers';
|
||||||
import { createColorClasses } from '../../utils/theme';
|
import { createColorClasses } from '../../utils/theme';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,6 +22,7 @@ export class Textarea implements ComponentInterface {
|
|||||||
private inputId = `ion-textarea-${textareaIds++}`;
|
private inputId = `ion-textarea-${textareaIds++}`;
|
||||||
private didBlurAfterEdit = false;
|
private didBlurAfterEdit = false;
|
||||||
private textareaWrapper?: HTMLElement;
|
private textareaWrapper?: HTMLElement;
|
||||||
|
private inheritedAttributes: { [k: string]: any } = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is required for a WebKit bug which requires us to
|
* This is required for a WebKit bug which requires us to
|
||||||
@ -212,6 +213,10 @@ export class Textarea implements ComponentInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillLoad() {
|
||||||
|
this.inheritedAttributes = inheritAttributes(this.el, ['title']);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
raf(() => this.runAutoGrow());
|
raf(() => this.runAutoGrow());
|
||||||
}
|
}
|
||||||
@ -379,6 +384,7 @@ export class Textarea implements ComponentInterface {
|
|||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
|
{...this.inheritedAttributes}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</textarea>
|
</textarea>
|
||||||
|
@ -5,6 +5,32 @@ import { Side } from '../interface';
|
|||||||
declare const __zone_symbol__requestAnimationFrame: any;
|
declare const __zone_symbol__requestAnimationFrame: any;
|
||||||
declare const requestAnimationFrame: any;
|
declare const requestAnimationFrame: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Elements inside of web components sometimes need to inherit global attributes
|
||||||
|
* set on the host. For example, the inner input in `ion-input` should inherit
|
||||||
|
* the `title` attribute that developers set directly on `ion-input`. This
|
||||||
|
* helper function should be called in componentWillLoad and assigned to a variable
|
||||||
|
* that is later used in the render function.
|
||||||
|
*
|
||||||
|
* This does not need to be reactive as changing attributes on the host element
|
||||||
|
* does not trigger a re-render.
|
||||||
|
*/
|
||||||
|
export const inheritAttributes = (el: HTMLElement, attributes: string[] = []) => {
|
||||||
|
const attributeObject: { [k: string]: any } = {};
|
||||||
|
|
||||||
|
attributes.forEach(attr => {
|
||||||
|
if (el.hasAttribute(attr)) {
|
||||||
|
const value = el.getAttribute(attr);
|
||||||
|
if (value !== null) {
|
||||||
|
attributeObject[attr] = el.getAttribute(attr);
|
||||||
|
}
|
||||||
|
el.removeAttribute(attr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return attributeObject;
|
||||||
|
}
|
||||||
|
|
||||||
export const addEventListener = (el: any, eventName: string, callback: any, opts?: any) => {
|
export const addEventListener = (el: any, eventName: string, callback: any, opts?: any) => {
|
||||||
if (typeof (window as any) !== 'undefined') {
|
if (typeof (window as any) !== 'undefined') {
|
||||||
const win = window as any;
|
const win = window as any;
|
||||||
|
39
core/src/utils/test/attributes.spec.ts
Normal file
39
core/src/utils/test/attributes.spec.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { inheritAttributes } from '../helpers';
|
||||||
|
|
||||||
|
describe('inheritAttributes()', () => {
|
||||||
|
it('should create an attribute inheritance object', () => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.setAttribute('tabindex', '20');
|
||||||
|
el.setAttribute('title', 'myTitle');
|
||||||
|
|
||||||
|
const attributeObject = inheritAttributes(el, ['tabindex', 'title']);
|
||||||
|
|
||||||
|
expect(attributeObject).toEqual({
|
||||||
|
tabindex: '20',
|
||||||
|
title: 'myTitle'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inherit attributes that are not defined on the element', () => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.setAttribute('tabindex', '20');
|
||||||
|
|
||||||
|
const attributeObject = inheritAttributes(el, ['tabindex', 'title']);
|
||||||
|
|
||||||
|
expect(attributeObject).toEqual({
|
||||||
|
tabindex: '20'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inherit attributes that are not defined on the input array', () => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
el.setAttribute('tabindex', '20');
|
||||||
|
el.setAttribute('title', 'myTitle');
|
||||||
|
|
||||||
|
const attributeObject = inheritAttributes(el, ['title']);
|
||||||
|
|
||||||
|
expect(attributeObject).toEqual({
|
||||||
|
title: 'myTitle'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user