From 2f3255b53dbdd402b6215baddf522688e32ea47d Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sat, 4 Nov 2023 15:22:32 +0300 Subject: [PATCH] reworking text selection + tweaks... Signed-off-by: Alex A. Naanou --- experiments/outline-editor/editor.css | 1 + experiments/outline-editor/editor.js | 48 ++++++++++++++++++++++----- experiments/outline-editor/generic.js | 5 ++- experiments/outline-editor/index.html | 48 +++++++++++++++------------ 4 files changed, 72 insertions(+), 30 deletions(-) diff --git a/experiments/outline-editor/editor.css b/experiments/outline-editor/editor.css index 3a6e3b5..889a402 100755 --- a/experiments/outline-editor/editor.css +++ b/experiments/outline-editor/editor.css @@ -183,6 +183,7 @@ &>.view { position: relative; pointer-events: none; + user-select: none; /* clickable things in view */ & a, diff --git a/experiments/outline-editor/editor.js b/experiments/outline-editor/editor.js index e6add2a..2c765a6 100755 --- a/experiments/outline-editor/editor.js +++ b/experiments/outline-editor/editor.js @@ -66,6 +66,12 @@ var getCharOffset = function(elem, x, y, c){ : null } +var getTextAreaOffset = function(elem, x, y){ + return elem.getTextGeometry(function(res, elem){ + // XXX this will not work as it needs correct placement of elem under the cursor... + return getCharOffset(elem, x, y) }) } + + // Get offset in markdown relative to the resulting text... // // v <----- position @@ -2017,24 +2023,50 @@ var Outline = { // click... // XXX revise... // XXX tap support... + // XXX support selection from first click... (see: mousemove handler) + var selecting, start outline.addEventListener('mousedown', function(evt){ var elem = evt.target // place the cursor where the user clicked in code/text... if(elem.classList.contains('code') && document.activeElement !== elem){ - evt.preventDefault() var view = that.get(elem).querySelector('.view') + var initial = elem.selectionStart var c = getCharOffset(view, evt.clientX, evt.clientY) - if(c == null){ + var m = getMarkdownOffset(elem.value, view.innerText, c) + // selecting an element with text offset by markup... + if(m != 0){ + evt.preventDefault() + selecting = elem } + start = c == null ? + elem.value.length + : c + m + // NOTE: this is done on next frame to allow the + // browser to place the caret before we correct + // its position... (if .preventDefault() was not called) + setTimeout(function(){ elem.focus() - elem.selectionStart = elem.value.length - elem.selectionEnd = elem.value.length + elem.selectionStart = + elem.selectionEnd = + start }, 0) } }) + outline.addEventListener('mousemove', + function(evt){ + // handle selection in element with text offset by markup... + // XXX should there be a timeout??? + if(selecting != null){ + // XXX need to get offset under cursor... + var c = getTextAreaOffset(selecting, evt.clientX, evt.clientY) + return + if(c > start){ + selecting.selectionStart = start + selecting.selectionEnd = c } else { - var m = getMarkdownOffset(elem.value, view.innerText, c) - elem.focus() - elem.selectionStart = c + m - elem.selectionEnd = c + m } } }) + selecting.selectionStart = c + selecting.selectionEnd = start } } }) + outline.addEventListener('mouseup', + function(evt){ + selecting = undefined }) outline.addEventListener('click', function(evt){ var elem = evt.target diff --git a/experiments/outline-editor/generic.js b/experiments/outline-editor/generic.js index 5185d02..0bb52f9 100755 --- a/experiments/outline-editor/generic.js +++ b/experiments/outline-editor/generic.js @@ -63,7 +63,7 @@ HTMLTextAreaElement.prototype.autoUpdateSize = function(){ function(evt){ that.updateSize() }) return this } -HTMLTextAreaElement.prototype.getTextGeometry = function(){ +HTMLTextAreaElement.prototype.getTextGeometry = function(func){ var offset = this.selectionStart var text = this.value @@ -128,6 +128,9 @@ HTMLTextAreaElement.prototype.getTextGeometry = function(){ offsetTop: carret.offsetTop, } + if(typeof(func) == 'function'){ + res = func(res, span) } + span.remove() return res } diff --git a/experiments/outline-editor/index.html b/experiments/outline-editor/index.html index 58636ee..e04f17d 100755 --- a/experiments/outline-editor/index.html +++ b/experiments/outline-editor/index.html @@ -75,6 +75,7 @@ var setup = function(){ - selection - DONE multiple node selection (via shift+motion) - fixed state -- while `shift` pressed select or deselect only depending on first action (a-la FAR) + - DONE double/triple click working... - touch/mouse (???) - Q: should we select text (mouse/touch) without first focusing?? - _...logseq does not do this either_ @@ -83,10 +84,8 @@ var setup = function(){ - numbered lists: add counters to a depth of 6-7... - _or find a way to make them repeat..._ - FEATURE: read-only mode - - auto-shift done blocks to the end of siblings... (option?) + - FEATURE: auto-shift done blocks to the end of siblings... (option?) - ...or should this be `sort:: done` -- i.e. sort children by done status?? - - `backspace`/`delete` in block contract the field with a delay... - - _...looks like we are updating size on keyup..._ - codeblock as a block _...if only whitespace before/after clear it and style whole block..._ _...might be a good idea to do this with codeblock at start/end of block..._ @@ -100,15 +99,21 @@ var setup = function(){ - cleanup html - generate ideomatic html (???) - style attrs (see: [attrs](#attributes)) - - FEATURE: `collapse-children:: true` block option -- when loading collapse all immediate children - FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)` - table inline editing a-la code editing -- click cell and edit directly... - - a way to make a block monospace (???) - - Nerd fonts (option???) - smooth scrolling - _...this is more complicated than adding `behavior: "smooth"` to `.scrollIntoView(..)` as scrolling animation will get interrupted by next user input..._ - need to cancel animation if things are moving too fast... - make this generic (???) + - JSON API + - cli + - Q: do we use \\t for indent? (option???) + - Q: persistent empty first/last node (a button to create a new node)? + - Q: search? + - _seems that search should be external to the editor_ + - empty item height is a bit off... + - Nerd fonts (option???) + - FEATURE: `collapse-children:: true` block option -- when loading collapse all immediate children - FEATURE? block templates... collapsed:: true - something like: `TPL: [_] -- ` @@ -116,24 +121,24 @@ var setup = function(){ - `` -- field marker - each child node will copy the template and allow editing of only fields - not clear how to handle template changes... - - JSON API - - cli - - Q: do we use \\t for indent? (option???) - - Q: persistent empty first/last node (a button to create a new node)? - - Q: should list bullets be on the same level as nodes or offset?? + - DONE `backspace`/`delete` in block contract the field with a delay... + collapsed:: true + - _...looks like we are updating size on keyup..._ + - DONE Q: should list bullets be on the same level as nodes or offset?? collapsed:: true - A) justified to bullet: - * list item - * list item - block text + ``` + * list item + * list item + block text + ``` + _This is impossible to create in the current implementation_ - B) justified to text _(current)_: - * list item - * list item - block text - - NOTE: this is only a problem if making list-items manually -- disable??? - - empty item height is a bit off... - - search? - - _...not sure if search should be internal or external yet..._ + ``` + * list item + * list item + block text + ``` - DONE add horizontal scroll to code blocks... collapsed:: true - ```html @@ -168,6 +173,7 @@ var setup = function(){ - DONE undo - DONE crop: make path clickable - DONE Q: crop: should we control crop via "crop-in"/"crop-out" instead of crop/uncrop?? + collapsed:: true - _crop-in/crop-out seems more natural..._ - DONE crop: show crop path (and depth) - DONE over-travel pause -- when going fast over start/end stop...