From 44714dfcb18b9a393dc34be3c182b0c092eec28a Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Thu, 17 Sep 2015 21:00:59 -0700 Subject: PLT-11 Adding ability to save config file --- web/react/utils/async_client.jsx | 26 ++++++++++++++++++++++++++ web/react/utils/client.jsx | 31 ++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'web/react/utils') diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index 3e23e5c33..ed228f6c4 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -345,6 +345,32 @@ export function getLogs() { ); } +export function getConfig() { + if (isCallInProgress('getConfig')) { + return; + } + + callTracker.getConfig = utils.getTimestamp(); + client.getConfig( + (data, textStatus, xhr) => { + callTracker.getConfig = 0; + + if (xhr.status === 304 || !data) { + return; + } + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECIEVED_CONFIG, + config: data + }); + }, + (err) => { + callTracker.getConfig = 0; + dispatchError(err, 'getConfig'); + } + ); +} + export function findTeams(email) { if (isCallInProgress('findTeams_' + email)) { return; diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index ba3042d78..c9eb09c00 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -297,7 +297,7 @@ export function getLogs(success, error) { dataType: 'json', contentType: 'application/json', type: 'GET', - success: success, + success, error: function onError(xhr, status, err) { var e = handleError('getLogs', xhr, status, err); error(e); @@ -305,6 +305,35 @@ export function getLogs(success, error) { }); } +export function getConfig(success, error) { + $.ajax({ + url: '/api/v1/admin/config', + dataType: 'json', + contentType: 'application/json', + type: 'GET', + success, + error: function onError(xhr, status, err) { + var e = handleError('getConfig', xhr, status, err); + error(e); + } + }); +} + +export function saveConfig(config, success, error) { + $.ajax({ + url: '/api/v1/admin/save_config', + dataType: 'json', + contentType: 'application/json', + type: 'POST', + data: JSON.stringify(config), + success, + error: function onError(xhr, status, err) { + var e = handleError('saveConfig', xhr, status, err); + error(e); + } + }); +} + export function getMeSynchronous(success, error) { var currentUser = null; $.ajax({ -- cgit v1.2.3-1-g7c22 From 804b696bdc7d0b68701ce80e6ff5fba7ff3677c3 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Thu, 17 Sep 2015 22:00:33 -0700 Subject: PLT-11 adding config for logs to UI --- web/react/utils/utils.jsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'web/react/utils') diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 032cf4ff4..074591489 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -54,6 +54,29 @@ export function isTestDomain() { return false; } +export function isInRole(roles, inRole) { + var parts = roles.split(' '); + for (var i = 0; i < parts.length; i++) { + if (parts[i] === inRole) { + return true; + } + } + + return false; +} + +export function isAdmin(roles) { + if (isInRole(roles, 'admin')) { + return true; + } + + if (isInRole(roles, 'system_admin')) { + return true; + } + + return false; +} + export function getDomainWithOutSub() { var parts = window.location.host.split('.'); -- cgit v1.2.3-1-g7c22 From bc8e69d99f5b7b22fd1b781fa1862c24e0de0b90 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 11:56:23 -0400 Subject: Fixed incorrect check if a url starts with an explicit protocol --- web/react/utils/text_formatting.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 2025e16da..54d010dbf 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -56,7 +56,7 @@ function autolinkUrls(text, tokens) { const linkText = match.getMatchedText(); let url = linkText; - if (!url.lastIndexOf('http', 0) === 0) { + if (url.lastIndexOf('http', 0) !== 0) { url = `http://${linkText}`; } -- cgit v1.2.3-1-g7c22 From 208bf914b8a5efb3f4474361e4d247826b25788c Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 11:29:52 -0400 Subject: Removed unnecessary conversion of newlines to html line breaks --- web/react/utils/text_formatting.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 54d010dbf..5bf3ca52c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -33,7 +33,9 @@ export function formatText(text, options = {}) { output = replaceTokens(output, tokens); // replace newlines with html line breaks - output = replaceNewlines(output, options.singleline); + if (options.singleline) { + output = replaceNewlines(output); + } return output; } @@ -246,11 +248,7 @@ function replaceTokens(text, tokens) { return output; } -function replaceNewlines(text, singleline) { - if (!singleline) { - return text.replace(/\n/g, '
'); - } - +function replaceNewlines(text) { return text.replace(/\n/g, ' '); } -- cgit v1.2.3-1-g7c22 From ae5a1e3ea84fcde2cf0375c1cad778eab6f2634b Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 11:31:39 -0400 Subject: Removed underscores surrounding formatting tokens since they won't work with markdown --- web/react/utils/text_formatting.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 5bf3ca52c..c00193e37 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -63,7 +63,7 @@ function autolinkUrls(text, tokens) { } const index = tokens.size; - const alias = `__MM_LINK${index}__`; + const alias = `MM_LINK${index}`; tokens.set(alias, { value: `${linkText}`, @@ -93,7 +93,7 @@ function autolinkAtMentions(text, tokens) { const usernameLower = username.toLowerCase(); if (Constants.SPECIAL_MENTIONS.indexOf(usernameLower) !== -1 || UserStore.getProfileByUsername(usernameLower)) { const index = tokens.size; - const alias = `__MM_ATMENTION${index}__`; + const alias = `MM_ATMENTION${index}`; tokens.set(alias, { value: `${mention}`, @@ -121,7 +121,7 @@ function highlightCurrentMentions(text, tokens) { for (const [alias, token] of tokens) { if (mentionKeys.indexOf(token.originalText) !== -1) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_SELFMENTION${index}__`; + const newAlias = `MM_SELFMENTION${index}`; newTokens.set(newAlias, { value: `${alias}`, @@ -140,7 +140,7 @@ function highlightCurrentMentions(text, tokens) { // look for self mentions in the text function replaceCurrentMentionWithToken(fullMatch, prefix, mention) { const index = tokens.size; - const alias = `__MM_SELFMENTION${index}__`; + const alias = `MM_SELFMENTION${index}`; tokens.set(alias, { value: `${mention}`, @@ -164,7 +164,7 @@ function autolinkHashtags(text, tokens) { for (const [alias, token] of tokens) { if (token.originalText.lastIndexOf('#', 0) === 0) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_HASHTAG${index}__`; + const newAlias = `MM_HASHTAG${index}`; newTokens.set(newAlias, { value: `${token.originalText}`, @@ -183,7 +183,7 @@ function autolinkHashtags(text, tokens) { // look for hashtags in the text function replaceHashtagWithToken(fullMatch, prefix, hashtag) { const index = tokens.size; - const alias = `__MM_HASHTAG${index}__`; + const alias = `MM_HASHTAG${index}`; tokens.set(alias, { value: `${hashtag}`, @@ -203,7 +203,7 @@ function highlightSearchTerm(text, tokens, searchTerm) { for (const [alias, token] of tokens) { if (token.originalText === searchTerm) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_SEARCHTERM${index}__`; + const newAlias = `MM_SEARCHTERM${index}`; newTokens.set(newAlias, { value: `${alias}`, @@ -221,7 +221,7 @@ function highlightSearchTerm(text, tokens, searchTerm) { function replaceSearchTermWithToken(fullMatch, prefix, word) { const index = tokens.size; - const alias = `__MM_SEARCHTERM${index}__`; + const alias = `MM_SEARCHTERM${index}`; tokens.set(alias, { value: `${word}`, -- cgit v1.2.3-1-g7c22 From bb330b662a60c6581eda6dde0d94eb3a57579b15 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 13:41:00 -0400 Subject: Added marked library to text_formatting.jsx --- web/react/utils/text_formatting.jsx | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index c00193e37..62e6978a9 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -6,6 +6,10 @@ const Constants = require('./constants.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); +const marked = require('marked'); + +const markdownRenderer = new marked.Renderer(); + // Performs formatting of user posts including highlighting mentions and search terms and converting urls, hashtags, and // @mentions to links by taking a user's message and returning a string of formatted html. Also takes a number of options // as part of the second parameter: @@ -29,6 +33,11 @@ export function formatText(text, options = {}) { output = highlightCurrentMentions(output, tokens); } + // perform markdown parsing while we have an html-free input string + console.log('output before marked ' + output); + output = marked(output, {renderer: markdownRenderer}); + console.log('output after marked ' + output); + // reinsert tokens with formatted versions of the important words and phrases output = replaceTokens(output, tokens); -- cgit v1.2.3-1-g7c22 From efb3462a683d1f4d88c56327b14256adda11115d Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 10:31:48 -0400 Subject: Prevented our url autolinking from breaking markdown links --- web/react/utils/text_formatting.jsx | 40 +++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 62e6978a9..da0595326 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -17,11 +17,14 @@ const markdownRenderer = new marked.Renderer(); // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. export function formatText(text, options = {}) { + // TODO remove me + options.markdown = true; + let output = sanitizeHtml(text); const tokens = new Map(); // replace important words and phrases with tokens - output = autolinkUrls(output, tokens); + output = autolinkUrls(output, tokens, !!options.markdown); output = autolinkAtMentions(output, tokens); output = autolinkHashtags(output, tokens); @@ -34,9 +37,11 @@ export function formatText(text, options = {}) { } // perform markdown parsing while we have an html-free input string - console.log('output before marked ' + output); - output = marked(output, {renderer: markdownRenderer}); - console.log('output after marked ' + output); + if (options.markdown) { + console.log('output before marked ' + output); + output = marked(output, {renderer: markdownRenderer}); + console.log('output after marked ' + output); + } // reinsert tokens with formatted versions of the important words and phrases output = replaceTokens(output, tokens); @@ -62,7 +67,7 @@ export function sanitizeHtml(text) { return output; } -function autolinkUrls(text, tokens) { +function autolinkUrls(text, tokens, markdown) { function replaceUrlWithToken(autolinker, match) { const linkText = match.getMatchedText(); let url = linkText; @@ -92,7 +97,30 @@ function autolinkUrls(text, tokens) { replaceFn: replaceUrlWithToken }); - return autolinker.link(text); + let output = text; + + // temporarily replace markdown links if markdown is enabled so that we don't accidentally parse them twice + const markdownLinkTokens = new Map(); + if (markdown) { + function replaceMarkdownLinkWithToken(markdownLink) { + const index = markdownLinkTokens.size; + const alias = `MM_MARKDOWNLINK${index}`; + + markdownLinkTokens.set(alias, {value: markdownLink}); + + return alias; + } + + output = output.replace(/\]\([^\)]*\)/g, replaceMarkdownLinkWithToken); + } + + output = autolinker.link(output); + + if (markdown) { + output = replaceTokens(output, markdownLinkTokens); + } + + return output; } function autolinkAtMentions(text, tokens) { -- cgit v1.2.3-1-g7c22 From 2eb320f48a66b42832b758e5fc6700358aef34ed Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 10:33:13 -0400 Subject: Changed markdown link parsing to automatically add an explicit protocol to urls --- web/react/utils/markdown.jsx | 14 ++++++++++++++ web/react/utils/text_formatting.jsx | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 web/react/utils/markdown.jsx (limited to 'web/react/utils') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx new file mode 100644 index 000000000..880e41a18 --- /dev/null +++ b/web/react/utils/markdown.jsx @@ -0,0 +1,14 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +const marked = require('marked'); + +export class MattermostMarkdownRenderer extends marked.Renderer { + link(href, title, text) { + if (href.lastIndexOf('http', 0) !== 0) { + href = `http://${href}`; + } + + return super.link(href, title, text); + } +} diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index da0595326..537ddb394 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -3,12 +3,13 @@ const Autolinker = require('autolinker'); const Constants = require('./constants.jsx'); +const Markdown = require('./markdown.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); const marked = require('marked'); -const markdownRenderer = new marked.Renderer(); +const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // Performs formatting of user posts including highlighting mentions and search terms and converting urls, hashtags, and // @mentions to links by taking a user's message and returning a string of formatted html. Also takes a number of options -- cgit v1.2.3-1-g7c22 From 5f18c71d07e8ea0ac3f9053ad0a67c5380e613ef Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 11:01:38 -0400 Subject: Deferred to marked.js's html sanitization when markdown is enabled --- web/react/utils/text_formatting.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 537ddb394..47b56cc3c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -21,7 +21,14 @@ export function formatText(text, options = {}) { // TODO remove me options.markdown = true; - let output = sanitizeHtml(text); + // wait until marked can sanitize the html so that we don't break markdown block quotes + let output; + if (!options.markdown) { + output = sanitizeHtml(text); + } else { + output = text; + } + const tokens = new Map(); // replace important words and phrases with tokens @@ -40,7 +47,10 @@ export function formatText(text, options = {}) { // perform markdown parsing while we have an html-free input string if (options.markdown) { console.log('output before marked ' + output); - output = marked(output, {renderer: markdownRenderer}); + output = marked(output, { + renderer: markdownRenderer, + sanitize: true + }); console.log('output after marked ' + output); } -- cgit v1.2.3-1-g7c22 From 144a277a44350af14993d439b3bd9999f75e84e7 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 11:08:39 -0400 Subject: Cleaned up markdown formatting code and removed debug statements --- web/react/utils/markdown.jsx | 8 +++++--- web/react/utils/text_formatting.jsx | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 880e41a18..8c63810cd 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -5,10 +5,12 @@ const marked = require('marked'); export class MattermostMarkdownRenderer extends marked.Renderer { link(href, title, text) { - if (href.lastIndexOf('http', 0) !== 0) { - href = `http://${href}`; + let outHref = href; + + if (outHref.lastIndexOf('http', 0) !== 0) { + outHref = `http://${outHref}`; } - return super.link(href, title, text); + return super.link(outHref, title, text); } } diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 47b56cc3c..4e390f708 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -17,9 +17,11 @@ const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // - searchTerm - If specified, this word is highlighted in the resulting html. Defaults to nothing. // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. +// - markdown - Enables markdown parsing. Defaults to true. export function formatText(text, options = {}) { - // TODO remove me - options.markdown = true; + if (!('markdown' in options)) { + options.markdown = true; + } // wait until marked can sanitize the html so that we don't break markdown block quotes let output; @@ -46,12 +48,10 @@ export function formatText(text, options = {}) { // perform markdown parsing while we have an html-free input string if (options.markdown) { - console.log('output before marked ' + output); output = marked(output, { renderer: markdownRenderer, sanitize: true }); - console.log('output after marked ' + output); } // reinsert tokens with formatted versions of the important words and phrases -- cgit v1.2.3-1-g7c22 From a2e3446e373c51e595fb4e80a04bf80c3ea18027 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 21 Sep 2015 11:41:40 -0400 Subject: Added theme class to markdown links --- web/react/utils/markdown.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'web/react/utils') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 8c63810cd..96da54217 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -11,6 +11,12 @@ export class MattermostMarkdownRenderer extends marked.Renderer { outHref = `http://${outHref}`; } - return super.link(outHref, title, text); + let output = ''; + + return output; } } -- cgit v1.2.3-1-g7c22 From 251d33ad23bd737c5b6954b6e5db14ee0b2611eb Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 21 Sep 2015 17:30:29 -0400 Subject: Added parsing for named emojis to TextFormatting and removed dependency on emojify --- web/react/utils/emoticons.jsx | 159 ++++++++++++++++++++++++++++++++++++ web/react/utils/text_formatting.jsx | 6 ++ 2 files changed, 165 insertions(+) create mode 100644 web/react/utils/emoticons.jsx (limited to 'web/react/utils') diff --git a/web/react/utils/emoticons.jsx b/web/react/utils/emoticons.jsx new file mode 100644 index 000000000..7210201ff --- /dev/null +++ b/web/react/utils/emoticons.jsx @@ -0,0 +1,159 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +const emoticonPatterns = { + smile: /:-?\)/g, // :) + open_mouth: /:o/gi, // :o + scream: /:-o/gi, // :-o + smirk: /[:;]-?]/g, // :] + grinning: /[:;]-?d/gi, // :D + stuck_out_tongue_closed_eyes: /x-d/gi, // x-d + stuck_out_tongue_winking_eye: /[:;]-?p/gi, // ;p + rage: /:-?[\[@]/g, // :@ + frowning: /:-?\(/g, // :( + sob: /:['’]-?\(|:'\(/g, // :`( + kissing_heart: /:-?\*/g, // :* + wink: /;-?\)/g, // ;) + pensive: /:-?\//g, // :/ + confounded: /:-?s/gi, // :s + flushed: /:-?\|/g, // :| + relaxed: /:-?\$/g, // :$ + mask: /:-x/gi, // :-x + heart: /<3|<3/g, // <3 + broken_heart: /<\/3|</3/g, // `, + originalText: match + }); + + return alias; + } + + return match; + } + + output = output.replace(/:([a-zA-Z0-9_-]+):/g, replaceEmoticonWithToken); + + $.each(emoticonPatterns, (name, pattern) => { + // this might look a bit funny, but since the name isn't contained in the actual match + // like with the named emoticons, we need to add it in manually + output = output.replace(pattern, (match) => replaceEmoticonWithToken(match, name)); + }); + + return output; +} + +function getImagePathForEmoticon(name) { + return `/static/images/emoji/${name}.png`; +} diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 4e390f708..be82f7b9c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -3,6 +3,7 @@ const Autolinker = require('autolinker'); const Constants = require('./constants.jsx'); +const Emoticons = require('./emoticons.jsx'); const Markdown = require('./markdown.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); @@ -17,6 +18,7 @@ const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // - searchTerm - If specified, this word is highlighted in the resulting html. Defaults to nothing. // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. +// - emoticons - Enables emoticon parsing. Defaults to true. // - markdown - Enables markdown parsing. Defaults to true. export function formatText(text, options = {}) { if (!('markdown' in options)) { @@ -34,6 +36,10 @@ export function formatText(text, options = {}) { const tokens = new Map(); // replace important words and phrases with tokens + if (!('emoticons' in options) || options.emoticon) { + output = Emoticons.handleEmoticons(output, tokens); + } + output = autolinkUrls(output, tokens, !!options.markdown); output = autolinkAtMentions(output, tokens); output = autolinkHashtags(output, tokens); -- cgit v1.2.3-1-g7c22