How to find user weather forward or backward in javascript?

I am new to javascript. I am trying to make a simple div switch. In user select mode, the div pointer does not fit well. After some searches, I found one working fiddle. But not as expected. See screenshot to see the difference.

When I select some text at the beginning of a paragraph, it works fine.

enter image description here

But when I selected some text from the bottom paragraph, it does not work as expected enter image description here

Jsfiddle

I actually work in a version of React. Fiddle is in jQuery

This is my code.

import React from 'react' import {render} from 'react-dom'; export default class App extends React.Component{ constructor(props){ super(props); this.state = { display:'none' , top:'', bottom:'', left:'', right:'', diplayForDown:'none' }; this.handleOnMouseDown = this.handleOnMouseDown.bind(this) this.onMounseUp = this.onMounseUp.bind(this) this.onMouseDwn = this.onMouseDwn.bind(this) this.triggerAlltime = this.triggerAlltime.bind(this) } handleOnMouseDown(){ let sel = window.getSelection && window.getSelection(); let r = sel.getRangeAt(0).getBoundingClientRect(); let relative=document.body.parentNode.getBoundingClientRect(); console.log('Relative ',relative); if(!sel.isCollapsed){ console.log(sel,r); let display = 'block'; let top = (r.bottom - relative.top - 80)+'px'; let bottom = r.bottom+'px'; let left =( r.left)+'px'; let right = (r.right)+'px'; console.log('This is Height',r.bottom-r.top); let selectionHeight = r.bottom - r.top; if(selectionHeight => 22.22){ this.setState({ display, top:top, bottom, left, right }) }else{ this.setState({ display, top, bottom, left, right }) } }else{ this.setState({ display:'none' }) } console.log('Slected') } onMounseUp(e){ e.preventDefault() let sel = window.getSelection && window.getSelection(); if(!sel.isCollapsed){ console.log('Moved Up') } } onMouseDwn(e){ let sel = window.getSelection && window.getSelection(); if(!sel.isCollapsed){ console.log('Moved Down') } } getSelectionHtml() { let html = ""; if (typeof window.getSelection != "undefined") { let sel = window.getSelection(); if (sel.rangeCount) { let container = document.createElement("div"); for (let i = 0, len = sel.rangeCount; i < len; ++i) { container.appendChild(sel.getRangeAt(i).cloneContents()); } html = container.innerHTML; } } else if (typeof document.selection != "undefined") { if (document.selection.type == "Text") { html = document.selection.createRange().htmlText; } } console.log('html',html) return html; } lastCharRTL(txt) { return /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]$/.test(txt); } triggerAlltime(e){ // console.log('Some Thinms') if(!window.getSelection().isCollapsed){ //find the Direction Of Slelection let sel = window.getSelection(); console.log(sel) let range = document.createRange(); range.setStart(sel.anchorNode, sel.anchorOffset); range.setEnd(sel.focusNode, sel.focusOffset); let backwards = range.collapsed; range.detach(); // get selection rects let rects = sel.getRangeAt(0).getClientRects(); let n = rects.length - 1; let display = 'block'; console.log(this.lastCharRTL(this.getSelectionHtml())) if (this.lastCharRTL(this.getSelectionHtml())) this.setState({ display:'none', diplayForDown:'none', top: rects[n].top + 10, left: rects[n].left - 10 }) else if (backwards) this.setState({ display, diplayForDown:'none', top: rects[0].top + -68, left: rects[0].left }) else this.setState({ display:'none', diplayForDown:'block', top: rects[n].top + 40, left: rects[n].right+-160 }) }else{ this.setState({ display:'none', diplayForDown:'none', }) } } render(){ return( <div className="container"> <div className="CenterCon"> <div contentEditable="true" onMouseUp={this.triggerAlltime} onMouseDown={this.triggerAlltime} onKeyUp={this.triggerAlltime} onKeyDown={this.triggerAlltime} className="Edithis" > <p>Test</p> </div> </div> <div style={{top: this.state.top, bottom: this.state.bottom, left:this.state.left, right:this.state.right, display: this.state.display}} className="Toggle"> <ul> <li>B</li> <li>U</li> <li>H</li> <li>"</li> </ul> <div className="triangle"> </div> </div> {/*DownWard Toggle*/} <div style={{top: this.state.top, bottom: this.state.bottom, left: this.state.left, right: this.state.right, display: this.state.diplayForDown}} className="ToggleForDownWardSelection"> <div className="triangle-bottom" /> <ul> <li>B</li> <li>U</li> <li>H</li> <li>li</li> </ul> </div> </div> ) } } render(<App/>,document.getElementById('app')); 
+5
source share
3 answers

The problem is that #pointer set to an absolute position, but when the content is long and scrollable, the top distance is calculated from above rather than from above.

Adding height: 100vh will solve this problem, but in some cases you may see two scrollbars.

Another way is to add window.pageYOffset when calculating the top the div pointer.

 if (backwards) { $('#pointer').css({top: rects[0].top + window.pageYOffset + 10, left: rects[0].left - 10}).show(); } else { $('#pointer').css({top: rects[n].top + window.pageYOffset + 10, left: rects[n].right}).show(); } 

Here is a demo

+1
source

Finally, I find the answer, I fixed it by applying a simple style to the contentEditable div. And it works like a Charm. I don't know why it works. But I doubt the window API

  <div contentEditable="true" style={{height:'100vh',overflow:'auto'}} onMouseUp={this.triggerAlltime} onMouseDown={this.triggerAlltime} onKeyUp={this.triggerAlltime} onKeyDown={this.triggerAlltime} className="Edithis" > <p>Test</p> </div> 
+2
source

There is no way to do this. You can probably check the mouse click and disable the location of events and determine the start / end positions to determine if it was a choice forward or backward.

0
source

Source: https://habr.com/ru/post/1263738/


All Articles