/* global ClipboardItem, Blob */
import { Storage } from '../storage';
import SupportedChannel from '../models/invites/SupportedChannel';
import SDK from '../sdk';
import Invites from '../Invites';
/**
* @class SmartShare
* @hideconstructor
*/
export default class SmartShare {
/**
* Create and display a Smart Share.
*
* @memberOf SmartShare
* @param {Object} params
* @param {string} params.target - ID of the div where the Smart Share will be shown.
* @param {Object} params.options - Customization options.
* @param {string} params.options.inviteText - Text to include with the invite link.
* @param {string} params.options.emailSubject - E-mail subject when sharing via e-mail.
* @param {string} params.options.twitterVia - Twitter account to include at the end of the tweet.
* @param {Object.<string, string>} params.customData - Custom data attached to the Smart Invite.
*/
static create (params) {
params = params || {};
// DOM element the widget will be rendered to.
const target = params.target;
// Make sure the container element exists.
if (typeof params.target !== 'string' || !document.getElementById(params.target)) {
console.error("Container for Smart Share with id '%s' doesn't exist.", params.target);
return;
}
SmartShare.options = params.options || {};
SmartShare.customData = params.customData || {};
SmartShare._render(target);
}
/** @ignore */
static _render (target) {
if (Storage.getIdentity()) {
const targetEl = document.getElementById(target);
// Include copy btn in Safari only if Clipboard API is available
const includeCopy = !navigator.vendor.match(/apple/i) ||
(navigator.clipboard &&
navigator.clipboard.write);
targetEl.innerHTML = SmartShare.getHTML(includeCopy);
if (targetEl.querySelectorAll('button').length) {
targetEl.querySelectorAll('button')
.forEach((el) => {
el.addEventListener('click', (e) => {
SmartShare.onButtonClicked(e);
});
});
}
} else {
console.error('User must be authenticated to render the SmartShare bar');
}
}
/** @ignore */
static getHTML (includeCopy) {
const copyItem = `<li>
<button id="gs-share-copy">
Copy
</button>
</li>`;
return `
<ul id="smart-share">
<li>
<button id="gs-share-facebook">
Facebook
</button>
</li>
<li>
<button id="gs-share-email">
E-mail
</button>
</li>
<li>
<button id="gs-share-twitter">
Twitter
</button>
</li>
${includeCopy ? copyItem : ''}
</ul>
<style>
#smart-share {
display: flex;
list-style-type: none;
margin: 0;
padding:0;
grid-auto-flow: column;
grid-column-gap: 4px;
grid-row-gap: 4px;
grid-auto-columns: min-content;
flex-wrap: wrap;
}
#smart-share button {
width: 140px;
white-space: nowrap;
border: 0;
color: white;
cursor: pointer;
padding: 8px 16px 8px 30px;
font-size: 18px;
line-height: 1;
background-size: 18px;
background-repeat: no-repeat;
background-position: 8px center;
}
#gs-share-facebook {
background-color: #38529a;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIGhlaWdodD0iMWVtIiB3aWR0aD0iMWVtIiB2aWV3Qm94PSIwIDAgNDAgNDAiPgogIDxnPgogICAgPHBhdGggZD0ibTIxLjcgMTYuN2g1djVoLTV2MTEuNmgtNXYtMTEuNmgtNXYtNWg1di0yLjFjMC0yIDAuNi00LjUgMS44LTUuOSAxLjMtMS4zIDIuOC0yIDQuNy0yaDMuNXY1aC0zLjVjLTAuOSAwLTEuNSAwLjYtMS41IDEuNXYzLjV6Ij48L3BhdGg+CiAgPC9nPgo8L3N2Zz4KCg==)
}
#gs-share-twitter {
background-color: #4da6e9;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIGhlaWdodD0iMWVtIiB3aWR0aD0iMWVtIiB2aWV3Qm94PSIwIDAgNDAgNDAiPgogIDxnPgogICAgPHBhdGggZD0ibTMxLjUgMTEuN2MxLjMtMC44IDIuMi0yIDIuNy0zLjQtMS40IDAuNy0yLjcgMS4yLTQgMS40LTEuMS0xLjItMi42LTEuOS00LjQtMS45LTEuNyAwLTMuMiAwLjYtNC40IDEuOC0xLjIgMS4yLTEuOCAyLjctMS44IDQuNCAwIDAuNSAwLjEgMC45IDAuMiAxLjMtNS4xLTAuMS05LjQtMi4zLTEyLjctNi40LTAuNiAxLTAuOSAyLjEtMC45IDMuMSAwIDIuMiAxIDMuOSAyLjggNS4yLTEuMS0wLjEtMi0wLjQtMi44LTAuOCAwIDEuNSAwLjUgMi44IDEuNCA0IDAuOSAxLjEgMi4xIDEuOCAzLjUgMi4xLTAuNSAwLjEtMSAwLjItMS42IDAuMi0wLjUgMC0wLjkgMC0xLjEtMC4xIDAuNCAxLjIgMS4xIDIuMyAyLjEgMyAxLjEgMC44IDIuMyAxLjIgMy42IDEuMy0yLjIgMS43LTQuNyAyLjYtNy42IDIuNi0wLjcgMC0xLjIgMC0xLjUtMC4xIDIuOCAxLjkgNiAyLjggOS41IDIuOCAzLjUgMCA2LjctMC45IDkuNC0yLjcgMi44LTEuOCA0LjgtNC4xIDYuMS02LjcgMS4zLTIuNiAxLjktNS4zIDEuOS04LjF2LTAuOGMxLjMtMC45IDIuMy0yIDMuMS0zLjItMS4xIDAuNS0yLjMgMC44LTMuNSAxeiI+PC9wYXRoPgogIDwvZz4KPC9zdmc+Cgo=);
}
#gs-share-email {
background-color: #ec4134;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIG1lZXQiIGhlaWdodD0iMWVtIiB3aWR0aD0iMWVtIiB2aWV3Qm94PSIwIDAgNDAgNDAiPgogIDxnPgogICAgPHBhdGggZD0ibTMzLjQgMTMuNHYtMy40bC0xMy40IDguNC0xMy40LTguNHYzLjRsMTMuNCA4LjJ6IG0wLTYuOHExLjMgMCAyLjMgMS4xdDAuOSAyLjN2MjBxMCAxLjMtMC45IDIuM3QtMi4zIDEuMWgtMjYuOHEtMS4zIDAtMi4zLTEuMXQtMC45LTIuM3YtMjBxMC0xLjMgMC45LTIuM3QyLjMtMS4xaDI2Ljh6Ij48L3BhdGg+CiAgPC9nPgo8L3N2Zz4KCg==);
}
#gs-share-copy {
background-color: #f6bf42;
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMjEwLjEwNyAyMTAuMTA3IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyMTAuMTA3IDIxMC4xMDc7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCgk8Zz4NCgkJPHBhdGggZD0iTTE2OC41MDYsMEg4MC4yMzVDNjcuNDEzLDAsNTYuOTgxLDEwLjQzMiw1Ni45ODEsMjMuMjU0djIuODU0aC0xNS4zOA0KCQkJYy0xMi44MjIsMC0yMy4yNTQsMTAuNDMyLTIzLjI1NCwyMy4yNTR2MTM3LjQ5MmMwLDEyLjgyMiwxMC40MzIsMjMuMjU0LDIzLjI1NCwyMy4yNTRoODguMjcxDQoJCQljMTIuODIyLDAsMjMuMjUzLTEwLjQzMiwyMy4yNTMtMjMuMjU0VjE4NGgxNS4zOGMxMi44MjIsMCwyMy4yNTQtMTAuNDMyLDIzLjI1NC0yMy4yNTRWMjMuMjU0QzE5MS43NiwxMC40MzIsMTgxLjMyOCwwLDE2OC41MDYsMHoNCgkJCU0xMzguMTI2LDE4Ni44NTRjMCw0LjU1MS0zLjcwMyw4LjI1NC04LjI1Myw4LjI1NEg0MS42MDFjLTQuNTUxLDAtOC4yNTQtMy43MDMtOC4yNTQtOC4yNTRWNDkuMzYxDQoJCQljMC00LjU1MSwzLjcwMy04LjI1NCw4LjI1NC04LjI1NGg4OC4yNzFjNC41NTEsMCw4LjI1MywzLjcwMyw4LjI1Myw4LjI1NFYxODYuODU0eiBNMTc2Ljc2LDE2MC43NDYNCgkJCWMwLDQuNTUxLTMuNzAzLDguMjU0LTguMjU0LDguMjU0aC0xNS4zOFY0OS4zNjFjMC0xMi44MjItMTAuNDMyLTIzLjI1NC0yMy4yNTMtMjMuMjU0SDcxLjk4MXYtMi44NTQNCgkJCWMwLTQuNTUxLDMuNzAzLTguMjU0LDguMjU0LTguMjU0aDg4LjI3MWM0LjU1MSwwLDguMjU0LDMuNzAzLDguMjU0LDguMjU0VjE2MC43NDZ6Ii8+DQoJPC9nPg0KPC9zdmc+DQo=);
}
</style>
`;
}
/** @ignore */
static getChannel (id) {
const prefix = 'gs-share-';
return id.startsWith(prefix)
? id.substr(prefix.length)
: null;
}
/** @ignore */
static copyToClipboard (txt) {
// Get current selection
const selected =
document.getSelection().rangeCount > 0
? document.getSelection().getRangeAt(0)
: false;
const txtArea = document.createElement('textarea');
txtArea.value = txt;
txtArea.setAttribute('readonly', '');
txtArea.style.position = 'absolute';
txtArea.style.left = '-9999px';
document.body.appendChild(txtArea);
txtArea.select();
document.execCommand('copy');
document.body.removeChild(txtArea);
if (selected) {
document.getSelection().removeAllRanges();
// Select back previously selected text
document.getSelection().addRange(selected);
}
}
/** @ignore */
static onButtonClicked (e) {
const channel = SmartShare.getChannel(e.target.id);
if (channel) {
e.target.disabled = true;
SmartShare.shareLinkViaChannel(channel)
.then(() => {
// Use ClipboardAPI in Safari
if (channel === 'copy') {
SmartShare.copySuccessful(e);
}
})
.finally(() => { e.target.disabled = false; })
}
}
/** @ignore */
static shareLinkViaChannel(channel, options) {
if (channel) {
options = options || SmartShare.options || {};
const windowFeatures = 'resizable,scrollbars,status,left=200,top=200,width=720,height=520';
let inviteText = options.inviteText
? options.inviteText + ' '
: '';
let subject = options.emailSubject
? options.emailSubject
: '';
const via = options.twitterVia
? `&via=${encodeURI(options.twitterVia)}`
: '';
const customData = options.customData || null;
if (inviteText.indexOf('[APP_INVITE_URL]') < 0) {
inviteText += '[APP_INVITE_URL]';
}
// Replace placeholders
const defaultContent = Invites.getDefaultContent(channel);
const user = SDK.getCurrentUser();
const name = user
? user.displayName
: '';
inviteText = inviteText
.replace(/\[APP_INVITE_TEXT\]/g, defaultContent.text || '');
subject = subject
.replace(/\[APP_INVITE_SUBJECT\]/g, defaultContent.subject || '');
inviteText = inviteText
.replace(/\[USER_NAME\]/g, name || '');
subject = subject
.replace(/\[USER_NAME\]/g, name || '');
inviteText = inviteText
.replace(/\[APP_NAME\]/g, SDK.superProps.appName || '');
subject = subject
.replace(/\[APP_NAME\]/g, SDK.superProps.appName || '');
// Use ClipboardAPI in Safari
if (channel === 'copy' &&
navigator.vendor.match(/apple/i)) {
const linkPromise = SmartShare.getLink(channel, customData);
const clipboardPromise = new Promise((resolve) => {
linkPromise
.then((url) => {
resolve(
new Blob(
[inviteText.replace(/\[APP_INVITE_URL\]/g, url)],
{
type: 'text/plain'
}
)
);
return url;
})
.catch(console.error);
});
navigator.clipboard.write([
new ClipboardItem({
'text/plain': clipboardPromise
})
]);
return linkPromise;
}
return SmartShare.getLink(channel, customData)
.then((url) => {
const shareTxt = inviteText.replace(/\[APP_INVITE_URL\]/g, '');
const fullTxt = inviteText.replace(/\[APP_INVITE_URL\]/g, url);
switch (channel) {
case SupportedChannel.Facebook:
window.open(`https://www.facebook.com/sharer.php?display=popup&u=${encodeURI(url)}"e=${encodeURI(shareTxt)}`, 'SmartShareFacebookPost', windowFeatures);
break;
case SupportedChannel.Twitter:
window.open(`https://twitter.com/intent/tweet?text=${encodeURI(shareTxt)}${via}&original_referer=${encodeURI(window.location.href)}&url=${encodeURI(url)}`, 'SmartShareTweet', windowFeatures);
break;
case SupportedChannel.Email:
window.location.href = `mailto:?subject=${encodeURI(subject)}&body=${encodeURI(fullTxt)}`;
break;
case SupportedChannel.CopyToClipboard:
SmartShare.copyToClipboard(fullTxt);
break;
default:
console.error(`Channel ${channel} is not supported`);
}
return url;
})
.catch(console.error);
}
return Promise.reject('Channel not provided');
}
/** @ignore */
static copySuccessful (e) {
var currentText = e.target.innerText;
e.target.innerText = 'Copied!';
setTimeout(() => {
e.target.innerText = currentText;
}, 1000);
}
/** @ignore */
static getLink (channel, customData) {
customData = customData || SmartShare.customData || {};
return Invites.createURL({
channel,
...customData
});
}
}