Skip to content

$mol_book in dom #761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions book2/book2.view.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
/* padding: 0 1px;
scroll-padding: 0 1px;
gap: 1px; */
--mol_book2_grip_top: 1.5rem;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем переменная для этого?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так гвоздями все прибито, если чуть меньше сделать хедеры, точки эти едут, т.к. они абсолютом делаются.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А хедер ты меньше через переменные делаешь тоже?

}

[mol_book2] > * {
Expand All @@ -26,11 +27,22 @@
box-shadow: inset 0 0 0 1px var(--mol_theme_field);
}

[mol_book2] > *:not(:first-of-type):before,
[mol_book2] > *:not(:last-of-type)::after {
/* Prepend dots to not first page in the book, exclude placeholder */
[mol_book2] > *:not(:first-child):not([mol_book2]):not([mol_book2_gap])::before,
/* Append dots to not last page in the book, exclude page before placeholder */
[mol_book2] > *:not(:last-child):not([mol_book2]):not([mol_book2_gap]):not(:has(+ [mol_book2_placeholder]))::after,

/* Can't add dots to the book due to display: contents */
/* Prepend dots to all pages in the not first child book, exclude placeholder and second level child book */
[mol_book2] > *:not(:first-child)[mol_book2] > *:not([mol_book2]):not([mol_book2_gap])::before,

/* Append dots to all pages in the not last child book not before placeholder */
[mol_book2] > *:not(:last-child)[mol_book2]:not(:has(+ [mol_book2_placeholder])) > :not([mol_book2]):not([mol_book2_gap])::after
Comment on lines +31 to +40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может всё же какой-то атрибут к страницам добавлять, через призрака? А то это какая-то адская логика в стилях.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Что б просетить атрибут, надо через js получить положение паги в общей иерархии паг.

Этот факт заблокирует весь первый буклет, вместо того что бы отрисовать паги с загрузкой в каждой к примеру.

Если буклет не блокировать, пропускать промис, то скорее всего будет меняться состав паг во время рендера, дребезг.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Какое отношение рендеринг призраков имеет к рендерингу бука?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не важно как добавляется атрибут, важно что для его значения надо знать где страница находится в иерархии.

Ты ж имеешь в виду атрибут типа last, first и т.д.? Без него не решить куда точки поставить, а куда нет.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не важно, где определено свойство, важно, где оно вызывается.

{
display: block;
content: '';
position: absolute;
top: 1.5rem;
top: var(--mol_book2_grip_top);
width: 3px;
height: 1rem;
background: linear-gradient(
Expand All @@ -49,14 +61,16 @@
opacity: .5;
z-index: var(--mol_layer_speck);
}
[mol_book2] > *:not(:first-of-type):before {

[mol_book2] > *:not(:first-child):not([mol_book2])::before {
left: -1px;
}
[mol_book2] > *:not(:last-of-type)::after {

[mol_book2] > *:not(:last-child):not([mol_book2])::after {
right: -1px;
}

:where([mol_book2]) > * {
:where([mol_book2]) > *:not([mol_book]) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А где-то ещё используется первый бук?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ошибка, тут надо book2

background-color: var(--mol_theme_card);
/* box-shadow: 0 0 0 1px var(--mol_theme_back); */
}
Expand All @@ -65,7 +79,11 @@
display: contents;
}

[mol_book2] > *:first-child {
[mol_book2] [mol_book2] > [mol_book2_placeholder] {
display: none;
}
Comment on lines +82 to +84
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем его тогда вообще рендерить?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Проверял эвенты

Идея была в том, что буклет ничего не знает про иерархию, просто предоставляет placeholder, хотелось бы его рендерить, справа от всех, но при этом не ломая структуру дом, что б владение и эвенты адекватными оставались, типа как портал.

Но у меня не получилось так сделать на css, поэтому можно выпилить наверное.


[mol_book2] > *:not([mol_book2]):first-child {
scroll-snap-align: start;
}

Expand Down
7 changes: 5 additions & 2 deletions book2/book2.view.tree
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
$mol_book2 $mol_scroll
menu_title \
sub /$mol_view
^ pages <= pages_deep /$mol_view
^ pages /$mol_view
^ placeholders /$mol_view
<= Placeholder $mol_view
Placeholder null
minimal_width 0
Gap* $mol_view title \
auto /
^
<= scroll_task_top null
112 changes: 74 additions & 38 deletions book2/book2.view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,8 @@ namespace $.$$ {
*/
export class $mol_book2 extends $.$mol_book2 {

@ $mol_mem
override pages_deep() {
let result = [] as $mol_view[]
for (const subpage of this.pages()) {
if (subpage instanceof $mol_book2) result = [ ...result, ...subpage.pages_deep() ]
else result.push(subpage)
}

return result
}

title() {
return this.pages_deep().map( page => {
return this.pages().map( page => {
try {
return page?.title()
} catch( error ) {
Expand All @@ -28,52 +17,99 @@ namespace $.$$ {
}

menu_title() {
return this.pages_deep()[0]?.title() || this.title()
return this.pages()[0]?.title() || this.title()
}

@ $mol_mem
sub() {
override sub() {
const placeholders = this.placeholders()
const next = [ ... this.pages_deep(), ...placeholders ]

const next = super.sub()
const prev = $mol_mem_cached( ()=> this.sub() ) ?? []
const top = this.top_book ?? this

for( let i = 1 ; i++ ; ) {
let scroll_target
for( let i = 1; i <= next.length; i++ ) {

const p = prev[ prev.length - i ]
const n = next[ next.length - i ]

if( !n ) break

if( p === n ) continue
if( placeholders.includes(n) ) continue

new this.$.$mol_after_tick( ()=> {
const b = this.dom_node() as HTMLElement
const p = n.dom_node() as HTMLElement
b.scroll({
left: p.offsetLeft + p.offsetWidth - b.offsetWidth,
behavior: 'smooth',
})
// new this.$.$mol_after_timeout( 1000, ()=> n.bring() )
} )

break
const prev_page = prev[ prev.length - i ]
const next_page = next[ next.length - i ]
if (next_page instanceof $mol_book2) {
next_page.top_book = top
}

if( prev_page === next_page ) continue
if( placeholders.includes(next_page) ) continue

if (! scroll_target) scroll_target = next_page
}

return next as readonly $mol_view[]
// need to set top_book to all sub books, can't break for
if (scroll_target) top.scroll_target(scroll_target)

return next
}


protected top_book = null as null | $mol_book2

@ $mol_mem
scroll_target(page?: $mol_view | null) {
return page ?? null
}

override scroll_task_top() {
// avoid mem creation for non-top book
if (this.top_book) return null
this.scroll_task()
}
Comment on lines +59 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему бы не сделать рекурсивную логику? Верхний бук спрашивает у нижнего куда в нём скроллить и в конечном счёте получает глубоко вложенную страницу.

Copy link
Collaborator Author

@zerkalica zerkalica Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

непонятное что-то

У меня логика была такая:

  1. страница к которой надо подскролить, может быть только одна, надо исключить конкуренцию подскролов, поэтому mem с этой логикой должен быть один. Конкуренция может появиться из-за асинхронщины при получения состава страниц в каком-либо буклете.

  2. Скролл может быть только у топового буклета, следовательно дочерние никуда никуда скролить не должны.

Отсюда, как раз наоборот, дочерние буклеты должны топовому передавать страницы, к которым они хотят, что б топовый подскролил.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Речь про получение страницы в топовом буке для подскролла..

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

так все мое объяснение выше про нее
Вся эта логика только в топовом и работает благодаря отсутствию this.top_book

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты там ниже ищешь страницу, к которой скроллить, не девая вложенным компонентам самим решать.


@ $mol_mem
scroll_task() {
let page = this.scroll_target()

// for display: contents view_rect always 0
// find last page
while (page instanceof $mol_book2) {
try {
page = page.pages()?.at(-1) ?? null
} catch (e) {
return null
}
}

if (! page ) return null

const page_rect = page.view_rect()
if (! page_rect) return null

const top_rect = this.view_rect()
if (! top_rect) return null

const scroll_left = this.scroll_left()

const page_right = page_rect.right + scroll_left

const left = page_right - top_rect.right

return new this.$.$mol_after_tick(() => {
this.dom_node().scroll({ left, behavior: 'smooth' })
this.scroll_target(null)
})
}

bring() {

const pages = this.pages_deep()
const pages = this.pages()

if( pages.length ) pages[ pages.length - 1 ].bring()
else super.bring()

}

override placeholders() {
if (this.Placeholder()) return [ this.Placeholder() ]
return super.placeholders()
}

}

}
1 change: 1 addition & 0 deletions book2/catalog/catalog.view.tree
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ $mol_book2_catalog $mol_book2
needle <= menu_filter
haystack <= spread_title* \
foot <= menu_foot /$mol_view
<= Spread_current null
Spread_close $mol_link
arg <= spread_close_arg *
hint @ \Close page
Expand Down
30 changes: 5 additions & 25 deletions book2/catalog/catalog.view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,10 @@ namespace $.$$ {
*/
export class $mol_book2_catalog extends $.$mol_book2_catalog {

spread_current() {
override Spread_current() {
return this.spread() === '' ? this.Spread_default() : this.Spread(this.spread())
}

@ $mol_mem
pages() {
const spread = this.spread_current()
return [
this.Menu(),
... spread
? spread instanceof $mol_book2
? spread.pages_deep()
: [ spread ]
: [],
]
}

override auto() {
const spread = this.spread_current()
if (spread instanceof $mol_book2) spread.auto()
}

@ $mol_mem
override spread_ids(): readonly string[] {
return Object.keys( this.spreads() )
Expand Down Expand Up @@ -86,14 +68,12 @@ namespace $.$$ {
|| spread
}

spread_current_book() {
const spread = this.spread_current()
return spread instanceof $mol_book2 ? spread : null
}

@ $mol_mem
override placeholders() {
const spread_placeholders = this.spread_current_book()?.placeholders() ?? []
const spread = this.Spread_current()
const spread_placeholders = spread instanceof $mol_book2
? spread.placeholders()
: []
return spread_placeholders.length ? spread_placeholders : super.placeholders()
}
}
Expand Down
1 change: 0 additions & 1 deletion page/page.view.tree
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ $mol_page $mol_view
tabIndex <= tabindex -1
sub /
<= Head $mol_view
minimal_height 64
dom_name \header
sub <= head /
<= Title $mol_view
Expand Down
2 changes: 1 addition & 1 deletion view/view/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ namespace $ {
}

auto() {
return null as any
return [] as any
}

@ $mol_mem
Expand Down