mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-29 01:50:07 +00:00
refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
71cb3f1f97
commit
9eddf696c4
@ -29,7 +29,7 @@
|
||||
/*text-size-adjust: none;*/
|
||||
text-size-adjust: 150%;
|
||||
|
||||
/*scroll-behavior: smooth;*/
|
||||
|
||||
}
|
||||
|
||||
.editor {
|
||||
@ -49,6 +49,9 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editor .children {
|
||||
}
|
||||
|
||||
.editor .outline {
|
||||
display: block;
|
||||
position: relative;
|
||||
@ -60,19 +63,18 @@
|
||||
padding-right: var(--outline-padding);
|
||||
}
|
||||
|
||||
.editor .outline [tabindex] {
|
||||
.editor .outline .block {
|
||||
position: relative;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
.editor .outline [tabindex] [tabindex] {
|
||||
.editor .outline .block .block {
|
||||
margin-left: var(--item-indent);
|
||||
}
|
||||
.editor .outline [tabindex]>span,
|
||||
.editor .outline [tabindex]>textarea {
|
||||
.editor .outline .block>.text {
|
||||
display: block;
|
||||
width: 100%;
|
||||
/* XXX this is a tiny bit off and using textarea's height here is off too... */
|
||||
/* XXX this is a tiny bit off and using .code's height here is off too... */
|
||||
min-height: calc(1em + var(--item-padding) * 2);
|
||||
padding-top: var(--item-padding);
|
||||
padding-bottom: var(--item-padding);
|
||||
@ -89,60 +91,58 @@
|
||||
border: none;
|
||||
}
|
||||
/* show/hide node's view/code... */
|
||||
/*.editor .outline [tabindex]>textarea:focus+span,*/
|
||||
.editor .outline [tabindex]>textarea:not(:focus) {
|
||||
/*.editor .outline .block>.code:focus+.view,*/
|
||||
.editor .outline .block>.code:not(:focus) {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
/* hide span content but show before/after -- keep bulets and touch zones... */
|
||||
.editor .outline [tabindex]>textarea:focus+span {
|
||||
/* hide .view content but show before/after -- keep bulets and touch zones... */
|
||||
.editor .outline .block>.code:focus+.view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.editor .outline [tabindex]>textarea:focus+span:before,
|
||||
.editor .outline [tabindex]>textarea:focus+span:after {
|
||||
.editor .outline .block>.code:focus+.view:before,
|
||||
.editor .outline .block>.code:focus+.view:after {
|
||||
visibility: visible;
|
||||
}
|
||||
/* click through the span text to the textarea */
|
||||
.editor .outline [tabindex]>span {
|
||||
/* click through the .view text to the .code */
|
||||
.editor .outline .block>.view {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* block hover... */
|
||||
.editor .outline [tabindex]:hover>span {
|
||||
.editor .outline .block:hover>.view {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(0,0,0,0.01) 0%,
|
||||
rgba(0,0,0,0.01) 80%,
|
||||
rgba(0,0,0,0.03) 100%);
|
||||
}
|
||||
.editor .outline [tabindex]>span:blank {
|
||||
.editor .outline .block>.view:blank {
|
||||
content: " ";
|
||||
}
|
||||
.editor .outline [tabindex]>textarea {
|
||||
.editor .outline .block>.code {
|
||||
height: calc(2 * var(--item-padding) + 1em);
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
/* clickable things in view */
|
||||
.editor .outline [tabindex]>span a,
|
||||
.editor .outline [tabindex]>span input {
|
||||
.editor .outline .block>.view a,
|
||||
.editor .outline .block>.view input {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
|
||||
/* focus... */
|
||||
editor .outline [tabindex]:focus {
|
||||
editor .outline .block:focus {
|
||||
/*outline: solid 0.2em silver;*/
|
||||
outline: none;
|
||||
}
|
||||
.editor .outline [tabindex]:focus>span,
|
||||
.editor .outline [tabindex]:focus>textarea {
|
||||
.editor .outline .block:focus>.text {
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
.editor .outline [tabindex].focused:not(:focus)>span,
|
||||
.editor .outline [tabindex].focused:not(:focus)>textarea {
|
||||
.editor .outline .block.focused:not(:focus)>.text {
|
||||
background: rgba(0,0,0,0.01);
|
||||
}
|
||||
|
||||
@ -151,8 +151,8 @@ editor .outline [tabindex]:focus {
|
||||
}
|
||||
|
||||
/* click/tap zones for expand button... */
|
||||
.editor .outline [tabindex]>span:before,
|
||||
.editor .outline [tabindex]>span:after {
|
||||
.editor .outline .block>.view:before,
|
||||
.editor .outline .block>.view:after {
|
||||
--size: 3rem;
|
||||
|
||||
content: "";
|
||||
@ -185,23 +185,23 @@ editor .outline [tabindex]:focus {
|
||||
background: transparent;
|
||||
}
|
||||
/* left indicator */
|
||||
.editor .outline [tabindex]>span:before {
|
||||
.editor .outline .block>.view:before {
|
||||
justify-content: right;
|
||||
left: calc(-1 * var(--size));
|
||||
}
|
||||
/* right indicator (collapse/expand) */
|
||||
.editor .outline [tabindex]>span:after {
|
||||
.editor .outline .block>.view:after {
|
||||
color: silver;
|
||||
}
|
||||
.editor .outline [tabindex]:has([tabindex])>span:after {
|
||||
.editor .outline .block:has(.block)>.view:after {
|
||||
content: "○";
|
||||
}
|
||||
.editor .outline [tabindex][collapsed]>span:after {
|
||||
.editor .outline .block[collapsed]>.view:after {
|
||||
content: "●";
|
||||
}
|
||||
|
||||
/* collapse -- hide children... */
|
||||
.editor .outline [tabindex][collapsed] [tabindex] {
|
||||
.editor .outline .block[collapsed] .block {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -242,58 +242,42 @@ editor .outline [tabindex]:focus {
|
||||
.editor .outline .heading-6 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.editor .outline .heading-1>span,
|
||||
.editor .outline .heading-1>textarea,
|
||||
.editor .outline .heading-2>span,
|
||||
.editor .outline .heading-2>textarea,
|
||||
.editor .outline .heading-3>span,
|
||||
.editor .outline .heading-3>textarea,
|
||||
.editor .outline .heading-4>span,
|
||||
.editor .outline .heading-4>textarea,
|
||||
.editor .outline .heading-5>span,
|
||||
.editor .outline .heading-5>textarea,
|
||||
.editor .outline .heading-6>span,
|
||||
.editor .outline .heading-6>textarea {
|
||||
.editor .outline .heading-1>.text,
|
||||
.editor .outline .heading-2>.text,
|
||||
.editor .outline .heading-3>.text,
|
||||
.editor .outline .heading-4>.text,
|
||||
.editor .outline .heading-5>.text,
|
||||
.editor .outline .heading-6>.text {
|
||||
font-weight: bold;
|
||||
}
|
||||
.editor .outline .heading-1>span,
|
||||
.editor .outline .heading-1>textarea,
|
||||
.editor .outline .heading-2>span,
|
||||
.editor .outline .heading-2>textarea,
|
||||
.editor .outline .heading-3>span,
|
||||
.editor .outline .heading-3>textarea {
|
||||
.editor .outline .heading-1>.text,
|
||||
.editor .outline .heading-2>.text,
|
||||
.editor .outline .heading-3>.text {
|
||||
border-bottom: solid 1px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.editor .outline .heading-1>span,
|
||||
.editor .outline .heading-1>textarea {
|
||||
.editor .outline .heading-1>.text {
|
||||
--font-size: 2.5em;
|
||||
}
|
||||
.editor .outline .heading-2>span,
|
||||
.editor .outline .heading-2>textarea {
|
||||
.editor .outline .heading-2>.text {
|
||||
--font-size: 1.9em;
|
||||
}
|
||||
.editor .outline .heading-3>span,
|
||||
.editor .outline .heading-3>textarea {
|
||||
.editor .outline .heading-3>.text {
|
||||
--font-size: 1.5em;
|
||||
}
|
||||
.editor .outline .heading-4>span,
|
||||
.editor .outline .heading-4>textarea {
|
||||
.editor .outline .heading-4>.text {
|
||||
--font-size: 1.3em;
|
||||
}
|
||||
.editor .outline .heading-5>span,
|
||||
.editor .outline .heading-5>textarea {
|
||||
.editor .outline .heading-5>.text {
|
||||
--font-size: 1.1em;
|
||||
}
|
||||
.editor .outline .heading-6>span,
|
||||
.editor .outline .heading-6>textarea {
|
||||
.editor .outline .heading-6>.text {
|
||||
--font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Quote... */
|
||||
.editor .outline .quote>span,
|
||||
.editor .outline .quote>textarea {
|
||||
.editor .outline .quote>.text {
|
||||
--indent: 1rem;
|
||||
--margin: 0.7rem;
|
||||
--item-padding-ratio: 0.7;
|
||||
@ -315,33 +299,66 @@ editor .outline [tabindex]:focus {
|
||||
|
||||
|
||||
/* List... */
|
||||
/* XXX needs to be in the middle of the first span but with universal size... */
|
||||
.editor .outline .list-item>span:before,
|
||||
.editor .outline .list>[tabindex]>span:not(:empty):before {
|
||||
/* XXX needs to be in the middle of the first .view but with universal size... */
|
||||
.editor .outline .list-item>.view:before,
|
||||
.editor .outline .list>.children>.block>.view:not(:empty):before {
|
||||
content: "◼";
|
||||
color: gray;
|
||||
}
|
||||
.editor .outline .list>.list>[tabindex]>span:not(:empty):before {
|
||||
.editor .outline
|
||||
.list>.children
|
||||
>.list>.children>.block>.view:not(:empty):before {
|
||||
content: "●";
|
||||
}
|
||||
.editor .outline .list>.list>.list>[tabindex]>span:not(:empty):before {
|
||||
.editor .outline
|
||||
.list>.children
|
||||
>.list>.children
|
||||
>.list>.children>.block>.view:not(:empty):before {
|
||||
content: "○";
|
||||
}
|
||||
.editor .outline .list>.list>.list>.list>[tabindex]>span:not(:empty):before {
|
||||
.editor .outline
|
||||
.list>.children
|
||||
>.list>.children
|
||||
>.list>.children
|
||||
>.list>.children>.block>.view:not(:empty):before {
|
||||
content: "▪";
|
||||
}
|
||||
|
||||
|
||||
/* List... */
|
||||
/* XXX nested lists are broken -- seems that I need a container for the children... */
|
||||
.editor .outline .numbered-list {
|
||||
.editor .outline .numbered-list>.children {
|
||||
counter-reset: numbered-list;
|
||||
}
|
||||
.editor .outline .numbered-list>[tabindex]>span:not(:empty):before {
|
||||
.editor .outline .numbered-list>.children>.block>.view:not(:empty):before {
|
||||
counter-increment: numbered-list;
|
||||
content: counter(numbered-list) ".";
|
||||
color: gray;
|
||||
}
|
||||
.editor .outline
|
||||
.numbered-list>.children
|
||||
>.numbered-list>.children>.block>.view:not(:empty):before {
|
||||
counter-increment: numbered-list;
|
||||
content: counter(numbered-list, lower-alpha) ".";
|
||||
color: gray;
|
||||
}
|
||||
.editor .outline
|
||||
.numbered-list>.children
|
||||
>.numbered-list>.children
|
||||
>.numbered-list>.children>.block>.view:not(:empty):before {
|
||||
counter-increment: numbered-list;
|
||||
content: counter(numbered-list, lower-roman) ".";
|
||||
color: gray;
|
||||
}
|
||||
.editor .outline
|
||||
.numbered-list>.children
|
||||
>.numbered-list>.children
|
||||
>.numbered-list>.children
|
||||
>.numbered-list>.children>.block>.view:not(:empty):before {
|
||||
counter-increment: numbered-list;
|
||||
content: counters(numbered-list, ".") ".";
|
||||
color: gray;
|
||||
}
|
||||
|
||||
|
||||
/* Notes... */
|
||||
@ -356,20 +373,20 @@ editor .outline [tabindex]:focus {
|
||||
background: rgba(0,0,0,0.05);
|
||||
}
|
||||
/* XXX this prevents it from being accesible via click/tap... */
|
||||
.editor .outline .NOTE>span:empty {
|
||||
.editor .outline .NOTE>.view:empty {
|
||||
display: none;
|
||||
}
|
||||
.editor .outline .NOTE>span:empty ~ [tabindex] {
|
||||
.editor .outline .NOTE>.view:empty ~ .block {
|
||||
/* XXX calculate this... */
|
||||
margin-left: 1em;
|
||||
}
|
||||
.editor .outline .NOTE>span:before {
|
||||
.editor .outline .NOTE>.view:before {
|
||||
content: "" !important;
|
||||
}
|
||||
/* correct the right click zone... */
|
||||
/* XXX need to account for nesting... (???) */
|
||||
.editor .outline [tabindex].NOTE>span:after,
|
||||
.editor .outline [tabindex].NOTE [tabindex]>span:after {
|
||||
.editor .outline .block.NOTE>.view:after,
|
||||
.editor .outline .block.NOTE .block>.view:after {
|
||||
margin-right: calc(-1 * var(--padding-h));
|
||||
}
|
||||
|
||||
@ -379,7 +396,7 @@ editor .outline [tabindex]:focus {
|
||||
font-weight: bold;
|
||||
background: yellow;
|
||||
}
|
||||
.editor .outline .XXX>span {
|
||||
.editor .outline .XXX>.view {
|
||||
background: yellow;
|
||||
}
|
||||
|
||||
@ -388,13 +405,13 @@ editor .outline [tabindex]:focus {
|
||||
.editor.hide-comments .outline .comment {
|
||||
display: none;
|
||||
}
|
||||
.editor .outline .comment>span {
|
||||
.editor .outline .comment>.view {
|
||||
color: silver;
|
||||
}
|
||||
|
||||
|
||||
/* Checkboxes... */
|
||||
.editor .outline [tabindex].todo>span {
|
||||
.editor .outline .block.todo>.view {
|
||||
width: calc(
|
||||
100%
|
||||
- var(--checkbox-size)
|
||||
@ -403,8 +420,8 @@ editor .outline [tabindex]:focus {
|
||||
var(--checkbox-size)
|
||||
+ var(--checkbox-margin));
|
||||
}
|
||||
.editor .outline [tabindex].check>span input[type=checkbox],
|
||||
.editor .outline [tabindex].todo>span input[type=checkbox] {
|
||||
.editor .outline .block.check>.view input[type=checkbox],
|
||||
.editor .outline .block.todo>.view input[type=checkbox] {
|
||||
height: var(--checkbox-size);
|
||||
width: var(--checkbox-size);
|
||||
|
||||
@ -417,13 +434,13 @@ editor .outline [tabindex]:focus {
|
||||
/* NOTE: this appears to be needed for the em sizes above to work correctly */
|
||||
font-size: 1em;
|
||||
}
|
||||
.editor .outline [tabindex].todo>span input[type=checkbox]:first-child {
|
||||
.editor .outline .block.todo>.view input[type=checkbox]:first-child {
|
||||
margin-left: calc(
|
||||
-1 * var(--checkbox-size)
|
||||
- var(--checkbox-margin));
|
||||
}
|
||||
/* correct the left click zone... */
|
||||
.editor .outline [tabindex].todo>span:before {
|
||||
.editor .outline .block.todo>.view:before {
|
||||
margin-left: calc(
|
||||
-1 * var(--checkbox-size)
|
||||
- var(--checkbox-margin));
|
||||
@ -431,7 +448,7 @@ editor .outline [tabindex]:focus {
|
||||
|
||||
|
||||
/* code... */
|
||||
.editor .outline [tabindex]>span code {
|
||||
.editor .outline .block>.view code {
|
||||
padding: 0.1em 0.3em;
|
||||
font-family: monospace;
|
||||
background: rgba(0,0,0,0.07);
|
||||
@ -440,19 +457,19 @@ editor .outline [tabindex]:focus {
|
||||
|
||||
|
||||
/* Tables... */
|
||||
.editor .outline [tabindex]>span>table {
|
||||
.editor .outline .block>.view>table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.editor .outline [tabindex]>span>table tr:nth-child(odd) {
|
||||
.editor .outline .block>.view>table tr:nth-child(odd) {
|
||||
background: rgba(0,0,0,0.03);
|
||||
}
|
||||
.editor .outline [tabindex]>span>table tr:first-child {
|
||||
.editor .outline .block>.view>table tr:first-child {
|
||||
font-weight: bold;
|
||||
border-bottom: solid 0.1rem silver;
|
||||
background: transparent;
|
||||
}
|
||||
.editor .outline [tabindex]>span>table td {
|
||||
.editor .outline .block>.view>table td {
|
||||
height: calc(1em + var(--item-padding) * 2);
|
||||
padding: 0 1em;
|
||||
/*text-align: center;*/
|
||||
@ -461,13 +478,13 @@ editor .outline [tabindex]:focus {
|
||||
|
||||
/********************************************************* Testing ***/
|
||||
|
||||
.editor.show-click-zones .outline [tabindex]>span:before,
|
||||
.editor.show-click-zones .outline [tabindex]>span:after {
|
||||
.editor.show-click-zones .outline .block>.view:before,
|
||||
.editor.show-click-zones .outline .block>.view:after {
|
||||
background: rgba(0,0,0,0.03);
|
||||
border: solid 1px silver;
|
||||
}
|
||||
.editor.show-click-zones .outline [tabindex]:hover>span:before,
|
||||
.editor.show-click-zones .outline [tabindex]:hover>span:after {
|
||||
.editor.show-click-zones .outline .block:hover>.view:before,
|
||||
.editor.show-click-zones .outline .block:hover>.view:after {
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
@ -82,6 +82,111 @@ var Outline = {
|
||||
//
|
||||
// XXX add support for node ID...
|
||||
// XXX need to be able to get the next elem on same level...
|
||||
get: function(node='focused', offset){
|
||||
var that = this
|
||||
offset =
|
||||
offset == 'next' ?
|
||||
1
|
||||
: offset == 'prev' ?
|
||||
-1
|
||||
: offset
|
||||
var outline = this.outline
|
||||
|
||||
// root nodes...
|
||||
if(node == 'top'){
|
||||
return [...outline.children] }
|
||||
// groups defaulting to .outline as base...
|
||||
if(['all', 'visible', 'editable', 'selected'].includes(node)){
|
||||
return this.get(outline, node) }
|
||||
// groups defaulting to .focused as base...
|
||||
if(['parent', 'next', 'prev', 'children', 'siblings'].includes(node)){
|
||||
return this.get('focused', node) }
|
||||
|
||||
// helpers...
|
||||
var parent = function(node){
|
||||
return node === outline ?
|
||||
node
|
||||
: node?.parentElement?.parentElement }
|
||||
var children = function(node){
|
||||
return node === outline ?
|
||||
[...node.children]
|
||||
: [...node?.lastChild?.children] }
|
||||
|
||||
// single base node...
|
||||
var edited
|
||||
;[node, edited] =
|
||||
typeof(node) == 'number' ?
|
||||
[this.get('visible').at(node),
|
||||
edited]
|
||||
: (node == 'outline' || node == 'root') ?
|
||||
[outline, edited]
|
||||
: node == 'focused' ?
|
||||
[outline.querySelector(`.block:focus`)
|
||||
|| outline.querySelector(`.code:focus`)
|
||||
|| outline.querySelector('.block.focused'),
|
||||
edited]
|
||||
: node == 'edited' ?
|
||||
[outline.querySelector(`.code:focus`),
|
||||
outline.querySelector(`.code:focus`)]
|
||||
: [node , edited]
|
||||
|
||||
// get the .block...
|
||||
if(node instanceof HTMLElement){
|
||||
while(node !== outline
|
||||
&& !node.classList.contains('block')){
|
||||
node = node.parentElement } }
|
||||
|
||||
// no reference node...
|
||||
if(node == null
|
||||
|| typeof(node) == 'string'){
|
||||
return undefined }
|
||||
|
||||
// parent...
|
||||
if(offset == 'parent'){
|
||||
return edited ?
|
||||
parent(node).querySelector('.code')
|
||||
: parent(node) }
|
||||
|
||||
// node groups...
|
||||
var nodes =
|
||||
typeof(offset) == 'number' ?
|
||||
this.get('visible')
|
||||
: offset == 'all' ?
|
||||
[...node.querySelectorAll('.block')]
|
||||
: offset == 'visible' ?
|
||||
[...node.querySelectorAll('.block')]
|
||||
.filter(function(e){
|
||||
return e.offsetParent != null })
|
||||
: offset == 'editable' ?
|
||||
[...node.querySelectorAll('.block>.code')]
|
||||
: offset == 'selected' ?
|
||||
[...node.querySelectorAll('.block[selected]')]
|
||||
.filter(function(e){
|
||||
return e.offsetParent != null })
|
||||
: offset == 'children' ?
|
||||
children(node)
|
||||
: offset == 'siblings' ?
|
||||
children(parent(node))
|
||||
: undefined
|
||||
|
||||
// get node by offset...
|
||||
if(typeof(offset) == 'number'){
|
||||
node = nodes.at(nodes.indexOf(node) + offset)
|
||||
?? nodes[0]
|
||||
edited = edited ?
|
||||
node.querySelector('.code')
|
||||
: edited
|
||||
nodes = undefined }
|
||||
|
||||
return nodes !== undefined ?
|
||||
edited ?
|
||||
nodes
|
||||
.map(function(){
|
||||
return node.querySelector('.code') })
|
||||
: nodes
|
||||
: (edited
|
||||
?? node) },
|
||||
/*/
|
||||
get: function(node='focused', offset){
|
||||
var that = this
|
||||
|
||||
@ -93,10 +198,15 @@ var Outline = {
|
||||
|
||||
var outline = this.outline
|
||||
|
||||
var parent = function(node){
|
||||
return node?.parentElement?.parentElement }
|
||||
var children = function(node){
|
||||
return [...node?.lastChild?.children] }
|
||||
|
||||
// get parent node...
|
||||
if(node instanceof HTMLElement){
|
||||
while(!node.getAttribute('tabindex')){
|
||||
node = node.parentElement
|
||||
while(!node.classList.contains('block')){
|
||||
node = node.parentElement
|
||||
if(node === this.outline){
|
||||
return undefined } } }
|
||||
|
||||
@ -104,15 +214,15 @@ var Outline = {
|
||||
var NO_NODES = {}
|
||||
var nodes =
|
||||
node == 'all' ?
|
||||
[...outline.querySelectorAll('[tabindex]')]
|
||||
[...outline.querySelectorAll('.block')]
|
||||
: node == 'visible' ?
|
||||
[...outline.querySelectorAll('[tabindex]')]
|
||||
[...outline.querySelectorAll('.block')]
|
||||
.filter(function(e){
|
||||
return e.offsetParent != null })
|
||||
: node == 'editable' ?
|
||||
[...outline.querySelectorAll('[tabindex]>textarea')]
|
||||
[...outline.querySelectorAll('.block>textarea')]
|
||||
: node == 'selected' ?
|
||||
[...outline.querySelectorAll('[tabindex][selected]')]
|
||||
[...outline.querySelectorAll('.block[selected]')]
|
||||
: node == 'top' ?
|
||||
[...outline.children]
|
||||
.filter(function(elem){
|
||||
@ -136,11 +246,11 @@ var Outline = {
|
||||
typeof(node) == 'number' ?
|
||||
this.at(node)
|
||||
: node == 'focused' ?
|
||||
(outline.querySelector(`[tabindex]:focus`)
|
||||
(outline.querySelector(`.block:focus`)
|
||||
|| outline.querySelector(`textarea:focus`)?.parentElement
|
||||
|| outline.querySelector('[tabindex].focused'))
|
||||
|| outline.querySelector('.block.focused'))
|
||||
: node == 'parent' ?
|
||||
this.get('focused')?.parentElement
|
||||
parent(this.get('focused'))
|
||||
: node
|
||||
var edited
|
||||
if(node == 'edited'){
|
||||
@ -152,15 +262,11 @@ var Outline = {
|
||||
|
||||
// children...
|
||||
if(offset == 'children'){
|
||||
return [...node.children]
|
||||
.filter(function(elem){
|
||||
return elem.getAttribute('tabindex') != null }) }
|
||||
return children(node) }
|
||||
|
||||
// siblings...
|
||||
if(offset == 'siblings'){
|
||||
return [...node.parentElement.children]
|
||||
.filter(function(elem){
|
||||
return elem.getAttribute('tabindex') != null }) }
|
||||
return children(parent(node)) }
|
||||
|
||||
// offset...
|
||||
offset =
|
||||
@ -177,9 +283,10 @@ var Outline = {
|
||||
: i % nodes.length
|
||||
node = nodes[i]
|
||||
edited = edited
|
||||
&& node.querySelector('textarea') }
|
||||
&& node.querySelector('.code') }
|
||||
return edited
|
||||
|| node },
|
||||
//*/
|
||||
at: function(index, nodes='visible'){
|
||||
return this.get(nodes).at(index) },
|
||||
focus: function(node='focused', offset){
|
||||
@ -229,20 +336,30 @@ var Outline = {
|
||||
var siblings = this.get(node, 'siblings')
|
||||
// deindent...
|
||||
if(!indent){
|
||||
var parent = cur.parentElement
|
||||
var parent = this.get(node, 'parent')
|
||||
if(!parent.classList.contains('.outline')){
|
||||
var children = siblings.slice(siblings.indexOf(cur)+1)
|
||||
var children = siblings
|
||||
.slice(siblings.indexOf(cur)+1)
|
||||
parent.after(cur)
|
||||
children.length > 0
|
||||
&& cur.append(...children) }
|
||||
&& cur.lastChild.append(...children) }
|
||||
// indent...
|
||||
} else {
|
||||
var parent = siblings[siblings.indexOf(cur) - 1]
|
||||
if(parent){
|
||||
parent.append(cur) } }
|
||||
parent.lastChild.append(cur) } }
|
||||
return cur },
|
||||
deindent: function(node='focused', indent=false){
|
||||
return this.indent(node, indent) },
|
||||
show: function(node='focused', offset){
|
||||
var node = this.get(...arguments)
|
||||
var outline = this.outline
|
||||
var parent = node
|
||||
do{
|
||||
parent = parent.parentElement
|
||||
parent.removeAttribute('collapsed')
|
||||
} while(parent !== outline)
|
||||
return node },
|
||||
toggleCollapse: function(node='focused', state='next'){
|
||||
var that = this
|
||||
if(node == 'all'){
|
||||
@ -256,7 +373,7 @@ var Outline = {
|
||||
node = this.get(node)
|
||||
if(!node
|
||||
// only nodes with children can be collapsed...
|
||||
|| !node.querySelector('[tabindex]')){
|
||||
|| !node.querySelector('.block')){
|
||||
return }
|
||||
state = state == 'next' ?
|
||||
node.getAttribute('collapsed') != ''
|
||||
@ -417,12 +534,9 @@ var Outline = {
|
||||
json: function(node){
|
||||
var that = this
|
||||
node ??= this.outline
|
||||
return [...node.children]
|
||||
return [...node.lastChild.children]
|
||||
.map(function(elem){
|
||||
return elem.nodeName != 'DIV' ?
|
||||
[]
|
||||
: [that.data(elem)] })
|
||||
.flat() },
|
||||
return that.data(elem) }) },
|
||||
// XXX add option to customize indent size...
|
||||
text: function(node, indent, level){
|
||||
// .text(<indent>, <level>)
|
||||
@ -489,16 +603,29 @@ var Outline = {
|
||||
// XXX should this handle children???
|
||||
// XXX revise name...
|
||||
Block: function(data={}, place=null){
|
||||
var that = this
|
||||
if(typeof(data) != 'object'){
|
||||
place = data
|
||||
data = {} }
|
||||
|
||||
// block...
|
||||
var block = document.createElement('div')
|
||||
block.classList.add('block')
|
||||
block.setAttribute('tabindex', '0')
|
||||
var text = document.createElement('textarea')
|
||||
// code...
|
||||
var code = document.createElement('textarea')
|
||||
.autoUpdateSize()
|
||||
code.classList.add('code', 'text')
|
||||
// view...
|
||||
var html = document.createElement('span')
|
||||
block.append(text, html)
|
||||
html.classList.add('view', 'text')
|
||||
// children...
|
||||
var children = document.createElement('div')
|
||||
children.classList.add('children')
|
||||
children.setAttribute('tabindex', '-1')
|
||||
block.append(code, html, children)
|
||||
this.update(block, data)
|
||||
|
||||
// place...
|
||||
var cur = this.get()
|
||||
if(place && cur){
|
||||
@ -506,7 +633,7 @@ var Outline = {
|
||||
'before'
|
||||
: place
|
||||
;(place == 'next'
|
||||
&& (cur.querySelector('[tabindex]')
|
||||
&& (cur.querySelector('.block')
|
||||
|| cur.nextElementSibling)) ?
|
||||
this.get(place).before(block)
|
||||
: (place == 'next'
|
||||
@ -527,7 +654,8 @@ var Outline = {
|
||||
.map(function(data){
|
||||
var elem = that.Block(data)
|
||||
if((data.children || []).length > 0){
|
||||
elem.append(...level(data.children)) }
|
||||
elem.lastChild
|
||||
.append(...level(data.children)) }
|
||||
return elem }) }
|
||||
this
|
||||
.clear()
|
||||
@ -616,19 +744,19 @@ var Outline = {
|
||||
return }
|
||||
if(this.right_key_expands){
|
||||
this.toggleCollapse(false)
|
||||
var child = this.focus('children')[0]
|
||||
if(!child){
|
||||
this.focus('next') }
|
||||
this.focus('next')
|
||||
} else {
|
||||
evt.shiftKey ?
|
||||
this.toggleCollapse(false)
|
||||
: this.get('children')[0]?.focus() } },
|
||||
: this.focus('next') } },
|
||||
|
||||
// indent...
|
||||
Tab: function(evt){
|
||||
evt.preventDefault()
|
||||
var edited = this.get('edited')
|
||||
var node = this.indent(!evt.shiftKey)
|
||||
var node = this.show(
|
||||
this.indent(!evt.shiftKey))
|
||||
// keep focus in node...
|
||||
;(edited ?
|
||||
edited
|
||||
: node)?.focus() },
|
||||
@ -698,8 +826,11 @@ var Outline = {
|
||||
function(evt){
|
||||
var elem = evt.target
|
||||
|
||||
if(elem.classList.contains('children')){
|
||||
return }
|
||||
|
||||
// expand/collapse
|
||||
if(elem.nodeName == 'SPAN'
|
||||
if(elem.classList.contains('view')
|
||||
&& elem.parentElement.getAttribute('tabindex')){
|
||||
// click: left of elem (outside)
|
||||
if(evt.offsetX < 0){
|
||||
@ -718,12 +849,12 @@ var Outline = {
|
||||
// NOTE: this is usefull if element text is hidden but the
|
||||
// frame is still visible...
|
||||
if(elem.getAttribute('tabindex')){
|
||||
elem.querySelector('textarea').focus() }
|
||||
elem.querySelector('.code').focus() }
|
||||
|
||||
// toggle checkbox...
|
||||
if(elem.type == 'checkbox'){
|
||||
var node = that.get(elem)
|
||||
var text = node.querySelector('textarea')
|
||||
var text = node.querySelector('.code')
|
||||
// get the checkbox order...
|
||||
var i = [...node.querySelectorAll('input[type=checkbox]')].indexOf(elem)
|
||||
var to = elem.checked ?
|
||||
@ -749,25 +880,27 @@ var Outline = {
|
||||
// toggle view/code of nodes...
|
||||
outline.addEventListener('focusin',
|
||||
function(evt){
|
||||
var node = evt.target
|
||||
// scroll...
|
||||
// XXX a bit odd still and not smooth...
|
||||
;((node.nodeName == 'SPAN'
|
||||
|| node.nodeName == 'TEXTAREA') ?
|
||||
node
|
||||
: node.querySelector('textarea+span'))
|
||||
?.scrollIntoView({
|
||||
block: 'nearest',
|
||||
behavior: 'smooth',
|
||||
})
|
||||
var elem = evt.target
|
||||
|
||||
if(elem.classList.contains('children')){
|
||||
return }
|
||||
|
||||
// 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'
|
||||
&& node?.nextElementSibling?.nodeName == 'SPAN'){
|
||||
node.updateSize() } })
|
||||
if(elem.classList.contains('code')){
|
||||
elem.updateSize() }
|
||||
|
||||
/*/ scroll...
|
||||
that.get(node).querySelector('view')
|
||||
?.scrollIntoView({
|
||||
block: 'nearest',
|
||||
behavior: 'smooth',
|
||||
})
|
||||
//*/
|
||||
})
|
||||
outline.addEventListener('focusout',
|
||||
function(evt){
|
||||
var node = evt.target
|
||||
@ -809,9 +942,11 @@ var Outline = {
|
||||
// code...
|
||||
var code = this.code
|
||||
if(code){
|
||||
var t = Date.now()
|
||||
this.load(code.innerHTML
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')) }
|
||||
.replace(/>/g, '>'))
|
||||
console.log(`Parse: ${Date.now() - t}ms`)}
|
||||
|
||||
return this },
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@ var setup = function(){
|
||||
- Bonsai
|
||||
-
|
||||
- ## ToDo:
|
||||
- BUG? odd/random focus jumps on refocusing page (can't reporduce yet)
|
||||
- BUG? pressing down from a longer line will jump over a shorter line
|
||||
- here is the line to jump from, for example from here
|
||||
an we'll not get here...
|
||||
@ -100,13 +99,29 @@ var setup = function(){
|
||||
- Text
|
||||
- Lists::
|
||||
- bullet:
|
||||
- a
|
||||
- a:
|
||||
collapsed:: true
|
||||
- bullets:
|
||||
- in:
|
||||
- very:
|
||||
- deep:
|
||||
- list:
|
||||
- of:
|
||||
- items:
|
||||
- b
|
||||
- c
|
||||
- numbered#
|
||||
- a
|
||||
- b#
|
||||
- x
|
||||
- x#
|
||||
collapsed:: true
|
||||
- bullets#
|
||||
- in#
|
||||
- very#
|
||||
- deep#
|
||||
- list#
|
||||
- of#
|
||||
- items#
|
||||
- y
|
||||
- z
|
||||
- c
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user