Compare commits

..

No commits in common. "2fd8fbdbeb308a47cc4426514531a1ba63ab9882" and "0c5c5f2a5f60b1f9d9fe2d841d39d357149bbb49" have entirely different histories.

3 changed files with 54 additions and 114 deletions

View File

@ -1,30 +1,17 @@
:root { :root {
--button-size: 5em;
font-family: sans-serif; font-family: sans-serif;
font-size: 5mm; font-size: 5mm;
} }
.editor { .editor [tabindex] {
display: block;
position: relative; position: relative;
} }
.editor div [tabindex] {
.editor .outline {
display: block;
position: relative;
width: calc(100% - var(--button-size));
}
.editor .outline [tabindex] {
position: relative;
}
.editor .outline div [tabindex] {
margin-left: 2em; margin-left: 2em;
} }
.editor .outline [tabindex]>span, .editor [tabindex]>span,
.editor .outline [tabindex]>textarea { .editor [tabindex]>textarea {
--padding: 0.2em; --padding: 0.2em;
display: block; display: block;
@ -41,61 +28,41 @@
outline: none; outline: none;
border: none; border: none;
} }
.editor .outline [tabindex]>textarea { .editor [tabindex]>textarea {
height: calc(2 * var(--padding) + 1em); height: calc(2 * var(--padding) + 1em);
overflow: hidden; overflow: hidden;
resize: none; resize: none;
} }
/* show/hide node's view/code... */ /* show/hide node's view/code... */
.editor .outline [tabindex]>span+textarea:not(:focus), .editor [tabindex]>span+textarea:not(:focus),
/* XXX not sure how to do this without :has(..)... */ /* XXX not sure how to do this without :has(..)... */
.editor .outline [tabindex]:has(>span+textarea:focus)>span:has(+textarea), .editor [tabindex]:has(>span+textarea:focus)>span:has(+textarea),
.editor .outline [tabindex]:focus>span+textarea { .editor [tabindex]:focus>span+textarea {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
top: 0; top: 0;
} }
/* focus... */ .editor div[collapsed] {
.editor .outline [tabindex]:focus {
/*outline: solid 0.2em silver;*/
outline: none;
}
.editor .outline [tabindex]:focus>span,
.editor .outline [tabindex]:focus>textarea {
background: rgba(0,0,0,0.1);
}
.editor .outline [tabindex].focused:not(:focus)>span,
.editor .outline [tabindex].focused:not(:focus)>textarea {
background: rgba(0,0,0,0.05);
}
.editor .outline div[collapsed] {
border-bottom: solid 1px silver; border-bottom: solid 1px silver;
} }
.editor .outline div[collapsed] div { .editor div[collapsed] div {
display: none; display: none;
} }
/* XXX are we selecting subtrees or blocks??? */ /* XXX are we selecting subtrees or blocks??? */
.editor .outline [selected] { .editor [selected] {
background: silver; background: silver;
} }
.editor div:focus {
.editor .toolbar { /*outline: solid 0.2em silver;*/
display: inline-block; outline: none;
position: absolute;
top: 1em;
right: 1em;
} }
.editor .toolbar button { .editor div:focus>span,
display: block; .editor div:focus>textarea {
width: var(--button-size); background: rgba(0,0,0,0.1);
height: var(--button-size);
} }

View File

@ -121,7 +121,6 @@ var Outline = {
// -> <nodes> // -> <nodes>
// //
// XXX add support for node ID... // XXX add support for node ID...
// XXX need to be able to get the next elem on same level...
get: function(node='focused', offset){ get: function(node='focused', offset){
var that = this var that = this
@ -168,8 +167,7 @@ var Outline = {
this.at(node) this.at(node)
: node == 'focused' ? : node == 'focused' ?
(this.dom.querySelector(`[tabindex]:focus`) (this.dom.querySelector(`[tabindex]:focus`)
|| this.dom.querySelector(`textarea:focus`)?.parentElement || this.dom.querySelector(`textarea:focus`)?.parentElement)
|| this.dom.querySelector('[tabindex].focused'))
: node == 'parent' ? : node == 'parent' ?
this.get('focused')?.parentElement this.get('focused')?.parentElement
: node : node
@ -194,12 +192,6 @@ var Outline = {
return elem.getAttribute('tabindex') != null }) } return elem.getAttribute('tabindex') != null }) }
// offset... // offset...
offset =
offset == 'next' ?
1
: offset == 'prev' ?
-1
: offset
if(typeof(offset) == 'number'){ if(typeof(offset) == 'number'){
nodes = this.get('visible') nodes = this.get('visible')
var i = nodes.indexOf(node) + offset var i = nodes.indexOf(node) + offset
@ -214,8 +206,8 @@ var Outline = {
at: function(index, nodes='visible'){ at: function(index, nodes='visible'){
return this.get(nodes).at(index) }, return this.get(nodes).at(index) },
focus: function(node='focused', offset){}, focus: function(node='focused'){},
edit: function(node='focused', offset){}, edit: function(node='focused'){},
indent: function(node='focused', indent=true){ indent: function(node='focused', indent=true){
// .indent(<indent>) // .indent(<indent>)
@ -229,7 +221,7 @@ var Outline = {
// deindent... // deindent...
if(!indent){ if(!indent){
var parent = cur.parentElement var parent = cur.parentElement
if(!parent.classList.contains('.outline')){ if(!parent.classList.contains('.editor')){
var children = siblings.slice(siblings.indexOf(cur)+1) var children = siblings.slice(siblings.indexOf(cur)+1)
parent.after(cur) parent.after(cur)
children.length > 0 children.length > 0
@ -268,16 +260,9 @@ var Outline = {
elem.updateSize() } } elem.updateSize() } }
return node }, return node },
remove: function(node='focused', offset){ // XXX
var elem = this.get(...arguments) remove: function(node){
var next },
if(elem.classList.contains('focused')){
// XXX need to be able to get the next elem on same level...
this.toggleCollapse(elem)
next = this.get(elem, 'next') }
elem?.remove()
next?.focus()
return this },
// block serialization... // block serialization...
__code2html__: function(code){ __code2html__: function(code){
@ -348,7 +333,7 @@ var Outline = {
// horizontal navigation / collapse... // horizontal navigation / collapse...
// XXX if at start/end of element move to prev/next... // XXX if at start/end of element move to prev/next...
ArrowLeft: function(evt){ ArrowLeft: function(evt){
if(this.dom.querySelector('.outline textarea:focus')){ if(this.dom.querySelector('.editor textarea:focus')){
// XXX if at end of element move to next... // XXX if at end of element move to next...
return } return }
;((this.left_key_collapses ;((this.left_key_collapses
@ -358,7 +343,7 @@ var Outline = {
this.toggleCollapse(true) this.toggleCollapse(true)
: this.get('parent')?.focus() }, : this.get('parent')?.focus() },
ArrowRight: function(evt){ ArrowRight: function(evt){
if(this.dom.querySelector('.outline textarea:focus')){ if(this.dom.querySelector('.editor textarea:focus')){
// XXX if at end of element move to next... // XXX if at end of element move to next...
return } return }
if(this.right_key_expands){ if(this.right_key_expands){
@ -407,7 +392,10 @@ var Outline = {
Delete: function(evt){ Delete: function(evt){
if(evt.target.isContentEditable){ if(evt.target.isContentEditable){
return } return }
this.remove() }, this.toggleCollapse(true)
var next = this.get('next')
this.get()?.remove()
next?.focus() },
// select... // select...
// XXX add: // XXX add:
@ -426,26 +414,20 @@ var Outline = {
setup: function(dom){ setup: function(dom){
var that = this var that = this
this.dom = dom this.dom = dom
var outline = dom.querySelector('.outline')
// update stuff already in DOM... // update stuff already in DOM...
for(var elem of [...outline.querySelectorAll('textarea')]){ for(var elem of [...dom.querySelectorAll('.editor textarea')]){
elem.autoUpdateSize() } elem.autoUpdateSize() }
// heboard handling... // heboard handling...
outline.addEventListener('keydown', dom.addEventListener('keydown',
function(evt){ function(evt){
evt.key in that.keyboard evt.key in that.keyboard
&& that.keyboard[evt.key].call(that, evt) }) && that.keyboard[evt.key].call(that, evt) })
// toggle view/code of nodes... // toggle view/code of nodes...
outline.addEventListener('focusin', dom.addEventListener('focusin',
function(evt){ function(evt){
var node = evt.target var node = evt.target
// handle focus...
for(var e of [...that.dom.querySelectorAll('.focused')]){
e.classList.remove('focused') }
that.get('focused')?.classList?.add('focused')
// textarea...
if(node.nodeName == 'TEXTAREA' if(node.nodeName == 'TEXTAREA'
&& node?.previousElementSibling?.nodeName == 'SPAN'){ && node?.previousElementSibling?.nodeName == 'SPAN'){
node.value = node.value =
@ -453,7 +435,7 @@ var Outline = {
that.__html2code__(node.previousElementSibling.innerHTML) that.__html2code__(node.previousElementSibling.innerHTML)
: node.previousElementSibling.innerHTML : node.previousElementSibling.innerHTML
node.updateSize() } }) node.updateSize() } })
outline.addEventListener('focusout', dom.addEventListener('focusout',
function(evt){ function(evt){
var node = evt.target var node = evt.target
if(node.nodeName == 'TEXTAREA' if(node.nodeName == 'TEXTAREA'

View File

@ -21,7 +21,6 @@ var setup = function(){
</head> </head>
<body onload="setup()"> <body onload="setup()">
<div class="editor"> <div class="editor">
<div class="outline">
<div tabindex=0> <div tabindex=0>
<span><i>root</i></span><textarea></textarea> <span><i>root</i></span><textarea></textarea>
<div tabindex=0 collapsed> <div tabindex=0 collapsed>
@ -48,14 +47,6 @@ var setup = function(){
</div> </div>
</div> </div>
</div> </div>
<div class="toolbar">
<button onclick="editor.deindent()">&lt;</button>
<button onclick="editor.indent()">&gt;</button>
<button onclick="editor.Block('before').focus()">O</button>
<button onclick="editor.Block('after').focus()">o</button>
<button onclick="editor.remove()">&times;</button>
</div>
</div>
<hr> <hr>