/* jshint sub: true */ 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 {number} **/ SELECTED_ROOM_UNREAD = -1, /** * @type {Element} **/ UNREAD_INDICATOR_DOM = document.createElement("span"), /** * @type {SimpleChatSystem|null} **/ SELECTED_CONTEXT = null, /** @type {Message|null} */ REPLYING_TO = null, /** @type {Message|null} */ EDITING = null, /** @const @type {number} */ KEEP_MESSAGES = 100, /** @type {Array<{channel: string, text: string, isMe: boolean, pendingId: (string|undefined), dom: Element}>} */ PENDING_MESSAGES = [] ; function initHljs() { HttpRequestWrapper("highlight.pack.js") .callbackSuccess(function(code, head, resp) { var script = document.createElement("script"), link = document.createElement("link"); script.innerHTML = resp; script.language = "text/javascript"; link.href = "hljs-androidstudio.css"; link.rel = "stylesheet"; document.head.appendChild(link); document.body.appendChild(script); }) .callbackError(function() { console.error("Failure loading hljs required files"); }) .setTimeout(1000 * 60 * 1) // 1 min timeout .send(); } /** * @param {Room} room * @param {function(boolean)} cb **/ function fetchHistory(room, cb) { HttpRequestWrapper("api/hist?room=" +HttpRequestWrapper.encode(room.id)) .setResponseType(HttpRequestResponseType.JSON) .callbackSuccess(function(code, status, resp) { if (resp) { var history = DATA.history[room.id], updated, now = Date.now(); if (!history) { history = DATA.history[room.id] = new UiRoomHistory(room, KEEP_MESSAGES, /** @type {Array} */ (resp), now); updated = true; } else { updated = !!history.pushAll(/** @type {Array} */ (resp), now); } if (updated) { if (history.messages.length) room.setLastMsg(history.lastMessage().ts, now); onMsgReceived(DATA.context.getChannelContext(room.id).getChatContext(), room, /** @type {Array} */ (resp)); if (room === SELECTED_ROOM) onRoomUpdated(); } } }, this) .callback(function() { // TODO ui stop loading }) .send(); } function onConfigUpdated() { if (isObjectEmpty(CONFIG.services)) { Settings.setClosable(false).display(Settings.pages.services); } loadEmojiProvider(CONFIG.getEmojiProvider()); if (CONFIG.isScrollAvatars()) { document.getElementById(R.id.currentRoom.content).addEventListener('scroll', updateAuthorAvatarImsOffset); updateAuthorAvatarImsOffset(); } else { invalidateAllMessages(); document.getElementById(R.id.currentRoom.content).removeEventListener('scroll', updateAuthorAvatarImsOffset); } for (var roomId in DATA.history) { DATA.history[roomId].messages.forEach(function(msg) { if (msg.dom) msg.updateDom(); }); } document.getElementById(R.id.stylesheet).innerHTML = CONFIG.compileCSS(); } function poll(callback) { if (!IS_LOCAL) { HttpRequestWrapper("api?v=" +DATA.lastServerVersion) .callback(function(statusCode, statusText, resp) { var success = Math.floor(statusCode / 100) === 2; if (success) { if (NEXT_RETRY) { NEXT_RETRY = 0; onNetworkStateUpdated(true); } } 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); }) .setResponseType(HttpRequestResponseType.JSON) .setTimeout(1000 * 60 * 1) .send(); } } function outOfSync() { DATA.lastServerVersion = 0; } /** * @param {Room} room **/ function sendTyping(room) { HttpRequestWrapper(HttpRequestMethod.POST, "api/typing?room=" +HttpRequestWrapper.encode(room.id)).send(); } /** * @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); } function setNativeTitle(title) { if (isNative()) { var enabled = !!(SELECTED_CONTEXT && SELECTED_CONTEXT.getChatContext().capacities["starChannel"]); __native.setTitle(title, enabled, enabled ? SELECTED_ROOM.starred : false); } } /** * @param {Room} room **/ function selectRoom(room) { if (SELECTED_ROOM) unselectRoom(); UNREAD_INDICATOR_DOM.className = R.klass.msg.unread; UNREAD_INDICATOR_DOM.textContent = locale.newMessage; 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)); SELECTED_ROOM_UNREAD = room.lastRead; if (isNative()) __native.setCurrentChannel(room.id); onRoomSelected(); roomInfo.hide(); createContextBackground(SELECTED_CONTEXT.getChatContext().team.id, SELECTED_CONTEXT.getChatContext().users, function(imgData) { document.getElementById(R.id.context).style.backgroundImage = 'url(' +imgData +')'; }); if (!DATA.history[SELECTED_ROOM.id] || DATA.history[SELECTED_ROOM.id].messages.length < KEEP_MESSAGES) fetchHistory(SELECTED_ROOM, function(success) {}); document.getElementById(R.id.mainSection).classList.remove(R.klass.noRoomSelected); document.getElementById(R.id.context).classList.remove(R.klass.opened); } function setRoomFromHashBang() { var hashId = document.location.hash.substr(1), room = DATA.context.getChannel(hashId); if (room && room !== SELECTED_ROOM) { selectRoom(room); return true; } else { var user = DATA.context.getUser(hashId); if (user && user.privateRoom) { selectRoom(user.privateRoom); return true; } } return false; } /** * @param {Room} room **/ function starChannel(room) { HttpRequestWrapper(HttpRequestMethod.POST, "api/starChannel?room=" +HttpRequestWrapper.encode(room.id)).send(); } /** * @param {Room} room **/ function unstarChannel(room) { HttpRequestWrapper(HttpRequestMethod.POST, "api/unstarChannel?room=" +HttpRequestWrapper.encode(room.id)).send(); } function unselectRoom() { document.getElementById("room_" +SELECTED_ROOM.id).classList.remove(R.klass.selected); document.getElementById(R.id.mainSection).classList.add(R.klass.noRoomSelected); UNREAD_INDICATOR_DOM.remove(); } /** * @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(); // FIXME NATIVE ! formData.append("file", file); formData.append("filename", filename); HttpRequestWrapper(HttpRequestMethod.POST, "api/file?room=" +HttpRequestWrapper.encode(chan.id)) .callbackSuccess(function() { callback(null); }) .callbackError(function(sCode, sText, resp) { callback(sText); }) .send(formData); } /** * @param {string} payload * @param {string} serviceId * @param {(function((string|null)))=} callback **/ function sendCommand(payload, serviceId, callback) { var xhr = HttpRequestWrapper(HttpRequestMethod.POST, "api/attachmentAction?serviceId=" +HttpRequestWrapper.encode(serviceId)); if (callback) xhr.callbackSuccess(function() { callback(null); }).callbackError(function(code, head, resp) { callback(head); }); xhr.send(JSON.stringify(payload)); } 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 payload; } /** * @param {Room} chan * @param {Command!} cmd * @param {string} args **/ function doCommand(chan, cmd, args) { HttpRequestWrapper(HttpRequestMethod.POST, "api/cmd?room=" +HttpRequestWrapper.encode(chan.id) +"&cmd=" +HttpRequestWrapper.encode(cmd.name.substr(1)) +"&args=" +HttpRequestWrapper.encode(args)).send(); } /** * @param {Room} chan * @param {string} msg * @param {Object=} pendingObj * @param {Message|null=} replyTo **/ function sendMsg(chan, msg, pendingObj, replyTo) { var url = 'api/msg?room=' +HttpRequestWrapper.encode(chan.id) +"&text=" +HttpRequestWrapper.encode(msg); if (replyTo) { var sender = DATA.context.getUser(replyTo.userId), footer = chan.isPrivate ? locale.message : chan.name; var attachment = { "fallback": replyTo.text, "author_name": sender.getName(), "text": replyTo.text, "footer": footer, "ts": replyTo.ts }; url += "&attachments=" +HttpRequestWrapper.encode(JSON.stringify([attachment])); } SELECTED_ROOM_UNREAD = -1; UNREAD_INDICATOR_DOM.remove(); HttpRequestWrapper(HttpRequestMethod.POST, url).setResponseType(HttpRequestResponseType.JSON).callbackSuccess(function(code, text, resp) { if (resp && resp["pendingId"] !== undefined) { pendingObj.pendingId = resp["pendingId"]; } }).send(); } /** * @param {Room} chan * @param {string} text * @param {Message} msg **/ function editMsg(chan, text, msg) { HttpRequestWrapper(HttpRequestMethod.PUT, "api/msg?room=" +HttpRequestWrapper.encode(chan.id) +"&ts=" +msg.id +"&text=" +HttpRequestWrapper.encode(text)).send(); } /** * @param {Room} chan * @param {Message} msg **/ function removeMsg(chan, msg) { HttpRequestWrapper(HttpRequestMethod.DELETE, "api/msg?room=" +HttpRequestWrapper.encode(chan.id) +"&ts=" +msg.id).send(); } /** * @param {Room} chan * @param {Message} msg **/ function pinMsg(chan, msg) { HttpRequestWrapper(HttpRequestMethod.POST, "api/pinMsg?room=" +HttpRequestWrapper.encode(chan.id) +"&msgId=" +msg.id).send(); } /** * @param {Room} chan * @param {Message} msg **/ function starMsg(chan, msg) { HttpRequestWrapper(HttpRequestMethod.POST, "api/starMsg?room=" +HttpRequestWrapper.encode(chan.id) +"&msgId=" +msg.id).send(); } /** * @param {Room} chan * @param {Message} msg **/ function unpinMsg(chan, msg) { HttpRequestWrapper(HttpRequestMethod.DELETE, "api/pinMsg?room=" +HttpRequestWrapper.encode(chan.id) +"&msgId=" +msg.id).send(); } /** * @param {Room} chan * @param {Message} msg **/ function unstarMsg(chan, msg) { HttpRequestWrapper(HttpRequestMethod.DELETE, "api/starMsg?room=" +HttpRequestWrapper.encode(chan.id) +"&msgId=" +msg.id).send(); } /** * @param {Room} chan * @param {string} id * @param {number} ts **/ function sendReadMarker(chan, id, ts) { HttpRequestWrapper(HttpRequestMethod.POST, "api/markread?room=" +HttpRequestWrapper.encode(chan.id) +"&id=" +id +"&ts=" +ts).send(); } /** * @param {string} channelId * @param {string} msgId * @param {string} reaction **/ function addReaction(channelId, msgId, reaction) { HttpRequestWrapper(HttpRequestMethod.POST, "api/reaction?room=" +HttpRequestWrapper.encode(channelId) +"&msg=" +msgId +"&reaction=" +HttpRequestWrapper.encode(reaction)).send(); } /** * @param {string} channelId * @param {string} msgId * @param {string} reaction **/ function removeReaction(channelId, msgId, reaction) { HttpRequestWrapper(HttpRequestMethod.DELETE, "api/reaction?room=" +HttpRequestWrapper.encode(channelId) +"&msg=" +msgId +"&reaction=" +HttpRequestWrapper.encode(reaction)).send(); } function logout() { HttpRequestWrapper(HttpRequestMethod.POST, "api/logout").send(); document.cookie = "sessID=;Path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT;"; document.location.reload(); if (isNative()) __native.logout(); } /** * @this {Element} **/ function filterChanList() { var chans = {}, matchingChans = [], val = this.value; DATA.context.foreachChannels(function(chan) { chans[chan.id] = chan.matchString(val, Utils); }); for (var chanId in chans) { var chanDom = document.getElementById("room_" +chanId); if (chanDom) { if (chans[chanId].name + chans[chanId].members + chans[chanId].topic +chans[chanId].purpose) { chanDom.classList.remove(R.klass.hidden); matchingChans.push(chanId); } else { chanDom.classList.add(R.klass.hidden); } } } //TODO sort }