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