1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

implementing basic directory view

This commit is contained in:
Braun Patrik 2017-03-18 00:11:53 +01:00
parent c86fbf3509
commit ccd756f3b7
9 changed files with 280 additions and 142 deletions

View File

@ -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);
@ -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,7 +105,7 @@ 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();
}
@ -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<AutoCompleteItem>) => {
ObjectManagerRepository.getInstance().getSearchManager().autocomplete(req.params.text, (err, items: Array<AutoCompleteItem>) => {
if (err || !items) {
return next(new Error(ErrorCodes.GENERAL_ERROR, err));
}

View File

@ -105,55 +105,77 @@ pool.run(
});
};
let parseDir = (directoryInfo: {
relativeDirectoryName: string,
directoryName: string,
directoryParent: string,
absoluteDirectoryName: string
}, maxPhotos: number = null, photosOnly: boolean = false): Promise<DirectoryDTO> => {
let directory = <DirectoryDTO>{
name: input.directoryName,
path: input.directoryParent,
lastUpdate: Date.now(),
directories: [],
photos: []
return new Promise<DirectoryDTO>((resolve, reject) => {
let promises: Array<Promise<any>> = [];
let directory = <DirectoryDTO>{
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(<PhotoDTO>{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<any> > = [];
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(<DirectoryDTO>{
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(<PhotoDTO>{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);

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -1,5 +1,19 @@
<a class="button btn btn-default" [routerLink]="['/gallery', getDirectoryPath()]"
style="display: inline-block;">
{{directory.name}}
<div class="photo-container">
<div class="photo" *ngIf="photo" [style.background-image]="'url('+photo.getThumbnailPath()+')'"></div>
<span *ngIf="!photo" class="glyphicon glyphicon-folder-open no-image" aria-hidden="true">
</span>
</div>
<!--Info box -->
<div #info class="info">
<div class="photo-name">{{directory.name}}</div>
</div>
</a>

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -1,4 +1,7 @@
<div class="static" *ngIf="animate == false"><span class="glyphicon glyphicon-picture" aria-hidden="true"></span></div>
<div class="static" *ngIf="animate == false">
<span class="glyphicon glyphicon-picture" aria-hidden="true">
</span>
</div>
<div class="sk-cube-grid animate" *ngIf="animate == true">
<div class="sk-cube sk-cube1"></div>
<div class="sk-cube sk-cube2"></div>