Преглед на файлове

Improve scroll sync to preview from editor

* impl scrollToRevealOverflowingSourceLine
Yuki Takei преди 8 години
родител
ревизия
2a48390918
променени са 2 файла, в които са добавени 45 реда и са изтрити 8 реда
  1. 11 4
      resource/js/components/PageEditor.js
  2. 34 4
      resource/js/components/PageEditor/ScrollSyncHelper.js

+ 11 - 4
resource/js/components/PageEditor.js

@@ -49,7 +49,8 @@ export default class PageEditor extends React.Component {
     this.lastScrolledDateWithCursor = null;
     this.lastScrolledDateWithCursor = null;
 
 
     // create throttled function
     // create throttled function
-    this.scrollPreviewByLineWithThrottle = throttle(20, this.scrollPreviewByLine);
+    this.scrollPreviewByEditorScrollWithThrottle = throttle(20, this.scrollPreviewByEditorScroll);
+    this.scrollPreviewByCursorMovingWithThrottle = throttle(20, this.scrollPreviewByCursorMoving);
     this.renderWithDebounce = debounce(50, throttle(100, this.renderPreview));
     this.renderWithDebounce = debounce(50, throttle(100, this.renderPreview));
     this.saveDraftWithDebounce = debounce(800, this.saveDraft);
     this.saveDraftWithDebounce = debounce(800, this.saveDraft);
   }
   }
@@ -197,24 +198,30 @@ export default class PageEditor extends React.Component {
       return;
       return;
     }
     }
 
 
-    this.scrollPreviewByLineWithThrottle(data.line);
+    this.scrollPreviewByEditorScrollWithThrottle(data.line);
   }
   }
 
 
   onEditorScrollCursorIntoView(line) {
   onEditorScrollCursorIntoView(line) {
     this.lastScrolledDateWithCursor = new Date();
     this.lastScrolledDateWithCursor = new Date();
-    this.scrollPreviewByLineWithThrottle(line);
+    this.scrollPreviewByCursorMovingWithThrottle(line);
   }
   }
 
 
   /**
   /**
    * scroll Preview by the specified line
    * scroll Preview by the specified line
    * @param {number} line
    * @param {number} line
    */
    */
-  scrollPreviewByLine(line) {
+  scrollPreviewByEditorScroll(line) {
     if (this.previewElement == null) {
     if (this.previewElement == null) {
       return;
       return;
     }
     }
     scrollSyncHelper.scrollToRevealSourceLine(this.previewElement, line);
     scrollSyncHelper.scrollToRevealSourceLine(this.previewElement, line);
   };
   };
+  scrollPreviewByCursorMoving(line) {
+    if (this.previewElement == null) {
+      return;
+    }
+    scrollSyncHelper.scrollToRevealOverflowingSourceLine(this.previewElement, line);
+  };
 
 
   /*
   /*
    * methods for draft
    * methods for draft

+ 34 - 4
resource/js/components/PageEditor/ScrollSyncHelper.js

@@ -51,12 +51,12 @@ class ScrollSyncHelper {
 		return { previous };
 		return { previous };
   }
   }
 
 
-  getSourceRevealAddedOffset(element) {
+  getParentElementOffset(parentElement) {
     // get paddingTop
     // get paddingTop
-    const style = window.getComputedStyle(element, null);
+    const style = window.getComputedStyle(parentElement, null);
     const paddingTop = +(style.paddingTop.replace('px', ''));
     const paddingTop = +(style.paddingTop.replace('px', ''));
 
 
-		return -(paddingTop + element.clientHeight * 1 / 5);
+		return paddingTop + parentElement.getBoundingClientRect().top;
   }
   }
 
 
   /**
   /**
@@ -78,7 +78,37 @@ class ScrollSyncHelper {
 			} else {
 			} else {
 				scrollTo = previous.element.getBoundingClientRect().top;
 				scrollTo = previous.element.getBoundingClientRect().top;
       }
       }
-      element.scroll(0, element.scrollTop + scrollTo + this.getSourceRevealAddedOffset(element));
+
+      scrollTo -= this.getParentElementOffset(element);
+
+      element.scroll(0, element.scrollTop + scrollTo);
+		}
+  }
+
+  /**
+	 * Attempt to reveal the element that is overflowing from parent element.
+	 *
+   * @param {Element} element
+	 * @param {number} line
+	 */
+	scrollToRevealOverflowingSourceLine(element, line) {
+		const { previous, next } = this.getElementsForSourceLine(element, line);
+		// marker.update(previous && previous.element);
+		if (previous) {
+      const parentElementOffset = this.getParentElementOffset(element);
+      const prevElmTop = previous.element.getBoundingClientRect().top - parentElementOffset;
+      const prevElmBottom = previous.element.getBoundingClientRect().bottom - parentElementOffset;
+
+      if (prevElmTop < 0) {
+        // set the top of 'previous.element' to the top of 'element'
+        const scrollTo = element.scrollTop + prevElmTop;
+        element.scroll(0, scrollTo);
+      }
+      if (prevElmBottom > element.clientHeight) {
+        // set the bottom of 'previous.element' to the bottom of 'element'
+        const scrollTo = element.scrollTop + prevElmBottom - element.clientHeight + 20;
+        element.scroll(0, scrollTo);
+      }
 		}
 		}
   }
   }