Compare commits

..

No commits in common. "7f2b027a7be4160206752c5b8ddebe4c70204b43" and "9b2b232f691b787e5fe7e0899607c1986dcf2c83" have entirely different histories.

3 changed files with 61 additions and 136 deletions

View File

@ -110,59 +110,14 @@
} }
/* Styles */ .editor .outline h1,
.editor .outline h2,
.editor .outline .heading-1>span, .editor .outline h3,
.editor .outline .heading-1>textarea, .editor .outline h4,
.editor .outline .heading-2>span, .editor .outline h5,
.editor .outline .heading-2>textarea, .editor .outline h6 {
.editor .outline .heading-3>span, margin-top: 0.5em;
.editor .outline .heading-3>textarea, margin-bottom: 0.5em;
.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 {
font-weight: bold;
}
.editor .outline .heading-1>span,
.editor .outline .heading-1>textarea {
font-size: 2.5em;
}
.editor .outline .heading-2>span,
.editor .outline .heading-2>textarea {
font-size: 1.9em;
}
.editor .outline .heading-3>span,
.editor .outline .heading-3>textarea {
font-size: 1.5em;
}
.editor .outline .heading-4>span,
.editor .outline .heading-4>textarea {
font-size: 1.3em;
}
.editor .outline .heading-5>span,
.editor .outline .heading-5>textarea {
font-size: 1.1em;
}
.editor .outline .heading-6>span,
.editor .outline .heading-6>textarea {
font-size: 1em;
}
/* XXX EXPERIMENTAL -- not sure about this... */
.editor .outline .list>[tabindex]:before {
display: inline-block;
position: absolute;
content: "";
top: 0.6em;
left: -0.8em;
width: 0.5em;
height: 0.5em;
background: silver;
} }

View File

@ -75,7 +75,6 @@ var Outline = {
left_key_collapses: true, left_key_collapses: true,
right_key_expands: true, right_key_expands: true,
code_update_interval: 5000, code_update_interval: 5000,
tab_size: 4,
get code(){ get code(){
@ -216,30 +215,6 @@ var Outline = {
focus: function(node='focused', offset){}, focus: function(node='focused', offset){},
edit: function(node='focused', offset){}, edit: function(node='focused', offset){},
// XXX should this handle children???
update: function(node='focused', data){
var node = this.get(node)
data.collapsed ?
node.setAttribute('collapsed', '')
: node.removeAttribute('collapsed')
if(data.text){
var text = node.querySelector('textarea')
var html = node.querySelector('span')
if(this.__code2html__){
// NOTE: we are ignoring the .collapsed attr here
var parsed = this.__code2html__(data.text)
html.innerHTML = parsed.text
// heading...
parsed.style ?
node.classList.add(parsed.style)
: node.classList.remove(...this.__styles__)
} else {
html.innerHTML = data.text }
text.value = data.text
// XXX this does not see to work until we click in the textarea...
text.autoUpdateSize() }
return node },
indent: function(node='focused', indent=true){ indent: function(node='focused', indent=true){
// .indent(<indent>) // .indent(<indent>)
if(node === true || node === false){ if(node === true || node === false){
@ -309,27 +284,10 @@ var Outline = {
// XXX STUB... // XXX STUB...
// XXX shouild we support headings + other formatting per block??? // XXX shouild we support headings + other formatting per block???
// XXX these should be symetrical -- now one returns text the other an object... // XXX these should be symetrical -- now one returns text the other an object...
__styles__: [
'heading-1',
'heading-2',
'heading-3',
'heading-4',
'heading-5',
'heading-6',
'list',
],
__code2html__: function(code){ __code2html__: function(code){
var elem = { var elem = {
collapsed: false, collapsed: false,
} }
var heading = function(level){
return function(_, text){
elem.style = 'heading-'+level
return text } }
var style = function(style){
return function(_, text){
elem.style = style
return text } }
elem.text = code elem.text = code
// attributes... // attributes...
// XXX make this generic... // XXX make this generic...
@ -338,22 +296,38 @@ var Outline = {
elem.collapsed = value.trim() == 'true' elem.collapsed = value.trim() == 'true'
return '' }) return '' })
// markdown... // markdown...
.replace(/^TODO\s*(.*)$/, '<input type="checkbox"> $1') .replace(/^######\s*(.*)\s*(\n|$)/, '<h6>$1</h6>')
.replace(/^DONE\s*(.*)$/, '<input type="checkbox" checked> $1') .replace(/^#####\s*(.*)\s*(\n|$)/, '<h5>$1</h5>')
.replace(/^######\s*(.*)$/, style('heading-6')) .replace(/^####\s*(.*)\s*(\n|$)/, '<h4>$1</h4>')
.replace(/^#####\s*(.*)$/, style('heading-5')) .replace(/^###\s*(.*)\s*(\n|$)/, '<h3>$1</h3>')
.replace(/^####\s*(.*)$/, style('heading-4')) .replace(/^##\s*(.*)\s*(\n|$)/, '<h2>$1</h2>')
.replace(/^###\s*(.*)$/, style('heading-3')) .replace(/^#\s*(.*)\s*(\n|$)/, '<h1>$1</h1>')
.replace(/^##\s*(.*)$/, style('heading-2'))
.replace(/^#\s*(.*)$/, style('heading-1'))
//.replace(/^[-\*]\s*(.*)$/, style('list'))
.replace(/^\s*(.*):\s*$/, style('list'))
.replace(/\*(.*)\*/g, '<b>$1</b>') .replace(/\*(.*)\*/g, '<b>$1</b>')
.replace(/~([^~]*)~/g, '<s>$1</s>') .replace(/~([^~]*)~/g, '<s>$1</s>')
.replace(/_([^_]*)_/g, '<i>$1</i>') .replace(/_([^_]*)_/g, '<i>$1</i>')
.replace(/(\n|^)---*\h*(\n|$)/, '$1<hr>') .replace(/(\n|^)---*\h*(\n|$)/, '$1<hr>')
.replace(/\n/g, '<br>\n') .replace(/\n/g, '<br>\n')
return elem }, return elem },
__html2code__: function(html){
var heading = function(level){
return function(_, text, rest){
return `${'#'.repeat(level)} ${text}${
(rest != '' ?
'\n'+ rest
: '') }` } }
return html
.replace(/<hr>$/, '---')
.replace(/<hr>/, '---\n')
.replace(/^<h6>(.*)<\/h6>(.*)$/g, heading(6))
.replace(/^<h5>(.*)<\/h5>(.*)$/g, heading(5))
.replace(/^<h4>(.*)<\/h4>(.*)$/g, heading(4))
.replace(/^<h3>(.*)<\/h3>(.*)$/g, heading(3))
.replace(/^<h2>(.*)<\/h2>(.*)$/g, heading(2))
.replace(/^<h1>(.*)<\/h1>(.*)$/g, heading(1))
.replace(/<b>(.*)<\/b>/g, '*$1*')
.replace(/<s>(.*)<\/s>/g, '~$1~')
.replace(/<i>(.*)<\/i>/g, '_$1_')
.replace(/<br>\s*/g, '\n') },
// serialization... // serialization...
json: function(node){ json: function(node){
@ -364,12 +338,13 @@ var Outline = {
return elem.nodeName != 'DIV' ? return elem.nodeName != 'DIV' ?
[] []
: [{ : [{
text: elem.querySelector('textarea').value, text: that.__html2code__ ?
that.__html2code__(elem.querySelector('span').innerHTML)
: elem.querySelector('span').innerHTML,
collapsed: elem.getAttribute('collapsed') != null, collapsed: elem.getAttribute('collapsed') != null,
children: that.json(elem) children: that.json(elem)
}] }) }] })
.flat() }, .flat() },
// XXX add option to customize indent size...
text: function(node, indent, level){ text: function(node, indent, level){
// .text(<indent>, <level>) // .text(<indent>, <level>)
if(typeof(node) == 'string'){ if(typeof(node) == 'string'){
@ -400,10 +375,9 @@ var Outline = {
text = ('\n' + text) text = ('\n' + text)
.split(/\n(\s*)- /g) .split(/\n(\s*)- /g)
.slice(1) .slice(1)
var tab = ' '.repeat(this.tab_size || 8)
var level = function(lst, prev_sep=undefined, parent=[]){ var level = function(lst, prev_sep=undefined, parent=[]){
while(lst.length > 0){ while(lst.length > 0){
sep = lst[0].replace(/\t/g, tab) sep = lst[0]
// deindent... // deindent...
if(prev_sep != null if(prev_sep != null
&& sep.length < prev_sep.length){ && sep.length < prev_sep.length){
@ -437,10 +411,19 @@ var Outline = {
data = {} } data = {} }
var block = document.createElement('div') var block = document.createElement('div')
block.setAttribute('tabindex', '0') block.setAttribute('tabindex', '0')
data.collapsed
&& block.setAttribute('collapsed', '')
var text = document.createElement('textarea') var text = document.createElement('textarea')
var html = document.createElement('span') var html = document.createElement('span')
block.append(text, html) block.append(text, html)
this.update(block, data) if(data.text){
html.innerHTML = this.__code2html__ ?
// NOTE: we are ignoring the .collapsed attr here (XXX)
this.__code2html__(data.text).text
: data.text
text.value = data.text
// XXX this does not see to work until we click in the textarea...
text.autoUpdateSize() }
var cur = this.get() var cur = this.get()
place && cur place && cur
&& cur[place](block) && cur[place](block)
@ -613,14 +596,23 @@ var Outline = {
// textarea... // textarea...
if(node.nodeName == 'TEXTAREA' if(node.nodeName == 'TEXTAREA'
&& node?.nextElementSibling?.nodeName == 'SPAN'){ && node?.nextElementSibling?.nodeName == 'SPAN'){
node.value =
that.__html2code__ ?
that.__html2code__(node.nextElementSibling.innerHTML)
: node.nextElementSibling.innerHTML
node.updateSize() } }) node.updateSize() } })
outline.addEventListener('focusout', outline.addEventListener('focusout',
function(evt){ function(evt){
var node = evt.target var node = evt.target
if(node.nodeName == 'TEXTAREA' if(node.nodeName == 'TEXTAREA'
&& node?.nextElementSibling?.nodeName == 'SPAN'){ && node?.nextElementSibling?.nodeName == 'SPAN'){
var block = node.parentElement if(that.__code2html__){
that.update(block, { text: node.value }) } }) var data = that.__code2html__(node.value)
node.nextElementSibling.innerHTML = data.text
data.collapsed
&& node.parentElement.setAttribute('collapsed', '')
} else {
node.nextElementSibling.innerHTML = node.value } } })
// update .code... // update .code...
var update_code_timeout var update_code_timeout
outline.addEventListener('change', outline.addEventListener('change',
@ -630,6 +622,7 @@ var Outline = {
update_code_timeout = setTimeout( update_code_timeout = setTimeout(
function(){ function(){
update_code_timeout = undefined update_code_timeout = undefined
console.log('SYNC')
that.sync() }, that.sync() },
that.code_update_interval || 5000) }) that.code_update_interval || 5000) })

View File

@ -28,10 +28,6 @@ var setup = function(){
<div class="code"> <div class="code">
- # Outline editor prototype - # Outline editor prototype
- ## TODO - ## TODO
- BUG: delete in edit mode deletes node
- BUG: multiline blocks do not indent correctly in editor
- make checkboxes clickable
- editor: enter on an expanded parent node should create child (currently next sibling)
- 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
@ -39,7 +35,7 @@ var setup = function(){
- handle up/down on wrapped blocks - handle up/down on wrapped blocks
_...can't seem to get caret line in a non-hacky way_ _...can't seem to get caret line in a non-hacky way_
- persistent empty first/last node (a button to create a new node) - persistent empty first/last node (a button to create a new node)
- ~loading from DOM -- fill textarea~ - loading from DOM -- fill textarea
- ~focus management~ - ~focus management~
- ~mouse/touch controls~ - ~mouse/touch controls~
- ~navigation~ - ~navigation~
@ -58,25 +54,6 @@ var setup = function(){
- ~add optional text styling to nodes~ - ~add optional text styling to nodes~
- -
- ## TEST - ## TEST
- Formatting
- Styles
- # Heading 1
- ## Heading 2
- ### Heading 3
- #### Heading 4
- ##### Heading 5
- ###### Heading 6
- Text
- List::
- a
- b
- c
- line
- ---
- basic inline *bold*, _italic_ and ~striked~
- To do items
- TODO undone item
- DONE done item
- A - A
collapsed:: true collapsed:: true
- a - a