mirror of
https://github.com/flynx/pWiki.git
synced 2025-12-25 12:21:58 +00:00
Compare commits
No commits in common. "9ecbf4e06074eec5ba0466d54b0fd17b983d59a8" and "90cdc0c3c71cdbc6a61f449daac56530a09d5c48" have entirely different histories.
9ecbf4e060
...
90cdc0c3c7
@ -7,7 +7,7 @@
|
||||
:root {
|
||||
--font-size: 5mm;
|
||||
|
||||
--outline-padding: 7rem;
|
||||
--outline-padding: 5rem;
|
||||
|
||||
--item-indent: 2rem;
|
||||
--item-padding-ratio: 0.2;
|
||||
@ -54,6 +54,8 @@
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
width: calc(100% - var(--button-size) - var(--outline-padding) * 2);
|
||||
|
||||
padding: 1em var(--outline-padding);
|
||||
padding-bottom: 1.2em
|
||||
}
|
||||
|
||||
@ -720,7 +720,6 @@ var Outline = {
|
||||
// .get('visible')
|
||||
// .get('editable')
|
||||
// .get('selected')
|
||||
// .get('viewport')
|
||||
// .get('top')
|
||||
// -> <nodes>
|
||||
//
|
||||
@ -740,7 +739,7 @@ var Outline = {
|
||||
if(node == 'top'){
|
||||
return [...outline.children] }
|
||||
// groups defaulting to .outline as base...
|
||||
if(['all', 'visible', 'editable', 'selected', 'viewport'].includes(node)){
|
||||
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)){
|
||||
@ -807,11 +806,6 @@ var Outline = {
|
||||
[...node.querySelectorAll('.block')]
|
||||
.filter(function(e){
|
||||
return e.offsetParent != null })
|
||||
: offset == 'viewport' ?
|
||||
[...node.querySelectorAll('.block')]
|
||||
.filter(function(e){
|
||||
return e.offsetParent != null
|
||||
&& e.querySelector('.code').visibleInViewport() })
|
||||
: offset == 'editable' ?
|
||||
[...node.querySelectorAll('.block>.code')]
|
||||
: offset == 'selected' ?
|
||||
@ -846,20 +840,13 @@ var Outline = {
|
||||
focus: function(node='focused', offset){
|
||||
var elem = this.get(...arguments)
|
||||
?? this.get(0)
|
||||
if(elem){
|
||||
elem.focus({preventScroll: true})
|
||||
;(elem.classList.contains('code') ?
|
||||
elem
|
||||
: elem.querySelector('.code'))
|
||||
.scrollIntoView({
|
||||
block: 'nearest',
|
||||
//behavior: 'smooth',
|
||||
}) }
|
||||
elem
|
||||
&& elem.focus()
|
||||
return elem },
|
||||
edit: function(node='focused', offset){
|
||||
var elem = this.get(...arguments)
|
||||
if(!elem.classList.contains('code')){
|
||||
elem = elem.querySelector('.code') }
|
||||
if(elem.nodeName != 'TEXTAREA'){
|
||||
elem = elem.querySelector('textarea') }
|
||||
elem?.focus()
|
||||
return elem },
|
||||
|
||||
@ -1040,8 +1027,7 @@ var Outline = {
|
||||
this.get(elem, 'prev')
|
||||
: this.get(elem, 'next') }
|
||||
elem?.remove()
|
||||
next
|
||||
&& this.focus(next)
|
||||
next?.focus()
|
||||
this.__change__()
|
||||
return this },
|
||||
clear: function(){
|
||||
@ -1051,13 +1037,12 @@ var Outline = {
|
||||
|
||||
|
||||
// crop...
|
||||
// XXX add crop/path indicator...
|
||||
__crop_stack: undefined,
|
||||
crop: function(node='focused'){
|
||||
var stack = this.__crop_stack ??= []
|
||||
stack.push([this.json(), this.path()])
|
||||
this.load(this.data())
|
||||
this.dom.classList.add('crop')
|
||||
.focus()
|
||||
return this },
|
||||
// XXX use JSON API...
|
||||
uncrop: function(){
|
||||
@ -1065,8 +1050,7 @@ var Outline = {
|
||||
return this}
|
||||
var [state, path] = this.__crop_stack.pop()
|
||||
if(this.__crop_stack.length == 0){
|
||||
this.__crop_stack = undefined
|
||||
this.dom.classList.remove('crop') }
|
||||
this.__crop_stack = undefined }
|
||||
// update state...
|
||||
path
|
||||
.slice(0, -1)
|
||||
@ -1074,6 +1058,7 @@ var Outline = {
|
||||
return res[i].children }, state)
|
||||
.splice(path.at(-1), 1, ...this.json())
|
||||
this.load(state)
|
||||
.focus()
|
||||
return this },
|
||||
|
||||
// block render...
|
||||
@ -1331,7 +1316,6 @@ var Outline = {
|
||||
cur[place](block)
|
||||
: undefined }
|
||||
return block },
|
||||
// XXX see inside...
|
||||
load: function(data){
|
||||
var that = this
|
||||
data = typeof(data) == 'string' ?
|
||||
@ -1352,14 +1336,9 @@ var Outline = {
|
||||
.clear()
|
||||
.outline
|
||||
.append(...level(data))
|
||||
//* XXX do we actually need this???
|
||||
// update sizes of all the textareas (transparent)...
|
||||
setTimeout(function(){
|
||||
for(var e of [...that.outline.querySelectorAll('textarea')]){
|
||||
e.updateSize() } }, 0)
|
||||
//*/
|
||||
// restore focus...
|
||||
this.focus()
|
||||
for(var e of [...this.outline.querySelectorAll('textarea')]){
|
||||
e.updateSize() }
|
||||
return this },
|
||||
|
||||
sync: function(){
|
||||
@ -1381,6 +1360,7 @@ var Outline = {
|
||||
right: function(){},
|
||||
|
||||
// XXX move the code here into methods/actions...
|
||||
// XXX add scrollIntoView(..) to nav...
|
||||
// XXX use keyboard.js...
|
||||
keyboard: {
|
||||
// vertical navigation...
|
||||
@ -1403,7 +1383,7 @@ var Outline = {
|
||||
var edited = this.get('edited')
|
||||
if(edited){
|
||||
var {line, lines} = edited.getTextGeometry()
|
||||
if(line == lines - 1){
|
||||
if(line == lines -1){
|
||||
evt.preventDefault()
|
||||
that.focus('edited', 'next') }
|
||||
} else {
|
||||
@ -1468,35 +1448,19 @@ var Outline = {
|
||||
evt.preventDefault()
|
||||
this.focus(-1) },
|
||||
PageUp: function(evt){
|
||||
var that = this
|
||||
var edited = this.get('edited')
|
||||
if(edited){
|
||||
return }
|
||||
if(evt.shiftKey
|
||||
|| evt.ctrlKey){
|
||||
if(!edited
|
||||
&& (evt.shiftKey
|
||||
|| evt.ctrlKey)){
|
||||
evt.preventDefault()
|
||||
this.shift('up')
|
||||
} else {
|
||||
var viewport = that.get('viewport')
|
||||
viewport[0] === that.get(0) ?
|
||||
that.focus(0)
|
||||
: that.focus(
|
||||
viewport[0], 'prev') } },
|
||||
this.shift('up') } },
|
||||
PageDown: function(evt){
|
||||
var that = this
|
||||
var edited = this.get('edited')
|
||||
if(edited){
|
||||
return }
|
||||
if(evt.shiftKey
|
||||
|| evt.ctrlKey){
|
||||
if(!edited
|
||||
&& (evt.shiftKey
|
||||
|| evt.ctrlKey)){
|
||||
evt.preventDefault()
|
||||
this.shift('down')
|
||||
} else {
|
||||
var viewport = that.get('viewport')
|
||||
viewport.at(-1) === that.get(-1) ?
|
||||
that.focus(-1)
|
||||
: that.focus(
|
||||
that.get('viewport').at(-1), 'next') } },
|
||||
this.shift('down') } },
|
||||
|
||||
// indent..
|
||||
Tab: function(evt){
|
||||
@ -1521,6 +1485,7 @@ var Outline = {
|
||||
this.edit(
|
||||
this.Block('next')) } },
|
||||
Enter: function(evt){
|
||||
|
||||
var edited = this.get('edited')
|
||||
// edit -> split text...
|
||||
if(edited){
|
||||
@ -1671,20 +1636,6 @@ var Outline = {
|
||||
if(elem.classList.contains('block')){
|
||||
elem.querySelector('.code').focus() }
|
||||
|
||||
// focus viewport...
|
||||
// XXX this does not work because by this point there is
|
||||
// no focused element...
|
||||
if(elem === outline){
|
||||
var cur = that.get()
|
||||
var viewport = that.get('viewport')
|
||||
if(!viewport.includes(cur)){
|
||||
var visible = that.get('visible')
|
||||
var i = visible.indexOf(cur)
|
||||
var v = visible.indexOf(viewport[0])
|
||||
i < v ?
|
||||
that.focus(viewport[0])
|
||||
: that.focus(viewport.at(-1)) } }
|
||||
|
||||
that.runPlugins('__click__', evt, that, elem) })
|
||||
// keyboard handling...
|
||||
outline.addEventListener('keydown',
|
||||
@ -1715,20 +1666,26 @@ var Outline = {
|
||||
return }
|
||||
|
||||
// handle focus...
|
||||
if(elem !== that.outline){
|
||||
for(var e of [...that.dom.querySelectorAll('.focused')]){
|
||||
e.classList.remove('focused') }
|
||||
that.get('focused')?.classList?.add('focused') }
|
||||
for(var e of [...that.dom.querySelectorAll('.focused')]){
|
||||
e.classList.remove('focused') }
|
||||
that.get('focused')?.classList?.add('focused')
|
||||
// textarea...
|
||||
if(elem.classList.contains('code')){
|
||||
elem.updateSize() }
|
||||
|
||||
/*/ scroll...
|
||||
that.get(node).querySelector('view')
|
||||
?.scrollIntoView({
|
||||
block: 'nearest',
|
||||
behavior: 'smooth',
|
||||
})
|
||||
//*/
|
||||
|
||||
// XXX do we need this???
|
||||
that.runPlugins('__focusin__', evt, that, elem) })
|
||||
outline.addEventListener('focusout',
|
||||
function(evt){
|
||||
var elem = evt.target
|
||||
// update code...
|
||||
if(elem.classList.contains('code')){
|
||||
var block = elem.parentElement
|
||||
// clean out attrs...
|
||||
@ -1756,7 +1713,7 @@ var Outline = {
|
||||
focus_textarea = document.activeElement.nodeName == 'TEXTAREA' }
|
||||
var refocusNode = function(){
|
||||
focus_textarea ?
|
||||
editor.get().querySelector('.code').focus()
|
||||
editor.get().querySelector('textarea').focus()
|
||||
: editor.focus()
|
||||
focus_textarea = undefined }
|
||||
// cache the focused node type before focus changes...
|
||||
|
||||
@ -4,26 +4,6 @@
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
Element.prototype.visibleInViewport = function(partial=false){
|
||||
var { top, left, bottom, right } = this.getBoundingClientRect()
|
||||
var { innerHeight, innerWidth } = window
|
||||
return partial
|
||||
? ((top > 0
|
||||
&& top < innerHeight)
|
||||
|| (bottom > 0
|
||||
&& bottom < innerHeight))
|
||||
&& ((left > 0
|
||||
&& left < innerWidth)
|
||||
|| (right > 0
|
||||
&& right < innerWidth))
|
||||
: (top >= 0
|
||||
&& left >= 0
|
||||
&& bottom <= innerHeight
|
||||
&& right <= innerWidth) }
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
HTMLTextAreaElement.prototype.updateSize = function(){
|
||||
this.style.height = ''
|
||||
this.style.height = this.scrollHeight + 'px'
|
||||
@ -40,7 +20,6 @@ HTMLTextAreaElement.prototype.getTextGeometry = function(){
|
||||
|
||||
// get the relevant styles...
|
||||
var style = getComputedStyle(this)
|
||||
var paddingV = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom)
|
||||
var s = {}
|
||||
for(var i=0; i < style.length; i++){
|
||||
var k = style[i]
|
||||
@ -50,11 +29,12 @@ HTMLTextAreaElement.prototype.getTextGeometry = function(){
|
||||
s[k] = style[k] } }
|
||||
|
||||
var carret = document.createElement('span')
|
||||
carret.innerText = '|'
|
||||
carret.innerText = '|'
|
||||
carret.style.margin = '0px'
|
||||
carret.style.padding = '0px'
|
||||
|
||||
var span = document.createElement('span')
|
||||
span.innerText = text.slice(0, offset)
|
||||
Object.assign(span.style, {
|
||||
...s,
|
||||
|
||||
@ -62,31 +42,22 @@ HTMLTextAreaElement.prototype.getTextGeometry = function(){
|
||||
display: 'block',
|
||||
top: '-100%',
|
||||
left: '-100%',
|
||||
width: style.width,
|
||||
height: style.height,
|
||||
width: this.offsetWidth + 'px',
|
||||
height: this.scrollHeight + 'px',
|
||||
|
||||
padding: style.padding,
|
||||
|
||||
boxSizing: style.boxSizing,
|
||||
|
||||
outline: 'solid 1px red',
|
||||
|
||||
pointerEvents: 'none',
|
||||
})
|
||||
span.append(
|
||||
text.slice(0, offset),
|
||||
carret,
|
||||
// NOTE: wee need the rest of the text for the carret to be typeset
|
||||
// to the correct line...
|
||||
text.slice(offset))
|
||||
span.append(carret)
|
||||
|
||||
document.body.append(span)
|
||||
|
||||
var res = {
|
||||
length: text.length,
|
||||
lines: Math.floor(
|
||||
(this.offsetHeight - paddingV)
|
||||
/ carret.offsetHeight),
|
||||
lines: Math.floor(this.offsetHeight / carret.offsetHeight),
|
||||
line: Math.floor(carret.offsetTop / carret.offsetHeight),
|
||||
offset: offset,
|
||||
offsetLeft: carret.offsetLeft,
|
||||
|
||||
@ -40,17 +40,18 @@ var setup = function(){
|
||||
- Logseq
|
||||
- Conboy (Nokia N900's Tomboy clone)
|
||||
- Bonsai (on PalmOS)
|
||||
- Google Keep
|
||||
-
|
||||
- // Seems that I unintentionally implemented quite a chunk of the markdown spec ;)
|
||||
-
|
||||
- ## Bugs:
|
||||
focused:: true
|
||||
- BUG: editor: FF seems to update the style every other key press -- should be live...
|
||||
- BUG: scrolling into view needs tuning...
|
||||
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
|
||||
-
|
||||
- ## ToDo:
|
||||
- crop: show crop path (and depth)
|
||||
- pgup/pgdown/~home/end~ buttons
|
||||
- identify a block:
|
||||
- DONE index (flat)
|
||||
- DONE path (index)
|
||||
@ -67,7 +68,7 @@ var setup = function(){
|
||||
- ...or should this be `sort:: done` -- i.e. sort children by done status??
|
||||
- codeblock as a block
|
||||
_...if only whitespace before/after clear it and style whole block..._
|
||||
_...might be a good idea to do this with codeblock at start/end of block..._
|
||||
_...might be a good idea to do this with codeblock at start/end of block..._
|
||||
- Code blocks and bullets:
|
||||
- ```
|
||||
code
|
||||
@ -77,8 +78,8 @@ var setup = function(){
|
||||
- FEATURE: read-only mode
|
||||
- export html
|
||||
- embed css
|
||||
- cleanup html
|
||||
- generate ideomatic html (???)
|
||||
- cleanup html
|
||||
- generate ideomatic html (???)
|
||||
- style attrs (see: [attrs](#attributes))
|
||||
- FEATURE: `collapse-children:: true` block option -- when loading collapse all immediate children
|
||||
- FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)`
|
||||
@ -87,15 +88,11 @@ var setup = function(){
|
||||
- editor as a custom element...
|
||||
- Nerd fonts (option???)
|
||||
- multiple node selection
|
||||
- smooth scrolling
|
||||
- _...this is more complicated that adding `behavior: "smooth"` to `.scrollIntoView(..)` as scrolling animation will get interrupted by next user input..._
|
||||
- need to cancel animation of things are moving too fast...
|
||||
- make this generic
|
||||
- FEATURE? block templates...
|
||||
collapsed:: true
|
||||
- something like: `TPL: [_] <editable/> -- <editable/>`
|
||||
- something like: `TPL: [_] <editable/> -- <editable/>`
|
||||
- `TPL:` -- template marker
|
||||
- `<editable/>` -- field marker
|
||||
- `<editable/>` -- field marker
|
||||
- each child node will copy the template and allow editing of only fields
|
||||
- not clear how to handle template changes...
|
||||
- JSON API
|
||||
@ -118,12 +115,11 @@ var setup = function(){
|
||||
block text
|
||||
- NOTE: this is only a problem if making list-items manually -- disable???
|
||||
- empty item height is a bit off...
|
||||
- DONE pgup/pgdown/home/end buttons
|
||||
- DONE FEATURE: "crop" -- view block tree separately...
|
||||
- DONE unify attr parsing
|
||||
collapsed:: true
|
||||
- _now duplicated in `.parse(..)` and `.__code2html__(..)`_
|
||||
- might be a good idea to add a special text parse stage and use in on both branches...
|
||||
- might be a good idea to add a special text parse stage and use in on both branches...
|
||||
- DONE attrs in editor are not parsed correctly (see: [attrs](#attributes))
|
||||
- DONE multiple attrs are not handled correctly (see: [attrs](#attributes))
|
||||
- DONE call `.sync()` on all changes...
|
||||
@ -140,7 +136,7 @@ var setup = function(){
|
||||
- _not sure how..._
|
||||
- DONE click to select/edit node must retain click position in text...
|
||||
- DONE checkbox navigation via `alt-<arrow>`
|
||||
collapsed:: true
|
||||
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
|
||||
@ -166,8 +162,8 @@ var setup = function(){
|
||||
- ## Refactoring:
|
||||
- Plugin architecture
|
||||
- DONE basic structure
|
||||
- plugin handler sequencing (see: `<editor>.setup(..)`)
|
||||
- DONE plugin handler canceling (see: `<editor>.runPlugins(..)`)
|
||||
- plugin handler sequencing (see: `<editor>.setup(..)`)
|
||||
- DONE plugin handler canceling (see: `<editor>.runPlugins(..)`)
|
||||
- DONE Item parser (`.__code2html__(..)`)
|
||||
collapsed:: true
|
||||
- DONE split out
|
||||
@ -175,7 +171,7 @@ var setup = function(){
|
||||
- DONE Format parser/generator
|
||||
collapsed:: true
|
||||
- DONE split out
|
||||
- DONE define api (see: `<editor>.__code2text__(..) / <editor>.__text2code__(..)`)
|
||||
- DONE define api (see: `<editor>.__code2text__(..) / <editor>.__text2code__(..)`)
|
||||
- CSS
|
||||
- separate out settings
|
||||
- separate out theming
|
||||
@ -245,20 +241,20 @@ var setup = function(){
|
||||
- y
|
||||
- z
|
||||
- c
|
||||
- > quote
|
||||
- > quote
|
||||
- Notes
|
||||
- NOTE: a note text
|
||||
- NOTE: a note text
|
||||
- NOTE:
|
||||
- a root note can also be empty
|
||||
- click on the outer border to edit root
|
||||
- // C-style comment
|
||||
- ; ASM-style comment
|
||||
- XXX Highlight
|
||||
- // C-style comment
|
||||
- ; ASM-style comment
|
||||
- XXX Highlight
|
||||
- DONE Done (toggled via: `ctrl-d`)
|
||||
- Basic inline *bold*, _italic_ and ~striked~
|
||||
- Marking ==text==
|
||||
- Code:
|
||||
- Inline quoting `html <b>code</b>`
|
||||
- Inline quoting `html <b>code</b>`
|
||||
- code blocks
|
||||
```javascript
|
||||
var text = 'Hello, world!'
|
||||
@ -322,7 +318,7 @@ var setup = function(){
|
||||
- Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text Lots of text
|
||||
- </textarea>
|
||||
<!-- outline -->
|
||||
<div class="outline" tabindex="0"></div>
|
||||
<div class="outline"></div>
|
||||
<!-- toolbar (optional) -->
|
||||
<!--div class="toolbar">
|
||||
<button onclick="editor.deindent().focus()"><</button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user