mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
PLT-3114 Moved preview collapse out of pre-release features (#3206)
* Added user setting to auto collapse image previews * Added slash commands for collapsing/expanding image previews * Added translation strings for collapse setting * Add default props for preview collapse setting
This commit is contained in:
committed by
Corey Hulen
parent
629b49a119
commit
1e245f19c7
@@ -72,6 +72,10 @@ export default class Post extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextProps.previewCollapsed !== this.props.previewCollapsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Utils.areObjectsEqual(nextProps.user, this.props.user)) {
|
||||
return true;
|
||||
}
|
||||
@@ -190,6 +194,7 @@ export default class Post extends React.Component {
|
||||
parentPost={parentPost}
|
||||
handleCommentClick={this.handleCommentClick}
|
||||
compactDisplay={this.props.compactDisplay}
|
||||
previewCollapsed={this.props.previewCollapsed}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -213,5 +218,6 @@ Post.propTypes = {
|
||||
currentUser: React.PropTypes.object.isRequired,
|
||||
center: React.PropTypes.bool,
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewCollapsed: React.PropTypes.string,
|
||||
commentCount: React.PropTypes.number
|
||||
};
|
||||
|
||||
@@ -25,7 +25,11 @@ export default class PostBody extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Utils.areObjectsEqual(nextProps.compactDisplay, this.props.compactDisplay)) {
|
||||
if (nextProps.compactDisplay !== this.props.compactDisplay) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextProps.previewCollapsed !== this.props.previewCollapsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -172,6 +176,7 @@ export default class PostBody extends React.Component {
|
||||
post={this.props.post}
|
||||
message={messageWrapper}
|
||||
compactDisplay={this.props.compactDisplay}
|
||||
previewCollapsed={this.props.previewCollapsed}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -193,5 +198,6 @@ PostBody.propTypes = {
|
||||
parentPost: React.PropTypes.object,
|
||||
retryPost: React.PropTypes.func.isRequired,
|
||||
handleCommentClick: React.PropTypes.func.isRequired,
|
||||
compactDisplay: React.PropTypes.bool
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewCollapsed: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -22,10 +22,14 @@ export default class PostBodyAdditionalContent extends React.Component {
|
||||
this.toggleEmbedVisibility = this.toggleEmbedVisibility.bind(this);
|
||||
|
||||
this.state = {
|
||||
embedVisible: true
|
||||
embedVisible: props.previewCollapsed.startsWith('false')
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({embedVisible: nextProps.previewCollapsed.startsWith('false')});
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
|
||||
return true;
|
||||
@@ -118,25 +122,23 @@ export default class PostBodyAdditionalContent extends React.Component {
|
||||
|
||||
if (generateEmbed) {
|
||||
let messageWithToggle = [];
|
||||
if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMBED_TOGGLE)) {
|
||||
// if message has only one line and starts with a link place toggle in this only line
|
||||
// else - place it in new line between message and embed
|
||||
const prependToggle = (/^\s*https?:\/\/.*$/).test(this.props.post.message);
|
||||
messageWithToggle.push(
|
||||
<a
|
||||
className={`post__embed-visibility ${prependToggle ? 'pull-left' : ''}`}
|
||||
data-expanded={this.state.embedVisible}
|
||||
aria-label='Toggle Embed Visibility'
|
||||
onClick={this.toggleEmbedVisibility}
|
||||
/>
|
||||
);
|
||||
if (prependToggle) {
|
||||
messageWithToggle.push(this.props.message);
|
||||
} else {
|
||||
messageWithToggle.unshift(this.props.message);
|
||||
}
|
||||
} else {
|
||||
|
||||
// if message has only one line and starts with a link place toggle in this only line
|
||||
// else - place it in new line between message and embed
|
||||
const prependToggle = (/^\s*https?:\/\/.*$/).test(this.props.post.message);
|
||||
messageWithToggle.push(
|
||||
<a
|
||||
className={`post__embed-visibility ${prependToggle ? 'pull-left' : ''}`}
|
||||
data-expanded={this.state.embedVisible}
|
||||
aria-label='Toggle Embed Visibility'
|
||||
onClick={this.toggleEmbedVisibility}
|
||||
/>
|
||||
);
|
||||
|
||||
if (prependToggle) {
|
||||
messageWithToggle.push(this.props.message);
|
||||
} else {
|
||||
messageWithToggle.unshift(this.props.message);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -156,8 +158,12 @@ export default class PostBodyAdditionalContent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
PostBodyAdditionalContent.defaultProps = {
|
||||
previewCollapsed: 'false'
|
||||
};
|
||||
PostBodyAdditionalContent.propTypes = {
|
||||
post: React.PropTypes.object.isRequired,
|
||||
message: React.PropTypes.element.isRequired,
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
message: React.PropTypes.element.isRequired
|
||||
previewCollapsed: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -260,6 +260,7 @@ export default class PostList extends React.Component {
|
||||
center={this.props.displayPostsInCenter}
|
||||
commentCount={commentCount}
|
||||
compactDisplay={this.props.compactDisplay}
|
||||
previewCollapsed={this.props.previewsCollapsed}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -520,5 +521,6 @@ PostList.propTypes = {
|
||||
postsToHighlight: React.PropTypes.object,
|
||||
displayNameType: React.PropTypes.string,
|
||||
displayPostsInCenter: React.PropTypes.bool,
|
||||
compactDisplay: React.PropTypes.bool
|
||||
compactDisplay: React.PropTypes.bool,
|
||||
previewsCollapsed: React.PropTypes.string
|
||||
};
|
||||
|
||||
@@ -51,7 +51,8 @@ export default class PostViewController extends React.Component {
|
||||
scrollType: ScrollTypes.NEW_MESSAGE,
|
||||
displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false'),
|
||||
displayPostsInCenter: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED,
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||
previewsCollapsed: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, 'false')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,11 +68,19 @@ export default class PostViewController extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceChange() {
|
||||
onPreferenceChange(category) {
|
||||
// Bit of a hack to force render when this setting is updated
|
||||
// regardless of change
|
||||
let previewSuffix = '';
|
||||
if (category === Preferences.CATEGORY_DISPLAY_SETTINGS) {
|
||||
previewSuffix = '_' + Utils.generateId();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false'),
|
||||
displayPostsInCenter: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED,
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||
previewsCollapsed: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, 'false') + previewSuffix
|
||||
});
|
||||
}
|
||||
|
||||
@@ -132,6 +141,7 @@ export default class PostViewController extends React.Component {
|
||||
displayNameType: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'false'),
|
||||
displayPostsInCenter: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT) === Preferences.CHANNEL_DISPLAY_MODE_CENTERED,
|
||||
compactDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
|
||||
previewsCollapsed: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, 'false'),
|
||||
scrollType: ScrollTypes.NEW_MESSAGE
|
||||
});
|
||||
}
|
||||
@@ -183,6 +193,10 @@ export default class PostViewController extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextState.previewsCollapsed !== this.state.previewsCollapsed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nextState.lastViewed !== this.state.lastViewed) {
|
||||
return true;
|
||||
}
|
||||
@@ -241,6 +255,7 @@ export default class PostViewController extends React.Component {
|
||||
displayNameType={this.state.displayNameType}
|
||||
displayPostsInCenter={this.state.displayPostsInCenter}
|
||||
compactDisplay={this.state.compactDisplay}
|
||||
previewsCollapsed={this.state.previewsCollapsed}
|
||||
lastViewed={this.state.lastViewed}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -234,13 +234,6 @@ export default class AdvancedSettingsDisplay extends React.Component {
|
||||
defaultMessage='Show preview snippet of links below message'
|
||||
/>
|
||||
);
|
||||
case 'EMBED_TOGGLE':
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='user.settings.advance.embed_toggle'
|
||||
defaultMessage='Show toggle for all embed previews'
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ function getDisplayStateFromStores() {
|
||||
nameFormat: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'username'),
|
||||
selectedFont: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT),
|
||||
channelDisplayMode: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT),
|
||||
messageDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT)
|
||||
messageDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT),
|
||||
collapseDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, Preferences.COLLAPSE_DISPLAY_DEFAULT)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,9 +42,11 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
this.updateSection = this.updateSection.bind(this);
|
||||
this.updateState = this.updateState.bind(this);
|
||||
this.deactivate = this.deactivate.bind(this);
|
||||
this.createCollapseSection = this.createCollapseSection.bind(this);
|
||||
|
||||
this.state = getDisplayStateFromStores();
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
const userId = UserStore.getCurrentId();
|
||||
|
||||
@@ -77,8 +80,14 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
name: Preferences.MESSAGE_DISPLAY,
|
||||
value: this.state.messageDisplay
|
||||
};
|
||||
const collapseDisplayPreference = {
|
||||
user_id: userId,
|
||||
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
|
||||
name: Preferences.COLLAPSE_DISPLAY,
|
||||
value: this.state.collapseDisplay
|
||||
};
|
||||
|
||||
AsyncClient.savePreferences([timePreference, namePreference, fontPreference, channelDisplayModePreference, messageDisplayPreference],
|
||||
AsyncClient.savePreferences([timePreference, namePreference, fontPreference, channelDisplayModePreference, messageDisplayPreference, collapseDisplayPreference],
|
||||
() => {
|
||||
this.updateSection('');
|
||||
},
|
||||
@@ -87,27 +96,38 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleClockRadio(militaryTime) {
|
||||
this.setState({militaryTime});
|
||||
}
|
||||
|
||||
handleNameRadio(nameFormat) {
|
||||
this.setState({nameFormat});
|
||||
}
|
||||
|
||||
handleChannelDisplayModeRadio(channelDisplayMode) {
|
||||
this.setState({channelDisplayMode});
|
||||
}
|
||||
|
||||
handlemessageDisplayRadio(messageDisplay) {
|
||||
this.setState({messageDisplay});
|
||||
}
|
||||
|
||||
handleFont(selectedFont) {
|
||||
Utils.applyFont(selectedFont);
|
||||
this.setState({selectedFont});
|
||||
}
|
||||
|
||||
handleCollapseRadio(collapseDisplay) {
|
||||
this.setState({collapseDisplay});
|
||||
}
|
||||
|
||||
updateSection(section) {
|
||||
$('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
|
||||
this.updateState();
|
||||
this.props.updateSection(section);
|
||||
}
|
||||
|
||||
updateState() {
|
||||
const newState = getDisplayStateFromStores();
|
||||
if (!Utils.areObjectsEqual(newState, this.state)) {
|
||||
@@ -115,9 +135,118 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
this.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
createCollapseSection() {
|
||||
if (this.props.activeSection === 'collapse') {
|
||||
const collapseFormat = [false, false];
|
||||
if (this.state.collapseDisplay === 'true') {
|
||||
collapseFormat[0] = true;
|
||||
} else {
|
||||
collapseFormat[1] = true;
|
||||
}
|
||||
|
||||
const handleUpdateCollapseSection = (e) => {
|
||||
this.updateSection('');
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const inputs = [
|
||||
<div key='userDisplayCollapseOptions'>
|
||||
<div className='radio'>
|
||||
<label>
|
||||
<input
|
||||
type='radio'
|
||||
name='collapseFormat'
|
||||
checked={collapseFormat[0]}
|
||||
onChange={this.handleCollapseRadio.bind(this, 'true')}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseOn'
|
||||
defaultMessage='On'
|
||||
/>
|
||||
</label>
|
||||
<br/>
|
||||
</div>
|
||||
<div className='radio'>
|
||||
<label>
|
||||
<input
|
||||
type='radio'
|
||||
name='collapseFormat'
|
||||
checked={collapseFormat[1]}
|
||||
onChange={this.handleCollapseRadio.bind(this, 'false')}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseOff'
|
||||
defaultMessage='Off'
|
||||
/>
|
||||
</label>
|
||||
<br/>
|
||||
</div>
|
||||
<div>
|
||||
<br/>
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseDesc'
|
||||
defaultMessage='Toggle whether to automatically collapse all image previews.'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
];
|
||||
|
||||
return (
|
||||
<SettingItemMax
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseDisplay'
|
||||
defaultMessage='Auto Collapse Previews'
|
||||
/>
|
||||
}
|
||||
inputs={inputs}
|
||||
submit={this.handleSubmit}
|
||||
server_error={this.state.serverError}
|
||||
updateSection={handleUpdateCollapseSection}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let describe;
|
||||
if (this.state.collapseDisplay === 'true') {
|
||||
describe = (
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseOn'
|
||||
defaultMessage='On'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
describe = (
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseOff'
|
||||
defaultMessage='Off'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const handleUpdateCollapseSection = () => {
|
||||
this.props.updateSection('collapse');
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingItemMin
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='user.settings.display.collapseDisplay'
|
||||
defaultMessage='Auto Collapse Previews'
|
||||
/>
|
||||
}
|
||||
describe={describe}
|
||||
updateSection={handleUpdateCollapseSection}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const serverError = this.state.serverError || null;
|
||||
let clockSection;
|
||||
@@ -127,6 +256,8 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
let languagesSection;
|
||||
let messageDisplaySection;
|
||||
|
||||
const collapseSection = this.createCollapseSection();
|
||||
|
||||
if (this.props.activeSection === 'clock') {
|
||||
const clockFormat = [false, false];
|
||||
if (this.state.militaryTime === 'true') {
|
||||
@@ -729,6 +860,8 @@ export default class UserSettingsDisplay extends React.Component {
|
||||
<div className='divider-dark'/>
|
||||
{nameFormatSection}
|
||||
<div className='divider-dark'/>
|
||||
{collapseSection}
|
||||
<div className='divider-dark'/>
|
||||
{messageDisplaySection}
|
||||
<div className='divider-dark'/>
|
||||
{channelDisplayModeSection}
|
||||
|
||||
@@ -1290,6 +1290,10 @@
|
||||
"user.settings.developer.register": "Register New Application",
|
||||
"user.settings.developer.thirdParty": "Open to register a new third-party application",
|
||||
"user.settings.developer.title": "Developer Settings",
|
||||
"user.settings.display.collapseOn": "On",
|
||||
"user.settings.display.collapseOff": "Off",
|
||||
"user.settings.display.collapseDesc": "Toggle whether to automatically collapse all image previews.",
|
||||
"user.settings.display.collapseDisplay": "Auto Collapse Previews",
|
||||
"user.settings.display.channelDisplayTitle": "Channel Display Mode",
|
||||
"user.settings.display.channeldisplaymode": "Select the width of the center channel.",
|
||||
"user.settings.display.clockDisplay": "Clock Display",
|
||||
|
||||
@@ -82,8 +82,8 @@ class PreferenceStoreClass extends EventEmitter {
|
||||
this.preferences.clear();
|
||||
}
|
||||
|
||||
emitChange() {
|
||||
this.emit(CHANGE_EVENT);
|
||||
emitChange(category) {
|
||||
this.emit(CHANGE_EVENT, category);
|
||||
}
|
||||
|
||||
addChangeListener(callback) {
|
||||
@@ -101,7 +101,7 @@ class PreferenceStoreClass extends EventEmitter {
|
||||
case ActionTypes.RECEIVED_PREFERENCE: {
|
||||
const preference = action.preference;
|
||||
this.setPreference(preference.category, preference.name, preference.value);
|
||||
this.emitChange();
|
||||
this.emitChange(preference.category);
|
||||
break;
|
||||
}
|
||||
case ActionTypes.RECEIVED_PREFERENCES:
|
||||
|
||||
@@ -547,7 +547,9 @@ export default {
|
||||
MESSAGE_DISPLAY: 'message_display',
|
||||
MESSAGE_DISPLAY_CLEAN: 'clean',
|
||||
MESSAGE_DISPLAY_COMPACT: 'compact',
|
||||
MESSAGE_DISPLAY_DEFAULT: 'clean'
|
||||
MESSAGE_DISPLAY_DEFAULT: 'clean',
|
||||
COLLAPSE_DISPLAY: 'collapse_previews',
|
||||
COLLAPSE_DISPLAY_DEFAULT: 'false'
|
||||
},
|
||||
TutorialSteps: {
|
||||
INTRO_SCREENS: 0,
|
||||
@@ -728,10 +730,6 @@ export default {
|
||||
EMBED_PREVIEW: {
|
||||
label: 'embed_preview',
|
||||
description: 'Show preview snippet of links below message'
|
||||
},
|
||||
EMBED_TOGGLE: {
|
||||
label: 'embed_toggle',
|
||||
description: 'Show toggle for all embed previews'
|
||||
}
|
||||
},
|
||||
OVERLAY_TIME_DELAY: 400,
|
||||
|
||||
Reference in New Issue
Block a user