From ccd756f3b7b77bc4df51b8d560c4364329688d23 Mon Sep 17 00:00:00 2001 From: Braun Patrik Date: Sat, 18 Mar 2017 00:11:53 +0100 Subject: [PATCH] implementing basic directory view --- backend/middlewares/GalleryMWs.ts | 37 +++--- backend/model/DiskManger.ts | 123 +++++++++++------- frontend/app/gallery/Photo.ts | 80 ++++++++++++ .../directory/directory.gallery.component.css | 52 ++++++++ .../directory.gallery.component.html | 16 ++- .../directory/directory.gallery.component.ts | 16 ++- frontend/app/gallery/gallery.service.ts | 16 ++- frontend/app/gallery/grid/GridPhoto.ts | 77 +---------- .../loading.photo.grid.gallery.component.html | 5 +- 9 files changed, 280 insertions(+), 142 deletions(-) create mode 100644 frontend/app/gallery/Photo.ts create mode 100644 frontend/app/gallery/directory/directory.gallery.component.css diff --git a/backend/middlewares/GalleryMWs.ts b/backend/middlewares/GalleryMWs.ts index 40f74255..6c837ee1 100644 --- a/backend/middlewares/GalleryMWs.ts +++ b/backend/middlewares/GalleryMWs.ts @@ -14,7 +14,7 @@ import {ProjectPath} from "../ProjectPath"; export class GalleryMWs { - public static listDirectory(req:Request, res:Response, next:NextFunction) { + public static listDirectory(req: Request, res: Response, next: NextFunction) { let directoryName = req.params.directory || "/"; let absoluteDirectoryName = path.join(ProjectPath.ImageFolder, directoryName); @@ -27,7 +27,7 @@ export class GalleryMWs { console.error(err); return next(new Error(ErrorCodes.GENERAL_ERROR, err)); } - + req.resultPipe = new ContentWrapper(directory, null); return next(); @@ -35,26 +35,33 @@ export class GalleryMWs { } - public static removeCyclicDirectoryReferences(req:Request, res:Response, next:NextFunction) { + public static removeCyclicDirectoryReferences(req: Request, res: Response, next: NextFunction) { if (!req.resultPipe) return next(); - let cw:ContentWrapper = req.resultPipe; - if (cw.directory) { - cw.directory.photos.forEach((photo: PhotoDTO) => { + let cw: ContentWrapper = req.resultPipe; + let removeDirs = (dir) => { + dir.photos.forEach((photo: PhotoDTO) => { photo.directory = null; }); - cw.directory.directories.forEach((photo: DirectoryDTO) => { - photo.parent = null; + dir.directories.forEach((directory: DirectoryDTO) => { + removeDirs(directory); + directory.parent = null; }); + + }; + + if (cw.directory) { + removeDirs(cw.directory); } + return next(); } - public static loadImage(req:Request, res:Response, next:NextFunction) { + public static loadImage(req: Request, res: Response, next: NextFunction) { if (!(req.params.imagePath)) { return next(); } @@ -74,7 +81,7 @@ export class GalleryMWs { } - public static search(req:Request, res:Response, next:NextFunction) { + public static search(req: Request, res: Response, next: NextFunction) { if (Config.Client.Search.searchEnabled === false) { return next(); } @@ -83,7 +90,7 @@ export class GalleryMWs { return next(); } - let type:SearchTypes; + let type: SearchTypes; if (req.query.type) { type = parseInt(req.query.type); } @@ -98,11 +105,11 @@ export class GalleryMWs { } - public static instantSearch(req:Request, res:Response, next:NextFunction) { + public static instantSearch(req: Request, res: Response, next: NextFunction) { if (Config.Client.Search.instantSearchEnabled === false) { return next(); } - + if (!(req.params.text)) { return next(); } @@ -117,7 +124,7 @@ export class GalleryMWs { }); } - public static autocomplete(req:Request, res:Response, next:NextFunction) { + public static autocomplete(req: Request, res: Response, next: NextFunction) { if (Config.Client.Search.autocompleteEnabled === false) { return next(); } @@ -125,7 +132,7 @@ export class GalleryMWs { return next(); } - ObjectManagerRepository.getInstance().getSearchManager().autocomplete(req.params.text, (err, items:Array) => { + ObjectManagerRepository.getInstance().getSearchManager().autocomplete(req.params.text, (err, items: Array) => { if (err || !items) { return next(new Error(ErrorCodes.GENERAL_ERROR, err)); } diff --git a/backend/model/DiskManger.ts b/backend/model/DiskManger.ts index 92e98a74..9293e18b 100644 --- a/backend/model/DiskManger.ts +++ b/backend/model/DiskManger.ts @@ -105,55 +105,77 @@ pool.run( }); }; + let parseDir = (directoryInfo: { + relativeDirectoryName: string, + directoryName: string, + directoryParent: string, + absoluteDirectoryName: string + }, maxPhotos: number = null, photosOnly: boolean = false): Promise => { - let directory = { - name: input.directoryName, - path: input.directoryParent, - lastUpdate: Date.now(), - directories: [], - photos: [] + return new Promise((resolve, reject) => { + let promises: Array> = []; + let directory = { + name: directoryInfo.directoryName, + path: directoryInfo.directoryParent, + lastUpdate: Date.now(), + directories: [], + photos: [] + }; + fs.readdir(directoryInfo.absoluteDirectoryName, (err, list) => { + + if (err) { + return reject(err); + } + + + for (let i = 0; i < list.length; i++) { + let file = list[i]; + let fullFilePath = path.normalize(path.resolve(directoryInfo.absoluteDirectoryName, file)); + if (photosOnly == false && fs.statSync(fullFilePath).isDirectory()) { + let promise = parseDir({ + relativeDirectoryName: path.join(directoryInfo.relativeDirectoryName, path.sep), + directoryName: file, + directoryParent: path.join(directoryInfo.relativeDirectoryName, path.sep), + absoluteDirectoryName: fullFilePath + }, + 5, true + ).then((dir) => { + directory.directories.push(dir); + }); + promises.push(promise); + } else if (isImage(fullFilePath)) { + + + let promise = loadPhotoMetadata(fullFilePath).then((photoMetadata) => { + directory.photos.push({name: file, directory: null, metadata: photoMetadata}); + }); + + promises.push(promise); + if (maxPhotos != null && promises.length > maxPhotos) { + break; + } + } + } + + Promise.all(promises).then(() => { + return resolve(directory); + }).catch((err) => { + console.error(err); + }); + + }); + + }); }; - let promises: Array< Promise > = []; - fs.readdir(input.absoluteDirectoryName, (err, list) => { - - if (err) { - return done(err, null); - } - - - for (let i = 0; i < list.length; i++) { - let file = list[i]; - let fullFilePath = path.normalize(path.resolve(input.absoluteDirectoryName, file)); - if (fs.statSync(fullFilePath).isDirectory()) { - directory.directories.push({ - name: file, - path: path.join(input.relativeDirectoryName, path.sep), - lastUpdate: Date.now(), - directories: [], - photos: [] - }); - } - - if (isImage(fullFilePath)) { - - - let promise = loadPhotoMetadata(fullFilePath).then((photoMetadata) => { - directory.photos.push({name: file, directory: null, metadata: photoMetadata}); - }); - - promises.push(promise); - } - } - - Promise.all(promises).then(() => { - console.log("DiskManager: scanDirectory finished"); - return done(err, directory); - }).catch((err) => { - console.error(err); - }); + parseDir(input).then((dir) => { + console.log(dir); + done(null, dir); + }).catch((err) => { + done(err, null); }); + }); export class DiskManager { @@ -169,9 +191,16 @@ export class DiskManager { directoryParent, absoluteDirectoryName }) .on('done', (error: any, result: DirectoryDTO) => { - result.photos.forEach((ph) => { - ph.directory = result; - }); + let addDirs = (dir: DirectoryDTO) => { + dir.photos.forEach((ph) => { + ph.directory = dir; + }); + dir.directories.forEach((d) => { + addDirs(d); + }); + }; + addDirs(result); + return cb(error, result); }).on('error', (job, error) => { return cb(error, null); diff --git a/frontend/app/gallery/Photo.ts b/frontend/app/gallery/Photo.ts new file mode 100644 index 00000000..85236417 --- /dev/null +++ b/frontend/app/gallery/Photo.ts @@ -0,0 +1,80 @@ +import {PhotoDTO} from "../../../common/entities/PhotoDTO"; +import {Utils} from "../../../common/Utils"; +import {Config} from "../config/Config"; +export class Photo { + + protected replacementSizeCache: boolean|number = false; + + constructor(public photo: PhotoDTO, public renderWidth: number, public renderHeight: number) { + + } + + + thumbnailLoaded() { + if (!this.isThumbnailAvailable()) { + this.photo.readyThumbnails = this.photo.readyThumbnails || []; + this.photo.readyThumbnails.push(this.getThumbnailSize()); + } + } + + getThumbnailSize() { + let renderSize = Math.sqrt(this.renderWidth * this.renderHeight); + return Utils.findClosest(renderSize, Config.Client.thumbnailSizes); + } + + getReplacementThumbnailSize() { + + if (this.replacementSizeCache === false) { + this.replacementSizeCache = null; + + let size = this.getThumbnailSize(); + if (!!this.photo.readyThumbnails) { + for (let i = 0; i < this.photo.readyThumbnails.length; i++) { + if (this.photo.readyThumbnails[i] < size) { + this.replacementSizeCache = this.photo.readyThumbnails[i]; + break; + } + } + } + } + return this.replacementSizeCache; + } + + isReplacementThumbnailAvailable() { + return this.getReplacementThumbnailSize() !== null; + } + + isThumbnailAvailable() { + return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) != -1; + } + + getReplacementThumbnailPath() { + let size = this.getReplacementThumbnailSize(); + return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString()); + + } + + getThumbnailPath() { + let size = this.getThumbnailSize(); + return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString()); + } + + getPhotoPath() { + return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name); + } + + + equals(other: any) { + //is gridphoto + if (other.photo) { + return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name + } + + //is photo + if (other.directory) { + return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name + } + + return false; + } +} \ No newline at end of file diff --git a/frontend/app/gallery/directory/directory.gallery.component.css b/frontend/app/gallery/directory/directory.gallery.component.css new file mode 100644 index 00000000..19d224e0 --- /dev/null +++ b/frontend/app/gallery/directory/directory.gallery.component.css @@ -0,0 +1,52 @@ +a { + position: relative; +} + +.photo-container { + border: 2px solid #333; + width: 150px; + height: 150px; + + background-color: #bbbbbb; +} + +.no-image { + + color: #7f7f7f; + font-size: 50px; + top: calc(50% - 25px); + left: calc(50% - 25px); +} + +.photo { + width: 100%; + height: 100%; + background-size: cover; + background-position: center; +} + +.button { + border: 0; + padding: 0; + text-align: left; + +} + +.info { + background-color: rgba(0, 0, 0, 0.6); + color: white; + font-size: medium; + position: absolute; + bottom: 0; + left: 0; + padding: 5px; + width: 100%; +} + +a:hover .info { + background-color: rgba(0, 0, 0, 0.8); +} + +a:hover .photo-container { + border-color: #000; +} \ No newline at end of file diff --git a/frontend/app/gallery/directory/directory.gallery.component.html b/frontend/app/gallery/directory/directory.gallery.component.html index fd7be798..8b6e9149 100644 --- a/frontend/app/gallery/directory/directory.gallery.component.html +++ b/frontend/app/gallery/directory/directory.gallery.component.html @@ -1,5 +1,19 @@ - {{directory.name}} + + +
+ +
+ + +
+ +
+
{{directory.name}}
+ +
diff --git a/frontend/app/gallery/directory/directory.gallery.component.ts b/frontend/app/gallery/directory/directory.gallery.component.ts index 5e8f273d..c3a8008f 100644 --- a/frontend/app/gallery/directory/directory.gallery.component.ts +++ b/frontend/app/gallery/directory/directory.gallery.component.ts @@ -1,19 +1,31 @@ -import {Component, Input} from "@angular/core"; +import {Component, Input, OnChanges} from "@angular/core"; import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO"; import {RouterLink} from "@angular/router"; import {Utils} from "../../../../common/Utils"; +import {Photo} from "../Photo"; @Component({ selector: 'gallery-directory', templateUrl: 'app/gallery/directory/directory.gallery.component.html', + styleUrls: ['app/gallery/directory/directory.gallery.component.css'], providers: [RouterLink], }) -export class GalleryDirectoryComponent { +export class GalleryDirectoryComponent implements OnChanges { @Input() directory: DirectoryDTO; + photo: Photo = null; constructor() { } + ngOnChanges() { + setImmediate(() => { + if (this.directory.photos.length > 0) { + this.photo = new Photo(this.directory.photos[0], 100, 100); + console.log(this.photo); + } + }); + } + getDirectoryPath() { return Utils.concatUrls(this.directory.path, this.directory.name); } diff --git a/frontend/app/gallery/gallery.service.ts b/frontend/app/gallery/gallery.service.ts index 2003b033..35808d2c 100644 --- a/frontend/app/gallery/gallery.service.ts +++ b/frontend/app/gallery/gallery.service.ts @@ -36,11 +36,21 @@ export class GalleryService { if (this.lastRequest.directory != directoryName) { return; } + let addDir = (dir: DirectoryDTO) => { + dir.photos.forEach((photo: PhotoDTO) => { + photo.directory = dir; + }); + + dir.directories.forEach((directory: DirectoryDTO) => { + addDir(directory); + directory.parent = dir; + }); + + + }; + addDir(message.result.directory); - message.result.directory.photos.forEach((photo: PhotoDTO) => { - photo.directory = message.result.directory; - }); this.lastDirectory = message.result.directory; this.content = message.result; diff --git a/frontend/app/gallery/grid/GridPhoto.ts b/frontend/app/gallery/grid/GridPhoto.ts index f803685b..ae44c131 100644 --- a/frontend/app/gallery/grid/GridPhoto.ts +++ b/frontend/app/gallery/grid/GridPhoto.ts @@ -1,80 +1,11 @@ import {PhotoDTO} from "../../../../common/entities/PhotoDTO"; -import {Config} from "../../config/Config"; -import {Utils} from "../../../../common/Utils"; -export class GridPhoto { +import {Photo} from "../Photo"; +export class GridPhoto extends Photo { - private replacementSizeCache:boolean|number = false; - - constructor(public photo: PhotoDTO, public renderWidth: number, public renderHeight: number, public rowId: number) { + constructor(photo: PhotoDTO, renderWidth: number, renderHeight: number, public rowId: number) { + super(photo, renderWidth, renderHeight); } - thumbnailLoaded() { - if (!this.isThumbnailAvailable()) { - this.photo.readyThumbnails = this.photo.readyThumbnails || []; - this.photo.readyThumbnails.push(this.getThumbnailSize()); - } - } - - getThumbnailSize() { - let renderSize = Math.sqrt(this.renderWidth * this.renderHeight); - return Utils.findClosest(renderSize, Config.Client.thumbnailSizes); - } - - getReplacementThumbnailSize() { - - if (this.replacementSizeCache === false) { - this.replacementSizeCache = null; - - let size = this.getThumbnailSize(); - if (!!this.photo.readyThumbnails) { - for (let i = 0; i < this.photo.readyThumbnails.length; i++) { - if (this.photo.readyThumbnails[i] < size) { - this.replacementSizeCache = this.photo.readyThumbnails[i]; - break; - } - } - } - } - return this.replacementSizeCache; - } - - isReplacementThumbnailAvailable() { - return this.getReplacementThumbnailSize() !== null; - } - - isThumbnailAvailable() { - return this.photo.readyThumbnails && this.photo.readyThumbnails.indexOf(this.getThumbnailSize()) != -1; - } - - getReplacementThumbnailPath() { - let size = this.getReplacementThumbnailSize(); - return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString()); - - } - - getThumbnailPath() { - let size = this.getThumbnailSize(); - return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString()); - } - - getPhotoPath() { - return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name); - } - - - equals(other:any) { - //is gridphoto - if (other.photo) { - return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name - } - - //is photo - if (other.directory) { - return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name - } - - return false; - } } \ No newline at end of file diff --git a/frontend/app/gallery/grid/photo/loading/loading.photo.grid.gallery.component.html b/frontend/app/gallery/grid/photo/loading/loading.photo.grid.gallery.component.html index 3308d366..3f332128 100644 --- a/frontend/app/gallery/grid/photo/loading/loading.photo.grid.gallery.component.html +++ b/frontend/app/gallery/grid/photo/loading/loading.photo.grid.gallery.component.html @@ -1,4 +1,7 @@ -
+
+ +