diff --git a/src/rebuild.ts b/src/rebuild.ts index 3dee6026..f6be61ca 100644 --- a/src/rebuild.ts +++ b/src/rebuild.ts @@ -11,11 +11,20 @@ function buildNode(n: serializedNodeWithId): Node | null { n.systemId, ); case NodeType.Element: - const node = document.createElement(n.tagName); + const tagName = n.tagName === 'script' ? 'noscript' : n.tagName; + const node = document.createElement(tagName); for (const name in n.attributes) { if (n.attributes.hasOwnProperty(name)) { + let value = n.attributes[name]; + value = typeof value === 'boolean' ? '' : value; + // textarea hack + if (n.tagName === 'textarea' && name === 'value') { + const child = document.createTextNode(value); + node.appendChild(child); + continue; + } try { - node.setAttribute(name, n.attributes[name]); + node.setAttribute(name, value); } catch (error) { // skip invalid attribute } diff --git a/src/snapshot.ts b/src/snapshot.ts index ce805da5..c6f4eb60 100644 --- a/src/snapshot.ts +++ b/src/snapshot.ts @@ -11,6 +11,10 @@ function genId(): number { return _id++; } +function resetId() { + _id = 1; +} + function serializeNode(n: Node): serializedNode | false { switch (n.nodeType) { case n.DOCUMENT_NODE: @@ -31,6 +35,28 @@ function serializeNode(n: Node): serializedNode | false { for (const { name, value } of Array.from((n as HTMLElement).attributes)) { attributes[name] = value; } + if ( + tagName === 'input' || + tagName === 'textarea' || + tagName === 'select' + ) { + const value = (n as HTMLInputElement | HTMLTextAreaElement).value; + if ( + attributes.type !== 'radio' && + attributes.type !== 'checkbox' && + value + ) { + attributes.value = value; + } else if ((n as HTMLInputElement).checked) { + attributes.checked = (n as HTMLInputElement).checked; + } + } + if (tagName === 'option') { + const selectValue = (n as HTMLOptionElement).parentElement; + if (attributes.value === (selectValue as HTMLSelectElement).value) { + attributes.selected = (n as HTMLOptionElement).selected; + } + } return { type: NodeType.Element, tagName, @@ -65,7 +91,7 @@ function serializeNode(n: Node): serializedNode | false { } } -function snapshot(n: Node): serializedNodeWithId | null { +function _snapshot(n: Node): serializedNodeWithId | null { const _serializedNode = serializeNode(n); if (!_serializedNode) { // TODO: dev only @@ -80,10 +106,15 @@ function snapshot(n: Node): serializedNodeWithId | null { serializedNode.type === NodeType.Element ) { for (const childN of Array.from(n.childNodes)) { - serializedNode.childNodes.push(snapshot(childN)); + serializedNode.childNodes.push(_snapshot(childN)); } } return serializedNode; } +function snapshot(n: Node): serializedNodeWithId | null { + resetId(); + return _snapshot(n); +} + export default snapshot; diff --git a/src/types.ts b/src/types.ts index 25fc9962..17fc0e42 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,7 +20,7 @@ export type documentTypeNode = { }; export type attributes = { - [key: string]: string; + [key: string]: string | boolean; }; export type elementNode = { type: NodeType.Element; diff --git a/test/html/with-script.html b/test/html/with-script.html new file mode 100644 index 00000000..e3598090 --- /dev/null +++ b/test/html/with-script.html @@ -0,0 +1,18 @@ + + + +
+ + + +