Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find a user selection weather forward or backward in javascript?

I am new to javascript.I am trying to make an simple toggle up div With user selection direction ill place the toggle div.After some googling I found one working fiddle But not as expected See the below screenshot to see the difference

When I select Some text on the front of the paragraph It works fine Like this

enter image description here

But when I selected some text from bottom paragraph It is not Working as expected enter image description here

JsFiddle

Actually I am working in React version 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'));
like image 622
Nane Avatar asked Oct 18 '22 17:10

Nane


2 Answers

At Last I find the answer,I fixed it apply simple style to the contentEditable div And It it is Working like a Charm.I don't know why it is working But i doubt 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>
like image 172
Nane Avatar answered Oct 20 '22 11:10

Nane


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

Adding height: 100vh would solve this problem, but you may see two scroll bars in some cases.

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

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 DEMO

like image 31
Alex.S Avatar answered Oct 20 '22 10:10

Alex.S