mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
adding browser history support for lightbox
This commit is contained in:
parent
4afff63415
commit
62ccedcc2f
@ -7,6 +7,7 @@ import {Title} from '@angular/platform-browser';
|
|||||||
import {NotificationService} from './model/notification.service';
|
import {NotificationService} from './model/notification.service';
|
||||||
import {ShareService} from './gallery/share.service';
|
import {ShareService} from './gallery/share.service';
|
||||||
import 'hammerjs';
|
import 'hammerjs';
|
||||||
|
import {QueryService} from './model/query.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pi-gallery2',
|
selector: 'app-pi-gallery2',
|
||||||
|
@ -66,6 +66,7 @@ import {DefaultUrlSerializer, UrlSerializer, UrlTree} from '@angular/router';
|
|||||||
import {IndexingSettingsComponent} from './settings/indexing/indexing.settings.component';
|
import {IndexingSettingsComponent} from './settings/indexing/indexing.settings.component';
|
||||||
import {LanguageComponent} from './language/language.component';
|
import {LanguageComponent} from './language/language.component';
|
||||||
import {I18n, MISSING_TRANSLATION_STRATEGY} from '@ngx-translate/i18n-polyfill';
|
import {I18n, MISSING_TRANSLATION_STRATEGY} from '@ngx-translate/i18n-polyfill';
|
||||||
|
import {QueryService} from './model/query.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleMapsConfig {
|
export class GoogleMapsConfig {
|
||||||
@ -173,18 +174,19 @@ export function translationsFactory(locale: string) {
|
|||||||
NavigationService,
|
NavigationService,
|
||||||
SettingsService,
|
SettingsService,
|
||||||
OverlayService,
|
OverlayService,
|
||||||
|
QueryService,
|
||||||
{
|
{
|
||||||
provide: TRANSLATIONS,
|
provide: TRANSLATIONS,
|
||||||
useFactory: translationsFactory,
|
useFactory: translationsFactory,
|
||||||
deps: [LOCALE_ID]
|
deps: [LOCALE_ID]
|
||||||
},
|
},
|
||||||
I18n,
|
I18n,
|
||||||
/*
|
|
||||||
{provide: TRANSLATIONS, useValue: translationsFactory('en')},
|
{provide: TRANSLATIONS, useValue: translationsFactory('en')},
|
||||||
{provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
|
{provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
|
||||||
{provide: LOCALE_ID, useValue: 'en'},
|
{provide: LOCALE_ID, useValue: 'en'},
|
||||||
{provide: MISSING_TRANSLATION_STRATEGY, useValue: MissingTranslationStrategy.Ignore},
|
{provide: MISSING_TRANSLATION_STRATEGY, useValue: MissingTranslationStrategy.Ignore},
|
||||||
*/
|
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<ng2-slim-loading-bar [color]="'#337ab7'" [height]="'3px'"></ng2-slim-loading-bar>
|
<ng2-slim-loading-bar [color]="'#337ab7'" [height]="'3px'"></ng2-slim-loading-bar>
|
||||||
<nav class="navbar navbar-dark bg-dark navbar-expand-md">
|
<nav class="navbar navbar-dark bg-dark navbar-expand-md">
|
||||||
<a class="navbar-brand" [routerLink]="['/gallery','/']"
|
<a class="navbar-brand" [routerLink]="['/gallery','/']"
|
||||||
[queryParams]="_shareService.isSharing() ? { sk: _shareService.getSharingKey() }:{}">
|
[queryParams]="queryService.getParams()">
|
||||||
<img src="assets/icon_inv.png" width="30" height="30" class="d-inline-block align-top" alt="">
|
<img src="assets/icon_inv.png" width="30" height="30" class="d-inline-block align-top" alt="">
|
||||||
<strong>{{title}}</strong>
|
<strong>{{title}}</strong>
|
||||||
</a>
|
</a>
|
||||||
|
@ -6,6 +6,7 @@ import {Config} from '../../../common/config/public/Config';
|
|||||||
import {BehaviorSubject} from 'rxjs';
|
import {BehaviorSubject} from 'rxjs';
|
||||||
import {NotificationService} from '../model/notification.service';
|
import {NotificationService} from '../model/notification.service';
|
||||||
import {ShareService} from '../gallery/share.service';
|
import {ShareService} from '../gallery/share.service';
|
||||||
|
import {QueryService} from '../model/query.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-frame',
|
selector: 'app-frame',
|
||||||
@ -23,7 +24,7 @@ export class FrameComponent {
|
|||||||
|
|
||||||
constructor(private _authService: AuthenticationService,
|
constructor(private _authService: AuthenticationService,
|
||||||
public notificationService: NotificationService,
|
public notificationService: NotificationService,
|
||||||
public _shareService: ShareService) {
|
public queryService: QueryService) {
|
||||||
this.user = this._authService.user;
|
this.user = this._authService.user;
|
||||||
this.authenticationRequired = Config.Client.authenticationRequired;
|
this.authenticationRequired = Config.Client.authenticationRequired;
|
||||||
this.title = Config.Client.applicationTitle;
|
this.title = Config.Client.applicationTitle;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<a #dirContainer class="button btn btn-default" [routerLink]="['/gallery', getDirectoryPath()]"
|
<a #dirContainer class="button btn btn-default"
|
||||||
[queryParams]="_shareService.isSharing() ? { sk: _shareService.getSharingKey() }:{}"
|
[routerLink]="['/gallery', getDirectoryPath()]"
|
||||||
|
[queryParams]="queryService.getParams()"
|
||||||
style="display: inline-block;">
|
style="display: inline-block;">
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import {Photo} from '../Photo';
|
|||||||
import {Thumbnail, ThumbnailManagerService} from '../thumnailManager.service';
|
import {Thumbnail, ThumbnailManagerService} from '../thumnailManager.service';
|
||||||
import {ShareService} from '../share.service';
|
import {ShareService} from '../share.service';
|
||||||
import {PageHelper} from '../../model/page.helper';
|
import {PageHelper} from '../../model/page.helper';
|
||||||
|
import {QueryService} from '../../model/query.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery-directory',
|
selector: 'app-gallery-directory',
|
||||||
@ -21,7 +22,7 @@ export class GalleryDirectoryComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor(private thumbnailService: ThumbnailManagerService,
|
constructor(private thumbnailService: ThumbnailManagerService,
|
||||||
private _sanitizer: DomSanitizer,
|
private _sanitizer: DomSanitizer,
|
||||||
public _shareService: ShareService) {
|
public queryService: QueryService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<app-gallery-lightbox #lightbox (onLastElement)="onLightboxLastElement()"></app-gallery-lightbox>
|
<app-gallery-lightbox #lightbox></app-gallery-lightbox>
|
||||||
<app-frame>
|
<app-frame>
|
||||||
|
|
||||||
<ng-container navbar>
|
<ng-container navbar>
|
||||||
|
@ -14,6 +14,8 @@ import {UserRoles} from '../../../common/entities/UserDTO';
|
|||||||
import {interval} from 'rxjs';
|
import {interval} from 'rxjs';
|
||||||
import {ContentWrapper} from '../../../common/entities/ConentWrapper';
|
import {ContentWrapper} from '../../../common/entities/ConentWrapper';
|
||||||
import {PageHelper} from '../model/page.helper';
|
import {PageHelper} from '../model/page.helper';
|
||||||
|
import {QueryService} from '../model/query.service';
|
||||||
|
import {LightboxStates} from './lightbox/lightbox.gallery.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery',
|
selector: 'app-gallery',
|
||||||
@ -92,6 +94,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this._galleryService.getDirectory(directoryName);
|
this._galleryService.getDirectory(directoryName);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
@ -150,11 +153,5 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onLightboxLastElement() {
|
|
||||||
this.grid.renderARow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ export class GridRowBuilder {
|
|||||||
private photoMargin: number,
|
private photoMargin: number,
|
||||||
private containerWidth: number) {
|
private containerWidth: number) {
|
||||||
this.photoIndex = startIndex;
|
this.photoIndex = startIndex;
|
||||||
|
if (this.containerWidth <= 0) {
|
||||||
|
throw new Error('container width cant be <=0, got:' + this.containerWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public addPhotos(number: number) {
|
public addPhotos(number: number) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<div #gridContainer>
|
<div #gridContainer>
|
||||||
<app-gallery-grid-photo
|
<app-gallery-grid-photo
|
||||||
*ngFor="let gridPhoto of photosToRender"
|
*ngFor="let gridPhoto of photosToRender"
|
||||||
(click)="lightbox.show(gridPhoto.photo)"
|
|
||||||
|
[routerLink]="[]"
|
||||||
|
[queryParams]="queryService.getParams(gridPhoto.photo)"
|
||||||
[gridPhoto]="gridPhoto"
|
[gridPhoto]="gridPhoto"
|
||||||
[style.width.px]="gridPhoto.renderWidth"
|
[style.width.px]="gridPhoto.renderWidth"
|
||||||
[style.height.px]="gridPhoto.renderHeight"
|
[style.height.px]="gridPhoto.renderHeight"
|
||||||
|
@ -9,23 +9,28 @@ import {
|
|||||||
OnDestroy,
|
OnDestroy,
|
||||||
QueryList,
|
QueryList,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewChildren
|
ViewChildren,
|
||||||
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {PhotoDTO} from '../../../../common/entities/PhotoDTO';
|
import {PhotoDTO} from '../../../../common/entities/PhotoDTO';
|
||||||
import {GridRowBuilder} from './GridRowBuilder';
|
import {GridRowBuilder} from './GridRowBuilder';
|
||||||
import {GalleryLightboxComponent} from '../lightbox/lightbox.gallery.component';
|
import {GalleryLightboxComponent, LightboxStates} from '../lightbox/lightbox.gallery.component';
|
||||||
import {GridPhoto} from './GridPhoto';
|
import {GridPhoto} from './GridPhoto';
|
||||||
import {GalleryPhotoComponent} from './photo/photo.grid.gallery.component';
|
import {GalleryPhotoComponent} from './photo/photo.grid.gallery.component';
|
||||||
import {OverlayService} from '../overlay.service';
|
import {OverlayService} from '../overlay.service';
|
||||||
import {Config} from '../../../../common/config/public/Config';
|
import {Config} from '../../../../common/config/public/Config';
|
||||||
import {PageHelper} from '../../model/page.helper';
|
import {PageHelper} from '../../model/page.helper';
|
||||||
|
import {Subscription} from 'rxjs';
|
||||||
|
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||||
|
import {QueryService} from '../../model/query.service';
|
||||||
|
import {SimpleChanges} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery-grid',
|
selector: 'app-gallery-grid',
|
||||||
templateUrl: './grid.gallery.component.html',
|
templateUrl: './grid.gallery.component.html',
|
||||||
styleUrls: ['./grid.gallery.component.css'],
|
styleUrls: ['./grid.gallery.component.css'],
|
||||||
})
|
})
|
||||||
export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy {
|
export class GalleryGridComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('gridContainer') gridContainer: ElementRef;
|
@ViewChild('gridContainer') gridContainer: ElementRef;
|
||||||
@ViewChildren(GalleryPhotoComponent) gridPhotoQL: QueryList<GalleryPhotoComponent>;
|
@ViewChildren(GalleryPhotoComponent) gridPhotoQL: QueryList<GalleryPhotoComponent>;
|
||||||
@ -47,9 +52,27 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
private helperTime = null;
|
private helperTime = null;
|
||||||
isAfterViewInit = false;
|
isAfterViewInit = false;
|
||||||
private renderedPhotoIndex = 0;
|
private renderedPhotoIndex = 0;
|
||||||
|
routeSubscription: Subscription = null;
|
||||||
|
delayedRenderUpToPhoto: string = null;
|
||||||
|
|
||||||
constructor(private overlayService: OverlayService,
|
constructor(private overlayService: OverlayService,
|
||||||
private changeDetector: ChangeDetectorRef) {
|
private changeDetector: ChangeDetectorRef,
|
||||||
|
public queryService: QueryService,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.routeSubscription = this.route.queryParams.subscribe((params: Params) => {
|
||||||
|
if (params[QueryService.PHOTO_PARAM] && params[QueryService.PHOTO_PARAM] !== '') {
|
||||||
|
this.delayedRenderUpToPhoto = params[QueryService.PHOTO_PARAM];
|
||||||
|
if (!this.photos || this.photos.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderUpToPhoto(params[QueryService.PHOTO_PARAM]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
@ -61,6 +84,9 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
this.mergeNewPhotos();
|
this.mergeNewPhotos();
|
||||||
this.helperTime = setTimeout(() => {
|
this.helperTime = setTimeout(() => {
|
||||||
this.renderPhotos();
|
this.renderPhotos();
|
||||||
|
if (this.delayedRenderUpToPhoto) {
|
||||||
|
this.renderUpToPhoto(this.delayedRenderUpToPhoto);
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,11 +131,22 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
this.isAfterViewInit = true;
|
this.isAfterViewInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderARow(): number {
|
|
||||||
if (this.renderedPhotoIndex >= this.photos.length) {
|
private renderUpToPhoto(photoName: string) {
|
||||||
return null;
|
const index = this.photos.findIndex(p => p.name === photoName);
|
||||||
|
if (index === -1) {
|
||||||
|
this.router.navigate([], {queryParams: this.queryService.getParams()});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (this.renderedPhotoIndex < index && this.renderARow()) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public renderARow(): number {
|
||||||
|
if (this.renderedPhotoIndex >= this.photos.length
|
||||||
|
|| this.containerWidth === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let maxRowHeight = this.screenHeight / this.MIN_ROW_COUNT;
|
let maxRowHeight = this.screenHeight / this.MIN_ROW_COUNT;
|
||||||
const minRowHeight = this.screenHeight / this.MAX_ROW_COUNT;
|
const minRowHeight = this.screenHeight / this.MAX_ROW_COUNT;
|
||||||
@ -146,7 +183,7 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
}
|
}
|
||||||
|
|
||||||
private sortPhotos() {
|
private sortPhotos() {
|
||||||
// sort pohots by date
|
// sort photos by date
|
||||||
this.photos.sort((a: PhotoDTO, b: PhotoDTO) => {
|
this.photos.sort((a: PhotoDTO, b: PhotoDTO) => {
|
||||||
return a.metadata.creationDate - b.metadata.creationDate;
|
return a.metadata.creationDate - b.metadata.creationDate;
|
||||||
});
|
});
|
||||||
@ -168,7 +205,6 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastSameIndex > 0) {
|
if (lastSameIndex > 0) {
|
||||||
this.photosToRender.splice(lastSameIndex, this.photosToRender.length - lastSameIndex);
|
this.photosToRender.splice(lastSameIndex, this.photosToRender.length - lastSameIndex);
|
||||||
this.renderedPhotoIndex = lastSameIndex;
|
this.renderedPhotoIndex = lastSameIndex;
|
||||||
@ -239,6 +275,8 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pre = PageHelper.isScrollYVisible();
|
||||||
|
PageHelper.showScrollY();
|
||||||
// if the width changed a bit or the height changed a lot
|
// if the width changed a bit or the height changed a lot
|
||||||
if (this.containerWidth !== this.gridContainer.nativeElement.clientWidth
|
if (this.containerWidth !== this.gridContainer.nativeElement.clientWidth
|
||||||
|| this.screenHeight < window.innerHeight * 0.75
|
|| this.screenHeight < window.innerHeight * 0.75
|
||||||
@ -246,9 +284,15 @@ export class GalleryGridComponent implements OnChanges, AfterViewInit, OnDestroy
|
|||||||
this.screenHeight = window.innerHeight;
|
this.screenHeight = window.innerHeight;
|
||||||
this.containerWidth = this.gridContainer.nativeElement.clientWidth;
|
this.containerWidth = this.gridContainer.nativeElement.clientWidth;
|
||||||
this.clearRenderedPhotos();
|
this.clearRenderedPhotos();
|
||||||
|
if (!pre) {
|
||||||
|
PageHelper.hideScrollY();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pre) {
|
||||||
|
PageHelper.hideScrollY();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div [hidden]="!visible" #root>
|
<div [hidden]="!isVisible()" #root>
|
||||||
|
|
||||||
<div class="blackCanvas"
|
<div class="blackCanvas"
|
||||||
[style.opacity]="blackCanvasOpacity">
|
[style.opacity]="blackCanvasOpacity">
|
||||||
|
@ -19,6 +19,15 @@ import {animate, AnimationBuilder, AnimationPlayer, style} from '@angular/animat
|
|||||||
import {GalleryLightboxPhotoComponent} from './photo/photo.lightbox.gallery.component';
|
import {GalleryLightboxPhotoComponent} from './photo/photo.lightbox.gallery.component';
|
||||||
import {Observable, Subscription, timer} from 'rxjs';
|
import {Observable, Subscription, timer} from 'rxjs';
|
||||||
import {filter} from 'rxjs/operators';
|
import {filter} from 'rxjs/operators';
|
||||||
|
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||||
|
import {PageHelper} from '../../model/page.helper';
|
||||||
|
import {QueryService} from '../../model/query.service';
|
||||||
|
|
||||||
|
export enum LightboxStates {
|
||||||
|
Open,
|
||||||
|
Closing,
|
||||||
|
Closed
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery-lightbox',
|
selector: 'app-gallery-lightbox',
|
||||||
@ -27,8 +36,6 @@ import {filter} from 'rxjs/operators';
|
|||||||
})
|
})
|
||||||
export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
|
|
||||||
@Output('onLastElement') onLastElement = new EventEmitter();
|
|
||||||
@ViewChild('photo') photoElement: GalleryLightboxPhotoComponent;
|
@ViewChild('photo') photoElement: GalleryLightboxPhotoComponent;
|
||||||
@ViewChild('lightbox') lightboxElement: ElementRef;
|
@ViewChild('lightbox') lightboxElement: ElementRef;
|
||||||
|
|
||||||
@ -39,8 +46,14 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
public activePhoto: GalleryPhotoComponent;
|
public activePhoto: GalleryPhotoComponent;
|
||||||
private gridPhotoQL: QueryList<GalleryPhotoComponent>;
|
private gridPhotoQL: QueryList<GalleryPhotoComponent>;
|
||||||
|
|
||||||
public visible = false;
|
public status: LightboxStates = LightboxStates.Closed;
|
||||||
private changeSubscription: Subscription = null;
|
private subscription: {
|
||||||
|
photosChange: Subscription,
|
||||||
|
route: Subscription
|
||||||
|
} = {
|
||||||
|
photosChange: null,
|
||||||
|
route: null
|
||||||
|
};
|
||||||
private timer: Observable<number>;
|
private timer: Observable<number>;
|
||||||
private timerSub: Subscription;
|
private timerSub: Subscription;
|
||||||
public playBackState = 0;
|
public playBackState = 0;
|
||||||
@ -53,21 +66,41 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
startPhotoDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0};
|
startPhotoDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0};
|
||||||
iPvisibilityTimer = null;
|
iPvisibilityTimer = null;
|
||||||
visibilityTimer = null;
|
visibilityTimer = null;
|
||||||
|
delayedPhotoShow: string = null;
|
||||||
|
|
||||||
|
|
||||||
constructor(public fullScreenService: FullScreenService,
|
constructor(public fullScreenService: FullScreenService,
|
||||||
private changeDetector: ChangeDetectorRef, private overlayService: OverlayService,
|
private changeDetector: ChangeDetectorRef,
|
||||||
private _builder: AnimationBuilder) {
|
private overlayService: OverlayService,
|
||||||
|
private _builder: AnimationBuilder,
|
||||||
|
private router: Router,
|
||||||
|
private queryService: QueryService,
|
||||||
|
private route: ActivatedRoute) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.timer = timer(1000, 2000);
|
this.timer = timer(1000, 2000);
|
||||||
|
this.subscription.route = this.route.queryParams.subscribe((params: Params) => {
|
||||||
|
if (params[QueryService.PHOTO_PARAM] && params[QueryService.PHOTO_PARAM] !== '') {
|
||||||
|
if (!this.gridPhotoQL) {
|
||||||
|
return this.delayedPhotoShow = params[QueryService.PHOTO_PARAM];
|
||||||
|
}
|
||||||
|
this.onNavigateTo(params[QueryService.PHOTO_PARAM]);
|
||||||
|
} else if (this.status === LightboxStates.Open) {
|
||||||
|
this.delayedPhotoShow = null;
|
||||||
|
this.hideLigthbox();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
console.log('destroy');
|
||||||
this.pause();
|
this.pause();
|
||||||
if (this.changeSubscription != null) {
|
if (this.subscription.photosChange != null) {
|
||||||
this.changeSubscription.unsubscribe();
|
this.subscription.photosChange.unsubscribe();
|
||||||
|
}
|
||||||
|
if (this.subscription.route != null) {
|
||||||
|
this.subscription.route.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.visibilityTimer != null) {
|
if (this.visibilityTimer != null) {
|
||||||
@ -78,6 +111,41 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onNavigateTo(photoName: string) {
|
||||||
|
if (this.activePhoto && this.activePhoto.gridPhoto.photo.name === photoName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const photo = this.gridPhotoQL.find(i => i.gridPhoto.photo.name === photoName);
|
||||||
|
if (!photo) {
|
||||||
|
return this.delayedPhotoShow = photoName;
|
||||||
|
}
|
||||||
|
if (this.status === LightboxStates.Closed) {
|
||||||
|
this.showLigthbox(photo.gridPhoto.photo);
|
||||||
|
} else {
|
||||||
|
this.showPhoto(this.gridPhotoQL.toArray().indexOf(photo));
|
||||||
|
}
|
||||||
|
this.delayedPhotoShow = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGridPhotoQL(value: QueryList<GalleryPhotoComponent>) {
|
||||||
|
if (this.subscription.photosChange != null) {
|
||||||
|
this.subscription.photosChange.unsubscribe();
|
||||||
|
}
|
||||||
|
this.gridPhotoQL = value;
|
||||||
|
this.subscription.photosChange = this.gridPhotoQL.changes.subscribe(() => {
|
||||||
|
if (this.activePhotoId != null && this.gridPhotoQL.length > this.activePhotoId) {
|
||||||
|
this.updateActivePhoto(this.activePhotoId);
|
||||||
|
}
|
||||||
|
if (this.delayedPhotoShow) {
|
||||||
|
this.onNavigateTo(this.delayedPhotoShow);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.delayedPhotoShow) {
|
||||||
|
this.onNavigateTo(this.delayedPhotoShow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//noinspection JSUnusedGlobalSymbols
|
//noinspection JSUnusedGlobalSymbols
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize() {
|
onResize() {
|
||||||
@ -89,10 +157,10 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
public nextImage() {
|
public nextImage() {
|
||||||
if (this.activePhotoId + 1 < this.gridPhotoQL.length) {
|
if (this.activePhotoId + 1 < this.gridPhotoQL.length) {
|
||||||
this.showPhoto(this.activePhotoId + 1);
|
this.navigateToPhoto(this.activePhotoId + 1);
|
||||||
if (this.activePhotoId + 3 >= this.gridPhotoQL.length) {
|
/*if (this.activePhotoId + 3 >= this.gridPhotoQL.length) {
|
||||||
this.onLastElement.emit({}); // trigger to render more photos if there are
|
this.onLastElement.emit({}); // trigger to render more photos if there are
|
||||||
}
|
}*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,29 +168,38 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
public prevImage() {
|
public prevImage() {
|
||||||
this.pause();
|
this.pause();
|
||||||
if (this.activePhotoId > 0) {
|
if (this.activePhotoId > 0) {
|
||||||
this.showPhoto(this.activePhotoId - 1);
|
this.navigateToPhoto(this.activePhotoId - 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private navigateToPhoto(photoIndex: number) {
|
||||||
|
this.router.navigate([],
|
||||||
|
{queryParams: this.queryService.getParams(this.gridPhotoQL.toArray()[photoIndex].gridPhoto.photo)});
|
||||||
|
/*
|
||||||
|
this.activePhoto = null;
|
||||||
|
this.changeDetector.detectChanges();
|
||||||
|
this.updateActivePhoto(photoIndex, resize);*/
|
||||||
|
}
|
||||||
|
|
||||||
private showPhoto(photoIndex: number, resize: boolean = true) {
|
private showPhoto(photoIndex: number, resize: boolean = true) {
|
||||||
this.activePhoto = null;
|
this.activePhoto = null;
|
||||||
this.changeDetector.detectChanges();
|
this.changeDetector.detectChanges();
|
||||||
this.updateActivePhoto(photoIndex, resize);
|
this.updateActivePhoto(photoIndex, resize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public show(photo: PhotoDTO) {
|
public showLigthbox(photo: PhotoDTO) {
|
||||||
this.controllersVisible = true;
|
this.controllersVisible = true;
|
||||||
this.showControls();
|
this.showControls();
|
||||||
this.visible = true;
|
this.status = LightboxStates.Open;
|
||||||
const selectedPhoto = this.findPhotoComponent(photo);
|
const selectedPhoto = this.findPhotoComponent(photo);
|
||||||
if (selectedPhoto === null) {
|
if (selectedPhoto === null) {
|
||||||
throw new Error('Can\'t find Photo');
|
throw new Error('Can\'t find Photo');
|
||||||
}
|
}
|
||||||
|
|
||||||
const lightboxDimension = selectedPhoto.getDimension();
|
const lightboxDimension = selectedPhoto.getDimension();
|
||||||
lightboxDimension.top -= this.getBodyScrollTop();
|
lightboxDimension.top -= PageHelper.ScrollY;
|
||||||
this.animating = true;
|
this.animating = true;
|
||||||
this.animatePhoto(selectedPhoto.getDimension(), this.calcLightBoxPhotoDimension(selectedPhoto.gridPhoto.photo)).onDone(() => {
|
this.animatePhoto(selectedPhoto.getDimension(), this.calcLightBoxPhotoDimension(selectedPhoto.gridPhoto.photo)).onDone(() => {
|
||||||
this.animating = false;
|
this.animating = false;
|
||||||
@ -148,7 +225,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
//noinspection JSUnusedGlobalSymbols
|
//noinspection JSUnusedGlobalSymbols
|
||||||
@HostListener('window:keydown', ['$event'])
|
@HostListener('window:keydown', ['$event'])
|
||||||
onKeyPress(e: KeyboardEvent) {
|
onKeyPress(e: KeyboardEvent) {
|
||||||
if (this.visible !== true) {
|
if (this.status !== LightboxStates.Open) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const event: KeyboardEvent = window.event ? <any>window.event : e;
|
const event: KeyboardEvent = window.event ? <any>window.event : e;
|
||||||
@ -170,13 +247,19 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hide() {
|
public hide() {
|
||||||
|
this.router.navigate([],
|
||||||
|
{queryParams: this.queryService.getParams()});
|
||||||
|
}
|
||||||
|
|
||||||
|
private hideLigthbox() {
|
||||||
this.controllersVisible = false;
|
this.controllersVisible = false;
|
||||||
|
this.status = LightboxStates.Closing;
|
||||||
this.fullScreenService.exitFullScreen();
|
this.fullScreenService.exitFullScreen();
|
||||||
this.pause();
|
this.pause();
|
||||||
|
|
||||||
this.animating = true;
|
this.animating = true;
|
||||||
const lightboxDimension = this.activePhoto.getDimension();
|
const lightboxDimension = this.activePhoto.getDimension();
|
||||||
lightboxDimension.top -= this.getBodyScrollTop();
|
lightboxDimension.top -= PageHelper.ScrollY;
|
||||||
this.blackCanvasOpacity = 0;
|
this.blackCanvasOpacity = 0;
|
||||||
|
|
||||||
this.animatePhoto(this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo), this.activePhoto.getDimension());
|
this.animatePhoto(this.calcLightBoxPhotoDimension(this.activePhoto.gridPhoto.photo), this.activePhoto.getDimension());
|
||||||
@ -186,8 +269,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
width: this.getPhotoFrameWidth(),
|
width: this.getPhotoFrameWidth(),
|
||||||
height: this.getPhotoFrameHeight()
|
height: this.getPhotoFrameHeight()
|
||||||
}, lightboxDimension).onDone(() => {
|
}, lightboxDimension).onDone(() => {
|
||||||
|
this.status = LightboxStates.Closed;
|
||||||
this.visible = false;
|
|
||||||
this.activePhoto = null;
|
this.activePhoto = null;
|
||||||
this.activePhotoId = null;
|
this.activePhotoId = null;
|
||||||
this.overlayService.hideOverlay();
|
this.overlayService.hideOverlay();
|
||||||
@ -227,18 +309,6 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
setGridPhotoQL(value: QueryList<GalleryPhotoComponent>) {
|
|
||||||
if (this.changeSubscription != null) {
|
|
||||||
this.changeSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
this.gridPhotoQL = value;
|
|
||||||
this.changeSubscription = this.gridPhotoQL.changes.subscribe(() => {
|
|
||||||
if (this.activePhotoId != null && this.gridPhotoQL.length > this.activePhotoId) {
|
|
||||||
this.updateActivePhoto(this.activePhotoId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleInfoPanel() {
|
public toggleInfoPanel() {
|
||||||
|
|
||||||
|
|
||||||
@ -287,7 +357,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
if (this.navigation.hasNext) {
|
if (this.navigation.hasNext) {
|
||||||
this.nextImage();
|
this.nextImage();
|
||||||
} else {
|
} else {
|
||||||
this.showPhoto(0);
|
this.navigateToPhoto(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.playBackState = 1;
|
this.playBackState = 1;
|
||||||
@ -326,21 +396,13 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
if (this.navigation.hasNext) {
|
if (this.navigation.hasNext) {
|
||||||
this.nextImage();
|
this.nextImage();
|
||||||
} else {
|
} else {
|
||||||
this.showPhoto(0);
|
this.navigateToPhoto(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.playBackState = 2;
|
this.playBackState = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private getBodyScrollTop(): number {
|
|
||||||
return window.scrollY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private setBodyScrollTop(value: number) {
|
|
||||||
window.scrollTo(window.scrollX, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPhotoFrameWidth(): number {
|
public getPhotoFrameWidth(): number {
|
||||||
return Math.max(window.innerWidth - this.infoPanelWidth, 0);
|
return Math.max(window.innerWidth - this.infoPanelWidth, 0);
|
||||||
}
|
}
|
||||||
@ -372,15 +434,15 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
const to = this.activePhoto.getDimension();
|
const to = this.activePhoto.getDimension();
|
||||||
|
|
||||||
// if target image out of screen -> scroll to there
|
// if target image out of screen -> scroll to there
|
||||||
if (this.getBodyScrollTop() > to.top || this.getBodyScrollTop() + this.getPhotoFrameHeight() < to.top) {
|
if (PageHelper.ScrollY > to.top || PageHelper.ScrollY + this.getPhotoFrameHeight() < to.top) {
|
||||||
this.setBodyScrollTop(to.top);
|
PageHelper.ScrollY = to.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@HostListener('mousemove')
|
@HostListener('mousemove')
|
||||||
onMousemove() {
|
onMouseMove() {
|
||||||
this.showControls();
|
this.showControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,5 +494,9 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
return <Dimension>{top: top, left: left, width: width, height: height};
|
return <Dimension>{top: top, left: left, width: width, height: height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isVisible(): boolean {
|
||||||
|
return this.status !== LightboxStates.Closed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<ol id="directory-path" class="breadcrumb">
|
<ol id="directory-path" class="breadcrumb">
|
||||||
<li *ngFor="let path of routes" class="breadcrumb-item">
|
<li *ngFor="let path of routes" class="breadcrumb-item">
|
||||||
<a *ngIf="path.route" [routerLink]="['/gallery',path.route]"
|
<a *ngIf="path.route" [routerLink]="['/gallery',path.route]"
|
||||||
[queryParams]="_shareService.isSharing() ? { sk: _shareService.getSharingKey() }:{}">{{path.name}}</a>
|
[queryParams]="queryService.getParams()">{{path.name}}</a>
|
||||||
<ng-container *ngIf="!path.route">{{path.name}}</ng-container>
|
<ng-container *ngIf="!path.route">{{path.name}}</ng-container>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -5,6 +5,7 @@ import {UserDTO} from '../../../../common/entities/UserDTO';
|
|||||||
import {AuthenticationService} from '../../model/network/authentication.service';
|
import {AuthenticationService} from '../../model/network/authentication.service';
|
||||||
import {ShareService} from '../share.service';
|
import {ShareService} from '../share.service';
|
||||||
import {I18n} from '@ngx-translate/i18n-polyfill';
|
import {I18n} from '@ngx-translate/i18n-polyfill';
|
||||||
|
import {QueryService} from '../../model/query.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-gallery-navbar',
|
selector: 'app-gallery-navbar',
|
||||||
@ -17,7 +18,7 @@ export class GalleryNavigatorComponent implements OnChanges {
|
|||||||
routes: Array<NavigatorPath> = [];
|
routes: Array<NavigatorPath> = [];
|
||||||
|
|
||||||
constructor(private _authService: AuthenticationService,
|
constructor(private _authService: AuthenticationService,
|
||||||
public _shareService: ShareService,
|
public queryService: QueryService,
|
||||||
private i18n: I18n) {
|
private i18n: I18n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,14 @@ export class PageHelper {
|
|||||||
return this.supportPageOffset ? window.pageYOffset : this.isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
|
return this.supportPageOffset ? window.pageYOffset : this.isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get ScrollX(): number {
|
||||||
|
return this.supportPageOffset ? window.pageXOffset : this.isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static set ScrollY(value: number) {
|
||||||
|
window.scrollTo(this.ScrollX, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static showScrollY() {
|
public static showScrollY() {
|
||||||
PageHelper.body.style.overflowY = 'scroll';
|
PageHelper.body.style.overflowY = 'scroll';
|
||||||
}
|
}
|
||||||
|
24
frontend/app/model/query.service.ts
Normal file
24
frontend/app/model/query.service.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {ShareService} from '../gallery/share.service';
|
||||||
|
import {PhotoDTO} from '../../../common/entities/PhotoDTO';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class QueryService {
|
||||||
|
|
||||||
|
public static readonly PHOTO_PARAM = 'p';
|
||||||
|
|
||||||
|
constructor(private shareService: ShareService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
getParams(photo?: PhotoDTO): { [key: string]: string } {
|
||||||
|
const query = {};
|
||||||
|
if (photo) {
|
||||||
|
query[QueryService.PHOTO_PARAM] = photo.name;
|
||||||
|
}
|
||||||
|
if (this.shareService.isSharing()) {
|
||||||
|
query['sk'] = this.shareService.getSharingKey();
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user