PageSourceSearch

https://casadecultura.org/View/ModulesVue/Web/FormUtils/FormUtils.js?1790282716

js casadecultura.org collected 2026-09-24 20:45:35 UTC 16,705 bytes, 393 lines download raw bytes

1
2Vue.component('form-utils', {
3    props: {        
4        id: String,
5        title: String,
6        fieldtype: String,
7        value: { default: () => "", type: String },         // Quan és un valor únic i no objecte
8        valorinicial: { default: () => [], type: Array },   // Sempre usem aquest si és un valor múltiple
9        valuefile: { default: () => {}, type: Object},      // Sempre usem aquest si és un arxiu que carreguem
10        helptext: { default: '', type: String },
11        placeholder: { default: '', type: String },         
12        disabled: { default: false, type: Boolean } ,
13        options: { default: () => [], type: Array },        
14        groupclass: { default: () => [], type: Array },
15        errors: { default: () => [] , type: Array },        
16        sterrors: { default: () => [] , type: Array },     //Llistat dels errors més comuns
17        rows: { default: () => 10, type: Number }
18    },          
19    data: function() {        
20        return {
21            checklist: this.valorinicial,
22            HiHaError: false,
23            Errors: [],            
24            ImageLoading: false,
25            ImageLoaded: false,
26            ImageShow: false,
27            ImageURL: {'url': '', 'hexfile': '', 'name': ''},
28            ImageName: "",
29
30            /* Variables per al cropping */
31            cropper: null, 
32            objectUrl: null,            
33            MostraModal: false, 
34            ImageData: {},
35            debouncedUpdatePreview: _.debounce(this.UpdatePreview, 257)
36
37        }
38    },        
39    computed: {
40        elementclass: function() {
41            let C = ['form-control'];            
42            
43            this.Errors = [];            
44            for(let VP of this.sterrors)  {               
45                if(VP == 'Telefon' && !ValidaTelefon(this.value)) this.Errors.push("El telèfon no és correcte.");                                 
46                if(VP == 'Email' && !ValidaEmail(this.value)) this.Errors.push("El correu electrònic no és correcte.");                                    
47                if(VP == 'Number' && isNaN(this.value)) this.Errors.push("El valor ha de ser numèric.");                   
48
49                if(VP == 'Required') {
50                    if(this.fieldtype == 'multipleselect') 
51                        if(!this.checklist) this.Errors.push('El camp és obligatori');
52                        else if(this.checklist.length == 0 ) this.Errors.push("El camp és obligatori.");                    
53                    
54                    if(this.fieldtype !== 'multipleselect')
55                        if(!this.value && this.value !== 0) this.Errors.push("El camp és obligatori.");                                                
56                        else if( this.value.length == 0 ) this.Errors.push("El camp és obligatori.");                                                
57                }
58                
59            };
60            
61            for(let EN of this.errors)  {                               
62                if(EN[0]) this.Errors.push(EN[1]);
63            };            
64
65            if(this.Errors.length == 0) C.push('is-valid');
66            else C.push('is-invalid');
67        
68            // Emitim si és o no vàlid            
69            if(this.fieldtype !== 'button') this.$emit('isvalid', (this.Errors.length == 0) );
70
71            return C;
72        }
73    },
74    watch: {},
75
76    methods: {
77        buttonPress: function() {
78            this.$emit('onButtonPress', this.id);
79        },
80        inputChange: function($val) {
81            if(this.fieldtype == 'multipleselect'){                
82                this.$emit('onchange', this.checklist);
83            } else {                                
84                this.$emit('onchange', $val.target.value);
85            }
86            
87        },
88        inputKeyup: function($val) {            
89            this.$emit('onkeyup', $val.target.value);
90        },
91        fileChange: function($val) {            
92
93            const files = $val.target.files            
94            const fileReader = new FileReader();
95            
96            this.ImageName = files[0].name
97
98            fileReader.addEventListener('load', () => {                 
99                this.ImageURL = fileReader.result                
100                this.ImageLoading = false;
101                this.ImageLoaded = true;
102                this.$emit('onchange', {'url': '', 'hexfile':this.ImageURL, 'name': this.ImageName})
103            })
104            this.ImageLoading = true;
105            fileReader.readAsDataURL(files[0])            
106        },
107        ReiniciaImatge: function(val) {
108            this.ImageURL = "";
109            this.ImageLoaded = false;
110        },
111        CarregaImatge: function(selectedFile) {
112            if(this.cropper) this.cropper.destroy();
113            if(this.objectUrl) { window.URL.revokeObjectURL(this.objectUrl); }
114            if(!selectedFile) { this.cropper = null; this.objectUrl = null; this.ImageURL = null; return; }
115            
116            let File = selectedFile.target.files[0];            
117            this.ImageName = File.name;
118            if (File) {
119                var reader = new FileReader();                        
120                reader.onload = (e) => {
121                this.objectUrl = e.target.result;                
122                this.MostraModal = true;
123                this.$nextTick(this.setupCropperInstance);            // Executa després d'un cicle de DOM. Primer carrego la imatge i després hi carrego el canvas
124                }
125
126                reader.readAsDataURL(File);
127            }                                         
128        },
129        setupCropperInstance() {            
130            let AspectRatio = 1;            
131            this.cropper = new Cropper(this.$refs.imatge, 
132                { 
133                    aspectRatio: AspectRatio, 
134                    crop: this.debouncedUpdatePreview 
135                }
136            ); 
137        },
138
139        UpdatePreview(event) {                     
140            this.ImageData = event.detail;
141            const canvas = this.cropper.getCroppedCanvas();            
142            this.ImageURL = canvas.toDataURL('image/png');                                     
143        },          
144
145        TancaModalImatge: function() {
146            this.MostraModal = false;
147        },
148        SaveCropImatge: function() {
149
150            const s = {width: 161, height: 90, minWidth: 200, minHeight: 200, maxWidth: 1096, maxHeight: 1096, fillColor: '#fff', imageSmoothingEnabled: false, imageSmoothingQuality: 'high' };
151            const m = {width: 161, height: 90, minWidth: 400, minHeight: 400, maxWidth: 2096, maxHeight: 2096, fillColor: '#fff', imageSmoothingEnabled: false, imageSmoothingQuality: 'high' };
152            const l = {width: 161, height: 90, minWidth: 400, minHeight: 400, maxWidth: 4096, maxHeight: 4096, fillColor: '#fff', imageSmoothingEnabled: false, imageSmoothingQuality: 'high' };
153            let parametresCropper = {};
154            parametresCropper = 'm';            
155            this.MostraModal = false;
156            this.ImageLoaded = true;
157            this.$emit('onchange', {'url': '', 'hexfile':this.ImageURL, 'name': this.ImageName})            
158        }
159
160    },
161
162
163
164
165
166
167
168
169
170
171
172    template: `            
173
174    <div :class="[groupclass, 'FormUtils']">        
175
176    <!-- ****************** -->
177    <!-- ***** INPUT ****** -->
178    <!-- ****************** -->
179
180        <div v-if="fieldtype == 'input'" >
181            <label :for="id" class="form-label">{{title}}</label>
182            <input  type="text" 
183                    :class="elementclass" 
184                    :placeholder="placeholder" 
185                    :aria-label="title" 
186                    :aria-describedby="title"
187                    :id="id"
188                    :value="value"
189                    @change="inputChange"
190                    @keyup="inputKeyup"
191                    >
192            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
193            <small class="form-text text-muted">{{helptext}}</small>            
194        </div>        
195
196        <!-- ****************** -->
197        <!-- ***** BUTTON ****** -->
198        <!-- ****************** -->
199
200        <div v-if="fieldtype == 'button'">
201            <label :for="id" class="form-label"></label>
202            <button :disabled="disabled" class="form-control btn btn-success" :aria-label="title" :id="id" @click="buttonPress">{{title}}</button>
203        </div>
204
205        <!-- ****************** -->
206        <!-- ***** SELECT ****** -->
207        <!-- ****************** -->
208
209        <div v-if="fieldtype == 'select'">
210            <label :for="id" class="form-label">{{title}}</label>
211            <select  type="select" 
212                    :class="elementclass" 
213                    :placeholder="placeholder" 
214                    :aria-label="title" 
215                    :aria-describedby="title"
216                    :id="id"
217                    :value="value"                    
218                    @change="inputChange"
219                    >
220                    <option value="">-- Escull una opció --</option>
221                    <option v-for="o of options" :value="o.id">{{o.text}}</option>
222            </select>
223            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
224            <small class="form-text text-muted">{{helptext}}</small>                        
225        </div>        
226
227        <!-- *************************** -->
228        <!-- ***** MULTIPLESELECT ****** -->
229        <!-- *************************** -->
230
231        <div v-if="fieldtype == 'multipleselect'">
232            <label :for="id" :class="[elementclass, 'form-label']">{{title}}</label>
233            <div v-for="o of options" class="form-check">
234                <input                     
235                    :class="['form-check-input']"
236                    type="checkbox" 
237                    :value="o.id" 
238                    :id="o.id" 
239                    :placeholder="placeholder" 
240                    :aria-label="o.text" 
241                    :aria-describedby="o.text"
242                    @change="inputChange" 
243                    v-model="checklist" >
244                <label class="form-check-label" for="flexCheckDefault">{{o.text}}</label>
245            </div>
246            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
247            <small class="form-text text-muted">{{helptext}}</small>                                                               
248        </div>        
249
250        <!-- ****************** -->
251        <!-- ***** DATE ****** -->
252        <!-- ****************** -->
253
254        <div v-if="fieldtype == 'date'">
255            <label :for="id" class="form-label">{{title}}</label>
256            <input  type="date" 
257                    :class="elementclass" 
258                    :placeholder="placeholder" 
259                    :aria-label="title" 
260                    :aria-describedby="title"
261                    :id="id"
262                    :value="value"
263                    @change="inputChange"
264                    @keyup="inputKeyup"
265                    @blur="inputKeyup"
266                    >
267            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
268            <small class="form-text text-muted">{{helptext}}</small>            
269        </div>        
270
271        <!-- ****************** -->
272        <!-- ***** TIME ****** -->
273        <!-- ****************** -->
274
275        <div v-if="fieldtype == 'time'">
276            <label :for="id" class="form-label">{{title}}</label>
277            <input  type="time" 
278                    :class="elementclass" 
279                    :placeholder="placeholder" 
280                    :aria-label="title" 
281                    :aria-describedby="title"
282                    :id="id"
283                    :value="value"
284                    @change="inputChange"
285                    @keyup="inputKeyup"
286                    @blur="inputKeyup"
287                    >
288            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
289            <small class="form-text text-muted">{{helptext}}</small>            
290        </div>        
291
292
293        <!-- ********************* -->
294        <!-- ***** TEXTAREA ****** -->
295        <!-- ********************* -->
296
297        <div v-if="fieldtype == 'textarea'">
298            <label :for="id" class="form-label">{{title}}</label>
299            <textarea   
300                    :class="elementclass" 
301                    :placeholder="placeholder" 
302                    :aria-label="title" 
303                    :aria-describedby="title"
304                    :id="id"
305                    :value="value"
306                    :rows="rows"
307                    @change="inputChange"
308                    @keyup="inputKeyup"
309                    >
310            </textarea>
311            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
312            <small class="form-text text-muted">{{helptext}}</small>            
313        </div>       
314
315        <!-- ********************* -->
316        <!-- ******** FILE ******* -->
317        <!-- ********************* -->
318
319        <div v-if="fieldtype == 'file' || fieldtype == 'image'">
320            <label :for="id" v-if="ImageLoaded" class="form-label">{{title}}</label>            
321            <label :for="id" v-if="!ImageLoaded" class="custom-file-label">{{title}}</label>            
322
323            <div v-if="ImageLoaded" style="display: block; margin-top: 0vw;">
324                
325                <div class="alert alert-success" style="margin-top: 1vw;" role="alert" v-if="ImageLoaded">
326                    Arxiu carregat correctament.    
327                </div>    
328                <a  style="display: block; cursor: pointer" @click="ReiniciaImatge" aria-label="Esborra arxiu"> Esborra </a>
329            </div>            
330
331            <div class="form-control" v-if="ImageLoading">Carregant l'arxiu</div>            
332            <input  v-if="!ImageLoading && !ImageLoaded"
333                    type="file" 
334                    accept="document/pdf, document/word"
335                    :class="elementclass" 
336                    :placeholder="placeholder" 
337                    :aria-label="title" 
338                    :aria-describedby="title"
339                    :id="id"                    
340                    @change="fileChange"                                        
341                    >
342            <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
343            <small class="form-text text-muted">{{helptext}}</small>                                    
344        </div>
345
346
347        <!-- ********************* -->
348        <!-- ****** CROPPED ****** -->
349        <!-- ********************* -->
350
351        <div v-if="fieldtype == 'crop'">
352            <div style="height: 50px" v-if="ImageLoaded">
353                <img :src="ImageURL" style="height: 50px">
354                <i @click="ReiniciaImatge()" class="withHand fas fa-tras
354h-alt"></i>                
355            </div>                         
356            <div v-else>
357                <input type="file" accept="image/png, image/jpeg" class="form-control" id="MidaImatge" @change="CarregaImatge($event)" >
358                <label class="custom-file-label" for="MidaImatge" >{{title}}</label>  
359                <small v-for="E of Errors" class="form-text-error">{{E}}<br /></small>
360                <small class="form-text text-muted">{{helptext}}</small>                                    
361            </div>        
362
363            <div class="modalbox" v-if="MostraModal">
364                <table>
365                <tr><td><div style="border:1 px solid blue; background-color: black;">                        
366                            <img style="display: block;" :src="objectUrl" ref="imatge" /> 
367                        </div>                                            
368                    </td><td>
369                        <div style="border:1 px solid blue; background-color: black;">                        
370                            <img style="display: block;" :src="ImageURL" /> 
371                        </div>                                            
372                    </td>
373                </tr><tr>
374                    <td>
375                        <button v-on:click="TancaModalImatge()" class="btn btn-info">Torna</button>
376                        <button v-on:click="SaveCropImatge()" class="btn btn-success">Retalla-la!</button>
377                    </td>
378                    <td> &nbsp;</td>
379                </tr>                            
380                </table>
381            </div>  
382        </div>
383
384
385
386
387
388              
389    </div>
390
391
392`
393});

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.