import _ from "underscore";
import $ from "jquery";
import Raphael from "raphael";
import dayjs from "dayjs";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
function rejectUser(username) {
return /^[A-Z][a-z]{2,8}[0-9]{4,6}$/.test(username);
}
function getGlobal(varkey, defaultValue) {
return typeof global[varkey] == "undefined" ? defaultValue : global[varkey];
}
let annotations = getGlobal("annotations", {
default: {
colors: {
h: 0,
s: 0,
},
},
positive: {
display_name: "++ | important",
keywords: [/\+\+/],
colors: {
h: 0.3,
s: 0.65,
},
},
negative: {
display_name: "** | index",
keywords: [/\*\*/],
colors: {
h: 0,
s: 0.8,
},
},
reference: {
display_name: "== | commentaire",
keywords: [/\=\=/],
colors: {
h: 0.16,
s: 0.8,
},
},
question: {
display_name: "?? | trouble",
keywords: [/\?\?/],
colors: {
h: 0.6,
s: 0.8,
},
},
});
function getSocialGroupUri(social_group) {
const groupParts = social_group.replace(/^\@+/, "").split("@");
return `https://${groupParts[1]}/u/${groupParts[0]}`;
}
var i10n = getGlobal("i10n", {
rechercher: "Rechercher",
loading_messages: "Chargement messages",
loading_messages_error: "Erreur chargement messages",
});
const suggested_keywords = getGlobal("suggested_keywords", []);
const max_pages = getGlobal("max_pages", 5);
const social_network = getGlobal("social_network", "Twitter");
const social_login_domain = getGlobal("social_login_domain");
const social_access_token = getGlobal("social_access_token");
const social_group = getGlobal("social_group");
tracking_keywords = _(getGlobal("tracking_keywords", [])).map(function (_w) {
return _w.toLowerCase();
});
var twCx = {
tlPaper: null,
followLast: true,
position: "0",
currentIdIndex: 0,
date_levels: [3600 * 1000, 15 * 60 * 1000, 5 * 60 * 1000, 60 * 1000],
timeLevel: 1,
deltaX: 40,
tlWidth: 150,
tlHeight: 480,
globalWords: {},
suggestCount: _(suggested_keywords).map(function (_w) {
return {
word: _w,
rgxp: new RegExp(_w.replace(/(\W)/g, "\\$1"), "im"),
freq: 0,
annotations: {},
};
}),
refMouse: { x: 0, y: 0 },
refPosTl: { x: 0, y: 0 },
tlMouseMoved: false,
tlMouseClicked: false,
filtre: null,
tlBuffer: "",
relHover: [],
wheelDelta: 0,
scrollEnabled: false,
scrollExtent: 8000 - 480,
lastScrollPos: 0,
urlRegExp: /https?:\/\/[0-9a-zA-Z\.%\/-_]+/g,
wordRegExp: /[^ \.&;,'"!\?\d\(\)\+\[\]\\\…\-«»:\/]{3,}/g,
stopWords: [
"aussi",
"and",
"avec",
"aux",
"bien",
"car",
"cette",
"comme",
"dans",
"donc",
"des",
"elle",
"encore",
"est",
"être",
"eux",
"faire",
"fait",
"http",
"ici",
"ils",
"les",
"leur",
"leurs",
"mais",
"mes",
"même",
"mon",
"notre",
"non",
"nos",
"nous",
"ont",
"oui",
"par",
"pas",
"peu",
"peut",
"plus",
"pour",
"que",
"qui",
"ses",
"son",
"sont",
"sur",
"tes",
"très",
"the",
"ton",
"tous",
"tout",
"une",
"votre",
"vos",
"vous",
],
};
function getSocialData() {
return $.ajax({
beforeSend: function (request) {
request.setRequestHeader(
"Authorization",
`Bearer ${social_access_token}`
);
},
type: "GET",
dataType: "json",
url: `https://${social_login_domain}/api/v1/accounts/verify_credentials`,
});
}
function getFollowing(user_id) {
return $.ajax({
beforeSend: function (request) {
request.setRequestHeader(
"Authorization",
`Bearer ${social_access_token}`
);
},
type: "GET",
dataType: "json",
url: `https://${social_login_domain}/api/v1/accounts/${user_id}/following`,
});
}
function getTweets(options) {
function getTweetUrl(url) {
$("#tweetLoader").addClass("tweetLoading");
$("#tweetLoader").attr("title", i10n["loading_messages"]);
$("#tweetLoader").removeClass("tweetLoadingError");
$.ajax({
url: url,
dataType: "json",
success: function (data) {
$("#tweetLoader").removeClass("tweetLoading");
$("#tweetLoader").removeAttr("title");
if (typeof data == "undefined" || !data) {
$("#tweetLoader").addClass("tweetLoadingError");
$("#tweetLoader").attr("title", i10n["loading_messages_error"]);
return;
}
options.tweets = options.tweets.concat(data.statuses);
options.currentPage++;
if (options.cbData) {
options.cbData();
}
var _isLast = true;
if (data.results && data.results.length) {
var _oldestTweetId = data.results[data.results.length - 1].id_str,
_maxId = _oldestTweetId;
if (options.currentPage < options.pages) {
_isLast = false;
getTweetUrl(
baseurl + firstparams + "&max_id=" + _maxId + lastparams
);
}
}
if (_isLast) {
options.tweets.sort(function (a, b) {
return a.id.localeCompare(b.id);
});
if (options.cbEnd) {
options.cbEnd();
}
}
},
timeout: 10000, //3 second timeout,
error: function (jqXHR, status, errorThrown) {
$("#tweetLoader").addClass("tweetLoadingError");
$("#tweetLoader").attr(
"title",
i10n["loading_messages_error"] + " - " + status
);
},
});
$.getJSON(url);
}
options.tweets = [];
options.pages || (options.pages = 1);
options.rpp || (options.rpp = 100);
options.currentPage = 0;
var urlParams = {
tweet_mode: "extended",
q: options.keyword,
count: options.rpp,
};
if (options.lang) {
urlParams.lang = options.lang;
}
if (options.since_id) {
urlParams.since_id = options.since_id;
}
urlParams.social_network = options.social_network
? options.social_network
: "Twitter";
var jsonurl = "search_tweets.php?" + $.param(urlParams);
getTweetUrl(jsonurl);
}
function getColor(annotation, lum) {
return Raphael.hsl2rgb(
annotations[annotation].colors.h,
annotations[annotation].colors.s,
lum
);
}
function tweetPopup(url) {
var popW = 550,
popH = 350,
scrW = screen.width,
scrH = screen.height,
posX = Math.round(scrW / 2 - popW / 2),
posY = scrH > popH ? Math.round(scrH / 2 - popH / 2) : 0;
window.open(
url,
"",
"left=" +
posX +
",top=" +
posY +
",width=" +
popW +
",height=" +
popH +
",personalbar=0,toolbar=0,scrollbars=1,resizable=1"
);
}
function arc(source, target) {
var x3 = 0.3 * target.y - 0.3 * source.y + 0.8 * source.x + 0.2 * target.x;
var y3 = 0.8 * source.y + 0.2 * target.y - 0.3 * target.x + 0.3 * source.x;
var x4 = 0.3 * target.y - 0.3 * source.y + 0.2 * source.x + 0.8 * target.x;
var y4 = 0.2 * source.y + 0.8 * target.y - 0.3 * target.x + 0.3 * source.x;
return (
"M" +
source.x +
" " +
source.y +
"C" +
[x3, y3, x4, y4, target.x, target.y].join(" ")
);
}
function addTweet(tweet) {
if (!tweet) {
console.log(tweet);
return;
}
if (rejectUser(tweet.from_user)) {
return;
}
function backRef(source_id, target_id, type) {
var target = tweetById(target_id);
if (target) {
var brobj = {
referenced_by_id: source_id,
type: type,
};
if (target.backRefs) {
target.backRefs.push(brobj);
} else {
target.backRefs = [brobj];
}
}
}
_(["id", "from_user_id", "in_reply_to_status_id"]).each(function (_i) {
if (typeof tweet[_i + "_str"] == "undefined") return;
tweet[_i] = tweet[_i + "_str"];
delete tweet[_i + "_str"];
});
if (_(twCx.idIndex).indexOf(tweet.id) != -1) {
return;
}
tweet.html_parts = [];
if (tweet.entities && tweet.entities.user_mentions) {
for (var _i = 0; _i < tweet.entities.user_mentions.length; _i++) {
var _m = tweet.entities.user_mentions[_i];
tweet.html_parts.push({
text: "@" + _m.screen_name,
start: _m.indices[0],
end: _m.indices[1],
link:
'<a href="http://twitter.com/' +
_m.screen_name +
'" onclick="filtrerTexte(\'' +
_m.screen_name +
'\'); return false;" target="_blank">',
});
}
}
if (tweet.entities && tweet.entities.hashtags) {
for (var _i = 0; _i < tweet.entities.hashtags.length; _i++) {
var _m = tweet.entities.hashtags[_i],
_h = "#" + _m.text;
tweet.html_parts.push({
text: _h,
start: _m.indices[0],
end: _m.indices[1],
link:
'<a href="http://twitter.com/search?q=' +
encodeURIComponent(_h) +
'" onclick="filtrerTexte(\'' +
_.escape(_h) +
'\'); return false;" target="_blank">',
});
}
}
if (tweet.entities && tweet.entities.urls) {
for (var _i = 0; _i < tweet.entities.urls.length; _i++) {
var _m = tweet.entities.urls[_i];
tweet.html_parts.push({
text: _m.display_url || _m.url,
start: _m.indices[0],
end: _m.indices[1],
link: '<a href="' + _m.url + '" target="_blank">',
});
}
}
tweet.date_value = dayjs(tweet.created_at).valueOf();
var ann = [];
for (var j in annotations) {
if (j != "default") {
for (var k in annotations[j].keywords) {
var tweetText = tweet.full_text;
if (tweetText.search(annotations[j].keywords[k]) != -1) {
ann.push(j);
break;
}
}
}
}
tweet.annotations = ann;
if (tweet.in_reply_to_status_id) {
backRef(tweet.id, tweet.in_reply_to_status_id, "reply");
}
if (tweet.retweeted_status && tweet.retweeted_status.id_str) {
tweet.retweeted_status_id = tweet.retweeted_status.id_str;
backRef(tweet.id, tweet.retweeted_status_id, "retweet");
}
// clean full text from html
const temp_div_element = document.createElement("div");
temp_div_element.innerHTML = tweet.full_text;
const full_text =
temp_div_element.textContent ||
temp_div_element.innerText ||
tweet.full_text;
var tab = full_text.replace(twCx.urlRegExp, "").match(twCx.wordRegExp);
_(tab).each(function (w) {
var word = w.toLowerCase();
if (
_(twCx.stopWords).indexOf(word) == -1 &&
_(tracking_keywords).indexOf(word) == -1 &&
word[0] != "@"
) {
if (twCx.globalWords[word]) {
twCx.globalWords[word].freq++;
} else {
twCx.globalWords[word] = {
freq: 1,
annotations: {},
};
for (var j in annotations) {
if (j != "default") {
twCx.globalWords[word].annotations[j] = 0;
}
}
}
for (var j in ann) {
if (typeof twCx.globalWords[word].annotations != "undefined") {
twCx.globalWords[word].annotations[ann[j]]++;
}
}
}
});
_(twCx.suggestCount).each(function (_k) {
if (tweet.full_text.search(_k.rgxp) != -1) {
_k.freq++;
_(ann).each(function (_a) {
_k.annotations[_a] = 1 + (_k.annotations[_a] || 0);
});
}
});
var p = twCx.idIndex.length;
while (p && tweet.id < twCx.idIndex[p - 1]) {
p--;
}
twCx.tweets.splice(p, 0, tweet);
twCx.idIndex.splice(p, 0, tweet.id);
if (!twCx.timeline.length) {
twCx.timeline = [
populateDateStruct(
0,
twCx.date_levels[0] * parseInt(tweet.date_value / twCx.date_levels[0])
),
];
}
while (tweet.date_value > twCx.timeline[twCx.timeline.length - 1].end) {
twCx.timeline.push(
populateDateStruct(0, twCx.timeline[twCx.timeline.length - 1].end)
);
}
insertIntoDateStruct(twCx.timeline, tweet);
}
function getSliceContent(slice) {
if (slice.slices) {
var result = [];
for (var i in slice.slices) {
result = result.concat(getSliceContent(slice.slices[i]));
}
} else {
var result = slice.tweets;
}
return result;
}
function flattenDateStruct(slices, target_level) {
if (!slices || !slices.length) {
return [];
}
var current_level = slices[0].level,
result = [];
if (current_level < target_level) {
if (slices[0].slices) {
for (var i in slices) {
result = result.concat(
flattenDateStruct(slices[i].slices, target_level)
);
}
}
} else {
for (var i in slices) {
result.push({
start: slices[i].start,
end: slices[i].end,
tweets: getSliceContent(slices[i]),
});
}
}
return result;
}
function trimFDS() {
var slices = flattenDateStruct(twCx.timeline, twCx.timeLevel);
if (!slices.length) {
return [];
}
while (slices[0].tweets.length == 0) {
slices.splice(0, 1);
}
while (slices[slices.length - 1].tweets.length == 0) {
slices.pop();
}
var centralTweet = twCx.centralTweet
? twCx.centralTweet
: twCx.tweets[twCx.tweets.length - 1],
delta = 30 * twCx.date_levels[twCx.timeLevel],
centre = Math.min(
slices[slices.length - 1].end - delta,
Math.max(slices[0].start + delta, centralTweet.date_value)
),
min = centre - delta,
max = centre + delta;
while (slices[0].start < min) {
slices.splice(0, 1);
}
while (slices[slices.length - 1].end > max) {
slices.pop();
}
return slices;
}
function populateDateStruct(level, start) {
var end = start + twCx.date_levels[level],
struct = {
level: level,
start: start,
end: end,
};
if (level < twCx.date_levels.length - 1) {
struct.slices = [];
var newstart = start;
while (newstart < end) {
struct.slices.push(populateDateStruct(level + 1, newstart));
newstart += twCx.date_levels[level + 1];
}
} else {
struct.tweets = [];
}
return struct;
}
function insertIntoDateStruct(slices, tweet) {
var creadate = tweet.date_value;
for (var i in slices) {
if (creadate < slices[i].end) {
if (slices[i].slices) {
insertIntoDateStruct(slices[i].slices, tweet);
} else {
slices[i].tweets.push(tweet.id);
}
break;
}
}
}
function placeHolder(className) {
return '<li class="placeholder ' + className + '"></li>';
}
function tweetById(tweetid) {
var pos = _(twCx.idIndex).indexOf(tweetid);
return pos == -1 ? false : twCx.tweets[pos];
}
function selectTweet(tweetid) {
twCx.position = tweetid;
twCx.followLast = twCx.position == twCx.idIndex[twCx.tweets.length - 1];
updateDisplay();
}
function goToPos(nPos) {
twCx.position =
twCx.currentIdIndex[
Math.min(twCx.currentIdIndex.length - 1, Math.max(0, nPos))
];
twCx.followLast = !twCx.filtre && nPos == twCx.tweets.length - 1;
updateDisplay();
}
function movePos(delta) {
goToPos(delta + _(twCx.currentIdIndex).indexOf(twCx.position));
}
// getMsgUrl
// getUserScreenName
// getDescription
//
function getMsgHtmlAdapter(msg) {
return {
Twitter: {
getMsgUrl: function () {
return (
"https://twitter.com/" + msg.user.screen_name + "/status/" + msg.id
);
},
getMsgUri: function () {
return (
"https://twitter.com/" + msg.user.screen_name + "/status/" + msg.id
);
},
getMsgId: function () {
return "tweet_" + msg.id;
},
getMsgTitle: function () {
return "Tweet by " + _(msg.user.name).escape();
},
getMsgDescription: function () {
return _(msg.full_text).escape();
},
getMsgUserUrl: function () {
return "https://twitter.com/" + msg.user.screen_name;
},
getMsgReplyUrl: function () {
return "https://twitter.com/intent/tweet?in_reply_to=" + msg.id;
},
getMsgRetweetUrl: function () {
return "https://twitter.com/intent/retweet?tweet_id=" + msg.id;
},
getMsgFavoriteUrl: function () {
return "https://twitter.com/intent/favorite?tweet_id=" + msg.id;
},
},
Mastodon: {
getMsgUrl: function () {
return msg.url;
},
getMsgUri: function () {
return msg.uri;
},
getMsgId: function () {
return "toot_" + msg.id;
},
getMsgTitle: function () {
return "Toot by " + _(msg.user.name).escape();
},
getMsgDescription: function () {
return _($(msg.full_text).text()).escape();
},
getMsgUserUrl: function () {
return msg.user.url;
},
getMsgReplyUrl: function () {
return "";
},
getMsgRetweetUrl: function () {
return "";
},
getMsgFavoriteUrl: function () {
return "";
},
},
}[msg.type];
}
function tweetToHtml(tweet, className, elName) {
function highlight(texte) {
return twCx.filtre
? texte.replace(twCx.filtre, '<span class="highlight">$1</span>')
: texte;
}
if (!tweet) {
return placeHolder(className);
}
const htmlAdapter = getMsgHtmlAdapter(tweet);
var el = elName ? elName : "li";
var html =
"<" +
el +
' draggable="true" class="tweet ' +
className +
'" id="tweet_' +
tweet.id +
'" data-title="' +
htmlAdapter.getMsgTitle() +
'" data-description="' +
htmlAdapter.getMsgDescription() +
'" data-uri="' +
htmlAdapter.getMsgUri() +
'"';
if (className != "full") {
html += " onclick=\"selectTweet('" + tweet.id + "'); return false;\"";
}
html +=
" onmouseover=\"rolloverTweet('" +
tweet.id +
"', " +
(className == "icons") +
');"';
if (twCx.followLast && className == "full" && el == "li") {
html += ' style="display: none"';
}
html += ">";
if (tweet.annotations && tweet.annotations.length) {
html += '<div class="annotations">';
for (var i in tweet.annotations) {
html +=
'<div class="annotation" style="width:' +
100 / tweet.annotations.length +
"%; background:" +
getColor(tweet.annotations[i], className == "icons" ? 0.4 : 0.85).hex +
'"></div>';
}
html += "</div>";
}
html += '<div class="twmain">';
var a_user =
'<a href="' +
htmlAdapter.getMsgUserUrl() +
'" onclick="filtrerTexte(\'@' +
tweet.user.screen_name +
'\'); return false;" target="_blank">';
html +=
'<div class="around_img"><img class="profile_image" src="' +
tweet.user.profile_image_url_https +
'" />';
if (className == "full") {
html +=
'<p class="created_at">' +
new Date(tweet.date_value).toTimeString().substr(0, 8) +
"</a></p>";
}
html += "</div>";
if (className != "icons") {
let lastend = 0;
var txt = "";
const full_text = $(tweet.full_text).text();
tweet.html_parts.sort(function (a, b) {
return a.start - b.start;
});
_(tweet.html_parts).each(function (_e) {
txt +=
highlight(full_text.substring(lastend, _e.start)) +
_e.link +
highlight(_e.text) +
"</a>";
lastend = _e.end;
});
//lastend = Math.max(120, lastend);
txt += highlight(full_text.substring(lastend));
html +=
'<p class="tweet_text"><b>' +
a_user +
'<span title="' +
tweet.user.screen_name +
'">' +
highlight("@" + tweet.user.name) +
"</span></a>" +
(className == "full"
? " (" + tweet.user.name + ")</b><br />"
: "</b> : ") +
txt +
"</p>";
if (className == "full" && el == "li") {
html +=
'<div class="tweet_actions"><a href="' +
htmlAdapter.getMsgUrl() +
'" onclick="tweetPopup(this.href); return false;" target="_blank">afficher message</a>';
const replyUrl = htmlAdapter.getMsgReplyUrl();
if (replyUrl) {
html +=
'<a href="' +
replyUrl +
'" onclick="tweetPopup(this.href); return false;" target="_blank">répondre</a> · ';
}
const retweetUrl = htmlAdapter.getMsgRetweetUrl();
if (retweetUrl) {
html +=
'<a href="' +
retweetUrl +
'" onclick="tweetPopup(this.href); return false;" target="_blank">retransmettre</a> · ';
}
const favoriteUrl = htmlAdapter.getMsgFavoriteUrl();
if (favoriteUrl) {
html +=
'<a href="' +
favoriteUrl +
'" onclick="tweetPopup(this.href); return false;" target="_blank">favori</a>';
}
html += "</div>";
}
}
html += "</div></" + el + ">";
return html;
}
function tlIdFromPos(x, y, outside) {
if (!twCx.tlOnDisplay || !twCx.tlOnDisplay.length) {
return;
}
var ligne = Math.min(
twCx.tlOnDisplay.length - 1,
Math.max(0, Math.floor((twCx.tlHeight - y) / twCx.scaleY))
),
colonne = Math.floor((x - twCx.deltaX) / twCx.scaleX),
l = 0;
if (colonne >= twCx.tlOnDisplay[ligne].totalTweets || colonne < 0) {
if (outside) {
colonne = Math.min(
twCx.tlOnDisplay[ligne].totalTweets - 1,
Math.max(0, colonne)
);
} else {
return null;
}
}
for (var i in twCx.tlOnDisplay[ligne].displayData) {
var nl = l + twCx.tlOnDisplay[ligne].displayData[i].length;
if (colonne < nl) {
return {
id: twCx.tlOnDisplay[ligne].displayData[i][colonne - l],
annotation: i,
};
}
l = nl;
}
}
function tlPosTweet(tweet, annotation) {
if (!twCx.tweets) {
return;
}
var x,
y,
dt = tweet.date_value,
ann = annotation
? annotation
: tweet.annotations && tweet.annotations.length
? tweet.annotations[0]
: "default";
for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
if (twCx.tlOnDisplay[i].end > dt) {
y = twCx.tlHeight - (i + 0.5) * twCx.scaleY;
var l = 0;
for (var j in twCx.tlOnDisplay[i].displayData) {
if (j == ann) {
var p = _(twCx.tlOnDisplay[i].displayData[j]).indexOf(tweet.id);
if (p != -1) {
x = twCx.deltaX + twCx.scaleX * (p + l + 0.5);
}
break;
}
l += twCx.tlOnDisplay[i].displayData[j].length;
}
break;
}
}
return x && y ? { x: x, y: y } : null;
}
function rolloverTweet(tweetid, showPopup, annotation) {
var t = tweetById(tweetid);
if (!t) {
return;
}
var p = tlPosTweet(t, annotation);
if (!p) {
return;
}
var ptl = $("#timeline").offset();
if (showPopup) {
$("#hovercontent").html(tweetToHtml(t, "full", "div"));
$("#hovertweet").css({
left: parseInt(ptl.left + p.x) + "px",
top: parseInt(ptl.top + p.y),
display: "block",
});
} else {
$("#hovertweet").hide();
}
for (var i in twCx.relHover) {
twCx.relHover[i].remove();
}
twCx.relHover = drawTweetArcs(t, p, "#303030");
twCx.relHover.push(drawTweetPos(p, "#ffffff"));
}
function drawTweetPos(pos, color) {
var rel = twCx.tlPaper.rect(
pos.x - 0.5 * twCx.scaleX,
pos.y - 0.5 * twCx.scaleY,
twCx.scaleX,
twCx.scaleY
);
rel.attr({ stroke: color, fill: color, "fill-opacity": 0.25 });
return rel;
}
function drawTweetArcs(tweet, pos, color) {
var res = [];
function tweetAndArc(a, b, aorb) {
if (a && b) {
res.push(drawTweetPos(aorb ? a : b, color));
var aa = twCx.tlPaper
.path(arc(a, b))
.attr({ stroke: color, "stroke-width": 1.5, "stroke-opacity": 0.8 });
res.push(aa);
}
}
if (tweet.retweeted_status_id) {
var t = tweetById(tweet.retweeted_status_id);
if (t) {
tweetAndArc(pos, tlPosTweet(t));
}
}
if (tweet.in_reply_to_status_id) {
var t = tweetById(tweet.in_reply_to_status_id);
if (t) {
tweetAndArc(pos, tlPosTweet(t));
}
}
if (tweet.backRefs) {
for (var i in tweet.backRefs) {
var t = tweetById(tweet.backRefs[i].referenced_by_id);
if (t) {
tweetAndArc(tlPosTweet(t), pos, true);
}
}
}
return res;
}
function mouseoverkw() {
var _jel = $(this),
_off = _jel.offset();
_jel.css({
color: "#0099ff",
});
$("#hoverkw")
.css({
left: _off.left + "px",
top: parseInt(_off.top) + ~~(_jel.height() / 2) + "px",
display: "block",
})
.attr("kw", _jel.text());
}
function mouseoutkw() {
$("#hoverkw").hide();
$(this).css({
color: "#000000",
});
}
function makeTagCloud(tab, div) {
var minfreq = _(tab).min(function (a) {
return a.freq;
}).freq,
maxfreq = Math.max(
minfreq + 0.1,
_(tab).max(function (a) {
return a.freq;
}).freq
),
echfreq = 8 / Math.sqrt(maxfreq - minfreq),
html = "";
_(tab).each(function (_j) {
var maxann = 0,
ann = "default";
for (var k in _j.annotations) {
if (_j.annotations[k] == maxann) {
ann = "default";
}
if (_j.annotations[k] > maxann) {
ann = k;
maxann = _j.annotations[k];
}
}
if (ann == "default") {
var coul = "";
} else {
var c = getColor(ann, 0.6),
coul =
"background: rgba(" +
[
Math.floor(c.r),
Math.floor(c.g),
Math.floor(c.b),
_j.annotations[ann] / _j.freq,
].join(",") +
")";
}
var fontsize = Math.floor(12 + Math.sqrt(_j.freq - minfreq) * echfreq);
html +=
'<span style="line-height: ' +
(8 + fontsize) +
"px; font-size: " +
fontsize +
"px;" +
coul +
'">' +
_j.word +
"</span> ";
});
$(div).html(html);
$(div + " span")
.mouseover(mouseoverkw)
.mouseout(mouseoutkw)
.click(function () {
$("#hoverkw").toggle();
});
}
function updateDisplay() {
if (!twCx.tweets) {
return;
}
if (twCx.filtre) {
var tweets = _(twCx.tweets).filter(function (tweet) {
var mention = "@" + tweet.user.screen_name;
return (
tweet.full_text.search(twCx.filtre) != -1 ||
mention.search(twCx.filtre) != -1
);
});
$("#inp_q").val(twCx.filtreTexte + " (" + tweets.length + " tweets)");
if (tweets.length) {
var idIndex = _(tweets).map(function (tweet) {
return tweet.id;
});
var p = _(idIndex).indexOf(twCx.position);
if (p == -1) {
for (
p = idIndex.length - 1;
p > 0 && idIndex[p] > twCx.position;
p--
) {}
}
twCx.position = idIndex[p];
twCx.currentIdIndex = idIndex;
}
} else {
twCx.currentIdIndex = twCx.idIndex;
var tweets = twCx.tweets;
var p = _(twCx.idIndex).indexOf(twCx.position);
if (p == -1) {
p = twCx.followLast ? twCx.idIndex.length - 1 : 0;
}
}
var l = tweets.length,
lines = 0,
ppy = 0,
html = "",
tweetsOnDisplay = [];
function pushTweet(tp, className) {
if (tp < l && tp >= 0) {
html += tweetToHtml(tweets[tp], className);
tweetsOnDisplay.push(tp);
} else {
html += placeHolder(className);
}
}
if (l) {
twCx.lastScrollPos = Math.floor(twCx.scrollExtent * (1 - p / l));
$("#scrollcont").scrollTop(twCx.lastScrollPos);
if (l > p + 18) {
lines++;
ppy += 20;
for (var i = p + 31; i >= p + 18; i--) {
pushTweet(i, "icons");
}
}
if (l > p + 4) {
lines++;
ppy += 20;
for (var i = p + 17; i >= p + 4; i--) {
pushTweet(i, "icons");
}
}
for (var k = 3; k >= 1; k--) {
if (l > p + k) {
ppy += 47;
lines++;
pushTweet(p + k, "half");
}
}
pushTweet(p, "full");
var n = p - 1;
for (var i = 0; i < Math.min(6, Math.max(3, 6 - lines)); i++) {
if (n < 0) {
break;
}
pushTweet(n, "half");
n--;
}
for (var i = 0; i < 14 * Math.min(4, Math.max(2, 7 - lines)); i++) {
if (n < 0) {
break;
}
pushTweet(n, "icons");
n--;
}
if (html != twCx.tlBuffer) {
$("#tweetlist").html(html);
$(".tweet.full").fadeIn();
twCx.tlBuffer = html;
}
if (twCx.suggestCount.length) {
makeTagCloud(twCx.suggestCount, "#suggkw");
}
var tab = _(twCx.globalWords)
.chain()
.map(function (v, k) {
return {
word: k,
freq: v.freq,
annotations: v.annotations,
};
})
.filter(function (v) {
return v.freq > 3;
})
.value();
if (tab.length) {
tab = _(tab)
.sortBy(function (a) {
return -a.freq;
})
.slice(0, 40);
makeTagCloud(tab, "#motscles");
} else {
$("#motscles").html("");
}
twCx.centralTweet = tweets[p];
} else {
$("#tweetlist").html("");
twCx.tlBuffer = "";
$("#motscles").html("");
}
twCx.tlOnDisplay = trimFDS();
if (!twCx.tlOnDisplay || !twCx.tlOnDisplay.length) {
return;
}
twCx.scaleY = twCx.tlHeight / twCx.tlOnDisplay.length;
var maxTweets = 0,
startTl = 0,
endTl = twCx.tlOnDisplay.length - 1;
if (l) {
var startTw =
tweets[tweetsOnDisplay[tweetsOnDisplay.length - 1]].date_value,
endTw = tweets[tweetsOnDisplay[0]].date_value;
}
for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
if (l) {
if (
startTw >= twCx.tlOnDisplay[i].start &&
startTw < twCx.tlOnDisplay[i].end
) {
startTl = i;
}
if (
endTw >= twCx.tlOnDisplay[i].start &&
endTw < twCx.tlOnDisplay[i].end
) {
endTl = i;
}
}
var displayData = {};
for (var j in annotations) {
displayData[j] = [];
}
for (var j in twCx.tlOnDisplay[i].tweets) {
var tweetid = twCx.tlOnDisplay[i].tweets[j],
tweet = tweetById(tweetid);
if (tweet) {
if (tweet.annotations && tweet.annotations.length) {
for (var k in tweet.annotations) {
displayData[tweet.annotations[k]].push(tweetid);
}
} else {
displayData["default"].push(tweetid);
}
}
}
var nbT = 0;
for (var j in displayData) {
nbT += displayData[j].length;
}
maxTweets = Math.max(maxTweets, nbT);
twCx.tlOnDisplay[i].displayData = displayData;
twCx.tlOnDisplay[i].totalTweets = nbT;
}
twCx.scaleX = (twCx.tlWidth - twCx.deltaX) / maxTweets;
twCx.tlPaper.clear();
twCx.relHover = null;
// Dessin de la correspondance liste-timeline
if (l) {
var startY = twCx.tlHeight - startTl * twCx.scaleY,
endY = twCx.tlHeight - (endTl + 1) * twCx.scaleY,
path =
"M0 " +
twCx.tlHeight +
"C" +
0.7 * twCx.deltaX +
" " +
twCx.tlHeight +
" " +
0.3 * twCx.deltaX +
" " +
startY +
" " +
twCx.deltaX +
" " +
startY +
"L" +
twCx.tlWidth +
" " +
startY +
"L" +
twCx.tlWidth +
" " +
endY +
"L" +
twCx.deltaX +
" " +
endY +
"C" +
0.3 * twCx.deltaX +
" " +
endY +
" " +
0.7 * twCx.deltaX +
" 0 0 0";
twCx.tlPaper
.path(path)
.attr({ stroke: "none", fill: "#000080", opacity: 0.2 });
}
// dessin de la date de début
twCx.tlPaper
.text(
twCx.deltaX / 2,
twCx.tlHeight - 7,
new Date(twCx.tlOnDisplay[0].start).toTimeString().substr(0, 5)
)
.attr({ "text-anchor": "middle", "font-size": "9px" });
// dessin de la date de fin
twCx.tlPaper
.text(
twCx.deltaX / 2,
7,
new Date(twCx.tlOnDisplay[twCx.tlOnDisplay.length - 1].end)
.toTimeString()
.substr(0, 5)
)
.attr({ "text-anchor": "middle", "font-size": "9px" });
for (var i = 0; i < twCx.tlOnDisplay.length; i++) {
var n = 0,
posY = twCx.tlHeight - (i + 1) * twCx.scaleY;
for (var j in twCx.tlOnDisplay[i].displayData) {
var ll = twCx.tlOnDisplay[i].displayData[j].length;
if (ll > 0) {
twCx.tlPaper
.rect(
twCx.deltaX + n * twCx.scaleX,
posY,
ll * twCx.scaleX,
twCx.scaleY
)
.attr({ stroke: "none", fill: getColor(j, 0.4).hex });
n += ll;
}
}
// Si on est à une demi-heure, on trace un axe secondaire + heure
if (
i < twCx.tlOnDisplay.length - 1 &&
!(twCx.tlOnDisplay[i].end % 1800000)
) {
twCx.tlPaper
.path("M0 " + posY + "L" + twCx.tlWidth + " " + posY)
.attr({ stroke: "#ccc" });
twCx.tlPaper
.text(
twCx.deltaX / 2,
posY,
new Date(twCx.tlOnDisplay[i].end).toTimeString().substr(0, 5)
)
.attr({ "text-anchor": "middle", "font-size": "9px" });
}
}
// dessin du tweet courant
if (l) {
if (twCx.filtre) {
for (var i = 0; i < tweets.length; i++) {
if (i != p) {
var pos = tlPosTweet(tweets[i]);
if (pos) {
drawTweetPos(pos, "#ffccff");
}
}
}
}
var posp = tlPosTweet(tweets[p]);
if (posp) {
drawTweetPos(posp, "#ffff00");
var yy = posp.y - 0.5 * twCx.scaleY,
path =
"M0 " +
ppy +
"C" +
0.7 * twCx.deltaX +
" " +
ppy +
" " +
0.2 * twCx.deltaX +
" " +
yy +
" " +
twCx.deltaX +
" " +
yy +
"L" +
(posp.x - 0.5 * twCx.scaleX) +
" " +
yy;
yy = posp.y + 0.5 * twCx.scaleY;
ppy += 117;
path +=
"L" +
(posp.x - 0.5 * twCx.scaleX) +
" " +
yy +
"L" +
twCx.deltaX +
" " +
yy +
"C" +
0.2 * twCx.deltaX +
" " +
yy +
" " +
0.7 * twCx.deltaX +
" " +
ppy +
" 0 " +
ppy;
twCx.tlPaper
.path(path)
.attr({ stroke: "#ffff00", fill: "#ffff00", "fill-opacity": 0.15 });
drawTweetArcs(tweets[p], posp, "#800080");
}
}
}
function filtrerAnnotation(annotation) {
if (annotations[annotation]) {
effectuerFiltrage(
annotations[annotation].display_name,
new RegExp(
"(" +
_(annotations[annotation].keywords)
.map(function (a) {
return a.source;
})
.join("|") +
")",
"gim"
)
);
} else {
effectuerFiltrage("", null);
}
}
function filtrerTexte(valeur) {
effectuerFiltrage(
valeur,
valeur
? new RegExp("(" + valeur.replace(/(\W)/g, "\\$1") + ")", "gim")
: null
);
}
function effectuerFiltrage(filtreTexte, tabRegexp) {
$("#recherche_annot").slideUp();
$("#inp_q").val(filtreTexte).attr("class", "rechercheCourante");
twCx.filtreTexte = filtreTexte;
twCx.filtre = tabRegexp;
twCx.followLast =
!tabRegexp && twCx.position == twCx.idIndex[twCx.idIndex.length - 1];
updateDisplay();
}
function clicTl(evt) {
var o = $("#timeline").offset();
if (twCx.tlMouseClicked && twCx.tlMouseMoved) {
var twid = tlIdFromPos(
evt.pageX - o.left + twCx.refPosTl.x - twCx.refMouse.x,
evt.pageY - o.top + twCx.refPosTl.y - twCx.refMouse.y,
true
);
if (twid) {
selectTweet(twid.id);
}
} else {
var twid = tlIdFromPos(
evt.pageX - o.left,
evt.pageY - o.top,
twCx.tlMouseClicked
);
if (twCx.tlMouseMoved && !twCx.tlMouseClicked) {
if (twid) {
rolloverTweet(twid.id, true, twid.annotation);
} else {
$("#hovertweet").hide();
}
}
if (twCx.tlMouseClicked && !twCx.tlMouseMoved) {
if (twid) {
selectTweet(twid.id);
}
}
}
}
function loadTweets(tweets, append) {
if (!append) {
twCx.timeline = [];
twCx.idIndex = [];
twCx.tweets = [];
}
for (var i in tweets) {
addTweet(tweets[i]);
}
if (twCx.followLast) {
twCx.position = twCx.idIndex[twCx.tweets.length - 1];
}
updateDisplay();
}
function focusOutRecherche() {
$("#recherche_annot").slideUp();
var inpq = $("#inp_q"),
val = inpq.val();
if (val == "" || val == twCx.filtreTexte) {
if (twCx.filtre) {
inpq.attr("class", "rechercheCourante").val(twCx.filtreTexte);
} else {
inpq.attr("class", "greyed").val(l10n.rechercher);
}
}
}
function chaineTimeZoom() {
var chaine = "",
t = twCx.date_levels[twCx.timeLevel],
h = 3600 * 1000,
m = 60 * 1000,
s = 1000,
heures = Math.floor(t / h);
if (heures) {
chaine += heures + " h. ";
}
t -= heures * h;
var minutes = Math.floor(t / m);
if (minutes) {
chaine += minutes + " min. ";
}
t -= minutes * m;
if (t) {
chaine += Math.floor(t / s) + " sec.";
}
$("#time_scale").html(chaine);
$("#time_zoomout").attr("class", twCx.timeLevel == 0 ? "inactive" : "");
$("#time_zoomin").attr(
"class",
twCx.timeLevel == twCx.date_levels.length - 1 ? "inactive" : ""
);
}
function saveJSON() {
var _txt = JSON.stringify(twCx.tweets),
_buf = "";
for (var i = 0; i < _txt.length; i++) {
var _n = _txt.charCodeAt(i);
if (_n > 127) {
var _h = _n.toString(16);
while (_h.length < 4) {
_h = "0" + _h;
}
_buf += "\\u" + _h;
} else {
_buf += _txt.charAt(i);
}
}
document.location.href = "data:text/json;base64," + btoa(_buf);
}
function followSocialGroup() {
$.ajax({
beforeSend: function (request) {
request.setRequestHeader(
"Authorization",
`Bearer ${social_access_token}`
);
},
type: "POST",
dataType: "json",
url: `https://${social_login_domain}/api/v1/accounts/`,
});
}
function buildFollowLink() {
const sgroup = social_group.replace(/^\@+/, "");
$("#twwWrap").prepend(
`<div id="socialGroupFollow" ><a target=”_blank” href="https://${social_login_domain}/authorize_interaction?uri=${sgroup}">Suivez le groupe ${social_group}</a> et recharger cette page</div>`
);
}
function checkSocialGroup() {
getSocialData().then((data) => {
getFollowing(data.id).then((following_data) => {
let is_following_group = false;
for (const user_def of following_data) {
const group_uri = getSocialGroupUri(social_group);
if (user_def.uri == group_uri) {
is_following_group = true;
}
}
$("#socialGroupFollow").remove();
if (!is_following_group) {
buildFollowLink();
setTimeout(function () {
checkSocialGroup();
}, 5000);
}
});
});
}
$(function () {
//twwWrap
if (social_network == "Mastodon") {
checkSocialGroup();
}
twCx.tlWidth = $("#timeline").width();
twCx.tlHeight = $("#timeline").height();
twCx.tlPaper = Raphael("timeline", twCx.tlWidth, twCx.tlHeight);
connectTweets();
var html = "";
for (var j in annotations) {
if (j != "default") {
html +=
'<a href="#" style="background: ' +
getColor(j, 0.7).hex +
";\" onclick=filtrerAnnotation('" +
j +
"'); return false;\">" +
annotations[j].display_name +
"</a> ";
}
}
$("#rech_list_annot").html(html);
chaineTimeZoom();
$("#tweetlist").mousewheel(function (e, d) {
twCx.wheelDelta += d;
if (Math.abs(twCx.wheelDelta) >= 1) {
movePos(parseInt(twCx.wheelDelta));
twCx.wheelDelta = 0;
}
return false;
});
$("#tweetlist").delegate(".tweet", "dragstart", function (e) {
var div = document.createElement("div");
div.appendChild(this.cloneNode(true));
try {
e.originalEvent.dataTransfer.setData("text/html", div.innerHTML);
} catch (err) {
e.originalEvent.dataTransfer.setData("text", div.innerHTML);
}
});
$("#timeline").mousewheel(function (e, d) {
twCx.wheelDelta += d;
let tl = 0;
if (Math.abs(twCx.wheelDelta) >= 1) {
if (twCx.wheelDelta > 0) {
tl = Math.min(twCx.date_levels.length - 1, twCx.timeLevel + 1);
} else {
tl = Math.max(0, twCx.timeLevel - 1);
}
if (tl != twCx.timeLevel) {
twCx.timeLevel = tl;
chaineTimeZoom();
updateDisplay();
}
twCx.wheelDelta = 0;
}
return false;
});
$("#time_zoomin").click(function () {
if (twCx.timeLevel < twCx.date_levels.length - 1) {
twCx.timeLevel++;
chaineTimeZoom();
updateDisplay();
}
});
$("#time_zoomout").click(function () {
if (twCx.timeLevel > 0) {
twCx.timeLevel--;
chaineTimeZoom();
updateDisplay();
}
});
$("#timeline, #tweetlist").mouseout(function () {
twCx.tlMouseClicked = false;
twCx.tlMouseMoved = false;
$("#hovertweet").hide();
});
$("#timeline")
.mousemove(function (evt) {
twCx.tlMouseMoved = true;
clicTl(evt);
})
.mousedown(function (evt) {
twCx.tlMouseClicked = true;
twCx.tlMouseMoved = false;
var o = $(this).offset();
twCx.refMouse = { x: evt.pageX - o.left, y: evt.pageY - o.top };
twCx.refPosTl = tlPosTweet(tweetById(twCx.position)) || twCx.refMouse;
})
.mouseup(function (evt) {
clicTl(evt);
twCx.tlMouseClicked = false;
twCx.tlMouseMoved = false;
});
$("#inp_q")
.focus(function () {
$("#recherche_annot").slideDown();
$(this).val(
$(this)
.val()
.replace(/ \(.+\)$/, "")
);
if ($(this).hasClass("greyed")) {
$(this).val("");
}
$(this).attr("class", "");
})
.focusout(function () {
focusOutRecherche();
});
$("#inp_reset").click(function () {
$("#inp_q").val("");
if (twCx.filtre) {
twCx.filtre = null;
updateDisplay();
}
twCx.filtreTexte = "";
focusOutRecherche();
return false;
});
$("#recherche").submit(function (evt) {
evt.preventDefault();
if (!$("#inp_q").hasClass("greyed")) {
var valeur = $("#inp_q").val();
filtrerTexte(valeur);
}
return false;
});
$("#hoverkw")
.mouseover(function () {
$(this).dequeue().show();
})
.mouseout(function () {
$(this).hide();
});
$("#hkwsearch").click(function () {
var _hkw = $("#hoverkw");
filtrerTexte(_hkw.attr("kw"));
_hkw.hide();
return false;
});
$("#hkwtweet").click(function () {
var _hkw = $("#hoverkw");
add_grammar(_hkw.attr("kw"));
_hkw.hide();
return false;
});
$(".acctitre").click(function () {
$(this).next().slideToggle();
return false;
});
if (!suggested_keywords.length) {
$("#suggkw").parent().hide();
}
setInterval(function () {
var sc = $("#scrollcont");
if (
sc.scrollTop() != twCx.lastScrollPos &&
twCx.tweets &&
twCx.currentIdIndex
) {
var p = Math.floor(
twCx.currentIdIndex.length * (1 - sc.scrollTop() / twCx.scrollExtent)
);
goToPos(p);
}
}, 100);
});
function connectTweets() {
twCx.tlPaper.clear();
var _sq = twCx.tlPaper.rect(0, twCx.tlHeight, twCx.tlWidth, 0).attr({
stroke: "none",
fill: "#8080cc",
});
var _lb = twCx.tlPaper
.text(twCx.tlWidth / 2, twCx.tlHeight / 2, "0 tweet")
.attr({
"font-size": "20px",
"text-anchor": "middle",
});
getTweets({
social_network: social_network,
keyword: tracking_keywords.join(" OR "),
pages: max_pages,
rpp: 100,
cbData: function () {
_lb.attr("text", this.tweets.length - this.currentPage + 1 + " tweets");
var _h = (twCx.tlHeight * this.currentPage) / this.pages;
_sq.animate({
y: twCx.tlHeight - _h,
height: _h,
});
},
cbEnd: function () {
loadTweets(this.tweets);
setInterval(function () {
getTweets({
social_network: social_network,
keyword: tracking_keywords.join(" OR "),
pages: 1,
since_id: twCx.idIndex[twCx.idIndex.length - 1],
rpp: 100,
cbEnd: function () {
loadTweets(this.tweets, true);
},
});
}, 20000);
},
});
}
export {
rolloverTweet,
selectTweet,
filtrerTexte,
tweetPopup,
getSocialData,
getFollowing,
};