_acf-blocks.js
1 year ago
_acf-field-flexible-content.js
1 year ago
_acf-field-gallery.js
1 year ago
_acf-field-repeater.js
1 year ago
_acf-jsx-names.js
1 year ago
_acf-setting-clone.js
1 year ago
_acf-setting-flexible-content.js
1 year ago
_acf-setting-repeater.js
1 year ago
_acf-ui-options-page.js
1 year ago
acf-pro-blocks.js
1 year ago
acf-pro-field-group.js
1 year ago
acf-pro-input.js
1 year ago
acf-pro-ui-options-page.js
1 year ago
_acf-field-gallery.js
616 lines
| 1 | ( function ( $ ) { |
| 2 | var Field = acf.Field.extend( { |
| 3 | type: 'gallery', |
| 4 | |
| 5 | events: { |
| 6 | 'click .acf-gallery-add': 'onClickAdd', |
| 7 | 'click .acf-gallery-edit': 'onClickEdit', |
| 8 | 'click .acf-gallery-remove': 'onClickRemove', |
| 9 | 'click .acf-gallery-attachment': 'onClickSelect', |
| 10 | 'click .acf-gallery-close': 'onClickClose', |
| 11 | 'change .acf-gallery-sort': 'onChangeSort', |
| 12 | 'click .acf-gallery-update': 'onUpdate', |
| 13 | mouseover: 'onHover', |
| 14 | showField: 'render', |
| 15 | }, |
| 16 | |
| 17 | actions: { |
| 18 | validation_begin: 'onValidationBegin', |
| 19 | validation_failure: 'onValidationFailure', |
| 20 | resize: 'onResize', |
| 21 | }, |
| 22 | |
| 23 | onValidationBegin: function () { |
| 24 | acf.disable( this.$sideData(), this.cid ); |
| 25 | }, |
| 26 | |
| 27 | onValidationFailure: function () { |
| 28 | acf.enable( this.$sideData(), this.cid ); |
| 29 | }, |
| 30 | |
| 31 | $control: function () { |
| 32 | return this.$( '.acf-gallery' ); |
| 33 | }, |
| 34 | |
| 35 | $collection: function () { |
| 36 | return this.$( '.acf-gallery-attachments' ); |
| 37 | }, |
| 38 | |
| 39 | $attachments: function () { |
| 40 | return this.$( '.acf-gallery-attachment' ); |
| 41 | }, |
| 42 | |
| 43 | $attachment: function ( id ) { |
| 44 | return this.$( '.acf-gallery-attachment[data-id="' + id + '"]' ); |
| 45 | }, |
| 46 | |
| 47 | $active: function () { |
| 48 | return this.$( '.acf-gallery-attachment.active' ); |
| 49 | }, |
| 50 | |
| 51 | $main: function () { |
| 52 | return this.$( '.acf-gallery-main' ); |
| 53 | }, |
| 54 | |
| 55 | $side: function () { |
| 56 | return this.$( '.acf-gallery-side' ); |
| 57 | }, |
| 58 | |
| 59 | $sideData: function () { |
| 60 | return this.$( '.acf-gallery-side-data' ); |
| 61 | }, |
| 62 | |
| 63 | isFull: function () { |
| 64 | var max = parseInt( this.get( 'max' ) ); |
| 65 | var count = this.$attachments().length; |
| 66 | return max && count >= max; |
| 67 | }, |
| 68 | |
| 69 | getValue: function () { |
| 70 | // vars |
| 71 | var val = []; |
| 72 | |
| 73 | // loop |
| 74 | this.$attachments().each( function () { |
| 75 | val.push( $( this ).data( 'id' ) ); |
| 76 | } ); |
| 77 | |
| 78 | // return |
| 79 | return val.length ? val : false; |
| 80 | }, |
| 81 | |
| 82 | addUnscopedEvents: function ( self ) { |
| 83 | // invalidField |
| 84 | this.on( 'change', '.acf-gallery-side', function ( e ) { |
| 85 | self.onUpdate( e, $( this ) ); |
| 86 | } ); |
| 87 | }, |
| 88 | |
| 89 | addSortable: function ( self ) { |
| 90 | // add sortable |
| 91 | this.$collection().sortable( { |
| 92 | items: '.acf-gallery-attachment', |
| 93 | forceHelperSize: true, |
| 94 | forcePlaceholderSize: true, |
| 95 | scroll: true, |
| 96 | start: function ( event, ui ) { |
| 97 | ui.placeholder.html( ui.item.html() ); |
| 98 | ui.placeholder.removeAttr( 'style' ); |
| 99 | }, |
| 100 | update: function ( event, ui ) { |
| 101 | self.$input().trigger( 'change' ); |
| 102 | }, |
| 103 | } ); |
| 104 | |
| 105 | // resizable |
| 106 | this.$control().resizable( { |
| 107 | handles: 's', |
| 108 | minHeight: 200, |
| 109 | stop: function ( event, ui ) { |
| 110 | acf.update_user_setting( 'gallery_height', ui.size.height ); |
| 111 | }, |
| 112 | } ); |
| 113 | }, |
| 114 | |
| 115 | initialize: function () { |
| 116 | // add unscoped events |
| 117 | this.addUnscopedEvents( this ); |
| 118 | |
| 119 | // render |
| 120 | this.render(); |
| 121 | }, |
| 122 | |
| 123 | render: function () { |
| 124 | // vars |
| 125 | var $sort = this.$( '.acf-gallery-sort' ); |
| 126 | var $add = this.$( '.acf-gallery-add' ); |
| 127 | var count = this.$attachments().length; |
| 128 | |
| 129 | // disable add |
| 130 | if ( this.isFull() ) { |
| 131 | $add.addClass( 'disabled' ); |
| 132 | } else { |
| 133 | $add.removeClass( 'disabled' ); |
| 134 | } |
| 135 | |
| 136 | // disable select |
| 137 | if ( ! count ) { |
| 138 | $sort.addClass( 'disabled' ); |
| 139 | } else { |
| 140 | $sort.removeClass( 'disabled' ); |
| 141 | } |
| 142 | |
| 143 | // resize |
| 144 | this.resize(); |
| 145 | }, |
| 146 | |
| 147 | resize: function () { |
| 148 | // vars |
| 149 | var width = this.$control().width(); |
| 150 | var target = 150; |
| 151 | var columns = Math.round( width / target ); |
| 152 | |
| 153 | // max columns = 8 |
| 154 | columns = Math.min( columns, 8 ); |
| 155 | |
| 156 | // update data |
| 157 | this.$control().attr( 'data-columns', columns ); |
| 158 | }, |
| 159 | |
| 160 | onResize: function () { |
| 161 | this.resize(); |
| 162 | }, |
| 163 | |
| 164 | openSidebar: function () { |
| 165 | // add class |
| 166 | this.$control().addClass( '-open' ); |
| 167 | |
| 168 | // hide bulk actions |
| 169 | // should be done with CSS |
| 170 | //this.$main().find('.acf-gallery-sort').hide(); |
| 171 | |
| 172 | // vars |
| 173 | var width = this.$control().width() / 3; |
| 174 | width = parseInt( width ); |
| 175 | width = Math.max( width, 350 ); |
| 176 | |
| 177 | // animate |
| 178 | this.$( '.acf-gallery-side-inner' ).css( { width: width - 1 } ); |
| 179 | this.$side().animate( { width: width - 1 }, 250 ); |
| 180 | this.$main().animate( { right: width }, 250 ); |
| 181 | }, |
| 182 | |
| 183 | closeSidebar: function () { |
| 184 | // remove class |
| 185 | this.$control().removeClass( '-open' ); |
| 186 | |
| 187 | // clear selection |
| 188 | this.$active().removeClass( 'active' ); |
| 189 | |
| 190 | // disable sidebar |
| 191 | acf.disable( this.$side() ); |
| 192 | |
| 193 | // animate |
| 194 | var $sideData = this.$( '.acf-gallery-side-data' ); |
| 195 | this.$main().animate( { right: 0 }, 250 ); |
| 196 | this.$side().animate( { width: 0 }, 250, function () { |
| 197 | $sideData.html( '' ); |
| 198 | } ); |
| 199 | }, |
| 200 | |
| 201 | onClickAdd: function ( e, $el ) { |
| 202 | // validate |
| 203 | if ( this.isFull() ) { |
| 204 | this.showNotice( { |
| 205 | text: acf.__( 'Maximum selection reached' ), |
| 206 | type: 'warning', |
| 207 | } ); |
| 208 | return; |
| 209 | } |
| 210 | |
| 211 | // new frame |
| 212 | var frame = acf.newMediaPopup( { |
| 213 | mode: 'select', |
| 214 | title: acf.__( 'Add Image to Gallery' ), |
| 215 | field: this.get( 'key' ), |
| 216 | multiple: 'add', |
| 217 | library: this.get( 'library' ), |
| 218 | allowedTypes: this.get( 'mime_types' ), |
| 219 | selected: this.val(), |
| 220 | select: $.proxy( function ( attachment, i ) { |
| 221 | this.appendAttachment( attachment, i ); |
| 222 | }, this ), |
| 223 | } ); |
| 224 | }, |
| 225 | |
| 226 | appendAttachment: function ( attachment, i ) { |
| 227 | // vars |
| 228 | attachment = this.validateAttachment( attachment ); |
| 229 | |
| 230 | // bail early if is full |
| 231 | if ( this.isFull() ) { |
| 232 | return; |
| 233 | } |
| 234 | |
| 235 | // bail early if already exists |
| 236 | if ( this.$attachment( attachment.id ).length ) { |
| 237 | return; |
| 238 | } |
| 239 | |
| 240 | // html |
| 241 | var html = [ |
| 242 | '<div class="acf-gallery-attachment" data-id="' + |
| 243 | attachment.id + |
| 244 | '">', |
| 245 | '<input type="hidden" value="' + |
| 246 | attachment.id + |
| 247 | '" name="' + |
| 248 | this.getInputName() + |
| 249 | '[]">', |
| 250 | '<div class="margin" title="">', |
| 251 | '<div class="thumbnail">', |
| 252 | '<img src="" alt="">', |
| 253 | '</div>', |
| 254 | '<div class="filename"></div>', |
| 255 | '</div>', |
| 256 | '<div class="actions">', |
| 257 | '<a href="#" class="acf-icon -cancel dark acf-gallery-remove" data-id="' + |
| 258 | attachment.id + |
| 259 | '"></a>', |
| 260 | '</div>', |
| 261 | '</div>', |
| 262 | ].join( '' ); |
| 263 | var $html = $( html ); |
| 264 | |
| 265 | // append |
| 266 | this.$collection().append( $html ); |
| 267 | |
| 268 | // move to beginning |
| 269 | if ( this.get( 'insert' ) === 'prepend' ) { |
| 270 | var $before = this.$attachments().eq( i ); |
| 271 | if ( $before.length ) { |
| 272 | $before.before( $html ); |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | // render attachment |
| 277 | this.renderAttachment( attachment ); |
| 278 | |
| 279 | // render |
| 280 | this.render(); |
| 281 | |
| 282 | // trigger change |
| 283 | this.$input().trigger( 'change' ); |
| 284 | }, |
| 285 | |
| 286 | validateAttachment: function ( attachment ) { |
| 287 | // defaults |
| 288 | attachment = acf.parseArgs( attachment, { |
| 289 | id: '', |
| 290 | url: '', |
| 291 | alt: '', |
| 292 | title: '', |
| 293 | filename: '', |
| 294 | type: 'image', |
| 295 | } ); |
| 296 | |
| 297 | // WP attachment |
| 298 | if ( attachment.attributes ) { |
| 299 | attachment = attachment.attributes; |
| 300 | |
| 301 | // preview size |
| 302 | var url = acf.isget( |
| 303 | attachment, |
| 304 | 'sizes', |
| 305 | this.get( 'preview_size' ), |
| 306 | 'url' |
| 307 | ); |
| 308 | if ( url !== null ) { |
| 309 | attachment.url = url; |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | // return |
| 314 | return attachment; |
| 315 | }, |
| 316 | |
| 317 | renderAttachment: function ( attachment ) { |
| 318 | // vars |
| 319 | attachment = this.validateAttachment( attachment ); |
| 320 | |
| 321 | // vars |
| 322 | var $el = this.$attachment( attachment.id ); |
| 323 | |
| 324 | // Image type. |
| 325 | if ( attachment.type == 'image' ) { |
| 326 | // Remove filename. |
| 327 | $el.find( '.filename' ).remove(); |
| 328 | |
| 329 | // Other file type. |
| 330 | } else { |
| 331 | // Check for attachment featured image. |
| 332 | var image = acf.isget( attachment, 'image', 'src' ); |
| 333 | if ( image !== null ) { |
| 334 | attachment.url = image; |
| 335 | } |
| 336 | |
| 337 | // Update filename text. |
| 338 | $el.find( '.filename' ).text( attachment.filename ); |
| 339 | } |
| 340 | |
| 341 | // Default to mimetype icon. |
| 342 | if ( ! attachment.url ) { |
| 343 | attachment.url = acf.get( 'mimeTypeIcon' ); |
| 344 | $el.addClass( '-icon' ); |
| 345 | } |
| 346 | |
| 347 | // update els |
| 348 | $el.find( 'img' ).attr( { |
| 349 | src: attachment.url, |
| 350 | alt: attachment.alt, |
| 351 | title: attachment.title, |
| 352 | } ); |
| 353 | |
| 354 | // update val |
| 355 | acf.val( $el.find( 'input' ), attachment.id ); |
| 356 | }, |
| 357 | |
| 358 | editAttachment: function ( id ) { |
| 359 | // new frame |
| 360 | var frame = acf.newMediaPopup( { |
| 361 | mode: 'edit', |
| 362 | title: acf.__( 'Edit Image' ), |
| 363 | button: acf.__( 'Update Image' ), |
| 364 | attachment: id, |
| 365 | field: this.get( 'key' ), |
| 366 | select: $.proxy( function ( attachment, i ) { |
| 367 | this.renderAttachment( attachment ); |
| 368 | // todo - render sidebar |
| 369 | }, this ), |
| 370 | } ); |
| 371 | }, |
| 372 | |
| 373 | onClickEdit: function ( e, $el ) { |
| 374 | var id = $el.data( 'id' ); |
| 375 | if ( id ) { |
| 376 | this.editAttachment( id ); |
| 377 | } |
| 378 | }, |
| 379 | |
| 380 | removeAttachment: function ( id ) { |
| 381 | // close sidebar (if open) |
| 382 | this.closeSidebar(); |
| 383 | |
| 384 | // remove attachment |
| 385 | this.$attachment( id ).remove(); |
| 386 | |
| 387 | // render |
| 388 | this.render(); |
| 389 | |
| 390 | // trigger change |
| 391 | this.$input().trigger( 'change' ); |
| 392 | }, |
| 393 | |
| 394 | onClickRemove: function ( e, $el ) { |
| 395 | // prevent event from triggering click on attachment |
| 396 | e.preventDefault(); |
| 397 | e.stopPropagation(); |
| 398 | |
| 399 | //remove |
| 400 | var id = $el.data( 'id' ); |
| 401 | if ( id ) { |
| 402 | this.removeAttachment( id ); |
| 403 | } |
| 404 | }, |
| 405 | |
| 406 | selectAttachment: function ( id ) { |
| 407 | // vars |
| 408 | var $el = this.$attachment( id ); |
| 409 | |
| 410 | // bail early if already active |
| 411 | if ( $el.hasClass( 'active' ) ) { |
| 412 | return; |
| 413 | } |
| 414 | |
| 415 | // step 1 |
| 416 | var step1 = this.proxy( function () { |
| 417 | // save any changes in sidebar |
| 418 | this.$side().find( ':focus' ).trigger( 'blur' ); |
| 419 | |
| 420 | // clear selection |
| 421 | this.$active().removeClass( 'active' ); |
| 422 | |
| 423 | // add selection |
| 424 | $el.addClass( 'active' ); |
| 425 | |
| 426 | // open sidebar |
| 427 | this.openSidebar(); |
| 428 | |
| 429 | // call step 2 |
| 430 | step2(); |
| 431 | } ); |
| 432 | |
| 433 | // step 2 |
| 434 | var step2 = this.proxy( function () { |
| 435 | const ajaxData = { |
| 436 | action: 'acf/fields/gallery/get_attachment', |
| 437 | nonce: this.get( 'nonce' ), |
| 438 | field_key: this.get( 'key' ), |
| 439 | id: id, |
| 440 | }; |
| 441 | |
| 442 | // abort prev ajax call |
| 443 | if ( this.has( 'xhr' ) ) { |
| 444 | this.get( 'xhr' ).abort(); |
| 445 | } |
| 446 | |
| 447 | // loading |
| 448 | acf.showLoading( this.$sideData() ); |
| 449 | |
| 450 | // get HTML |
| 451 | var xhr = $.ajax( { |
| 452 | url: acf.get( 'ajaxurl' ), |
| 453 | data: acf.prepareForAjax( ajaxData ), |
| 454 | type: 'post', |
| 455 | dataType: 'html', |
| 456 | cache: false, |
| 457 | success: step3, |
| 458 | } ); |
| 459 | |
| 460 | // update |
| 461 | this.set( 'xhr', xhr ); |
| 462 | } ); |
| 463 | |
| 464 | // step 3 |
| 465 | var step3 = this.proxy( function ( html ) { |
| 466 | // bail early if no html |
| 467 | if ( ! html ) { |
| 468 | return; |
| 469 | } |
| 470 | |
| 471 | // vars |
| 472 | var $side = this.$sideData(); |
| 473 | |
| 474 | // render |
| 475 | $side.html( html ); |
| 476 | |
| 477 | // remove acf form data |
| 478 | $side.find( '.compat-field-acf-form-data' ).remove(); |
| 479 | |
| 480 | // merge tables |
| 481 | $side |
| 482 | .find( '> table.form-table > tbody' ) |
| 483 | .append( |
| 484 | $side.find( '> .compat-attachment-fields > tbody > tr' ) |
| 485 | ); |
| 486 | |
| 487 | // setup fields |
| 488 | acf.doAction( 'append', $side ); |
| 489 | } ); |
| 490 | |
| 491 | // run step 1 |
| 492 | step1(); |
| 493 | }, |
| 494 | |
| 495 | onClickSelect: function ( e, $el ) { |
| 496 | var id = $el.data( 'id' ); |
| 497 | if ( id ) { |
| 498 | this.selectAttachment( id ); |
| 499 | } |
| 500 | }, |
| 501 | |
| 502 | onClickClose: function ( e, $el ) { |
| 503 | this.closeSidebar(); |
| 504 | }, |
| 505 | |
| 506 | onChangeSort: function ( e, $el ) { |
| 507 | // Bail early if is disabled. |
| 508 | if ( $el.hasClass( 'disabled' ) ) { |
| 509 | return; |
| 510 | } |
| 511 | |
| 512 | // Get sort val. |
| 513 | var val = $el.val(); |
| 514 | if ( ! val ) { |
| 515 | return; |
| 516 | } |
| 517 | |
| 518 | // find ids |
| 519 | var ids = []; |
| 520 | this.$attachments().each( function () { |
| 521 | ids.push( $( this ).data( 'id' ) ); |
| 522 | } ); |
| 523 | |
| 524 | // step 1 |
| 525 | var step1 = this.proxy( function () { |
| 526 | const ajaxData = { |
| 527 | action: 'acf/fields/gallery/get_sort_order', |
| 528 | nonce: this.get( 'nonce' ), |
| 529 | field_key: this.get( 'key' ), |
| 530 | ids: ids, |
| 531 | sort: val, |
| 532 | }; |
| 533 | |
| 534 | // get results |
| 535 | var xhr = $.ajax( { |
| 536 | url: acf.get( 'ajaxurl' ), |
| 537 | dataType: 'json', |
| 538 | type: 'post', |
| 539 | cache: false, |
| 540 | data: acf.prepareForAjax( ajaxData ), |
| 541 | success: step2, |
| 542 | } ); |
| 543 | } ); |
| 544 | |
| 545 | // step 2 |
| 546 | var step2 = this.proxy( function ( json ) { |
| 547 | // validate |
| 548 | if ( ! acf.isAjaxSuccess( json ) ) { |
| 549 | return; |
| 550 | } |
| 551 | |
| 552 | // reverse order |
| 553 | json.data.reverse(); |
| 554 | |
| 555 | // loop |
| 556 | json.data.map( function ( id ) { |
| 557 | this.$collection().prepend( this.$attachment( id ) ); |
| 558 | }, this ); |
| 559 | } ); |
| 560 | |
| 561 | // call step 1 |
| 562 | step1(); |
| 563 | }, |
| 564 | |
| 565 | onUpdate: function ( e, $el ) { |
| 566 | // vars |
| 567 | var $submit = this.$( '.acf-gallery-update' ); |
| 568 | |
| 569 | // validate |
| 570 | if ( $submit.hasClass( 'disabled' ) ) { |
| 571 | return; |
| 572 | } |
| 573 | |
| 574 | // serialize data |
| 575 | const ajaxData = acf.serialize( this.$sideData() ); |
| 576 | |
| 577 | // loading |
| 578 | $submit.addClass( 'disabled' ); |
| 579 | $submit.before( '<i class="acf-loading"></i> ' ); |
| 580 | |
| 581 | // Append AJAX action and nonce. |
| 582 | ajaxData.action = 'acf/fields/gallery/update_attachment'; |
| 583 | ajaxData.nonce = this.get( 'nonce' ); |
| 584 | ajaxData.field_key = this.get( 'key' ); |
| 585 | |
| 586 | // ajax |
| 587 | $.ajax( { |
| 588 | url: acf.get( 'ajaxurl' ), |
| 589 | data: acf.prepareForAjax( ajaxData ), |
| 590 | type: 'post', |
| 591 | dataType: 'json', |
| 592 | complete: function () { |
| 593 | $submit.removeClass( 'disabled' ); |
| 594 | $submit.prev( '.acf-loading' ).remove(); |
| 595 | }, |
| 596 | } ); |
| 597 | }, |
| 598 | |
| 599 | onHover: function () { |
| 600 | // add sortable |
| 601 | this.addSortable( this ); |
| 602 | |
| 603 | // remove event |
| 604 | this.off( 'mouseover' ); |
| 605 | }, |
| 606 | } ); |
| 607 | |
| 608 | acf.registerFieldType( Field ); |
| 609 | |
| 610 | // register existing conditions |
| 611 | acf.registerConditionForFieldType( 'hasValue', 'gallery' ); |
| 612 | acf.registerConditionForFieldType( 'hasNoValue', 'gallery' ); |
| 613 | acf.registerConditionForFieldType( 'selectionLessThan', 'gallery' ); |
| 614 | acf.registerConditionForFieldType( 'selectionGreaterThan', 'gallery' ); |
| 615 | } )( jQuery ); |
| 616 |