diff options
Diffstat (limited to 'web/react/utils')
-rw-r--r-- | web/react/utils/async_client.jsx | 4 | ||||
-rw-r--r-- | web/react/utils/client.jsx | 16 | ||||
-rw-r--r-- | web/react/utils/constants.jsx | 2 | ||||
-rw-r--r-- | web/react/utils/markdown.jsx | 9 | ||||
-rw-r--r-- | web/react/utils/text_formatting.jsx | 10 | ||||
-rw-r--r-- | web/react/utils/utils.jsx | 50 |
6 files changed, 82 insertions, 9 deletions
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx index b1bc71d54..75dd35e3f 100644 --- a/web/react/utils/async_client.jsx +++ b/web/react/utils/async_client.jsx @@ -132,7 +132,7 @@ export function getChannel(id) { callTracker['getChannel' + id] = utils.getTimestamp(); client.getChannel(id, - function getChannelSuccess(data, textStatus, xhr) { + (data, textStatus, xhr) => { callTracker['getChannel' + id] = 0; if (xhr.status === 304 || !data) { @@ -145,7 +145,7 @@ export function getChannel(id) { member: data.member }); }, - function getChannelFailure(err) { + (err) => { callTracker['getChannel' + id] = 0; dispatchError(err, 'getChannel'); } diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index bc73f3c64..bf117b3b3 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -34,7 +34,7 @@ function handleError(methodName, xhr, status, err) { if (oldError && oldError.connErrorCount) { errorCount += oldError.connErrorCount; - connectError = 'We cannot reach the Mattermost service. The service may be down or misconfigured. Please contact an administrator to make sure the WebSocket port is configured properly.'; + connectError = 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.'; } e = {message: connectError, connErrorCount: errorCount}; @@ -328,6 +328,20 @@ export function getConfig(success, error) { }); } +export function getAnalytics(teamId, name, success, error) { + $.ajax({ + url: '/api/v1/admin/analytics/' + teamId + '/' + name, + dataType: 'json', + contentType: 'application/json', + type: 'GET', + success, + error: (xhr, status, err) => { + var e = handleError('getAnalytics', xhr, status, err); + error(e); + } + }); +} + export function saveConfig(config, success, error) { $.ajax({ url: '/api/v1/admin/save_config', diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index c20d84f40..0e89b9470 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -98,6 +98,7 @@ module.exports = { POST_LOADING: 'loading', POST_FAILED: 'failed', POST_DELETED: 'deleted', + POST_TYPE_JOIN_LEAVE: 'join_leave', RESERVED_TEAM_NAMES: [ 'www', 'web', @@ -132,6 +133,7 @@ module.exports = { OFFLINE_ICON_SVG: "<svg version='1.1' id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:svg='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' sodipodi:docname='TRASH_1_4.svg' inkscape:version='0.48.4 r9939' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='12px' height='12px' viewBox='0 0 12 12' enable-background='new 0 0 12 12' xml:space='preserve'><sodipodi:namedview inkscape:cy='139.7898' inkscape:cx='26.358185' inkscape:zoom='1.18' showguides='true' showgrid='false' id='namedview6' guidetolerance='10' gridtolerance='10' objecttolerance='10' borderopacity='1' bordercolor='#666666' pagecolor='#ffffff' inkscape:current-layer='Layer_1' inkscape:window-maximized='1' inkscape:window-y='-8' inkscape:window-x='-8' inkscape:window-height='705' inkscape:window-width='1366' inkscape:guide-bbox='true' inkscape:pageshadow='2' inkscape:pageopacity='0'><sodipodi:guide position='50.036793,85.991376' orientation='1,0' id='guide2986'></sodipodi:guide><sodipodi:guide position='58.426196,66.216355' orientation='0,1' id='guide3047'></sodipodi:guide></sodipodi:namedview><g><g><path fill='#cccccc' d='M6.002,7.143C5.645,7.363,5.167,7.52,4.502,7.52c-2.493,0-2.5-2.02-2.5-2.02S1.029,5.607,0.775,6.004C0.41,6.577,0.15,7.716,0.049,8.545c-0.025,0.145-0.057,0.537-0.05,0.598c0.162,1.295,2.237,2.321,4.375,2.357c0.043,0.001,0.085,0.001,0.127,0.001c0.043,0,0.084,0,0.127-0.001c1.879-0.023,3.793-0.879,4.263-2h-2.89L6.002,7.143L6.002,7.143z M4.501,5.488c1.372,0,2.483-1.117,2.483-2.494c0-1.378-1.111-2.495-2.483-2.495c-1.371,0-2.481,1.117-2.481,2.495C2.02,4.371,3.13,5.488,4.501,5.488z M7.002,6.5v2h5v-2H7.002z'/></g></g></svg>", MENU_ICON: "<svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='4px' height='16px' viewBox='0 0 8 32' enable-background='new 0 0 8 32' xml:space='preserve'> <g> <circle cx='4' cy='4.062' r='4'/> <circle cx='4' cy='16' r='4'/> <circle cx='4' cy='28' r='4'/> </g> </svg>", COMMENT_ICON: "<svg version='1.1' id='Layer_2' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'width='15px' height='15px' viewBox='1 1.5 15 15' enable-background='new 1 1.5 15 15' xml:space='preserve'> <g> <g> <path fill='#211B1B' d='M14,1.5H3c-1.104,0-2,0.896-2,2v8c0,1.104,0.896,2,2,2h1.628l1.884,3l1.866-3H14c1.104,0,2-0.896,2-2v-8 C16,2.396,15.104,1.5,14,1.5z M15,11.5c0,0.553-0.447,1-1,1H8l-1.493,2l-1.504-1.991L5,12.5H3c-0.552,0-1-0.447-1-1v-8 c0-0.552,0.448-1,1-1h11c0.553,0,1,0.448,1,1V11.5z'/> </g> </g> </svg>", + UPDATE_TYPING_MS: 5000, THEMES: { default: { type: 'Mattermost', diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 01cc309b8..ad11a95ac 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -121,8 +121,11 @@ export class MattermostMarkdownRenderer extends marked.Renderer { paragraph(text) { let outText = text; + // required so markdown does not strip '_' from @user_names + outText = TextFormatting.doFormatMentions(text); + if (!('emoticons' in this.options) || this.options.emoticon) { - outText = TextFormatting.doFormatEmoticons(text); + outText = TextFormatting.doFormatEmoticons(outText); } if (this.formattingOptions.singleline) { @@ -136,7 +139,7 @@ export class MattermostMarkdownRenderer extends marked.Renderer { return `<table class="markdown__table"><thead>${header}</thead><tbody>${body}</tbody></table>`; } - text(text) { - return TextFormatting.doFormatText(text, this.formattingOptions); + text(txt) { + return TextFormatting.doFormatText(txt, this.formattingOptions); } } diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 4b6d87254..9f1a5a53f 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -47,8 +47,8 @@ export function doFormatText(text, options) { const tokens = new Map(); // replace important words and phrases with tokens - output = autolinkUrls(output, tokens); output = autolinkAtMentions(output, tokens); + output = autolinkUrls(output, tokens); output = autolinkHashtags(output, tokens); if (!('emoticons' in options) || options.emoticon) { @@ -78,6 +78,13 @@ export function doFormatEmoticons(text) { return output; } +export function doFormatMentions(text) { + const tokens = new Map(); + let output = autolinkAtMentions(text, tokens); + output = replaceTokens(output, tokens); + return output; +} + export function sanitizeHtml(text) { let output = text; @@ -188,6 +195,7 @@ function autolinkAtMentions(text, tokens) { let output = text; output = output.replace(/(^|\s)(@([a-z0-9.\-_]*))/gi, replaceAtMentionWithToken); + return output; } diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index 7a876d518..3140a5d77 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -8,6 +8,7 @@ var PreferenceStore = require('../stores/preference_store.jsx'); var TeamStore = require('../stores/team_store.jsx'); var Constants = require('../utils/constants.jsx'); var ActionTypes = Constants.ActionTypes; +var Client = require('./client.jsx'); var AsyncClient = require('./async_client.jsx'); var client = require('./client.jsx'); var Autolinker = require('autolinker'); @@ -210,11 +211,15 @@ export function displayDateTime(ticks) { } interval = Math.floor(seconds / 60); - if (interval > 1) { + if (interval >= 2) { return interval + ' minutes ago'; } - return '1 minute ago'; + if (interval >= 1) { + return '1 minute ago'; + } + + return 'just now'; } export function displayCommentDateTime(ticks) { @@ -1009,3 +1014,44 @@ export function windowWidth() { export function windowHeight() { return $(window).height(); } + +export function openDirectChannelToUser(user, successCb, errorCb) { + const channelName = this.getDirectChannelName(UserStore.getCurrentId(), user.id); + let channel = ChannelStore.getByName(channelName); + + const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true'); + AsyncClient.savePreferences([preference]); + + if (channel) { + if ($.isFunction(successCb)) { + successCb(channel, true); + } + } else { + channel = { + name: channelName, + last_post_at: 0, + total_msg_count: 0, + type: 'D', + display_name: user.username, + teammate_id: user.id, + status: UserStore.getStatus(user.id) + }; + + Client.createDirectChannel( + channel, + user.id, + (data) => { + AsyncClient.getChannel(data.id); + if ($.isFunction(successCb)) { + successCb(data, false); + } + }, + () => { + window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channelName; + if ($.isFunction(errorCb)) { + errorCb(); + } + } + ); + } +} |