parent
ea6010c782
commit
db7098c4f8
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "wkit",
|
"name": "wkit",
|
||||||
"version": "1.11.2",
|
"version": "1.11.3",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "A library for building fast, lightweight web components.",
|
"description": "A library for building fast, lightweight web components.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|
132
src/html.js
132
src/html.js
|
@ -6,31 +6,28 @@
|
||||||
|
|
||||||
import { boolMap, WC_PART, NOTHING } from './constants.js'
|
import { boolMap, WC_PART, NOTHING } from './constants.js'
|
||||||
import { animate, MODES } from './anim.js'
|
import { animate, MODES } from './anim.js'
|
||||||
import { nextTick } from './utils.js'
|
import { nextTick, noop } from './utils.js'
|
||||||
|
|
||||||
|
const BIND_ATTR_SUFFIX = '{{$wkit$}}'
|
||||||
|
const MARKER = `{{^wkit${String(Math.random()).slice(-8)}^}}`
|
||||||
|
const MARKER_MATCH = '?' + MARKER
|
||||||
|
const NODE_MARKER = `<${MARKER_MATCH}>`
|
||||||
|
|
||||||
const boundAttributeSuffix = '$wc$'
|
|
||||||
const marker = `wc$${String(Math.random()).slice(9)}$`
|
|
||||||
const markerMatch = '?' + marker
|
|
||||||
const nodeMarker = `<${markerMatch}>`
|
|
||||||
const createMarker = (v = '') => document.createComment(v)
|
|
||||||
const isPrimitive = value =>
|
const isPrimitive = value =>
|
||||||
value === null || (typeof value != 'object' && typeof value != 'function')
|
value === null || (typeof value != 'object' && typeof value != 'function')
|
||||||
const isArray = Array.isArray
|
const isArray = Array.isArray
|
||||||
const isIterable = value =>
|
const isIterable = value =>
|
||||||
isArray(value) ||
|
value ? isArray(value) || typeof value[Symbol.iterator] === 'function' : false
|
||||||
typeof (value === null || value === void 0
|
|
||||||
? false
|
|
||||||
: value[Symbol.iterator]) === 'function'
|
|
||||||
const SPACE_CHAR = `[ \n\f\r]`
|
const SPACE_CHAR = `[ \n\f\r]`
|
||||||
const ATTR_VALUE_CHAR = `[^ \n\f\r"'\`<>=]`
|
const ATTR_VALUE_CHAR = `[^ \n\f\r"'\`<>=]`
|
||||||
const NAME_CHAR = `[^\\s"'>=/]`
|
const NAME_CHAR = `[^\\s"'>=/]`
|
||||||
const textEndRegex = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g
|
const TEXT_END_REGEX = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g
|
||||||
const COMMENT_START = 1
|
const COMMENT_START = 1
|
||||||
const TAG_NAME = 2
|
const TAG_NAME = 2
|
||||||
const DYNAMIC_TAG_NAME = 3
|
const DYNAMIC_TAG_NAME = 3
|
||||||
const commentEndRegex = /-->/g
|
const COMMENT_END_REGEXP = /-->/g
|
||||||
const comment2EndRegex = />/g
|
const COMMENT_END_REGEXP_2 = />/g
|
||||||
const tagEndRegex = new RegExp(
|
const TAG_END_REGEXP = new RegExp(
|
||||||
`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`,
|
`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`,
|
||||||
'g'
|
'g'
|
||||||
)
|
)
|
||||||
|
@ -38,9 +35,9 @@ const ENTIRE_MATCH = 0
|
||||||
const ATTRIBUTE_NAME = 1
|
const ATTRIBUTE_NAME = 1
|
||||||
const SPACES_AND_EQUALS = 2
|
const SPACES_AND_EQUALS = 2
|
||||||
const QUOTE_CHAR = 3
|
const QUOTE_CHAR = 3
|
||||||
const singleQuoteAttrEndRegex = /'/g
|
const SINGLE_QUOTE_REGEXP = /'/g
|
||||||
const doubleQuoteAttrEndRegex = /"/g
|
const DOUBLE_QUOTE_REGEXP = /"/g
|
||||||
const rawTextElement = /^(?:script|style|textarea|title)$/i
|
const RAW_TEXT_ELEM_REGEXP = /^(?:script|style|textarea|title)$/i
|
||||||
const HTML_RESULT = 1
|
const HTML_RESULT = 1
|
||||||
const SVG_RESULT = 2
|
const SVG_RESULT = 2
|
||||||
const ATTRIBUTE_PART = 1
|
const ATTRIBUTE_PART = 1
|
||||||
|
@ -52,14 +49,12 @@ const COMMENT_PART = 7
|
||||||
const TEMPLATE_CACHE = new Map()
|
const TEMPLATE_CACHE = new Map()
|
||||||
const walker = document.createTreeWalker(document, 129, null, false)
|
const walker = document.createTreeWalker(document, 129, null, false)
|
||||||
|
|
||||||
function noop() {}
|
|
||||||
|
|
||||||
function getTemplateHtml(strings, type) {
|
function getTemplateHtml(strings, type) {
|
||||||
let len = strings.length - 1
|
let len = strings.length - 1
|
||||||
let attrNames = []
|
let attrNames = []
|
||||||
let html2 = type === SVG_RESULT ? '<svg>' : ''
|
let html2 = type === SVG_RESULT ? '<svg>' : ''
|
||||||
let rawTextEndRegex
|
let rawTextEndRegex
|
||||||
let regex = textEndRegex
|
let regex = TEXT_END_REGEX
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let s = strings[i]
|
let s = strings[i]
|
||||||
let attrNameEndIndex = -1
|
let attrNameEndIndex = -1
|
||||||
|
@ -73,25 +68,26 @@ function getTemplateHtml(strings, type) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastIndex = regex.lastIndex
|
lastIndex = regex.lastIndex
|
||||||
if (regex === textEndRegex) {
|
|
||||||
|
if (regex === TEXT_END_REGEX) {
|
||||||
if (match[COMMENT_START] === '!--') {
|
if (match[COMMENT_START] === '!--') {
|
||||||
regex = commentEndRegex
|
regex = COMMENT_END_REGEXP
|
||||||
} else if (match[COMMENT_START] !== void 0) {
|
} else if (match[COMMENT_START] !== void 0) {
|
||||||
regex = comment2EndRegex
|
regex = COMMENT_END_REGEXP_2
|
||||||
} else if (match[TAG_NAME] !== void 0) {
|
} else if (match[TAG_NAME] !== void 0) {
|
||||||
if (rawTextElement.test(match[TAG_NAME])) {
|
if (RAW_TEXT_ELEM_REGEXP.test(match[TAG_NAME])) {
|
||||||
rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, 'g')
|
rawTextEndRegex = new RegExp(`</${match[TAG_NAME]}`, 'g')
|
||||||
}
|
}
|
||||||
regex = tagEndRegex
|
regex = TAG_END_REGEXP
|
||||||
} else if (match[DYNAMIC_TAG_NAME] !== void 0) {
|
} else if (match[DYNAMIC_TAG_NAME] !== void 0) {
|
||||||
regex = tagEndRegex
|
regex = TAG_END_REGEXP
|
||||||
}
|
}
|
||||||
} else if (regex === tagEndRegex) {
|
} else if (regex === TAG_END_REGEXP) {
|
||||||
if (match[ENTIRE_MATCH] === '>') {
|
if (match[ENTIRE_MATCH] === '>') {
|
||||||
regex =
|
regex =
|
||||||
rawTextEndRegex !== null && rawTextEndRegex !== void 0
|
rawTextEndRegex !== null && rawTextEndRegex !== void 0
|
||||||
? rawTextEndRegex
|
? rawTextEndRegex
|
||||||
: textEndRegex
|
: TEXT_END_REGEX
|
||||||
attrNameEndIndex = -1
|
attrNameEndIndex = -1
|
||||||
} else if (match[ATTRIBUTE_NAME] === void 0) {
|
} else if (match[ATTRIBUTE_NAME] === void 0) {
|
||||||
attrNameEndIndex = -2
|
attrNameEndIndex = -2
|
||||||
|
@ -100,52 +96,65 @@ function getTemplateHtml(strings, type) {
|
||||||
attrName = match[ATTRIBUTE_NAME]
|
attrName = match[ATTRIBUTE_NAME]
|
||||||
regex =
|
regex =
|
||||||
match[QUOTE_CHAR] === void 0
|
match[QUOTE_CHAR] === void 0
|
||||||
? tagEndRegex
|
? TAG_END_REGEXP
|
||||||
: match[QUOTE_CHAR] === '"'
|
: match[QUOTE_CHAR] === '"'
|
||||||
? doubleQuoteAttrEndRegex
|
? DOUBLE_QUOTE_REGEXP
|
||||||
: singleQuoteAttrEndRegex
|
: SINGLE_QUOTE_REGEXP
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
regex === doubleQuoteAttrEndRegex ||
|
regex === DOUBLE_QUOTE_REGEXP ||
|
||||||
regex === singleQuoteAttrEndRegex
|
regex === SINGLE_QUOTE_REGEXP
|
||||||
) {
|
) {
|
||||||
regex = tagEndRegex
|
regex = TAG_END_REGEXP
|
||||||
} else if (regex === commentEndRegex || regex === comment2EndRegex) {
|
} else if (
|
||||||
regex = textEndRegex
|
regex === COMMENT_END_REGEXP ||
|
||||||
|
regex === COMMENT_END_REGEXP_2
|
||||||
|
) {
|
||||||
|
regex = TEXT_END_REGEX
|
||||||
} else {
|
} else {
|
||||||
regex = tagEndRegex
|
regex = TAG_END_REGEXP
|
||||||
rawTextEndRegex = void 0
|
rawTextEndRegex = void 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let end =
|
let end =
|
||||||
regex === tagEndRegex && strings[i + 1].startsWith('/>') ? ' ' : ''
|
regex === TAG_END_REGEXP && strings[i + 1].startsWith('/>') ? ' ' : ''
|
||||||
html2 +=
|
html2 +=
|
||||||
regex === textEndRegex
|
regex === TEXT_END_REGEX
|
||||||
? s + nodeMarker
|
? s + NODE_MARKER
|
||||||
: attrNameEndIndex >= 0
|
: attrNameEndIndex >= 0
|
||||||
? (attrNames.push(attrName),
|
? (attrNames.push(attrName),
|
||||||
s.slice(0, attrNameEndIndex) +
|
s.slice(0, attrNameEndIndex) +
|
||||||
boundAttributeSuffix +
|
BIND_ATTR_SUFFIX +
|
||||||
s.slice(attrNameEndIndex)) +
|
s.slice(attrNameEndIndex)) +
|
||||||
marker +
|
MARKER +
|
||||||
end
|
end
|
||||||
: s +
|
: s +
|
||||||
marker +
|
MARKER +
|
||||||
(attrNameEndIndex === -2 ? (attrNames.push(void 0), i) : end)
|
(attrNameEndIndex === -2 ? (attrNames.push(void 0), i) : end)
|
||||||
}
|
}
|
||||||
let htmlResult =
|
let htmlResult =
|
||||||
html2 + (strings[len] || '<?>') + (type === SVG_RESULT ? '</svg>' : '')
|
html2 + (strings[len] || '<?>') + (type === SVG_RESULT ? '</svg>' : '')
|
||||||
if (!Array.isArray(strings) || !strings.hasOwnProperty('raw')) {
|
if (!isArray(strings) || !strings.hasOwnProperty('raw')) {
|
||||||
throw new Error('invalid html ast')
|
throw new Error('invalid html ast')
|
||||||
}
|
}
|
||||||
return [htmlResult, attrNames]
|
return [htmlResult, attrNames]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createElement(v = '') {
|
||||||
|
let el = document.createElement('template')
|
||||||
|
el.innerHTML = v
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMarker(v = '') {
|
||||||
|
return document.createComment(v)
|
||||||
|
}
|
||||||
|
|
||||||
class Template {
|
class Template {
|
||||||
parts = []
|
parts = []
|
||||||
|
|
||||||
constructor({ strings, ['__dom_type__']: type }, options) {
|
constructor({ strings, values, __dom_type__: type }, options) {
|
||||||
let node
|
let node
|
||||||
let nodeIndex = 0
|
let nodeIndex = 0
|
||||||
let attrNameIndex = 0
|
let attrNameIndex = 0
|
||||||
|
@ -153,7 +162,7 @@ class Template {
|
||||||
let parts = this.parts
|
let parts = this.parts
|
||||||
let [html2, attrNames] = getTemplateHtml(strings, type)
|
let [html2, attrNames] = getTemplateHtml(strings, type)
|
||||||
|
|
||||||
this.el = Template.createElement(html2)
|
this.el = createElement(html2)
|
||||||
|
|
||||||
walker.currentNode = this.el.content
|
walker.currentNode = this.el.content
|
||||||
|
|
||||||
|
@ -170,17 +179,14 @@ class Template {
|
||||||
let attrsToRemove = []
|
let attrsToRemove = []
|
||||||
|
|
||||||
for (let name of node.getAttributeNames()) {
|
for (let name of node.getAttributeNames()) {
|
||||||
if (
|
if (name.endsWith(BIND_ATTR_SUFFIX) || name.startsWith(MARKER)) {
|
||||||
name.endsWith(boundAttributeSuffix) ||
|
|
||||||
name.startsWith(marker)
|
|
||||||
) {
|
|
||||||
let realName = attrNames[attrNameIndex++]
|
let realName = attrNames[attrNameIndex++]
|
||||||
attrsToRemove.push(name)
|
attrsToRemove.push(name)
|
||||||
if (realName !== void 0) {
|
if (realName !== void 0) {
|
||||||
let value = node.getAttribute(
|
let value = node.getAttribute(
|
||||||
realName.toLowerCase() + boundAttributeSuffix
|
realName.toLowerCase() + BIND_ATTR_SUFFIX
|
||||||
)
|
)
|
||||||
let statics = value.split(marker)
|
let statics = value.split(MARKER)
|
||||||
let m = /([#:@])?(.*)/.exec(realName)
|
let m = /([#:@])?(.*)/.exec(realName)
|
||||||
let decorates = []
|
let decorates = []
|
||||||
|
|
||||||
|
@ -216,8 +222,8 @@ class Template {
|
||||||
node.removeAttribute(name)
|
node.removeAttribute(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rawTextElement.test(node.tagName)) {
|
if (RAW_TEXT_ELEM_REGEXP.test(node.tagName)) {
|
||||||
let strings2 = node.textContent.split(marker)
|
let strings2 = node.textContent.split(MARKER)
|
||||||
let lastIndex = strings2.length - 1
|
let lastIndex = strings2.length - 1
|
||||||
if (lastIndex > 0) {
|
if (lastIndex > 0) {
|
||||||
node.textContent = ''
|
node.textContent = ''
|
||||||
|
@ -231,24 +237,19 @@ class Template {
|
||||||
}
|
}
|
||||||
} else if (node.nodeType === 8) {
|
} else if (node.nodeType === 8) {
|
||||||
let data = node.data
|
let data = node.data
|
||||||
if (data === markerMatch) {
|
if (data === MARKER_MATCH) {
|
||||||
parts.push({ type: CHILD_PART, index: nodeIndex })
|
parts.push({ type: CHILD_PART, index: nodeIndex })
|
||||||
} else {
|
} else {
|
||||||
let i = -1
|
let i = -1
|
||||||
while ((i = node.data.indexOf(marker, i + 1)) !== -1) {
|
while ((i = node.data.indexOf(MARKER, i + 1)) !== -1) {
|
||||||
parts.push({ type: COMMENT_PART, index: nodeIndex })
|
parts.push({ type: COMMENT_PART, index: nodeIndex })
|
||||||
i += marker.length - 1
|
i += MARKER.length - 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodeIndex++
|
nodeIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static createElement(html2) {
|
|
||||||
let el = document.createElement('template')
|
|
||||||
el.innerHTML = html2
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TemplateInstance {
|
class TemplateInstance {
|
||||||
|
@ -378,7 +379,7 @@ class ChildPart {
|
||||||
} else if (value !== this.#value) {
|
} else if (value !== this.#value) {
|
||||||
this.#commitText(value)
|
this.#commitText(value)
|
||||||
}
|
}
|
||||||
} else if (value['__dom_type__'] !== void 0) {
|
} else if (value.__dom_type__ !== void 0) {
|
||||||
this.#commitTemplateResult(value)
|
this.#commitTemplateResult(value)
|
||||||
} else if (value.nodeType !== void 0) {
|
} else if (value.nodeType !== void 0) {
|
||||||
this.#commitNode(value)
|
this.#commitNode(value)
|
||||||
|
@ -415,12 +416,11 @@ class ChildPart {
|
||||||
}
|
}
|
||||||
|
|
||||||
#commitTemplateResult(result) {
|
#commitTemplateResult(result) {
|
||||||
let { values, ['__dom_type__']: type } = result
|
let { values, __dom_type__: type } = result
|
||||||
let template =
|
let template =
|
||||||
typeof type === 'number'
|
typeof type === 'number'
|
||||||
? this.#getTemplate(result)
|
? this.#getTemplate(result)
|
||||||
: (type.el === void 0 && (type.el = Template.createElement(type.h)),
|
: (type.el === void 0 && (type.el = createElement(type.h)), type)
|
||||||
type)
|
|
||||||
|
|
||||||
if (this.#value?.$template === template) {
|
if (this.#value?.$template === template) {
|
||||||
this.#value.update(values)
|
this.#value.update(values)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* @date 2023/03/07 22:11:30
|
* @date 2023/03/07 22:11:30
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function noop() {}
|
export function noop() {}
|
||||||
|
|
||||||
export function $(selector, container, multi) {
|
export function $(selector, container, multi) {
|
||||||
let fn = multi ? 'querySelectorAll' : 'querySelector'
|
let fn = multi ? 'querySelectorAll' : 'querySelector'
|
||||||
|
|
Loading…
Reference in New Issue