You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
Desktop: Fixes #6074: Scroll jumps when typing if heavy scripts or many large elements are used (#6383)
This commit is contained in:
committed by
GitHub
parent
e02422070e
commit
f6e21e0180
@ -242,9 +242,9 @@ describe('MdToHtml', function() {
|
||||
{
|
||||
const input = '# Head\nFruits\n- Apple\n';
|
||||
const result = await mdToHtml.render(input, null, { bodyOnly: true, mapsToLine: true });
|
||||
expect(result.html.trim()).toBe('<h1 id="head" class="maps-to-line" source-line="0">Head</h1>\n' +
|
||||
'<p class="maps-to-line" source-line="1">Fruits</p>\n' +
|
||||
'<ul>\n<li class="maps-to-line" source-line="2">Apple</li>\n</ul>'
|
||||
expect(result.html.trim()).toBe('<h1 id="head" class="maps-to-line" source-line="0" source-line-end="1">Head</h1>\n' +
|
||||
'<p class="maps-to-line" source-line="1" source-line-end="2">Fruits</p>\n' +
|
||||
'<ul>\n<li class="maps-to-line" source-line="2" source-line-end="3">Apple</li>\n</ul>'
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
@ -649,6 +649,11 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
// undefined. Maybe due to the error boundary that unmount components.
|
||||
// Since we can't do much about it we just print an error.
|
||||
if (webviewRef.current && webviewRef.current.wrappedInstance) {
|
||||
// To keep consistency among CodeMirror's editing and scroll percents
|
||||
// of Editor and Viewer.
|
||||
const percent = getLineScrollPercent();
|
||||
setEditorPercentScroll(percent);
|
||||
options.percent = percent;
|
||||
webviewRef.current.wrappedInstance.send('setHtml', renderedBody.html, options);
|
||||
} else {
|
||||
console.error('Trying to set HTML on an undefined webview ref');
|
||||
|
@ -100,6 +100,7 @@ export interface EditorProps {
|
||||
function Editor(props: EditorProps, ref: any) {
|
||||
const [editor, setEditor] = useState(null);
|
||||
const editorParent = useRef(null);
|
||||
const lastEditTime = useRef(NaN);
|
||||
|
||||
// Codemirror plugins add new commands to codemirror (or change it's behavior)
|
||||
// This command adds the smartListIndent function which will be bound to tab
|
||||
@ -120,6 +121,7 @@ function Editor(props: EditorProps, ref: any) {
|
||||
const editor_change = useCallback((cm: any, change: any) => {
|
||||
if (props.onChange && change.origin !== 'setValue') {
|
||||
props.onChange(cm.getValue());
|
||||
lastEditTime.current = Date.now();
|
||||
}
|
||||
}, [props.onChange]);
|
||||
|
||||
@ -154,7 +156,8 @@ function Editor(props: EditorProps, ref: any) {
|
||||
}, [props.onResize]);
|
||||
|
||||
const editor_update = useCallback((cm: any) => {
|
||||
props.onUpdate(cm);
|
||||
const edited = Date.now() - lastEditTime.current <= 100;
|
||||
props.onUpdate(cm, edited);
|
||||
}, [props.onUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -17,7 +17,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
|
||||
const now = Date.now();
|
||||
if (now >= ignoreNextEditorScrollTime_.current) ignoreNextEditorScrollEventCount_.current = 0;
|
||||
if (ignoreNextEditorScrollEventCount_.current < 10) { // for safety
|
||||
ignoreNextEditorScrollTime_.current = now + 200;
|
||||
ignoreNextEditorScrollTime_.current = now + 1000;
|
||||
ignoreNextEditorScrollEventCount_.current += 1;
|
||||
}
|
||||
};
|
||||
@ -157,8 +157,9 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
|
||||
// When heights of lines are updated in CodeMirror, 'update' events are raised.
|
||||
// If such an update event is raised, scroll position should be restored.
|
||||
// See https://github.com/laurent22/joplin/issues/5981
|
||||
const editor_update = useCallback((cm) => {
|
||||
const editor_update = useCallback((cm: any, edited: boolean) => {
|
||||
if (isCodeMirrorReady(cm)) {
|
||||
if (edited) return;
|
||||
const linesHeight = cm.heightAtLine(cm.lineCount()) - cm.heightAtLine(0);
|
||||
if (lastLinesHeight_.current !== linesHeight) {
|
||||
// To avoid cancelling intentional scroll position changes,
|
||||
|
@ -116,7 +116,7 @@
|
||||
const now = Date.now();
|
||||
if (now >= ignoreNextScrollTime_) ignoreNextScrollEventCount_ = 0;
|
||||
if (ignoreNextScrollEventCount_ < 10) { // for safety
|
||||
ignoreNextScrollTime_ = now + 200;
|
||||
ignoreNextScrollTime_ = now + 1000;
|
||||
ignoreNextScrollEventCount_ += 1;
|
||||
}
|
||||
};
|
||||
@ -293,7 +293,7 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!heightChanged) return;
|
||||
if (!heightChanged && cause !== 'dom-changed') return;
|
||||
const restoreAndRefresh = () => {
|
||||
scrollmap.refresh();
|
||||
restorePercentScroll();
|
||||
@ -337,7 +337,11 @@
|
||||
contentElement.innerHTML = html;
|
||||
|
||||
scrollmap.create(event.options.markupLineCount);
|
||||
if (typeof event.options.percent !== 'number') {
|
||||
restorePercentScroll(); // First, a quick treatment is applied.
|
||||
} else {
|
||||
setPercentScroll(event.options.percent);
|
||||
}
|
||||
|
||||
addPluginAssets(event.options.pluginAssets);
|
||||
|
||||
|
@ -45,7 +45,8 @@ scrollmap.get_ = () => {
|
||||
// Each map entry is total-ordered.
|
||||
let last = 0;
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
const top = elems[i].getBoundingClientRect().top - offset;
|
||||
const rect = elems[i].getBoundingClientRect();
|
||||
const top = rect.top - offset;
|
||||
const line = Number(elems[i].getAttribute('source-line'));
|
||||
const percent = Math.max(0, Math.min(1, top / height));
|
||||
if (map.line[last] < line && map.percent[last] < percent) {
|
||||
@ -53,12 +54,20 @@ scrollmap.get_ = () => {
|
||||
map.percent.push(percent);
|
||||
last += 1;
|
||||
}
|
||||
const bottom = rect.bottom - offset;
|
||||
const lineEnd = Number(elems[i].getAttribute('source-line-end'));
|
||||
const percentEnd = Math.max(0, Math.min(1, bottom / height));
|
||||
if (map.line[last] < lineEnd && map.percent[last] < percentEnd) {
|
||||
map.line.push(lineEnd);
|
||||
map.percent.push(percentEnd);
|
||||
last += 1;
|
||||
}
|
||||
}
|
||||
const lineCount = scrollmap.lineCount_;
|
||||
if (lineCount) {
|
||||
map.lineCount = lineCount;
|
||||
} else {
|
||||
if (map.lineCount <= map.line[last]) map.lineCount = map.line[last] + 1;
|
||||
if (map.lineCount < map.line[last]) map.lineCount = map.line[last];
|
||||
}
|
||||
if (map.percent[last] < 1) {
|
||||
map.line.push(lineCount || 1e10);
|
||||
|
@ -22,8 +22,10 @@ export default {
|
||||
markdownIt.renderer.rules[key] = (tokens: any[], idx: number, options: any, env: any, self: any) => {
|
||||
if (!!tokens[idx].map && tokens[idx].level <= allowedLevel) {
|
||||
const line = tokens[idx].map[0];
|
||||
const lineEnd = tokens[idx].map[1];
|
||||
tokens[idx].attrJoin('class', 'maps-to-line');
|
||||
tokens[idx].attrSet('source-line', `${line}`);
|
||||
tokens[idx].attrSet('source-line-end', `${lineEnd}`);
|
||||
}
|
||||
if (precedentRule) {
|
||||
return precedentRule(tokens, idx, options, env, self);
|
||||
|
Reference in New Issue
Block a user