Skip to content

Commit

Permalink
Merge branch 'file-upload-image-crop' into 6.2-user-coverphoto
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyperghost committed Dec 10, 2024
2 parents 89143be + 1c6b805 commit b1250d9
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 39 deletions.
55 changes: 36 additions & 19 deletions ts/WoltLabSuite/Core/Component/Image/Cropper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ export interface CropperConfiguration {

function inSelection(selection: Selection, maxSelection: Selection): boolean {
return (
Math.ceil(selection.x) >= maxSelection.x &&
Math.ceil(selection.y) >= maxSelection.y &&
Math.ceil(selection.x + selection.width) <= Math.ceil(maxSelection.x + maxSelection.width) &&
Math.ceil(selection.y + selection.height) <= Math.ceil(maxSelection.y + maxSelection.height)
Math.round(selection.x) >= maxSelection.x &&
Math.round(selection.y) >= maxSelection.y &&
Math.round(selection.x + selection.width) <= Math.round(maxSelection.x + maxSelection.width) &&
Math.round(selection.y + selection.height) <= Math.round(maxSelection.y + maxSelection.height)
);
}

Expand Down Expand Up @@ -355,18 +355,22 @@ class MinMaxImageCropper extends ImageCropper {
this.#cropperCanvasRect = this.cropperCanvas!.getBoundingClientRect();

const maxImageWidth = Math.min(this.image!.width, this.maxSize.width);
const widthRatio = this.#cropperCanvasRect.width / maxImageWidth;
const maxImageHeight = Math.min(this.image!.height, this.maxSize.height);
const selectionRatio = Math.min(
this.#cropperCanvasRect.width / maxImageWidth,
this.#cropperCanvasRect.height / maxImageHeight,
);

const minWidth = this.minSize.width * widthRatio;
const maxWidth = this.maxSize.width * widthRatio;
const minWidth = this.minSize.width * selectionRatio;
const maxWidth = this.maxSize.width * selectionRatio;
const minHeight = minWidth / this.configuration.aspectRatio;
const maxHeight = maxWidth / this.configuration.aspectRatio;

if (
selection.width < minWidth ||
selection.height < minHeight ||
selection.width > maxWidth ||
selection.height > maxHeight
Math.round(selection.width) < minWidth ||
Math.round(selection.height) < minHeight ||
Math.round(selection.width) > maxWidth ||
Math.round(selection.height) > maxHeight
) {
event.preventDefault();
}
Expand All @@ -387,20 +391,33 @@ class MinMaxImageCropper extends ImageCropper {
}

protected centerSelection(): void {
// Reset to get the maximum available height
// Reset to get the maximum available height and width
this.cropperCanvas!.style.height = "";
this.cropperCanvas!.style.width = "";

const dimension = DomUtil.innerDimensions(this.cropperCanvas!.parentElement!);
const ratio = Math.min(dimension.width / this.image!.width, dimension.height / this.image!.height);

const dimensions = DomUtil.outerDimensions(this.cropperCanvas!.parentElement!);
this.cropperCanvas!.style.height = `${dimensions.height}px`;
this.cropperCanvas!.style.height = `${this.image!.height * ratio}px`;
this.cropperCanvas!.style.width = `${this.image!.width * ratio}px`;

this.cropperImage!.$center("contain");
this.#cropperCanvasRect = this.cropperImage!.getBoundingClientRect();

if (this.configuration.aspectRatio >= 1.0) {
this.cropperSelection!.$change(0, 0, this.#cropperCanvasRect.width, 0, this.configuration.aspectRatio, true);
} else {
this.cropperSelection!.$change(0, 0, 0, this.#cropperCanvasRect.height, this.configuration.aspectRatio, true);
}
const selectionRatio = Math.min(
this.#cropperCanvasRect.width / this.maxSize.width,
this.#cropperCanvasRect.height / this.maxSize.height,
);

this.cropperSelection!.$change(
0,
0,
this.maxSize.width * selectionRatio,
this.maxSize.height * selectionRatio,
this.configuration.aspectRatio,
true,
);

this.cropperSelection!.$center();
this.cropperSelection!.scrollIntoView({ block: "center", inline: "center" });
}
Expand Down
36 changes: 36 additions & 0 deletions ts/WoltLabSuite/Core/Dom/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,42 @@ const DomUtil = {
return id;
},

/**
* Returns the inner height of an element including paddings.
*/
innerHeight(element: HTMLElement, styles?: CSSStyleDeclaration): number {
styles = styles || window.getComputedStyle(element);

let height = element.clientHeight;
height += ~~styles.paddingTop + ~~styles.paddingBottom;

return height;
},

/**
* Returns the inner width of an element including paddings.
*/
innerWidth(element: HTMLElement, styles?: CSSStyleDeclaration): number {
styles = styles || window.getComputedStyle(element);

let width = element.clientWidth;
width += ~~styles.paddingLeft + ~~styles.paddingRight;

return width;
},

/**
* Returns the inner dimensions of an element including paddings.
*/
innerDimensions(element: HTMLElement): Dimensions {
const styles = window.getComputedStyle(element);

return {
height: DomUtil.innerHeight(element, styles),
width: DomUtil.innerWidth(element, styles),
};
},

/**
* Returns the outer height of an element including margins.
*/
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions wcfsetup/install/files/js/WoltLabSuite/Core/Dom/Util.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions wcfsetup/install/files/style/ui/dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,9 @@ html[data-color-scheme="dark"] .dialog::backdrop {
.dialog cropper-canvas {
margin-left: auto;
margin-right: auto;
/* overwrites the default values of `min-height: 100px` and `min-width: 200px` */
min-height: 1px;
min-width: 1px;
}

/* If the height of the image is many times greater than the width, a white area would be displayed at the bottom and/or top. */
Expand Down

0 comments on commit b1250d9

Please sign in to comment.