File viewer v2 #1826
4 changed files with 44 additions and 15 deletions
|
@ -6,7 +6,7 @@ import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
import SimpleMDE from 'react-simplemde-editor';
|
import SimpleMDE from 'react-simplemde-editor';
|
||||||
import 'simplemde/dist/simplemde.min.css';
|
import 'simplemde/dist/simplemde.min.css';
|
||||||
import Toggle from 'react-toggle';
|
import Toggle from 'react-toggle';
|
||||||
import { openEditorMenu } from 'util/contextMenu';
|
import { openEditorMenu, stopContextMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -55,15 +55,10 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
</select>
|
</select>
|
||||||
);
|
);
|
||||||
} else if (type === 'markdown') {
|
} else if (type === 'markdown') {
|
||||||
const stopContextMenu = event => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
};
|
|
||||||
const handleEvents = {
|
const handleEvents = {
|
||||||
contextmenu(codeMirror, event) {
|
contextmenu: openEditorMenu,
|
||||||
openEditorMenu(event, codeMirror);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
input = (
|
input = (
|
||||||
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
|
<div className="form-field--SimpleMDE" onContextMenu={stopContextMenu}>
|
||||||
<SimpleMDE
|
<SimpleMDE
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import CodeMirror from 'codemirror/lib/codemirror';
|
import CodeMirror from 'codemirror/lib/codemirror';
|
||||||
|
import { openSnippetMenu, stopContextMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
// Addons
|
// Addons
|
||||||
import 'codemirror/addon/selection/mark-selection';
|
import 'codemirror/addon/selection/mark-selection';
|
||||||
|
@ -26,21 +27,29 @@ class CodeViewer extends React.PureComponent<Props> {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { theme, contentType } = this.props;
|
const { theme, contentType } = this.props;
|
||||||
|
// Init CodeMirror
|
||||||
this.codeMirror = CodeMirror.fromTextArea(this.textarea.current, {
|
this.codeMirror = CodeMirror.fromTextArea(this.textarea.current, {
|
||||||
|
// Auto detect syntax with file contentType
|
||||||
mode: contentType,
|
mode: contentType,
|
||||||
|
// Adaptive theme
|
||||||
theme: theme === 'dark' ? 'dark' : 'default',
|
theme: theme === 'dark' ? 'dark' : 'default',
|
||||||
readOnly: 'nocursor',
|
// Hide the cursor
|
||||||
|
readOnly: true,
|
||||||
|
// Styled text selection
|
||||||
|
styleSelectedText: true,
|
||||||
|
// Additional config opts
|
||||||
dragDrop: false,
|
dragDrop: false,
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
lineWrapping: true,
|
lineWrapping: true,
|
||||||
styleSelectedText: true,
|
|
||||||
});
|
});
|
||||||
|
// Add events
|
||||||
|
this.codeMirror.on('contextmenu', openSnippetMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value } = this.props;
|
const { value } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="code-viewer">
|
<div className="code-viewer" onContextMenu={stopContextMenu}>
|
||||||
<textarea ref={this.textarea} disabled value={value} />
|
<textarea ref={this.textarea} disabled value={value} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,9 +23,9 @@ function injectDevelopmentTemplate(event, templates) {
|
||||||
|
|
||||||
export function openContextMenu(event, templates = [], canEdit = false, selection = '') {
|
export function openContextMenu(event, templates = [], canEdit = false, selection = '') {
|
||||||
const { type, value } = event.target;
|
const { type, value } = event.target;
|
||||||
const isSomethingSelected = selection.length > 0 || window.getSelection().toString().length > 0;
|
|
||||||
const isInput = event.target.matches('input') && (type === 'text' || type === 'number');
|
const isInput = event.target.matches('input') && (type === 'text' || type === 'number');
|
||||||
const isTextField = canEdit || isInput || event.target.matches('textarea');
|
const isTextField = canEdit || isInput || event.target.matches('textarea');
|
||||||
|
const isSomethingSelected = selection.length > 0 || window.getSelection().toString().length > 0;
|
||||||
|
|
||||||
templates.push({
|
templates.push({
|
||||||
label: 'Copy',
|
label: 'Copy',
|
||||||
|
@ -63,7 +63,7 @@ export function openContextMenu(event, templates = [], canEdit = false, selectio
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is used for the markdown description on the publish page
|
// This function is used for the markdown description on the publish page
|
||||||
export function openEditorMenu(event, codeMirror) {
|
export function openEditorMenu(codeMirror, event) {
|
||||||
const value = codeMirror.doc.getValue();
|
const value = codeMirror.doc.getValue();
|
||||||
const selection = codeMirror.doc.getSelection();
|
const selection = codeMirror.doc.getSelection();
|
||||||
const templates = [
|
const templates = [
|
||||||
|
@ -86,6 +86,25 @@ export function openEditorMenu(event, codeMirror) {
|
||||||
openContextMenu(event, templates, true, selection);
|
openContextMenu(event, templates, true, selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is used for the CodeViewer component
|
||||||
|
export function openSnippetMenu(codeMirror, event) {
|
||||||
|
const value = codeMirror.doc.getValue();
|
||||||
|
const selection = codeMirror.doc.getSelection();
|
||||||
|
const templates = [
|
||||||
|
{
|
||||||
|
label: 'Select All',
|
||||||
|
accelerator: 'CmdOrCtrl+A',
|
||||||
|
role: 'selectall',
|
||||||
|
click: () => {
|
||||||
|
codeMirror.execCommand('selectAll');
|
||||||
|
},
|
||||||
|
// Enabled if there is text to select
|
||||||
|
enabled: value.length > 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
openContextMenu(event, templates, false, selection);
|
||||||
|
}
|
||||||
|
|
||||||
export function openCopyLinkMenu(text, event) {
|
export function openCopyLinkMenu(text, event) {
|
||||||
const templates = [
|
const templates = [
|
||||||
{
|
{
|
||||||
|
@ -97,3 +116,9 @@ export function openCopyLinkMenu(text, event) {
|
||||||
];
|
];
|
||||||
openContextMenu(event, templates);
|
openContextMenu(event, templates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Block context menu
|
||||||
|
export function stopContextMenu(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import mime from 'mime';
|
||||||
const formats = [
|
const formats = [
|
||||||
[/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'],
|
[/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'],
|
||||||
[/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'],
|
[/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'],
|
||||||
[/\.(json|csv|txt|log|md|markdown|docx|pdf|rtf|xml|yml|yaml)$/i, 'document'],
|
[/\.(json|csv|txt|log|md|markdown|docx|pdf|xml|yml|yaml)$/i, 'document'],
|
||||||
[/\.(pdf|odf|doc|docx|epub|org)$/i, 'e-book'],
|
[/\.(pdf|odf|doc|docx|epub|org|rtf)$/i, 'e-book'],
|
||||||
[/\.(stl|obj|fbx|gcode)$/i, '3D-file'],
|
[/\.(stl|obj|fbx|gcode)$/i, '3D-file'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue