2026-03-25 10:09:57 +00:00
|
|
|
import Handlebars from "handlebars";
|
|
|
|
|
import {Controller} from "@hotwired/stimulus";
|
|
|
|
|
|
|
|
|
|
const processorFrame = Handlebars.compile(`
|
|
|
|
|
<div class="card mb-3">
|
|
|
|
|
<div class="card-header d-flex justify-content-between">
|
|
|
|
|
<span>{{name}}</span>
|
2026-03-26 10:44:20 +00:00
|
|
|
<a href="#" class="btn btn-sm btn-secondary float-end"
|
|
|
|
|
data-action="edit-upload#removeProcessor"
|
|
|
|
|
data-edit-upload-id-param="{{id}}"
|
|
|
|
|
>X</a>
|
2026-03-25 10:09:57 +00:00
|
|
|
</div>
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
{{{props}}}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
`);
|
|
|
|
|
|
2026-03-26 10:44:20 +00:00
|
|
|
const processorUIs = {
|
|
|
|
|
"shadow": {
|
2026-03-25 10:09:57 +00:00
|
|
|
label: "Shadow",
|
|
|
|
|
template: Handlebars.compile(`This processor has no properties.`),
|
|
|
|
|
},
|
2026-03-26 10:44:20 +00:00
|
|
|
"resize": {
|
2026-03-25 10:09:57 +00:00
|
|
|
label: "Resize",
|
|
|
|
|
template: Handlebars.compile(`
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<label for="{{id}}_width" class="form-label">Width</label>
|
|
|
|
|
<input name="width" class="form-control" id="{{id}}_width">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<label for="{{id}}_height" class="form-label">Height</label>
|
|
|
|
|
<input name="width" class="form-control" id="{{id}}_width">
|
|
|
|
|
</div>
|
|
|
|
|
`),
|
2026-03-26 10:44:20 +00:00
|
|
|
},
|
|
|
|
|
};
|
2026-03-25 10:09:57 +00:00
|
|
|
|
|
|
|
|
export default class UploadEditController extends Controller {
|
2026-03-25 11:35:53 +00:00
|
|
|
static targets = ['processList', 'preview'];
|
|
|
|
|
static values = {
|
|
|
|
|
uploadId: Number,
|
|
|
|
|
siteId: Number,
|
|
|
|
|
};
|
2026-03-25 10:09:57 +00:00
|
|
|
|
|
|
|
|
connect() {
|
|
|
|
|
this._rebuildProcessList();
|
2026-03-25 11:35:53 +00:00
|
|
|
this._createSession();
|
2026-03-25 10:09:57 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-26 10:16:50 +00:00
|
|
|
async addProcessor(ev) {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
await this._addProcessor({
|
|
|
|
|
type: "shadow"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-26 10:44:20 +00:00
|
|
|
async removeProcessor(ev) {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
let id = ev.params.id;
|
|
|
|
|
console.log(ev.params);
|
|
|
|
|
await this._removeProcessor(id);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-25 10:09:57 +00:00
|
|
|
_rebuildProcessList() {
|
|
|
|
|
let el = this.processListTarget;
|
|
|
|
|
|
2026-03-26 10:44:20 +00:00
|
|
|
if ((!this._state) || (!this._state.session) || (!this._state.session.processors)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
el.innerHTML = "";
|
|
|
|
|
for (let p of this._state.session.processors) {
|
|
|
|
|
let ui = processorUIs[p.type];
|
|
|
|
|
if (!ui) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
let cardOuter = processorFrame({
|
|
|
|
|
id: p.id,
|
|
|
|
|
name: ui.label,
|
|
|
|
|
props: ui.template(p),
|
|
|
|
|
});
|
|
|
|
|
el.innerHTML += cardOuter;
|
|
|
|
|
}
|
2026-03-25 10:09:57 +00:00
|
|
|
}
|
2026-03-25 11:35:53 +00:00
|
|
|
|
|
|
|
|
async _createSession() {
|
|
|
|
|
try {
|
|
|
|
|
let resp = await fetch(`/sites/${this.siteIdValue}/imageedit/`, {
|
|
|
|
|
method: 'POST',
|
2026-03-26 10:16:50 +00:00
|
|
|
headers: {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
},
|
2026-03-25 11:35:53 +00:00
|
|
|
body: JSON.stringify({
|
|
|
|
|
"base_upload": this.uploadIdValue,
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._state = await resp.json();
|
|
|
|
|
|
2026-03-26 10:44:20 +00:00
|
|
|
this._rebuildProcessList();
|
|
|
|
|
this.previewTarget.src = this._state.preview_url;
|
2026-03-25 11:35:53 +00:00
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-26 10:16:50 +00:00
|
|
|
|
|
|
|
|
async _addProcessor(processor) {
|
|
|
|
|
try {
|
|
|
|
|
let resp = await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/processors`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Accept': 'application/json',
|
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify(processor)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this._state = await resp.json();
|
2026-03-26 10:44:20 +00:00
|
|
|
|
|
|
|
|
this._rebuildProcessList();
|
|
|
|
|
this.previewTarget.src = this._state.preview_url;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _removeProcessor(processorID) {
|
|
|
|
|
await this._doReturningState(async () => {
|
|
|
|
|
return (await fetch(`/sites/${this.siteIdValue}/imageedit/${this._state.session.guid}/processors/${processorID}`, {
|
|
|
|
|
method: 'DELETE',
|
|
|
|
|
})).json();
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _doReturningState(fn) {
|
|
|
|
|
try {
|
|
|
|
|
this._state = await fn();
|
|
|
|
|
|
|
|
|
|
this._rebuildProcessList();
|
2026-03-26 10:16:50 +00:00
|
|
|
this.previewTarget.src = this._state.preview_url;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
}
|
2026-03-26 10:44:20 +00:00
|
|
|
|
2026-03-26 10:16:50 +00:00
|
|
|
}
|
2026-03-25 10:09:57 +00:00
|
|
|
}
|