Skip to content

Commit 020a422

Browse files
committed
Adding syntax highlighting selection to source code dialogs.
1 parent 2910850 commit 020a422

File tree

4 files changed

+69
-10
lines changed

4 files changed

+69
-10
lines changed

src/components/helpers/SourceCodeViewer/SourceCodeHighlightingSelector.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState, useRef } from 'react';
1+
import React, { useState, useRef, useEffect } from 'react';
22
import PropTypes from 'prop-types';
33
import { FormattedMessage } from 'react-intl';
44
import { Overlay, Popover, FormSelect, ButtonGroup } from 'react-bootstrap';
@@ -8,6 +8,8 @@ import Icon, { CloseIcon, RefreshIcon, SaveIcon } from '../../icons';
88

99
import { getPrismModeFromExtension, PRISM_SUPPORTED_LANGUAGES } from '../../helpers/syntaxHighlighting.js';
1010

11+
export const localStorageHighlightOverridesKey = 'SourceCodeViewer.highlightOverrides';
12+
1113
const SourceCodeHighlightingSelector = ({
1214
id,
1315
fullButton = false,
@@ -21,15 +23,23 @@ const SourceCodeHighlightingSelector = ({
2123
const [visible, setVisible] = useState(false);
2224
const [selectedMode, setSelectedMode] = useState(initialMode !== null ? initialMode : defaultMode);
2325

26+
useEffect(() => {
27+
setSelectedMode(initialMode !== null ? initialMode : defaultMode);
28+
}, [initialMode, extension]);
29+
2430
const clickHandler = ev => {
2531
ev.stopPropagation();
2632
setVisible(!visible);
2733
};
2834

35+
const changeHandler = ev => {
36+
setSelectedMode(ev.target.value);
37+
};
38+
2939
return (
3040
<>
3141
{fullButton ? (
32-
<Button variant="secondary" size="xs" {...props} onClick={clickHandler} ref={target}>
42+
<Button {...props} onClick={clickHandler} ref={target}>
3343
<Icon icon="highlighter" gapRight={2} />
3444
{(initialMode !== null ? initialMode : defaultMode) || (
3545
<FormattedMessage id="app.solutionSourceCodes.noHighlighting" defaultMessage="no highlighting" />
@@ -41,7 +51,7 @@ const SourceCodeHighlightingSelector = ({
4151

4252
<Overlay target={target.current} show={visible} placement="bottom">
4353
{props => (
44-
<Popover id={id} onClick={e => e.stopPropagation()} className="highlighting-selector" {...props}>
54+
<Popover id={id} onClick={ev => ev.stopPropagation()} className="highlighting-selector" {...props}>
4555
<Popover.Header>
4656
{extension ? (
4757
<>
@@ -59,7 +69,7 @@ const SourceCodeHighlightingSelector = ({
5969
)}
6070
</Popover.Header>
6171
<Popover.Body className="text-center">
62-
<FormSelect onChange={e => setSelectedMode(e.target.value)} value={selectedMode}>
72+
<FormSelect onChange={changeHandler} value={selectedMode}>
6373
<option value="" className={selectedMode === '' ? 'fw-bold text-primary' : 'fw-italic text-muted'}>
6474
[<FormattedMessage id="app.solutionSourceCodes.noHighlighting" defaultMessage="no highlighting" />]
6575
{defaultMode === '' && (
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export { default } from './SourceCodeViewer.js';
22
export { default as SourceCodeComment } from './SourceCodeComment.js';
3-
export { default as SourceCodeHighlightingSelector } from './SourceCodeHighlightingSelector.js';
3+
export {
4+
default as SourceCodeHighlightingSelector,
5+
localStorageHighlightOverridesKey,
6+
} from './SourceCodeHighlightingSelector.js';

src/containers/SourceCodeViewerContainer/SourceCodeViewerContainer.js

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ import { download } from '../../redux/modules/files.js';
1414
import { fetchContentIfNeeded } from '../../redux/modules/filesContent.js';
1515
import { getFilesContent } from '../../redux/selectors/files.js';
1616
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
17-
import SourceCodeViewer from '../../components/helpers/SourceCodeViewer';
17+
import SourceCodeViewer, {
18+
SourceCodeHighlightingSelector,
19+
localStorageHighlightOverridesKey,
20+
} from '../../components/helpers/SourceCodeViewer';
21+
1822
import DownloadSolutionArchiveContainer from '../DownloadSolutionArchiveContainer';
1923
import UsersNameContainer from '../UsersNameContainer';
24+
import { getFileExtensionLC } from '../../helpers/common.js';
25+
import { storageGetItem, storageSetItem } from '../../helpers/localStorage.js';
2026

2127
import * as styles from './sourceCode.less';
2228

@@ -41,12 +47,15 @@ const preprocessFiles = lruMemoize(files =>
4147
);
4248

4349
class SourceCodeViewerContainer extends Component {
44-
state = { clipboardCopied: false };
50+
state = { clipboardCopied: false, highlightOverrides: {} };
4551

4652
componentDidMount() {
4753
const { fileId, loadAsync } = this.props;
4854
if (fileId !== null) {
4955
loadAsync();
56+
this.setState({
57+
highlightOverrides: storageGetItem(localStorageHighlightOverridesKey, {}),
58+
});
5059
}
5160
}
5261

@@ -56,9 +65,21 @@ class SourceCodeViewerContainer extends Component {
5665
(this.props.fileId !== prevProps.fileId || this.props.zipEntry !== prevProps.zipEntry)
5766
) {
5867
this.props.loadAsync();
68+
this.setState({
69+
highlightOverrides: storageGetItem(localStorageHighlightOverridesKey, {}),
70+
});
5971
}
6072
}
6173

74+
setHighlightOverride = (extension, mode) => {
75+
const { [extension]: _, ...newOverrides } = this.state.highlightOverrides;
76+
if (mode || mode === '') {
77+
newOverrides[extension] = mode;
78+
}
79+
this.setState({ highlightOverrides: newOverrides });
80+
storageSetItem(localStorageHighlightOverridesKey, newOverrides);
81+
};
82+
6283
render() {
6384
const {
6485
show,
@@ -75,6 +96,8 @@ class SourceCodeViewerContainer extends Component {
7596
submittedBy = null,
7697
} = this.props;
7798

99+
const fileExtension = getFileExtensionLC(fileName);
100+
78101
return (
79102
<ResourceRenderer
80103
loading={
@@ -95,7 +118,13 @@ class SourceCodeViewerContainer extends Component {
95118
}
96119
resource={content}>
97120
{content => (
98-
<Modal show={show} onHide={onHide} onEscapeKeyDown={onHide} dialogClassName={styles.modal} size="xl">
121+
<Modal
122+
show={show}
123+
onHide={onHide}
124+
onEscapeKeyDown={onHide}
125+
dialogClassName={styles.modal}
126+
size="xl"
127+
enforceFocus={false}>
99128
<Modal.Header closeButton>
100129
<ResourceRenderer resource={files}>
101130
{files => (
@@ -116,6 +145,17 @@ class SourceCodeViewerContainer extends Component {
116145
))}
117146
</DropdownButton>
118147

148+
<SourceCodeHighlightingSelector
149+
id="highlighting"
150+
fullButton
151+
size="sm"
152+
className="me-2"
153+
variant="outline-secondary"
154+
extension={fileExtension}
155+
initialMode={this.state.highlightOverrides[fileExtension]}
156+
onChange={this.setHighlightOverride}
157+
/>
158+
119159
<Button size="sm" className="me-2" onClick={() => download(fileId, zipEntry)}>
120160
<DownloadIcon gapRight={2} />
121161
<FormattedMessage id="app.sourceCodeViewer.downloadButton" defaultMessage="Download file" />
@@ -180,7 +220,13 @@ class SourceCodeViewerContainer extends Component {
180220
{content.malformedCharacters ? (
181221
<pre className="border-top">{content.content}</pre>
182222
) : (
183-
<SourceCodeViewer id={fileId} content={content.content} name={fileName} solutionId={solutionId} />
223+
<SourceCodeViewer
224+
id={fileId}
225+
content={content.content}
226+
name={fileName}
227+
solutionId={solutionId}
228+
highlightOverrides={this.state.highlightOverrides}
229+
/>
184230
)}
185231
<div className="border-top pt-1 bg-light rounded-bottom"></div>
186232
</Modal.Body>

src/pages/SolutionSourceCodes/SolutionSourceCodes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import ReviewSummary from '../../components/Solutions/ReviewSummary';
2727
import RecentlyVisited from '../../components/Solutions/RecentlyVisited';
2828
import { registerSolutionVisit } from '../../components/Solutions/RecentlyVisited/functions.js';
2929
import Callout from '../../components/widgets/Callout';
30+
import { localStorageHighlightOverridesKey } from '../../components/helpers/SourceCodeViewer';
3031
import SolutionActionsContainer from '../../containers/SolutionActionsContainer';
3132
import SolutionReviewRequestButtonContainer from '../../containers/SolutionReviewRequestButtonContainer';
3233
import CommentThreadContainer from '../../containers/CommentThreadContainer';
@@ -69,7 +70,6 @@ const fileNameAndEntry = file => [file.parentId || file.id, file.entryName || nu
6970
const wrapInArray = lruMemoize(entry => [entry]);
7071

7172
const localStorageDiffMappingsKey = 'SolutionSourceCodes.diffMappings.';
72-
const localStorageHighlightOverridesKey = 'SolutionSourceCodes.highlightOverrides';
7373

7474
class SolutionSourceCodes extends Component {
7575
state = {

0 commit comments

Comments
 (0)