programmatically select part of content on another contenteditable div - javascript

<div id="leftdiv" style="float:left;display:inline-block;height:100px;font-family:Helvetica;font-size:14px;width:300px;border:1px solid red;" contenteditable>
<div>
first text
</div>
<div>
second text
</div>
...
<div>
other texts
</div>
</div>
<div id="rightdiv" style="margin-left:1em;display:inline-block;float:left;width:300px;height:100px;font-family:Helvetica;font-size:14px;border:1px solid red;" contenteditable>
<div>
first text
</div>
<div>
second text
</div>
...
<div>
other texts
</div>
</div>
I have two contenteditable divs and these divs have exactly the same content. When I highlight part of content in leftdiv like "ond" in "second" text using mouse, i want exactly the same part in rightdiv highlighted at the same time. Eventually 2 highlighting in seperate divs will occur simultaneously.
I have tried this but nothing happens.
$('#leftdiv').on('mousedown', function() {
$('#leftdiv').on('selectstart', function() {
document.getElementById('rightdiv').tabIndex = -1 ;
document.getElementById('rightdiv').focus();
var range = document.createRange();
range.selectNodeContents(this);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
});
});

This is far from a complete solution, and it makes use of css to fake the second selection, but perhaps it will give you an idea.
Try selecting "ond" in the leftdiv, as you suggested in your description, and "ond" is highlighted in the rightdiv (after the selection is complete - it won't live update as you drag the mouse to change the selection).
If you select content across multiple divs within leftdiv, this will break, and if you select text that appears multiple times, it will highlight the first match, not the exact match. Like I said, just trying to give you a potential path to explore further.
$('#leftdiv').on('mouseup', function() {
$("*").removeClass("highlight");
$('#rightdiv').html($('#leftdiv').html());
var selection = window.getSelection()+"";
var matchStart = $('#rightdiv').html().indexOf(selection);
var matchEnd = matchStart + selection.length - 1;
var beforeMatch = $('#rightdiv').html().slice(0, matchStart);
var matchText = $('#rightdiv').html().slice(matchStart, matchEnd + 1);
var afterMatch = $('#rightdiv').html().slice(matchEnd + 1);
$('#rightdiv').html(beforeMatch + "<font class='highlight'>" + matchText + "</font>" + afterMatch);
});
.highlight {background-color:#b4daf7;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="leftdiv" style="float:left;display:inline-block;height:100px;font-family:Helvetica;font-size:14px;width:300px;border:1px solid red;" contenteditable>
<div>
first text
</div>
<div>
second text
</div>
...
<div>
other texts
</div>
</div>
<div id="rightdiv" style="margin-left:1em;display:inline-block;float:left;width:300px;height:100px;font-family:Helvetica;font-size:14px;border:1px solid red;" contenteditable>
<div>
first text
</div>
<div>
second text
</div>
...
<div>
other texts
</div>
</div>

Related

Call previous sibling as function parameter?

I'm building a wee letter-writing tool that will have a range of paragraphs the user can choose to add to a letter, but I worry that I'm doing it in a really inefficient way.
Currently, it's structured like this:
<p id="deposit-dispute" class="paragraph">This is a paragraph about deposits not being protected</p>
<button onclick="addPara(depositDispute)" class="add">Add paragraph</button>
and then in the Javascript, I create a const that pulls the inner HTML of that id:
const depositDispute = "\n" + document.getElementById("deposit-dispute").innerHTML + "\n";
which the addPara() function then adds to the textarea:
function addPara(text) {
document.getElementById("text-body").value += text;
}
But would there be a way to make the function just call whatever the previous p element had in it, rather than having to give them all unique IDs and creating a unique variable for them all?
Here it is in a codepen so you can see what I'm trying to do - the paragraphs to be added are in the accordion on the right: https://codepen.io/gordonmaloney/pen/GRWyjOP
Thanks a lot - and big apologies if this is a ridiculously amateurish question, I've spent ages trying to google a solution but can't find a thing!
G
Each box contains a paragraph and a button.
We can get all the boxes and each box paragraph and button, and finally add click event to the button to insert the paragraph html of this box to the textarea
// Get textarea and boxes
var textarea = document.getElementById('textarea');
var boxes = document.querySelectorAll('.box');
// get the button and the paragraph of each box
boxes.forEach(box => {
var btn = box.querySelector('.button');
var paragraph = box.querySelector('.paragraph');
// add the html of the selected box paragraph to the textarea
btn.addEventListener('click', () => {
textarea.value += "\n" + paragraph.innerHTML; + "\n";
});
});
<div class="wrapper">
<div class="box">
<p class="paragraph">This is paragraph 1</p>
<button class="button">Add to textarea</button>
</div>
<div class="box">
<p class="paragraph">This is paragraph 2</p>
<button class="button">Add to textarea</button>
</div>
<div class="box">
<p class="paragraph">This is paragraph 3</p>
<button class="button">Add to textarea</button>
</div>
</div>
<textarea name="" id="textarea" cols="30" rows="10"></textarea>

How to search for keywords from array and highlight all text in parent div tag using JavaScript

I'm searching a web page containing a list of products for keywords from an array. When it finds any word in the array it highlights it with a red background. That works fine. Now, when it finds the keywords I want it to make all of the text for that product (within the <div> tag) to have a light grey colour so I can easily ignore that particular product when scanning down the page. How can I do this? Here's the demo: JSFiddle
Here's the HTML:
<div>
<p>I bought some apples.</p>
<p>Apples are £2 per kg.</p>
</div>
<hr>
<div>
<p>I bought some oranges.</p>
<p>Oranges are £1.50 per kg.</p>
</div>
<hr>
<div>
<p>I bought some pears.</p>
<p>Pears are £1.80 per kg.</p>
</div>
Here's the JavaScript:
var regex = /(apples|oranges)/g;
$('body a, body p').each(function() {
var $this = $(this);
var text = $this.text();
if (text.match(regex) && $this.children().length===0) {
$this.html(
$this.html().replace(regex, '<span style="background: #fa7373;">$1</span>')
);
}
});
You can check the text of each element and set its CSS color property if it matches the regular expression.
var regex = /(apples|oranges)/g;
$('body a, body p, body div').each(function() {
var $this = $(this);
var text = $this.text();
if (text.match(regex)) {
$this.css("color", "grey");
if($this.children().length===0){
$this.html(
$this.html().replace(regex, '<span style="background: #fa7373;">$1</span>')
);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<p>I bought some apples.</p>
<p>Apples are £2 per kg.</p>
</div>
<hr>
<div>
<p>I bought some oranges.</p>
<p>Oranges are £1.50 per kg.</p>
</div>
<hr>
<div>
<p>I bought some pears.</p>
<p>Pears are £1.80 per kg.</p>
</div>

Swapping text of parent and child elements

I have the following elements:
<div contenteditable="true" id="write">
<div class="tooltip">
<span>test</span> <!--text to be written in text area-->
<span class="tooltiptext"> <!--holds words to be displayed on hover-->
<span class="popUpWord">hello</span>
<br>
<span class="popUpWord">dog</span>
</span>
</div>
<div class="tooltip">
<span>test</span>
<span class="tooltiptext">
<span class="popUpWord">hello</span>
<br>
<span class="popUpWord">test</span>
</span>
</div>
</div>
These basically show a pop-up similar to the following - http://www.w3schools.com/css/tryit.asp?filename=trycss_tooltip
On hover event of elements having the '.tooltop' class (words to be displayed inside the pop-up area), I would like to swap the word which is hovered in the pop-up area, with the word displayed in the text area after a couple of seconds.
I did the following function:
//--choosing word from pop-up list--//
$(document).on("mouseover", ".popUpWord", function(e)
{
if(!timeoutId)
{
timeoutId=window.setTimeout(function()
{
timeoutId=null;
e.currentTarget.innerHTML = e.fromElement.parentElement.parentElement.childNodes[0].childNodes[0].innerText;
/*not working*/ e.fromElement.parentElement.parentElement.childNodes[0].childNodes[0].innerHTML = e.currentTarget.innerHTML; //Although the elements I want to swap are referred to correctly,the element's text is not changing. (Tried using innerText)
},1500);
}
}).on('mouseout', '.popUpWord', function(e)
{
if(timeoutId)
{
window.clearTimeout(timeoutId);
timeoutId=null;
}
});
However, in the line marked not working - the element's text is not changing. And it is being referred to correctly.
Any help is greatly appreciated.
Thanks
Its because you are assigning the value of tooltip to the text element and re-assigning it to the tooltip.
Try this:
timeoutId=null;
var text = e.currentTarget.innerHTML;
e.currentTarget.innerHTML = e.fromElement.parentElement.parentElement.childNodes[0].childNodes[0].innerText;
e.fromElement.parentElement.parentElement.childNodes[0].childNodes[0].innerHTML = text;
You are trying to locate the source and destination elements in a way that can only lead to brittleness and errors. Give elements you know you want to work with ids and reference them that way.
Try this out. Hover over "helo".
var orig = $("orig");
var hold = $("hold");
var timeoutId = null;
$(".popUpWord").on("mouseover", function(e){
if(!timeoutId) {
timeoutId = setTimeout(function() {
e.target.innerHTML = original.textContent;
original.innerHTML = e.target.innerHTML;
},1500);
}
}).on('mouseout', function(e){
if(timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" id="write">
<div class="tooltip">
<span id="original">test</span> <!--text to be written in text area-->
<span class="tooltiptext"> <!--holds words to be displayed on hover-->
<span id="hold" class="popUpWord">hello</span>
<br>
<span class="popUpWord">dog</span>
</span>
</div>
<div class="tooltip">
<span>test</span>
<span class="tooltiptext">
<span class="popUpWord">hello</span>
<br>
<span class="popUpWord">test</span>
</span>
</div>
</div>
You will need to store the new text strings in a variable. Otherwise you are just setting it right back:
timeoutId=window.setTimeout(function()
{
var child = e.currentTarget,
parent = e.fromElement.parentElement.parentElement.childNodes[0].childNodes[0],
childtext = child.innerText,
parenttext = parent.innerText
child.innerHTML = parenttext;
parent.innerHTML = childtext;
},1500);

Javascript split by spaces, but not within html-tags

My first goal is to split a string by spaces, but not the ones within html-tags.
I've tried to rewrite the following, unsuccessfully: Javascript split by spaces but not those in quotes
What would the regex look like in:
arr = fullHtmlString.split(?);
?
My main goal is to shift an IMG-tag by one space at a time.
After that I'll iterate over the array, search for the img-tag, remove it, and add it the next item, and finally join the array.
The code I use at the moment is quite comprehensive and use jQuery extensively to achive the goal.
Input:
<div>
<p><img class=something>Some text.</p>
<p>Some more text.</p>
</div>
Deisred output first time:
<div>
<p>Some<img class=something> text.</p>
<p>Some more text.</p>
</div>
...second time:
<div>
<p>Some text.<img class=something></p>
<p>Some more text.</p>
</div>
...third time:
<div>
<p>Some text.</p>
<p><img class=something>Some more text.</p>
</div>
You should not try to do this with a regular expression, why explained here.
You can use DOM properties and methods though
function run(){
var img = document.querySelector(".something"),
sibling = img,
parent = img.parentNode,
next = parent.nextElementSibling;
//Search for the next textNode
while((sibling = sibling.nextSibling) && sibling.nodeType !=3);
if(sibling) {
//split the text only once,
//so "some more text" becomes ["some","more text"]
var textParts = sibling.textContent.split(/ (.*)?/,2);
//put the first split item before the sibling
parent.insertBefore(document.createTextNode(textParts[0]+" "),sibling);
//replace the sibling with the img element
parent.replaceChild(img,sibling);
//finally if there was more text insert it after the img
textParts[1] && parent.insertBefore(document.createTextNode(textParts[1]),img.nextSibling);
} else if(!sibling && next) {
//no sibling in the current parent,
//so prepend it to the next available element in parent
next.insertBefore(img,next.firstChild);
} else {
clearInterval(timer);
}
}
var timer = setInterval(run,2000);
<div>
<p><img class="something" src="http://placehold.it/10x10">Some text.</p>
<p>Some <span>skip me</span> more text.</p>
</div>

How to add text when onmouseover is activated

<div id="first_caption">
<p style="float: left; clear: left">
<img
src="http://www.ottawaskeptics.org/images/stories/lightbulb.jpg"
onmouseover="this.src='http://pngimg.com/upload/small/bulb_PNG1251.png'"
onmouseout="this.src='http://www.ottawaskeptics.org/images/stories/lightbulb.jpg'"
height="50" width="50"
>
<p>How can you save money to do the things you love, and live a healthier life? rollover on the light bulb to see how!</p>
</div>
This is the code. what i am trying to do is make a text appear below the first paragraph when i hover over the image.
Add div or span, assign an ID and then on event add values to the ID.
var div = document.getElementById('divID');
div.innerHTML = div.innerHTML + 'Extra stuff';
here is the complete example:
click here
<div id="heading1">
This is existing text.
</div>
<script>
function myClick(){
text = "This text is added.";
document.getElementById('heading1').innerHTML = document.getElementById('heading1').innerHTML + text;
}
</script>

Categories

Resources