Is there a clean and robust way in which I can test (using pure javascript or also jQuery) if an HTML element can contain some text?
For instance,
I believe you're looking for a list of void HTML tags:
The following is a complete list of the void elements in HTML:
area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
From there you would just test the node to see if it is in the list. For example:
var voidNodeTags = ['AREA', 'BASE', ...];
var isNodeVoid = function (node) {
return voidNodeTags.indexOf(node.nodeName) !== -1;
};
http://jsfiddle.net/3uQjH/
The W3 standard for "void elements" specifies:
Void elements
area, base, br, col, embed, hr, img, input, keygen, link, menuitem, meta, param, source, track, wbr
And apparently there's some unofficial tags as well.
You can make a black list and use .prop('tagName')
to get the tag name:
(function ($) {
var cannotContainText = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX'];
$.fn.canContainText = function() {
var tagName = $(this).prop('tagName').toUpperCase();
return ($.inArray(tagName, cannotContainText) == -1);
};
}(jQuery));
$('<br>').canContainText(); //false
$('<div>').canContainText(); //true
Here you can also add your own tags to cannotContainText
(eg. to add <tr>
which is not officially a void element as it doesn't match the specification "A void element is an element whose content model never allows it to have contents under any circumstances. Void elements can have attributes.").
I mostly agree with everybody that a blacklist would be a very orthodox way of doing it but if we are really required to test for the ability, then this would be one way I think (with some jquery):
isTextContainerTag=function(tagName){
try{
var test = $('<'+tagName+'></'+tagName+'>');
test.html(123);
if(test.html()=='123'){
return true;
}else{
return false;
}
}
catch(err){return false;}
}
I tested it on Chrome on various tags names and got these results:
console.log('input',isTextContainerTag('input'));//answer:false
console.log('textarea',isTextContainerTag('textarea'));//true
console.log('option',isTextContainerTag('option'));//true
console.log('ul',isTextContainerTag('ul'));//true
console.log('li',isTextContainerTag('li'));//true
console.log('tr',isTextContainerTag('tr'));//true
console.log('td',isTextContainerTag('td'));//true
console.log('hr',isTextContainerTag('hr'));//false
console.log('br',isTextContainerTag('br'));//false
console.log('div',isTextContainerTag('div'));//true
console.log('p',isTextContainerTag('p'));//true
console.log('html',isTextContainerTag('html'));//false
console.log('body',isTextContainerTag('body'));//false
console.log('table',isTextContainerTag('table'));//false
console.log('tbody',isTextContainerTag('tbody'));//true
We may also test some real tags using jquery "prop" on these two examples:
<div id="A">AAAAAA</div>
<br id="B">
Which gives:
var obj1 = $('#A').prop('tagName');
var obj2 = $('#B').prop('tagName');
console.log('id:A (div)',isTextContainerTag(obj1));//true
console.log('id:B (br)',isTextContainerTag(obj2));//false
I'm sure it is way away from perfect though, but it was fun to look into.