Browse Source

Merge branch 'devel' of isundil/mimouchat into master

isundil 6 years ago
parent
commit
b027145ed2

+ 18 - 0
cli/config.js

@@ -2,6 +2,12 @@
 /** @type Config */
 var CONFIG;
 
+var CONFIG_AUTO_EXPAND = {
+    NEVER: 0,
+    ALWAYS: 1,
+    NOT_IMAGE: 2
+};
+
 /** @constructor */
 function Config(configData) {
     this.deviceId = null;
@@ -17,6 +23,9 @@ function Config(configData) {
     /** @type{boolean|undefined} */
     this.scrollAvatars;
 
+    /** @type{number|undefined} */
+    this.autoExpandAttachments;
+
     // Load global configurations
     for (var i =0, nbConfig = configData.length; i < nbConfig; i++)
         if (configData[i]["service"] === null && configData[i]["device"] === null)
@@ -36,6 +45,10 @@ Config.prototype.mergeConfig = function(configData) {
         this.colorfulNames = configData["colorfulNames"];
     if (configData["scrollAvatars"] !== undefined)
         this.scrollAvatars = configData["scrollAvatars"];
+    if (configData["autoExpandAttachments"] !== undefined)
+        this.autoExpandAttachments = configData["autoExpandAttachments"];
+    if (typeof this.autoExpandAttachments === "string")
+        this.autoExpandAttachments = parseInt(this.autoExpandAttachments, 10);
 };
 
 /** @return {string|undefined} */
@@ -55,6 +68,11 @@ Config.prototype.isColorfulNames = function() {
     return this.colorfulNames === true;
 };
 
+Config.prototype.shouldExpandAttachment = function(attachmentHasImage) {
+    return this.autoExpandAttachments === CONFIG_AUTO_EXPAND.ALWAYS ||
+        ((this.autoExpandAttachments === CONFIG_AUTO_EXPAND.NOT_IMAGE || this.autoExpandAttachments === undefined) && !attachmentHasImage);
+};
+
 Config.prototype.commitNewSettings = function(newSettings) {
     for (var i in newSettings) {
         // Just to check not empty object

+ 1 - 0
cli/data.js

@@ -45,6 +45,7 @@ SimpleChatSystem.prototype.sendTyping = function(chan) { console.error("unimplem
 SimpleChatSystem.prototype.markRead = function(chan, ts) { console.error("unimplemented"); };
 SimpleChatSystem.prototype.sendCommand = function(chan, cmd, args) { console.error("unimplemented"); };
 SimpleChatSystem.prototype.poll = function(knownVersion, now) { console.error("unimplemented"); return null; };
+SimpleChatSystem.prototype.getImage = function(path) { console.error("unimplemented"); return null; };
 
 /**
  * @constructor

+ 8 - 2
cli/dom.js

@@ -233,7 +233,8 @@ function addHoverButtons(hover, msg) {
 function doCreateMessageDom(msg) {
     var dom = document.createElement("div")
         ,msgBlock = document.createElement("div")
-        ,hoverReaction = document.createElement("li");
+        ,hoverReaction = document.createElement("li")
+        ,attachmentSummary = document.createElement("summary");
     dom.hover = document.createElement("ul");
 
     dom.attachments = document.createElement("ul");
@@ -241,7 +242,9 @@ function doCreateMessageDom(msg) {
     dom.ts = document.createElement("div");
     dom.textDom = document.createElement("div");
     dom.authorName = document.createElement("span");
+    dom.attachmentWrapper = document.createElement("details");
 
+    dom.attachmentWrapper.addEventListener("toggle", function() { this.toggled = true; });
     dom.className = R.klass.msg.item;
     dom.ts.className = R.klass.msg.ts;
     dom.textDom.className = R.klass.msg.msg;
@@ -256,7 +259,10 @@ function doCreateMessageDom(msg) {
     msgBlock.appendChild(dom.authorName);
     msgBlock.appendChild(dom.textDom);
     msgBlock.appendChild(dom.ts);
-    msgBlock.appendChild(dom.attachments);
+    attachmentSummary.textContent = "attachment";
+    dom.attachmentWrapper.appendChild(attachmentSummary);
+    dom.attachmentWrapper.appendChild(dom.attachments);
+    msgBlock.appendChild(dom.attachmentWrapper);
 
     dom.edited = document.createElement("div");
     dom.edited.className = R.klass.msg.edited;

+ 6 - 1
cli/lang/en.js

@@ -85,7 +85,12 @@ lang["en"] = {
         "settings-displayEmojiProviderLbl": "Emoji provider",
         "settings-displayDisplayAvatarLbl": "Display avatars",
         "settings-displayColorfulNamesLbl": "Colorful names",
-        "settings-displayScrollAvatarsLbl": "Scroll avatars"
+        "settings-displayScrollAvatarsLbl": "Scroll avatars",
+
+        "settings-displayAttachmentContentLbl": "Automaticcaly unwrap attachments ?",
+        "settings-displayAttachmentContent-never": "Never",
+        "settings-displayAttachmentContent-always": "Always",
+        "settings-displayAttachmentContent-notimg": "If they don't contain image"
     }
 };
 

+ 6 - 1
cli/lang/fr.js

@@ -85,7 +85,12 @@ lang["fr"] = {
         "settings-displayEmojiProviderLbl": "Gestionnaire d'emojis",
         "settings-displayDisplayAvatarLbl": "Afficher les avatars",
         "settings-displayColorfulNamesLbl": "Afficher les nomes en couleur",
-        "settings-displayScrollAvatarsLbl": "Faire défiler les avatars lors de la lecture"
+        "settings-displayScrollAvatarsLbl": "Faire défiler les avatars lors de la lecture",
+
+        "settings-displayAttachmentContentLbl": "Afficher les pieces jointes ?",
+        "settings-displayAttachmentContent-never": "Jamais",
+        "settings-displayAttachmentContent-always": "Toujours",
+        "settings-displayAttachmentContent-notimg": "Si elles ne contiennent pas d'images"
     }
 };
 

+ 1 - 1
cli/msgFormatter

@@ -1 +1 @@
-Subproject commit febf876d6732cfed2cb0b2be9799868177b5fdc8
+Subproject commit f13402228f52ff8949af775cb4838cfbf6ffe898

+ 3 - 1
cli/resources.js

@@ -53,7 +53,8 @@ var R = {
                 emojiProvider: "settings-displayEmojiProvider",
                 displayAvatar: "settings-displayDisplayAvatar",
                 colorfulNames: "settings-displayColorfulNames",
-                scrollAvatars: "settings-displayScrollAvatars"
+                scrollAvatars: "settings-displayScrollAvatars",
+                displayAttachments: "settings-displayAttachmentContent"
             }
         },
         favicon: "linkFavicon"
@@ -143,6 +144,7 @@ var R = {
             notice: "chatmsg-notice",
             firstUnread: "chatmsg-first-unread",
             firstOfDay: "chatmsg-first-daily",
+            unread: "chatmsg-unread",
             content: "chatmsg-content",
             meMessage: "chatmsg-me_message",
             ts: "chatmsg-ts",

+ 14 - 8
cli/ui.js

@@ -313,6 +313,7 @@ function onRoomUpdated() {
         prevMsg = null,
         firstTsCombo = 0,
         prevMsgDom = null,
+        prevTs = 0,
         currentMsgGroupDom;
 
     if (SELECTED_ROOM.starred)
@@ -325,7 +326,7 @@ function onRoomUpdated() {
             if (!msg.removed) {
                 var dom = msg.getDom(),
                     newGroupDom = false,
-                    sameDayThanPrevious = prevMsg && isSameDay(msg.ts, prevMsg.ts);
+                    sameDayThanPrevious = isSameDay(msg.ts, prevTs);
 
                 if (prevMsg && prevMsg.userId === msg.userId && msg.userId && sameDayThanPrevious) {
                     if (Math.abs(firstTsCombo -msg.ts) < 30 && !(msg instanceof MeMessage))
@@ -338,10 +339,12 @@ function onRoomUpdated() {
                 }
                 if (SELECTED_ROOM_UNREAD > -1 &&
                         (!prevMsg || prevMsg.ts <= SELECTED_ROOM_UNREAD) &&
-                        msg.ts > SELECTED_ROOM_UNREAD)
+                        msg.ts > SELECTED_ROOM_UNREAD) {
                     dom.classList.add(R.klass.msg.firstUnread);
-                else
+                    dom.insertBefore(UNREAD_INDICATOR_DOM, dom.firstChild);
+                } else {
                     dom.classList.remove(R.klass.msg.firstUnread);
+                }
                 if (msg instanceof MeMessage) {
                     prevMsg = null;
                     prevMsgDom = null;
@@ -359,12 +362,15 @@ function onRoomUpdated() {
                     prevMsgDom = dom;
                     currentMsgGroupDom.content.appendChild(dom);
                 }
-                if (sameDayThanPrevious) {
-                    (currentMsgGroupDom || dom).classList.remove(R.klass.msg.firstOfDay);
-                } else {
-                    (currentMsgGroupDom || dom).classList.add(R.klass.msg.firstOfDay);
-                    (currentMsgGroupDom || dom).dataset["date"] = locale.formatDay(msg.ts);
+                if (!currentMsgGroupDom || currentMsgGroupDom.content.firstChild === dom) {
+                    if (sameDayThanPrevious) {
+                        (currentMsgGroupDom || dom).classList.remove(R.klass.msg.firstOfDay);
+                    } else {
+                        (currentMsgGroupDom || dom).classList.add(R.klass.msg.firstOfDay);
+                        (currentMsgGroupDom || dom).dataset["date"] = locale.formatDay(msg.ts);
+                    }
                 }
+                prevTs = msg.ts;
             } else {
                 msg.removeDom();
             }

+ 20 - 2
cli/uiMessage.js

@@ -154,18 +154,34 @@ var AbstractUiMessage = (function() {
     },
 
     updateAttachments = function(_this, channelId) {
-        var attachmentFrag = document.createDocumentFragment();
+        var attachmentFrag = document.createDocumentFragment(),
+            containImages = false,
+            hasAttachment = false;
 
         for (var i =0, nbAttachments = _this.attachments.length; i < nbAttachments; i++) {
             var attachment = _this.attachments[i];
             if (attachment) {
                 var domAttachment = createAttachmentDom(channelId, _this, attachment, i);
-                if (domAttachment)
+                if (domAttachment) {
                     attachmentFrag.appendChild(domAttachment);
+                    containImages |= !!attachment["image_url"];
+                    hasAttachment = true;
+                }
             }
         }
         _this.dom.attachments.textContent = '';
         _this.dom.attachments.appendChild(attachmentFrag);
+        if (hasAttachment) {
+            _this.dom.attachmentWrapper.classList.remove(R.klass.hidden);
+            if (!_this.dom.attachmentWrapper.toggled) {
+                if (CONFIG.shouldExpandAttachment(containImages))
+                    _this.dom.attachmentWrapper["open"] = true;
+                else
+                    _this.dom.attachmentWrapper["open"] = false;
+            }
+        } else {
+            _this.dom.attachmentWrapper.classList.add(R.klass.hidden);
+        }
     },
 
     updateHover = function(_this, channelId) {
@@ -493,6 +509,8 @@ function createTmpMsgDom(input, isMe) {
     dot.textContent = '.';
     dom.ts.appendChild(dot);
     dom.ts.classList.add(R.klass.typing.container);
+
+    dom.attachmentWrapper.remove();
     return dom;
 }
 

+ 5 - 0
cli/uiSettings.js

@@ -59,6 +59,7 @@ var Settings = (function() {
         document.getElementById(R.id.settings.display.displayAvatar).checked = CONFIG.isDisplayAvatars();
         document.getElementById(R.id.settings.display.colorfulNames).checked = CONFIG.isColorfulNames();
         document.getElementById(R.id.settings.display.scrollAvatars).checked = CONFIG.isScrollAvatars();
+        document.getElementById(R.id.settings.display.displayAttachments).value = CONFIG.autoExpandAttachments !== undefined ? CONFIG.autoExpandAttachments : CONFIG_AUTO_EXPAND.NOT_IMAGE;
 
         displayed = true;
     },
@@ -126,6 +127,10 @@ var Settings = (function() {
         if (isScrollAvatars !== CONFIG.isScrollAvatars()) {
             newSettings["scrollAvatars"] = isScrollAvatars;
         }
+        var displayAttachmentValue = document.getElementById(R.id.settings.display.displayAttachments).value;
+        if (displayAttachmentValue !== CONFIG.autoExpandAttachments) {
+            newSettings["autoExpandAttachments"] = displayAttachmentValue;
+        }
         CONFIG.commitNewSettings(newSettings);
         close();
     });

+ 9 - 3
cli/utils.js

@@ -21,8 +21,14 @@ function isObjectEmpty(o) {
 function isSameDay(ts1, ts2) {
     var d1 = new Date(ts1),
         d2 = new Date(ts2);
-    return d1.getDay() == d2.getDay() &&
-        d1.getMonth() == d2.getMonth() &&
-        d1.getYear() == d2.getYear();
+    d1.setHours(0);
+    d1.setMinutes(0);
+    d1.setSeconds(0);
+    d1.setMilliseconds(0);
+    d2.setHours(0);
+    d2.setMinutes(0);
+    d2.setSeconds(0);
+    d2.setMilliseconds(0);
+    return d1.getTime() === d2.getTime();
 }
 

+ 18 - 1
cli/workflow.js

@@ -14,7 +14,12 @@ var
     /**
      * @type {number}
     **/
-    SELECTED_ROOM_UNREAD =-1,
+    SELECTED_ROOM_UNREAD = -1,
+
+    /**
+     * @type {Element}
+    **/
+    UNREAD_INDICATOR_DOM = document.createElement("span"),
 
     /**
      * @type {SimpleChatSystem|null}
@@ -100,6 +105,12 @@ function onConfigUpdated() {
         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();
 }
 
@@ -174,6 +185,10 @@ function setNativeTitle(title) {
 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;
@@ -226,6 +241,7 @@ function unstarChannel(room) {
 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();
 }
 
 /**
@@ -306,6 +322,7 @@ function sendMsg(chan, msg, pendingObj, replyTo) {
         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"];

File diff suppressed because it is too large
+ 53 - 141
srv/public/mimouchat.min.js


+ 3 - 3
srv/public/style.css

@@ -74,7 +74,7 @@ button, .button { border: 1px solid black; border-radius: 3px; background: rgb(2
 .no-network .error { display: inline-block; }
 .chatsystem-content { flex: 1; overflow: auto; }
 .chatsystem-title { display: inline-block; padding: 14px 10px; font-size: 1.75em; font-style: italic; }
-.chatsystem-header-star { background: center center no-repeat /100%; background-image: url("star_empty.png"); display: inline-block; height: 1em; width: 1em; }
+.chatsystem-header-star { background: center center no-repeat; background-size: 100%; background-image: url("star_empty.png"); display: inline-block; height: 1em; width: 1em; }
 .chatsystem-container.starred .chatsystem-header-star { background-image: url("star_full.png"); }
 .chatsystem-container.no-room-selected { position: relative; visibility: hidden; }
 .chatsystem-container.no-room-selected::after { position: absolute; top: 0; bottom: 0; left: 0; right: 0; background: #e0e0e0; content: " "; visibility: visible; }
@@ -102,8 +102,8 @@ button, .button { border: 1px solid black; border-radius: 3px; background: rgb(2
 .chatmsg-item { display: flex; position: relative; }
 .chatmsg-item:hover { background: #F9F9F9; }
 .chat-context-roominfo .chatmsg-item:hover { background: inherit; }
-.chatmsg-item.chatmsg-first-unread { border-top: 1px solid rgba(255,135,109,.5); }
-.chatmsg-item.chatmsg-first-unread::before { display: inline-block; position: absolute; right: 0; top: -0.8em; content: "New"; color: rgba(255,135,109,.5); background: white; padding: 0 5px 0 3px; font-style: italic; }
+.chatmsg-item .chatmsg-unread { display: inline-block; position: absolute; right: 0; top: -1em; color: rgba(255,135,109,.5); background: white; padding: 0 5px 0 3px; font-style: italic; text-align: right; }
+.chatmsg-item .chatmsg-unread::after { border-top: 2px solid rgba(255,135,109); display: inline-block; position: absolute; right: 0; left: -10px; bottom: -1px; content: " "; }
 .chatmsg-content { display: inline-block; width: 100%; }
 .chatmsg-content .chatmsg-msg, .chatmsg-content .chatmsg-msg *,
 .chatmsg-content .chatmsg-attachments, .chatmsg-content .chatmsg-attachments * { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }

+ 28 - 3
srv/src/controller/apiController.js

@@ -6,19 +6,19 @@ const config = require("../../config.js"),
     sessionManager = require("../session.js").SessionManager,
     accountConfigManager = require("../models/accountConfig.js").accountConfigManager;
 
-function recursiveGet(url, cb, redirectLoop) {
+function recursiveGet(url, cb, headers, redirectLoop) {
     var getFnc = http.get;
 
     if (url.substr(0, 8) === "https://")
         getFnc = https.get;
-    getFnc(url, (d) => {
+    getFnc(url, headers ? { headers: headers } : {}, (d) => {
         if (d.statusCode >= 300 && d.statusCode < 400 && d.headers["location"]) {
             if (!redirectLoop)
                 redirectLoop = [];
 
             if (redirectLoop.indexOf(d.headers["location"]) === -1 && redirectLoop.length < 5) {
                 redirectLoop.push(d.headers["location"]);
-                recursiveGet(d.headers["location"], cb, redirectLoop);
+                recursiveGet(d.headers["location"], cb, headers, redirectLoop);
                 return;
             }
         }
@@ -398,6 +398,31 @@ module.exports.ApiController = {
                 res.writeHeader("400", "Bad Request");
                 res.end();
             }
+        } else if (req.urlObj.match(["api", "serviceImage"])) {
+            if (req.urlObj.queryTokens.team && req.urlObj.queryTokens.path) {
+                var ctx = res.chatContext.getChatSystem(req.urlObj.queryTokens.team[0]);
+
+                if (!ctx) {
+                    res.writeHeader("404", "Not Found");
+                    res.end();
+                } else if (req.method !== 'GET') {
+                    res.writeHeader("400", "Bad Request");
+                    res.end();
+                } else {
+                    let url = ctx.getImage(req.urlObj.queryTokens.path[0]);
+                    if (!url) {
+                        res.writeHeader("400", "Bad Request");
+                        res.end();
+                    } else {
+                        recursiveGet(url.url, (d) => {
+                            d.pipe(res, { end: true });
+                        }, url.headers);
+                    }
+                }
+            } else {
+                res.writeHeader("400", "Bad Request");
+                res.end();
+            }
         } else if (req.urlObj.match(["api"])) {
             let knownVersion = (req.urlObj.queryTokens.v ? parseInt(req.urlObj.queryTokens.v[0], 10) : 0) || 0;
             res.chatContext.poll(knownVersion, req.reqT,

+ 7 - 1
srv/src/models/accountConfig.js

@@ -98,6 +98,10 @@ AccountConfig.prototype.merge = function(configBlob) {
         this.scrollAvatars = configBlob["scrollAvatars"];
         modified = true;
     }
+    if (configBlob["autoExpandAttachments"] !== undefined && configBlob["autoExpandAttachments"] !== this.autoExpandAttachments) {
+        this.autoExpandAttachments = configBlob["autoExpandAttachments"];
+        modified = true;
+    }
     return modified;
 };
 
@@ -211,7 +215,8 @@ AccountConfig.prototype.toDb = function() {
         emojiProvider: this.emojiProvider,
         displayAvatar: this.displayAvatar,
         colorfulNames: this.colorfulNames,
-        scrollAvatars: this.scrollAvatars
+        scrollAvatars: this.scrollAvatars,
+        autoExpandAttachments: this.autoExpandAttachments
     });
 };
 
@@ -222,6 +227,7 @@ AccountConfig.prototype.fromDb = function(dbObj) {
     this.displayAvatar = dbObj.displayAvatar;
     this.colorfulNames = dbObj.colorfulNames;
     this.scrollAvatars = dbObj.scrollAvatars;
+    this.autoExpandAttachments = dbObj.autoExpandAttachments;
 };
 
 module.exports.accountConfigManager = new AccountConfigManager();

+ 15 - 0
srv/src/multichatManager.js

@@ -119,6 +119,12 @@ ChatSystem.prototype.sendCommand = function(chan, cmd, args) {};
 **/
 ChatSystem.prototype.poll = function(knownVersion, nowTs, withTyping) {};
 
+/**
+ * @param {string} path
+ * @return {({url: string, headers: Object})|null} path to get
+**/
+ChatSystem.prototype.getImage = function(path) {};
+
 /**
  * @constructor
 **/
@@ -223,6 +229,15 @@ MultiChatManager.prototype.getChannelIds = function(filter) {
     return ids;
 };
 
+MultiChatManager.prototype.getChatSystem =function(teamId) {
+    for (var i =0, nbCtx = this.contexts.length; i < nbCtx; i++) {
+        var sys = this.contexts[i]
+            ,ctx = sys.getChatContext();
+        if (ctx && ctx.team && ctx.team.id === teamId)
+            return sys;
+    }
+};
+
 /**
  * @param {string} userId
  * @return {Chatter|null}

+ 9 - 0
srv/src/slack.js

@@ -949,5 +949,14 @@ Slack.prototype.getChatContext = function() {
     return this.data;
 };
 
+Slack.prototype.getImage = function(path) {
+    return {
+        url: "https://files.slack.com/" +path.replace(/[^\/A-Za-z0-9\-_\.]/g, ''),
+        headers: {
+            "Authorization": "Bearer " +this.token
+        }
+    };
+};
+
 module.exports.Slack = Slack;
 

+ 23 - 10
srv/src/slackHistory.js

@@ -47,16 +47,29 @@ SlackHistory.prototype.prepareMessage = function(ev, targetId) {
 }
 
 SlackHistory.prototype.messageFactory = function(ev, ts) {
-    let img;
-    if (ev["file"] && ev["file"]["mimetype"].indexOf("image/") >= 0)
-        img = ev["file"]["thumb_360"] || ev["file"]["url_private"] || ev["file"]["permalink"] || undefined;
-    if (img) {
-        if (!ev["attachments"])
-            ev["attachments"] = [];
-        ev["attachments"].push({
-            "image_url": img
-        });
-    }
+    ev["files"] && ev["files"].forEach(f => {
+        if (f["mimetype"].indexOf("image/") >= 0) {
+            let imgUrl = f["thumb_360"] || f["url_private"] || f["permalink"];
+            if (imgUrl) {
+                if (!ev["attachments"])
+                    ev["attachments"] = [];
+                ev["attachments"].push({
+                    "image_url": imgUrl
+                });
+                return;
+            }
+        }
+        // FIXME manage uploads that are not images
+    });
+    if (ev["attachments"]) ev["attachments"].forEach(attachment => {
+        const slackDomainUri = "https://files.slack.com/";
+        if (attachment.color && attachment.color.length === 6)
+            attachment.color = '#' +attachment.color;
+        if (attachment.image_url && attachment.image_url.startsWith(slackDomainUri)) {
+            attachment.remote_image_url = attachment.image_url;
+            attachment.image_url = "api/serviceImage?team=" +encodeURIComponent(this.ctx.data.team.id) +"&path=" +encodeURIComponent(attachment.image_url.substr(slackDomainUri.length));
+        }
+    }, this);
     if (!ev["user"]) {
         if (ev["bot_id"])
             ev["user"] = ev["bot_id"];

+ 1 - 1
srv/src/template/_templates.js

@@ -3,7 +3,7 @@ const config = require('../../config.js');
 
 module.exports = {
     header: function(title, cssFiles, moreHeader) {
-        var res = `<html><head><title>${title}</title><link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" />`;
+        var res = `<!DOCTYPE HTML5><html><head><title>${title}</title><link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" />`;
         (cssFiles || []).forEach(function(i) {
             if (i[0] === '_') {
                 res += '<style id="' +i.substr(1) +'"></style>';

+ 2 - 0
srv/src/template/index.js

@@ -7,6 +7,7 @@ module.exports.needLogin = function(urlObj) {
 };
 
 module.exports.exec = function(req, res) {
+    res.setHeader('Content-Type', "text/html; charset=UTF-8");
     if (req.account && !req.account.cguReadAndAccepted) {
         if (config.allowNewAccounts)
             return {
@@ -72,6 +73,7 @@ module.exports.exec = function(req, res) {
                           <label><span id="settings-displayDisplayAvatarLbl"></span><input type="checkbox" value="1" id="settings-displayDisplayAvatar"></label>
                           <label><span id="settings-displayColorfulNamesLbl"></span><input type="checkbox" value="1" id="settings-displayColorfulNames"></label>
                           <label><span id="settings-displayScrollAvatarsLbl"></span><input type="checkbox" value="1" id="settings-displayScrollAvatars"></label>
+                          <label><span id="settings-displayAttachmentContentLbl"></span><select id="settings-displayAttachmentContent"><option id="settings-displayAttachmentContent-never" value="0"/><option id="settings-displayAttachmentContent-always" value="1"/><option id="settings-displayAttachmentContent-notimg" value="2"/></select></label>
                       </section>
                       <section class="settings-privacy">
                           <h4 id="settings-privacy-title"></h4>

+ 1 - 0
srv/src/template/login.js

@@ -160,6 +160,7 @@ module.exports.match = function(url) {
 };
 
 module.exports.exec = function(req, res, srv) {
+    res.setHeader('Content-Type', "text/html; charset=UTF-8");
     if (!req.urlObj.urlParts[1]) {
         if (req.urlObj.queryTokens["native"]) {
             req.session = sessionManager.lazyForRequest(req);

Some files were not shown because too many files changed in this diff