480 lines
19 KiB
JavaScript
480 lines
19 KiB
JavaScript
/*********************************************************************
|
|
* #### Twitter Post Fetcher v18.0.3 ####
|
|
* Coded by Jason Mayes 2015. A present to all the developers out there.
|
|
* www.jasonmayes.com
|
|
* Please keep this disclaimer with my code if you use it. Thanks. :-)
|
|
* Got feedback or questions, ask here:
|
|
* http://www.jasonmayes.com/projects/twitterApi/
|
|
* Github: https://github.com/jasonmayes/Twitter-Post-Fetcher
|
|
* Updates will be posted to this site.
|
|
*********************************************************************/
|
|
(function(root, factory) {
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD. Register as an anonymous module.
|
|
define([], factory);
|
|
} else if (typeof exports === 'object') {
|
|
// Node. Does not work with strict CommonJS, but
|
|
// only CommonJS-like environments that support module.exports,
|
|
// like Node.
|
|
module.exports = factory();
|
|
} else {
|
|
// Browser globals.
|
|
factory();
|
|
}
|
|
}(this, function() {
|
|
var domNode = '';
|
|
var maxTweets = 20;
|
|
var parseLinks = true;
|
|
var queue = [];
|
|
var inProgress = false;
|
|
var printTime = true;
|
|
var printUser = true;
|
|
var formatterFunction = null;
|
|
var supportsClassName = true;
|
|
var showRts = true;
|
|
var customCallbackFunction = null;
|
|
var showInteractionLinks = true;
|
|
var showImages = false;
|
|
var useEmoji = false;
|
|
var targetBlank = true;
|
|
var lang = 'en';
|
|
var permalinks = true;
|
|
var dataOnly = false;
|
|
var script = null;
|
|
var scriptAdded = false;
|
|
|
|
function handleTweets(tweets){
|
|
if (customCallbackFunction === null) {
|
|
var x = tweets.length;
|
|
var n = 0;
|
|
var element = document.getElementById(domNode);
|
|
var html = '<ul>';
|
|
while(n < x) {
|
|
html += '<li>' + tweets[n] + '</li>';
|
|
n++;
|
|
}
|
|
html += '</ul>';
|
|
element.innerHTML = html;
|
|
} else {
|
|
customCallbackFunction(tweets);
|
|
}
|
|
}
|
|
|
|
function strip(data) {
|
|
return data.replace(/<b[^>]*>(.*?)<\/b>/gi, function(a,s){return s;})
|
|
.replace(/class="(?!(tco-hidden|tco-display|tco-ellipsis))+.*?"|data-query-source=".*?"|dir=".*?"|rel=".*?"/gi,
|
|
'');
|
|
}
|
|
|
|
function targetLinksToNewWindow(el) {
|
|
var links = el.getElementsByTagName('a');
|
|
for (var i = links.length - 1; i >= 0; i--) {
|
|
links[i].setAttribute('target', '_blank');
|
|
links[i].setAttribute('rel', 'noopener');
|
|
}
|
|
}
|
|
|
|
function getElementsByClassName (node, classname) {
|
|
var a = [];
|
|
var regex = new RegExp('(^| )' + classname + '( |$)');
|
|
var elems = node.getElementsByTagName('*');
|
|
for (var i = 0, j = elems.length; i < j; i++) {
|
|
if(regex.test(elems[i].className)){
|
|
a.push(elems[i]);
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
|
|
function extractImagesUrl(image_data) {
|
|
if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0) {
|
|
var data_src = image_data.innerHTML.match(/data-image=\"([A-z0-9]+:\/\/[A-z0-9]+\.[A-z0-9]+\.[A-z0-9]+\/[A-z0-9]+\/[A-z0-9\-]+)\"/ig);
|
|
for (var i = 0; i < data_src.length; i++) {
|
|
data_src[i] = data_src[i].match(/data-image=\"([A-z0-9]+:\/\/[A-z0-9]+\.[A-z0-9]+\.[A-z0-9]+\/[A-z0-9]+\/[A-z0-9\-]+)\"/i)[1];
|
|
data_src[i] = decodeURIComponent(data_src[i]) + '.jpg';
|
|
}
|
|
return data_src;
|
|
}
|
|
}
|
|
|
|
|
|
var twitterFetcher = {
|
|
fetch: function(config) {
|
|
if (config.maxTweets === undefined) {
|
|
config.maxTweets = 20;
|
|
}
|
|
if (config.enableLinks === undefined) {
|
|
config.enableLinks = true;
|
|
}
|
|
if (config.showUser === undefined) {
|
|
config.showUser = true;
|
|
}
|
|
if (config.showTime === undefined) {
|
|
config.showTime = true;
|
|
}
|
|
if (config.dateFunction === undefined) {
|
|
config.dateFunction = 'default';
|
|
}
|
|
if (config.showRetweet === undefined) {
|
|
config.showRetweet = true;
|
|
}
|
|
if (config.customCallback === undefined) {
|
|
config.customCallback = null;
|
|
}
|
|
if (config.showInteraction === undefined) {
|
|
config.showInteraction = true;
|
|
}
|
|
if (config.showImages === undefined) {
|
|
config.showImages = false;
|
|
}
|
|
if (config.useEmoji === undefined) {
|
|
config.useEmoji = false;
|
|
}
|
|
if (config.linksInNewWindow === undefined) {
|
|
config.linksInNewWindow = true;
|
|
}
|
|
if (config.showPermalinks === undefined) {
|
|
config.showPermalinks = true;
|
|
}
|
|
if (config.dataOnly === undefined) {
|
|
config.dataOnly = false;
|
|
}
|
|
|
|
if (inProgress) {
|
|
queue.push(config);
|
|
} else {
|
|
inProgress = true;
|
|
|
|
domNode = config.domId;
|
|
maxTweets = config.maxTweets;
|
|
parseLinks = config.enableLinks;
|
|
printUser = config.showUser;
|
|
printTime = config.showTime;
|
|
showRts = config.showRetweet;
|
|
formatterFunction = config.dateFunction;
|
|
customCallbackFunction = config.customCallback;
|
|
showInteractionLinks = config.showInteraction;
|
|
showImages = config.showImages;
|
|
useEmoji = config.useEmoji;
|
|
targetBlank = config.linksInNewWindow;
|
|
permalinks = config.showPermalinks;
|
|
dataOnly = config.dataOnly;
|
|
|
|
var head = document.getElementsByTagName('head')[0];
|
|
if (script !== null) {
|
|
head.removeChild(script);
|
|
}
|
|
script = document.createElement('script');
|
|
script.type = 'text/javascript';
|
|
if (config.list !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/list?' +
|
|
'callback=__twttrf.callback&dnt=false&list_slug=' +
|
|
config.list.listSlug + '&screen_name=' + config.list.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.profile !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/profile?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&screen_name=' + config.profile.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.likes !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/likes?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&screen_name=' + config.likes.screenName +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else if (config.collection !== undefined) {
|
|
script.src = 'https://syndication.twitter.com/timeline/collection?' +
|
|
'callback=__twttrf.callback&dnt=false' +
|
|
'&collection_id=' + config.collection.collectionId +
|
|
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
|
|
'&rnd=' + Math.random();
|
|
} else {
|
|
script.src = 'https://cdn.syndication.twimg.com/widgets/timelines/' +
|
|
config.id + '?&lang=' + (config.lang || lang) +
|
|
'&callback=__twttrf.callback&' +
|
|
'suppress_response_codes=true&rnd=' + Math.random();
|
|
}
|
|
head.appendChild(script);
|
|
}
|
|
},
|
|
callback: function(data) {
|
|
if (data === undefined || data.body === undefined) {
|
|
inProgress = false;
|
|
|
|
if (queue.length > 0) {
|
|
twitterFetcher.fetch(queue[0]);
|
|
queue.splice(0,1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Remove emoji and summary card images.
|
|
if(!useEmoji){
|
|
data.body = data.body.replace(/(<img[^c]*class="Emoji[^>]*>)|(<img[^c]*class="u-block[^>]*>)/g, '');
|
|
}
|
|
|
|
// Remove display images.
|
|
if (!showImages) {
|
|
data.body = data.body.replace(/(<img[^c]*class="NaturalImage-image[^>]*>|(<img[^c]*class="CroppedImage-image[^>]*>))/g, '');
|
|
}
|
|
// Remove avatar images.
|
|
if (!printUser) {
|
|
data.body = data.body.replace(/(<img[^c]*class="Avatar"[^>]*>)/g, '');
|
|
}
|
|
|
|
var div = document.createElement('div');
|
|
div.innerHTML = data.body;
|
|
if (typeof(div.getElementsByClassName) === 'undefined') {
|
|
supportsClassName = false;
|
|
}
|
|
|
|
function swapDataSrc(element) {
|
|
var avatarImg = element.getElementsByTagName('img')[0];
|
|
if (avatarImg) {
|
|
avatarImg.src = avatarImg.getAttribute('data-src-2x');
|
|
} else {
|
|
var screenName = element.getElementsByTagName('a')[0]
|
|
.getAttribute('href').split('twitter.com/')[1];
|
|
var img = document.createElement('img');
|
|
img.setAttribute('src', 'https://twitter.com/' + screenName +
|
|
'/profile_image?size=bigger');
|
|
element.prepend(img);
|
|
}
|
|
return element;
|
|
}
|
|
|
|
var tweets = [];
|
|
var authors = [];
|
|
var times = [];
|
|
var images = [];
|
|
var rts = [];
|
|
var tids = [];
|
|
var permalinksURL = [];
|
|
var x = 0;
|
|
|
|
if (supportsClassName) {
|
|
var tmp = div.getElementsByClassName('timeline-Tweet');
|
|
while (x < tmp.length) {
|
|
if (tmp[x].getElementsByClassName('timeline-Tweet-retweetCredit').length > 0) {
|
|
rts.push(true);
|
|
} else {
|
|
rts.push(false);
|
|
}
|
|
if (!rts[x] || rts[x] && showRts) {
|
|
tweets.push(tmp[x].getElementsByClassName('timeline-Tweet-text')[0]);
|
|
tids.push(tmp[x].getAttribute('data-tweet-id'));
|
|
if (printUser) {
|
|
authors.push(swapDataSrc(tmp[x].getElementsByClassName('timeline-Tweet-author')[0]));
|
|
}
|
|
times.push(tmp[x].getElementsByClassName('dt-updated')[0]);
|
|
permalinksURL.push(tmp[x].getElementsByClassName('timeline-Tweet-timestamp')[0]);
|
|
if (tmp[x].getElementsByClassName('timeline-Tweet-media')[0] !==
|
|
undefined) {
|
|
images.push(tmp[x].getElementsByClassName('timeline-Tweet-media')[0]);
|
|
} else {
|
|
images.push(undefined);
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
} else {
|
|
var tmp = getElementsByClassName(div, 'timeline-Tweet');
|
|
while (x < tmp.length) {
|
|
if (getElementsByClassName(tmp[x], 'timeline-Tweet-retweetCredit').length > 0) {
|
|
rts.push(true);
|
|
} else {
|
|
rts.push(false);
|
|
}
|
|
if (!rts[x] || rts[x] && showRts) {
|
|
tweets.push(getElementsByClassName(tmp[x], 'timeline-Tweet-text')[0]);
|
|
tids.push(tmp[x].getAttribute('data-tweet-id'));
|
|
if (printUser) {
|
|
authors.push(swapDataSrc(getElementsByClassName(tmp[x],'timeline-Tweet-author')[0]));
|
|
}
|
|
times.push(getElementsByClassName(tmp[x], 'dt-updated')[0]);
|
|
permalinksURL.push(getElementsByClassName(tmp[x], 'timeline-Tweet-timestamp')[0]);
|
|
if (getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0] !== undefined) {
|
|
images.push(getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0]);
|
|
} else {
|
|
images.push(undefined);
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
}
|
|
|
|
if (tweets.length > maxTweets) {
|
|
tweets.splice(maxTweets, (tweets.length - maxTweets));
|
|
authors.splice(maxTweets, (authors.length - maxTweets));
|
|
times.splice(maxTweets, (times.length - maxTweets));
|
|
rts.splice(maxTweets, (rts.length - maxTweets));
|
|
images.splice(maxTweets, (images.length - maxTweets));
|
|
permalinksURL.splice(maxTweets, (permalinksURL.length - maxTweets));
|
|
}
|
|
|
|
var arrayTweets = [];
|
|
var x = tweets.length;
|
|
var n = 0;
|
|
if (dataOnly) {
|
|
while (n < x) {
|
|
arrayTweets.push({
|
|
tweet: tweets[n].innerHTML,
|
|
author: authors[n] ? authors[n].innerHTML : 'Unknown Author',
|
|
author_data: {
|
|
profile_url: authors[n] ? authors[n].querySelector('[data-scribe="element:user_link"]').href : null,
|
|
profile_image: authors[n] ?
|
|
'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=bigger' : null,
|
|
profile_image_2x: authors[n] ? 'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=original' : null,
|
|
screen_name: authors[n] ? authors[n].querySelector('[data-scribe="element:screen_name"]').title : null,
|
|
name: authors[n] ? authors[n].querySelector('[data-scribe="element:name"]').title : null
|
|
},
|
|
time: times[n].textContent,
|
|
timestamp: times[n].getAttribute('datetime').replace('+0000', 'Z').replace(/([\+\-])(\d\d)(\d\d)/, '$1$2:$3'),
|
|
image: (extractImagesUrl(images[n]) ? extractImagesUrl(images[n])[0] : undefined),
|
|
images: extractImagesUrl(images[n]),
|
|
rt: rts[n],
|
|
tid: tids[n],
|
|
permalinkURL: (permalinksURL[n] === undefined) ?
|
|
'' : permalinksURL[n].href
|
|
});
|
|
n++;
|
|
}
|
|
} else {
|
|
while (n < x) {
|
|
if (typeof(formatterFunction) !== 'string') {
|
|
var datetimeText = times[n].getAttribute('datetime');
|
|
var newDate = new Date(times[n].getAttribute('datetime')
|
|
.replace(/-/g,'/').replace('T', ' ').split('+')[0]);
|
|
var dateString = formatterFunction(newDate, datetimeText);
|
|
times[n].setAttribute('aria-label', dateString);
|
|
|
|
if (tweets[n].textContent) {
|
|
// IE hack.
|
|
if (supportsClassName) {
|
|
times[n].textContent = dateString;
|
|
} else {
|
|
var h = document.createElement('p');
|
|
var t = document.createTextNode(dateString);
|
|
h.appendChild(t);
|
|
h.setAttribute('aria-label', dateString);
|
|
times[n] = h;
|
|
}
|
|
} else {
|
|
times[n].textContent = dateString;
|
|
}
|
|
}
|
|
var op = '';
|
|
if (parseLinks) {
|
|
if (targetBlank) {
|
|
targetLinksToNewWindow(tweets[n]);
|
|
if (printUser) {
|
|
targetLinksToNewWindow(authors[n]);
|
|
}
|
|
}
|
|
if (printUser) {
|
|
op += '<div class="user">' + strip(authors[n].innerHTML) +
|
|
'</div>';
|
|
}
|
|
op += '<p class="tweet">' + strip(tweets[n].innerHTML) + '</p>';
|
|
if (printTime) {
|
|
if (permalinks) {
|
|
op += '<p class="timePosted"><a href="' + permalinksURL[n] +
|
|
'">' + times[n].getAttribute('aria-label') + '</a></p>';
|
|
} else {
|
|
op += '<p class="timePosted">' +
|
|
times[n].getAttribute('aria-label') + '</p>';
|
|
}
|
|
}
|
|
} else {
|
|
if (tweets[n].textContent) {
|
|
if (printUser) {
|
|
op += '<p class="user">' + authors[n].textContent + '</p>';
|
|
}
|
|
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
|
|
if (printTime) {
|
|
op += '<p class="timePosted">' + times[n].textContent + '</p>';
|
|
}
|
|
|
|
} else {
|
|
if (printUser) {
|
|
op += '<p class="user">' + authors[n].textContent + '</p>';
|
|
}
|
|
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
|
|
if (printTime) {
|
|
op += '<p class="timePosted">' + times[n].textContent + '</p>';
|
|
}
|
|
}
|
|
}
|
|
if (showInteractionLinks) {
|
|
op += '<p class="interact"><a href="https://twitter.com/intent/' +
|
|
'tweet?in_reply_to=' + tids[n] +
|
|
'" class="twitter_reply_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') +
|
|
'Reply</a><a href="https://twitter.com/intent/retweet?' +
|
|
'tweet_id=' + tids[n] + '" class="twitter_retweet_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + 'Retweet</a>' +
|
|
'<a href="https://twitter.com/intent/favorite?tweet_id=' +
|
|
tids[n] + '" class="twitter_fav_icon"' +
|
|
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + 'Favorite</a></p>';
|
|
}
|
|
if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined) {
|
|
var extractedImages = extractImagesUrl(images[n]);
|
|
for (var i = 0; i < extractedImages.length; i++) {
|
|
op += '<div class="media">' +
|
|
'<img src="' + extractedImages[i] +
|
|
'" alt="Image from tweet" />' + '</div>';
|
|
}
|
|
}
|
|
if (showImages) {
|
|
arrayTweets.push(op);
|
|
} else if (!showImages && tweets[n].textContent.length) {
|
|
arrayTweets.push(op);
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
|
|
handleTweets(arrayTweets);
|
|
inProgress = false;
|
|
|
|
if (queue.length > 0) {
|
|
twitterFetcher.fetch(queue[0]);
|
|
queue.splice(0,1);
|
|
}
|
|
}
|
|
};
|
|
|
|
// It must be a global variable because it will be called by JSONP.
|
|
window.__twttrf = twitterFetcher;
|
|
window.twitterFetcher = twitterFetcher;
|
|
return twitterFetcher;
|
|
}));
|
|
|
|
|
|
// Prepend polyfill for IE/Edge.
|
|
(function (arr) {
|
|
arr.forEach(function (item) {
|
|
if (item.hasOwnProperty('prepend')) {
|
|
return;
|
|
}
|
|
Object.defineProperty(item, 'prepend', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
writable: true,
|
|
value: function prepend() {
|
|
var argArr = Array.prototype.slice.call(arguments),
|
|
docFrag = document.createDocumentFragment();
|
|
|
|
argArr.forEach(function (argItem) {
|
|
var isNode = argItem instanceof Node;
|
|
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
|
|
});
|
|
|
|
this.insertBefore(docFrag, this.firstChild);
|
|
}
|
|
});
|
|
});
|
|
})([Element.prototype, Document.prototype, DocumentFragment.prototype]); |