I have this string that can represent two things either some text or an anchor tag with text. I wrote something to always return the text like follows:
$(text).is('a') ? $(text).text() : text;
My logic is that if text is an anchor tag ? return the content of the anchor tag : if it's not then it's already just text so return that.
My question is that why does the following expression return true:
$('a').is('a');
Is is checking for the letter or anchor element? How can I check if my text is an anchor tag.
I would prefer not using any regular expressions
Edit:
I have a variable x that can have these values:
x = 'some text' or x = '<a>some text</a>'
How can I always extract the text from my variable x.
'a' is a valid query selector. It will select all the anchor elements in your document. So $('a').is('a') is saying "find anchor tags in the document and tell me if they are anchor tags" -- this will always be true unless there are no anchor tags in your document.
I have this string that can represent two things either some text or an anchor tag with text. I wrote something to always return the text like follows:
$(text).is('a') ? $(text).text() : text;
My logic is that if text is an anchor tag ? return the content of the anchor tag : if it's not then it's already just text so return that.
If possible, I would avoid having text be vague like that.
You certainly can't just dump the text into $() and assume all will be well. For instance, $("Some text here") searches the DOM for elements with the tag here inside elements with the tag text inside elements with the tag Some.
You've said you want to differentiate between
text = "Some text here"
and
text = "<a>Some text here</a>"
I'd just look at the string. Inspired partially by jQuery's check for whether what you pass it is a selector or HTML (here), how about:
text = text.trim();
if (text.substring(0, 2) === "<a" && text.substr(-1) === ">") {
text = $(text).text();
}
or similar?
But again, I'd avoid putting myself in this position in the first place if you have any choice.
Just set the string you have to an element's html. Grab the text of the element and this way you do not worry about if it is an anchor or plain text.
function getText (content) {
var div = document.createElement("div")
div.innerHTML = content
return div.textContent
}
console.log('some text', getText('some text'))
console.log('<a>some text</a>', getText('<a>some text</a>'))
If you want to use jQuery
function getText (content) {
return $("<div></div>", {html: content}).text()
}
console.log('some text', getText('some text'))
console.log('<a>some text</a>', getText('<a>some text</a>'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have been unable to replicate the issue as you explained it. Please see: https://api.jquery.com/is/
Here is my testing:
$(function() {
var tableData = [
"Text 1",
"Text 2",
"<a>Text 3</a>",
"Text 4"
];
function isLink(el) {
return $(el).is("a");
}
var x = [];
$.each(tableData, function(i, s) {
x.push(isLink(s) ? $(s).text().trim() : s);
});
$(".results").html(x.join(", "));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="results"></div>
You can pass Text, Element, or even a jQuery Object to the function.
Related
how do i check whether the inner HTML contains only Text or any tags inside .
for example here
<img src="/media/1020/phone.png">
this anchor tag inside there is an image tag is here i have to skip this scenario , where as
Hello
if this .innerHTML will return only Hello text , the above one returns the entire image tag like this <img src="/media/1020/phone.png"> .
so i need only with texts inside directly , if any html tag inside i have to throw error , any help
You might check if every childNode of the parent is a text node:
const as = [...document.querySelectorAll('a')];
as.forEach(a => {
console.log(
[...a.childNodes].every(node => node.nodeType === 3)
);
});
<img src="/media/1020/phone.png">
Hello
Hello<img src="/media/1020/phone.png">Hello
As yourself said i need direct text so i haven't considered the text inside these tags p,H1 etc. Here is my logic.
$(document).ready(function(){
$("a").each(function() {
if($(this).text() != '') {
console.log($(this).text());
}
else {
console.log("Error");
}
})
});
JSFiddle
https://jsfiddle.net/n6pe5fx4/15/
In WordPress I have added a custom editor button to get the contents of a selection and wrap it in a shortcode. The content is not getting the tags surrounding the selection.
For example:
<h1>Heading text</h1>
becomes
<h1>[shortcode]Heading Text[/shortcode]</h1>
Not
[shortcode]<h1>Heading Text</h1>[/shortcode]
It does work for
<h1>Header</h1>
<h2>Sub-Header</h2>
becomes
[shortcode]<h1>Header</h1>
<h2>Sub-Header</h2>[/shortcode]
This is the code I have.
(function() {
tinymce.create('tinymce.plugins.zgwd', {
init : function(ed, url) {
ed.addButton('headerblock', {
title : 'Add a Header Block',
cmd: 'headerblock',
});
ed.addCommand('headerblock', function() {
var selected_text = ed.selection.getContent({ format: 'html' });
var return_text = '';
if( !(selected_text && selected_text.length > 0) ) {
selected_text = 'Add header block text here';
}
return_text = '[header-block]' + selected_text + '[/header-block]';
ed.execCommand('mceInsertContent', 0, return_text);
});
},
createControl : function(n, cm) {
return null;
},
});
tinymce.PluginManager.add('zgwd', tinymce.plugins.zgwd);
})();
How can I get the content including the <h1> tags (or similar). Am I using the wrong function to get the content or is there a setting I am missing somewhere? I tried .getnode() but get the same result.
If you want to do something with a single block tag, getNode is your best bet. If you look at this Fiddle with the console open in Dev Tools, try selecting one line, and then try selecting both. getNode() and getContent() behave a little differently based on selection.
getNode() Returns the selected element, but, if you have more than one element selected, it returns the common ancestor (in this case body).
getSelection() will return tags if you select multiple blocks, which is why it works when trying to surround more than one block tag.
If I format a piece of text on a page like this:
document.execCommand('formatBlock', false, 'h1');
What do I do to remove this formatting?
I suppose document.execCommand('removeFormat',false,false) would do it?
Issuing document.execCommand('formatBlock', false, 'div') on the <h1>-block will remove the <h1>-tag and replace it with a <div>-tag 1. Would that be viable?
1 If you're not using IE that is
I clear the effect of h1 using this:
document.execCommand('formatBlock', false, 'p');
You have changed its format to h1, so we can change it back to normal paragraph format in the same way.
If your put each paragraph in a <div> , you can also use this:
document.execCommand('formatBlock', false, 'div');
to set the format to the same as other blocks.
I had the same problem where I need to delete the h1 tag wrapping my text.
What I did was get the parent node of the selected text:
var elem_parent_node =
window.getSelection().getRangeAt(0).startContainer.parentNode;
And then check if it's nodeName is "H1"; if yes, then store the selected text in a selected_text variable and then delete the node itself:
elem_parent_node.remove();
Then,
document.execCommand('insertText', false, select_text);
To replace the h1 with its text content node, then use the code below.
For a complete code, you would need to add some checks to make sure you remove what you want.
const button = document.getElementsByTagName('button')[0]
button.addEventListener('click', event => {
const selection = window.getSelection()
if (!selection.isCollapsed) {
selection.anchorNode.parentNode.replaceWith(selection.anchorNode)
}
})
<div contenteditable="true">
<p>Some text</p>
<h1>Select me then click the button</h1>
<p>Some text</p>
</div>
<button>Click to remove H1</button>
you may have to find the parent tag, then use innerHTML to get the text and replace the original data between the parent tag and end-tag with the innerHTML. This would however remove all formatting.
Seems that you cannot "undo" a formatBlock. You can always replace one "formatBlock" with some other "formatBlock" as long as it is another block level HTML tag.
Proposed solutions above are feasible, although they don't proof against the parent beeing the conteneditable-container (div?), so this could potentially remove/destroy the writable area.
A bit safer workaround for this issue may be to replace the "formatBlock" with a less used one, as f.ex. <address> and then remove this <address> with a regexp-replacer:
function Header() { //formatBlock: "h1"-"h6", "p", "pre", "div", "dd", "dt" or unformat it(=empty) - except using "address" (⇓see⇓)
var Fo = prompt('Please enter: h1-h6(=number), p, pre, ...','1');
if (Number(Fo)) {
Fo = 'h' + Fo; //format with h1-h6 directly by entering numbers - or p, pre, etc...
document.execCommand('formatblock', false, Fo);
} else if (Fo=='') { //if let empty, then unformat the block:
document.execCommand('formatBlock', false, 'address'); //using "address" as a temporary substitute - hoping that it's not used anywhere else in the document...
let inner = document.getElementById('content').innerHTML; //internal code of document
inner = inner.replace(/<address>/g,'<br>').replace(/n\n\n|\n\n|\n\s/g,'\n'); //Regex deleting (all) <address>-headings (and spaces) from document, replacing them with a line-break
document.getElementById('content').innerHTML = inner; //restore the content with replaced paragraph's
} else { document.execCommand('formatblock', false, Fo) }
}
I have the following HTML snippet:
<span class="target">Change me <a class="changeme" href="#">now</a></span>
I'd like to change the text node (i.e. "Change me ") inside the span from jQuery, while leaving the nested <a> tag with all attributes etc. intact. My initial huch was to use .text(...) on the span node, but as it turns out this will replace the whole inner part with the passed textual content.
I solved this with first cloning the <a> tag, then setting the new text content of <span> (which will remove the original <a> tag), and finally appending the cloned <a> tag to my <span>. This works, but feels such an overkill for a simple task like this. Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty, just like:
<span class="target"><a class="changeme" href="#">now</a></span>
I did a jsfiddle too. So, what would be the neat way to do this?
Try something like:
$('a.changeme').on('click', function() {
$(this).closest('.target').contents().not(this).eq(0).replaceWith('Do it again ');
});
demo: http://jsfiddle.net/eEMGz/
ref: http://api.jquery.com/contents/
Update:
I guess I read your question wrong, and you're trying to replace the text if it's already there and inject it otherwise. For this, try:
$('a.changeme').on('click', function() {
var
$tmp = $(this).closest('.target').contents().not(this).eq(0),
dia = document.createTextNode('Do it again ');
$tmp.length > 0 ? $tmp.replaceWith(dia) : $(dia).insertBefore(this);
});
Demo: http://jsfiddle.net/eEMGz/3/
You can use .contents():
//set the new text to replace the old text
var newText = 'New Text';
//bind `click` event handler to the `.changeme` elements
$('.changeme').on('click', function () {
//iterate over the nodes in this `<span>` element
$.each($(this).parent().contents(), function () {
//if the type of this node is undefined then it's a text node and we want to replace it
if (typeof this.tagName == 'undefined') {
//to replace the node we can use `.replaceWith()`
$(this).replaceWith(newText);
}
});
});
Here is a demo: http://jsfiddle.net/jasper/PURHA/1/
Some docs for ya:
.contents(): http://api.jquery.com/contents
.replaceWith(): http://api.jquery.com/replacewith
typeof: https://developer.mozilla.org/en/JavaScript/Reference/Operators/typeof
Update
var newText = 'New Text';
$('a').on('click', function () {
$.each($(this).parent().contents(), function () {
if (typeof this.tagName == 'undefined') {
//instead of replacing this node with the replacement string, just replace it with a blank string
$(this).replaceWith('');
}
});
//then add the replacement string to the `<span>` element regardless of it's initial state
$(this).parent().prepend(newText);
});
Demo: http://jsfiddle.net/jasper/PURHA/2/
You can try this.
var $textNode, $parent;
$('.changeme').on('click', function(){
$parent = $(this).parent();
$textNode= $parent.contents().filter(function() {
return this.nodeType == 3;
});
if($textNode.length){
$textNode.replaceWith('Content changed')
}
else{
$parent.prepend('New content');
}
});
Working demo - http://jsfiddle.net/ShankarSangoli/yx5Ju/8/
You step out of jQuery because it doesn't help you to deal with text nodes. The following will remove the first child of every <span> element with class "target" if and only if it exists and is a text node.
Demo: http://jsfiddle.net/yx5Ju/11/
Code:
$('span.target').each(function() {
var firstChild = this.firstChild;
if (firstChild && firstChild.nodeType == 3) {
firstChild.data = "Do it again";
}
});
This is not a perfect example I guess, but you could use contents function.
console.log($("span.target").contents()[0].data);
You could wrap the text into a span ... but ...
try this.
http://jsfiddle.net/Y8tMk/
$(function(){
var txt = '';
$('.target').contents().each(function(){
if(this.nodeType==3){
this.textContent = 'done ';
}
});
});
You can change the native (non-jquery) data property of the object. Updated jsfiddle here: http://jsfiddle.net/elgreg/yx5Ju/2/
Something like:
$('a.changeme3').click(function(){
$('span.target3').contents().get(0).data = 'Do it again';
});
The contents() gets the innards and the get(0) gets us back to the original element and the .data is now a reference to the native js textnode. (I haven't tested this cross browser.)
This jsfiddle and answer are really just an expanded explanation of the answer to this question:
Change text-nodes text
$('a.changeme').click(function() {
var firstNode= $(this).parent().contents()[0];
if( firstNode.nodeType==3){
firstNode.nodeValue='New text';
}
})
EDIT: not sure what layout rules you need, update to test only first node, otherwise adapt as needed
i have the following code:
function getArticleContent() {
var toPromote = 'example';
var toReplace = ''+toPromote+'';
var content = $(".a-entry").text();
if (content.search(toPromote) > -1)
{
$('.a-entry').html($('.a-entry').html().replace(new RegExp(toPromote, "g"), toReplace) );
}
else
{
//
}
}
$(document).ready(function() {
getArticleContent();
});
The code works fine, but if an image, or link has an title or alt attribute equal with the text that i want to replace the html it's broken, because the script put's the link in the alt, or title tag.
Best regards
I am trying to do something like this:
<div id="article">
<p>Some text here, bla bla.</p>
</div>
After the JS function i want to be:
<div>
<p>Some text here, bla bla.</p>
</div>
You can do something like this, though there may be a shorter way (text nodes are a very rare occurrence for me):
function getArticleContent() {
var toPromote = 'example';
$(".a-entry").contents().filter(function() { return this.nodeType == 3; })
.each(function() {
if(this.nodeValue.indexOf(toPromote) > -1)
$(this).replaceWith(this.nodeValue.replace(new RegExp(toPromote, "g"),
function(m) { return ''+m+''; })
);
});
}
$(getArticleContent);
You can try a demo here. This filters for text nodes specifically nodeType == 3, for .each() of those, it loops through, and if the text is there, replaces each match with the corresponding link.
Try using the jQuery .attr() tag to do the replacement on the tag on the href attribute or on the .text() of that is what you wish to change.
Otherwise, it might help to show some markup to see what exactly you want (before/after examples).
.attr('href',yournewstuff);
OR
.text(yournewstuff);