mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-05-04 22:27:10 -04:00
Fixed types
This commit is contained in:
parent
f7bd2185a8
commit
71c222c72f
3 changed files with 87 additions and 53 deletions
|
@ -3,8 +3,11 @@
|
||||||
// One rep.line(div) can be broken in more than one line in the browser.
|
// One rep.line(div) can be broken in more than one line in the browser.
|
||||||
// This function is useful to get the caret position of the line as
|
// This function is useful to get the caret position of the line as
|
||||||
// is represented by the browser
|
// is represented by the browser
|
||||||
|
import {Position, RepModel, RepNode} from "./types/RepModel";
|
||||||
|
|
||||||
export const getPosition = () => {
|
export const getPosition = () => {
|
||||||
const range = getSelectionRange();
|
const range = getSelectionRange();
|
||||||
|
// @ts-ignore
|
||||||
if (!range || $(range.endContainer).closest('body')[0].id !== 'innerdocbody') return null;
|
if (!range || $(range.endContainer).closest('body')[0].id !== 'innerdocbody') return null;
|
||||||
// When there's a <br> or any element that has no height, we can't get the dimension of the
|
// When there's a <br> or any element that has no height, we can't get the dimension of the
|
||||||
// element where the caret is. As we can't get the element height, we create a text node to get
|
// element where the caret is. As we can't get the element height, we create a text node to get
|
||||||
|
@ -18,7 +21,7 @@ export const getPosition = () => {
|
||||||
return line;
|
return line;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSelectionRange = (range) => {
|
const createSelectionRange = (range: Range) => {
|
||||||
const clonedRange = range.cloneRange();
|
const clonedRange = range.cloneRange();
|
||||||
|
|
||||||
// we set the selection start and end to avoid error when user selects a text bigger than
|
// we set the selection start and end to avoid error when user selects a text bigger than
|
||||||
|
@ -30,14 +33,14 @@ const createSelectionRange = (range) => {
|
||||||
return clonedRange;
|
return clonedRange;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPositionOfRepLineAtOffset = (node, offset) => {
|
const getPositionOfRepLineAtOffset = (node: any, offset: number) => {
|
||||||
// it is not a text node, so we cannot make a selection
|
// it is not a text node, so we cannot make a selection
|
||||||
if (node.tagName === 'BR' || node.tagName === 'EMPTY') {
|
if (node.tagName === 'BR' || node.tagName === 'EMPTY') {
|
||||||
return getPositionOfElementOrSelection(node);
|
return getPositionOfElementOrSelection(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (node.length === 0 && node.nextSibling) {
|
while (node.length === 0 && node.nextSibling) {
|
||||||
node = node.nextSibling;
|
node = node.nextSibling as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newRange = new Range();
|
const newRange = new Range();
|
||||||
|
@ -48,14 +51,13 @@ const getPositionOfRepLineAtOffset = (node, offset) => {
|
||||||
return linePosition;
|
return linePosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPositionOfElementOrSelection = (element) => {
|
const getPositionOfElementOrSelection = (element: Range):Position => {
|
||||||
const rect = element.getBoundingClientRect();
|
const rect = element.getBoundingClientRect();
|
||||||
const linePosition = {
|
return {
|
||||||
bottom: rect.bottom,
|
bottom: rect.bottom,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
top: rect.top,
|
top: rect.top,
|
||||||
};
|
} satisfies Position;
|
||||||
return linePosition;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// here we have two possibilities:
|
// here we have two possibilities:
|
||||||
|
@ -64,7 +66,7 @@ const getPositionOfElementOrSelection = (element) => {
|
||||||
// where is the top of the previous line
|
// where is the top of the previous line
|
||||||
// [2] the line before is part of another rep line. It's possible this line has different margins
|
// [2] the line before is part of another rep line. It's possible this line has different margins
|
||||||
// height. So we have to get the exactly position of the line
|
// height. So we have to get the exactly position of the line
|
||||||
export const getPositionTopOfPreviousBrowserLine = (caretLinePosition, rep) => {
|
export const getPositionTopOfPreviousBrowserLine = (caretLinePosition: Position, rep: RepModel) => {
|
||||||
let previousLineTop = caretLinePosition.top - caretLinePosition.height; // [1]
|
let previousLineTop = caretLinePosition.top - caretLinePosition.height; // [1]
|
||||||
const isCaretLineFirstBrowserLine = caretLineIsFirstBrowserLine(caretLinePosition.top, rep);
|
const isCaretLineFirstBrowserLine = caretLineIsFirstBrowserLine(caretLinePosition.top, rep);
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ export const getPositionTopOfPreviousBrowserLine = (caretLinePosition, rep) => {
|
||||||
return previousLineTop;
|
return previousLineTop;
|
||||||
};
|
};
|
||||||
|
|
||||||
const caretLineIsFirstBrowserLine = (caretLineTop, rep) => {
|
const caretLineIsFirstBrowserLine = (caretLineTop: number, rep: RepModel) => {
|
||||||
const caretRepLine = rep.selStart[0];
|
const caretRepLine = rep.selStart[0];
|
||||||
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
||||||
const firstRootNode = getFirstRootChildNode(lineNode);
|
const firstRootNode = getFirstRootChildNode(lineNode);
|
||||||
|
@ -91,7 +93,7 @@ const caretLineIsFirstBrowserLine = (caretLineTop, rep) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// find the first root node, usually it is a text node
|
// find the first root node, usually it is a text node
|
||||||
const getFirstRootChildNode = (node) => {
|
const getFirstRootChildNode = (node: RepNode) => {
|
||||||
if (!node.firstChild) {
|
if (!node.firstChild) {
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,7 +101,7 @@ const getFirstRootChildNode = (node) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDimensionOfLastBrowserLineOfRepLine = (line, rep) => {
|
const getDimensionOfLastBrowserLineOfRepLine = (line: number, rep: RepModel) => {
|
||||||
const lineNode = rep.lines.atIndex(line).lineNode;
|
const lineNode = rep.lines.atIndex(line).lineNode;
|
||||||
const lastRootChildNode = getLastRootChildNode(lineNode);
|
const lastRootChildNode = getLastRootChildNode(lineNode);
|
||||||
|
|
||||||
|
@ -109,7 +111,7 @@ const getDimensionOfLastBrowserLineOfRepLine = (line, rep) => {
|
||||||
return lastRootChildNodePosition;
|
return lastRootChildNodePosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getLastRootChildNode = (node) => {
|
const getLastRootChildNode = (node: RepNode) => {
|
||||||
if (!node.lastChild) {
|
if (!node.lastChild) {
|
||||||
return {
|
return {
|
||||||
node,
|
node,
|
||||||
|
@ -125,7 +127,7 @@ const getLastRootChildNode = (node) => {
|
||||||
// So, we can use the caret line to calculate the bottom of the line.
|
// So, we can use the caret line to calculate the bottom of the line.
|
||||||
// [2] the next line is part of another rep line.
|
// [2] the next line is part of another rep line.
|
||||||
// It's possible this line has different dimensions, so we have to get the exactly dimension of it
|
// It's possible this line has different dimensions, so we have to get the exactly dimension of it
|
||||||
export const getBottomOfNextBrowserLine = (caretLinePosition, rep) => {
|
export const getBottomOfNextBrowserLine = (caretLinePosition: Position, rep: RepModel) => {
|
||||||
let nextLineBottom = caretLinePosition.bottom + caretLinePosition.height; // [1]
|
let nextLineBottom = caretLinePosition.bottom + caretLinePosition.height; // [1]
|
||||||
const isCaretLineLastBrowserLine =
|
const isCaretLineLastBrowserLine =
|
||||||
caretLineIsLastBrowserLineOfRepLine(caretLinePosition.top, rep);
|
caretLineIsLastBrowserLineOfRepLine(caretLinePosition.top, rep);
|
||||||
|
@ -142,7 +144,7 @@ export const getBottomOfNextBrowserLine = (caretLinePosition, rep) => {
|
||||||
return nextLineBottom;
|
return nextLineBottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
const caretLineIsLastBrowserLineOfRepLine = (caretLineTop, rep) => {
|
const caretLineIsLastBrowserLineOfRepLine = (caretLineTop: number, rep: RepModel) => {
|
||||||
const caretRepLine = rep.selStart[0];
|
const caretRepLine = rep.selStart[0];
|
||||||
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
||||||
const lastRootChildNode = getLastRootChildNode(lineNode);
|
const lastRootChildNode = getLastRootChildNode(lineNode);
|
||||||
|
@ -153,7 +155,7 @@ const caretLineIsLastBrowserLineOfRepLine = (caretLineTop, rep) => {
|
||||||
return lastRootChildNodePosition.top === caretLineTop;
|
return lastRootChildNodePosition.top === caretLineTop;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPreviousVisibleLine = (line, rep) => {
|
export const getPreviousVisibleLine = (line: number, rep: RepModel): number => {
|
||||||
const firstLineOfPad = 0;
|
const firstLineOfPad = 0;
|
||||||
if (line <= firstLineOfPad) {
|
if (line <= firstLineOfPad) {
|
||||||
return firstLineOfPad;
|
return firstLineOfPad;
|
||||||
|
@ -166,7 +168,7 @@ export const getPreviousVisibleLine = (line, rep) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const getNextVisibleLine = (line, rep) => {
|
export const getNextVisibleLine = (line: number, rep: RepModel): number => {
|
||||||
const lastLineOfThePad = rep.lines.length() - 1;
|
const lastLineOfThePad = rep.lines.length() - 1;
|
||||||
if (line >= lastLineOfThePad) {
|
if (line >= lastLineOfThePad) {
|
||||||
return lastLineOfThePad;
|
return lastLineOfThePad;
|
||||||
|
@ -177,9 +179,9 @@ export const getNextVisibleLine = (line, rep) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLineVisible = (line, rep) => rep.lines.atIndex(line).lineNode.offsetHeight > 0;
|
const isLineVisible = (line: number, rep: RepModel) => rep.lines.atIndex(line).lineNode.offsetHeight > 0;
|
||||||
|
|
||||||
const getDimensionOfFirstBrowserLineOfRepLine = (line, rep) => {
|
const getDimensionOfFirstBrowserLineOfRepLine = (line: number, rep: RepModel) => {
|
||||||
const lineNode = rep.lines.atIndex(line).lineNode;
|
const lineNode = rep.lines.atIndex(line).lineNode;
|
||||||
const firstRootChildNode = getFirstRootChildNode(lineNode);
|
const firstRootChildNode = getFirstRootChildNode(lineNode);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {getBottomOfNextBrowserLine, getNextVisibleLine, getPosition, getPositionTopOfPreviousBrowserLine, getPreviousVisibleLine} from './caretPosition';
|
import {getBottomOfNextBrowserLine, getNextVisibleLine, getPosition, getPositionTopOfPreviousBrowserLine, getPreviousVisibleLine} from './caretPosition';
|
||||||
|
import {Position, RepModel, RepNode, WindowElementWithScrolling} from "./types/RepModel";
|
||||||
|
|
||||||
|
|
||||||
class Scroll {
|
class Scroll {
|
||||||
|
@ -8,6 +9,7 @@ class Scroll {
|
||||||
private scrollSettings: any;
|
private scrollSettings: any;
|
||||||
|
|
||||||
constructor(outerWin: HTMLIFrameElement) {
|
constructor(outerWin: HTMLIFrameElement) {
|
||||||
|
// @ts-ignore
|
||||||
this.scrollSettings = window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
this.scrollSettings = window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
||||||
|
|
||||||
// DOM reference
|
// DOM reference
|
||||||
|
@ -16,7 +18,7 @@ class Scroll {
|
||||||
this.rootDocument = parent.parent.document;
|
this.rootDocument = parent.parent.document;
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollWhenCaretIsInTheLastLineOfViewportWhenNecessary(rep, isScrollableEvent, innerHeight) {
|
scrollWhenCaretIsInTheLastLineOfViewportWhenNecessary(rep: RepModel, isScrollableEvent: boolean, innerHeight: number) {
|
||||||
// are we placing the caret on the line at the bottom of viewport?
|
// are we placing the caret on the line at the bottom of viewport?
|
||||||
// And if so, do we need to scroll the editor, as defined on the settings.json?
|
// And if so, do we need to scroll the editor, as defined on the settings.json?
|
||||||
const shouldScrollWhenCaretIsAtBottomOfViewport =
|
const shouldScrollWhenCaretIsAtBottomOfViewport =
|
||||||
|
@ -36,7 +38,7 @@ class Scroll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollWhenPressArrowKeys(arrowUp, rep, innerHeight) {
|
scrollWhenPressArrowKeys(arrowUp: boolean, rep: RepModel, innerHeight: number) {
|
||||||
// if percentageScrollArrowUp is 0, let the scroll to be handled as default, put the previous
|
// if percentageScrollArrowUp is 0, let the scroll to be handled as default, put the previous
|
||||||
// rep line on the top of the viewport
|
// rep line on the top of the viewport
|
||||||
if (this._arrowUpWasPressedInTheFirstLineOfTheViewport(arrowUp, rep)) {
|
if (this._arrowUpWasPressedInTheFirstLineOfTheViewport(arrowUp, rep)) {
|
||||||
|
@ -50,7 +52,7 @@ class Scroll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isCaretAtTheBottomOfViewport(rep) {
|
_isCaretAtTheBottomOfViewport(rep: RepModel) {
|
||||||
// computing a line position using getBoundingClientRect() is expensive.
|
// computing a line position using getBoundingClientRect() is expensive.
|
||||||
// (obs: getBoundingClientRect() is called on caretPosition.getPosition())
|
// (obs: getBoundingClientRect() is called on caretPosition.getPosition())
|
||||||
// To avoid that, we only call this function when it is possible that the
|
// To avoid that, we only call this function when it is possible that the
|
||||||
|
@ -64,16 +66,15 @@ class Scroll {
|
||||||
this._isLinePartiallyVisibleOnViewport(firstLineVisibleAfterCaretLine, rep);
|
this._isLinePartiallyVisibleOnViewport(firstLineVisibleAfterCaretLine, rep);
|
||||||
if (caretLineIsPartiallyVisibleOnViewport || lineAfterCaretLineIsPartiallyVisibleOnViewport) {
|
if (caretLineIsPartiallyVisibleOnViewport || lineAfterCaretLineIsPartiallyVisibleOnViewport) {
|
||||||
// check if the caret is in the bottom of the viewport
|
// check if the caret is in the bottom of the viewport
|
||||||
const caretLinePosition = getPosition();
|
const caretLinePosition = getPosition()!;
|
||||||
const viewportBottom = this._getViewPortTopBottom().bottom;
|
const viewportBottom = this._getViewPortTopBottom().bottom;
|
||||||
const nextLineBottom = getBottomOfNextBrowserLine(caretLinePosition, rep);
|
const nextLineBottom = getBottomOfNextBrowserLine(caretLinePosition, rep);
|
||||||
const nextLineIsBelowViewportBottom = nextLineBottom > viewportBottom;
|
return nextLineBottom > viewportBottom;
|
||||||
return nextLineIsBelowViewportBottom;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
_isLinePartiallyVisibleOnViewport(lineNumber, rep){
|
_isLinePartiallyVisibleOnViewport(lineNumber: number, rep: RepModel){
|
||||||
const lineNode = rep.lines.atIndex(lineNumber);
|
const lineNode = rep.lines.atIndex(lineNumber);
|
||||||
const linePosition = this._getLineEntryTopBottom(lineNode);
|
const linePosition = this._getLineEntryTopBottom(lineNode);
|
||||||
const lineTop = linePosition.top;
|
const lineTop = linePosition.top;
|
||||||
|
@ -123,7 +124,7 @@ class Scroll {
|
||||||
};
|
};
|
||||||
|
|
||||||
_getScrollXY() {
|
_getScrollXY() {
|
||||||
const win = this.outerWin;
|
const win = this.outerWin as WindowElementWithScrolling;
|
||||||
const odoc = this.doc;
|
const odoc = this.doc;
|
||||||
if (typeof (win.pageYOffset) === 'number') {
|
if (typeof (win.pageYOffset) === 'number') {
|
||||||
return {
|
return {
|
||||||
|
@ -141,26 +142,26 @@ class Scroll {
|
||||||
};
|
};
|
||||||
|
|
||||||
getScrollX() {
|
getScrollX() {
|
||||||
return this._getScrollXY().x;
|
return this._getScrollXY()!.x;
|
||||||
};
|
};
|
||||||
|
|
||||||
getScrollY () {
|
getScrollY () {
|
||||||
return this._getScrollXY().y;
|
return this._getScrollXY()!.y;
|
||||||
};
|
};
|
||||||
|
|
||||||
setScrollX(x) {
|
setScrollX(x: number) {
|
||||||
this.outerWin.scrollTo(x, this.getScrollY());
|
this.outerWin.scrollTo(x, this.getScrollY());
|
||||||
};
|
};
|
||||||
|
|
||||||
setScrollY(y) {
|
setScrollY(y: number) {
|
||||||
this.outerWin.scrollTo(this.getScrollX(), y);
|
this.outerWin.scrollTo(this.getScrollX(), y);
|
||||||
};
|
};
|
||||||
|
|
||||||
setScrollXY(x, y) {
|
setScrollXY(x: number, y: number) {
|
||||||
this.outerWin.scrollTo(x, y);
|
this.outerWin.scrollTo(x, y);
|
||||||
};
|
};
|
||||||
|
|
||||||
_isCaretAtTheTopOfViewport(rep) {
|
_isCaretAtTheTopOfViewport(rep: RepModel) {
|
||||||
const caretLine = rep.selStart[0];
|
const caretLine = rep.selStart[0];
|
||||||
const linePrevCaretLine = caretLine - 1;
|
const linePrevCaretLine = caretLine - 1;
|
||||||
const firstLineVisibleBeforeCaretLine =
|
const firstLineVisibleBeforeCaretLine =
|
||||||
|
@ -174,12 +175,12 @@ class Scroll {
|
||||||
const viewportPosition = this._getViewPortTopBottom();
|
const viewportPosition = this._getViewPortTopBottom();
|
||||||
const viewportTop = viewportPosition.top;
|
const viewportTop = viewportPosition.top;
|
||||||
const viewportBottom = viewportPosition.bottom;
|
const viewportBottom = viewportPosition.bottom;
|
||||||
const caretLineIsBelowViewportTop = caretLinePosition.bottom >= viewportTop;
|
const caretLineIsBelowViewportTop = caretLinePosition!.bottom >= viewportTop;
|
||||||
const caretLineIsAboveViewportBottom = caretLinePosition.top < viewportBottom;
|
const caretLineIsAboveViewportBottom = caretLinePosition!.top < viewportBottom;
|
||||||
const caretLineIsInsideOfViewport =
|
const caretLineIsInsideOfViewport =
|
||||||
caretLineIsBelowViewportTop && caretLineIsAboveViewportBottom;
|
caretLineIsBelowViewportTop && caretLineIsAboveViewportBottom;
|
||||||
if (caretLineIsInsideOfViewport) {
|
if (caretLineIsInsideOfViewport) {
|
||||||
const prevLineTop = getPositionTopOfPreviousBrowserLine(caretLinePosition, rep);
|
const prevLineTop = getPositionTopOfPreviousBrowserLine(caretLinePosition!, rep);
|
||||||
const previousLineIsAboveViewportTop = prevLineTop < viewportTop;
|
const previousLineIsAboveViewportTop = prevLineTop < viewportTop;
|
||||||
return previousLineIsAboveViewportTop;
|
return previousLineIsAboveViewportTop;
|
||||||
}
|
}
|
||||||
|
@ -190,18 +191,18 @@ class Scroll {
|
||||||
// By default, when user makes an edition in a line out of viewport, this line goes
|
// By default, when user makes an edition in a line out of viewport, this line goes
|
||||||
// to the edge of viewport. This function gets the extra pixels necessary to get the
|
// to the edge of viewport. This function gets the extra pixels necessary to get the
|
||||||
// caret line in a position X relative to Y% viewport.
|
// caret line in a position X relative to Y% viewport.
|
||||||
_getPixelsRelativeToPercentageOfViewport(innerHeight, aboveOfViewport) {
|
_getPixelsRelativeToPercentageOfViewport(innerHeight: number, aboveOfViewport?: boolean) {
|
||||||
let pixels = 0;
|
let pixels = 0;
|
||||||
const scrollPercentageRelativeToViewport = this._getPercentageToScroll(aboveOfViewport);
|
const scrollPercentageRelativeToViewport = this._getPercentageToScroll(aboveOfViewport);
|
||||||
if (scrollPercentageRelativeToViewport > 0 && scrollPercentageRelativeToViewport <= 1) {
|
if (scrollPercentageRelativeToViewport > 0 && scrollPercentageRelativeToViewport <= 1) {
|
||||||
pixels = parseInt(innerHeight * scrollPercentageRelativeToViewport);
|
pixels = parseInt(String(innerHeight * scrollPercentageRelativeToViewport));
|
||||||
}
|
}
|
||||||
return pixels;
|
return pixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
// we use different percentages when change selection. It depends on if it is
|
// we use different percentages when change selection. It depends on if it is
|
||||||
// either above the top or below the bottom of the page
|
// either above the top or below the bottom of the page
|
||||||
_getPercentageToScroll(aboveOfViewport: boolean) {
|
_getPercentageToScroll(aboveOfViewport: boolean|undefined) {
|
||||||
let percentageToScroll = this.scrollSettings.percentage.editionBelowViewport;
|
let percentageToScroll = this.scrollSettings.percentage.editionBelowViewport;
|
||||||
if (aboveOfViewport) {
|
if (aboveOfViewport) {
|
||||||
percentageToScroll = this.scrollSettings.percentage.editionAboveViewport;
|
percentageToScroll = this.scrollSettings.percentage.editionAboveViewport;
|
||||||
|
@ -209,16 +210,16 @@ class Scroll {
|
||||||
return percentageToScroll;
|
return percentageToScroll;
|
||||||
};
|
};
|
||||||
|
|
||||||
_getPixelsToScrollWhenUserPressesArrowUp(innerHeight) {
|
_getPixelsToScrollWhenUserPressesArrowUp(innerHeight: number) {
|
||||||
let pixels = 0;
|
let pixels = 0;
|
||||||
const percentageToScrollUp = this.scrollSettings.percentageToScrollWhenUserPressesArrowUp;
|
const percentageToScrollUp = this.scrollSettings.percentageToScrollWhenUserPressesArrowUp;
|
||||||
if (percentageToScrollUp > 0 && percentageToScrollUp <= 1) {
|
if (percentageToScrollUp > 0 && percentageToScrollUp <= 1) {
|
||||||
pixels = parseInt(innerHeight * percentageToScrollUp);
|
pixels = parseInt(String(innerHeight * percentageToScrollUp));
|
||||||
}
|
}
|
||||||
return pixels;
|
return pixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
_scrollYPage(pixelsToScroll) {
|
_scrollYPage(pixelsToScroll: number) {
|
||||||
const durationOfAnimationToShowFocusline = this.scrollSettings.duration;
|
const durationOfAnimationToShowFocusline = this.scrollSettings.duration;
|
||||||
if (durationOfAnimationToShowFocusline) {
|
if (durationOfAnimationToShowFocusline) {
|
||||||
this._scrollYPageWithAnimation(pixelsToScroll, durationOfAnimationToShowFocusline);
|
this._scrollYPageWithAnimation(pixelsToScroll, durationOfAnimationToShowFocusline);
|
||||||
|
@ -227,15 +228,15 @@ class Scroll {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_scrollYPageWithoutAnimation(pixelsToScroll) {
|
_scrollYPageWithoutAnimation(pixelsToScroll: number) {
|
||||||
this.outerWin.scrollBy(0, pixelsToScroll);
|
this.outerWin.scrollBy(0, pixelsToScroll);
|
||||||
};
|
};
|
||||||
|
|
||||||
_scrollYPageWithAnimation(pixelsToScroll, durationOfAnimationToShowFocusline) {
|
_scrollYPageWithAnimation(pixelsToScroll: number, durationOfAnimationToShowFocusline: number) {
|
||||||
const outerDocBody = this.doc.getElementById('outerdocbody');
|
const outerDocBody = this.doc.getElementById('outerdocbody');
|
||||||
|
|
||||||
// it works on later versions of Chrome
|
// it works on later versions of Chrome
|
||||||
const $outerDocBody = $(outerDocBody);
|
const $outerDocBody = $(outerDocBody!);
|
||||||
this._triggerScrollWithAnimation(
|
this._triggerScrollWithAnimation(
|
||||||
$outerDocBody, pixelsToScroll, durationOfAnimationToShowFocusline);
|
$outerDocBody, pixelsToScroll, durationOfAnimationToShowFocusline);
|
||||||
|
|
||||||
|
@ -245,7 +246,7 @@ class Scroll {
|
||||||
$outerDocBodyParent, pixelsToScroll, durationOfAnimationToShowFocusline);
|
$outerDocBodyParent, pixelsToScroll, durationOfAnimationToShowFocusline);
|
||||||
};
|
};
|
||||||
|
|
||||||
_triggerScrollWithAnimation($elem, pixelsToScroll, durationOfAnimationToShowFocusline) {
|
_triggerScrollWithAnimation($elem:any, pixelsToScroll: number, durationOfAnimationToShowFocusline: number) {
|
||||||
// clear the queue of animation
|
// clear the queue of animation
|
||||||
$elem.stop('scrollanimation');
|
$elem.stop('scrollanimation');
|
||||||
$elem.animate({
|
$elem.animate({
|
||||||
|
@ -258,7 +259,7 @@ class Scroll {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scrollNodeVerticallyIntoView(rep, innerHeight) {
|
scrollNodeVerticallyIntoView(rep: RepModel, innerHeight: number) {
|
||||||
const viewport = this._getViewPortTopBottom();
|
const viewport = this._getViewPortTopBottom();
|
||||||
|
|
||||||
// when the selection changes outside of the viewport the browser automatically scrolls the line
|
// when the selection changes outside of the viewport the browser automatically scrolls the line
|
||||||
|
@ -288,7 +289,7 @@ class Scroll {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_partOfRepLineIsOutOfViewport(viewportPosition, rep) {
|
_partOfRepLineIsOutOfViewport(viewportPosition: Position, rep: RepModel) {
|
||||||
const focusLine = (rep.selFocusAtStart ? rep.selStart[0] : rep.selEnd[0]);
|
const focusLine = (rep.selFocusAtStart ? rep.selStart[0] : rep.selEnd[0]);
|
||||||
const line = rep.lines.atIndex(focusLine);
|
const line = rep.lines.atIndex(focusLine);
|
||||||
const linePosition = this._getLineEntryTopBottom(line);
|
const linePosition = this._getLineEntryTopBottom(line);
|
||||||
|
@ -298,25 +299,25 @@ class Scroll {
|
||||||
return lineIsBelowOfViewport || lineIsAboveOfViewport;
|
return lineIsBelowOfViewport || lineIsAboveOfViewport;
|
||||||
};
|
};
|
||||||
|
|
||||||
_getLineEntryTopBottom(entry, destObj) {
|
_getLineEntryTopBottom(entry: RepNode, destObj?: Position) {
|
||||||
const dom = entry.lineNode;
|
const dom = entry.lineNode;
|
||||||
const top = dom.offsetTop;
|
const top = dom.offsetTop;
|
||||||
const height = dom.offsetHeight;
|
const height = dom.offsetHeight;
|
||||||
const obj = (destObj || {});
|
const obj = (destObj || {}) as Position;
|
||||||
obj.top = top;
|
obj.top = top;
|
||||||
obj.bottom = (top + height);
|
obj.bottom = (top + height);
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
_arrowUpWasPressedInTheFirstLineOfTheViewport(arrowUp, rep) {
|
_arrowUpWasPressedInTheFirstLineOfTheViewport(arrowUp: boolean, rep: RepModel) {
|
||||||
const percentageScrollArrowUp = this.scrollSettings.percentageToScrollWhenUserPressesArrowUp;
|
const percentageScrollArrowUp = this.scrollSettings.percentageToScrollWhenUserPressesArrowUp;
|
||||||
return percentageScrollArrowUp && arrowUp && this._isCaretAtTheTopOfViewport(rep);
|
return percentageScrollArrowUp && arrowUp && this._isCaretAtTheTopOfViewport(rep);
|
||||||
};
|
};
|
||||||
|
|
||||||
getVisibleLineRange(rep) {
|
getVisibleLineRange(rep: RepModel) {
|
||||||
const viewport = this._getViewPortTopBottom();
|
const viewport = this._getViewPortTopBottom();
|
||||||
// console.log("viewport top/bottom: %o", viewport);
|
// console.log("viewport top/bottom: %o", viewport);
|
||||||
const obj = {};
|
const obj = {} as Position;
|
||||||
const self = this;
|
const self = this;
|
||||||
const start = rep.lines.search((e) => self._getLineEntryTopBottom(e, obj).bottom > viewport.top);
|
const start = rep.lines.search((e) => self._getLineEntryTopBottom(e, obj).bottom > viewport.top);
|
||||||
// return the first line that the top position is greater or equal than
|
// return the first line that the top position is greater or equal than
|
||||||
|
@ -328,7 +329,7 @@ class Scroll {
|
||||||
return [start, end - 1];
|
return [start, end - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
getVisibleCharRange(rep) {
|
getVisibleCharRange(rep: RepModel) {
|
||||||
const lineRange = this.getVisibleLineRange(rep);
|
const lineRange = this.getVisibleLineRange(rep);
|
||||||
return [rep.lines.offsetOfIndex(lineRange[0]), rep.lines.offsetOfIndex(lineRange[1])];
|
return [rep.lines.offsetOfIndex(lineRange[0]), rep.lines.offsetOfIndex(lineRange[1])];
|
||||||
};
|
};
|
||||||
|
|
31
src/static/js/types/RepModel.ts
Normal file
31
src/static/js/types/RepModel.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
export type RepModel = {
|
||||||
|
lines: {
|
||||||
|
atIndex: (num: number)=>RepNode,
|
||||||
|
offsetOfIndex: (range: number)=>number,
|
||||||
|
search: (filter: (e: RepNode)=>boolean)=>number,
|
||||||
|
length: ()=>number
|
||||||
|
}
|
||||||
|
selStart: number[],
|
||||||
|
selEnd: number[],
|
||||||
|
selFocusAtStart: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Position = {
|
||||||
|
bottom: number,
|
||||||
|
height: number,
|
||||||
|
top: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RepNode = {
|
||||||
|
firstChild: RepNode,
|
||||||
|
lineNode: RepNode
|
||||||
|
length: number,
|
||||||
|
lastChild: RepNode,
|
||||||
|
offsetHeight: number,
|
||||||
|
offsetTop: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WindowElementWithScrolling = HTMLIFrameElement & {
|
||||||
|
pageYOffset: number|string,
|
||||||
|
pageXOffset: number
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue