1import { Controller } from "@hotwired/stimulus" 2import { mostrar, esconder } from "lib/visibilidade" 3 4// Escolha e recorte da foto do produto. O recorte sai em base64 e vai para o campo 5// escondido do formulario; a previa ao lado mostra o resultado. 6// 7// O campo e a previa ficam fora desta janela, no formulario que a renderiza, por isso vem 8// por id. 9export default class extends Controller { 10 static targets = ["janela", "fundo", "recorte", "arquivo", "aviso", "area"] 11 static values = { campo: String, previa: String } 12 13 connect() { 14 this.cortador = $(this.recorteTarget).croppie({ 15 viewport: { width: 260, height: 260 }, 16 boundary: { width: 260, height: 260 }, 17 enableOrientation: true, 18 }) 19 } 20 21 disconnect() { 22 this.cortador?.croppie("destroy") 23 } 24 25 abrir(evento) { 26 evento.preventDefault() 27 28 mostrar(this.janelaTarget) 29 mostrar(this.fundoTarget) 30 mostrar(this.avisoTarget) 31 esconder(this.areaTarget) 32 } 33 34 fechar(evento) { 35 evento.preventDefault() 36 37 esconder(this.janelaTarget) 38 esconder(this.fundoTarget) 39 } 40 41 escolher() { 42 const arquivo = this.arquivoTarget.files?.[0] 43 if (!arquivo) return 44 45 const leitor = new FileReader() 46 leitor.onload = (evento) => { 47 this.element.querySelector(".upload-photo")?.classList.add("ready") 48 this.cortador.croppie("bind", { url: evento.target.result }) 49 } 50 leitor.readAsDataURL(arquivo) 51 52 esconder(this.avisoTarget) 53 mostrar(this.areaTarget) 54 } 55 56 async salvar() { 57 const recortada = await this.cortador.croppie("result", { type: "base64", size: "viewport" }) 58 59 document.getElementById(this.campoValue).value = recortada 60 document.getElementById(this.previaValue).src = recortada 61 62 esconder(this.janelaTarget) 63 esconder(this.fundoTarget) 64 } 65}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.