focus and scroll into view now seems OK, not smooth though...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-10-23 14:37:14 +03:00
parent 90cdc0c3c7
commit b2a3173f8d
4 changed files with 64 additions and 26 deletions

View File

@ -7,7 +7,7 @@
:root {
--font-size: 5mm;
--outline-padding: 5rem;
--outline-padding: 7rem;
--item-indent: 2rem;
--item-padding-ratio: 0.2;
@ -54,8 +54,6 @@
display: block;
position: relative;
width: calc(100% - var(--button-size) - var(--outline-padding) * 2);
padding: 1em var(--outline-padding);
padding-bottom: 1.2em
}

View File

@ -720,6 +720,7 @@ var Outline = {
// .get('visible')
// .get('editable')
// .get('selected')
// .get('viewport')
// .get('top')
// -> <nodes>
//
@ -739,7 +740,7 @@ var Outline = {
if(node == 'top'){
return [...outline.children] }
// groups defaulting to .outline as base...
if(['all', 'visible', 'editable', 'selected'].includes(node)){
if(['all', 'visible', 'editable', 'selected', 'viewport'].includes(node)){
return this.get(outline, node) }
// groups defaulting to .focused as base...
if(['parent', 'next', 'prev', 'children', 'siblings'].includes(node)){
@ -806,6 +807,11 @@ var Outline = {
[...node.querySelectorAll('.block')]
.filter(function(e){
return e.offsetParent != null })
: offset == 'viewport' ?
[...node.querySelectorAll('.block')]
.filter(function(e){
return e.offsetParent != null
&& e.querySelector('.code').visibleInViewport() })
: offset == 'editable' ?
[...node.querySelectorAll('.block>.code')]
: offset == 'selected' ?
@ -840,13 +846,20 @@ var Outline = {
focus: function(node='focused', offset){
var elem = this.get(...arguments)
?? this.get(0)
elem
&& elem.focus()
if(elem){
elem.focus({preventScroll: true})
;(elem.classList.contains('code') ?
elem
: elem.querySelector('.code'))
.scrollIntoView({
block: 'nearest',
//behavior: 'smooth',
}) }
return elem },
edit: function(node='focused', offset){
var elem = this.get(...arguments)
if(elem.nodeName != 'TEXTAREA'){
elem = elem.querySelector('textarea') }
if(!elem.classList.contains('code')){
elem = elem.querySelector('.code') }
elem?.focus()
return elem },
@ -1027,7 +1040,8 @@ var Outline = {
this.get(elem, 'prev')
: this.get(elem, 'next') }
elem?.remove()
next?.focus()
next
&& this.focus(next)
this.__change__()
return this },
clear: function(){
@ -1042,7 +1056,6 @@ var Outline = {
var stack = this.__crop_stack ??= []
stack.push([this.json(), this.path()])
this.load(this.data())
.focus()
return this },
// XXX use JSON API...
uncrop: function(){
@ -1058,7 +1071,6 @@ var Outline = {
return res[i].children }, state)
.splice(path.at(-1), 1, ...this.json())
this.load(state)
.focus()
return this },
// block render...
@ -1339,6 +1351,8 @@ var Outline = {
// update sizes of all the textareas (transparent)...
for(var e of [...this.outline.querySelectorAll('textarea')]){
e.updateSize() }
// restore focus...
this.focus()
return this },
sync: function(){
@ -1485,7 +1499,6 @@ var Outline = {
this.edit(
this.Block('next')) } },
Enter: function(evt){
var edited = this.get('edited')
// edit -> split text...
if(edited){
@ -1636,6 +1649,20 @@ var Outline = {
if(elem.classList.contains('block')){
elem.querySelector('.code').focus() }
// focus viewport...
// XXX this does not work because by this point there is
// no focused element...
if(elem === outline){
var cur = that.get()
var viewport = that.get('viewport')
if(!viewport.includes(cur)){
var visible = that.get('visible')
var i = visible.indexOf(cur)
var v = visible.indexOf(viewport[0])
i < v ?
that.focus(viewport[0])
: that.focus(viewport.at(-1)) } }
that.runPlugins('__click__', evt, that, elem) })
// keyboard handling...
outline.addEventListener('keydown',
@ -1666,26 +1693,20 @@ var Outline = {
return }
// handle focus...
for(var e of [...that.dom.querySelectorAll('.focused')]){
e.classList.remove('focused') }
that.get('focused')?.classList?.add('focused')
if(elem !== that.outline){
for(var e of [...that.dom.querySelectorAll('.focused')]){
e.classList.remove('focused') }
that.get('focused')?.classList?.add('focused') }
// textarea...
if(elem.classList.contains('code')){
elem.updateSize() }
/*/ scroll...
that.get(node).querySelector('view')
?.scrollIntoView({
block: 'nearest',
behavior: 'smooth',
})
//*/
// XXX do we need this???
that.runPlugins('__focusin__', evt, that, elem) })
outline.addEventListener('focusout',
function(evt){
var elem = evt.target
// update code...
if(elem.classList.contains('code')){
var block = elem.parentElement
// clean out attrs...
@ -1713,7 +1734,7 @@ var Outline = {
focus_textarea = document.activeElement.nodeName == 'TEXTAREA' }
var refocusNode = function(){
focus_textarea ?
editor.get().querySelector('textarea').focus()
editor.get().querySelector('.code').focus()
: editor.focus()
focus_textarea = undefined }
// cache the focused node type before focus changes...

View File

@ -4,6 +4,26 @@
*
**********************************************************************/
Element.prototype.visibleInViewport = function(partial=false){
var { top, left, bottom, right } = this.getBoundingClientRect()
var { innerHeight, innerWidth } = window
return partial
? ((top > 0
&& top < innerHeight)
|| (bottom > 0
&& bottom < innerHeight))
&& ((left > 0
&& left < innerWidth)
|| (right > 0
&& right < innerWidth))
: (top >= 0
&& left >= 0
&& bottom <= innerHeight
&& right <= innerWidth) }
//---------------------------------------------------------------------
HTMLTextAreaElement.prototype.updateSize = function(){
this.style.height = ''
this.style.height = this.scrollHeight + 'px'

View File

@ -46,7 +46,6 @@ var setup = function(){
- ## Bugs:
focused:: true
- BUG: editor: FF seems to update the style every other key press -- should be live...
- BUG: scrolling into view needs tuning...
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
-
- ## ToDo:
@ -318,7 +317,7 @@ var setup = function(){
- Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text
- </textarea>
<!-- outline -->
<div class="outline"></div>
<div class="outline" tabindex="0"></div>
<!-- toolbar (optional) -->
<!--div class="toolbar">
<button onclick="editor.deindent().focus()">&lt;</button>