mirror of
https://github.com/flynx/pWiki.git
synced 2025-12-25 12:21:58 +00:00
Compare commits
No commits in common. "4998ac950cc9ea40a42192078768fbb00a5c1412" and "a8797669feaab289c82580ba1ef4e118af82c949" have entirely different histories.
4998ac950c
...
a8797669fe
@ -1,24 +1,9 @@
|
|||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--font-size: 5mm;
|
--font-size: 5mm;
|
||||||
|
|
||||||
--outline-padding: 5rem;
|
|
||||||
|
|
||||||
--item-indent: 2rem;
|
|
||||||
--item-padding: 0.2em;
|
--item-padding: 0.2em;
|
||||||
|
|
||||||
--checkbox-size: 1.5rem;
|
|
||||||
|
|
||||||
--button-size: 2em;
|
--button-size: 2em;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
|
|
||||||
:root {
|
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: var(--font-size);
|
font-size: var(--font-size);
|
||||||
|
|
||||||
@ -40,26 +25,22 @@
|
|||||||
.editor .outline {
|
.editor .outline {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
/* XXX do a better calculation... */
|
/* XXX do a better calculation... */
|
||||||
width: calc(100% - var(--button-size) - var(--outline-padding) * 2);
|
width: calc(100% - (var(--button-size) + 4em));
|
||||||
|
|
||||||
padding-left: var(--outline-padding);
|
|
||||||
padding-right: var(--outline-padding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor .outline [tabindex] {
|
.editor .outline [tabindex] {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
.editor .outline [tabindex] [tabindex] {
|
.editor .outline div [tabindex] {
|
||||||
margin-left: var(--item-indent);
|
margin-left: 2em;
|
||||||
}
|
}
|
||||||
.editor .outline [tabindex]>span,
|
.editor .outline [tabindex]>span,
|
||||||
.editor .outline [tabindex]>textarea {
|
.editor .outline [tabindex]>textarea {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
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 textarea's height here is off too... */
|
||||||
min-height: calc(1em + var(--item-padding) * 2);
|
min-height: 1em;
|
||||||
padding-top: var(--item-padding);
|
padding-top: var(--item-padding);
|
||||||
padding-bottom: var(--item-padding);
|
padding-bottom: var(--item-padding);
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
@ -74,9 +55,6 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
.editor .outline [tabindex]>span:blank {
|
|
||||||
content: " ";
|
|
||||||
}
|
|
||||||
.editor .outline [tabindex]>textarea {
|
.editor .outline [tabindex]>textarea {
|
||||||
height: calc(2 * var(--item-padding) + 1em);
|
height: calc(2 * var(--item-padding) + 1em);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -109,67 +87,7 @@
|
|||||||
.editor .outline div[collapsed] {
|
.editor .outline div[collapsed] {
|
||||||
border-bottom: solid 1px silver;
|
border-bottom: solid 1px silver;
|
||||||
}
|
}
|
||||||
/* expand/collapse button... */
|
.editor .outline div[collapsed] div {
|
||||||
.editor .outline [tabindex]:after {
|
|
||||||
--size: 0.5rem;
|
|
||||||
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
top: calc(1em / 2);
|
|
||||||
right: calc(-1rem + -1 * var(--size) - var(--item-padding));
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border: solid calc(var(--size) / 1.2) transparent;
|
|
||||||
border-top: solid var(--size) black;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.editor .outline [tabindex][collapsed]:after {
|
|
||||||
border: solid calc(var(--size) / 1.2) transparent;
|
|
||||||
border-left: solid var(--size) black;
|
|
||||||
margin-right: -0.25rem;
|
|
||||||
opacity: 0.1;
|
|
||||||
}
|
|
||||||
.editor .outline [tabindex]:hover:after {
|
|
||||||
opacity: 0.1;
|
|
||||||
}
|
|
||||||
/* click/tap zone for expand button... */
|
|
||||||
.editor .outline [tabindex]:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
right: -2rem;
|
|
||||||
width: 2rem;
|
|
||||||
height: calc(1em + var(--item-padding) * 2);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
.editor .outline div[collapsed]:before,
|
|
||||||
.editor .outline div[collapsed]:after {
|
|
||||||
--size: 0.3em;
|
|
||||||
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
width: var(--size);
|
|
||||||
height: var(--size);
|
|
||||||
bottom: 0;
|
|
||||||
right: calc(-1 * var(--size));
|
|
||||||
margin-bottom: calc(var(--size) / -2 - 0.5px);
|
|
||||||
rotate: -45deg;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
color: silver;
|
|
||||||
border-top: solid 1px silver;
|
|
||||||
border-left: solid 1px silver;
|
|
||||||
}
|
|
||||||
.editor .outline div[collapsed]:before {
|
|
||||||
right: auto;
|
|
||||||
left: calc(-1 * var(--size));
|
|
||||||
rotate: 135deg;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
.editor .outline div[collapsed] [tabindex] {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +119,6 @@
|
|||||||
/*-------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------*/
|
||||||
/* Styles */
|
/* Styles */
|
||||||
|
|
||||||
/* Headings... */
|
|
||||||
.editor .outline .heading-1>span,
|
.editor .outline .heading-1>span,
|
||||||
.editor .outline .heading-1>textarea,
|
.editor .outline .heading-1>textarea,
|
||||||
.editor .outline .heading-2>span,
|
.editor .outline .heading-2>span,
|
||||||
@ -222,7 +139,7 @@
|
|||||||
.editor .outline .heading-2>textarea,
|
.editor .outline .heading-2>textarea,
|
||||||
.editor .outline .heading-3>span,
|
.editor .outline .heading-3>span,
|
||||||
.editor .outline .heading-3>textarea {
|
.editor .outline .heading-3>textarea {
|
||||||
border-bottom: solid 1px rgba(0,0,0,0.1);
|
border-bottom: solid 1px rgba(0,0,0,0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor .outline .heading-1>span,
|
.editor .outline .heading-1>span,
|
||||||
@ -278,48 +195,24 @@
|
|||||||
color: silver;
|
color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor .outline [tabindex]>span>input[type=checkbox].check,
|
||||||
|
.editor .outline [tabindex]>span>input[type=checkbox].todo {
|
||||||
|
--size: 1.5rem;
|
||||||
|
--height: calc(var(--font-size) + 2 * var(--item-padding));
|
||||||
|
|
||||||
/* checkboxes... */
|
top: calc(0.6em + var(--item-padding));
|
||||||
:root {
|
height: var(--size);
|
||||||
/* NOTE: this must have a unit... */
|
width: var(--size);
|
||||||
/* XXX move this to the config when fixed... */
|
margin-top: calc(var(--size) / -2);
|
||||||
/* XXX setting this to >0em will add margins to both sides of
|
|
||||||
* the inline checkbox even if it is the first thing in the
|
|
||||||
* element -- can's seem to figure out a way to avoid this */
|
|
||||||
--checkbox-margin: 0em;
|
|
||||||
}
|
|
||||||
/* align todo checkboxes to indnt (otherwise they are on the indent) */
|
|
||||||
.editor .outline [tabindex].todo>span {
|
|
||||||
margin-left: var(--checkbox-size);
|
|
||||||
padding-left: calc(
|
|
||||||
var(--item-padding)
|
|
||||||
+ var(--checkbox-margin) * 2);
|
|
||||||
}
|
|
||||||
.editor .outline [tabindex].check>span>input[type=checkbox],
|
|
||||||
.editor .outline [tabindex].todo>span>input[type=checkbox] {
|
|
||||||
height: var(--checkbox-size);
|
|
||||||
width: var(--checkbox-size);
|
|
||||||
|
|
||||||
margin-top: calc(var(--checkbox-size) / -2);
|
|
||||||
margin-left: var(--checkbox-margin);
|
|
||||||
margin-right: var(--checkbox-margin);
|
|
||||||
|
|
||||||
transform: translateY(calc(2 * var(--item-padding)));
|
|
||||||
|
|
||||||
/* 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 [tabindex].todo>span>input[type=checkbox]:first-child {
|
.editor .outline [tabindex]>span>input[type=checkbox].todo {
|
||||||
margin-left: calc(
|
position: absolute;
|
||||||
var(--checkbox-size) * -1
|
margin-left: calc(-1 * var(--size) - var(--item-padding) * 2);
|
||||||
- var(--item-padding)
|
|
||||||
- var(--checkbox-margin) * 2);
|
|
||||||
margin-right: calc(
|
|
||||||
var(--item-padding)
|
|
||||||
+ var(--checkbox-margin));
|
|
||||||
}
|
}
|
||||||
/* XXX need to remove left margin from strictly the first itme in block... */
|
.editor .outline [tabindex]>span>input[type=checkbox].check {
|
||||||
.editor .outline [tabindex].check>span>input[type=checkbox] {
|
transform: translateY(calc(2 * var(--item-padding)));
|
||||||
/*margin-left: 0;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -195,7 +195,7 @@ var Outline = {
|
|||||||
// heading...
|
// heading...
|
||||||
parsed.style ?
|
parsed.style ?
|
||||||
node.classList.add(...parsed.style)
|
node.classList.add(...parsed.style)
|
||||||
: node.classList.remove(...this.__styles)
|
: node.classList.remove(...this.__styles__)
|
||||||
} else {
|
} else {
|
||||||
html.innerHTML = data.text }
|
html.innerHTML = data.text }
|
||||||
text.value = data.text
|
text.value = data.text
|
||||||
@ -259,9 +259,7 @@ var Outline = {
|
|||||||
if(elem.classList.contains('focused')){
|
if(elem.classList.contains('focused')){
|
||||||
// XXX need to be able to get the next elem on same level...
|
// XXX need to be able to get the next elem on same level...
|
||||||
this.toggleCollapse(elem, true)
|
this.toggleCollapse(elem, true)
|
||||||
next = elem === this.get(-1) ?
|
next = this.get(elem, 'next') }
|
||||||
this.get(elem, 'prev')
|
|
||||||
: this.get(elem, 'next') }
|
|
||||||
elem?.remove()
|
elem?.remove()
|
||||||
next?.focus()
|
next?.focus()
|
||||||
return this },
|
return this },
|
||||||
@ -271,27 +269,33 @@ var Outline = {
|
|||||||
return this },
|
return this },
|
||||||
|
|
||||||
// block serialization...
|
// block serialization...
|
||||||
|
// XXX shouild we support headings + other formatting per block???
|
||||||
// XXX split this up into a generic handler + plugins...
|
// XXX split this up into a generic handler + plugins...
|
||||||
// XXX need a way to filter input text...
|
// XXX need a way to filter input text...
|
||||||
// use-case: hidden attributes...
|
// use-case: hidden attributes...
|
||||||
// NOTE: this is auto-populated by .__code2html__(..)
|
__styles__: [
|
||||||
__styles: undefined,
|
'heading-1',
|
||||||
|
'heading-2',
|
||||||
|
'heading-3',
|
||||||
|
'heading-4',
|
||||||
|
'heading-5',
|
||||||
|
'heading-6',
|
||||||
|
'list',
|
||||||
|
],
|
||||||
__code2html__: function(code){
|
__code2html__: function(code){
|
||||||
var that = this
|
|
||||||
var elem = {
|
var elem = {
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
}
|
}
|
||||||
var style = function(style, code=undefined){
|
var heading = function(level){
|
||||||
style = [style].flat()
|
|
||||||
that.__styles = [...new Set([
|
|
||||||
...(that.__styles ?? []),
|
|
||||||
...style,
|
|
||||||
])]
|
|
||||||
return function(_, text){
|
return function(_, text){
|
||||||
elem.style ??= []
|
elem.style ??= []
|
||||||
elem.style.push(...style)
|
elem.style.push('heading-'+level)
|
||||||
return code
|
return text } }
|
||||||
?? text } }
|
var style = function(style){
|
||||||
|
return function(_, text){
|
||||||
|
elem.style ??= []
|
||||||
|
elem.style.push(style)
|
||||||
|
return text } }
|
||||||
elem.text = code
|
elem.text = code
|
||||||
// hidden attributes...
|
// hidden attributes...
|
||||||
// XXX make this generic...
|
// XXX make this generic...
|
||||||
@ -324,12 +328,12 @@ var Outline = {
|
|||||||
// elements...
|
// elements...
|
||||||
.replace(/(\n|^)---*\h*(\n|$)/m, '$1<hr>')
|
.replace(/(\n|^)---*\h*(\n|$)/m, '$1<hr>')
|
||||||
// ToDo...
|
// ToDo...
|
||||||
.replace(/^TODO\s*/m, style('todo', '<input type="checkbox">'))
|
.replace(/^TODO\s*(.*)$/m, '<input class="todo" type="checkbox">$1')
|
||||||
.replace(/^DONE\s*/m, style('todo', '<input type="checkbox" checked>'))
|
.replace(/^DONE\s*(.*)$/m, '<input class="todo" type="checkbox" checked>$1')
|
||||||
// checkboxes...
|
// checkboxes...
|
||||||
// XXX these can not be clicked (yet)...
|
// XXX these can not be clicked (yet)...
|
||||||
.replace(/\[_\]/gm, style('check', '<input class="check" type="checkbox">'))
|
.replace(/\[_\]/gm, '<input class="check" type="checkbox">')
|
||||||
.replace(/\[[X]\]/gm, style('check', '<input class="check" type="checkbox" checked>'))
|
.replace(/\[[X]\]/gm, '<input class="check" type="checkbox" checked>')
|
||||||
// basic styling...
|
// basic styling...
|
||||||
// XXX these are quite naive...
|
// XXX these are quite naive...
|
||||||
.replace(/\*(.*)\*/gm, '<b>$1</b>')
|
.replace(/\*(.*)\*/gm, '<b>$1</b>')
|
||||||
@ -423,7 +427,6 @@ var Outline = {
|
|||||||
var block = document.createElement('div')
|
var block = document.createElement('div')
|
||||||
block.setAttribute('tabindex', '0')
|
block.setAttribute('tabindex', '0')
|
||||||
var text = document.createElement('textarea')
|
var text = document.createElement('textarea')
|
||||||
.autoUpdateSize()
|
|
||||||
var html = document.createElement('span')
|
var html = document.createElement('span')
|
||||||
block.append(text, html)
|
block.append(text, html)
|
||||||
this.update(block, data)
|
this.update(block, data)
|
||||||
@ -434,12 +437,9 @@ var Outline = {
|
|||||||
'before'
|
'before'
|
||||||
: place
|
: place
|
||||||
;(place == 'next'
|
;(place == 'next'
|
||||||
&& (cur.querySelector('[tabindex]')
|
&& (cur.querySelector('[tabindex]')
|
||||||
|| cur.nextElementSibling)) ?
|
|| cur.nextElementSibling)) ?
|
||||||
this.get(place).before(block)
|
this.get(place).before(block)
|
||||||
: (place == 'next'
|
|
||||||
&& !cur.nextElementSibling) ?
|
|
||||||
cur.after(block)
|
|
||||||
: (place == 'before' || place == 'after') ?
|
: (place == 'before' || place == 'after') ?
|
||||||
cur[place](block)
|
cur[place](block)
|
||||||
: undefined }
|
: undefined }
|
||||||
@ -596,9 +596,6 @@ var Outline = {
|
|||||||
: focused.setAttribute('selected', '') },
|
: focused.setAttribute('selected', '') },
|
||||||
},
|
},
|
||||||
|
|
||||||
// XXX might be a good idea to defer specific actions to event-like
|
|
||||||
// handlers...
|
|
||||||
// e.g. clicking left if block -> .blockleft(..) ... etc.
|
|
||||||
setup: function(dom){
|
setup: function(dom){
|
||||||
var that = this
|
var that = this
|
||||||
this.dom = dom
|
this.dom = dom
|
||||||
@ -612,34 +609,16 @@ var Outline = {
|
|||||||
outline.addEventListener('click',
|
outline.addEventListener('click',
|
||||||
function(evt){
|
function(evt){
|
||||||
var elem = evt.target
|
var elem = evt.target
|
||||||
|
|
||||||
// expand/collapse
|
|
||||||
if(elem.nodeName == 'DIV'
|
|
||||||
&& elem.getAttribute('tabindex')){
|
|
||||||
// click: left of elem (outside)
|
|
||||||
if(evt.offsetX < 0){
|
|
||||||
// XXX item menu?
|
|
||||||
|
|
||||||
// click: right of elem (outside)
|
|
||||||
} else if(elem.offsetWidth < evt.offsetX){
|
|
||||||
that.toggleCollapse(elem)
|
|
||||||
|
|
||||||
// click inside element...
|
|
||||||
} else {
|
|
||||||
// XXX
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: toggle checkbox...
|
// todo: toggle checkbox...
|
||||||
} else if(elem.classList.contains('todo')){
|
if(elem.classList.contains('todo')){
|
||||||
var node = elem.parentElement.parentElement
|
var node = elem.parentElement.parentElement
|
||||||
var text = node.querySelector('textarea')
|
var text = node.querySelector('textarea')
|
||||||
text.value =
|
text.value =
|
||||||
elem.checked ?
|
elem.checked ?
|
||||||
text.value.replace(/^\s*TODO(\s*)/, 'DONE$1')
|
text.value.replace(/^\s*TODO(\s*)/, 'DONE$1')
|
||||||
: text.value.replace(/^\s*DONE(\s*)/, 'TODO$1')
|
: text.value.replace(/^\s*DONE(\s*)/, 'TODO$1') }
|
||||||
|
|
||||||
// check: toggle checkbox...
|
// check: toggle checkbox...
|
||||||
} else if(elem.classList.contains('check')){
|
if(elem.classList.contains('check')){
|
||||||
var node = elem.parentElement.parentElement
|
var node = elem.parentElement.parentElement
|
||||||
var text = node.querySelector('textarea')
|
var text = node.querySelector('textarea')
|
||||||
var i = [...node.querySelectorAll('.check')].indexOf(elem)
|
var i = [...node.querySelectorAll('.check')].indexOf(elem)
|
||||||
|
|||||||
@ -28,15 +28,7 @@ var setup = function(){
|
|||||||
<!-- code -->
|
<!-- code -->
|
||||||
<div class="code">
|
<div class="code">
|
||||||
- # Outline editor prototype
|
- # Outline editor prototype
|
||||||
- An outline-based markdown editor experiment
|
|
||||||
- ### Infuences::
|
|
||||||
- Logseq
|
|
||||||
- Tomboy
|
|
||||||
- Bonsai
|
|
||||||
-
|
|
||||||
- ## ToDo
|
- ## ToDo
|
||||||
- do a better expand/collapse icon on hover
|
|
||||||
- read-only mode
|
|
||||||
- editor: bksapce/del at start/end of a block should join it with prev/next
|
- editor: bksapce/del at start/end of a block should join it with prev/next
|
||||||
- editor: pressing enter in text edit mode should split text into two blocks
|
- editor: pressing enter in text edit mode should split text into two blocks
|
||||||
- editor: caret
|
- editor: caret
|
||||||
@ -59,8 +51,7 @@ var setup = function(){
|
|||||||
- indent/deindent
|
- indent/deindent
|
||||||
- edit node
|
- edit node
|
||||||
- copy/paste nodes/trees
|
- copy/paste nodes/trees
|
||||||
- markdown: tables
|
- markdown tables
|
||||||
- empty item height is a bit off...
|
|
||||||
- ~serialize~/deserialize
|
- ~serialize~/deserialize
|
||||||
- ~add optional text styling to nodes~
|
- ~add optional text styling to nodes~
|
||||||
-
|
-
|
||||||
@ -86,9 +77,8 @@ var setup = function(){
|
|||||||
- Basic inline *bold*, _italic_ and ~striked~
|
- Basic inline *bold*, _italic_ and ~striked~
|
||||||
- To do items
|
- To do items
|
||||||
- TODO undone item
|
- TODO undone item
|
||||||
_(clicking the checkbox updates the item)_
|
|
||||||
- DONE done item
|
- DONE done item
|
||||||
- [_] a different way to draw a checkbox
|
_(clicking the checkbox updates the item)_
|
||||||
- Inline [X] checkboxes [_]
|
- Inline [X] checkboxes [_]
|
||||||
- A
|
- A
|
||||||
collapsed:: true
|
collapsed:: true
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user