share-selected-text
Version:
share selected text on twitter, buffer, stumbleupon, digg, tumblr & reddit. Inspired by medium.com
311 lines (253 loc) • 10.5 kB
JavaScript
/*!
* Share Selected Text
* version: 1.1.5
* license: MIT
* url: https://github.com/VincentLoy/share-selected-text
* author: Vincent Loy <vincent.loy1@gmail.com>
* contributors:
* - Wendy Beth <wendybeth010@gmail.com>
* - Dmitry Motorin <dmitry.mot@gmail.com>
* - Dustin Armstrong
*/
(function (exports) {
'use strict';
var getPageUrl = function getPageUrl() {
if (document.querySelector('meta[property="og:url"]') && document.querySelector('meta[property="og:url"]').getAttribute('content')) {
return document.querySelector('meta[property="og:url"]').getAttribute('content');
}
return encodeURIComponent(window.location.href);
};
// constants
var TOOLTIP_HEIGHT = 50;
var FACTOR = 1.33;
var TWITTER_LIMIT_LENGTH = 140;
var TWITTER_URL_LENGTH_COUNT = 24;
var TWITTER_QUOTES = 2;
var TWITTER_DOTS = 3;
var TOOLTIP_TIMEOUT = 250;
var FACEBOOK_DISPLAY_MODES = {
popup: 'popup',
page: 'page'
};
var REAL_TWITTER_LIMIT = TWITTER_LIMIT_LENGTH - TWITTER_URL_LENGTH_COUNT - TWITTER_QUOTES - TWITTER_DOTS;
var SOCIAL = {
twitter: 'twitter',
buffer: 'buffer',
digg: 'digg',
linkedin: 'linkedin',
stumbleupon: 'stumbleupon',
reddit: 'reddit',
tumblr: 'tumblr',
facebook: 'facebook'
};
var NO_START_WITH = /[ .,!?/\\\+\-=*£$€:~§%^µ)(|@"{}&#><_]/g;
var NO_ENDS_WITH = /[ ,/\\\+\-=*£$€:~§%^µ)(|@"{}&#><_]/g;
// globals
var tooltip = void 0;
var parameters = void 0;
var selected = {};
var extend = function extend(out) {
out = out || {};
for (var i = 1; i < arguments.length; i += 1) {
if (arguments[i]) {
for (var key in arguments[i]) {
if (arguments[i].hasOwnProperty(key)) {
out[key] = arguments[i][key];
}
}
}
}
return out;
};
var hideTooltip = function hideTooltip() {
tooltip.classList.remove('active');
};
var showTooltip = function showTooltip() {
tooltip.classList.add('active');
};
var smartSanitize = function smartSanitize(text) {
while (text.length && text[0].match(NO_START_WITH)) {
text = text.substring(1, text.length);
}
while (text.length && text[text.length - 1].match(NO_ENDS_WITH)) {
text = text.substring(0, text.length - 1);
}
return text;
};
var sanitizeText = function sanitizeText(text) {
var sociaType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var author = '';
var tweetLimit = REAL_TWITTER_LIMIT;
if (!text) {
return '';
}
if (parameters.twitterUsername && sociaType === SOCIAL.twitter) {
author = ' via @' + parameters.twitterUsername;
tweetLimit = REAL_TWITTER_LIMIT - author.length;
}
if (text.length > REAL_TWITTER_LIMIT) {
text = text.substring(0, tweetLimit);
text = text.substring(0, text.lastIndexOf(' ')) + '...';
} else {
text = text.substring(0, tweetLimit + TWITTER_DOTS);
}
return smartSanitize(text);
};
var generateSocialUrl = function generateSocialUrl(socialType, text) {
if (parameters.sanitize) {
text = sanitizeText(text, socialType);
} else {
text = smartSanitize(text);
}
var twitterUrl = 'https://twitter.com/intent/tweet?url=' + getPageUrl() + '&text="' + text + '"';
if (parameters.twitterUsername && parameters.twitterUsername.length) {
twitterUrl += '&via=' + parameters.twitterUsername;
}
var facebookUrl = 'https://facebook.com/dialog/share?display=' + parameters.facebookDisplayMode + '&href=' + getPageUrl() + '"e=' + text;
if (document.querySelector('meta[property="fb:app_id"]') && document.querySelector('meta[property="fb:app_id"]').getAttribute('content')) {
var content = document.querySelector('meta[property="fb:app_id"]');
facebookUrl += '&app_id=' + content;
} else if (parameters.facebookAppID && parameters.facebookAppID.length) {
facebookUrl += '&app_id=' + parameters.facebookAppID;
} else {
var idx = parameters.buttons.indexOf('facebook');
if (idx > -1) {
parameters.buttons.splice(idx, 1);
}
}
var urls = {
twitter: twitterUrl,
buffer: 'https://buffer.com/add?text="' + text + '"&url=' + getPageUrl(),
digg: 'http://digg.com/submit?url=' + getPageUrl() + '&title=' + text,
linkedin: 'https://www.linkedin.com/shareArticle?url=' + getPageUrl() + '&title=' + text,
stumbleupon: 'http://www.stumbleupon.com/submit?url=' + getPageUrl() + '&title=' + text,
reddit: 'https://reddit.com/submit?url=' + getPageUrl() + '&title=' + text,
tumblr: 'https://www.tumblr.com/widgets/share/tool?canonicalUrl=' + getPageUrl() + '&caption=' + text,
facebook: facebookUrl
};
if (urls.hasOwnProperty(socialType)) {
return urls[socialType];
}
return '';
};
var updateTooltip = function updateTooltip(rect) {
var actualPosition = document.documentElement.scrollTop || document.body.scrollTop;
var body = document.querySelector('body');
tooltip.style.top = actualPosition + rect.top - TOOLTIP_HEIGHT * FACTOR + 'px';
tooltip.style.left = rect.left + rect.width / 2 - body.getBoundingClientRect().width / 2 + 'px';
Array.prototype.forEach.call(parameters.buttons, function (btn) {
tooltip.querySelector('.share-selected-text-btn-' + btn).href = generateSocialUrl(btn, selected.text);
});
window.setTimeout(function () {
showTooltip();
}, parameters.tooltipTimeout);
};
var generateAnchorTag = function generateAnchorTag(anchorType) {
var customIconClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
var anchorTag = document.createElement('A');
var anchorIcon = document.createElement('i');
if (parameters.anchorsClass) {
['share-selected-text-btn', 'share-selected-text-btn-' + anchorType, '' + parameters.anchorsClass].map(function (item) {
return anchorTag.classList.add(item);
});
} else {
['share-selected-text-btn', 'share-selected-text-btn-' + anchorType].map(function (item) {
return anchorTag.classList.add(item);
});
}
if (customIconClass) {
anchorIcon.classList.add('' + customIconClass);
} else {
['icon-sst-' + anchorType, 'fa', 'fa-' + anchorType].map(function (item) {
return anchorIcon.classList.add(item);
});
}
anchorIcon.style.pointerEvents = 'none';
anchorTag.addEventListener('click', function (e) {
e.preventDefault();
var windowFeatures = 'status=no,menubar=no,location=no,scrollbars=no,width=720,height=540';
var url = e.target.href;
window.open(url, 'Share this post', windowFeatures);
});
anchorTag.href = generateSocialUrl(anchorType, selected.text ? selected.text : '');
anchorTag.appendChild(anchorIcon);
return anchorTag;
};
var generateTooltip = function generateTooltip() {
var body = document.querySelector('body');
var mainDiv = document.createElement('DIV');
var btnContainer = document.createElement('DIV');
mainDiv.classList.add('share-selected-text-main-container');
btnContainer.classList.add('share-selected-text-inner');
if (parameters.tooltipClass) {
btnContainer.classList.add(parameters.tooltipClass);
}
mainDiv.style.height = TOOLTIP_HEIGHT + 'px';
mainDiv.style.top = 0;
mainDiv.style.left = 0;
Array.prototype.forEach.call(parameters.buttons, function (btn) {
var aTag = generateAnchorTag(btn);
btnContainer.appendChild(aTag);
});
mainDiv.appendChild(btnContainer);
body.appendChild(mainDiv);
return mainDiv;
};
var getSelectedText = function getSelectedText() {
var text = '';
var selection = void 0;
if (window.getSelection) {
selection = window.getSelection();
text = selection.toString();
} else if (document.selection && document.selection.type !== 'Control') {
selection = document.selection.createRange();
text = selection.text;
}
return {
selection: selection,
text: text
};
};
var shareTooltip = function shareTooltip() {
selected = getSelectedText();
if (selected.text.length) {
var oRange = selected.selection.getRangeAt(0);
var oRect = oRange.getBoundingClientRect();
updateTooltip(oRect);
} else {
hideTooltip();
}
};
exports.shareSelectedText = function (element, args) {
var elt = document.querySelectorAll(element);
parameters = extend({
tooltipClass: '',
sanitize: true,
buttons: [SOCIAL.twitter, SOCIAL.buffer],
anchorsClass: '',
twitterUsername: '',
facebookAppID: '',
facebookDisplayMode: FACEBOOK_DISPLAY_MODES.popup,
tooltipTimeout: TOOLTIP_TIMEOUT
}, args);
tooltip = generateTooltip();
Array.prototype.forEach.call(elt, function (el) {
el.addEventListener('mouseup', function () {
shareTooltip();
});
});
};
})(window);
/*global jQuery, shareSelectedText*/
if (window.jQuery) {
(function ($, shareSelected) {
'use strict';
var shareSelectedify = function shareSelectedify(el, options) {
shareSelected(el, options);
};
$.fn.shareSelectedText = function (options) {
return shareSelectedify(this.selector, options);
};
})(jQuery, shareSelectedText);
}
;