Compare commits

..

6 Commits

Author SHA1 Message Date
d21d233b07 fixes...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 17:37:02 +03:00
b80312497c notes...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 15:26:09 +03:00
f07a4e5b66 notes...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 15:21:12 +03:00
bf8ac4e089 notes + fix + cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 15:18:30 +03:00
e2092e808d cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 15:05:02 +03:00
2bd9781951 implemented css-based crop...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2023-10-25 15:04:41 +03:00
3 changed files with 86 additions and 87 deletions

View File

@ -47,16 +47,39 @@
display: none;
}
.editor .children {
/* header */
.editor .header {
margin: 1em var(--outline-padding);
padding-bottom: 1.2em;
border-bottom: solid 1px rgba(0,0,0,0.15);
}
.editor .header:empty {
display: none;
}
.editor .header .path-item {
color: gray;
cursor: pointer;
/* XXX needs more work... */
max-width: 10rem;
text-overflow: ellipsis;
}
.editor .header .path-item:hover {
text-decoration: underline;
}
.editor .header .path-item:first-child {
padding-left: 3em;
margin-left: -2em;
}
.editor .header,
.editor .outline {
display: block;
position: relative;
padding: 1em var(--outline-padding);
padding-bottom: 1.2em
padding-bottom: 1.2em;
}
/* virtual empty block... */
@ -69,21 +92,6 @@
.editor .outline:empty:hover:after {
}
/* XXX header */
.editor .header {
}
.editor .header:empty {
display: none;
}
/* XXX needs more work... *//*
.editor .header span {
display: inline;
max-width: 10rem;
text-overflow: ellipsis;
overflow: hidden;
}
*/
.editor .outline .block {
position: relative;
@ -93,7 +101,8 @@
.editor.block-offsets .outline .block {
border-left: solid 1px silver;
}
.editor .outline .block .block {
.editor .outline .block .block,
.editor.crop .outline .block[cropped] .block[cropped] {
margin-left: var(--item-indent);
}
.editor .outline .block>.text {
@ -255,6 +264,25 @@ editor .outline .block:focus {
}
/* crop... */
/* NOTE: also see rules for: .editor .outline .block .block
* ...can we avoid this?? (XXX) */
.editor.crop .outline .block:not([cropped]) {
padding: 0;
border: none;
background: none;
}
.editor.crop .outline .block:not([cropped])>.text {
display: none;
}
.editor.crop .outline .block[cropped] {
margin-left: 0;
}
.editor.crop .outline .block[cropped] .text {
display: block;
}
.editor .toolbar {
display: inline-block;
position: absolute;

View File

@ -895,18 +895,18 @@ var Outline = {
: offset == 'visible' ?
[...node.querySelectorAll('.block')]
.filter(function(e){
return e.offsetParent != null })
return e.querySelector('.view').offsetParent != null })
: offset == 'viewport' ?
[...node.querySelectorAll('.block')]
.filter(function(e){
return e.offsetParent != null
return e.querySelector('.view').offsetParent != null
&& e.querySelector('.code').visibleInViewport() })
: offset == 'editable' ?
[...node.querySelectorAll('.block>.code')]
: offset == 'selected' ?
[...node.querySelectorAll('.block[selected]')]
.filter(function(e){
return e.offsetParent != null })
return e.querySelector('.view').offsetParent != null })
: offset == 'children' ?
children(node)
: offset == 'siblings' ?
@ -1145,70 +1145,35 @@ var Outline = {
return this },
// crop...
// XXX shoud we control crops as "crop in" / "crop out" instead of crom/uncrop???
// XXX add crop-level/path indicator...
__crop_stack: undefined,
crop: function(node='focused'){
var that = this
var stack = this.__crop_stack =
this.__crop_stack ?? []
var state = stack[0] = stack[0] ?? this.json()
var path = stack[1] = stack[1] ?
[...stack[1], ...this.path().slice(1)]
: this.path(...arguments)
stack[2] = [
...(stack[2] ?? []),
...this.path('text').slice(0, -1),
]
// clear focused -- prevent focus from shifting on uncrop...
var e = state
for(var i of path.slice(0, -1)){
e = e[i].children }
delete e[path.at(-1)].focused
this.load(this.data(...arguments))
// XXX make this linkable...
this.header.innerHTML = '/ ' + stack[2].join(' / ')
this.dom.classList.add('crop')
for(var block of [...this.outline.querySelectorAll('[cropped]')]){
block.removeAttribute('cropped') }
this.get(...arguments).setAttribute('cropped', '')
this.header.innerHTML =
`<span class="path-item" onclick="editor.uncrop('all')">/</span> `
+ this.path(...arguments, 'text')
.slice(0, -1)
.map(function(s, i, {length}){
return `<span class="path-item" onclick="editor.uncrop(${ length-i })">${s}</span> ` })
.join(' / ')
return this },
// XXX use JSON API...
uncrop: function(mode=undefined){
if(this.__crop_stack == null){
return this }
// XXX is this a good way do go???
if(mode == 'all'){
while(this.__crop_stack != null){
this.uncrop() }
return this }
// merge changes into the state above...
var stack = this.__crop_stack
var [state, path, text] = stack
var s = state
for(var i of path.slice(0, -1)){
s = s[i].children }
s.splice(path.at(-1), 1, ...this.json())
if(path.length > 1){
path.pop()
text.pop()
s = state
for(var i of path.slice(0, -1)){
s = s[i].children }
s = s[path.at(-1)]
this.load(s)
this.header.innerHTML =
'/ ' + stack[2].join(' / ')
} else {
this.load(state)
uncrop: function(mode=1){
var outline = this.outline
var top = this.get(0)
for(var block of [...this.outline.querySelectorAll('[cropped]')]){
block.removeAttribute('cropped') }
// crop parent if available...
while(mode != 'all'
&& mode > 0
&& top !== outline){
top = this.get(top, 'parent')
mode-- }
if(mode == 'all' || top === outline){
this.dom.classList.remove('crop')
this.__crop_stack = undefined
this.header.innerHTML = '' }
this.header.innerHTML = ''
} else {
this.crop(top) }
return this },
// block render...
@ -1364,7 +1329,7 @@ var Outline = {
// ...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 ]*)+$/,
.replace(/([\n\t ]*)(?:(?:\n|^)[\t ]*\w+[\t ]*::[\t ]*[^\n]+[\t ]*)+$/,
function(match, ws){
var attrs = match
.trim()
@ -1434,6 +1399,8 @@ var Outline = {
var block = document.createElement('div')
block.classList.add('block')
block.setAttribute('tabindex', '0')
// XXX hack??
block.setAttribute('cropped', '')
// code...
var code = document.createElement('textarea')
.autoUpdateSize()
@ -1457,10 +1424,10 @@ var Outline = {
: place
;(place == 'next'
&& (cur.querySelector('.block')
|| cur.nextElementSibling)) ?
|| cur !== this.get(-1))) ?
this.get(place).before(block)
: (place == 'next'
&& !cur.nextElementSibling) ?
&& cur === this.get(-1)) ?
cur.after(block)
: (place == 'before' || place == 'after') ?
cur[place](block)

View File

@ -51,8 +51,6 @@ var setup = function(){
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
-
- ## ToDo:
- Q: crop: should we control crop via "crop-in"/"crop-out" instead of crop/uncrop??
- crop: make path clickable
- undo
collapsed:: true
- edit stack (position, action, ...)
@ -113,6 +111,9 @@ var setup = function(){
- empty item height is a bit off...
- search?
- _...not sure if search should be internal or external yet..._
- DONE crop: make path clickable
- DONE Q: crop: should we control crop via "crop-in"/"crop-out" instead of crop/uncrop??
- _crop-in/crop-out seems more natural..._
- DONE crop: show crop path (and depth)
- DONE over-travel pause -- when going fast over start/end stop...
- DONE focus:
@ -172,6 +173,9 @@ var setup = function(){
- DONE add optional text styling to nodes
-
- ## Refactoring:
- Q: Implementation: JSON-based, DOM-based (current) or both?
- implement JSON-based
- compare and decide...
- Plugin architecture
- DONE basic structure
- plugin handler sequencing (see: `<editor>.setup(..)`)