now DONE/checkboxes can also be undone...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2023-10-26 18:11:12 +03:00
parent 5f69c73954
commit 0125964dd6
2 changed files with 52 additions and 25 deletions

View File

@ -351,7 +351,8 @@ var tasks = {
return elem }, return elem },
updateCheckboxes: function(editor, elem){ updateCheckboxes: function(editor, elem){
elem = this.getCheckbox(editor, elem) elem = this.getCheckbox(editor, elem)
var node = editor.get(elem) var node = editor.get(elem, false)
var data = editor.data(node)
var text = node.querySelector('.code') var text = node.querySelector('.code')
// get the checkbox order... // get the checkbox order...
var i = [...node.querySelectorAll('input[type=checkbox]')].indexOf(elem) var i = [...node.querySelectorAll('input[type=checkbox]')].indexOf(elem)
@ -363,6 +364,12 @@ var tasks = {
to to
: m } : m }
text.value = text.value.replace(/\[[Xx_]\]/g, toggle) text.value = text.value.replace(/\[[Xx_]\]/g, toggle)
// NOTE: status is updated via a timeout set in .__parse__(..)...
editor.setUndo(
editor.path(node),
'update',
[editor.path(node),
data])
return elem }, return elem },
toggleCheckbox: function(editor, checkbox, offset){ toggleCheckbox: function(editor, checkbox, offset){
checkbox = this.getCheckbox(editor, checkbox, offset) checkbox = this.getCheckbox(editor, checkbox, offset)
@ -396,6 +403,7 @@ var tasks = {
var node = editor.get(elem) var node = editor.get(elem)
if(node == null){ if(node == null){
return } return }
var data = editor.data(elem, false)
var text = node.querySelector('.code') var text = node.querySelector('.code')
var value = text.value var value = text.value
var s = text.selectionStart var s = text.selectionStart
@ -413,6 +421,11 @@ var tasks = {
text.selectionStart = s + (value.length - l) text.selectionStart = s + (value.length - l)
text.selectionEnd = e + (value.length - l) text.selectionEnd = e + (value.length - l)
editor.update(node) editor.update(node)
editor.setUndo(
editor.path(node),
'update',
[editor.path(node),
data])
return node }, return node },
__setup__: function(editor){ __setup__: function(editor){
@ -424,8 +437,9 @@ var tasks = {
text = text text = text
.replace(p, handler) } .replace(p, handler) }
return text }, return text },
__update_checkboxes_timeout: undefined,
__parse__: function(text, editor, elem){ __parse__: function(text, editor, elem){
return text var res = text
// block checkboxes... // block checkboxes...
// NOTE: these are separate as we need to align block text // NOTE: these are separate as we need to align block text
// to leading chekbox... // to leading chekbox...
@ -440,7 +454,15 @@ var tasks = {
this.style(editor, elem, 'check', '<input type="checkbox" checked>')) this.style(editor, elem, 'check', '<input type="checkbox" checked>'))
// 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>')
// need to update status...
// XXX not sure if this is a good way to do this...
if(res != text && this.__update_checkboxes_timeout == null){
var that = this
this.__update_checkboxes_timeout = setTimeout(function(){
that.__update_checkboxes_timeout = undefined
that.updateAllStatus(editor) }, 200) }
return res },
__focusin__: function(evt, editor, elem){ __focusin__: function(evt, editor, elem){
elem.classList.contains('block') elem.classList.contains('block')
&& this.selectCheckbox(editor, elem) }, && this.selectCheckbox(editor, elem) },
@ -964,8 +986,14 @@ var Outline = {
// XXX should we call plugin's __change__ live or every second??? // XXX should we call plugin's __change__ live or every second???
__change_timeout: undefined, __change_timeout: undefined,
__change_requested: false, __change_requested: false,
__change__: function(){ __change__: function(options={}){
var that = this var that = this
// handle undo...
options.undo
&& this.setUndo(...options.undo)
// long changes...
this.__change_requested = true this.__change_requested = true
if(this.__change_timeout){ if(this.__change_timeout){
return this } return this }
@ -973,7 +1001,7 @@ var Outline = {
// do the action... // do the action...
if(this.__change_requested){ if(this.__change_requested){
this.sync() this.sync()
this.runPlugins('__change__', that) this.runPlugins('__change__', this)
this.__change_requested = false } this.__change_requested = false }
this.__change_timeout = setTimeout( this.__change_timeout = setTimeout(
@ -989,6 +1017,8 @@ var Outline = {
collapsed: 'attr', collapsed: 'attr',
focused: 'cls', focused: 'cls',
}, },
// NOTE: this does not internally handle undo as it would be too
// granular...
update: function(node='focused', data){ update: function(node='focused', data){
var node = this.get(node) var node = this.get(node)
data ??= this.data(node, false) data ??= this.data(node, false)
@ -1054,23 +1084,21 @@ var Outline = {
parent.after(cur) parent.after(cur)
children.length > 0 children.length > 0
&& cur.lastChild.append(...children) && cur.lastChild.append(...children)
this.setUndo( this.__change__({undo: [
this.path(cur), this.path(cur),
'indent', 'indent',
['in'], ['in'],
prev) prev ]}) }
this.__change__() }
// indent... // indent...
} else { } else {
var parent = siblings[siblings.indexOf(cur) - 1] var parent = siblings[siblings.indexOf(cur) - 1]
if(parent){ if(parent){
parent.lastChild.append(cur) parent.lastChild.append(cur)
this.setUndo( this.__change__({undo: [
this.path(cur), this.path(cur),
'indent', 'indent',
['out'], ['out'],
prev) prev ]})} }
this.__change__()} }
return cur }, return cur },
shift: function(node='focused', direction){ shift: function(node='focused', direction){
if(node == 'up' || node == 'down'){ if(node == 'up' || node == 'down'){
@ -1092,13 +1120,12 @@ var Outline = {
siblings[i+1].after(node) } siblings[i+1].after(node) }
focused focused
&& this.focus() && this.focus()
this.setUndo( this.__change__({undo: [
this.path(node), this.path(node),
'shift', 'shift',
[direction == 'up' ? [direction == 'up' ?
'down' 'down'
: 'up']) : 'up'] ]})
this.__change__()
return this }, return this },
// XXX make undo a bit more refined... // XXX make undo a bit more refined...
remove: function(node='focused'){ remove: function(node='focused'){
@ -1115,20 +1142,19 @@ var Outline = {
elem?.remove() elem?.remove()
next next
&& this.focus(next) && this.focus(next)
// XXX HACK... this.__change__({undo: [
this.setUndo(
undefined, undefined,
'load', 'load',
[data]) // XXX HACK...
this.__change__() [data] ]})
return this }, return this },
clear: function(){ clear: function(){
this.setUndo( var data = this.json()
this.outline.innerText = ''
this.__change__({undo: [
undefined, undefined,
'load', 'load',
[this.json()]) [data] ]})
this.outline.innerText = ''
this.__change__()
return this }, return this },
// expand/collapse... // expand/collapse...
@ -1315,7 +1341,7 @@ var Outline = {
var attrs = this.__block_attrs__ var attrs = this.__block_attrs__
var cls_attrs = ['focused'] var cls_attrs = ['focused']
return { return {
text: elem.querySelector('textarea').value, text: elem.querySelector('.code').value,
...(Object.entries(attrs) ...(Object.entries(attrs)
.reduce(function(res, [attr, type]){ .reduce(function(res, [attr, type]){
if(type == 'attr'){ if(type == 'attr'){

View File

@ -51,8 +51,6 @@ var setup = function(){
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling... - BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
- -
- ## ToDo: - ## ToDo:
- undo: checkboxes and DONE??
_...this should be triggered by text change -- move current implementation to .__editedcode__()??..._
- copy/paste nodes/trees - copy/paste nodes/trees
- FEATURE: read-only mode - FEATURE: read-only mode
- auto-shift done blocks to the end of siblings... (option?) - auto-shift done blocks to the end of siblings... (option?)
@ -106,6 +104,9 @@ var setup = function(){
- empty item height is a bit off... - empty item height is a bit off...
- search? - search?
- _...not sure if search should be internal or external yet..._ - _...not sure if search should be internal or external yet..._
- DONE: undo: checkboxes and DONE??
collapsed:: true
_...this should be triggered by text change -- move current implementation to .__editedcode__()??..._
- DONE undo - DONE undo
- DONE crop: make path clickable - DONE crop: make path clickable
- DONE Q: crop: should we control crop via "crop-in"/"crop-out" instead of crop/uncrop?? - DONE Q: crop: should we control crop via "crop-in"/"crop-out" instead of crop/uncrop??