admin
3 years ago
action-localize-helper.js
3 years ago
admin-package.js
3 years ago
admin-vuex-package.js
3 years ago
editor.js
3 years ago
file-upload.js
3 years ago
form-block.js
3 years ago
frontend-forms.js
3 years ago
import-form.js
3 years ago
map-field.js
3 years ago
package.js
3 years ago
re-captcha-v3.js
3 years ago
file-upload.js
361 lines
| 1 | ( |
| 2 | function ( $ ) { |
| 3 | |
| 4 | 'use strict'; |
| 5 | |
| 6 | const createFileList = ( inputFileArray ) => { |
| 7 | const transfer = new DataTransfer(); |
| 8 | |
| 9 | for ( const file of inputFileArray ) { |
| 10 | transfer.items.add( file ); |
| 11 | } |
| 12 | |
| 13 | return transfer.files; |
| 14 | }; |
| 15 | |
| 16 | const convertFields = scope => { |
| 17 | scope.find( '.jet-form-builder-file-upload' ).each( function () { |
| 18 | const wrapper = $( this ); |
| 19 | const input = wrapper.find( |
| 20 | '.jet-form-builder-file-upload__input' ); |
| 21 | |
| 22 | const files = wrapper.find( |
| 23 | '.jet-form-builder-file-upload__file' ); |
| 24 | const urls = []; |
| 25 | |
| 26 | for ( const preview of files ) { |
| 27 | const url = $( preview ).data( 'file' ); |
| 28 | const removeNode = $( preview ).find( |
| 29 | '.jet-form-builder-file-upload__file-remove', |
| 30 | ); |
| 31 | |
| 32 | urls.push( [ url, removeNode.data( 'file-name' ) ] ); |
| 33 | } |
| 34 | |
| 35 | if ( !urls.length ) { |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | Promise.allSettled( urls.map( ( [ url, fileName ] ) => ( |
| 40 | new Promise( ( resolve, reject ) => { |
| 41 | fetch( url ).then( |
| 42 | response => response.blob(), |
| 43 | ).then( |
| 44 | blob => resolve( |
| 45 | new File( [ blob ], fileName, blob ), |
| 46 | ), |
| 47 | ).catch( reject ); |
| 48 | } ) |
| 49 | ) ) ).then( values => { |
| 50 | const files = values.map( ( { value } ) => value ); |
| 51 | |
| 52 | addFileToInput( input[ 0 ], files ); |
| 53 | input.trigger( 'change.JetFormBuilderMain' ); |
| 54 | } ); |
| 55 | } ); |
| 56 | }; |
| 57 | |
| 58 | const addFileToInput = ( input, newFiles ) => { |
| 59 | input.files = createFileList( [ ...newFiles ] ); |
| 60 | input.jfbPrevFiles = createFileList( [ ...input.files ] ); |
| 61 | }; |
| 62 | |
| 63 | var JetFormBuilderFileUpload = { |
| 64 | |
| 65 | init: function ( event, scope ) { |
| 66 | $( '.jet-form-builder-file-upload__files', scope ). |
| 67 | sortable( { |
| 68 | items: '.jet-form-builder-file-upload__file', |
| 69 | forcePlaceholderSize: true, |
| 70 | } ). |
| 71 | bind( 'sortupdate', |
| 72 | JetFormBuilderFileUpload.onSortCallback ); |
| 73 | |
| 74 | convertFields( scope ); |
| 75 | }, |
| 76 | |
| 77 | onSortCallback: function ( e, ui ) { |
| 78 | const transfer = new DataTransfer(); |
| 79 | const field = $( e.target ). |
| 80 | closest( '.jet-form-builder-file-upload' ); |
| 81 | const input = field.find( |
| 82 | '.jet-form-builder-file-upload__input' ); |
| 83 | const { files } = input[ 0 ]; |
| 84 | |
| 85 | $( e.target ). |
| 86 | find( '.jet-form-builder-file-upload__file-remove' ). |
| 87 | each( function () { |
| 88 | const name = $( this ).data( 'file-name' ); |
| 89 | |
| 90 | for ( const file of files ) { |
| 91 | if ( file.name !== name ) { |
| 92 | continue; |
| 93 | } |
| 94 | |
| 95 | transfer.items.add( file ); |
| 96 | } |
| 97 | |
| 98 | } ); |
| 99 | |
| 100 | input[ 0 ].files = transfer.files; |
| 101 | }, |
| 102 | |
| 103 | deleteUpload: function () { |
| 104 | const action = new DeleteAction( this ); |
| 105 | |
| 106 | action.remove(); |
| 107 | action.showErrors(); |
| 108 | }, |
| 109 | |
| 110 | issetMessage: function ( formId, status ) { |
| 111 | if ( !window.JetFormBuilderFileUploadConfig.errors[ formId ] ) { |
| 112 | return false; |
| 113 | } |
| 114 | |
| 115 | return window.JetFormBuilderFileUploadConfig.errors[ formId ][ status ]; |
| 116 | }, |
| 117 | |
| 118 | getMessage: function ( formId, status ) { |
| 119 | const { __ } = wp.i18n; |
| 120 | const unknown = __( 'Unknown error.', 'jet-form-builder' ); |
| 121 | const message = JetFormBuilderFileUpload.issetMessage( formId, |
| 122 | status ); |
| 123 | |
| 124 | return message || unknown; |
| 125 | }, |
| 126 | |
| 127 | processUpload: function ( event ) { |
| 128 | const upload = new UploadAction( event ); |
| 129 | |
| 130 | upload.loadFiles(); |
| 131 | upload.removeSingle(); |
| 132 | upload.insertPreviews(); |
| 133 | upload.sortable(); |
| 134 | |
| 135 | upload.showErrors(); |
| 136 | }, |
| 137 | }; |
| 138 | |
| 139 | class ChangeFiles { |
| 140 | constructor( event ) { |
| 141 | this.uploadEl = $( event.target ?? event ). |
| 142 | closest( '.jet-form-builder-file-upload' ); |
| 143 | this.errorsEl = this.uploadEl.find( |
| 144 | '.jet-form-builder-file-upload__errors' ); |
| 145 | this.previewsEl = this.uploadEl.find( |
| 146 | '.jet-form-builder-file-upload__files' ); |
| 147 | this.settings = this.previewsEl.data( 'args' ); |
| 148 | this.fields = this.getFields(); |
| 149 | this.input = this.getFields().find( 'input[type="file"]' ); |
| 150 | this.hasError = false; |
| 151 | } |
| 152 | |
| 153 | removeSingle() { |
| 154 | if ( this.isSingle() ) { |
| 155 | this.getPreview().remove(); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | showErrors() { |
| 160 | this.input.removeClass( 'field-has-error' ); |
| 161 | this.fields.find( '.error-message' ).remove(); |
| 162 | |
| 163 | if ( this.getPreview()?.length > this.settings.max_files ) { |
| 164 | this.input.addClass( 'field-has-error' ); |
| 165 | this.fields.append( |
| 166 | $( `<div class="error-message">${ this.getMessage( |
| 167 | 'upload_max_files' ) }</div>` ), |
| 168 | ); |
| 169 | |
| 170 | return; |
| 171 | } |
| 172 | |
| 173 | if ( this.hasError ) { |
| 174 | this.input.addClass( 'field-has-error' ); |
| 175 | this.fields.append( |
| 176 | $( `<div class="error-message">${ this.getMessage( |
| 177 | this.hasError ) }</div>` ), |
| 178 | ); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | getPreview() { |
| 183 | return this.previewsEl.find( |
| 184 | '.jet-form-builder-file-upload__file' ); |
| 185 | } |
| 186 | |
| 187 | getFields() { |
| 188 | return this.uploadEl.find( |
| 189 | '.jet-form-builder-file-upload__fields' ); |
| 190 | } |
| 191 | |
| 192 | getFormId() { |
| 193 | return this.uploadEl.closest( 'form.jet-form-builder' ). |
| 194 | data( 'form-id' ); |
| 195 | } |
| 196 | |
| 197 | getMessage( status ) { |
| 198 | return JetFormBuilderFileUpload.getMessage( this.getFormId(), |
| 199 | status ); |
| 200 | } |
| 201 | |
| 202 | isSingle() { |
| 203 | return ( |
| 204 | !this.settings?.max_files || this.settings.max_files <= 1 |
| 205 | ); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | class UploadAction extends ChangeFiles { |
| 210 | constructor( event ) { |
| 211 | super( event ); |
| 212 | |
| 213 | this.template = this.getTemplate(); |
| 214 | } |
| 215 | |
| 216 | loadFiles() { |
| 217 | const originalInput = this.input[ 0 ]; |
| 218 | const { files } = originalInput; |
| 219 | |
| 220 | this.files = createFileList( [ ...files ] ); |
| 221 | |
| 222 | if ( this.isSingle() ) { |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | if ( !originalInput.jfbPrevFiles?.length ) { |
| 227 | originalInput.jfbPrevFiles = createFileList( [ ...files ] ); |
| 228 | |
| 229 | return; |
| 230 | } |
| 231 | |
| 232 | originalInput.jfbPrevFiles = createFileList( [ |
| 233 | ...originalInput.jfbPrevFiles, |
| 234 | ...this.files, |
| 235 | ] ); |
| 236 | |
| 237 | originalInput.files = createFileList( [ |
| 238 | ...originalInput.jfbPrevFiles, |
| 239 | ] ); |
| 240 | } |
| 241 | |
| 242 | insertPreviews() { |
| 243 | this.errorsEl.html( '' ).addClass( 'is-hidden' ); |
| 244 | |
| 245 | const previewElements = []; |
| 246 | |
| 247 | for ( const file of this.files ) { |
| 248 | const url = URL.createObjectURL( file ); |
| 249 | const current = this.getFilePreview( url, file ); |
| 250 | |
| 251 | try { |
| 252 | this.validateImage( file, current ); |
| 253 | } |
| 254 | catch ( error ) { |
| 255 | this.hasError = error; |
| 256 | current.find( |
| 257 | '.jet-form-builder-file-upload__file-invalid-marker' ). |
| 258 | show(); |
| 259 | } |
| 260 | |
| 261 | previewElements.push( current ); |
| 262 | } |
| 263 | |
| 264 | this.previewsEl.append( previewElements ); |
| 265 | } |
| 266 | |
| 267 | sortable() { |
| 268 | this.previewsEl.sortable( { |
| 269 | items: '.jet-form-builder-file-upload__file', |
| 270 | forcePlaceholderSize: true, |
| 271 | } ). |
| 272 | bind( 'sortupdate', |
| 273 | JetFormBuilderFileUpload.onSortCallback ); |
| 274 | } |
| 275 | |
| 276 | validateImage( file, current ) { |
| 277 | if ( file.size > this.settings.max_size ) { |
| 278 | throw 'upload_max_size'; |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | getFilePreview( url, file ) { |
| 283 | let template = this.template.replace( '%file_url%', url ); |
| 284 | template = $( |
| 285 | template.replace( '%file_name%', file.name ) ); |
| 286 | |
| 287 | if ( /^image\//.test( file.type ) ) { |
| 288 | template.prepend( |
| 289 | $( `<img src="${ url }" alt="${ file.name }">` ) ); |
| 290 | } |
| 291 | |
| 292 | return template; |
| 293 | } |
| 294 | |
| 295 | getTemplate() { |
| 296 | return this.uploadEl.closest( '.field-type-media-field' ). |
| 297 | find( '.jet-form-builder__preview-template' ). |
| 298 | html(); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | class DeleteAction extends ChangeFiles { |
| 303 | constructor( event ) { |
| 304 | super( event ); |
| 305 | |
| 306 | this.self = $( event ); |
| 307 | this.previewEl = this.self.closest( |
| 308 | '.jet-form-builder-file-upload__file' ); |
| 309 | this.name = this.self.data( 'file-name' ); |
| 310 | } |
| 311 | |
| 312 | remove() { |
| 313 | const fieldValue = this.removeFileFromFileList(); |
| 314 | this.input.trigger( 'change.JetFormBuilderMain' ); |
| 315 | |
| 316 | this.previewEl.trigger( 'jet-form-builder/on-remove-media-item', |
| 317 | [ fieldValue ] ); |
| 318 | this.previewEl.remove(); |
| 319 | } |
| 320 | |
| 321 | removeFileFromFileList() { |
| 322 | const dt = new DataTransfer(); |
| 323 | const originalInput = this.input[ 0 ]; |
| 324 | |
| 325 | const { files } = originalInput; |
| 326 | let removedFile; |
| 327 | |
| 328 | for ( const file of files ) { |
| 329 | if ( this.name !== file.name ) { |
| 330 | dt.items.add( file ); |
| 331 | } |
| 332 | else { |
| 333 | removedFile = file; |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | originalInput.files = dt.files; |
| 338 | |
| 339 | if ( !dt.files.length ) { |
| 340 | delete originalInput.jfbPrevFiles; |
| 341 | |
| 342 | return removedFile; |
| 343 | } |
| 344 | |
| 345 | originalInput.jfbPrevFiles = createFileList( [ |
| 346 | ...originalInput.files, |
| 347 | ] ); |
| 348 | |
| 349 | return removedFile; |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | $( document ). |
| 354 | on( 'jet-form-builder/init', JetFormBuilderFileUpload.init ). |
| 355 | on( 'change', '.jet-form-builder-file-upload__input', |
| 356 | JetFormBuilderFileUpload.processUpload ). |
| 357 | on( 'click', '.jet-form-builder-file-upload__file-remove', |
| 358 | JetFormBuilderFileUpload.deleteUpload ); |
| 359 | |
| 360 | }( jQuery ) |
| 361 | ); |