Browse Source

clean code

Yuki Takei 8 years ago
parent
commit
b369734305

+ 36 - 1
resource/js/components/PageEditor.js

@@ -48,6 +48,8 @@ export default class PageEditor extends React.Component {
 
     // for scrolling
     this.lastScrolledDateWithCursor = null;
+    this.isOriginOfScrollSyncEditor = false;
+    this.isOriginOfScrollSyncEditor = false;
 
     // create throttled function
     this.scrollPreviewByEditorLineWithThrottle = throttle(20, this.scrollPreviewByEditorLine);
@@ -74,7 +76,7 @@ export default class PageEditor extends React.Component {
    */
   setCaretLine(line) {
     this.refs.editor.setCaretLine(line);
-    this.scrollPreviewByEditorLine(line);
+    scrollSyncHelper.scrollPreview(this.previewElement, line);
   }
 
   /**
@@ -203,7 +205,13 @@ export default class PageEditor extends React.Component {
     this.scrollPreviewByEditorLineWithThrottle(data.line);
   }
 
+  /**
+   * the scroll event handler from codemirror
+   * @param {number} line
+   * @see https://codemirror.net/doc/manual.html#events
+   */
   onEditorScrollCursorIntoView(line) {
+    // record date
     this.lastScrolledDateWithCursor = new Date();
     this.scrollPreviewByCursorMovingWithThrottle(line);
   }
@@ -216,6 +224,15 @@ export default class PageEditor extends React.Component {
     if (this.previewElement == null) {
       return;
     }
+
+    // prevent circular invocation
+    if (this.isOriginOfScrollSyncPreview) {
+      this.isOriginOfScrollSyncPreview = false; // turn off the flag
+      return;
+    }
+
+    // turn on the flag
+    this.isOriginOfScrollSyncEditor = true;
     scrollSyncHelper.scrollPreview(this.previewElement, line);
   };
 
@@ -227,6 +244,15 @@ export default class PageEditor extends React.Component {
     if (this.previewElement == null) {
       return;
     }
+
+    // prevent circular invocation
+    if (this.isOriginOfScrollSyncPreview) {
+      this.isOriginOfScrollSyncPreview = false; // turn off the flag
+      return;
+    }
+
+    // turn on the flag
+    this.isOriginOfScrollSyncEditor = true;
     scrollSyncHelper.scrollPreviewToRevealOverflowing(this.previewElement, line);
   };
 
@@ -242,6 +268,15 @@ export default class PageEditor extends React.Component {
     if (this.previewElement == null) {
       return;
     }
+
+    // prevent circular invocation
+    if (this.isOriginOfScrollSyncEditor) {
+      this.isOriginOfScrollSyncEditor = false;  // turn off the flag
+      return;
+    }
+
+    // turn on the flag
+    this.isOriginOfScrollSyncPreview = true;
     scrollSyncHelper.scrollEditor(this.refs.editor, this.previewElement, offset);
   }
 

+ 8 - 0
resource/js/components/PageEditor/Editor.js

@@ -97,6 +97,10 @@ export default class Editor extends React.Component {
    * @param {string} number
    */
   setCaretLine(line) {
+    if (isNaN(line)) {
+      return;
+    }
+
     const editor = this.getCodeMirror();
     const linePosition = Math.max(0, line);
 
@@ -109,6 +113,10 @@ export default class Editor extends React.Component {
    * @param {number} line
    */
   setScrollTopByLine(line) {
+    if (isNaN(line)) {
+      return;
+    }
+
     const editor = this.getCodeMirror();
     // get top position of the line
     var top = editor.charCoords({line, ch: 0}, 'local').top;

+ 14 - 37
resource/js/components/PageEditor/ScrollSyncHelper.js

@@ -9,8 +9,6 @@ class ScrollSyncHelper {
 	 */
 
   constructor() {
-    this.isSyncScrollToPreviewFired = false;
-    this.isSyncScrollToEditorFired = false;
   }
 
   getCodeLineElements(parentElement) {
@@ -34,13 +32,13 @@ class ScrollSyncHelper {
 	 * If an exact match, returns a single element. If the line is between elements,
 	 * returns the element prior to and the element after the given line.
 	 *
-   * @param {Element} parentElement
+   * @param {Element} element
 	 * @param {number} targetLine
 	 *
 	 * @returns {{ previous: CodeLineElement, next?: CodeLineElement }}
 	 */
-	getElementsForSourceLine(parentElement, targetLine) {
-		const lines = this.getCodeLineElements(parentElement);
+	getElementsForSourceLine(element, targetLine) {
+		const lines = this.getCodeLineElements(element);
 		let previous = lines[0] || null;
 		for (const entry of lines) {
 			if (entry.line === targetLine) {
@@ -82,8 +80,11 @@ class ScrollSyncHelper {
 		if (hi >= 1 && hiElement.element.getBoundingClientRect().top > position) {
 			const loElement = lines[lo];
 			const bounds = loElement.element.getBoundingClientRect();
-			const previous = { element: loElement.element, line: loElement.line + (position - bounds.top) / (bounds.height) };
-			const next = { element: hiElement.element, line: hiElement.line, fractional: 0 };
+      let previous = { element: loElement.element, line: loElement.line };
+      if (bounds.height > 0) {
+        previous.line += (position - bounds.top) / (bounds.height);
+      }
+      const next = { element: hiElement.element, line: hiElement.line, fractional: 0 };
 			return { previous, next };
 		}
 
@@ -105,12 +106,17 @@ class ScrollSyncHelper {
 		return null;
   }
 
+  /**
+   * return the sum of the offset position of parent element and paddingTop
+   * @param {Element} parentElement
+   */
   getParentElementOffset(parentElement) {
+    const offsetY = parentElement.getBoundingClientRect().top;
     // get paddingTop
     const style = window.getComputedStyle(parentElement, null);
     const paddingTop = +(style.paddingTop.replace('px', ''));
 
-		return paddingTop + parentElement.getBoundingClientRect().top;
+		return offsetY + paddingTop;
   }
 
   /**
@@ -120,14 +126,7 @@ class ScrollSyncHelper {
 	 * @param {number} line
 	 */
 	scrollPreview(previewElement, line) {
-    // turn off the flag
-    if (this.isSyncScrollToEditorFired) {
-      this.isSyncScrollToEditorFired = false;
-      return;
-    }
-
 		const { previous, next } = this.getElementsForSourceLine(previewElement, line);
-		// marker.update(previous && previous.element);
 		if (previous) {
 			let scrollTo = 0;
 			if (next) {
@@ -141,9 +140,6 @@ class ScrollSyncHelper {
 
       scrollTo -= this.getParentElementOffset(previewElement);
 
-      // turn on the flag
-      this.isSyncScrollToPreviewFired = true;
-
       previewElement.scroll(0, previewElement.scrollTop + scrollTo);
 		}
   }
@@ -155,14 +151,7 @@ class ScrollSyncHelper {
 	 * @param {number} line
 	 */
   scrollPreviewToRevealOverflowing(previewElement, line) {
-    // turn off the flag
-    if (this.isSyncScrollToEditorFired) {
-      this.isSyncScrollToEditorFired = false;
-      return;
-    }
-
 		const { previous, next } = this.getElementsForSourceLine(previewElement, line);
-		// marker.update(previous && previous.element);
 		if (previous) {
       const parentElementOffset = this.getParentElementOffset(previewElement);
       const prevElmTop = previous.element.getBoundingClientRect().top - parentElementOffset;
@@ -182,9 +171,6 @@ class ScrollSyncHelper {
         return;
       }
 
-      // turn on the flag
-      this.isSyncScrollToPreviewFired = true;
-
       previewElement.scroll(0, scrollTo);
 		}
   }
@@ -197,17 +183,8 @@ class ScrollSyncHelper {
    * @param {number} offset
    */
   scrollEditor(editor, previewElement, offset) {
-    // turn off the flag
-    if (this.isSyncScrollToPreviewFired) {
-      this.isSyncScrollToPreviewFired = false;
-      return;
-    }
-
     let line = this.getEditorLineNumberForPageOffset(previewElement, offset);
     line = Math.floor(line);
-
-    // turn on flag
-    this.isSyncScrollToEditorFired = true;
     editor.setScrollTopByLine(line);
   }
 }