Merge pull request #8201 from opf/housekeeping/reuse-resizer-in-wp-resizer

[29220] Reuse resizer component in wp-resizer
pull/8214/head
Henriette Dinger 5 years ago committed by GitHub
commit ba8bc457ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      frontend/src/app/components/resizer/main-menu-resizer.component.ts
  2. 145
      frontend/src/app/components/resizer/wp-resizer.component.ts
  3. 3
      frontend/src/app/modules/common/resizer/resizer.component.html
  4. 74
      frontend/src/app/modules/common/resizer/resizer.component.ts

@ -90,7 +90,7 @@ export class MainMenuResizerComponent extends UntilDestroyedMixin implements OnI
}
public resizeMove(deltas:ResizeDelta) {
this.toggleService.saveWidth(this.elementWidth + deltas.x);
this.toggleService.saveWidth(this.elementWidth + deltas.absolute.x);
}
public resizeEnd() {

@ -26,20 +26,29 @@
// See docs/COPYRIGHT.rdoc for more details.
//++
import {Component, ElementRef, HostListener, Input, OnInit} from '@angular/core';
import {distinctUntilChanged} from 'rxjs/operators';
import {AfterViewInit, Component, ElementRef, Input, OnInit} from '@angular/core';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {TransitionService} from '@uirouter/core';
import {MainMenuToggleService} from "core-components/main-menu/main-menu-toggle.service";
import {BrowserDetector} from "core-app/modules/common/browser/browser-detector.service";
import {UntilDestroyedMixin} from "core-app/helpers/angular/until-destroyed.mixin";
import {ResizeDelta} from "core-app/modules/common/resizer/resizer.component";
import {fromEvent} from "rxjs";
@Component({
selector: 'wp-resizer',
template: `
<div class="work-packages--resizer icon-resizer-vertical-lines"></div>`
<resizer [customHandler]="false"
resizerClass="work-packages--resizer icon-resizer-vertical-lines"
cursorClass="col-resize"
(end)="resizeEnd()"
(start)="resizeStart()"
(move)="resizeMove($event)">
</resizer>
`
})
export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
export class WpResizerDirective extends UntilDestroyedMixin implements OnInit, AfterViewInit {
@Input() elementClass:string;
@Input() resizeEvent:string;
@Input() localStorageKey:string;
@ -47,8 +56,6 @@ export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
private resizingElement:HTMLElement;
private elementWidth:number;
private oldPosition:number;
private mouseMoveHandler:any;
private element:HTMLElement;
public moving:boolean = false;
@ -75,12 +82,6 @@ export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
}
this.resizingElement.style[this.resizeStyle] = this.elementWidth + 'px';
// Wait until dom content is loaded and initialize column layout
// Otherwise function will be executed with empty list
jQuery(document).ready(() => {
this.applyColumnLayout(this.resizingElement, this.elementWidth);
});
// Add event listener
this.element = this.elementRef.nativeElement;
@ -93,10 +94,18 @@ export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
.subscribe(changeData => {
this.toggleFullscreenColumns();
});
let that = this;
jQuery(window).resize(function () {
that.toggleFullscreenColumns();
});
// Listen to event
fromEvent(window, 'resize', { passive: true })
.pipe(
this.untilDestroyed(),
debounceTime(250)
)
.subscribe(() => this.toggleFullscreenColumns());
}
ngAfterViewInit():void {
this.applyColumnLayout(this.resizingElement, this.elementWidth);
}
ngOnDestroy() {
@ -105,79 +114,44 @@ export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
this.resizingElement.style[this.resizeStyle] = '';
}
@HostListener('mousedown', ['$event'])
private handleMouseDown(e:MouseEvent) {
e.preventDefault();
e.stopPropagation();
// Only on left mouse click the resizing is started
if (e.buttons === 1 || e.which === 1) {
// Gettig starting position
this.oldPosition = e.clientX;
this.moving = true;
// In case we dragged the resizer farther than the element can actually grow,
// we reset it to the actual width at the start of the new resizing
let localStorageValue = this.parseLocalStorageValue();
let actualElementWidth = this.resizingElement.offsetWidth;
if (localStorageValue && localStorageValue > actualElementWidth) {
this.elementWidth = actualElementWidth;
}
// Necessary to encapsulate this to be able to remove the eventlistener later
this.mouseMoveHandler = this.resizeElement.bind(this, this.resizingElement);
// Change cursor icon
// This is handled via JS to ensure
// that the cursor stays the same even when the mouse leaves the actual resizer.
document.getElementsByTagName("body")[0].setAttribute('style',
'cursor: col-resize !important');
// Enable mouse move
window.addEventListener('mousemove', this.mouseMoveHandler);
window.addEventListener('touchmove', this.mouseMoveHandler, { passive: false });
}
}
@HostListener('window:touchend', ['$event'])
private handleTouchEnd(e:MouseEvent) {
window.removeEventListener('touchmove', this.mouseMoveHandler);
resizeStart() {
// In case we dragged the resizer farther than the element can actually grow,
// we reset it to the actual width at the start of the new resizing
let localStorageValue = this.parseLocalStorageValue();
if (localStorageValue) {
this.elementWidth = localStorageValue;
let actualElementWidth = this.resizingElement.offsetWidth;
if (localStorageValue && localStorageValue > actualElementWidth) {
this.elementWidth = actualElementWidth;
}
}
@HostListener('window:mouseup', ['$event'])
private handleMouseUp(e:MouseEvent):boolean {
if (!this.moving) {
return true;
}
// Disable mouse move
window.removeEventListener('mousemove', this.mouseMoveHandler);
// Change cursor icon back
document.body.style.cursor = 'auto';
// Take care at the end that the elementWidth-Value is the same as the actual value
// When the mouseup is outside the container these values will differ
// which will cause problems at the next movement start
resizeEnd() {
let localStorageValue = this.parseLocalStorageValue();
if (localStorageValue) {
this.elementWidth = localStorageValue;
}
this.moving = false;
// Send a event that we resized this element
const event = new Event(this.resizeEvent);
window.dispatchEvent(event);
}
resizeMove(deltas:ResizeDelta) {
// Get new value depending on the delta
// The resizingElement is not allowed to be smaller than 530px
this.elementWidth = this.elementWidth - deltas.relative.x;
let newValue = this.elementWidth < 530 ? 530 : this.elementWidth;
// Store item in local storage
window.OpenProject.guardedLocalStorage(this.localStorageKey, `${newValue}`);
// Apply two column layout
this.applyColumnLayout(this.resizingElement, newValue);
return false;
// Set new width
this.resizingElement.style[this.resizeStyle] = newValue + 'px';
}
private parseLocalStorageValue():number|undefined {
let localStorageValue = window.OpenProject.guardedLocalStorage(this.localStorageKey);
let number = parseInt(localStorageValue || '', 10);
@ -189,29 +163,6 @@ export class WpResizerDirective extends UntilDestroyedMixin implements OnInit {
return undefined;
}
private resizeElement(element:HTMLElement, e:MouseEvent) {
e.preventDefault();
e.stopPropagation();
// Get delta to resize
let delta = this.oldPosition - (e.clientX || e.pageX);
this.oldPosition = (e.clientX || e.pageX);
// Get new value depending on the delta
// The resizingElement is not allowed to be smaller than 530px
this.elementWidth = this.elementWidth + delta;
let newValue = this.elementWidth < 530 ? 530 : this.elementWidth;
// Store item in local storage
window.OpenProject.guardedLocalStorage(this.localStorageKey, String(newValue));
// Apply two column layout
this.applyColumnLayout(element, newValue);
// Set new width
element.style[this.resizeStyle] = newValue + 'px';
}
private applyColumnLayout(element:HTMLElement, newWidth:number) {
// Apply two column layout in fullscreen view of a workpackage
if (element === jQuery('.work-packages-full-view--split-right')[0]) {

@ -1,5 +1,4 @@
<div class="resizer"
[ngClass]="resizerClass"
<div [ngClass]="resizerClass"
*ngIf="!customHandler">
</div>
<ng-content></ng-content>

@ -1,15 +1,20 @@
import {
Component,
OnDestroy,
EventEmitter,
Output,
Input,
HostListener} from "@angular/core";
import {Component, EventEmitter, HostListener, Input, OnDestroy, Output} from "@angular/core";
export interface ResizeDelta {
x:number;
y:number;
origin:MouseEvent;
// Absolute difference from start
absolute:{
x:number;
y:number;
};
// Relative difference from last position
relative:{
x:number;
y:number;
};
}
@Component({
@ -17,6 +22,8 @@ export interface ResizeDelta {
templateUrl: './resizer.component.html'
})
export class ResizerComponent implements OnDestroy {
private startX:number;
private startY:number;
private oldX:number;
private oldY:number;
private newX:number;
@ -26,7 +33,7 @@ export class ResizerComponent implements OnDestroy {
private resizing = false;
@Output() end:EventEmitter<ResizeDelta> = new EventEmitter();
@Output() start:EventEmitter<null> = new EventEmitter();
@Output() start:EventEmitter<ResizeDelta> = new EventEmitter();
@Output() move:EventEmitter<ResizeDelta> = new EventEmitter();
@Input() customHandler = false;
@ -45,46 +52,39 @@ export class ResizerComponent implements OnDestroy {
// Only on left mouse click the resizing is started
if (event.buttons === 1 || event.which === 1) {
// Getting starting position
this.oldX = event.clientX;
this.oldY = event.clientY;
this.oldX = this.startX = event.clientX || event.pageX;
this.oldY = this.startY = event.clientY || event.pageY;
this.newX = event.clientX;
this.newY = event.clientY;
this.newX = event.clientX || event.pageX;
this.newY = event.clientY || event.pageY;
this.resizing = true;
this.setResizeCursor();
this.bindEventListener(event);
}
this.start.emit();
this.start.emit(this.buildDelta(event));
}
}
private onMouseUp(element:HTMLElement, event:MouseEvent) {
this.setAutoCursor();
this.removeEventListener();
let deltas = {
x: this.newX - this.oldX,
y: this.newY - this.oldY
};
this.end.emit(deltas);
this.end.emit(this.buildDelta(event));
}
private onMouseMove(element:HTMLElement, event:MouseEvent) {
event.preventDefault();
event.stopPropagation();
this.newX = event.clientX;
this.newY = event.clientY;
this.oldX = this.newX;
this.oldY = this.newY;
let deltas = {
x: this.newX - this.oldX,
y: this.newY - this.oldY
};
this.newX = event.clientX || event.pageX;
this.newY = event.clientY || event.pageY;
this.move.emit(deltas);
this.move.emit(this.buildDelta(event));
}
// Necessary to encapsulate this to be able to remove the event listener later
@ -93,10 +93,12 @@ export class ResizerComponent implements OnDestroy {
this.mouseUpHandler = this.onMouseUp.bind(this, event.currentTarget);
window.addEventListener('mousemove', this.mouseMoveHandler);
window.addEventListener('touchmove', this.mouseMoveHandler);
window.addEventListener('mouseup', this.mouseUpHandler);
}
private removeEventListener() {
window.addEventListener('touchmove', this.mouseMoveHandler);
window.removeEventListener('mousemove', this.mouseMoveHandler);
window.removeEventListener('mouseup', this.mouseUpHandler);
}
@ -109,6 +111,20 @@ export class ResizerComponent implements OnDestroy {
this.setCursor('auto');
}
private buildDelta(event:MouseEvent):ResizeDelta {
return {
origin: event,
absolute: {
x: this.newX - this.startX,
y: this.newY - this.startY,
},
relative: {
x: this.newX - this.oldX,
y: this.newY - this.oldX,
}
};
}
// Change cursor icon
// This is handled via JS to ensure
// that the cursor stays the same even when the mouse leaves the actual resizer.

Loading…
Cancel
Save