mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
On Windows when pressing AltGr it will trigger event with same properties as left Ctrl key. Check explicitly that altKey is false otherwise on some keyboard layouts input of special characters is blocked.
1309 lines
54 KiB
JavaScript
1309 lines
54 KiB
JavaScript
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import $ from 'jquery';
|
|
import AppDispatcher from '../dispatcher/app_dispatcher.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 Client from 'client/web_client.jsx';
|
|
import * as UserAgent from 'utils/user_agent.jsx';
|
|
|
|
import {browserHistory} from 'react-router/es6';
|
|
import {FormattedMessage} from 'react-intl';
|
|
|
|
import icon50 from 'images/icon50x50.png';
|
|
import bing from 'images/bing.mp3';
|
|
|
|
import React from 'react';
|
|
|
|
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 isMac() {
|
|
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
|
}
|
|
|
|
export function cmdOrCtrlPressed(e) {
|
|
return (isMac() && e.metaKey) || (!isMac() && e.ctrlKey && !e.altKey);
|
|
}
|
|
|
|
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 isChannelAdmin(roles) {
|
|
if (isInRole(roles, 'channel_admin')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function isAdmin(roles) {
|
|
if (isInRole(roles, 'team_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 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, teamId, duration, silent) {
|
|
if (!('Notification' in window)) {
|
|
return;
|
|
}
|
|
|
|
let notificationDuration = Constants.DEFAULT_NOTIFICATION_DURATION;
|
|
if (duration != null) {
|
|
notificationDuration = duration;
|
|
}
|
|
|
|
if (Notification.permission === 'granted' || (Notification.permission === 'default' && !requestedNotificationPermission)) {
|
|
requestedNotificationPermission = true;
|
|
|
|
Notification.requestPermission((permission) => {
|
|
if (permission === 'granted') {
|
|
try {
|
|
var notification = new Notification(title, {body, tag: body, icon: icon50, requireInteraction: notificationDuration === 0, silent});
|
|
notification.onclick = () => {
|
|
window.focus();
|
|
if (channel && (channel.type === Constants.DM_CHANNEL || channel.type === Constants.GM_CHANNEL)) {
|
|
browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name);
|
|
} else if (channel) {
|
|
browserHistory.push(TeamStore.getTeamUrl(teamId) + '/channels/' + channel.name);
|
|
} else if (teamId) {
|
|
browserHistory.push(TeamStore.getTeamUrl(teamId) + '/channels/town-square');
|
|
} else {
|
|
browserHistory.push(TeamStore.getCurrentTeamUrl() + '/channels/town-square');
|
|
}
|
|
};
|
|
|
|
if (notificationDuration > 0) {
|
|
setTimeout(() => {
|
|
notification.close();
|
|
}, notificationDuration);
|
|
}
|
|
} catch (e) {
|
|
console.error(e); //eslint-disable-line no-console
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
var canDing = true;
|
|
|
|
export function ding() {
|
|
if (!UserAgent.isFirefox() && canDing) {
|
|
var audio = new Audio(bing);
|
|
audio.play();
|
|
canDing = false;
|
|
setTimeout(() => {
|
|
canDing = true;
|
|
}, 3000);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// returns Unix timestamp in milliseconds
|
|
export function getTimestamp() {
|
|
return Date.now();
|
|
}
|
|
|
|
// extracts links not styled by Markdown
|
|
export function extractFirstLink(text) {
|
|
const pattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/i;
|
|
let inText = text;
|
|
|
|
// strip out code blocks
|
|
inText = inText.replace(/`[^`]*`/g, '');
|
|
|
|
// strip out inline markdown images
|
|
inText = inText.replace(/!\[[^\]]*]\([^)]*\)/g, '');
|
|
|
|
const match = pattern.exec(inText);
|
|
if (match) {
|
|
return match[0].trim();
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
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 = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>'
|
|
};
|
|
var newtext = text;
|
|
for (var tag in tagsToReplace) {
|
|
if (Reflect.apply({}.hasOwnProperty, this, [tagsToReplace, tag])) {
|
|
var regex = new RegExp(tag, 'g');
|
|
newtext = newtext.replace(regex, tagsToReplace[tag]);
|
|
}
|
|
}
|
|
return newtext;
|
|
}
|
|
|
|
export function insertHtmlEntities(text) {
|
|
var tagsToReplace = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>'
|
|
};
|
|
var newtext = text;
|
|
for (var tag in tagsToReplace) {
|
|
if (Reflect.apply({}.hasOwnProperty, this, [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,
|
|
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 getFileIconPath(fileInfo) {
|
|
const fileType = getFileType(fileInfo.extension);
|
|
|
|
var icon;
|
|
if (fileType in Constants.ICON_FROM_TYPE) {
|
|
icon = Constants.ICON_FROM_TYPE[fileType];
|
|
} else {
|
|
icon = Constants.ICON_FROM_TYPE.other;
|
|
}
|
|
|
|
return icon;
|
|
}
|
|
|
|
export function getIconClassName(fileTypeIn) {
|
|
var fileType = fileTypeIn.toLowerCase();
|
|
|
|
if (fileType in Constants.ICON_NAME_FROM_TYPE) {
|
|
return Constants.ICON_NAME_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, name: filename, path: filePath};
|
|
}
|
|
|
|
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 isHexColor(value) {
|
|
return value && (/^#[0-9a-f]{3}([0-9a-f]{3})?$/i).test(value);
|
|
}
|
|
|
|
export function applyTheme(theme) {
|
|
if (theme.sidebarBg) {
|
|
changeCss('.sidebar--left, .sidebar--left .sidebar__divider .sidebar__divider__text, .app__body .modal .settings-modal .settings-table .settings-links, .app__body .sidebar--menu', 'background:' + theme.sidebarBg);
|
|
changeCss('body.app__body', 'scrollbar-face-color:' + theme.sidebarBg);
|
|
changeCss('@media(max-width: 768px){.app__body .modal .settings-modal:not(.settings-modal--tabless):not(.display--content) .modal-content', 'background:' + theme.sidebarBg);
|
|
}
|
|
|
|
if (theme.sidebarText) {
|
|
changeCss('.app__body .ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y', 'background:' + theme.sidebarText);
|
|
changeCss('.app__body .ps-container:hover .ps-scrollbar-y-rail:hover', 'background:' + changeOpacity(theme.sidebarText, 0.15));
|
|
changeCss('.sidebar--left .nav-pills__container li>a, .app__body .sidebar--right, .app__body .modal .settings-modal .nav-pills>li a', 'color:' + changeOpacity(theme.sidebarText, 0.6));
|
|
changeCss('@media(max-width: 768px){.app__body .modal .settings-modal .settings-table .nav>li>a, .app__body .sidebar--menu', 'color:' + changeOpacity(theme.sidebarText, 0.8));
|
|
changeCss('.sidebar--left .nav-pills__container li>h4, .sidebar--left .add-channel-btn', 'color:' + changeOpacity(theme.sidebarText, 0.6));
|
|
changeCss('.sidebar--left .add-channel-btn:hover, .sidebar--left .add-channel-btn:focus', 'color:' + theme.sidebarText);
|
|
changeCss('.sidebar--left .status .offline--icon', 'fill:' + theme.sidebarText);
|
|
changeCss('.sidebar--left .status.status--group', 'background:' + changeOpacity(theme.sidebarText, 0.3));
|
|
changeCss('@media(max-width: 768px){.app__body .modal .settings-modal .settings-table .nav>li>a, .app__body .sidebar--menu .divider', 'border-color:' + changeOpacity(theme.sidebarText, 0.2));
|
|
changeCss('@media(max-width: 768px){.sidebar--left .add-channel-btn:hover, .sidebar--left .add-channel-btn:focus', 'color:' + changeOpacity(theme.sidebarText, 0.6));
|
|
}
|
|
|
|
if (theme.sidebarUnreadText) {
|
|
changeCss('.sidebar--left .nav-pills__container li>a.unread-title', 'color:' + theme.sidebarUnreadText + '!important;');
|
|
}
|
|
|
|
if (theme.sidebarTextHoverBg) {
|
|
changeCss('.sidebar--left .nav-pills__container li>a:hover, .app__body .modal .settings-modal .nav-pills>li:hover a', 'background:' + theme.sidebarTextHoverBg);
|
|
}
|
|
|
|
if (theme.sidebarTextActiveBorder) {
|
|
changeCss('.sidebar--left .nav li.active a:before, .app__body .modal .settings-modal .nav-pills>li.active a:before', 'background:' + theme.sidebarTextActiveBorder);
|
|
changeCss('.sidebar--left .sidebar__divider:before', 'background:' + changeOpacity(theme.sidebarTextActiveBorder, 0.5));
|
|
changeCss('.sidebar--left .sidebar__divider', 'color:' + theme.sidebarTextActiveBorder);
|
|
changeCss('.multi-teams .team-sidebar .team-wrapper .team-container.active:before', 'background:' + theme.sidebarTextActiveBorder);
|
|
changeCss('.multi-teams .team-sidebar .team-wrapper .team-container.unread:before', 'background:' + theme.sidebarTextActiveBorder);
|
|
}
|
|
|
|
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, .app__body .modal .settings-modal .nav-pills>li.active a, .app__body .modal .settings-modal .nav-pills>li.active a:hover, .app__body .modal .settings-modal .nav-pills>li.active a:active', 'color:' + theme.sidebarTextActiveColor);
|
|
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));
|
|
changeCss('@media(max-width: 768px){.app__body .modal .settings-modal .nav-pills > li.active a', 'color:' + changeOpacity(theme.sidebarText, 0.8));
|
|
}
|
|
|
|
if (theme.sidebarHeaderBg) {
|
|
changeCss('.sidebar--left .team__header, .app__body .sidebar--menu .team__header, .app__body .post-list__timestamp > div', 'background:' + theme.sidebarHeaderBg);
|
|
changeCss('.app__body .modal .modal-header', 'background:' + theme.sidebarHeaderBg);
|
|
changeCss('.app__body .multi-teams .team-sidebar, .app__body #navbar .navbar-default', 'background:' + theme.sidebarHeaderBg);
|
|
changeCss('@media(max-width: 768px){.app__body .search-bar__container', 'background:' + theme.sidebarHeaderBg);
|
|
changeCss('.app__body .attachment .attachment__container', 'border-left-color:' + theme.sidebarHeaderBg);
|
|
}
|
|
|
|
if (theme.sidebarHeaderTextColor) {
|
|
changeCss('.multi-teams .team-sidebar .team-wrapper .team-container .team-btn, .sidebar--left .team__header .header__info, .app__body .sidebar--menu .team__header .header__info, .app__body .post-list__timestamp > div', 'color:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.app__body .sidebar-header-dropdown__icon', 'fill:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.sidebar--left .team__header .user__name, .app__body .sidebar--menu .team__header .user__name', 'color:' + changeOpacity(theme.sidebarHeaderTextColor, 0.8));
|
|
changeCss('.sidebar--left .team__header:hover .user__name, .app__body .sidebar--menu .team__header:hover .user__name', 'color:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.app__body .modal .modal-header .modal-title, .app__body .modal .modal-header .modal-title .name, .app__body .modal .modal-header button.close', 'color:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.app__body #navbar .navbar-default .navbar-brand .heading', 'color:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.app__body #navbar .navbar-default .navbar-toggle .icon-bar', 'background:' + theme.sidebarHeaderTextColor);
|
|
changeCss('.app__body .post-list__timestamp > div', 'border-color:' + changeOpacity(theme.sidebarHeaderTextColor, 0.5));
|
|
changeCss('@media(max-width: 768px){.app__body .search-bar__container', 'color:' + theme.sidebarHeaderTextColor);
|
|
}
|
|
|
|
if (theme.onlineIndicator) {
|
|
changeCss('.app__body .status .online--icon', 'fill:' + theme.onlineIndicator);
|
|
changeCss('.app__body .channel-header__info .status .online--icon', 'fill:' + theme.onlineIndicator);
|
|
changeCss('.app__body .navbar .status .online--icon', 'fill:' + theme.onlineIndicator);
|
|
}
|
|
|
|
if (theme.awayIndicator) {
|
|
changeCss('.app__body .status .away--icon', 'fill:' + theme.awayIndicator);
|
|
changeCss('.app__body .channel-header__info .status .away--icon', 'fill:' + theme.awayIndicator);
|
|
changeCss('.app__body .navbar .status .away--icon', 'fill:' + theme.awayIndicator);
|
|
}
|
|
|
|
if (theme.mentionBj) {
|
|
changeCss('.sidebar--left .nav-pills__unread-indicator, .app__body .new-messages__button div', 'background:' + theme.mentionBj);
|
|
changeCss('.sidebar--left .badge', 'background:' + theme.mentionBj + '!important;');
|
|
changeCss('.multi-teams .team-sidebar .team-wrapper .team-container .team-btn .badge', 'background:' + theme.mentionBj + '!important;');
|
|
}
|
|
|
|
if (theme.mentionColor) {
|
|
changeCss('.sidebar--left .nav-pills__unread-indicator, .app__body .new-messages__button div', 'color:' + theme.mentionColor);
|
|
changeCss('.sidebar--left .badge', 'color:' + theme.mentionColor + '!important;');
|
|
changeCss('.multi-teams .team-sidebar .team-wrapper .team-container .team-btn .badge', 'color:' + theme.mentionColor + '!important;');
|
|
}
|
|
|
|
if (theme.centerChannelBg) {
|
|
changeCss('@media(min-width: 768px){.app__body .post:hover .post__header .col__reply, .app__body .post.post--hovered .post__header .col__reply', 'background:' + theme.centerChannelBg);
|
|
changeCss('@media(max-width: 320px){.tutorial-steps__container', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .app__content, .app__body .markdown__table, .app__body .markdown__table tbody tr, .app__body .suggestion-list__content, .app__body .modal .modal-content, .app__body .modal .modal-footer, .app__body .post.post--compact .post-image__column, .app__body .suggestion-list__divider > span, .app__body .status-wrapper .status', 'background:' + theme.centerChannelBg);
|
|
changeCss('#post-list .post-list-holder-by-time, .app__body .post .dropdown-menu a', 'background:' + theme.centerChannelBg);
|
|
changeCss('#post-create', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .date-separator .separator__text, .app__body .new-separator .separator__text', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .post-image__details, .app__body .search-help-popover .search-autocomplete__divider span', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .sidebar--right, .app__body .dropdown-menu, .app__body .popover, .app__body .tip-overlay', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .popover.bottom>.arrow:after', 'border-bottom-color:' + theme.centerChannelBg);
|
|
changeCss('.app__body .popover.right>.arrow:after, .app__body .tip-overlay.tip-overlay--sidebar .arrow, .app__body .tip-overlay.tip-overlay--header .arrow', 'border-right-color:' + theme.centerChannelBg);
|
|
changeCss('.app__body .popover.left>.arrow:after', 'border-left-color:' + theme.centerChannelBg);
|
|
changeCss('.app__body .popover.top>.arrow:after, .app__body .tip-overlay.tip-overlay--chat .arrow', 'border-top-color:' + theme.centerChannelBg);
|
|
changeCss('@media(min-width: 768px){.app__body .search-bar__container .search__form .search-bar, .app__body .form-control', 'background:' + theme.centerChannelBg);
|
|
changeCss('@media(min-width: 768px){.app__body .sidebar--right.sidebar--right--expanded .sidebar-right-container', 'background:' + theme.centerChannelBg);
|
|
changeCss('.app__body .attachment__content', 'background:' + theme.centerChannelBg);
|
|
changeCss('body.app__body', 'scrollbar-face-color:' + theme.centerChannelBg);
|
|
changeCss('body.app__body', 'scrollbar-track-color:' + theme.centerChannelBg);
|
|
changeCss('.app__body .post-list__new-messages-below', 'color:' + theme.centerChannelBg);
|
|
}
|
|
|
|
if (theme.centerChannelColor) {
|
|
changeCss('.app__body .mentions__name .status.status--group, .app__body .multi-select__note', 'background:' + changeOpacity(theme.centerChannelColor, 0.12));
|
|
changeCss('.app__body .post-list__arrows, .app__body .post .flag-icon__container', 'fill:' + changeOpacity(theme.centerChannelColor, 0.3));
|
|
changeCss('.app__body .modal .status .offline--icon, .app__body .channel-header__links .icon, .app__body .sidebar--right .sidebar--right__subheader .usage__icon', 'fill:' + theme.centerChannelColor);
|
|
changeCss('@media(min-width: 768px){.app__body .post:hover .post__header .col__reply, .app__body .post.post--hovered .post__header .col__reply', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .post .dropdown-menu a, .sidebar--left, .app__body .sidebar--right .sidebar--right__header, .app__body .suggestion-list__content .command', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .post.post--system .post__body', 'color:' + changeOpacity(theme.centerChannelColor, 0.6));
|
|
changeCss('.app__body .input-group-addon, .app__body .app__content, .app__body .post-create__container .post-create-body .btn-file, .app__body .post-create__container .post-create-footer .msg-typing, .app__body .suggestion-list__content .command, .app__body .modal .modal-content, .app__body .dropdown-menu, .app__body .popover, .app__body .mentions__name, .app__body .tip-overlay, .app__body .form-control[disabled], .app__body .form-control[readonly], .app__body fieldset[disabled] .form-control', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .post .post__link', 'color:' + changeOpacity(theme.centerChannelColor, 0.65));
|
|
changeCss('.app__body #archive-link-home, .video-div .video-thumbnail__error', 'background:' + changeOpacity(theme.centerChannelColor, 0.15));
|
|
changeCss('.app__body #post-create', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .mentions--top, .app__body .suggestion-list', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px');
|
|
changeCss('.app__body .mentions--top, .app__body .suggestion-list', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px');
|
|
changeCss('.app__body .mentions--top, .app__body .suggestion-list', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.2) + ' 1px -3px 12px');
|
|
changeCss('.app__body .dropdown-menu, .app__body .popover ', 'box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px');
|
|
changeCss('.app__body .dropdown-menu, .app__body .popover ', '-webkit-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px');
|
|
changeCss('.app__body .dropdown-menu, .app__body .popover ', '-moz-box-shadow:' + changeOpacity(theme.centerChannelColor, 0.1) + ' 0px 6px 12px');
|
|
changeCss('.app__body .post__body hr, .app__body .loading-screen .loading__content .round, .app__body .tutorial__circles .circle', 'background:' + theme.centerChannelColor);
|
|
changeCss('.app__body .channel-header .heading', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .markdown__table tbody tr:nth-child(2n)', 'background:' + changeOpacity(theme.centerChannelColor, 0.07));
|
|
changeCss('.app__body .channel-header__info>div.dropdown .header-dropdown__icon', 'color:' + changeOpacity(theme.centerChannelColor, 0.8));
|
|
changeCss('.app__body .channel-header #member_popover', 'color:' + changeOpacity(theme.centerChannelColor, 0.8));
|
|
changeCss('.app__body .custom-textarea, .app__body .custom-textarea:focus, .app__body .file-preview, .app__body .post-image__details, .app__body .sidebar--right .sidebar-right__body, .app__body .markdown__table th, .app__body .markdown__table td, .app__body .suggestion-list__content, .app__body .modal .modal-content, .app__body .modal .settings-modal .settings-table .settings-content .divider-light, .app__body .webhooks__container, .app__body .dropdown-menu, .app__body .modal .modal-header, .app__body .popover', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .popover.bottom>.arrow', 'border-bottom-color:' + changeOpacity(theme.centerChannelColor, 0.25));
|
|
changeCss('.app__body .search-help-popover .search-autocomplete__divider span, .app__body .suggestion-list__divider > span', 'color:' + changeOpacity(theme.centerChannelColor, 0.7));
|
|
changeCss('.app__body .popover.right>.arrow', 'border-right-color:' + changeOpacity(theme.centerChannelColor, 0.25));
|
|
changeCss('.app__body .popover.left>.arrow', 'border-left-color:' + changeOpacity(theme.centerChannelColor, 0.25));
|
|
changeCss('.app__body .popover.top>.arrow', 'border-top-color:' + changeOpacity(theme.centerChannelColor, 0.25));
|
|
changeCss('.app__body .suggestion-list__content .command, .app__body .popover .popover-title', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .suggestion-list__content .command, .app__body .popover .popover__row', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .suggestion-list__divider:before, .app__body .dropdown-menu .divider, .app__body .search-help-popover .search-autocomplete__divider:before', 'background:' + theme.centerChannelColor);
|
|
changeCss('.app__body .custom-textarea', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .post-image__details', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .post-image__column a, .app__body .post-image__column a:hover, .app__body .post-image__column a:focus', 'color:' + theme.centerChannelColor);
|
|
changeCss('@media(min-width: 768px){.app__body .search-bar__container .search__form .search-bar, .app__body .form-control', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .input-group-addon, .app__body .search-bar__container .search__form, .app__body .form-control', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('@media(min-width: 768px){.app__body .post-list__table .post-list__content .dropdown-menu a:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.1));
|
|
changeCss('.app__body .form-control:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3));
|
|
changeCss('.app__body .attachment .attachment__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3));
|
|
changeCss('.app__body .input-group-addon, .app__body .channel-intro .channel-intro__content, .app__body .webhooks__container', 'background:' + changeOpacity(theme.centerChannelColor, 0.05));
|
|
changeCss('.app__body .date-separator .separator__text', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .date-separator .separator__hr, .app__body .modal-footer, .app__body .modal .custom-textarea', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .search-item-container, .app__body .post-right__container .post.post--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1));
|
|
changeCss('.app__body .modal .custom-textarea:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3));
|
|
changeCss('.app__body .channel-intro, .app__body .modal .settings-modal .settings-table .settings-content .divider-dark, .app__body hr, .app__body .modal .settings-modal .settings-table .settings-links, .app__body .modal .settings-modal .settings-table .settings-content .appearance-section .theme-elements__header, .app__body .user-settings .authorized-app:not(:last-child)', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .post.current--user .post__body, .app__body .post.post--comment.other--root.current--user .post-comment, .app__body pre, .app__body .post-right__container .post.post--root', 'background:' + changeOpacity(theme.centerChannelColor, 0.05));
|
|
changeCss('.app__body .post.post--comment.other--root.current--user .post-comment, .app__body .more-modal__list .more-modal__row, .app__body .member-div:first-child, .app__body .member-div, .app__body .access-history__table .access__report, .app__body .activity-log__table', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1));
|
|
changeCss('@media(max-width: 1800px){.app__body .inner-wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07));
|
|
changeCss('.app__body .post.post--hovered', 'background:' + changeOpacity(theme.centerChannelColor, 0.08));
|
|
changeCss('@media(min-width: 768px){.app__body .post:hover, .app__body .more-modal__list .more-modal__row:hover, .app__body .modal .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.08));
|
|
changeCss('.app__body .more-modal__row.more-modal__row--selected, .app__body .date-separator.hovered--before:after, .app__body .date-separator.hovered--after:before, .app__body .new-separator.hovered--after:before, .app__body .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07));
|
|
changeCss('@media(min-width: 768px){.app__body .suggestion-list__content .command:hover, .app__body .mentions__name:hover, .app__body .dropdown-menu>li>a:focus, .app__body .dropdown-menu>li>a:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.15));
|
|
changeCss('.app__body .suggestion--selected, .app__body .bot-indicator', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
|
|
changeCss('code, .app__body .form-control[disabled], .app__body .form-control[readonly], .app__body fieldset[disabled] .form-control', 'background:' + changeOpacity(theme.centerChannelColor, 0.1));
|
|
changeCss('@media(min-width: 960px){.app__body .post.current--user:hover .post__body ', 'background: none;');
|
|
changeCss('.app__body .sidebar--right', 'color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .search-help-popover .search-autocomplete__item:hover, .app__body .modal .settings-modal .settings-table .settings-content .appearance-section .theme-elements__body', 'background:' + changeOpacity(theme.centerChannelColor, 0.05));
|
|
changeCss('.app__body .search-help-popover .search-autocomplete__item.selected', 'background:' + changeOpacity(theme.centerChannelColor, 0.15));
|
|
if (!UserAgent.isFirefox() && !UserAgent.isInternetExplorer() && !UserAgent.isEdge()) {
|
|
changeCss('body.app__body ::-webkit-scrollbar-thumb', 'background:' + changeOpacity(theme.centerChannelColor, 0.4), 1);
|
|
}
|
|
changeCss('body', 'scrollbar-arrow-color:' + theme.centerChannelColor);
|
|
changeCss('.app__body .post-create__container .post-create-body .btn-file svg, .app__body .post.post--compact .post-image__column .post-image__details svg, .app__body .modal .about-modal .about-modal__logo svg, .app__body .post .post__img svg', 'fill:' + theme.centerChannelColor);
|
|
changeCss('.app__body .scrollbar--horizontal, .app__body .scrollbar--vertical', 'background:' + changeOpacity(theme.centerChannelColor, 0.5));
|
|
changeCss('.app__body .post-list__new-messages-below', 'background:' + changeColor(theme.centerChannelColor, 0.5));
|
|
changeCss('.app__body .post.post--comment .post__body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('@media(min-width: 768px){.app__body .post.post--compact.same--root.post--comment .post__content', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .post.post--comment.current--user .post__body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2));
|
|
changeCss('.app__body .channel-header__info .status .offline--icon', 'fill:' + theme.centerChannelColor);
|
|
changeCss('.app__body .navbar .status .offline--icon', 'fill:' + theme.centerChannelColor);
|
|
changeCss('.app__body .post-reaction:not(.post-reaction--current-user)', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.25));
|
|
changeCss('.app__body .post-reaction:not(.post-reaction--current-user)', 'color:' + changeOpacity(theme.centerChannelColor, 0.7));
|
|
}
|
|
|
|
if (theme.newMessageSeparator) {
|
|
changeCss('.app__body .new-separator .separator__text', 'color:' + theme.newMessageSeparator);
|
|
changeCss('.app__body .new-separator .separator__hr', 'border-color:' + changeOpacity(theme.newMessageSeparator, 0.5));
|
|
}
|
|
|
|
if (theme.linkColor) {
|
|
changeCss('.app__body a, .app__body a:focus, .app__body a:hover, .app__body .btn, .app__body .btn:focus, .app__body .btn:hover', 'color:' + theme.linkColor);
|
|
changeCss('.app__body .attachment .attachment__container', 'border-left-color:' + changeOpacity(theme.linkColor, 0.5));
|
|
changeCss('.app__body .channel-header__links .icon:hover, .app__body .post .flag-icon__container.visible, .app__body .post .comment-icon__container, .app__body .post .post__reply', 'fill:' + theme.linkColor);
|
|
changeCss('.app__body .post-reaction.post-reaction--current-user', 'background:' + changeOpacity(theme.linkColor, 0.1));
|
|
changeCss('.app__body .post-reaction.post-reaction--current-user', 'border-color:' + changeOpacity(theme.linkColor, 0.4));
|
|
changeCss('.app__body .post-reaction.post-reaction--current-user', 'color:' + theme.linkColor);
|
|
}
|
|
|
|
if (theme.buttonBg) {
|
|
changeCss('.app__body .btn.btn-primary, .app__body .tutorial__circles .circle.active', 'background:' + theme.buttonBg);
|
|
changeCss('.app__body .btn.btn-primary:hover, .app__body .btn.btn-primary:active, .app__body .btn.btn-primary:focus', 'background:' + changeColor(theme.buttonBg, -0.25));
|
|
}
|
|
|
|
if (theme.buttonColor) {
|
|
changeCss('.app__body .btn.btn-primary', 'color:' + theme.buttonColor);
|
|
}
|
|
|
|
if (theme.mentionHighlightBg) {
|
|
changeCss('.app__body .mention--highlight, .app__body .search-highlight', 'background:' + theme.mentionHighlightBg);
|
|
changeCss('.mention-comment', 'border-color:' + theme.mentionHighlightBg + ' !important');
|
|
changeCss('.app__body .post.post--highlight', 'background:' + changeOpacity(theme.mentionHighlightBg, 0.5));
|
|
}
|
|
|
|
if (theme.mentionHighlightLink) {
|
|
changeCss('.app__body .mention--highlight .mention-link, .app__body .mention--highlight, .app__body .search-highlight', 'color:' + theme.mentionHighlightLink);
|
|
}
|
|
|
|
if (!theme.codeTheme) {
|
|
theme.codeTheme = Constants.DEFAULT_CODE_THEME;
|
|
}
|
|
updateCodeTheme(theme.codeTheme);
|
|
}
|
|
|
|
export function resetTheme() {
|
|
applyTheme(Constants.THEMES.default);
|
|
}
|
|
|
|
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) {
|
|
let styleEl = document.querySelector('style[data-class="' + className + '"]');
|
|
if (!styleEl) {
|
|
styleEl = document.createElement('style');
|
|
styleEl.setAttribute('data-class', className);
|
|
|
|
// Append style element to head
|
|
document.head.appendChild(styleEl);
|
|
}
|
|
|
|
// Grab style sheet
|
|
const styleSheet = styleEl.sheet;
|
|
const rules = styleSheet.cssRules || styleSheet.rules;
|
|
const style = classValue.substr(0, classValue.indexOf(':'));
|
|
const value = classValue.substr(classValue.indexOf(':') + 1);
|
|
|
|
for (let i = 0; i < rules.length; i++) {
|
|
if (rules[i].selectorText === className) {
|
|
rules[i].style[style] = value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
let mediaQuery = '';
|
|
if (className.indexOf('@media') >= 0) {
|
|
mediaQuery = '}';
|
|
}
|
|
styleSheet.insertRule(className + '{' + classValue + '}' + mediaQuery, styleSheet.cssRules.length);
|
|
}
|
|
|
|
export function updateCodeTheme(userTheme) {
|
|
let cssPath = '';
|
|
Constants.THEME_ELEMENTS.forEach((element) => {
|
|
if (element.id === 'codeTheme') {
|
|
element.themes.forEach((theme) => {
|
|
if (userTheme === theme.id) {
|
|
cssPath = theme.cssURL;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
const $link = $('link.code_theme');
|
|
if (cssPath !== $link.attr('href')) {
|
|
changeCss('code.hljs', 'visibility: hidden');
|
|
var xmlHTTP = new XMLHttpRequest();
|
|
xmlHTTP.open('GET', cssPath, true);
|
|
xmlHTTP.onload = function onLoad() {
|
|
$link.attr('href', cssPath);
|
|
if (UserAgent.isFirefox()) {
|
|
$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;
|
|
}
|
|
|
|
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 isMobile() {
|
|
return window.innerWidth <= Constants.MOBILE_SCREEN_WIDTH;
|
|
}
|
|
|
|
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) {
|
|
return displayUsernameForUser(UserStore.getProfile(userId));
|
|
}
|
|
|
|
export function displayUsernameForUser(user) {
|
|
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;
|
|
}
|
|
|
|
// 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';
|
|
}
|
|
|
|
// 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, (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 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 windowWidth() {
|
|
return $(window).width();
|
|
}
|
|
|
|
export function windowHeight() {
|
|
return $(window).height();
|
|
}
|
|
|
|
// Use when sorting multiple teams by their `display_name` field
|
|
export function sortTeamsByDisplayName(a, b) {
|
|
const locale = LocalizationStore.getLocale();
|
|
|
|
if (a.display_name !== b.display_name) {
|
|
return a.display_name.localeCompare(b.display_name, locale, {numeric: true});
|
|
}
|
|
|
|
return a.name.localeCompare(b.name, locale, {numeric: true});
|
|
}
|
|
|
|
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 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 (UserAgent.isInternetExplorer() || UserAgent.isEdge()) {
|
|
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 isPostEphemeral(post) {
|
|
return post.type === Constants.PostTypes.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;
|
|
}
|
|
|
|
export function mod(a, b) {
|
|
return ((a % b) + b) % b;
|
|
}
|
|
|
|
export function canCreateCustomEmoji(user) {
|
|
if (global.window.mm_license.IsLicensed !== 'true') {
|
|
return true;
|
|
}
|
|
|
|
if (isSystemAdmin(user.roles)) {
|
|
return true;
|
|
}
|
|
|
|
// already checked for system admin for both these cases
|
|
if (window.mm_config.RestrictCustomEmojiCreation === 'system_admin') {
|
|
return false;
|
|
} else if (window.mm_config.RestrictCustomEmojiCreation === 'admin') {
|
|
// check whether the user is an admin on any of their teams
|
|
if (TeamStore.isTeamAdminForAnyTeam()) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
export function isValidPassword(password) {
|
|
let errorMsg = '';
|
|
let errorId = 'user.settings.security.passwordError';
|
|
let error = false;
|
|
let minimumLength = Constants.MIN_PASSWORD_LENGTH;
|
|
|
|
if (global.window.mm_config.BuildEnterpriseReady === 'true' && global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
|
|
if (password.length < parseInt(global.window.mm_config.PasswordMinimumLength, 10) || password.length > Constants.MAX_PASSWORD_LENGTH) {
|
|
error = true;
|
|
}
|
|
|
|
if (global.window.mm_config.PasswordRequireLowercase === 'true') {
|
|
if (!password.match(/[a-z]/)) {
|
|
error = true;
|
|
}
|
|
|
|
errorId = errorId + 'Lowercase';
|
|
}
|
|
|
|
if (global.window.mm_config.PasswordRequireUppercase === 'true') {
|
|
if (!password.match(/[0-9]/)) {
|
|
error = true;
|
|
}
|
|
|
|
errorId = errorId + 'Uppercase';
|
|
}
|
|
|
|
if (global.window.mm_config.PasswordRequireNumber === 'true') {
|
|
if (!password.match(/[A-Z]/)) {
|
|
error = true;
|
|
}
|
|
|
|
errorId = errorId + 'Number';
|
|
}
|
|
|
|
if (global.window.mm_config.PasswordRequireSymbol === 'true') {
|
|
if (!password.match(/[ !"\\#$%&'()*+,-./:;<=>?@[\]^_`|~]/)) {
|
|
error = true;
|
|
}
|
|
|
|
errorId = errorId + 'Symbol';
|
|
}
|
|
|
|
minimumLength = global.window.mm_config.PasswordMinimumLength;
|
|
} else if (password.length < Constants.MIN_PASSWORD_LENGTH) {
|
|
error = true;
|
|
}
|
|
|
|
if (error) {
|
|
errorMsg = (
|
|
<FormattedMessage
|
|
id={errorId}
|
|
default='Your password must be at least {min} characters.'
|
|
values={{
|
|
min: minimumLength
|
|
}}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return errorMsg;
|
|
}
|
|
|
|
export function handleFormattedTextClick(e) {
|
|
const mentionAttribute = e.target.getAttributeNode('data-mention');
|
|
const hashtagAttribute = e.target.getAttributeNode('data-hashtag');
|
|
const linkAttribute = e.target.getAttributeNode('data-link');
|
|
const channelMentionAttribute = e.target.getAttributeNode('data-channel-mention');
|
|
|
|
if (mentionAttribute) {
|
|
e.preventDefault();
|
|
|
|
searchForTerm(mentionAttribute.value);
|
|
} else if (hashtagAttribute) {
|
|
e.preventDefault();
|
|
|
|
searchForTerm(hashtagAttribute.value);
|
|
} else if (linkAttribute) {
|
|
const MIDDLE_MOUSE_BUTTON = 1;
|
|
|
|
if (!(e.button === MIDDLE_MOUSE_BUTTON || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)) {
|
|
e.preventDefault();
|
|
|
|
browserHistory.push(linkAttribute.value);
|
|
}
|
|
} else if (channelMentionAttribute) {
|
|
e.preventDefault();
|
|
browserHistory.push('/' + TeamStore.getCurrent().name + '/channels/' + channelMentionAttribute.value);
|
|
}
|
|
}
|
|
|
|
export function isEmptyObject(object) {
|
|
if (!object) {
|
|
return true;
|
|
}
|
|
|
|
if (Object.keys(object).length === 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function updateWindowDimensions(component) {
|
|
component.setState({width: window.innerWidth, height: window.innerHeight});
|
|
}
|