From 03c10a313c3ddb65a1c1057c1d06cca6d5ea471b Mon Sep 17 00:00:00 2001 From: Josh Pollock Date: Mon, 23 Jul 2018 02:28:16 -0400 Subject: [PATCH 01/17] Document switching node version using nvm so tests will work. (#8117) * Document switching node version using nvm so tests will work. * Update CONTRIBUTING.md --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1311bd2ab401f6..69c7174fea19fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,13 @@ The easiest way to get started (on MacOS, Linux, or Windows 10 with the Linux Su For other version of Windows, or if you prefer to set things up manually, be sure to have Node.js installed first. You should be running a Node version matching the [current active LTS release](https://github.com/nodejs/Release#release-schedule) or newer for this plugin to work correctly. You can check your Node.js version by typing `node -v` in the Terminal prompt. +If you have an incompatible version of Node in your development environment, you can use [nvm](https://github.com/creationix/nvm) to change node versions on the command line: + +``` +npx nvm install +npx nvm use +``` + You should also have the latest release of npm installed, npm is a separate project from Node.js and is updated frequently. If you've just installed Node.js which includes a version of npm within the installation you most likely will need to also update your npm install. To update npm, type this into your terminal: `npm install npm@latest -g` To test the plugin, or to contribute to it, you can clone this repository and build the plugin files using Node. How you do that depends on whether you're developing locally or uploading the plugin to a remote host. From 09db90456689a4e83d045bf1fe8ea1614c156ca5 Mon Sep 17 00:00:00 2001 From: Chris Van Patten Date: Mon, 23 Jul 2018 05:30:51 -0400 Subject: [PATCH 02/17] Improve JS package descriptions (#8121) * Improve package descriptions * Update package.json * Update package.json --- packages/a11y/package.json | 2 +- packages/api-fetch/package.json | 2 +- packages/babel-plugin-import-jsx-pragma/package.json | 2 +- packages/babel-plugin-makepot/package.json | 2 +- packages/blob/package.json | 2 +- packages/browserslist-config/package.json | 2 +- packages/components/package.json | 2 +- packages/compose/package.json | 2 +- packages/dom-ready/package.json | 2 +- packages/dom/package.json | 2 +- packages/hooks/package.json | 2 +- packages/html-entities/package.json | 2 +- packages/i18n/package.json | 2 +- packages/keycodes/package.json | 2 +- packages/npm-package-json-lint-config/package.json | 2 +- packages/wordcount/package.json | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 095c713fafdd39..52b7e4054b4252 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/a11y", "version": "1.1.1", - "description": "Collection of JS modules and tools for WordPress development", + "description": "Accessibility (a11y) utilities for WordPress", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index 7971a073ea0de9..373af059d4cbce 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/api-fetch", "version": "1.0.1", - "description": "Utility to call WordPress REST APIs", + "description": "Utility to make WordPress REST API requests", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 4710bc19d9a2c7..11611c90d21217 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", "version": "1.0.1", - "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", + "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 80be3a0a14b2e3..f2a496dddddd1c 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/babel-plugin-makepot", "version": "2.0.1", - "description": "WordPress Babel i18n Plugin", + "description": "WordPress Babel internationalization (i18n) plugin", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/blob/package.json b/packages/blob/package.json index b91444601ae730..4b4810c98c2aca 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/blob", "version": "1.0.1", - "description": "Blob utils for WordPress", + "description": "Blob utilities for WordPress", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index 92f19fe9149d75..fd252d16b23bce 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/browserslist-config", "version": "2.2.0", - "description": "WordPress Browserslist Shared Config", + "description": "WordPress Browserslist shared configuration", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/components/package.json b/packages/components/package.json index c0ad6d453fd31b..25ad7ab4c5ecb7 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/components", "version": "1.0.1", - "description": "UI Compoonents for WordPress", + "description": "UI components for WordPress", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/compose/package.json b/packages/compose/package.json index c9ce28608ba821..4b974a34a24ed6 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/compose", "version": "1.0.1", - "description": "WordPress Higher Order components", + "description": "WordPress higher-order components (HOCs)", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index abfe4dcfe03b27..269aaa15d77f19 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/dom-ready", "version": "1.1.1", - "description": "Execute callback after the DOM is loaded.", + "description": "Execute callback after the DOM is loaded", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/dom/package.json b/packages/dom/package.json index a3cbc0d872cd9e..cb005d3803244f 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/dom", "version": "1.0.1", - "description": "DOM utils module for WordPress", + "description": "DOM utilities module for WordPress", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/hooks/package.json b/packages/hooks/package.json index eb2090a8382f31..4947bac9aaebca 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/hooks", "version": "1.3.1", - "description": "WordPress Hooks library", + "description": "WordPress hooks library", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 671a894765deca..d13a6db0a424f6 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/html-entities", "version": "1.0.1", - "description": "HTML entities utils for WordPress", + "description": "HTML entity utilties for WordPress", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/i18n/package.json b/packages/i18n/package.json index cebaec0044322f..7565c4a282f6fe 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/i18n", "version": "1.2.1", - "description": "WordPress i18n library", + "description": "WordPress internationalization (i18n) library", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index a3186f54525eb0..d717ffbc731180 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/keycodes", "version": "1.0.1", - "description": "KeyCodes utilities for WordPress", + "description": "Keycodes utilities for WordPress; used to check for keyboard events across browsers/operating systems", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index 46438fee55a8a8..69537707b5c4ca 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/npm-package-json-lint-config", "version": "1.1.1", - "description": "WordPress npm-package-json-lint shareable config", + "description": "WordPress npm-package-json-lint shareable configuration", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index 9ec41c4e4075b9..08c648438cc381 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,7 +1,7 @@ { "name": "@wordpress/wordcount", "version": "1.1.1", - "description": "WordPress Word Count Utility", + "description": "WordPress word count utility", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ From b129f0ea490bd3be398278d19bb2cf0b347beb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= Date: Mon, 23 Jul 2018 14:04:35 +0200 Subject: [PATCH 03/17] Editor: Move media upload from utils (#7978) * Testing: Simplify tests for media upload function * Packages: Duplicate deprecated code for media-upload utils * Editor: Move media upload from utils * Editor: Rename editorMediaUpload to mediaUpload * Editor: Update apiRequest occurrences with apiFetch * Bump deprecation version for util methods --- core-blocks/file/edit.js | 4 +- core-blocks/gallery/edit.js | 4 +- core-blocks/gallery/index.js | 4 +- core-blocks/image/edit.js | 4 +- docs/reference/deprecated.md | 7 + editor/components/media-placeholder/index.js | 4 +- editor/store/defaults.js | 6 + editor/utils/index.js | 21 ++- .../index.js | 19 +- editor/utils/media-upload/media-upload.js | 168 ++++++++++++++++++ .../utils/media-upload/test/media-upload.js | 40 ++--- lib/client-assets.php | 22 ++- utils/index.js | 3 +- utils/mediaupload.js | 29 ++- 14 files changed, 271 insertions(+), 64 deletions(-) rename editor/utils/{editor-media-upload => media-upload}/index.js (74%) create mode 100644 editor/utils/media-upload/media-upload.js rename utils/test/mediaupload.js => editor/utils/media-upload/test/media-upload.js (73%) diff --git a/core-blocks/file/edit.js b/core-blocks/file/edit.js index 0f9bf176675b9d..46ffb595520d85 100644 --- a/core-blocks/file/edit.js +++ b/core-blocks/file/edit.js @@ -21,7 +21,7 @@ import { MediaPlaceholder, BlockControls, RichText, - editorMediaUpload, + mediaUpload, } from '@wordpress/editor'; import { compose } from '@wordpress/compose'; @@ -55,7 +55,7 @@ class FileEdit extends Component { if ( this.isBlobURL( href ) ) { const file = getBlobByURL( href ); - editorMediaUpload( { + mediaUpload( { allowedType: '*', filesList: [ file ], onFileChange: ( [ media ] ) => this.onSelectFile( media ), diff --git a/core-blocks/gallery/edit.js b/core-blocks/gallery/edit.js index 14267a27cd459b..c706ea74817d11 100644 --- a/core-blocks/gallery/edit.js +++ b/core-blocks/gallery/edit.js @@ -25,7 +25,7 @@ import { MediaUpload, MediaPlaceholder, InspectorControls, - editorMediaUpload, + mediaUpload, } from '@wordpress/editor'; /** @@ -137,7 +137,7 @@ class GalleryEdit extends Component { addFiles( files ) { const currentImages = this.props.attributes.images || []; const { noticeOperations, setAttributes } = this.props; - editorMediaUpload( { + mediaUpload( { allowedType: 'image', filesList: files, onFileChange: ( images ) => { diff --git a/core-blocks/gallery/index.js b/core-blocks/gallery/index.js index b12ae034d5e3a7..333dedfea1c1bd 100644 --- a/core-blocks/gallery/index.js +++ b/core-blocks/gallery/index.js @@ -8,7 +8,7 @@ import { filter, every } from 'lodash'; */ import { __ } from '@wordpress/i18n'; import { createBlock } from '@wordpress/blocks'; -import { RichText, editorMediaUpload } from '@wordpress/editor'; +import { RichText, mediaUpload } from '@wordpress/editor'; import { createBlobURL } from '@wordpress/blob'; /** @@ -135,7 +135,7 @@ export const settings = { const block = createBlock( 'core/gallery', { images: files.map( ( file ) => ( { url: createBlobURL( file ) } ) ), } ); - editorMediaUpload( { + mediaUpload( { filesList: files, onFileChange: ( images ) => onChange( block.clientId, { images } ), allowedType: 'image', diff --git a/core-blocks/image/edit.js b/core-blocks/image/edit.js index 4453072293d84b..15b4e2a5a6c0eb 100644 --- a/core-blocks/image/edit.js +++ b/core-blocks/image/edit.js @@ -36,7 +36,7 @@ import { MediaPlaceholder, MediaUpload, BlockAlignmentToolbar, - editorMediaUpload, + mediaUpload, } from '@wordpress/editor'; import { withViewportMatch } from '@wordpress/viewport'; import { compose } from '@wordpress/compose'; @@ -84,7 +84,7 @@ class ImageEdit extends Component { const file = getBlobByURL( url ); if ( file ) { - editorMediaUpload( { + mediaUpload( { filesList: [ file ], onFileChange: ( [ image ] ) => { setAttributes( { ...image } ); diff --git a/docs/reference/deprecated.md b/docs/reference/deprecated.md index 699cf8ad1ac224..4be6209416cada 100644 --- a/docs/reference/deprecated.md +++ b/docs/reference/deprecated.md @@ -1,5 +1,12 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility for two minor releases, when possible. The current deprecations are listed below and are grouped by _the version at which they will be removed completely_. If your plugin depends on these behaviors, you must update to the recommended alternative before the noted version. +## 3.6.0 + + - `wp.editor.editorMediaUpload` has been removed. Please use `wp.editor.mediaUpload` instead. + - `wp.utils.getMimeTypesArray` has been removed. + - `wp.utils.mediaUpload` has been removed. Please use `wp.editor.mediaUpload` instead. + - `wp.utils.preloadImage` has been removed. + ## 3.5.0 - `wp.components.ifCondition` has been removed. Please use `wp.compose.ifCondition` instead. diff --git a/editor/components/media-placeholder/index.js b/editor/components/media-placeholder/index.js index 0fb751644af70d..30ecc9c50e2639 100644 --- a/editor/components/media-placeholder/index.js +++ b/editor/components/media-placeholder/index.js @@ -22,7 +22,7 @@ import deprecated from '@wordpress/deprecated'; */ import './style.scss'; import MediaUpload from '../media-upload'; -import editorMediaUpload from '../../utils/editor-media-upload'; +import { mediaUpload } from '../../utils/'; class MediaPlaceholder extends Component { constructor() { @@ -84,7 +84,7 @@ class MediaPlaceholder extends Component { onFilesUpload( files ) { const { onSelect, type, multiple, onError } = this.props; const setMedia = multiple ? onSelect : ( [ media ] ) => onSelect( media ); - editorMediaUpload( { + mediaUpload( { allowedType: type, filesList: files, onFileChange: setMedia, diff --git a/editor/store/defaults.js b/editor/store/defaults.js index 7fe4ffe517011a..b0b597a9d96d67 100644 --- a/editor/store/defaults.js +++ b/editor/store/defaults.js @@ -81,4 +81,10 @@ export const EDITOR_SETTINGS_DEFAULTS = { // Allowed block types for the editor, defaulting to true (all supported). allowedBlockTypes: true, + + // Maximum upload size in bytes allowed for the site. + maxUploadFileSize: 0, + + // List of allowed mime types and file extensions. + allowedMimeTypes: null, }; diff --git a/editor/utils/index.js b/editor/utils/index.js index b1f9d6a838063e..be415d33c3ab08 100644 --- a/editor/utils/index.js +++ b/editor/utils/index.js @@ -1 +1,20 @@ -export { default as editorMediaUpload } from './editor-media-upload'; +/** + * WordPress dependencies + */ +import deprecated from '@wordpress/deprecated'; + +/** + * Internal dependencies + */ +import mediaUpload from './media-upload'; + +export { mediaUpload }; + +export function editorMediaUpload( ...params ) { + deprecated( 'wp.editor.editorMediaUpload', { + version: '3.6', + alternative: 'wp.editor.mediaUpload', + plugin: 'Gutenberg', + } ); + mediaUpload( ...params ); +} diff --git a/editor/utils/editor-media-upload/index.js b/editor/utils/media-upload/index.js similarity index 74% rename from editor/utils/editor-media-upload/index.js rename to editor/utils/media-upload/index.js index bd6e08683a96da..5a8e39d7159e06 100644 --- a/editor/utils/editor-media-upload/index.js +++ b/editor/utils/media-upload/index.js @@ -7,7 +7,11 @@ import { noop } from 'lodash'; * WordPress dependencies */ import { select } from '@wordpress/data'; -import { mediaUpload } from '@wordpress/utils'; + +/** + * Internal dependencies + */ +import { mediaUpload } from './media-upload'; /** * Upload a media file when the file upload button is activated. @@ -15,29 +19,34 @@ import { mediaUpload } from '@wordpress/utils'; * * @param {Object} $0 Parameters object passed to the function. * @param {string} $0.allowedType The type of media that can be uploaded, or '*' to allow all. - * @param {?Object} $0.additionalData Additional data to include in the request. * @param {Array} $0.filesList List of files. * @param {?number} $0.maxUploadFileSize Maximum upload size in bytes allowed for the site. * @param {Function} $0.onError Function called when an error happens. * @param {Function} $0.onFileChange Function called each time a file or a temporary representation of the file is available. */ -export default function editorMediaUpload( { +export default function( { allowedType, filesList, maxUploadFileSize, onError = noop, onFileChange, } ) { - const postId = select( 'core/editor' ).getCurrentPostId(); + const { + getCurrentPostId, + getEditorSettings, + } = select( 'core/editor' ); + const allowedMimeTypes = getEditorSettings().allowedMimeTypes; + maxUploadFileSize = maxUploadFileSize || getEditorSettings().maxUploadFileSize; mediaUpload( { allowedType, filesList, onFileChange, additionalData: { - post: postId, + post: getCurrentPostId(), }, maxUploadFileSize, onError: ( { message } ) => onError( message ), + allowedMimeTypes, } ); } diff --git a/editor/utils/media-upload/media-upload.js b/editor/utils/media-upload/media-upload.js new file mode 100644 index 00000000000000..b925b7032bf8d7 --- /dev/null +++ b/editor/utils/media-upload/media-upload.js @@ -0,0 +1,168 @@ +/** + * External Dependencies + */ +import { compact, flatMap, forEach, get, has, includes, map, noop, startsWith } from 'lodash'; + +/** + * WordPress dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Browsers may use unexpected mime types, and they differ from browser to browser. + * This function computes a flexible array of mime types from the mime type structured provided by the server. + * Converts { jpg|jpeg|jpe: "image/jpeg" } into [ "image/jpeg", "image/jpg", "image/jpeg", "image/jpe" ] + * The computation of this array instead of directly using the object, + * solves the problem in chrome where mp3 files have audio/mp3 as mime type instead of audio/mpeg. + * https://bugs.chromium.org/p/chromium/issues/detail?id=227004 + * + * @param {?Object} wpMimeTypesObject Mime type object received from the server. + * Extensions are keys separated by '|' and values are mime types associated with an extension. + * + * @return {?Array} An array of mime types or the parameter passed if it was "falsy". + */ +export function getMimeTypesArray( wpMimeTypesObject ) { + if ( ! wpMimeTypesObject ) { + return wpMimeTypesObject; + } + return flatMap( wpMimeTypesObject, ( mime, extensionsString ) => { + const [ type ] = mime.split( '/' ); + const extensions = extensionsString.split( '|' ); + return [ mime, ...map( extensions, ( extension ) => `${ type }/${ extension }` ) ]; + } ); +} + +/** + * Media Upload is used by audio, image, gallery, video, and file blocks to + * handle uploading a media file when a file upload button is activated. + * + * TODO: future enhancement to add an upload indicator. + * + * @param {Object} $0 Parameters object passed to the function. + * @param {string} $0.allowedType The type of media that can be uploaded, or '*' to allow all. + * @param {?Object} $0.additionalData Additional data to include in the request. + * @param {Array} $0.filesList List of files. + * @param {?number} $0.maxUploadFileSize Maximum upload size in bytes allowed for the site. + * @param {Function} $0.onError Function called when an error happens. + * @param {Function} $0.onFileChange Function called each time a file or a temporary representation of the file is available. + * @param {?Object} $0.allowedMimeTypes List of allowed mime types and file extensions. + */ +export function mediaUpload( { + allowedType, + additionalData = {}, + filesList, + maxUploadFileSize, + onError = noop, + onFileChange, + allowedMimeTypes = null, +} ) { + // Cast filesList to array + const files = [ ...filesList ]; + + const filesSet = []; + const setAndUpdateFiles = ( idx, value ) => { + filesSet[ idx ] = value; + onFileChange( compact( filesSet ) ); + }; + + // Allowed type specified by consumer + const isAllowedType = ( fileType ) => { + return ( allowedType === '*' ) || startsWith( fileType, `${ allowedType }/` ); + }; + + // Allowed types for the current WP_User + const allowedMimeTypesForUser = getMimeTypesArray( allowedMimeTypes ); + const isAllowedMimeTypeForUser = ( fileType ) => { + return includes( allowedMimeTypesForUser, fileType ); + }; + + files.forEach( ( mediaFile, idx ) => { + if ( ! isAllowedType( mediaFile.type ) ) { + return; + } + + // verify if user is allowed to upload this mime type + if ( allowedMimeTypesForUser && ! isAllowedMimeTypeForUser( mediaFile.type ) ) { + onError( { + code: 'MIME_TYPE_NOT_ALLOWED_FOR_USER', + message: __( 'Sorry, this file type is not permitted for security reasons.' ), + file: mediaFile, + } ); + return; + } + + // verify if file is greater than the maximum file upload size allowed for the site. + if ( maxUploadFileSize && mediaFile.size > maxUploadFileSize ) { + onError( { + code: 'SIZE_ABOVE_LIMIT', + message: sprintf( + // translators: %s: file name + __( '%s exceeds the maximum upload size for this site.' ), + mediaFile.name + ), + file: mediaFile, + } ); + return; + } + + // Set temporary URL to create placeholder media file, this is replaced + // with final file from media gallery when upload is `done` below + filesSet.push( { url: window.URL.createObjectURL( mediaFile ) } ); + onFileChange( filesSet ); + + return createMediaFromFile( mediaFile, additionalData ) + .then( ( savedMedia ) => { + const mediaObject = { + alt: savedMedia.alt_text, + caption: get( savedMedia, [ 'caption', 'raw' ], '' ), + id: savedMedia.id, + link: savedMedia.link, + title: savedMedia.title.raw, + url: savedMedia.source_url, + mediaDetails: {}, + }; + if ( has( savedMedia, [ 'media_details', 'sizes' ] ) ) { + mediaObject.mediaDetails.sizes = get( savedMedia, [ 'media_details', 'sizes' ], {} ); + } + setAndUpdateFiles( idx, mediaObject ); + } ) + .catch( ( error ) => { + // Reset to empty on failure. + setAndUpdateFiles( idx, null ); + let message; + if ( has( error, [ 'message' ] ) ) { + message = get( error, [ 'message' ] ); + } else { + message = sprintf( + // translators: %s: file name + __( 'Error while uploading file %s to the media library.' ), + mediaFile.name + ); + } + onError( { + code: 'GENERAL', + message, + file: mediaFile, + } ); + } ); + } ); +} + +/** + * @param {File} file Media File to Save. + * @param {?Object} additionalData Additional data to include in the request. + * + * @return {Promise} Media Object Promise. + */ +function createMediaFromFile( file, additionalData ) { + // Create upload payload + const data = new window.FormData(); + data.append( 'file', file, file.name || file.type.replace( '/', '.' ) ); + forEach( additionalData, ( ( value, key ) => data.append( key, value ) ) ); + return apiFetch( { + path: '/wp/v2/media', + body: data, + method: 'POST', + } ); +} diff --git a/utils/test/mediaupload.js b/editor/utils/media-upload/test/media-upload.js similarity index 73% rename from utils/test/mediaupload.js rename to editor/utils/media-upload/test/media-upload.js index 35dca2906e2499..9090bad7467017 100644 --- a/utils/test/mediaupload.js +++ b/editor/utils/media-upload/test/media-upload.js @@ -1,14 +1,7 @@ -/* eslint-disable no-console */ - /** * Internal dependencies */ -import { mediaUpload, getMimeTypesArray } from '../mediaupload'; - -// mediaUpload is passed the onImagesChange function -// so we can stub that out have it pass the data to -// console.error to check if proper thing is called -const onFileChange = ( obj ) => console.error( obj ); +import { mediaUpload, getMimeTypesArray } from '../media-upload'; const invalidMediaObj = { url: 'https://cldup.com/uuUqE_dXzy.jpg', @@ -23,34 +16,25 @@ const validMediaObj = { }; describe( 'mediaUpload', () => { - const originalConsoleError = console.error; - const originalGetUserSetting = window.getUserSetting; - - beforeEach( () => { - console.error = jest.fn(); - } ); - - afterEach( () => { - console.error = originalConsoleError; - window.getUserSetting = originalGetUserSetting; - } ); + const onFileChangeSpy = jest.fn(); it( 'should do nothing on no files', () => { - mediaUpload( { filesList: [ ], onFileChange, allowedType: 'image' } ); - expect( console.error ).not.toHaveBeenCalled(); + mediaUpload( { filesList: [ ], onFileChange: onFileChangeSpy, allowedType: 'image' } ); + expect( onFileChangeSpy ).not.toHaveBeenCalled(); } ); it( 'should do nothing on invalid image type', () => { - mediaUpload( { filesList: [ invalidMediaObj ], onFileChange, allowedType: 'image' } ); - expect( console.error ).not.toHaveBeenCalled(); + mediaUpload( { filesList: [ invalidMediaObj ], onFileChange: onFileChangeSpy, allowedType: 'image' } ); + expect( onFileChangeSpy ).not.toHaveBeenCalled(); } ); it( 'should call error handler with the correct error object if file size is greater than the maximum', () => { const onError = jest.fn(); + mediaUpload( { allowedType: 'image', filesList: [ validMediaObj ], - onFileChange, + onFileChange: onFileChangeSpy, maxUploadFileSize: 512, onError, } ); @@ -63,14 +47,14 @@ describe( 'mediaUpload', () => { it( 'should call error handler with the correct error object if file type is not allowed for user', () => { const onError = jest.fn(); - global._wpMediaSettings = { - allowedMimeTypes: { aac: 'audio/aac' }, - }; + const allowedMimeTypes = { aac: 'audio/aac' }; + mediaUpload( { allowedType: 'image', filesList: [ validMediaObj ], - onFileChange, + onFileChange: onFileChangeSpy, onError, + allowedMimeTypes, } ); expect( onError ).toBeCalledWith( { code: 'MIME_TYPE_NOT_ALLOWED_FOR_USER', diff --git a/lib/client-assets.php b/lib/client-assets.php index 8b93863e4f89dc..dba04765eb2229 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -227,7 +227,7 @@ function gutenberg_register_scripts_and_styles() { wp_register_script( 'wp-utils', gutenberg_url( 'build/utils/index.js' ), - array( 'lodash', 'wp-api-fetch', 'wp-deprecated', 'wp-html-entities', 'wp-i18n', 'wp-keycodes' ), + array( 'lodash', 'wp-api-fetch', 'wp-deprecated', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-editor' ), filemtime( gutenberg_dir_path() . 'build/utils/index.js' ), true ); @@ -458,7 +458,6 @@ function gutenberg_register_scripts_and_styles() { 'wp-keycodes', 'wp-element', 'wp-plugins', - 'wp-utils', 'wp-viewport', 'wp-tinymce', 'tinymce-latest-lists', @@ -1093,6 +1092,7 @@ function gutenberg_editor_scripts_and_styles( $hook ) { // https://github.com/WordPress/gutenberg/issues/5667. add_filter( 'user_can_richedit', '__return_true' ); + wp_enqueue_script( 'wp-utils' ); wp_enqueue_script( 'wp-edit-post' ); global $post; @@ -1160,16 +1160,6 @@ function gutenberg_editor_scripts_and_styles( $hook ) { ); } - $max_upload_size = wp_max_upload_size(); - if ( ! $max_upload_size ) { - $max_upload_size = 0; - } - // Initialize media settings. - wp_add_inline_script( 'wp-editor', 'window._wpMediaSettings = ' . wp_json_encode( array( - 'maxUploadSize' => $max_upload_size, - 'allowedMimeTypes' => get_allowed_mime_types(), - ) ), 'before' ); - // Prepare Jed locale data. $locale_data = gutenberg_get_jed_locale_data( 'gutenberg' ); wp_add_inline_script( @@ -1251,6 +1241,12 @@ function gutenberg_editor_scripts_and_styles( $hook ) { '' => apply_filters( 'default_page_template_title', __( 'Default template', 'gutenberg' ), 'rest-api' ), ), $available_templates ) : $available_templates; + // Media settings. + $max_upload_size = wp_max_upload_size(); + if ( ! $max_upload_size ) { + $max_upload_size = 0; + } + $editor_settings = array( 'alignWide' => $align_wide || ! empty( $gutenberg_theme_support[0]['wide-images'] ), // Backcompat. Use `align-wide` outside of `gutenberg` array. 'availableTemplates' => $available_templates, @@ -1261,6 +1257,8 @@ function gutenberg_editor_scripts_and_styles( $hook ) { 'bodyPlaceholder' => apply_filters( 'write_your_story', __( 'Write your story', 'gutenberg' ), $post ), 'isRTL' => is_rtl(), 'autosaveInterval' => 10, + 'maxUploadFileSize' => $max_upload_size, + 'allowedMimeTypes' => get_allowed_mime_types(), ); $post_autosave = get_autosave_newer_than_post_save( $post ); diff --git a/utils/index.js b/utils/index.js index c96efed8801f9a..d206dc2362eea7 100644 --- a/utils/index.js +++ b/utils/index.js @@ -1,4 +1,3 @@ -export * from './mediaupload'; - // Deprecations export * from './deprecated'; +export * from './mediaupload'; diff --git a/utils/mediaupload.js b/utils/mediaupload.js index 20e38427ab8e2d..af592a2e8beb67 100644 --- a/utils/mediaupload.js +++ b/utils/mediaupload.js @@ -6,12 +6,10 @@ import { compact, flatMap, forEach, get, has, includes, map, noop, startsWith } /** * WordPress dependencies */ +import deprecated from '@wordpress/deprecated'; import { __, sprintf } from '@wordpress/i18n'; - -/** - * WordPress dependencies - */ import apiFetch from '@wordpress/api-fetch'; +import { select } from '@wordpress/data'; /** * Browsers may use unexpected mime types, and they differ from browser to browser. @@ -27,6 +25,11 @@ import apiFetch from '@wordpress/api-fetch'; * @return {?Array} An array of mime types or the parameter passed if it was "falsy". */ export function getMimeTypesArray( wpMimeTypesObject ) { + deprecated( 'wp.utils.getMimeTypesArray', { + version: '3.6', + plugin: 'Gutenberg', + } ); + if ( ! wpMimeTypesObject ) { return wpMimeTypesObject; } @@ -55,10 +58,19 @@ export function mediaUpload( { allowedType, additionalData = {}, filesList, - maxUploadFileSize = get( window, [ '_wpMediaSettings', 'maxUploadSize' ], 0 ), + maxUploadFileSize, onError = noop, onFileChange, } ) { + deprecated( 'wp.utils.mediaUpload', { + version: '3.6', + alternative: 'wp.editor.mediaUpload', + plugin: 'Gutenberg', + } ); + + const editorSettings = select( 'core/editor' ).getSettings(); + maxUploadFileSize = maxUploadFileSize || editorSettings.maxUploadFileSize; + // Cast filesList to array const files = [ ...filesList ]; @@ -74,7 +86,7 @@ export function mediaUpload( { }; // Allowed types for the current WP_User - const allowedMimeTypesForUser = getMimeTypesArray( get( window, [ '_wpMediaSettings', 'allowedMimeTypes' ] ) ); + const allowedMimeTypesForUser = getMimeTypesArray( editorSettings.allowedMimeTypes ); const isAllowedMimeTypeForUser = ( fileType ) => { return includes( allowedMimeTypesForUser, fileType ); }; @@ -176,6 +188,11 @@ function createMediaFromFile( file, additionalData ) { * @return {Promise} Promise resolved once the image is preloaded. */ export function preloadImage( url ) { + deprecated( 'wp.utils.preloadImage', { + version: '3.6', + plugin: 'Gutenberg', + } ); + return new Promise( ( resolve ) => { const newImg = new window.Image(); newImg.onload = function() { From 1533c334ee233a96f0df84e6f587c7551b5c4aab Mon Sep 17 00:00:00 2001 From: Miguel Fonseca Date: Mon, 23 Jul 2018 13:58:15 +0100 Subject: [PATCH 04/17] Docs: Add example for registerBlockType hook (#8091) * Docs: Add example for registerBlockType hook * Rewrite example using ES5 syntax and wp.* globals --- docs/extensibility/extending-blocks.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/extensibility/extending-blocks.md b/docs/extensibility/extending-blocks.md index 59a8e6418edc91..0c774397b7804f 100644 --- a/docs/extensibility/extending-blocks.md +++ b/docs/extensibility/extending-blocks.md @@ -10,6 +10,30 @@ To modify the behavior of existing blocks, Gutenberg exposes the following Filte Used to filter the block settings. It receives the block settings and the name of the block the registered block as arguments. +_Example:_ + +Ensure that List blocks are saved with the canonical generated class name (`wp-block-list`): + +```js +function addListBlockClassName( settings, name ) { + if ( name !== 'core/list' ) { + return settings; + } + + return Object.assign( {}, settings, { + supports: Object.assign( {}, settings.supports, { + className: true + } ), + } ); +} + +wp.hooks.addFilter( + 'blocks.registerBlockType', + 'my-plugin/class-names/list-block', + addListBlockClassName +); +``` + #### `blocks.getSaveElement` A filter that applies to the result of a block's `save` function. This filter is used to replace or extend the element, for example using `wp.element.cloneElement` to modify the element's props or replace its children, or returning an entirely new element. From 5f69fc897e4d013b313202e5963e2d21225b3c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= Date: Mon, 23 Jul 2018 15:59:17 +0200 Subject: [PATCH 05/17] Update is-shallow-equal to use ES5 code as before (#8132) * Update is-shallow-equal to use ES5 code as before * Fix order of properties in package.json of is-shallow-equal --- packages/is-shallow-equal/.eslintrc.json | 5 +++++ packages/is-shallow-equal/{src => }/arrays.js | 8 ++++++-- packages/is-shallow-equal/{src => }/index.js | 15 +++++++-------- .../is-shallow-equal/{src => }/objects.js | 19 ++++++++++--------- packages/is-shallow-equal/package.json | 7 +++++-- .../is-shallow-equal/{src => }/test/index.js | 0 webpack.config.js | 2 +- 7 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 packages/is-shallow-equal/.eslintrc.json rename packages/is-shallow-equal/{src => }/arrays.js (81%) rename packages/is-shallow-equal/{src => }/index.js (73%) rename packages/is-shallow-equal/{src => }/objects.js (73%) rename packages/is-shallow-equal/{src => }/test/index.js (100%) diff --git a/packages/is-shallow-equal/.eslintrc.json b/packages/is-shallow-equal/.eslintrc.json new file mode 100644 index 00000000000000..118dc091c3c8a3 --- /dev/null +++ b/packages/is-shallow-equal/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-var": 0 + } +} diff --git a/packages/is-shallow-equal/src/arrays.js b/packages/is-shallow-equal/arrays.js similarity index 81% rename from packages/is-shallow-equal/src/arrays.js rename to packages/is-shallow-equal/arrays.js index b11693ce1e8654..950224a8c8c50a 100644 --- a/packages/is-shallow-equal/src/arrays.js +++ b/packages/is-shallow-equal/arrays.js @@ -1,3 +1,5 @@ +'use strict'; + /** * Returns true if the two arrays are shallow equal, or false otherwise. * @@ -7,6 +9,8 @@ * @return {boolean} Whether the two arrays are shallow equal. */ function isShallowEqualArrays( a, b ) { + var i; + if ( a === b ) { return true; } @@ -15,7 +19,7 @@ function isShallowEqualArrays( a, b ) { return false; } - for ( let i = 0; i < a.length; i++ ) { + for ( i = 0; i < a.length; i++ ) { if ( a[ i ] !== b[ i ] ) { return false; } @@ -24,4 +28,4 @@ function isShallowEqualArrays( a, b ) { return true; } -export default isShallowEqualArrays; +module.exports = isShallowEqualArrays; diff --git a/packages/is-shallow-equal/src/index.js b/packages/is-shallow-equal/index.js similarity index 73% rename from packages/is-shallow-equal/src/index.js rename to packages/is-shallow-equal/index.js index 8ccdec24924335..8ab40b0cf25d73 100644 --- a/packages/is-shallow-equal/src/index.js +++ b/packages/is-shallow-equal/index.js @@ -1,13 +1,12 @@ -/** - * Internal dependencies - */ -import isShallowEqualObjects from './objects'; -import isShallowEqualArrays from './arrays'; +'use strict'; /** - * Local variables + * Internal dependencies; */ -const { isArray } = Array; +var isShallowEqualObjects = require( './objects' ); +var isShallowEqualArrays = require( './arrays' ); + +var isArray = Array.isArray; /** * Returns true if the two arrays or objects are shallow equal, or false @@ -30,4 +29,4 @@ function isShallowEqual( a, b ) { return a === b; } -export default isShallowEqual; +module.exports = isShallowEqual; diff --git a/packages/is-shallow-equal/src/objects.js b/packages/is-shallow-equal/objects.js similarity index 73% rename from packages/is-shallow-equal/src/objects.js rename to packages/is-shallow-equal/objects.js index e02ed8469367e7..12df62d2a04075 100644 --- a/packages/is-shallow-equal/src/objects.js +++ b/packages/is-shallow-equal/objects.js @@ -1,7 +1,6 @@ -/** - * Local variables - */ -const { keys } = Object; +'use strict'; + +var keys = Object.keys; /** * Returns true if the two objects are shallow equal, or false otherwise. @@ -12,21 +11,23 @@ const { keys } = Object; * @return {boolean} Whether the two objects are shallow equal. */ function isShallowEqualObjects( a, b ) { + var aKeys, bKeys, i, key; + if ( a === b ) { return true; } - const aKeys = keys( a ); - const bKeys = keys( b ); + aKeys = keys( a ); + bKeys = keys( b ); if ( aKeys.length !== bKeys.length ) { return false; } - let i = 0; + i = 0; while ( i < aKeys.length ) { - const key = aKeys[ i ]; + key = aKeys[ i ]; if ( a[ key ] !== b[ key ] ) { return false; } @@ -37,4 +38,4 @@ function isShallowEqualObjects( a, b ) { return true; } -export default isShallowEqualObjects; +module.exports = isShallowEqualObjects; diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index 9de339c3178cd4..722049d5a4fb93 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -18,8 +18,11 @@ "bugs": { "url": "https://github.com/WordPress/gutenberg/issues" }, - "main": "build/index.js", - "module": "build-module/index.js", + "files": [ + "arrays.js", + "objects.js" + ], + "main": "index.js", "dependencies": { "@babel/runtime": "^7.0.0-beta.52" }, diff --git a/packages/is-shallow-equal/src/test/index.js b/packages/is-shallow-equal/test/index.js similarity index 100% rename from packages/is-shallow-equal/src/test/index.js rename to packages/is-shallow-equal/test/index.js diff --git a/webpack.config.js b/webpack.config.js index fcb61fd7487d19..49528634399c4b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -163,6 +163,7 @@ const config = { test: /\.js$/, exclude: [ /block-serialization-spec-parser/, + /is-shallow-equal/, /node_modules/, ], use: 'babel-loader', @@ -233,7 +234,6 @@ const config = { 'api-fetch', 'deprecated', 'dom-ready', - 'is-shallow-equal', ].map( camelCaseDash ) ), ], stats: { From 4b7f8295055293772d79576917f81781e00f7d81 Mon Sep 17 00:00:00 2001 From: "Nahid F. Mohit" Date: Mon, 23 Jul 2018 20:32:31 +0600 Subject: [PATCH 06/17] Update block alignment setting to use "supports: align" block alignment hook instead of "align" attribute (#7100) * Update block-alignment setting to use supports:align instead of align attribute * Update block-alignment setting to use supports:align instead of align attribute * Exclude Categories block from PR * Update tests to adapt with new supports: align option * Reset changes made in categories block * Fixed deprecated blocks, removed unnecessary components * Fixed code formatting issues and tests * Some more refinements to the button and gallery blocks --- core-blocks/button/edit.js | 11 --- core-blocks/button/index.js | 31 ++++--- core-blocks/embed/index.js | 80 +++++++------------ core-blocks/gallery/edit.js | 10 --- core-blocks/gallery/index.js | 22 +++-- core-blocks/pullquote/index.js | 77 +++++++----------- core-blocks/table/index.js | 26 ++---- core-blocks/test/fixtures/core__gallery.html | 2 +- core-blocks/test/fixtures/core__gallery.json | 3 +- .../test/fixtures/core__gallery.parsed.json | 2 +- .../fixtures/core__gallery.serialized.html | 2 +- .../test/fixtures/core__gallery__columns.html | 2 +- .../test/fixtures/core__gallery__columns.json | 3 +- .../core__gallery__columns.parsed.json | 2 +- .../core__gallery__columns.serialized.html | 2 +- .../test/fixtures/core__pullquote.html | 2 +- .../test/fixtures/core__pullquote.json | 5 +- .../test/fixtures/core__pullquote.parsed.json | 2 +- .../fixtures/core__pullquote.serialized.html | 2 +- .../core__pullquote__multi-paragraph.html | 2 +- .../core__pullquote__multi-paragraph.json | 5 +- ...re__pullquote__multi-paragraph.parsed.json | 2 +- ...pullquote__multi-paragraph.serialized.html | 2 +- test/integration/fixtures/wordpress-out.html | 2 +- 24 files changed, 105 insertions(+), 194 deletions(-) diff --git a/core-blocks/button/edit.js b/core-blocks/button/edit.js index b9a95d10f10812..a7b39cb90d8365 100644 --- a/core-blocks/button/edit.js +++ b/core-blocks/button/edit.js @@ -16,8 +16,6 @@ import { import { URLInput, RichText, - BlockControls, - BlockAlignmentToolbar, ContrastChecker, InspectorControls, withColors, @@ -46,11 +44,6 @@ class ButtonEdit extends Component { super( ...arguments ); this.nodeRef = null; this.bindRef = this.bindRef.bind( this ); - this.updateAlignment = this.updateAlignment.bind( this ); - } - - updateAlignment( nextAlign ) { - this.props.setAttributes( { align: nextAlign } ); } bindRef( node ) { @@ -76,14 +69,10 @@ class ButtonEdit extends Component { text, url, title, - align, } = attributes; return ( - - - +
setAttributes( { align: nextAlign } ); - - const controls = ( - - - - ); if ( fetching ) { return ( - - { controls } -
- -

{ __( 'Embedding…' ) }

-
-
+
+ +

{ __( 'Embedding…' ) }

+
); } @@ -213,26 +192,23 @@ function getEmbedBlockSettings( { title, description, icon, category = 'embed', const label = sprintf( __( '%s URL' ), title ); return ( - - { controls } - -
- setAttributes( { url: event.target.value } ) } /> - - { error &&

{ __( 'Sorry, we could not embed that content.' ) }

} -
-
-
+ +
+ setAttributes( { url: event.target.value } ) } /> + + { error &&

{ __( 'Sorry, we could not embed that content.' ) }

} +
+
); } @@ -257,7 +233,6 @@ function getEmbedBlockSettings( { title, description, icon, category = 'embed', return ( - { controls }
{ ( cannotPreview ) ? ( @@ -281,14 +256,13 @@ function getEmbedBlockSettings( { title, description, icon, category = 'embed', }, save( { attributes } ) { - const { url, caption, align, type, providerNameSlug } = attributes; + const { url, caption, type, providerNameSlug } = attributes; if ( ! url ) { return null; } const embedClassName = classnames( 'wp-block-embed', { - [ `align${ align }` ]: align, [ `is-type-${ type }` ]: type, [ `is-provider-${ providerNameSlug }` ]: providerNameSlug, } ); diff --git a/core-blocks/gallery/edit.js b/core-blocks/gallery/edit.js index c706ea74817d11..b38d95007466fc 100644 --- a/core-blocks/gallery/edit.js +++ b/core-blocks/gallery/edit.js @@ -21,7 +21,6 @@ import { } from '@wordpress/components'; import { BlockControls, - BlockAlignmentToolbar, MediaUpload, MediaPlaceholder, InspectorControls, @@ -53,7 +52,6 @@ class GalleryEdit extends Component { this.onSelectImages = this.onSelectImages.bind( this ); this.setLinkTo = this.setLinkTo.bind( this ); this.setColumnsNumber = this.setColumnsNumber.bind( this ); - this.updateAlignment = this.updateAlignment.bind( this ); this.toggleImageCrop = this.toggleImageCrop.bind( this ); this.onRemoveImage = this.onRemoveImage.bind( this ); this.setImageAttributes = this.setImageAttributes.bind( this ); @@ -101,10 +99,6 @@ class GalleryEdit extends Component { this.props.setAttributes( { columns: value } ); } - updateAlignment( nextAlign ) { - this.props.setAttributes( { align: nextAlign } ); - } - toggleImageCrop() { this.props.setAttributes( { imageCrop: ! this.props.attributes.imageCrop } ); } @@ -171,10 +165,6 @@ class GalleryEdit extends Component { const controls = ( - { !! images.length && ( +