Lettore 0.3.2: navigazione con proprietà native del WebView
window.scrollY/scrollBy via runJavaScript non riflette lo scroll reale del WebView Sailfish (la posizione non arrivava mai a fine documento) -> il cambio capitolo non scattava. Ora contentHeight/scrollPosition (proprietà native): nextPage/prevPage = aritmetica QML pura, cambio capitolo deterministico.
This commit is contained in:
+36
-63
@@ -145,10 +145,8 @@ Page {
|
|||||||
if (off >= book.chapterTextLength(page.currentChapter)) {
|
if (off >= book.chapterTextLength(page.currentChapter)) {
|
||||||
// oltre la fine = vai all'ultima pagina (usato da
|
// oltre la fine = vai all'ultima pagina (usato da
|
||||||
// prevPage per non saltare la coda del capitolo)
|
// prevPage per non saltare la coda del capitolo)
|
||||||
web.runJavaScript(
|
web.scrollPosition = Qt.point(0, Math.max(1, web.contentHeight - web.height))
|
||||||
"window.scrollTo(0,Math.max(1,"
|
readScrollPosition()
|
||||||
+ "document.documentElement.scrollHeight-window.innerHeight));true",
|
|
||||||
function() { readScrollPosition() })
|
|
||||||
} else {
|
} else {
|
||||||
web.runJavaScript(page.scrollToCharJs(off), function() {
|
web.runJavaScript(page.scrollToCharJs(off), function() {
|
||||||
readScrollPosition()
|
readScrollPosition()
|
||||||
@@ -255,16 +253,12 @@ Page {
|
|||||||
+ "return true;})()"
|
+ "return true;})()"
|
||||||
}
|
}
|
||||||
|
|
||||||
// JS che legge la posizione: {o: caratteri di testo sopra la viewport,
|
// JS che conta i caratteri di testo sopra la viewport (per il bookmark).
|
||||||
// f: frazione di scroll, p: pagina corrente, pc: pagine totali}.
|
// Lo scroll NON è gestito qui: pagina/frazione si leggono dalle proprietà
|
||||||
// Il conteggio cammina i text node del DOM: stabile al variare di font e
|
// native del WebView (contentHeight/scrollPosition), sempre affidabili.
|
||||||
// margini (a differenza della frazione di scroll).
|
|
||||||
function positionJs() {
|
function positionJs() {
|
||||||
return "(function(){"
|
return "(function(){"
|
||||||
+ "var de=document.documentElement,b=document.body;"
|
+ "var b=document.body;"
|
||||||
+ "var max=Math.max(1,Math.max(de.scrollHeight,b.scrollHeight)-window.innerHeight);"
|
|
||||||
+ "var y=Math.max(0,Math.min(max,window.scrollY));"
|
|
||||||
+ "var vh=window.innerHeight;"
|
|
||||||
+ "var o=0;"
|
+ "var o=0;"
|
||||||
+ "var it=document.createTreeWalker(b,NodeFilter.SHOW_TEXT);"
|
+ "var it=document.createTreeWalker(b,NodeFilter.SHOW_TEXT);"
|
||||||
+ "var n;"
|
+ "var n;"
|
||||||
@@ -278,8 +272,7 @@ Page {
|
|||||||
+ "var h=rect.bottom-rect.top;"
|
+ "var h=rect.bottom-rect.top;"
|
||||||
+ "if(h>0)o+=Math.round(n.data.length*(0-rect.top)/h);"
|
+ "if(h>0)o+=Math.round(n.data.length*(0-rect.top)/h);"
|
||||||
+ "break;}"
|
+ "break;}"
|
||||||
+ "return JSON.stringify({o:o,f:y/max,p:Math.floor(y/vh)+1,"
|
+ "return o;})()"
|
||||||
+ "pc:Math.max(1,Math.floor(max/vh)+1)});})()"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JS che porta in cima alla viewport il carattere 'off' del capitolo
|
// JS che porta in cima alla viewport il carattere 'off' del capitolo
|
||||||
@@ -303,12 +296,16 @@ Page {
|
|||||||
function readScrollPosition() {
|
function readScrollPosition() {
|
||||||
if (!web.loaded)
|
if (!web.loaded)
|
||||||
return
|
return
|
||||||
web.runJavaScript(page.positionJs(), function(res) {
|
// posizione letta dalle proprietà NATIVE del WebView (affidabili),
|
||||||
var r = JSON.parse(res)
|
// il JS serve solo a contare i caratteri per il bookmark
|
||||||
page.charOffset = r.o
|
var vh = Math.max(1, web.height)
|
||||||
page.chapterFraction = r.f
|
var max = Math.max(1, web.contentHeight - vh)
|
||||||
page.pageIndex = r.p
|
var y = Math.max(0, Math.min(max, web.scrollPosition.y))
|
||||||
page.pageCount = r.pc
|
page.chapterFraction = y / max
|
||||||
|
page.pageIndex = Math.floor(y / vh) + 1
|
||||||
|
page.pageCount = Math.max(1, Math.floor(max / vh) + 1)
|
||||||
|
web.runJavaScript(page.positionJs(), function(o) {
|
||||||
|
page.charOffset = o || 0
|
||||||
maybeSave(false)
|
maybeSave(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -349,59 +346,36 @@ Page {
|
|||||||
loadChapter()
|
loadChapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pagina successiva: una viewport avanti. Lo scroll avviene con scrollBy e
|
// pagina successiva: una viewport avanti, usando le proprietà native del
|
||||||
// la verifica è "lo scroll si è MOSSO?" — non un confronto con max calcolato
|
// WebView (contentHeight/scrollPosition) — niente JS di navigazione, quindi
|
||||||
// (innerHeight/scrollHeight del WebView non sempre corrispondono allo scroll
|
// nessuna dipendenza da runJavaScript/scrollY per il cambio capitolo.
|
||||||
// reale: con max sovrastimato scrollY non lo raggiungeva mai e il passaggio
|
// A fine capitolo (y >= max-2) passa al capitolo successivo.
|
||||||
// al capitolo successivo non scattava). Se non si muove: unlock CSS e riprova;
|
|
||||||
// se ancora fermo, siamo a fine capitolo (o capitolo non scrollabile) -> avanti.
|
|
||||||
function nextPage() {
|
function nextPage() {
|
||||||
if (!web.loaded || !page.ready)
|
if (!web.loaded || !page.ready)
|
||||||
return
|
return
|
||||||
web.runJavaScript(
|
var vh = Math.max(1, web.height)
|
||||||
"(function(){"
|
var max = Math.max(1, web.contentHeight - vh)
|
||||||
+ "var de=document.documentElement,b=document.body;"
|
var y = web.scrollPosition.y
|
||||||
+ "var vh=window.innerHeight;"
|
if (y >= max - 2) {
|
||||||
+ "var before=window.scrollY;"
|
// fine capitolo (o capitolo non scrollabile) -> avanti
|
||||||
+ "window.scrollBy(0,vh);"
|
|
||||||
+ "if(window.scrollY>before+1)"
|
|
||||||
+ "return JSON.stringify({ok:true,atEnd:false});"
|
|
||||||
+ "de.style.setProperty('overflow','visible','important');"
|
|
||||||
+ "b.style.setProperty('overflow','visible','important');"
|
|
||||||
+ "de.style.setProperty('height','auto','important');"
|
|
||||||
+ "b.style.setProperty('height','auto','important');"
|
|
||||||
+ "window.scrollBy(0,vh);"
|
|
||||||
+ "if(window.scrollY>before+1)"
|
|
||||||
+ "return JSON.stringify({ok:true,atEnd:false});"
|
|
||||||
+ "return JSON.stringify({ok:false,atEnd:true});})()",
|
|
||||||
function(res) {
|
|
||||||
var r = JSON.parse(res)
|
|
||||||
if (r.ok) {
|
|
||||||
readScrollPosition()
|
|
||||||
} else if (r.atEnd) {
|
|
||||||
gotoChapter(page.currentChapter + 1)
|
gotoChapter(page.currentChapter + 1)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
})
|
web.scrollPosition = Qt.point(0, Math.min(max, y + vh))
|
||||||
|
readScrollPosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pagina precedente: una viewport indietro; se lo scroll non si muove siamo
|
// pagina precedente: una viewport indietro; all'inizio -> capitolo prima
|
||||||
// all'inizio -> capitolo prima SULL'ULTIMA PAGINA (non salta la coda)
|
// SULL'ULTIMA PAGINA (non salta la coda del capitolo)
|
||||||
function prevPage() {
|
function prevPage() {
|
||||||
if (!web.loaded || !page.ready)
|
if (!web.loaded || !page.ready)
|
||||||
return
|
return
|
||||||
web.runJavaScript(
|
var vh = Math.max(1, web.height)
|
||||||
"(function(){"
|
var y = web.scrollPosition.y
|
||||||
+ "var vh=window.innerHeight;"
|
if (y > 1) {
|
||||||
+ "var before=window.scrollY;"
|
web.scrollPosition = Qt.point(0, Math.max(0, y - vh))
|
||||||
+ "window.scrollBy(0,-vh);"
|
|
||||||
+ "if(window.scrollY<before-1)"
|
|
||||||
+ "return JSON.stringify({ok:true,atStart:false});"
|
|
||||||
+ "return JSON.stringify({ok:false,atStart:true});})()",
|
|
||||||
function(res) {
|
|
||||||
var r = JSON.parse(res)
|
|
||||||
if (r.ok) {
|
|
||||||
readScrollPosition()
|
readScrollPosition()
|
||||||
} else if (r.atStart && page.currentChapter > 0) {
|
} else if (page.currentChapter > 0) {
|
||||||
maybeSave(true)
|
maybeSave(true)
|
||||||
page.currentChapter -= 1
|
page.currentChapter -= 1
|
||||||
page.chapterFraction = 0
|
page.chapterFraction = 0
|
||||||
@@ -412,7 +386,6 @@ Page {
|
|||||||
page.lastSavedAbs = -1
|
page.lastSavedAbs = -1
|
||||||
loadChapter()
|
loadChapter()
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fontPx() {
|
function fontPx() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Name: harbour-calibreweb
|
Name: harbour-calibreweb
|
||||||
Summary: Client OPDS per Calibre Web
|
Summary: Client OPDS per Calibre Web
|
||||||
Version: 0.3.1
|
Version: 0.3.2
|
||||||
Release: 1
|
Release: 1
|
||||||
Group: Qt/Qt
|
Group: Qt/Qt
|
||||||
License: MIT
|
License: MIT
|
||||||
@@ -24,6 +24,12 @@ reflow del testo, margini configurabili e posizione salvata
|
|||||||
in locale.
|
in locale.
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Aug 21 2026 Carlo Baratto <carlo@carlobaratto.it> - 0.3.2-1
|
||||||
|
- Fix definitivo cambio capitolo: la navigazione non usa piu' window.scrollY/
|
||||||
|
scrollBy via runJavaScript (lo scroll reale del WebView Sailfish non e' sempre
|
||||||
|
riflesso in window.scrollY: la posizione non arrivava mai a fine documento e
|
||||||
|
il cambio capitolo non scattava). Ora paginazione con le proprieta' NATIVE
|
||||||
|
del WebView (contentHeight/scrollPosition): aritmetica QML pura, affidabile
|
||||||
* Fri Aug 21 2026 Carlo Baratto <carlo@carlobaratto.it> - 0.3.1-1
|
* Fri Aug 21 2026 Carlo Baratto <carlo@carlobaratto.it> - 0.3.1-1
|
||||||
- Fix passaggio di capitolo: il tap avanti/indietro usava un confronto con max
|
- Fix passaggio di capitolo: il tap avanti/indietro usava un confronto con max
|
||||||
calcolato (scrollHeight - innerHeight), che sul WebView di Sailfish può essere
|
calcolato (scrollHeight - innerHeight), che sul WebView di Sailfish può essere
|
||||||
|
|||||||
Reference in New Issue
Block a user