Compare commits

..

No commits in common. "6c484194ae80e71485fc46af0aa502169bbcfdd8" and "9489220ec3934be81e09db06844f4c44938cb390" have entirely different histories.

2 changed files with 75 additions and 129 deletions

View File

@ -138,25 +138,23 @@ var plugin = {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// XXX style attributes...
var attributes = { var attributes = {
__proto__: plugin, __proto__: plugin,
__parse__: function(text, editor, elem){ __pre_parse__: function(text, editor, elem){
var skip = new Set([
'text',
'focused',
'collapsed',
'id',
'children',
'style',
])
return text return text
+ Object.entries(elem) // hidden attributes...
.reduce(function(res, [key, value]){ // XXX make this generic...
return skip.has(key) ? // collapsed...
res .replace(/(\n|^)\s*collapsed::\s*(.*)\s*(\n|$)/,
: res + `<br>${key}: ${value}` }, '') }, function(_, value){
elem.collapsed = value.trim() == 'true'
return '' })
// id...
.replace(/(\n|^)\s*id::\s*(.*)\s*(\n|$)/,
function(_, value){
elem.id = value.trim()
return '' }) },
} }
@ -616,6 +614,7 @@ var Outline = {
// - parsing // - parsing
// - event dropping // - event dropping
plugins: [ plugins: [
attributes,
blocks, blocks,
quoted, quoted,
@ -623,8 +622,6 @@ var Outline = {
// treating '[_] ... [_]' as italic... // treating '[_] ... [_]' as italic...
tasks, tasks,
styling, styling,
// XXX
//attributes,
tables, tables,
symbols, symbols,
//syntax, //syntax,
@ -841,28 +838,26 @@ var Outline = {
update: function(node='focused', data){ update: function(node='focused', data){
var node = this.get(node) var node = this.get(node)
data ??= this.data(node, false) data ??= this.data(node, false)
for(var [attr, value] of Object.entries(data)){
if(attr == 'children'){
continue }
var parsed = {} if(attr == 'text'){
if('text' in data){
var text = node.querySelector('textarea') var text = node.querySelector('textarea')
var html = node.querySelector('span') var html = node.querySelector('span')
if(this.__code2html__){ if(this.__code2html__){
// NOTE: we are ignoring the .collapsed attr here // NOTE: we are ignoring the .collapsed attr here
parsed = this.__code2html__(data.text, {...data}) var parsed = this.__code2html__(data.text)
html.innerHTML = parsed.text html.innerHTML = parsed.text
// heading... // heading...
node.classList.remove(...this.__styles) node.classList.remove(...this.__styles)
parsed.style parsed.style
&& node.classList.add(...parsed.style) && node.classList.add(...parsed.style)
delete parsed.style
} else { } else {
html.innerHTML = data.text } html.innerHTML = data.text }
text.value = data.text text.value = data.text
// XXX this does not seem to work until we click in the textarea... // XXX this does not seem to work until we click in the textarea...
text.autoUpdateSize() } text.autoUpdateSize()
for(var [attr, value] of Object.entries({...data, ...parsed})){
if(attr == 'children' || attr == 'text'){
continue } continue }
var type = this.__block_attrs__[attr] var type = this.__block_attrs__[attr]
@ -877,7 +872,8 @@ var Outline = {
(value ? (value ?
node.setAttribute(attr, '') node.setAttribute(attr, '')
: node.removeAttribute(attr)) : node.removeAttribute(attr))
: value != null ? : (attr in data
&& value != null) ?
node.setAttribute(attr, value) node.setAttribute(attr, value)
: node.removeAttribute(attr) } } : node.removeAttribute(attr) } }
this.__change__() this.__change__()
@ -992,13 +988,16 @@ var Outline = {
this.__change__() this.__change__()
return this }, return this },
// block render... // block serialization...
// 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__(..) // NOTE: this is auto-populated by .__code2html__(..)
__styles: undefined, __styles: undefined,
__code2html__: function(code, elem={}){ __code2html__: function(code){
var that = this var that = this
var elem = {
collapsed: false,
}
// only whitespace -> keep element blank... // only whitespace -> keep element blank...
if(code.trim() == ''){ if(code.trim() == ''){
@ -1014,9 +1013,6 @@ var Outline = {
}[stage] }[stage]
return that.threadPlugins(meth, text, that, elem) } return that.threadPlugins(meth, text, that, elem) }
elem = this.parseBlockAttrs(code, elem)
code = elem.text
// stage: pre... // stage: pre...
var text = run('pre', var text = run('pre',
// pre-sanitize... // pre-sanitize...
@ -1119,54 +1115,6 @@ var Outline = {
.flat() .flat()
.join('\n') }, .join('\n') },
//
// Parse attrs...
// .parseBlockAttrs(<text>[, <elem>])
// -> <elem>
//
// Parse attrs keeping non-system attrs in .text...
// .parseBlockAttrs(<text>, true[, <elem>])
// -> <elem>
//
// Parse attrs keeping all attrs in .text...
// .parseBlockAttrs(<text>, 'all'[, <elem>])
// -> <elem>
//
parseBlockAttrs: function(text, keep=false, elem={}){
if(typeof(keep) == 'object'){
elem = keep
keep = typeof(elem) == 'boolean' ?
elem
: false }
var system = this.__block_attrs__
var clean = text
// XXX for some reason changing the first group into (?<= .. )
// still eats up the whitespace...
// ...putting the same pattern in a normal group and
// returning it works fine...
//.replace(/(?<=[\n\h]*)(?:(?:\n|^)\s*\w*\s*::\s*[^\n]*\s*)*$/,
.replace(/([\n\t ]*)(?:(?:\n|^)[\t ]*\w*[\t ]*::[\t ]*[^\n]*[\t ]*)+$/,
function(match, ws){
var attrs = match
.trim()
.split(/(?:[\t ]*::[\t ]*|[\t ]*\n[\t ]*)/g)
while(attrs.length > 0){
var [name, val] = attrs.splice(0, 2)
elem[name] =
val == 'true' ?
true
: val == 'false' ?
false
: val
// keep non-system attrs...
if(keep
&& !(name in system)){
ws += `\n${name}::${val}` } }
return ws })
elem.text = keep == 'all' ?
text
: clean
return elem },
parse: function(text){ parse: function(text){
var that = this var that = this
text = text text = text
@ -1186,14 +1134,29 @@ var Outline = {
// same level... // same level...
if(sep.length == prev_sep.length){ if(sep.length == prev_sep.length){
var [_, block] = lst.splice(0, 2) var [_, block] = lst.splice(0, 2)
var attrs = that.parseBlockAttrs(block) var attrs = {
attrs.text = that.__text2code__(attrs.text
// normalize indent...
.split(new RegExp('\n'+sep+' ', 'g'))
.join('\n'))
parent.push({
collapsed: false, collapsed: false,
focused: false, focused: false,
}
block = block
// XXX generalize attr processing...
.replace(/\n\s*id::\s*(.*)\s*$/,
function(_, value){
attrs.id = value
return '' })
.replace(/\n\s*focused::\s*(.*)\s*$/,
function(_, value){
attrs.focused = value == 'true'
return '' })
.replace(/\n\s*collapsed::\s*(.*)\s*$/,
function(_, value){
attrs.collapsed = value == 'true'
return '' })
parent.push({
text: that.__text2code__(block
// normalize indent...
.split(new RegExp('\n'+sep+' ', 'g'))
.join('\n')),
...attrs, ...attrs,
children: [], children: [],
}) })
@ -1227,7 +1190,6 @@ var Outline = {
children.classList.add('children') children.classList.add('children')
children.setAttribute('tabindex', '-1') children.setAttribute('tabindex', '-1')
block.append(code, html, children) block.append(code, html, children)
this.update(block, data) this.update(block, data)
// place... // place...
@ -1364,18 +1326,6 @@ var Outline = {
this.toggleCollapse(false) this.toggleCollapse(false)
: this.focus('next') } }, : this.focus('next') } },
Home: function(evt){
if(this.get('edited')
&& !evt.ctrlKey){
return }
evt.preventDefault()
this.focus(0) },
End: function(evt){
if(this.get('edited')
&& !evt.ctrlKey){
return }
evt.preventDefault()
this.focus(-1) },
PageUp: function(evt){ PageUp: function(evt){
var edited = this.get('edited') var edited = this.get('edited')
if(!edited if(!edited
@ -1391,7 +1341,7 @@ var Outline = {
evt.preventDefault() evt.preventDefault()
this.shift('down') } }, this.shift('down') } },
// indent.. // indent...
Tab: function(evt){ Tab: function(evt){
evt.preventDefault() evt.preventDefault()
var edited = this.get('edited') var edited = this.get('edited')
@ -1611,9 +1561,7 @@ var Outline = {
var elem = evt.target var elem = evt.target
if(elem.classList.contains('code')){ if(elem.classList.contains('code')){
var block = elem.parentElement var block = elem.parentElement
// clean out attrs... that.update(block, { text: elem.value })
elem.value = that.parseBlockAttrs(elem.value).text
that.update(block)
// give the browser a chance to update the DOM... // give the browser a chance to update the DOM...
// XXX revise... // XXX revise...
setTimeout(function(){ setTimeout(function(){

View File

@ -38,18 +38,24 @@ var setup = function(){
- An outline-based markdown editor experiment - An outline-based markdown editor experiment
- ### Infuences:: - ### Infuences::
- Logseq - Logseq
- Conboy (Nokia N900's Tomboy clone) - Tomboy
- Bonsai - Bonsai
- -
- // Seems that I unintentionally implemented quite a chunk of the markdown spec ;) - // Seems that I unintentionally implemented quite a chunk of the markdown spec ;)
- -
- ## Bugs: - ## Bugs:
- BUG: editor: FF seems to update the style every other key press -- should be live... - 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: - ## ToDo:
- pgup/pgdown/~home/end~ buttons - ASAP: unify attr parsing
- _now duplicated in `.parse(..)` and `.__code2html__(..)`_
- might be a good idea to add a special text parse stage and use in on both branches...
- ASAP: attrs in editor are not parsed correctly (see: [attrs](#attributes))
- ASAP: multiple attrs are not handled correctly (see: [attrs](#attributes))
- ASAP: style attrs (see: [attrs](#attributes))
- ASAP: scroll into view is bad...
- ASAP: mobile browsers behave quite chaotically ignoring parts of the styling...
- pgup/pgdown/home/end buttons
- identify a block (index, id, ...) - identify a block (index, id, ...)
- FEATURE: "crop" -- view block tree separately... - FEATURE: "crop" -- view block tree separately...
- focus - focus
@ -75,7 +81,6 @@ var setup = function(){
- embed css - embed css
- cleanup html - cleanup html
- generate ideomatic html (???) - generate ideomatic html (???)
- style attrs (see: [attrs](#attributes))
- FEATURE: `collapse-children:: true` block option -- when loading collapse all immediate children - 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(..)` - FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)`
- table inline editing a-la code editing -- click cell and edit directly... - table inline editing a-la code editing -- click cell and edit directly...
@ -106,12 +111,6 @@ var setup = function(){
block text block text
- NOTE: this is only a problem if making list-items manually -- disable??? - NOTE: this is only a problem if making list-items manually -- disable???
- empty item height is a bit off... - empty item height is a bit off...
- 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...
- 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... - DONE call `.sync()` on all changes...
- DONE show list bullet if node is empty but edited... - DONE show list bullet if node is empty but edited...
collapsed:: true collapsed:: true
@ -264,8 +263,7 @@ var setup = function(){
- [_] we can also add inline [x] checkboxes and states: [%] - [_] we can also add inline [x] checkboxes and states: [%]
- navigating checkboxes in view mode can be done via `ctrl-left` / `ctrl-right` and toggling is done via `space` - navigating checkboxes in view mode can be done via `ctrl-left` / `ctrl-right` and toggling is done via `space`
- links - links
- [link](about:blank) - [example](about:blank)
- [local links](#attributes)
- https://example.com - https://example.com
- ./path/to/file /path/to -- _not supported yet_ - ./path/to/file /path/to -- _not supported yet_
- Tables - Tables