oof struggling with char offset

This commit is contained in:
John McLear 2021-01-02 16:30:32 +00:00
parent 8e5c124f5e
commit 81e50061dc
2 changed files with 118 additions and 63 deletions

View file

@ -3071,50 +3071,14 @@ function Ace2Inner() {
// boolean - reflects if the user is attempting to highlight content // boolean - reflects if the user is attempting to highlight content
const highlighting = shiftKey && (rep.selStart[0] !== rep.selEnd[0] || rep.selStart[1] !== rep.selEnd[1]); const highlighting = shiftKey && (rep.selStart[0] !== rep.selEnd[0] || rep.selStart[1] !== rep.selEnd[1]);
// input is a line
// returned is the number of characters in that index that are currently
// visible in the viewport
// TODO CAKE JM
const getVisibleCharRangeOfLineInViewport = (line) => {
const range = document.createRange();
const chars = line.text.split(''); // split "abc" into ["a","b","c"]
const parentElement = document.getElementById(line.domInfo.node.id).childNodes;
// top.console.log(parentElement);
const nodeArray = Array.from(document.body.childNodes).filter;
// top.console.log(nodeArray);
/*
const characterTopOffset = [];
for (const node of parentElement) {
// each span..
top.console.log('span', node); // shows all nodes from the collection
top.console.log('span length', node.offsetTop); // shows all nodes from the collection
// now do each character
let i = 0;
while (i < node.textContent.length) {
top.console.log(i, node.textContent[i]);
const range = document.createRange();
range.setStart(node, i);
range.setEnd(node, i + 1);
const char = range.getClientRects();
if (char.length) {
for (const element in chars) {
top.console.log(element.top);
}
}
// above is broken..
i++;
}
}
*/
return 1000;
};
if (isPageUp) { if (isPageUp) {
// Approach #99991248928174 to solve this problem.... // Approach #99991248928174 to solve this problem....
scroll.movePage('up'); scroll.movePage('up');
const firstVisible = scroll.getFirstVisibleCharacter('up', rep); const modifiedRep = scroll.getFirstVisibleCharacter('up', rep);
rep.selStart[0] = firstVisible; rep.selStart[0] = modifiedRep.selStart[0];
rep.selEnd[0] = firstVisible; rep.selEnd[0] = modifiedRep.selEnd[0];
rep.selStart[1] = modifiedRep.selStart[1];
rep.selEnd[1] = modifiedRep.selEnd[1];
} }
if (isPageDown) { if (isPageDown) {
/** * /** *
@ -3124,33 +3088,39 @@ function Ace2Inner() {
const lengthOfLastLine = rep.lines.atIndex(rep.selEnd[0]).width - 1; const lengthOfLastLine = rep.lines.atIndex(rep.selEnd[0]).width - 1;
const endOfLine = lengthOfLastLine === rep.selEnd[1]; const endOfLine = lengthOfLastLine === rep.selEnd[1];
const atBottom = (rep.lines.length() - 1) === rep.selEnd[0]; const atBottom = (rep.lines.length() - 1) === rep.selEnd[0];
const originalPosition = scroll._getViewPortTopBottom();
// If we are right at the bottom of the document, no need to continue // If we are right at the bottom of the document, no need to continue
if (atBottom && endOfLine) return; if (atBottom && endOfLine) return;
/** * /** *
* Move the actual view * Move the actual view
*/ */
scroll.movePage('down'); scroll.movePage('down');
const hasMoved = originalPosition.top !== scroll._getViewPortTopBottom().top;
/** * /** *
* Move the caret * Move the caret
*/ */
const firstVisible = scroll.getFirstVisibleCharacter('down', rep); const modifiedRep = scroll.getFirstVisibleCharacter('down', rep);
top.console.log('fB', firstVisible); rep.selStart[0] = modifiedRep.selStart[0];
top.console.log(rep.lines.length()); rep.selEnd[0] = modifiedRep.selEnd[0];
rep.selStart[1] = modifiedRep.selStart[1];
rep.selEnd[1] = modifiedRep.selEnd[1];
if (rep.selStart[0] === firstVisible) { top.console.log(rep.lines.length());
// we're at the bottom if (!hasMoved) {
// we're at the bottom so select the last bit of content.
rep.selStart[0] = rep.lines.length() - 1; rep.selStart[0] = rep.lines.length() - 1;
rep.selEnd[0] = rep.lines.length() - 1; rep.selEnd[0] = rep.lines.length() - 1;
rep.selStart[1] = rep.lines.atIndex(rep.selStart[0]).length; rep.selStart[1] = rep.lines.atIndex(rep.selStart[0]).length;
rep.selEnd[1] = rep.lines.atIndex(rep.selStart[0]).length; rep.selEnd[1] = rep.lines.atIndex(rep.selStart[0]).length;
} else { } else {
rep.selStart[0] = firstVisible; // we moved, this will need modifying to support remembered x offset
rep.selEnd[0] = firstVisible; rep.selStart[0] = modifiedRep.selStart[0];
rep.selEnd[0] = modifiedRep.selEnd[0];
} }
} }

View file

@ -369,30 +369,115 @@ Scroll.prototype.movePage = function (direction) {
return; return;
}; };
Scroll.prototype.getFirstVisibleCharacter = function (direction) { Scroll.prototype.getFirstVisibleCharacter = function (direction, rep) {
const viewport = this._getViewPortTopBottom(); const viewport = this._getViewPortTopBottom();
console.log('viewport', viewport); console.log('viewport', viewport);
const editor = parent.document.getElementsByTagName('iframe'); const editor = parent.document.getElementsByTagName('iframe');
const lines = $(editor).contents().find('div'); const lines = $(editor).contents().find('div');
let goToLine = 0; // const currentLine = $(editor).contents().find('#innerdocbody');
const currentLine = rep.lines.atIndex(rep.selEnd[0]);
console.log('currentLine', currentLine);
const modifiedRep = {};
modifiedRep.selStart = [];
modifiedRep.selEnd = [];
let willGoToNextLine = false;
// we have moved the viewport at this point, we want to know which
// line is visible?
$.each(lines, (index, line) => { $.each(lines, (index, line) => {
const lineTopOffset = $(line).offset().top; // Line height important for supporting long lines that fill viewport.
// console.log(index, line); const lineBase = $(line).offset().top + $(line).height();
// console.log($(line).offset().top);
// console.log(index, 'lineTopOffset', lineTopOffset);
// console.log('viewport.top', viewport.top);
// is each line in the viewport? // is each line in the viewport?
if (lineBase > viewport.top) {
top.console.log('returning', index);
modifiedRep.selEnd[0] = index;
modifiedRep.selStart[0] = index;
modifiedRep.selEnd[1] = 0;
modifiedRep.selStart[1] = 0;
// JM TODO Long lines... // Important for supporting long lines.
if (lineTopOffset > viewport.top) { if (modifiedRep.selEnd[0] !== rep.selEnd[0]) willGoToNextLine = true;
// top.console.log('returning', index); return false; // exit $.each because we found a lovely line :)
goToLine = index;
return false;
} }
}); });
// go to this rep.
return goToLine; if (willGoToNextLine) return modifiedRep;
// oh dear, looks like the original line is still the first in the viewport..
// we will need to move the rep X chars within that original position.
console.log('CANT SEE NEXT LiNE!');
modifiedRep.selStart[0] = rep.selStart[0];
modifiedRep.selEnd[0] = rep.selEnd[0];
const numberOfVisibleChars = this.getCountOfVisibleCharsInViewport(currentLine, viewport);
// TODO, figure out how many chars are visible in line.
modifiedRep.selStart[1] = rep.selStart[1] + numberOfVisibleChars;
modifiedRep.selEnd[1] = rep.selEnd[1] + numberOfVisibleChars;
return modifiedRep;
};
// line is a DOM Line
// returned is the number of characters in that index that are currently visible
// IE 120,240
Scroll.prototype.getCountOfVisibleCharsInViewport = (line, viewport) => {
const range = document.createRange();
const chars = line.text.split(''); // split "abc" into ["a","b","c"]
const parentElement = document.getElementById(line.domInfo.node.id).childNodes;
const charNumber = [];
// top.console.log(parentElement);
for (let node of parentElement) {
// each span..
// top.console.log('span', node); // shows all nodes from the collection
// top.console.log('span length', node.offsetTop); // shows all nodes from the collection
// each character
let i = 0;
console.log(node);
node = node.childNodes[0];
if (node.childNodes && node.childNodes[1].length === 0) return;
console.log(node);
console.log(node.wholeText.length);
while (i < node.wholeText.length) {
// top.console.log(i, node.textContent[i]);
const range = document.createRange();
let failed = false;
try {
range.setStart(node, i);
} catch (e) {
failed = true;
console.log('fail', e);
// console.log('node', node);
}
try {
range.setEnd(node, i + 1);
} catch (e) {
failed = true;
console.log('fail', e);
console.log('node', node);
}
// console.log('range', range);
let char;
if (!failed) char = range.getClientRects();
console.log(node);
console.log('charr????', char);
if (char) return;
if (char && char.length && char[0]) {
const topOffset = char[0].y;
charNumber.push(topOffset);
// is this element in view?
console.log('topOffset', topOffset, 'viewport', viewport);
if (topOffset > viewport.top) {
console.log('can put rep here!', i);
return;
}
}
i++;
}
top.console.log('charNumber', charNumber);
return; // TEMPJM CAKE remove once stable
}
return 1000;
}; };