mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-29 10:00:08 +00:00
lots of fixes + started major refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
53ad572369
commit
4690bc0770
@ -54,13 +54,23 @@
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
/* XXX do a better calculation... */
|
||||
width: calc(100% - var(--button-size) - var(--outline-padding) * 2);
|
||||
|
||||
padding-left: var(--outline-padding);
|
||||
padding-right: var(--outline-padding);
|
||||
padding: 1em var(--outline-padding);
|
||||
padding-bottom: 1.2em
|
||||
}
|
||||
|
||||
/* virtual empty block... */
|
||||
.editor .outline:empty:after {
|
||||
content: "Empty";
|
||||
display: block;
|
||||
font-style: italic;
|
||||
color: rgba(0,0,0,0.2);
|
||||
}
|
||||
.editor .outline:empty:hover:after {
|
||||
}
|
||||
|
||||
|
||||
.editor .outline .block {
|
||||
position: relative;
|
||||
outline: none;
|
||||
@ -110,6 +120,7 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
/* block hover... */
|
||||
.editor .outline:empty:hover:after,
|
||||
.editor .outline .block:hover>.view {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
@ -127,6 +138,7 @@
|
||||
}
|
||||
/* clickable things in view */
|
||||
.editor .outline .block>.view a,
|
||||
.editor .outline .block>.view pre,
|
||||
.editor .outline .block>.view input {
|
||||
pointer-events: auto;
|
||||
}
|
||||
@ -138,7 +150,7 @@ editor .outline .block:focus {
|
||||
outline: none;
|
||||
}
|
||||
.editor .outline .block:focus>.text {
|
||||
background: rgba(0,0,0,0.1);
|
||||
background: rgba(0,0,0,0.07);
|
||||
}
|
||||
.editor .outline .block.focused:not(:focus)>.text {
|
||||
background: rgba(0,0,0,0.01);
|
||||
@ -464,11 +476,13 @@ editor .outline .block:focus {
|
||||
font-family: monospace;
|
||||
background: rgba(0,0,0,0.07);
|
||||
border-radius: 0.2em;
|
||||
outline: none;
|
||||
}
|
||||
.editor .outline .block>.view pre>code {
|
||||
display: block;
|
||||
padding: 0.6em 0.6em;
|
||||
padding-bottom: 0.8em;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -25,6 +25,56 @@ var atLine = function(elem, index){
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
var codeBlock = {
|
||||
// can be used in:
|
||||
// <string>.replace(codeBlock.pattern, codeBlock.handler)
|
||||
// or:
|
||||
// codeBlock
|
||||
pattern: /(?<!\\)```(.*\s*\n)((\n|.)*?)\h*(?<!\\)```/g,
|
||||
handler: function(_, language, code){
|
||||
var quote = this?.quote
|
||||
|| codeBlock.quote
|
||||
language = language.trim()
|
||||
language = language ?
|
||||
'language-'+language
|
||||
: language
|
||||
return `<pre>`
|
||||
+`<code contenteditable="true" class="${language}">${
|
||||
quote ?
|
||||
quote(code)
|
||||
: code
|
||||
}</code>`
|
||||
+`</pre>` },
|
||||
|
||||
quote: function(text){
|
||||
return text
|
||||
.replace(/(?<!\\)&/g, '&')
|
||||
.replace(/(?<!\\)</g, '<')
|
||||
.replace(/(?<!\\)>/g, '>')
|
||||
.replace(/\\(?!`)/g, '\\\\') },
|
||||
|
||||
map: function(text, func){
|
||||
return text.replace(this.pattern, func) },
|
||||
|
||||
replace: function(text, index, updated){
|
||||
return this.map(text,
|
||||
function(match, language, code){
|
||||
return index-- != 0 ?
|
||||
match
|
||||
: ('```'+language
|
||||
+ (typeof(updated) == 'function' ?
|
||||
updated(code)
|
||||
: updated)
|
||||
+'```') }) },
|
||||
|
||||
toHTML: function(text){
|
||||
return this.map(text, this.handler) },
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// XXX experiment with a concatinative model...
|
||||
@ -101,12 +151,13 @@ var Outline = {
|
||||
// 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 }
|
||||
outline
|
||||
: node.parentElement === outline ?
|
||||
outline
|
||||
: node.parentElement.parentElement }
|
||||
var children = function(node){
|
||||
return node === outline ?
|
||||
[...node.children]
|
||||
@ -337,11 +388,6 @@ var Outline = {
|
||||
.replace(/\\(?!`)/g, '\\\\') }
|
||||
var quote = function(_, code){
|
||||
return `<code>${quoteText(code)}</code>` }
|
||||
var pre = function(_, language, code){
|
||||
language = language ?
|
||||
'language-'+language
|
||||
: language
|
||||
return `<pre><code class="${language}">${ quoteText(code) }</code></pre>` }
|
||||
var table = function(_, body){
|
||||
return `<table><tr><td>${
|
||||
body
|
||||
@ -349,7 +395,8 @@ var Outline = {
|
||||
.replace(/\s*\|\s*/gm, '</td><td>')
|
||||
}</td></td></table>` }
|
||||
|
||||
elem.text = code
|
||||
var preParse = function(text){
|
||||
return text
|
||||
// hidden attributes...
|
||||
// XXX make this generic...
|
||||
// collapsed...
|
||||
@ -361,7 +408,9 @@ var Outline = {
|
||||
.replace(/(\n|^)\s*id::\s*(.*)\s*(\n|$)/,
|
||||
function(_, value){
|
||||
elem.id = value.trim()
|
||||
return '' })
|
||||
return '' }) }
|
||||
var blockParse = function(text){
|
||||
return text
|
||||
// markdown...
|
||||
// style: headings...
|
||||
.replace(/^(?<!\\)######\s+(.*)$/m, style('heading-6'))
|
||||
@ -374,12 +423,21 @@ var Outline = {
|
||||
//.replace(/^(?<!\\)[-\*]\s+(.*)$/m, style('list-item'))
|
||||
.replace(/^\s*(.*)(?<!\\):\s*$/m, style('list'))
|
||||
.replace(/^\s*(.*)(?<!\\)#\s*$/m, style('numbered-list'))
|
||||
|
||||
// style: misc...
|
||||
.replace(/^\s*(?<!\\)>\s+(.*)$/m, style('quote'))
|
||||
.replace(/^\s*(?<!\\)((\/\/|;)\s+.*)$/m, style('comment'))
|
||||
.replace(/^\s*(?<!\\)NOTE:?\s*(.*)$/m, style('NOTE'))
|
||||
.replace(/^\s*(?<!\\)XXX\s+(.*)$/m, style('XXX'))
|
||||
.replace(/^(.*)\s*(?<!\\)XXX$/m, style('XXX'))
|
||||
.replace(/^(.*)\s*(?<!\\)XXX$/m, style('XXX')) }
|
||||
var quoteParse = function(text){
|
||||
return text
|
||||
.replace(codeBlock.pattern, codeBlock.handler)
|
||||
.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote) }
|
||||
var inlineParse = function(text){
|
||||
return text
|
||||
.replace(/(\s*)(?<!\\)(FEATURE:|Q:|Question:|Note:)(\s*)/gm,
|
||||
'$1<b class="$2">$2</b>$3')
|
||||
.replace(/(\s*)(?<!\\)(ASAP|BUG|FIX|HACK|STUB|WARNING|CAUTION)(\s*)/gm,
|
||||
'$1<span class="highlight $2">$2</span>$3')
|
||||
// elements...
|
||||
@ -404,8 +462,7 @@ var Outline = {
|
||||
.replace(/(?<!\\)~(?=[^\s~])(([^~]|\\~)*[^\s~])(?<!\\)~/gm, '<s>$1</s>')
|
||||
.replace(/(?<!\\)_(?=[^\s_])(([^_]|\\_)*[^\s_])(?<!\\)_/gm, '<i>$1</i>')
|
||||
// code/quoting...
|
||||
.replace(/(?<!\\)```(.*)\s*\n((\n|.)*)\h*(?<!\\)```\s*/g, pre)
|
||||
.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote)
|
||||
//.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote)
|
||||
// XXX support "\==" in mark...
|
||||
.replace(/(?<!\\)==(?=[^\s])(.*[^\s])(?<!\\)==/gm, '<mark>$1</mark>')
|
||||
// links...
|
||||
@ -417,10 +474,44 @@ var Outline = {
|
||||
.replace(/(?<!\\)\(c\)/gm, '©')
|
||||
.replace(/(?<!\\)\/!\\/gm, '⚠')
|
||||
.replace(/(?<!\\)---(?!-)/gm, '—')
|
||||
.replace(/(?<!\\)--(?!-)/gm, '–')
|
||||
.replace(/(?<!\\)--(?!-)/gm, '–') }
|
||||
var postParse = function(text){
|
||||
return text
|
||||
// quoting...
|
||||
// NOTE: this must be last...
|
||||
.replace(/(?<!\\)\\(.)/gm, '$1')
|
||||
.replace(/(?<!\\)\\(.)/gm, '$1') }
|
||||
|
||||
var parse = function(text){
|
||||
// split text into parsable and non-parsable sections...
|
||||
// split fomat:
|
||||
// [ text <match> <type> <body>, ... ]
|
||||
var pattern = /(<(pre|code)(?:|\s[^>]*)>((?:\n|.)*)<\/\2>)/g
|
||||
var sections =
|
||||
quoteParse(
|
||||
blockParse(
|
||||
preParse(text
|
||||
.replace(/\x00/g, ''))))
|
||||
.split(pattern)
|
||||
// sort out the sections...
|
||||
var parsable = []
|
||||
var quoted = []
|
||||
while(sections.length > 0){
|
||||
var [section, match] = sections.splice(0, 4)
|
||||
parsable.push(section)
|
||||
quoted.push(match) }
|
||||
// parse only the parsable sections...
|
||||
return postParse(
|
||||
inlineParse(
|
||||
parsable
|
||||
.join('\x00'))
|
||||
.split(/\x00/g)
|
||||
.map(function(section){
|
||||
return [section, quoted.shift() ?? ''] })
|
||||
.flat()
|
||||
.join('')) }
|
||||
|
||||
elem.text = parse(code)
|
||||
|
||||
return elem },
|
||||
// XXX essentially here we need to remove service stuff like some
|
||||
// attributes (collapsed, id, ...)...
|
||||
@ -482,7 +573,7 @@ var Outline = {
|
||||
text = text
|
||||
.replace(/^\s*\n/, '')
|
||||
text = ('\n' + text)
|
||||
.split(/\n(\s*)- /g)
|
||||
.split(/\n(\s*)(?:- |-\s*$)/gm)
|
||||
.slice(1)
|
||||
var tab = ' '.repeat(this.tab_size || 8)
|
||||
var level = function(lst, prev_sep=undefined, parent=[]){
|
||||
@ -747,6 +838,15 @@ var Outline = {
|
||||
if(elem.classList.contains('children')){
|
||||
return }
|
||||
|
||||
// empty outline -> create new eleemnt...
|
||||
if(elem.classList.contains('outline')
|
||||
&& elem.children.length == 0){
|
||||
// create new eleemnt and edit it...
|
||||
var block = that.Block()
|
||||
that.outline.append(block)
|
||||
that.edit(block)
|
||||
return }
|
||||
|
||||
// expand/collapse
|
||||
if(elem.classList.contains('view')
|
||||
&& elem.parentElement.getAttribute('tabindex')){
|
||||
@ -783,10 +883,14 @@ var Outline = {
|
||||
to
|
||||
: m }
|
||||
text.value = text.value.replace(/\[[Xx_]\]/g, toggle) } })
|
||||
// heboard handling...
|
||||
// keyboard handling...
|
||||
outline.addEventListener('keydown',
|
||||
function(evt){
|
||||
var elem = evt.target
|
||||
// code editing...
|
||||
if(elem.nodeName == 'CODE'
|
||||
&& elem.getAttribute('contenteditable') == 'true'){
|
||||
return }
|
||||
// update element state...
|
||||
if(elem.nodeName == 'TEXTAREA'){
|
||||
setTimeout(function(){
|
||||
@ -795,6 +899,28 @@ var Outline = {
|
||||
// handle keyboard...
|
||||
evt.key in that.keyboard
|
||||
&& that.keyboard[evt.key].call(that, evt) })
|
||||
// update code block...
|
||||
outline.addEventListener('keyup',
|
||||
function(evt){
|
||||
var elem = evt.target
|
||||
// editable code...
|
||||
if(elem.nodeName == 'CODE'
|
||||
&& elem.getAttribute('contenteditable') == 'true'){
|
||||
// XXX should we clear the syntax???
|
||||
// XXX do this only if things changed...
|
||||
delete elem.dataset.highlighted
|
||||
|
||||
var block = that.get(elem)
|
||||
var code = block.querySelector('.code')
|
||||
|
||||
var update = elem.innerText
|
||||
var i = [...block
|
||||
.querySelectorAll('.view code[contenteditable=true]')]
|
||||
.indexOf(elem)
|
||||
// update element content...
|
||||
code.value = codeBlock.replace(code.value, i, update)
|
||||
|
||||
return } })
|
||||
// toggle view/code of nodes...
|
||||
outline.addEventListener('focusin',
|
||||
function(evt){
|
||||
@ -829,7 +955,8 @@ var Outline = {
|
||||
|
||||
// XXX do a plugin...
|
||||
window.hljs
|
||||
&& hljs.highlightAll() })
|
||||
&& hljs.highlightAll()
|
||||
})
|
||||
// update .code...
|
||||
var update_code_timeout
|
||||
outline.addEventListener('change',
|
||||
@ -870,6 +997,10 @@ var Outline = {
|
||||
.replace(/>/g, '>'))
|
||||
console.log(`Parse: ${Date.now() - t}ms`)}
|
||||
|
||||
// XXX do a plugin...
|
||||
window.hljs
|
||||
&& hljs.highlightAll()
|
||||
|
||||
return this },
|
||||
}
|
||||
|
||||
|
||||
@ -26,11 +26,7 @@ var setup = function(){
|
||||
window.editor = {
|
||||
__proto__: Outline,
|
||||
}.setup(
|
||||
document.querySelector('.editor'))
|
||||
|
||||
// XXX make this a plugin...
|
||||
window.hljs
|
||||
&& hljs.highlightAll() }
|
||||
document.querySelector('.editor')) }
|
||||
|
||||
</script>
|
||||
</head>
|
||||
@ -56,19 +52,41 @@ var setup = function(){
|
||||
an we'll not get here...
|
||||
-
|
||||
- ## ToDo:
|
||||
- ASAP: editor: bksapce/del at start/end of a block should join it with prev/next
|
||||
- ASAP: editor: backsapce/del at start/end of a block should join it with prev/next
|
||||
- ASAP: editor: pressing enter in text edit mode should split text into two blocks
|
||||
- ASAP: editor: shifting nodes up/down
|
||||
- ASAP: use \\t for indent...
|
||||
- ASAP: scroll into view is bad...
|
||||
- on item click, place the cursor where it was clicked before the code expanded...
|
||||
- ~editor: semi-live update styles~
|
||||
- need to reach checkboxes via keyboard
|
||||
- persistent empty first/last node (a button to create a new node)
|
||||
- add completion percentage to blocks with todo's nested
|
||||
- _...use `[%]`, `%%`, or something similar..._
|
||||
- read-only mode
|
||||
- should bulets be on the same level as nodes or offset??
|
||||
- ASAP: need to reach checkboxes via keyboard
|
||||
- FEATURE: "percentage complete" in parent blocks with todo's nested
|
||||
- _...use `[%]` (preferred), `%%`, or something similar..._
|
||||
- FEATURE: read-only mode
|
||||
- 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(..)`
|
||||
- Code blocks and bullets:
|
||||
- ```
|
||||
code
|
||||
```
|
||||
- _bullet should be either in the middle of the block or at the first line of code (preferred)..._
|
||||
- custom element...
|
||||
- Nerd fonts (option???)
|
||||
- multiple node selection
|
||||
- copy/paste nodes/trees
|
||||
- undo
|
||||
collapsed:: true
|
||||
- delete node
|
||||
- indent/deindent
|
||||
- edit node
|
||||
- Q: can we get the caret line in a textarea???
|
||||
- _...this will fix a lot of issues with moving between blocks in edit mode..._
|
||||
- Q: do we use \\t for indent? (option???)
|
||||
- Q: can we place the cursor on item click where it was clicked before before the code expanded?
|
||||
collapsed:: true
|
||||
- for example
|
||||
- #### Click in this line and see where the cursor goes
|
||||
- _not sure how..._
|
||||
- Q: persistent empty first/last node (a button to create a new node)?
|
||||
- Q: should bullets be on the same level as nodes or offset??
|
||||
collapsed:: true
|
||||
- A) justified to bullet:
|
||||
* list item
|
||||
* list item
|
||||
@ -78,8 +96,10 @@ var setup = function(){
|
||||
* list item
|
||||
block text
|
||||
- NOTE: this is only a problem if making list-items manually -- disable???
|
||||
- FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)`
|
||||
- Nerd fonts (options?)
|
||||
- ~Q: can we edit code in a code block directly? (a-la Logseq)~
|
||||
- empty item height is a bit off...
|
||||
- ~`.editor .outline:empty` view and behavior...~
|
||||
- ~editor: semi-live update styles~
|
||||
- ~do a better expand/collapse icons~
|
||||
- ~loading from DOM -- fill textarea~
|
||||
- ~focus management~
|
||||
@ -89,17 +109,29 @@ var setup = function(){
|
||||
- ~shift subtree up/down~
|
||||
- ~create node~
|
||||
- ~edit node~
|
||||
- multiple node selection
|
||||
- copy/paste nodes/trees
|
||||
- undo
|
||||
collapsed:: true
|
||||
- delete node
|
||||
- indent/deindent
|
||||
- edit node
|
||||
- empty item height is a bit off...
|
||||
- ~serialize/deserialize~
|
||||
- ~add optional text styling to nodes~
|
||||
-
|
||||
- ## Refactoring:
|
||||
- Item parser (`.__code2html__(..)`)
|
||||
- split out
|
||||
- define api
|
||||
- define a way to extend/stack parsers
|
||||
_...add wikiwords, ..._
|
||||
- Format parser/generator
|
||||
- split out
|
||||
- define api
|
||||
- experiment with clean markdown as format
|
||||
- CSS
|
||||
- separate out theming
|
||||
- separate out settings
|
||||
- Actions -- move user actions (code in `.keyboard`) into methods
|
||||
- Move to `keyboard.js`
|
||||
- Plugin architecture
|
||||
- Q: do we need `features.js` and/or `actions.js`
|
||||
- Q: do we need a concatenative API??
|
||||
- `<block>.get() -> <block>`
|
||||
-
|
||||
- ## TEST
|
||||
- ### Formatting:
|
||||
- Styles
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user