mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Use ACE for Markdown syntax highlighting in editor
This commit is contained in:
parent
0806530fd9
commit
d4a0f7791a
@ -31,21 +31,21 @@ class MainScreenComponent extends React.Component {
|
||||
const rowHeight = style.height - theme.headerHeight;
|
||||
|
||||
const sideBarStyle = {
|
||||
width: layoutUtils.size(style.width * .2, 100, 300),
|
||||
width: Math.floor(layoutUtils.size(style.width * .2, 100, 300)),
|
||||
height: rowHeight,
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'top',
|
||||
};
|
||||
|
||||
const noteListStyle = {
|
||||
width: layoutUtils.size(style.width * .2, 100, 300),
|
||||
width: Math.floor(layoutUtils.size(style.width * .2, 100, 300)),
|
||||
height: rowHeight,
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'top',
|
||||
};
|
||||
|
||||
const noteTextStyle = {
|
||||
width: layoutUtils.size(style.width - sideBarStyle.width - noteListStyle.width, 0),
|
||||
width: Math.floor(layoutUtils.size(style.width - sideBarStyle.width - noteListStyle.width, 0)),
|
||||
height: rowHeight,
|
||||
display: 'inline-block',
|
||||
verticalAlign: 'top',
|
||||
|
@ -7,6 +7,9 @@ const MdToHtml = require('lib/MdToHtml');
|
||||
const shared = require('lib/components/shared/note-screen-shared.js');
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
const { themeStyle } = require('../theme.js');
|
||||
const AceEditor = require('react-ace').default;
|
||||
require('brace/mode/markdown');
|
||||
require('brace/theme/chrome');
|
||||
|
||||
class NoteTextComponent extends React.Component {
|
||||
|
||||
@ -23,6 +26,7 @@ class NoteTextComponent extends React.Component {
|
||||
isLoading: true,
|
||||
webviewReady: false,
|
||||
scrollHeight: null,
|
||||
editorScrollTop: 0,
|
||||
};
|
||||
|
||||
this.lastLoadedNoteId_ = null;
|
||||
@ -30,6 +34,20 @@ class NoteTextComponent extends React.Component {
|
||||
this.webviewListeners_ = null;
|
||||
this.ignoreNextEditorScroll_ = false;
|
||||
this.scheduleSaveTimeout_ = null;
|
||||
this.restoreScrollTop_ = null;
|
||||
|
||||
// Complicated but reliable method to get editor content height
|
||||
// https://github.com/ajaxorg/ace/issues/2046
|
||||
this.editorMaxScrollTop_ = 0;
|
||||
this.onAfterEditorRender_ = () => {
|
||||
const r = this.editor_.editor.renderer;
|
||||
this.editorMaxScrollTop_ = Math.max(0, r.layerConfig.maxHeight - r.$size.scrollerHeight);
|
||||
|
||||
if (this.restoreScrollTop_) {
|
||||
this.editorSetScrollTop(this.restoreScrollTop_);
|
||||
this.restoreScrollTop_ = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mdToHtml() {
|
||||
@ -120,6 +138,12 @@ class NoteTextComponent extends React.Component {
|
||||
reg.logger().info('Got ipc-message: ' + msg, args);
|
||||
|
||||
if (msg.indexOf('checkboxclick:') === 0) {
|
||||
// Ugly hack because setting the body here will make the scrollbar
|
||||
// go to some random position. So we save the scrollTop here and it
|
||||
// will be restored after the editor ref has been reset, and the
|
||||
// "afterRender" event has been called.
|
||||
this.restoreScrollTop_ = this.editorScrollTop();
|
||||
|
||||
const newBody = this.mdToHtml_.handleCheckboxClick(msg, this.state.note.body);
|
||||
this.saveOneProperty('body', newBody);
|
||||
} else if (msg.toLowerCase().indexOf('http') === 0) {
|
||||
@ -143,11 +167,19 @@ class NoteTextComponent extends React.Component {
|
||||
}
|
||||
|
||||
editorMaxScroll() {
|
||||
return Math.max(0, this.editor_.scrollHeight - this.editor_.clientHeight);
|
||||
return this.editorMaxScrollTop_;
|
||||
}
|
||||
|
||||
editorScrollTop() {
|
||||
return this.editor_.editor.getSession().getScrollTop();
|
||||
}
|
||||
|
||||
editorSetScrollTop(v) {
|
||||
this.editor_.editor.getSession().setScrollTop(v);
|
||||
}
|
||||
|
||||
setEditorPercentScroll(p) {
|
||||
this.editor_.scrollTop = p * this.editorMaxScroll();
|
||||
this.editorSetScrollTop(p * this.editorMaxScroll());
|
||||
}
|
||||
|
||||
setViewerPercentScroll(p) {
|
||||
@ -159,8 +191,9 @@ class NoteTextComponent extends React.Component {
|
||||
this.ignoreNextEditorScroll_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const m = this.editorMaxScroll();
|
||||
this.setViewerPercentScroll(m ? this.editor_.scrollTop / m : 0);
|
||||
this.setViewerPercentScroll(m ? this.editorScrollTop() / m : 0);
|
||||
}
|
||||
|
||||
webview_domReady() {
|
||||
@ -188,7 +221,17 @@ class NoteTextComponent extends React.Component {
|
||||
|
||||
editor_ref(element) {
|
||||
if (this.editor_ === element) return;
|
||||
|
||||
if (this.editor_) {
|
||||
this.editorMaxScrollTop_ = 0;
|
||||
this.editor_.editor.renderer.off('afterRender', this.onAfterEditorRender_);
|
||||
}
|
||||
|
||||
this.editor_ = element;
|
||||
|
||||
if (this.editor_) {
|
||||
this.editor_.editor.renderer.on('afterRender', this.onAfterEditorRender_);
|
||||
}
|
||||
}
|
||||
|
||||
initWebview(wv) {
|
||||
@ -220,6 +263,11 @@ class NoteTextComponent extends React.Component {
|
||||
this.webview_ = null;
|
||||
}
|
||||
|
||||
aceEditor_change(body) {
|
||||
shared.noteComponent_change(this, 'body', body);
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
render() {
|
||||
const style = this.props.style;
|
||||
const note = this.state.note;
|
||||
@ -239,7 +287,7 @@ class NoteTextComponent extends React.Component {
|
||||
const editorStyle = {
|
||||
width: style.width - viewerStyle.width,
|
||||
height: style.height - paddingTop,
|
||||
overflowY: 'scroll',
|
||||
overflowY: 'hidden',
|
||||
float: 'left',
|
||||
verticalAlign: 'top',
|
||||
paddingTop: paddingTop + 'px',
|
||||
@ -259,7 +307,32 @@ class NoteTextComponent extends React.Component {
|
||||
}
|
||||
|
||||
const viewer = <webview style={viewerStyle} nodeintegration="1" src="note-content.html" ref={(elem) => { this.webview_ref(elem); } } />
|
||||
const editor = <textarea style={editorStyle} value={body} onScroll={() => { this.editor_scroll(); }} onChange={(event) => { this.editor_change(event) }} ref={(elem) => { this.editor_ref(elem); } }></textarea>
|
||||
|
||||
const editorRootStyle = Object.assign({}, editorStyle);
|
||||
delete editorRootStyle.width;
|
||||
delete editorRootStyle.height;
|
||||
delete editorRootStyle.fontSize;
|
||||
|
||||
const editor = <AceEditor
|
||||
value={body}
|
||||
mode="markdown"
|
||||
theme="chrome"
|
||||
style={editorRootStyle}
|
||||
width={editorStyle.width + 'px'}
|
||||
height={editorStyle.height + 'px'}
|
||||
fontSize={editorStyle.fontSize}
|
||||
showGutter={false}
|
||||
name="note-editor"
|
||||
wrapEnabled={true}
|
||||
onScroll={(event) => { this.editor_scroll(); }}
|
||||
ref={(elem) => { this.editor_ref(elem); } }
|
||||
onChange={(body) => { this.aceEditor_change(body) }}
|
||||
|
||||
// Disable warning: "Automatically scrolling cursor into view after
|
||||
// selection change this will be disabled in the next version set
|
||||
// editor.$blockScrolling = Infinity to disable this message"
|
||||
editorProps={{$blockScrolling: true}}
|
||||
/>
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
|
39
ElectronClient/app/package-lock.json
generated
39
ElectronClient/app/package-lock.json
generated
@ -780,6 +780,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"brace": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/brace/-/brace-0.10.0.tgz",
|
||||
"integrity": "sha1-7e9OubCSi6HuX3F//BV3SabdXXY=",
|
||||
"requires": {
|
||||
"w3c-blob": "0.0.1"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
|
||||
@ -2062,6 +2070,11 @@
|
||||
"sntp": "2.1.0"
|
||||
}
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "9.12.0",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
|
||||
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
|
||||
},
|
||||
"hoek": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
|
||||
@ -2576,6 +2589,16 @@
|
||||
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||
},
|
||||
"lodash.toarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
|
||||
@ -3471,6 +3494,17 @@
|
||||
"prop-types": "15.6.0"
|
||||
}
|
||||
},
|
||||
"react-ace": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-5.5.0.tgz",
|
||||
"integrity": "sha1-N9nCAR23IYTr8nq2/9inmBqAQUI=",
|
||||
"requires": {
|
||||
"brace": "0.10.0",
|
||||
"lodash.get": "4.4.2",
|
||||
"lodash.isequal": "4.5.0",
|
||||
"prop-types": "15.6.0"
|
||||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.0.0.tgz",
|
||||
@ -5055,6 +5089,11 @@
|
||||
"extsprintf": "1.3.0"
|
||||
}
|
||||
},
|
||||
"w3c-blob": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/w3c-blob/-/w3c-blob-0.0.1.tgz",
|
||||
"integrity": "sha1-sM01KhpQ9RVWNCD/1YYflQ8dhbg="
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz",
|
||||
|
@ -28,6 +28,7 @@
|
||||
"app-module-path": "^2.2.0",
|
||||
"electron-context-menu": "^0.9.1",
|
||||
"fs-extra": "^4.0.2",
|
||||
"highlight.js": "^9.12.0",
|
||||
"html-entities": "^1.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
"markdown-it": "^8.4.0",
|
||||
@ -38,6 +39,7 @@
|
||||
"promise": "^8.0.1",
|
||||
"query-string": "^5.0.1",
|
||||
"react": "^16.0.0",
|
||||
"react-ace": "^5.5.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"redux": "^3.7.2",
|
||||
|
Loading…
Reference in New Issue
Block a user