summaryrefslogtreecommitdiffstats
path: root/web/react/utils
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/utils')
-rw-r--r--web/react/utils/async_client.jsx1085
-rw-r--r--web/react/utils/channel_intro_messages.jsx253
-rw-r--r--web/react/utils/client.jsx1650
-rw-r--r--web/react/utils/constants.jsx520
-rw-r--r--web/react/utils/delayed_action.jsx27
-rw-r--r--web/react/utils/emoticons.jsx161
-rw-r--r--web/react/utils/markdown.jsx575
-rw-r--r--web/react/utils/text_formatting.jsx402
-rw-r--r--web/react/utils/utils.jsx1416
9 files changed, 0 insertions, 6089 deletions
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
deleted file mode 100644
index b9770a6e9..000000000
--- a/web/react/utils/async_client.jsx
+++ /dev/null
@@ -1,1085 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as client from './client.jsx';
-import * as GlobalActions from '../action_creators/global_actions.jsx';
-import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
-import BrowserStore from '../stores/browser_store.jsx';
-import ChannelStore from '../stores/channel_store.jsx';
-import PreferenceStore from '../stores/preference_store.jsx';
-import PostStore from '../stores/post_store.jsx';
-import UserStore from '../stores/user_store.jsx';
-import * as utils from './utils.jsx';
-
-import Constants from './constants.jsx';
-const ActionTypes = Constants.ActionTypes;
-const StatTypes = Constants.StatTypes;
-
-// Used to track in progress async calls
-const callTracker = {};
-
-export function dispatchError(err, method) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ERROR,
- err,
- method
- });
-}
-
-function isCallInProgress(callName) {
- if (!(callName in callTracker)) {
- return false;
- }
-
- if (callTracker[callName] === 0) {
- return false;
- }
-
- if (utils.getTimestamp() - callTracker[callName] > 5000) {
- //console.log('AsyncClient call ' + callName + ' expired after more than 5 seconds');
- return false;
- }
-
- return true;
-}
-
-export function getChannels(checkVersion) {
- if (isCallInProgress('getChannels')) {
- return null;
- }
-
- callTracker.getChannels = utils.getTimestamp();
-
- return client.getChannels(
- (data, textStatus, xhr) => {
- callTracker.getChannels = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- if (checkVersion) {
- var serverVersion = xhr.getResponseHeader('X-Version-ID');
-
- if (serverVersion !== BrowserStore.getLastServerVersion()) {
- if (!BrowserStore.getLastServerVersion() || BrowserStore.getLastServerVersion() === '') {
- BrowserStore.setLastServerVersion(serverVersion);
- } else {
- BrowserStore.setLastServerVersion(serverVersion);
- window.location.reload(true);
- console.log('Detected version update refreshing the page'); //eslint-disable-line no-console
- }
- }
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNELS,
- channels: data.channels,
- members: data.members
- });
- },
- (err) => {
- callTracker.getChannels = 0;
- dispatchError(err, 'getChannels');
- }
- );
-}
-
-export function getChannel(id) {
- if (isCallInProgress('getChannel' + id)) {
- return;
- }
-
- callTracker['getChannel' + id] = utils.getTimestamp();
-
- client.getChannel(id,
- (data, textStatus, xhr) => {
- callTracker['getChannel' + id] = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL,
- channel: data.channel,
- member: data.member
- });
- },
- (err) => {
- callTracker['getChannel' + id] = 0;
- dispatchError(err, 'getChannel');
- }
- );
-}
-
-export function updateLastViewedAt(id) {
- let channelId;
- if (id) {
- channelId = id;
- } else {
- channelId = ChannelStore.getCurrentId();
- }
-
- if (channelId == null) {
- return;
- }
-
- if (isCallInProgress(`updateLastViewed${channelId}`)) {
- return;
- }
-
- callTracker[`updateLastViewed${channelId}`] = utils.getTimestamp();
- client.updateLastViewedAt(
- channelId,
- () => {
- callTracker.updateLastViewed = 0;
- },
- (err) => {
- callTracker.updateLastViewed = 0;
- dispatchError(err, 'updateLastViewedAt');
- }
- );
-}
-
-export function getMoreChannels(force) {
- if (isCallInProgress('getMoreChannels')) {
- return;
- }
-
- if (ChannelStore.getMoreAll().loading || force) {
- callTracker.getMoreChannels = utils.getTimestamp();
- client.getMoreChannels(
- function getMoreChannelsSuccess(data, textStatus, xhr) {
- callTracker.getMoreChannels = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_MORE_CHANNELS,
- channels: data.channels,
- members: data.members
- });
- },
- function getMoreChannelsFailure(err) {
- callTracker.getMoreChannels = 0;
- dispatchError(err, 'getMoreChannels');
- }
- );
- }
-}
-
-export function getChannelExtraInfo(id, memberLimit) {
- let channelId;
- if (id) {
- channelId = id;
- } else {
- channelId = ChannelStore.getCurrentId();
- }
-
- if (channelId != null) {
- if (isCallInProgress('getChannelExtraInfo_' + channelId)) {
- return;
- }
-
- callTracker['getChannelExtraInfo_' + channelId] = utils.getTimestamp();
-
- client.getChannelExtraInfo(
- channelId,
- memberLimit,
- (data, textStatus, xhr) => {
- callTracker['getChannelExtraInfo_' + channelId] = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_CHANNEL_EXTRA_INFO,
- extra_info: data
- });
- },
- (err) => {
- callTracker['getChannelExtraInfo_' + channelId] = 0;
- dispatchError(err, 'getChannelExtraInfo');
- }
- );
- }
-}
-
-export function getProfiles() {
- if (isCallInProgress('getProfiles')) {
- return;
- }
-
- callTracker.getProfiles = utils.getTimestamp();
- client.getProfiles(
- function getProfilesSuccess(data, textStatus, xhr) {
- callTracker.getProfiles = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_PROFILES,
- profiles: data
- });
- },
- function getProfilesFailure(err) {
- callTracker.getProfiles = 0;
- dispatchError(err, 'getProfiles');
- }
- );
-}
-
-export function getSessions() {
- if (isCallInProgress('getSessions')) {
- return;
- }
-
- callTracker.getSessions = utils.getTimestamp();
- client.getSessions(
- UserStore.getCurrentId(),
- function getSessionsSuccess(data, textStatus, xhr) {
- callTracker.getSessions = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_SESSIONS,
- sessions: data
- });
- },
- function getSessionsFailure(err) {
- callTracker.getSessions = 0;
- dispatchError(err, 'getSessions');
- }
- );
-}
-
-export function getAudits() {
- if (isCallInProgress('getAudits')) {
- return;
- }
-
- callTracker.getAudits = utils.getTimestamp();
- client.getAudits(
- UserStore.getCurrentId(),
- function getAuditsSuccess(data, textStatus, xhr) {
- callTracker.getAudits = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_AUDITS,
- audits: data
- });
- },
- function getAuditsFailure(err) {
- callTracker.getAudits = 0;
- dispatchError(err, 'getAudits');
- }
- );
-}
-
-export function getLogs() {
- if (isCallInProgress('getLogs')) {
- return;
- }
-
- callTracker.getLogs = utils.getTimestamp();
- client.getLogs(
- (data, textStatus, xhr) => {
- callTracker.getLogs = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_LOGS,
- logs: data
- });
- },
- (err) => {
- callTracker.getLogs = 0;
- dispatchError(err, 'getLogs');
- }
- );
-}
-
-export function getServerAudits() {
- if (isCallInProgress('getServerAudits')) {
- return;
- }
-
- callTracker.getServerAudits = utils.getTimestamp();
- client.getServerAudits(
- (data, textStatus, xhr) => {
- callTracker.getServerAudits = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_SERVER_AUDITS,
- audits: data
- });
- },
- (err) => {
- callTracker.getServerAudits = 0;
- dispatchError(err, 'getServerAudits');
- }
- );
-}
-
-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.RECEIVED_CONFIG,
- config: data
- });
- },
- (err) => {
- callTracker.getConfig = 0;
- dispatchError(err, 'getConfig');
- }
- );
-}
-
-export function getAllTeams() {
- if (isCallInProgress('getAllTeams')) {
- return;
- }
-
- callTracker.getAllTeams = utils.getTimestamp();
- client.getAllTeams(
- (data, textStatus, xhr) => {
- callTracker.getAllTeams = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ALL_TEAMS,
- teams: data
- });
- },
- (err) => {
- callTracker.getAllTeams = 0;
- dispatchError(err, 'getAllTeams');
- }
- );
-}
-
-export function search(terms) {
- if (isCallInProgress('search_' + String(terms))) {
- return;
- }
-
- callTracker['search_' + String(terms)] = utils.getTimestamp();
- client.search(
- terms,
- function searchSuccess(data, textStatus, xhr) {
- callTracker['search_' + String(terms)] = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_SEARCH,
- results: data
- });
- },
- function searchFailure(err) {
- callTracker['search_' + String(terms)] = 0;
- dispatchError(err, 'search');
- }
- );
-}
-
-export function getPostsPage(id, maxPosts) {
- let channelId = id;
- if (channelId == null) {
- channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
- }
-
- if (isCallInProgress('getPostsPage_' + channelId)) {
- return;
- }
-
- var postList = PostStore.getAllPosts(id);
-
- var max = maxPosts;
- if (max == null) {
- max = Constants.POST_CHUNK_SIZE * Constants.MAX_POST_CHUNKS;
- }
-
- // if we already have more than POST_CHUNK_SIZE posts,
- // let's get the amount we have but rounded up to next multiple of POST_CHUNK_SIZE,
- // with a max at maxPosts
- var numPosts = Math.min(max, Constants.POST_CHUNK_SIZE);
- if (postList && postList.order.length > 0) {
- numPosts = Math.min(max, Constants.POST_CHUNK_SIZE * Math.ceil(postList.order.length / Constants.POST_CHUNK_SIZE));
- }
-
- if (channelId != null) {
- callTracker['getPostsPage_' + channelId] = utils.getTimestamp();
-
- client.getPostsPage(
- channelId,
- 0,
- numPosts,
- (data, textStatus, xhr) => {
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- numRequested: numPosts,
- post_list: data
- });
-
- getProfiles();
- },
- (err) => {
- dispatchError(err, 'getPostsPage');
- },
- () => {
- callTracker['getPostsPage_' + channelId] = 0;
- }
- );
- }
-}
-
-export function getPosts(id) {
- let channelId = id;
- if (channelId == null) {
- channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
- }
-
- if (isCallInProgress('getPosts_' + channelId)) {
- return;
- }
-
- const postList = PostStore.getAllPosts(channelId);
-
- if ($.isEmptyObject(postList) || postList.order.length < Constants.POST_CHUNK_SIZE) {
- getPostsPage(channelId, Constants.POST_CHUNK_SIZE);
- return;
- }
-
- const latestPost = PostStore.getLatestPost(channelId);
- let latestPostTime = 0;
-
- if (latestPost != null && latestPost.update_at != null) {
- latestPostTime = latestPost.create_at;
- }
-
- callTracker['getPosts_' + channelId] = utils.getTimestamp();
-
- client.getPosts(
- channelId,
- latestPostTime,
- (data, textStatus, xhr) => {
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- numRequested: 0,
- post_list: data
- });
-
- getProfiles();
- },
- (err) => {
- dispatchError(err, 'getPosts');
- },
- () => {
- callTracker['getPosts_' + channelId] = 0;
- }
- );
-}
-
-export function getPostsBefore(postId, offset, numPost) {
- const channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
-
- if (isCallInProgress('getPostsBefore_' + channelId)) {
- return;
- }
-
- client.getPostsBefore(
- channelId,
- postId,
- offset,
- numPost,
- (data, textStatus, xhr) => {
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: true,
- numRequested: numPost,
- post_list: data
- });
-
- getProfiles();
- },
- (err) => {
- dispatchError(err, 'getPostsBefore');
- },
- () => {
- callTracker['getPostsBefore_' + channelId] = 0;
- }
- );
-}
-
-export function getPostsAfter(postId, offset, numPost) {
- const channelId = ChannelStore.getCurrentId();
- if (channelId == null) {
- return;
- }
-
- if (isCallInProgress('getPostsAfter_' + channelId)) {
- return;
- }
-
- client.getPostsAfter(
- channelId,
- postId,
- offset,
- numPost,
- (data, textStatus, xhr) => {
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POSTS,
- id: channelId,
- before: false,
- numRequested: numPost,
- post_list: data
- });
-
- getProfiles();
- },
- (err) => {
- dispatchError(err, 'getPostsAfter');
- },
- () => {
- callTracker['getPostsAfter_' + channelId] = 0;
- }
- );
-}
-
-export function getMe() {
- if (isCallInProgress('getMe')) {
- return null;
- }
-
- callTracker.getMe = utils.getTimestamp();
- return client.getMe(
- (data, textStatus, xhr) => {
- callTracker.getMe = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ME,
- me: data
- });
-
- GlobalActions.newLocalizationSelected(data.locale);
- },
- (err) => {
- callTracker.getMe = 0;
- dispatchError(err, 'getMe');
- }
- );
-}
-
-export function getStatuses() {
- const preferences = PreferenceStore.getCategory(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
-
- const teammateIds = [];
- for (const preference of preferences) {
- if (preference.value === 'true') {
- teammateIds.push(preference.name);
- }
- }
-
- if (isCallInProgress('getStatuses') || teammateIds.length === 0) {
- return;
- }
-
- callTracker.getStatuses = utils.getTimestamp();
- client.getStatuses(teammateIds,
- (data, textStatus, xhr) => {
- callTracker.getStatuses = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_STATUSES,
- statuses: data
- });
- },
- (err) => {
- callTracker.getStatuses = 0;
- dispatchError(err, 'getStatuses');
- }
- );
-}
-
-export function getMyTeam() {
- if (isCallInProgress('getMyTeam')) {
- return null;
- }
-
- callTracker.getMyTeam = utils.getTimestamp();
- return client.getMyTeam(
- function getMyTeamSuccess(data, textStatus, xhr) {
- callTracker.getMyTeam = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_MY_TEAM,
- team: data
- });
- },
- function getMyTeamFailure(err) {
- callTracker.getMyTeam = 0;
- dispatchError(err, 'getMyTeam');
- }
- );
-}
-
-export function getAllPreferences() {
- if (isCallInProgress('getAllPreferences')) {
- return;
- }
-
- callTracker.getAllPreferences = utils.getTimestamp();
- client.getAllPreferences(
- (data, textStatus, xhr) => {
- callTracker.getAllPreferences = 0;
-
- if (xhr.status === 304 || !data) {
- return;
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_PREFERENCES,
- preferences: data
- });
- },
- (err) => {
- callTracker.getAllPreferences = 0;
- dispatchError(err, 'getAllPreferences');
- }
- );
-}
-
-export function savePreferences(preferences, success, error) {
- client.savePreferences(
- preferences,
- (data, textStatus, xhr) => {
- if (xhr.status !== 304) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_PREFERENCES,
- preferences
- });
- }
-
- if (success) {
- success(data);
- }
- },
- (err) => {
- dispatchError(err, 'savePreferences');
-
- if (error) {
- error();
- }
- }
- );
-}
-
-export function getSuggestedCommands(command, suggestionId, component) {
- client.listCommands(
- (data) => {
- var matches = [];
- data.forEach((cmd) => {
- if (('/' + cmd.trigger).indexOf(command) === 0) {
- let s = '/' + cmd.trigger;
- let hint = '';
- if (cmd.auto_complete_hint && cmd.auto_complete_hint.length !== 0) {
- hint = cmd.auto_complete_hint;
- }
- matches.push({
- suggestion: s,
- hint,
- description: cmd.auto_complete_desc
- });
- }
- });
-
- matches = matches.sort((a, b) => a.suggestion.localeCompare(b.suggestion));
-
- // pull out the suggested commands from the returned data
- const terms = matches.map((suggestion) => suggestion.suggestion);
-
- if (terms.length > 0) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS,
- id: suggestionId,
- matchedPretext: command,
- terms,
- items: matches,
- component
- });
- }
- },
- (err) => {
- dispatchError(err, 'getCommandSuggestions');
- }
- );
-}
-
-export function getFileInfo(filename) {
- const callName = 'getFileInfo' + filename;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getFileInfo(
- filename,
- (data) => {
- callTracker[callName] = 0;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_FILE_INFO,
- filename,
- info: data
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getFileInfo');
- }
- );
-}
-
-export function getStandardAnalytics(teamId) {
- const callName = 'getStandardAnaytics' + teamId;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getAnalytics(
- 'standard',
- teamId,
- (data) => {
- callTracker[callName] = 0;
-
- const stats = {};
-
- for (const index in data) {
- if (data[index].name === 'channel_open_count') {
- stats[StatTypes.TOTAL_PUBLIC_CHANNELS] = data[index].value;
- }
-
- if (data[index].name === 'channel_private_count') {
- stats[StatTypes.TOTAL_PRIVATE_GROUPS] = data[index].value;
- }
-
- if (data[index].name === 'post_count') {
- stats[StatTypes.TOTAL_POSTS] = data[index].value;
- }
-
- if (data[index].name === 'unique_user_count') {
- stats[StatTypes.TOTAL_USERS] = data[index].value;
- }
-
- if (data[index].name === 'team_count' && teamId == null) {
- stats[StatTypes.TOTAL_TEAMS] = data[index].value;
- }
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ANALYTICS,
- teamId,
- stats
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getStandardAnalytics');
- }
- );
-}
-
-export function getAdvancedAnalytics(teamId) {
- const callName = 'getAdvancedAnalytics' + teamId;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getAnalytics(
- 'extra_counts',
- teamId,
- (data) => {
- callTracker[callName] = 0;
-
- const stats = {};
-
- for (const index in data) {
- if (data[index].name === 'file_post_count') {
- stats[StatTypes.TOTAL_FILE_POSTS] = data[index].value;
- }
-
- if (data[index].name === 'hashtag_post_count') {
- stats[StatTypes.TOTAL_HASHTAG_POSTS] = data[index].value;
- }
-
- if (data[index].name === 'incoming_webhook_count') {
- stats[StatTypes.TOTAL_IHOOKS] = data[index].value;
- }
-
- if (data[index].name === 'outgoing_webhook_count') {
- stats[StatTypes.TOTAL_OHOOKS] = data[index].value;
- }
-
- if (data[index].name === 'command_count') {
- stats[StatTypes.TOTAL_COMMANDS] = data[index].value;
- }
-
- if (data[index].name === 'session_count') {
- stats[StatTypes.TOTAL_SESSIONS] = data[index].value;
- }
- }
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ANALYTICS,
- teamId,
- stats
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getAdvancedAnalytics');
- }
- );
-}
-
-export function getPostsPerDayAnalytics(teamId) {
- const callName = 'getPostsPerDayAnalytics' + teamId;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getAnalytics(
- 'post_counts_day',
- teamId,
- (data) => {
- callTracker[callName] = 0;
-
- data.reverse();
-
- const stats = {};
- stats[StatTypes.POST_PER_DAY] = data;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ANALYTICS,
- teamId,
- stats
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getPostsPerDayAnalytics');
- }
- );
-}
-
-export function getUsersPerDayAnalytics(teamId) {
- const callName = 'getUsersPerDayAnalytics' + teamId;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getAnalytics(
- 'user_counts_with_posts_day',
- teamId,
- (data) => {
- callTracker[callName] = 0;
-
- data.reverse();
-
- const stats = {};
- stats[StatTypes.USERS_WITH_POSTS_PER_DAY] = data;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ANALYTICS,
- teamId,
- stats
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getUsersPerDayAnalytics');
- }
- );
-}
-
-export function getRecentAndNewUsersAnalytics(teamId) {
- const callName = 'getRecentAndNewUsersAnalytics' + teamId;
-
- if (isCallInProgress(callName)) {
- return;
- }
-
- callTracker[callName] = utils.getTimestamp();
-
- client.getProfilesForTeam(
- teamId,
- (users) => {
- const stats = {};
-
- const usersList = [];
- for (const id in users) {
- if (users.hasOwnProperty(id)) {
- usersList.push(users[id]);
- }
- }
-
- usersList.sort((a, b) => {
- if (a.last_activity_at < b.last_activity_at) {
- return 1;
- }
-
- if (a.last_activity_at > b.last_activity_at) {
- return -1;
- }
-
- return 0;
- });
-
- const recentActive = [];
- for (let i = 0; i < usersList.length; i++) {
- if (usersList[i].last_activity_at == null) {
- continue;
- }
-
- recentActive.push(usersList[i]);
- if (i >= Constants.STAT_MAX_ACTIVE_USERS) {
- break;
- }
- }
-
- stats[StatTypes.RECENTLY_ACTIVE_USERS] = recentActive;
-
- usersList.sort((a, b) => {
- if (a.create_at < b.create_at) {
- return 1;
- }
-
- if (a.create_at > b.create_at) {
- return -1;
- }
-
- return 0;
- });
-
- var newlyCreated = [];
- for (let i = 0; i < usersList.length; i++) {
- newlyCreated.push(usersList[i]);
- if (i >= Constants.STAT_MAX_NEW_USERS) {
- break;
- }
- }
-
- stats[StatTypes.NEWLY_CREATED_USERS] = newlyCreated;
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_ANALYTICS,
- teamId,
- stats
- });
- },
- (err) => {
- callTracker[callName] = 0;
-
- dispatchError(err, 'getRecentAndNewUsersAnalytics');
- }
- );
-}
diff --git a/web/react/utils/channel_intro_messages.jsx b/web/react/utils/channel_intro_messages.jsx
deleted file mode 100644
index 94f3f0ce0..000000000
--- a/web/react/utils/channel_intro_messages.jsx
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import * as Utils from './utils.jsx';
-import ChannelInviteModal from '../components/channel_invite_modal.jsx';
-import EditChannelHeaderModal from '../components/edit_channel_header_modal.jsx';
-import ToggleModalButton from '../components/toggle_modal_button.jsx';
-import UserProfile from '../components/user_profile.jsx';
-import ChannelStore from '../stores/channel_store.jsx';
-import Constants from '../utils/constants.jsx';
-import * as GlobalActions from '../action_creators/global_actions.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'mm-intl';
-
-export function createChannelIntroMessage(channel) {
- if (channel.type === 'D') {
- return createDMIntroMessage(channel);
- } else if (ChannelStore.isDefault(channel)) {
- return createDefaultIntroMessage(channel);
- } else if (channel.name === Constants.OFFTOPIC_CHANNEL) {
- return createOffTopicIntroMessage(channel);
- } else if (channel.type === 'O' || channel.type === 'P') {
- return createStandardIntroMessage(channel);
- }
- return null;
-}
-
-export function createDMIntroMessage(channel) {
- var teammate = Utils.getDirectTeammate(channel.id);
-
- if (teammate) {
- var teammateName = teammate.username;
- if (teammate.nickname.length > 0) {
- teammateName = teammate.nickname;
- }
-
- return (
- <div className='channel-intro'>
- <div className='post-profile-img__container channel-intro-img'>
- <img
- className='post-profile-img'
- src={'/api/v1/users/' + teammate.id + '/image?time=' + teammate.update_at}
- height='50'
- width='50'
- />
- </div>
- <div className='channel-intro-profile'>
- <strong>
- <UserProfile user={teammate}/>
- </strong>
- </div>
- <p className='channel-intro-text'>
- <FormattedHTMLMessage
- id='intro_messages.DM'
- defaultMessage='This is the start of your direct message history with {teammate}.<br />Direct messages and files shared here are not shown to people outside this area.'
- values={{
- teammate: teammateName
- }}
- />
- </p>
- {createSetHeaderButton(channel)}
- </div>
- );
- }
-
- return (
- <div className='channel-intro'>
- <p className='channel-intro-text'>
- <FormattedMessage
- id='intro_messages.teammate'
- defaultMessage='This is the start of your direct message history with this teammate. Direct messages and files shared here are not shown to people outside this area.'
- />
- </p>
- </div>
- );
-}
-
-export function createOffTopicIntroMessage(channel) {
- return (
- <div className='channel-intro'>
- <FormattedHTMLMessage
- id='intro_messages.offTopic'
- defaultMessage='<h4 class="channel-intro__title">Beginning of {display_name}</h4><p class="channel-intro__content">This is the start of {display_name}, a channel for non-work-related conversations.<br/></p>'
- values={{
- display_name: channel.display_name
- }}
- />
- {createSetHeaderButton(channel)}
- {createInviteChannelMemberButton(channel, 'channel')}
- </div>
- );
-}
-
-export function createDefaultIntroMessage(channel) {
- const inviteModalLink = (
- <a
- className='intro-links'
- href='#'
- onClick={GlobalActions.showGetTeamInviteLinkModal}
- >
- <i className='fa fa-user-plus'></i>
- <FormattedMessage
- id='intro_messages.inviteOthers'
- defaultMessage='Invite others to this team'
- />
- </a>
- );
-
- return (
- <div className='channel-intro'>
- <FormattedHTMLMessage
- id='intro_messages.default'
- defaultMessage="<h4 class='channel-intro__title'>Beginning of {display_name}</h4><p class='channel-intro__content'><strong>Welcome to {display_name}!</strong><br/><br/>This is the first channel teammates see when they sign up - use it for posting updates everyone needs to know.</p>"
- values={{
- display_name: channel.display_name
- }}
- />
- {inviteModalLink}
- {createSetHeaderButton(channel)}
- <br/>
- </div>
- );
-}
-
-export function createStandardIntroMessage(channel) {
- var uiName = channel.display_name;
- var creatorName = '';
-
- var uiType;
- var memberMessage;
- if (channel.type === 'P') {
- uiType = (
- <FormattedMessage
- id='intro_messages.group'
- defaultMessage='private group'
- />
- );
- memberMessage = (
- <FormattedMessage
- id='intro_messages.onlyInvited'
- defaultMessage=' Only invited members can see this private group.'
- />
- );
- } else {
- uiType = (
- <FormattedMessage
- id='intro_messages.channel'
- defaultMessage='channel'
- />
- );
- memberMessage = (
- <FormattedMessage
- id='intro_messages.anyMember'
- defaultMessage=' Any member can join and read this channel.'
- />
- );
- }
-
- const date = (
- <FormattedDate
- value={channel.create_at}
- month='long'
- day='2-digit'
- year='numeric'
- />
- );
-
- var createMessage;
- if (creatorName === '') {
- createMessage = (
- <FormattedMessage
- id='intro_messages.noCreator'
- defaultMessage='This is the start of the {name} {type}, created on {date}.'
- values={{
- name: (uiName),
- type: (uiType),
- date: (date)
- }}
- />
- );
- } else {
- createMessage = (
- <span>
- <FormattedHTMLMessage
- id='intro_messages.creator'
- defaultMessage='This is the start of the <strong>{name}</strong> {type}, created by <strong>{creator}</strong> on <strong>{date}</strong>'
- values={{
- name: (uiName),
- type: (uiType),
- date: (date),
- creator: creatorName
- }}
- />
- </span>
- );
- }
-
- return (
- <div className='channel-intro'>
- <h4 className='channel-intro__title'>
- <FormattedMessage
- id='intro_messages.beginning'
- defaultMessage='Beginning of {name}'
- values={{
- name: (uiName)
- }}
- />
- </h4>
- <p className='channel-intro__content'>
- {createMessage}
- {memberMessage}
- <br/>
- </p>
- {createSetHeaderButton(channel)}
- {createInviteChannelMemberButton(channel, uiType)}
- </div>
- );
-}
-
-function createInviteChannelMemberButton(channel, uiType) {
- return (
- <ToggleModalButton
- className='intro-links'
- dialogType={ChannelInviteModal}
- dialogProps={{channel}}
- >
- <i className='fa fa-user-plus'></i>
- <FormattedMessage
- id='intro_messages.invite'
- defaultMessage='Invite others to this {type}'
- values={{
- type: (uiType)
- }}
- />
- </ToggleModalButton>
- );
-}
-
-function createSetHeaderButton(channel) {
- return (
- <ToggleModalButton
- className='intro-links'
- dialogType={EditChannelHeaderModal}
- dialogProps={{channel}}
- >
- <i className='fa fa-pencil'></i>
- <FormattedMessage
- id='intro_messages.setHeader'
- defaultMessage='Set a Header'
- />
- </ToggleModalButton>
- );
-}
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
deleted file mode 100644
index e00f28a14..000000000
--- a/web/react/utils/client.jsx
+++ /dev/null
@@ -1,1650 +0,0 @@
-// See License.txt for license information.
-
-import BrowserStore from '../stores/browser_store.jsx';
-
-import {browserHistory} from 'react-router';
-
-let translations = {
- connectionError: 'There appears to be a problem with your internet connection.',
- unknownError: 'We received an unexpected status code from the server.'
-};
-
-export function setTranslations(messages) {
- translations = messages;
-}
-
-export function track(category, action, label, property, value) {
- global.window.analytics.track(action, {category, label, property, value});
-}
-
-export function trackPage() {
- global.window.analytics.page();
-}
-
-function handleError(methodName, xhr, status, err) {
- var e = null;
- try {
- e = JSON.parse(xhr.responseText);
- } catch (parseError) {
- e = null;
- }
-
- var msg = '';
-
- if (e) {
- msg = 'method=' + methodName + ' msg=' + e.message + ' detail=' + e.detailed_error + ' rid=' + e.request_id;
- } else {
- msg = 'method=' + methodName + ' status=' + status + ' statusCode=' + xhr.status + ' err=' + err;
-
- if (xhr.status === 0) {
- e = {message: translations.connectionError};
- } else {
- e = {message: translations.unknownError + ' (' + xhr.status + ')'};
- }
- }
-
- console.error(msg); //eslint-disable-line no-console
- console.error(e); //eslint-disable-line no-console
-
- track('api', 'api_weberror', methodName, 'message', msg);
-
- if (xhr.status === 401) {
- if (window.location.href.indexOf('/channels') === 0) {
- browserHistory.push('/login?extra=expired&redirect=' + encodeURIComponent(window.location.pathname + window.location.search));
- } else {
- var teamURL = window.location.pathname.split('/channels')[0];
- browserHistory.push(teamURL + '/login?extra=expired&redirect=' + encodeURIComponent(window.location.pathname + window.location.search));
- }
- }
-
- return e;
-}
-
-export function getTranslations(locale, success, error) {
- $.ajax({
- url: '/static/i18n/' + locale + '.json',
- dataType: 'json',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getTranslations', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function createTeamFromSignup(teamSignup, success, error) {
- $.ajax({
- url: '/api/v1/teams/create_from_signup',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(teamSignup),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createTeamFromSignup', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function createTeamWithLdap(teamSignup, success, error) {
- $.ajax({
- url: '/api/v1/teams/create_with_ldap',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(teamSignup),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createTeamFromSignup', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function createTeamWithSSO(team, service, success, error) {
- $.ajax({
- url: '/api/v1/teams/create_with_sso/' + service,
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(team),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createTeamWithSSO', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function createUser(user, data, emailHash, success, error) {
- $.ajax({
- url: '/api/v1/users/create?d=' + encodeURIComponent(data) + '&h=' + encodeURIComponent(emailHash),
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(user),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createUser', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_create', user.team_id, 'email', user.email);
-}
-
-export function updateUser(user, success, error) {
- $.ajax({
- url: '/api/v1/users/update',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(user),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateUser', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_update');
-}
-
-export function updatePassword(data, success, error) {
- $.ajax({
- url: '/api/v1/users/newpassword',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('newPassword', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_newpassword');
-}
-
-export function updateUserNotifyProps(data, success, error) {
- $.ajax({
- url: '/api/v1/users/update_notify',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateUserNotifyProps', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function updateRoles(data, success, error) {
- $.ajax({
- url: '/api/v1/users/update_roles',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateRoles', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_update_roles');
-}
-
-export function updateActive(userId, active, success, error) {
- var data = {};
- data.user_id = userId;
- data.active = '' + active;
-
- $.ajax({
- url: '/api/v1/users/update_active',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateActive', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_update_roles');
-}
-
-export function sendPasswordReset(data, success, error) {
- $.ajax({
- url: '/api/v1/users/send_password_reset',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('sendPasswordReset', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_send_password_reset');
-}
-
-export function resetPassword(data, success, error) {
- $.ajax({
- url: '/api/v1/users/reset_password',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('resetPassword', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_reset_password');
-}
-
-export function switchToSSO(data, success, error) {
- $.ajax({
- url: '/api/v1/users/switch_to_sso',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('switchToSSO', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_switch_to_sso');
-}
-
-export function switchToEmail(data, success, error) {
- $.ajax({
- url: '/api/v1/users/switch_to_email',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('switchToEmail', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_users_switch_to_email');
-}
-
-export function logout(success, error) {
- track('api', 'api_users_logout');
- $.ajax({
- url: '/api/v1/users/logout',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('logout', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function loginByEmail(name, email, password, success, error) {
- $.ajax({
- url: '/api/v1/users/login',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({name, email, password}),
- success: function onSuccess(data, textStatus, xhr) {
- track('api', 'api_users_login_success', data.team_id, 'email', data.email);
- sessionStorage.removeItem(data.id + '_last_error');
- BrowserStore.signalLogin();
- success(data, textStatus, xhr);
- },
- error: function onError(xhr, status, err) {
- track('api', 'api_users_login_fail', name, 'email', email);
-
- var e = handleError('loginByEmail', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function loginByUsername(name, username, password, success, error) {
- $.ajax({
- url: '/api/v1/users/login',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({name, username, password}),
- success: function onSuccess(data, textStatus, xhr) {
- track('api', 'api_users_login_success', data.team_id, 'username', data.username);
- sessionStorage.removeItem(data.id + '_last_error');
- BrowserStore.signalLogin();
- success(data, textStatus, xhr);
- },
- error: function onError(xhr, status, err) {
- track('api', 'api_users_login_fail', name, 'username', username);
-
- var e = handleError('loginByUsername', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function loginByLdap(teamName, id, password, success, error) {
- $.ajax({
- url: '/api/v1/users/login_ldap',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({teamName, id, password}),
- success: function onSuccess(data, textStatus, xhr) {
- track('api', 'api_users_loginLdap_success', data.team_id, 'id', id);
- sessionStorage.removeItem(data.id + '_last_error');
- BrowserStore.signalLogin();
- success(data, textStatus, xhr);
- },
- error: function onError(xhr, status, err) {
- track('api', 'api_users_loginLdap_fail', teamName, 'id', id);
-
- var e = handleError('loginByLdap', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function revokeSession(altId, success, error) {
- $.ajax({
- url: '/api/v1/users/revoke_session',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({id: altId}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('revokeSession', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getSessions(userId, success, error) {
- $.ajax({
- cache: false,
- url: '/api/v1/users/' + userId + '/sessions',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getSessions', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getAudits(userId, success, error) {
- $.ajax({
- url: '/api/v1/users/' + userId + '/audits',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getAudits', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getLogs(success, error) {
- $.ajax({
- url: '/api/v1/admin/logs',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getLogs', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getServerAudits(success, error) {
- $.ajax({
- url: '/api/v1/admin/audits',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getServerAudits', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getConfig(success, error) {
- return $.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 getAnalytics(name, teamId, success, error) {
- let url = '/api/v1/admin/analytics/';
- if (teamId == null) {
- url += name;
- } else {
- url += teamId + '/' + name;
- }
- $.ajax({
- url,
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('getSystemAnalytics', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getClientConfig(success, error) {
- return $.ajax({
- url: '/api/v1/admin/client_props',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getClientConfig', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getTeamAnalytics(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('getTeamAnalytics', 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 logClientError(msg) {
- var l = {};
- l.level = 'ERROR';
- l.message = msg;
-
- $.ajax({
- url: '/api/v1/admin/log_client',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(l)
- });
-}
-
-export function testEmail(config, success, error) {
- $.ajax({
- url: '/api/v1/admin/test_email',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(config),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('testEmail', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getAllTeams(success, error) {
- $.ajax({
- url: '/api/v1/teams/all',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getAllTeams', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getMeLoggedIn(success, error) {
- return $.ajax({
- cache: false,
- url: '/api/v1/users/me_logged_in',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getMeLoggedIn', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getMe(success, error) {
- var currentUser = null;
- $.ajax({
- cache: false,
- url: '/api/v1/users/me',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success: function gotUser(data, textStatus, xhr) {
- currentUser = data;
- if (success) {
- success(data, textStatus, xhr);
- }
- },
- error: function onError(xhr, status, err) {
- if (error) {
- var e = handleError('getMe', xhr, status, err);
- error(e);
- }
- }
- });
-
- return currentUser;
-}
-
-export function inviteMembers(data, success, error) {
- $.ajax({
- url: '/api/v1/teams/invite_members',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('inviteMembers', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_teams_invite_members');
-}
-
-export function updateTeam(team, success, error) {
- $.ajax({
- url: '/api/v1/teams/update',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(team),
- success,
- error: (xhr, status, err) => {
- var e = handleError('updateTeam', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_teams_update_name');
-}
-
-export function signupTeam(email, success, error) {
- $.ajax({
- url: '/api/v1/teams/signup',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({email: email}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('singupTeam', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_teams_signup');
-}
-
-export function createTeam(team, success, error) {
- $.ajax({
- url: '/api/v1/teams/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(team),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createTeam', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function findTeamByName(teamName, success, error) {
- $.ajax({
- url: '/api/v1/teams/find_team_by_name',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({name: teamName}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('findTeamByName', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function createChannel(channel, success, error) {
- $.ajax({
- url: '/api/v1/channels/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(channel),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_create', channel.type, 'name', channel.name);
-}
-
-export function createDirectChannel(channel, userId, success, error) {
- $.ajax({
- url: '/api/v1/channels/create_direct',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({user_id: userId}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createDirectChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_create_direct', channel.type, 'name', channel.name);
-}
-
-export function updateChannel(channel, success, error) {
- $.ajax({
- url: '/api/v1/channels/update',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(channel),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_update');
-}
-
-export function updateChannelHeader(channelId, header, success, error) {
- const data = {
- channel_id: channelId,
- channel_header: header
- };
-
- $.ajax({
- url: '/api/v1/channels/update_header',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateChannelHeader', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_header');
-}
-
-export function updateChannelPurpose(data, success, error) {
- $.ajax({
- url: '/api/v1/channels/update_purpose',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateChannelPurpose', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_purpose');
-}
-
-export function updateNotifyProps(data, success, error) {
- $.ajax({
- url: '/api/v1/channels/update_notify_props',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateNotifyProps', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function joinChannel(id, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + id + '/join',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('joinChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_join');
-}
-
-export function leaveChannel(id, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + id + '/leave',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('leaveChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_leave');
-}
-
-export function deleteChannel(id, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + id + '/delete',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('deleteChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_delete');
-}
-
-export function updateLastViewedAt(channelId, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + channelId + '/update_last_viewed_at',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updateLastViewedAt', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getChannels(success, error) {
- return $.ajax({
- cache: false,
- url: '/api/v1/channels/',
- dataType: 'json',
- type: 'GET',
- success,
- ifModified: true,
- error: function onError(xhr, status, err) {
- var e = handleError('getChannels', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getChannel(id, success, error) {
- $.ajax({
- cache: false,
- url: '/api/v1/channels/' + id + '/',
- dataType: 'json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getChannel', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channel_get');
-}
-
-export function getMoreChannels(success, error) {
- $.ajax({
- url: '/api/v1/channels/more',
- dataType: 'json',
- type: 'GET',
- success,
- ifModified: true,
- error: function onError(xhr, status, err) {
- var e = handleError('getMoreChannels', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getChannelCounts(success, error) {
- $.ajax({
- cache: false,
- url: '/api/v1/channels/counts',
- dataType: 'json',
- type: 'GET',
- success,
- ifModified: true,
- error: function onError(xhr, status, err) {
- var e = handleError('getChannelCounts', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getChannelExtraInfo(id, memberLimit, success, error) {
- let url = '/api/v1/channels/' + id + '/extra_info';
-
- if (memberLimit) {
- url += '/' + memberLimit;
- }
-
- return $.ajax({
- url,
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getChannelExtraInfo', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function executeCommand(channelId, command, suggest, success, error) {
- $.ajax({
- url: '/api/v1/commands/execute',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify({channelId, command, suggest: '' + suggest}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('executeCommand', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function addCommand(cmd, success, error) {
- $.ajax({
- url: '/api/v1/commands/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(cmd),
- success,
- error: (xhr, status, err) => {
- var e = handleError('addCommand', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function deleteCommand(data, success, error) {
- $.ajax({
- url: '/api/v1/commands/delete',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: (xhr, status, err) => {
- var e = handleError('deleteCommand', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function listTeamCommands(success, error) {
- $.ajax({
- url: '/api/v1/commands/list_team_commands',
- dataType: 'json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('listTeamCommands', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function regenCommandToken(data, success, error) {
- $.ajax({
- url: '/api/v1/commands/regen_token',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: (xhr, status, err) => {
- var e = handleError('regenCommandToken', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function listCommands(success, error) {
- $.ajax({
- url: '/api/v1/commands/list',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('listCommands', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getPostsPage(channelId, offset, limit, success, error, complete) {
- $.ajax({
- cache: false,
- url: '/api/v1/channels/' + channelId + '/posts/' + offset + '/' + limit,
- dataType: 'json',
- type: 'GET',
- ifModified: true,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPosts', xhr, status, err);
- error(e);
- },
- complete: complete
- });
-}
-
-export function getPosts(channelId, since, success, error, complete) {
- return $.ajax({
- url: '/api/v1/channels/' + channelId + '/posts/' + since,
- dataType: 'json',
- type: 'GET',
- ifModified: true,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPosts', xhr, status, err);
- error(e);
- },
- complete: complete
- });
-}
-
-export function getPostsBefore(channelId, post, offset, numPost, success, error, complete) {
- $.ajax({
- url: '/api/v1/channels/' + channelId + '/post/' + post + '/before/' + offset + '/' + numPost,
- dataType: 'json',
- type: 'GET',
- ifModified: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPostsBefore', xhr, status, err);
- error(e);
- },
- complete: complete
- });
-}
-
-export function getPostsAfter(channelId, post, offset, numPost, success, error, complete) {
- $.ajax({
- url: '/api/v1/channels/' + channelId + '/post/' + post + '/after/' + offset + '/' + numPost,
- dataType: 'json',
- type: 'GET',
- ifModified: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPostsAfter', xhr, status, err);
- error(e);
- },
- complete: complete
- });
-}
-
-export function getPost(channelId, postId, success, error, complete) {
- $.ajax({
- cache: false,
- url: '/api/v1/channels/' + channelId + '/post/' + postId,
- dataType: 'json',
- type: 'GET',
- ifModified: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPost', xhr, status, err);
- error(e);
- },
- complete
- });
-}
-
-export function getPostById(postId, success, error, complete) {
- $.ajax({
- cache: false,
- url: '/api/v1/posts/' + postId,
- dataType: 'json',
- type: 'GET',
- ifModified: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPostById', xhr, status, err);
- error(e);
- },
- complete
- });
-}
-
-export function search(terms, success, error) {
- $.ajax({
- url: '/api/v1/posts/search',
- dataType: 'json',
- type: 'GET',
- data: {terms: terms},
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('search', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_posts_search');
-}
-
-export function deletePost(channelId, id, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + channelId + '/post/' + id + '/delete',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('deletePost', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_posts_delete');
-}
-
-export function createPost(post, channel, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + post.channel_id + '/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(post),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('createPost', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_posts_create', channel.name, 'length', post.message.length);
-
- // global.window.analytics.track('api_posts_create', {
- // category: 'api',
- // channel_name: channel.name,
- // channel_type: channel.type,
- // length: post.message.length,
- // files: (post.filenames || []).length,
- // mentions: (post.message.match('/<mention>/g') || []).length
- // });
-}
-
-export function updatePost(post, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + post.channel_id + '/update',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(post),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('updatePost', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_posts_update');
-}
-
-export function addChannelMember(id, data, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + id + '/add',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('addChannelMember', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_add_member');
-}
-
-export function removeChannelMember(id, data, success, error) {
- $.ajax({
- url: '/api/v1/channels/' + id + '/remove',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('removeChannelMember', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_channels_remove_member');
-}
-
-export function getProfiles(success, error) {
- $.ajax({
- cache: false,
- url: '/api/v1/users/profiles',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- ifModified: true,
- error: function onError(xhr, status, err) {
- var e = handleError('getProfiles', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getProfilesForTeam(teamId, success, error) {
- $.ajax({
- cache: false,
- url: '/api/v1/users/profiles/' + teamId,
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getProfilesForTeam', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function uploadFile(formData, success, error) {
- var request = $.ajax({
- url: '/api/v1/files/upload',
- type: 'POST',
- data: formData,
- cache: false,
- contentType: false,
- processData: false,
- success,
- error: function onError(xhr, status, err) {
- if (err !== 'abort') {
- var e = handleError('uploadFile', xhr, status, err);
- error(e);
- }
- }
- });
-
- track('api', 'api_files_upload');
-
- return request;
-}
-
-export function getFileInfo(filename, success, error) {
- $.ajax({
- url: '/api/v1/files/get_info' + filename,
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success: (data) => {
- success(data);
- },
- error: function onError(xhr, status, err) {
- var e = handleError('getFileInfo', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getPublicLink(data, success, error) {
- $.ajax({
- url: '/api/v1/files/get_public_link',
- dataType: 'json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getPublicLink', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function uploadProfileImage(imageData, success, error) {
- $.ajax({
- url: '/api/v1/users/newimage',
- type: 'POST',
- data: imageData,
- cache: false,
- contentType: false,
- processData: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('uploadProfileImage', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function importSlack(fileData, success, error) {
- $.ajax({
- url: '/api/v1/teams/import_team',
- type: 'POST',
- data: fileData,
- cache: false,
- contentType: false,
- processData: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('importTeam', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function exportTeam(success, error) {
- $.ajax({
- url: '/api/v1/teams/export_team',
- type: 'GET',
- dataType: 'json',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('exportTeam', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getStatuses(ids, success, error) {
- $.ajax({
- url: '/api/v1/users/status',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(ids),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getStatuses', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getMyTeam(success, error) {
- return $.ajax({
- url: '/api/v1/teams/me',
- dataType: 'json',
- type: 'GET',
- success,
- ifModified: true,
- error: function onError(xhr, status, err) {
- var e = handleError('getMyTeam', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function registerOAuthApp(app, success, error) {
- $.ajax({
- url: '/api/v1/oauth/register',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(app),
- success: success,
- error: (xhr, status, err) => {
- const e = handleError('registerApp', xhr, status, err);
- error(e);
- }
- });
-
- module.exports.track('api', 'api_apps_register');
-}
-
-export function allowOAuth2(responseType, clientId, redirectUri, state, scope, success, error) {
- $.ajax({
- url: '/api/v1/oauth/allow?response_type=' + responseType + '&client_id=' + clientId + '&redirect_uri=' + redirectUri + '&scope=' + scope + '&state=' + state,
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- const e = handleError('allowOAuth2', xhr, status, err);
- error(e);
- }
- });
-
- module.exports.track('api', 'api_users_allow_oauth2');
-}
-
-export function addIncomingHook(hook, success, error) {
- $.ajax({
- url: '/api/v1/hooks/incoming/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(hook),
- success,
- error: (xhr, status, err) => {
- var e = handleError('addIncomingHook', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function deleteIncomingHook(data, success, error) {
- $.ajax({
- url: '/api/v1/hooks/incoming/delete',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: (xhr, status, err) => {
- var e = handleError('deleteIncomingHook', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function listIncomingHooks(success, error) {
- $.ajax({
- url: '/api/v1/hooks/incoming/list',
- dataType: 'json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('listIncomingHooks', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getAllPreferences(success, error) {
- return $.ajax({
- url: '/api/v1/preferences/',
- dataType: 'json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('getAllPreferences', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getPreferenceCategory(category, success, error) {
- $.ajax({
- url: `/api/v1/preferences/${category}`,
- dataType: 'json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('getPreferenceCategory', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function savePreferences(preferences, success, error) {
- $.ajax({
- url: '/api/v1/preferences/save',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(preferences),
- success,
- error: (xhr, status, err) => {
- var e = handleError('savePreferences', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function addOutgoingHook(hook, success, error) {
- $.ajax({
- url: '/api/v1/hooks/outgoing/create',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(hook),
- success,
- error: (xhr, status, err) => {
- var e = handleError('addOutgoingHook', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function deleteOutgoingHook(data, success, error) {
- $.ajax({
- url: '/api/v1/hooks/outgoing/delete',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: (xhr, status, err) => {
- var e = handleError('deleteOutgoingHook', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function listOutgoingHooks(success, error) {
- $.ajax({
- url: '/api/v1/hooks/outgoing/list',
- dataType: 'json',
- type: 'GET',
- success,
- error: (xhr, status, err) => {
- var e = handleError('listOutgoingHooks', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function regenOutgoingHookToken(data, success, error) {
- $.ajax({
- url: '/api/v1/hooks/outgoing/regen_token',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(data),
- success,
- error: (xhr, status, err) => {
- var e = handleError('regenOutgoingHookToken', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function uploadLicenseFile(formData, success, error) {
- $.ajax({
- url: '/api/v1/license/add',
- type: 'POST',
- data: formData,
- cache: false,
- contentType: false,
- processData: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('uploadLicenseFile', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_license_upload');
-}
-
-export function removeLicenseFile(success, error) {
- $.ajax({
- url: '/api/v1/license/remove',
- type: 'POST',
- cache: false,
- contentType: false,
- processData: false,
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('removeLicenseFile', xhr, status, err);
- error(e);
- }
- });
-
- track('api', 'api_license_upload');
-}
-
-export function getClientLicenceConfig(success, error) {
- return $.ajax({
- url: '/api/v1/license/client_config',
- dataType: 'json',
- contentType: 'application/json',
- type: 'GET',
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getClientLicenceConfig', xhr, status, err);
- error(e);
- }
- });
-}
-
-export function getInviteInfo(success, error, id) {
- $.ajax({
- url: '/api/v1/teams/get_invite_info',
- type: 'POST',
- dataType: 'json',
- contentType: 'application/json',
- data: JSON.stringify({invite_id: id}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('getInviteInfo', xhr, status, err);
- if (error) {
- error(e);
- }
- }
- });
-}
-
-export function verifyEmail(success, error, uid, hid) {
- $.ajax({
- url: '/api/v1/users/verify_email',
- type: 'POST',
- contentType: 'application/json',
- dataType: 'text',
- data: JSON.stringify({uid, hid}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('verifyEmail', xhr, status, err);
- if (error) {
- error(e);
- }
- }
- });
-}
-
-export function resendVerification(success, error, teamName, email) {
- $.ajax({
- url: '/api/v1/users/resend_verification',
- type: 'POST',
- contentType: 'application/json',
- dataType: 'text',
- data: JSON.stringify({team_name: teamName, email}),
- success,
- error: function onError(xhr, status, err) {
- var e = handleError('resendVerification', xhr, status, err);
- if (error) {
- error(e);
- }
- }
- });
-}
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
deleted file mode 100644
index 3de562b7b..000000000
--- a/web/react/utils/constants.jsx
+++ /dev/null
@@ -1,520 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import keyMirror from 'keymirror';
-
-export default {
- ActionTypes: keyMirror({
- RECEIVED_ERROR: null,
-
- CLICK_CHANNEL: null,
- CREATE_CHANNEL: null,
- LEAVE_CHANNEL: null,
- CREATE_POST: null,
- POST_DELETED: null,
- REMOVE_POST: null,
-
- RECEIVED_CHANNELS: null,
- RECEIVED_CHANNEL: null,
- RECEIVED_MORE_CHANNELS: null,
- RECEIVED_CHANNEL_EXTRA_INFO: null,
-
- FOCUS_POST: null,
- RECEIVED_POSTS: null,
- RECEIVED_FOCUSED_POST: null,
- RECEIVED_POST: null,
- RECEIVED_EDIT_POST: null,
- RECEIVED_SEARCH: null,
- RECEIVED_SEARCH_TERM: null,
- RECEIVED_POST_SELECTED: null,
- RECEIVED_MENTION_DATA: null,
- RECEIVED_ADD_MENTION: null,
-
- RECEIVED_PROFILES: null,
- RECEIVED_ME: null,
- RECEIVED_SESSIONS: null,
- RECEIVED_AUDITS: null,
- RECEIVED_TEAMS: null,
- RECEIVED_STATUSES: null,
- RECEIVED_PREFERENCE: null,
- RECEIVED_PREFERENCES: null,
- RECEIVED_FILE_INFO: null,
-
- RECEIVED_MSG: null,
-
- RECEIVED_MY_TEAM: null,
-
- RECEIVED_CONFIG: null,
- RECEIVED_LOGS: null,
- RECEIVED_SERVER_AUDITS: null,
- RECEIVED_ALL_TEAMS: null,
-
- RECEIVED_LOCALE: null,
-
- SHOW_SEARCH: null,
-
- TOGGLE_IMPORT_THEME_MODAL: null,
- TOGGLE_INVITE_MEMBER_MODAL: null,
- TOGGLE_DELETE_POST_MODAL: null,
- TOGGLE_GET_POST_LINK_MODAL: null,
- TOGGLE_GET_TEAM_INVITE_LINK_MODAL: null,
- TOGGLE_REGISTER_APP_MODAL: null,
-
- SUGGESTION_PRETEXT_CHANGED: null,
- SUGGESTION_RECEIVED_SUGGESTIONS: null,
- SUGGESTION_CLEAR_SUGGESTIONS: null,
- SUGGESTION_COMPLETE_WORD: null,
- SUGGESTION_SELECT_NEXT: null,
- SUGGESTION_SELECT_PREVIOUS: null
- }),
-
- PayloadSources: keyMirror({
- SERVER_ACTION: null,
- VIEW_ACTION: null
- }),
-
- StatTypes: keyMirror({
- TOTAL_USERS: null,
- TOTAL_PUBLIC_CHANNELS: null,
- TOTAL_PRIVATE_GROUPS: null,
- TOTAL_POSTS: null,
- TOTAL_TEAMS: null,
- TOTAL_FILE_POSTS: null,
- TOTAL_HASHTAG_POSTS: null,
- TOTAL_IHOOKS: null,
- TOTAL_OHOOKS: null,
- TOTAL_COMMANDS: null,
- TOTAL_SESSIONS: null,
- POST_PER_DAY: null,
- USERS_WITH_POSTS_PER_DAY: null,
- RECENTLY_ACTIVE_USERS: null,
- NEWLY_CREATED_USERS: null
- }),
- STAT_MAX_ACTIVE_USERS: 20,
- STAT_MAX_NEW_USERS: 20,
-
- SocketEvents: {
- POSTED: 'posted',
- POST_EDITED: 'post_edited',
- POST_DELETED: 'post_deleted',
- CHANNEL_VIEWED: 'channel_viewed',
- NEW_USER: 'new_user',
- USER_ADDED: 'user_added',
- USER_REMOVED: 'user_removed',
- TYPING: 'typing',
- PREFERENCE_CHANGED: 'preference_changed',
- EPHEMERAL_MESSAGE: 'ephemeral_message'
- },
-
- //SPECIAL_MENTIONS: ['all', 'channel'],
- SPECIAL_MENTIONS: ['channel'],
- CHARACTER_LIMIT: 4000,
- IMAGE_TYPES: ['jpg', 'gif', 'bmp', 'png', 'jpeg'],
- AUDIO_TYPES: ['mp3', 'wav', 'wma', 'm4a', 'flac', 'aac', 'ogg'],
- VIDEO_TYPES: ['mp4', 'avi', 'webm', 'mkv', 'wmv', 'mpg', 'mov', 'flv'],
- PRESENTATION_TYPES: ['ppt', 'pptx'],
- SPREADSHEET_TYPES: ['xlsx', 'csv'],
- WORD_TYPES: ['doc', 'docx'],
- CODE_TYPES: ['css', 'html', 'js', 'php', 'rb'],
- PDF_TYPES: ['pdf'],
- PATCH_TYPES: ['patch'],
- ICON_FROM_TYPE: {
- audio: 'audio',
- video: 'video',
- spreadsheet: 'excel',
- presentation: 'ppt',
- pdf: 'pdf',
- code: 'code',
- word: 'word',
- patch: 'patch',
- other: 'generic'
- },
- MAX_DISPLAY_FILES: 5,
- MAX_UPLOAD_FILES: 5,
- MAX_FILE_SIZE: 50000000, // 50 MB
- THUMBNAIL_WIDTH: 128,
- THUMBNAIL_HEIGHT: 100,
- WEB_VIDEO_WIDTH: 640,
- WEB_VIDEO_HEIGHT: 480,
- MOBILE_VIDEO_WIDTH: 480,
- MOBILE_VIDEO_HEIGHT: 360,
- DEFAULT_CHANNEL: 'town-square',
- OFFTOPIC_CHANNEL: 'off-topic',
- GITLAB_SERVICE: 'gitlab',
- GOOGLE_SERVICE: 'google',
- EMAIL_SERVICE: 'email',
- SIGNIN_CHANGE: 'signin_change',
- SIGNIN_VERIFIED: 'verified',
- SESSION_EXPIRED: 'expired',
- POST_CHUNK_SIZE: 60,
- MAX_POST_CHUNKS: 3,
- POST_FOCUS_CONTEXT_RADIUS: 10,
- POST_LOADING: 'loading',
- POST_FAILED: 'failed',
- POST_DELETED: 'deleted',
- POST_TYPE_EPHEMERAL: 'system_ephemeral',
- POST_TYPE_JOIN_LEAVE: 'system_join_leave',
- SYSTEM_MESSAGE_PREFIX: 'system_',
- SYSTEM_MESSAGE_PROFILE_NAME: 'System',
- SYSTEM_MESSAGE_PROFILE_IMAGE: '/static/images/logo_compact.png',
- RESERVED_TEAM_NAMES: [
- 'www',
- 'web',
- 'admin',
- 'support',
- 'notify',
- 'test',
- 'demo',
- 'mail',
- 'team',
- 'channel',
- 'internal',
- 'localhost',
- 'dockerhost',
- 'stag',
- 'post',
- 'cluster',
- 'api'
- ],
- RESERVED_USERNAMES: [
- 'valet',
- 'all',
- 'channel'
- ],
- MONTHS: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- MAX_DMS: 20,
- MAX_CHANNEL_POPOVER_COUNT: 100,
- DM_CHANNEL: 'D',
- OPEN_CHANNEL: 'O',
- PRIVATE_CHANNEL: 'P',
- INVITE_TEAM: 'I',
- OPEN_TEAM: 'O',
- MAX_POST_LEN: 4000,
- EMOJI_SIZE: 16,
- ONLINE_ICON_SVG: "<svg version='1.1'id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' 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:cc='http://creativecommons.org/ns#' inkscape:version='0.48.4 r9939' sodipodi:docname='TRASH_1_4.svg'xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='-243 245 12 12'style='enable-background:new -243 245 12 12;' xml:space='preserve'> <sodipodi:namedview inkscape:cx='26.358185' inkscape:zoom='1.18' bordercolor='#666666' pagecolor='#ffffff' borderopacity='1' objecttolerance='10' inkscape:cy='139.7898' gridtolerance='10' guidetolerance='10' showgrid='false' showguides='true' id='namedview6' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:guide-bbox='true' inkscape:window-width='1366' inkscape:current-layer='Layer_1' inkscape:window-height='705' inkscape:window-y='-8' inkscape:window-maximized='1' inkscape:window-x='-8'> <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> <path class='online--icon' d='M-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5z'/> <ellipse class='online--icon' cx='-238.5' cy='248' rx='2.5' ry='2.5'/> </g> <path class='online--icon' d='M-238.9,253.8c0-0.4,0.1-0.9,0.2-1.3c-2.2-0.2-2.2-2-2.2-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5c0,0.1-0.1,0.5,0,0.6 c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0C-238.7,255.7-238.9,254.8-238.9,253.8z'/> <g> <g> <path class='online--icon' d='M-232.3,250.1l1.3,1.3c0,0,0,0.1,0,0.1l-4.1,4.1c0,0,0,0-0.1,0c0,0,0,0,0,0l-2.7-2.7c0,0,0-0.1,0-0.1l1.2-1.2 c0,0,0.1,0,0.1,0l1.4,1.4l2.9-2.9C-232.4,250.1-232.3,250.1-232.3,250.1z'/> </g> </g> </svg>",
- AWAY_ICON_SVG: "<svg version='1.1'id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' 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:cc='http://creativecommons.org/ns#' inkscape:version='0.48.4 r9939' sodipodi:docname='TRASH_1_4.svg'xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='-299 391 12 12'style='enable-background:new -299 391 12 12;' xml:space='preserve'> <sodipodi:namedview inkscape:cx='26.358185' inkscape:zoom='1.18' bordercolor='#666666' pagecolor='#ffffff' borderopacity='1' objecttolerance='10' inkscape:cy='139.7898' gridtolerance='10' guidetolerance='10' showgrid='false' showguides='true' id='namedview6' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:guide-bbox='true' inkscape:window-width='1366' inkscape:current-layer='Layer_1' inkscape:window-height='705' inkscape:window-y='-8' inkscape:window-maximized='1' inkscape:window-x='-8'> <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> <ellipse class='away--icon' cx='-294.6' cy='394' rx='2.5' ry='2.5'/> <path class='away--icon' d='M-293.8,399.4c0-0.4,0.1-0.7,0.2-1c-0.3,0.1-0.6,0.2-1,0.2c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0.7,0,1.4-0.1,2-0.3 C-293.3,401.5-293.8,400.5-293.8,399.4z'/> </g> <path class='away--icon' d='M-287,400c0,0.1-0.1,0.1-0.1,0.1l-4.9,0c-0.1,0-0.1-0.1-0.1-0.1v-1.6c0-0.1,0.1-0.1,0.1-0.1l4.9,0c0.1,0,0.1,0.1,0.1,0.1 V400z'/> </svg>",
- OFFLINE_ICON_SVG: "<svg version='1.1'id='Layer_1' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' 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:cc='http://creativecommons.org/ns#' inkscape:version='0.48.4 r9939' sodipodi:docname='TRASH_1_4.svg'xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='-299 391 12 12'style='enable-background:new -299 391 12 12;' xml:space='preserve'> <sodipodi:namedview inkscape:cx='26.358185' inkscape:zoom='1.18' bordercolor='#666666' pagecolor='#ffffff' borderopacity='1' objecttolerance='10' inkscape:cy='139.7898' gridtolerance='10' guidetolerance='10' showgrid='false' showguides='true' id='namedview6' inkscape:pageopacity='0' inkscape:pageshadow='2' inkscape:guide-bbox='true' inkscape:window-width='1366' inkscape:current-layer='Layer_1' inkscape:window-height='705' inkscape:window-y='-8' inkscape:window-maximized='1' inkscape:window-x='-8'> <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> <ellipse class='offline--icon' cx='-294.5' cy='394' rx='2.5' ry='2.5'/> <path class='offline--icon' d='M-294.3,399.7c0-0.4,0.1-0.8,0.2-1.2c-0.1,0-0.2,0-0.4,0c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4h0.1h0.1c0.3,0,0.7,0,1-0.1C-293.9,401.6-294.3,400.7-294.3,399.7z'/> </g> </g> <g> <path class='offline--icon' d='M-288.9,399.4l1.8-1.8c0.1-0.1,0.1-0.3,0-0.3l-0.7-0.7c-0.1-0.1-0.3-0.1-0.3,0l-1.8,1.8l-1.8-1.8c-0.1-0.1-0.3-0.1-0.3,0 l-0.7,0.7c-0.1,0.1-0.1,0.3,0,0.3l1.8,1.8l-1.8,1.8c-0.1,0.1-0.1,0.3,0,0.3l0.7,0.7c0.1,0.1,0.3,0.1,0.3,0l1.8-1.8l1.8,1.8 c0.1,0.1,0.3,0.1,0.3,0l0.7-0.7c0.1-0.1,0.1-0.3,0-0.3L-288.9,399.4z'/> </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>",
- REPLY_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'viewBox='-158 242 18 18' style='enable-background:new -158 242 18 18;' xml:space='preserve'> <path d='M-142.2,252.6c-2-3-4.8-4.7-8.3-4.8v-3.3c0-0.2-0.1-0.3-0.2-0.3s-0.3,0-0.4,0.1l-6.9,6.2c-0.1,0.1-0.1,0.2-0.1,0.3 c0,0.1,0,0.2,0.1,0.3l6.9,6.4c0.1,0.1,0.3,0.1,0.4,0.1c0.1-0.1,0.2-0.2,0.2-0.4v-3.8c4.2,0,7.4,0.4,9.6,4.4c0.1,0.1,0.2,0.2,0.3,0.2 c0,0,0.1,0,0.1,0c0.2-0.1,0.3-0.3,0.2-0.4C-140.2,257.3-140.6,255-142.2,252.6z M-150.8,252.5c-0.2,0-0.4,0.2-0.4,0.4v3.3l-6-5.5 l6-5.3v2.8c0,0.2,0.2,0.4,0.4,0.4c3.3,0,6,1.5,8,4.5c0.5,0.8,0.9,1.6,1.2,2.3C-144,252.8-147.1,252.5-150.8,252.5z'/> </svg>",
- SCROLL_BOTTOM_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'viewBox='-239 239 21 23' style='enable-background:new -239 239 21 23;' xml:space='preserve'> <path d='M-239,241.4l2.4-2.4l8.1,8.2l8.1-8.2l2.4,2.4l-10.5,10.6L-239,241.4z M-228.5,257.2l8.1-8.2l2.4,2.4l-10.5,10.6l-10.5-10.6 l2.4-2.4L-228.5,257.2z'/> </svg>",
- UPDATE_TYPING_MS: 5000,
- THEMES: {
- default: {
- type: 'Organization',
- sidebarBg: '#2071a7',
- sidebarText: '#fff',
- sidebarUnreadText: '#fff',
- sidebarTextHoverBg: '#136197',
- sidebarTextActiveBorder: '#7AB0D6',
- sidebarTextActiveColor: '#FFFFFF',
- sidebarHeaderBg: '#2f81b7',
- sidebarHeaderTextColor: '#FFFFFF',
- onlineIndicator: '#7DBE00',
- awayIndicator: '#DCBD4E',
- mentionBj: '#FBFBFB',
- mentionColor: '#2071A7',
- centerChannelBg: '#f2f4f8',
- centerChannelColor: '#333333',
- newMessageSeparator: '#FF8800',
- linkColor: '#2f81b7',
- buttonBg: '#1dacfc',
- buttonColor: '#FFFFFF',
- mentionHighlightBg: '#fff2bb',
- mentionHighlightLink: '#2f81b7',
- codeTheme: 'github'
- },
- mattermost: {
- type: 'Mattermost',
- sidebarBg: '#fafafa',
- sidebarText: '#333333',
- sidebarUnreadText: '#333333',
- sidebarTextHoverBg: '#e6f2fa',
- sidebarTextActiveBorder: '#378FD2',
- sidebarTextActiveColor: '#111111',
- sidebarHeaderBg: '#2389d7',
- sidebarHeaderTextColor: '#ffffff',
- onlineIndicator: '#7DBE00',
- awayIndicator: '#DCBD4E',
- mentionBj: '#2389d7',
- mentionColor: '#ffffff',
- centerChannelBg: '#ffffff',
- centerChannelColor: '#333333',
- newMessageSeparator: '#FF8800',
- linkColor: '#2389d7',
- buttonBg: '#2389d7',
- buttonColor: '#FFFFFF',
- mentionHighlightBg: '#fff2bb',
- mentionHighlightLink: '#2f81b7',
- codeTheme: 'github'
- },
- mattermostDark: {
- type: 'Mattermost Dark',
- sidebarBg: '#1B2C3E',
- sidebarText: '#fff',
- sidebarUnreadText: '#fff',
- sidebarTextHoverBg: '#4A5664',
- sidebarTextActiveBorder: '#39769C',
- sidebarTextActiveColor: '#FFFFFF',
- sidebarHeaderBg: '#1B2C3E',
- sidebarHeaderTextColor: '#FFFFFF',
- onlineIndicator: '#55C5B2',
- awayIndicator: '#A9A14C',
- mentionBj: '#B74A4A',
- mentionColor: '#FFFFFF',
- centerChannelBg: '#2F3E4E',
- centerChannelColor: '#DDDDDD',
- newMessageSeparator: '#5de5da',
- linkColor: '#A4FFEB',
- buttonBg: '#4CBBA4',
- buttonColor: '#FFFFFF',
- mentionHighlightBg: '#984063',
- mentionHighlightLink: '#A4FFEB',
- codeTheme: 'solarized-dark'
- },
- windows10: {
- type: 'Windows Dark',
- sidebarBg: '#171717',
- sidebarText: '#fff',
- sidebarUnreadText: '#fff',
- sidebarTextHoverBg: '#302e30',
- sidebarTextActiveBorder: '#196CAF',
- sidebarTextActiveColor: '#FFFFFF',
- sidebarHeaderBg: '#1f1f1f',
- sidebarHeaderTextColor: '#FFFFFF',
- onlineIndicator: '#0177e7',
- awayIndicator: '#A9A14C',
- mentionBj: '#0177e7',
- mentionColor: '#FFFFFF',
- centerChannelBg: '#1F1F1F',
- centerChannelColor: '#DDDDDD',
- newMessageSeparator: '#CC992D',
- linkColor: '#0D93FF',
- buttonBg: '#0177e7',
- buttonColor: '#FFFFFF',
- mentionHighlightBg: '#784098',
- mentionHighlightLink: '#A4FFEB',
- codeTheme: 'monokai'
- }
- },
- THEME_ELEMENTS: [
- {
- group: 'sidebarElements',
- id: 'sidebarBg',
- uiName: 'Sidebar BG'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarText',
- uiName: 'Sidebar Text'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarHeaderBg',
- uiName: 'Sidebar Header BG'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarHeaderTextColor',
- uiName: 'Sidebar Header Text'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarUnreadText',
- uiName: 'Sidebar Unread Text'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarTextHoverBg',
- uiName: 'Sidebar Text Hover BG'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarTextActiveBorder',
- uiName: 'Sidebar Text Active Border'
- },
- {
- group: 'sidebarElements',
- id: 'sidebarTextActiveColor',
- uiName: 'Sidebar Text Active Color'
- },
- {
- group: 'sidebarElements',
- id: 'onlineIndicator',
- uiName: 'Online Indicator'
- },
- {
- group: 'sidebarElements',
- id: 'awayIndicator',
- uiName: 'Away Indicator'
- },
- {
- group: 'sidebarElements',
- id: 'mentionBj',
- uiName: 'Mention Jewel BG'
- },
- {
- group: 'sidebarElements',
- id: 'mentionColor',
- uiName: 'Mention Jewel Text'
- },
- {
- group: 'centerChannelElements',
- id: 'centerChannelBg',
- uiName: 'Center Channel BG'
- },
- {
- group: 'centerChannelElements',
- id: 'centerChannelColor',
- uiName: 'Center Channel Text'
- },
- {
- group: 'centerChannelElements',
- id: 'newMessageSeparator',
- uiName: 'New Message Separator'
- },
- {
- group: 'centerChannelElements',
- id: 'mentionHighlightBg',
- uiName: 'Mention Highlight BG'
- },
- {
- group: 'centerChannelElements',
- id: 'mentionHighlightLink',
- uiName: 'Mention Highlight Link'
- },
- {
- group: 'centerChannelElements',
- id: 'codeTheme',
- uiName: 'Code Theme',
- themes: [
- {
- id: 'solarized-dark',
- uiName: 'Solarized Dark'
- },
- {
- id: 'solarized-light',
- uiName: 'Solarized Light'
- },
- {
- id: 'github',
- uiName: 'GitHub'
- },
- {
- id: 'monokai',
- uiName: 'Monokai'
- }
- ]
- },
- {
- group: 'linkAndButtonElements',
- id: 'linkColor',
- uiName: 'Link Color'
- },
- {
- group: 'linkAndButtonElements',
- id: 'buttonBg',
- uiName: 'Button BG'
- },
- {
- group: 'linkAndButtonElements',
- id: 'buttonColor',
- uiName: 'Button Text'
- }
- ],
- DEFAULT_CODE_THEME: 'github',
- FONTS: {
- 'Droid Serif': 'font--droid_serif',
- 'Roboto Slab': 'font--roboto_slab',
- Lora: 'font--lora',
- Arvo: 'font--arvo',
- 'Open Sans': 'font--open_sans',
- Roboto: 'font--roboto',
- 'PT Sans': 'font--pt_sans',
- Lato: 'font--lato',
- 'Source Sans Pro': 'font--source_sans_pro',
- 'Exo 2': 'font--exo_2',
- Ubuntu: 'font--ubuntu'
- },
- DEFAULT_FONT: 'Open Sans',
- Preferences: {
- CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show',
- CATEGORY_DISPLAY_SETTINGS: 'display_settings',
- DISPLAY_PREFER_NICKNAME: 'nickname_full_name',
- DISPLAY_PREFER_FULL_NAME: 'full_name',
- CATEGORY_ADVANCED_SETTINGS: 'advanced_settings',
- TUTORIAL_STEP: 'tutorial_step'
- },
- TutorialSteps: {
- INTRO_SCREENS: 0,
- POST_POPOVER: 1,
- CHANNEL_POPOVER: 2,
- MENU_POPOVER: 3
- },
- KeyCodes: {
- UP: 38,
- DOWN: 40,
- LEFT: 37,
- RIGHT: 39,
- BACKSPACE: 8,
- ENTER: 13,
- ESCAPE: 27,
- SPACE: 32,
- TAB: 9
- },
- HighlightedLanguages: {
- diff: 'Diff',
- apache: 'Apache',
- makefile: 'Makefile',
- http: 'HTTP',
- json: 'JSON',
- markdown: 'Markdown',
- javascript: 'JavaScript',
- css: 'CSS',
- nginx: 'nginx',
- objectivec: 'Objective-C',
- python: 'Python',
- xml: 'XML',
- perl: 'Perl',
- bash: 'Bash',
- php: 'PHP',
- coffeescript: 'CoffeeScript',
- cs: 'C#',
- cpp: 'C++',
- sql: 'SQL',
- go: 'Go',
- ruby: 'Ruby',
- java: 'Java',
- ini: 'ini'
- },
- PostsViewJumpTypes: {
- BOTTOM: 1,
- POST: 2,
- SIDEBAR_OPEN: 3
- },
- NotificationPrefs: {
- MENTION: 'mention'
- },
- FeatureTogglePrefix: 'feature_enabled_',
- PRE_RELEASE_FEATURES: {
- MARKDOWN_PREVIEW: {
- label: 'markdown_preview', // github issue: https://github.com/mattermost/platform/pull/1389
- description: 'Show markdown preview option in message input box'
- },
- EMBED_PREVIEW: {
- label: 'embed_preview',
- description: 'Show preview snippet of links below message'
- },
- EMBED_TOGGLE: {
- label: 'embed_toggle',
- description: 'Show toggle for all embed previews'
- }
- },
- OVERLAY_TIME_DELAY: 400,
- MIN_USERNAME_LENGTH: 3,
- MAX_USERNAME_LENGTH: 64,
- MIN_PASSWORD_LENGTH: 5,
- MAX_PASSWORD_LENGTH: 50,
- TIME_SINCE_UPDATE_INTERVAL: 30000,
- MIN_HASHTAG_LINK_LENGTH: 3
-};
diff --git a/web/react/utils/delayed_action.jsx b/web/react/utils/delayed_action.jsx
deleted file mode 100644
index 4f6239ad0..000000000
--- a/web/react/utils/delayed_action.jsx
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-export default class DelayedAction {
- constructor(action) {
- this.action = action;
-
- this.timer = -1;
-
- // bind fire since it doesn't get passed the correct this value with setTimeout
- this.fire = this.fire.bind(this);
- }
-
- fire() {
- this.action();
-
- this.timer = -1;
- }
-
- fireAfter(timeout) {
- if (this.timer >= 0) {
- window.clearTimeout(this.timer);
- }
-
- this.timer = window.setTimeout(this.fire, timeout);
- }
-}
diff --git a/web/react/utils/emoticons.jsx b/web/react/utils/emoticons.jsx
deleted file mode 100644
index bed798b3e..000000000
--- a/web/react/utils/emoticons.jsx
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-const emoticonPatterns = {
- slightly_smiling_face: /(^|\s)(:-?\))(?=$|\s)/g, // :)
- wink: /(^|\s)(;-?\))(?=$|\s)/g, // ;)
- open_mouth: /(^|\s)(:o)(?=$|\s)/gi, // :o
- scream: /(^|\s)(:-o)(?=$|\s)/gi, // :-o
- smirk: /(^|\s)(:-?])(?=$|\s)/g, // :]
- smile: /(^|\s)(:-?d)(?=$|\s)/gi, // :D
- stuck_out_tongue_closed_eyes: /(^|\s)(x-d)(?=$|\s)/gi, // x-d
- stuck_out_tongue: /(^|\s)(:-?p)(?=$|\s)/gi, // :p
- rage: /(^|\s)(:-?[\[@])(?=$|\s)/g, // :@
- slightly_frowning_face: /(^|\s)(:-?\()(?=$|\s)/g, // :(
- cry: /(^|\s)(:['ā€™]-?\(|:&#x27;\(|:&#39;\()(?=$|\s)/g, // :`(
- confused: /(^|\s)(:-?\/)(?=$|\s)/g, // :/
- confounded: /(^|\s)(:-?s)(?=$|\s)/gi, // :s
- neutral_face: /(^|\s)(:-?\|)(?=$|\s)/g, // :|
- flushed: /(^|\s)(:-?\$)(?=$|\s)/g, // :$
- mask: /(^|\s)(:-x)(?=$|\s)/gi, // :-x
- heart: /(^|\s)(<3|&lt;3)(?=$|\s)/g, // <3
- broken_heart: /(^|\s)(<\/3|&lt;&#x2F;3)(?=$|\s)/g, // </3
- thumbsup: /(^|\s)(:\+1:)(?=$|\s)/g, // :+1:
- thumbsdown: /(^|\s)(:\-1:)(?=$|\s)/g // :-1:
-};
-
-function initializeEmoticonMap() {
- const emoticonNames =
- ('+1,-1,100,1234,8ball,a,ab,abc,abcd,accept,aerial_tramway,airplane,alarm_clock,alien,ambulance,anchor,angel,' +
- 'anger,angry,anguished,ant,apple,aquarius,aries,arrow_backward,arrow_double_down,arrow_double_up,arrow_down,' +
- 'arrow_down_small,arrow_forward,arrow_heading_down,arrow_heading_up,arrow_left,arrow_lower_left,' +
- 'arrow_lower_right,arrow_right,arrow_right_hook,arrow_up,arrow_up_down,arrow_up_small,arrow_upper_left,' +
- 'arrow_upper_right,arrows_clockwise,arrows_counterclockwise,art,articulated_lorry,astonished,atm,b,baby,' +
- 'baby_bottle,baby_chick,baby_symbol,back,baggage_claim,balloon,ballot_box_with_check,bamboo,banana,bangbang,' +
- 'bank,bar_chart,barber,baseball,basketball,bath,bathtub,battery,bear,bee,beer,beers,beetle,beginner,bell,bento,' +
- 'bicyclist,bike,bikini,bird,birthday,black_circle,black_joker,black_medium_small_square,black_medium_square,' +
- 'black_large_square,black_nib,black_small_square,black_square,black_square_button,blossom,blowfish,blue_book,' +
- 'blue_car,blue_heart,blush,boar,boat,bomb,book,bookmark,bookmark_tabs,books,boom,boot,bouquet,bow,bowling,bowtie,' +
- 'boy,bread,bride_with_veil,bridge_at_night,briefcase,broken_heart,bug,bulb,bullettrain_front,bullettrain_side,bus,' +
- 'busstop,bust_in_silhouette,busts_in_silhouette,cactus,cake,calendar,calling,camel,camera,cancer,candy,capital_abcd,' +
- 'capricorn,car,card_index,carousel_horse,cat,cat2,cd,chart,chart_with_downwards_trend,chart_with_upwards_trend,' +
- 'checkered_flag,cherries,cherry_blossom,chestnut,chicken,children_crossing,chocolate_bar,christmas_tree,church,' +
- 'cinema,circus_tent,city_sunrise,city_sunset,cl,clap,clapper,clipboard,clock1,clock10,clock1030,clock11,' +
- 'clock1130,clock12,clock1230,clock130,clock2,clock230,clock3,clock330,clock4,clock430,clock5,clock530,clock6,' +
- 'clock630,clock7,clock730,clock8,clock830,clock9,clock930,closed_book,closed_lock_with_key,closed_umbrella,cloud,' +
- 'clubs,cn,cocktail,coffee,cold_sweat,collision,computer,confetti_ball,confounded,confused,congratulations,' +
- 'construction,construction_worker,convenience_store,cookie,cool,cop,copyright,corn,couple,couple_with_heart,' +
- 'couplekiss,cow,cow2,credit_card,crescent_moon,crocodile,crossed_flags,crown,cry,crying_cat_face,crystal_ball,' +
- 'cupid,curly_loop,currency_exchange,curry,custard,customs,cyclone,dancer,dancers,dango,dart,dash,date,de,' +
- 'deciduous_tree,department_store,diamond_shape_with_a_dot_inside,diamonds,disappointed,disappointed_relieved,' +
- 'dizzy,dizzy_face,do_not_litter,dog,dog2,dollar,dolls,dolphin,donut,door,doughnut,dragon,dragon_face,dress,' +
- 'dromedary_camel,droplet,dvd,e-mail,ear,ear_of_rice,earth_africa,earth_americas,earth_asia,egg,eggplant,eight,' +
- 'eight_pointed_black_star,eight_spoked_asterisk,electric_plug,elephant,email,end,envelope,es,euro,' +
- 'european_castle,european_post_office,evergreen_tree,exclamation,expressionless,eyeglasses,eyes,facepunch,' +
- 'factory,fallen_leaf,family,fast_forward,fax,fearful,feelsgood,feet,ferris_wheel,file_folder,finnadie,fire,' +
- 'fire_engine,fireworks,first_quarter_moon,first_quarter_moon_with_face,fish,fish_cake,fishing_pole_and_fish,fist,' +
- 'five,flags,flashlight,floppy_disk,flower_playing_cards,flushed,foggy,football,fork_and_knife,fountain,four,' +
- 'four_leaf_clover,fr,free,fried_shrimp,fries,frog,frowning,fu,fuelpump,full_moon,full_moon_with_face,game_die,gb,' +
- 'gem,gemini,ghost,gift,gift_heart,girl,globe_with_meridians,goat,goberserk,godmode,golf,grapes,green_apple,' +
- 'green_book,green_heart,grey_exclamation,grey_question,grimacing,grin,grinning,guardsman,guitar,gun,haircut,' +
- 'hamburger,hammer,hamster,hand,handbag,hankey,hash,hatched_chick,hatching_chick,headphones,hear_no_evil,heart,' +
- 'heart_decoration,heart_eyes,heart_eyes_cat,heartbeat,heartpulse,hearts,heavy_check_mark,heavy_division_sign,' +
- 'heavy_dollar_sign,heavy_exclamation_mark,heavy_minus_sign,heavy_multiplication_x,heavy_plus_sign,helicopter,' +
- 'herb,hibiscus,high_brightness,high_heel,hocho,honey_pot,honeybee,horse,horse_racing,hospital,hotel,hotsprings,' +
- 'hourglass,hourglass_flowing_sand,house,house_with_garden,hurtrealbad,hushed,ice_cream,icecream,id,' +
- 'ideograph_advantage,imp,inbox_tray,incoming_envelope,information_desk_person,information_source,innocent,' +
- 'interrobang,iphone,it,izakaya_lantern,jack_o_lantern,japan,japanese_castle,japanese_goblin,japanese_ogre,jeans,' +
- 'joy,joy_cat,jp,key,keycap_ten,kimono,kiss,kissing,kissing_cat,kissing_closed_eyes,kissing_face,kissing_heart,' +
- 'kissing_smiling_eyes,koala,koko,kr,large_blue_circle,large_blue_diamond,large_orange_diamond,last_quarter_moon,' +
- 'last_quarter_moon_with_face,laughing,leaves,ledger,left_luggage,left_right_arrow,leftwards_arrow_with_hook,' +
- 'lemon,leo,leopard,libra,light_rail,link,lips,lipstick,lock,lock_with_ink_pen,lollipop,loop,loudspeaker,' +
- 'love_hotel,love_letter,low_brightness,m,mag,mag_right,mahjong,mailbox,mailbox_closed,mailbox_with_mail,' +
- 'mailbox_with_no_mail,man,man_with_gua_pi_mao,man_with_turban,mans_shoe,maple_leaf,mask,massage,meat_on_bone,' +
- 'mega,melon,memo,mens,metal,metro,microphone,microscope,milky_way,minibus,minidisc,mobile_phone_off,' +
- 'money_with_wings,moneybag,monkey,monkey_face,monorail,mortar_board,mount_fuji,mountain_bicyclist,' +
- 'mountain_cableway,mountain_railway,mouse,mouse2,movie_camera,moyai,muscle,mushroom,musical_keyboard,' +
- 'musical_note,musical_score,mute,nail_care,name_badge,neckbeard,necktie,negative_squared_cross_mark,' +
- 'neutral_face,new,new_moon,new_moon_with_face,newspaper,ng,nine,no_bell,no_bicycles,no_entry,no_entry_sign,' +
- 'no_good,no_mobile_phones,no_mouth,no_pedestrians,no_smoking,non-potable_water,nose,notebook,' +
- 'notebook_with_decorative_cover,notes,nut_and_bolt,o,o2,ocean,octocat,octopus,oden,office,ok,ok_hand,' +
- 'ok_woman,older_man,older_woman,on,oncoming_automobile,oncoming_bus,oncoming_police_car,oncoming_taxi,one,' +
- 'open_file_folder,open_hands,open_mouth,ophiuchus,orange_book,outbox_tray,ox,package,page_facing_up,' +
- 'page_with_curl,pager,palm_tree,panda_face,paperclip,parking,part_alternation_mark,partly_sunny,' +
- 'passport_control,paw_prints,peach,pear,pencil,pencil2,penguin,pensive,performing_arts,persevere,' +
- 'person_frowning,person_with_blond_hair,person_with_pouting_face,phone,pig,pig2,pig_nose,pill,pineapple,pisces,' +
- 'pizza,plus1,point_down,point_left,point_right,point_up,point_up_2,police_car,poodle,poop,post_office,' +
- 'postal_horn,postbox,potable_water,pouch,poultry_leg,pound,pouting_cat,pray,princess,punch,purple_heart,purse,' +
- 'pushpin,put_litter_in_its_place,question,rabbit,rabbit2,racehorse,radio,radio_button,rage,rage1,rage2,rage3,' +
- 'rage4,railway_car,rainbow,raised_hand,raised_hands,raising_hand,ram,ramen,rat,recycle,red_car,red_circle,' +
- 'registered,relaxed,relieved,repeat,repeat_one,restroom,revolving_hearts,rewind,ribbon,rice,rice_ball,' +
- 'rice_cracker,rice_scene,ring,rocket,roller_coaster,rooster,rose,rotating_light,round_pushpin,rowboat,ru,' +
- 'rugby_football,runner,running,running_shirt_with_sash,sa,sagittarius,sailboat,sake,sandal,santa,satellite,' +
- 'satisfied,saxophone,school,school_satchel,scissors,scorpius,scream,scream_cat,scroll,seat,secret,see_no_evil,' +
- 'seedling,seven,shaved_ice,sheep,shell,ship,shipit,shirt,shit,shoe,shower,signal_strength,six,six_pointed_star,' +
- 'ski,skull,sleeping,sleepy,slightly_smiling_face,slightly_frowning_face,slot_machine,small_blue_diamond,' +
- 'small_orange_diamond,small_red_triangle,small_red_triangle_down,smile,smile_cat,smiley,smiley_cat,smiling_imp,' +
- 'smirk,smirk_cat,smoking,snail,snake,snowboarder,snowflake,snowman,sob,soccer,soon,sos,sound,space_invader,spades,' +
- 'spaghetti,sparkle,sparkler,sparkles,sparkling_heart,speak_no_evil,speaker,speech_balloon,speedboat,squirrel,star,' +
- 'star2,stars,station,statue_of_liberty,steam_locomotive,stew,straight_ruler,strawberry,stuck_out_tongue,' +
- 'stuck_out_tongue_closed_eyes,stuck_out_tongue_winking_eye,sun_with_face,sunflower,sunglasses,sunny,sunrise,' +
- 'sunrise_over_mountains,surfer,sushi,suspect,suspension_railway,sweat,sweat_drops,sweat_smile,sweet_potato,swimmer,' +
- 'symbols,syringe,tada,tanabata_tree,tangerine,taurus,taxi,tea,telephone,telephone_receiver,telescope,tennis,tent,' +
- 'thought_balloon,three,thumbsdown,thumbsup,ticket,tiger,tiger2,tired_face,tm,toilet,tokyo_tower,tomato,tongue,top,' +
- 'tophat,tractor,traffic_light,train,train2,tram,triangular_flag_on_post,triangular_ruler,trident,triumph,trolleybus,' +
- 'trollface,trophy,tropical_drink,tropical_fish,truck,trumpet,tshirt,tulip,turtle,tv,twisted_rightwards_arrows,' +
- 'two,two_hearts,two_men_holding_hands,two_women_holding_hands,u5272,u5408,u55b6,u6307,u6708,u6709,u6e80,u7121,' +
- 'u7533,u7981,u7a7a,uk,umbrella,unamused,underage,unlock,up,us,v,vertical_traffic_light,vhs,vibration_mode,' +
- 'video_camera,video_game,violin,virgo,volcano,vs,walking,waning_crescent_moon,waning_gibbous_moon,warning,watch,' +
- 'water_buffalo,watermelon,wave,wavy_dash,waxing_crescent_moon,waxing_gibbous_moon,wc,weary,wedding,whale,whale2,' +
- 'wheelchair,white_check_mark,white_circle,white_flower,white_large_square,white_medium_small_square,' +
- 'white_medium_square,white_small_square,white_square_button,wind_chime,wine_glass,wink,wolf,woman,' +
- 'womans_clothes,womans_hat,womens,worried,wrench,x,yellow_heart,yen,yum,zap,zero,zzz').split(',');
-
- // use a map to help make lookups faster instead of having to use indexOf on an array
- const out = new Map();
-
- for (let i = 0; i < emoticonNames.length; i++) {
- out.set(emoticonNames[i], true);
- }
-
- return out;
-}
-
-export const emoticonMap = initializeEmoticonMap();
-
-export function handleEmoticons(text, tokens) {
- let output = text;
-
- function replaceEmoticonWithToken(fullMatch, prefix, matchText, name) {
- if (emoticonMap.has(name)) {
- const index = tokens.size;
- const alias = `MM_EMOTICON${index}`;
-
- tokens.set(alias, {
- value: `<img align="absmiddle" alt="${matchText}" class="emoticon" src="${getImagePathForEmoticon(name)}" title="${matchText}" />`,
- originalText: fullMatch
- });
-
- return prefix + alias;
- }
-
- return fullMatch;
- }
-
- output = output.replace(/(^|\s)(:([a-zA-Z0-9_-]+):)(?=$|\s)/g, (fullMatch, prefix, matchText, name) => replaceEmoticonWithToken(fullMatch, prefix, matchText, name));
-
- $.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, (fullMatch, prefix, matchText) => replaceEmoticonWithToken(fullMatch, prefix, matchText, name));
- });
-
- return output;
-}
-
-export function getImagePathForEmoticon(name) {
- if (name) {
- return `/static/images/emoji/${name}.png`;
- }
- return '/static/images/emoji';
-}
diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx
deleted file mode 100644
index 2b1aed9c0..000000000
--- a/web/react/utils/markdown.jsx
+++ /dev/null
@@ -1,575 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import highlightJs from 'highlight.js/lib/highlight.js';
-import highlightJsDiff from 'highlight.js/lib/languages/diff.js';
-import highlightJsApache from 'highlight.js/lib/languages/apache.js';
-import highlightJsMakefile from 'highlight.js/lib/languages/makefile.js';
-import highlightJsHttp from 'highlight.js/lib/languages/http.js';
-import highlightJsJson from 'highlight.js/lib/languages/json.js';
-import highlightJsMarkdown from 'highlight.js/lib/languages/markdown.js';
-import highlightJsJavascript from 'highlight.js/lib/languages/javascript.js';
-import highlightJsCss from 'highlight.js/lib/languages/css.js';
-import highlightJsNginx from 'highlight.js/lib/languages/nginx.js';
-import highlightJsObjectivec from 'highlight.js/lib/languages/objectivec.js';
-import highlightJsPython from 'highlight.js/lib/languages/python.js';
-import highlightJsXml from 'highlight.js/lib/languages/xml.js';
-import highlightJsPerl from 'highlight.js/lib/languages/perl.js';
-import highlightJsBash from 'highlight.js/lib/languages/bash.js';
-import highlightJsPhp from 'highlight.js/lib/languages/php.js';
-import highlightJsCoffeescript from 'highlight.js/lib/languages/coffeescript.js';
-import highlightJsCs from 'highlight.js/lib/languages/cs.js';
-import highlightJsCpp from 'highlight.js/lib/languages/cpp.js';
-import highlightJsSql from 'highlight.js/lib/languages/sql.js';
-import highlightJsGo from 'highlight.js/lib/languages/go.js';
-import highlightJsRuby from 'highlight.js/lib/languages/ruby.js';
-import highlightJsJava from 'highlight.js/lib/languages/java.js';
-import highlightJsIni from 'highlight.js/lib/languages/ini.js';
-
-highlightJs.registerLanguage('diff', highlightJsDiff);
-highlightJs.registerLanguage('apache', highlightJsApache);
-highlightJs.registerLanguage('makefile', highlightJsMakefile);
-highlightJs.registerLanguage('http', highlightJsHttp);
-highlightJs.registerLanguage('json', highlightJsJson);
-highlightJs.registerLanguage('markdown', highlightJsMarkdown);
-highlightJs.registerLanguage('javascript', highlightJsJavascript);
-highlightJs.registerLanguage('css', highlightJsCss);
-highlightJs.registerLanguage('nginx', highlightJsNginx);
-highlightJs.registerLanguage('objectivec', highlightJsObjectivec);
-highlightJs.registerLanguage('python', highlightJsPython);
-highlightJs.registerLanguage('xml', highlightJsXml);
-highlightJs.registerLanguage('perl', highlightJsPerl);
-highlightJs.registerLanguage('bash', highlightJsBash);
-highlightJs.registerLanguage('php', highlightJsPhp);
-highlightJs.registerLanguage('coffeescript', highlightJsCoffeescript);
-highlightJs.registerLanguage('cs', highlightJsCs);
-highlightJs.registerLanguage('cpp', highlightJsCpp);
-highlightJs.registerLanguage('sql', highlightJsSql);
-highlightJs.registerLanguage('go', highlightJsGo);
-highlightJs.registerLanguage('ruby', highlightJsRuby);
-highlightJs.registerLanguage('java', highlightJsJava);
-highlightJs.registerLanguage('ini', highlightJsIni);
-
-import * as TextFormatting from './text_formatting.jsx';
-import * as Utils from './utils.jsx';
-
-import marked from 'marked';
-
-import Constants from '../utils/constants.jsx';
-const HighlightedLanguages = Constants.HighlightedLanguages;
-
-function markdownImageLoaded(image) {
- image.style.height = 'auto';
-}
-window.markdownImageLoaded = markdownImageLoaded;
-
-class MattermostInlineLexer extends marked.InlineLexer {
- constructor(links, options) {
- super(links, options);
-
- this.rules = Object.assign({}, this.rules);
-
- // modified version of the regex that allows for links starting with www and those surrounded by parentheses
- // the original is /^[\s\S]+?(?=[\\<!\[_*`~]|https?:\/\/| {2,}\n|$)/
- this.rules.text = /^[\s\S]+?(?=[\\<!\[_*`~]|https?:\/\/|www\.|\(| {2,}\n|$)/;
-
- // modified version of the regex that allows links starting with www and those surrounded by parentheses
- // the original is /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/
- this.rules.url = /^(\(?(?:https?:\/\/|www\.)[^\s<.][^\s<]*[^<.,:;"'\]\s])/;
-
- // modified version of the regex that allows <links> starting with www.
- // the original is /^<([^ >]+(@|:\/)[^ >]+)>/
- this.rules.autolink = /^<((?:[^ >]+(@|:\/)|www\.)[^ >]+)>/;
- }
-}
-
-class MattermostParser extends marked.Parser {
- parse(src) {
- this.inline = new MattermostInlineLexer(src.links, this.options, this.renderer);
- this.tokens = src.reverse();
-
- var out = '';
- while (this.next()) {
- out += this.tok();
- }
-
- return out;
- }
-}
-
-class MattermostMarkdownRenderer extends marked.Renderer {
- constructor(options, formattingOptions = {}) {
- super(options);
-
- this.heading = this.heading.bind(this);
- this.paragraph = this.paragraph.bind(this);
- this.text = this.text.bind(this);
-
- this.formattingOptions = formattingOptions;
- }
-
- code(code, language, escaped) {
- let usedLanguage = language || '';
- usedLanguage = usedLanguage.toLowerCase();
-
- // treat html as xml to prevent injection attacks
- if (usedLanguage === 'html') {
- usedLanguage = 'xml';
- }
-
- if (HighlightedLanguages[usedLanguage]) {
- const parsed = highlightJs.highlight(usedLanguage, code);
-
- return (
- '<div class="post-body--code">' +
- '<span class="post-body--code__language">' +
- HighlightedLanguages[usedLanguage] +
- '</span>' +
- '<pre>' +
- '<code class="hljs">' +
- parsed.value +
- '</code>' +
- '</pre>' +
- '</div>'
- );
- } else if (usedLanguage === 'tex' || usedLanguage === 'latex') {
- try {
- const html = katex.renderToString(code, {throwOnError: false, displayMode: true});
-
- return '<div class="post-body--code tex">' + html + '</div>';
- } catch (e) {
- // fall through if latex parsing fails and handle below
- }
- }
-
- return (
- '<pre>' +
- '<code class="hljs">' +
- (escaped ? code : TextFormatting.sanitizeHtml(code)) + '\n' +
- '</code>' +
- '</pre>'
- );
- }
-
- codespan(text) {
- return '<span class="codespan__pre-wrap">' + super.codespan(text) + '</span>';
- }
-
- br() {
- if (this.formattingOptions.singleline) {
- return ' ';
- }
-
- return super.br();
- }
-
- image(href, title, text) {
- let out = '<img src="' + href + '" alt="' + text + '"';
- if (title) {
- out += ' title="' + title + '"';
- }
- out += ' onload="window.markdownImageLoaded(this)" onerror="window.markdownImageLoaded(this)" class="markdown-inline-img"';
- out += this.options.xhtml ? '/>' : '>';
- return out;
- }
-
- heading(text, level, raw) {
- const id = `${this.options.headerPrefix}${raw.toLowerCase().replace(/[^\w]+/g, '-')}`;
- return `<h${level} id="${id}" class="markdown__heading">${text}</h${level}>`;
- }
-
- link(href, title, text) {
- let outHref = href;
- let outText = text;
- let prefix = '';
- let suffix = '';
-
- // some links like https://en.wikipedia.org/wiki/Rendering_(computer_graphics) contain brackets
- // and we try our best to differentiate those from ones just wrapped in brackets when autolinking
- if (outHref.startsWith('(') && outHref.endsWith(')') && text === outHref) {
- prefix = '(';
- suffix = ')';
- outText = text.substring(1, text.length - 1);
- outHref = outHref.substring(1, outHref.length - 1);
- }
-
- try {
- const unescaped = decodeURIComponent(unescape(href)).replace(/[^\w:]/g, '').toLowerCase();
-
- if (unescaped.indexOf('javascript:') === 0 || unescaped.indexOf('vbscript:') === 0) { // eslint-disable-line no-script-url
- return '';
- }
- } catch (e) {
- return '';
- }
-
- if (!(/[a-z+.-]+:/i).test(outHref)) {
- outHref = `http://${outHref}`;
- }
-
- let output = '<a class="theme markdown__link" href="' + outHref + '"';
- if (title) {
- output += ' title="' + title + '"';
- }
-
- if (outHref.lastIndexOf(Utils.getTeamURLFromAddressBar(), 0) === 0) {
- output += '>';
- } else {
- output += ' target="_blank">';
- }
-
- output += outText + '</a>';
-
- return prefix + output + suffix;
- }
-
- paragraph(text) {
- if (this.formattingOptions.singleline) {
- return `<p class="markdown__paragraph-inline">${text}</p>`;
- }
-
- return super.paragraph(text);
- }
-
- table(header, body) {
- return `<div class="table-responsive"><table class="markdown__table"><thead>${header}</thead><tbody>${body}</tbody></table></div>`;
- }
-
- listitem(text) {
- const taskListReg = /^\[([ |xX])\] /;
- const isTaskList = taskListReg.exec(text);
-
- if (isTaskList) {
- return `<li class="list-item--task-list">${'<input type="checkbox" disabled="disabled" ' + (isTaskList[1] === ' ' ? '' : 'checked="checked" ') + '/> '}${text.replace(taskListReg, '')}</li>`;
- }
- return `<li>${text}</li>`;
- }
-
- text(txt) {
- return TextFormatting.doFormatText(txt, this.formattingOptions);
- }
-}
-
-class MattermostLexer extends marked.Lexer {
- token(originalSrc, top, bq) {
- let src = originalSrc.replace(/^ +$/gm, '');
-
- while (src) {
- // newline
- let cap = this.rules.newline.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- if (cap[0].length > 1) {
- this.tokens.push({
- type: 'space'
- });
- }
- }
-
- // code
- cap = this.rules.code.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- cap = cap[0].replace(/^ {4}/gm, '');
- this.tokens.push({
- type: 'code',
- text: this.options.pedantic ? cap : cap.replace(/\n+$/, '')
- });
- continue;
- }
-
- // fences (gfm)
- cap = this.rules.fences.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'code',
- lang: cap[2],
- text: cap[3] || ''
- });
- continue;
- }
-
- // heading
- cap = this.rules.heading.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'heading',
- depth: cap[1].length,
- text: cap[2]
- });
- continue;
- }
-
- // table no leading pipe (gfm)
- cap = this.rules.nptable.exec(src);
- if (top && cap) {
- src = src.substring(cap[0].length);
-
- const item = {
- type: 'table',
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
- cells: cap[3].replace(/\n$/, '').split('\n')
- };
-
- for (let i = 0; i < item.align.length; i++) {
- if (/^ *-+: *$/.test(item.align[i])) {
- item.align[i] = 'right';
- } else if (/^ *:-+: *$/.test(item.align[i])) {
- item.align[i] = 'center';
- } else if (/^ *:-+ *$/.test(item.align[i])) {
- item.align[i] = 'left';
- } else {
- item.align[i] = null;
- }
- }
-
- for (let i = 0; i < item.cells.length; i++) {
- item.cells[i] = item.cells[i].split(/ *\| */);
- }
-
- this.tokens.push(item);
-
- continue;
- }
-
- // lheading
- cap = this.rules.lheading.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'heading',
- depth: cap[2] === '=' ? 1 : 2,
- text: cap[1]
- });
- continue;
- }
-
- // hr
- cap = this.rules.hr.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'hr'
- });
- continue;
- }
-
- // blockquote
- cap = this.rules.blockquote.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
-
- this.tokens.push({
- type: 'blockquote_start'
- });
-
- cap = cap[0].replace(/^ *> ?/gm, '');
-
- // Pass `top` to keep the current
- // "toplevel" state. This is exactly
- // how markdown.pl works.
- this.token(cap, top, true);
-
- this.tokens.push({
- type: 'blockquote_end'
- });
-
- continue;
- }
-
- // list
- cap = this.rules.list.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- const bull = cap[2];
-
- this.tokens.push({
- type: 'list_start',
- ordered: bull.length > 1
- });
-
- // Get each top-level item.
- cap = cap[0].match(this.rules.item);
-
- let next = false;
- const l = cap.length;
- let i = 0;
-
- for (; i < l; i++) {
- let item = cap[i];
-
- // Remove the list item's bullet
- // so it is seen as the next token.
- let space = item.length;
- item = item.replace(/^ *([*+-]|\d+\.) +/, '');
-
- // Outdent whatever the
- // list item contains. Hacky.
- if (~item.indexOf('\n ')) {
- space -= item.length;
- item = this.options.pedantic ?
- item.replace(/^ {1,4}/gm, '') :
- item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '');
- }
-
- // Determine whether the next list item belongs here.
- // Backpedal if it does not belong in this list.
- if (this.options.smartLists && i !== l - 1) {
- const b = this.rules.bullet.exec(cap[i + 1])[0];
- if (bull !== b && !(bull.length > 1 && b.length > 1)) {
- src = cap.slice(i + 1).join('\n') + src;
- i = l - 1;
- }
- }
-
- // Determine whether item is loose or not.
- // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
- // for discount behavior.
- let loose = next || (/\n\n(?!\s*$)/).test(item);
- if (i !== l - 1) {
- next = item.charAt(item.length - 1) === '\n';
- if (!loose) {
- loose = next;
- }
- }
-
- this.tokens.push({
- type: loose ?
- 'loose_item_start' :
- 'list_item_start'
- });
-
- // Recurse.
- this.token(item, false, bq);
-
- this.tokens.push({
- type: 'list_item_end'
- });
- }
-
- this.tokens.push({
- type: 'list_end'
- });
-
- continue;
- }
-
- // html
- cap = this.rules.html.exec(src);
- if (cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: this.options.sanitize ? 'paragraph' : 'html',
- pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
- text: cap[0]
- });
- continue;
- }
-
- // def
- cap = this.rules.def.exec(src);
- if ((!bq && top) && cap) {
- src = src.substring(cap[0].length);
- this.tokens.links[cap[1].toLowerCase()] = {
- href: cap[2],
- title: cap[3]
- };
- continue;
- }
-
- // table (gfm)
- cap = this.rules.table.exec(src);
- if (top && cap) {
- src = src.substring(cap[0].length);
-
- const item = {
- type: 'table',
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
- cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
- };
-
- for (let i = 0; i < item.align.length; i++) {
- if (/^ *-+: *$/.test(item.align[i])) {
- item.align[i] = 'right';
- } else if (/^ *:-+: *$/.test(item.align[i])) {
- item.align[i] = 'center';
- } else if (/^ *:-+ *$/.test(item.align[i])) {
- item.align[i] = 'left';
- } else {
- item.align[i] = null;
- }
- }
-
- for (let i = 0; i < item.cells.length; i++) {
- item.cells[i] = item.cells[i].replace(/^ *\| *| *\| *$/g, '').split(/ *\| */);
- }
-
- this.tokens.push(item);
-
- continue;
- }
-
- // top-level paragraph
- cap = this.rules.paragraph.exec(src);
- if (top && cap) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'paragraph',
- text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
- });
- continue;
- }
-
- // text
- cap = this.rules.text.exec(src);
- if (cap) {
- // Top-level should never reach here.
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'text',
- text: cap[0]
- });
- continue;
- }
-
- if (src) {
- throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
- }
- }
-
- return this.tokens;
- }
-}
-
-export function format(text, options) {
- const markdownOptions = {
- renderer: new MattermostMarkdownRenderer(null, options),
- sanitize: true,
- gfm: true,
- tables: true
- };
-
- const tokens = new MattermostLexer(markdownOptions).lex(text);
-
- return new MattermostParser(markdownOptions).parse(tokens);
-}
-
-// Marked helper functions that should probably just be exported
-
-function unescape(html) {
- return html.replace(/&([#\w]+);/g, (_, m) => {
- const n = m.toLowerCase();
- if (n === 'colon') {
- return ':';
- } else if (n.charAt(0) === '#') {
- return n.charAt(1) === 'x' ?
- String.fromCharCode(parseInt(n.substring(2), 16)) :
- String.fromCharCode(+n.substring(1));
- }
- return '';
- });
-}
diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx
deleted file mode 100644
index 552d93fac..000000000
--- a/web/react/utils/text_formatting.jsx
+++ /dev/null
@@ -1,402 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import Autolinker from 'autolinker';
-import Constants from './constants.jsx';
-import * as Emoticons from './emoticons.jsx';
-import * as Markdown from './markdown.jsx';
-import UserStore from '../stores/user_store.jsx';
-import * as Utils from './utils.jsx';
-
-// 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:
-// - 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 = {}) {
- let output;
-
- if (!('markdown' in options) || options.markdown) {
- // the markdown renderer will call doFormatText as necessary
- output = Markdown.format(text, options);
- } else {
- output = sanitizeHtml(text);
- output = doFormatText(output, options);
- }
-
- // replace newlines with spaces if necessary
- if (options.singleline) {
- output = replaceNewlines(output);
- }
-
- return output;
-}
-
-// Performs most of the actual formatting work for formatText. Not intended to be called normally.
-export function doFormatText(text, options) {
- let output = text;
-
- const tokens = new Map();
-
- // replace important words and phrases with tokens
- output = autolinkAtMentions(output, tokens);
- output = autolinkEmails(output, tokens);
- output = autolinkHashtags(output, tokens);
-
- if (!('emoticons' in options) || options.emoticon) {
- output = Emoticons.handleEmoticons(output, tokens);
- }
-
- if (options.searchTerm) {
- output = highlightSearchTerm(output, tokens, options.searchTerm);
- }
-
- if (!('mentionHighlight' in options) || options.mentionHighlight) {
- output = highlightCurrentMentions(output, tokens);
- }
-
- // reinsert tokens with formatted versions of the important words and phrases
- output = replaceTokens(output, tokens);
-
- return output;
-}
-
-export function sanitizeHtml(text) {
- let output = text;
-
- // normal string.replace only does a single occurrance so use a regex instead
- output = output.replace(/&/g, '&amp;');
- output = output.replace(/</g, '&lt;');
- output = output.replace(/>/g, '&gt;');
- output = output.replace(/'/g, '&apos;');
- output = output.replace(/"/g, '&quot;');
-
- return output;
-}
-
-// Convert emails into tokens
-function autolinkEmails(text, tokens) {
- function replaceEmailWithToken(autolinker, match) {
- const linkText = match.getMatchedText();
- let url = linkText;
-
- if (match.getType() === 'email') {
- url = `mailto:${url}`;
- }
-
- const index = tokens.size;
- const alias = `MM_EMAIL${index}`;
-
- tokens.set(alias, {
- value: `<a class="theme" href="${url}">${linkText}</a>`,
- originalText: linkText
- });
-
- return alias;
- }
-
- // we can't just use a static autolinker because we need to set replaceFn
- const autolinker = new Autolinker({
- urls: false,
- email: true,
- phone: false,
- twitter: false,
- hashtag: false,
- replaceFn: replaceEmailWithToken
- });
-
- return autolinker.link(text);
-}
-
-function autolinkAtMentions(text, tokens) {
- // Return true if provided character is punctuation
- function isPunctuation(character) {
- const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/g;
- return re.test(character);
- }
-
- // Test if provided text needs to be highlighted, special mention or current user
- function mentionExists(u) {
- return (Constants.SPECIAL_MENTIONS.indexOf(u) !== -1 || UserStore.getProfileByUsername(u));
- }
-
- function addToken(username, mention) {
- const index = tokens.size;
- const alias = `MM_ATMENTION${index}`;
-
- tokens.set(alias, {
- value: `<a class='mention-link' href='#' data-mention='${username}'>${mention}</a>`,
- originalText: mention
- });
- return alias;
- }
-
- function replaceAtMentionWithToken(fullMatch, mention, username) {
- let usernameLower = username.toLowerCase();
-
- if (mentionExists(usernameLower)) {
- // Exact match
- const alias = addToken(usernameLower, mention, '');
- return alias;
- }
-
- // Not an exact match, attempt to truncate any punctuation to see if we can find a user
- const originalUsername = usernameLower;
-
- for (let c = usernameLower.length; c > 0; c--) {
- if (isPunctuation(usernameLower[c - 1])) {
- usernameLower = usernameLower.substring(0, c - 1);
-
- if (mentionExists(usernameLower)) {
- const suffix = originalUsername.substr(c - 1);
- const alias = addToken(usernameLower, '@' + usernameLower);
- return alias + suffix;
- }
- } else {
- // If the last character is not punctuation, no point in going any further
- break;
- }
- }
-
- return fullMatch;
- }
-
- let output = text;
- output = output.replace(/(@([a-z0-9.\-_]*))/gi, replaceAtMentionWithToken);
-
- return output;
-}
-
-function escapeRegex(text) {
- return text.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
-}
-
-function highlightCurrentMentions(text, tokens) {
- let output = text;
-
- const mentionKeys = UserStore.getCurrentMentionKeys();
-
- // look for any existing tokens which are self mentions and should be highlighted
- var newTokens = new Map();
- for (const [alias, token] of tokens) {
- if (mentionKeys.indexOf(token.originalText) !== -1) {
- const index = tokens.size + newTokens.size;
- const newAlias = `MM_SELFMENTION${index}`;
-
- newTokens.set(newAlias, {
- value: `<span class='mention--highlight'>${alias}</span>`,
- originalText: token.originalText
- });
- output = output.replace(alias, newAlias);
- }
- }
-
- // the new tokens are stashed in a separate map since we can't add objects to a map during iteration
- for (const newToken of newTokens) {
- tokens.set(newToken[0], newToken[1]);
- }
-
- // look for self mentions in the text
- function replaceCurrentMentionWithToken(fullMatch, prefix, mention) {
- const index = tokens.size;
- const alias = `MM_SELFMENTION${index}`;
-
- tokens.set(alias, {
- value: `<span class='mention--highlight'>${mention}</span>`,
- originalText: mention
- });
-
- return prefix + alias;
- }
-
- for (const mention of UserStore.getCurrentMentionKeys()) {
- output = output.replace(new RegExp(`(^|\\W)(${escapeRegex(mention)})\\b`, 'gi'), replaceCurrentMentionWithToken);
- }
-
- return output;
-}
-
-function autolinkHashtags(text, tokens) {
- let output = text;
-
- var newTokens = new Map();
- for (const [alias, token] of tokens) {
- if (token.originalText.lastIndexOf('#', 0) === 0) {
- const index = tokens.size + newTokens.size;
- const newAlias = `MM_HASHTAG${index}`;
-
- newTokens.set(newAlias, {
- value: `<a class='mention-link' href='#' data-hashtag='${token.originalText}'>${token.originalText}</a>`,
- originalText: token.originalText
- });
-
- output = output.replace(alias, newAlias);
- }
- }
-
- // the new tokens are stashed in a separate map since we can't add objects to a map during iteration
- for (const newToken of newTokens) {
- tokens.set(newToken[0], newToken[1]);
- }
-
- // look for hashtags in the text
- function replaceHashtagWithToken(fullMatch, prefix, hashtag) {
- const index = tokens.size;
- const alias = `MM_HASHTAG${index}`;
-
- let value = hashtag;
-
- if (hashtag.length > Constants.MIN_HASHTAG_LINK_LENGTH) {
- value = `<a class='mention-link' href='#' data-hashtag='${hashtag}'>${hashtag}</a>`;
- }
-
- tokens.set(alias, {
- value,
- originalText: hashtag
- });
-
- return prefix + alias;
- }
-
- return output.replace(/(^|\W)(#[a-zA-ZĆ¤Ć¶Ć¼Ć„Ć–ĆœĆŸ][a-zA-Z0-9Ć¤Ć¶Ć¼Ć„Ć–ĆœĆŸ.\-_]*)\b/g, replaceHashtagWithToken);
-}
-
-const puncStart = /^[.,()&$!\[\]{}':;\\]+/;
-const puncEnd = /[.,()&$#!\[\]{}':;\\]+$/;
-
-function parseSearchTerms(searchTerm) {
- let terms = [];
-
- let termString = searchTerm;
-
- while (termString) {
- let captured;
-
- // check for a quoted string
- captured = (/^"(.*?)"/).exec(termString);
- if (captured) {
- termString = termString.substring(captured[0].length);
- terms.push(captured[1]);
- continue;
- }
-
- // check for a search flag (and don't add it to terms)
- captured = (/^(?:in|from|channel): ?\S+/).exec(termString);
- if (captured) {
- termString = termString.substring(captured[0].length);
- continue;
- }
-
- // capture any plain text up until the next quote or search flag
- captured = (/^.+?(?=\bin|\bfrom|\bchannel|"|$)/).exec(termString);
- if (captured) {
- termString = termString.substring(captured[0].length);
-
- // break the text up into words based on how the server splits them in SqlPostStore.SearchPosts and then discard empty terms
- terms.push(...captured[0].split(/[ <>+\-\(\)\~\@]/).filter((term) => !!term));
- continue;
- }
-
- // we should never reach this point since at least one of the regexes should match something in the remaining text
- throw new Error('Infinite loop in search term parsing: ' + termString);
- }
-
- // remove punctuation from each term
- terms = terms.map((term) => term.replace(puncStart, '').replace(puncEnd, ''));
-
- return terms;
-}
-
-function convertSearchTermToRegex(term) {
- let pattern;
- if (term.endsWith('*')) {
- pattern = '\\b' + escapeRegex(term.substring(0, term.length - 1));
- } else {
- pattern = '\\b' + escapeRegex(term) + '\\b';
- }
-
- return new RegExp(pattern, 'gi');
-}
-
-function highlightSearchTerm(text, tokens, searchTerm) {
- const terms = parseSearchTerms(searchTerm);
-
- if (terms.length === 0) {
- return text;
- }
-
- let output = text;
-
- function replaceSearchTermWithToken(word) {
- const index = tokens.size;
- const alias = `MM_SEARCHTERM${index}`;
-
- tokens.set(alias, {
- value: `<span class='search-highlight'>${word}</span>`,
- originalText: word
- });
-
- return alias;
- }
-
- for (const term of terms) {
- // highlight existing tokens matching search terms
- var newTokens = new Map();
- for (const [alias, token] of tokens) {
- if (token.originalText === term.replace(/\*$/, '')) {
- const index = tokens.size + newTokens.size;
- const newAlias = `MM_SEARCHTERM${index}`;
-
- newTokens.set(newAlias, {
- value: `<span class='search-highlight'>${alias}</span>`,
- originalText: token.originalText
- });
-
- output = output.replace(alias, newAlias);
- }
- }
-
- // the new tokens are stashed in a separate map since we can't add objects to a map during iteration
- for (const newToken of newTokens) {
- tokens.set(newToken[0], newToken[1]);
- }
-
- output = output.replace(convertSearchTermToRegex(term), replaceSearchTermWithToken);
- }
-
- return output;
-}
-
-function replaceTokens(text, tokens) {
- let output = text;
-
- // iterate backwards through the map so that we do replacement in the opposite order that we added tokens
- const aliases = [...tokens.keys()];
- for (let i = aliases.length - 1; i >= 0; i--) {
- const alias = aliases[i];
- const token = tokens.get(alias);
- output = output.replace(alias, token.value);
- }
-
- return output;
-}
-
-function replaceNewlines(text) {
- return text.replace(/\n/g, ' ');
-}
-
-// A click handler that can be used with the results of TextFormatting.formatText to add default functionality
-// to clicked hashtags and @mentions.
-export function handleClick(e) {
- const mentionAttribute = e.target.getAttributeNode('data-mention');
- const hashtagAttribute = e.target.getAttributeNode('data-hashtag');
-
- if (mentionAttribute) {
- Utils.searchForTerm(mentionAttribute.value);
- } else if (hashtagAttribute) {
- Utils.searchForTerm(hashtagAttribute.value);
- }
-}
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
deleted file mode 100644
index 360d1f4a5..000000000
--- a/web/react/utils/utils.jsx
+++ /dev/null
@@ -1,1416 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
-import * as GlobalActions from '../action_creators/global_actions.jsx';
-import ChannelStore from '../stores/channel_store.jsx';
-import UserStore from '../stores/user_store.jsx';
-import LocalizationStore from '../stores/localization_store.jsx';
-import PreferenceStore from '../stores/preference_store.jsx';
-import TeamStore from '../stores/team_store.jsx';
-import Constants from '../utils/constants.jsx';
-var ActionTypes = Constants.ActionTypes;
-import * as Client from './client.jsx';
-import * as AsyncClient from './async_client.jsx';
-import * as client from './client.jsx';
-import Autolinker from 'autolinker';
-
-import {FormattedTime} from 'mm-intl';
-
-export function isEmail(email) {
- // writing a regex to match all valid email addresses is really, really hard (see http://stackoverflow.com/a/201378)
- // so we just do a simple check and rely on a verification email to tell if it's a real address
- return (/^.+@.+$/).test(email);
-}
-
-export function cleanUpUrlable(input) {
- var cleaned = input.trim().replace(/-/g, ' ').replace(/[^\w\s]/gi, '').toLowerCase().replace(/\s/g, '-');
- cleaned = cleaned.replace(/-{2,}/, '-');
- cleaned = cleaned.replace(/^\-+/, '');
- cleaned = cleaned.replace(/\-+$/, '');
- return cleaned;
-}
-
-export function isTestDomain() {
- if ((/^localhost/).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^dockerhost/).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^test/).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^127.0./).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^192.168./).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^10./).test(window.location.hostname)) {
- return true;
- }
-
- if ((/^176./).test(window.location.hostname)) {
- return true;
- }
-
- return false;
-}
-
-export function isChrome() {
- if (navigator.userAgent.indexOf('Chrome') > -1) {
- return true;
- }
- return false;
-}
-
-export function isSafari() {
- if (navigator.userAgent.indexOf('Safari') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) {
- return true;
- }
- return false;
-}
-
-export function isIosChrome() {
- // https://developer.chrome.com/multidevice/user-agent
- return navigator.userAgent.indexOf('CriOS') !== -1;
-}
-
-export function isMobileApp() {
- const userAgent = navigator.userAgent;
-
- // the mobile app has different user agents for the native api calls and the shim, so handle them both
- const isApi = userAgent.indexOf('Mattermost') !== -1;
- const isShim = userAgent.indexOf('iPhone') !== -1 && userAgent.indexOf('Safari') === -1 && userAgent.indexOf('Chrome') === -1;
-
- return isApi || isShim;
-}
-
-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 isSystemAdmin(roles) {
- if (isInRole(roles, 'system_admin')) {
- return true;
- }
-
- return false;
-}
-
-export function getDomainWithOutSub() {
- var parts = window.location.host.split('.');
-
- if (parts.length === 1) {
- if (parts[0].indexOf('dockerhost') > -1) {
- return 'dockerhost:8065';
- }
-
- return 'localhost:8065';
- }
-
- return parts[1] + '.' + parts[2];
-}
-
-export function getCookie(name) {
- var value = '; ' + document.cookie;
- var parts = value.split('; ' + name + '=');
- if (parts.length === 2) {
- return parts.pop().split(';').shift();
- }
- return '';
-}
-
-var requestedNotificationPermission = false;
-
-export function notifyMe(title, body, channel) {
- if (!('Notification' in window)) {
- return;
- }
-
- if (Notification.permission === 'granted' || (Notification.permission === 'default' && !requestedNotificationPermission)) {
- requestedNotificationPermission = true;
-
- Notification.requestPermission((permission) => {
- if (permission === 'granted') {
- try {
- var notification = new Notification(title, {body: body, tag: body, icon: '/static/images/icon50x50.png'});
- notification.onclick = () => {
- window.focus();
- if (channel) {
- switchChannel(channel);
- } else {
- window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/town-square';
- }
- };
- setTimeout(() => {
- notification.close();
- }, 5000);
- } catch (e) {
- console.error(e); //eslint-disable-line no-console
- }
- }
- });
- }
-}
-
-var canDing = true;
-
-export function ding() {
- if (!isBrowserFirefox() && canDing) {
- var audio = new Audio('/static/images/bing.mp3');
- audio.play();
- canDing = false;
- setTimeout(() => {
- canDing = true;
- return;
- }, 3000);
- }
-}
-
-export function getUrlParameter(sParam) {
- var sPageURL = window.location.search.substring(1);
- var sURLVariables = sPageURL.split('&');
- for (var i = 0; i < sURLVariables.length; i++) {
- var sParameterName = sURLVariables[i].split('=');
- if (sParameterName[0] === sParam) {
- return sParameterName[1];
- }
- }
- return null;
-}
-
-export function getDateForUnixTicks(ticks) {
- return new Date(ticks);
-}
-
-export function displayDate(ticks) {
- var d = new Date(ticks);
- var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
-
- return monthNames[d.getMonth()] + ' ' + d.getDate() + ', ' + d.getFullYear();
-}
-
-export function displayTime(ticks, utc) {
- const d = new Date(ticks);
- let hours;
- let minutes;
- let ampm = '';
- let timezone = '';
-
- if (utc) {
- hours = d.getUTCHours();
- minutes = d.getUTCMinutes();
- timezone = ' UTC';
- } else {
- hours = d.getHours();
- minutes = d.getMinutes();
- }
-
- if (minutes <= 9) {
- minutes = '0' + minutes;
- }
-
- const useMilitaryTime = PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time');
- if (!useMilitaryTime) {
- ampm = ' AM';
- if (hours >= 12) {
- ampm = ' PM';
- }
-
- hours = hours % 12;
- if (!hours) {
- hours = '12';
- }
- }
-
- return hours + ':' + minutes + ampm + timezone;
-}
-
-export function displayTimeFormatted(ticks) {
- const useMilitaryTime = PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time');
-
- return (
- <FormattedTime
- value={ticks}
- hour='numeric'
- minute='numeric'
- hour12={!useMilitaryTime}
- />
- );
-}
-
-export function isMilitaryTime() {
- return PreferenceStore.getBool(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time');
-}
-
-export function displayDateTime(ticks) {
- var seconds = Math.floor((Date.now() - ticks) / 1000);
-
- var interval = Math.floor(seconds / 3600);
-
- if (interval > 24) {
- return this.displayTime(ticks);
- }
-
- if (interval > 1) {
- return interval + ' hours ago';
- }
-
- if (interval === 1) {
- return interval + ' hour ago';
- }
-
- interval = Math.floor(seconds / 60);
- if (interval >= 2) {
- return interval + ' minutes ago';
- }
-
- if (interval >= 1) {
- return '1 minute ago';
- }
-
- return 'just now';
-}
-
-export function displayCommentDateTime(ticks) {
- return displayDate(ticks) + ' ' + displayTime(ticks);
-}
-
-// returns Unix timestamp in milliseconds
-export function getTimestamp() {
- return Date.now();
-}
-
-// extracts links not styled by Markdown
-export function extractLinks(text) {
- const links = [];
- let inText = text;
-
- // strip out code blocks
- inText = inText.replace(/`[^`]*`/g, '');
-
- // strip out inline markdown images
- inText = inText.replace(/!\[[^\]]*\]\([^\)]*\)/g, '');
-
- function replaceFn(autolinker, match) {
- let link = '';
- const matchText = match.getMatchedText();
-
- if (matchText.trim().indexOf('http') === 0) {
- link = matchText;
- } else {
- link = 'http://' + matchText;
- }
-
- links.push(link);
- }
-
- Autolinker.link(
- inText,
- {
- replaceFn,
- urls: {schemeMatches: true, wwwMatches: true, tldMatches: false},
- emails: false,
- twitter: false,
- phone: false,
- hashtag: false
- }
- );
-
- return links;
-}
-
-export function escapeRegExp(string) {
- return string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
-}
-
-// Taken from http://stackoverflow.com/questions/1068834/object-comparison-in-javascript and modified slightly
-export function areObjectsEqual(x, y) {
- let p;
- const leftChain = [];
- const rightChain = [];
-
- // Remember that NaN === NaN returns false
- // and isNaN(undefined) returns true
- if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
- return true;
- }
-
- // Compare primitives and functions.
- // Check if both arguments link to the same object.
- // Especially useful on step when comparing prototypes
- if (x === y) {
- return true;
- }
-
- // Works in case when functions are created in constructor.
- // Comparing dates is a common scenario. Another built-ins?
- // We can even handle functions passed across iframes
- if ((typeof x === 'function' && typeof y === 'function') ||
- (x instanceof Date && y instanceof Date) ||
- (x instanceof RegExp && y instanceof RegExp) ||
- (x instanceof String && y instanceof String) ||
- (x instanceof Number && y instanceof Number)) {
- return x.toString() === y.toString();
- }
-
- if (x instanceof Map && y instanceof Map) {
- return areMapsEqual(x, y);
- }
-
- // At last checking prototypes as good a we can
- if (!(x instanceof Object && y instanceof Object)) {
- return false;
- }
-
- if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
- return false;
- }
-
- if (x.constructor !== y.constructor) {
- return false;
- }
-
- if (x.prototype !== y.prototype) {
- return false;
- }
-
- // Check for infinitive linking loops
- if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
- return false;
- }
-
- // Quick checking of one object beeing a subset of another.
- for (p in y) {
- if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
- return false;
- } else if (typeof y[p] !== typeof x[p]) {
- return false;
- }
- }
-
- for (p in x) {
- if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
- return false;
- } else if (typeof y[p] !== typeof x[p]) {
- return false;
- }
-
- switch (typeof (x[p])) {
- case 'object':
- case 'function':
-
- leftChain.push(x);
- rightChain.push(y);
-
- if (!areObjectsEqual(x[p], y[p])) {
- return false;
- }
-
- leftChain.pop();
- rightChain.pop();
- break;
-
- default:
- if (x[p] !== y[p]) {
- return false;
- }
- break;
- }
- }
-
- return true;
-}
-
-export function areMapsEqual(a, b) {
- if (a.size !== b.size) {
- return false;
- }
-
- for (const [key, value] of a) {
- if (!b.has(key)) {
- return false;
- }
-
- if (!areObjectsEqual(value, b.get(key))) {
- return false;
- }
- }
-
- return true;
-}
-
-export function replaceHtmlEntities(text) {
- var tagsToReplace = {
- '&amp;': '&',
- '&lt;': '<',
- '&gt;': '>'
- };
- var newtext = text;
- for (var tag in tagsToReplace) {
- if ({}.hasOwnProperty.call(tagsToReplace, tag)) {
- var regex = new RegExp(tag, 'g');
- newtext = newtext.replace(regex, tagsToReplace[tag]);
- }
- }
- return newtext;
-}
-
-export function insertHtmlEntities(text) {
- var tagsToReplace = {
- '&': '&amp;',
- '<': '&lt;',
- '>': '&gt;'
- };
- var newtext = text;
- for (var tag in tagsToReplace) {
- if ({}.hasOwnProperty.call(tagsToReplace, tag)) {
- var regex = new RegExp(tag, 'g');
- newtext = newtext.replace(regex, tagsToReplace[tag]);
- }
- }
- return newtext;
-}
-
-export function searchForTerm(term) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_SEARCH_TERM,
- term: term,
- do_search: true
- });
-}
-
-export function getFileType(extin) {
- var ext = extin.toLowerCase();
- if (Constants.IMAGE_TYPES.indexOf(ext) > -1) {
- return 'image';
- }
-
- if (Constants.AUDIO_TYPES.indexOf(ext) > -1) {
- return 'audio';
- }
-
- if (Constants.VIDEO_TYPES.indexOf(ext) > -1) {
- return 'video';
- }
-
- if (Constants.SPREADSHEET_TYPES.indexOf(ext) > -1) {
- return 'spreadsheet';
- }
-
- if (Constants.CODE_TYPES.indexOf(ext) > -1) {
- return 'code';
- }
-
- if (Constants.WORD_TYPES.indexOf(ext) > -1) {
- return 'word';
- }
-
- if (Constants.PRESENTATION_TYPES.indexOf(ext) > -1) {
- return 'presentation';
- }
-
- if (Constants.PDF_TYPES.indexOf(ext) > -1) {
- return 'pdf';
- }
-
- if (Constants.PATCH_TYPES.indexOf(ext) > -1) {
- return 'patch';
- }
-
- return 'other';
-}
-
-export function getPreviewImagePathForFileType(fileTypeIn) {
- var fileType = fileTypeIn.toLowerCase();
-
- var icon;
- if (fileType in Constants.ICON_FROM_TYPE) {
- icon = Constants.ICON_FROM_TYPE[fileType];
- } else {
- icon = Constants.ICON_FROM_TYPE.other;
- }
-
- return '/static/images/icons/' + icon + '.png';
-}
-
-export function getIconClassName(fileTypeIn) {
- var fileType = fileTypeIn.toLowerCase();
-
- if (fileType in Constants.ICON_FROM_TYPE) {
- return Constants.ICON_FROM_TYPE[fileType];
- }
-
- return 'glyphicon-file';
-}
-
-export function splitFileLocation(fileLocation) {
- var fileSplit = fileLocation.split('.');
-
- var ext = '';
- if (fileSplit.length > 1) {
- ext = fileSplit[fileSplit.length - 1];
- fileSplit.splice(fileSplit.length - 1, 1);
- }
-
- var filePath = fileSplit.join('.');
- var filename = filePath.split('/')[filePath.split('/').length - 1];
-
- return {ext: ext, name: filename, path: filePath};
-}
-
-export function getPreviewImagePath(filename) {
- // Returns the path to a preview image that can be used to represent a file.
- const fileInfo = splitFileLocation(filename);
- const fileType = getFileType(fileInfo.ext);
-
- if (fileType === 'image') {
- return getFileUrl(fileInfo.path + '_preview.jpg');
- }
-
- // only images have proper previews, so just use a placeholder icon for non-images
- return getPreviewImagePathForFileType(fileType);
-}
-
-export function toTitleCase(str) {
- function doTitleCase(txt) {
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
- }
- return str.replace(/\w\S*/g, doTitleCase);
-}
-
-export function applyTheme(theme) {
- if (theme.sidebarBg) {
- changeCss('.sidebar--left, .modal .settings-modal .settings-table .settings-links, .sidebar--menu', 'background:' + theme.sidebarBg, 1);
- changeCss('body', 'scrollbar-face-color:' + theme.sidebarBg, 3);
- }
-
- if (theme.sidebarText) {
- changeCss('.sidebar--left .nav-pills__container li>a, .sidebar--right, .modal .settings-modal .nav-pills>li a, .sidebar--menu', 'color:' + changeOpacity(theme.sidebarText, 0.6), 1);
- changeCss('@media(max-width: 768px){.modal .settings-modal .settings-table .nav>li>a', 'color:' + theme.sidebarText, 1);
- changeCss('.sidebar--left .nav-pills__container li>h4, .sidebar--left .add-channel-btn', 'color:' + changeOpacity(theme.sidebarText, 0.6), 1);
- changeCss('.sidebar--left .add-channel-btn:hover, .sidebar--left .add-channel-btn:focus', 'color:' + theme.sidebarText, 1);
- changeCss('.sidebar--left .status .offline--icon, .sidebar--left .status .offline--icon', 'fill:' + theme.sidebarText, 1);
- changeCss('@media(max-width: 768px){.modal .settings-modal .settings-table .nav>li>a', 'border-color:' + changeOpacity(theme.sidebarText, 0.2), 2);
- }
-
- if (theme.sidebarUnreadText) {
- changeCss('.sidebar--left .nav-pills__container li>a.unread-title', 'color:' + theme.sidebarUnreadText + '!important;', 2);
- }
-
- if (theme.sidebarTextHoverBg) {
- changeCss('.sidebar--left .nav-pills__container li>a:hover, .sidebar--left .nav-pills__container li>a:focus, .modal .settings-modal .nav-pills>li:hover a, .modal .settings-modal .nav-pills>li:focus a', 'background:' + theme.sidebarTextHoverBg, 1);
- changeCss('@media(max-width: 768px){.modal .settings-modal .settings-table .nav>li:hover a', 'background:' + theme.sidebarTextHoverBg, 1);
- }
-
- if (theme.sidebarTextActiveBorder) {
- changeCss('.sidebar--left .nav li.active a:before, .modal .settings-modal .nav-pills>li.active a:before', 'background:' + theme.sidebarTextActiveBorder, 1);
- }
-
- if (theme.sidebarTextActiveColor) {
- changeCss('.sidebar--left .nav-pills__container li.active a, .sidebar--left .nav-pills__container li.active a:hover, .sidebar--left .nav-pills__container li.active a:focus, .modal .settings-modal .nav-pills>li.active a, .modal .settings-modal .nav-pills>li.active a:hover, .modal .settings-modal .nav-pills>li.active a:active', 'color:' + theme.sidebarTextActiveColor, 2);
- changeCss('.sidebar--left .nav li.active a, .sidebar--left .nav li.active a:hover, .sidebar--left .nav li.active a:focus', 'background:' + changeOpacity(theme.sidebarTextActiveColor, 0.1), 1);
- }
-
- if (theme.sidebarHeaderBg) {
- changeCss('.sidebar--left .team__header, .sidebar--menu .team__header, .post-list__timestamp', 'background:' + theme.sidebarHeaderBg, 1);
- changeCss('.modal .modal-header', 'background:' + theme.sidebarHeaderBg, 1);
- changeCss('#navbar .navbar-default', 'background:' + theme.sidebarHeaderBg, 1);
- changeCss('@media(max-width: 768px){.search-bar__container', 'background:' + theme.sidebarHeaderBg, 1);
- changeCss('.attachment .attachment__container', 'border-left-color:' + theme.sidebarHeaderBg, 1);
- }
-
- if (theme.sidebarHeaderTextColor) {
- changeCss('.sidebar--left .team__header .header__info, .sidebar--menu .team__header .header__info, .post-list__timestamp', 'color:' + theme.sidebarHeaderTextColor, 1);
- changeCss('.sidebar--left .team__header .navbar-right .dropdown__icon, .sidebar--menu .team__header .navbar-right .dropdown__icon', 'fill:' + theme.sidebarHeaderTextColor, 1);
- changeCss('.sidebar--left .team__header .user__name, .sidebar--menu .team__header .user__name', 'color:' + changeOpacity(theme.sidebarHeaderTextColor, 0.8), 1);
- changeCss('.sidebar--left .team__header:hover .user__name, .sidebar--menu .team__header:hover .user__name', 'color:' + theme.sidebarHeaderTextColor, 1);
- changeCss('.modal .modal-header .modal-title, .modal .modal-header .modal-title .name, .modal .modal-header button.close', 'color:' + theme.sidebarHeaderTextColor, 1);
- changeCss('#navbar .navbar-default .navbar-brand .heading', 'color:' + theme.sidebarHeaderTextColor, 1);
- changeCss('#navbar .navbar-default .navbar-toggle .icon-bar, ', 'background:' + theme.sidebarHeaderTextColor, 1);
- changeCss('@media(max-width: 768px){.search-bar__container', 'color:' + theme.sidebarHeaderTextColor, 2);
- }
-
- if (theme.onlineIndicator) {
- changeCss('.sidebar--left .status .online--icon', 'fill:' + theme.onlineIndicator, 1);
- }
-
- if (theme.awayIndicator) {
- changeCss('.sidebar--left .status .away--icon', 'fill:' + theme.awayIndicator, 1);
- }
-
- if (theme.mentionBj) {
- changeCss('.sidebar--left .nav-pills__unread-indicator', 'background:' + theme.mentionBj, 1);
- changeCss('.sidebar--left .badge', 'background:' + theme.mentionBj + '!important;', 1);
- }
-
- if (theme.mentionColor) {
- changeCss('.sidebar--left .nav-pills__unread-indicator', 'color:' + theme.mentionColor, 2);
- changeCss('.sidebar--left .badge', 'color:' + theme.mentionColor + '!important;', 2);
- }
-
- if (theme.centerChannelBg) {
- changeCss('.app__content, .markdown__table, .markdown__table tbody tr, .suggestion-list__content, .modal .modal-content', 'background:' + theme.centerChannelBg, 1);
- changeCss('#post-list .post-list-holder-by-time', 'background:' + theme.centerChannelBg, 1);
- changeCss('#post-create', 'background:' + theme.centerChannelBg, 1);
- changeCss('.date-separator .separator__text, .new-separator .separator__text', 'background:' + theme.centerChannelBg, 1);
- changeCss('.post-image__details, .search-help-popover .search-autocomplete__divider span', 'background:' + theme.centerChannelBg, 1);
- changeCss('.sidebar--right, .dropdown-menu, .popover, .tip-overlay', 'background:' + theme.centerChannelBg, 1);
- changeCss('.popover.bottom>.arrow:after', 'border-bottom-color:' + theme.centerChannelBg, 1);
- changeCss('.popover.right>.arrow:after, .tip-overlay.tip-overlay--sidebar .arrow, .tip-overlay.tip-overlay--header .arrow', 'border-right-color:' + theme.centerChannelBg, 1);
- changeCss('.popover.left>.arrow:after', 'border-left-color:' + theme.centerChannelBg, 1);
- changeCss('.popover.top>.arrow:after, .tip-overlay.tip-overlay--chat .arrow', 'border-top-color:' + theme.centerChannelBg, 1);
- changeCss('@media(min-width: 768px){.search-bar__container .search__form .search-bar, .form-control', 'background:' + theme.centerChannelBg, 1);
- changeCss('.attachment__content', 'background:' + theme.centerChannelBg, 1);
- changeCss('body', 'scrollbar-face-color:' + theme.centerChannelBg, 2);
- changeCss('body', 'scrollbar-track-color:' + theme.centerChannelBg, 2);
- }
-
- if (theme.centerChannelColor) {
- changeCss('.post-list__arrows', 'fill:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
- changeCss('.sidebar--left, .sidebar--right .sidebar--right__header, .suggestion-list__content .command', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.app__content, .post-create__container .post-create-body .btn-file, .post-create__container .post-create-footer .msg-typing, .suggestion-list__content .command, .modal .modal-content, .dropdown-menu, .popover, .mentions__name, .tip-overlay', 'color:' + theme.centerChannelColor, 1);
- changeCss('#archive-link-home', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
- changeCss('#post-create', 'color:' + theme.centerChannelColor, 2);
- changeCss('.mentions--top, .suggestion-list', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 3);
- changeCss('.mentions--top, .suggestion-list', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 2);
- changeCss('.mentions--top, .suggestion-list', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px', 1);
- changeCss('.dropdown-menu, .popover ', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 3);
- changeCss('.dropdown-menu, .popover ', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 2);
- changeCss('.dropdown-menu, .popover ', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px', 1);
- changeCss('.post__body hr, .loading-screen .loading__content .round, .tutorial__circles .circle', 'background:' + theme.centerChannelColor, 1);
- changeCss('.channel-header .heading', 'color:' + theme.centerChannelColor, 1);
- changeCss('.markdown__table tbody tr:nth-child(2n)', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
- changeCss('.channel-header__info>div.dropdown .header-dropdown__icon', 'color:' + changeOpacity(theme.centerChannelColor, 0.8), 1);
- changeCss('.channel-header #member_popover', 'color:' + changeOpacity(theme.centerChannelColor, 0.8), 1);
- changeCss('.custom-textarea, .custom-textarea:focus, .file-preview, .post-image__details, .sidebar--right .sidebar-right__body, .markdown__table th, .markdown__table td, .suggestion-list__content, .modal .modal-content, .modal .settings-modal .settings-table .settings-content .divider-light, .webhooks__container, .dropdown-menu, .modal .modal-header, .popover', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.popover.bottom>.arrow', 'border-bottom-color:' + changeOpacity(theme.centerChannelColor, 0.25), 1);
- changeCss('.search-help-popover .search-autocomplete__divider span', 'color:' + changeOpacity(theme.centerChannelColor, 0.7), 1);
- changeCss('.popover.right>.arrow', 'border-right-color:' + changeOpacity(theme.centerChannelColor, 0.25), 1);
- changeCss('.popover.left>.arrow', 'border-left-color:' + changeOpacity(theme.centerChannelColor, 0.25), 1);
- changeCss('.popover.top>.arrow', 'border-top-color:' + changeOpacity(theme.centerChannelColor, 0.25), 1);
- changeCss('.suggestion-list__content .command, .popover .popover-title', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.dropdown-menu .divider, .search-help-popover .search-autocomplete__divider:before', 'background:' + theme.centerChannelColor, 1);
- changeCss('.custom-textarea', 'color:' + theme.centerChannelColor, 1);
- changeCss('.post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 2);
- changeCss('.post-image__details', 'color:' + theme.centerChannelColor, 2);
- changeCss('.post-image__column a, .post-image__column a:hover, .post-image__column a:focus', 'color:' + theme.centerChannelColor, 1);
- changeCss('@media(min-width: 768px){.search-bar__container .search__form .search-bar, .form-control', 'color:' + theme.centerChannelColor, 2);
- changeCss('.input-group-addon, .search-bar__container .search__form, .form-control', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.form-control:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
- changeCss('.attachment .attachment__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
- changeCss('.channel-intro .channel-intro__content, .webhooks__container', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1);
- changeCss('.date-separator .separator__text', 'color:' + theme.centerChannelColor, 2);
- changeCss('.date-separator .separator__hr, .modal-footer, .modal .custom-textarea', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.search-item-container, .post-right__container .post.post--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1), 1);
- changeCss('.modal .custom-textarea:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
- changeCss('.channel-intro, .modal .settings-modal .settings-table .settings-content .divider-dark, hr, .modal .settings-modal .settings-table .settings-links, .modal .settings-modal .settings-table .settings-content .appearance-section .theme-elements__header', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
- changeCss('.post.current--user .post__body, .post.post--comment.other--root.current--user .post-comment, pre, .post-right__container .post.post--root', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
- changeCss('.post.current--user .post__body, .post.post--comment.other--root.current--user .post-comment, .post.same--root.post--comment .post__body, .more-modal__list .more-modal__row, .member-div:first-child, .member-div, .access-history__table .access__report, .activity-log__table', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1), 2);
- changeCss('@media(max-width: 1800px){.inner-wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
- changeCss('.post:hover, .more-modal__list .more-modal__row:hover, .modal .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
- changeCss('.date-separator.hovered--before:after, .date-separator.hovered--after:before, .new-separator.hovered--after:before, .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
- changeCss('.suggestion-list__content .command:hover, .mentions__name:hover, .suggestion--selected, .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover, .bot-indicator', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
- changeCss('code, .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control', 'background:' + changeOpacity(theme.centerChannelColor, 0.1), 1);
- changeCss('@media(min-width: 960px){.post.current--user:hover .post__body ', 'background: none;', 1);
- changeCss('.sidebar--right', 'color:' + theme.centerChannelColor, 2);
- changeCss('.search-help-popover .search-autocomplete__item:hover, .modal .settings-modal .settings-table .settings-content .appearance-section .theme-elements__body', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1);
- changeCss('.search-help-popover .search-autocomplete__item.selected', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
- changeCss('::-webkit-scrollbar-thumb', 'background:' + changeOpacity(theme.centerChannelColor, 0.4), 1);
- changeCss('body', 'scrollbar-arrow-color:' + theme.centerChannelColor, 4);
- }
-
- if (theme.newMessageSeparator) {
- changeCss('.new-separator .separator__text', 'color:' + theme.newMessageSeparator, 1);
- changeCss('.new-separator .separator__hr', 'border-color:' + changeOpacity(theme.newMessageSeparator, 0.5), 1);
- }
-
- if (theme.linkColor) {
- changeCss('a, a:focus, a:hover, .btn, .btn:focus, .btn:hover', 'color:' + theme.linkColor, 1);
- changeCss('.post .comment-icon__container, .post .post__reply', 'fill:' + theme.linkColor, 1);
- }
-
- if (theme.buttonBg) {
- changeCss('.btn.btn-primary, .tutorial__circles .circle.active', 'background:' + theme.buttonBg, 1);
- changeCss('.btn.btn-primary:hover, .btn.btn-primary:active, .btn.btn-primary:focus', 'background:' + changeColor(theme.buttonBg, -0.25), 1);
- changeCss('.file-playback__controls', 'color:' + changeColor(theme.buttonBg, -0.25), 1);
- }
-
- if (theme.buttonColor) {
- changeCss('.btn.btn-primary', 'color:' + theme.buttonColor, 2);
- }
-
- if (theme.mentionHighlightBg) {
- changeCss('.mention--highlight, .search-highlight', 'background:' + theme.mentionHighlightBg, 1);
- }
-
- if (theme.mentionHighlightBg) {
- changeCss('.post.post--highlight', 'background:' + changeOpacity(theme.mentionHighlightBg, 0.5), 1);
- }
-
- if (theme.mentionHighlightLink) {
- changeCss('.mention--highlight .mention-link', 'color:' + theme.mentionHighlightLink, 1);
- }
-
- if (!theme.codeTheme) {
- theme.codeTheme = Constants.DEFAULT_CODE_THEME;
- }
- updateCodeTheme(theme.codeTheme);
-}
-
-export function applyFont(fontName) {
- const body = $('body');
-
- for (const key of Reflect.ownKeys(Constants.FONTS)) {
- const className = Constants.FONTS[key];
-
- if (fontName === key) {
- if (!body.hasClass(className)) {
- body.addClass(className);
- }
- } else {
- body.removeClass(className);
- }
- }
-}
-
-export function changeCss(className, classValue, classRepeat) {
- // we need invisible container to store additional css definitions
- var cssMainContainer = $('#css-modifier-container');
- if (cssMainContainer.length === 0) {
- cssMainContainer = $('<div id="css-modifier-container"></div>');
- cssMainContainer.hide();
- cssMainContainer.appendTo($('body'));
- }
-
- // and we need one div for each class
- var classContainer = cssMainContainer.find('div[data-class="' + className + classRepeat + '"]');
- if (classContainer.length === 0) {
- classContainer = $('<div data-class="' + className + classRepeat + '"></div>');
- classContainer.appendTo(cssMainContainer);
- }
-
- // append additional style
- classContainer.html('<style>' + className + ' {' + classValue + '}</style>');
-}
-
-export function rgb2hex(rgbIn) {
- if (/^#[0-9A-F]{6}$/i.test(rgbIn)) {
- return rgbIn;
- }
-
- var rgb = rgbIn.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
- function hex(x) {
- return ('0' + parseInt(x, 10).toString(16)).slice(-2);
- }
- return '#' + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
-}
-
-export function updateCodeTheme(theme) {
- const path = '/static/css/highlight/' + theme + '.css';
- const $link = $('link.code_theme');
- if (path !== $link.attr('href')) {
- changeCss('code.hljs', 'visibility: hidden');
- var xmlHTTP = new XMLHttpRequest();
- xmlHTTP.open('GET', path, true);
- xmlHTTP.onload = function onLoad() {
- $link.attr('href', path);
- if (isBrowserFirefox()) {
- $link.one('load', () => {
- changeCss('code.hljs', 'visibility: visible');
- });
- } else {
- changeCss('code.hljs', 'visibility: visible');
- }
- };
- xmlHTTP.send();
- }
-}
-
-export function placeCaretAtEnd(el) {
- el.focus();
- el.selectionStart = el.value.length;
- el.selectionEnd = el.value.length;
-
- return;
-}
-
-export function getCaretPosition(el) {
- if (el.selectionStart) {
- return el.selectionStart;
- } else if (document.selection) {
- el.focus();
-
- var r = document.selection.createRange();
- if (r == null) {
- return 0;
- }
-
- var re = el.createTextRange();
- var rc = re.duplicate();
- re.moveToBookmark(r.getBookmark());
- rc.setEndPoint('EndToStart', re);
-
- return rc.text.length;
- }
- return 0;
-}
-
-export function setSelectionRange(input, selectionStart, selectionEnd) {
- if (input.setSelectionRange) {
- input.focus();
- input.setSelectionRange(selectionStart, selectionEnd);
- } else if (input.createTextRange) {
- var range = input.createTextRange();
- range.collapse(true);
- range.moveEnd('character', selectionEnd);
- range.moveStart('character', selectionStart);
- range.select();
- }
-}
-
-export function setCaretPosition(input, pos) {
- setSelectionRange(input, pos, pos);
-}
-
-export function getSelectedText(input) {
- var selectedText;
- if (typeof document.selection !== 'undefined') {
- input.focus();
- var sel = document.selection.createRange();
- selectedText = sel.text;
- } else if (typeof input.selectionStart !== 'undefined') {
- var startPos = input.selectionStart;
- var endPos = input.selectionEnd;
- selectedText = input.value.substring(startPos, endPos);
- }
-
- return selectedText;
-}
-
-export function isValidUsername(name) {
- var error = '';
- if (!name) {
- error = 'This field is required';
- } else if (name.length < Constants.MIN_USERNAME_LENGTH || name.length > Constants.MAX_USERNAME_LENGTH) {
- error = 'Must be between ' + Constants.MIN_USERNAME_LENGTH + ' and ' + Constants.MAX_USERNAME_LENGTH + ' characters';
- } else if (!(/^[a-z0-9\.\-\_]+$/).test(name)) {
- error = "Must contain only letters, numbers, and the symbols '.', '-', and '_'.";
- } else if (!(/[a-z]/).test(name.charAt(0))) { //eslint-disable-line no-negated-condition
- error = 'First character must be a letter.';
- } else {
- for (var i = 0; i < Constants.RESERVED_USERNAMES.length; i++) {
- if (name === Constants.RESERVED_USERNAMES[i]) {
- error = 'Cannot use a reserved word as a username.';
- break;
- }
- }
- }
-
- return error;
-}
-
-export function updateAddressBar(channelName) {
- const teamURL = TeamStore.getCurrentTeamUrl();
- history.replaceState('data', '', teamURL + '/channels/' + channelName);
-}
-
-export function switchChannel(channel) {
- GlobalActions.emitChannelClickEvent(channel);
-
- updateAddressBar(channel.name);
-
- $('.inner-wrap').removeClass('move--right');
- $('.sidebar--left').removeClass('move--right');
-
- client.trackPage();
-
- return false;
-}
-
-export function isMobile() {
- return screen.width <= 768;
-}
-
-export function isComment(post) {
- if ('root_id' in post) {
- return post.root_id !== '' && post.root_id != null;
- }
- return false;
-}
-
-export function getDirectTeammate(channelId) {
- var userIds = ChannelStore.get(channelId).name.split('__');
- var curUserId = UserStore.getCurrentId();
- var teammate = {};
-
- if (userIds.length !== 2 || userIds.indexOf(curUserId) === -1) {
- return teammate;
- }
-
- for (var idx in userIds) {
- if (userIds[idx] !== curUserId) {
- teammate = UserStore.getProfile(userIds[idx]);
- break;
- }
- }
-
- return teammate;
-}
-
-Image.prototype.load = function imageLoad(url, progressCallback) {
- var self = this;
- var xmlHTTP = new XMLHttpRequest();
- xmlHTTP.open('GET', url, true);
- xmlHTTP.responseType = 'arraybuffer';
- xmlHTTP.onload = function onLoad() {
- var h = xmlHTTP.getAllResponseHeaders();
- var m = h.match(/^Content-Type\:\s*(.*?)$/mi);
- var mimeType = m[1] || 'image/png';
-
- var blob = new Blob([this.response], {type: mimeType});
- self.src = window.URL.createObjectURL(blob);
- };
- xmlHTTP.onprogress = function onprogress(e) {
- parseInt(self.completedPercentage = (e.loaded / e.total) * 100, 10);
- if (progressCallback) {
- progressCallback();
- }
- };
- xmlHTTP.onloadstart = function onloadstart() {
- self.completedPercentage = 0;
- };
- xmlHTTP.send();
-};
-
-Image.prototype.completedPercentage = 0;
-
-export function changeColor(colourIn, amt) {
- var hex = colourIn;
- var lum = amt;
-
- // validate hex string
- hex = String(hex).replace(/[^0-9a-f]/gi, '');
- if (hex.length < 6) {
- hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
- }
- lum = lum || 0;
-
- // convert to decimal and change luminosity
- var rgb = '#';
- var c;
- var i;
- for (i = 0; i < 3; i++) {
- c = parseInt(hex.substr(i * 2, 2), 16);
- c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
- rgb += ('00' + c).substr(c.length);
- }
-
- return rgb;
-}
-
-export function changeOpacity(oldColor, opacity) {
- var color = oldColor;
- if (color[0] === '#') {
- color = color.slice(1);
- }
-
- if (color.length === 3) {
- const tempColor = color;
- color = '';
-
- color += tempColor[0] + tempColor[0];
- color += tempColor[1] + tempColor[1];
- color += tempColor[2] + tempColor[2];
- }
-
- var r = parseInt(color.substring(0, 2), 16);
- var g = parseInt(color.substring(2, 4), 16);
- var b = parseInt(color.substring(4, 6), 16);
-
- return 'rgba(' + r + ',' + g + ',' + b + ',' + opacity + ')';
-}
-
-export function getFullName(user) {
- if (user.first_name && user.last_name) {
- return user.first_name + ' ' + user.last_name;
- } else if (user.first_name) {
- return user.first_name;
- } else if (user.last_name) {
- return user.last_name;
- }
-
- return '';
-}
-
-export function getDisplayName(user) {
- if (user.nickname && user.nickname.trim().length > 0) {
- return user.nickname;
- }
- var fullName = getFullName(user);
-
- if (fullName) {
- return fullName;
- }
-
- return user.username;
-}
-
-export function displayUsername(userId) {
- const user = UserStore.getProfile(userId);
- const nameFormat = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false');
-
- let username = '';
- if (user) {
- if (nameFormat === Constants.Preferences.DISPLAY_PREFER_NICKNAME) {
- username = user.nickname || getFullName(user);
- } else if (nameFormat === Constants.Preferences.DISPLAY_PREFER_FULL_NAME) {
- username = getFullName(user);
- }
- if (!username.trim().length) {
- username = user.username;
- }
- }
-
- return username;
-}
-
-//IE10 does not set window.location.origin automatically so this must be called instead when using it
-export function getWindowLocationOrigin() {
- var windowLocationOrigin = window.location.origin;
- if (!windowLocationOrigin) {
- windowLocationOrigin = window.location.protocol + '//' + window.location.hostname;
- if (window.location.port) {
- windowLocationOrigin += ':' + window.location.port;
- }
- }
- return windowLocationOrigin;
-}
-
-// Converts a file size in bytes into a human-readable string of the form '123MB'.
-export function fileSizeToString(bytes) {
- // it's unlikely that we'll have files bigger than this
- if (bytes > 1024 * 1024 * 1024 * 1024) {
- return Math.floor(bytes / (1024 * 1024 * 1024 * 1024)) + 'TB';
- } else if (bytes > 1024 * 1024 * 1024) {
- return Math.floor(bytes / (1024 * 1024 * 1024)) + 'GB';
- } else if (bytes > 1024 * 1024) {
- return Math.floor(bytes / (1024 * 1024)) + 'MB';
- } else if (bytes > 1024) {
- return Math.floor(bytes / 1024) + 'KB';
- }
-
- return bytes + 'B';
-}
-
-// Converts a filename (like those attached to Post objects) to a url that can be used to retrieve attachments from the server.
-export function getFileUrl(filename, isDownload) {
- const downloadParam = isDownload ? '?download=1' : '';
- return getWindowLocationOrigin() + '/api/v1/files/get' + filename + downloadParam;
-}
-
-// Gets the name of a file (including extension) from a given url or file path.
-export function getFileName(path) {
- var split = path.split('/');
- return split[split.length - 1];
-}
-
-// Gets the websocket port to use. Configurable on the server.
-export function getWebsocketPort(protocol) {
- if ((/^wss:/).test(protocol)) { // wss://
- return ':' + global.window.mm_config.WebsocketSecurePort;
- }
- if ((/^ws:/).test(protocol)) {
- return ':' + global.window.mm_config.WebsocketPort;
- }
- return '';
-}
-
-// Generates a RFC-4122 version 4 compliant globally unique identifier.
-export function generateId() {
- // implementation taken from http://stackoverflow.com/a/2117523
- var id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
-
- id = id.replace(/[xy]/g, function replaceRandom(c) {
- var r = Math.floor(Math.random() * 16);
-
- var v;
- if (c === 'x') {
- v = r;
- } else {
- v = r & 0x3 | 0x8;
- }
-
- return v.toString(16);
- });
-
- return id;
-}
-
-export function isBrowserFirefox() {
- return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
-}
-
-// Checks if browser is IE10 or IE11
-export function isBrowserIE() {
- if (window.navigator && window.navigator.userAgent) {
- var ua = window.navigator.userAgent;
-
- return ua.indexOf('Trident/7.0') > 0 || ua.indexOf('Trident/6.0') > 0;
- }
-
- return false;
-}
-
-export function isBrowserEdge() {
- return window.navigator && navigator.userAgent && navigator.userAgent.toLowerCase().indexOf('edge') > -1;
-}
-
-export function getDirectChannelName(id, otherId) {
- let handle;
-
- if (otherId > id) {
- handle = id + '__' + otherId;
- } else {
- handle = otherId + '__' + id;
- }
-
- return handle;
-}
-
-// Used to get the id of the other user from a DM channel
-export function getUserIdFromChannelName(channel) {
- var ids = channel.name.split('__');
- var otherUserId = '';
- if (ids[0] === UserStore.getCurrentId()) {
- otherUserId = ids[1];
- } else {
- otherUserId = ids[0];
- }
-
- return otherUserId;
-}
-
-// Returns true if the given channel is a direct channel between the current user and the given one
-export function isDirectChannelForUser(otherUserId, channel) {
- return channel.type === Constants.DM_CHANNEL && getUserIdFromChannelName(channel) === otherUserId;
-}
-
-export function importSlack(file, success, error) {
- var formData = new FormData();
- formData.append('file', file, file.name);
- formData.append('filesize', file.size);
- formData.append('importFrom', 'slack');
-
- client.importSlack(formData, success, error);
-}
-
-export function getTeamURLFromAddressBar() {
- return window.location.href.split('/channels')[0];
-}
-
-export function getShortenedTeamURL() {
- const teamURL = getTeamURLFromAddressBar();
- if (teamURL.length > 35) {
- return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length) + '/';
- }
- return teamURL + '/';
-}
-
-export function windowWidth() {
- return $(window).width();
-}
-
-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();
- }
- }
- );
- }
-}
-
-// Use when sorting multiple channels or teams by their `display_name` field
-export function sortByDisplayName(a, b) {
- let aDisplayName = '';
- let bDisplayName = '';
-
- if (a && a.display_name) {
- aDisplayName = a.display_name.toLowerCase();
- }
- if (b && b.display_name) {
- bDisplayName = b.display_name.toLowerCase();
- }
-
- if (aDisplayName < bDisplayName) {
- return -1;
- }
- if (aDisplayName > bDisplayName) {
- return 1;
- }
- return 0;
-}
-
-export function getChannelTerm(channelType) {
- let channelTerm = 'Channel';
- if (channelType === Constants.PRIVATE_CHANNEL) {
- channelTerm = 'Group';
- }
-
- return channelTerm;
-}
-
-export function getPostTerm(post) {
- let postTerm = 'Post';
- if (post.root_id) {
- postTerm = 'Comment';
- }
-
- return postTerm;
-}
-
-export function isFeatureEnabled(feature) {
- return PreferenceStore.getBool(Constants.Preferences.CATEGORY_ADVANCED_SETTINGS, Constants.FeatureTogglePrefix + feature.label);
-}
-
-export function isSystemMessage(post) {
- return post.type && (post.type.lastIndexOf(Constants.SYSTEM_MESSAGE_PREFIX) === 0);
-}
-
-export function fillArray(value, length) {
- const arr = [];
-
- for (let i = 0; i < length; i++) {
- arr.push(value);
- }
-
- return arr;
-}
-
-// Checks if a data transfer contains files not text, folders, etc..
-// Slightly modified from http://stackoverflow.com/questions/6848043/how-do-i-detect-a-file-is-being-dragged-rather-than-a-draggable-element-on-my-pa
-export function isFileTransfer(files) {
- if (isBrowserIE()) {
- return files.types != null && files.types.contains('Files');
- }
-
- return files.types != null && (files.types.indexOf ? files.types.indexOf('Files') !== -1 : files.types.contains('application/x-moz-file'));
-}
-
-export function clearFileInput(elm) {
- // clear file input for all modern browsers
- try {
- elm.value = '';
- if (elm.value) {
- elm.type = 'text';
- elm.type = 'file';
- }
- } catch (e) {
- // Do nothing
- }
-}
-
-export function languages() {
- return (
- [
- {
- value: 'en',
- name: 'English'
- },
- {
- value: 'es',
- name: 'EspaƱol (Beta)'
- },
- {
- value: 'pt',
- name: 'Portugues (Beta)'
- }
- ]
- );
-}
-
-export function isPostEphemeral(post) {
- return post.type === Constants.POST_TYPE_EPHEMERAL || post.state === Constants.POST_DELETED;
-}
-
-export function getRootId(post) {
- return post.root_id === '' ? post.id : post.root_id;
-}
-
-export function localizeMessage(id, defaultMessage) {
- const translations = LocalizationStore.getTranslations();
- if (translations) {
- const value = translations[id];
- if (value) {
- return value;
- }
- }
-
- if (defaultMessage) {
- return defaultMessage;
- }
-
- return id;
-}