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; 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 { .editor .outline {
display: block; display: block;
position: relative; position: relative;
padding: 1em var(--outline-padding); padding: 1em var(--outline-padding);
padding-bottom: 1.2em padding-bottom: 1.2em;
} }
/* virtual empty block... */ /* virtual empty block... */
@ -69,21 +92,6 @@
.editor .outline:empty:hover:after { .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 { .editor .outline .block {
position: relative; position: relative;
@ -93,7 +101,8 @@
.editor.block-offsets .outline .block { .editor.block-offsets .outline .block {
border-left: solid 1px silver; 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); margin-left: var(--item-indent);
} }
.editor .outline .block>.text { .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 { .editor .toolbar {
display: inline-block; display: inline-block;
position: absolute; position: absolute;

View File

@ -895,18 +895,18 @@ var Outline = {
: offset == 'visible' ? : offset == 'visible' ?
[...node.querySelectorAll('.block')] [...node.querySelectorAll('.block')]
.filter(function(e){ .filter(function(e){
return e.offsetParent != null }) return e.querySelector('.view').offsetParent != null })
: offset == 'viewport' ? : offset == 'viewport' ?
[...node.querySelectorAll('.block')] [...node.querySelectorAll('.block')]
.filter(function(e){ .filter(function(e){
return e.offsetParent != null return e.querySelector('.view').offsetParent != null
&& e.querySelector('.code').visibleInViewport() }) && e.querySelector('.code').visibleInViewport() })
: offset == 'editable' ? : offset == 'editable' ?
[...node.querySelectorAll('.block>.code')] [...node.querySelectorAll('.block>.code')]
: offset == 'selected' ? : offset == 'selected' ?
[...node.querySelectorAll('.block[selected]')] [...node.querySelectorAll('.block[selected]')]
.filter(function(e){ .filter(function(e){
return e.offsetParent != null }) return e.querySelector('.view').offsetParent != null })
: offset == 'children' ? : offset == 'children' ?
children(node) children(node)
: offset == 'siblings' ? : offset == 'siblings' ?
@ -1145,70 +1145,35 @@ var Outline = {
return this }, return this },
// crop... // 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'){ 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') this.dom.classList.add('crop')
return this }, for(var block of [...this.outline.querySelectorAll('[cropped]')]){
// XXX use JSON API... block.removeAttribute('cropped') }
uncrop: function(mode=undefined){ this.get(...arguments).setAttribute('cropped', '')
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 = this.header.innerHTML =
'/ ' + stack[2].join(' / ') `<span class="path-item" onclick="editor.uncrop('all')">/</span> `
+ this.path(...arguments, 'text')
} else { .slice(0, -1)
this.load(state) .map(function(s, i, {length}){
return `<span class="path-item" onclick="editor.uncrop(${ length-i })">${s}</span> ` })
.join(' / ')
return this },
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.dom.classList.remove('crop')
this.__crop_stack = undefined this.header.innerHTML = ''
this.header.innerHTML = '' } } else {
this.crop(top) }
return this }, return this },
// block render... // block render...
@ -1364,7 +1329,7 @@ var Outline = {
// ...putting the same pattern in a normal group and // ...putting the same pattern in a normal group and
// returning it works fine... // returning it works fine...
//.replace(/(?<=[\n\h]*)(?:(?:\n|^)\s*\w*\s*::\s*[^\n]*\s*)*$/, //.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){ function(match, ws){
var attrs = match var attrs = match
.trim() .trim()
@ -1434,6 +1399,8 @@ var Outline = {
var block = document.createElement('div') var block = document.createElement('div')
block.classList.add('block') block.classList.add('block')
block.setAttribute('tabindex', '0') block.setAttribute('tabindex', '0')
// XXX hack??
block.setAttribute('cropped', '')
// code... // code...
var code = document.createElement('textarea') var code = document.createElement('textarea')
.autoUpdateSize() .autoUpdateSize()
@ -1457,10 +1424,10 @@ var Outline = {
: place : place
;(place == 'next' ;(place == 'next'
&& (cur.querySelector('.block') && (cur.querySelector('.block')
|| cur.nextElementSibling)) ? || cur !== this.get(-1))) ?
this.get(place).before(block) this.get(place).before(block)
: (place == 'next' : (place == 'next'
&& !cur.nextElementSibling) ? && cur === this.get(-1)) ?
cur.after(block) cur.after(block)
: (place == 'before' || place == 'after') ? : (place == 'before' || place == 'after') ?
cur[place](block) cur[place](block)

View File

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