Anton Shestakov <av6@dwimlabs.net>, Sat, 16 Sep 2017 22:29:17 +0800
Make: use npm update for devel target
package.json says we want coffee-script >= 1.6.1, so that's what `make devel`
should install (the newest version): since .js source is tracked, there's no
risk of running into breaking changes in coffee-script outside of test
environment. But running into such changes during tests is OK and even
potentially desirable.
js/index.js
Permissions: -rw-r--r--
// Generated by CoffeeScript 1.12.2 var $form, _saveEntityCache, _saveSettings, connectfn, enableCSI, enableCarbons, getChat, getClientEntity, getContact, getProfile, getServerEntity, getServerVersion, getStamp, getText, loadEntityCache, loadSettings, onAnyError, onChatMessage, onChatState, onConnected, onDisconnected, onGetLast, onGetTime, onGetVersion, onPing, onPresence, onWebRTC, origTitle, saveEntityCache, saveSettings, sendMessage, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps'); Strophe.addNamespace('CARBONS', 'urn:xmpp:carbons:2'); Strophe.addNamespace('CHATSTATES', 'http://jabber.org/protocol/chatstates'); Strophe.addNamespace('CSI', 'urn:xmpp:csi:0'); Strophe.addNamespace('DELAY', 'urn:xmpp:delay'); Strophe.addNamespace('FORWARD', 'urn:xmpp:forward:0'); Strophe.addNamespace('LAST', 'jabber:iq:last'); Strophe.addNamespace('MESSAGE_CORRECT', 'urn:xmpp:message-correct:0'); Strophe.addNamespace('PRIVATE', 'jabber:iq:private'); Strophe.addNamespace('TIME', 'urn:xmpp:time'); window.contacts = new Tram.Contacts(); window.contactsApp = new Tram.ContactsApp({ el: $('[data-app="contacts"]'), window.calls = new Tram.Calls(); window.callsApp = new Tram.CallsApp({ el: $('[data-app="calls"]'), window.settings = new Tram.ClientSettings(); window.serverInfo = new Tram.ServerInfo(); window.clientState = new Tram.ClientState(); window.faviconApp = new Tram.FaviconApp({ window.sidebarApp = new Tram.SidebarApp({ el: $('[data-app="sidebar"]'), window.progressApp = new Tram.ProgressApp({ el: $('[data-app="progress"]'), window.profiles = new Tram.Profiles(); window.entities = new Tram.Entities(); contacts.on('change:show', function(model) { if (model.get('type') === 'self') { return clientState.set('show', model.get('show')); origTitle = document.title; contacts.on('change:d/unread', function() { total = contacts.reduce(function(memo, c) { return memo += (ref = c.get('d/unread')) != null ? ref : 0; return document.title = "(" + total + ") " + origTitle; return document.title = origTitle; contacts.on('change:chatstate/self', function(contact, cs) { if (settings.get('chatstates') && (ref = Strophe.NS.CHATSTATES, indexOf.call((ref1 = contact != null ? contact.get('features') : void 0) != null ? ref1 : [], ref) >= 0)) { xmlns: Strophe.NS.CHATSTATES return X.conn.send(msg.tree()); contacts.on('change:presence', function(contact) { bjid: contact.get('bjid') for (i = 0, len = dupes.length; i < len; i++) { if (c.get('presence') === 'unavailable') { if (offline.length === dupes.length) { for (i = 0, len = offline.length; i < len; i++) { if (c.get('jid') !== contact.get('jid')) { return contacts.remove(offline); clientState.on('action/show', function(show, status) { clientState.on('action/disconnect', function() { return X.disconnect('Logged out'); clientState.on('change:contact', function() { var $logs, contact, previous; previous = clientState.previous('contact'); previous.set('chatstate/self', 'inactive'); previous.unset('active'); contact = clientState.get('contact'); contact.set('chatstate/self', 'active'); contact.set('active', true); bjid: contact.get('bjid') })).each(function(contact) { return contact.unset('d/unread'); $logs = $('[data-app="logs"]'); $logs.children().detach(); $logs.append(contact.chat.render().el); return $('[data-form="send"]').toggleClass('uk-hidden', contact == null); clientState.on('change:csi', function() { state = clientState.get('csi'); return X.conn.send($build(state, { onConnected = function() { var dCache, dCarbons, dInfo, dRoster, dSettings, dVersion; X.conn.addHandler(onPresence, null, 'presence'); X.conn.addHandler(onChatMessage, null, 'message', 'chat'); X.conn.addHandler(onChatState, Strophe.NS.CHATSTATES, 'message'); X.conn.addHandler(onWebRTC, Tram.NS.WEBRTC, 'message', 'chat'); X.conn.addHandler(onAnyError, null, null, 'error'); X.conn.addHandler(onGetLast, Strophe.NS.LAST, 'iq', 'get'); X.conn.addHandler(onGetTime, Strophe.NS.TIME, 'iq', 'get'); X.conn.addHandler(onGetVersion, Strophe.NS.VERSION, 'iq', 'get'); X.conn.ping.addPingHandler(onPing); X.conn.disco.addIdentity('client', 'web', Tram.info.client); X.conn.disco.addFeature(Strophe.NS.CAPS); X.conn.disco.addFeature(Strophe.NS.CARBONS); X.conn.disco.addFeature(Strophe.NS.CHATSTATES); X.conn.disco.addFeature(Strophe.NS.CSI); X.conn.disco.addFeature(Strophe.NS.DISCO_INFO); X.conn.disco.addFeature(Strophe.NS.LAST); X.conn.disco.addFeature(Strophe.NS.MESSAGE_CORRECT); X.conn.disco.addFeature(Strophe.NS.PING); X.conn.disco.addFeature(Strophe.NS.PRIVATE); X.conn.disco.addFeature(Strophe.NS.TIME); X.conn.disco.addFeature(Strophe.NS.VERSION); X.conn.disco.addFeature(Strophe.NS.XHTML_IM); X.conn.disco.addFeature(Tram.NS.WEBRTC); dSettings = $.Deferred(); loadSettings(dSettings.resolve, dSettings.reject); loadEntityCache(dCache.resolve, dCache.reject); getServerVersion(dVersion.resolve, dVersion.reject); X.conn.roster.get(dRoster.resolve); $.when(dCache).always(function() { return getServerEntity(dInfo.resolve, dInfo.reject); $.when(dInfo).always(function() { if (ref = Strophe.NS.CARBONS, indexOf.call(serverInfo.get('features'), ref) >= 0) { enableCarbons(dCarbons.resolve, dCarbons.reject); hasCSI = ((ref1 = X.conn.features) != null ? ref1.getElementsByTagNameNS(Strophe.NS.CSI, 'csi')[0] : void 0) != null; serverInfo.set('csi', hasCSI); return $.when(dSettings, dVersion, dInfo, dRoster, dCarbons).always(function() { entities.on('add change', saveEntityCache); return settings.on('change', saveSettings); onDisconnected = function() { return location.reload(); getStamp = function(stanza) { delay = stanza.getElementsByTagNameNS(Strophe.NS.DELAY, 'delay')[0]; return new Date((ref = delay != null ? delay.getAttribute('stamp') : void 0) != null ? ref : Date.now()); var i, len, node, ref, str; if (el.childNodes.length === 0 && el.nodeType === Strophe.ElementType.TEXT) { for (i = 0, len = ref.length; i < len; i++) { if (node.nodeType === Strophe.ElementType.TEXT) { getServerVersion = function(doneCallback, failCallback) { id: X.conn.getUniqueId('version'), xmlns: Strophe.NS.VERSION okcb = function(stanza) { name: getText(stanza.getElementsByTagName('name')[0]), version: getText(stanza.getElementsByTagName('version')[0]), os: getText(stanza.getElementsByTagName('os')[0]) return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.error("couldn't get version", stanza != null ? stanza.innerHTML : void 0); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); enableCarbons = function(doneCallback, failCallback) { id: X.conn.getUniqueId('enable') xmlns: Strophe.NS.CARBONS okcb = function(stanza) { serverInfo.set('carbons', true); return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { serverInfo.set('carbons', false); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); $(window).on('focus.tram', function() { window.clearTimeout(csiTimer); return clientState.set('csi', 'active'); return $(window).on('blur.tram', function() { window.clearTimeout(csiTimer); return csiTimer = window.setTimeout(function() { return clientState.set('csi', 'inactive'); }, Tram.config.inactiveTime); loadSettings = function(doneCallback, failCallback) { id: X.conn.getUniqueId('settings') xmlns: Strophe.NS.PRIVATE okcb = function(stanza) { el = stanza.getElementsByTagName('settings')[0]; if ((el != null ? el.firstChild : void 0) != null) { data = JSON.parse(el.firstChild.nodeValue); if (typeof failCallback === "function") { return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.error("couldn't load settings", stanza); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); _saveSettings = function(doneCallback, failCallback) { var failcb, iq, okcb, payload; payload = JSON.stringify(settings.toJSON()); id: X.conn.getUniqueId('settings') xmlns: Strophe.NS.PRIVATE okcb = function(stanza) { return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.warn("couldn't save settings", stanza); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); saveSettings = _(_saveSettings).debounce(1000); loadEntityCache = function(doneCallback, failCallback) { id: X.conn.getUniqueId('entity-cache') xmlns: Strophe.NS.PRIVATE okcb = function(stanza) { el = stanza.getElementsByTagName('entity-cache')[0]; if ((el != null ? el.firstChild : void 0) != null) { data = JSON.parse(el.firstChild.nodeValue); if (typeof failCallback === "function") { return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.error("couldn't load caps cache", stanza); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); _saveEntityCache = function(doneCallback, failCallback) { var failcb, iq, okcb, payload; payload = JSON.stringify(entities.chain().filter(function(e) { id: X.conn.getUniqueId('entity-cache') xmlns: Strophe.NS.PRIVATE okcb = function(stanza) { return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.warn("couldn't save entity cache", stanza); return typeof failCallback === "function" ? failCallback() : void 0; return X.conn.sendIQ(iq.tree(), okcb, failcb, Tram.config.iqTimeout); saveEntityCache = _(_saveEntityCache).debounce(1000); onAnyError = function(stanza) { console.warn('got an error:', stanza, stanza.outerHTML); onGetLast = function(stanza) { id = stanza.getAttribute('id'); from = stanza.getAttribute('from'); onGetTime = function(stanza) { id = stanza.getAttribute('id'); from = stanza.getAttribute('from'); }).c('tzo').t(now.format('Z')).up().c('utc').t(now.toISOString()); onGetVersion = function(stanza) { id = stanza.getAttribute('id'); from = stanza.getAttribute('from'); xmlns: Strophe.NS.VERSION }).c('name').t(Tram.info.client).up().c('version').t(Tram.info.version); onPing = function(stanza) { X.conn.ping.pong(stanza); getChat = function(jid) { return chats[jid] != null ? chats[jid] : chats[jid] = new Tram.LogApp({ collection: new Tram.Messages() getContact = function(jid, node, ver) { contact = contacts.get(jid); self = jid === X.conn.jid; contacts.each(function(model) { return model.set('type', 'contact'); bjid = Strophe.getBareJidFromJid(jid); type: self ? 'self' : 'contact' contact.set('profile', getProfile(bjid)); if (Strophe.getResourceFromJid(jid) != null) { getClientEntity(contact, node, ver); contact.chat = getChat(bjid); contact.chat.collection.on('add', function(model) { if (model.get('type') === 'chat' && model.get('from') === contact.get('jid') && ((ref = clientState.get('contact')) != null ? ref.get('bjid') : void 0) !== bjid) { return contact.set('d/unread', ((ref1 = contact.get('d/unread')) != null ? ref1 : 0) + 1); contact.on('action/chat', function() { return clientState.set('contact', contact); contact.on('action/authorize', function() { return X.conn.roster.authorize(bjid); contact.on('action/unauthorize', function() { X.conn.roster.unauthorize(bjid); return contacts.remove(contact); contact.on('action/remove', function() { if (X.conn.roster.findItem(bjid)) { return X.conn.roster.remove(bjid, function() { return contacts.remove(contacts.where({ X.conn.roster.unauthorize(bjid); return contacts.remove(contacts.where({ contact.w = new Tram.WebRTCInterface(contact); contact.on('action/call', function(media) { contact.set('callstate', 'outgoing'); return contact.w.init(true, { audio: indexOf.call(media, 'a') >= 0, video: indexOf.call(media, 'v') >= 0 contact.on('action/accept', function(media) { return contact.w.init(false, { audio: indexOf.call(media, 'a') >= 0, video: indexOf.call(media, 'v') >= 0 contact.on('action/decline action/hangup', function() { contact.w.sendIntent('terminate'); return contact.unset('callstate'); getProfile = function(bjid) { var failcb, okcb, profile, to; profile = profiles.get(bjid); okcb = function(stanza) { vcard = stanza.getElementsByTagNameNS(Strophe.NS.VCARD, 'vCard')[0]; console.warn("no vcard in response", stanza); nickname: getText(vcard.querySelector('NICKNAME')), fullname: getText(vcard.querySelector('FN')), firstname: getText(vcard.querySelector('N > GIVEN')), lastname: getText(vcard.querySelector('N > FAMILY')) mime: getText(vcard.querySelector('PHOTO > TYPE')), data: getText(vcard.querySelector('PHOTO > BINVAL')) if (avatar.mime && avatar.data) { return profile.set(data); failcb = function(stanza) { return console.warn("couldn't get vcard", stanza); if (to === Strophe.getBareJidFromJid(X.conn.jid)) { X.conn.vcard.get(okcb, to, failcb); getClientEntity = function(contact, node, ver) { var entity, failcb, jid, nodever, okcb; jid = contact.get('jid'); if ((node != null) && (ver != null)) { nodever = node + "#" + ver; entity = entities.get(nodever); contact.set('entity', entity); contact.set('features', entity.get('features')); contact.set('entity', entity); okcb = function(stanza) { var el, features, identities; identities = (function() { var i, len, ref, results; ref = stanza.getElementsByTagName('identity'); for (i = 0, len = ref.length; i < len; i++) { type: el.getAttribute('type'), name: el.getAttribute('name'), category: el.getAttribute('category') var i, len, ref, results; ref = stanza.getElementsByTagName('feature'); for (i = 0, len = ref.length; i < len; i++) { results.push(el.getAttribute('var')); client: _(identities).findWhere({ return contact.set('features', features); failcb = function(stanza) { return console.warn("couldn't get client info", stanza); X.conn.disco.info(jid, nodever, okcb, failcb, Tram.config.iqTimeout); getServerEntity = function(doneCallback, failCallback) { var caps, entity, failcb, jid, node, nodever, okcb, ver; caps = X.conn.features.getElementsByTagNameNS(Strophe.NS.CAPS, 'c')[0]; node = caps != null ? caps.getAttribute('node') : void 0; ver = caps != null ? caps.getAttribute('ver') : void 0; if ((node != null) && (ver != null)) { nodever = node + "#" + ver; entity = entities.get(nodever); serverInfo.set('entity', entity); serverInfo.set('features', entity.get('features')); if (typeof doneCallback === "function") { serverInfo.set('entity', entity); okcb = function(stanza) { var el, features, identities; identities = (function() { var i, len, ref, results; ref = stanza.getElementsByTagName('identity'); for (i = 0, len = ref.length; i < len; i++) { type: el.getAttribute('type'), name: el.getAttribute('name'), category: el.getAttribute('category') var i, len, ref, results; ref = stanza.getElementsByTagName('feature'); for (i = 0, len = ref.length; i < len; i++) { results.push(el.getAttribute('var')); client: _(identities).findWhere({ serverInfo.set('features', features); return typeof doneCallback === "function" ? doneCallback() : void 0; failcb = function(stanza) { console.warn("couldn't get server info", stanza); return typeof failCallback === "function" ? failCallback() : void 0; X.conn.disco.info(jid, nodever, okcb, failcb, Tram.config.iqTimeout); onPresence = function(stanza) { var bjid, caps, contact, from, node, priority, ref, show, stamp, status, type, ver; type = (ref = stanza.getAttribute('type')) != null ? ref : 'available'; from = stanza.getAttribute('from'); bjid = Strophe.getBareJidFromJid(from); if (X.conn.roster.findItem(bjid)) { X.conn.roster.authorize(bjid); X.conn.roster.subscribe(bjid); X.conn.roster.unauthorize(bjid); X.conn.roster.unsubscribe(bjid); caps = stanza.getElementsByTagNameNS(Strophe.NS.CAPS, 'c')[0]; ver = caps != null ? caps.getAttribute('ver') : void 0; node = caps != null ? caps.getAttribute('node') : void 0; contact = getContact(from, node, ver); show = getText(stanza.getElementsByTagName('show')[0]); status = getText(stanza.getElementsByTagName('status')[0]); priority = getText(stanza.getElementsByTagName('priority')[0]); if (type === 'unavailable') { if ((type === 'available' || type === 'unavailable') && contact.get('type') !== 'self') { stamp = getStamp(stanza); contact.chat.collection.add({ id: stanza.getAttribute('id'), text: status != null ? status : "is now " + show onChatMessage = function(stanza) { var body, carbon, chat, cls, contact, forwarded, from, fromSelf, html, id, message, msg, received, ref, replace, rid, sent, stamp, subject, text, thread, to, type, xhtml; sent = stanza.getElementsByTagNameNS(Strophe.NS.CARBONS, 'sent')[0]; received = stanza.getElementsByTagNameNS(Strophe.NS.CARBONS, 'received')[0]; carbon = (sent != null) || (received != null); forwarded = sent.getElementsByTagNameNS(Strophe.NS.FORWARD, 'forwarded')[0]; } else if (received != null) { forwarded = received.getElementsByTagNameNS(Strophe.NS.FORWARD, 'forwarded')[0]; message = forwarded.getElementsByTagName('message')[0]; text = getText(message.getElementsByTagName('body')[0]); xhtml = message.getElementsByTagNameNS(Strophe.NS.XHTML_IM, 'html')[0]; id = message.getAttribute('id'); to = message.getAttribute('to'); from = message.getAttribute('from'); type = (ref = message.getAttribute('type')) != null ? ref : 'normal'; thread = getText(message.getElementsByTagName('thread')[0]); subject = getText(message.getElementsByTagName('subject')[0]); stamp = getStamp(stanza); contact = getContact(from); fromSelf = contact.get('bjid') === Strophe.getBareJidFromJid(X.conn.jid); if ((xhtml != null) && (fromSelf || X.conn.roster.findItem(contact.get('bjid')))) { body = xhtml.getElementsByTagNameNS(Strophe.NS.XHTML, 'body')[0]; html = Strophe.createHtml(body).innerHTML; if ((forwarded != null) && fromSelf) { chat = getContact(to).chat; replace = stanza.getElementsByTagNameNS(Strophe.NS.MESSAGE_CORRECT, 'replace')[0]; rid = replace != null ? replace.getAttribute('id') : void 0; msg = chat.collection.get(rid); if ((msg != null) && msg.get('from') === from) { onChatState = function(stanza) { var contact, delay, elements, from; delay = stanza.getElementsByTagNameNS(Strophe.NS.DELAY, 'delay')[0]; from = stanza.getAttribute('from'); contact = getContact(from); elements = stanza.getElementsByTagNameNS(Strophe.NS.CHATSTATES, '*'); if (elements[0] != null) { contact.set('chatstate', elements[0].tagName.toLowerCase()); onWebRTC = function(stanza) { var contact, from, intent, payload, stamp; from = stanza.getAttribute('from'); contact = getContact(from); intent = stanza.getElementsByTagNameNS(Tram.NS.WEBRTC, 'intent')[0]; payload = stanza.getElementsByTagNameNS(Tram.NS.WEBRTC, 'payload')[0]; stamp = getStamp(stanza); switch (getText(intent)) { contact.set('callstate', 'incoming'); contact.chat.collection.add({ id: stanza.getAttribute('id'), contact.unset('callstate'); contact.w.onPayload(stanza); window.X = new Tram.XMPPInterface(); X.on('connecting', function() { return connForm.unset('auth-errors'); X.on('authfail', function() { return connForm.set('auth-errors', ['Invalid username or password.']); X.on('disconnected', function() { $('[data-step="login"]').removeClass('uk-hidden'); $('[data-step="main"]').addClass('uk-hidden'); X.on('connected attached', function() { $('[data-step="login"]').addClass('uk-hidden'); $('[data-step="main"]').removeClass('uk-hidden'); X.on('status', function(status) { case Strophe.Status.CONNECTING: return clientState.set('progress', 0); case Strophe.Status.CONNECTED: return clientState.set('progress', 100); return clientState.unset('progress'); $(window).on('beforeunload unload', function() { return X.disconnect('Window closed'); window.connForm = new Tram.ConnectionForm(); if (connForm.isValid()) { return X.connect(connForm.get('username').trim(), connForm.get('password')); $form = $('[data-form="connect"]'); window.connRivet = rivets.bind($form, { sendMessage = function() { var contact, msg, ref, ref1, text; if (text !== '' && clientState.has('contact')) { contact = clientState.get('contact'); }).c('body').t(text).up(); if (settings.get('chatstates') && (ref = Strophe.NS.CHATSTATES, indexOf.call((ref1 = contact.get('features')) != null ? ref1 : [], ref) >= 0)) { xmlns: Strophe.NS.CHATSTATES contact.set('chatstate/self', 'active', { contact.chat.collection.add({ contact: contacts.findWhere({ return $('#msg').val(''); $('body').on('dragover dragenter', function(event) { return event.preventDefault(); $('body').on('drop', function(event) { return event.preventDefault(); $('[data-send-button]').on('click', sendMessage); $('#msg').on('keypress', function(e) { return (ref = clientState.get('contact')) != null ? ref.set('chatstate/self', 'composing') : void 0; $('#msg').on('blur', function() { if (((ref = clientState.get('contact')) != null ? ref.get('chatstate/self') : void 0) === 'composing') { return (ref1 = clientState.get('contact')) != null ? ref1.set('chatstate/self', 'paused') : void 0; $('[data-add-button]').on('click', function() { jid = $('#new-contact').val().trim(); if (indexOf.call(jid, '@') < 0) { jid = jid + "@" + Tram.config.domain; $('#new-contact').val(''); return X.conn.roster.add(jid, null, [], function() { return X.conn.roster.subscribe(jid, 'I want to chat', null); $('#new-contact').on('keypress', function(e) { return $('[data-add-button]').trigger('click'); $('[data-unregister-button]').on('click', function() { $('#settings-modal').one('show.uk.modal', function() { window.settingsRivet = rivets.bind($('[data-app="settings"]'), { return window.serverRivet = rivets.bind($('[data-app="server-info"]'), { $('#profile-modal').one('show.uk.modal', function() { return window.profileRivet = rivets.bind($('[data-app="profile"]'), { contact: contacts.get(X.conn.jid) window.setInterval(function() { return $('time[datetime]').each(function() { return $this.text(moment($this.attr('datetime')).fromNow()); //# sourceMappingURL=index.js.map