Send original file, better offers view
This commit is contained in:
parent
d69c4bb6ef
commit
d922326ce3
@ -9,15 +9,26 @@ customElements.define('offer-form', class extends Component {
|
||||
super(`
|
||||
<style>
|
||||
:host { display: block; }
|
||||
section > form {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#imageSection {
|
||||
margin-right: 16px;
|
||||
}
|
||||
#descriptionSection {
|
||||
width: calc(100% - 230px);
|
||||
}
|
||||
${ FORM_STYLE }
|
||||
</style>
|
||||
<section>
|
||||
<form action="/offers/create" method="post">
|
||||
<div>
|
||||
<image-input></image-input>
|
||||
<div id="imageSection">
|
||||
<image-input send-original="true"></image-input>
|
||||
<input name="picture_url" id="picture_url" type="hidden" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="descriptionSection">
|
||||
<label for="description">Opis</label>
|
||||
<input name="description" id="description" type="text" />
|
||||
</div>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { BUTTON_STYLE, Component } from "../shared.js";
|
||||
|
||||
customElements.define('image-input', class extends Component {
|
||||
#file;
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['width', 'height', "account-id", "url"]
|
||||
return ['width', 'height', "account-id", "url", "send-original"];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@ -15,8 +17,7 @@ customElements.define('image-input', class extends Component {
|
||||
}
|
||||
#hidden { overflow: hidden; width: 1px; height: 1px; position: relative; }
|
||||
input[type=file] { position: absolute; top: -10px; left: -10px; display: none; }
|
||||
#view { height: 200px; cursor: pointer; }
|
||||
canvas { width: 200px; height: 200px; }
|
||||
#view { width: 200px; height: 200px; cursor: pointer; }
|
||||
div > input[type=button] {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
@ -26,15 +27,19 @@ customElements.define('image-input', class extends Component {
|
||||
border-color: var(--border-light-gray-color);
|
||||
}
|
||||
img[src=""] { display: none; }
|
||||
img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
${ BUTTON_STYLE }
|
||||
</style>
|
||||
<article>
|
||||
<section id="hidden">
|
||||
<input id="file" type="file" accept="image/*" />
|
||||
<img alt="" src="" />
|
||||
</section>
|
||||
<div id="view">
|
||||
<canvas width="200" height="200"></canvas>
|
||||
</div>
|
||||
<div>
|
||||
<input id="save" type="button" value="Wyślij" />
|
||||
@ -42,45 +47,48 @@ customElements.define('image-input', class extends Component {
|
||||
</article>
|
||||
`);
|
||||
|
||||
this.shadowRoot.querySelector('#save').addEventListener('click', ev => {
|
||||
this.shadowRoot.querySelector('#save').addEventListener('click', async ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.#uploadBase64(this.width, this.height);
|
||||
await this.#sendFile(this.#file);
|
||||
});
|
||||
|
||||
const f = new FileReader();
|
||||
const input = this.shadowRoot.querySelector('#file');
|
||||
const view = this.shadowRoot.querySelector('#view');
|
||||
const img = this.shadowRoot.querySelector('img');
|
||||
const canvas = this.shadowRoot.querySelector('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
img.addEventListener('load', () => {
|
||||
let width, height;
|
||||
if (img.width > img.height) {
|
||||
width = 200;
|
||||
height = (img.height * 200) / img.width;
|
||||
} else {
|
||||
width = (img.width * 200) / img.height;
|
||||
height = 200;
|
||||
}
|
||||
this.setAttribute('width', width);
|
||||
this.setAttribute('height', height);
|
||||
const toFile = (canvas) =>
|
||||
canvas.toBlob((blob) => {
|
||||
this.#file = new File([blob], `${ crypto.randomUUID() }.webp`, { type: blob.type });
|
||||
}, 'image/webp');
|
||||
|
||||
img.width = width;
|
||||
img.height = height;
|
||||
ctx.clearRect(0, 0, 200, 200);
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
});
|
||||
input.addEventListener('change', ev => {
|
||||
ev.stopPropagation();
|
||||
|
||||
f.addEventListener('loadend', (readerEvent) => {
|
||||
if (readerEvent.total !== readerEvent.loaded)
|
||||
return;
|
||||
img.src = readerEvent.target.result || '';
|
||||
});
|
||||
f.readAsDataURL(ev.target.files[0]);
|
||||
const image = new Image();
|
||||
const canvas = document.createElement('canvas');
|
||||
if (this.send_original) {
|
||||
image.onload = () => {
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
canvas.getContext('2d').drawImage(image, 0, 0);
|
||||
toFile(canvas);
|
||||
};
|
||||
|
||||
image.src = URL.createObjectURL(input.files[0]);
|
||||
} else {
|
||||
image.onload = () => {
|
||||
const width = image.width > image.height ? 200 : (image.width * 200) / image.height;
|
||||
const height = image.width > image.height ? (image.width * 200) / image.height : 200;
|
||||
canvas.width = image.width = width;
|
||||
canvas.height = image.height = height;
|
||||
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
|
||||
toFile(canvas);
|
||||
};
|
||||
|
||||
image.src = URL.createObjectURL(input.files[0]);
|
||||
}
|
||||
view.innerHTML = '';
|
||||
view.appendChild(image);
|
||||
});
|
||||
|
||||
view.addEventListener('click', ev => {
|
||||
@ -109,22 +117,20 @@ customElements.define('image-input', class extends Component {
|
||||
|
||||
get width() {
|
||||
const v = parseInt(this.getAttribute('width'));
|
||||
return isNaN(v) ? 0 : v;
|
||||
return isNaN(v) ? 200 : v;
|
||||
}
|
||||
|
||||
set width(v) {
|
||||
this.setAttribute('width', v);
|
||||
this.shadowRoot.querySelector('canvas').width = v;
|
||||
}
|
||||
|
||||
get height() {
|
||||
const v = parseInt(this.getAttribute('height'));
|
||||
return isNaN(v) ? 0 : v;
|
||||
return isNaN(v) ? 200 : v;
|
||||
}
|
||||
|
||||
set height(v) {
|
||||
this.setAttribute('height', v);
|
||||
this.shadowRoot.querySelector('canvas').height = v;
|
||||
}
|
||||
|
||||
get url() {
|
||||
@ -134,26 +140,15 @@ customElements.define('image-input', class extends Component {
|
||||
set url(v) {
|
||||
if (!(v || '').startsWith("/")) v = '';
|
||||
this.setAttribute('url', v);
|
||||
this.shadowRoot.querySelector('img').src = v;
|
||||
const view = this.shadowRoot.querySelector('#view');
|
||||
view.innerHTML = `<img src="${ v }" alt=""/>`;
|
||||
}
|
||||
|
||||
#uploadBase64(width, height) {
|
||||
const canvas = this.shadowRoot.querySelector('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const c = document.createElement('canvas');
|
||||
c.width = width;
|
||||
c.height = height;
|
||||
c.getContext('2d').putImageData(ctx.getImageData(0, 0, width, height), 0, 0);
|
||||
|
||||
const blobBin = atob(c.toDataURL("image/webp", 1.0).split(',')[1]);
|
||||
const array = [];
|
||||
for (let i = 0; i < blobBin.length; i++) {
|
||||
array.push(blobBin.charCodeAt(i));
|
||||
}
|
||||
const file = new Blob([new Uint8Array(array)], { type: 'image/webp' });
|
||||
async #sendFile(file) {
|
||||
if (!file) return;
|
||||
const form = new FormData;
|
||||
form.append(`${ crypto.randomUUID() }.webp`, file);
|
||||
fetch("/upload", {
|
||||
await fetch("/upload", {
|
||||
method: "POST",
|
||||
body: form,
|
||||
}).then(res => res.json()).then(({ path }) => {
|
||||
@ -161,36 +156,16 @@ customElements.define('image-input', class extends Component {
|
||||
this.dispatchEvent(new CustomEvent('image-input:uploaded', { bubbles: true, composed: true }));
|
||||
});
|
||||
}
|
||||
|
||||
get send_original() {
|
||||
return this.getAttribute('send-original') === 'true';
|
||||
}
|
||||
|
||||
set send_original(v) {
|
||||
v = v === true || v === 'true';
|
||||
if (v)
|
||||
this.setAttribute('send-original', 'true')
|
||||
else
|
||||
this.removeAttribute('send-original');
|
||||
}
|
||||
});
|
||||
|
||||
customElements.define('upload-size', class extends Component {
|
||||
static get observedAttributes() {
|
||||
return ['width', 'height'];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super(``);
|
||||
}
|
||||
|
||||
get width() {
|
||||
const v = parseInt(this.getAttribute('width'));
|
||||
return isNaN(v) ? 0 : v;
|
||||
}
|
||||
|
||||
set width(v) {
|
||||
this.setAttribute('width', v);
|
||||
}
|
||||
|
||||
get height() {
|
||||
const v = parseInt(this.getAttribute('height'));
|
||||
return isNaN(v) ? 0 : v;
|
||||
}
|
||||
|
||||
set height(v) {
|
||||
this.setAttribute('height', v);
|
||||
}
|
||||
|
||||
get size() {
|
||||
return { width: this.width, height: this.height }
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user