Copy to clipboard fixes including support for Android Native Bridge (#7382)

* Adds Clipboard Async API & makes use of Android Native Bridge interface for write post image copy to clipboard

* Checks for clipboard api support before trying to use it

* Adds support for comment dropdown copy link

* Adds AndroidBridge to globals definition
This commit is contained in:
Fernando Valverde 2020-04-21 08:36:49 -06:00 committed by GitHub
parent 984e2647e7
commit 5dc0ebbb04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 44 deletions

View file

@ -25,5 +25,6 @@ module.exports = {
initializeAllFollowButts: false,
initializeSponsorshipVisibility: false,
ActiveXObject: false,
AndroidBridge: false,
},
};

View file

@ -3,10 +3,18 @@
function initializeCommentDropdown() {
const announcer = document.getElementById('article-copy-link-announcer');
function isIOSDevice() {
function isClipboardSupported() {
return (
/iPhone|CriOS|iPad/i.test(navigator.userAgent) ||
navigator.userAgent === 'DEV-Native-ios'
typeof navigator.clipboard !== "undefined" &&
navigator.clipboard !== null
);
}
function isNativeAndroidDevice() {
return (
navigator.userAgent === 'DEV-Native-android' &&
typeof AndroidBridge !== "undefined" &&
AndroidBridge !== null
);
}
@ -23,7 +31,7 @@ function initializeCommentDropdown() {
const input =
activeElement.localName === 'clipboard-copy'
? activeElement.querySelector('input')
: activeElement;
: document.getElementById('article-copy-link-input');
input.focus();
input.setSelectionRange(0, input.value.length);
announcer.hidden = false;
@ -35,11 +43,27 @@ function initializeCommentDropdown() {
}
}
function iOSCopyText() {
const input = document.getElementById('article-copy-link-input');
input.setSelectionRange(0, input.value.length);
document.execCommand('copy');
function execCopyText() {
showAnnouncer();
document.execCommand('copy');
}
function copyText() {
const inputValue = document.getElementById('article-copy-link-input').value;
if (isNativeAndroidDevice()) {
AndroidBridge.copyToClipboard(inputValue);
showAnnouncer();
} else if (isClipboardSupported()) {
navigator.clipboard.writeText(inputValue)
.then(() => {
showAnnouncer();
})
.catch((err) => {
execCopyText();
});
} else {
execCopyText();
}
}
function shouldCloseDropdown(event) {
@ -61,15 +85,11 @@ function initializeCommentDropdown() {
}
function removeCopyListener() {
if (isIOSDevice()) {
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
if (clipboardCopyElement) {
clipboardCopyElement.removeEventListener('click', iOSCopyText);
}
} else {
document.removeEventListener('clipboard-copy', showAnnouncer);
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
if (clipboardCopyElement) {
clipboardCopyElement.removeEventListener('click', copyText);
}
}
@ -98,18 +118,13 @@ function initializeCommentDropdown() {
} else {
removeAllShowing();
dropdownContent.classList.add('showing');
if (isIOSDevice()) {
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
const clipboardCopyElement = document.getElementsByTagName(
'clipboard-copy',
)[0];
document.addEventListener('click', outsideClickListener);
if (clipboardCopyElement) {
clipboardCopyElement.addEventListener('click', iOSCopyText);
}
} else {
document.addEventListener('click', outsideClickListener);
document.addEventListener('clipboard-copy', showAnnouncer);
document.addEventListener('click', outsideClickListener);
if (clipboardCopyElement) {
clipboardCopyElement.addEventListener('click', copyText);
}
}
}

View file

@ -48,5 +48,6 @@ module.exports = {
algoliasearch: false,
ga: false,
Honeybadger: false,
AndroidBridge: false,
},
};

View file

@ -74,6 +74,15 @@ export default class ImageManagement extends Component {
});
};
execCopyText = () => {
this.imageMarkdownInput.setSelectionRange(
0,
this.imageMarkdownInput.value.length,
);
document.execCommand('copy');
this.imageMarkdownAnnouncer.hidden = false;
}
copyText = () => {
this.imageMarkdownAnnouncer = document.getElementById(
'image-markdown-copy-link-announcer',
@ -82,25 +91,29 @@ export default class ImageManagement extends Component {
'image-markdown-copy-link-input',
);
const isIOSDevice =
navigator.userAgent.match(/iPhone|iPad/i) ||
navigator.userAgent.match('CriOS') ||
navigator.userAgent === 'DEV-Native-ios';
const isNativeAndroid =
navigator.userAgent === 'DEV-Native-android' &&
typeof AndroidBridge !== "undefined" &&
AndroidBridge !== null;
if (isIOSDevice) {
this.imageMarkdownInput.setSelectionRange(
0,
this.imageMarkdownInput.value.length,
);
document.execCommand('copy');
const isClipboardSupported =
typeof navigator.clipboard !== "undefined" &&
navigator.clipboard !== null;
if (isNativeAndroid) {
AndroidBridge.copyToClipboard(this.imageMarkdownInput.value);
this.imageMarkdownAnnouncer.hidden = false;
} else if (isClipboardSupported) {
navigator.clipboard.writeText(this.imageMarkdownInput.value)
.then(() => {
this.imageMarkdownAnnouncer.hidden = false;
})
.catch((err) => {
this.execCopyText();
});
} else {
this.imageMarkdownInput.focus();
this.imageMarkdownInput.setSelectionRange(
0,
this.imageMarkdownInput.value.length,
);
this.execCopyText();
}
this.imageMarkdownAnnouncer.hidden = false;
};
linksToMarkdownForm = imageLinks => {