diff --git a/README.md b/README.md
index 0f66e3d..965ec49 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,10 @@ Query CSS Selector to find matching node.
Append a child node to childNodes
+### HTMLElement#insertAdjacentHTML(where, html)
+
+parses the specified text as HTML and inserts the resulting nodes into the DOM tree at a specified position.
+
### HTMLElement#firstChild
Get first child node
diff --git a/src/nodes/html.ts b/src/nodes/html.ts
index 1890224..de909a4 100644
--- a/src/nodes/html.ts
+++ b/src/nodes/html.ts
@@ -19,6 +19,8 @@ export interface RawAttributes {
[key: string]: string;
}
+export type InsertPosition = 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend';
+
const kBlockElements = {
div: true,
p: true,
@@ -57,7 +59,7 @@ export default class HTMLElement extends Node {
*
* @memberof HTMLElement
*/
- constructor(public tagName: string, keyAttrs: KeyAttributes, private rawAttrs = '', public parentNode = null as Node) {
+ public constructor(public tagName: string, keyAttrs: KeyAttributes, private rawAttrs = '', public parentNode = null as Node) {
super();
this.rawAttrs = rawAttrs || '';
this.parentNode = parentNode || null;
@@ -97,7 +99,7 @@ export default class HTMLElement extends Node {
* Get escpaed (as-it) text value of current node and its children.
* @return {string} text content
*/
- get rawText() {
+ public get rawText() {
return this.childNodes.reduce((pre, cur) => {
return pre += cur.rawText;
}, '');
@@ -106,14 +108,14 @@ export default class HTMLElement extends Node {
* Get unescaped text value of current node and its children.
* @return {string} text content
*/
- get text() {
+ public get text() {
return decode(this.rawText);
}
/**
* Get structured Text (with '\n' etc.)
* @return {string} structured text
*/
- get structuredText() {
+ public get structuredText() {
let currentBlock = [] as string[];
const blocks = [currentBlock];
function dfs(node: Node) {
@@ -170,7 +172,7 @@ export default class HTMLElement extends Node {
}
}
- get innerHTML() {
+ public get innerHTML() {
return this.childNodes.map((child) => {
return child.toString();
}).join('');
@@ -186,7 +188,7 @@ export default class HTMLElement extends Node {
this.childNodes = content;
}
- get outerHTML() {
+ public get outerHTML() {
return this.toString();
}
@@ -215,7 +217,7 @@ export default class HTMLElement extends Node {
* Get DOM structure
* @return {string} strucutre
*/
- get structure() {
+ public get structure() {
const res = [] as string[];
let indention = 0;
function write(str: string) {
@@ -383,7 +385,7 @@ export default class HTMLElement extends Node {
* Get first child node
* @return {Node} first child node
*/
- get firstChild() {
+ public get firstChild() {
return this.childNodes[0];
}
@@ -391,7 +393,7 @@ export default class HTMLElement extends Node {
* Get last child node
* @return {Node} last child node
*/
- get lastChild() {
+ public get lastChild() {
return arr_back(this.childNodes);
}
@@ -399,7 +401,7 @@ export default class HTMLElement extends Node {
* Get attributes
* @return {Object} parsed and unescaped attributes
*/
- get attributes() {
+ public get attributes() {
if (this._attrs) {
return this._attrs;
}
@@ -416,7 +418,7 @@ export default class HTMLElement extends Node {
* Get escaped (as-it) attributes
* @return {Object} parsed attributes
*/
- get rawAttributes() {
+ public get rawAttributes() {
if (this._rawAttrs)
return this._rawAttrs;
const attrs = {} as RawAttributes;
@@ -510,4 +512,29 @@ export default class HTMLElement extends Node {
}
}).join(' ');
}
+
+ public insertAdjacentHTML(where: InsertPosition, html: string) {
+ if (arguments.length < 2) {
+ throw new Error('2 arguments required');
+ }
+ const p = parse(html) as HTMLElement;
+ if (where === 'afterend') {
+ p.childNodes.forEach((n) => {
+ (this.parentNode as HTMLElement).appendChild(n);
+ });
+ } else if (where === 'afterbegin') {
+ this.childNodes.unshift(...p.childNodes);
+ } else if (where === 'beforeend') {
+ p.childNodes.forEach((n) => {
+ this.appendChild(n);
+ });
+ } else if (where === 'beforebegin') {
+ (this.parentNode as HTMLElement).childNodes.unshift(...p.childNodes);
+ } else {
+ throw new Error(`The value provided ('${where}') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'`);
+ }
+ if (!where || html === undefined || html === null) {
+ return;
+ }
+ }
}
diff --git a/test/html.js b/test/html.js
index ebc0d93..0ea581d 100644
--- a/test/html.js
+++ b/test/html.js
@@ -416,11 +416,13 @@ describe('HTML Parser', function () {
});
describe('#hasAttribute', function () {
- var root = parseHTML('');
- var input = root.firstChild;
- input.hasAttribute('required').should.eql(true);
- input.removeAttribute('required');
- input.hasAttribute('required').should.eql(false);
+ it('should return true or false when has or has not some attribute', function () {
+ var root = parseHTML('');
+ var input = root.firstChild;
+ input.hasAttribute('required').should.eql(true);
+ input.removeAttribute('required');
+ input.hasAttribute('required').should.eql(false);
+ });
});
describe('#querySelector()', function () {
@@ -514,6 +516,46 @@ describe('HTML Parser', function () {
root.firstChild.rawAttributes.alt.should.eql('«Sogno');
});
});
+
+ describe('#insertAdjacentHTML() should parse and insert childrens', function () {
+ it('shoud insert children after current node', function () {
+ const html = '';
+ const root = parseHTML(html);
+ const a = root.firstChild;
+ const b = a.firstChild;
+ b.insertAdjacentHTML('afterend', '');
+ a.toString().should.eql('');
+ });
+
+ it('shoud insert children before current node', function () {
+ const html = '';
+ const root = parseHTML(html);
+ const a = root.firstChild;
+ const b = a.firstChild;
+ b.insertAdjacentHTML('beforebegin', '');
+ a.toString().should.eql('');
+ });
+
+ it('shoud append children in current node', function () {
+ const html = '';
+ const root = parseHTML(html);
+ const a = root.firstChild;
+ a.insertAdjacentHTML('beforeend', '');
+ a.toString().should.eql('');
+ a.insertAdjacentHTML('beforeend', '');
+ a.toString().should.eql('');
+ });
+
+ it('shoud insert children at position 0', function () {
+ const html = '';
+ const root = parseHTML(html);
+ const a = root.firstChild;
+ a.insertAdjacentHTML('afterbegin', '');
+ a.toString().should.eql('');
+ a.insertAdjacentHTML('afterbegin', '');
+ a.toString().should.eql('');
+ });
+ });
});
describe('stringify', function () {