maxisam/ngx-clipboard

On IOS/Safari the page scroll to top when copying

ygodin opened this issue · 9 comments

OS: iOs 12
Device: iPhone XR, XS (and other)
Browser: Safari
ngx-clipboard version: 12.2.0
Angular version: 7.2.15

When you have scrollable content, if you click the target copy button, the page will scroll to top because of the of the inputElement inputElement.focus(); call that is made within the clearSelection function, looks like the fake text area yPosition is wrong.

I cannot reproduce this on other os/device, works great.

Thank you !

I am also experiencing this with any iOS device.

iOS Chrome scrolls to bottom on copy

ash67 commented

any quick workaround to deal with this problem till @maxisam applies a proper fix?

I have the same issue on both Chrome and Safari on iOS (tested from 10.1 to 13), on iPhone (tested from 6 to X).
Works fine on other devices/os.

any quick workaround to deal with this problem till @maxisam applies a proper fix?

@ash67 , in the meantime, i've created this directive as a quick fix, using the work of @rproenca in his Clipboard.js

`
import { Directive, Input, Inject, PLATFORM_ID, HostListener, EventEmitter, ElementRef, Output } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@directive({
selector: '[appCopyToClipboard]'
})
export class CopyToClipboardDirective {
@input() cbContent: string = "";
@output() cbOnSuccess: EventEmitter = new EventEmitter();
private textArea: HTMLTextAreaElement;

constructor(el: ElementRef,
    @Inject(PLATFORM_ID) private platformId: Object
) { }

@HostListener('click') onClick() {
    if (isPlatformBrowser(this.platformId)) {
        this.copy();
        this.cbOnSuccess.emit(this.cbContent);
    }
}

copy() {
    this.createTextArea();
    this.selectText();
    this.copyToClipboard();
}

isOS() {
    return navigator.userAgent.match(/ipad|iphone/i);
}

createTextArea() {
    this.textArea = document.createElement('textArea') as HTMLTextAreaElement;
    this.textArea.style.position = "absolute";
    this.textArea.style.left = "-9999px";
    this.textArea.style.top = "-9999px";
    this.textArea.readOnly = true;
    this.textArea.value = this.cbContent;
    document.body.appendChild(this.textArea);
}

selectText() {
    var range: Range;
    var selection: Selection;

    if (this.isOS()) {
        range = document.createRange();
        range.selectNodeContents(this.textArea);
        selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
        this.textArea.setSelectionRange(0, 999999);
    } else {
        this.textArea.select();
    }
}

copyToClipboard() {
    document.execCommand('copy');
    document.body.removeChild(this.textArea);
}

}
`

you can use it like this :
<button appCopyToClipboard [cbContent]="'hello world'" (cbOnSuccess)="isCopyClicked = true">Copy</button>

I'm using "isPlatformBrowser" because I'm using SSR, but you can get ride of it if you want.

ash67 commented

any quick workaround to deal with this problem till @maxisam applies a proper fix?

@ash67 , in the meantime, i've created this directive as a quick fix, using the work of @rproenca in his Clipboard.js

`
import { Directive, Input, Inject, PLATFORM_ID, HostListener, EventEmitter, ElementRef, Output } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

@directive({
selector: '[appCopyToClipboard]'
})
export class CopyToClipboardDirective {
@input() cbContent: string = "";
@output() cbOnSuccess: EventEmitter = new EventEmitter();
private textArea: HTMLTextAreaElement;

constructor(el: ElementRef,
    @Inject(PLATFORM_ID) private platformId: Object
) { }

@HostListener('click') onClick() {
    if (isPlatformBrowser(this.platformId)) {
        this.copy();
        this.cbOnSuccess.emit(this.cbContent);
    }
}

copy() {
    this.createTextArea();
    this.selectText();
    this.copyToClipboard();
}

isOS() {
    return navigator.userAgent.match(/ipad|iphone/i);
}

createTextArea() {
    this.textArea = document.createElement('textArea') as HTMLTextAreaElement;
    this.textArea.style.position = "absolute";
    this.textArea.style.left = "-9999px";
    this.textArea.style.top = "-9999px";
    this.textArea.readOnly = true;
    this.textArea.value = this.cbContent;
    document.body.appendChild(this.textArea);
}

selectText() {
    var range: Range;
    var selection: Selection;

    if (this.isOS()) {
        range = document.createRange();
        range.selectNodeContents(this.textArea);
        selection = window.getSelection();
        selection.removeAllRanges();
        selection.addRange(range);
        this.textArea.setSelectionRange(0, 999999);
    } else {
        this.textArea.select();
    }
}

copyToClipboard() {
    document.execCommand('copy');
    document.body.removeChild(this.textArea);
}

}
`

you can use it like this :
<button appCopyToClipboard [cbContent]="'hello world'" (cbOnSuccess)="isCopyClicked = true">Copy</button>

I'm using "isPlatformBrowser" because I'm using SSR, but you can get ride of it if you want.

@MarineMarin awesome, thanks for providing the solution. Much appreciated!

@MarineMarin Do you want to create a pull request? thx

@maxisam Is an official fix coming soon? This can create quite a disorienting effect for users. Otherwise tool is great. Glad I found it, was recommended to me by a coworker.

please try 12.2.2. Thanks @nicholasconfer for testing.