diff --git a/eslint/eslintrc.json b/eslint/eslintrc.json index 5fd6db2..77aaba5 100644 --- a/eslint/eslintrc.json +++ b/eslint/eslintrc.json @@ -31,6 +31,9 @@ "function-paren-newline": ["warn", "consistent"], "no-magic-numbers": ["error", {"ignore": [0,1,2,100]}], "quote-props": ["warn", "as-needed"], - "no-unused-vars": ["error", {"argsIgnorePattern": "^_"}] + "no-unused-vars": ["error", {"argsIgnorePattern": "^_"}], + "max-len" : ["warn", {"code": 88}], + "capitalized-comments": "off", + "operator-linebreak": ["warn", "before"] } } diff --git a/melpomene.js b/melpomene.js index 8689592..8572c8c 100644 --- a/melpomene.js +++ b/melpomene.js @@ -45,7 +45,7 @@ const VERSION_DISPLAY = document.getElementById("melpomene-version"); var PAGES_ZOOMS; // The variable ZOOMS can either be defined by another JS file or contructed at init -if (typeof PAGES_ZOOMS === 'undefined') +if (typeof PAGES_ZOOMS === "undefined") { PAGES_ZOOMS = null; } @@ -64,109 +64,6 @@ var MOUSEWHELL_WAIT = false; // UTILITIES // ============= -// Zooms utilites -// -------------- - -function globalZoomScale() -{ - if (READER_PAGES.dataset.globalZoomScale !== undefined) - { - return parseFloat(READER_PAGES.dataset.globalZoomScale); - } - - return 1.0; -} - -function globalZoomOffsetX() -{ - if (READER_PAGES.dataset.globalZoomOffset !== undefined) - { - return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(',')[0]); - } - - return 0.0; -} - -function globalZoomOffsetY() -{ - if (READER_PAGES.dataset.globalZoomOffset !== undefined) - { - return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(',')[1]); - } - - return 0.0; -} - -function loadZoomsFromImgTagsIfRequired() -{ - // Zooms may be defined by another JS file - if (PAGES_ZOOMS === null) - { - PAGES_ZOOMS = []; - - // parse the data-zooms of each img and and the page number info - for (let idx = 0; idx < READER_PAGES.children.length; idx += 1) - { - const zoomsRawData = READER_PAGES.children[idx].dataset.zooms; - - // ';' separates zooms data, ',' separates values - // We add the page number (adding 1 because of indexing) - const zooms = zoomsRawData.split(";").map( - zoom => [idx + 1].concat( - zoom.split(',').map( - value => parseFloat(value) - ) - ) - ); - - PAGES_ZOOMS = PAGES_ZOOMS.concat(zooms); - } - } -} - -function getFirstZoomOfPage(pageNumber) -{ - for (let zoomIdx = 0; zoomIdx < PAGES_ZOOMS.length; zoomIdx += 1) - { - if (PAGES_ZOOMS[zoomIdx][0] === pageNumber) - { - return zoomIdx; - } - } -} - -function getZoomCountForPage(pageNumber) -{ - return PAGES_ZOOMS.filter(zoom => zoom[0] === pageNumber).length; -} - -function getCurrentZoomIndexForPage() -{ - const previousZoomsCount = PAGES_ZOOMS.filter(zoom => zoom[0] < CURRENT_PAGE).length; - return CURRENT_ZOOM - previousZoomsCount + 1; -} - -function getReadingProgressPercent() -{ - const progressPerPage = 1 / getPagesCount(); - - if (IS_PAGE_MODE) - { - return 100 * progressPerPage * CURRENT_PAGE; - } - - const progressPerZoom = progressPerPage / getZoomCountForPage(CURRENT_PAGE); - - const readingProgress = (CURRENT_PAGE - 1) * progressPerPage + getCurrentZoomIndexForPage() * progressPerZoom; - - return 100 * readingProgress; -} - -function updateProgressBar() -{ - PROGRESS_BAR.style.width = getReadingProgressPercent() + "%"; -} - // Dimensions utilites // ------------------- @@ -194,11 +91,11 @@ function pageMaxHeight() { let maxHeight = 0; - for (let i = 0; i < READER_PAGES.children.length; i += 1) + for (let pageIdx = 0; pageIdx < READER_PAGES.children.length; pageIdx += 1) { - if(READER_PAGES.children[i].naturalHeight > maxHeight) + if (READER_PAGES.children[pageIdx].naturalHeight > maxHeight) { - maxHeight = READER_PAGES.children[i].naturalHeight; + maxHeight = READER_PAGES.children[pageIdx].naturalHeight; } } @@ -207,7 +104,7 @@ function pageMaxHeight() function pageVerticalOffset(pageNumber) { - return ( pageMaxHeight() - pageOriginalHeight(pageNumber) ) / 2; + return (pageMaxHeight() - pageOriginalHeight(pageNumber)) / 2; } function previousPagesWidth(pageNumber) @@ -224,64 +121,128 @@ function previousPagesWidth(pageNumber) return totalWidth; } +// Zooms utilites +// -------------- + +function globalZoomScale() +{ + if (READER_PAGES.dataset.globalZoomScale !== undefined) + { + return parseFloat(READER_PAGES.dataset.globalZoomScale); + } + + return 1.0; +} + +function globalZoomOffsetX() +{ + if (READER_PAGES.dataset.globalZoomOffset !== undefined) + { + return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(",")[0]); + } + + return 0.0; +} + +function globalZoomOffsetY() +{ + if (READER_PAGES.dataset.globalZoomOffset !== undefined) + { + return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(",")[1]); + } + + return 0.0; +} + +function loadZoomsFromImgTagsIfRequired() +{ + // Zooms may be defined by another JS file + if (PAGES_ZOOMS === null) + { + PAGES_ZOOMS = []; + + // parse the data-zooms of each img and and the page number info + for (let idx = 0; idx < READER_PAGES.children.length; idx += 1) + { + const zoomsRawData = READER_PAGES.children[idx].dataset.zooms; + + // ";" separates zooms data, "," separates values + // We add the page number (adding 1 because of indexing) + const zooms = zoomsRawData.split(";").map( + (zoom) => [idx + 1].concat( + zoom.split(",").map( + (value) => parseFloat(value) + ) + ) + ); + + PAGES_ZOOMS = PAGES_ZOOMS.concat(zooms); + } + } +} + +function getFirstZoomOfPage(pageNumber) +{ + for (let zoomIdx = 0; zoomIdx < PAGES_ZOOMS.length; zoomIdx += 1) + { + if (PAGES_ZOOMS[zoomIdx][0] === pageNumber) + { + return zoomIdx; + } + } + + return undefined; +} + +function getZoomCountForPage(pageNumber) +{ + return PAGES_ZOOMS.filter((zoom) => zoom[0] === pageNumber).length; +} + +function getCurrentZoomIndexForPage() +{ + const previousZoomsCount = PAGES_ZOOMS.filter((zoom) => zoom[0] < CURRENT_PAGE).length; + return CURRENT_ZOOM - previousZoomsCount + 1; +} + +function getReadingProgressPercent() +{ + const progressPerPage = 1 / getPagesCount(); + + if (IS_PAGE_MODE) + { + return 100 * progressPerPage * CURRENT_PAGE; + } + + const progressPerZoom = progressPerPage / getZoomCountForPage(CURRENT_PAGE); + + + let readingProgress = (CURRENT_PAGE - 1) * progressPerPage; + readingProgress += getCurrentZoomIndexForPage() * progressPerZoom; + + return 100 * readingProgress; +} + +function updateProgressBar() +{ + PROGRESS_BAR.style.width = `${getReadingProgressPercent()}%`; +} + // ========= // ACTIONS // ========= -function initReader() +function updateFocusByWidth(width) { - VERSION_DISPLAY.innerText = VERSION_DISPLAY.innerText.replace("Unknown version", MELPOMENE_VERSION); - - loadZoomsFromImgTagsIfRequired(); - moveReaderDisplayToZoom(0); - - // Smoothly show pictures when they intersect with the viewport - const visibilityObserver = new IntersectionObserver( - (entries, _observer) => - { - entries.forEach((entry) => - { - if (entry.isIntersecting) - { - entry.target.style.opacity = 1; - entry.target.style.visibility = "visible"; - } - - else - { - entry.target.style.opacity = 0; - entry.target.style.visibility = "hidden"; - } - }); - }, - { root: READER_CONTENT_FRAME, rootMargin: "-10px" } - ); - - for (let i = 0; i < READER_PAGES.children.length; i += 1) - { - const img = READER_PAGES.children[i]; - visibilityObserver.observe(img); - - PROGRESS_BAR_PAGES.appendChild(document.createElement("div")); - } - - READER_PAGES.style.display = "flex"; - - setTimeout( - () => { READER_PAGES.hidden = false }, - "300" - ); - - setTimeout( - () => - { - HELP_CONTROLS.style.opacity = null; - HELP_CONTROLS.style.transform = null; - }, - DELAY_BEFORE_HIDDING_CONTROLS - ); + FOCUS_OVERLAY_WIDTH.style.width = `${width / READER_CONTENT_FRAME.clientWidth * 100}%`; + FOCUS_OVERLAY_HEIGHT.style.height = "100%"; } +function updateFocusByHeight(height) +{ + FOCUS_OVERLAY_WIDTH.style.width = "100%"; + FOCUS_OVERLAY_HEIGHT.style.height = `${height / READER_CONTENT_FRAME.clientHeight * 100}%`; +} function moveReaderDisplayToArea(pageNumber, oWidth, oHeight, oPosx, oPosy) { @@ -307,8 +268,8 @@ function moveReaderDisplayToArea(pageNumber, oWidth, oHeight, oPosx, oPosy) width = width + posx; posx = 0; } - - if ((posx + width) > pageOriginalWidth(pageNumber)) + + if (posx + width > pageOriginalWidth(pageNumber)) { width = pageOriginalWidth(pageNumber) - posx; } @@ -319,18 +280,18 @@ function moveReaderDisplayToArea(pageNumber, oWidth, oHeight, oPosx, oPosy) height = height + posy; posy = 0; } - - if ((posy + height) > pageOriginalHeight(pageNumber)) + + if (posy + height > pageOriginalHeight(pageNumber)) { height = pageOriginalHeight(pageNumber) - posy; } // Align the top-left corner of the frame with the page - READER_PAGES.style.transform = "translate(-" + previousPagesWidth(pageNumber) + "px, -" + pageVerticalOffset(pageNumber) + "px )"; + READER_PAGES.style.transform = `translate(-${previousPagesWidth(pageNumber)}px, -${pageVerticalOffset(pageNumber)}px)`; // Then move so the top-left point of the zoom match the frame top-left - READER_PAGES.style.transform = "translate(" + (- posx) + "px, " + (-posy) + "px )" + READER_PAGES.style.transform; + READER_PAGES.style.transform = `translate(${-posx}px, ${-posy}px) ${READER_PAGES.style.transform}`; // Then, scale so the zoom would fit the frame, and center the zoom if (width === 0) @@ -350,27 +311,27 @@ function moveReaderDisplayToArea(pageNumber, oWidth, oHeight, oPosx, oPosy) // Frame wider than zoom => scale so heights are the same, offset on x const zoomToFrameScaleFactor = READER_CONTENT_FRAME.clientHeight / height; - READER_PAGES.style.transform = "scale(" + zoomToFrameScaleFactor + ")" + READER_PAGES.style.transform; + READER_PAGES.style.transform = `scale(${zoomToFrameScaleFactor}) ${READER_PAGES.style.transform}`; const scaledWidth = width * zoomToFrameScaleFactor; const offset = (READER_CONTENT_FRAME.clientWidth - scaledWidth) / 2; - READER_PAGES.style.transform = "translateX(" + offset + "px)" + READER_PAGES.style.transform; + READER_PAGES.style.transform = `translateX(${offset}px) ${READER_PAGES.style.transform}`; updateFocusByWidth(scaledWidth); } - + else { // Frame narower than zoom => scale so left/right match, offset on y const zoomToFrameScaleFactor = READER_CONTENT_FRAME.clientWidth / width; - READER_PAGES.style.transform = "scale(" + zoomToFrameScaleFactor + ")" + READER_PAGES.style.transform; + READER_PAGES.style.transform = `scale(${zoomToFrameScaleFactor}) ${READER_PAGES.style.transform}`; const scaledHeight = height * zoomToFrameScaleFactor; const offset = (READER_CONTENT_FRAME.clientHeight - scaledHeight) / 2; - READER_PAGES.style.transform = "translateY(" + offset + "px)" + READER_PAGES.style.transform; + READER_PAGES.style.transform = `translateY(${offset}px) ${READER_PAGES.style.transform}"`; updateFocusByHeight(scaledHeight); } @@ -385,7 +346,13 @@ function moveReaderDisplayToArea(pageNumber, oWidth, oHeight, oPosx, oPosy) function refreshReaderDisplay() { - moveReaderDisplayToArea(CURRENT_PAGE, CURRENT_WIDTH, CURRENT_HEIGHT, CURRENT_X, CURRENT_Y); + moveReaderDisplayToArea( + CURRENT_PAGE, + CURRENT_WIDTH, + CURRENT_HEIGHT, + CURRENT_X, + CURRENT_Y + ); } function moveReaderDisplayToPage(pageNumber) @@ -395,40 +362,34 @@ function moveReaderDisplayToPage(pageNumber) function moveReaderDisplayToZoom(index) { - moveReaderDisplayToArea(PAGES_ZOOMS[index][0], PAGES_ZOOMS[index][1], PAGES_ZOOMS[index][2], PAGES_ZOOMS[index][3], PAGES_ZOOMS[index][4]); + moveReaderDisplayToArea( + PAGES_ZOOMS[index][0], + PAGES_ZOOMS[index][1], + PAGES_ZOOMS[index][2], + PAGES_ZOOMS[index][3], + PAGES_ZOOMS[index][4] + ); CURRENT_ZOOM = index; } -function updateFocusByWidth(width) -{ - FOCUS_OVERLAY_WIDTH.style.width = (width / READER_CONTENT_FRAME.clientWidth * 100) + "%"; - FOCUS_OVERLAY_HEIGHT.style.height = "100%"; -} - -function updateFocusByHeight(height) -{ - FOCUS_OVERLAY_WIDTH.style.width = "100%"; - FOCUS_OVERLAY_HEIGHT.style.height = (height / READER_CONTENT_FRAME.clientHeight * 100) + "%"; -} - function toggleViewMode() { if (IS_PAGE_MODE) { - if (CURRENT_ZOOM !== null) - { - moveReaderDisplayToZoom(CURRENT_ZOOM); - } - - else + if (CURRENT_ZOOM === null) { moveReaderDisplayToZoom(getFirstZoomOfPage(CURRENT_PAGE)); } - + + else + { + moveReaderDisplayToZoom(CURRENT_ZOOM); + } + IS_PAGE_MODE = false; } - + else { moveReaderDisplayToPage(CURRENT_PAGE); @@ -453,8 +414,11 @@ function moveReader(toNext) moveReaderDisplayToPage(CURRENT_PAGE - 1); CURRENT_ZOOM = null; } + + updateProgressBar(); } - + + // Zoom mode else { if (toNext && CURRENT_ZOOM < PAGES_ZOOMS.length - 1) @@ -466,9 +430,66 @@ function moveReader(toNext) { moveReaderDisplayToZoom(CURRENT_ZOOM - 1); } + + updateProgressBar(); + } +} + +function initReader() +{ + VERSION_DISPLAY.innerText = VERSION_DISPLAY.innerText.replace("Unknown version", MELPOMENE_VERSION); + + loadZoomsFromImgTagsIfRequired(); + moveReaderDisplayToZoom(0); + + // Smoothly show pictures when they intersect with the viewport + const visibilityObserver = new IntersectionObserver( + (entries, _observer) => + { + entries.forEach((entry) => + { + if (entry.isIntersecting) + { + entry.target.style.opacity = 1; + entry.target.style.visibility = "visible"; + } + + else + { + entry.target.style.opacity = 0; + entry.target.style.visibility = "hidden"; + } + }); + }, + { + root: READER_CONTENT_FRAME, + rootMargin: "-10px" + } + ); + + for (let pageIndex = 0; pageIndex < READER_PAGES.children.length; pageIndex += 1) + { + const img = READER_PAGES.children[pageIndex]; + visibilityObserver.observe(img); + + PROGRESS_BAR_PAGES.appendChild(document.createElement("div")); } - updateProgressBar(); + READER_PAGES.style.display = "flex"; + + setTimeout( + () => { READER_PAGES.hidden = false; }, + "300" + ); + + setTimeout( + () => + { + HELP_CONTROLS.style.opacity = null; + HELP_CONTROLS.style.transform = null; + }, + DELAY_BEFORE_HIDDING_CONTROLS + ); } @@ -494,7 +515,7 @@ function handleKeyPress(key) { READER_FRAME.requestFullscreen(); } - + else { document.exitFullscreen(); @@ -507,12 +528,12 @@ function handleKeyPress(key) { PROGRESS_BAR_CONTAINER.hidden = false; } - + else { PROGRESS_BAR_CONTAINER.hidden = true; } - + refreshReaderDisplay(); } @@ -529,7 +550,7 @@ function handleMouseWhell(event) // Do disable page scrolling when we do prev/next, though - if (! READER_FRAME.contains(event.target)) + if (!READER_FRAME.contains(event.target)) { return; } @@ -541,15 +562,12 @@ function handleMouseWhell(event) { return; } - - else - { - MOUSEWHELL_WAIT = true; - setTimeout( - () => { MOUSEWHELL_WAIT = false; }, - MOUSEWHELL_MIN_DELAY - ); - } + + MOUSEWHELL_WAIT = true; + setTimeout( + () => { MOUSEWHELL_WAIT = false; }, + MOUSEWHELL_MIN_DELAY + ); if (event.deltaY > 0) {