Change icon if text contains string with jQuery - javascript

I have the following structure that cannot be changed:
<div class="activityinstance">
<a class="aalink" onclick="" href="https://...">
<img src="..../icon" class="iconlarge activityicon">
<span class="instancename">[h5p-iv] Interaktives Video
<span class="accesshide ">Interactive Content</span>
</span>
</a>
</div>
What I need to do, is to change the icon if span.instancename contains "[h5p-iv]" (plus, ideally, delete or hide that partial string from the span)
The "if" and "then" are not part of the code and the last line is unfinished, this is intended to show what I want to achieve. How do I construct an if-then in Javascript to achieve that logic?
if
$(".activityinstance .instancename:contains('[h5p-iv]')")
then
$(".activityicon") attr("src", "/static/img/icons/video.svg");
The second part is to change
<span class="instancename">[h5p-iv] Interaktives Video</span>
into
<span class="instancename">Interaktives Video</span>
that is: removing the string from "contains"
Explanation:
Moodle does not discern H5P activities, they all get the same icon. Teachers are supposed to be able to enter strings to the activity-names in order to get a different icon. So in the end there will be a list of strings linked to different icons. If that can be simplified by a switch etc., even better, but there are not that many different icons, that it would be unreasonable to repeat the code regardingly.
Additions 1: added span.accesshide because it became visible after string replacement.
Additions 2: I actually have a (kind of) working code now, but I suppose it could be done more safely and elegantly.... Any suggestions?
var elem = $(".instancename:contains('[icon-video]')");
if (elem.length) {
$(".instancename:contains('[icon-video]')").each(function() {
$(this).prev().attr("src", "/static/img/icons/video.svg");
$(".accesshide").remove();
elem.text(function(_, text) { return text.replace('[icon-video] ', '');
});
});
}
Esp. removing the .accesshide worries me, I am not sure, what it does and I would rather just remove the display and not the whole thing from the DOM. I suppose the text replace reads the whole text including the contained span.accesshide and puts the text back minus the replaced text - but also removing the span.accesshide-tag thus it looses its css that makes it invisible.

jQuery object is truthy so you would need to check its length to see if it found the element. Other thing you need to do is just do a simple string replacement
var elem = $(".activityinstance .instancename:contains('[h5p-iv]')");
if (elem.length) {
$(".activityicon").attr("src", "/static/img/icons/video.svg");
elem.text(function(_, text) { return text.replace('[h5p-iv] ', ''); });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="activityinstance">
<a class="aalink" onclick="" href="https://...">
<img src="..../icon" class="iconlarge activityicon">
<span class="instancename">[h5p-iv] Interaktives Video</span>
</a>
</div>
Now since you said it could be multiple
function replaceThis(text, imgPath) {
$(".activityinstance .instancename:contains('" + text + "')").each(function() {
const instanceName = $(this);
instanceName.find(".accesshide").hide();
instanceName.prev("img").attr("src", imgPath);
instanceName.contents().each(function(_, node) {
if (node.nodeValue && node.nodeValue.includes(text)) {
node.nodeValue = node.nodeValue.replace(text, "");
}
})
});
}
replaceThis("[h5p-iv] ", "http://placekitten.com/20/20");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="activityinstance">
<a class="aalink" onclick="" href="https://...">
<img src="..../icon" class="iconlarge activityicon">
<span class="instancename">[h5p-iv] Interaktives Video
<span class="accesshide ">Interactive Content</span>
</span>
</a>
</div>

Related

scope for jquery onclick event/parameters with generic onclick event

How would I capture additional details in a div/span tag with a generic onclick event?
I.e.,
<span id=item1>Value #001<span id=clickableitem>xxx</span></span>
<span id=item2>Value #002<span id=clickableitem>xxx</span></span>
<span id=item3>Value #003<span id=clickableitem>xxx</span></span>
And then:
$(document).on('click','#clickableitem',function(e){
e.preventDefault();
// how do I get the "value #001, #002, #003" value just 'outside'
// of the span tag?
I was trying to figure it out with .parent().html(), but that didn't quite seem to work...
Thanks!
HTML:
<span id=item1>Value #001<span class="clickableitem">xxx</span></span>
<span id=item2>Value #002<span class="clickableitem">xxx</span></span>
<span id=item3>Value #003<span class="clickableitem">xxx</span></span>
JS:
$('.clickableitem').click(function() {
let text = $(this).parent().text().substring(0, $(this).parent().text().indexOf($(this).text()));
console.log(text);
});
Replacing the text is unsafe could be resulting in an empty text if the value is the same as xxxx child span....
This aproach is more effective
HTML
<span id='item1'>Value #001<span id='clickableitem1' class='spanClickable'>xxx</span></span>
<span id='item2'>Value #002<span id='clickableitem2' class='spanClickable'>xxx</span></span>
<span id='item3'>Value #003<span id='clickableitem3' class='spanClickable'>xxx</span></span>
JS
$(document).on('click','.spanClickable',function(e){
alert( $(this).parent().contents().get(0).nodeValue );
});
The id property should always be unique, instead give your span's a common className and hook up the event handler callback with it, also, in your HTML
you need to put single or double quotes around the values of properties such as id and class:
HTML:
<span id='item1'>Value #001<span id='clickableitem1' class='spanClickable'>xxx</span></span>
<span id='item2'>Value #002<span id='clickableitem2' class='spanClickable'>xxx</span></span>
<span id='item3'>Value #003<span id='clickableitem3' class='spanClickable'>xxx</span></span>
JQuery:
$(document).on('click','.spanClickable',function(e){
e.preventDefault();
//Using .text() on the parent produces the child span text as well
//Replace the child text and the word Value since all you want is
//ex. #001
const childSpanText = $(this).text();
alert($(this).parent().text().replace(childSpanText, "").replace('Value ', ''));
});
Working Fiddle
(https://jsfiddle.net/a5Lkon4j/2/)

Editing quickedit-label text

I would like to change the text of the quickedit-label class.
<span class="quickedit" data-id="9917488">
<span class="quickedit-content">
<span class="quickedit-label">Label text</span>
<a class="rename-icon" href="#" title="Rename"></a>
</span>
</span>
I used the following code to get the text and pass it to a variable, then change the text and assign it to the element.
var labelContent = $('a.quickedit').text;
var newLabel = labelContent.subst(6,9);
$('a.quickedit').text = newLabel;
I tried using innerhtml, .data() and .value() but all returned incorrect outputs.
I know this isn't correct (and the newLabel format is just for demonstration purposes) but this should outline what I'm trying to do.
Ideally, I would like to have this within a function where the data-id of the span I want to edit is passed.
Thanks for any help on this.
You can use jquery .text( function ) method to do this work like this example.
$(".quickedit-label").text(function(index, text){
return text.substr(6, 9);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="quickedit-label">Label text</span>

Insert span in a dom element without overwrite child nodes?

I have an HTML article with some annotations that I retrieve with SPARQL queries. These annotations refer to some text in the document, and I have to highlight this text (wrapping it in a span).
I had already asked how to wrap text in a span, but now I have a more specific problem that I do not know how to solve.
The code I wrote was:
var currentText = $("#"+v[4]["element"]+"").text();
var newText = currentText.substring(0, v[5]["start"]) + "<span class=' annotation' >" + currentText.substring(v[5]["start"], v[6]["end"]) + "</span>" + currentText.substring(v[6]["end"], currentText.length);
$("#"+v[4]["element"]+"").html(newText);
Where:
v[4]["element"] is the id of the parent element of the annotation
v[5]["start"] is the position of the first character of the annotation
v[6]["end"] is the position of the last character of the annoation
Note that start and end don't consider html tags.
In fact my mistake consists in extracting data from the node with the text() method (to be able to go back to the correct position of the annotation) and put back with the html() method; but in this manner if parent node has children nodes, they will be lost and overwritten by simple text.
Example:
having an annotation on '2003'
<p class="metadata-entry" id="k673f4141ea127b">
<span class="generated" id="bcf5791f3bcca26">Publication date (<span class="data" id="caa7b9266191929">collection</span>): </span>
2003
</p>
It becomes:
<p class="metadata-entry" id="k673f4141ea127b">
Publication date (collection):
<span class="annotation">2003</span>
</p>
I think I should work with nodes instead of simply extract and rewrite the content, but I don't know how to identify the exact point where to insert the annotation without considering html tags and without eliminating child elements.
I read something about the jQuery .contents() method, but I didn't figure out how to use it in my code.
Can anyone help me with this issue? Thank you
EDIT: Added php code to extract body of the page.
function get_doc_body(){
if (isset ($_GET ["doc_url"])) {
$doc_url = $_GET ["doc_url"];
$doc_name = $_GET ["doc_name"];
$doc = new DOMDocument;
$mock_doc = new DOMDocument;
$doc->loadHTML(file_get_contents($doc_url.'/'.$doc_name));
$doc_body = $doc->getElementsByTagName('body')->item(0);
foreach ($doc_body->childNodes as $child){
$mock_doc->appendChild($mock_doc->importNode($child, true));
}
$doc_html = $mock_doc->saveHTML();
$doc_html = str_replace ('src="images','src="'.$doc_url.'/images',$doc_html);
echo($doc_html);
}
}
Instead of doing all these, you can either use $(el).append() or $(el).prepend() for inserting the <span> tag!
$("#k673f4141ea127b").append('<span class="annotation">2003</span>');
Or, If I understand correctly, you wanna wrap the final 2003 with a span.annotation right? If that's the case, you can do:
$("#k673f4141ea127b").contents().eq(1).wrap('<span class="annotation" />');
Fiddle:
$(document).ready(function() {
$("#k673f4141ea127b").contents().eq(1).wrap('<span class="annotation" />');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p class="metadata-entry" id="k673f4141ea127b">
<span class="generated" id="bcf5791f3bcca26">Publication date (<span class="data" id="caa7b9266191929">collection</span>): </span>
2003
</p>
At the end my solution is in this Fiddle.
Generalizing:
var element = document.getElementById(id);
var totalText = element.textContent;
var toFindText = totalText.substring(start,end);
var toReplaceText = "<span class='annotation'>"+toFindText+"</span>";
element.innerHTML = element.innerHTML.replace(toFindText, toReplaceText);
Hope it could help someone else.
Note: This don't check if two or more annotations refers to the same node, I'm working on it right now.

How to replace inner content of a class?

I have used a class 4 times in a page and I want to replace the content from one of them by using JavaScript
Here is the code of my html
<span class="footer">Publisher Solutions</span>
<span class="footer">Social Media 360</span>
<span class="footer">Partnerships</span>
<span class="footer">Brown Bag Presentations</span>
and I want to change like this
<span class="footer">Publisher Solutions</span>
<span class="footer">Social Media 360</span>
<span class="footer">Partnerships</span>
<span class="footer">Custom New Text From js</span>
Would something like this fits?
var elems = document.getElementsByClassName("footer");
var elem = elems[3];
elem.firstChild.href="edited_link_from_js.html";
elem.firstChild.innerHTML="My new text";
Here I manually select the 4th one, but you can change by elems.lenght - 1 if you always want last, or any selector you need.

jQuery find and replace string

I have somewhere on website a specific text, let's say "lollypops", and I want to replace all the occurrences of this string with "marshmellows". The problem is that I don't know where exactly the text is. I know I could do something like:
$(body).html($(body).html().replace('lollypops', 'marshmellows'));
This would probably work, but I need to rewrite as little HTML as I can, so I'm thinking something like:
search for the string
find the closest parent element
rewrite only the closest parent element
replace this even in attributes, but not all, for example replace it in class, but not in src
In example, I would have structure like this
<body>
<div>
<div>
<p>
<h1>
<a>lollypops</a>
</h1>
</p>
<span>lollypops</span>
</div>
</div>
<p>
<span class="lollypops">Hello, World!</span>
<img src="/lollypops.jpg" alt="Cool image" />
</p>
<body>
In this example, every occurrence of "lollypops" would be replaced, only <img src="... would remain the same and the only elements that would actually be manipulated would be <a> and both <span>s.
Does anybody know how to do this?
You could do something like this:
$("span, p").each(function() {
var text = $(this).text();
text = text.replace("lollypops", "marshmellows");
$(this).text(text);
});
It will be better to mark all tags with text that needs to be examined with a suitable class name.
Also, this may have performance issues. jQuery or javascript in general aren't really suitable for this kind of operations. You are better off doing it server side.
You could do something this way:
$(document.body).find('*').each(function() {
if($(this).hasClass('lollypops')){ //class replacing..many ways to do this :)
$(this).removeClass('lollypops');
$(this).addClass('marshmellows');
}
var tmp = $(this).children().remove(); //removing and saving children to a tmp obj
var text = $(this).text(); //getting just current node text
text = text.replace(/lollypops/g, "marshmellows"); //replacing every lollypops occurence with marshmellows
$(this).text(text); //setting text
$(this).append(tmp); //re-append 'foundlings'
});
example: http://jsfiddle.net/steweb/MhQZD/
You could do something like this:
HTML
<div class="element">
<span>Hi, I am Murtaza</span>
</div>
jQuery
$(".element span").text(function(index, text) {
return text.replace('am', 'am not');
});
Below is the code I used to replace some text, with colored text. It's simple, took the text and replace it within an HTML tag. It works for each words in that class tags.
$('.hightlight').each(function(){
//highlight_words('going', this);
var high = 'going';
high = high.replace(/\W/g, '');
var str = high.split(" ");
var text = $(this).text();
text = text.replace(str, "<span style='color: blue'>"+str+"</span>");
$(this).html(text);
});
var string ='my string'
var new_string = string.replace('string','new string');
alert(string);
alert(new_string);
Why you just don't add a class to the string container and then replace the inner text ? Just like in this example.
HTML:
<div>
<div>
<p>
<h1>
<a class="swapText">lollipops</a>
</h1>
</p>
<span class="swapText">lollipops</span>
</div>
</div>
<p>
<span class="lollipops">Hello, World!</span>
<img src="/lollipops.jpg" alt="Cool image" />
</p>
jQuery:
$(document).ready(function() {
$('.swapText').text("marshmallows");
});

Categories

Resources