[MM-53650] Add disable emoticon rendering setting to webapp (#29414)
* add renderEmoticonsAsEmoji to post_markdown * add renderEmoticonsAsEmoji to preferences, config * add EnableRenderEmoticonsAsEmoji to GenerateClientConfig * add EnableRenderEmoticonsAsEmoji to TeamSettings * create renderEmoticonsAsEmoji component * update translation file * update tests * add tests for RenderEmoticonsAsEmoji * remove unused prop * remove unused variables * add test cases for undefined/false values for renderemoticonsasemoji * switch strings from backticks to single quotes * Update webapp/channels/src/components/user_settings/display/render_emoticons_as_emoji/render_emoticons_as_emoji.tsx Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com> * Update webapp/channels/src/components/user_settings/display/render_emoticons_as_emoji/render_emoticons_as_emoji.tsx Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com> * Update webapp/channels/src/components/user_settings/display/render_emoticons_as_emoji/render_emoticons_as_emoji.tsx Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com> * Update webapp/channels/src/utils/emoticons.tsx Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com> * remove server setting * remove usestate * update i18n * remove config setting * fix broken test * fix focus edit button logic * update tests for when render emoticons option is undefined * remove config usage from selectors * update setting display text * remove 'automatically' from setting description * use default from preferences instead of hardcoded true * update component snapshot * remove renderemoticonsasemoji = true from emoticons tests * Apply suggestions from code review * Switch from useEffect to useDidUpdate * Run fix-style * Add RenderEmoticonsAsEmoji component to test spec * Rewrite RenderEmoticonsAsEmoji to mirror ManageTimezones and ManageLanguages * Update UserSettingsDisplay snapshot * Switch test to renderWithContext, update props * Move options into const objects * Wrap functions in useCallback --------- Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com> Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
@@ -50,6 +50,7 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
|||||||
{key: 'click_to_reply', label: 'Click to open threads', type: 'radio'},
|
{key: 'click_to_reply', label: 'Click to open threads', type: 'radio'},
|
||||||
{key: 'channel_display_mode', label: 'Channel Display', type: 'radio'},
|
{key: 'channel_display_mode', label: 'Channel Display', type: 'radio'},
|
||||||
{key: 'one_click_reactions_enabled', label: 'Quick reactions on messages', type: 'radio'},
|
{key: 'one_click_reactions_enabled', label: 'Quick reactions on messages', type: 'radio'},
|
||||||
|
{key: 'renderEmoticonsAsEmoji', label: 'Render emoticons as emojis', type: 'radio'},
|
||||||
{key: 'languages', label: 'Language', type: 'dropdown'},
|
{key: 'languages', label: 'Language', type: 'dropdown'},
|
||||||
],
|
],
|
||||||
sidebar: [
|
sidebar: [
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ function makeMapStateToProps() {
|
|||||||
hideGuestTags: getConfig(state).HideGuestTags === 'true',
|
hideGuestTags: getConfig(state).HideGuestTags === 'true',
|
||||||
isEnterpriseOrCloudOrSKUStarterFree: isEnterpriseOrCloudOrSKUStarterFree(license, subscriptionProduct, isEnterpriseReady),
|
isEnterpriseOrCloudOrSKUStarterFree: isEnterpriseOrCloudOrSKUStarterFree(license, subscriptionProduct, isEnterpriseReady),
|
||||||
isEnterpriseReady,
|
isEnterpriseReady,
|
||||||
|
renderEmoticonsAsEmoji: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.RENDER_EMOTICONS_AS_EMOJI, Preferences.RENDER_EMOTICONS_AS_EMOJI_DEFAULT === 'true'),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ describe('components/PostMarkdown', () => {
|
|||||||
isEnterpriseOrCloudOrSKUStarterFree: true,
|
isEnterpriseOrCloudOrSKUStarterFree: true,
|
||||||
isEnterpriseReady: false,
|
isEnterpriseReady: false,
|
||||||
dispatch: jest.fn(),
|
dispatch: jest.fn(),
|
||||||
|
renderEmoticonsAsEmoji: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = {entities: {
|
const state = {entities: {
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ export type OwnProps = {
|
|||||||
*/
|
*/
|
||||||
showPostEditedIndicator?: boolean;
|
showPostEditedIndicator?: boolean;
|
||||||
options?: TextFormattingOptions;
|
options?: TextFormattingOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to render text emoticons (:D) as emojis
|
||||||
|
*/
|
||||||
|
renderEmoticonsAsEmoji?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = PropsFromRedux & OwnProps;
|
type Props = PropsFromRedux & OwnProps;
|
||||||
@@ -52,12 +57,13 @@ export default class PostMarkdown extends React.PureComponent<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getOptions = memoize(
|
getOptions = memoize(
|
||||||
(options?: TextFormattingOptions, disableGroupHighlight?: boolean, mentionHighlight?: boolean, editedAt?: number) => {
|
(options?: TextFormattingOptions, disableGroupHighlight?: boolean, mentionHighlight?: boolean, editedAt?: number, renderEmoticonsAsEmoji?: boolean) => {
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
disableGroupHighlight,
|
disableGroupHighlight,
|
||||||
mentionHighlight,
|
mentionHighlight,
|
||||||
editedAt,
|
editedAt,
|
||||||
|
renderEmoticonsAsEmoji,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,6 +116,7 @@ export default class PostMarkdown extends React.PureComponent<Props> {
|
|||||||
this.props.post?.props?.disable_group_highlight === true,
|
this.props.post?.props?.disable_group_highlight === true,
|
||||||
mentionHighlight,
|
mentionHighlight,
|
||||||
this.props.post?.edit_at,
|
this.props.post?.edit_at,
|
||||||
|
this.props?.renderEmoticonsAsEmoji,
|
||||||
);
|
);
|
||||||
|
|
||||||
let highlightKeys;
|
let highlightKeys;
|
||||||
|
|||||||
@@ -314,6 +314,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -669,6 +711,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -1024,6 +1108,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -1379,6 +1505,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -1661,6 +1829,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={true}
|
active={true}
|
||||||
@@ -1925,6 +2135,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -2280,6 +2532,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -2653,6 +2947,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -2935,6 +3271,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={true}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -3217,6 +3595,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -3499,6 +3919,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -3793,6 +4255,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -4075,6 +4579,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={false}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
@@ -4333,6 +4879,48 @@ exports[`components/user_settings/display/UserSettingsDisplay should not show la
|
|||||||
className="divider-dark"
|
className="divider-dark"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Memo(SettingItem)
|
||||||
|
active={false}
|
||||||
|
areAllSectionsInactive={true}
|
||||||
|
describe={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Off"
|
||||||
|
id="user.settings.advance.off"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
<Memo(Connect(RenderEmoticonsAsEmoji))
|
||||||
|
adminMode={false}
|
||||||
|
renderEmoticonsAsEmoji=""
|
||||||
|
updateSection={[Function]}
|
||||||
|
user={
|
||||||
|
Object {
|
||||||
|
"id": "user_id",
|
||||||
|
"locale": "en",
|
||||||
|
"timezone": Object {
|
||||||
|
"automaticTimezone": "America/New_York",
|
||||||
|
"manualTimezone": "",
|
||||||
|
"useAutomaticTimezone": "true",
|
||||||
|
},
|
||||||
|
"username": "username",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
section="renderEmoticonsAsEmoji"
|
||||||
|
title={
|
||||||
|
<Memo(MemoizedFormattedMessage)
|
||||||
|
defaultMessage="Render emoticons as emojis"
|
||||||
|
id="user.settings.display.renderEmoticonsAsEmojiTitle"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
updateSection={[Function]}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="divider-dark"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Memo(SettingItem)
|
<Memo(SettingItem)
|
||||||
active={false}
|
active={false}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ export function makeMapStateToProps() {
|
|||||||
clickToReply: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CLICK_TO_REPLY, Preferences.CLICK_TO_REPLY_DEFAULT, userPreference),
|
clickToReply: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CLICK_TO_REPLY, Preferences.CLICK_TO_REPLY_DEFAULT, userPreference),
|
||||||
linkPreviewDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, Preferences.LINK_PREVIEW_DISPLAY_DEFAULT, userPreference),
|
linkPreviewDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, Preferences.LINK_PREVIEW_DISPLAY_DEFAULT, userPreference),
|
||||||
oneClickReactionsOnPosts: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.ONE_CLICK_REACTIONS_ENABLED, Preferences.ONE_CLICK_REACTIONS_ENABLED_DEFAULT, userPreference),
|
oneClickReactionsOnPosts: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.ONE_CLICK_REACTIONS_ENABLED, Preferences.ONE_CLICK_REACTIONS_ENABLED_DEFAULT, userPreference),
|
||||||
|
renderEmoticonsAsEmoji: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.RENDER_EMOTICONS_AS_EMOJI, Preferences.RENDER_EMOTICONS_AS_EMOJI_DEFAULT, userPreference),
|
||||||
emojiPickerEnabled,
|
emojiPickerEnabled,
|
||||||
lastActiveDisplay,
|
lastActiveDisplay,
|
||||||
lastActiveTimeEnabled,
|
lastActiveTimeEnabled,
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/user_settings/display/render_emoticons_as_emoji/render_emoticons_as_emoji should match snapshot 1`] = `
|
||||||
|
<div>
|
||||||
|
<section
|
||||||
|
class="section-max form-horizontal "
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="col-sm-12 section-title"
|
||||||
|
id="settingTitle"
|
||||||
|
>
|
||||||
|
Render emoticons as emojis
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<fieldset>
|
||||||
|
<legend
|
||||||
|
class="form-legend hidden-label"
|
||||||
|
>
|
||||||
|
Render emoticons as emojis
|
||||||
|
</legend>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
checked=""
|
||||||
|
class="a11y--active a11y--focused"
|
||||||
|
id="renderEmoticonsAsEmojiOn"
|
||||||
|
name="renderEmoticonsAsEmoji"
|
||||||
|
type="radio"
|
||||||
|
value="true"
|
||||||
|
/>
|
||||||
|
On
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
id="renderEmoticonsAsEmojiOff"
|
||||||
|
name="renderEmoticonsAsEmoji"
|
||||||
|
type="radio"
|
||||||
|
value="false"
|
||||||
|
/>
|
||||||
|
Off
|
||||||
|
</label>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mt-5"
|
||||||
|
>
|
||||||
|
When enabled, text emoticons in messages will be rendered as emojis (For example :D as 😄)
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<hr />
|
||||||
|
<button
|
||||||
|
class="btn btn-primary "
|
||||||
|
data-testid="saveSetting"
|
||||||
|
id="saveSetting"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-tertiary"
|
||||||
|
id="cancelSetting"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {bindActionCreators} from 'redux';
|
||||||
|
import type {Dispatch} from 'redux';
|
||||||
|
|
||||||
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
|
|
||||||
|
import RenderEmoticonsAsEmoji from './render_emoticons_as_emoji';
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch: Dispatch) {
|
||||||
|
return {
|
||||||
|
actions: bindActionCreators({
|
||||||
|
savePreferences,
|
||||||
|
}, dispatch),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(null, mapDispatchToProps)(RenderEmoticonsAsEmoji);
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import type {UserProfile} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
|
||||||
|
|
||||||
|
import RenderEmoticonsAsEmoji from './render_emoticons_as_emoji';
|
||||||
|
|
||||||
|
describe('components/user_settings/display/render_emoticons_as_emoji/render_emoticons_as_emoji', () => {
|
||||||
|
const user = {
|
||||||
|
id: 'user_id',
|
||||||
|
username: 'username',
|
||||||
|
locale: 'en',
|
||||||
|
timezone: {
|
||||||
|
useAutomaticTimezone: 'true',
|
||||||
|
automaticTimezone: 'America/New_York',
|
||||||
|
manualTimezone: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
user: user as UserProfile,
|
||||||
|
renderEmoticonsAsEmoji: 'true',
|
||||||
|
updateSection: jest.fn(),
|
||||||
|
adminMode: false,
|
||||||
|
userPreferences: undefined,
|
||||||
|
actions: {
|
||||||
|
savePreferences: jest.fn(() => {
|
||||||
|
return new Promise<void>((resolve) => {
|
||||||
|
process.nextTick(() => resolve());
|
||||||
|
});
|
||||||
|
})},
|
||||||
|
};
|
||||||
|
|
||||||
|
test('should match snapshot', () => {
|
||||||
|
const {container} = renderWithContext(<RenderEmoticonsAsEmoji {...props}/>);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call updateSection on submit', async () => {
|
||||||
|
const {getByRole, getByLabelText} = renderWithContext(<RenderEmoticonsAsEmoji {...props}/>);
|
||||||
|
|
||||||
|
const radioButtonOff = getByLabelText(/off/i);
|
||||||
|
userEvent.click(radioButtonOff);
|
||||||
|
|
||||||
|
const submitButton = getByRole('button', {name: /save/i});
|
||||||
|
userEvent.click(submitButton);
|
||||||
|
|
||||||
|
expect(props.actions.savePreferences).toHaveBeenCalled();
|
||||||
|
expect(props.updateSection).toHaveBeenCalledWith('');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React, {useCallback, useState} from 'react';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
|
import type {PreferencesType, PreferenceType} from '@mattermost/types/preferences';
|
||||||
|
import type {UserProfile} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import {Preferences} from 'mattermost-redux/constants';
|
||||||
|
|
||||||
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
|
|
||||||
|
export type Actions = {
|
||||||
|
savePreferences: (userId: string, preferences: PreferenceType[]) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OwnProps = {
|
||||||
|
user: UserProfile;
|
||||||
|
updateSection: (section: string) => void;
|
||||||
|
adminMode?: boolean;
|
||||||
|
userPreferences?: PreferencesType;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = OwnProps & {
|
||||||
|
renderEmoticonsAsEmoji: string;
|
||||||
|
actions: Actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderEmoticonsAsEmoji: React.FC<Props> = ({user, renderEmoticonsAsEmoji, updateSection, actions}) => {
|
||||||
|
const [value, setValue] = useState<string>(renderEmoticonsAsEmoji);
|
||||||
|
const [isSaving, setIsSaving] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setValue(e.currentTarget.value);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const submitPreference = useCallback(() => {
|
||||||
|
setIsSaving(true);
|
||||||
|
const pref: PreferenceType = {
|
||||||
|
user_id: user.id,
|
||||||
|
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
|
||||||
|
name: Preferences.RENDER_EMOTICONS_AS_EMOJI,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
actions.savePreferences(user.id, [pref]);
|
||||||
|
setIsSaving(false);
|
||||||
|
updateSection('');
|
||||||
|
}, [user.id, updateSection, actions, value]);
|
||||||
|
|
||||||
|
const changePreference = useCallback(() => {
|
||||||
|
if (value === renderEmoticonsAsEmoji) {
|
||||||
|
updateSection('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitPreference();
|
||||||
|
}, [renderEmoticonsAsEmoji, updateSection, value, submitPreference]);
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
option: 'true',
|
||||||
|
inputId: 'renderEmoticonsAsEmojiOn',
|
||||||
|
messageId: 'user.settings.advance.on',
|
||||||
|
defaultMessage: 'On',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
option: 'false',
|
||||||
|
inputId: 'renderEmoticonsAsEmojiOff',
|
||||||
|
messageId: 'user.settings.advance.off',
|
||||||
|
defaultMessage: 'Off',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const input = (
|
||||||
|
<fieldset key='renderEmoticonsAsEmojiSetting'>
|
||||||
|
<legend className='form-legend hidden-label'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.display.renderEmoticonsAsEmojiTitle'
|
||||||
|
defaultMessage='Render emoticons as emojis'
|
||||||
|
/>
|
||||||
|
</legend>
|
||||||
|
{options.map(({option, inputId, messageId, defaultMessage}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className='radio'
|
||||||
|
key={option}
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
id={inputId}
|
||||||
|
type='radio'
|
||||||
|
name='renderEmoticonsAsEmoji'
|
||||||
|
value={option}
|
||||||
|
checked={value === option}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id={messageId}
|
||||||
|
defaultMessage={defaultMessage}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div className='mt-5'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.display.renderEmoticonsAsEmojiDesc'
|
||||||
|
defaultMessage='When enabled, text emoticons in messages will be rendered as emojis (For example :D as 😄)'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingItemMax
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.display.renderEmoticonsAsEmojiTitle'
|
||||||
|
defaultMessage='Render emoticons as emojis'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
inputs={[input]}
|
||||||
|
submit={changePreference}
|
||||||
|
saving={isSaving}
|
||||||
|
updateSection={updateSection}
|
||||||
|
disableEnterSubmit={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RenderEmoticonsAsEmoji;
|
||||||
@@ -94,6 +94,7 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
|
|||||||
globalHeaderAllowed: true,
|
globalHeaderAllowed: true,
|
||||||
lastActiveDisplay: true,
|
lastActiveDisplay: true,
|
||||||
oneClickReactionsOnPosts: '',
|
oneClickReactionsOnPosts: '',
|
||||||
|
renderEmoticonsAsEmoji: '',
|
||||||
emojiPickerEnabled: true,
|
emojiPickerEnabled: true,
|
||||||
clickToReply: '',
|
clickToReply: '',
|
||||||
lastActiveTimeEnabled: true,
|
lastActiveTimeEnabled: true,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {a11yFocus} from 'utils/utils';
|
|||||||
|
|
||||||
import ManageLanguages from './manage_languages';
|
import ManageLanguages from './manage_languages';
|
||||||
import ManageTimezones from './manage_timezones';
|
import ManageTimezones from './manage_timezones';
|
||||||
|
import RenderEmoticonsAsEmoji from './render_emoticons_as_emoji';
|
||||||
|
|
||||||
import SettingDesktopHeader from '../headers/setting_desktop_header';
|
import SettingDesktopHeader from '../headers/setting_desktop_header';
|
||||||
import SettingMobileHeader from '../headers/setting_mobile_header';
|
import SettingMobileHeader from '../headers/setting_mobile_header';
|
||||||
@@ -120,6 +121,7 @@ type Props = OwnProps & {
|
|||||||
timezoneLabel: string;
|
timezoneLabel: string;
|
||||||
lastActiveDisplay: boolean;
|
lastActiveDisplay: boolean;
|
||||||
lastActiveTimeEnabled: boolean;
|
lastActiveTimeEnabled: boolean;
|
||||||
|
renderEmoticonsAsEmoji: string;
|
||||||
actions: {
|
actions: {
|
||||||
savePreferences: (userId: string, preferences: PreferenceType[]) => void;
|
savePreferences: (userId: string, preferences: PreferenceType[]) => void;
|
||||||
autoUpdateTimezone: (deviceTimezone: string) => void;
|
autoUpdateTimezone: (deviceTimezone: string) => void;
|
||||||
@@ -1147,6 +1149,46 @@ export default class UserSettingsDisplay extends React.PureComponent<Props, Stat
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderEmoticonsAsEmojiSection = (
|
||||||
|
<div>
|
||||||
|
<SettingItem
|
||||||
|
active={this.props.activeSection === 'renderEmoticonsAsEmoji'}
|
||||||
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.display.renderEmoticonsAsEmojiTitle'
|
||||||
|
defaultMessage='Render emoticons as emojis'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
describe={
|
||||||
|
this.props.renderEmoticonsAsEmoji === 'true' ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.advance.on'
|
||||||
|
defaultMessage='On'
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.advance.off'
|
||||||
|
defaultMessage='Off'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
section='renderEmoticonsAsEmoji'
|
||||||
|
updateSection={this.updateSection}
|
||||||
|
max={(
|
||||||
|
<RenderEmoticonsAsEmoji
|
||||||
|
renderEmoticonsAsEmoji={this.props.renderEmoticonsAsEmoji}
|
||||||
|
user={this.props.user}
|
||||||
|
updateSection={this.updateSection}
|
||||||
|
adminMode={this.props.adminMode}
|
||||||
|
userPreferences={this.props.userPreferences}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className='divider-dark'/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id='displaySettings'
|
id='displaySettings'
|
||||||
@@ -1187,6 +1229,7 @@ export default class UserSettingsDisplay extends React.PureComponent<Props, Stat
|
|||||||
{clickToReply}
|
{clickToReply}
|
||||||
{channelDisplayModeSection}
|
{channelDisplayModeSection}
|
||||||
{oneClickReactionsOnPostsSection}
|
{oneClickReactionsOnPostsSection}
|
||||||
|
{renderEmoticonsAsEmojiSection}
|
||||||
{languagesSection}
|
{languagesSection}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5903,6 +5903,8 @@
|
|||||||
"user.settings.display.oneClickReactionsOnPostsDescription": "When enabled, you can react quickly with recently used reactions when hovering over a message.",
|
"user.settings.display.oneClickReactionsOnPostsDescription": "When enabled, you can react quickly with recently used reactions when hovering over a message.",
|
||||||
"user.settings.display.oneClickReactionsOnPostsTitle": "Quick reactions on messages",
|
"user.settings.display.oneClickReactionsOnPostsTitle": "Quick reactions on messages",
|
||||||
"user.settings.display.preferTime": "Select how you prefer time displayed.",
|
"user.settings.display.preferTime": "Select how you prefer time displayed.",
|
||||||
|
"user.settings.display.renderEmoticonsAsEmojiDesc": "When enabled, text emoticons in messages will automatically be rendered as emojis (For example :D as 😄)",
|
||||||
|
"user.settings.display.renderEmoticonsAsEmojiTitle": "Render emoticons as emojis",
|
||||||
"user.settings.display.teammateNameDisplay": "This field is handled through your System Administrator. If you want to change it, you need to do so through your System Administrator.",
|
"user.settings.display.teammateNameDisplay": "This field is handled through your System Administrator. If you want to change it, you need to do so through your System Administrator.",
|
||||||
"user.settings.display.teammateNameDisplayDescription": "Set how to display other user's names in posts and the Direct Messages list.",
|
"user.settings.display.teammateNameDisplayDescription": "Set how to display other user's names in posts and the Direct Messages list.",
|
||||||
"user.settings.display.teammateNameDisplayFullname": "Show first and last name",
|
"user.settings.display.teammateNameDisplayFullname": "Show first and last name",
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const Preferences = {
|
|||||||
SHOW_UNREAD_SECTION: 'show_unread_section',
|
SHOW_UNREAD_SECTION: 'show_unread_section',
|
||||||
CATEGORY_ADVANCED_SETTINGS: 'advanced_settings',
|
CATEGORY_ADVANCED_SETTINGS: 'advanced_settings',
|
||||||
ADVANCED_FILTER_JOIN_LEAVE: 'join_leave',
|
ADVANCED_FILTER_JOIN_LEAVE: 'join_leave',
|
||||||
|
RENDER_EMOTICONS_AS_EMOJI: 'render_emoticons_as_emoji',
|
||||||
ADVANCED_CODE_BLOCK_ON_CTRL_ENTER: 'code_block_ctrl_enter',
|
ADVANCED_CODE_BLOCK_ON_CTRL_ENTER: 'code_block_ctrl_enter',
|
||||||
ADVANCED_SEND_ON_CTRL_ENTER: 'send_on_ctrl_enter',
|
ADVANCED_SEND_ON_CTRL_ENTER: 'send_on_ctrl_enter',
|
||||||
ADVANCED_SYNC_DRAFTS: 'sync_drafts',
|
ADVANCED_SYNC_DRAFTS: 'sync_drafts',
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ export const Preferences = {
|
|||||||
CLICK_TO_REPLY: 'click_to_reply',
|
CLICK_TO_REPLY: 'click_to_reply',
|
||||||
CLICK_TO_REPLY_DEFAULT: 'true',
|
CLICK_TO_REPLY_DEFAULT: 'true',
|
||||||
COLLAPSED_REPLY_THREADS_FALLBACK_DEFAULT: 'off',
|
COLLAPSED_REPLY_THREADS_FALLBACK_DEFAULT: 'off',
|
||||||
|
RENDER_EMOTICONS_AS_EMOJI: 'render_emoticons_as_emoji',
|
||||||
|
RENDER_EMOTICONS_AS_EMOJI_DEFAULT: 'true',
|
||||||
LINK_PREVIEW_DISPLAY: 'link_previews',
|
LINK_PREVIEW_DISPLAY: 'link_previews',
|
||||||
LINK_PREVIEW_DISPLAY_DEFAULT: 'true',
|
LINK_PREVIEW_DISPLAY_DEFAULT: 'true',
|
||||||
COLLAPSE_DISPLAY: 'collapse_previews',
|
COLLAPSE_DISPLAY: 'collapse_previews',
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ describe('Emoticons', () => {
|
|||||||
expect(Emoticons.handleEmoticons('":P"', new Map())).
|
expect(Emoticons.handleEmoticons('":P"', new Map())).
|
||||||
toEqual('"$MM_EMOTICON0$"');
|
toEqual('"$MM_EMOTICON0$"');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('shouldn\'t render text-based emoticons as emoji when renderEmoticonsAsEmoji is false', () => {
|
||||||
|
expect(Emoticons.handleEmoticons('":P"', new Map(), false)).
|
||||||
|
toEqual('":P"');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('matchEmoticons', () => {
|
describe('matchEmoticons', () => {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export function matchEmoticons(text: string): string[] | null {
|
|||||||
export function handleEmoticons(
|
export function handleEmoticons(
|
||||||
text: string,
|
text: string,
|
||||||
tokens: Map<string, {value: string; originalText: string}>,
|
tokens: Map<string, {value: string; originalText: string}>,
|
||||||
|
renderEmoticonsAsEmoji = true,
|
||||||
): string {
|
): string {
|
||||||
let output = text;
|
let output = text;
|
||||||
|
|
||||||
@@ -85,12 +86,14 @@ export function handleEmoticons(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// match text smilies like :D
|
// match text smilies like :D
|
||||||
for (const name of Object.keys(emoticonPatterns)) {
|
if (renderEmoticonsAsEmoji) {
|
||||||
const pattern = emoticonPatterns[name];
|
for (const name of Object.keys(emoticonPatterns)) {
|
||||||
|
const pattern = emoticonPatterns[name];
|
||||||
|
|
||||||
// this might look a bit funny, but since the name isn't contained in the actual match
|
// this might look a bit funny, but since the name isn't contained in the actual match
|
||||||
// like with the named emoticons, we need to add it in manually
|
// like with the named emoticons, we need to add it in manually
|
||||||
output = output.replace(pattern, (fullMatch, prefix, matchText) => replaceEmoticonWithToken(fullMatch, prefix, matchText, name));
|
output = output.replace(pattern, (fullMatch, prefix, matchText) => replaceEmoticonWithToken(fullMatch, prefix, matchText, name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -90,6 +90,11 @@ describe('formatText', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('emoticons should not be rendered as emojis when renderEmoticonsAsEmoji is false', () => {
|
||||||
|
const output = formatText(':)', {renderEmoticonsAsEmoji: false}, emptyEmojiMap);
|
||||||
|
expect(output).toBe('<p>:)</p>');
|
||||||
|
});
|
||||||
|
|
||||||
test('code blocks newlines are not converted into <br/> with inline markdown image in the post', () => {
|
test('code blocks newlines are not converted into <br/> with inline markdown image in the post', () => {
|
||||||
const output = formatText('```\nsome text\nsecond line\n```\n ', {}, emptyEmojiMap);
|
const output = formatText('```\nsome text\nsecond line\n```\n ', {}, emptyEmojiMap);
|
||||||
expect(output).not.toContain('<br/>');
|
expect(output).not.toContain('<br/>');
|
||||||
|
|||||||
@@ -230,6 +230,11 @@ export interface TextFormattingOptionsBase {
|
|||||||
* Defaults to `false`.
|
* Defaults to `false`.
|
||||||
*/
|
*/
|
||||||
unsafeLinks: boolean;
|
unsafeLinks: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not to render text emoticons (:D) as emojis
|
||||||
|
*/
|
||||||
|
renderEmoticonsAsEmoji: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TextFormattingOptions = Partial<TextFormattingOptionsBase>;
|
export type TextFormattingOptions = Partial<TextFormattingOptionsBase>;
|
||||||
@@ -258,6 +263,7 @@ const DEFAULT_OPTIONS: TextFormattingOptions = {
|
|||||||
editedAt: 0,
|
editedAt: 0,
|
||||||
postId: '',
|
postId: '',
|
||||||
unsafeLinks: false,
|
unsafeLinks: false,
|
||||||
|
renderEmoticonsAsEmoji: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -401,7 +407,7 @@ export function doFormatText(text: string, options: TextFormattingOptions, emoji
|
|||||||
output = autolinkHashtags(output, tokens, options.minimumHashtagLength);
|
output = autolinkHashtags(output, tokens, options.minimumHashtagLength);
|
||||||
|
|
||||||
if (!('emoticons' in options) || options.emoticons) {
|
if (!('emoticons' in options) || options.emoticons) {
|
||||||
output = Emoticons.handleEmoticons(output, tokens);
|
output = Emoticons.handleEmoticons(output, tokens, options.renderEmoticonsAsEmoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.searchPatterns) {
|
if (options.searchPatterns) {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user