admin管理员组

文章数量:1410730

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

But when I selected some text from bottom paragraph It is not Working as expected

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'));

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

But when I selected some text from bottom paragraph It is not Working as expected

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'));
Share Improve this question edited Feb 2, 2017 at 15:35 Nane asked Feb 2, 2017 at 15:27 NaneNane 4336 gold badges39 silver badges82 bronze badges 3
  • 2 What browser are you in because this fiddle correctly adds the toggle div for me in both directions.. jsfiddle/vCwwN/2 - works for me in GC and FF – Zze Commented Feb 9, 2017 at 4:56
  • It will work .But try it Select the last line of the content see what happens if it work pls post the screenshot @Zze – Nane Commented Feb 9, 2017 at 13:11
  • @Alex.S was right in his ment on your answer. I didn't see the issue, because I didn't have to scroll to get to the bottom paragraph. Glad you found your solve. – Zze Commented Feb 9, 2017 at 20:37
Add a ment  | 

5 Answers 5

Reset to default 3
const isBackwards = () => {
  const selection = window.getSelection();
  let range = document.createRange();
  range.setStart(selection.anchorNode, selection.anchorOffset);
  range.setEnd(selection.focusNode, selection.focusOffset);

  let backwards = range.collapsed;
  range.detach();
  return backwards;
}

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>

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

There is no way to do that. Probably you can check mouse press and unpress events locations and determine initial/end positions to determine whether it was forward or backward selection.

To answer the question in the title - checking if selection was forward or backwards:

window.getSelection() returns a Selection object and in the documentation you can read the following:

  • Selection.anchorNode: Returns the Node in which the selection begins.

However, when you call Selection.getRangeAt(0) on this Selection object, you get instead the selection as Range. Range does not have anchor (and focus) but instead startContainer and endContainer.

  • Range.startContainer: Returns the Node within which the Range starts.
  • Range.endContainer: Returns the Node within which the Range ends.

Basically the anchordNode is always the Node where the selection started by the user while startContainer is always the first Node in the DOM tree of the selection. So:

  • If the anchorNode and the anchorOffset of the selection corresponds with the startContainer and startOffset of the Range, you have (normal) forward selection
  • If the anchorNode and the anchorOffset of the selection corresponds with the endContainer and endOffset of the Range, you have backwards selection

(do check in the beginning off course if the selection is collapsed or not)

本文标签: jqueryHow to find a user selection weather forward or backward in javascriptStack Overflow