merging files
Этот коммит содержится в:
192
webapp/stores/admin_store.jsx
Обычный файл
192
webapp/stores/admin_store.jsx
Обычный файл
@@ -0,0 +1,192 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const LOG_CHANGE_EVENT = 'log_change';
|
||||
const SERVER_AUDIT_CHANGE_EVENT = 'server_audit_change';
|
||||
const CONFIG_CHANGE_EVENT = 'config_change';
|
||||
const ALL_TEAMS_EVENT = 'all_team_change';
|
||||
const SERVER_COMPLIANCE_REPORT_CHANGE_EVENT = 'server_compliance_reports_change';
|
||||
|
||||
class AdminStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.logs = null;
|
||||
this.audits = null;
|
||||
this.config = null;
|
||||
this.teams = null;
|
||||
this.complianceReports = null;
|
||||
|
||||
this.emitLogChange = this.emitLogChange.bind(this);
|
||||
this.addLogChangeListener = this.addLogChangeListener.bind(this);
|
||||
this.removeLogChangeListener = this.removeLogChangeListener.bind(this);
|
||||
|
||||
this.emitAuditChange = this.emitAuditChange.bind(this);
|
||||
this.addAuditChangeListener = this.addAuditChangeListener.bind(this);
|
||||
this.removeAuditChangeListener = this.removeAuditChangeListener.bind(this);
|
||||
|
||||
this.emitComplianceReportsChange = this.emitComplianceReportsChange.bind(this);
|
||||
this.addComplianceReportsChangeListener = this.addComplianceReportsChangeListener.bind(this);
|
||||
this.removeComplianceReportsChangeListener = this.removeComplianceReportsChangeListener.bind(this);
|
||||
|
||||
this.emitConfigChange = this.emitConfigChange.bind(this);
|
||||
this.addConfigChangeListener = this.addConfigChangeListener.bind(this);
|
||||
this.removeConfigChangeListener = this.removeConfigChangeListener.bind(this);
|
||||
|
||||
this.emitAllTeamsChange = this.emitAllTeamsChange.bind(this);
|
||||
this.addAllTeamsChangeListener = this.addAllTeamsChangeListener.bind(this);
|
||||
this.removeAllTeamsChangeListener = this.removeAllTeamsChangeListener.bind(this);
|
||||
}
|
||||
|
||||
emitLogChange() {
|
||||
this.emit(LOG_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addLogChangeListener(callback) {
|
||||
this.on(LOG_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeLogChangeListener(callback) {
|
||||
this.removeListener(LOG_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitAuditChange() {
|
||||
this.emit(SERVER_AUDIT_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addAuditChangeListener(callback) {
|
||||
this.on(SERVER_AUDIT_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeAuditChangeListener(callback) {
|
||||
this.removeListener(SERVER_AUDIT_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitComplianceReportsChange() {
|
||||
this.emit(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addComplianceReportsChangeListener(callback) {
|
||||
this.on(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeComplianceReportsChangeListener(callback) {
|
||||
this.removeListener(SERVER_COMPLIANCE_REPORT_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitConfigChange() {
|
||||
this.emit(CONFIG_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addConfigChangeListener(callback) {
|
||||
this.on(CONFIG_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeConfigChangeListener(callback) {
|
||||
this.removeListener(CONFIG_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitAllTeamsChange() {
|
||||
this.emit(ALL_TEAMS_EVENT);
|
||||
}
|
||||
|
||||
addAllTeamsChangeListener(callback) {
|
||||
this.on(ALL_TEAMS_EVENT, callback);
|
||||
}
|
||||
|
||||
removeAllTeamsChangeListener(callback) {
|
||||
this.removeListener(ALL_TEAMS_EVENT, callback);
|
||||
}
|
||||
|
||||
getLogs() {
|
||||
return this.logs;
|
||||
}
|
||||
|
||||
saveLogs(logs) {
|
||||
this.logs = logs;
|
||||
}
|
||||
|
||||
getAudits() {
|
||||
return this.audits;
|
||||
}
|
||||
|
||||
saveAudits(audits) {
|
||||
this.audits = audits;
|
||||
}
|
||||
|
||||
getComplianceReports() {
|
||||
return this.complianceReports;
|
||||
}
|
||||
|
||||
saveComplianceReports(complianceReports) {
|
||||
this.complianceReports = complianceReports;
|
||||
}
|
||||
|
||||
getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
||||
saveConfig(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
getAllTeams() {
|
||||
return this.teams;
|
||||
}
|
||||
|
||||
saveAllTeams(teams) {
|
||||
this.teams = teams;
|
||||
}
|
||||
|
||||
getSelectedTeams() {
|
||||
const result = BrowserStore.getItem('seleted_teams');
|
||||
if (!result) {
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
saveSelectedTeams(teams) {
|
||||
BrowserStore.setItem('seleted_teams', teams);
|
||||
}
|
||||
}
|
||||
|
||||
var AdminStore = new AdminStoreClass();
|
||||
|
||||
AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_LOGS:
|
||||
AdminStore.saveLogs(action.logs);
|
||||
AdminStore.emitLogChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_SERVER_AUDITS:
|
||||
AdminStore.saveAudits(action.audits);
|
||||
AdminStore.emitAuditChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_SERVER_COMPLIANCE_REPORTS:
|
||||
AdminStore.saveComplianceReports(action.complianceReports);
|
||||
AdminStore.emitComplianceReportsChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_CONFIG:
|
||||
AdminStore.saveConfig(action.config);
|
||||
AdminStore.emitConfigChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ALL_TEAMS:
|
||||
AdminStore.saveAllTeams(action.teams);
|
||||
AdminStore.emitAllTeamsChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default AdminStore;
|
||||
85
webapp/stores/analytics_store.jsx
Обычный файл
85
webapp/stores/analytics_store.jsx
Обычный файл
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
class AnalyticsStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.systemStats = {};
|
||||
this.teamStats = {};
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
getAllSystem() {
|
||||
return JSON.parse(JSON.stringify(this.systemStats));
|
||||
}
|
||||
|
||||
getAllTeam(id) {
|
||||
if (id in this.teamStats) {
|
||||
return JSON.parse(JSON.stringify(this.teamStats[id]));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
storeSystemStats(newStats) {
|
||||
for (const stat in newStats) {
|
||||
if (!newStats.hasOwnProperty(stat)) {
|
||||
continue;
|
||||
}
|
||||
this.systemStats[stat] = newStats[stat];
|
||||
}
|
||||
}
|
||||
|
||||
storeTeamStats(id, newStats) {
|
||||
if (!(id in this.teamStats)) {
|
||||
this.teamStats[id] = {};
|
||||
}
|
||||
|
||||
for (const stat in newStats) {
|
||||
if (!newStats.hasOwnProperty(stat)) {
|
||||
continue;
|
||||
}
|
||||
this.teamStats[id][stat] = newStats[stat];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var AnalyticsStore = new AnalyticsStoreClass();
|
||||
|
||||
AnalyticsStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_ANALYTICS:
|
||||
if (action.teamId == null) {
|
||||
AnalyticsStore.storeSystemStats(action.stats);
|
||||
} else {
|
||||
AnalyticsStore.storeTeamStats(action.teamId, action.stats);
|
||||
}
|
||||
AnalyticsStore.emitChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default AnalyticsStore;
|
||||
225
webapp/stores/browser_store.jsx
Обычный файл
225
webapp/stores/browser_store.jsx
Обычный файл
@@ -0,0 +1,225 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {generateId} from 'utils/utils.jsx';
|
||||
|
||||
function getPrefix() {
|
||||
if (global.window.mm_current_user_id) {
|
||||
return global.window.mm_current_user_id + '_';
|
||||
}
|
||||
|
||||
return 'unknown_';
|
||||
}
|
||||
|
||||
class BrowserStoreClass {
|
||||
constructor() {
|
||||
this.getItem = this.getItem.bind(this);
|
||||
this.setItem = this.setItem.bind(this);
|
||||
this.removeItem = this.removeItem.bind(this);
|
||||
this.setGlobalItem = this.setGlobalItem.bind(this);
|
||||
this.getGlobalItem = this.getGlobalItem.bind(this);
|
||||
this.removeGlobalItem = this.removeGlobalItem.bind(this);
|
||||
this.actionOnItemsWithPrefix = this.actionOnItemsWithPrefix.bind(this);
|
||||
this.actionOnGlobalItemsWithPrefix = this.actionOnGlobalItemsWithPrefix.bind(this);
|
||||
this.isLocalStorageSupported = this.isLocalStorageSupported.bind(this);
|
||||
this.getLastServerVersion = this.getLastServerVersion.bind(this);
|
||||
this.setLastServerVersion = this.setLastServerVersion.bind(this);
|
||||
this.clear = this.clear.bind(this);
|
||||
this.clearAll = this.clearAll.bind(this);
|
||||
this.checkedLocalStorageSupported = '';
|
||||
this.signalLogout = this.signalLogout.bind(this);
|
||||
this.isSignallingLogout = this.isSignallingLogout.bind(this);
|
||||
this.signalLogin = this.signalLogin.bind(this);
|
||||
this.isSignallingLogin = this.isSignallingLogin.bind(this);
|
||||
}
|
||||
|
||||
checkVersion() {
|
||||
var currentVersion = sessionStorage.getItem('storage_version');
|
||||
if (currentVersion !== global.window.mm_config.Version) {
|
||||
sessionStorage.clear();
|
||||
try {
|
||||
sessionStorage.setItem('storage_version', global.window.mm_config.Version);
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getItem(name, defaultValue) {
|
||||
var result = null;
|
||||
try {
|
||||
result = JSON.parse(sessionStorage.getItem(getPrefix() + name));
|
||||
} catch (err) {
|
||||
result = null;
|
||||
}
|
||||
|
||||
if (result === null && typeof defaultValue !== 'undefined') {
|
||||
result = defaultValue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
setItem(name, value) {
|
||||
sessionStorage.setItem(getPrefix() + name, JSON.stringify(value));
|
||||
}
|
||||
|
||||
removeItem(name) {
|
||||
sessionStorage.removeItem(getPrefix() + name);
|
||||
}
|
||||
|
||||
setGlobalItem(name, value) {
|
||||
try {
|
||||
if (this.isLocalStorageSupported()) {
|
||||
localStorage.setItem(getPrefix() + name, JSON.stringify(value));
|
||||
} else {
|
||||
sessionStorage.setItem(getPrefix() + name, JSON.stringify(value));
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('An error occurred while setting local storage, clearing all props'); //eslint-disable-line no-console
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
window.location.reload(true);
|
||||
}
|
||||
}
|
||||
|
||||
getGlobalItem(name, defaultValue) {
|
||||
var result = null;
|
||||
try {
|
||||
if (this.isLocalStorageSupported()) {
|
||||
result = JSON.parse(localStorage.getItem(getPrefix() + name));
|
||||
} else {
|
||||
result = JSON.parse(sessionStorage.getItem(getPrefix() + name));
|
||||
}
|
||||
} catch (err) {
|
||||
result = null;
|
||||
}
|
||||
|
||||
if (result === null && typeof defaultValue !== 'undefined') {
|
||||
result = defaultValue;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
removeGlobalItem(name) {
|
||||
if (this.isLocalStorageSupported()) {
|
||||
localStorage.removeItem(getPrefix() + name);
|
||||
} else {
|
||||
sessionStorage.removeItem(getPrefix() + name);
|
||||
}
|
||||
}
|
||||
|
||||
getLastServerVersion() {
|
||||
return sessionStorage.getItem('last_server_version');
|
||||
}
|
||||
|
||||
setLastServerVersion(version) {
|
||||
sessionStorage.setItem('last_server_version', version);
|
||||
}
|
||||
|
||||
signalLogout() {
|
||||
if (this.isLocalStorageSupported()) {
|
||||
// PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11
|
||||
const logoutId = generateId();
|
||||
|
||||
sessionStorage.setItem('__logout__', logoutId);
|
||||
localStorage.setItem('__logout__', logoutId);
|
||||
localStorage.removeItem('__logout__');
|
||||
}
|
||||
}
|
||||
|
||||
isSignallingLogout(logoutId) {
|
||||
return logoutId === sessionStorage.getItem('__logout__');
|
||||
}
|
||||
|
||||
signalLogin() {
|
||||
if (this.isLocalStorageSupported()) {
|
||||
// PLT-1285 store an identifier in session storage so we can catch if the logout came from this tab on IE11
|
||||
const loginId = generateId();
|
||||
|
||||
sessionStorage.setItem('__login__', loginId);
|
||||
localStorage.setItem('__login__', loginId);
|
||||
localStorage.removeItem('__login__');
|
||||
}
|
||||
}
|
||||
|
||||
isSignallingLogin(loginId) {
|
||||
return loginId === sessionStorage.getItem('__login__');
|
||||
}
|
||||
|
||||
/**
|
||||
* Preforms the given action on each item that has the given prefix
|
||||
* Signature for action is action(key, value)
|
||||
*/
|
||||
actionOnGlobalItemsWithPrefix(prefix, action) {
|
||||
var globalPrefix = getPrefix();
|
||||
var globalPrefixiLen = globalPrefix.length;
|
||||
|
||||
var storage = sessionStorage;
|
||||
if (this.isLocalStorageSupported()) {
|
||||
storage = localStorage;
|
||||
}
|
||||
|
||||
for (var key in storage) {
|
||||
if (key.lastIndexOf(globalPrefix + prefix, 0) === 0) {
|
||||
var userkey = key.substring(globalPrefixiLen);
|
||||
action(userkey, this.getGlobalItem(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actionOnItemsWithPrefix(prefix, action) {
|
||||
var globalPrefix = getPrefix();
|
||||
var globalPrefixiLen = globalPrefix.length;
|
||||
for (var key in sessionStorage) {
|
||||
if (key.lastIndexOf(globalPrefix + prefix, 0) === 0) {
|
||||
var userkey = key.substring(globalPrefixiLen);
|
||||
action(userkey, this.getGlobalItem(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
// don't clear the logout id so IE11 can tell which tab sent a logout request
|
||||
const logoutId = sessionStorage.getItem('__logout__');
|
||||
|
||||
sessionStorage.clear();
|
||||
|
||||
if (logoutId) {
|
||||
sessionStorage.setItem('__logout__', logoutId);
|
||||
}
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
sessionStorage.clear();
|
||||
localStorage.clear();
|
||||
}
|
||||
|
||||
isLocalStorageSupported() {
|
||||
if (this.checkedLocalStorageSupported !== '') {
|
||||
return this.checkedLocalStorageSupported;
|
||||
}
|
||||
|
||||
try {
|
||||
sessionStorage.setItem('__testSession__', '1');
|
||||
sessionStorage.removeItem('__testSession__');
|
||||
|
||||
localStorage.setItem('__testLocal__', '1');
|
||||
if (localStorage.getItem('__testLocal__') !== '1') {
|
||||
this.checkedLocalStorageSupported = false;
|
||||
}
|
||||
localStorage.removeItem('__testLocal__', '1');
|
||||
|
||||
this.checkedLocalStorageSupported = true;
|
||||
} catch (e) {
|
||||
this.checkedLocalStorageSupported = false;
|
||||
}
|
||||
|
||||
return this.checkedLocalStorageSupported;
|
||||
}
|
||||
}
|
||||
|
||||
var BrowserStore = new BrowserStoreClass();
|
||||
export default BrowserStore;
|
||||
window.BrowserStore = BrowserStore;
|
||||
352
webapp/stores/channel_store.jsx
Обычный файл
352
webapp/stores/channel_store.jsx
Обычный файл
@@ -0,0 +1,352 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
var Utils;
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const NotificationPrefs = Constants.NotificationPrefs;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
const LEAVE_EVENT = 'leave';
|
||||
const MORE_CHANGE_EVENT = 'change';
|
||||
const EXTRA_INFO_EVENT = 'extra_info';
|
||||
|
||||
class ChannelStoreClass extends EventEmitter {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setMaxListeners(15);
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.emitMoreChange = this.emitMoreChange.bind(this);
|
||||
this.addMoreChangeListener = this.addMoreChangeListener.bind(this);
|
||||
this.removeMoreChangeListener = this.removeMoreChangeListener.bind(this);
|
||||
this.emitExtraInfoChange = this.emitExtraInfoChange.bind(this);
|
||||
this.addExtraInfoChangeListener = this.addExtraInfoChangeListener.bind(this);
|
||||
this.removeExtraInfoChangeListener = this.removeExtraInfoChangeListener.bind(this);
|
||||
this.emitLeave = this.emitLeave.bind(this);
|
||||
this.addLeaveListener = this.addLeaveListener.bind(this);
|
||||
this.removeLeaveListener = this.removeLeaveListener.bind(this);
|
||||
this.findFirstBy = this.findFirstBy.bind(this);
|
||||
this.get = this.get.bind(this);
|
||||
this.getMember = this.getMember.bind(this);
|
||||
this.getByName = this.getByName.bind(this);
|
||||
this.setPostMode = this.setPostMode.bind(this);
|
||||
this.getPostMode = this.getPostMode.bind(this);
|
||||
this.setUnreadCount = this.setUnreadCount.bind(this);
|
||||
this.setUnreadCounts = this.setUnreadCounts.bind(this);
|
||||
this.getUnreadCount = this.getUnreadCount.bind(this);
|
||||
this.getUnreadCounts = this.getUnreadCounts.bind(this);
|
||||
|
||||
this.currentId = null;
|
||||
this.postMode = this.POST_MODE_CHANNEL;
|
||||
this.channels = [];
|
||||
this.channelMembers = {};
|
||||
this.moreChannels = {};
|
||||
this.moreChannels.loading = true;
|
||||
this.extraInfos = {};
|
||||
this.unreadCounts = {};
|
||||
}
|
||||
get POST_MODE_CHANNEL() {
|
||||
return 1;
|
||||
}
|
||||
get POST_MODE_FOCUS() {
|
||||
return 2;
|
||||
}
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
emitMoreChange() {
|
||||
this.emit(MORE_CHANGE_EVENT);
|
||||
}
|
||||
addMoreChangeListener(callback) {
|
||||
this.on(MORE_CHANGE_EVENT, callback);
|
||||
}
|
||||
removeMoreChangeListener(callback) {
|
||||
this.removeListener(MORE_CHANGE_EVENT, callback);
|
||||
}
|
||||
emitExtraInfoChange() {
|
||||
this.emit(EXTRA_INFO_EVENT);
|
||||
}
|
||||
addExtraInfoChangeListener(callback) {
|
||||
this.on(EXTRA_INFO_EVENT, callback);
|
||||
}
|
||||
removeExtraInfoChangeListener(callback) {
|
||||
this.removeListener(EXTRA_INFO_EVENT, callback);
|
||||
}
|
||||
emitLeave(id) {
|
||||
this.emit(LEAVE_EVENT, id);
|
||||
}
|
||||
addLeaveListener(callback) {
|
||||
this.on(LEAVE_EVENT, callback);
|
||||
}
|
||||
removeLeaveListener(callback) {
|
||||
this.removeListener(LEAVE_EVENT, callback);
|
||||
}
|
||||
findFirstBy(field, value) {
|
||||
var channels = this.getChannels();
|
||||
for (var i = 0; i < channels.length; i++) {
|
||||
if (channels[i][field] === value) {
|
||||
return channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
get(id) {
|
||||
return this.findFirstBy('id', id);
|
||||
}
|
||||
getMember(id) {
|
||||
return this.getAllMembers()[id];
|
||||
}
|
||||
getByName(name) {
|
||||
return this.findFirstBy('name', name);
|
||||
}
|
||||
getAll() {
|
||||
return this.getChannels();
|
||||
}
|
||||
getAllMembers() {
|
||||
return this.getChannelMembers();
|
||||
}
|
||||
getMoreAll() {
|
||||
return this.getMoreChannels();
|
||||
}
|
||||
setCurrentId(id) {
|
||||
this.currentId = id;
|
||||
}
|
||||
resetCounts(id) {
|
||||
const cm = this.channelMembers;
|
||||
for (var cmid in cm) {
|
||||
if (cm[cmid].channel_id === id) {
|
||||
var c = this.get(id);
|
||||
if (c) {
|
||||
cm[cmid].msg_count = this.get(id).total_msg_count;
|
||||
cm[cmid].mention_count = 0;
|
||||
this.setUnreadCount(id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
getCurrentId() {
|
||||
return this.currentId;
|
||||
}
|
||||
getCurrent() {
|
||||
var currentId = this.getCurrentId();
|
||||
|
||||
if (currentId) {
|
||||
return this.get(currentId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
getCurrentMember() {
|
||||
var currentId = this.getCurrentId();
|
||||
|
||||
if (currentId) {
|
||||
return this.getAllMembers()[currentId];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
setChannelMember(member) {
|
||||
var members = this.getChannelMembers();
|
||||
members[member.channel_id] = member;
|
||||
this.storeChannelMembers(members);
|
||||
this.emitChange();
|
||||
}
|
||||
getCurrentExtraInfo() {
|
||||
return this.getExtraInfo(this.getCurrentId());
|
||||
}
|
||||
getExtraInfo(channelId) {
|
||||
var extra = null;
|
||||
|
||||
if (channelId) {
|
||||
extra = this.getExtraInfos()[channelId];
|
||||
}
|
||||
|
||||
if (extra) {
|
||||
// create a defensive copy
|
||||
extra = JSON.parse(JSON.stringify(extra));
|
||||
} else {
|
||||
extra = {members: []};
|
||||
}
|
||||
|
||||
return extra;
|
||||
}
|
||||
pStoreChannel(channel) {
|
||||
var channels = this.getChannels();
|
||||
var found;
|
||||
|
||||
for (var i = 0; i < channels.length; i++) {
|
||||
if (channels[i].id === channel.id) {
|
||||
channels[i] = channel;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
channels.push(channel);
|
||||
}
|
||||
|
||||
if (!Utils) {
|
||||
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
|
||||
}
|
||||
|
||||
channels.sort(Utils.sortByDisplayName);
|
||||
this.storeChannels(channels);
|
||||
}
|
||||
storeChannels(channels) {
|
||||
this.channels = channels;
|
||||
}
|
||||
getChannels() {
|
||||
return this.channels;
|
||||
}
|
||||
pStoreChannelMember(channelMember) {
|
||||
var members = this.getChannelMembers();
|
||||
members[channelMember.channel_id] = channelMember;
|
||||
this.storeChannelMembers(members);
|
||||
}
|
||||
storeChannelMembers(channelMembers) {
|
||||
this.channelMembers = channelMembers;
|
||||
}
|
||||
getChannelMembers() {
|
||||
return this.channelMembers;
|
||||
}
|
||||
storeMoreChannels(channels) {
|
||||
this.moreChannels = channels;
|
||||
}
|
||||
getMoreChannels() {
|
||||
return this.moreChannels;
|
||||
}
|
||||
storeExtraInfos(extraInfos) {
|
||||
this.extraInfos = extraInfos;
|
||||
}
|
||||
getExtraInfos() {
|
||||
return this.extraInfos;
|
||||
}
|
||||
isDefault(channel) {
|
||||
return channel.name === Constants.DEFAULT_CHANNEL;
|
||||
}
|
||||
|
||||
setPostMode(mode) {
|
||||
this.postMode = mode;
|
||||
}
|
||||
|
||||
getPostMode() {
|
||||
return this.postMode;
|
||||
}
|
||||
|
||||
setUnreadCount(id) {
|
||||
const ch = this.get(id);
|
||||
const chMember = this.getMember(id);
|
||||
|
||||
let chMentionCount = chMember.mention_count;
|
||||
let chUnreadCount = ch.total_msg_count - chMember.msg_count - chMentionCount;
|
||||
|
||||
if (ch.type === 'D') {
|
||||
chMentionCount = chUnreadCount;
|
||||
chUnreadCount = 0;
|
||||
} else if (chMember.notify_props && chMember.notify_props.mark_unread === NotificationPrefs.MENTION) {
|
||||
chUnreadCount = 0;
|
||||
}
|
||||
|
||||
this.unreadCounts[id] = {msgs: chUnreadCount, mentions: chMentionCount};
|
||||
}
|
||||
|
||||
setUnreadCounts() {
|
||||
const channels = this.getAll();
|
||||
channels.forEach((ch) => {
|
||||
this.setUnreadCount(ch.id);
|
||||
});
|
||||
}
|
||||
|
||||
getUnreadCount(id) {
|
||||
return this.unreadCounts[id] || {msgs: 0, mentions: 0};
|
||||
}
|
||||
|
||||
getUnreadCounts() {
|
||||
return this.unreadCounts;
|
||||
}
|
||||
}
|
||||
|
||||
var ChannelStore = new ChannelStoreClass();
|
||||
|
||||
ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
var currentId;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.CLICK_CHANNEL:
|
||||
ChannelStore.setCurrentId(action.id);
|
||||
ChannelStore.resetCounts(action.id);
|
||||
ChannelStore.setPostMode(ChannelStore.POST_MODE_CHANNEL);
|
||||
ChannelStore.emitChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_FOCUSED_POST: {
|
||||
const post = action.post_list.posts[action.postId];
|
||||
ChannelStore.setCurrentId(post.channel_id);
|
||||
ChannelStore.setPostMode(ChannelStore.POST_MODE_FOCUS);
|
||||
ChannelStore.emitChange();
|
||||
break;
|
||||
}
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNELS:
|
||||
ChannelStore.storeChannels(action.channels);
|
||||
ChannelStore.storeChannelMembers(action.members);
|
||||
currentId = ChannelStore.getCurrentId();
|
||||
if (currentId && window.isActive) {
|
||||
ChannelStore.resetCounts(currentId);
|
||||
}
|
||||
ChannelStore.setUnreadCounts();
|
||||
ChannelStore.emitChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNEL:
|
||||
ChannelStore.pStoreChannel(action.channel);
|
||||
if (action.member) {
|
||||
ChannelStore.pStoreChannelMember(action.member);
|
||||
}
|
||||
currentId = ChannelStore.getCurrentId();
|
||||
if (currentId && window.isActive) {
|
||||
ChannelStore.resetCounts(currentId);
|
||||
}
|
||||
ChannelStore.setUnreadCount(action.channel.id);
|
||||
ChannelStore.emitChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_MORE_CHANNELS:
|
||||
ChannelStore.storeMoreChannels(action.channels);
|
||||
ChannelStore.emitMoreChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNEL_EXTRA_INFO:
|
||||
var extraInfos = ChannelStore.getExtraInfos();
|
||||
extraInfos[action.extra_info.id] = action.extra_info;
|
||||
ChannelStore.storeExtraInfos(extraInfos);
|
||||
ChannelStore.emitExtraInfoChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.LEAVE_CHANNEL:
|
||||
ChannelStore.emitLeave(action.id);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
export default ChannelStore;
|
||||
80
webapp/stores/error_store.jsx
Обычный файл
80
webapp/stores/error_store.jsx
Обычный файл
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
class ErrorStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.getLastError = this.getLastError.bind(this);
|
||||
this.storeLastError = this.storeLastError.bind(this);
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
getLastError() {
|
||||
return BrowserStore.getItem('last_error');
|
||||
}
|
||||
|
||||
storeLastError(error) {
|
||||
BrowserStore.setItem('last_error', error);
|
||||
}
|
||||
|
||||
getConnectionErrorCount() {
|
||||
var count = BrowserStore.getItem('last_error_conn');
|
||||
|
||||
if (count == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
setConnectionErrorCount(count) {
|
||||
BrowserStore.setItem('last_error_conn', count);
|
||||
}
|
||||
|
||||
clearLastError() {
|
||||
BrowserStore.removeItem('last_error');
|
||||
BrowserStore.removeItem('last_error_conn');
|
||||
}
|
||||
}
|
||||
|
||||
var ErrorStore = new ErrorStoreClass();
|
||||
|
||||
ErrorStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_ERROR:
|
||||
ErrorStore.storeLastError(action.err);
|
||||
ErrorStore.emitChange();
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default ErrorStore;
|
||||
window.ErrorStore = ErrorStore;
|
||||
60
webapp/stores/file_store.jsx
Обычный файл
60
webapp/stores/file_store.jsx
Обычный файл
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'changed';
|
||||
|
||||
class FileStore extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
|
||||
this.handleEventPayload = this.handleEventPayload.bind(this);
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||
|
||||
this.fileInfo = new Map();
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
emitChange(filename) {
|
||||
this.emit(CHANGE_EVENT, filename);
|
||||
}
|
||||
|
||||
hasInfo(filename) {
|
||||
return this.fileInfo.has(filename);
|
||||
}
|
||||
|
||||
getInfo(filename) {
|
||||
return this.fileInfo.get(filename);
|
||||
}
|
||||
|
||||
setInfo(filename, info) {
|
||||
this.fileInfo.set(filename, info);
|
||||
}
|
||||
|
||||
handleEventPayload(payload) {
|
||||
const action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_FILE_INFO:
|
||||
this.setInfo(action.filename, action.info);
|
||||
this.emitChange(action.filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new FileStore();
|
||||
60
webapp/stores/localization_store.jsx
Обычный файл
60
webapp/stores/localization_store.jsx
Обычный файл
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
class LocalizationStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.currentLocale = 'en';
|
||||
this.currentTranslations = null;
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
setCurrentLocale(locale, translations) {
|
||||
this.currentLocale = locale;
|
||||
this.currentTranslations = translations;
|
||||
}
|
||||
|
||||
getLocale() {
|
||||
return this.currentLocale;
|
||||
}
|
||||
|
||||
getTranslations() {
|
||||
return this.currentTranslations;
|
||||
}
|
||||
}
|
||||
|
||||
var LocalizationStore = new LocalizationStoreClass();
|
||||
LocalizationStore.setMaxListeners(0);
|
||||
|
||||
LocalizationStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_LOCALE:
|
||||
LocalizationStore.setCurrentLocale(action.locale, action.translations);
|
||||
LocalizationStore.emitChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default LocalizationStore;
|
||||
47
webapp/stores/modal_store.jsx
Обычный файл
47
webapp/stores/modal_store.jsx
Обычный файл
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
class ModalStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addModalListener = this.addModalListener.bind(this);
|
||||
this.removeModalListener = this.removeModalListener.bind(this);
|
||||
|
||||
this.handleEventPayload = this.handleEventPayload.bind(this);
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||
}
|
||||
|
||||
addModalListener(action, callback) {
|
||||
this.on(action, callback);
|
||||
}
|
||||
|
||||
removeModalListener(action, callback) {
|
||||
this.removeListener(action, callback);
|
||||
}
|
||||
|
||||
handleEventPayload(payload) {
|
||||
// toggle event handlers should accept a boolean show/hide value and can accept a map of arguments
|
||||
const {type, value, ...args} = payload.action; //eslint-disable-line no-use-before-define
|
||||
|
||||
switch (type) {
|
||||
case ActionTypes.TOGGLE_IMPORT_THEME_MODAL:
|
||||
case ActionTypes.TOGGLE_INVITE_MEMBER_MODAL:
|
||||
case ActionTypes.TOGGLE_DELETE_POST_MODAL:
|
||||
case ActionTypes.TOGGLE_GET_POST_LINK_MODAL:
|
||||
case ActionTypes.TOGGLE_GET_TEAM_INVITE_LINK_MODAL:
|
||||
case ActionTypes.TOGGLE_REGISTER_APP_MODAL:
|
||||
this.emit(type, value, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ModalStore = new ModalStoreClass();
|
||||
export default ModalStore;
|
||||
610
webapp/stores/post_store.jsx
Обычный файл
610
webapp/stores/post_store.jsx
Обычный файл
@@ -0,0 +1,610 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
const FOCUSED_POST_CHANGE = 'focused_post_change';
|
||||
const EDIT_POST_EVENT = 'edit_post';
|
||||
const POSTS_VIEW_JUMP_EVENT = 'post_list_jump';
|
||||
const SELECTED_POST_CHANGE_EVENT = 'selected_post_change';
|
||||
|
||||
class PostStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.selectedPostId = null;
|
||||
this.postsInfo = {};
|
||||
this.currentFocusedPostId = null;
|
||||
}
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitPostFocused() {
|
||||
this.emit(FOCUSED_POST_CHANGE);
|
||||
}
|
||||
|
||||
addPostFocusedListener(callback) {
|
||||
this.on(FOCUSED_POST_CHANGE, callback);
|
||||
}
|
||||
|
||||
removePostFocusedListener(callback) {
|
||||
this.removeListener(FOCUSED_POST_CHANGE, callback);
|
||||
}
|
||||
|
||||
emitEditPost(post) {
|
||||
this.emit(EDIT_POST_EVENT, post);
|
||||
}
|
||||
|
||||
addEditPostListener(callback) {
|
||||
this.on(EDIT_POST_EVENT, callback);
|
||||
}
|
||||
|
||||
removeEditPostListner(callback) {
|
||||
this.removeListener(EDIT_POST_EVENT, callback);
|
||||
}
|
||||
|
||||
emitPostsViewJump(type, post) {
|
||||
this.emit(POSTS_VIEW_JUMP_EVENT, type, post);
|
||||
}
|
||||
|
||||
addPostsViewJumpListener(callback) {
|
||||
this.on(POSTS_VIEW_JUMP_EVENT, callback);
|
||||
}
|
||||
|
||||
removePostsViewJumpListener(callback) {
|
||||
this.removeListener(POSTS_VIEW_JUMP_EVENT, callback);
|
||||
}
|
||||
|
||||
jumpPostsViewToBottom() {
|
||||
this.emitPostsViewJump(Constants.PostsViewJumpTypes.BOTTOM, null);
|
||||
}
|
||||
|
||||
jumpPostsViewToPost(post) {
|
||||
this.emitPostsViewJump(Constants.PostsViewJumpTypes.POST, post);
|
||||
}
|
||||
|
||||
jumpPostsViewSidebarOpen() {
|
||||
this.emitPostsViewJump(Constants.PostsViewJumpTypes.SIDEBAR_OPEN, null);
|
||||
}
|
||||
|
||||
// All this does is makes sure the postsInfo is not null for the specified channel
|
||||
makePostsInfo(id) {
|
||||
if (!this.postsInfo.hasOwnProperty(id)) {
|
||||
this.postsInfo[id] = {};
|
||||
}
|
||||
}
|
||||
|
||||
getPost(channelId, postId) {
|
||||
const posts = this.postsInfo[channelId].postList;
|
||||
let post = null;
|
||||
|
||||
if (posts.posts.hasOwnProperty(postId)) {
|
||||
post = Object.assign({}, posts.posts[postId]);
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
getAllPosts(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id)) {
|
||||
return Object.assign({}, this.postsInfo[id].postList);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getEarliestPost(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id)) {
|
||||
return this.postsInfo[id].postList.posts[this.postsInfo[id].postList.order[this.postsInfo[id].postList.order.length - 1]];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getLatestPost(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id)) {
|
||||
return this.postsInfo[id].postList.posts[this.postsInfo[id].postList.order[0]];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getVisiblePosts(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id) && this.postsInfo[id].hasOwnProperty('postList')) {
|
||||
const postList = JSON.parse(JSON.stringify(this.postsInfo[id].postList));
|
||||
|
||||
// Only limit visibility if we are not focused on a post
|
||||
if (this.currentFocusedPostId === null) {
|
||||
postList.order = postList.order.slice(0, this.postsInfo[id].endVisible);
|
||||
}
|
||||
|
||||
// Add pending posts
|
||||
if (this.postsInfo[id].hasOwnProperty('pendingPosts')) {
|
||||
Object.assign(postList.posts, this.postsInfo[id].pendingPosts.posts);
|
||||
postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order);
|
||||
}
|
||||
|
||||
return postList;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getVisibilityAtTop(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id)) {
|
||||
return this.postsInfo[id].atTop && this.postsInfo[id].endVisible >= this.postsInfo[id].postList.order.length;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getVisibilityAtBottom(id) {
|
||||
if (this.postsInfo.hasOwnProperty(id)) {
|
||||
return this.postsInfo[id].atBottom;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if posts need to be fetched
|
||||
requestVisibilityIncrease(id, ammount) {
|
||||
const endVisible = this.postsInfo[id].endVisible;
|
||||
const postList = this.postsInfo[id].postList;
|
||||
if (this.getVisibilityAtTop(id)) {
|
||||
return false;
|
||||
}
|
||||
this.postsInfo[id].endVisible += ammount;
|
||||
this.emitChange();
|
||||
return endVisible + ammount > postList.order.length;
|
||||
}
|
||||
|
||||
getFocusedPostId() {
|
||||
return this.currentFocusedPostId;
|
||||
}
|
||||
|
||||
storePosts(id, newPosts) {
|
||||
if (isPostListNull(newPosts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const combinedPosts = makePostListNonNull(this.getAllPosts(id));
|
||||
|
||||
for (const pid in newPosts.posts) {
|
||||
if (newPosts.posts.hasOwnProperty(pid)) {
|
||||
const np = newPosts.posts[pid];
|
||||
if (np.delete_at === 0) {
|
||||
combinedPosts.posts[pid] = np;
|
||||
if (combinedPosts.order.indexOf(pid) === -1 && newPosts.order.indexOf(pid) !== -1) {
|
||||
combinedPosts.order.push(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
combinedPosts.order.sort((a, b) => {
|
||||
if (combinedPosts.posts[a].create_at > combinedPosts.posts[b].create_at) {
|
||||
return -1;
|
||||
}
|
||||
if (combinedPosts.posts[a].create_at < combinedPosts.posts[b].create_at) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
this.makePostsInfo(id);
|
||||
this.postsInfo[id].postList = combinedPosts;
|
||||
}
|
||||
|
||||
storePost(post) {
|
||||
const postList = makePostListNonNull(this.getAllPosts(post.channel_id));
|
||||
|
||||
if (post.pending_post_id !== '') {
|
||||
this.removePendingPost(post.channel_id, post.pending_post_id);
|
||||
}
|
||||
|
||||
post.pending_post_id = '';
|
||||
|
||||
postList.posts[post.id] = post;
|
||||
if (postList.order.indexOf(post.id) === -1) {
|
||||
postList.order.unshift(post.id);
|
||||
}
|
||||
|
||||
this.makePostsInfo(post.channel_id);
|
||||
this.postsInfo[post.channel_id].postList = postList;
|
||||
}
|
||||
|
||||
storeFocusedPost(postId, postList) {
|
||||
const focusedPost = postList.posts[postId];
|
||||
if (!focusedPost) {
|
||||
return;
|
||||
}
|
||||
this.currentFocusedPostId = postId;
|
||||
this.storePosts(postId, postList);
|
||||
}
|
||||
|
||||
checkBounds(id, numRequested, postList, before) {
|
||||
if (numRequested > postList.order.length) {
|
||||
if (before) {
|
||||
this.postsInfo[id].atTop = true;
|
||||
} else {
|
||||
this.postsInfo[id].atBottom = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearFocusedPost() {
|
||||
if (this.currentFocusedPostId != null) {
|
||||
Reflect.deleteProperty(this.postsInfo, this.currentFocusedPostId);
|
||||
this.currentFocusedPostId = null;
|
||||
}
|
||||
}
|
||||
|
||||
clearChannelVisibility(id, atBottom) {
|
||||
this.makePostsInfo(id);
|
||||
this.postsInfo[id].endVisible = Constants.POST_CHUNK_SIZE;
|
||||
this.postsInfo[id].atTop = false;
|
||||
this.postsInfo[id].atBottom = atBottom;
|
||||
}
|
||||
|
||||
deletePost(post) {
|
||||
const postInfo = this.postsInfo[post.channel_id];
|
||||
if (!postInfo) {
|
||||
// the post that has been deleted is in a channel that we haven't seen so just ignore it
|
||||
return;
|
||||
}
|
||||
|
||||
const postList = this.postsInfo[post.channel_id].postList;
|
||||
|
||||
if (isPostListNull(postList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (post.id in postList.posts) {
|
||||
// make sure to copy the post so that component state changes work properly
|
||||
postList.posts[post.id] = Object.assign({}, post, {
|
||||
state: Constants.POST_DELETED,
|
||||
filenames: []
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removePost(post) {
|
||||
const channelId = post.channel_id;
|
||||
this.makePostsInfo(channelId);
|
||||
const postList = this.postsInfo[channelId].postList;
|
||||
if (isPostListNull(postList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (post.id in postList.posts) {
|
||||
Reflect.deleteProperty(postList.posts, post.id);
|
||||
}
|
||||
|
||||
const index = postList.order.indexOf(post.id);
|
||||
if (index !== -1) {
|
||||
postList.order.splice(index, 1);
|
||||
}
|
||||
|
||||
for (const pid in postList.posts) {
|
||||
if (!postList.posts.hasOwnProperty(pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (postList.posts[pid].root_id === post.id) {
|
||||
Reflect.deleteProperty(postList.posts, pid);
|
||||
const commentIndex = postList.order.indexOf(pid);
|
||||
if (commentIndex !== -1) {
|
||||
postList.order.splice(commentIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.postsInfo[channelId].postList = postList;
|
||||
}
|
||||
|
||||
getPendingPosts(channelId) {
|
||||
if (this.postsInfo.hasOwnProperty(channelId)) {
|
||||
return this.postsInfo[channelId].pendingPosts;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
storePendingPost(post) {
|
||||
const copyPost = JSON.parse(JSON.stringify(post));
|
||||
copyPost.state = Constants.POST_LOADING;
|
||||
|
||||
const postList = makePostListNonNull(this.getPendingPosts(copyPost.channel_id));
|
||||
|
||||
postList.posts[copyPost.pending_post_id] = copyPost;
|
||||
postList.order.unshift(copyPost.pending_post_id);
|
||||
|
||||
this.makePostsInfo(copyPost.channel_id);
|
||||
this.postsInfo[copyPost.channel_id].pendingPosts = postList;
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
removePendingPost(channelId, pendingPostId) {
|
||||
const postList = makePostListNonNull(this.getPendingPosts(channelId));
|
||||
|
||||
Reflect.deleteProperty(postList.posts, pendingPostId);
|
||||
const index = postList.order.indexOf(pendingPostId);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
postList.order.splice(index, 1);
|
||||
|
||||
this.postsInfo[channelId].pendingPosts = postList;
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
clearPendingPosts(channelId) {
|
||||
if (this.postsInfo.hasOwnProperty(channelId)) {
|
||||
Reflect.deleteProperty(this.postsInfo[channelId], 'pendingPosts');
|
||||
}
|
||||
}
|
||||
|
||||
updatePendingPost(post) {
|
||||
const copyPost = JSON.parse(JSON.stringify(post));
|
||||
const postList = makePostListNonNull(this.getPendingPosts(copyPost.channel_id));
|
||||
|
||||
if (postList.order.indexOf(copyPost.pending_post_id) === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
postList.posts[copyPost.pending_post_id] = copyPost;
|
||||
this.postsInfo[copyPost.channel_id].pendingPosts = postList;
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
storeSelectedPostId(postId) {
|
||||
this.selectedPostId = postId;
|
||||
}
|
||||
|
||||
getSelectedPostId() {
|
||||
return this.selectedPostId;
|
||||
}
|
||||
|
||||
getSelectedPost() {
|
||||
if (this.selectedPostId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const k in this.postsInfo) {
|
||||
if (this.postsInfo[k].postList.posts.hasOwnProperty(this.selectedPostId)) {
|
||||
return this.postsInfo[k].postList.posts[this.selectedPostId];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getSelectedPostThread() {
|
||||
if (this.selectedPostId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let posts;
|
||||
let pendingPosts;
|
||||
for (const k in this.postsInfo) {
|
||||
if (this.postsInfo[k].postList.posts.hasOwnProperty(this.selectedPostId)) {
|
||||
posts = this.postsInfo[k].postList.posts;
|
||||
if (this.postsInfo[k].pendingPosts != null) {
|
||||
pendingPosts = this.postsInfo[k].pendingPosts.posts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const threadPosts = {};
|
||||
const rootId = this.selectedPostId;
|
||||
for (const k in posts) {
|
||||
if (posts[k].root_id === rootId) {
|
||||
threadPosts[k] = JSON.parse(JSON.stringify(posts[k]));
|
||||
}
|
||||
}
|
||||
|
||||
for (const k in pendingPosts) {
|
||||
if (pendingPosts[k].root_id === rootId) {
|
||||
threadPosts[k] = JSON.parse(JSON.stringify(pendingPosts[k]));
|
||||
}
|
||||
}
|
||||
|
||||
return threadPosts;
|
||||
}
|
||||
|
||||
emitSelectedPostChange(fromSearch) {
|
||||
this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch);
|
||||
}
|
||||
|
||||
addSelectedPostChangeListener(callback) {
|
||||
this.on(SELECTED_POST_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeSelectedPostChangeListener(callback) {
|
||||
this.removeListener(SELECTED_POST_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
getCurrentUsersLatestPost(channelId, rootId) {
|
||||
const userId = UserStore.getCurrentId();
|
||||
var postList = makePostListNonNull(this.getAllPosts(channelId));
|
||||
var i = 0;
|
||||
var len = postList.order.length;
|
||||
var lastPost = null;
|
||||
|
||||
for (i; i < len; i++) {
|
||||
const post = postList.posts[postList.order[i]];
|
||||
if (post.user_id === userId && (post.props && !post.props.from_webhook || !post.props)) {
|
||||
if (rootId) {
|
||||
if (post.root_id === rootId || post.id === rootId) {
|
||||
lastPost = post;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
lastPost = post;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lastPost;
|
||||
}
|
||||
|
||||
getEmptyDraft() {
|
||||
return {message: '', uploadsInProgress: [], previews: []};
|
||||
}
|
||||
storeCurrentDraft(draft) {
|
||||
var channelId = ChannelStore.getCurrentId();
|
||||
BrowserStore.setGlobalItem('draft_' + channelId, draft);
|
||||
}
|
||||
getCurrentDraft() {
|
||||
var channelId = ChannelStore.getCurrentId();
|
||||
return this.getDraft(channelId);
|
||||
}
|
||||
storeDraft(channelId, draft) {
|
||||
BrowserStore.setGlobalItem('draft_' + channelId, draft);
|
||||
}
|
||||
getDraft(channelId) {
|
||||
return BrowserStore.getGlobalItem('draft_' + channelId, this.getEmptyDraft());
|
||||
}
|
||||
storeCommentDraft(parentPostId, draft) {
|
||||
BrowserStore.setGlobalItem('comment_draft_' + parentPostId, draft);
|
||||
}
|
||||
getCommentDraft(parentPostId) {
|
||||
return BrowserStore.getGlobalItem('comment_draft_' + parentPostId, this.getEmptyDraft());
|
||||
}
|
||||
clearDraftUploads() {
|
||||
BrowserStore.actionOnGlobalItemsWithPrefix('draft_', (key, value) => {
|
||||
if (value) {
|
||||
value.uploadsInProgress = [];
|
||||
BrowserStore.setItem(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
clearCommentDraftUploads() {
|
||||
BrowserStore.actionOnGlobalItemsWithPrefix('comment_draft_', (key, value) => {
|
||||
if (value) {
|
||||
value.uploadsInProgress = [];
|
||||
BrowserStore.setItem(key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
getCommentCount(post) {
|
||||
const posts = this.getAllPosts(post.channel_id).posts;
|
||||
|
||||
let commentCount = 0;
|
||||
for (const id in posts) {
|
||||
if (posts.hasOwnProperty(id)) {
|
||||
if (posts[id].root_id === post.id) {
|
||||
commentCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commentCount;
|
||||
}
|
||||
}
|
||||
|
||||
var PostStore = new PostStoreClass();
|
||||
|
||||
PostStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_POSTS: {
|
||||
const id = PostStore.currentFocusedPostId == null ? action.id : PostStore.currentFocusedPostId;
|
||||
PostStore.checkBounds(id, action.numRequested, makePostListNonNull(action.post_list), action.before);
|
||||
PostStore.storePosts(id, makePostListNonNull(action.post_list));
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
}
|
||||
case ActionTypes.RECEIVED_FOCUSED_POST:
|
||||
PostStore.clearChannelVisibility(action.postId, false);
|
||||
PostStore.storeFocusedPost(action.postId, makePostListNonNull(action.post_list));
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_POST:
|
||||
PostStore.storePost(action.post);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_EDIT_POST:
|
||||
PostStore.emitEditPost(action);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.CLICK_CHANNEL:
|
||||
PostStore.clearFocusedPost();
|
||||
PostStore.clearChannelVisibility(action.id, true);
|
||||
break;
|
||||
case ActionTypes.CREATE_POST:
|
||||
PostStore.storePendingPost(action.post);
|
||||
PostStore.storeDraft(action.post.channel_id, null);
|
||||
PostStore.jumpPostsViewToBottom();
|
||||
break;
|
||||
case ActionTypes.POST_DELETED:
|
||||
PostStore.deletePost(action.post);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.REMOVE_POST:
|
||||
PostStore.removePost(action.post);
|
||||
PostStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_POST_SELECTED:
|
||||
PostStore.storeSelectedPostId(action.postId);
|
||||
PostStore.emitSelectedPostChange(action.from_search);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default PostStore;
|
||||
|
||||
function makePostListNonNull(pl) {
|
||||
var postList = pl;
|
||||
if (postList == null) {
|
||||
postList = {order: [], posts: {}};
|
||||
}
|
||||
|
||||
if (postList.order == null) {
|
||||
postList.order = [];
|
||||
}
|
||||
|
||||
if (postList.posts == null) {
|
||||
postList.posts = {};
|
||||
}
|
||||
|
||||
return postList;
|
||||
}
|
||||
|
||||
function isPostListNull(pl) {
|
||||
if (pl == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pl.posts == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pl.order == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
178
webapp/stores/preference_store.jsx
Обычный файл
178
webapp/stores/preference_store.jsx
Обычный файл
@@ -0,0 +1,178 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import BrowserStore from './browser_store.jsx';
|
||||
import EventEmitter from 'events';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
function getPreferenceKey(category, name) {
|
||||
return `${category}-${name}`;
|
||||
}
|
||||
|
||||
function getPreferenceKeyForModel(preference) {
|
||||
return `${preference.category}-${preference.name}`;
|
||||
}
|
||||
|
||||
class PreferenceStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.getAllPreferences = this.getAllPreferences.bind(this);
|
||||
this.get = this.get.bind(this);
|
||||
this.getBool = this.getBool.bind(this);
|
||||
this.getInt = this.getInt.bind(this);
|
||||
this.getPreference = this.getPreference.bind(this);
|
||||
this.getCategory = this.getCategory.bind(this);
|
||||
this.getPreferencesWhere = this.getPreferencesWhere.bind(this);
|
||||
this.setAllPreferences = this.setAllPreferences.bind(this);
|
||||
this.setPreference = this.setPreference.bind(this);
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
|
||||
this.handleEventPayload = this.handleEventPayload.bind(this);
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||
}
|
||||
|
||||
getAllPreferences() {
|
||||
return new Map(BrowserStore.getItem('preferences', []));
|
||||
}
|
||||
|
||||
get(category, name, defaultValue = '') {
|
||||
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
|
||||
|
||||
if (!preference) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return preference.value || defaultValue;
|
||||
}
|
||||
|
||||
getBool(category, name, defaultValue = false) {
|
||||
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
|
||||
|
||||
if (!preference) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// prevent a non-false default value from being returned instead of an actual false value
|
||||
if (preference.value === 'false') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (preference.value !== 'false') || defaultValue;
|
||||
}
|
||||
|
||||
getInt(category, name, defaultValue = 0) {
|
||||
const preference = this.getAllPreferences().get(getPreferenceKey(category, name));
|
||||
|
||||
if (!preference) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// prevent a non-zero default value from being returned instead of an actual 0 value
|
||||
if (preference.value === '0') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parseInt(preference.value, 10) || defaultValue;
|
||||
}
|
||||
|
||||
getPreference(category, name, defaultValue = {}) {
|
||||
return this.getAllPreferences().get(getPreferenceKey(category, name)) || defaultValue;
|
||||
}
|
||||
|
||||
getCategory(category) {
|
||||
return this.getPreferencesWhere((preference) => (preference.category === category));
|
||||
}
|
||||
|
||||
getPreferencesWhere(pred) {
|
||||
const all = this.getAllPreferences();
|
||||
const preferences = [];
|
||||
|
||||
for (const [, preference] of all) {
|
||||
if (pred(preference)) {
|
||||
preferences.push(preference);
|
||||
}
|
||||
}
|
||||
|
||||
return preferences;
|
||||
}
|
||||
|
||||
setAllPreferences(preferences) {
|
||||
// note that we store the preferences as an array of key-value pairs so that we can deserialize
|
||||
// it as a proper Map instead of an object
|
||||
BrowserStore.setItem('preferences', [...preferences]);
|
||||
}
|
||||
|
||||
setPreference(category, name, value) {
|
||||
const preferences = this.getAllPreferences();
|
||||
|
||||
const key = getPreferenceKey(category, name);
|
||||
let preference = preferences.get(key);
|
||||
|
||||
if (!preference) {
|
||||
preference = {
|
||||
user_id: UserStore.getCurrentId(),
|
||||
category,
|
||||
name
|
||||
};
|
||||
}
|
||||
preference.value = value;
|
||||
|
||||
preferences.set(key, preference);
|
||||
|
||||
this.setAllPreferences(preferences);
|
||||
|
||||
return preference;
|
||||
}
|
||||
|
||||
setPreferences(newPreferences) {
|
||||
const preferences = this.getAllPreferences();
|
||||
|
||||
for (const preference of newPreferences) {
|
||||
preferences.set(getPreferenceKeyForModel(preference), preference);
|
||||
}
|
||||
|
||||
this.setAllPreferences(preferences);
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
handleEventPayload(payload) {
|
||||
const action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_PREFERENCE: {
|
||||
const preference = action.preference;
|
||||
this.setPreference(preference.category, preference.name, preference.value);
|
||||
this.emitChange();
|
||||
break;
|
||||
}
|
||||
case ActionTypes.RECEIVED_PREFERENCES:
|
||||
this.setPreferences(action.preferences);
|
||||
this.emitChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const PreferenceStore = new PreferenceStoreClass();
|
||||
export default PreferenceStore;
|
||||
window.PreferenceStore = PreferenceStore;
|
||||
137
webapp/stores/search_store.jsx
Обычный файл
137
webapp/stores/search_store.jsx
Обычный файл
@@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
var ActionTypes = Constants.ActionTypes;
|
||||
|
||||
var CHANGE_EVENT = 'change';
|
||||
var SEARCH_CHANGE_EVENT = 'search_change';
|
||||
var SEARCH_TERM_CHANGE_EVENT = 'search_term_change';
|
||||
var SHOW_SEARCH_EVENT = 'show_search';
|
||||
|
||||
class SearchStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
|
||||
this.emitSearchChange = this.emitSearchChange.bind(this);
|
||||
this.addSearchChangeListener = this.addSearchChangeListener.bind(this);
|
||||
this.removeSearchChangeListener = this.removeSearchChangeListener.bind(this);
|
||||
|
||||
this.emitSearchTermChange = this.emitSearchTermChange.bind(this);
|
||||
this.addSearchTermChangeListener = this.addSearchTermChangeListener.bind(this);
|
||||
this.removeSearchTermChangeListener = this.removeSearchTermChangeListener.bind(this);
|
||||
|
||||
this.emitShowSearch = this.emitShowSearch.bind(this);
|
||||
this.addShowSearchListener = this.addShowSearchListener.bind(this);
|
||||
this.removeShowSearchListener = this.removeShowSearchListener.bind(this);
|
||||
|
||||
this.getSearchResults = this.getSearchResults.bind(this);
|
||||
this.getIsMentionSearch = this.getIsMentionSearch.bind(this);
|
||||
|
||||
this.storeSearchTerm = this.storeSearchTerm.bind(this);
|
||||
this.getSearchTerm = this.getSearchTerm.bind(this);
|
||||
|
||||
this.storeSearchResults = this.storeSearchResults.bind(this);
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitSearchChange() {
|
||||
this.emit(SEARCH_CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addSearchChangeListener(callback) {
|
||||
this.on(SEARCH_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeSearchChangeListener(callback) {
|
||||
this.removeListener(SEARCH_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitSearchTermChange(doSearch, isMentionSearch) {
|
||||
this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch);
|
||||
}
|
||||
|
||||
addSearchTermChangeListener(callback) {
|
||||
this.on(SEARCH_TERM_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeSearchTermChangeListener(callback) {
|
||||
this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitShowSearch() {
|
||||
this.emit(SHOW_SEARCH_EVENT);
|
||||
}
|
||||
|
||||
addShowSearchListener(callback) {
|
||||
this.on(SHOW_SEARCH_EVENT, callback);
|
||||
}
|
||||
|
||||
removeShowSearchListener(callback) {
|
||||
this.removeListener(SHOW_SEARCH_EVENT, callback);
|
||||
}
|
||||
|
||||
getSearchResults() {
|
||||
return BrowserStore.getItem('search_results');
|
||||
}
|
||||
|
||||
getIsMentionSearch() {
|
||||
return BrowserStore.getItem('is_mention_search');
|
||||
}
|
||||
|
||||
storeSearchTerm(term) {
|
||||
BrowserStore.setItem('search_term', term);
|
||||
}
|
||||
|
||||
getSearchTerm() {
|
||||
return BrowserStore.getItem('search_term');
|
||||
}
|
||||
|
||||
storeSearchResults(results, isMentionSearch) {
|
||||
BrowserStore.setItem('search_results', results);
|
||||
BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch));
|
||||
}
|
||||
}
|
||||
|
||||
var SearchStore = new SearchStoreClass();
|
||||
|
||||
SearchStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_SEARCH:
|
||||
SearchStore.storeSearchResults(action.results, action.is_mention_search);
|
||||
SearchStore.emitSearchChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_SEARCH_TERM:
|
||||
SearchStore.storeSearchTerm(action.term);
|
||||
SearchStore.emitSearchTermChange(action.do_search, action.is_mention_search);
|
||||
break;
|
||||
case ActionTypes.SHOW_SEARCH:
|
||||
SearchStore.emitShowSearch();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default SearchStore;
|
||||
343
webapp/stores/socket_store.jsx
Обычный файл
343
webapp/stores/socket_store.jsx
Обычный файл
@@ -0,0 +1,343 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import $ from 'jquery';
|
||||
import UserStore from './user_store.jsx';
|
||||
import PostStore from './post_store.jsx';
|
||||
import ChannelStore from './channel_store.jsx';
|
||||
import BrowserStore from './browser_store.jsx';
|
||||
import ErrorStore from './error_store.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as GlobalActions from 'action_creators/global_actions.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const SocketEvents = Constants.SocketEvents;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
var conn;
|
||||
|
||||
class SocketStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.initialize = this.initialize.bind(this);
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.sendMessage = this.sendMessage.bind(this);
|
||||
this.close = this.close.bind(this);
|
||||
|
||||
this.failCount = 0;
|
||||
this.isInitialize = false;
|
||||
|
||||
this.translations = this.getDefaultTranslations();
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
initialize() {
|
||||
if (!UserStore.getCurrentId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setMaxListeners(0);
|
||||
|
||||
if (window.WebSocket && !conn) {
|
||||
var protocol = 'ws://';
|
||||
if (window.location.protocol === 'https:') {
|
||||
protocol = 'wss://';
|
||||
}
|
||||
|
||||
var connUrl = protocol + location.host + ((/:\d+/).test(location.host) ? '' : Utils.getWebsocketPort(protocol)) + '/api/v1/websocket';
|
||||
|
||||
if (this.failCount === 0) {
|
||||
console.log('websocket connecting to ' + connUrl); //eslint-disable-line no-console
|
||||
}
|
||||
|
||||
conn = new WebSocket(connUrl);
|
||||
|
||||
conn.onopen = () => {
|
||||
if (this.failCount > 0) {
|
||||
console.log('websocket re-established connection'); //eslint-disable-line no-console
|
||||
AsyncClient.getChannels();
|
||||
AsyncClient.getPosts(ChannelStore.getCurrentId());
|
||||
}
|
||||
|
||||
if (this.isInitialize) {
|
||||
ErrorStore.clearLastError();
|
||||
ErrorStore.emitChange();
|
||||
}
|
||||
|
||||
this.isInitialize = true;
|
||||
this.failCount = 0;
|
||||
};
|
||||
|
||||
conn.onclose = () => {
|
||||
conn = null;
|
||||
|
||||
if (this.failCount === 0) {
|
||||
console.log('websocket closed'); //eslint-disable-line no-console
|
||||
}
|
||||
|
||||
this.failCount = this.failCount + 1;
|
||||
|
||||
if (this.failCount > 7) {
|
||||
ErrorStore.storeLastError({message: this.translations.socketError});
|
||||
}
|
||||
|
||||
ErrorStore.setConnectionErrorCount(this.failCount);
|
||||
ErrorStore.emitChange();
|
||||
|
||||
setTimeout(
|
||||
() => {
|
||||
this.initialize();
|
||||
},
|
||||
3000
|
||||
);
|
||||
};
|
||||
|
||||
conn.onerror = (evt) => {
|
||||
if (this.failCount <= 1) {
|
||||
console.log('websocket error'); //eslint-disable-line no-console
|
||||
console.log(evt); //eslint-disable-line no-console
|
||||
}
|
||||
};
|
||||
|
||||
conn.onmessage = (evt) => {
|
||||
const msg = JSON.parse(evt.data);
|
||||
this.handleMessage(msg);
|
||||
this.emitChange(msg);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
emitChange(msg) {
|
||||
this.emit(CHANGE_EVENT, msg);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
handleMessage(msg) {
|
||||
switch (msg.action) {
|
||||
case SocketEvents.POSTED:
|
||||
case SocketEvents.EPHEMERAL_MESSAGE:
|
||||
handleNewPostEvent(msg, this.translations);
|
||||
break;
|
||||
|
||||
case SocketEvents.POST_EDITED:
|
||||
handlePostEditEvent(msg);
|
||||
break;
|
||||
|
||||
case SocketEvents.POST_DELETED:
|
||||
handlePostDeleteEvent(msg);
|
||||
break;
|
||||
|
||||
case SocketEvents.NEW_USER:
|
||||
handleNewUserEvent();
|
||||
break;
|
||||
|
||||
case SocketEvents.USER_ADDED:
|
||||
handleUserAddedEvent(msg);
|
||||
break;
|
||||
|
||||
case SocketEvents.USER_REMOVED:
|
||||
handleUserRemovedEvent(msg);
|
||||
break;
|
||||
|
||||
case SocketEvents.CHANNEL_VIEWED:
|
||||
handleChannelViewedEvent(msg);
|
||||
break;
|
||||
|
||||
case SocketEvents.PREFERENCE_CHANGED:
|
||||
handlePreferenceChangedEvent(msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage(msg) {
|
||||
if (conn && conn.readyState === WebSocket.OPEN) {
|
||||
conn.send(JSON.stringify(msg));
|
||||
} else if (!conn || conn.readyState === WebSocket.Closed) {
|
||||
conn = null;
|
||||
this.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
setTranslations(messages) {
|
||||
this.translations = messages;
|
||||
}
|
||||
|
||||
getDefaultTranslations() {
|
||||
return ({
|
||||
socketError: 'Please check connection, Mattermost unreachable. If issue persists, ask administrator to check WebSocket port.',
|
||||
someone: 'Someone',
|
||||
posted: 'Posted',
|
||||
uploadedImage: ' uploaded an image',
|
||||
uploadedFile: ' uploaded a file',
|
||||
something: ' did something new',
|
||||
wrote: ' wrote: '
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
if (conn && conn.readyState === WebSocket.OPEN) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewPostEvent(msg, translations) {
|
||||
// Store post
|
||||
const post = JSON.parse(msg.props.post);
|
||||
GlobalActions.emitPostRecievedEvent(post);
|
||||
|
||||
// Update channel state
|
||||
if (ChannelStore.getCurrentId() === msg.channel_id) {
|
||||
if (window.isActive) {
|
||||
AsyncClient.updateLastViewedAt();
|
||||
} else {
|
||||
AsyncClient.getChannel(msg.channel_id);
|
||||
}
|
||||
} else if (UserStore.getCurrentId() !== msg.user_id || post.type !== Constants.POST_TYPE_JOIN_LEAVE) {
|
||||
AsyncClient.getChannel(msg.channel_id);
|
||||
}
|
||||
|
||||
// Send desktop notification
|
||||
if ((UserStore.getCurrentId() !== msg.user_id || post.props.from_webhook === 'true') && !Utils.isSystemMessage(post)) {
|
||||
const msgProps = msg.props;
|
||||
|
||||
let mentions = [];
|
||||
if (msgProps.mentions) {
|
||||
mentions = JSON.parse(msg.props.mentions);
|
||||
}
|
||||
|
||||
const channel = ChannelStore.get(msg.channel_id);
|
||||
const user = UserStore.getCurrentUser();
|
||||
const member = ChannelStore.getMember(msg.channel_id);
|
||||
|
||||
let notifyLevel = member && member.notify_props ? member.notify_props.desktop : 'default';
|
||||
if (notifyLevel === 'default') {
|
||||
notifyLevel = user.notify_props.desktop;
|
||||
}
|
||||
|
||||
if (notifyLevel === 'none') {
|
||||
return;
|
||||
} else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== Constants.DM_CHANNEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
let username = translations.someone;
|
||||
if (post.props.override_username && global.window.mm_config.EnablePostUsernameOverride === 'true') {
|
||||
username = post.props.override_username;
|
||||
} else if (UserStore.hasProfile(msg.user_id)) {
|
||||
username = UserStore.getProfile(msg.user_id).username;
|
||||
}
|
||||
|
||||
let title = translations.posted;
|
||||
if (channel) {
|
||||
title = channel.display_name;
|
||||
}
|
||||
|
||||
let notifyText = post.message.replace(/\n+/g, ' ');
|
||||
if (notifyText.length > 50) {
|
||||
notifyText = notifyText.substring(0, 49) + '...';
|
||||
}
|
||||
|
||||
if (notifyText.length === 0) {
|
||||
if (msgProps.image) {
|
||||
Utils.notifyMe(title, username + translations.uploadedImage, channel);
|
||||
} else if (msgProps.otherFile) {
|
||||
Utils.notifyMe(title, username + translations.uploadedFile, channel);
|
||||
} else {
|
||||
Utils.notifyMe(title, username + translations.something, channel);
|
||||
}
|
||||
} else {
|
||||
Utils.notifyMe(title, username + translations.wrote + notifyText, channel);
|
||||
}
|
||||
if (!user.notify_props || user.notify_props.desktop_sound === 'true') {
|
||||
Utils.ding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handlePostEditEvent(msg) {
|
||||
// Store post
|
||||
const post = JSON.parse(msg.props.post);
|
||||
PostStore.storePost(post);
|
||||
PostStore.emitChange();
|
||||
|
||||
// Update channel state
|
||||
if (ChannelStore.getCurrentId() === msg.channel_id) {
|
||||
if (window.isActive) {
|
||||
AsyncClient.updateLastViewedAt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handlePostDeleteEvent(msg) {
|
||||
const post = JSON.parse(msg.props.post);
|
||||
GlobalActions.emitPostDeletedEvent(post);
|
||||
}
|
||||
|
||||
function handleNewUserEvent() {
|
||||
AsyncClient.getProfiles();
|
||||
AsyncClient.getChannelExtraInfo();
|
||||
}
|
||||
|
||||
function handleUserAddedEvent(msg) {
|
||||
if (ChannelStore.getCurrentId() === msg.channel_id) {
|
||||
AsyncClient.getChannelExtraInfo();
|
||||
}
|
||||
|
||||
if (UserStore.getCurrentId() === msg.user_id) {
|
||||
AsyncClient.getChannel(msg.channel_id);
|
||||
}
|
||||
}
|
||||
|
||||
function handleUserRemovedEvent(msg) {
|
||||
if (UserStore.getCurrentId() === msg.user_id) {
|
||||
AsyncClient.getChannels();
|
||||
|
||||
if (msg.props.remover_id !== msg.user_id &&
|
||||
msg.channel_id === ChannelStore.getCurrentId() &&
|
||||
$('#removed_from_channel').length > 0) {
|
||||
var sentState = {};
|
||||
sentState.channelName = ChannelStore.getCurrent().display_name;
|
||||
sentState.remover = UserStore.getProfile(msg.props.remover_id).username;
|
||||
|
||||
BrowserStore.setItem('channel-removed-state', sentState);
|
||||
$('#removed_from_channel').modal('show');
|
||||
}
|
||||
} else if (ChannelStore.getCurrentId() === msg.channel_id) {
|
||||
AsyncClient.getChannelExtraInfo();
|
||||
}
|
||||
}
|
||||
|
||||
function handleChannelViewedEvent(msg) {
|
||||
// Useful for when multiple devices have the app open to different channels
|
||||
if (ChannelStore.getCurrentId() !== msg.channel_id && UserStore.getCurrentId() === msg.user_id) {
|
||||
AsyncClient.getChannel(msg.channel_id);
|
||||
}
|
||||
}
|
||||
|
||||
function handlePreferenceChangedEvent(msg) {
|
||||
const preference = JSON.parse(msg.props.preference);
|
||||
GlobalActions.emitPreferenceChangedEvent(preference);
|
||||
}
|
||||
|
||||
var SocketStore = new SocketStoreClass();
|
||||
|
||||
export default SocketStore;
|
||||
window.SocketStore = SocketStore;
|
||||
261
webapp/stores/suggestion_store.jsx
Обычный файл
261
webapp/stores/suggestion_store.jsx
Обычный файл
@@ -0,0 +1,261 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const COMPLETE_WORD_EVENT = 'complete_word';
|
||||
const PRETEXT_CHANGED_EVENT = 'pretext_changed';
|
||||
const SUGGESTIONS_CHANGED_EVENT = 'suggestions_changed';
|
||||
|
||||
class SuggestionStore extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.addSuggestionsChangedListener = this.addSuggestionsChangedListener.bind(this);
|
||||
this.removeSuggestionsChangedListener = this.removeSuggestionsChangedListener.bind(this);
|
||||
this.emitSuggestionsChanged = this.emitSuggestionsChanged.bind(this);
|
||||
|
||||
this.addPretextChangedListener = this.addPretextChangedListener.bind(this);
|
||||
this.removePretextChangedListener = this.removePretextChangedListener.bind(this);
|
||||
this.emitPretextChanged = this.emitPretextChanged.bind(this);
|
||||
|
||||
this.addCompleteWordListener = this.addCompleteWordListener.bind(this);
|
||||
this.removeCompleteWordListener = this.removeCompleteWordListener.bind(this);
|
||||
this.emitCompleteWord = this.emitCompleteWord.bind(this);
|
||||
|
||||
this.handleEventPayload = this.handleEventPayload.bind(this);
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||
|
||||
// this.suggestions stores the state of all SuggestionBoxes by mapping their unique identifier to an
|
||||
// object with the following fields:
|
||||
// pretext: the text before the cursor
|
||||
// matchedPretext: the text before the cursor that will be replaced if an autocomplete term is selected
|
||||
// terms: a list of strings which the previously typed text may be replaced by
|
||||
// items: a list of objects backing the terms which may be used in rendering
|
||||
// components: a list of react components that can be used to render their corresponding item
|
||||
// selection: the term currently selected by the keyboard
|
||||
this.suggestions = new Map();
|
||||
}
|
||||
|
||||
addSuggestionsChangedListener(id, callback) {
|
||||
this.on(SUGGESTIONS_CHANGED_EVENT + id, callback);
|
||||
}
|
||||
removeSuggestionsChangedListener(id, callback) {
|
||||
this.removeListener(SUGGESTIONS_CHANGED_EVENT + id, callback);
|
||||
}
|
||||
emitSuggestionsChanged(id) {
|
||||
this.emit(SUGGESTIONS_CHANGED_EVENT + id);
|
||||
}
|
||||
|
||||
addPretextChangedListener(id, callback) {
|
||||
this.on(PRETEXT_CHANGED_EVENT + id, callback);
|
||||
}
|
||||
removePretextChangedListener(id, callback) {
|
||||
this.removeListener(PRETEXT_CHANGED_EVENT + id, callback);
|
||||
}
|
||||
emitPretextChanged(id, pretext) {
|
||||
this.emit(PRETEXT_CHANGED_EVENT + id, pretext);
|
||||
}
|
||||
|
||||
addCompleteWordListener(id, callback) {
|
||||
this.on(COMPLETE_WORD_EVENT + id, callback);
|
||||
}
|
||||
removeCompleteWordListener(id, callback) {
|
||||
this.removeListener(COMPLETE_WORD_EVENT + id, callback);
|
||||
}
|
||||
emitCompleteWord(id, term) {
|
||||
this.emit(COMPLETE_WORD_EVENT + id, term);
|
||||
}
|
||||
|
||||
registerSuggestionBox(id) {
|
||||
this.suggestions.set(id, {
|
||||
pretext: '',
|
||||
matchedPretext: '',
|
||||
terms: [],
|
||||
items: [],
|
||||
components: [],
|
||||
selection: ''
|
||||
});
|
||||
}
|
||||
|
||||
unregisterSuggestionBox(id) {
|
||||
this.suggestions.delete(id);
|
||||
}
|
||||
|
||||
clearSuggestions(id) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.matchedPretext = '';
|
||||
suggestion.terms = [];
|
||||
suggestion.items = [];
|
||||
suggestion.components = [];
|
||||
}
|
||||
|
||||
clearSelection(id) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.selection = '';
|
||||
}
|
||||
|
||||
hasSuggestions(id) {
|
||||
return this.suggestions.get(id).terms.length > 0;
|
||||
}
|
||||
|
||||
setPretext(id, pretext) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.pretext = pretext;
|
||||
}
|
||||
|
||||
setMatchedPretext(id, matchedPretext) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.matchedPretext = matchedPretext;
|
||||
}
|
||||
|
||||
addSuggestion(id, term, item, component) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.terms.push(term);
|
||||
suggestion.items.push(item);
|
||||
suggestion.components.push(component);
|
||||
}
|
||||
|
||||
addSuggestions(id, terms, items, component) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
suggestion.terms.push(...terms);
|
||||
suggestion.items.push(...items);
|
||||
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
suggestion.components.push(component);
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that if suggestions exist, then one of them is selected. return true if the selection changes.
|
||||
ensureSelectionExists(id) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
if (suggestion.terms.length > 0) {
|
||||
// if the current selection is no longer in the map, select the first term in the list
|
||||
if (!suggestion.selection || suggestion.terms.indexOf(suggestion.selection) === -1) {
|
||||
suggestion.selection = suggestion.terms[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (suggestion.selection) {
|
||||
suggestion.selection = '';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getPretext(id) {
|
||||
return this.suggestions.get(id).pretext;
|
||||
}
|
||||
|
||||
getMatchedPretext(id) {
|
||||
return this.suggestions.get(id).matchedPretext;
|
||||
}
|
||||
|
||||
getItems(id) {
|
||||
return this.suggestions.get(id).items;
|
||||
}
|
||||
|
||||
getTerms(id) {
|
||||
return this.suggestions.get(id).terms;
|
||||
}
|
||||
|
||||
getComponents(id) {
|
||||
return this.suggestions.get(id).components;
|
||||
}
|
||||
|
||||
getSelection(id) {
|
||||
return this.suggestions.get(id).selection;
|
||||
}
|
||||
|
||||
selectNext(id) {
|
||||
this.setSelectionByDelta(id, 1);
|
||||
}
|
||||
|
||||
selectPrevious(id) {
|
||||
this.setSelectionByDelta(id, -1);
|
||||
}
|
||||
|
||||
setSelectionByDelta(id, delta) {
|
||||
const suggestion = this.suggestions.get(id);
|
||||
|
||||
let selectionIndex = suggestion.terms.indexOf(suggestion.selection);
|
||||
|
||||
if (selectionIndex === -1) {
|
||||
// this should never happen since selection should always be in terms
|
||||
throw new Error('selection is not in terms');
|
||||
}
|
||||
|
||||
selectionIndex += delta;
|
||||
|
||||
if (selectionIndex < 0) {
|
||||
selectionIndex = 0;
|
||||
} else if (selectionIndex > suggestion.terms.length - 1) {
|
||||
selectionIndex = suggestion.terms.length - 1;
|
||||
}
|
||||
|
||||
suggestion.selection = suggestion.terms[selectionIndex];
|
||||
}
|
||||
|
||||
handleEventPayload(payload) {
|
||||
const {type, id, ...other} = payload.action; // eslint-disable-line no-use-before-define
|
||||
|
||||
switch (type) {
|
||||
case ActionTypes.SUGGESTION_PRETEXT_CHANGED:
|
||||
this.clearSuggestions(id);
|
||||
|
||||
this.setPretext(id, other.pretext);
|
||||
this.emitPretextChanged(id, other.pretext);
|
||||
|
||||
this.ensureSelectionExists(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
|
||||
if (this.getMatchedPretext(id) === '') {
|
||||
this.setMatchedPretext(id, other.matchedPretext);
|
||||
|
||||
// ensure the matched pretext hasn't changed so that we don't receive suggestions for outdated pretext
|
||||
this.addSuggestions(id, other.terms, other.items, other.component);
|
||||
|
||||
this.ensureSelectionExists(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
}
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_CLEAR_SUGGESTIONS:
|
||||
this.clearSuggestions(id);
|
||||
this.clearSelection(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_SELECT_NEXT:
|
||||
this.selectNext(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_SELECT_PREVIOUS:
|
||||
this.selectPrevious(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_COMPLETE_WORD:
|
||||
this.emitCompleteWord(id, other.term || this.getSelection(id), this.getMatchedPretext(id));
|
||||
|
||||
this.setPretext(id, '');
|
||||
this.clearSuggestions(id);
|
||||
this.clearSelection(id);
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new SuggestionStore();
|
||||
142
webapp/stores/team_store.jsx
Обычный файл
142
webapp/stores/team_store.jsx
Обычный файл
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
var Utils;
|
||||
function getWindowLocationOrigin() {
|
||||
if (!Utils) {
|
||||
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
|
||||
}
|
||||
return Utils.getWindowLocationOrigin();
|
||||
}
|
||||
|
||||
class TeamStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.get = this.get.bind(this);
|
||||
this.getByName = this.getByName.bind(this);
|
||||
this.getAll = this.getAll.bind(this);
|
||||
this.getCurrentId = this.getCurrentId.bind(this);
|
||||
this.getCurrent = this.getCurrent.bind(this);
|
||||
this.getCurrentTeamUrl = this.getCurrentTeamUrl.bind(this);
|
||||
this.getCurrentInviteLink = this.getCurrentInviteLink.bind(this);
|
||||
this.saveTeam = this.saveTeam.bind(this);
|
||||
|
||||
this.teams = {};
|
||||
this.currentTeamId = '';
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
get(id) {
|
||||
var c = this.getAll();
|
||||
return c[id];
|
||||
}
|
||||
|
||||
getByName(name) {
|
||||
var t = this.getAll();
|
||||
|
||||
for (var id in t) {
|
||||
if (t[id].name === name) {
|
||||
return t[id];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return this.teams;
|
||||
}
|
||||
|
||||
getCurrentId() {
|
||||
var team = this.get(this.currentTeamId);
|
||||
|
||||
if (team) {
|
||||
return team.id;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getCurrent() {
|
||||
const team = this.teams[this.currentTeamId];
|
||||
|
||||
if (team) {
|
||||
return team;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getCurrentTeamUrl() {
|
||||
if (this.getCurrent()) {
|
||||
return getWindowLocationOrigin() + '/' + this.getCurrent().name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getCurrentInviteLink() {
|
||||
const current = this.getCurrent();
|
||||
|
||||
if (current) {
|
||||
return getWindowLocationOrigin() + '/signup_user_complete/?id=' + current.invite_id;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
saveTeam(team) {
|
||||
this.teams[team.id] = team;
|
||||
}
|
||||
|
||||
saveTeams(teams) {
|
||||
this.teams = teams;
|
||||
}
|
||||
|
||||
saveMyTeam(team) {
|
||||
this.saveTeam(team);
|
||||
this.currentTeamId = team.id;
|
||||
}
|
||||
}
|
||||
|
||||
var TeamStore = new TeamStoreClass();
|
||||
|
||||
TeamStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_MY_TEAM:
|
||||
TeamStore.saveMyTeam(action.team);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ALL_TEAMS:
|
||||
TeamStore.saveTeams(action.teams);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export default TeamStore;
|
||||
305
webapp/stores/user_store.jsx
Обычный файл
305
webapp/stores/user_store.jsx
Обычный файл
@@ -0,0 +1,305 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
import BrowserStore from './browser_store.jsx';
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
||||
const CHANGE_EVENT_AUDITS = 'change_audits';
|
||||
const CHANGE_EVENT_STATUSES = 'change_statuses';
|
||||
|
||||
class UserStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.profileCache = null;
|
||||
this.currentUserId = '';
|
||||
}
|
||||
|
||||
emitChange(userId) {
|
||||
this.emit(CHANGE_EVENT, userId);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
removeChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitSessionsChange() {
|
||||
this.emit(CHANGE_EVENT_SESSIONS);
|
||||
}
|
||||
|
||||
addSessionsChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_SESSIONS, callback);
|
||||
}
|
||||
|
||||
removeSessionsChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_SESSIONS, callback);
|
||||
}
|
||||
|
||||
emitAuditsChange() {
|
||||
this.emit(CHANGE_EVENT_AUDITS);
|
||||
}
|
||||
|
||||
addAuditsChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_AUDITS, callback);
|
||||
}
|
||||
|
||||
removeAuditsChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_AUDITS, callback);
|
||||
}
|
||||
|
||||
emitStatusesChange() {
|
||||
this.emit(CHANGE_EVENT_STATUSES);
|
||||
}
|
||||
|
||||
addStatusesChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_STATUSES, callback);
|
||||
}
|
||||
|
||||
removeStatusesChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_STATUSES, callback);
|
||||
}
|
||||
|
||||
getCurrentUser() {
|
||||
return this.getProfiles()[this.currentUserId];
|
||||
}
|
||||
|
||||
setCurrentUser(user) {
|
||||
this.saveProfile(user);
|
||||
this.currentUserId = user.id;
|
||||
global.window.mm_current_user_id = this.currentUserId;
|
||||
}
|
||||
|
||||
getCurrentId() {
|
||||
var user = this.getCurrentUser();
|
||||
|
||||
if (user) {
|
||||
return user.id;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getLastEmail() {
|
||||
return BrowserStore.getGlobalItem('last_email', '');
|
||||
}
|
||||
|
||||
setLastEmail(email) {
|
||||
BrowserStore.setGlobalItem('last_email', email);
|
||||
}
|
||||
|
||||
getLastUsername() {
|
||||
return BrowserStore.getGlobalItem('last_username', '');
|
||||
}
|
||||
|
||||
setLastUsername(username) {
|
||||
BrowserStore.setGlobalItem('last_username', username);
|
||||
}
|
||||
|
||||
hasProfile(userId) {
|
||||
return this.getProfiles()[userId] != null;
|
||||
}
|
||||
|
||||
getProfile(userId) {
|
||||
if (userId === this.getCurrentId()) {
|
||||
return this.getCurrentUser();
|
||||
}
|
||||
|
||||
return this.getProfiles()[userId];
|
||||
}
|
||||
|
||||
getProfileByUsername(username) {
|
||||
return this.getProfilesUsernameMap()[username];
|
||||
}
|
||||
|
||||
getProfilesUsernameMap() {
|
||||
var profileUsernameMap = {};
|
||||
|
||||
var profiles = this.getProfiles();
|
||||
for (var key in profiles) {
|
||||
if (profiles.hasOwnProperty(key)) {
|
||||
var profile = profiles[key];
|
||||
profileUsernameMap[profile.username] = profile;
|
||||
}
|
||||
}
|
||||
|
||||
return profileUsernameMap;
|
||||
}
|
||||
|
||||
getProfiles() {
|
||||
if (this.profileCache !== null) {
|
||||
return this.profileCache;
|
||||
}
|
||||
|
||||
return BrowserStore.getItem('profiles', {});
|
||||
}
|
||||
|
||||
getActiveOnlyProfiles(skipCurrent) {
|
||||
const active = {};
|
||||
const profiles = this.getProfiles();
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
for (var key in profiles) {
|
||||
if (!(profiles[key].id === currentId && skipCurrent) && profiles[key].delete_at === 0) {
|
||||
active[key] = profiles[key];
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
getActiveOnlyProfileList() {
|
||||
const profileMap = this.getActiveOnlyProfiles();
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
for (const id in profileMap) {
|
||||
if (profileMap.hasOwnProperty(id) && id !== currentId) {
|
||||
profiles.push(profileMap[id]);
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
saveProfile(profile) {
|
||||
var ps = this.getProfiles();
|
||||
ps[profile.id] = profile;
|
||||
this.profileCache = ps;
|
||||
BrowserStore.setItem('profiles', ps);
|
||||
}
|
||||
|
||||
saveProfiles(profiles) {
|
||||
const currentId = this.getCurrentId();
|
||||
if (this.profileCache) {
|
||||
const currentUser = this.profileCache[currentId];
|
||||
if (currentUser) {
|
||||
if (currentId in profiles) {
|
||||
delete profiles[currentId];
|
||||
}
|
||||
|
||||
this.profileCache = profiles;
|
||||
this.profileCache[currentId] = currentUser;
|
||||
} else {
|
||||
this.profileCache = profiles;
|
||||
}
|
||||
} else {
|
||||
this.profileCache = profiles;
|
||||
}
|
||||
|
||||
BrowserStore.setItem('profiles', profiles);
|
||||
}
|
||||
|
||||
setSessions(sessions) {
|
||||
BrowserStore.setItem('sessions', sessions);
|
||||
}
|
||||
|
||||
getSessions() {
|
||||
return BrowserStore.getItem('sessions', {loading: true});
|
||||
}
|
||||
|
||||
setAudits(audits) {
|
||||
BrowserStore.setItem('audits', audits);
|
||||
}
|
||||
|
||||
getAudits() {
|
||||
return BrowserStore.getItem('audits', {loading: true});
|
||||
}
|
||||
|
||||
getCurrentMentionKeys() {
|
||||
return this.getMentionKeys(this.getCurrentId());
|
||||
}
|
||||
|
||||
getMentionKeys(id) {
|
||||
var user = this.getProfile(id);
|
||||
|
||||
var keys = [];
|
||||
|
||||
if (!user || !user.notify_props) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
if (user.notify_props.mention_keys) {
|
||||
keys = keys.concat(user.notify_props.mention_keys.split(','));
|
||||
}
|
||||
|
||||
if (user.notify_props.first_name === 'true' && user.first_name) {
|
||||
keys.push(user.first_name);
|
||||
}
|
||||
|
||||
if (user.notify_props.all === 'true') {
|
||||
keys.push('@all');
|
||||
}
|
||||
|
||||
if (user.notify_props.channel === 'true') {
|
||||
keys.push('@channel');
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
setStatuses(statuses) {
|
||||
this.pSetStatuses(statuses);
|
||||
this.emitStatusesChange();
|
||||
}
|
||||
|
||||
pSetStatuses(statuses) {
|
||||
BrowserStore.setItem('statuses', statuses);
|
||||
}
|
||||
|
||||
setStatus(userId, status) {
|
||||
var statuses = this.getStatuses();
|
||||
statuses[userId] = status;
|
||||
this.pSetStatuses(statuses);
|
||||
this.emitStatusesChange();
|
||||
}
|
||||
|
||||
getStatuses() {
|
||||
return BrowserStore.getItem('statuses', {});
|
||||
}
|
||||
|
||||
getStatus(id) {
|
||||
return this.getStatuses()[id];
|
||||
}
|
||||
}
|
||||
|
||||
var UserStore = new UserStoreClass();
|
||||
UserStore.setMaxListeners(15);
|
||||
|
||||
UserStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_PROFILES:
|
||||
UserStore.saveProfiles(action.profiles);
|
||||
UserStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ME:
|
||||
UserStore.setCurrentUser(action.me);
|
||||
UserStore.emitChange(action.me.id);
|
||||
break;
|
||||
case ActionTypes.RECEIVED_SESSIONS:
|
||||
UserStore.setSessions(action.sessions);
|
||||
UserStore.emitSessionsChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_AUDITS:
|
||||
UserStore.setAudits(action.audits);
|
||||
UserStore.emitAuditsChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_STATUSES:
|
||||
UserStore.pSetStatuses(action.statuses);
|
||||
UserStore.emitStatusesChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export {UserStore as default};
|
||||
Ссылка в новой задаче
Block a user