mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-03 11:25:29 -04:00
Add paged reading mode
This commit is contained in:
parent
a6c2799521
commit
a86f0d0f34
@ -5,12 +5,68 @@ let longPages = false;
|
|||||||
$(() => {
|
$(() => {
|
||||||
getPages();
|
getPages();
|
||||||
|
|
||||||
|
const storedMode = localStorage.getItem('mode') || 'continuous';
|
||||||
|
|
||||||
|
setProp('mode', storedMode);
|
||||||
|
updateMode(storedMode, page);
|
||||||
|
$('#mode-select').val(storedMode);
|
||||||
|
|
||||||
$('#page-select').change(() => {
|
$('#page-select').change(() => {
|
||||||
const p = parseInt($('#page-select').val());
|
const p = parseInt($('#page-select').val());
|
||||||
toPage(p);
|
toPage(p);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#mode-select').change(() => {
|
||||||
|
const mode = $('#mode-select').val();
|
||||||
|
const curIdx = parseInt($('#page-select').val());
|
||||||
|
|
||||||
|
updateMode(mode, curIdx);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(window).resize(() => {
|
||||||
|
const mode = getProp('mode');
|
||||||
|
if (mode === 'continuous') return;
|
||||||
|
|
||||||
|
const wideScreen = $(window).width() > $(window).height();
|
||||||
|
const propMode = wideScreen ? 'height' : 'width';
|
||||||
|
setProp('mode', propMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the reader mode
|
||||||
|
*
|
||||||
|
* @function updateMode
|
||||||
|
* @param {string} mode - The mode. Can be one of the followings:
|
||||||
|
* {'continuous', 'paged', 'height', 'width'}
|
||||||
|
* @param {number} targetPage - The one-based index of the target page
|
||||||
|
*/
|
||||||
|
const updateMode = (mode, targetPage) => {
|
||||||
|
localStorage.setItem('mode', mode);
|
||||||
|
|
||||||
|
// The mode to be put into the `mode` prop. It can't be `screen`
|
||||||
|
let propMode = mode;
|
||||||
|
|
||||||
|
if (mode === 'paged') {
|
||||||
|
const wideScreen = $(window).width() > $(window).height();
|
||||||
|
propMode = wideScreen ? 'height' : 'width';
|
||||||
|
}
|
||||||
|
|
||||||
|
setProp('mode', propMode);
|
||||||
|
|
||||||
|
if (mode === 'continuous') {
|
||||||
|
waitForPage(items.length, () => {
|
||||||
|
setupScroller();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForPage(targetPage, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
toPage(targetPage);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an alpine.js property
|
* Set an alpine.js property
|
||||||
*
|
*
|
||||||
@ -22,6 +78,17 @@ const setProp = (key, prop) => {
|
|||||||
$('#root').get(0).__x.$data[key] = prop;
|
$('#root').get(0).__x.$data[key] = prop;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an alpine.js property
|
||||||
|
*
|
||||||
|
* @function getProp
|
||||||
|
* @param {string} key - Key of the data property
|
||||||
|
* @return {*} The data property
|
||||||
|
*/
|
||||||
|
const getProp = (key) => {
|
||||||
|
return $('#root').get(0).__x.$data[key];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get dimension of the pages in the entry from the API and update the view
|
* Get dimension of the pages in the entry from the API and update the view
|
||||||
*/
|
*/
|
||||||
@ -50,11 +117,6 @@ const getPages = () => {
|
|||||||
|
|
||||||
setProp('items', items);
|
setProp('items', items);
|
||||||
setProp('loading', false);
|
setProp('loading', false);
|
||||||
|
|
||||||
waitForPage(items.length, () => {
|
|
||||||
toPage(page);
|
|
||||||
setupScroller();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
const errMsg = `Failed to get the page dimensions. ${e}`;
|
const errMsg = `Failed to get the page dimensions. ${e}`;
|
||||||
@ -71,7 +133,15 @@ const getPages = () => {
|
|||||||
* @param {number} idx - One-based index of the page
|
* @param {number} idx - One-based index of the page
|
||||||
*/
|
*/
|
||||||
const toPage = (idx) => {
|
const toPage = (idx) => {
|
||||||
$(`#${idx}`).get(0).scrollIntoView(true);
|
const mode = getProp('mode');
|
||||||
|
if (mode === 'continuous') {
|
||||||
|
$(`#${idx}`).get(0).scrollIntoView(true);
|
||||||
|
} else {
|
||||||
|
if (idx >= 1 && idx <= items.length) {
|
||||||
|
setProp('curItem', items[idx - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replaceHistory(idx);
|
||||||
UIkit.modal($('#modal-sections')).hide();
|
UIkit.modal($('#modal-sections')).hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -137,6 +207,8 @@ const replaceHistory = (idx) => {
|
|||||||
* @function setupScroller
|
* @function setupScroller
|
||||||
*/
|
*/
|
||||||
const setupScroller = () => {
|
const setupScroller = () => {
|
||||||
|
const mode = getProp('mode');
|
||||||
|
if (mode !== 'continuous') return;
|
||||||
$('#root img').each((idx, el) => {
|
$('#root img').each((idx, el) => {
|
||||||
$(el).on('inview', (event, inView) => {
|
$(el).on('inview', (event, inView) => {
|
||||||
if (inView) {
|
if (inView) {
|
||||||
@ -193,3 +265,30 @@ const nextEntry = (nextUrl) => {
|
|||||||
redirect(nextUrl);
|
redirect(nextUrl);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the next or the previous page
|
||||||
|
*
|
||||||
|
* @function flipPage
|
||||||
|
* @param {bool} isNext - Whether we are going to the next page
|
||||||
|
*/
|
||||||
|
const flipPage = (isNext) => {
|
||||||
|
const curItem = getProp('curItem');
|
||||||
|
const idx = parseInt(curItem.id);
|
||||||
|
const delta = isNext ? 1 : -1;
|
||||||
|
const newIdx = idx + delta;
|
||||||
|
|
||||||
|
toPage(newIdx);
|
||||||
|
|
||||||
|
if (isNext)
|
||||||
|
setProp('flipAnimation', 'right');
|
||||||
|
else
|
||||||
|
setProp('flipAnimation', 'left');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setProp('flipAnimation', null);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
replaceHistory(newIdx);
|
||||||
|
saveProgress(newIdx);
|
||||||
|
};
|
||||||
|
@ -3,41 +3,67 @@
|
|||||||
|
|
||||||
<%= render_component "head" %>
|
<%= render_component "head" %>
|
||||||
|
|
||||||
<body>
|
<body style="position:relative;">
|
||||||
<div class="uk-section uk-section-default uk-section-small reader-bg">
|
<div class="uk-section uk-section-default uk-section-small reader-bg"
|
||||||
|
id="root"
|
||||||
|
:style="mode === 'continuous' ? '' : 'padding:0'"
|
||||||
|
x-data="{
|
||||||
|
loading: true,
|
||||||
|
mode: 'continuous', // can be 'continuous', 'height' or 'width'
|
||||||
|
msg: 'Loading the web reader. Please wait...',
|
||||||
|
alertClass: 'uk-alert-primary',
|
||||||
|
items: [],
|
||||||
|
curItem: {},
|
||||||
|
flipAnimation: null
|
||||||
|
}">
|
||||||
|
|
||||||
<div class="uk-container uk-container-small">
|
<div class="uk-container uk-container-small">
|
||||||
<div id="alert"></div>
|
<div id="alert"></div>
|
||||||
<div id="root" x-data="{
|
<div x-show="loading">
|
||||||
loading: true,
|
<div :class="alertClass" x-show="msg" uk-alert>
|
||||||
msg: 'Loading the web reader. Please wait...',
|
<p x-text="msg"></p>
|
||||||
alertClass: 'uk-alert-primary',
|
|
||||||
items: []
|
|
||||||
}">
|
|
||||||
<div x-show="loading">
|
|
||||||
<div :class="alertClass" x-show="msg" uk-alert>
|
|
||||||
<p x-text="msg"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div x-show="!loading" x-cloak>
|
|
||||||
<template x-for="item in items">
|
|
||||||
<img
|
|
||||||
uk-img
|
|
||||||
class="uk-align-center"
|
|
||||||
:data-src="item.url"
|
|
||||||
:width="item.width"
|
|
||||||
:height="item.height"
|
|
||||||
:id="item.id"
|
|
||||||
@click="showControl($event)"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<%- if next_entry_url -%>
|
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="nextEntry('<%= next_entry_url %>')">Next Entry</button>
|
|
||||||
<%- else -%>
|
|
||||||
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
|
||||||
<%- end -%>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:class="{'uk-container': true, 'uk-container-small': mode === 'continuous', 'uk-container-expand': mode !== 'continuous'}">
|
||||||
|
<div x-show="!loading && mode === 'continuous'" x-cloak>
|
||||||
|
<template x-for="item in items">
|
||||||
|
<img
|
||||||
|
uk-img
|
||||||
|
class="uk-align-center"
|
||||||
|
:data-src="item.url"
|
||||||
|
:width="item.width"
|
||||||
|
:height="item.height"
|
||||||
|
:id="item.id"
|
||||||
|
@click="showControl($event)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<%- if next_entry_url -%>
|
||||||
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="nextEntry('<%= next_entry_url %>')">Next Entry</button>
|
||||||
|
<%- else -%>
|
||||||
|
<button id="next-btn" class="uk-align-center uk-button uk-button-primary" @click="redirect('<%= exit_url %>')">Exit Reader</button>
|
||||||
|
<%- end -%>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div x-cloak x-show="!loading && mode !== 'continuous'" class="uk-flex uk-flex-middle" style="height:100vh">
|
||||||
|
|
||||||
|
<img uk-img :class="{
|
||||||
|
'uk-align-center': true,
|
||||||
|
'uk-animation-slide-left': flipAnimation === 'left',
|
||||||
|
'uk-animation-slide-right': flipAnimation === 'right'
|
||||||
|
}" :data-src="curItem.url" :width="curItem.width" :height="curItem.height" :id="curItem.id" @click="showControl($event)" :style="`
|
||||||
|
width:${mode === 'width' ? '100vw' : 'auto'};
|
||||||
|
height:${mode === 'height' ? '100vh' : 'auto'};
|
||||||
|
margin-bottom:0;
|
||||||
|
`" />
|
||||||
|
|
||||||
|
<div style="position:absolute;z-index:1; top:0;left:0; width:30%;height:100%;" @click="flipPage(false)"></div>
|
||||||
|
<div style="position:absolute;z-index:1; top:0;right:0; width:30%;height:100%;" @click="flipPage(true)"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="modal-sections" class="uk-flex-top" uk-modal>
|
<div id="modal-sections" class="uk-flex-top" uk-modal>
|
||||||
@ -52,7 +78,7 @@
|
|||||||
<p id="progress-label"></p>
|
<p id="progress-label"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-margin">
|
<div class="uk-margin">
|
||||||
<label class="uk-form-label" for="form-stacked-select">Jump to page</label>
|
<label class="uk-form-label" for="page-select">Jump to page</label>
|
||||||
<div class="uk-form-controls">
|
<div class="uk-form-controls">
|
||||||
<select id="page-select" class="uk-select">
|
<select id="page-select" class="uk-select">
|
||||||
<%- (1..entry.pages).each do |p| -%>
|
<%- (1..entry.pages).each do |p| -%>
|
||||||
@ -61,6 +87,15 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="uk-margin">
|
||||||
|
<label class="uk-form-label" for="mode-select">Mode</label>
|
||||||
|
<div class="uk-form-controls">
|
||||||
|
<select id="mode-select" class="uk-select">
|
||||||
|
<option value="continuous">Continuous</option>
|
||||||
|
<option value="paged">Paged</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-modal-footer uk-text-right">
|
<div class="uk-modal-footer uk-text-right">
|
||||||
<button class="uk-button uk-button-danger" type="button" onclick="redirect('<%= exit_url %>')">Exit Reader</button>
|
<button class="uk-button uk-button-danger" type="button" onclick="redirect('<%= exit_url %>')">Exit Reader</button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user