Compare commits

..

No commits in common. "30bbe21088ae3d612e904a106fa8aec4b6b499c7" and "a7d9d9e40fe160adb663dc7da8d13942853e6b38" have entirely different histories.

3 changed files with 29 additions and 75 deletions

View File

@ -1,6 +1,6 @@
:root { :root {
--button-size: 2em; --button-size: 5em;
font-family: sans-serif; font-family: sans-serif;
font-size: 5mm; font-size: 5mm;
@ -93,11 +93,8 @@
} }
.editor .toolbar button { .editor .toolbar button {
display: block; display: block;
width: var(--button-size); width: var(--button-size);
height: var(--button-size); height: var(--button-size);
font-size: var(--button-size);
} }

View File

@ -24,7 +24,6 @@ var atLine = function(elem, index){
//--------------------------------------------------------------------- //---------------------------------------------------------------------
var Node = { var Node = {
@ -76,12 +75,6 @@ var Outline = {
right_key_expands: true, right_key_expands: true,
get outline(){
return this.dom.querySelector('.outline') },
get toolbar(){
return this.dom.querySelector('.toolbar') },
// XXX revise name... // XXX revise name...
Block: function(place=none){ Block: function(place=none){
var block = document.createElement('div') var block = document.createElement('div')
@ -137,23 +130,21 @@ var Outline = {
if(node == 'prev' || node == 'previous'){ if(node == 'prev' || node == 'previous'){
return this.get('focused', -1) } return this.get('focused', -1) }
var outline = this.outline
// node lists... // node lists...
var NO_NODES = {} var NO_NODES = {}
var nodes = var nodes =
node == 'all' ? node == 'all' ?
[...outline.querySelectorAll('[tabindex]')] [...this.dom.querySelectorAll('[tabindex]')]
: node == 'visible' ? : node == 'visible' ?
[...outline.querySelectorAll('[tabindex]')] [...this.dom.querySelectorAll('[tabindex]')]
.filter(function(e){ .filter(function(e){
return e.offsetParent != null }) return e.offsetParent != null })
: node == 'editable' ? : node == 'editable' ?
[...outline.querySelectorAll('[tabindex]>textarea')] [...this.dom.querySelectorAll('[tabindex]>textarea')]
: node == 'selected' ? : node == 'selected' ?
[...outline.querySelectorAll('[tabindex][selected]')] [...this.dom.querySelectorAll('[tabindex][selected]')]
: node == 'top' ? : node == 'top' ?
[...outline.children] [...this.dom.children]
.filter(function(elem){ .filter(function(elem){
return elem.getAttribute('tabindex') != null }) return elem.getAttribute('tabindex') != null })
: ['siblings', 'children'].includes(node) ? : ['siblings', 'children'].includes(node) ?
@ -175,15 +166,15 @@ var Outline = {
typeof(node) == 'number' ? typeof(node) == 'number' ?
this.at(node) this.at(node)
: node == 'focused' ? : node == 'focused' ?
(outline.querySelector(`[tabindex]:focus`) (this.dom.querySelector(`[tabindex]:focus`)
|| outline.querySelector(`textarea:focus`)?.parentElement || this.dom.querySelector(`textarea:focus`)?.parentElement
|| outline.querySelector('[tabindex].focused')) || this.dom.querySelector('[tabindex].focused'))
: node == 'parent' ? : node == 'parent' ?
this.get('focused')?.parentElement this.get('focused')?.parentElement
: node : node
var edited var edited
if(node == 'edited'){ if(node == 'edited'){
edited = outline.querySelector(`textarea:focus`) edited = this.dom.querySelector(`textarea:focus`)
node = edited?.parentElement } node = edited?.parentElement }
if(!node || typeof(node) == 'string'){ if(!node || typeof(node) == 'string'){
@ -288,22 +279,14 @@ var Outline = {
// block serialization... // block serialization...
__code2html__: function(code){ __code2html__: function(code){
return code return code },
// XXX STUB...
.replace(/\*(.*)\*/g, '<b>$1</b>')
.replace(/~([^~]*)~/g, '<s>$1</s>')
.replace(/_([^_]*)_/g, '<i>$1</i>') },
__html2code__: function(html){ __html2code__: function(html){
return html return html },
// XXX STUB...
.replace(/<b>(.*)<\/b>/g, '*$1*')
.replace(/<s>(.*)<\/s>/g, '~$1~')
.replace(/<i>(.*)<\/i>/g, '_$1_') },
// serialization... // serialization...
json: function(node){ json: function(node){
var that = this var that = this
node ??= this.outline node ??= this.dom
return [...node.children] return [...node.children]
.map(function(elem){ .map(function(elem){
return elem.nodeName != 'DIV' ? return elem.nodeName != 'DIV' ?
@ -335,14 +318,7 @@ var Outline = {
return text }, return text },
// XXX use .__code2html__(..) // XXX use .__code2html__(..)
load: function(data){ load: function(){},
// text...
if(typeof(data) == 'string'){
// XXX
}
// json...
// XXX
},
// XXX add scrollIntoView(..) to nav... // XXX add scrollIntoView(..) to nav...
keyboard: { keyboard: {
@ -370,7 +346,7 @@ var Outline = {
// horizontal navigation / collapse... // horizontal navigation / collapse...
// XXX if at start/end of element move to prev/next... // XXX if at start/end of element move to prev/next...
ArrowLeft: function(evt){ ArrowLeft: function(evt){
if(this.outline.querySelector('textarea:focus')){ if(this.dom.querySelector('.outline textarea:focus')){
// XXX if at end of element move to next... // XXX if at end of element move to next...
return } return }
;((this.left_key_collapses ;((this.left_key_collapses
@ -380,7 +356,7 @@ var Outline = {
this.toggleCollapse(true) this.toggleCollapse(true)
: this.get('parent')?.focus() }, : this.get('parent')?.focus() },
ArrowRight: function(evt){ ArrowRight: function(evt){
if(this.outline.querySelector('textarea:focus')){ if(this.dom.querySelector('.outline textarea:focus')){
// XXX if at end of element move to next... // XXX if at end of element move to next...
return } return }
if(this.right_key_expands){ if(this.right_key_expands){
@ -425,7 +401,7 @@ var Outline = {
this.Block('after')?.querySelector('textarea')?.focus() this.Block('after')?.querySelector('textarea')?.focus()
: this.get()?.querySelector('textarea')?.focus() }, : this.get()?.querySelector('textarea')?.focus() },
Escape: function(evt){ Escape: function(evt){
this.outline.querySelector('textarea:focus')?.parentElement?.focus() }, this.dom.querySelector('textarea:focus')?.parentElement?.focus() },
Delete: function(evt){ Delete: function(evt){
if(evt.target.isContentEditable){ if(evt.target.isContentEditable){
return } return }
@ -448,17 +424,17 @@ var Outline = {
setup: function(dom){ setup: function(dom){
var that = this var that = this
this.dom = dom this.dom = dom
var outline = dom.querySelector('.outline')
// outline...
var outline = this.outline
// update stuff already in DOM... // update stuff already in DOM...
for(var elem of [...outline.querySelectorAll('textarea')]){ for(var elem of [...outline.querySelectorAll('textarea')]){
elem.autoUpdateSize() } elem.autoUpdateSize() }
// heboard handling... // heboard handling...
outline.addEventListener('keydown', outline.addEventListener('keydown',
function(evt){ function(evt){
evt.key in that.keyboard evt.key in that.keyboard
&& that.keyboard[evt.key].call(that, evt) }) && that.keyboard[evt.key].call(that, evt) })
// toggle view/code of nodes... // toggle view/code of nodes...
outline.addEventListener('focusin', outline.addEventListener('focusin',
function(evt){ function(evt){
@ -485,25 +461,6 @@ var Outline = {
that.__code2html__(node.value) that.__code2html__(node.value)
: node.value } }) : node.value } })
// toolbar...
var toolbar = this.toolbar
if(toolbar){
// handle return of focus when clicking toolbar...
var focus_textarea
var cahceNodeType = function(){
// NOTE: for some reason .activeElement returns an element
// that is not in the DOM after the action is done...
focus_textarea = document.activeElement.nodeName == 'TEXTAREA' }
var refocusNode = function(){
focus_textarea ?
editor.get().querySelector('textarea').focus()
: editor.get().focus()
focus_textarea = undefined }
// cache the focused node type before focus changes...
toolbar.addEventListener('mousedown', cahceNodeType)
// refocus the node after we are done...
toolbar.addEventListener('click', refocusNode) }
return this }, return this },
} }

View File

@ -49,11 +49,12 @@ text lines</span><textarea></textarea>
</div> </div>
</div> </div>
<div class="toolbar"> <div class="toolbar">
<button onclick="editor.deindent().focus()">&lt;</button> <!-- XXX these all should focus the node back so as not to hide the keyboard on mobine -->
<button onclick="editor.indent().focus()">&gt;</button> <button onclick="editor.deindent()">&lt;</button>
<button onclick="editor.Block('before').focus()">-<sup>+</sup>-</button> <button onclick="editor.indent()">&gt;</button>
<button onclick="editor.Block('after').focus()">-<sub>+</sub>-</button> <button onclick="editor.Block('before').focus()" style="text-decoration:underline">+</button>
<button onclick="editor.toggleCollapse()?.focus()">&#709;&#708;</button> <button onclick="editor.Block('after').focus()" style="text-decoration:overline">+</button>
<button onclick="editor.toggleCollapse()">+/-</button>
<button onclick="editor.remove()">&times;</button> <button onclick="editor.remove()">&times;</button>
</div> </div>
</div> </div>
@ -62,9 +63,8 @@ text lines</span><textarea></textarea>
<pre> <pre>
TODO: TODO:
- Firefox compatibility -- remove ':has(..)' - mouse controls
- <s>focus management</s> - touch controls
- <s>mouse/touch controls</s>
- <s>navigation</s> - <s>navigation</s>
- <s>expand/collapse subtree</s> - <s>expand/collapse subtree</s>
- <s>shift subtree up/down</s> - <s>shift subtree up/down</s>