Skip to content

Commit

Permalink
Merge pull request #3193 from AlchemyCMS/backport/7.4-stable/pr-3192
Browse files Browse the repository at this point in the history
[7.4-stable] Fix image cropper
  • Loading branch information
tvdeyen authored Mar 5, 2025
2 parents 9d5fe03 + d67f6b1 commit 3c8e7dd
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 20 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jobs:
runs-on: ubuntu-22.04
name: Build JS packages
needs: check_bun_lock
if: needs.check_bun_lock.outputs.bun_lock_changed == 'true'
steps:
- uses: actions/checkout@v4
- name: Setup Bun
Expand All @@ -49,8 +48,10 @@ jobs:
- name: Install dependencies
run: bun install
- name: bun build
if: needs.check_bun_lock.outputs.bun_lock_changed == 'true'
run: bun run --bun build
- uses: actions/upload-artifact@v4
if: needs.check_bun_lock.outputs.bun_lock_changed == 'true'
with:
name: javascript-bundles
path: vendor/javascript
Expand All @@ -59,7 +60,6 @@ jobs:
permissions:
contents: read
needs: [check_bun_lock, build_javascript]
if: ${{ success('check_bun_lock') && !failure('build_javascript') }}
runs-on: ubuntu-22.04
strategy:
fail-fast: false
Expand Down
25 changes: 8 additions & 17 deletions app/javascript/alchemy_admin/image_cropper.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,29 @@ export default class ImageCropper {
#cropFromField = null
#cropSizeField = null

constructor(
image,
minSize,
defaultBox,
aspectRatio,
formFieldIds,
elementId
) {
constructor(image, defaultBox, aspectRatio, formFieldIds, elementId) {
this.image = image
this.minSize = minSize
this.defaultBox = defaultBox
this.aspectRatio = aspectRatio
this.#cropFromField = document.getElementById(formFieldIds[0])
this.#cropSizeField = document.getElementById(formFieldIds[1])
this.elementId = elementId
this.dialog = Alchemy.currentDialog()
this.dialog.options.closed = () => this.destroy()
if (this.dialog) {
this.dialog.options.closed = () => this.destroy()
this.bind()
}
this.init()
this.bind()
}

get cropperOptions() {
return {
aspectRatio: this.aspectRatio,
viewMode: 1,
zoomable: false,
minCropBoxWidth: this.minSize && this.minSize[0],
minCropBoxHeight: this.minSize && this.minSize[1],
ready: (event) => {
const cropper = event.target.cropper
cropper.setData(this.box)
},
checkCrossOrigin: false, // Prevent CORS issues
checkOrientation: false, // Prevent loading the image via AJAX which can cause CORS issues
data: this.box,
cropend: () => {
const data = this.#cropper.getData(true)
this.update(data)
Expand Down
1 change: 0 additions & 1 deletion app/views/alchemy/admin/crop.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
new ImageLoader(image);
new ImageCropper(
image,
<%= @settings[:min_size].to_json %>,
<%= @settings[:default_box].to_json %>,
<%= @settings[:ratio] %>,
[
Expand Down
58 changes: 58 additions & 0 deletions spec/javascript/alchemy_admin/image_cropper.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import ImageCropper from "alchemy_admin/image_cropper"

describe("ImageCropper", () => {
describe("cropperOptions", () => {
beforeEach(() => {
document.body.innerHTML = `
<div id="element_id">
<input id="crop_from" type="hidden" value="0x423" />
<input id="crop_size" type="hidden" value="1200x480" />
</div>
`
Alchemy.currentDialog = jest.fn()
})

it("is sets initial data", () => {
const image = new Image()
const cropper = new ImageCropper(
image,
{},
1,
["crop_from", "crop_size"],
"element_id"
)
expect(cropper.cropperOptions["data"]).toEqual({
height: 480,
width: 1200,
x: 0,
y: 423
})
})

it("does not set min crop size", () => {
const image = new Image()
const cropper = new ImageCropper(
image,
{},
1,
["crop_from", "crop_size"],
"element_id"
)
expect(cropper.cropperOptions["minCropBoxWidth"]).toBeUndefined()
expect(cropper.cropperOptions["minCropBoxHeight"]).toBeUndefined()
})

it("prevents CORS issues", () => {
const image = new Image()
const cropper = new ImageCropper(
image,
{},
1,
["crop_from", "crop_size"],
"element_id"
)
expect(cropper.cropperOptions["checkCrossOrigin"]).toBe(false)
expect(cropper.cropperOptions["checkOrientation"]).toBe(false)
})
})
})

0 comments on commit 3c8e7dd

Please sign in to comment.