Replace <pre> without <code> to <pre> <code> once only - javascript

How to replace just <pre> which is not already wrapping <code>
with <pre><code> using jquery or javascript.
Example:
I have code like:
<pre><p>Hello</p></pre> <-- Target
<pre><code><p>Hello World</p></code></pre>
I need change only <pre> like this:
<pre><code><p>Hello</p></code></pre> <-- Only change this <pre>
<pre><code><p>Hello World</p></code></pre>
Check my problem below site: http://www.webmanajemen.com/p/testting-page.html

Thank to "Alon Eitan".
I have done with my problem using this jquery:
$("pre:not(:has(code))").each(function() { $(this).wrapInner( "<code></code>") });
Check my problem below site: web-development.cf/p/testting-page.html

You question is definitely unclear, but if I understand correctly, you want to basically add a tag into any tags that don't already contain .
This can be done by getting all of the tags, and then looking at its children to see if there is a tag:
function fillInMissingTags(outerTag, innerTag) {
var elements = document.getElementsByTagName(outerTag);
for(var elementIndex = 0, elementsLength = elements.length; elementIndex < elementsLength; elementIndex++) {
var element = elements[elementIndex],
found = false
html;
for(var childIndex = 0, childrenLength = element.children.length; childIndex < childrenLength; childIndex++) {
var child = element.children[childIndex];
if(child.tagName.toLowerCase() === innerTag) {
found = true;
html = element.innerHTML;
break;
}
}
if(found !== true) {
var codeElement = document.createElement(innerTag);
codeElement.innerHTML = html;
element.innerHTML = codeElement;
}
}
}
fillInMissingTags('pre', 'code');
This would only handle checking for in the immediate children. If you wanted to do a deep check, you would need to modify it to check the children recursively.
EDIT
I made it more generic so you can use the method to wrap the insides of any element that is missing a proper child.

Ick.
Regex I guess.
function replace(html) {
return html
// Look-ahead for <code>
.replace(/(<pre>)(?!<code>)/gi, '<pre><code>')
// Look-behind for </code>
.replace(/(<\/pre>)/gi, function(m, g, i, s) {
return s.slice(i-7, i) === '</code>'
? m
: '</code></pre>'
})
}
replace('<pre><p>Hello</p></pre>')
// returns "<pre><code><p>Hello</p></code></pre>"
replace('<pre><code><p>Hello World</p></code></pre>')
// returns "<pre><code><p>Hello World</p></code></pre>"

Related

If array item includes string but does not include other string then remove string

I have a big block of text which I've split by new line, so each item in the array is a line of text.
I'm looping through these lines and trying to detect where a line includes a </mark> but doesn't include a <mark>, and if this condition has been met then it removes the </mark> (as it's missing an opening tag).
final_formatted_log_split = logtext.split("\n");
for (i = 0, l = final_formatted_log_split.length; i < l; i++) {
if (final_formatted_log_split[i].includes("<mark>") === false) {
if (final_formatted_log_split[i].includes("</mark>") === true) {
var removed_mark = final_formatted_log_split[i].replace("</mark>", "");
}
}
}
var final_formatted_log = final_formatted_log_split.join("\n");
console.log(final_formatted_log);
and this console log still includes in the text where it doesn't include a
Just to be super clear, the expected outcome is the following:
if a line is like this:
line of text here</mark>
then it needs to remove the </mark> because it does not contain an opening <mark>
I suspect it is to do with the === false, but from what I've read online that is how others have used .includes to see if something does 'not include'
You can do it with simple String.prototype.includes:
const arr = [
'<mark>1</mark>',
'2</mark>',
'3</mark></mark>',
'<mark>4</mark>',
]
const replaceMark = (arr) => {
return arr.map(e => {
if (e.includes('</mark>') && !e.includes('<mark>')) e = e.replace(/\<\/mark\>/g, '')
return e
})
}
console.log('original:', arr)
console.log('replaced:', replaceMark(arr))
This solution doesn't handle complex situations like <mark>text</mark></mark>, only the most basic ones.
There's nothing wrong with ===false.Its working properly.To check this one you just put a console.log inside if block.
What you are doing here is,you are not replacing array value with modified one.So replace this line
var removed_mark = final_formatted_log_split[i].replace("</mark>", "");
with
final_formatted_log_split[i] = final_formatted_log_split[i].replace("</mark>", "");
And you can use one if block instead of two if block.
var final_formatted_log_split = logtext.split("\n");;
for (i = 0, l = final_formatted_log_split.length; i < l; i++) {
if (!final_formatted_log_split[i].includes("<mark>") && final_formatted_log_split[i].includes("</mark>")) {
final_formatted_log_split[i] = final_formatted_log_split[i].replace("</mark>", "");
}
}
var final_formatted_log = final_formatted_log_split.join("\n");
console.log(final_formatted_log);

Converting html to textual representation with preserved whitespace meaning of tags -- how?

Consider such html piece:
<p>foo</p><p>bar</p>
If you run (for example) jQuery text for it you will get "foobar" -- so it is raw text actually, not textual representation.
I am looking for some ready to use library to get textual representation, in this case it should be -- "foo\nbar". Or clever hints how to make this as easy as possible ;-).
NOTE: I am not looking for beautiful output text, but just preserved meaning of whitespaces, so for:
<tr><td>foo</td><td>bar</td></tr>
<tr><td>1</td><td>2</td></tr>
I will be happy with
foo bar
1 2
it does NOT have to be:
foo bar
1 2
(but of course no harm done).
Have you looked at the innerText or textContent properties?
function getText(element){
var s = "";
if(element.innerText){
s = element.innerText;
}else if(element.textContent){
s = element.textContent;
}
return s;
}
Example
Adds a PRE tag to the body and appends the body text.
document.body.appendChild(
document.createElement('pre')
)
.appendChild(
document.createTextNode(
getText(document.body)
)
);
Edit
Does using a range work with firefox?
var r = document.createRange();
r.selectNode(document.body);
console.log(r.toString());
Edit
It looks like you're stuck with a parsing function like this then.
var parse = function(element){
var s = "";
for(var i = 0; i < element.childNodes.length; i++){
if(/^(iframe|noscript|script|style)$/i.test(element.childNodes[i].nodeName)){
continue;
}else if(/^(tr|br|p|hr)$/i.test(element.childNodes[i].nodeName)){
s+='\n';
}else if(/^(td|th)$/.test(element.childNodes[i].nodeName)){
s+='\t';
}
if(element.childNodes[i].nodeType == 3){
s+=element.childNodes[i].nodeValue.replace(/[\r\n]+/, "");
}else{
s+=parse(element.childNodes[i]);
}
}
return s;
}
console.log(parse(document.body));
I started writing my own function probably at the same time as Zapthedingbat, so just for the record:
var NodeTypeEnum = { Element : 1,Attribute : 2, Text: 3, Comment :8,Document :9};
function doTextualRepresentation(elem)
{
if (elem.nodeType==NodeTypeEnum.Text)
return elem.nodeValue;
else if (elem.nodeType==NodeTypeEnum.Element || elem.nodeType==NodeTypeEnum.Document)
{
var s = "";
var child = elem.firstChild;
while (child!=null)
{
s += doTextualRepresentation(child);
child = child.nextSibling;
}
if (['P','DIV','TABLE','TR','BR','HR'].indexOf(elem.tagName)>-1)
s = "\n"+s+"\n";
else if (['TD','TR'].indexOf(elem.tagName)>-1)
s = "\t"+s+"\t";
return s;
}
return "";
}
function TextualRepresentation(elem)
{
return doTextualRepresentation(elem).replace(/\n[\s]+/g,"\n").replace(/\t{2,}/g,"\t");
}
One thing I am surprised with -- I couldn't get
for (var child in elem.childNodes)
working, and it is a pity, because I spend most time in C# and I like this syntax, theoretically it should work in JS, but it doesn't.

How do I find if an element contains a specific class with jQuery?

I need to check if an element contains a certain child class using JQUERY.
I tried:
if ($('#myElement').has('.myClass')) {
do work son
}
Didn't work.
My html code is laid out like this:
<div id="myElement">
<img>
<span>something</span>
<span class="myClass">Hello</span>
</div>
The easiest way would be to search for .myClass as a child of #myElement:
if($('#myElement .myClass')).length > 0)
If you only want first level children, you'd use >
if($('#myElement > .myClass')).length > 0)
Another way would be passing a selector to find and checking for any results:
if($('#myElement').find('.myClass').length > 0)
Or for first level children only:
if($('#myElement').children('.myClass').length > 0)
Just use QS
var hasClass = document.getElementById("myElement").querySelector(".myClass");
or you could recurse over the children
var element = document.getElementById("myElement");
var hasClass = recursivelyWalk(element.childNodes, function hasClass(node) {
return node.classList.contains("myClass");
});
function recursivelyWalk(nodes, cb) {
for (var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
var ret = cb(node);
if (ret) {
return ret;
}
if (node.childNodes && node.childNodes.length) {
var ret = recursivelyWalk(node.childNodes, cb);
if (ret) {
return ret;
}
}
}
}
Using recursivelyWalk and .classList (which can be shimmed).
Alternatively you can use jQuery
$("#myElement .myClass").hasClass("myClass");
or if you want composite operations without jQuery then try NodeComposite
NodeComposite.$("#myElement *").classList.contains("myClass");
Try:
if($('#myElement').children('.myClass').length) {
// Do what you need to
}
The jQuery object returns an array, which has the .length property. The above code checks if there are any .myClass children in #myElement and, if there are (when .length isn't 0), executes the code inside the if() statement.
Here's a more explicit version:
if($('#myElement').children('.myClass').length > 0) {
// Do what you need to
}
You could always use $('#myElement .myClass').length too, but $.children() is clearer to some. To find elements that aren't direct children, use $.find() in place of $.children().
if($.contains($('#myElement'), $('.myClass'))){
alert("True");
}
else{alert("False")};

Find the inner most text with javascript (jquery) regardless of number of nested elements and replace it

If I have this:
<em>any random text</em>
Or this:
any random text
Or this:
<em><div id="foo"><span>any random text</span></div></em>
I would like to capture the text "any random text" and then replace it.
How can I do this with jQuery? If not with jQuery, just regular javascript?
You could do this recursively. It's pretty simple:
function replaceTextNodes(node, newText) {
if (node.nodeType == 3) {
// Filter out text nodes that contain only whitespace
if (!/^\s*$/.test(node.data)) {
node.data = newText;
}
} else if (node.hasChildNodes()) {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
replaceTextNodes(node.childNodes[i], newText);
}
}
}
replaceTextNodes(document.getElementById("the-link"), "NEW TEXT");
$('a:contains(starcraft)').html('starcraft 2');
Edit for comment: jsfiddle
$('a').find(':only-child:last').html('starcraft 2');
You might want to check out this question: select deepest child in jQuery
Looks like you need to find the deepest child and then call .html('new string') or .text('new string') on it.
var link = $('#the-link');
var inner = link;
while(inner.children().length > 0)
inner = inner.children();
inner.html('whatever');

In Javascript or jQuery, how do I detect if a specific tag exists or not?

Given the following strings:
htmlStr1 = "<img>test1</img>";
htmlStr2 = "<div>test2</div>";
I'd like to know if there's a way to write a function just to detect for the "img" tag (for example). So if both of these strings are passed to it, and it should not do anything if the 2nd string is passed to it.
so for example, you'd run a function like:
result1 = checkIfTagExists(htmlStr1, "img");
result2 = checkIfTagExists(htmlStr2, "img");
alert(result1); // should output "true" or "1" or whatever
alert(result2); // should output "false" or do nothing
I would use a speedy RegExp for this, no need to use any jQuery selectors when not needed.
function checkIfTagExists(str, tag) {
return new RegExp('<'+tag+'[^>]*>','g').test(str);
}
If this is more of an example of functionality you are looking for and not the exact situation you'd use it in, the jQuery has selector may be helpful.
Related question with example.
For this situation you would do:
var str1ContainsImg = $(htmlStr1 + ":has(img)").length > 1;
var str2ContainsImg = $(htmlStr2 + ":has(img)").length > 1;
Edit: As tvanfosson pointed out in the comments, if your img tag doesn't have a closing tag ( <img src='' /> ),this exact solution wouldn't work. If that's an issue, you can check the tag name of the first element returned like this:
var htmlStr3 = "<img src='' />";
var containsEmptyImg = $(htmlStr3 + ":has(img)").length > 1 ||
$(htmlStr3 + ":has(img)")[0].tagName.toUpperCase() == 'IMG';
Wrap this in an if statement and you are good to go
jQuery(jQuery(htmlStr1)).find('img').size() > 0
This will be easier if the strings are in the innerHTML of an element:
function checkIfTagExists(element, tagName) {
return element.getElementsByTagName(tagName).length > 0;
}
A regex check would probably be insufficient (see RegEx match open tags except XHTML self-contained tags) :)
If you really do just have the strings, you can create an element from the string, and set the innerHTML to the string, then do the above check on that new element. This is what the $(tagName, htmlContext) would be doing.
This might have a bit of overhead, but it should be robust enough for use with any given string or the innerHTML of any element.
function getTagCountFromString(string, tag) {
var count = 0;
tag = tag.toLowerCase();
$(string).each(function(idx, el){
if(el.nodeType === 1) {
if(el.tagName && el.tagName.toLowerCase() === tag) {
count++;
}
if(el.childNodes.length > 0) {
try {
count += getTagCountFromString(el.innerHTML, tag);
} catch (ex) { }
}
}
});
return count;
}
getTagCountFromString('<img src=""/><a href=""/>', 'img'); //returns 1
Then to get a boolean value you could check if the count is not equal to 0 or make a helper function which does it for you.
in straight javascript:
function checkIfTagExists(src, tag) {
var re = "<"+tag + ">\.+<\\/"+tag+">";
return new RegExp(re).test(src);
}

Categories