[REF] initial prototype of owl 2

This commit is contained in:
Géry Debongnie
2020-11-26 16:45:25 +01:00
committed by Aaron Bohy
parent c06049076a
commit e746574a1d
186 changed files with 29153 additions and 33120 deletions
+155
View File
@@ -0,0 +1,155 @@
import type { Setter } from "./block_compiler";
const { setAttribute, removeAttribute } = Element.prototype;
const tokenList = DOMTokenList.prototype;
const tokenListAdd = tokenList.add;
const tokenListRemove = tokenList.remove;
const isArray = Array.isArray;
const { split, trim } = String.prototype;
const wordRegexp = /\s+/;
/**
* We regroup here all code related to updating attributes in a very loose sense:
* attributes, properties and classs are all managed by the functions in this
* file.
*/
export function createAttrUpdater(attr: string): Setter<HTMLElement> {
return function (this: HTMLElement, value: any) {
if (value !== false) {
setAttribute.call(this, attr, value === true ? "" : value);
}
};
}
export function attrsSetter(this: HTMLElement, attrs: any) {
if (isArray(attrs)) {
setAttribute.call(this, attrs[0], attrs[1]);
} else {
for (let k in attrs) {
setAttribute.call(this, k, attrs[k]);
}
}
}
export function attrsUpdater(this: HTMLElement, attrs: any, oldAttrs: any) {
if (isArray(attrs)) {
const name = attrs[0];
const val = attrs[1];
if (name === oldAttrs[0]) {
if (val === oldAttrs[1]) {
return;
}
setAttribute.call(this, name, val);
} else {
removeAttribute.call(this, oldAttrs[0]);
setAttribute.call(this, name, val);
}
} else {
for (let k in oldAttrs) {
if (!(k in attrs)) {
removeAttribute.call(this, k);
}
}
for (let k in attrs) {
const val = attrs[k];
if (val !== oldAttrs[k]) {
setAttribute.call(this, k, val);
}
}
}
}
function toClassObj(expr: string | number | { [c: string]: any }) {
const result: { [c: string]: any } = {};
switch (typeof expr) {
case "string":
// we transform here a list of classes into an object:
// 'hey you' becomes {hey: true, you: true}
const str = trim.call(expr);
if (!str) {
return {};
}
let words = split.call(str, wordRegexp);
for (let i = 0, l = words.length; i < l; i++) {
result[words[i]] = true;
}
return result;
case "object":
// this is already an object but we may need to split keys:
// {'a': true, 'b c': true} should become {a: true, b: true, c: true}
for (let key in expr as any) {
const value = (expr as any)[key];
if (value) {
const words = split.call(key, wordRegexp);
for (let word of words) {
result[word] = value;
}
}
}
return result;
case "undefined":
return {};
case "number":
return { [expr as number]: true };
default:
return { [expr as any]: true };
}
}
export function setClass(this: HTMLElement, val: any) {
val = val === "" ? {} : toClassObj(val);
// add classes
const cl = this.classList;
for (let c in val) {
tokenListAdd.call(cl, c);
}
}
export function updateClass(this: HTMLElement, val: any, oldVal: any) {
oldVal = oldVal === "" ? {} : toClassObj(oldVal);
val = val === "" ? {} : toClassObj(val);
const cl = this.classList;
// remove classes
for (let c in oldVal) {
if (!(c in val)) {
tokenListRemove.call(cl, c);
}
}
// add classes
for (let c in val) {
if (!(c in oldVal)) {
tokenListAdd.call(cl, c);
}
}
}
export function makePropSetter(name: string): Setter<HTMLElement> {
return function setProp(this: HTMLElement, value: any) {
(this as any)[name] = value;
};
}
export function isProp(tag: string, key: string): boolean {
switch (tag) {
case "input":
return (
key === "checked" ||
key === "indeterminate" ||
key === "value" ||
key === "readonly" ||
key === "disabled"
);
case "option":
return key === "selected" || key === "disabled";
case "textarea":
return key === "readonly" || key === "disabled";
break;
case "button":
case "select":
case "optgroup":
return key === "disabled";
}
return false;
}