Reputation: 25
I am changing my website to a modern web app of sorts, here is my HTML code..
<joexn-profile>
<joexn-logo></joexn-logo>
<joexn-text></joexn-text>
</joexn-profile>
and this is the JavaScript I use for the <joexn-profile>
tags.
var joexnprofile = document.querySelector('joexn-profile');
joexnprofile.insertAdjacentHTML( 'afterBegin', '<center><div class="joexn-profile">');
joexnprofile.insertAdjacentHTML( 'afterEnd', '</div></center>');
The issue is, the <div class="joexn-profile">
tag automatically closes.
Take a look at the inspect element view:
JavaScript Only
Upvotes: 1
Views: 2383
Reputation: 12647
As already explained by Quentin, you can't insert only half of a Node.
On the other hand, why do you want to do that at all?
1st: avoid tags like <center>
or <font>
or <b>
, ... If you want to style sth. do it with CSS.
and 2nd: what's the point in replacing <joexn-profile>
with <div class="joexn-profile">
?
Every style that you apply to the .joexn-profile
CSS-Selector you can also apply to the joexn-profile
CSS-Selector.
The only difference is, that you have to declare display:block
for joexn-profile
so that the browser knows how to render this Node; block
or inline
or whatever.
But if you insist in going your way, here a little utility to handle such compositions of html-markup (even partial) and DON-Nodes.
Disclaimer: Code not fully tested, it may still contain bugs. And fragment()
doesn't handle cyclic references!
https://jsfiddle.net/mkapLz1k/1/
//just to be clear: this ain't a replacement for jQuery, nor does it interfere with it's purposes.
//it's a set of utilities to enable working with compositions of HTML-Markup and plain DOM-Nodes
var nodeUtils = (function(){
var container = document.createElement("div"),
placeholder = document.createElement("div"),
forEach = Array.prototype.forEach;
function _replacePlaceholder(node){
var parent = node.parentNode;
parent.insertBefore(this[node.id], node);
parent.removeChild(node);
}
function _randomId(){
return ("id"+Math.random()+Math.random()+Math.random()).replace(/0\./g, "-")
}
function _fragment(src){
var markup = [],
nodesById = {},
id = "",
ids = [];
function _addNode(node){
if(!id){
nodesById[id=_randomId()] = fragment();
ids.push("#"+id);
//add placeholder into the html-markup.
//These placeholder get eventually replaced.
markup.push('<div id="'+id+'"></div>');
}
nodesById[id].appendChild( node );
}
function _parse(node){
if(node == null || node === "" || typeof node === "function") return;
if(typeof node === "object"){
if("nodeType" in node){
//processes DOM Nodes, of all shapes and sizes ;)
//including Comment-Nodes, TextNodes and DocumentFragments, ...
_addNode( node );
}else if(this.NodeList && node instanceof NodeList){
//nodeLists change
//so I have to process them differently than regular lists
while(node.length) _addNode( node[0] );
}else{
//processes anything ArrayLike
for(var i = 0, len = ("length" in node && node.length)|0; i<len; ++i)
i in node && _parse( node[i] );
}
}else{
//processes primitives as html-markup
id = "";
markup.push( node );
}
}
_parse( src );
if(ids.length === markup.length){ //=> 0 or 1
//src contained only Nodes, no strings or primitives
return id? nodesById[id]: void 0;
}
//src contained html-markup that needs to be parsed
container.innerHTML = markup.join("");
if(ids.length){
//injecting the DOM-Nodes
forEach.call( container.querySelectorAll( ids.join(",") ), _replacePlaceholder, nodesById );
}
for(var frag = fragment(), fc; fc = container.firstChild; )
frag.appendChild( fc );
return frag;
}
//`fragment()` is shorthand for `document.createDocumentFragment()`
//`fragment(composition)` returns a DocumentFragment, that can be used with `node.appendChild()`.
//takes an arbitrary composition of nested Arrays (or ArrayLike-structures, like jQuery-Objects, NodeLists, ...), containing DOM-Nodes or strings/primitives and builds a DocumentFragment out of that
function fragment(composition){
return composition != null && _fragment(composition) || document.createDocumentFragment();
}
//all the following functions can take anything that `fragment()` can handle as input:
//only `node` has to be a real DOM-Node!
//almost like setting a Nodes innerHTML, but it takes more than just HTML-Markup
function content(node, composition){
for(var frag = fragment(composition), fc; fc=node.firstChild;) node.removeChild(fc);
node.appendChild(frag);
return node;
}
//replace a Node with the provided
function replace(node, composition){
var parent = node.parentNode;
parent.insertBefore(placeholder, node);
parent.insertBefore(fragment(composition), placeholder);
parent.removeChild(placeholder);
//how parent could have changed? maybe you referenced node somewhere in composition.
if(parent === node.parentNode) parent.removeChild(node);
return node;
}
//wraps a Node in the provided markup.
//beforeBegin and afterEnd CAN contain associated markup. Like opening and closing Tag of the same Node.
//e.g.: wrapNode(node, "<div>", "</div>");
function wrapNode(node, beforeBegin, afterEnd){
return replace(node, [beforeBegin, node, afterEnd]);
}
//wraps the content of the node in the provided Markup.
//afterBegin and beforeEnd CAN contain associated markup. Like opening and closing Tag of the same Node.
function wrapContent(node, afterBegin, beforeEnd){
node.appendChild(fragment([afterBegin, node.childNodes, beforeEnd]));
return node;
}
return {
fragment: fragment,
replace: replace,
wrapNode: wrapNode,
wrapContent: wrapContent,
content: content,
}
})();
and your Markup:
var joexnprofile = document.querySelector('joexn-profile');
//telling by your code, it's not entirely clear
//wich of these you actually want to do:
nodeUtils.wrapNode(
joexnprofile,
'<center><div class="joexn-profile">',
'</div></center>'
);
//or
nodeUtils.wrapContent(
joexnprofile,
'<center><div class="joexn-profile">',
'</div></center>'
);
//or maybe
nodeUtils.replace(
//replace this:
joexnprofile,
//with this:
[
'<center><div class="joexn-profile">',
joexnprofile.childNodes,
'</div></center>'
]
);
Take a look at the code-examples and you get a first impression of what fragment()
is able to handle
var frag = nodeUtils.fragment([
//you can build this Array inline, no need to do that beforehand
condition?
window.title:
//simply inject `null` or `undefined` or `""` and this entry will be ignored
null,
//nest Arrays, they get parsed recursively
[
//mix (partial) HTML with other types
'<div class="columns">',
//real Nodes in the middle of some Markup: check
document.getElementById('leftColumn'),
//even more nesting, no problem
[
'<div class="middle">',
//handles anything Arraylike that contains Nodes or Markup
jQuery('.someClass'),
"</div>"
]
'</div>'
],
//NodeLists, no Problem
document.querySelectorAll("#footer > div")
])
Now it's up to you how you use this.
Upvotes: 1
Reputation: 943939
Despite the abstraction offered by insertAdjacentHTML
, you are still working on a DOM. It has elements in a strict hierarchy, it doesn't have start and end tags.
The HTML will be converted to DOM nodes and inserted. You aren't editing the raw source code.
Use createElement
instead. Get the element you want inside the new element using querySelector
and then use appendChild
to move it inside the new element.
Upvotes: 1