@@ -51,6 +51,7 @@ export interface RawAttributes {
5151}
5252
5353export type InsertPosition = 'beforebegin' | 'afterbegin' | 'beforeend' | 'afterend' ;
54+ export type NodeInsertable = Node | string ;
5455
5556// https://developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements
5657const Htags = [ 'h1' , 'h2' , 'h3' , 'h4' , 'h5' , 'h6' , 'header' , 'hgroup' ] ;
@@ -643,29 +644,10 @@ export default class HTMLElement extends Node {
643644 * @return {Node } node appended
644645 */
645646 public appendChild < T extends Node = Node > ( node : T ) {
646- // remove the node from it's parent
647- node . remove ( ) ;
648- this . childNodes . push ( node ) ;
649- node . parentNode = this ;
647+ this . append ( node ) ;
650648 return node ;
651649 }
652650
653- /**
654- * Get first child node
655- * @return {Node | undefined } first child node; or undefined if none
656- */
657- public get firstChild ( ) : Node | undefined {
658- return this . childNodes [ 0 ] ;
659- }
660-
661- /**
662- * Get last child node
663- * @return {Node | undefined } last child node; or undefined if none
664- */
665- public get lastChild ( ) : Node | undefined {
666- return arr_back ( this . childNodes ) ;
667- }
668-
669651 /**
670652 * Get attributes
671653 * @access private
@@ -818,33 +800,46 @@ export default class HTMLElement extends Node {
818800 }
819801 const p = parse ( html , this . _parseOptions ) ;
820802 if ( where === 'afterend' ) {
821- const idx = this . parentNode . childNodes . findIndex ( ( child ) => {
822- return child === this ;
823- } ) ;
824- resetParent ( p . childNodes , this . parentNode ) ;
825- this . parentNode . childNodes . splice ( idx + 1 , 0 , ...p . childNodes ) ;
803+ this . after ( ...p . childNodes ) ;
826804 } else if ( where === 'afterbegin' ) {
827- resetParent ( p . childNodes , this ) ;
828- this . childNodes . unshift ( ...p . childNodes ) ;
805+ this . prepend ( ...p . childNodes ) ;
829806 } else if ( where === 'beforeend' ) {
830- p . childNodes . forEach ( ( n ) => {
831- this . appendChild ( n ) ;
832- } ) ;
807+ this . append ( ...p . childNodes ) ;
833808 } else if ( where === 'beforebegin' ) {
834- const idx = this . parentNode . childNodes . findIndex ( ( child ) => {
835- return child === this ;
836- } ) ;
837- resetParent ( p . childNodes , this . parentNode ) ;
838- this . parentNode . childNodes . splice ( idx , 0 , ...p . childNodes ) ;
809+ this . before ( ...p . childNodes ) ;
839810 } else {
840811 throw new Error (
841812 `The value provided ('${ where as string } ') is not one of 'beforebegin', 'afterbegin', 'beforeend', or 'afterend'`
842813 ) ;
843814 }
844815 return this ;
845- // if (!where || html === undefined || html === null) {
846- // return;
847- // }
816+ }
817+
818+ /** Prepend nodes or strings to this node's children. */
819+ public prepend ( ...insertable : NodeInsertable [ ] ) {
820+ const nodes = resolveInsertable ( insertable ) ;
821+ resetParent ( nodes , this ) ;
822+ this . childNodes . unshift ( ...nodes ) ;
823+ }
824+ /** Append nodes or strings to this node's children. */
825+ public append ( ...insertable : NodeInsertable [ ] ) {
826+ const nodes = resolveInsertable ( insertable ) ;
827+ resetParent ( nodes , this ) ;
828+ this . childNodes . push ( ...nodes ) ;
829+ }
830+ /** Insert nodes or strings before this node. */
831+ public before ( ...insertable : NodeInsertable [ ] ) {
832+ const nodes = resolveInsertable ( insertable ) ;
833+ const siblings = this . parentNode . childNodes ;
834+ resetParent ( nodes , this . parentNode ) ;
835+ siblings . splice ( siblings . indexOf ( this ) , 0 , ...nodes ) ;
836+ }
837+ /** Insert nodes or strings after this node. */
838+ public after ( ...insertable : NodeInsertable [ ] ) {
839+ const nodes = resolveInsertable ( insertable ) ;
840+ const siblings = this . parentNode . childNodes ;
841+ resetParent ( nodes , this . parentNode ) ;
842+ siblings . splice ( siblings . indexOf ( this ) + 1 , 0 , ...nodes ) ;
848843 }
849844
850845 public get nextSibling ( ) : Node | null {
@@ -909,13 +904,56 @@ export default class HTMLElement extends Node {
909904 }
910905 }
911906
912- public get classNames ( ) {
913- return this . classList . toString ( ) ;
907+ /** Get all childNodes of type {@link HTMLElement}. */
908+ public get children ( ) : HTMLElement [ ] {
909+ const children = [ ] ;
910+ for ( const childNode of this . childNodes ) {
911+ if ( childNode instanceof HTMLElement ) {
912+ children . push ( childNode ) ;
913+ }
914+ }
915+ return children ;
916+ }
917+
918+ /**
919+ * Get the first child node.
920+ * @return The first child or undefined if none exists.
921+ */
922+ public get firstChild ( ) : Node | undefined {
923+ return this . childNodes [ 0 ] ;
924+ }
925+ /**
926+ * Get the first child node of type {@link HTMLElement}.
927+ * @return The first child element or undefined if none exists.
928+ */
929+ public get firstElementChild ( ) : HTMLElement | undefined {
930+ return this . children [ 0 ] ;
914931 }
915932
916933 /**
917- * Clone this Node
934+ * Get the last child node.
935+ * @return The last child or undefined if none exists.
918936 */
937+ public get lastChild ( ) : Node | undefined {
938+ return arr_back ( this . childNodes ) ;
939+ }
940+ /**
941+ * Get the last child node of type {@link HTMLElement}.
942+ * @return The last child element or undefined if none exists.
943+ */
944+ public get lastElementChild ( ) : HTMLElement | undefined {
945+ return this . children [ this . children . length - 1 ] ;
946+ }
947+
948+ public get childElementCount ( ) : number {
949+ return this . children . length ;
950+ }
951+
952+ public get classNames ( ) {
953+ return this . classList . toString ( ) ;
954+ }
955+
956+ /** Clone this Node */
919957 public clone ( ) {
920958 return parse ( this . toString ( ) , this . _parseOptions ) . firstChild ;
921959 }
@@ -1204,6 +1242,20 @@ export function parse(data: string, options = {} as Partial<Options>) {
12041242 return root ;
12051243}
12061244
1245+ /**
1246+ * Resolves a list of {@link NodeInsertable} to a list of nodes,
1247+ * and removes nodes from any potential parent.
1248+ */
1249+ function resolveInsertable ( insertable : NodeInsertable [ ] ) : Node [ ] {
1250+ return insertable . map ( val => {
1251+ if ( typeof val === 'string' ) {
1252+ return new TextNode ( val ) ;
1253+ }
1254+ val . remove ( ) ;
1255+ return val ;
1256+ } ) ;
1257+ }
1258+
12071259function resetParent ( nodes : Node [ ] , parent : HTMLElement ) {
12081260 return nodes . map ( ( node ) => {
12091261 node . parentNode = parent ;
0 commit comments