Fixed zoomIn/Out slider in editBook + now you can view books offline. click on a book on your home page
This commit is contained in:
parent
c75afd74f9
commit
3364adbe31
14 changed files with 219 additions and 24 deletions
33
app/Middleware/BookCallPageAuth.js
Normal file
33
app/Middleware/BookCallPageAuth.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
'use strict'
|
||||||
|
/** @typedef {import('@adonisjs/framework/src/Request')} Request */
|
||||||
|
/** @typedef {import('@adonisjs/framework/src/Response')} Response */
|
||||||
|
/** @typedef {import('@adonisjs/framework/src/View')} View */
|
||||||
|
|
||||||
|
class BookCallPageAuth {
|
||||||
|
/**
|
||||||
|
* @param {object} ctx
|
||||||
|
* @param {Request} ctx.request
|
||||||
|
* @param {Function} next
|
||||||
|
*/
|
||||||
|
async handle(ctx, next) {
|
||||||
|
const {request, auth, response, book, call} = ctx;
|
||||||
|
// call next to advance the request
|
||||||
|
const user = auth.user;
|
||||||
|
if (book.user_id) {
|
||||||
|
// Belongs to a user. Check if the book user has a connection with this
|
||||||
|
// user
|
||||||
|
if (book.user_id === user.id) {
|
||||||
|
await next();
|
||||||
|
} else if (call.parent_id === user.id || call.guest_id === user.id) {
|
||||||
|
await next();
|
||||||
|
} else {
|
||||||
|
response.status(403);
|
||||||
|
response.send({code: 403, message: 'Book is private'});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = BookCallPageAuth
|
|
@ -2,8 +2,7 @@
|
||||||
/** @typedef {import('@adonisjs/framework/src/Request')} Request */
|
/** @typedef {import('@adonisjs/framework/src/Request')} Request */
|
||||||
/** @typedef {import('@adonisjs/framework/src/Response')} Response */
|
/** @typedef {import('@adonisjs/framework/src/Response')} Response */
|
||||||
/** @typedef {import('@adonisjs/framework/src/View')} View */
|
/** @typedef {import('@adonisjs/framework/src/View')} View */
|
||||||
const Book = use('App/Models/Book');
|
|
||||||
const UserChildUtils = use('App/Utils/UserChildUtils');
|
|
||||||
class BookPageAuth {
|
class BookPageAuth {
|
||||||
/**
|
/**
|
||||||
* @param {object} ctx
|
* @param {object} ctx
|
||||||
|
@ -11,7 +10,7 @@ class BookPageAuth {
|
||||||
* @param {Function} next
|
* @param {Function} next
|
||||||
*/
|
*/
|
||||||
async handle(ctx, next) {
|
async handle(ctx, next) {
|
||||||
const {request, auth, response, book, call} = ctx;
|
const {request, auth, response, book} = ctx;
|
||||||
// call next to advance the request
|
// call next to advance the request
|
||||||
const user = auth.user;
|
const user = auth.user;
|
||||||
if (book.user_id) {
|
if (book.user_id) {
|
||||||
|
@ -19,8 +18,6 @@ class BookPageAuth {
|
||||||
// user
|
// user
|
||||||
if (book.user_id === user.id) {
|
if (book.user_id === user.id) {
|
||||||
await next();
|
await next();
|
||||||
} else if (call.parent_id === user.id || call.guest_id === user.id) {
|
|
||||||
await next();
|
|
||||||
} else {
|
} else {
|
||||||
response.status(403);
|
response.status(403);
|
||||||
response.send({code: 403, message: 'Book is private'});
|
response.send({code: 403, message: 'Book is private'});
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8118,9 +8118,6 @@ video {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: white; }
|
color: white; }
|
||||||
|
|
||||||
.book-thumb.page-preview {
|
|
||||||
flex-basis: unset; }
|
|
||||||
|
|
||||||
.book-stitch-preview-left::before {
|
.book-stitch-preview-left::before {
|
||||||
content: '';
|
content: '';
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -505,7 +505,7 @@ video{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.book-thumb.page-preview{
|
.book-thumb.page-preview{
|
||||||
flex-basis: unset;
|
// flex-basis: unset;
|
||||||
}
|
}
|
||||||
.book-stitch-preview-left{
|
.book-stitch-preview-left{
|
||||||
&::before{
|
&::before{
|
||||||
|
|
|
@ -15,6 +15,7 @@ import Settings from "../views/settings.vue";
|
||||||
import Call from "../views/call.vue";
|
import Call from "../views/call.vue";
|
||||||
import ChildProfile from "../views/child_profile.vue";
|
import ChildProfile from "../views/child_profile.vue";
|
||||||
import EditBook from "../views/edit_book.vue";
|
import EditBook from "../views/edit_book.vue";
|
||||||
|
import BookOfflineViewer from "../views/BookOfflineViewer.vue";
|
||||||
|
|
||||||
// Call Views
|
// Call Views
|
||||||
import CallLobby from "../views/call_views/Lobby.vue";
|
import CallLobby from "../views/call_views/Lobby.vue";
|
||||||
|
@ -35,6 +36,10 @@ const routes: RouteConfig[] = [
|
||||||
path: "/create/book",
|
path: "/create/book",
|
||||||
component: EditBook
|
component: EditBook
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/book/:id",
|
||||||
|
component: BookOfflineViewer
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/call/:id",
|
path: "/call/:id",
|
||||||
component: Call,
|
component: Call,
|
||||||
|
|
137
resources/scripts/applications/home/views/BookOfflineViewer.vue
Normal file
137
resources/scripts/applications/home/views/BookOfflineViewer.vue
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
<template>
|
||||||
|
<div class="is-fullwidth is-fullheight-container p-l-lg p-r-lg">
|
||||||
|
<Loading v-if="loading" />
|
||||||
|
<div :class="`is-fullheight-container ${flipbookRef ? '' : 'is-transparent'}`" v-else>
|
||||||
|
<div class="book-view m-sm m-r-md">
|
||||||
|
<div
|
||||||
|
class="go-left m-r-sm"
|
||||||
|
style="display: inline-block; align-items: center; position: absolute; left:0px; top:0px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button book-flip-buttons"
|
||||||
|
:disabled="!canFlipLeft"
|
||||||
|
@click="onLeftClicked()"
|
||||||
|
>
|
||||||
|
<i class="fa fa-fw fa-arrow-left"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<flipbook
|
||||||
|
class="flipbook"
|
||||||
|
:pages="pages"
|
||||||
|
:forwardDirection="book.ltr ? 'right': 'left'"
|
||||||
|
:zooms="null"
|
||||||
|
:enabled="true"
|
||||||
|
@on-mounted="bookMounted()"
|
||||||
|
ref="flipbook"
|
||||||
|
v-slot="flipbook"
|
||||||
|
>
|
||||||
|
<!-- @flip-left-start="onFlip('left')" -->
|
||||||
|
<!-- @flip-right-start="onFlip('right')" -->
|
||||||
|
<div class="page-progress has-text-centered m-b-none">
|
||||||
|
<p>Page {{ flipbook.page }} of {{ flipbook.numPages }}</p>
|
||||||
|
</div>
|
||||||
|
</flipbook>
|
||||||
|
<div
|
||||||
|
class="go-right m-l-sm"
|
||||||
|
style="display: inline-block; align-items: center; position: absolute; right:0px; top:0px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="button book-flip-buttons"
|
||||||
|
:disabled="!canFlipRight"
|
||||||
|
@click="onRightClicked()"
|
||||||
|
>
|
||||||
|
<i class="fa fa-fw fa-arrow-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { mapGetters, mapActions } from "vuex";
|
||||||
|
import Flipbook from "../components/flipbook/flipbook.cjs.js";
|
||||||
|
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "BookOfflineViewer",
|
||||||
|
components: {
|
||||||
|
Flipbook,
|
||||||
|
Loading
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
const bookId = Number(this.$route.params.id);
|
||||||
|
if (!this.user || !bookId) {
|
||||||
|
this.$router.replace({ path: `/` });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.user.books.forEach(b => {
|
||||||
|
if (this.book) return;
|
||||||
|
if (b.id === bookId) {
|
||||||
|
console.log("Found Book");
|
||||||
|
this.book = b;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!this.book) {
|
||||||
|
this.notify({ message: "Book Not Found!", level: "danger" });
|
||||||
|
this.$router.replace({ path: `/` });
|
||||||
|
} else {
|
||||||
|
// create pages
|
||||||
|
// /u/books/:bookId/page/:pageNumber
|
||||||
|
const pages = [null];
|
||||||
|
for (let i = 1; i < this.book.pages + 1; i++) {
|
||||||
|
pages.push(`/u/books/${bookId}/page/${i}`);
|
||||||
|
}
|
||||||
|
this.pages = pages;
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
bookMounted() {
|
||||||
|
console.log("Book Mounted!");
|
||||||
|
if (this.$refs.flipbook) {
|
||||||
|
console.log("Found!");
|
||||||
|
this.flipbookRef = true;
|
||||||
|
// this.$refs.flipbook.onResize();
|
||||||
|
// console.log("resized");
|
||||||
|
} else {
|
||||||
|
console.log("Still Null!!");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLeftClicked() {
|
||||||
|
this.$refs.flipbook.flipLeft();
|
||||||
|
},
|
||||||
|
onRightClicked() {
|
||||||
|
this.$refs.flipbook.flipRight();
|
||||||
|
},
|
||||||
|
...mapActions(["notify"])
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canFlipLeft() {
|
||||||
|
return this.flipbookRef && this.$refs.flipbook.canFlipLeft;
|
||||||
|
},
|
||||||
|
canFlipRight() {
|
||||||
|
return this.flipbookRef && this.$refs.flipbook.canFlipRight;
|
||||||
|
},
|
||||||
|
...mapGetters(["user"])
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
book: <IBook>null,
|
||||||
|
pages: <string[]>[],
|
||||||
|
flipbookRef: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IBook {
|
||||||
|
id: number;
|
||||||
|
pages: number;
|
||||||
|
user_id?: number;
|
||||||
|
title: string;
|
||||||
|
ltr: boolean;
|
||||||
|
created_at: string;
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -199,7 +199,7 @@
|
||||||
<div class="book-text">
|
<div class="book-text">
|
||||||
<div>Previouse Page</div>
|
<div>Previouse Page</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="book-cover">
|
<div class="book-cover is-flex">
|
||||||
<img
|
<img
|
||||||
:src="pages[currentPage - 1] ? pages[currentPage - 1].base64: ''"
|
:src="pages[currentPage - 1] ? pages[currentPage - 1].base64: ''"
|
||||||
/>
|
/>
|
||||||
|
@ -245,30 +245,33 @@
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="1000"
|
:max="DEFAULT_ZOOM*2"
|
||||||
v-model="pageZoom"
|
v-model="pageZoom"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded"
|
||||||
|
ref="zoomRangeSlider"
|
||||||
|
@mouseup="blurZoomSlider()"
|
||||||
/>
|
/>
|
||||||
<div class="is-flex is-justify-between">
|
<div class="is-flex is-justify-between">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || pageZoom <= 0"
|
||||||
@click="pageZoom-=2"
|
@click="zoom(false)"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-minus"></i>
|
<i class="fa fa-fw fa-minus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || pageZoom >= DEFAULT_ZOOM * 2"
|
||||||
@click="pageZoom+=2"
|
@click="zoom(true)"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-plus"></i>
|
<i class="fa fa-fw fa-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rotations is-flex is-justify-between m-b-lg">
|
<div class="rotations is-flex is-justify-between m-b-lg">
|
||||||
|
<label class="label">Rotate Image</label>
|
||||||
<button
|
<button
|
||||||
class="button"
|
class="button"
|
||||||
@click="onRotateClicked(false)"
|
@click="onRotateClicked(false)"
|
||||||
|
@ -382,7 +385,7 @@ import Services from "../../services";
|
||||||
const DEFAULT_PAGE_WIDTH = 350;
|
const DEFAULT_PAGE_WIDTH = 350;
|
||||||
const DEFAULT_PAGE_HEIGHT = 350;
|
const DEFAULT_PAGE_HEIGHT = 350;
|
||||||
|
|
||||||
const DEFAULT_ZOOM = 500;
|
const DEFAULT_ZOOM = 250;
|
||||||
const MIME_TYPE = "image/jpeg";
|
const MIME_TYPE = "image/jpeg";
|
||||||
const COMPRESSION_RATE = 0.4;
|
const COMPRESSION_RATE = 0.4;
|
||||||
export default {
|
export default {
|
||||||
|
@ -448,6 +451,7 @@ export default {
|
||||||
const page = this.pages[this.currentPage];
|
const page = this.pages[this.currentPage];
|
||||||
console.log(newVal, oldVal);
|
console.log(newVal, oldVal);
|
||||||
const delta = Math.abs(newVal - oldVal);
|
const delta = Math.abs(newVal - oldVal);
|
||||||
|
if (!page.croppa.zoomOut) return;
|
||||||
if (newVal < oldVal) {
|
if (newVal < oldVal) {
|
||||||
//zoomOut
|
//zoomOut
|
||||||
for (let i = delta; i > 0; i--) page.croppa.zoomOut();
|
for (let i = delta; i > 0; i--) page.croppa.zoomOut();
|
||||||
|
@ -657,6 +661,16 @@ export default {
|
||||||
onRightClicked() {
|
onRightClicked() {
|
||||||
this.$refs.flipbook.flipRight();
|
this.$refs.flipbook.flipRight();
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
zoom(zoomIn: boolean) {
|
||||||
|
const amount = zoomIn ? 2 : -2;
|
||||||
|
this.pageZoom = Number(this.pageZoom) + amount;
|
||||||
|
},
|
||||||
|
blurZoomSlider() {
|
||||||
|
const slider: HTMLInputElement = this.$refs.zoomRangeSlider;
|
||||||
|
if (slider) {
|
||||||
|
slider.blur();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -703,7 +717,8 @@ export default {
|
||||||
uploading: false,
|
uploading: false,
|
||||||
errors: {},
|
errors: {},
|
||||||
DEFAULT_PAGE_WIDTH,
|
DEFAULT_PAGE_WIDTH,
|
||||||
DEFAULT_PAGE_HEIGHT
|
DEFAULT_PAGE_HEIGHT,
|
||||||
|
DEFAULT_ZOOM
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -139,7 +139,12 @@
|
||||||
<i class="fa fa-fw fa-book"></i> My Books
|
<i class="fa fa-fw fa-book"></i> My Books
|
||||||
</h2>
|
</h2>
|
||||||
<div class="is-flex m-b-md is-justify-centered has-wrap">
|
<div class="is-flex m-b-md is-justify-centered has-wrap">
|
||||||
<div class="book-thumb m-l-md" v-for="book in user.books" :key="book.id">
|
<div
|
||||||
|
class="book-thumb enabled m-l-md"
|
||||||
|
v-for="book in user.books"
|
||||||
|
:key="book.id"
|
||||||
|
@click="goToBook(book)"
|
||||||
|
>
|
||||||
<div class="book-cover">
|
<div class="book-cover">
|
||||||
<figure class="image is-2by3 m-a">
|
<figure class="image is-2by3 m-a">
|
||||||
<img :src="`/u/books/${book.id}/thumbnail`" />
|
<img :src="`/u/books/${book.id}/thumbnail`" />
|
||||||
|
@ -246,6 +251,9 @@ export default {
|
||||||
goChildProfile(connection) {
|
goChildProfile(connection) {
|
||||||
this.$router.push({ path: `/child/${connection.id}` });
|
this.$router.push({ path: `/child/${connection.id}` });
|
||||||
},
|
},
|
||||||
|
goToBook(book) {
|
||||||
|
this.$router.push({ path: `/book/${book.id}` });
|
||||||
|
},
|
||||||
async onChildCreated(child) {
|
async onChildCreated(child) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
await this.getUser();
|
await this.getUser();
|
||||||
|
|
|
@ -42,6 +42,7 @@ const globalMiddleware =
|
||||||
auth: 'Adonis/Middleware/Auth',
|
auth: 'Adonis/Middleware/Auth',
|
||||||
guest: 'Adonis/Middleware/AllowGuestOnly',
|
guest: 'Adonis/Middleware/AllowGuestOnly',
|
||||||
adminAuth: 'App/Middleware/AdminAuth',
|
adminAuth: 'App/Middleware/AdminAuth',
|
||||||
|
BookCallPageAuth: 'App/Middleware/BookCallPageAuth',
|
||||||
BookPageAuth: 'App/Middleware/BookPageAuth',
|
BookPageAuth: 'App/Middleware/BookPageAuth',
|
||||||
BookContext: 'App/Middleware/BookContext',
|
BookContext: 'App/Middleware/BookContext',
|
||||||
CallContext: 'App/Middleware/CallContext',
|
CallContext: 'App/Middleware/CallContext',
|
||||||
|
|
|
@ -61,7 +61,9 @@ Route
|
||||||
.get(
|
.get(
|
||||||
'/u/call/:callId/books/:bookId/page/:pageNumber',
|
'/u/call/:callId/books/:bookId/page/:pageNumber',
|
||||||
'BookApiController.getPage')
|
'BookApiController.getPage')
|
||||||
.middleware(['auth', 'BookContext', 'CallContext', 'BookPageAuth']);
|
.middleware(['auth', 'BookContext', 'CallContext', 'BookCallPageAuth']);
|
||||||
|
Route.get('/u/books/:bookId/page/:pageNumber', 'BookApiController.getPage')
|
||||||
|
.middleware(['auth', 'BookContext', 'BookPageAuth']);
|
||||||
/**
|
/**
|
||||||
* Public book thumbnail
|
* Public book thumbnail
|
||||||
*/
|
*/
|
||||||
|
|
Reference in a new issue