Ticket #40894: 40894.7.diff
File 40894.7.diff, 527.3 KB (added by , 7 years ago) |
---|
-
.jshintrc
diff --git .jshintrc .jshintrc index 0a082dded5..278eac22c3 100644
21 21 "Backbone": false, 22 22 "jQuery": false, 23 23 "JSON": false, 24 "wp": false 24 "wp": false, 25 "export": false, 26 "module": false, 27 "require": false 25 28 } 26 29 } -
Gruntfile.js
diff --git Gruntfile.js Gruntfile.js index 7cda785b56..011f020531 100644
1 1 /* jshint node:true */ 2 var webpackConfig = require( './webpack.config' ); 3 var webpackDevConfig = require( './webpack-dev.config' ); 4 2 5 module.exports = function(grunt) { 3 6 var path = require('path'), 4 7 fs = require( 'fs' ), 5 8 SOURCE_DIR = 'src/', 6 9 BUILD_DIR = 'build/', 7 10 BANNER_TEXT = '/*! This file is auto-generated */', 8 autoprefixer = require('autoprefixer'), 9 mediaConfig = {}, 10 mediaBuilds = ['audiovideo', 'grid', 'models', 'views']; 11 autoprefixer = require( 'autoprefixer' ); 11 12 12 13 // Load tasks. 13 14 require('matchdep').filterDev(['grunt-*', '!grunt-legacy-util']).forEach( grunt.loadNpmTasks ); 14 15 // Load legacy utils 15 16 grunt.util = require('grunt-legacy-util'); 16 17 17 mediaBuilds.forEach( function ( build ) {18 var path = SOURCE_DIR + 'wp-includes/js/media';19 mediaConfig[ build ] = { files : {} };20 mediaConfig[ build ].files[ path + '-' + build + '.js' ] = [ path + '/' + build + '.manifest.js' ];21 } );22 23 18 // Project configuration. 24 19 grunt.initConfig({ 25 20 postcss: { … … module.exports = function(grunt) { 175 170 } 176 171 } 177 172 }, 178 browserify: mediaConfig,179 173 sass: { 180 174 colors: { 181 175 expand: true, … … module.exports = function(grunt) { 336 330 ] 337 331 }, 338 332 media: { 339 options: {340 browserify: true341 },342 333 src: [ 343 334 SOURCE_DIR + 'wp-includes/js/media/**/*.js' 344 335 ] … … module.exports = function(grunt) { 552 543 dest: SOURCE_DIR + 'wp-includes/js/jquery/jquery.masonry.min.js' 553 544 } 554 545 }, 555 546 webpack: { 547 prod: webpackConfig, 548 dev: webpackDevConfig 549 }, 556 550 concat: { 557 551 tinymce: { 558 552 options: { … … module.exports = function(grunt) { 735 729 } 736 730 }, 737 731 config: { 738 files: 'Gruntfile.js' 732 files: [ 733 'Gruntfile.js', 734 'webpack-dev.config.js', 735 'webpack.config.js' 736 ] 739 737 }, 740 738 colors: { 741 739 files: [SOURCE_DIR + 'wp-admin/css/colors/**'], … … module.exports = function(grunt) { 773 771 774 772 // Register tasks. 775 773 774 // Webpack task. 775 grunt.loadNpmTasks( 'grunt-webpack' ); 776 776 777 // RTL task. 777 778 grunt.registerTask('rtl', ['rtlcss:core', 'rtlcss:colors']); 778 779 … … module.exports = function(grunt) { 796 797 grunt.renameTask( 'watch', '_watch' ); 797 798 798 799 grunt.registerTask( 'watch', function() { 799 if ( ! this.args.length || this.args.indexOf( 'browserify' ) > -1 ) { 800 grunt.config( 'browserify.options', { 801 browserifyOptions: { 802 debug: true 803 }, 804 watch: true 805 } ); 800 if ( ! this.args.length || this.args.indexOf( 'webpack' ) > -1 ) { 806 801 807 grunt.task.run( ' browserify' );802 grunt.task.run( 'webpack:dev' ); 808 803 } 809 804 810 805 grunt.task.run( '_' + this.nameArgs ); … … module.exports = function(grunt) { 815 810 ] ); 816 811 817 812 grunt.registerTask( 'precommit:js', [ 818 ' browserify',813 'webpack:prod', 819 814 'jshint:corejs', 820 815 'uglify:masonry', 821 816 'qunit:compiled' … … module.exports = function(grunt) { 883 878 return regex.test( result.stdout ); 884 879 } 885 880 886 if ( [ 'package.json', 'Gruntfile.js' ].some( testPath ) ) {881 if ( [ 'package.json', 'Gruntfile.js', 'webpack.config.js' ].some( testPath ) ) { 887 882 grunt.log.writeln( 'Configuration files modified. Running `prerelease`.' ); 888 883 taskList.push( 'prerelease' ); 889 884 } else { … … module.exports = function(grunt) { 981 976 grunt.event.on('watch', function( action, filepath, target ) { 982 977 var src; 983 978 984 if ( [ 'all', 'rtl', ' browserify' ].indexOf( target ) === -1 ) {979 if ( [ 'all', 'rtl', 'webpack' ].indexOf( target ) === -1 ) { 985 980 return; 986 981 } 987 982 -
package.json
diff --git package.json package.json index 71695dfb77..4e1655c099 100644
15 15 "autoprefixer": "^6.5.1", 16 16 "grunt": "~0.4.5", 17 17 "grunt-banner": "^0.6.0", 18 "grunt-browserify": "~5.0.0",19 18 "grunt-contrib-clean": "~1.0.0", 20 19 "grunt-contrib-compress": "~1.3.0", 21 20 "grunt-contrib-concat": "~1.0.0", … … 36 35 "grunt-rtlcss": "~2.0.1", 37 36 "grunt-sass": "~1.2.1", 38 37 "ink-docstrap": "^1.3.0", 39 "matchdep": "~1.0.0" 38 "grunt-webpack": "^3.0.2", 39 "matchdep": "~1.0.0", 40 "webpack": "^3.5.4", 41 "webpack-dev-server": "^2.7.1" 40 42 } 41 43 } -
src/wp-includes/js/media-audiovideo.js
diff --git src/wp-includes/js/media-audiovideo.js src/wp-includes/js/media-audiovideo.js index 0a819747d2..cb2abd57ae 100644
1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 1 /******/ (function(modules) { // webpackBootstrap 2 /******/ // The module cache 3 /******/ var installedModules = {}; 4 /******/ 5 /******/ // The require function 6 /******/ function __webpack_require__(moduleId) { 7 /******/ 8 /******/ // Check if module is in cache 9 /******/ if(installedModules[moduleId]) { 10 /******/ return installedModules[moduleId].exports; 11 /******/ } 12 /******/ // Create a new module (and put it into the cache) 13 /******/ var module = installedModules[moduleId] = { 14 /******/ i: moduleId, 15 /******/ l: false, 16 /******/ exports: {} 17 /******/ }; 18 /******/ 19 /******/ // Execute the module function 20 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 /******/ 22 /******/ // Flag the module as loaded 23 /******/ module.l = true; 24 /******/ 25 /******/ // Return the exports of the module 26 /******/ return module.exports; 27 /******/ } 28 /******/ 29 /******/ 30 /******/ // expose the modules object (__webpack_modules__) 31 /******/ __webpack_require__.m = modules; 32 /******/ 33 /******/ // expose the module cache 34 /******/ __webpack_require__.c = installedModules; 35 /******/ 36 /******/ // define getter function for harmony exports 37 /******/ __webpack_require__.d = function(exports, name, getter) { 38 /******/ if(!__webpack_require__.o(exports, name)) { 39 /******/ Object.defineProperty(exports, name, { 40 /******/ configurable: false, 41 /******/ enumerable: true, 42 /******/ get: getter 43 /******/ }); 44 /******/ } 45 /******/ }; 46 /******/ 47 /******/ // getDefaultExport function for compatibility with non-harmony modules 48 /******/ __webpack_require__.n = function(module) { 49 /******/ var getter = module && module.__esModule ? 50 /******/ function getDefault() { return module['default']; } : 51 /******/ function getModuleExports() { return module; }; 52 /******/ __webpack_require__.d(getter, 'a', getter); 53 /******/ return getter; 54 /******/ }; 55 /******/ 56 /******/ // Object.prototype.hasOwnProperty.call 57 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 /******/ 59 /******/ // __webpack_public_path__ 60 /******/ __webpack_require__.p = ""; 61 /******/ 62 /******/ // Load entry module and return exports 63 /******/ return __webpack_require__(__webpack_require__.s = 0); 64 /******/ }) 65 /************************************************************************/ 66 /******/ ([ 67 /* 0 */ 68 /***/ (function(module, exports, __webpack_require__) { 69 2 70 var media = wp.media, 3 71 baseSettings = window._wpmejsSettings || {}, 4 72 l10n = window._wpMediaViewsL10n || {}; … … wp.media.video = { 268 336 } 269 337 }; 270 338 271 media.model.PostMedia = require( './models/post-media.js' ); 272 media.controller.AudioDetails = require( './controllers/audio-details.js' ); 273 media.controller.VideoDetails = require( './controllers/video-details.js' ); 274 media.view.MediaFrame.MediaDetails = require( './views/frame/media-details.js' ); 275 media.view.MediaFrame.AudioDetails = require( './views/frame/audio-details.js' ); 276 media.view.MediaFrame.VideoDetails = require( './views/frame/video-details.js' ); 277 media.view.MediaDetails = require( './views/media-details.js' ); 278 media.view.AudioDetails = require( './views/audio-details.js' ); 279 media.view.VideoDetails = require( './views/video-details.js' ); 280 281 },{"./controllers/audio-details.js":2,"./controllers/video-details.js":3,"./models/post-media.js":4,"./views/audio-details.js":5,"./views/frame/audio-details.js":6,"./views/frame/media-details.js":7,"./views/frame/video-details.js":8,"./views/media-details.js":9,"./views/video-details.js":10}],2:[function(require,module,exports){ 282 var State = wp.media.controller.State, 283 l10n = wp.media.view.l10n, 284 AudioDetails; 285 286 /** 287 * wp.media.controller.AudioDetails 288 * 289 * The controller for the Audio Details state 290 * 291 * @memberOf wp.media.controller 292 * 293 * @class 294 * @augments wp.media.controller.State 295 * @augments Backbone.Model 296 */ 297 AudioDetails = State.extend(/** @lends wp.media.controller.AudioDetails.prototype */{ 298 defaults: { 299 id: 'audio-details', 300 toolbar: 'audio-details', 301 title: l10n.audioDetailsTitle, 302 content: 'audio-details', 303 menu: 'audio-details', 304 router: false, 305 priority: 60 306 }, 307 308 initialize: function( options ) { 309 this.media = options.media; 310 State.prototype.initialize.apply( this, arguments ); 311 } 312 }); 313 314 module.exports = AudioDetails; 315 316 },{}],3:[function(require,module,exports){ 317 /** 318 * wp.media.controller.VideoDetails 319 * 320 * The controller for the Video Details state 321 * 322 * @memberOf wp.media.controller 323 * 324 * @class 325 * @augments wp.media.controller.State 326 * @augments Backbone.Model 327 */ 328 var State = wp.media.controller.State, 329 l10n = wp.media.view.l10n, 330 VideoDetails; 331 332 VideoDetails = State.extend(/** @lends wp.media.controller.VideoDetails.prototype */{ 333 defaults: { 334 id: 'video-details', 335 toolbar: 'video-details', 336 title: l10n.videoDetailsTitle, 337 content: 'video-details', 338 menu: 'video-details', 339 router: false, 340 priority: 60 341 }, 339 media.model.PostMedia = __webpack_require__( 1 ); 340 media.controller.AudioDetails = __webpack_require__( 2 ); 341 media.controller.VideoDetails = __webpack_require__( 3 ); 342 media.view.MediaFrame.MediaDetails = __webpack_require__( 4 ); 343 media.view.MediaFrame.AudioDetails = __webpack_require__( 5 ); 344 media.view.MediaFrame.VideoDetails = __webpack_require__( 6 ); 345 media.view.MediaDetails = __webpack_require__( 7 ); 346 media.view.AudioDetails = __webpack_require__( 8 ); 347 media.view.VideoDetails = __webpack_require__( 9 ); 342 348 343 initialize: function( options ) {344 this.media = options.media;345 State.prototype.initialize.apply( this, arguments );346 }347 });348 349 349 module.exports = VideoDetails; 350 /***/ }), 351 /* 1 */ 352 /***/ (function(module, exports) { 350 353 351 },{}],4:[function(require,module,exports){352 354 /** 353 355 * wp.media.model.PostMedia 354 356 * … … var PostMedia = Backbone.Model.extend(/** @lends wp.media.model.PostMedia.protot 392 394 393 395 module.exports = PostMedia; 394 396 395 },{}],5:[function(require,module,exports){ 396 var MediaDetails = wp.media.view.MediaDetails, 397 398 /***/ }), 399 /* 2 */ 400 /***/ (function(module, exports) { 401 402 var State = wp.media.controller.State, 403 l10n = wp.media.view.l10n, 397 404 AudioDetails; 398 405 399 406 /** 400 * wp.media. view.AudioDetails407 * wp.media.controller.AudioDetails 401 408 * 402 * @memberOf wp.media.view 409 * The controller for the Audio Details state 410 * 411 * @memberOf wp.media.controller 403 412 * 404 413 * @class 405 * @augments wp.media.view.MediaDetails 406 * @augments wp.media.view.Settings.AttachmentDisplay 407 * @augments wp.media.view.Settings 408 * @augments wp.media.View 409 * @augments wp.Backbone.View 410 * @augments Backbone.View 414 * @augments wp.media.controller.State 415 * @augments Backbone.Model 411 416 */ 412 AudioDetails = MediaDetails.extend(/** @lends wp.media.view.AudioDetails.prototype */{ 413 className: 'audio-details', 414 template: wp.template('audio-details'), 415 416 setMedia: function() { 417 var audio = this.$('.wp-audio-shortcode'); 418 419 if ( audio.find( 'source' ).length ) { 420 if ( audio.is(':hidden') ) { 421 audio.show(); 422 } 423 this.media = MediaDetails.prepareSrc( audio.get(0) ); 424 } else { 425 audio.hide(); 426 this.media = false; 427 } 417 AudioDetails = State.extend(/** @lends wp.media.controller.AudioDetails.prototype */{ 418 defaults: { 419 id: 'audio-details', 420 toolbar: 'audio-details', 421 title: l10n.audioDetailsTitle, 422 content: 'audio-details', 423 menu: 'audio-details', 424 router: false, 425 priority: 60 426 }, 428 427 429 return this; 428 initialize: function( options ) { 429 this.media = options.media; 430 State.prototype.initialize.apply( this, arguments ); 430 431 } 431 432 }); 432 433 433 434 module.exports = AudioDetails; 434 435 435 },{}],6:[function(require,module,exports){436 var MediaDetails = wp.media.view.MediaFrame.MediaDetails,437 MediaLibrary = wp.media.controller.MediaLibrary,438 436 439 l10n = wp.media.view.l10n, 440 AudioDetails; 437 /***/ }), 438 /* 3 */ 439 /***/ (function(module, exports) { 441 440 442 441 /** 443 * wp.media. view.MediaFrame.AudioDetails442 * wp.media.controller.VideoDetails 444 443 * 445 * @memberOf wp.media.view.MediaFrame 444 * The controller for the Video Details state 445 * 446 * @memberOf wp.media.controller 446 447 * 447 448 * @class 448 * @augments wp.media.view.MediaFrame.MediaDetails 449 * @augments wp.media.view.MediaFrame.Select 450 * @augments wp.media.view.MediaFrame 451 * @augments wp.media.view.Frame 452 * @augments wp.media.View 453 * @augments wp.Backbone.View 454 * @augments Backbone.View 455 * @mixes wp.media.controller.StateMachine 449 * @augments wp.media.controller.State 450 * @augments Backbone.Model 456 451 */ 457 AudioDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.AudioDetails.prototype */{ 452 var State = wp.media.controller.State, 453 l10n = wp.media.view.l10n, 454 VideoDetails; 455 456 VideoDetails = State.extend(/** @lends wp.media.controller.VideoDetails.prototype */{ 458 457 defaults: { 459 id: 'audio', 460 url: '', 461 menu: 'audio-details', 462 content: 'audio-details', 463 toolbar: 'audio-details', 464 type: 'link', 465 title: l10n.audioDetailsTitle, 466 priority: 120 458 id: 'video-details', 459 toolbar: 'video-details', 460 title: l10n.videoDetailsTitle, 461 content: 'video-details', 462 menu: 'video-details', 463 router: false, 464 priority: 60 467 465 }, 468 466 469 467 initialize: function( options ) { 470 options.DetailsView = wp.media.view.AudioDetails; 471 options.cancelText = l10n.audioDetailsCancel; 472 options.addText = l10n.audioAddSourceTitle; 473 474 MediaDetails.prototype.initialize.call( this, options ); 475 }, 476 477 bindHandlers: function() { 478 MediaDetails.prototype.bindHandlers.apply( this, arguments ); 479 480 this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this ); 481 this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this ); 482 }, 483 484 createStates: function() { 485 this.states.add([ 486 new wp.media.controller.AudioDetails( { 487 media: this.media 488 } ), 489 490 new MediaLibrary( { 491 type: 'audio', 492 id: 'replace-audio', 493 title: l10n.audioReplaceTitle, 494 toolbar: 'replace-audio', 495 media: this.media, 496 menu: 'audio-details' 497 } ), 498 499 new MediaLibrary( { 500 type: 'audio', 501 id: 'add-audio-source', 502 title: l10n.audioAddSourceTitle, 503 toolbar: 'add-audio-source', 504 media: this.media, 505 menu: false 506 } ) 507 ]); 468 this.media = options.media; 469 State.prototype.initialize.apply( this, arguments ); 508 470 } 509 471 }); 510 472 511 module.exports = AudioDetails; 473 module.exports = VideoDetails; 474 475 476 /***/ }), 477 /* 4 */ 478 /***/ (function(module, exports) { 512 479 513 },{}],7:[function(require,module,exports){514 480 var Select = wp.media.view.MediaFrame.Select, 515 481 l10n = wp.media.view.l10n, 516 482 MediaDetails; … … MediaDetails = Select.extend(/** @lends wp.media.view.MediaFrame.MediaDetails.pr 642 608 643 609 module.exports = MediaDetails; 644 610 645 },{}],8:[function(require,module,exports){ 611 612 /***/ }), 613 /* 5 */ 614 /***/ (function(module, exports) { 615 616 var MediaDetails = wp.media.view.MediaFrame.MediaDetails, 617 MediaLibrary = wp.media.controller.MediaLibrary, 618 619 l10n = wp.media.view.l10n, 620 AudioDetails; 621 622 /** 623 * wp.media.view.MediaFrame.AudioDetails 624 * 625 * @memberOf wp.media.view.MediaFrame 626 * 627 * @class 628 * @augments wp.media.view.MediaFrame.MediaDetails 629 * @augments wp.media.view.MediaFrame.Select 630 * @augments wp.media.view.MediaFrame 631 * @augments wp.media.view.Frame 632 * @augments wp.media.View 633 * @augments wp.Backbone.View 634 * @augments Backbone.View 635 * @mixes wp.media.controller.StateMachine 636 */ 637 AudioDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.AudioDetails.prototype */{ 638 defaults: { 639 id: 'audio', 640 url: '', 641 menu: 'audio-details', 642 content: 'audio-details', 643 toolbar: 'audio-details', 644 type: 'link', 645 title: l10n.audioDetailsTitle, 646 priority: 120 647 }, 648 649 initialize: function( options ) { 650 options.DetailsView = wp.media.view.AudioDetails; 651 options.cancelText = l10n.audioDetailsCancel; 652 options.addText = l10n.audioAddSourceTitle; 653 654 MediaDetails.prototype.initialize.call( this, options ); 655 }, 656 657 bindHandlers: function() { 658 MediaDetails.prototype.bindHandlers.apply( this, arguments ); 659 660 this.on( 'toolbar:render:replace-audio', this.renderReplaceToolbar, this ); 661 this.on( 'toolbar:render:add-audio-source', this.renderAddSourceToolbar, this ); 662 }, 663 664 createStates: function() { 665 this.states.add([ 666 new wp.media.controller.AudioDetails( { 667 media: this.media 668 } ), 669 670 new MediaLibrary( { 671 type: 'audio', 672 id: 'replace-audio', 673 title: l10n.audioReplaceTitle, 674 toolbar: 'replace-audio', 675 media: this.media, 676 menu: 'audio-details' 677 } ), 678 679 new MediaLibrary( { 680 type: 'audio', 681 id: 'add-audio-source', 682 title: l10n.audioAddSourceTitle, 683 toolbar: 'add-audio-source', 684 media: this.media, 685 menu: false 686 } ) 687 ]); 688 } 689 }); 690 691 module.exports = AudioDetails; 692 693 694 /***/ }), 695 /* 6 */ 696 /***/ (function(module, exports) { 697 646 698 var MediaDetails = wp.media.view.MediaFrame.MediaDetails, 647 699 MediaLibrary = wp.media.controller.MediaLibrary, 648 700 l10n = wp.media.view.l10n, … … VideoDetails = MediaDetails.extend(/** @lends wp.media.view.MediaFrame.VideoDeta 779 831 780 832 module.exports = VideoDetails; 781 833 782 },{}],9:[function(require,module,exports){ 834 835 /***/ }), 836 /* 7 */ 837 /***/ (function(module, exports) { 838 783 839 /* global MediaElementPlayer */ 784 840 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay, 785 841 $ = jQuery, … … MediaDetails = AttachmentDisplay.extend(/** @lends wp.media.view.MediaDetails.pr 949 1005 950 1006 module.exports = MediaDetails; 951 1007 952 },{}],10:[function(require,module,exports){ 1008 1009 /***/ }), 1010 /* 8 */ 1011 /***/ (function(module, exports) { 1012 1013 var MediaDetails = wp.media.view.MediaDetails, 1014 AudioDetails; 1015 1016 /** 1017 * wp.media.view.AudioDetails 1018 * 1019 * @memberOf wp.media.view 1020 * 1021 * @class 1022 * @augments wp.media.view.MediaDetails 1023 * @augments wp.media.view.Settings.AttachmentDisplay 1024 * @augments wp.media.view.Settings 1025 * @augments wp.media.View 1026 * @augments wp.Backbone.View 1027 * @augments Backbone.View 1028 */ 1029 AudioDetails = MediaDetails.extend(/** @lends wp.media.view.AudioDetails.prototype */{ 1030 className: 'audio-details', 1031 template: wp.template('audio-details'), 1032 1033 setMedia: function() { 1034 var audio = this.$('.wp-audio-shortcode'); 1035 1036 if ( audio.find( 'source' ).length ) { 1037 if ( audio.is(':hidden') ) { 1038 audio.show(); 1039 } 1040 this.media = MediaDetails.prepareSrc( audio.get(0) ); 1041 } else { 1042 audio.hide(); 1043 this.media = false; 1044 } 1045 1046 return this; 1047 } 1048 }); 1049 1050 module.exports = AudioDetails; 1051 1052 1053 /***/ }), 1054 /* 9 */ 1055 /***/ (function(module, exports) { 1056 953 1057 var MediaDetails = wp.media.view.MediaDetails, 954 1058 VideoDetails; 955 1059 … … VideoDetails = MediaDetails.extend(/** @lends wp.media.view.VideoDetails.prototy 994 1098 995 1099 module.exports = VideoDetails; 996 1100 997 },{}]},{},[1]); 1101 1102 /***/ }) 1103 /******/ ]); 1104 No newline at end of file -
src/wp-includes/js/media-grid.js
diff --git src/wp-includes/js/media-grid.js src/wp-includes/js/media-grid.js index 6e35fb52a6..c9babd6d50 100644
1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 1 /******/ (function(modules) { // webpackBootstrap 2 /******/ // The module cache 3 /******/ var installedModules = {}; 4 /******/ 5 /******/ // The require function 6 /******/ function __webpack_require__(moduleId) { 7 /******/ 8 /******/ // Check if module is in cache 9 /******/ if(installedModules[moduleId]) { 10 /******/ return installedModules[moduleId].exports; 11 /******/ } 12 /******/ // Create a new module (and put it into the cache) 13 /******/ var module = installedModules[moduleId] = { 14 /******/ i: moduleId, 15 /******/ l: false, 16 /******/ exports: {} 17 /******/ }; 18 /******/ 19 /******/ // Execute the module function 20 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 /******/ 22 /******/ // Flag the module as loaded 23 /******/ module.l = true; 24 /******/ 25 /******/ // Return the exports of the module 26 /******/ return module.exports; 27 /******/ } 28 /******/ 29 /******/ 30 /******/ // expose the modules object (__webpack_modules__) 31 /******/ __webpack_require__.m = modules; 32 /******/ 33 /******/ // expose the module cache 34 /******/ __webpack_require__.c = installedModules; 35 /******/ 36 /******/ // define getter function for harmony exports 37 /******/ __webpack_require__.d = function(exports, name, getter) { 38 /******/ if(!__webpack_require__.o(exports, name)) { 39 /******/ Object.defineProperty(exports, name, { 40 /******/ configurable: false, 41 /******/ enumerable: true, 42 /******/ get: getter 43 /******/ }); 44 /******/ } 45 /******/ }; 46 /******/ 47 /******/ // getDefaultExport function for compatibility with non-harmony modules 48 /******/ __webpack_require__.n = function(module) { 49 /******/ var getter = module && module.__esModule ? 50 /******/ function getDefault() { return module['default']; } : 51 /******/ function getModuleExports() { return module; }; 52 /******/ __webpack_require__.d(getter, 'a', getter); 53 /******/ return getter; 54 /******/ }; 55 /******/ 56 /******/ // Object.prototype.hasOwnProperty.call 57 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 /******/ 59 /******/ // __webpack_public_path__ 60 /******/ __webpack_require__.p = ""; 61 /******/ 62 /******/ // Load entry module and return exports 63 /******/ return __webpack_require__(__webpack_require__.s = 10); 64 /******/ }) 65 /************************************************************************/ 66 /******/ ([ 67 /* 0 */, 68 /* 1 */, 69 /* 2 */, 70 /* 3 */, 71 /* 4 */, 72 /* 5 */, 73 /* 6 */, 74 /* 7 */, 75 /* 8 */, 76 /* 9 */, 77 /* 10 */ 78 /***/ (function(module, exports, __webpack_require__) { 79 80 var media = wp.media; 81 82 media.controller.EditAttachmentMetadata = __webpack_require__( 11 ); 83 media.view.MediaFrame.Manage = __webpack_require__( 12 ); 84 media.view.Attachment.Details.TwoColumn = __webpack_require__( 13 ); 85 media.view.MediaFrame.Manage.Router = __webpack_require__( 14 ); 86 media.view.EditImage.Details = __webpack_require__( 15 ); 87 media.view.MediaFrame.EditAttachments = __webpack_require__( 16 ); 88 media.view.SelectModeToggleButton = __webpack_require__( 17 ); 89 media.view.DeleteSelectedButton = __webpack_require__( 18 ); 90 media.view.DeleteSelectedPermanentlyButton = __webpack_require__( 19 ); 91 92 93 /***/ }), 94 /* 11 */ 95 /***/ (function(module, exports) { 96 2 97 var l10n = wp.media.view.l10n, 3 98 EditAttachmentMetadata; 4 99 … … EditAttachmentMetadata = wp.media.controller.State.extend(/** @lends wp.media.co 28 123 29 124 module.exports = EditAttachmentMetadata; 30 125 31 },{}],2:[function(require,module,exports){32 var media = wp.media;33 126 34 media.controller.EditAttachmentMetadata = require( './controllers/edit-attachment-metadata.js' ); 35 media.view.MediaFrame.Manage = require( './views/frame/manage.js' ); 36 media.view.Attachment.Details.TwoColumn = require( './views/attachment/details-two-column.js' ); 37 media.view.MediaFrame.Manage.Router = require( './routers/manage.js' ); 38 media.view.EditImage.Details = require( './views/edit-image-details.js' ); 39 media.view.MediaFrame.EditAttachments = require( './views/frame/edit-attachments.js' ); 40 media.view.SelectModeToggleButton = require( './views/button/select-mode-toggle.js' ); 41 media.view.DeleteSelectedButton = require( './views/button/delete-selected.js' ); 42 media.view.DeleteSelectedPermanentlyButton = require( './views/button/delete-selected-permanently.js' ); 43 44 },{"./controllers/edit-attachment-metadata.js":1,"./routers/manage.js":3,"./views/attachment/details-two-column.js":4,"./views/button/delete-selected-permanently.js":5,"./views/button/delete-selected.js":6,"./views/button/select-mode-toggle.js":7,"./views/edit-image-details.js":8,"./views/frame/edit-attachments.js":9,"./views/frame/manage.js":10}],3:[function(require,module,exports){ 127 /***/ }), 128 /* 12 */ 129 /***/ (function(module, exports) { 130 131 var MediaFrame = wp.media.view.MediaFrame, 132 Library = wp.media.controller.Library, 133 134 $ = Backbone.$, 135 Manage; 136 45 137 /** 46 * wp.media.view.MediaFrame.Manage .Router138 * wp.media.view.MediaFrame.Manage 47 139 * 48 * A router for handling the browser history and application state.140 * A generic management frame workflow. 49 141 * 50 * @memberOf wp.media.view.MediaFrame.Manage 142 * Used in the media grid view. 143 * 144 * @memberOf wp.media.view.MediaFrame 51 145 * 52 146 * @class 53 * @augments Backbone.Router 147 * @augments wp.media.view.MediaFrame 148 * @augments wp.media.view.Frame 149 * @augments wp.media.View 150 * @augments wp.Backbone.View 151 * @augments Backbone.View 152 * @mixes wp.media.controller.StateMachine 54 153 */ 55 var Router = Backbone.Router.extend(/** @lends wp.media.view.MediaFrame.Manage.Router.prototype */{ 56 routes: { 57 'upload.php?item=:slug&mode=edit': 'editItem', 58 'upload.php?item=:slug': 'showItem', 59 'upload.php?search=:query': 'search', 60 'upload.php': 'reset' 61 }, 154 Manage = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Manage.prototype */{ 155 /** 156 * @constructs 157 */ 158 initialize: function() { 159 _.defaults( this.options, { 160 title: '', 161 modal: false, 162 selection: [], 163 library: {}, // Options hash for the query to the media library. 164 multiple: 'add', 165 state: 'library', 166 uploader: true, 167 mode: [ 'grid', 'edit' ] 168 }); 62 169 63 // Map routes against the page URL 64 baseUrl: function( url ) { 65 return 'upload.php' + url; 66 }, 170 this.$body = $( document.body ); 171 this.$window = $( window ); 172 this.$adminBar = $( '#wpadminbar' ); 173 // Store the Add New button for later reuse in wp.media.view.UploaderInline. 174 this.$uploaderToggler = $( '.page-title-action' ) 175 .attr( 'aria-expanded', 'false' ) 176 .on( 'click', _.bind( this.addNewClickHandler, this ) ); 67 177 68 reset: function() { 69 var frame = wp.media.frames.edit; 178 this.$window.on( 'scroll resize', _.debounce( _.bind( this.fixPosition, this ), 15 ) ); 70 179 71 if ( frame ) { 72 frame.close(); 180 // Ensure core and media grid view UI is enabled. 181 this.$el.addClass('wp-core-ui'); 182 183 // Force the uploader off if the upload limit has been exceeded or 184 // if the browser isn't supported. 185 if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 186 this.options.uploader = false; 73 187 } 74 },75 188 76 // Respond to the search route by filling the search field and trigggering the input event 77 search: function( query ) { 78 jQuery( '#media-search-input' ).val( query ).trigger( 'input' ); 79 }, 189 // Initialize a window-wide uploader. 190 if ( this.options.uploader ) { 191 this.uploader = new wp.media.view.UploaderWindow({ 192 controller: this, 193 uploader: { 194 dropzone: document.body, 195 container: document.body 196 } 197 }).render(); 198 this.uploader.ready(); 199 $('body').append( this.uploader.el ); 80 200 81 // Show the modal with a specific item 82 showItem: function( query ) { 83 var media = wp.media, 84 frame = media.frames.browse, 85 library = frame.state().get('library'), 86 item; 201 this.options.uploader = false; 202 } 87 203 88 // Trigger the media frame to open the correct item 89 item = library.findWhere( { id: parseInt( query, 10 ) } ); 90 item.set( 'skipHistory', true ); 204 this.gridRouter = new wp.media.view.MediaFrame.Manage.Router(); 91 205 92 if ( item ) { 93 frame.trigger( 'edit:attachment', item ); 94 } else { 95 item = media.attachment( query ); 96 frame.listenTo( item, 'change', function( model ) { 97 frame.stopListening( item ); 98 frame.trigger( 'edit:attachment', model ); 99 } ); 100 item.fetch(); 101 } 102 }, 206 // Call 'initialize' directly on the parent class. 207 MediaFrame.prototype.initialize.apply( this, arguments ); 103 208 104 // Show the modal in edit mode with a specific item. 105 editItem: function( query ) { 106 this.showItem( query ); 107 wp.media.frames.edit.content.mode( 'edit-details' ); 108 } 109 }); 209 // Append the frame view directly the supplied container. 210 this.$el.appendTo( this.options.container ); 110 211 111 module.exports = Router; 212 this.createStates(); 213 this.bindRegionModeHandlers(); 214 this.render(); 215 this.bindSearchHandler(); 112 216 113 },{}],4:[function(require,module,exports){ 114 var Details = wp.media.view.Attachment.Details, 115 TwoColumn; 217 wp.media.frames.browse = this; 218 }, 116 219 117 /** 118 * wp.media.view.Attachment.Details.TwoColumn 119 * 120 * A similar view to media.view.Attachment.Details 121 * for use in the Edit Attachment modal. 122 * 123 * @memberOf wp.media.view.Attachment.Details 124 * 125 * @class 126 * @augments wp.media.view.Attachment.Details 127 * @augments wp.media.view.Attachment 128 * @augments wp.media.View 129 * @augments wp.Backbone.View 130 * @augments Backbone.View 131 */ 132 TwoColumn = Details.extend(/** @lends wp.media.view.Attachment.Details.TowColumn.prototype */{ 133 template: wp.template( 'attachment-details-two-column' ), 220 bindSearchHandler: function() { 221 var search = this.$( '#media-search-input' ), 222 searchView = this.browserView.toolbar.get( 'search' ).$el, 223 listMode = this.$( '.view-list' ), 134 224 135 initialize: function() { 136 this.controller.on( 'content:activate:edit-details', _.bind( this.editAttachment, this ) ); 225 input = _.throttle( function (e) { 226 var val = $( e.currentTarget ).val(), 227 url = ''; 137 228 138 Details.prototype.initialize.apply( this, arguments ); 139 }, 229 if ( val ) { 230 url += '?search=' + val; 231 this.gridRouter.navigate( this.gridRouter.baseUrl( url ), { replace: true } ); 232 } 233 }, 1000 ); 140 234 141 editAttachment: function( event ) { 142 if ( event ) { 143 event.preventDefault(); 144 } 145 this.controller.content.mode( 'edit-image' ); 235 // Update the URL when entering search string (at most once per second) 236 search.on( 'input', _.bind( input, this ) ); 237 238 this.gridRouter 239 .on( 'route:search', function () { 240 var href = window.location.href; 241 if ( href.indexOf( 'mode=' ) > -1 ) { 242 href = href.replace( /mode=[^&]+/g, 'mode=list' ); 243 } else { 244 href += href.indexOf( '?' ) > -1 ? '&mode=list' : '?mode=list'; 245 } 246 href = href.replace( 'search=', 's=' ); 247 listMode.prop( 'href', href ); 248 }) 249 .on( 'route:reset', function() { 250 searchView.val( '' ).trigger( 'input' ); 251 }); 146 252 }, 147 253 148 254 /** 149 * Noop this from parent class, doesn't apply here.255 * Create the default states for the frame. 150 256 */ 151 toggleSelectionHandler: function() {}, 152 153 render: function() { 154 Details.prototype.render.apply( this, arguments ); 257 createStates: function() { 258 var options = this.options; 155 259 156 wp.media.mixin.removeAllPlayers(); 157 this.$( 'audio, video' ).each( function (i, elem) { 158 var el = wp.media.view.MediaDetails.prepareSrc( elem ); 159 new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings ); 160 } ); 161 } 162 }); 260 if ( this.options.states ) { 261 return; 262 } 163 263 164 module.exports = TwoColumn; 264 // Add the default states. 265 this.states.add([ 266 new Library({ 267 library: wp.media.query( options.library ), 268 multiple: options.multiple, 269 title: options.title, 270 content: 'browse', 271 toolbar: 'select', 272 contentUserSetting: false, 273 filterable: 'all', 274 autoSelect: false 275 }) 276 ]); 277 }, 165 278 166 },{}],5:[function(require,module,exports){ 167 var Button = wp.media.view.Button, 168 DeleteSelected = wp.media.view.DeleteSelectedButton, 169 DeleteSelectedPermanently; 279 /** 280 * Bind region mode activation events to proper handlers. 281 */ 282 bindRegionModeHandlers: function() { 283 this.on( 'content:create:browse', this.browseContent, this ); 170 284 171 /** 172 * wp.media.view.DeleteSelectedPermanentlyButton 173 * 174 * When MEDIA_TRASH is true, a button that handles bulk Delete Permanently logic 175 * 176 * @memberOf wp.media.view 177 * 178 * @class 179 * @augments wp.media.view.DeleteSelectedButton 180 * @augments wp.media.view.Button 181 * @augments wp.media.View 182 * @augments wp.Backbone.View 183 * @augments Backbone.View 184 */ 185 DeleteSelectedPermanently = DeleteSelected.extend(/** @lends wp.media.view.DeleteSelectedPermanentlyButton.prototype */{ 186 initialize: function() { 187 DeleteSelected.prototype.initialize.apply( this, arguments ); 188 this.controller.on( 'select:activate', this.selectActivate, this ); 189 this.controller.on( 'select:deactivate', this.selectDeactivate, this ); 190 }, 285 // Handle a frame-level event for editing an attachment. 286 this.on( 'edit:attachment', this.openEditAttachmentModal, this ); 191 287 192 filterChange: function( model ) {193 this. canShow = ( 'trash' === model.get( 'status' ));288 this.on( 'select:activate', this.bindKeydown, this ); 289 this.on( 'select:deactivate', this.unbindKeydown, this ); 194 290 }, 195 291 196 selectActivate: function() { 197 this.toggleDisabled(); 198 this.$el.toggleClass( 'hidden', ! this.canShow ); 292 handleKeydown: function( e ) { 293 if ( 27 === e.which ) { 294 e.preventDefault(); 295 this.deactivateMode( 'select' ).activateMode( 'edit' ); 296 } 199 297 }, 200 298 201 selectDeactivate: function() { 202 this.toggleDisabled(); 203 this.$el.addClass( 'hidden' ); 299 bindKeydown: function() { 300 this.$body.on( 'keydown.select', _.bind( this.handleKeydown, this ) ); 204 301 }, 205 302 206 render: function() { 207 Button.prototype.render.apply( this, arguments ); 208 this.selectActivate(); 209 return this; 210 } 211 }); 303 unbindKeydown: function() { 304 this.$body.off( 'keydown.select' ); 305 }, 212 306 213 module.exports = DeleteSelectedPermanently; 307 fixPosition: function() { 308 var $browser, $toolbar; 309 if ( ! this.isModeActive( 'select' ) ) { 310 return; 311 } 214 312 215 },{}],6:[function(require,module,exports){ 216 var Button = wp.media.view.Button, 217 l10n = wp.media.view.l10n, 218 DeleteSelected; 313 $browser = this.$('.attachments-browser'); 314 $toolbar = $browser.find('.media-toolbar'); 219 315 220 /** 221 * wp.media.view.DeleteSelectedButton 222 * 223 * A button that handles bulk Delete/Trash logic 224 * 225 * @memberOf wp.media.view 226 * 227 * @class 228 * @augments wp.media.view.Button 229 * @augments wp.media.View 230 * @augments wp.Backbone.View 231 * @augments Backbone.View 232 */ 233 DeleteSelected = Button.extend(/** @lends wp.media.view.DeleteSelectedButton.prototype */{ 234 initialize: function() { 235 Button.prototype.initialize.apply( this, arguments ); 236 if ( this.options.filters ) { 237 this.options.filters.model.on( 'change', this.filterChange, this ); 316 // Offset doesn't appear to take top margin into account, hence +16 317 if ( ( $browser.offset().top + 16 ) < this.$window.scrollTop() + this.$adminBar.height() ) { 318 $browser.addClass( 'fixed' ); 319 $toolbar.css('width', $browser.width() + 'px'); 320 } else { 321 $browser.removeClass( 'fixed' ); 322 $toolbar.css('width', ''); 238 323 } 239 this.controller.on( 'selection:toggle', this.toggleDisabled, this );240 324 }, 241 325 242 filterChange: function( model ) { 243 if ( 'trash' === model.get( 'status' ) ) { 244 this.model.set( 'text', l10n.untrashSelected ); 245 } else if ( wp.media.view.settings.mediaTrash ) { 246 this.model.set( 'text', l10n.trashSelected ); 326 /** 327 * Click handler for the `Add New` button. 328 */ 329 addNewClickHandler: function( event ) { 330 event.preventDefault(); 331 this.trigger( 'toggle:upload:attachment' ); 332 333 if ( this.uploader ) { 334 this.uploader.refresh(); 335 } 336 }, 337 338 /** 339 * Open the Edit Attachment modal. 340 */ 341 openEditAttachmentModal: function( model ) { 342 // Create a new EditAttachment frame, passing along the library and the attachment model. 343 if ( wp.media.frames.edit ) { 344 wp.media.frames.edit.open().trigger( 'refresh', model ); 247 345 } else { 248 this.model.set( 'text', l10n.deleteSelected ); 346 wp.media.frames.edit = wp.media( { 347 frame: 'edit-attachments', 348 controller: this, 349 library: this.state().get('library'), 350 model: model 351 } ); 249 352 } 250 353 }, 251 354 252 toggleDisabled: function() { 253 this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length ); 355 /** 356 * Create an attachments browser view within the content region. 357 * 358 * @param {Object} contentRegion Basic object with a `view` property, which 359 * should be set with the proper region view. 360 * @this wp.media.controller.Region 361 */ 362 browseContent: function( contentRegion ) { 363 var state = this.state(); 364 365 // Browse our library of attachments. 366 this.browserView = contentRegion.view = new wp.media.view.AttachmentsBrowser({ 367 controller: this, 368 collection: state.get('library'), 369 selection: state.get('selection'), 370 model: state, 371 sortable: state.get('sortable'), 372 search: state.get('searchable'), 373 filters: state.get('filterable'), 374 date: state.get('date'), 375 display: state.get('displaySettings'), 376 dragInfo: state.get('dragInfo'), 377 sidebar: 'errors', 378 379 suggestedWidth: state.get('suggestedWidth'), 380 suggestedHeight: state.get('suggestedHeight'), 381 382 AttachmentView: state.get('AttachmentView'), 383 384 scrollElement: document 385 }); 386 this.browserView.on( 'ready', _.bind( this.bindDeferred, this ) ); 387 388 this.errors = wp.Uploader.errors; 389 this.errors.on( 'add remove reset', this.sidebarVisibility, this ); 254 390 }, 255 391 256 render: function() { 257 Button.prototype.render.apply( this, arguments ); 258 if ( this.controller.isModeActive( 'select' ) ) { 259 this.$el.addClass( 'delete-selected-button' ); 260 } else { 261 this.$el.addClass( 'delete-selected-button hidden' ); 392 sidebarVisibility: function() { 393 this.browserView.$( '.media-sidebar' ).toggle( !! this.errors.length ); 394 }, 395 396 bindDeferred: function() { 397 if ( ! this.browserView.dfd ) { 398 return; 399 } 400 this.browserView.dfd.done( _.bind( this.startHistory, this ) ); 401 }, 402 403 startHistory: function() { 404 // Verify pushState support and activate 405 if ( window.history && window.history.pushState ) { 406 if ( Backbone.History.started ) { 407 Backbone.history.stop(); 408 } 409 Backbone.history.start( { 410 root: window._wpMediaGridSettings.adminUrl, 411 pushState: true 412 } ); 262 413 } 263 this.toggleDisabled();264 return this;265 414 } 266 415 }); 267 416 268 module.exports = DeleteSelected;417 module.exports = Manage; 269 418 270 },{}],7:[function(require,module,exports){271 419 272 var Button = wp.media.view.Button, 273 l10n = wp.media.view.l10n, 274 SelectModeToggle; 420 /***/ }), 421 /* 13 */ 422 /***/ (function(module, exports) { 423 424 var Details = wp.media.view.Attachment.Details, 425 TwoColumn; 275 426 276 427 /** 277 * wp.media.view. SelectModeToggleButton428 * wp.media.view.Attachment.Details.TwoColumn 278 429 * 279 * @memberOf wp.media.view 430 * A similar view to media.view.Attachment.Details 431 * for use in the Edit Attachment modal. 432 * 433 * @memberOf wp.media.view.Attachment.Details 280 434 * 281 435 * @class 282 * @augments wp.media.view.Button 436 * @augments wp.media.view.Attachment.Details 437 * @augments wp.media.view.Attachment 283 438 * @augments wp.media.View 284 439 * @augments wp.Backbone.View 285 440 * @augments Backbone.View 286 441 */ 287 SelectModeToggle = Button.extend(/** @lends wp.media.view.SelectModeToggle.prototype */{ 288 initialize: function() { 289 _.defaults( this.options, { 290 size : '' 291 } ); 442 TwoColumn = Details.extend(/** @lends wp.media.view.Attachment.Details.TowColumn.prototype */{ 443 template: wp.template( 'attachment-details-two-column' ), 292 444 293 Button.prototype.initialize.apply( this, arguments ); 294 this.controller.on( 'select:activate select:deactivate', this.toggleBulkEditHandler, this ); 295 this.controller.on( 'selection:action:done', this.back, this ); 296 }, 445 initialize: function() { 446 this.controller.on( 'content:activate:edit-details', _.bind( this.editAttachment, this ) ); 297 447 298 back: function () { 299 this.controller.deactivateMode( 'select' ).activateMode( 'edit' ); 448 Details.prototype.initialize.apply( this, arguments ); 300 449 }, 301 450 302 click: function() { 303 Button.prototype.click.apply( this, arguments ); 304 if ( this.controller.isModeActive( 'select' ) ) { 305 this.back(); 306 } else { 307 this.controller.deactivateMode( 'edit' ).activateMode( 'select' ); 451 editAttachment: function( event ) { 452 if ( event ) { 453 event.preventDefault(); 308 454 } 455 this.controller.content.mode( 'edit-image' ); 309 456 }, 310 457 311 render: function() { 312 Button.prototype.render.apply( this, arguments ); 313 this.$el.addClass( 'select-mode-toggle-button' ); 314 return this; 315 }, 316 317 toggleBulkEditHandler: function() { 318 var toolbar = this.controller.content.get().toolbar, children; 458 /** 459 * Noop this from parent class, doesn't apply here. 460 */ 461 toggleSelectionHandler: function() {}, 319 462 320 children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *' ); 463 render: function() { 464 Details.prototype.render.apply( this, arguments ); 321 465 322 // TODO: the Frame should be doing all of this. 323 if ( this.controller.isModeActive( 'select' ) ) { 324 this.model.set( { 325 size: 'large', 326 text: l10n.cancelSelection 327 } ); 328 children.not( '.spinner, .media-button' ).hide(); 329 this.$el.show(); 330 toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' ); 331 } else { 332 this.model.set( { 333 size: '', 334 text: l10n.bulkSelect 335 } ); 336 this.controller.content.get().$el.removeClass( 'fixed' ); 337 toolbar.$el.css( 'width', '' ); 338 toolbar.$( '.delete-selected-button' ).addClass( 'hidden' ); 339 children.not( '.media-button' ).show(); 340 this.controller.state().get( 'selection' ).reset(); 341 } 466 wp.media.mixin.removeAllPlayers(); 467 this.$( 'audio, video' ).each( function (i, elem) { 468 var el = wp.media.view.MediaDetails.prepareSrc( elem ); 469 new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings ); 470 } ); 342 471 } 343 472 }); 344 473 345 module.exports = SelectModeToggle;474 module.exports = TwoColumn; 346 475 347 },{}],8:[function(require,module,exports){ 348 var View = wp.media.View,349 EditImage = wp.media.view.EditImage, 350 Details; 476 477 /***/ }), 478 /* 14 */ 479 /***/ (function(module, exports) { 351 480 352 481 /** 353 * wp.media.view. EditImage.Details482 * wp.media.view.MediaFrame.Manage.Router 354 483 * 355 * @memberOf wp.media.view.EditImage 484 * A router for handling the browser history and application state. 485 * 486 * @memberOf wp.media.view.MediaFrame.Manage 356 487 * 357 488 * @class 358 * @augments wp.media.view.EditImage 359 * @augments wp.media.View 360 * @augments wp.Backbone.View 361 * @augments Backbone.View 489 * @augments Backbone.Router 362 490 */ 363 Details = EditImage.extend(/** @lends wp.media.view.EditImage.Details.prototype */{ 491 var Router = Backbone.Router.extend(/** @lends wp.media.view.MediaFrame.Manage.Router.prototype */{ 492 routes: { 493 'upload.php?item=:slug&mode=edit': 'editItem', 494 'upload.php?item=:slug': 'showItem', 495 'upload.php?search=:query': 'search', 496 'upload.php': 'reset' 497 }, 498 499 // Map routes against the page URL 500 baseUrl: function( url ) { 501 return 'upload.php' + url; 502 }, 503 504 reset: function() { 505 var frame = wp.media.frames.edit; 506 507 if ( frame ) { 508 frame.close(); 509 } 510 }, 511 512 // Respond to the search route by filling the search field and trigggering the input event 513 search: function( query ) { 514 jQuery( '#media-search-input' ).val( query ).trigger( 'input' ); 515 }, 516 517 // Show the modal with a specific item 518 showItem: function( query ) { 519 var media = wp.media, 520 frame = media.frames.browse, 521 library = frame.state().get('library'), 522 item; 523 524 // Trigger the media frame to open the correct item 525 item = library.findWhere( { id: parseInt( query, 10 ) } ); 526 item.set( 'skipHistory', true ); 527 528 if ( item ) { 529 frame.trigger( 'edit:attachment', item ); 530 } else { 531 item = media.attachment( query ); 532 frame.listenTo( item, 'change', function( model ) { 533 frame.stopListening( item ); 534 frame.trigger( 'edit:attachment', model ); 535 } ); 536 item.fetch(); 537 } 538 }, 539 540 // Show the modal in edit mode with a specific item. 541 editItem: function( query ) { 542 this.showItem( query ); 543 wp.media.frames.edit.content.mode( 'edit-details' ); 544 } 545 }); 546 547 module.exports = Router; 548 549 550 /***/ }), 551 /* 15 */ 552 /***/ (function(module, exports) { 553 554 var View = wp.media.View, 555 EditImage = wp.media.view.EditImage, 556 Details; 557 558 /** 559 * wp.media.view.EditImage.Details 560 * 561 * @memberOf wp.media.view.EditImage 562 * 563 * @class 564 * @augments wp.media.view.EditImage 565 * @augments wp.media.View 566 * @augments wp.Backbone.View 567 * @augments Backbone.View 568 */ 569 Details = EditImage.extend(/** @lends wp.media.view.EditImage.Details.prototype */{ 364 570 initialize: function( options ) { 365 571 this.editor = window.imageEdit; 366 572 this.frame = options.frame; … … Details = EditImage.extend(/** @lends wp.media.view.EditImage.Details.prototype 381 587 382 588 module.exports = Details; 383 589 384 },{}],9:[function(require,module,exports){ 590 591 /***/ }), 592 /* 16 */ 593 /***/ (function(module, exports) { 594 385 595 var Frame = wp.media.view.Frame, 386 596 MediaFrame = wp.media.view.MediaFrame, 387 597 … … EditAttachments = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.EditAtta 643 853 644 854 module.exports = EditAttachments; 645 855 646 },{}],10:[function(require,module,exports){647 var MediaFrame = wp.media.view.MediaFrame,648 Library = wp.media.controller.Library,649 856 650 $ = Backbone.$, 651 Manage; 857 /***/ }), 858 /* 17 */ 859 /***/ (function(module, exports) { 860 861 862 var Button = wp.media.view.Button, 863 l10n = wp.media.view.l10n, 864 SelectModeToggle; 652 865 653 866 /** 654 * wp.media.view.MediaFrame.Manage 655 * 656 * A generic management frame workflow. 657 * 658 * Used in the media grid view. 867 * wp.media.view.SelectModeToggleButton 659 868 * 660 * @memberOf wp.media.view .MediaFrame869 * @memberOf wp.media.view 661 870 * 662 871 * @class 663 * @augments wp.media.view.MediaFrame 664 * @augments wp.media.view.Frame 872 * @augments wp.media.view.Button 665 873 * @augments wp.media.View 666 874 * @augments wp.Backbone.View 667 875 * @augments Backbone.View 668 * @mixes wp.media.controller.StateMachine669 876 */ 670 Manage = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Manage.prototype */{ 671 /** 672 * @constructs 673 */ 877 SelectModeToggle = Button.extend(/** @lends wp.media.view.SelectModeToggle.prototype */{ 674 878 initialize: function() { 675 879 _.defaults( this.options, { 676 title: '', 677 modal: false, 678 selection: [], 679 library: {}, // Options hash for the query to the media library. 680 multiple: 'add', 681 state: 'library', 682 uploader: true, 683 mode: [ 'grid', 'edit' ] 684 }); 685 686 this.$body = $( document.body ); 687 this.$window = $( window ); 688 this.$adminBar = $( '#wpadminbar' ); 689 // Store the Add New button for later reuse in wp.media.view.UploaderInline. 690 this.$uploaderToggler = $( '.page-title-action' ) 691 .attr( 'aria-expanded', 'false' ) 692 .on( 'click', _.bind( this.addNewClickHandler, this ) ); 693 694 this.$window.on( 'scroll resize', _.debounce( _.bind( this.fixPosition, this ), 15 ) ); 695 696 // Ensure core and media grid view UI is enabled. 697 this.$el.addClass('wp-core-ui'); 880 size : '' 881 } ); 698 882 699 // Force the uploader off if the upload limit has been exceeded or 700 // if the browser isn't supported. 701 if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 702 this.options.uploader = false; 703 } 883 Button.prototype.initialize.apply( this, arguments ); 884 this.controller.on( 'select:activate select:deactivate', this.toggleBulkEditHandler, this ); 885 this.controller.on( 'selection:action:done', this.back, this ); 886 }, 704 887 705 // Initialize a window-wide uploader. 706 if ( this.options.uploader ) { 707 this.uploader = new wp.media.view.UploaderWindow({ 708 controller: this, 709 uploader: { 710 dropzone: document.body, 711 container: document.body 712 } 713 }).render(); 714 this.uploader.ready(); 715 $('body').append( this.uploader.el ); 888 back: function () { 889 this.controller.deactivateMode( 'select' ).activateMode( 'edit' ); 890 }, 716 891 717 this.options.uploader = false; 892 click: function() { 893 Button.prototype.click.apply( this, arguments ); 894 if ( this.controller.isModeActive( 'select' ) ) { 895 this.back(); 896 } else { 897 this.controller.deactivateMode( 'edit' ).activateMode( 'select' ); 718 898 } 719 720 this.gridRouter = new wp.media.view.MediaFrame.Manage.Router();721 722 // Call 'initialize' directly on the parent class.723 MediaFrame.prototype.initialize.apply( this, arguments );724 725 // Append the frame view directly the supplied container.726 this.$el.appendTo( this.options.container );727 728 this.createStates();729 this.bindRegionModeHandlers();730 this.render();731 this.bindSearchHandler();732 733 wp.media.frames.browse = this;734 899 }, 735 900 736 bindSearchHandler: function() { 737 var search = this.$( '#media-search-input' ), 738 searchView = this.browserView.toolbar.get( 'search' ).$el, 739 listMode = this.$( '.view-list' ), 740 741 input = _.throttle( function (e) { 742 var val = $( e.currentTarget ).val(), 743 url = ''; 744 745 if ( val ) { 746 url += '?search=' + val; 747 this.gridRouter.navigate( this.gridRouter.baseUrl( url ), { replace: true } ); 748 } 749 }, 1000 ); 750 751 // Update the URL when entering search string (at most once per second) 752 search.on( 'input', _.bind( input, this ) ); 753 754 this.gridRouter 755 .on( 'route:search', function () { 756 var href = window.location.href; 757 if ( href.indexOf( 'mode=' ) > -1 ) { 758 href = href.replace( /mode=[^&]+/g, 'mode=list' ); 759 } else { 760 href += href.indexOf( '?' ) > -1 ? '&mode=list' : '?mode=list'; 761 } 762 href = href.replace( 'search=', 's=' ); 763 listMode.prop( 'href', href ); 764 }) 765 .on( 'route:reset', function() { 766 searchView.val( '' ).trigger( 'input' ); 767 }); 901 render: function() { 902 Button.prototype.render.apply( this, arguments ); 903 this.$el.addClass( 'select-mode-toggle-button' ); 904 return this; 768 905 }, 769 906 770 /** 771 * Create the default states for the frame. 772 */ 773 createStates: function() { 774 var options = this.options; 907 toggleBulkEditHandler: function() { 908 var toolbar = this.controller.content.get().toolbar, children; 775 909 776 if ( this.options.states ) { 777 return; 910 children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *' ); 911 912 // TODO: the Frame should be doing all of this. 913 if ( this.controller.isModeActive( 'select' ) ) { 914 this.model.set( { 915 size: 'large', 916 text: l10n.cancelSelection 917 } ); 918 children.not( '.spinner, .media-button' ).hide(); 919 this.$el.show(); 920 toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' ); 921 } else { 922 this.model.set( { 923 size: '', 924 text: l10n.bulkSelect 925 } ); 926 this.controller.content.get().$el.removeClass( 'fixed' ); 927 toolbar.$el.css( 'width', '' ); 928 toolbar.$( '.delete-selected-button' ).addClass( 'hidden' ); 929 children.not( '.media-button' ).show(); 930 this.controller.state().get( 'selection' ).reset(); 778 931 } 932 } 933 }); 779 934 780 // Add the default states. 781 this.states.add([ 782 new Library({ 783 library: wp.media.query( options.library ), 784 multiple: options.multiple, 785 title: options.title, 786 content: 'browse', 787 toolbar: 'select', 788 contentUserSetting: false, 789 filterable: 'all', 790 autoSelect: false 791 }) 792 ]); 793 }, 935 module.exports = SelectModeToggle; 794 936 795 /**796 * Bind region mode activation events to proper handlers.797 */798 bindRegionModeHandlers: function() {799 this.on( 'content:create:browse', this.browseContent, this );800 937 801 // Handle a frame-level event for editing an attachment. 802 this.on( 'edit:attachment', this.openEditAttachmentModal, this ); 938 /***/ }), 939 /* 18 */ 940 /***/ (function(module, exports) { 803 941 804 this.on( 'select:activate', this.bindKeydown, this ); 805 this.on( 'select:deactivate', this.unbindKeydown, this );806 },942 var Button = wp.media.view.Button, 943 l10n = wp.media.view.l10n, 944 DeleteSelected; 807 945 808 handleKeydown: function( e ) { 809 if ( 27 === e.which ) { 810 e.preventDefault(); 811 this.deactivateMode( 'select' ).activateMode( 'edit' ); 946 /** 947 * wp.media.view.DeleteSelectedButton 948 * 949 * A button that handles bulk Delete/Trash logic 950 * 951 * @memberOf wp.media.view 952 * 953 * @class 954 * @augments wp.media.view.Button 955 * @augments wp.media.View 956 * @augments wp.Backbone.View 957 * @augments Backbone.View 958 */ 959 DeleteSelected = Button.extend(/** @lends wp.media.view.DeleteSelectedButton.prototype */{ 960 initialize: function() { 961 Button.prototype.initialize.apply( this, arguments ); 962 if ( this.options.filters ) { 963 this.options.filters.model.on( 'change', this.filterChange, this ); 812 964 } 965 this.controller.on( 'selection:toggle', this.toggleDisabled, this ); 813 966 }, 814 967 815 bindKeydown: function() { 816 this.$body.on( 'keydown.select', _.bind( this.handleKeydown, this ) ); 817 }, 818 819 unbindKeydown: function() { 820 this.$body.off( 'keydown.select' ); 821 }, 822 823 fixPosition: function() { 824 var $browser, $toolbar; 825 if ( ! this.isModeActive( 'select' ) ) { 826 return; 827 } 828 829 $browser = this.$('.attachments-browser'); 830 $toolbar = $browser.find('.media-toolbar'); 831 832 // Offset doesn't appear to take top margin into account, hence +16 833 if ( ( $browser.offset().top + 16 ) < this.$window.scrollTop() + this.$adminBar.height() ) { 834 $browser.addClass( 'fixed' ); 835 $toolbar.css('width', $browser.width() + 'px'); 968 filterChange: function( model ) { 969 if ( 'trash' === model.get( 'status' ) ) { 970 this.model.set( 'text', l10n.untrashSelected ); 971 } else if ( wp.media.view.settings.mediaTrash ) { 972 this.model.set( 'text', l10n.trashSelected ); 836 973 } else { 837 $browser.removeClass( 'fixed' ); 838 $toolbar.css('width', ''); 974 this.model.set( 'text', l10n.deleteSelected ); 839 975 } 840 976 }, 841 977 842 /** 843 * Click handler for the `Add New` button. 844 */ 845 addNewClickHandler: function( event ) { 846 event.preventDefault(); 847 this.trigger( 'toggle:upload:attachment' ); 848 849 if ( this.uploader ) { 850 this.uploader.refresh(); 851 } 978 toggleDisabled: function() { 979 this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length ); 852 980 }, 853 981 854 /** 855 * Open the Edit Attachment modal. 856 */ 857 openEditAttachmentModal: function( model ) { 858 // Create a new EditAttachment frame, passing along the library and the attachment model. 859 if ( wp.media.frames.edit ) { 860 wp.media.frames.edit.open().trigger( 'refresh', model ); 982 render: function() { 983 Button.prototype.render.apply( this, arguments ); 984 if ( this.controller.isModeActive( 'select' ) ) { 985 this.$el.addClass( 'delete-selected-button' ); 861 986 } else { 862 wp.media.frames.edit = wp.media( { 863 frame: 'edit-attachments', 864 controller: this, 865 library: this.state().get('library'), 866 model: model 867 } ); 987 this.$el.addClass( 'delete-selected-button hidden' ); 868 988 } 869 }, 989 this.toggleDisabled(); 990 return this; 991 } 992 }); 870 993 871 /** 872 * Create an attachments browser view within the content region. 873 * 874 * @param {Object} contentRegion Basic object with a `view` property, which 875 * should be set with the proper region view. 876 * @this wp.media.controller.Region 877 */ 878 browseContent: function( contentRegion ) { 879 var state = this.state(); 994 module.exports = DeleteSelected; 880 995 881 // Browse our library of attachments.882 this.browserView = contentRegion.view = new wp.media.view.AttachmentsBrowser({883 controller: this,884 collection: state.get('library'),885 selection: state.get('selection'),886 model: state,887 sortable: state.get('sortable'),888 search: state.get('searchable'),889 filters: state.get('filterable'),890 date: state.get('date'),891 display: state.get('displaySettings'),892 dragInfo: state.get('dragInfo'),893 sidebar: 'errors',894 996 895 suggestedWidth: state.get('suggestedWidth'), 896 suggestedHeight: state.get('suggestedHeight'), 997 /***/ }), 998 /* 19 */ 999 /***/ (function(module, exports) { 897 1000 898 AttachmentView: state.get('AttachmentView'), 1001 var Button = wp.media.view.Button, 1002 DeleteSelected = wp.media.view.DeleteSelectedButton, 1003 DeleteSelectedPermanently; 899 1004 900 scrollElement: document 901 }); 902 this.browserView.on( 'ready', _.bind( this.bindDeferred, this ) ); 1005 /** 1006 * wp.media.view.DeleteSelectedPermanentlyButton 1007 * 1008 * When MEDIA_TRASH is true, a button that handles bulk Delete Permanently logic 1009 * 1010 * @memberOf wp.media.view 1011 * 1012 * @class 1013 * @augments wp.media.view.DeleteSelectedButton 1014 * @augments wp.media.view.Button 1015 * @augments wp.media.View 1016 * @augments wp.Backbone.View 1017 * @augments Backbone.View 1018 */ 1019 DeleteSelectedPermanently = DeleteSelected.extend(/** @lends wp.media.view.DeleteSelectedPermanentlyButton.prototype */{ 1020 initialize: function() { 1021 DeleteSelected.prototype.initialize.apply( this, arguments ); 1022 this.controller.on( 'select:activate', this.selectActivate, this ); 1023 this.controller.on( 'select:deactivate', this.selectDeactivate, this ); 1024 }, 903 1025 904 this.errors = wp.Uploader.errors;905 this. errors.on( 'add remove reset', this.sidebarVisibility, this);1026 filterChange: function( model ) { 1027 this.canShow = ( 'trash' === model.get( 'status' ) ); 906 1028 }, 907 1029 908 sidebarVisibility: function() { 909 this.browserView.$( '.media-sidebar' ).toggle( !! this.errors.length ); 1030 selectActivate: function() { 1031 this.toggleDisabled(); 1032 this.$el.toggleClass( 'hidden', ! this.canShow ); 910 1033 }, 911 1034 912 bindDeferred: function() { 913 if ( ! this.browserView.dfd ) { 914 return; 915 } 916 this.browserView.dfd.done( _.bind( this.startHistory, this ) ); 1035 selectDeactivate: function() { 1036 this.toggleDisabled(); 1037 this.$el.addClass( 'hidden' ); 917 1038 }, 918 1039 919 startHistory: function() { 920 // Verify pushState support and activate 921 if ( window.history && window.history.pushState ) { 922 if ( Backbone.History.started ) { 923 Backbone.history.stop(); 924 } 925 Backbone.history.start( { 926 root: window._wpMediaGridSettings.adminUrl, 927 pushState: true 928 } ); 929 } 1040 render: function() { 1041 Button.prototype.render.apply( this, arguments ); 1042 this.selectActivate(); 1043 return this; 930 1044 } 931 1045 }); 932 1046 933 module.exports = Manage; 1047 module.exports = DeleteSelectedPermanently; 1048 934 1049 935 },{}]},{},[2]); 1050 /***/ }) 1051 /******/ ]); 1052 No newline at end of file -
src/wp-includes/js/media-models.js
diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js index caa7fcb590..af64387257 100644
1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 1 /******/ (function(modules) { // webpackBootstrap 2 /******/ // The module cache 3 /******/ var installedModules = {}; 4 /******/ 5 /******/ // The require function 6 /******/ function __webpack_require__(moduleId) { 7 /******/ 8 /******/ // Check if module is in cache 9 /******/ if(installedModules[moduleId]) { 10 /******/ return installedModules[moduleId].exports; 11 /******/ } 12 /******/ // Create a new module (and put it into the cache) 13 /******/ var module = installedModules[moduleId] = { 14 /******/ i: moduleId, 15 /******/ l: false, 16 /******/ exports: {} 17 /******/ }; 18 /******/ 19 /******/ // Execute the module function 20 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 /******/ 22 /******/ // Flag the module as loaded 23 /******/ module.l = true; 24 /******/ 25 /******/ // Return the exports of the module 26 /******/ return module.exports; 27 /******/ } 28 /******/ 29 /******/ 30 /******/ // expose the modules object (__webpack_modules__) 31 /******/ __webpack_require__.m = modules; 32 /******/ 33 /******/ // expose the module cache 34 /******/ __webpack_require__.c = installedModules; 35 /******/ 36 /******/ // define getter function for harmony exports 37 /******/ __webpack_require__.d = function(exports, name, getter) { 38 /******/ if(!__webpack_require__.o(exports, name)) { 39 /******/ Object.defineProperty(exports, name, { 40 /******/ configurable: false, 41 /******/ enumerable: true, 42 /******/ get: getter 43 /******/ }); 44 /******/ } 45 /******/ }; 46 /******/ 47 /******/ // getDefaultExport function for compatibility with non-harmony modules 48 /******/ __webpack_require__.n = function(module) { 49 /******/ var getter = module && module.__esModule ? 50 /******/ function getDefault() { return module['default']; } : 51 /******/ function getModuleExports() { return module; }; 52 /******/ __webpack_require__.d(getter, 'a', getter); 53 /******/ return getter; 54 /******/ }; 55 /******/ 56 /******/ // Object.prototype.hasOwnProperty.call 57 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 /******/ 59 /******/ // __webpack_public_path__ 60 /******/ __webpack_require__.p = ""; 61 /******/ 62 /******/ // Load entry module and return exports 63 /******/ return __webpack_require__(__webpack_require__.s = 20); 64 /******/ }) 65 /************************************************************************/ 66 /******/ ({ 67 68 /***/ 20: 69 /***/ (function(module, exports, __webpack_require__) { 70 2 71 var $ = jQuery, 3 72 Attachment, Attachments, l10n, media; 4 73 … … l10n = media.model.l10n = window._wpMediaModelsL10n || {}; 65 134 media.model.settings = l10n.settings || {}; 66 135 delete l10n.settings; 67 136 68 Attachment = media.model.Attachment = require( './models/attachment.js');69 Attachments = media.model.Attachments = require( './models/attachments.js');137 Attachment = media.model.Attachment = __webpack_require__( 21 ); 138 Attachments = media.model.Attachments = __webpack_require__( 22 ); 70 139 71 media.model.Query = require( './models/query.js');72 media.model.PostImage = require( './models/post-image.js');73 media.model.Selection = require( './models/selection.js');140 media.model.Query = __webpack_require__( 23 ); 141 media.model.PostImage = __webpack_require__( 24 ); 142 media.model.Selection = __webpack_require__( 25 ); 74 143 75 144 /** 76 145 * ======================================================================== … … $(window).on('unload', function(){ 238 307 window.wp = null; 239 308 }); 240 309 241 },{"./models/attachment.js":2,"./models/attachments.js":3,"./models/post-image.js":4,"./models/query.js":5,"./models/selection.js":6}],2:[function(require,module,exports){ 310 311 /***/ }), 312 313 /***/ 21: 314 /***/ (function(module, exports) { 315 242 316 var $ = Backbone.$, 243 317 Attachment; 244 318 … … Attachment = Backbone.Model.extend(/** @lends wp.media.model.Attachment.prototyp 409 483 410 484 module.exports = Attachment; 411 485 412 },{}],3:[function(require,module,exports){ 486 487 /***/ }), 488 489 /***/ 22: 490 /***/ (function(module, exports) { 491 413 492 /** 414 493 * wp.media.model.Attachments 415 494 * … … var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen 954 1033 955 1034 module.exports = Attachments; 956 1035 957 },{}],4:[function(require,module,exports){958 /**959 * wp.media.model.PostImage960 *961 * An instance of an image that's been embedded into a post.962 *963 * Used in the embedded image attachment display settings modal - @see wp.media.view.MediaFrame.ImageDetails.964 *965 * @memberOf wp.media.model966 *967 * @class968 * @augments Backbone.Model969 *970 * @param {int} [attributes] Initial model attributes.971 * @param {int} [attributes.attachment_id] ID of the attachment.972 **/973 var PostImage = Backbone.Model.extend(/** @lends wp.media.model.PostImage.prototype */{974 975 initialize: function( attributes ) {976 var Attachment = wp.media.model.Attachment;977 this.attachment = false;978 1036 979 if ( attributes.attachment_id ) { 980 this.attachment = Attachment.get( attributes.attachment_id ); 981 if ( this.attachment.get( 'url' ) ) { 982 this.dfd = jQuery.Deferred(); 983 this.dfd.resolve(); 984 } else { 985 this.dfd = this.attachment.fetch(); 986 } 987 this.bindAttachmentListeners(); 988 } 1037 /***/ }), 989 1038 990 // keep url in sync with changes to the type of link 991 this.on( 'change:link', this.updateLinkUrl, this ); 992 this.on( 'change:size', this.updateSize, this ); 1039 /***/ 23: 1040 /***/ (function(module, exports) { 993 1041 994 this.setLinkTypeFromUrl();995 this.setAspectRatio();996 997 this.set( 'originalUrl', attributes.url );998 },999 1000 bindAttachmentListeners: function() {1001 this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );1002 this.listenTo( this.attachment, 'sync', this.setAspectRatio );1003 this.listenTo( this.attachment, 'change', this.updateSize );1004 },1005 1006 changeAttachment: function( attachment, props ) {1007 this.stopListening( this.attachment );1008 this.attachment = attachment;1009 this.bindAttachmentListeners();1010 1011 this.set( 'attachment_id', this.attachment.get( 'id' ) );1012 this.set( 'caption', this.attachment.get( 'caption' ) );1013 this.set( 'alt', this.attachment.get( 'alt' ) );1014 this.set( 'size', props.get( 'size' ) );1015 this.set( 'align', props.get( 'align' ) );1016 this.set( 'link', props.get( 'link' ) );1017 this.updateLinkUrl();1018 this.updateSize();1019 },1020 1021 setLinkTypeFromUrl: function() {1022 var linkUrl = this.get( 'linkUrl' ),1023 type;1024 1025 if ( ! linkUrl ) {1026 this.set( 'link', 'none' );1027 return;1028 }1029 1030 // default to custom if there is a linkUrl1031 type = 'custom';1032 1033 if ( this.attachment ) {1034 if ( this.attachment.get( 'url' ) === linkUrl ) {1035 type = 'file';1036 } else if ( this.attachment.get( 'link' ) === linkUrl ) {1037 type = 'post';1038 }1039 } else {1040 if ( this.get( 'url' ) === linkUrl ) {1041 type = 'file';1042 }1043 }1044 1045 this.set( 'link', type );1046 },1047 1048 updateLinkUrl: function() {1049 var link = this.get( 'link' ),1050 url;1051 1052 switch( link ) {1053 case 'file':1054 if ( this.attachment ) {1055 url = this.attachment.get( 'url' );1056 } else {1057 url = this.get( 'url' );1058 }1059 this.set( 'linkUrl', url );1060 break;1061 case 'post':1062 this.set( 'linkUrl', this.attachment.get( 'link' ) );1063 break;1064 case 'none':1065 this.set( 'linkUrl', '' );1066 break;1067 }1068 },1069 1070 updateSize: function() {1071 var size;1072 1073 if ( ! this.attachment ) {1074 return;1075 }1076 1077 if ( this.get( 'size' ) === 'custom' ) {1078 this.set( 'width', this.get( 'customWidth' ) );1079 this.set( 'height', this.get( 'customHeight' ) );1080 this.set( 'url', this.get( 'originalUrl' ) );1081 return;1082 }1083 1084 size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ];1085 1086 if ( ! size ) {1087 return;1088 }1089 1090 this.set( 'url', size.url );1091 this.set( 'width', size.width );1092 this.set( 'height', size.height );1093 },1094 1095 setAspectRatio: function() {1096 var full;1097 1098 if ( this.attachment && this.attachment.get( 'sizes' ) ) {1099 full = this.attachment.get( 'sizes' ).full;1100 1101 if ( full ) {1102 this.set( 'aspectRatio', full.width / full.height );1103 return;1104 }1105 }1106 1107 this.set( 'aspectRatio', this.get( 'customWidth' ) / this.get( 'customHeight' ) );1108 }1109 });1110 1111 module.exports = PostImage;1112 1113 },{}],5:[function(require,module,exports){1114 1042 var Attachments = wp.media.model.Attachments, 1115 1043 Query; 1116 1044 … … Query = Attachments.extend(/** @lends wp.media.model.Query.prototype */{ 1418 1346 1419 1347 module.exports = Query; 1420 1348 1421 },{}],6:[function(require,module,exports){ 1349 1350 /***/ }), 1351 1352 /***/ 24: 1353 /***/ (function(module, exports) { 1354 1355 /** 1356 * wp.media.model.PostImage 1357 * 1358 * An instance of an image that's been embedded into a post. 1359 * 1360 * Used in the embedded image attachment display settings modal - @see wp.media.view.MediaFrame.ImageDetails. 1361 * 1362 * @memberOf wp.media.model 1363 * 1364 * @class 1365 * @augments Backbone.Model 1366 * 1367 * @param {int} [attributes] Initial model attributes. 1368 * @param {int} [attributes.attachment_id] ID of the attachment. 1369 **/ 1370 var PostImage = Backbone.Model.extend(/** @lends wp.media.model.PostImage.prototype */{ 1371 1372 initialize: function( attributes ) { 1373 var Attachment = wp.media.model.Attachment; 1374 this.attachment = false; 1375 1376 if ( attributes.attachment_id ) { 1377 this.attachment = Attachment.get( attributes.attachment_id ); 1378 if ( this.attachment.get( 'url' ) ) { 1379 this.dfd = jQuery.Deferred(); 1380 this.dfd.resolve(); 1381 } else { 1382 this.dfd = this.attachment.fetch(); 1383 } 1384 this.bindAttachmentListeners(); 1385 } 1386 1387 // keep url in sync with changes to the type of link 1388 this.on( 'change:link', this.updateLinkUrl, this ); 1389 this.on( 'change:size', this.updateSize, this ); 1390 1391 this.setLinkTypeFromUrl(); 1392 this.setAspectRatio(); 1393 1394 this.set( 'originalUrl', attributes.url ); 1395 }, 1396 1397 bindAttachmentListeners: function() { 1398 this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl ); 1399 this.listenTo( this.attachment, 'sync', this.setAspectRatio ); 1400 this.listenTo( this.attachment, 'change', this.updateSize ); 1401 }, 1402 1403 changeAttachment: function( attachment, props ) { 1404 this.stopListening( this.attachment ); 1405 this.attachment = attachment; 1406 this.bindAttachmentListeners(); 1407 1408 this.set( 'attachment_id', this.attachment.get( 'id' ) ); 1409 this.set( 'caption', this.attachment.get( 'caption' ) ); 1410 this.set( 'alt', this.attachment.get( 'alt' ) ); 1411 this.set( 'size', props.get( 'size' ) ); 1412 this.set( 'align', props.get( 'align' ) ); 1413 this.set( 'link', props.get( 'link' ) ); 1414 this.updateLinkUrl(); 1415 this.updateSize(); 1416 }, 1417 1418 setLinkTypeFromUrl: function() { 1419 var linkUrl = this.get( 'linkUrl' ), 1420 type; 1421 1422 if ( ! linkUrl ) { 1423 this.set( 'link', 'none' ); 1424 return; 1425 } 1426 1427 // default to custom if there is a linkUrl 1428 type = 'custom'; 1429 1430 if ( this.attachment ) { 1431 if ( this.attachment.get( 'url' ) === linkUrl ) { 1432 type = 'file'; 1433 } else if ( this.attachment.get( 'link' ) === linkUrl ) { 1434 type = 'post'; 1435 } 1436 } else { 1437 if ( this.get( 'url' ) === linkUrl ) { 1438 type = 'file'; 1439 } 1440 } 1441 1442 this.set( 'link', type ); 1443 }, 1444 1445 updateLinkUrl: function() { 1446 var link = this.get( 'link' ), 1447 url; 1448 1449 switch( link ) { 1450 case 'file': 1451 if ( this.attachment ) { 1452 url = this.attachment.get( 'url' ); 1453 } else { 1454 url = this.get( 'url' ); 1455 } 1456 this.set( 'linkUrl', url ); 1457 break; 1458 case 'post': 1459 this.set( 'linkUrl', this.attachment.get( 'link' ) ); 1460 break; 1461 case 'none': 1462 this.set( 'linkUrl', '' ); 1463 break; 1464 } 1465 }, 1466 1467 updateSize: function() { 1468 var size; 1469 1470 if ( ! this.attachment ) { 1471 return; 1472 } 1473 1474 if ( this.get( 'size' ) === 'custom' ) { 1475 this.set( 'width', this.get( 'customWidth' ) ); 1476 this.set( 'height', this.get( 'customHeight' ) ); 1477 this.set( 'url', this.get( 'originalUrl' ) ); 1478 return; 1479 } 1480 1481 size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ]; 1482 1483 if ( ! size ) { 1484 return; 1485 } 1486 1487 this.set( 'url', size.url ); 1488 this.set( 'width', size.width ); 1489 this.set( 'height', size.height ); 1490 }, 1491 1492 setAspectRatio: function() { 1493 var full; 1494 1495 if ( this.attachment && this.attachment.get( 'sizes' ) ) { 1496 full = this.attachment.get( 'sizes' ).full; 1497 1498 if ( full ) { 1499 this.set( 'aspectRatio', full.width / full.height ); 1500 return; 1501 } 1502 } 1503 1504 this.set( 'aspectRatio', this.get( 'customWidth' ) / this.get( 'customHeight' ) ); 1505 } 1506 }); 1507 1508 module.exports = PostImage; 1509 1510 1511 /***/ }), 1512 1513 /***/ 25: 1514 /***/ (function(module, exports) { 1515 1422 1516 var Attachments = wp.media.model.Attachments, 1423 1517 Selection; 1424 1518 … … Selection = Attachments.extend(/** @lends wp.media.model.Selection.prototype */{ 1517 1611 1518 1612 module.exports = Selection; 1519 1613 1520 },{}]},{},[1]); 1614 1615 /***/ }) 1616 1617 /******/ }); 1618 No newline at end of file -
src/wp-includes/js/media-views.js
diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js index 18e6444691..2e462971e2 100644
1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 2 var Selection = wp.media.model.Selection, 3 Library = wp.media.controller.Library, 4 CollectionAdd; 1 /******/ (function(modules) { // webpackBootstrap 2 /******/ // The module cache 3 /******/ var installedModules = {}; 4 /******/ 5 /******/ // The require function 6 /******/ function __webpack_require__(moduleId) { 7 /******/ 8 /******/ // Check if module is in cache 9 /******/ if(installedModules[moduleId]) { 10 /******/ return installedModules[moduleId].exports; 11 /******/ } 12 /******/ // Create a new module (and put it into the cache) 13 /******/ var module = installedModules[moduleId] = { 14 /******/ i: moduleId, 15 /******/ l: false, 16 /******/ exports: {} 17 /******/ }; 18 /******/ 19 /******/ // Execute the module function 20 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 /******/ 22 /******/ // Flag the module as loaded 23 /******/ module.l = true; 24 /******/ 25 /******/ // Return the exports of the module 26 /******/ return module.exports; 27 /******/ } 28 /******/ 29 /******/ 30 /******/ // expose the modules object (__webpack_modules__) 31 /******/ __webpack_require__.m = modules; 32 /******/ 33 /******/ // expose the module cache 34 /******/ __webpack_require__.c = installedModules; 35 /******/ 36 /******/ // define getter function for harmony exports 37 /******/ __webpack_require__.d = function(exports, name, getter) { 38 /******/ if(!__webpack_require__.o(exports, name)) { 39 /******/ Object.defineProperty(exports, name, { 40 /******/ configurable: false, 41 /******/ enumerable: true, 42 /******/ get: getter 43 /******/ }); 44 /******/ } 45 /******/ }; 46 /******/ 47 /******/ // getDefaultExport function for compatibility with non-harmony modules 48 /******/ __webpack_require__.n = function(module) { 49 /******/ var getter = module && module.__esModule ? 50 /******/ function getDefault() { return module['default']; } : 51 /******/ function getModuleExports() { return module; }; 52 /******/ __webpack_require__.d(getter, 'a', getter); 53 /******/ return getter; 54 /******/ }; 55 /******/ 56 /******/ // Object.prototype.hasOwnProperty.call 57 /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 58 /******/ 59 /******/ // __webpack_public_path__ 60 /******/ __webpack_require__.p = ""; 61 /******/ 62 /******/ // Load entry module and return exports 63 /******/ return __webpack_require__(__webpack_require__.s = 26); 64 /******/ }) 65 /************************************************************************/ 66 /******/ (Array(26).concat([ 67 /* 26 */ 68 /***/ (function(module, exports, __webpack_require__) { 5 69 6 /** 7 * wp.media.controller.CollectionAdd 8 * 9 * A state for adding attachments to a collection (e.g. video playlist). 10 * 11 * @memberOf wp.media.controller 12 * 13 * @class 14 * @augments wp.media.controller.Library 15 * @augments wp.media.controller.State 16 * @augments Backbone.Model 17 * 18 * @param {object} [attributes] The attributes hash passed to the state. 19 * @param {string} [attributes.id=library] Unique identifier. 20 * @param {string} attributes.title Title for the state. Displays in the frame's title region. 21 * @param {boolean} [attributes.multiple=add] Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean. 22 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 23 * If one is not supplied, a collection of attachments of the specified type will be created. 24 * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown. 25 * Accepts 'all', 'uploaded', or 'unattached'. 26 * @param {string} [attributes.menu=gallery] Initial mode for the menu region. 27 * @param {string} [attributes.content=upload] Initial mode for the content region. 28 * Overridden by persistent user setting if 'contentUserSetting' is true. 29 * @param {string} [attributes.router=browse] Initial mode for the router region. 30 * @param {string} [attributes.toolbar=gallery-add] Initial mode for the toolbar region. 31 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 32 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 33 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 34 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 35 * @param {int} [attributes.priority=100] The priority for the state link in the media menu. 36 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 37 * Defaults to false because for this state, because the library of the Edit Gallery state is the selection. 38 * @param {string} attributes.type The collection's media type. (e.g. 'video'). 39 * @param {string} attributes.collectionType The collection type. (e.g. 'playlist'). 40 */ 41 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{ 42 defaults: _.defaults( { 43 // Selection defaults. @see media.model.Selection 44 multiple: 'add', 45 // Attachments browser defaults. @see media.view.AttachmentsBrowser 46 filterable: 'uploaded', 70 var media = wp.media, 71 $ = jQuery, 72 l10n; 47 73 48 priority: 100, 49 syncSelection: false 50 }, Library.prototype.defaults ), 74 media.isTouchDevice = ( 'ontouchend' in document ); 51 75 52 /** 53 * @since 3.9.0 54 */ 55 initialize: function() { 56 var collectionType = this.get('collectionType'); 76 // Link any localized strings. 77 l10n = media.view.l10n = window._wpMediaViewsL10n || {}; 57 78 58 if ( 'video' === this.get( 'type' ) ) { 59 collectionType = 'video-' + collectionType;60 } 79 // Link any settings. 80 media.view.settings = l10n.settings || {}; 81 delete l10n.settings; 61 82 62 this.set( 'id', collectionType + '-library' ); 63 this.set( 'toolbar', collectionType + '-add' ); 64 this.set( 'menu', collectionType ); 83 // Copy the `post` setting over to the model settings. 84 media.model.settings.post = media.view.settings.post; 65 85 66 // If we haven't been provided a `library`, create a `Selection`. 67 if ( ! this.get('library') ) { 68 this.set( 'library', wp.media.query({ type: this.get('type') }) ); 69 } 70 Library.prototype.initialize.apply( this, arguments ); 71 }, 86 // Check if the browser supports CSS 3.0 transitions 87 $.support.transition = (function(){ 88 var style = document.documentElement.style, 89 transitions = { 90 WebkitTransition: 'webkitTransitionEnd', 91 MozTransition: 'transitionend', 92 OTransition: 'oTransitionEnd otransitionend', 93 transition: 'transitionend' 94 }, transition; 72 95 73 /** 74 * @since 3.9.0 75 */ 76 activate: function() { 77 var library = this.get('library'), 78 editLibrary = this.get('editLibrary'), 79 edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library'); 96 transition = _.find( _.keys( transitions ), function( transition ) { 97 return ! _.isUndefined( style[ transition ] ); 98 }); 80 99 81 if ( editLibrary && editLibrary !== edit ) { 82 library.unobserve( editLibrary ); 100 return transition && { 101 end: transitions[ transition ] 102 }; 103 }()); 104 105 /** 106 * A shared event bus used to provide events into 107 * the media workflows that 3rd-party devs can use to hook 108 * in. 109 */ 110 media.events = _.extend( {}, Backbone.Events ); 111 112 /** 113 * Makes it easier to bind events using transitions. 114 * 115 * @param {string} selector 116 * @param {Number} sensitivity 117 * @returns {Promise} 118 */ 119 media.transition = function( selector, sensitivity ) { 120 var deferred = $.Deferred(); 121 122 sensitivity = sensitivity || 2000; 123 124 if ( $.support.transition ) { 125 if ( ! (selector instanceof $) ) { 126 selector = $( selector ); 83 127 } 84 128 85 // Accepts attachments that exist in the original library and 86 // that do not exist in gallery's library. 87 library.validator = function( attachment ) { 88 return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments ); 89 }; 129 // Resolve the deferred when the first element finishes animating. 130 selector.first().one( $.support.transition.end, deferred.resolve ); 90 131 91 // Reset the library to ensure that all attachments are re-added 92 // to the collection. Do so silently, as calling `observe` will 93 // trigger the `reset` event. 94 library.reset( library.mirroring.models, { silent: true }); 95 library.observe( edit ); 96 this.set('editLibrary', edit); 132 // Just in case the event doesn't trigger, fire a callback. 133 _.delay( deferred.resolve, sensitivity ); 97 134 98 Library.prototype.activate.apply( this, arguments ); 135 // Otherwise, execute on the spot. 136 } else { 137 deferred.resolve(); 99 138 } 100 });101 139 102 module.exports = CollectionAdd; 140 return deferred.promise(); 141 }; 103 142 104 },{}],2:[function(require,module,exports){ 105 var Library = wp.media.controller.Library, 106 l10n = wp.media.view.l10n, 107 $ = jQuery, 108 CollectionEdit; 143 media.controller.Region = __webpack_require__( 27 ); 144 media.controller.StateMachine = __webpack_require__( 28 ); 145 media.controller.State = __webpack_require__( 29 ); 146 147 media.selectionSync = __webpack_require__( 30 ); 148 media.controller.Library = __webpack_require__( 31 ); 149 media.controller.ImageDetails = __webpack_require__( 32 ); 150 media.controller.GalleryEdit = __webpack_require__( 33 ); 151 media.controller.GalleryAdd = __webpack_require__( 34 ); 152 media.controller.CollectionEdit = __webpack_require__( 35 ); 153 media.controller.CollectionAdd = __webpack_require__( 36 ); 154 media.controller.FeaturedImage = __webpack_require__( 37 ); 155 media.controller.ReplaceImage = __webpack_require__( 38 ); 156 media.controller.EditImage = __webpack_require__( 39 ); 157 media.controller.MediaLibrary = __webpack_require__( 40 ); 158 media.controller.Embed = __webpack_require__( 41 ); 159 media.controller.Cropper = __webpack_require__( 42 ); 160 media.controller.CustomizeImageCropper = __webpack_require__( 43 ); 161 media.controller.SiteIconCropper = __webpack_require__( 44 ); 162 163 media.View = __webpack_require__( 45 ); 164 media.view.Frame = __webpack_require__( 46 ); 165 media.view.MediaFrame = __webpack_require__( 47 ); 166 media.view.MediaFrame.Select = __webpack_require__( 48 ); 167 media.view.MediaFrame.Post = __webpack_require__( 49 ); 168 media.view.MediaFrame.ImageDetails = __webpack_require__( 50 ); 169 media.view.Modal = __webpack_require__( 51 ); 170 media.view.FocusManager = __webpack_require__( 52 ); 171 media.view.UploaderWindow = __webpack_require__( 53 ); 172 media.view.EditorUploader = __webpack_require__( 54 ); 173 media.view.UploaderInline = __webpack_require__( 55 ); 174 media.view.UploaderStatus = __webpack_require__( 56 ); 175 media.view.UploaderStatusError = __webpack_require__( 57 ); 176 media.view.Toolbar = __webpack_require__( 58 ); 177 media.view.Toolbar.Select = __webpack_require__( 59 ); 178 media.view.Toolbar.Embed = __webpack_require__( 60 ); 179 media.view.Button = __webpack_require__( 61 ); 180 media.view.ButtonGroup = __webpack_require__( 62 ); 181 media.view.PriorityList = __webpack_require__( 63 ); 182 media.view.MenuItem = __webpack_require__( 64 ); 183 media.view.Menu = __webpack_require__( 65 ); 184 media.view.RouterItem = __webpack_require__( 66 ); 185 media.view.Router = __webpack_require__( 67 ); 186 media.view.Sidebar = __webpack_require__( 68 ); 187 media.view.Attachment = __webpack_require__( 69 ); 188 media.view.Attachment.Library = __webpack_require__( 70 ); 189 media.view.Attachment.EditLibrary = __webpack_require__( 71 ); 190 media.view.Attachments = __webpack_require__( 72 ); 191 media.view.Search = __webpack_require__( 73 ); 192 media.view.AttachmentFilters = __webpack_require__( 74 ); 193 media.view.DateFilter = __webpack_require__( 75 ); 194 media.view.AttachmentFilters.Uploaded = __webpack_require__( 76 ); 195 media.view.AttachmentFilters.All = __webpack_require__( 77 ); 196 media.view.AttachmentsBrowser = __webpack_require__( 78 ); 197 media.view.Selection = __webpack_require__( 79 ); 198 media.view.Attachment.Selection = __webpack_require__( 80 ); 199 media.view.Attachments.Selection = __webpack_require__( 81 ); 200 media.view.Attachment.EditSelection = __webpack_require__( 82 ); 201 media.view.Settings = __webpack_require__( 83 ); 202 media.view.Settings.AttachmentDisplay = __webpack_require__( 84 ); 203 media.view.Settings.Gallery = __webpack_require__( 85 ); 204 media.view.Settings.Playlist = __webpack_require__( 86 ); 205 media.view.Attachment.Details = __webpack_require__( 87 ); 206 media.view.AttachmentCompat = __webpack_require__( 88 ); 207 media.view.Iframe = __webpack_require__( 89 ); 208 media.view.Embed = __webpack_require__( 90 ); 209 media.view.Label = __webpack_require__( 91 ); 210 media.view.EmbedUrl = __webpack_require__( 92 ); 211 media.view.EmbedLink = __webpack_require__( 93 ); 212 media.view.EmbedImage = __webpack_require__( 94 ); 213 media.view.ImageDetails = __webpack_require__( 95 ); 214 media.view.Cropper = __webpack_require__( 96 ); 215 media.view.SiteIconCropper = __webpack_require__( 97 ); 216 media.view.SiteIconPreview = __webpack_require__( 98 ); 217 media.view.EditImage = __webpack_require__( 99 ); 218 media.view.Spinner = __webpack_require__( 100 ); 219 220 221 /***/ }), 222 /* 27 */ 223 /***/ (function(module, exports) { 109 224 110 225 /** 111 * wp.media.controller. CollectionEdit226 * wp.media.controller.Region 112 227 * 113 * A state for editing a collection, which is used by audio and video playlists, 114 * and can be used for other collections. 228 * A region is a persistent application layout area. 229 * 230 * A region assumes one mode at any time, and can be switched to another. 231 * 232 * When mode changes, events are triggered on the region's parent view. 233 * The parent view will listen to specific events and fill the region with an 234 * appropriate view depending on mode. For example, a frame listens for the 235 * 'browse' mode t be activated on the 'content' view and then fills the region 236 * with an AttachmentsBrowser view. 115 237 * 116 238 * @memberOf wp.media.controller 117 239 * 118 240 * @class 119 * @augments wp.media.controller.Library120 * @augments wp.media.controller.State121 * @augments Backbone.Model122 241 * 123 * @param {object} [attributes] The attributes hash passed to the state. 124 * @param {string} attributes.title Title for the state. Displays in the media menu and the frame's title region. 125 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to edit. 126 * If one is not supplied, an empty media.model.Selection collection is created. 127 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 128 * @param {string} [attributes.content=browse] Initial mode for the content region. 129 * @param {string} attributes.menu Initial mode for the menu region. @todo this needs a better explanation. 130 * @param {boolean} [attributes.searchable=false] Whether the library is searchable. 131 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 132 * @param {boolean} [attributes.date=true] Whether to show the date filter in the browser's toolbar. 133 * @param {boolean} [attributes.describe=true] Whether to offer UI to describe the attachments - e.g. captioning images in a gallery. 134 * @param {boolean} [attributes.dragInfo=true] Whether to show instructional text about the attachments being sortable. 135 * @param {boolean} [attributes.dragInfoText] Instructional text about the attachments being sortable. 136 * @param {int} [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments. 137 * @param {boolean} [attributes.editing=false] Whether the gallery is being created, or editing an existing instance. 138 * @param {int} [attributes.priority=60] The priority for the state link in the media menu. 139 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 140 * Defaults to false for this state, because the library passed in *is* the selection. 141 * @param {view} [attributes.SettingsView] The view to edit the collection instance settings (e.g. Playlist settings with "Show tracklist" checkbox). 142 * @param {view} [attributes.AttachmentView] The single `Attachment` view to be used in the `Attachments`. 143 * If none supplied, defaults to wp.media.view.Attachment.EditLibrary. 144 * @param {string} attributes.type The collection's media type. (e.g. 'video'). 145 * @param {string} attributes.collectionType The collection type. (e.g. 'playlist'). 242 * @param {object} options Options hash for the region. 243 * @param {string} options.id Unique identifier for the region. 244 * @param {Backbone.View} options.view A parent view the region exists within. 245 * @param {string} options.selector jQuery selector for the region within the parent view. 146 246 */ 147 CollectionEdit = Library.extend(/** @lends wp.media.controller.CollectionEdit.prototype */{ 148 defaults: { 149 multiple: false, 150 sortable: true, 151 date: false, 152 searchable: false, 153 content: 'browse', 154 describe: true, 155 dragInfo: true, 156 idealColumnWidth: 170, 157 editing: false, 158 priority: 60, 159 SettingsView: false, 160 syncSelection: false 161 }, 247 var Region = function( options ) { 248 _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) ); 249 }; 250 251 // Use Backbone's self-propagating `extend` inheritance method. 252 Region.extend = Backbone.Model.extend; 162 253 254 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{ 163 255 /** 164 * @since 3.9.0 256 * Activate a mode. 257 * 258 * @since 3.5.0 259 * 260 * @param {string} mode 261 * 262 * @fires Region#activate 263 * @fires Region#deactivate 264 * 265 * @returns {wp.media.controller.Region} Returns itself to allow chaining. 165 266 */ 166 initialize: function() { 167 var collectionType = this.get('collectionType'); 168 169 if ( 'video' === this.get( 'type' ) ) { 170 collectionType = 'video-' + collectionType; 171 } 172 173 this.set( 'id', collectionType + '-edit' ); 174 this.set( 'toolbar', collectionType + '-edit' ); 175 176 // If we haven't been provided a `library`, create a `Selection`. 177 if ( ! this.get('library') ) { 178 this.set( 'library', new wp.media.model.Selection() ); 267 mode: function( mode ) { 268 if ( ! mode ) { 269 return this._mode; 179 270 } 180 // The single `Attachment` view to be used in the `Attachments` view.181 if ( ! this.get('AttachmentView')) {182 this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );271 // Bail if we're trying to change to the current mode. 272 if ( mode === this._mode ) { 273 return this; 183 274 } 184 Library.prototype.initialize.apply( this, arguments );185 },186 187 /**188 * @since 3.9.0189 */190 activate: function() {191 var library = this.get('library');192 275 193 // Limit the library to images only. 194 library.props.set( 'type', this.get( 'type' ) ); 195 196 // Watch for uploaded attachments. 197 this.get('library').observe( wp.Uploader.queue ); 276 /** 277 * Region mode deactivation event. 278 * 279 * @event wp.media.controller.Region#deactivate 280 */ 281 this.trigger('deactivate'); 198 282 199 this.frame.on( 'content:render:browse', this.renderSettings, this ); 283 this._mode = mode; 284 this.render( mode ); 200 285 201 Library.prototype.activate.apply( this, arguments ); 286 /** 287 * Region mode activation event. 288 * 289 * @event wp.media.controller.Region#activate 290 */ 291 this.trigger('activate'); 292 return this; 202 293 }, 203 204 294 /** 205 * @since 3.9.0 295 * Render a mode. 296 * 297 * @since 3.5.0 298 * 299 * @param {string} mode 300 * 301 * @fires Region#create 302 * @fires Region#render 303 * 304 * @returns {wp.media.controller.Region} Returns itself to allow chaining 206 305 */ 207 deactivate: function() { 208 // Stop watching for uploaded attachments. 209 this.get('library').unobserve( wp.Uploader.queue ); 306 render: function( mode ) { 307 // If the mode isn't active, activate it. 308 if ( mode && mode !== this._mode ) { 309 return this.mode( mode ); 310 } 210 311 211 this.frame.off( 'content:render:browse', this.renderSettings, this ); 312 var set = { view: null }, 313 view; 212 314 213 Library.prototype.deactivate.apply( this, arguments ); 315 /** 316 * Create region view event. 317 * 318 * Region view creation takes place in an event callback on the frame. 319 * 320 * @event wp.media.controller.Region#create 321 * @type {object} 322 * @property {object} view 323 */ 324 this.trigger( 'create', set ); 325 view = set.view; 326 327 /** 328 * Render region view event. 329 * 330 * Region view creation takes place in an event callback on the frame. 331 * 332 * @event wp.media.controller.Region#render 333 * @type {object} 334 */ 335 this.trigger( 'render', view ); 336 if ( view ) { 337 this.set( view ); 338 } 339 return this; 214 340 }, 215 341 216 342 /** 217 * Render the collection embed settings view in the browser sidebar. 218 * 219 * @todo This is against the pattern elsewhere in media. Typically the frame 220 * is responsible for adding region mode callbacks. Explain. 343 * Get the region's view. 221 344 * 222 * @since 3. 9.0345 * @since 3.5.0 223 346 * 224 * @ param {wp.media.view.attachmentsBrowser} The attachments browser view.347 * @returns {wp.media.View} 225 348 */ 226 renderSettings: function( attachmentsBrowserView ) { 227 var library = this.get('library'), 228 collectionType = this.get('collectionType'), 229 dragInfoText = this.get('dragInfoText'), 230 SettingsView = this.get('SettingsView'), 231 obj = {}; 349 get: function() { 350 return this.view.views.first( this.selector ); 351 }, 232 352 233 if ( ! library || ! attachmentsBrowserView ) { 234 return; 353 /** 354 * Set the region's view as a subview of the frame. 355 * 356 * @since 3.5.0 357 * 358 * @param {Array|Object} views 359 * @param {Object} [options={}] 360 * @returns {wp.Backbone.Subviews} Subviews is returned to allow chaining 361 */ 362 set: function( views, options ) { 363 if ( options ) { 364 options.add = false; 235 365 } 366 return this.view.views.set( this.selector, views, options ); 367 }, 236 368 237 library[ collectionType ] = library[ collectionType ] || new Backbone.Model(); 238 239 obj[ collectionType ] = new SettingsView({ 240 controller: this, 241 model: library[ collectionType ], 242 priority: 40 243 }); 244 245 attachmentsBrowserView.sidebar.set( obj ); 369 /** 370 * Trigger regional view events on the frame. 371 * 372 * @since 3.5.0 373 * 374 * @param {string} event 375 * @returns {undefined|wp.media.controller.Region} Returns itself to allow chaining. 376 */ 377 trigger: function( event ) { 378 var base, args; 246 379 247 if ( dragInfoText ) { 248 attachmentsBrowserView.toolbar.set( 'dragInfo', new wp.media.View({ 249 el: $( '<div class="instructions">' + dragInfoText + '</div>' )[0], 250 priority: -40 251 }) ); 380 if ( ! this._mode ) { 381 return; 252 382 } 253 383 254 // Add the 'Reverse order' button to the toolbar. 255 attachmentsBrowserView.toolbar.set( 'reverse', { 256 text: l10n.reverseOrder, 257 priority: 80, 384 args = _.toArray( arguments ); 385 base = this.id + ':' + event; 258 386 259 click: function() { 260 library.reset( library.toArray().reverse() ); 261 } 262 }); 387 // Trigger `{this.id}:{event}:{this._mode}` event on the frame. 388 args[0] = base + ':' + this._mode; 389 this.view.trigger.apply( this.view, args ); 390 391 // Trigger `{this.id}:{event}` event on the frame. 392 args[0] = base; 393 this.view.trigger.apply( this.view, args ); 394 return this; 263 395 } 264 396 }); 265 397 266 module.exports = CollectionEdit;398 module.exports = Region; 267 399 268 },{}],3:[function(require,module,exports){ 269 var l10n = wp.media.view.l10n, 270 Cropper; 400 401 /***/ }), 402 /* 28 */ 403 /***/ (function(module, exports) { 271 404 272 405 /** 273 * wp.media.controller. Cropper406 * wp.media.controller.StateMachine 274 407 * 275 * A state for cropping an image. 408 * A state machine keeps track of state. It is in one state at a time, 409 * and can change from one state to another. 410 * 411 * States are stored as models in a Backbone collection. 276 412 * 277 413 * @memberOf wp.media.controller 278 414 * 415 * @since 3.5.0 416 * 279 417 * @class 280 * @augments wp.media.controller.State281 418 * @augments Backbone.Model 419 * @mixin 420 * @mixes Backbone.Events 421 * 422 * @param {Array} states 282 423 */ 283 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{ 284 defaults: { 285 id: 'cropper', 286 title: l10n.cropImage, 287 // Region mode defaults. 288 toolbar: 'crop', 289 content: 'crop', 290 router: false, 291 canSkipCrop: false, 292 293 // Default doCrop Ajax arguments to allow the Customizer (for example) to inject state. 294 doCropArgs: {} 295 }, 424 var StateMachine = function( states ) { 425 // @todo This is dead code. The states collection gets created in media.view.Frame._createStates. 426 this.states = new Backbone.Collection( states ); 427 }; 296 428 297 activate: function() { 298 this.frame.on( 'content:create:crop', this.createCropContent, this ); 299 this.frame.on( 'close', this.removeCropper, this ); 300 this.set('selection', new Backbone.Collection(this.frame._selection.single)); 301 }, 429 // Use Backbone's self-propagating `extend` inheritance method. 430 StateMachine.extend = Backbone.Model.extend; 302 431 303 deactivate: function() { 304 this.frame.toolbar.mode('browse'); 305 }, 432 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{ 433 /** 434 * Fetch a state. 435 * 436 * If no `id` is provided, returns the active state. 437 * 438 * Implicitly creates states. 439 * 440 * Ensure that the `states` collection exists so the `StateMachine` 441 * can be used as a mixin. 442 * 443 * @since 3.5.0 444 * 445 * @param {string} id 446 * @returns {wp.media.controller.State} Returns a State model 447 * from the StateMachine collection 448 */ 449 state: function( id ) { 450 this.states = this.states || new Backbone.Collection(); 306 451 307 createCropContent: function() { 308 this.cropperView = new wp.media.view.Cropper({ 309 controller: this, 310 attachment: this.get('selection').first() 311 }); 312 this.cropperView.on('image-loaded', this.createCropToolbar, this); 313 this.frame.content.set(this.cropperView); 452 // Default to the active state. 453 id = id || this._state; 314 454 455 if ( id && ! this.states.get( id ) ) { 456 this.states.add({ id: id }); 457 } 458 return this.states.get( id ); 315 459 }, 316 removeCropper: function() {317 this.imgSelect.cancelSelection();318 this.imgSelect.setOptions({remove: true});319 this.imgSelect.update();320 this.cropperView.remove();321 },322 createCropToolbar: function() {323 var canSkipCrop, toolbarOptions;324 460 325 canSkipCrop = this.get('canSkipCrop') || false; 461 /** 462 * Sets the active state. 463 * 464 * Bail if we're trying to select the current state, if we haven't 465 * created the `states` collection, or are trying to select a state 466 * that does not exist. 467 * 468 * @since 3.5.0 469 * 470 * @param {string} id 471 * 472 * @fires wp.media.controller.State#deactivate 473 * @fires wp.media.controller.State#activate 474 * 475 * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining 476 */ 477 setState: function( id ) { 478 var previous = this.state(); 326 479 327 toolbarOptions = { 328 controller: this.frame, 329 items: { 330 insert: { 331 style: 'primary', 332 text: l10n.cropImage, 333 priority: 80, 334 requires: { library: false, selection: false }, 335 336 click: function() { 337 var controller = this.controller, 338 selection; 339 340 selection = controller.state().get('selection').first(); 341 selection.set({cropDetails: controller.state().imgSelect.getSelection()}); 342 343 this.$el.text(l10n.cropping); 344 this.$el.attr('disabled', true); 345 346 controller.state().doCrop( selection ).done( function( croppedImage ) { 347 controller.trigger('cropped', croppedImage ); 348 controller.close(); 349 }).fail( function() { 350 controller.trigger('content:error:crop'); 351 }); 352 } 353 } 354 } 355 }; 480 if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) { 481 return this; 482 } 356 483 357 if ( canSkipCrop ) { 358 _.extend( toolbarOptions.items, { 359 skip: { 360 style: 'secondary', 361 text: l10n.skipCropping, 362 priority: 70, 363 requires: { library: false, selection: false }, 364 click: function() { 365 var selection = this.controller.state().get('selection').first(); 366 this.controller.state().cropperView.remove(); 367 this.controller.trigger('skippedcrop', selection); 368 this.controller.close(); 369 } 370 } 371 }); 484 if ( previous ) { 485 previous.trigger('deactivate'); 486 this._lastState = previous.id; 372 487 } 373 488 374 this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) ); 489 this._state = id; 490 this.state().trigger('activate'); 491 492 return this; 375 493 }, 376 494 377 doCrop: function( attachment ) { 378 return wp.ajax.post( 'custom-header-crop', _.extend( 379 {}, 380 this.defaults.doCropArgs, 381 { 382 nonce: attachment.get( 'nonces' ).edit, 383 id: attachment.get( 'id' ), 384 cropDetails: attachment.get( 'cropDetails' ) 385 } 386 ) ); 495 /** 496 * Returns the previous active state. 497 * 498 * Call the `state()` method with no parameters to retrieve the current 499 * active state. 500 * 501 * @since 3.5.0 502 * 503 * @returns {wp.media.controller.State} Returns a State model 504 * from the StateMachine collection 505 */ 506 lastState: function() { 507 if ( this._lastState ) { 508 return this.state( this._lastState ); 509 } 387 510 } 388 511 }); 389 512 390 module.exports = Cropper; 391 392 },{}],4:[function(require,module,exports){ 393 var Controller = wp.media.controller, 394 CustomizeImageCropper; 395 396 /** 397 * wp.media.controller.CustomizeImageCropper 398 * 399 * @memberOf wp.media.controller 400 * 401 * A state for cropping an image. 402 * 403 * @class 404 * @augments wp.media.controller.Cropper 405 * @augments wp.media.controller.State 406 * @augments Backbone.Model 407 */ 408 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{ 409 doCrop: function( attachment ) { 410 var cropDetails = attachment.get( 'cropDetails' ), 411 control = this.get( 'control' ), 412 ratio = cropDetails.width / cropDetails.height; 413 414 // Use crop measurements when flexible in both directions. 415 if ( control.params.flex_width && control.params.flex_height ) { 416 cropDetails.dst_width = cropDetails.width; 417 cropDetails.dst_height = cropDetails.height; 418 419 // Constrain flexible side based on image ratio and size of the fixed side. 420 } else { 421 cropDetails.dst_width = control.params.flex_width ? control.params.height * ratio : control.params.width; 422 cropDetails.dst_height = control.params.flex_height ? control.params.width / ratio : control.params.height; 423 } 424 425 return wp.ajax.post( 'crop-image', { 426 wp_customize: 'on', 427 nonce: attachment.get( 'nonces' ).edit, 428 id: attachment.get( 'id' ), 429 context: control.id, 430 cropDetails: cropDetails 431 } ); 432 } 513 // Map all event binding and triggering on a StateMachine to its `states` collection. 514 _.each([ 'on', 'off', 'trigger' ], function( method ) { 515 /** 516 * @function on 517 * @memberOf wp.media.controller.StateMachine 518 * @instance 519 * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. 520 */ 521 /** 522 * @function off 523 * @memberOf wp.media.controller.StateMachine 524 * @instance 525 * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. 526 */ 527 /** 528 * @function trigger 529 * @memberOf wp.media.controller.StateMachine 530 * @instance 531 * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining. 532 */ 533 StateMachine.prototype[ method ] = function() { 534 // Ensure that the `states` collection exists so the `StateMachine` 535 // can be used as a mixin. 536 this.states = this.states || new Backbone.Collection(); 537 // Forward the method to the `states` collection. 538 this.states[ method ].apply( this.states, arguments ); 539 return this; 540 }; 433 541 }); 434 542 435 module.exports = CustomizeImageCropper;543 module.exports = StateMachine; 436 544 437 },{}],5:[function(require,module,exports){ 438 var l10n = wp.media.view.l10n, 439 EditImage; 545 546 /***/ }), 547 /* 29 */ 548 /***/ (function(module, exports) { 440 549 441 550 /** 442 * wp.media.controller. EditImage551 * wp.media.controller.State 443 552 * 444 * A state for editing (cropping, etc.) an image. 553 * A state is a step in a workflow that when set will trigger the controllers 554 * for the regions to be updated as specified in the frame. 555 * 556 * A state has an event-driven lifecycle: 557 * 558 * 'ready' triggers when a state is added to a state machine's collection. 559 * 'activate' triggers when a state is activated by a state machine. 560 * 'deactivate' triggers when a state is deactivated by a state machine. 561 * 'reset' is not triggered automatically. It should be invoked by the 562 * proper controller to reset the state to its default. 445 563 * 446 564 * @memberOf wp.media.controller 447 565 * 448 566 * @class 449 * @augments wp.media.controller.State450 567 * @augments Backbone.Model 451 *452 * @param {object} attributes The attributes hash passed to the state.453 * @param {wp.media.model.Attachment} attributes.model The attachment.454 * @param {string} [attributes.id=edit-image] Unique identifier.455 * @param {string} [attributes.title=Edit Image] Title for the state. Displays in the media menu and the frame's title region.456 * @param {string} [attributes.content=edit-image] Initial mode for the content region.457 * @param {string} [attributes.toolbar=edit-image] Initial mode for the toolbar region.458 * @param {string} [attributes.menu=false] Initial mode for the menu region.459 * @param {string} [attributes.url] Unused. @todo Consider removal.460 568 */ 461 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{ 462 defaults: { 463 id: 'edit-image', 464 title: l10n.editImage, 465 menu: false, 466 toolbar: 'edit-image', 467 content: 'edit-image', 468 url: '' 569 var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{ 570 /** 571 * Constructor. 572 * 573 * @since 3.5.0 574 */ 575 constructor: function() { 576 this.on( 'activate', this._preActivate, this ); 577 this.on( 'activate', this.activate, this ); 578 this.on( 'activate', this._postActivate, this ); 579 this.on( 'deactivate', this._deactivate, this ); 580 this.on( 'deactivate', this.deactivate, this ); 581 this.on( 'reset', this.reset, this ); 582 this.on( 'ready', this._ready, this ); 583 this.on( 'ready', this.ready, this ); 584 /** 585 * Call parent constructor with passed arguments 586 */ 587 Backbone.Model.apply( this, arguments ); 588 this.on( 'change:menu', this._updateMenu, this ); 469 589 }, 590 /** 591 * Ready event callback. 592 * 593 * @abstract 594 * @since 3.5.0 595 */ 596 ready: function() {}, 470 597 471 598 /** 472 * @since 3.9.0 599 * Activate event callback. 600 * 601 * @abstract 602 * @since 3.5.0 473 603 */ 474 activate: function() { 475 this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) ); 476 }, 604 activate: function() {}, 477 605 478 606 /** 479 * @since 3.9.0 607 * Deactivate event callback. 608 * 609 * @abstract 610 * @since 3.5.0 480 611 */ 481 deactivate: function() { 482 this.frame.off( 'toolbar:render:edit-image' ); 483 }, 612 deactivate: function() {}, 484 613 485 614 /** 486 * @since 3.9.0 615 * Reset event callback. 616 * 617 * @abstract 618 * @since 3.5.0 487 619 */ 488 toolbar: function() { 489 var frame = this.frame, 490 lastState = frame.lastState(), 491 previous = lastState && lastState.id; 620 reset: function() {}, 492 621 493 frame.toolbar.set( new wp.media.view.Toolbar({ 494 controller: frame, 495 items: { 496 back: { 497 style: 'primary', 498 text: l10n.back, 499 priority: 20, 500 click: function() { 501 if ( previous ) { 502 frame.setState( previous ); 503 } else { 504 frame.close(); 505 } 506 } 507 } 508 } 509 }) ); 510 } 511 }); 622 /** 623 * @access private 624 * @since 3.5.0 625 */ 626 _ready: function() { 627 this._updateMenu(); 628 }, 512 629 513 module.exports = EditImage; 630 /** 631 * @access private 632 * @since 3.5.0 633 */ 634 _preActivate: function() { 635 this.active = true; 636 }, 514 637 515 },{}],6:[function(require,module,exports){ 516 var l10n = wp.media.view.l10n, 517 $ = Backbone.$, 518 Embed; 638 /** 639 * @access private 640 * @since 3.5.0 641 */ 642 _postActivate: function() { 643 this.on( 'change:menu', this._menu, this ); 644 this.on( 'change:titleMode', this._title, this ); 645 this.on( 'change:content', this._content, this ); 646 this.on( 'change:toolbar', this._toolbar, this ); 519 647 520 /** 521 * wp.media.controller.Embed 522 * 523 * A state for embedding media from a URL. 524 * 525 * @memberOf wp.media.controller 526 * 527 * @class 528 * @augments wp.media.controller.State 529 * @augments Backbone.Model 530 * 531 * @param {object} attributes The attributes hash passed to the state. 532 * @param {string} [attributes.id=embed] Unique identifier. 533 * @param {string} [attributes.title=Insert From URL] Title for the state. Displays in the media menu and the frame's title region. 534 * @param {string} [attributes.content=embed] Initial mode for the content region. 535 * @param {string} [attributes.menu=default] Initial mode for the menu region. 536 * @param {string} [attributes.toolbar=main-embed] Initial mode for the toolbar region. 537 * @param {string} [attributes.menu=false] Initial mode for the menu region. 538 * @param {int} [attributes.priority=120] The priority for the state link in the media menu. 539 * @param {string} [attributes.type=link] The type of embed. Currently only link is supported. 540 * @param {string} [attributes.url] The embed URL. 541 * @param {object} [attributes.metadata={}] Properties of the embed, which will override attributes.url if set. 542 */ 543 Embed = wp.media.controller.State.extend(/** @lends wp.media.controller.Embed.prototype */{ 544 defaults: { 545 id: 'embed', 546 title: l10n.insertFromUrlTitle, 547 content: 'embed', 548 menu: 'default', 549 toolbar: 'main-embed', 550 priority: 120, 551 type: 'link', 552 url: '', 553 metadata: {} 648 this.frame.on( 'title:render:default', this._renderTitle, this ); 649 650 this._title(); 651 this._menu(); 652 this._toolbar(); 653 this._content(); 654 this._router(); 554 655 }, 555 656 556 // The amount of time used when debouncing the scan. 557 sensitivity: 400, 657 /** 658 * @access private 659 * @since 3.5.0 660 */ 661 _deactivate: function() { 662 this.active = false; 558 663 559 initialize: function(options) { 560 this.metadata = options.metadata; 561 this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity ); 562 this.props = new Backbone.Model( this.metadata || { url: '' }); 563 this.props.on( 'change:url', this.debouncedScan, this ); 564 this.props.on( 'change:url', this.refresh, this ); 565 this.on( 'scan', this.scanImage, this ); 664 this.frame.off( 'title:render:default', this._renderTitle, this ); 665 666 this.off( 'change:menu', this._menu, this ); 667 this.off( 'change:titleMode', this._title, this ); 668 this.off( 'change:content', this._content, this ); 669 this.off( 'change:toolbar', this._toolbar, this ); 566 670 }, 567 671 568 672 /** 569 * Trigger a scan of the embedded URL's content for metadata required to embed. 570 * 571 * @fires wp.media.controller.Embed#scan 673 * @access private 674 * @since 3.5.0 572 675 */ 573 scan: function() { 574 var scanners, 575 embed = this, 576 attributes = { 577 type: 'link', 578 scanners: [] 579 }; 676 _title: function() { 677 this.frame.title.render( this.get('titleMode') || 'default' ); 678 }, 580 679 581 // Scan is triggered with the list of `attributes` to set on the 582 // state, useful for the 'type' attribute and 'scanners' attribute, 583 // an array of promise objects for asynchronous scan operations. 584 if ( this.props.get('url') ) { 585 this.trigger( 'scan', attributes ); 586 } 680 /** 681 * @access private 682 * @since 3.5.0 683 */ 684 _renderTitle: function( view ) { 685 view.$el.text( this.get('title') || '' ); 686 }, 587 687 588 if ( attributes.scanners.length ) { 589 scanners = attributes.scanners = $.when.apply( $, attributes.scanners ); 590 scanners.always( function() { 591 if ( embed.get('scanners') === scanners ) { 592 embed.set( 'loading', false ); 593 } 594 }); 595 } else { 596 attributes.scanners = null; 688 /** 689 * @access private 690 * @since 3.5.0 691 */ 692 _router: function() { 693 var router = this.frame.router, 694 mode = this.get('router'), 695 view; 696 697 this.frame.$el.toggleClass( 'hide-router', ! mode ); 698 if ( ! mode ) { 699 return; 597 700 } 598 701 599 attributes.loading = !! attributes.scanners; 600 this.set( attributes ); 702 this.frame.router.render( mode ); 703 704 view = router.get(); 705 if ( view && view.select ) { 706 view.select( this.frame.content.mode() ); 707 } 601 708 }, 709 602 710 /** 603 * Try scanning the embed as an image to discover its dimensions. 604 * 605 * @param {Object} attributes 711 * @access private 712 * @since 3.5.0 606 713 */ 607 scanImage: function( attributes ) { 608 var frame = this.frame, 609 state = this, 610 url = this.props.get('url'), 611 image = new Image(), 612 deferred = $.Deferred(); 714 _menu: function() { 715 var menu = this.frame.menu, 716 mode = this.get('menu'), 717 view; 613 718 614 attributes.scanners.push( deferred.promise() ); 719 this.frame.$el.toggleClass( 'hide-menu', ! mode ); 720 if ( ! mode ) { 721 return; 722 } 615 723 616 // Try to load the image and find its width/height. 617 image.onload = function() { 618 deferred.resolve(); 724 menu.mode( mode ); 619 725 620 if ( state !== frame.state() || url !== state.props.get('url') ) { 621 return; 622 } 726 view = menu.get(); 727 if ( view && view.select ) { 728 view.select( this.id ); 729 } 730 }, 623 731 624 state.set({ 625 type: 'image' 626 }); 732 /** 733 * @access private 734 * @since 3.5.0 735 */ 736 _updateMenu: function() { 737 var previous = this.previous('menu'), 738 menu = this.get('menu'); 627 739 628 state.props.set({ 629 width: image.width, 630 height: image.height 631 }); 632 }; 740 if ( previous ) { 741 this.frame.off( 'menu:render:' + previous, this._renderMenu, this ); 742 } 633 743 634 image.onerror = deferred.reject; 635 image.src = url; 744 if ( menu ) { 745 this.frame.on( 'menu:render:' + menu, this._renderMenu, this ); 746 } 636 747 }, 637 748 638 refresh: function() { 639 this.frame.toolbar.get().refresh(); 640 }, 749 /** 750 * Create a view in the media menu for the state. 751 * 752 * @access private 753 * @since 3.5.0 754 * 755 * @param {media.view.Menu} view The menu view. 756 */ 757 _renderMenu: function( view ) { 758 var menuItem = this.get('menuItem'), 759 title = this.get('title'), 760 priority = this.get('priority'); 641 761 642 reset: function() {643 this.props.clear().set({ url: '' });762 if ( ! menuItem && title ) { 763 menuItem = { text: title }; 644 764 645 if ( this.active ) { 646 this.refresh(); 765 if ( priority ) { 766 menuItem.priority = priority; 767 } 768 } 769 770 if ( ! menuItem ) { 771 return; 647 772 } 773 774 view.set( this.id, menuItem ); 648 775 } 649 776 }); 650 777 651 module.exports = Embed; 778 _.each(['toolbar','content'], function( region ) { 779 /** 780 * @access private 781 */ 782 State.prototype[ '_' + region ] = function() { 783 var mode = this.get( region ); 784 if ( mode ) { 785 this.frame[ region ].render( mode ); 786 } 787 }; 788 }); 789 790 module.exports = State; 652 791 653 },{}],7:[function(require,module,exports){ 654 var Attachment = wp.media.model.Attachment, 655 Library = wp.media.controller.Library, 656 l10n = wp.media.view.l10n, 657 FeaturedImage; 792 793 /***/ }), 794 /* 30 */ 795 /***/ (function(module, exports) { 658 796 659 797 /** 660 * wp.media. controller.FeaturedImage798 * wp.media.selectionSync 661 799 * 662 * A state for selecting a featured image for a post.800 * Sync an attachments selection in a state with another state. 663 801 * 664 * @memberOf wp.media.controller 802 * Allows for selecting multiple images in the Add Media workflow, and then 803 * switching to the Insert Gallery workflow while preserving the attachments selection. 665 804 * 666 * @class 667 * @augments wp.media.controller.Library 668 * @augments wp.media.controller.State 669 * @augments Backbone.Model 805 * @memberOf wp.media 670 806 * 671 * @param {object} [attributes] The attributes hash passed to the state. 672 * @param {string} [attributes.id=featured-image] Unique identifier. 673 * @param {string} [attributes.title=Set Featured Image] Title for the state. Displays in the media menu and the frame's title region. 674 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 675 * If one is not supplied, a collection of all images will be created. 676 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 677 * @param {string} [attributes.content=upload] Initial mode for the content region. 678 * Overridden by persistent user setting if 'contentUserSetting' is true. 679 * @param {string} [attributes.menu=default] Initial mode for the menu region. 680 * @param {string} [attributes.router=browse] Initial mode for the router region. 681 * @param {string} [attributes.toolbar=featured-image] Initial mode for the toolbar region. 682 * @param {int} [attributes.priority=60] The priority for the state link in the media menu. 683 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 684 * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown. 685 * Accepts 'all', 'uploaded', or 'unattached'. 686 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 687 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 688 * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. 689 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 690 * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state. 807 * @mixin 691 808 */ 692 FeaturedImage = Library.extend(/** @lends wp.media.controller.FeaturedImage.prototype */{ 693 defaults: _.defaults({ 694 id: 'featured-image', 695 title: l10n.setFeaturedImageTitle, 696 multiple: false, 697 filterable: 'uploaded', 698 toolbar: 'featured-image', 699 priority: 60, 700 syncSelection: true 701 }, Library.prototype.defaults ), 702 809 var selectionSync = { 703 810 /** 704 811 * @since 3.5.0 705 812 */ 706 initialize: function() { 707 var library, comparator; 813 syncSelection: function() { 814 var selection = this.get('selection'), 815 manager = this.frame._selection; 708 816 709 // If we haven't been provided a `library`, create a `Selection`. 710 if ( ! this.get('library') ) { 711 this.set( 'library', wp.media.query({ type: 'image' }) ); 817 if ( ! this.get('syncSelection') || ! manager || ! selection ) { 818 return; 712 819 } 713 820 714 Library.prototype.initialize.apply( this, arguments ); 715 716 library = this.get('library'); 717 comparator = library.comparator; 718 719 // Overload the library's comparator to push items that are not in 720 // the mirrored query to the front of the aggregate collection. 721 library.comparator = function( a, b ) { 722 var aInQuery = !! this.mirroring.get( a.cid ), 723 bInQuery = !! this.mirroring.get( b.cid ); 724 725 if ( ! aInQuery && bInQuery ) { 726 return -1; 727 } else if ( aInQuery && ! bInQuery ) { 728 return 1; 729 } else { 730 return comparator.apply( this, arguments ); 731 } 732 }; 733 734 // Add all items in the selection to the library, so any featured 735 // images that are not initially loaded still appear. 736 library.observe( this.get('selection') ); 737 }, 738 739 /** 740 * @since 3.5.0 741 */ 742 activate: function() { 743 this.updateSelection(); 744 this.frame.on( 'open', this.updateSelection, this ); 745 746 Library.prototype.activate.apply( this, arguments ); 747 }, 748 749 /** 750 * @since 3.5.0 751 */ 752 deactivate: function() { 753 this.frame.off( 'open', this.updateSelection, this ); 821 // If the selection supports multiple items, validate the stored 822 // attachments based on the new selection's conditions. Record 823 // the attachments that are not included; we'll maintain a 824 // reference to those. Other attachments are considered in flux. 825 if ( selection.multiple ) { 826 selection.reset( [], { silent: true }); 827 selection.validateAll( manager.attachments ); 828 manager.difference = _.difference( manager.attachments.models, selection.models ); 829 } 754 830 755 Library.prototype.deactivate.apply( this, arguments ); 831 // Sync the selection's single item with the master. 832 selection.single( manager.single ); 756 833 }, 757 834 758 835 /** 836 * Record the currently active attachments, which is a combination 837 * of the selection's attachments and the set of selected 838 * attachments that this specific selection considered invalid. 839 * Reset the difference and record the single attachment. 840 * 759 841 * @since 3.5.0 760 842 */ 761 updateSelection: function() {843 recordSelection: function() { 762 844 var selection = this.get('selection'), 763 id = wp.media.view.settings.post.featuredImageId, 764 attachment; 845 manager = this.frame._selection; 765 846 766 if ( '' !== id && -1 !== id ) { 767 attachment = Attachment.get( id ); 768 attachment.fetch(); 847 if ( ! this.get('syncSelection') || ! manager || ! selection ) { 848 return; 769 849 } 770 850 771 selection.reset( attachment ? [ attachment ] : [] ); 851 if ( selection.multiple ) { 852 manager.attachments.reset( selection.toArray().concat( manager.difference ) ); 853 manager.difference = []; 854 } else { 855 manager.attachments.add( selection.toArray() ); 856 } 857 858 manager.single = selection._single; 772 859 } 773 } );860 }; 774 861 775 module.exports = FeaturedImage;862 module.exports = selectionSync; 776 863 777 },{}],8:[function(require,module,exports){ 778 var Selection = wp.media.model.Selection, 779 Library = wp.media.controller.Library, 780 l10n = wp.media.view.l10n, 781 GalleryAdd; 864 865 /***/ }), 866 /* 31 */ 867 /***/ (function(module, exports) { 868 869 var l10n = wp.media.view.l10n, 870 getUserSetting = window.getUserSetting, 871 setUserSetting = window.setUserSetting, 872 Library; 782 873 783 874 /** 784 * wp.media.controller. GalleryAdd875 * wp.media.controller.Library 785 876 * 786 * A state for selecting more images to add to a gallery.877 * A state for choosing an attachment or group of attachments from the media library. 787 878 * 788 879 * @memberOf wp.media.controller 789 880 * 790 881 * @class 791 * @augments wp.media.controller.Library792 882 * @augments wp.media.controller.State 793 883 * @augments Backbone.Model 884 * @mixes media.selectionSync 794 885 * 795 * @param {object} [attributes] The attributes hash passed to the state. 796 * @param {string} [attributes.id=gallery-library] Unique identifier. 797 * @param {string} [attributes.title=Add to Gallery] Title for the state. Displays in the frame's title region. 798 * @param {boolean} [attributes.multiple=add] Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean. 799 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 800 * If one is not supplied, a collection of all images will be created. 801 * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown. 802 * Accepts 'all', 'uploaded', or 'unattached'. 803 * @param {string} [attributes.menu=gallery] Initial mode for the menu region. 804 * @param {string} [attributes.content=upload] Initial mode for the content region. 805 * Overridden by persistent user setting if 'contentUserSetting' is true. 806 * @param {string} [attributes.router=browse] Initial mode for the router region. 807 * @param {string} [attributes.toolbar=gallery-add] Initial mode for the toolbar region. 808 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 809 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 810 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 811 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 812 * @param {int} [attributes.priority=100] The priority for the state link in the media menu. 813 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 814 * Defaults to false because for this state, because the library of the Edit Gallery state is the selection. 886 * @param {object} [attributes] The attributes hash passed to the state. 887 * @param {string} [attributes.id=library] Unique identifier. 888 * @param {string} [attributes.title=Media library] Title for the state. Displays in the media menu and the frame's title region. 889 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 890 * If one is not supplied, a collection of all attachments will be created. 891 * @param {wp.media.model.Selection|object} [attributes.selection] A collection to contain attachment selections within the state. 892 * If the 'selection' attribute is a plain JS object, 893 * a Selection will be created using its values as the selection instance's `props` model. 894 * Otherwise, it will copy the library's `props` model. 895 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 896 * @param {string} [attributes.content=upload] Initial mode for the content region. 897 * Overridden by persistent user setting if 'contentUserSetting' is true. 898 * @param {string} [attributes.menu=default] Initial mode for the menu region. 899 * @param {string} [attributes.router=browse] Initial mode for the router region. 900 * @param {string} [attributes.toolbar=select] Initial mode for the toolbar region. 901 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 902 * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown. 903 * Accepts 'all', 'uploaded', or 'unattached'. 904 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 905 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 906 * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. 907 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 908 * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state. 815 909 */ 816 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{ 817 defaults: _.defaults({ 818 id: 'gallery-library', 819 title: l10n.addToGalleryTitle, 820 multiple: 'add', 821 filterable: 'uploaded', 822 menu: 'gallery', 823 toolbar: 'gallery-add', 824 priority: 100, 825 syncSelection: false 826 }, Library.prototype.defaults ), 910 Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{ 911 defaults: { 912 id: 'library', 913 title: l10n.mediaLibraryTitle, 914 multiple: false, 915 content: 'upload', 916 menu: 'default', 917 router: 'browse', 918 toolbar: 'select', 919 searchable: true, 920 filterable: false, 921 sortable: true, 922 autoSelect: true, 923 describe: false, 924 contentUserSetting: true, 925 syncSelection: true 926 }, 827 927 828 928 /** 929 * If a library isn't provided, query all media items. 930 * If a selection instance isn't provided, create one. 931 * 829 932 * @since 3.5.0 830 933 */ 831 934 initialize: function() { 832 // If a library wasn't supplied, create a library of images. 935 var selection = this.get('selection'), 936 props; 937 833 938 if ( ! this.get('library') ) { 834 this.set( 'library', wp.media.query( { type: 'image' }) );939 this.set( 'library', wp.media.query() ); 835 940 } 836 941 837 Library.prototype.initialize.apply( this, arguments ); 942 if ( ! ( selection instanceof wp.media.model.Selection ) ) { 943 props = selection; 944 945 if ( ! props ) { 946 props = this.get('library').props.toJSON(); 947 props = _.omit( props, 'orderby', 'query' ); 948 } 949 950 this.set( 'selection', new wp.media.model.Selection( null, { 951 multiple: this.get('multiple'), 952 props: props 953 }) ); 954 } 955 956 this.resetDisplays(); 838 957 }, 839 958 840 959 /** 841 960 * @since 3.5.0 842 961 */ 843 962 activate: function() { 844 var library = this.get('library'), 845 edit = this.frame.state('gallery-edit').get('library'); 963 this.syncSelection(); 846 964 847 if ( this.editLibrary && this.editLibrary !== edit ) { 848 library.unobserve( this.editLibrary ); 849 } 965 wp.Uploader.queue.on( 'add', this.uploading, this ); 850 966 851 // Accepts attachments that exist in the original library and 852 // that do not exist in gallery's library. 853 library.validator = function( attachment ) { 854 return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments ); 855 }; 967 this.get('selection').on( 'add remove reset', this.refreshContent, this ); 856 968 857 // Reset the library to ensure that all attachments are re-added 858 // to the collection. Do so silently, as calling `observe` will 859 // trigger the `reset` event. 860 library.reset( library.mirroring.models, { silent: true }); 861 library.observe( edit ); 862 this.editLibrary = edit; 969 if ( this.get( 'router' ) && this.get('contentUserSetting') ) { 970 this.frame.on( 'content:activate', this.saveContentMode, this ); 971 this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) ); 972 } 973 }, 863 974 864 Library.prototype.activate.apply( this, arguments ); 865 } 866 }); 975 /** 976 * @since 3.5.0 977 */ 978 deactivate: function() { 979 this.recordSelection(); 867 980 868 module.exports = GalleryAdd;981 this.frame.off( 'content:activate', this.saveContentMode, this ); 869 982 870 },{}],9:[function(require,module,exports){ 871 var Library = wp.media.controller.Library, 872 l10n = wp.media.view.l10n, 873 GalleryEdit; 983 // Unbind all event handlers that use this state as the context 984 // from the selection. 985 this.get('selection').off( null, null, this ); 874 986 875 /** 876 * wp.media.controller.GalleryEdit 877 * 878 * A state for editing a gallery's images and settings. 879 * 880 * @memberOf wp.media.controller 881 * 882 * @class 883 * @augments wp.media.controller.Library 884 * @augments wp.media.controller.State 885 * @augments Backbone.Model 886 * 887 * @param {object} [attributes] The attributes hash passed to the state. 888 * @param {string} [attributes.id=gallery-edit] Unique identifier. 889 * @param {string} [attributes.title=Edit Gallery] Title for the state. Displays in the frame's title region. 890 * @param {wp.media.model.Attachments} [attributes.library] The collection of attachments in the gallery. 891 * If one is not supplied, an empty media.model.Selection collection is created. 892 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 893 * @param {boolean} [attributes.searchable=false] Whether the library is searchable. 894 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 895 * @param {boolean} [attributes.date=true] Whether to show the date filter in the browser's toolbar. 896 * @param {string|false} [attributes.content=browse] Initial mode for the content region. 897 * @param {string|false} [attributes.toolbar=image-details] Initial mode for the toolbar region. 898 * @param {boolean} [attributes.describe=true] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. 899 * @param {boolean} [attributes.displaySettings=true] Whether to show the attachment display settings interface. 900 * @param {boolean} [attributes.dragInfo=true] Whether to show instructional text about the attachments being sortable. 901 * @param {int} [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments. 902 * @param {boolean} [attributes.editing=false] Whether the gallery is being created, or editing an existing instance. 903 * @param {int} [attributes.priority=60] The priority for the state link in the media menu. 904 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 905 * Defaults to false for this state, because the library passed in *is* the selection. 906 * @param {view} [attributes.AttachmentView] The single `Attachment` view to be used in the `Attachments`. 907 * If none supplied, defaults to wp.media.view.Attachment.EditLibrary. 908 */ 909 GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{ 910 defaults: { 911 id: 'gallery-edit', 912 title: l10n.editGalleryTitle, 913 multiple: false, 914 searchable: false, 915 sortable: true, 916 date: false, 917 display: false, 918 content: 'browse', 919 toolbar: 'gallery-edit', 920 describe: true, 921 displaySettings: true, 922 dragInfo: true, 923 idealColumnWidth: 170, 924 editing: false, 925 priority: 60, 926 syncSelection: false 987 wp.Uploader.queue.off( null, null, this ); 927 988 }, 928 989 929 990 /** 991 * Reset the library to its initial state. 992 * 930 993 * @since 3.5.0 931 994 */ 932 initialize: function() { 933 // If we haven't been provided a `library`, create a `Selection`. 934 if ( ! this.get('library') ) { 935 this.set( 'library', new wp.media.model.Selection() ); 995 reset: function() { 996 this.get('selection').reset(); 997 this.resetDisplays(); 998 this.refreshContent(); 999 }, 1000 1001 /** 1002 * Reset the attachment display settings defaults to the site options. 1003 * 1004 * If site options don't define them, fall back to a persistent user setting. 1005 * 1006 * @since 3.5.0 1007 */ 1008 resetDisplays: function() { 1009 var defaultProps = wp.media.view.settings.defaultProps; 1010 this._displays = []; 1011 this._defaultDisplaySettings = { 1012 align: getUserSetting( 'align', defaultProps.align ) || 'none', 1013 size: getUserSetting( 'imgsize', defaultProps.size ) || 'medium', 1014 link: getUserSetting( 'urlbutton', defaultProps.link ) || 'none' 1015 }; 1016 }, 1017 1018 /** 1019 * Create a model to represent display settings (alignment, etc.) for an attachment. 1020 * 1021 * @since 3.5.0 1022 * 1023 * @param {wp.media.model.Attachment} attachment 1024 * @returns {Backbone.Model} 1025 */ 1026 display: function( attachment ) { 1027 var displays = this._displays; 1028 1029 if ( ! displays[ attachment.cid ] ) { 1030 displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) ); 936 1031 } 1032 return displays[ attachment.cid ]; 1033 }, 937 1034 938 // The single `Attachment` view to be used in the `Attachments` view. 939 if ( ! this.get('AttachmentView') ) { 940 this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary ); 1035 /** 1036 * Given an attachment, create attachment display settings properties. 1037 * 1038 * @since 3.6.0 1039 * 1040 * @param {wp.media.model.Attachment} attachment 1041 * @returns {Object} 1042 */ 1043 defaultDisplaySettings: function( attachment ) { 1044 var settings = _.clone( this._defaultDisplaySettings ); 1045 1046 if ( settings.canEmbed = this.canEmbed( attachment ) ) { 1047 settings.link = 'embed'; 1048 } else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) { 1049 settings.link = 'file'; 941 1050 } 942 1051 943 Library.prototype.initialize.apply( this, arguments );1052 return settings; 944 1053 }, 945 1054 946 1055 /** 947 * @since 3.5.0 1056 * Whether an attachment is image. 1057 * 1058 * @since 4.4.1 1059 * 1060 * @param {wp.media.model.Attachment} attachment 1061 * @returns {Boolean} 948 1062 */ 949 activate: function() { 950 var library = this.get('library'); 1063 isImageAttachment: function( attachment ) { 1064 // If uploading, we know the filename but not the mime type. 1065 if ( attachment.get('uploading') ) { 1066 return /\.(jpe?g|png|gif)$/i.test( attachment.get('filename') ); 1067 } 951 1068 952 // Limit the library to images only.953 library.props.set( 'type', 'image' );1069 return attachment.get('type') === 'image'; 1070 }, 954 1071 955 // Watch for uploaded attachments. 956 this.get('library').observe( wp.Uploader.queue ); 1072 /** 1073 * Whether an attachment can be embedded (audio or video). 1074 * 1075 * @since 3.6.0 1076 * 1077 * @param {wp.media.model.Attachment} attachment 1078 * @returns {Boolean} 1079 */ 1080 canEmbed: function( attachment ) { 1081 // If uploading, we know the filename but not the mime type. 1082 if ( ! attachment.get('uploading') ) { 1083 var type = attachment.get('type'); 1084 if ( type !== 'audio' && type !== 'video' ) { 1085 return false; 1086 } 1087 } 957 1088 958 this.frame.on( 'content:render:browse', this.gallerySettings, this ); 1089 return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() ); 1090 }, 959 1091 960 Library.prototype.activate.apply( this, arguments ); 1092 1093 /** 1094 * If the state is active, no items are selected, and the current 1095 * content mode is not an option in the state's router (provided 1096 * the state has a router), reset the content mode to the default. 1097 * 1098 * @since 3.5.0 1099 */ 1100 refreshContent: function() { 1101 var selection = this.get('selection'), 1102 frame = this.frame, 1103 router = frame.router.get(), 1104 mode = frame.content.mode(); 1105 1106 if ( this.active && ! selection.length && router && ! router.get( mode ) ) { 1107 this.frame.content.render( this.get('content') ); 1108 } 961 1109 }, 962 1110 963 1111 /** 1112 * Callback handler when an attachment is uploaded. 1113 * 1114 * Switch to the Media Library if uploaded from the 'Upload Files' tab. 1115 * 1116 * Adds any uploading attachments to the selection. 1117 * 1118 * If the state only supports one attachment to be selected and multiple 1119 * attachments are uploaded, the last attachment in the upload queue will 1120 * be selected. 1121 * 964 1122 * @since 3.5.0 1123 * 1124 * @param {wp.media.model.Attachment} attachment 965 1125 */ 966 deactivate: function() { 967 // Stop watching for uploaded attachments. 968 this.get('library').unobserve( wp.Uploader.queue ); 1126 uploading: function( attachment ) { 1127 var content = this.frame.content; 969 1128 970 this.frame.off( 'content:render:browse', this.gallerySettings, this ); 1129 if ( 'upload' === content.mode() ) { 1130 this.frame.content.mode('browse'); 1131 } 971 1132 972 Library.prototype.deactivate.apply( this, arguments ); 1133 if ( this.get( 'autoSelect' ) ) { 1134 this.get('selection').add( attachment ); 1135 this.frame.trigger( 'library:selection:add' ); 1136 } 973 1137 }, 974 1138 975 1139 /** 976 * @since 3.5.01140 * Persist the mode of the content region as a user setting. 977 1141 * 978 * @ param browser1142 * @since 3.5.0 979 1143 */ 980 gallerySettings: function( browser) {981 if ( ! this.get('displaySettings') ) {1144 saveContentMode: function() { 1145 if ( 'browse' !== this.get('router') ) { 982 1146 return; 983 1147 } 984 1148 985 var library = this.get('library'); 1149 var mode = this.frame.content.mode(), 1150 view = this.frame.router.get(); 986 1151 987 if ( ! library || ! browser) {988 return;1152 if ( view && view.get( mode ) ) { 1153 setUserSetting( 'libraryContent', mode ); 989 1154 } 1155 } 1156 }); 990 1157 991 library.gallery = library.gallery || new Backbone.Model(); 1158 // Make selectionSync available on any Media Library state. 1159 _.extend( Library.prototype, wp.media.selectionSync ); 992 1160 993 browser.sidebar.set({ 994 gallery: new wp.media.view.Settings.Gallery({ 995 controller: this, 996 model: library.gallery, 997 priority: 40 998 }) 999 }); 1161 module.exports = Library; 1000 1162 1001 browser.toolbar.set( 'reverse', {1002 text: l10n.reverseOrder,1003 priority: 80,1004 1005 click: function() {1006 library.reset( library.toArray().reverse() );1007 }1008 });1009 }1010 });1011 1163 1012 module.exports = GalleryEdit; 1164 /***/ }), 1165 /* 32 */ 1166 /***/ (function(module, exports) { 1013 1167 1014 },{}],10:[function(require,module,exports){1015 1168 var State = wp.media.controller.State, 1016 1169 Library = wp.media.controller.Library, 1017 1170 l10n = wp.media.view.l10n, … … ImageDetails = State.extend(/** @lends wp.media.controller.ImageDetails.prototyp 1075 1228 1076 1229 module.exports = ImageDetails; 1077 1230 1078 },{}],11:[function(require,module,exports){ 1079 var l10n = wp.media.view.l10n, 1080 getUserSetting = window.getUserSetting, 1081 setUserSetting = window.setUserSetting, 1082 Library; 1231 1232 /***/ }), 1233 /* 33 */ 1234 /***/ (function(module, exports) { 1235 1236 var Library = wp.media.controller.Library, 1237 l10n = wp.media.view.l10n, 1238 GalleryEdit; 1083 1239 1084 1240 /** 1085 * wp.media.controller. Library1241 * wp.media.controller.GalleryEdit 1086 1242 * 1087 * A state for choosing an attachment or group of attachments from the media library.1243 * A state for editing a gallery's images and settings. 1088 1244 * 1089 1245 * @memberOf wp.media.controller 1090 1246 * 1091 1247 * @class 1248 * @augments wp.media.controller.Library 1092 1249 * @augments wp.media.controller.State 1093 1250 * @augments Backbone.Model 1094 * @mixes media.selectionSync1095 1251 * 1096 * @param {object} [attributes] The attributes hash passed to the state. 1097 * @param {string} [attributes.id=library] Unique identifier. 1098 * @param {string} [attributes.title=Media library] Title for the state. Displays in the media menu and the frame's title region. 1099 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 1100 * If one is not supplied, a collection of all attachments will be created. 1101 * @param {wp.media.model.Selection|object} [attributes.selection] A collection to contain attachment selections within the state. 1102 * If the 'selection' attribute is a plain JS object, 1103 * a Selection will be created using its values as the selection instance's `props` model. 1104 * Otherwise, it will copy the library's `props` model. 1105 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 1106 * @param {string} [attributes.content=upload] Initial mode for the content region. 1107 * Overridden by persistent user setting if 'contentUserSetting' is true. 1108 * @param {string} [attributes.menu=default] Initial mode for the menu region. 1109 * @param {string} [attributes.router=browse] Initial mode for the router region. 1110 * @param {string} [attributes.toolbar=select] Initial mode for the toolbar region. 1111 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 1112 * @param {boolean|string} [attributes.filterable=false] Whether the library is filterable, and if so what filters should be shown. 1113 * Accepts 'all', 'uploaded', or 'unattached'. 1114 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 1115 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 1116 * @param {boolean} [attributes.describe=false] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. 1117 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 1118 * @param {boolean} [attributes.syncSelection=true] Whether the Attachments selection should be persisted from the last state. 1252 * @param {object} [attributes] The attributes hash passed to the state. 1253 * @param {string} [attributes.id=gallery-edit] Unique identifier. 1254 * @param {string} [attributes.title=Edit Gallery] Title for the state. Displays in the frame's title region. 1255 * @param {wp.media.model.Attachments} [attributes.library] The collection of attachments in the gallery. 1256 * If one is not supplied, an empty media.model.Selection collection is created. 1257 * @param {boolean} [attributes.multiple=false] Whether multi-select is enabled. 1258 * @param {boolean} [attributes.searchable=false] Whether the library is searchable. 1259 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 1260 * @param {boolean} [attributes.date=true] Whether to show the date filter in the browser's toolbar. 1261 * @param {string|false} [attributes.content=browse] Initial mode for the content region. 1262 * @param {string|false} [attributes.toolbar=image-details] Initial mode for the toolbar region. 1263 * @param {boolean} [attributes.describe=true] Whether to offer UI to describe attachments - e.g. captioning images in a gallery. 1264 * @param {boolean} [attributes.displaySettings=true] Whether to show the attachment display settings interface. 1265 * @param {boolean} [attributes.dragInfo=true] Whether to show instructional text about the attachments being sortable. 1266 * @param {int} [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments. 1267 * @param {boolean} [attributes.editing=false] Whether the gallery is being created, or editing an existing instance. 1268 * @param {int} [attributes.priority=60] The priority for the state link in the media menu. 1269 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 1270 * Defaults to false for this state, because the library passed in *is* the selection. 1271 * @param {view} [attributes.AttachmentView] The single `Attachment` view to be used in the `Attachments`. 1272 * If none supplied, defaults to wp.media.view.Attachment.EditLibrary. 1119 1273 */ 1120 Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{1274 GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{ 1121 1275 defaults: { 1122 id: 'library', 1123 title: l10n.mediaLibraryTitle, 1124 multiple: false, 1125 content: 'upload', 1126 menu: 'default', 1127 router: 'browse', 1128 toolbar: 'select', 1129 searchable: true, 1130 filterable: false, 1131 sortable: true, 1132 autoSelect: true, 1133 describe: false, 1134 contentUserSetting: true, 1135 syncSelection: true 1276 id: 'gallery-edit', 1277 title: l10n.editGalleryTitle, 1278 multiple: false, 1279 searchable: false, 1280 sortable: true, 1281 date: false, 1282 display: false, 1283 content: 'browse', 1284 toolbar: 'gallery-edit', 1285 describe: true, 1286 displaySettings: true, 1287 dragInfo: true, 1288 idealColumnWidth: 170, 1289 editing: false, 1290 priority: 60, 1291 syncSelection: false 1136 1292 }, 1137 1293 1138 1294 /** 1139 * If a library isn't provided, query all media items.1140 * If a selection instance isn't provided, create one.1141 *1142 1295 * @since 3.5.0 1143 1296 */ 1144 1297 initialize: function() { 1145 var selection = this.get('selection'), 1146 props; 1147 1298 // If we haven't been provided a `library`, create a `Selection`. 1148 1299 if ( ! this.get('library') ) { 1149 this.set( 'library', wp.media.query() );1300 this.set( 'library', new wp.media.model.Selection() ); 1150 1301 } 1151 1302 1152 if ( ! ( selection instanceof wp.media.model.Selection ) ) { 1153 props = selection; 1154 1155 if ( ! props ) { 1156 props = this.get('library').props.toJSON(); 1157 props = _.omit( props, 'orderby', 'query' ); 1158 } 1159 1160 this.set( 'selection', new wp.media.model.Selection( null, { 1161 multiple: this.get('multiple'), 1162 props: props 1163 }) ); 1303 // The single `Attachment` view to be used in the `Attachments` view. 1304 if ( ! this.get('AttachmentView') ) { 1305 this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary ); 1164 1306 } 1165 1307 1166 this.resetDisplays();1308 Library.prototype.initialize.apply( this, arguments ); 1167 1309 }, 1168 1310 1169 1311 /** 1170 1312 * @since 3.5.0 1171 1313 */ 1172 1314 activate: function() { 1173 this.syncSelection();1315 var library = this.get('library'); 1174 1316 1175 wp.Uploader.queue.on( 'add', this.uploading, this ); 1317 // Limit the library to images only. 1318 library.props.set( 'type', 'image' ); 1176 1319 1177 this.get('selection').on( 'add remove reset', this.refreshContent, this ); 1320 // Watch for uploaded attachments. 1321 this.get('library').observe( wp.Uploader.queue ); 1178 1322 1179 if ( this.get( 'router' ) && this.get('contentUserSetting') ) { 1180 this.frame.on( 'content:activate', this.saveContentMode, this ); 1181 this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) ); 1182 } 1323 this.frame.on( 'content:render:browse', this.gallerySettings, this ); 1324 1325 Library.prototype.activate.apply( this, arguments ); 1183 1326 }, 1184 1327 1185 1328 /** 1186 1329 * @since 3.5.0 1187 1330 */ 1188 1331 deactivate: function() { 1189 this.recordSelection(); 1190 1191 this.frame.off( 'content:activate', this.saveContentMode, this ); 1332 // Stop watching for uploaded attachments. 1333 this.get('library').unobserve( wp.Uploader.queue ); 1192 1334 1193 // Unbind all event handlers that use this state as the context 1194 // from the selection. 1195 this.get('selection').off( null, null, this ); 1335 this.frame.off( 'content:render:browse', this.gallerySettings, this ); 1196 1336 1197 wp.Uploader.queue.off( null, null, this );1337 Library.prototype.deactivate.apply( this, arguments ); 1198 1338 }, 1199 1339 1200 1340 /** 1201 * Reset the library to its initial state.1202 *1203 1341 * @since 3.5.0 1204 */1205 reset: function() {1206 this.get('selection').reset();1207 this.resetDisplays();1208 this.refreshContent();1209 },1210 1211 /**1212 * Reset the attachment display settings defaults to the site options.1213 *1214 * If site options don't define them, fall back to a persistent user setting.1215 1342 * 1216 * @ since 3.5.01343 * @param browser 1217 1344 */ 1218 resetDisplays: function() { 1219 var defaultProps = wp.media.view.settings.defaultProps; 1220 this._displays = []; 1221 this._defaultDisplaySettings = { 1222 align: getUserSetting( 'align', defaultProps.align ) || 'none', 1223 size: getUserSetting( 'imgsize', defaultProps.size ) || 'medium', 1224 link: getUserSetting( 'urlbutton', defaultProps.link ) || 'none' 1225 }; 1226 }, 1345 gallerySettings: function( browser ) { 1346 if ( ! this.get('displaySettings') ) { 1347 return; 1348 } 1227 1349 1228 /** 1229 * Create a model to represent display settings (alignment, etc.) for an attachment. 1230 * 1231 * @since 3.5.0 1232 * 1233 * @param {wp.media.model.Attachment} attachment 1234 * @returns {Backbone.Model} 1235 */ 1236 display: function( attachment ) { 1237 var displays = this._displays; 1350 var library = this.get('library'); 1238 1351 1239 if ( ! displays[ attachment.cid ]) {1240 displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );1352 if ( ! library || ! browser ) { 1353 return; 1241 1354 } 1242 return displays[ attachment.cid ];1243 },1244 1355 1245 /** 1246 * Given an attachment, create attachment display settings properties. 1247 * 1248 * @since 3.6.0 1249 * 1250 * @param {wp.media.model.Attachment} attachment 1251 * @returns {Object} 1252 */ 1253 defaultDisplaySettings: function( attachment ) { 1254 var settings = _.clone( this._defaultDisplaySettings ); 1356 library.gallery = library.gallery || new Backbone.Model(); 1255 1357 1256 if ( settings.canEmbed = this.canEmbed( attachment ) ) { 1257 settings.link = 'embed'; 1258 } else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) { 1259 settings.link = 'file'; 1260 } 1358 browser.sidebar.set({ 1359 gallery: new wp.media.view.Settings.Gallery({ 1360 controller: this, 1361 model: library.gallery, 1362 priority: 40 1363 }) 1364 }); 1261 1365 1262 return settings; 1263 }, 1366 browser.toolbar.set( 'reverse', { 1367 text: l10n.reverseOrder, 1368 priority: 80, 1264 1369 1265 /** 1266 * Whether an attachment is image. 1267 * 1268 * @since 4.4.1 1269 * 1270 * @param {wp.media.model.Attachment} attachment 1271 * @returns {Boolean} 1272 */ 1273 isImageAttachment: function( attachment ) { 1274 // If uploading, we know the filename but not the mime type. 1275 if ( attachment.get('uploading') ) { 1276 return /\.(jpe?g|png|gif)$/i.test( attachment.get('filename') ); 1277 } 1370 click: function() { 1371 library.reset( library.toArray().reverse() ); 1372 } 1373 }); 1374 } 1375 }); 1278 1376 1279 return attachment.get('type') === 'image'; 1280 }, 1377 module.exports = GalleryEdit; 1281 1378 1282 /**1283 * Whether an attachment can be embedded (audio or video).1284 *1285 * @since 3.6.01286 *1287 * @param {wp.media.model.Attachment} attachment1288 * @returns {Boolean}1289 */1290 canEmbed: function( attachment ) {1291 // If uploading, we know the filename but not the mime type.1292 if ( ! attachment.get('uploading') ) {1293 var type = attachment.get('type');1294 if ( type !== 'audio' && type !== 'video' ) {1295 return false;1296 }1297 }1298 1299 return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );1300 },1301 1379 1380 /***/ }), 1381 /* 34 */ 1382 /***/ (function(module, exports) { 1302 1383 1303 /** 1304 * If the state is active, no items are selected, and the current 1305 * content mode is not an option in the state's router (provided 1306 * the state has a router), reset the content mode to the default. 1307 * 1308 * @since 3.5.0 1309 */ 1310 refreshContent: function() { 1311 var selection = this.get('selection'), 1312 frame = this.frame, 1313 router = frame.router.get(), 1314 mode = frame.content.mode(); 1384 var Selection = wp.media.model.Selection, 1385 Library = wp.media.controller.Library, 1386 l10n = wp.media.view.l10n, 1387 GalleryAdd; 1315 1388 1316 if ( this.active && ! selection.length && router && ! router.get( mode ) ) { 1317 this.frame.content.render( this.get('content') ); 1318 } 1319 }, 1389 /** 1390 * wp.media.controller.GalleryAdd 1391 * 1392 * A state for selecting more images to add to a gallery. 1393 * 1394 * @memberOf wp.media.controller 1395 * 1396 * @class 1397 * @augments wp.media.controller.Library 1398 * @augments wp.media.controller.State 1399 * @augments Backbone.Model 1400 * 1401 * @param {object} [attributes] The attributes hash passed to the state. 1402 * @param {string} [attributes.id=gallery-library] Unique identifier. 1403 * @param {string} [attributes.title=Add to Gallery] Title for the state. Displays in the frame's title region. 1404 * @param {boolean} [attributes.multiple=add] Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean. 1405 * @param {wp.media.model.Attachments} [attributes.library] The attachments collection to browse. 1406 * If one is not supplied, a collection of all images will be created. 1407 * @param {boolean|string} [attributes.filterable=uploaded] Whether the library is filterable, and if so what filters should be shown. 1408 * Accepts 'all', 'uploaded', or 'unattached'. 1409 * @param {string} [attributes.menu=gallery] Initial mode for the menu region. 1410 * @param {string} [attributes.content=upload] Initial mode for the content region. 1411 * Overridden by persistent user setting if 'contentUserSetting' is true. 1412 * @param {string} [attributes.router=browse] Initial mode for the router region. 1413 * @param {string} [attributes.toolbar=gallery-add] Initial mode for the toolbar region. 1414 * @param {boolean} [attributes.searchable=true] Whether the library is searchable. 1415 * @param {boolean} [attributes.sortable=true] Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection. 1416 * @param {boolean} [attributes.autoSelect=true] Whether an uploaded attachment should be automatically added to the selection. 1417 * @param {boolean} [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user. 1418 * @param {int} [attributes.priority=100] The priority for the state link in the media menu. 1419 * @param {boolean} [attributes.syncSelection=false] Whether the Attachments selection should be persisted from the last state. 1420 * Defaults to false because for this state, because the library of the Edit Gallery state is the selection. 1421 */ 1422 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{ 1423 defaults: _.defaults({ 1424 id: 'gallery-library', 1425 title: l10n.addToGalleryTitle, 1426 multiple: 'add', 1427 filterable: 'uploaded', 1428 menu: 'gallery', 1429 toolbar: 'gallery-add', 1430 priority: 100, 1431 syncSelection: false 1432 }, Library.prototype.defaults ), 1320 1433 1321 1434 /** 1322 * Callback handler when an attachment is uploaded.1323 *1324 * Switch to the Media Library if uploaded from the 'Upload Files' tab.1325 *1326 * Adds any uploading attachments to the selection.1327 *1328 * If the state only supports one attachment to be selected and multiple1329 * attachments are uploaded, the last attachment in the upload queue will1330 * be selected.1331 *1332 1435 * @since 3.5.0 1333 *1334 * @param {wp.media.model.Attachment} attachment1335 1436 */ 1336 uploading: function( attachment ) { 1337 var content = this.frame.content; 1338 1339 if ( 'upload' === content.mode() ) { 1340 this.frame.content.mode('browse'); 1437 initialize: function() { 1438 // If a library wasn't supplied, create a library of images. 1439 if ( ! this.get('library') ) { 1440 this.set( 'library', wp.media.query({ type: 'image' }) );