@ribajs/core
Version:
Core module of Riba.js
108 lines (92 loc) • 2.76 kB
text/typescript
import { Binder } from "../binder.js";
import { getInputValue, getString, setAttribute } from "@ribajs/utils";
const DEFAULT_EVENTS = "change input paste blur focus";
/**
* Sets the element's value. Also sets the model property when the input changes
* (two-way binder).
*/
export class ValueBinder extends Binder<any, HTMLElement> {
static key = "value";
publishes = true;
priority = 3000;
event?: string;
getData(el: HTMLElement) {
const data = {
type: (el as HTMLInputElement).type,
tagName: el.tagName,
contenteditable: el.getAttribute("contenteditable") ? true : false,
isRadio: false,
isOption: false,
};
data.isRadio = data.tagName === "INPUT" && data.type === "radio";
data.isOption = data.tagName === "OPTION";
return data;
}
onChange = this.publish.bind(this);
bind(el: HTMLElement) {
if (el.tagName === "OPTION") {
return;
}
const data = this.getData(el);
if (!data.isRadio) {
this.event = el.getAttribute("event-name") || DEFAULT_EVENTS;
const events = this.event.split(" ");
for (const event of events) {
el.addEventListener(event.trim(), this.onChange, false);
}
}
}
unbind(el: HTMLUnknownElement) {
if (this.event) {
const events = this.event.split(" ");
for (const event in events) {
el.removeEventListener(event.trim(), this.onChange);
}
}
}
routine(
el: HTMLElement | HTMLSelectElement,
newValue?: number | string | string[],
) {
let oldValue = this.getValue(el);
if (!Array.isArray(newValue)) {
if (newValue != null) {
newValue = getString(newValue);
} else {
newValue = "";
}
}
if (!Array.isArray(oldValue)) {
if (oldValue != null) {
oldValue = getString(oldValue);
} else {
oldValue = "";
}
}
if (oldValue === newValue) {
// nothing changed
return;
}
const data = this.getData(el);
if (data.isRadio || data.isOption) {
return setAttribute(el, "value", newValue);
}
if ((el as HTMLSelectElement).type === "select-multiple") {
if (Array.isArray(newValue)) {
for (let i = 0; i < (el as HTMLSelectElement).options.length; i++) {
const option = (el as HTMLSelectElement).options[
i
] as HTMLOptionElement;
option.selected = newValue.indexOf(option.value) > -1;
}
}
} else if (el.getAttribute("contenteditable")) {
el.innerHTML = newValue as string; // TODO write test for contenteditable
} else {
(el as HTMLInputElement).value = newValue as string;
}
}
getValue(el: HTMLElement) {
return getInputValue(el);
}
}