added checlbox navigation + refactoring...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-10-18 18:40:04 +03:00
parent a816b62a76
commit ffbc4d5031
3 changed files with 122 additions and 21 deletions

View File

@ -462,6 +462,14 @@ editor .outline .block:focus {
/* NOTE: this appears to be needed for the em sizes above to work correctly */ /* NOTE: this appears to be needed for the em sizes above to work correctly */
font-size: 1em; font-size: 1em;
} }
.editor .outline .block.check.focused>.view input[type=checkbox].selected,
.editor .outline .block.todo.focused>.view input[type=checkbox].selected {
outline: solid 0.2em silver;
}
.editor .outline .block.check:focus>.view input[type=checkbox].selected,
.editor .outline .block.todo:focus>.view input[type=checkbox].selected {
outline: solid 0.2em gray;
}
.editor .outline .block.todo>.view input[type=checkbox]:first-child { .editor .outline .block.todo>.view input[type=checkbox]:first-child {
margin-left: calc( margin-left: calc(
-1 * var(--checkbox-size) -1 * var(--checkbox-size)

View File

@ -199,7 +199,6 @@ var quoted = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX add actions...
var tasks = { var tasks = {
__proto__: plugin, __proto__: plugin,
@ -233,6 +232,89 @@ var tasks = {
this.updateStatus(editor, e) } this.updateStatus(editor, e) }
return this }, return this },
getCheckbox: function(editor, elem, offset=0){
elem = elem
?? editor.get()
if(elem == null
|| (offset == 0
&& elem.type == 'checkbox')){
return elem }
var node = editor.get(elem)
var view = node.querySelector('.view')
var cur = view.querySelector('input[type=checkbox].selected')
?? view.querySelector('input[type=checkbox]')
if(offset == 0 && cur == null){
return}
var checkboxes = [...editor.outline.querySelectorAll('.view input[type=checkbox]')]
if(checkboxes.length == 0){
return }
// no checkbox in node -> get closest to cur in offset direction...
if(cur == null){
var nodes = [...editor.outline.querySelectorAll('.block')]
var checkbox_nodes = checkboxes
.map(function(e){
return editor.get(e) })
var i = nodes.indexOf(node)
var p, n
for(var c of checkbox_nodes){
p = n
var j = nodes.indexOf(c)
if(j >= i){
n = j
break } }
cur = offset < 0 ?
nodes[p]
: nodes[n] }
var elem = cur == null ?
checkboxes.at(
offset > 0 ?
offset -1
: offset)
: checkboxes.at(
(checkboxes.indexOf(cur) + offset) % checkboxes.length)
return elem },
updateCheckbox: function(editor, elem){
elem = this.getCheckbox(editor, elem)
var node = editor.get(elem)
var text = node.querySelector('.code')
// get the checkbox order...
var i = [...node.querySelectorAll('input[type=checkbox]')].indexOf(elem)
var to = elem.checked ?
'[X]'
: '[_]'
var toggle = function(m){
return i-- == 0 ?
to
: m }
text.value = text.value.replace(/\[[Xx_]\]/g, toggle)
return elem },
toggleCheckbox: function(editor, checkbox, offset){
checkbox = this.getCheckbox(editor, checkbox, offset)
if(checkbox){
checkbox.checked = !checkbox.checked
this.updateCheckbox(editor, checkbox) }
return checkbox },
selectCheckbox: function(editor, checkbox, offset){
checkbox = this.getCheckbox(editor, checkbox, offset)
if(checkbox == null){
return }
var checkboxes = editor.get(checkbox)
.querySelector('.view')
.querySelectorAll('input[type=checkbox]')
if(checkboxes.length == 0){
return }
for(var c of checkboxes){
c.classList.remove('selected') }
checkbox.classList.add('selected')
editor.show(checkbox)
return checkbox },
nextCheckbox: function(editor, node='focused', offset=1){
node = this.selectCheckbox(editor, node, offset)
editor.focus(node)
return node },
prevCheckbox: function(editor, node='focused', offset=-1){
return this.nextCheckbox(editor, node, offset) },
__setup__: function(editor){ __setup__: function(editor){
return this.updateAll(editor) }, return this.updateAll(editor) },
__parse__: function(text, editor, elem){ __parse__: function(text, editor, elem){
@ -252,25 +334,20 @@ var tasks = {
// completion... // completion...
// XXX add support for being like a todo checkbox... // XXX add support for being like a todo checkbox...
.replace(/(?<!\\)\[[%]\]/gm, '<span class="completion"></span>') }, .replace(/(?<!\\)\[[%]\]/gm, '<span class="completion"></span>') },
__editedcode__: function(evt, editor, node){ __focusin__: function(evt, editor, elem){
return this.updateBranch(editor, node) }, elem.classList.contains('block')
&& this.selectCheckbox(editor, elem) },
__editedcode__: function(evt, editor, elem){
this.updateBranch(editor, elem)
this.selectCheckbox(editor, elem) },
__click__: function(evt, editor, elem){ __click__: function(evt, editor, elem){
// toggle checkbox... // toggle checkbox...
if(elem.type == 'checkbox'){ if(elem.type == 'checkbox'){
var node = editor.get(elem) var node = editor.get(elem)
var text = node.querySelector('.code') this.updateCheckbox(editor, elem)
// get the checkbox order... this.updateBranch(editor, node)
var i = [...node.querySelectorAll('input[type=checkbox]')].indexOf(elem) this.selectCheckbox(editor, elem)
var to = elem.checked ? node.focus() }
'[X]'
: '[_]'
var toggle = function(m){
return i-- == 0 ?
to
: m }
text.value = text.value.replace(/\[[Xx_]\]/g, toggle)
// update status...
this.updateBranch(editor, node) }
return this }, return this },
} }
@ -992,6 +1069,10 @@ var Outline = {
edited.selectionStart = edited.selectionStart =
edited.selectionEnd = edited.value.length + 1 } edited.selectionEnd = edited.value.length + 1 }
return } return }
if(evt.ctrlKey){
evt.preventDefault()
tasks.prevCheckbox(this)
return }
;((this.left_key_collapses ;((this.left_key_collapses
|| evt.shiftKey) || evt.shiftKey)
&& this.get().getAttribute('collapsed') == null && this.get().getAttribute('collapsed') == null
@ -1009,6 +1090,10 @@ var Outline = {
edited.selectionStart = edited.selectionStart =
edited.selectionEnd = 0 } edited.selectionEnd = 0 }
return } return }
if(evt.ctrlKey){
evt.preventDefault()
tasks.nextCheckbox(this)
return }
if(this.right_key_expands){ if(this.right_key_expands){
this.toggleCollapse(false) this.toggleCollapse(false)
this.focus('next') this.focus('next')
@ -1126,10 +1211,14 @@ var Outline = {
if(this.get('edited') != null){ if(this.get('edited') != null){
return } return }
evt.preventDefault() evt.preventDefault()
tasks.toggleCheckbox(this)
/* XXX selection...
var focused = this.get() var focused = this.get()
focused.getAttribute('selected') != null ? focused.getAttribute('selected') != null ?
focused.removeAttribute('selected') focused.removeAttribute('selected')
: focused.setAttribute('selected', '') }, : focused.setAttribute('selected', '')
//*/
},
}, },
setup: function(dom){ setup: function(dom){

View File

@ -47,10 +47,6 @@ var setup = function(){
- BUG: last node seems to get trash tags added to it's end... - BUG: last node seems to get trash tags added to it's end...
- -
- ## ToDo: - ## ToDo:
- ASAP: checkbox navigation via `alt-<arrow>`
- _might be a good idea to include also TODO/DONE navigation -- not yet sure how to mark undone blocks (i.e. the ones marked with TODO in Logseg)..._
- toggle with `space`
- navigation auto-selects first checkbox
- ASAP: scroll into view is bad... - ASAP: scroll into view is bad...
- ASAP: mobile browsers behave quite chaotically ignoring parts of the styling... - ASAP: mobile browsers behave quite chaotically ignoring parts of the styling...
- ASAP: need to reach checkboxes via keyboard - ASAP: need to reach checkboxes via keyboard
@ -110,6 +106,11 @@ var setup = function(){
block text block text
- NOTE: this is only a problem if making list-items manually -- disable??? - NOTE: this is only a problem if making list-items manually -- disable???
- empty item height is a bit off... - empty item height is a bit off...
- DONE checkbox navigation via `alt-<arrow>`
collapsed:: true
- _might be a good idea to include also TODO/DONE navigation -- not yet sure how to mark undone blocks (i.e. the ones marked with TODO in Logseg)..._
- toggle with `space`
- navigation auto-selects first checkbox
- DONE editor: backsapce/del at start/end of a block should join it with prev/next - DONE editor: backsapce/del at start/end of a block should join it with prev/next
- DONE editor: pressing enter in text edit mode should split text into two blocks - DONE editor: pressing enter in text edit mode should split text into two blocks
- DONE editor: shifting nodes up/down - DONE editor: shifting nodes up/down
@ -166,6 +167,9 @@ var setup = function(){
| s-pgdown | shift node down | | s-pgdown | shift node down |
| s-left | collapse node | | s-left | collapse node |
| s-right | expand node | | s-right | expand node |
| c-left | prev checkbox |
| c-right | next checkbox |
| space | toggle current checkbox |
| enter | normal mode: edit node | | enter | normal mode: edit node |
| | edit mode: create node below | | | edit mode: create node below |
| esc | exit edit mode | | esc | exit edit mode |