From 487f1a969f328b08a56012c5b028febf7bfb3cc4 Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Sep 2013 14:57:02 +0100 Subject: [PATCH 1/2] vast improvement on movement of caret due to isolation of cause of problem - TLDR is Chrome detects blank rows line heights as incorrect --- src/static/js/ace2_inner.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index f53e9de8e..57f418fca 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3793,21 +3793,35 @@ function Ace2Inner(){ }, 200); } - /* Attempt to apply some sanity to cursor handling in Chrome after a copy / paste event We have to do this the way we do because rep. doesn't hold the value for keyheld events IE if the user - presses and holds the arrow key */ + presses and holds the arrow key .. Sorry if this is ugly, blame Chrome's weird handling of viewports after new content is added*/ if((evt.which == 37 || evt.which == 38 || evt.which == 39 || evt.which == 40) && $.browser.chrome){ var viewport = getViewPortTopBottom(); var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current - var caretOffsetTop = myselection.focusNode.parentNode.offsetTop; // get the carets selection offset in px IE 214 - var lineHeight = $(myselection.focusNode.parentNode).parent().height(); // get the line height of the caret line + var caretOffsetTop = myselection.focusNode.parentNode.offsetTop || myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214 + var lineHeight = $(myselection.focusNode.parentNode).parent("div").height(); // get the line height of the caret line + // top.console.log("offsetTop", myselection.focusNode.parentNode.parentNode.offsetTop); + try { + lineHeight = $(myselection.focusNode).height() // needed for how chrome handles line heights of null objects + // console.log("lineHeight now", lineHeight); + }catch(e){} var caretOffsetTopBottom = caretOffsetTop + lineHeight; var visibleLineRange = getVisibleLineRange(); // the visible lines IE 1,10 if(caretOffsetTop){ // sometimes caretOffsetTop bugs out and returns 0, not sure why, possible Chrome bug? Either way if it does we don't wanna mess with it - var caretIsNotVisible = (caretOffsetTop <= viewport.top || caretOffsetTopBottom >= viewport.bottom); // Is the Caret Visible to the user? + // top.console.log(caretOffsetTop, viewport.top, caretOffsetTopBottom, viewport.bottom); + var caretIsNotVisible = (caretOffsetTop < viewport.top || caretOffsetTopBottom >= viewport.bottom); // Is the Caret Visible to the user? + // Expect some weird behavior caretOffsetTopBottom is greater than viewport.bottom on a keypress down + var offsetTopSamePlace = caretOffsetTop == viewport.top; // sometimes moving key left & up leaves the caret at the same point as the viewport.top, technically the caret is visible but it's not fully visible so we should move to it + if(offsetTopSamePlace && (evt.which == 37 || evt.which == 38)){ + var newY = caretOffsetTop; + setScrollY(newY); + } + if(caretIsNotVisible){ // is the cursor no longer visible to the user? + // top.console.log("Caret is NOT visible to the user"); + // top.console.log(caretOffsetTop,viewport.top,caretOffsetTopBottom,viewport.bottom); // Oh boy the caret is out of the visible area, I need to scroll the browser window to lineNum. if(evt.which == 37 || evt.which == 38){ // If left or up arrow var newY = caretOffsetTop; // That was easy! @@ -3819,10 +3833,11 @@ function Ace2Inner(){ // top.console.log("line #", rep.selStart[0]); // the line our caret is on // top.console.log("firstvisible", visibleLineRange[0]); // the first visiblel ine // top.console.log("lastVisible", visibleLineRange[1]); // the last visible line - + // top.console.log(rep.selStart[0],visibleLineRange[1],rep.selStart[0], visibleLineRange[0]); // Holding down arrow after a paste can lose the cursor -- This is the best fix I can find if(rep.selStart[0] >= visibleLineRange[1] || rep.selStart[0] < visibleLineRange[0] ){ // if we're not at the bottom of the viewport - // top.console.log(viewport, lineHeight, myselection); + // top.console.log("Moving down doc", viewport, lineHeight, myselection); + // is the line in alignment with the bottom of the viewport cause if so we shouldnt be paginating? // TODO: Make it so chrome doesnt need to redraw the page by only applying this technique if required var newY = caretOffsetTop; }else{ // we're at the bottom of the viewport so snap to a "new viewport" From c8109b739866014daf20eee068ecfd614c8e813d Mon Sep 17 00:00:00 2001 From: John McLear Date: Wed, 25 Sep 2013 15:56:56 +0100 Subject: [PATCH 2/2] sanity also control home support --- src/static/js/ace2_inner.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 57f418fca..c4ad8117f 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -3745,6 +3745,7 @@ function Ace2Inner(){ doDeleteKey(); specialHandled = true; } + if((evt.which == 36 && evt.ctrlKey == true)){ setScrollY(0); } // Control Home send to Y = 0 if((evt.which == 33 || evt.which == 34) && type == 'keydown'){ evt.preventDefault(); // This is required, browsers will try to do normal default behavior on page up / down and the default behavior SUCKS @@ -3830,20 +3831,11 @@ function Ace2Inner(){ // only move the viewport if we're at the bottom of the viewport, if we hit down any other time the viewport shouldn't change // NOTE: This behavior only fires if Chrome decides to break the page layout after a paste, it's annoying but nothing I can do var selection = getSelection(); - // top.console.log("line #", rep.selStart[0]); // the line our caret is on - // top.console.log("firstvisible", visibleLineRange[0]); // the first visiblel ine - // top.console.log("lastVisible", visibleLineRange[1]); // the last visible line - // top.console.log(rep.selStart[0],visibleLineRange[1],rep.selStart[0], visibleLineRange[0]); - // Holding down arrow after a paste can lose the cursor -- This is the best fix I can find - if(rep.selStart[0] >= visibleLineRange[1] || rep.selStart[0] < visibleLineRange[0] ){ // if we're not at the bottom of the viewport - // top.console.log("Moving down doc", viewport, lineHeight, myselection); - // is the line in alignment with the bottom of the viewport cause if so we shouldnt be paginating? - // TODO: Make it so chrome doesnt need to redraw the page by only applying this technique if required - var newY = caretOffsetTop; - }else{ // we're at the bottom of the viewport so snap to a "new viewport" - // top.console.log(viewport, lineHeight, myselection); - var newY = caretOffsetTopBottom; // Allow continuous holding of down arrow to redraw the screen so we can see what we are going to highlight - } + top.console.log("line #", rep.selStart[0]); // the line our caret is on + top.console.log("firstvisible", visibleLineRange[0]); // the first visiblel ine + top.console.log("lastVisible", visibleLineRange[1]); // the last visible line + top.console.log(rep.selStart[0], visibleLineRange[1], rep.selStart[0], visibleLineRange[0]); + var newY = viewport.top + lineHeight; } if(newY){ setScrollY(newY); // set the scrollY offset of the viewport on the document