var
/**
* @type {number} next period to wait before next retry in case of failure, in seconds
**/
NEXT_RETRY = 0
/**
* @type {Room|null}
**/
,SELECTED_ROOM = null
/**
* @type {SimpleChatSystem|null}
**/
,SELECTED_CONTEXT = null
/** @type {Message|null} */
,REPLYING_TO = null
/** @type {Message|null} */
,EDITING = null
;
function initHljs() {
document.head.innerHTML += '';
document.body.innerHTML += '';
}
/**
* @param {Room} room
* @param {function(boolean)} cb
**/
function fetchHistory(room, cb) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'api/hist?room=' +room.id, true);
xhr.send(null);
}
function poll(callback) {
var xhr = new XMLHttpRequest();
xhr.timeout = 1000 * 60 * 1; // 3 min timeout
xhr.onreadystatechange = function(e) {
if (xhr.readyState === 4) {
if (xhr.status === 0) {
if (NEXT_RETRY) {
NEXT_RETRY = 0;
onNetworkStateUpdated(true);
}
poll(callback); // retry on timeout
return;
}
var resp = null
,success = Math.floor(xhr.status / 100) === 2;
if (success) {
if (NEXT_RETRY) {
NEXT_RETRY = 0;
onNetworkStateUpdated(true);
}
resp = xhr.response;
try {
resp = JSON.parse(/** @type {string} */ (resp));
} catch (e) {
resp = null;
}
} else {
if (NEXT_RETRY) {
NEXT_RETRY += Math.floor((NEXT_RETRY || 5)/2);
NEXT_RETRY = Math.min(60, NEXT_RETRY);
} else {
NEXT_RETRY = 5;
onNetworkStateUpdated(false);
}
}
callback(success, resp);
}
};
xhr.open('GET', 'api?v=' +DATA.lastServerVersion, true);
xhr.send(null);
}
function outOfSync() {
DATA.lastServerVersion = 0;
}
/**
* @param {Room} room
**/
function sendTyping(room) {
var xhr = new XMLHttpRequest()
,url = 'api/typing?room=' +room.id;
xhr.open('POST', url, true);
xhr.send(null);
}
/**
* @param {boolean} success
* @param {*} response
**/
function onPollResponse(success, response) {
if (success) {
if (response) {
DATA.update(response);
}
startPolling();
} else {
setTimeout(startPolling, NEXT_RETRY * 1000);
}
}
function startPolling() {
poll(onPollResponse);
}
/**
* @param {Room} room
**/
function selectRoom(room) {
if (SELECTED_ROOM)
unselectRoom();
document.getElementById("room_" +room.id).classList.add(R.klass.selected);
document.body.classList.remove(R.klass.noRoomSelected);
SELECTED_ROOM = room;
SELECTED_CONTEXT = /** @type {SimpleChatSystem} */ (DATA.context.getChannelContext(room.id));
onRoomSelected();
createContextBackground(SELECTED_CONTEXT.getChatContext().team.id, SELECTED_CONTEXT.getChatContext().users, function(imgData) {
document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')';
});
if (SELECTED_ROOM.lastMsg && !DATA.history[SELECTED_ROOM.id])
fetchHistory(SELECTED_ROOM, function(success) {});
}
function unselectRoom() {
document.getElementById("room_" +SELECTED_ROOM.id).classList.remove(R.klass.selected);
}
/**
* @param {Room} chan
* @param {string} filename
* @param {File} file
* @param {function(string?)} callback
**/
function uploadFile(chan, filename, file, callback) {
var fileReader = new FileReader()
,formData = new FormData()
,xhr = new XMLHttpRequest();
formData.append("file", file);
formData.append("filename", filename);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 204) {
callback(null);
} else {
callback(xhr.statusText);
}
}
}
xhr.open('POST', 'api/file?room=' +chan.id);
xhr.send(formData);
}
/**
* @param {string} payload
* @param {string} serviceId
* @param {(function((string|null)))=} callback
**/
function sendCommand(payload, serviceId, callback) {
var formData = new FormData()
,xhr = new XMLHttpRequest();
formData.append("payload", payload);
formData.append("service_id", serviceId);
if (callback) {
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 204) {
callback(null);
} else {
callback(xhr.statusText);
}
}
}
}
xhr.open('POST', "api/attachmentAction");
xhr.send(formData);
}
function getActionPayload(channelId, msg, attachment, action) {
var payload = {
"actions": [ action ]
,"attachment_id": attachment["id"]
,"callback_id": attachment["callback_id"]
,"channel_id": channelId
,"is_ephemeral": msg instanceof NoticeMessage
,"message_ts": msg["id"]
};
return JSON.stringify(payload);
}
/**
* @param {Room} chan
* @param {Command!} cmd
* @param {string} args
**/
function doCommand(chan, cmd, args) {
var xhr = new XMLHttpRequest()
,url = 'api/cmd?room=' +chan.id +"&cmd=" +encodeURIComponent(cmd.name.substr(1)) +"&args=" +encodeURIComponent(args);
xhr.open('POST', url, true);
xhr.send(null);
}
/**
* @param {Room} chan
* @param {string} msg
* @param {Message|null=} replyTo
**/
function sendMsg(chan, msg, replyTo) {
var xhr = new XMLHttpRequest();
var url = 'api/msg?room=' +chan.id +"&text=" +encodeURIComponent(msg);
if (replyTo) {
var sender = DATA.context.getUser(replyTo.userId)
,footer = "Message";
if (chan.isPrivate) {
footer = "Private message";
} else {
footer = chan.name;
}
var attachment = {
"fallback": replyTo.text
,"author_name": "<@" +sender.id +"|" +sender.name +">"
,"text": replyTo.text
,"footer": footer
,"ts": replyTo.ts
};
url += "&attachments=" +encodeURIComponent(JSON.stringify([attachment]));
}
xhr.open('POST', url, true);
xhr.send(null);
}
/**
* @param {string} input
* @param {boolean=} skipCommand
* @return {boolean} true on recognized input
**/
function onTextEntered(input, skipCommand) {
var success = true;
if (EDITING) {
editMsg(SELECTED_ROOM, input, EDITING);
return true;
}
if (input[0] === '/' && skipCommand !== true) {
var endCmd = input.indexOf(' ')
,cmd = input.substr(0, endCmd === -1 ? undefined : endCmd)
,args = endCmd === -1 ? "" : input.substr(endCmd)
,ctx = SELECTED_CONTEXT
,cmdObject = ctx ? ctx.getChatContext().commands.data[cmd] : null;
if (cmdObject) {
doCommand(SELECTED_ROOM, cmdObject, args.trim());
return true;
}
return false;
}
sendMsg(SELECTED_ROOM, input, REPLYING_TO);
return true;
}
/**
* @param {Room} chan
* @param {string} text
* @param {Message|null=} msg
**/
function editMsg(chan, text, msg) {
var xhr = new XMLHttpRequest();
var url = 'api/msg?room=' +chan.id +"&ts=" +msg.id +"&text=" +encodeURIComponent(text);
xhr.open('PUT', url, true);
xhr.send(null);
}
/**
* @param {Room} chan
* @param {Message|null=} msg
**/
function removeMsg(chan, msg) {
var xhr = new XMLHttpRequest();
var url = 'api/msg?room=' +chan.id +"&ts=" +msg.id;
xhr.open('DELETE', url, true);
xhr.send(null);
}
/**
* @param {Room} chan
* @param {number} ts
**/
function sendReadMArker(chan, ts) {
var xhr = new XMLHttpRequest();
var url = 'api/markread?room=' +chan.id +"&ts=" +ts;
xhr.open('POST', url, true);
xhr.send(null);
}
/**
* @param {string} channelId
* @param {string} msgId
* @param {string} reaction
**/
function addReaction(channelId, msgId, reaction) {
var xhr = new XMLHttpRequest();
var url = 'api/reaction?room=' +channelId +"&msg=" +msgId +"&reaction=" +encodeURIComponent(reaction);
xhr.open('POST', url, true);
xhr.send(null);
}
/**
* @param {string} channelId
* @param {string} msgId
* @param {string} reaction
**/
function removeReaction(channelId, msgId, reaction) {
var xhr = new XMLHttpRequest();
var url = 'api/reaction?room=' +channelId +"&msg=" +msgId +"&reaction=" +encodeURIComponent(reaction);
xhr.open('DELETE', url, true);
xhr.send(null);
}