I would like to get the position of highlighted text but not the bounded yellow rect (using range.getBoundingClientRect()) here I'm talking about the red area in the picture meaning it have an indent. Basically I want to save selection area and be-able to replicate them. I could not use the technique to save and restore Range object.
Here is what I'm trying to do:
function addMarkerOnSelection(){
var range = window.getSelection().getRangeAt(0);
var rect = range.getBoundingClientRect();
var scrolltop = jQuery('body,html').scrollTop();
//var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
var marker = document.createElement('div');
marker.style.position = 'absolute';
marker.style.display='block';
marker.style.left = rect.left + 'px';
marker.style.top = scrolltop + rect.top + 'px';
marker.style.height = rect.bottom-rect.top + 'px';
marker.style.width = rect.right-rect.left + 'px';
marker.style.border='1px solid black';
marker.style.background='yellow';
marker.style.opacity = 0.5;
document.body.appendChild(marker);
}
You can try google docs, try no highlight multiple line of text and add an comment. They wrap the highlight area correctly.
I have another approach, using Range.surroundContents I am able to wrap content with an element and its work as expected. BUT how to save it without saving the whole text content?
function surround(){
var range = window.getSelection().getRangeAt(0);
var marker = document.createElement('span');
marker.style.border='1px solid black';
marker.style.background='yellow';
marker.style.opacity = 0.5;
range.surroundContents(marker);
};
Related
This is being weird. I am using getBoundingClientRect() to get the values to position my blue coloured div so that it can surround an element on mouseover.
It works great and is getting all the values correctly. See this for reference:
As you can see, the blue div here surrounded the password element on hover as it should! (I have used Bootstrap demo form from w3schools for this.)
However, the problem arises when I create a form page myself without using Bootstrap or any other framework.
It gets the top and left correctly, but width and height 2px more! See the extra spacing here:
I don't know what is causing this to output those 2px extra. Why it works perfectly with Bootstrap or W3.CSS like frameworks but spit out 2px more without any frameworks? What's the workaround for this?
Here's the code snippet:
document.addEventListener("mouseover", (e) => {
elem = e.target;
var rect = elem.getBoundingClientRect();
var x = rect.left;
var y = rect.top;
var w = rect.width;
var h = rect.height;
div.style.width = w + "px";
div.style.height = h + "px";
div.style.left = x + window.scrollX + "px";
div.style.top = y + window.scrollY + "px";
});
I run into an issue when I have to simulate a click on a range input element in HTML. I thought it would be easy thing to do, since the method itself works on every other element. However, range input does not seem to work.
The method will simulate click on the given coordinates
function simulateClick(x, y) {
let clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent('click', true, true);
let element = document.elementFromPoint(x, y);
element.dispatchEvent(clickEvent);
let marker = document.createElement('div');
marker.style.width = '4px';
marker.style.height = '4px';
marker.style.position = 'fixed';
marker.style.backgroundColor = 'black';
marker.style.pointerEvents = 'none';
marker.style.left = x + 'px';
marker.style.top = y + 'px';
document.body.appendChild(marker);
}
Please see this fiddle https://jsfiddle.net/3eqmzoLk/
After executing the code, the black dot simulates the click and the range handle should move to that desired position, however it does not work.
I am using the following sentence to get the element in some position, but he takes the first ...
$(this.cTaskItem[0]).mouseup(function(event){
var posX = event.clientX, posY = event.clientY;
var overElem = document.elementFromPoint(posX, posY);
overElem.style.border = "3px solid red";
});
I wonder how do I get the element at a given position and Z-Index.
Thank You
If the first element (the one that's selected by document.elementFromPoint(posX, posY)) is not supposed to be clickable you can set the css prepoerty pointer-events: none; to it and it will not be selected anymore
As #t.niese suggested above you could do this:
$(this.cTaskItem[0]).mouseup(function(event)
{
var posX = event.clientX, posY = event.clientY;
var elements = [];
var elm = document.elementFromPoint(posX, posY);
while(elm.tagName != "HTML")
{
elements.push(elm);
elm.style.display = "none";
elm = document.elementFromPoint(posX, posY);
}
});
Then all you would need to do is go through your elements array and select the one you need.
I have table with few records and I need to show a popup box when the user mouses over a certain record.
I have created the popup box and set the message there. The only thing that's left is to set the coordinates of that box (<div id="popup"></div>) so that it's next to the element that triggers this box.
So I got the this of the tag I mouse over. Now how can I get its location on the window?
I tried this.offsetLeft and it's relative to parent. The element is inline so I don't know how to find it.
I using pure JavaScript and please don't suggest jQuery as I don't want to use it in this project.
var box = this.getBoundingClientRect();
alert( "y:" + box.top + "x:"+ box.left );
http://jsfiddle.net/hNShL/
To take scrolling into account:
var body = document.body,
html = document.documentElement,
scrollTop = window.pageYOffset || html.scrollTop || body.scrollTop || 0,
scrollLeft = window.pageXOffset || html.scrollLeft || body.scrollLeft || 0,
box = this.getBoundingClientRect(),
top = box.top + scrollTop,
left = box.left + scrollLeft;
alert( "y:" + top + "x:"+ left );
You could try recursively going through the element's offsetParents to get their offsetLeft values and add them to the element's own offsetLeft.
Something like this should do the trick:
function offsetLeftRelativeToPage(element) {
var offset = element.offsetLeft;
var offsetParent = element.offsetParent;
if (offsetParent != null) {
offset += offsetLeftRelativeToPage(offsetParent);
}
return offset;
}
var trigger = document.getElementById('trigger');
var popup = document.getElementById('popup');
trigger.onmouseover = function() {
var offsetLeft = offsetLeftRelativeToPage(this);
popup.style.left = offsetLeft;
}
JSFiddle demo: jsfiddle.net/e6vWV/
I would like to position a floating div element in an iframe with contentEditable, in case the user enters a certain key combination (for auto-complete purposes).
I know how to get the caret position:
document.getElementById('elm1_ifr').contentWindow.getSelection().anchorOffset
I can use this to calculate the left property of the div, but I can't seem to figure out how to get the top.
Another possibility I thought about was using:
document.getElementById('elm1_ifr').contentWindow.getSelection().anchorNode.parentNode
And using jQuery to get the offset, but if that parent has a long text line, I would only be able to extract the top position of the first line.
Can anyone help me with this?
The only reliable way of doing this is to insert a temporary element at the caret (ensuring that it is zero width), get its position and remove it again. You should also glue the two ends of the text node (if it was a text node that contained the caret) back together to ensure the DOM is as it was before inserting the node. Note, however, that doing this (or any other manual DOM manipulation on the editable content) breaks the browser's internal undo stack.
The reason for this is that careful reading of the spec for the getBoundingClientRect() method of Range shows that getBoundingClientRect() is not obliged to return a Rect for a collapsed Range. Conceptually, not every position in the document has a well-defined bounding rectangle. The caret, however, does have physical location on the screen which in my opinion should be provided by the Selection API, but currently there is nothing in browsers to provide this.
I came into this problem today. After some testing, I got this working, without using temorary element.
In IE, it's easy to work it out with offsetLeft and offsetTop property of a TextRange object. Some effort is needed for webkit though.
Here's a test, you can see the result. http://jsfiddle.net/gliheng/vbucs/12/
var getCaretPixelPos = function ($node, offsetx, offsety){
offsetx = offsetx || 0;
offsety = offsety || 0;
var nodeLeft = 0,
nodeTop = 0;
if ($node){
nodeLeft = $node.offsetLeft;
nodeTop = $node.offsetTop;
}
var pos = {left: 0, top: 0};
if (document.selection){
var range = document.selection.createRange();
pos.left = range.offsetLeft + offsetx - nodeLeft + 'px';
pos.top = range.offsetTop + offsety - nodeTop + 'px';
}else if (window.getSelection){
var sel = window.getSelection();
var range = sel.getRangeAt(0).cloneRange();
try{
range.setStart(range.startContainer, range.startOffset-1);
}catch(e){}
var rect = range.getBoundingClientRect();
if (range.endOffset == 0 || range.toString() === ''){
// first char of line
if (range.startContainer == $node){
// empty div
if (range.endOffset == 0){
pos.top = '0px';
pos.left = '0px';
}else{
// firefox need this
var range2 = range.cloneRange();
range2.setStart(range2.startContainer, 0);
var rect2 = range2.getBoundingClientRect();
pos.left = rect2.left + offsetx - nodeLeft + 'px';
pos.top = rect2.top + rect2.height + offsety - nodeTop + 'px';
}
}else{
pos.top = range.startContainer.offsetTop+'px';
pos.left = range.startContainer.offsetLeft+'px';
}
}else{
pos.left = rect.left + rect.width + offsetx - nodeLeft + 'px';
pos.top = rect.top + offsety - nodeTop + 'px';
}
}
return pos;
};