Comments (22)
Here's my function for getting the selected block element
getSelectedBlockElement = () => {
var selection = window.getSelection()
if (selection.rangeCount == 0) return null
var node = selection.getRangeAt(0).startContainer
do {
if (node.getAttribute && node.getAttribute('data-block') == 'true')
return node
node = node.parentNode
} while (node != null)
return null
};
from draft-js.
Great question.
For the Notes editor, I reach directly into the DOM Selection
object, identify the block that contains the cursor, and calculate the position of the element.
This isn't exposed in the current API, though I think it might be useful to have a utility function available so that this doesn't need to be reimplemented.
from draft-js.
A utility that provides a reference to the current block with cursor focus would be great.
How about the boundingClientRect of the current selection (to ease in positioning popups, widgets, etc)?
from draft-js.
I've had some success with https://github.com/bkniffler/draft-wysiwyg/blob/master/src/draft.js#L67 and https://github.com/bkniffler/draft-wysiwyg/blob/master/src/draft.js#L269
Its a mouseUp handler on the draft-js wrapping div.
mouseUp(e) {
function getSelected() {
var t = '';
if (window.getSelection) {
t = window.getSelection();
} else if (document.getSelection) {
t = document.getSelection();
} else if (document.selection) {
t = document.selection.createRange().text;
}
return t;
}
setTimeout(()=> {
var selection = this.state.value.getSelection();
if (selection.isCollapsed()) {
return this.setState({toolbox: null});
}
else {
var selected = getSelected();
var rect = selected.getRangeAt(0).getBoundingClientRect();
this.setState({toolbox: {left: rect.left, top: rect.top, width: rect.width}});
}
}, 1)
}
The resulting position data can easily be used with something like react-portal to show a tooltip like here https://github.com/bkniffler/draft-wysiwyg/blob/master/src/components/tooltip.js
The live example: http://draft-wysiwyg.herokuapp.com/
I've only tested in Safari/Chrome though.
from draft-js.
@AlastairTaft Getting the current block is straightforward using Draft:
const currentContent = editorState.getCurrentContent()
const selection = editorState.getSelection()
const currentBlock = currentContent.getBlockForKey(selection.getStartKey())
I prefer this technique over using the window
object and digging through DOM nodes.
from draft-js.
One solution would be to add ref={blockKey}
to DraftEditorBlock or its parent div so we could use findDOMNode
to get the element.
Example:
ReactDOM.findDOMNode(editorState.getSelection().getStartKey())
from draft-js.
What would be most helpful here? A utility to provide the DOM element for the selected ContentBlock
? I don't want people to have to go digging into the Selection API docs at MDN. :) So I can put something together if it would be useful.
from draft-js.
@azangru This is working for me:
// From MobX observables
@observable isSelectionActive = false;
@observable selectionCoords = {};
@action modifySelection(value) {
this.isSelectionActive = value;
}
@action setCoords({ editorBound, cursorBound }) {
console.log('editorBound, cursorBound', editorBound, cursorBound);
this.selectionCoords = {
top: cursorBound.top - editorBound.top + 20,
left: cursorBound.left - editorBound.left,
};
}
// The events of the class
_handleBeforeInput(char) {
switch(char) {
case '@': {
// The rectangle that bounds the editor
const
editorNode = document.getElementById(this.props.id),
editorBound = editorNode.getBoundingClientRect();
// The rectangle that bounds the cursor
const
s = window.getSelection(),
oRange = s.getRangeAt(0),
cursorBound = oRange.getBoundingClientRect();
this.setCoords({ editorBound, cursorBound });
this.modifySelection(true);
return true;
}
case '#': {
console.log('handled #!');
break;
}
}
return false;
}
What is still needed is to control when the position of the caret is close to the edge to prevent the autosuggest div to overflow the parent div. In that case the property should be top & right instead of top & left.
Hope this helps!
from draft-js.
Great library! I was toying around with the Medium style formatting bar shown in the video (centering controls above selection), and, from quickly digging around MDN got something working in Chrome with just window.getSelection().getRangeAt(0).getBoundingClientRect()
. But I have no clue if this will break in IE, etc.
It'd be amazing if this library itself could handle any cross-browser and edge cases involved in positioning relative to a selection!
from draft-js.
For retrieving information about the ContentBlock
that contains selection, definitely rely on the model, not on the DOM.
For retrieving information about the actual node in order to obtain DOM position information, @AlastairTaft's solution is pretty close to what we use internally. :)
from draft-js.
Hopefully this will be useful as well: https://github.com/facebook/draft-js/blob/master/src/component/selection/getVisibleSelectionRect.js
Going to go ahead and close this issue since we've got a useful thread here.
from draft-js.
I'm trying to display a suggestions container and I'm trying to use the "new" getVisibleSelectionRect
, but it returns null when the editor is empty. And the editor is empty when I'm typing the first character, because I'm using the function inside the onChange event.
So I tried to use @AlastairTaft's code to get the block and calculate the position but I'm having some difficulties to properly get the exact position of the cursor/selection, because the block is quite large. I cannot display the container at the beginning/end of the block. @hellendag do you mind sharing a bit how you do this at facebook?
from draft-js.
@jmaguirrei Wow, thank you!
I eventually adopted the approach taken by the Draft-js-plugins team, where they use a draft-js decorator to wrap the word for which autosuggestion is offered in a span, and save the coordinates of that span. Once those coordinates are available, it is trivial to position the autocompletion box near the word that the cursor is in.
Thank you for offering another solution to this problem!
from draft-js.
Using window.getSelection().getRangeAt(0).getBoundingClientRect()
or document.getSelection().getRangeAt(0).getBoundingClientRect()
to get the "cursor's" position does not work with Safari 10.0.3. It works with Chrome, Firefox and Edge, though.
Any idea how to get the position in another way?
from draft-js.
Yes, I've wondered the same. Is there some kind of event on editor that gets fired if the selection changed with infos about position etc.?
from draft-js.
Each top-level block element has data-block={true}
, which you can use to find it if looking upward from the node with the current DOM Selection
.
from draft-js.
Thank you that helps a lot!
from draft-js.
@bkniffler Nice! Thanks for sharing.
from draft-js.
I managed to get this working. To position the buttons on the left, I first retrieved the selected block element using something akin to the function above. Then I used the offsetTop
property as it's parent node is the editor container, so it's safe to use this. This gave me the vertical offset for the buttons.
To then display the popover container which adds all the inline styles, like bold, italic, link, etc. I grabbed the position of the editor and the position of the current selection using the getBoundingClientRect
method and computed the difference between the two to figure out where to place the inline buttons relative to the editor.
See it in action here
from draft-js.
@gscottolson That's much nicer thanks
EDIT: Just realised that method pulls back the object representation of the block not the DOM element.
from draft-js.
Reading through this thread several months after it was closed, and still am confused. I too would like to display a popover block with autocomplete suggestions positioned close to the caret. Is there a good technique for finding the position of the caret (its absolute top and left offsets or the offsets relative to the Editor element)?
from draft-js.
@azangru You are welcome, glad to help! I havent finished my editor component yet, so maybe I will be trying another solutions, like yours, in the future. Keep in touch. Regards
from draft-js.
Related Issues (20)
- read-only font size not working
- Ctrl+A selection doesn't work in Firefox when there are action items
- Bug in demo text editor on website HOT 4
- created by DraftEditorTextNode
- state in decorator are memorised
- Add custom classes
- Ordered and unordered lists don't work
- Is/should convertToRaw be based on some kind of open standard? HOT 1
- How to insert texts via google chrome extension to an input created by DraftJS HOT 1
- Pressing return jumps to start of line in Android API 33 HOT 1
- How to change blockType by pressing keyboard
- why draftInlineStyleType only can be default type? HOT 1
- How to get the cursor position? HOT 4
- URGENT :: How to update words arrays in handleStrategy of decorator?
- how to stop the style i add in replaceText?
- pre select inline style, then input in composition mode, the selected inlinestyle not work
- when input some IME punctuation, the editor crashs
- wrong return value of getInlineStyleForCollapsedSelection and getInlineStyleForNonCollapsedSelection
- http://localhost:8000/
- InvalidStateError: 'extend' requires a Range to be added to the Selection HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from draft-js.