From 1a6817e1045194647e9053e953e6eb3c3f2f8aec Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 2 Oct 2017 13:16:03 +0100 Subject: [PATCH 01/13] Framework: Use a simple JS object to declare the attribute's source --- blocks/api/index.js | 6 - blocks/api/parser.js | 158 ++++++++---------- .../api/raw-handling/shortcode-converter.js | 10 +- blocks/api/registration.js | 20 ++- blocks/api/serializer.js | 2 +- blocks/api/source.js | 37 +--- blocks/library/audio/index.js | 15 +- blocks/library/button/index.js | 24 ++- blocks/library/code/index.js | 10 +- blocks/library/cover-image/index.js | 9 +- blocks/library/embed/index.js | 9 +- blocks/library/freeform/index.js | 9 +- blocks/library/gallery/index.js | 30 +++- blocks/library/heading/index.js | 15 +- blocks/library/html/index.js | 8 +- blocks/library/image/index.js | 49 ++++-- blocks/library/list/index.js | 15 +- blocks/library/paragraph/index.js | 9 +- blocks/library/preformatted/index.js | 9 +- blocks/library/pullquote/index.js | 17 +- blocks/library/quote/index.js | 17 +- blocks/library/shortcode/index.js | 8 +- blocks/library/table/index.js | 9 +- blocks/library/text-columns/index.js | 12 +- blocks/library/verse/index.js | 9 +- blocks/library/video/index.js | 15 +- editor/modes/visual-editor/block.js | 6 +- editor/selectors.js | 4 +- 28 files changed, 302 insertions(+), 239 deletions(-) diff --git a/blocks/api/index.js b/blocks/api/index.js index 4cb6c022af85da..f1c7204ff0c530 100644 --- a/blocks/api/index.js +++ b/blocks/api/index.js @@ -1,9 +1,3 @@ -/** - * External dependencies - */ -import * as source from './source'; - -export { source }; export { createBlock, switchToBlockType, createReusableBlock } from './factory'; export { default as parse, getSourcedAttributes } from './parser'; export { default as rawHandler } from './raw-handling'; diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 159f8c9ecdb7bc..cd4643e0b1666d 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -2,7 +2,7 @@ * External dependencies */ import { parse as hpqParse } from 'hpq'; -import { mapValues, reduce, pickBy } from 'lodash'; +import { keys } from 'lodash'; /** * Internal dependencies @@ -12,42 +12,7 @@ import { getBlockType, getUnknownTypeHandlerName } from './registration'; import { createBlock } from './factory'; import { isValidBlock } from './validation'; import { getCommentDelimitedContent } from './serializer'; - -/** - * Returns true if the provided function is a valid attribute source, or false - * otherwise. - * - * Sources are implemented as functions receiving a DOM node to select data - * from. Using the DOM is incidental and we shouldn't guarantee a contract that - * this be provided, else block implementers may feel inclined to use the node. - * Instead, sources are intended as a generic interface to query data from any - * tree shape. Here we pick only sources which include an internal flag. - * - * @param {Function} source Function to test - * @return {Boolean} Whether function is an attribute source - */ -export function isValidSource( source ) { - return !! source && '_wpBlocksKnownSource' in source; -} - -/** - * Returns the block attributes parsed from raw content. - * - * @param {String} innerHTML Raw block content - * @param {Object} schema Block attribute schema - * @return {Object} Block attribute values - */ -export function getSourcedAttributes( innerHTML, schema ) { - const sources = mapValues( - // Parse only sources with source defined - pickBy( schema, ( attributeSchema ) => isValidSource( attributeSchema.source ) ), - - // Transform to object where source is value - ( attributeSchema ) => attributeSchema.source - ); - - return hpqParse( innerHTML, sources ); -} +import { attr, prop, html, text, query, node, children } from './source'; /** * Returns value coerced to the specified JSON schema type string @@ -87,6 +52,69 @@ export function asType( value, type ) { return value; } +/** + * Returns an hpq matcher given a source object + * + * @param {Object} source Attribute Source object + * @return {Function} hpq Matcher + */ +export function matcherFromSource( source ) { + switch ( source.type ) { + case 'attribute': + return attr( source.selector, source.attribute ); + case 'property': + return prop( source.selector, source.property ); + case 'html': + return html( source.selector ); + case 'text': + return text( source.selector ); + case 'children': + return children( source.selector ); + case 'node': + return node( source.selector ); + case 'query': + return query( source.selector, matcherFromSource( source.source ) ); + case 'object': + return keys( source.source ).reduce( ( memo, key ) => { + memo[ key ] = matcherFromSource( source.source[ key ] ); + return memo; + }, {} ); + default: + // eslint-disable-next-line no-console + console.error( `Unkown source type "${ source.type }"` ); + } +} + +/** + * Given a blocktype, a block's raw content and the commentAttributes returns the attribute value depending on its source definition + * + * @param {string} attributeKey Attribute key + * @param {Object} attributeSchema Attribute's schema + * @param {string} innerHTML Block's raw content + * @param {Object} commentAttributes Block's comment attributes + * + * @return {mixed} Attribute value + */ +export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, commentAttributes ) { + let value; + switch ( attributeSchema.source.type ) { + case 'meta': + break; + case 'comment': + value = commentAttributes ? commentAttributes[ attributeKey ] : undefined; + break; + default: { + // Coerce value to specified type + const matcher = matcherFromSource( attributeSchema.source ); + const rawValue = hpqParse( innerHTML, matcher ); + value = rawValue === undefined ? rawValue : asType( rawValue, attributeSchema.type ); + break; + } + } + + return value === undefined ? attributeSchema.default : value; +} + /** * Returns the block attributes of a registered block node given its type. * @@ -96,57 +124,11 @@ export function asType( value, type ) { * @return {Object} All block attributes */ export function getBlockAttributes( blockType, innerHTML, attributes ) { - // Retrieve additional attributes sourced from content - const sourcedAttributes = getSourcedAttributes( - innerHTML, - blockType.attributes - ); - - const blockAttributes = reduce( blockType.attributes, ( result, source, key ) => { - let value; - if ( sourcedAttributes.hasOwnProperty( key ) ) { - value = sourcedAttributes[ key ]; - } else if ( attributes ) { - value = attributes[ key ]; - } - - // Return default if attribute value not assigned - if ( undefined === value ) { - // Nest the condition so that constructor coercion never occurs if - // value is undefined and block type doesn't specify default value - if ( 'default' in source ) { - value = source.default; - } else { - return result; - } - } - - // Coerce value to specified type - const coercedValue = asType( value, source.type ); - - if ( 'development' === process.env.NODE_ENV && - ! sourcedAttributes.hasOwnProperty( key ) && - value !== coercedValue ) { - // Only in case of sourcing attribute from content do we want to - // allow coercion, as comment attributes are serialized respecting - // original data type. In development environments, log if value - // coerced to specified type is not strictly equal. We still allow - // coerced value to be assigned into attributes to avoid errors. - // - // Example: - // Number( 5 ) === 5 - // Number( '5' ) !== '5' - - // eslint-disable-next-line no-console - console.error( - `Expected attribute "${ key }" of type ${ source.type } for ` + - `block type "${ blockType.name }" but received ${ typeof value }.` - ); - } - - result[ key ] = coercedValue; - return result; - }, {} ); + const blockAttributes = keys( blockType.attributes ).reduce( ( memo, attributeKey ) => { + const attributeSchema = blockType.attributes[ attributeKey ]; + memo[ attributeKey ] = getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes ); + return memo; + }, {} ) || {}; // If the block supports a custom className parse it if ( blockType.className !== false && attributes && attributes.className ) { diff --git a/blocks/api/raw-handling/shortcode-converter.js b/blocks/api/raw-handling/shortcode-converter.js index 0b429b8063dce9..d4bd40beae1bdc 100644 --- a/blocks/api/raw-handling/shortcode-converter.js +++ b/blocks/api/raw-handling/shortcode-converter.js @@ -36,12 +36,20 @@ export default function( HTML ) { ( schema ) => schema.shortcode( match.shortcode.attrs ), ); + console.log( mapValues( transform.attributes, attribute => ( { + source: { type: 'comment' }, + ...attribute, + } ) ) ); + const block = createBlock( blockType.name, getBlockAttributes( { ...blockType, - attributes: transform.attributes, + attributes: mapValues( transform.attributes, attribute => ( { + source: { type: 'comment' }, + ...attribute, + } ) ), }, match.shortcode.content, attributes, diff --git a/blocks/api/registration.js b/blocks/api/registration.js index b220d9778f9317..c3139572864651 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -3,7 +3,7 @@ /** * External dependencies */ -import { get, isFunction, some } from 'lodash'; +import { get, isFunction, some, mapValues } from 'lodash'; /** * WordPress dependencies @@ -118,15 +118,23 @@ export function registerBlockType( name, settings ) { if ( ! settings.icon ) { settings.icon = 'block-default'; } - settings = { - name, - attributes: get( window._wpBlocksAttributes, name ), + + const attributes = settings.attributes ? + settings.attributes : + get( window._wpBlocksAttributes, name ); + + let block = blocks[ name ] = { ...settings, + name, + attributes: mapValues( attributes, ( attribute ) => ( { + source: { type: 'comment' }, + ...attribute, + } ) ), }; - settings = applyFilters( 'registerBlockType', settings, name ); + block = applyFilters( 'registerBlockType', block, name ); - return blocks[ name ] = settings; + return blocks[ name ] = block; } /** diff --git a/blocks/api/serializer.js b/blocks/api/serializer.js index 4c88e5275fb110..2c850d1ce3edc9 100644 --- a/blocks/api/serializer.js +++ b/blocks/api/serializer.js @@ -99,7 +99,7 @@ export function getCommentAttributes( allAttributes, blockType ) { } // Ignore values sources from content and post meta - if ( attributeSchema.source || attributeSchema.meta ) { + if ( attributeSchema.source.type !== 'comment' ) { return result; } diff --git a/blocks/api/source.js b/blocks/api/source.js index eee04d56e604fa..0ccf4cf8d8832b 100644 --- a/blocks/api/source.js +++ b/blocks/api/source.js @@ -7,35 +7,9 @@ import { createElement } from '@wordpress/element'; * External dependencies */ import { nodeListToReact, nodeToReact } from 'dom-react'; -import { flow } from 'lodash'; -import { - attr as originalAttr, - prop as originalProp, - html as originalHtml, - text as originalText, - query as originalQuery, -} from 'hpq'; +export { attr, prop, html, text, query } from 'hpq'; -/** - * Given a source function creator, returns a new function which applies an - * internal flag to the created source. - * - * @param {Function} fn Original source function creator - * @return {Function} Modified source function creator - */ -function withKnownSourceFlag( fn ) { - return flow( fn, ( source ) => { - source._wpBlocksKnownSource = true; - return source; - } ); -} - -export const attr = withKnownSourceFlag( originalAttr ); -export const prop = withKnownSourceFlag( originalProp ); -export const html = withKnownSourceFlag( originalHtml ); -export const text = withKnownSourceFlag( originalText ); -export const query = withKnownSourceFlag( originalQuery ); -export const children = withKnownSourceFlag( ( selector ) => { +export const children = ( selector ) => { return ( domNode ) => { let match = domNode; @@ -49,8 +23,9 @@ export const children = withKnownSourceFlag( ( selector ) => { return []; }; -} ); -export const node = withKnownSourceFlag( ( selector ) => { +}; + +export const node = ( selector ) => { return ( domNode ) => { let match = domNode; @@ -60,4 +35,4 @@ export const node = withKnownSourceFlag( ( selector ) => { return nodeToReact( match, createElement ); }; -} ); +}; diff --git a/blocks/library/audio/index.js b/blocks/library/audio/index.js index ba112bc16e8632..664b002dc975b6 100644 --- a/blocks/library/audio/index.js +++ b/blocks/library/audio/index.js @@ -13,7 +13,7 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import MediaUploadButton from '../../media-upload-button'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; @@ -21,8 +21,6 @@ import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { attr, children } = source; - registerBlockType( 'core/audio', { title: __( 'Audio' ), @@ -33,14 +31,21 @@ registerBlockType( 'core/audio', { attributes: { src: { type: 'string', - source: attr( 'audio', 'src' ), + source: { + type: 'attribute', + selector: 'audio', + attribute: 'src', + }, }, align: { type: 'string', }, caption: { type: 'array', - source: children( 'figcaption' ), + source: { + type: 'children', + selector: 'figcaption', + }, }, }, diff --git a/blocks/library/button/index.js b/blocks/library/button/index.js index e7edef6b8bd199..df030218fbac62 100644 --- a/blocks/library/button/index.js +++ b/blocks/library/button/index.js @@ -10,7 +10,7 @@ import { Dashicon, IconButton, PanelBody } from '@wordpress/components'; */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import UrlInput from '../../url-input'; import BlockControls from '../../block-controls'; @@ -21,7 +21,6 @@ import ContrastChecker from '../../contrast-checker'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { attr, children } = source; const { getComputedStyle } = window; class ButtonBlock extends Component { @@ -181,15 +180,26 @@ registerBlockType( 'core/button', { attributes: { url: { type: 'string', - source: attr( 'a', 'href' ), + source: { + type: 'attribute', + selector: 'a', + attribute: 'href', + }, }, title: { type: 'string', - source: attr( 'a', 'title' ), + source: { + type: 'attribute', + selector: 'a', + attribute: 'title', + }, }, text: { type: 'array', - source: children( 'a' ), + source: { + type: 'children', + selector: 'a', + }, }, align: { type: 'string', @@ -218,9 +228,7 @@ registerBlockType( 'core/button', { return props; }, - edit( props ) { - return ; - }, + edit: ButtonBlock, save( { attributes } ) { const { url, text, title, align, color, textColor } = attributes; diff --git a/blocks/library/code/index.js b/blocks/library/code/index.js index 3fbfad5bd57633..30d9ef17731f1d 100644 --- a/blocks/library/code/index.js +++ b/blocks/library/code/index.js @@ -12,12 +12,10 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { prop } = source; - registerBlockType( 'core/code', { title: __( 'Code' ), @@ -28,7 +26,11 @@ registerBlockType( 'core/code', { attributes: { content: { type: 'string', - source: prop( 'code', 'textContent' ), + source: { + type: 'property', + selector: 'code', + property: 'textContent', + }, }, }, diff --git a/blocks/library/cover-image/index.js b/blocks/library/cover-image/index.js index aeed1dbde6b1ec..8119d6f5705a4b 100644 --- a/blocks/library/cover-image/index.js +++ b/blocks/library/cover-image/index.js @@ -10,7 +10,7 @@ import classnames from 'classnames'; */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import MediaUploadButton from '../../media-upload-button'; import BlockControls from '../../block-controls'; @@ -20,8 +20,6 @@ import ToggleControl from '../../inspector-controls/toggle-control'; import RangeControl from '../../inspector-controls/range-control'; import BlockDescription from '../../block-description'; -const { children } = source; - const validAlignments = [ 'left', 'center', 'right', 'wide', 'full' ]; registerBlockType( 'core/cover-image', { @@ -34,7 +32,10 @@ registerBlockType( 'core/cover-image', { attributes: { title: { type: 'array', - source: children( 'h2' ), + source: { + type: 'children', + selector: 'h2', + }, }, url: { type: 'string', diff --git a/blocks/library/embed/index.js b/blocks/library/embed/index.js index 7df5f9fc25fea2..54a9985506d3b2 100644 --- a/blocks/library/embed/index.js +++ b/blocks/library/embed/index.js @@ -17,15 +17,13 @@ import { addQueryArgs } from '@wordpress/url'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children } = source; - // These embeds do not work in sandboxes const HOSTS_NO_PREVIEWS = [ 'facebook.com' ]; @@ -45,7 +43,10 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k }, caption: { type: 'array', - source: children( 'figcaption' ), + source: { + type: 'children', + selector: 'figcaption', + }, default: [], }, align: { diff --git a/blocks/library/freeform/index.js b/blocks/library/freeform/index.js index 1df0c44a58d46e..53c82abb0fb365 100644 --- a/blocks/library/freeform/index.js +++ b/blocks/library/freeform/index.js @@ -7,11 +7,9 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, setUnknownTypeHandlerName } from '../../api'; +import { registerBlockType, setUnknownTypeHandlerName } from '../../api'; import OldEditor from './old-editor'; -const { prop } = source; - registerBlockType( 'core/freeform', { title: __( 'Classic Text' ), @@ -22,7 +20,10 @@ registerBlockType( 'core/freeform', { attributes: { content: { type: 'string', - source: prop( 'innerHTML' ), + source: { + type: 'property', + property: 'innerHTML', + }, }, }, diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index c26bb5b330044c..9331e518ee7ecc 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -13,11 +13,9 @@ import { __ } from '@wordpress/i18n'; */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import { default as GalleryBlock, defaultColumnsNumber } from './block'; -const { query, attr } = source; - registerBlockType( 'core/gallery', { title: __( 'Gallery' ), icon: 'format-gallery', @@ -32,11 +30,27 @@ registerBlockType( 'core/gallery', { images: { type: 'array', default: [], - source: query( 'div.wp-block-gallery figure.blocks-gallery-image img', { - url: attr( 'src' ), - alt: attr( 'alt' ), - id: attr( 'data-id' ), - } ), + source: { + type: 'query', + selector: 'div.wp-block-gallery figure.blocks-gallery-image img', + source: { + type: 'object', + source: { + url: { + type: 'attribute', + attribute: 'src', + }, + alt: { + type: 'attribute', + attribute: 'alt', + }, + id: { + type: 'attribute', + attribute: 'data-id', + }, + }, + }, + }, }, columns: { type: 'number', diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index d61c2024565bc9..89c15fa1dda623 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -9,15 +9,13 @@ import { Toolbar } from '@wordpress/components'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import InspectorControls from '../../inspector-controls'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockDescription from '../../block-description'; -const { children, prop } = source; - registerBlockType( 'core/heading', { title: __( 'Heading' ), @@ -36,11 +34,18 @@ registerBlockType( 'core/heading', { attributes: { content: { type: 'array', - source: children( 'h1,h2,h3,h4,h5,h6' ), + source: { + type: 'children', + selector: 'h1,h2,h3,h4,h5,h6', + }, }, nodeName: { type: 'string', - source: prop( 'h1,h2,h3,h4,h5,h6', 'nodeName' ), + source: { + type: 'property', + selector: 'h1,h2,h3,h4,h5,h6', + property: 'nodeName', + }, default: 'H2', }, align: { diff --git a/blocks/library/html/index.js b/blocks/library/html/index.js index 32a494ed0fc25f..61ef13d67896ea 100644 --- a/blocks/library/html/index.js +++ b/blocks/library/html/index.js @@ -13,13 +13,11 @@ import { Component } from '@wordpress/element'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import BlockControls from '../../block-controls'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { html } = source; - registerBlockType( 'core/html', { title: __( 'Custom HTML' ), @@ -36,7 +34,9 @@ registerBlockType( 'core/html', { attributes: { content: { type: 'string', - source: html(), + source: { + type: 'html', + }, }, }, diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 1ff78cf0929589..709264095b2977 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -9,11 +9,9 @@ import { createMediaFromFile } from '@wordpress/utils'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import ImageBlock from './block'; -const { attr, children, text } = source; - registerBlockType( 'core/image', { title: __( 'Image' ), @@ -26,19 +24,34 @@ registerBlockType( 'core/image', { attributes: { url: { type: 'string', - source: attr( 'img', 'src' ), + source: { + type: 'attribute', + selector: 'img', + attribute: 'src', + }, }, alt: { type: 'string', - source: attr( 'img', 'alt' ), + source: { + type: 'attribute', + selector: 'img', + attribute: 'alt', + }, }, caption: { type: 'array', - source: children( 'figcaption' ), + source: { + type: 'children', + selector: 'figcaption', + }, }, href: { type: 'string', - source: attr( 'a', 'href' ), + source: { + type: 'attribute', + selector: 'a', + attribute: 'href', + }, }, id: { type: 'number', @@ -85,20 +98,34 @@ registerBlockType( 'core/image', { attributes: { url: { type: 'string', - source: attr( 'img', 'src' ), + source: { + type: 'attribute', + attribute: 'src', + selector: 'img', + }, }, alt: { type: 'string', - source: attr( 'img', 'alt' ), + source: { + type: 'attribute', + attribute: 'alt', + selector: 'img', + }, }, caption: { type: 'array', // To do: needs to support HTML. - source: text(), + source: { + type: 'text', + }, }, href: { type: 'string', - source: attr( 'a', 'href' ), + source: { + type: 'attribute', + attribute: 'href', + selector: 'a', + }, }, id: { type: 'number', diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index aac5e699254788..be1269cdd0d638 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -13,14 +13,12 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children, prop } = source; - const fromBrDelimitedContent = ( content ) => { if ( undefined === content ) { // converting an empty block to a list block @@ -84,12 +82,19 @@ registerBlockType( 'core/list', { attributes: { nodeName: { type: 'string', - source: prop( 'ol,ul', 'nodeName' ), + source: { + type: 'property', + selector: 'ol,ul', + property: 'nodeName', + }, default: 'UL', }, values: { type: 'array', - source: children( 'ol,ul' ), + source: { + type: 'children', + selector: 'ol,ul', + }, default: [], }, }, diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index e16a2711c4fbad..6725e146fd6330 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -14,7 +14,7 @@ import { Autocomplete, PanelBody } from '@wordpress/components'; * Internal dependencies */ import './style.scss'; -import { registerBlockType, createBlock, source, setDefaultBlockName } from '../../api'; +import { registerBlockType, createBlock, setDefaultBlockName } from '../../api'; import { blockAutocompleter, userAutocompleter } from '../../autocompleters'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; @@ -26,8 +26,6 @@ import RangeControl from '../../inspector-controls/range-control'; import ColorPalette from '../../color-palette'; import BlockDescription from '../../block-description'; -const { children } = source; - registerBlockType( 'core/paragraph', { title: __( 'Paragraph' ), @@ -42,7 +40,10 @@ registerBlockType( 'core/paragraph', { attributes: { content: { type: 'array', - source: children( 'p' ), + source: { + type: 'children', + selector: 'p', + }, }, align: { type: 'string', diff --git a/blocks/library/preformatted/index.js b/blocks/library/preformatted/index.js index 8b273f9ced170a..b82d0d560f6b3c 100644 --- a/blocks/library/preformatted/index.js +++ b/blocks/library/preformatted/index.js @@ -7,13 +7,11 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children } = source; - registerBlockType( 'core/preformatted', { title: __( 'Preformatted' ), @@ -24,7 +22,10 @@ registerBlockType( 'core/preformatted', { attributes: { content: { type: 'array', - source: children( 'pre' ), + source: { + type: 'children', + selector: 'pre', + }, }, }, diff --git a/blocks/library/pullquote/index.js b/blocks/library/pullquote/index.js index 24a1c246f4c50e..c1834f690f1ea8 100644 --- a/blocks/library/pullquote/index.js +++ b/blocks/library/pullquote/index.js @@ -8,15 +8,13 @@ import { __ } from '@wordpress/i18n'; */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children, query, node } = source; - registerBlockType( 'core/pullquote', { title: __( 'Pullquote' ), @@ -28,11 +26,20 @@ registerBlockType( 'core/pullquote', { attributes: { value: { type: 'array', - source: query( 'blockquote > p', node() ), + source: { + type: 'query', + selector: 'blockquote > p', + source: { + type: 'node', + }, + }, }, citation: { type: 'array', - source: children( 'footer' ), + source: { + type: 'children', + selector: 'footer', + }, }, align: { type: 'string', diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index 1b23060efc8166..1bd86235221c56 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -14,15 +14,13 @@ import { Toolbar } from '@wordpress/components'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockControls from '../../block-controls'; import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children, node: element, query } = source; - registerBlockType( 'core/quote', { title: __( 'Quote' ), icon: 'format-quote', @@ -31,12 +29,21 @@ registerBlockType( 'core/quote', { attributes: { value: { type: 'array', - source: query( 'blockquote > p', element() ), + source: { + type: 'query', + selector: 'blockquote > p', + source: { + type: 'node', + }, + }, default: [], }, citation: { type: 'array', - source: children( 'footer' ), + source: { + type: 'children', + selector: 'footer', + }, }, align: { type: 'string', diff --git a/blocks/library/shortcode/index.js b/blocks/library/shortcode/index.js index 500c6736127420..350b1efb0cc3e8 100644 --- a/blocks/library/shortcode/index.js +++ b/blocks/library/shortcode/index.js @@ -13,12 +13,10 @@ import { withInstanceId, Dashicon } from '@wordpress/components'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { text } = source; - registerBlockType( 'core/shortcode', { title: __( 'Shortcode' ), @@ -29,7 +27,9 @@ registerBlockType( 'core/shortcode', { attributes: { text: { type: 'string', - source: text(), + source: { + type: 'text', + }, }, }, diff --git a/blocks/library/table/index.js b/blocks/library/table/index.js index f2a9488246c8b5..b74b161da7f81a 100644 --- a/blocks/library/table/index.js +++ b/blocks/library/table/index.js @@ -8,15 +8,13 @@ import { __ } from '@wordpress/i18n'; */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import TableBlock from './table-block'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children } = source; - registerBlockType( 'core/table', { title: __( 'Table' ), icon: 'editor-table', @@ -25,7 +23,10 @@ registerBlockType( 'core/table', { attributes: { content: { type: 'array', - source: children( 'table' ), + source: { + type: 'children', + selector: 'table', + }, default: [

diff --git a/blocks/library/text-columns/index.js b/blocks/library/text-columns/index.js index 0e1b7c787cea47..8091fb73f80222 100644 --- a/blocks/library/text-columns/index.js +++ b/blocks/library/text-columns/index.js @@ -13,7 +13,7 @@ import { __ } from '@wordpress/i18n'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import RangeControl from '../../inspector-controls/range-control'; @@ -21,8 +21,6 @@ import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children, query } = source; - registerBlockType( 'core/text-columns', { title: __( 'Text Columns' ), @@ -33,7 +31,13 @@ registerBlockType( 'core/text-columns', { attributes: { content: { type: 'array', - source: query( 'p', children() ), + source: { + type: 'query', + selector: 'p', + source: { + type: 'children', + }, + }, default: [ [], [] ], }, columns: { diff --git a/blocks/library/verse/index.js b/blocks/library/verse/index.js index f6c22fba4bc275..c1a02ba35e4642 100644 --- a/blocks/library/verse/index.js +++ b/blocks/library/verse/index.js @@ -7,13 +7,11 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType, createBlock } from '../../api'; import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { children } = source; - registerBlockType( 'core/verse', { title: __( 'Verse' ), @@ -26,7 +24,10 @@ registerBlockType( 'core/verse', { attributes: { content: { type: 'array', - source: children( 'pre' ), + source: { + type: 'children', + selector: 'pre', + }, }, }, diff --git a/blocks/library/video/index.js b/blocks/library/video/index.js index 7b3207cb2c248c..10da12b2b2bc9e 100644 --- a/blocks/library/video/index.js +++ b/blocks/library/video/index.js @@ -12,7 +12,7 @@ import { Placeholder, Toolbar, Dashicon } from '@wordpress/components'; * Internal dependencies */ import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import MediaUploadButton from '../../media-upload-button'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; @@ -20,8 +20,6 @@ import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; -const { attr, children } = source; - registerBlockType( 'core/video', { title: __( 'Video' ), @@ -38,11 +36,18 @@ registerBlockType( 'core/video', { }, src: { type: 'string', - source: attr( 'video', 'src' ), + source: { + type: 'attribute', + selector: 'video', + attribute: 'src', + }, }, caption: { type: 'array', - source: children( 'figcaption' ), + source: { + type: 'children', + selector: 'figcaption', + }, }, }, diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 02cb53d21b4234..32f3cb413ab7f3 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -3,7 +3,7 @@ */ import { connect } from 'react-redux'; import classnames from 'classnames'; -import { has, partial, reduce, size } from 'lodash'; +import { get, partial, reduce, size } from 'lodash'; /** * WordPress dependencies @@ -152,8 +152,8 @@ class VisualEditorBlock extends Component { onChange( block.uid, attributes ); const metaAttributes = reduce( attributes, ( result, value, key ) => { - if ( type && has( type, [ 'attributes', key, 'meta' ] ) ) { - result[ type.attributes[ key ].meta ] = value; + if ( type && get( type, [ 'attributes', key, 'source', 'type' ] ) === 'meta' ) { + result[ type.attributes[ key ].source.meta ] = value; } return result; diff --git a/editor/selectors.js b/editor/selectors.js index 1ad2a81576ed10..a084cc74cf933f 100644 --- a/editor/selectors.js +++ b/editor/selectors.js @@ -433,8 +433,8 @@ export const getBlock = createSelector( } const metaAttributes = reduce( type.attributes, ( result, value, key ) => { - if ( value && 'meta' in value ) { - result[ key ] = getPostMeta( state, value.meta ); + if ( value.source.type === 'meta' ) { + result[ key ] = getPostMeta( state, value.source.meta ); } return result; From 4598bb201ed528024722a2e9b0b7bb465ee5a085 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 13 Oct 2017 14:32:47 +0100 Subject: [PATCH 02/13] Block API: Simplify the source declaration (drop one nesting level) --- blocks/api/parser.js | 32 +++++----- .../api/raw-handling/shortcode-converter.js | 7 +-- blocks/api/registration.js | 2 +- blocks/api/serializer.js | 2 +- blocks/library/audio/index.js | 14 ++--- blocks/library/button/index.js | 22 +++---- blocks/library/code/index.js | 8 +-- blocks/library/cover-image/index.js | 6 +- blocks/library/embed/index.js | 6 +- blocks/library/freeform/index.js | 6 +- blocks/library/gallery/index.js | 34 +++++------ blocks/library/heading/index.js | 14 ++--- blocks/library/html/index.js | 4 +- blocks/library/image/index.js | 58 +++++++------------ blocks/library/list/index.js | 14 ++--- blocks/library/paragraph/index.js | 6 +- blocks/library/preformatted/index.js | 6 +- blocks/library/pullquote/index.js | 16 ++--- blocks/library/quote/index.js | 16 ++--- blocks/library/shortcode/index.js | 4 +- blocks/library/table/index.js | 6 +- blocks/library/text-columns/index.js | 10 ++-- blocks/library/verse/index.js | 6 +- blocks/library/video/index.js | 14 ++--- editor/modes/visual-editor/block.js | 4 +- editor/selectors.js | 4 +- 26 files changed, 123 insertions(+), 198 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index cd4643e0b1666d..9dacf639d91b6a 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -55,33 +55,33 @@ export function asType( value, type ) { /** * Returns an hpq matcher given a source object * - * @param {Object} source Attribute Source object - * @return {Function} hpq Matcher + * @param {Object} sourceConfig Attribute Source object + * @return {Function} hpq Matcher */ -export function matcherFromSource( source ) { - switch ( source.type ) { +export function matcherFromSource( sourceConfig ) { + switch ( sourceConfig.source ) { case 'attribute': - return attr( source.selector, source.attribute ); + return attr( sourceConfig.selector, sourceConfig.attribute ); case 'property': - return prop( source.selector, source.property ); + return prop( sourceConfig.selector, sourceConfig.property ); case 'html': - return html( source.selector ); + return html( sourceConfig.selector ); case 'text': - return text( source.selector ); + return text( sourceConfig.selector ); case 'children': - return children( source.selector ); + return children( sourceConfig.selector ); case 'node': - return node( source.selector ); + return node( sourceConfig.selector ); case 'query': - return query( source.selector, matcherFromSource( source.source ) ); + return query( sourceConfig.selector, matcherFromSource( sourceConfig.query ) ); case 'object': - return keys( source.source ).reduce( ( memo, key ) => { - memo[ key ] = matcherFromSource( source.source[ key ] ); + return keys( sourceConfig.object ).reduce( ( memo, key ) => { + memo[ key ] = matcherFromSource( sourceConfig.object[ key ] ); return memo; }, {} ); default: // eslint-disable-next-line no-console - console.error( `Unkown source type "${ source.type }"` ); + console.error( `Unkown source type "${ sourceConfig.source }"` ); } } @@ -97,7 +97,7 @@ export function matcherFromSource( source ) { */ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, commentAttributes ) { let value; - switch ( attributeSchema.source.type ) { + switch ( attributeSchema.source ) { case 'meta': break; case 'comment': @@ -105,7 +105,7 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com break; default: { // Coerce value to specified type - const matcher = matcherFromSource( attributeSchema.source ); + const matcher = matcherFromSource( attributeSchema ); const rawValue = hpqParse( innerHTML, matcher ); value = rawValue === undefined ? rawValue : asType( rawValue, attributeSchema.type ); break; diff --git a/blocks/api/raw-handling/shortcode-converter.js b/blocks/api/raw-handling/shortcode-converter.js index d4bd40beae1bdc..71f775c29af503 100644 --- a/blocks/api/raw-handling/shortcode-converter.js +++ b/blocks/api/raw-handling/shortcode-converter.js @@ -36,18 +36,13 @@ export default function( HTML ) { ( schema ) => schema.shortcode( match.shortcode.attrs ), ); - console.log( mapValues( transform.attributes, attribute => ( { - source: { type: 'comment' }, - ...attribute, - } ) ) ); - const block = createBlock( blockType.name, getBlockAttributes( { ...blockType, attributes: mapValues( transform.attributes, attribute => ( { - source: { type: 'comment' }, + source: 'comment', ...attribute, } ) ), }, diff --git a/blocks/api/registration.js b/blocks/api/registration.js index c3139572864651..9996c22d0c98ab 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -127,7 +127,7 @@ export function registerBlockType( name, settings ) { ...settings, name, attributes: mapValues( attributes, ( attribute ) => ( { - source: { type: 'comment' }, + source: 'comment', ...attribute, } ) ), }; diff --git a/blocks/api/serializer.js b/blocks/api/serializer.js index 2c850d1ce3edc9..f26863f00f630d 100644 --- a/blocks/api/serializer.js +++ b/blocks/api/serializer.js @@ -99,7 +99,7 @@ export function getCommentAttributes( allAttributes, blockType ) { } // Ignore values sources from content and post meta - if ( attributeSchema.source.type !== 'comment' ) { + if ( attributeSchema.source !== 'comment' ) { return result; } diff --git a/blocks/library/audio/index.js b/blocks/library/audio/index.js index 664b002dc975b6..2504da2da80151 100644 --- a/blocks/library/audio/index.js +++ b/blocks/library/audio/index.js @@ -31,21 +31,17 @@ registerBlockType( 'core/audio', { attributes: { src: { type: 'string', - source: { - type: 'attribute', - selector: 'audio', - attribute: 'src', - }, + source: 'attribute', + selector: 'audio', + attribute: 'src', }, align: { type: 'string', }, caption: { type: 'array', - source: { - type: 'children', - selector: 'figcaption', - }, + source: 'children', + selector: 'figcaption', }, }, diff --git a/blocks/library/button/index.js b/blocks/library/button/index.js index df030218fbac62..381549faf4948c 100644 --- a/blocks/library/button/index.js +++ b/blocks/library/button/index.js @@ -180,26 +180,20 @@ registerBlockType( 'core/button', { attributes: { url: { type: 'string', - source: { - type: 'attribute', - selector: 'a', - attribute: 'href', - }, + source: 'attribute', + selector: 'a', + attribute: 'href', }, title: { type: 'string', - source: { - type: 'attribute', - selector: 'a', - attribute: 'title', - }, + source: 'attribute', + selector: 'a', + attribute: 'title', }, text: { type: 'array', - source: { - type: 'children', - selector: 'a', - }, + source: 'children', + selector: 'a', }, align: { type: 'string', diff --git a/blocks/library/code/index.js b/blocks/library/code/index.js index 30d9ef17731f1d..3a61cdaa01fe8e 100644 --- a/blocks/library/code/index.js +++ b/blocks/library/code/index.js @@ -26,11 +26,9 @@ registerBlockType( 'core/code', { attributes: { content: { type: 'string', - source: { - type: 'property', - selector: 'code', - property: 'textContent', - }, + source: 'property', + selector: 'code', + property: 'textContent', }, }, diff --git a/blocks/library/cover-image/index.js b/blocks/library/cover-image/index.js index 8119d6f5705a4b..7404a4cb5333c0 100644 --- a/blocks/library/cover-image/index.js +++ b/blocks/library/cover-image/index.js @@ -32,10 +32,8 @@ registerBlockType( 'core/cover-image', { attributes: { title: { type: 'array', - source: { - type: 'children', - selector: 'h2', - }, + source: 'children', + selector: 'h2', }, url: { type: 'string', diff --git a/blocks/library/embed/index.js b/blocks/library/embed/index.js index 54a9985506d3b2..3a940151dfaa47 100644 --- a/blocks/library/embed/index.js +++ b/blocks/library/embed/index.js @@ -43,10 +43,8 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k }, caption: { type: 'array', - source: { - type: 'children', - selector: 'figcaption', - }, + source: 'children', + selector: 'figcaption', default: [], }, align: { diff --git a/blocks/library/freeform/index.js b/blocks/library/freeform/index.js index 53c82abb0fb365..2bb358e4cd1293 100644 --- a/blocks/library/freeform/index.js +++ b/blocks/library/freeform/index.js @@ -20,10 +20,8 @@ registerBlockType( 'core/freeform', { attributes: { content: { type: 'string', - source: { - type: 'property', - property: 'innerHTML', - }, + source: 'property', + property: 'innerHTML', }, }, diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index 9331e518ee7ecc..d275526415e5a3 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -30,24 +30,22 @@ registerBlockType( 'core/gallery', { images: { type: 'array', default: [], - source: { - type: 'query', - selector: 'div.wp-block-gallery figure.blocks-gallery-image img', - source: { - type: 'object', - source: { - url: { - type: 'attribute', - attribute: 'src', - }, - alt: { - type: 'attribute', - attribute: 'alt', - }, - id: { - type: 'attribute', - attribute: 'data-id', - }, + source: 'query', + selector: 'div.wp-block-gallery figure.blocks-gallery-image img', + query: { + source: 'object', + object: { + url: { + source: 'attribute', + attribute: 'src', + }, + alt: { + source: 'attribute', + attribute: 'alt', + }, + id: { + source: 'attribute', + attribute: 'data-id', }, }, }, diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index 89c15fa1dda623..b8a94aee14bf1e 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -34,18 +34,14 @@ registerBlockType( 'core/heading', { attributes: { content: { type: 'array', - source: { - type: 'children', - selector: 'h1,h2,h3,h4,h5,h6', - }, + source: 'children', + selector: 'h1,h2,h3,h4,h5,h6', }, nodeName: { type: 'string', - source: { - type: 'property', - selector: 'h1,h2,h3,h4,h5,h6', - property: 'nodeName', - }, + source: 'property', + selector: 'h1,h2,h3,h4,h5,h6', + property: 'nodeName', default: 'H2', }, align: { diff --git a/blocks/library/html/index.js b/blocks/library/html/index.js index 61ef13d67896ea..38ff029c7df5bf 100644 --- a/blocks/library/html/index.js +++ b/blocks/library/html/index.js @@ -34,9 +34,7 @@ registerBlockType( 'core/html', { attributes: { content: { type: 'string', - source: { - type: 'html', - }, + source: 'html', }, }, diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 709264095b2977..4c94d5f26de71b 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -24,34 +24,26 @@ registerBlockType( 'core/image', { attributes: { url: { type: 'string', - source: { - type: 'attribute', - selector: 'img', - attribute: 'src', - }, + source: 'attribute', + selector: 'img', + attribute: 'src', }, alt: { type: 'string', - source: { - type: 'attribute', - selector: 'img', - attribute: 'alt', - }, + source: 'attribute', + selector: 'img', + attribute: 'alt', }, caption: { type: 'array', - source: { - type: 'children', - selector: 'figcaption', - }, + source: 'children', + selector: 'figcaption', }, href: { type: 'string', - source: { - type: 'attribute', - selector: 'a', - attribute: 'href', - }, + source: 'attribute', + selector: 'a', + attribute: 'href', }, id: { type: 'number', @@ -98,34 +90,26 @@ registerBlockType( 'core/image', { attributes: { url: { type: 'string', - source: { - type: 'attribute', - attribute: 'src', - selector: 'img', - }, + source: 'attribute', + attribute: 'src', + selector: 'img', }, alt: { type: 'string', - source: { - type: 'attribute', - attribute: 'alt', - selector: 'img', - }, + source: 'attribute', + attribute: 'alt', + selector: 'img', }, caption: { type: 'array', // To do: needs to support HTML. - source: { - type: 'text', - }, + source: 'text', }, href: { type: 'string', - source: { - type: 'attribute', - attribute: 'href', - selector: 'a', - }, + source: 'attribute', + attribute: 'href', + selector: 'a', }, id: { type: 'number', diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index be1269cdd0d638..0ae6cfad4cffe6 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -82,19 +82,15 @@ registerBlockType( 'core/list', { attributes: { nodeName: { type: 'string', - source: { - type: 'property', - selector: 'ol,ul', - property: 'nodeName', - }, + source: 'property', + selector: 'ol,ul', + property: 'nodeName', default: 'UL', }, values: { type: 'array', - source: { - type: 'children', - selector: 'ol,ul', - }, + source: 'children', + selector: 'ol,ul', default: [], }, }, diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index 6725e146fd6330..0ab39bd698188c 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -40,10 +40,8 @@ registerBlockType( 'core/paragraph', { attributes: { content: { type: 'array', - source: { - type: 'children', - selector: 'p', - }, + source: 'children', + selector: 'p', }, align: { type: 'string', diff --git a/blocks/library/preformatted/index.js b/blocks/library/preformatted/index.js index b82d0d560f6b3c..e5fe21e7a6d6eb 100644 --- a/blocks/library/preformatted/index.js +++ b/blocks/library/preformatted/index.js @@ -22,10 +22,8 @@ registerBlockType( 'core/preformatted', { attributes: { content: { type: 'array', - source: { - type: 'children', - selector: 'pre', - }, + source: 'children', + selector: 'pre', }, }, diff --git a/blocks/library/pullquote/index.js b/blocks/library/pullquote/index.js index c1834f690f1ea8..655756d2d0b14c 100644 --- a/blocks/library/pullquote/index.js +++ b/blocks/library/pullquote/index.js @@ -26,20 +26,16 @@ registerBlockType( 'core/pullquote', { attributes: { value: { type: 'array', - source: { - type: 'query', - selector: 'blockquote > p', - source: { - type: 'node', - }, + source: 'query', + selector: 'blockquote > p', + query: { + source: 'node', }, }, citation: { type: 'array', - source: { - type: 'children', - selector: 'footer', - }, + source: 'children', + selector: 'footer', }, align: { type: 'string', diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index 1bd86235221c56..1ebdf652a5cb3d 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -29,21 +29,17 @@ registerBlockType( 'core/quote', { attributes: { value: { type: 'array', - source: { - type: 'query', - selector: 'blockquote > p', - source: { - type: 'node', - }, + source: 'query', + selector: 'blockquote > p', + query: { + source: 'node', }, default: [], }, citation: { type: 'array', - source: { - type: 'children', - selector: 'footer', - }, + source: 'children', + selector: 'footer', }, align: { type: 'string', diff --git a/blocks/library/shortcode/index.js b/blocks/library/shortcode/index.js index 350b1efb0cc3e8..f2f67db907d6d2 100644 --- a/blocks/library/shortcode/index.js +++ b/blocks/library/shortcode/index.js @@ -27,9 +27,7 @@ registerBlockType( 'core/shortcode', { attributes: { text: { type: 'string', - source: { - type: 'text', - }, + source: 'text', }, }, diff --git a/blocks/library/table/index.js b/blocks/library/table/index.js index b74b161da7f81a..861017d695fcfa 100644 --- a/blocks/library/table/index.js +++ b/blocks/library/table/index.js @@ -23,10 +23,8 @@ registerBlockType( 'core/table', { attributes: { content: { type: 'array', - source: { - type: 'children', - selector: 'table', - }, + source: 'children', + selector: 'table', default: [

diff --git a/blocks/library/text-columns/index.js b/blocks/library/text-columns/index.js index 8091fb73f80222..3843af938c9bac 100644 --- a/blocks/library/text-columns/index.js +++ b/blocks/library/text-columns/index.js @@ -31,12 +31,10 @@ registerBlockType( 'core/text-columns', { attributes: { content: { type: 'array', - source: { - type: 'query', - selector: 'p', - source: { - type: 'children', - }, + source: 'query', + selector: 'p', + query: { + source: 'children', }, default: [ [], [] ], }, diff --git a/blocks/library/verse/index.js b/blocks/library/verse/index.js index c1a02ba35e4642..7c553121bacb0f 100644 --- a/blocks/library/verse/index.js +++ b/blocks/library/verse/index.js @@ -24,10 +24,8 @@ registerBlockType( 'core/verse', { attributes: { content: { type: 'array', - source: { - type: 'children', - selector: 'pre', - }, + source: 'children', + selector: 'pre', }, }, diff --git a/blocks/library/video/index.js b/blocks/library/video/index.js index 10da12b2b2bc9e..427054dbbabb0e 100644 --- a/blocks/library/video/index.js +++ b/blocks/library/video/index.js @@ -36,18 +36,14 @@ registerBlockType( 'core/video', { }, src: { type: 'string', - source: { - type: 'attribute', - selector: 'video', - attribute: 'src', - }, + source: 'attribute', + selector: 'video', + attribute: 'src', }, caption: { type: 'array', - source: { - type: 'children', - selector: 'figcaption', - }, + source: 'children', + selector: 'figcaption', }, }, diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 32f3cb413ab7f3..e0ec097bf9daf1 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -152,8 +152,8 @@ class VisualEditorBlock extends Component { onChange( block.uid, attributes ); const metaAttributes = reduce( attributes, ( result, value, key ) => { - if ( type && get( type, [ 'attributes', key, 'source', 'type' ] ) === 'meta' ) { - result[ type.attributes[ key ].source.meta ] = value; + if ( type && get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { + result[ type.attributes[ key ].meta ] = value; } return result; diff --git a/editor/selectors.js b/editor/selectors.js index a084cc74cf933f..dd0cf773197cd5 100644 --- a/editor/selectors.js +++ b/editor/selectors.js @@ -433,8 +433,8 @@ export const getBlock = createSelector( } const metaAttributes = reduce( type.attributes, ( result, value, key ) => { - if ( value.source.type === 'meta' ) { - result[ key ] = getPostMeta( state, value.source.meta ); + if ( value.source === 'meta' ) { + result[ key ] = getPostMeta( state, value.meta ); } return result; From c55bde6cd5ee61192f56b8248c8796fe2c5b23d2 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 16 Oct 2017 09:27:59 +0100 Subject: [PATCH 03/13] Blocks API: Fix some styling issues per review --- blocks/api/parser.js | 5 +++-- editor/modes/visual-editor/block.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 9dacf639d91b6a..9c4a7e81a1d537 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -86,14 +86,15 @@ export function matcherFromSource( sourceConfig ) { } /** - * Given a blocktype, a block's raw content and the commentAttributes returns the attribute value depending on its source definition + * Given an attribute key, an attributes schema, a block's raw content and the commentAttributes + * returns the attribute value depending on its source definition of the given attribute key * * @param {string} attributeKey Attribute key * @param {Object} attributeSchema Attribute's schema * @param {string} innerHTML Block's raw content * @param {Object} commentAttributes Block's comment attributes * - * @return {mixed} Attribute value + * @return {*} Attribute value */ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, commentAttributes ) { let value; diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index e0ec097bf9daf1..32c5fc1c4c70fc 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -152,7 +152,7 @@ class VisualEditorBlock extends Component { onChange( block.uid, attributes ); const metaAttributes = reduce( attributes, ( result, value, key ) => { - if ( type && get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { + if ( get( type, [ 'attributes', key, 'source' ] ) === 'meta' ) { result[ type.attributes[ key ].meta ] = value; } From cc4b4fd4e0f3c63dfcde9aa3945d3de0d27980a8 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 16 Oct 2017 09:50:43 +0100 Subject: [PATCH 04/13] Tests: Fix existing unit tests after attributs refactoring --- blocks/api/parser.js | 5 +-- blocks/api/raw-handling/test/index.js | 7 +-- blocks/api/test/parser.js | 65 +++++---------------------- blocks/api/test/registration.js | 39 +++++++++++++--- blocks/api/test/serializer.js | 11 +++-- blocks/api/test/source.js | 6 --- editor/test/selectors.js | 1 + 7 files changed, 58 insertions(+), 76 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 9c4a7e81a1d537..2e175f941364eb 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -107,13 +107,12 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com default: { // Coerce value to specified type const matcher = matcherFromSource( attributeSchema ); - const rawValue = hpqParse( innerHTML, matcher ); - value = rawValue === undefined ? rawValue : asType( rawValue, attributeSchema.type ); + value = hpqParse( innerHTML, matcher ); break; } } - return value === undefined ? attributeSchema.default : value; + return value === undefined ? attributeSchema.default : asType( value, attributeSchema.type ); } /** diff --git a/blocks/api/raw-handling/test/index.js b/blocks/api/raw-handling/test/index.js index b6891123f653ee..38db1ad7a5f472 100644 --- a/blocks/api/raw-handling/test/index.js +++ b/blocks/api/raw-handling/test/index.js @@ -9,7 +9,6 @@ import { equal, deepEqual } from 'assert'; import rawHandler from '../index'; import { registerBlockType, unregisterBlockType, setUnknownTypeHandlerName } from '../../registration'; import { createBlock } from '../../factory'; -import { children, prop } from '../../source'; describe( 'rawHandler', () => { beforeAll( () => { @@ -19,7 +18,8 @@ describe( 'rawHandler', () => { attributes: { content: { type: 'array', - source: children( 'figure' ), + source: 'children', + selector: 'figure', }, }, transforms: { @@ -39,7 +39,8 @@ describe( 'rawHandler', () => { attributes: { content: { type: 'string', - source: prop( 'innerHTML' ), + source: 'property', + property: 'innerHTML', }, }, save: () => {}, diff --git a/blocks/api/test/parser.js b/blocks/api/test/parser.js index cd3cf20177b3f7..fd8022bb9839cd 100644 --- a/blocks/api/test/parser.js +++ b/blocks/api/test/parser.js @@ -6,12 +6,9 @@ import { noop } from 'lodash'; /** * Internal dependencies */ -import { text, attr, html } from '../source'; import { - isValidSource, getBlockAttributes, asType, - getSourcedAttributes, createBlockWithFallback, default as parse, } from '../parser'; @@ -41,47 +38,6 @@ describe( 'block parser', () => { } ); } ); - describe( 'isValidSource()', () => { - it( 'returns false if falsey argument', () => { - expect( isValidSource() ).toBe( false ); - } ); - - it( 'returns true if valid source argument', () => { - expect( isValidSource( text() ) ).toBe( true ); - } ); - - it( 'returns false if invalid source argument', () => { - expect( isValidSource( () => {} ) ).toBe( false ); - } ); - } ); - - describe( 'getSourcedAttributes()', () => { - it( 'should return matched attributes from valid sources', () => { - const sources = { - number: { - type: 'number', - }, - emphasis: { - type: 'string', - source: text( 'strong' ), - }, - }; - - const innerHTML = 'Ribs & Chicken'; - - expect( getSourcedAttributes( innerHTML, sources ) ).toEqual( { - emphasis: '& Chicken', - } ); - } ); - - it( 'should return an empty object if no sources defined', () => { - const sources = {}; - const innerHTML = 'Ribs & Chicken'; - - expect( getSourcedAttributes( innerHTML, sources ) ).toEqual( {} ); - } ); - } ); - describe( 'asType()', () => { it( 'gracefully handles undefined type', () => { expect( asType( 5 ) ).toBe( 5 ); @@ -126,22 +82,23 @@ describe( 'block parser', () => { attributes: { content: { type: 'string', - source: text( 'div' ), + source: 'text', + selector: 'div', }, number: { type: 'number', - source: attr( 'div', 'data-number' ), + source: 'attribute', + attribute: 'data-number', + selector: 'div', }, align: { type: 'string', + source: 'comment', }, topic: { type: 'string', default: 'none', - }, - ignoredDomSource: { - type: 'string', - source: ( node ) => node.innerHTML, + source: 'comment', }, }, }; @@ -211,7 +168,7 @@ describe( 'block parser', () => { attributes: { content: { type: 'string', - source: html(), + source: 'html', }, fruit: { type: 'string', @@ -252,7 +209,7 @@ describe( 'block parser', () => { attributes: { content: { type: 'string', - source: text(), + source: 'text', }, smoked: { type: 'string' }, url: { type: 'string' }, @@ -291,7 +248,7 @@ describe( 'block parser', () => { attributes: { content: { type: 'string', - source: text(), + source: 'text', }, }, save: noop, @@ -364,7 +321,7 @@ describe( 'block parser', () => { attributes: { content: { type: 'string', - source: html(), + source: 'html', }, }, save: noop, diff --git a/blocks/api/test/registration.js b/blocks/api/test/registration.js index 4411d93276e607..a2deb51659956f 100644 --- a/blocks/api/test/registration.js +++ b/blocks/api/test/registration.js @@ -73,7 +73,14 @@ describe( 'blocks', () => { it( 'should accept valid block names', () => { const block = registerBlockType( 'my-plugin/fancy-block-4', defaultBlockSettings ); expect( console.error ).not.toHaveBeenCalled(); - expect( block ).toEqual( { name: 'my-plugin/fancy-block-4', icon: 'block-default', save: noop, category: 'common', title: 'block title' } ); + expect( block ).toEqual( { + name: 'my-plugin/fancy-block-4', + icon: 'block-default', + save: noop, + category: 'common', + title: 'block title', + attributes: {}, + } ); } ); it( 'should prohibit registering the same block twice', () => { @@ -153,7 +160,10 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', - attributes, + attributes: { ok: { + source: 'comment', + type: 'boolean', + } }, } ); } ); @@ -168,6 +178,7 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', + attributes: {}, } ); } ); } ); @@ -181,9 +192,14 @@ describe( 'blocks', () => { it( 'should unregister existing blocks', () => { registerBlockType( 'core/test-block', defaultBlockSettings ); - expect( getBlockTypes() ).toEqual( [ - { name: 'core/test-block', save: noop, category: 'common', title: 'block title', icon: 'block-default' }, - ] ); + expect( getBlockTypes() ).toEqual( [ { + name: 'core/test-block', + save: noop, + category: 'common', + title: 'block title', + icon: 'block-default', + attributes: {}, + } ] ); const oldBlock = unregisterBlockType( 'core/test-block' ); expect( console.error ).not.toHaveBeenCalled(); expect( oldBlock ).toEqual( { @@ -192,6 +208,7 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', + attributes: {}, } ); expect( getBlockTypes() ).toEqual( [] ); } ); @@ -234,6 +251,7 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', + attributes: {}, } ); } ); @@ -247,6 +265,7 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', + attributes: {}, } ); } ); } ); @@ -261,7 +280,14 @@ describe( 'blocks', () => { const blockType = { settingName: 'settingValue', save: noop, category: 'common', title: 'block title' }; registerBlockType( 'core/test-block-with-settings', blockType ); expect( getBlockTypes() ).toEqual( [ - { name: 'core/test-block', save: noop, category: 'common', title: 'block title', icon: 'block-default' }, + { + name: 'core/test-block', + save: noop, + category: 'common', + title: 'block title', + icon: 'block-default', + attributes: {}, + }, { name: 'core/test-block-with-settings', settingName: 'settingValue', @@ -269,6 +295,7 @@ describe( 'blocks', () => { category: 'common', title: 'block title', icon: 'block-default', + attributes: {}, }, ] ); } ); diff --git a/blocks/api/test/serializer.js b/blocks/api/test/serializer.js index 71f116fd77eec0..93862a77e47ddc 100644 --- a/blocks/api/test/serializer.js +++ b/blocks/api/test/serializer.js @@ -6,7 +6,6 @@ import { createElement, Component } from '@wordpress/element'; /** * Internal dependencies */ -import { text } from '../source'; import serialize, { getCommentAttributes, getBeautifulContent, @@ -157,13 +156,15 @@ describe( 'block serializer', () => { }, { attributes: { fruit: { type: 'string', - source: text(), + source: 'text', }, category: { type: 'string', + source: 'comment', }, ripeness: { type: 'string', + source: 'comment', }, } } ); @@ -180,9 +181,11 @@ describe( 'block serializer', () => { }, { attributes: { fruit: { type: 'string', + source: 'comment', }, ripeness: { type: 'string', + source: 'comment', }, } } ); @@ -359,7 +362,7 @@ describe( 'block serializer', () => { }, content: { type: 'string', - source: text(), + source: 'text', }, stuff: { type: 'string', @@ -422,7 +425,7 @@ describe( 'block serializer', () => { attributes: { content: { type: 'string', - source: text(), + source: 'text', }, }, save( { attributes } ) { diff --git a/blocks/api/test/source.js b/blocks/api/test/source.js index 957c60df466879..c9e71eb95bb0cf 100644 --- a/blocks/api/test/source.js +++ b/blocks/api/test/source.js @@ -14,12 +14,6 @@ import { renderToString } from '@wordpress/element'; import * as sources from '../source'; describe( 'sources', () => { - it( 'should generate sources which apply internal flag', () => { - for ( const sourceFn in sources ) { - expect( sources[ sourceFn ]()._wpBlocksKnownSource ).toBe( true ); - } - } ); - describe( 'children()', () => { it( 'should return a source function', () => { const source = sources.children(); diff --git a/editor/test/selectors.js b/editor/test/selectors.js index 5a40bb0f3ffc3f..377759b0692cea 100644 --- a/editor/test/selectors.js +++ b/editor/test/selectors.js @@ -1166,6 +1166,7 @@ describe( 'selectors', () => { attributes: { foo: { type: 'string', + source: 'meta', meta: 'foo', }, }, From d82ceabbf4639389af9859d58510265c0faf4eb3 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 16 Oct 2017 10:00:38 +0100 Subject: [PATCH 05/13] Tests: Add getBlockAttribute unit test --- blocks/api/parser.js | 2 +- blocks/api/test/parser.js | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 2e175f941364eb..f1154bfe69e53c 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -86,7 +86,7 @@ export function matcherFromSource( sourceConfig ) { } /** - * Given an attribute key, an attributes schema, a block's raw content and the commentAttributes + * Given an attribute key, an attribute's schema, a block's raw content and the commentAttributes * returns the attribute value depending on its source definition of the given attribute key * * @param {string} attributeKey Attribute key diff --git a/blocks/api/test/parser.js b/blocks/api/test/parser.js index fd8022bb9839cd..619c6241c7eb7c 100644 --- a/blocks/api/test/parser.js +++ b/blocks/api/test/parser.js @@ -7,6 +7,7 @@ import { noop } from 'lodash'; * Internal dependencies */ import { + getBlockAttribute, getBlockAttributes, asType, createBlockWithFallback, @@ -76,6 +77,50 @@ describe( 'block parser', () => { } ); } ); + describe( 'getBlockAttribute', () => { + it( 'should return the comment attribute value', () => { + const value = getBlockAttribute( + 'number', + { + type: 'number', + source: 'comment', + }, + '', + { number: 10 } + ); + + expect( value ).toBe( 10 ); + } ); + + it( 'should return the matcher\'s attribute value', () => { + const value = getBlockAttribute( + 'content', + { + type: 'string', + source: 'text', + selector: 'div', + }, + '
chicken
', + {} + ); + expect( value ).toBe( 'chicken' ); + } ); + + it( 'should return undefined for meta attributes', () => { + const value = getBlockAttribute( + 'content', + { + type: 'string', + source: 'meta', + meta: 'content', + }, + '
chicken
', + {} + ); + expect( value ).toBeUndefined(); + } ); + } ); + describe( 'getBlockAttributes()', () => { it( 'should merge attributes with the parsed and default attributes', () => { const blockType = { From f21347659f969a64c7430682792b0503b908c728 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 16 Oct 2017 10:12:56 +0100 Subject: [PATCH 06/13] Documentation: Update the attributes' documentation to match the latest API changes --- blocks/README.md | 8 ++-- docs/attributes.md | 91 ++++++++++++++++++++++++++++++++++++----- docs/block-api.md | 7 +++- docs/blocks-controls.md | 10 ++--- docs/blocks-editable.md | 10 ++--- 5 files changed, 101 insertions(+), 25 deletions(-) diff --git a/blocks/README.md b/blocks/README.md index 8c44e41462249b..d95a742872df18 100644 --- a/blocks/README.md +++ b/blocks/README.md @@ -138,7 +138,9 @@ add_action( 'enqueue_block_editor_assets', 'random_image_enqueue_block_editor_as attributes: { category: { type: 'string', - source: source.attr( 'img', 'alt' ) + source: 'attribute', + attribute: 'alt', + selector: 'img', } }, @@ -238,8 +240,8 @@ editor interface where blocks are implemented. keys of the object define the shape of attributes, and each value an object schema describing the `type`, `default` (optional), and [`source`](https://wordpress.org/gutenberg/handbook/reference/attributes/) - (optional) of the attribute. If `source` is omitted, the attribute is - serialized into the block's comment delimiters. Alternatively, define + (optional) of the attribute. If `source` is omitted, the attribute is + serialized into the block's comment delimiters. Alternatively, define `attributes` as a function which returns the attributes object. - `category: string` - Slug of the block's category. The category is used to organize the blocks in the block inserter. diff --git a/docs/attributes.md b/docs/attributes.md index bffe0c1fd9210c..e742b16c77690c 100644 --- a/docs/attributes.md +++ b/docs/attributes.md @@ -8,21 +8,85 @@ Each source accepts an optional selector as the first argument. If a selector is Under the hood, attribute sources are a superset of functionality provided by [hpq](https://github.com/aduth/hpq), a small library used to parse and query HTML markup into an object shape. In an object of attributes sources, you can name the keys as you see fit. The resulting object will assign as a value to each key the result of its attribute source. -### `attr` +### `attribute` -Use `attr` to extract the value of an attribute from markup. +Use `attribute` to extract the value of an attribute from markup. _Example_: Extract the `src` attribute from an image found in the block's markup. ```js { url: { - source: attr( 'img', 'src' ) + source: 'attribute', + selector: 'img', + attribute: 'src', } } // { "url": "https://lorempixel.com/1200/800/" } ``` +### `attribute` + +Use `attribute` to extract the value of an attribute from markup. + +_Example_: Extract the `src` attribute from an image found in the block's markup. + +```js +{ + url: { + source: 'attribute', + selector: 'img', + attribute: 'src', + } +} +// { "url": "https://lorempixel.com/1200/800/" } +``` + +### `property` + +Use `property` to extract the value of a property of a DOM Node from markup. + +_Example_: Extract the `nodeName` property from a heading's node. + +```js +{ + tagName: { + source: 'property', + selector: 'h1,h2,h3,h4,h5,h6', + property: 'nodeName', + } +} +// { "tagName": "h2" } +``` + +### `text` + +Use `text` to extract the inner text from markup. + +```js +{ + content: { + source: 'text', + selector: 'figcaption', + } +} +// { "content": "The inner text of the figcaption element" } +``` + +### `html` + +Use `html` to extract the inner HTML from markup. + +```js +{ + content: { + source: 'html', + selector: 'figcaption', + } +} +// { "content": "The inner text of the figcaption element" } +``` + ### `children` Use `children` to extract child nodes of the matched element, returned as an array of virtual elements. This is most commonly used in combination with the `Editable` component. @@ -32,13 +96,14 @@ _Example_: Extract child nodes from a paragraph of rich text. ```js { content: { - source: children( 'p' ) + source: 'children', + selector: 'p' } } // { // "content": [ // "Vestibulum eu ", -// { "type": "strong", "children": "tortor" }, +// { "type": "strong", "children": "tortor" }, // " vel urna." // ] // } @@ -53,14 +118,19 @@ _Example_: Extract `src` and `alt` from each image element in the block's markup ```js { images: { - source: query( 'img', { - url: attr( 'src' ) - alt: attr( 'alt' ) - } ) + source: 'query' + selector: 'img', + query: { + source: 'object', + object: { + url: { source: 'attribute', attribute: 'src' }, + alt: { source: 'attribute', attribute: 'alt' }, + }, + } } } // { -// "images": [ +// "images": [ // { "url": "https://lorempixel.com/1200/800/", "alt": "large image" }, // { "url": "https://lorempixel.com/50/50/", "alt": "small image" } // ] @@ -75,6 +145,7 @@ Attributes may be obtained from a post's meta rather than from the block's repre attributes: { author: { type: 'string', + source: 'meta', meta: 'author' }, }, diff --git a/docs/block-api.md b/docs/block-api.md index 1e230e9e3f4bd0..784c611e57028e 100644 --- a/docs/block-api.md +++ b/docs/block-api.md @@ -78,11 +78,14 @@ Attributes provide the structured data needs of a block. They can exist in diffe attributes: { cover: { type: 'string', - source: attr( 'img', 'src' ), + source: 'attribute', + selector: 'img', + attribute: 'src', }, author: { type: 'string', - source: children( '.book-author' ), + source: 'children', + selector: '.book-author', }, pages: { type: 'number', diff --git a/docs/blocks-controls.md b/docs/blocks-controls.md index c68c6c0a9811a2..50d96ce1e3029b 100644 --- a/docs/blocks-controls.md +++ b/docs/blocks-controls.md @@ -17,8 +17,7 @@ var el = wp.element.createElement, registerBlockType = wp.blocks.registerBlockType, Editable = wp.blocks.Editable, BlockControls = wp.blocks.BlockControls, - AlignmentToolbar = wp.blocks.AlignmentToolbar, - children = wp.blocks.source.children; + AlignmentToolbar = wp.blocks.AlignmentToolbar; registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { title: 'Hello World (Step 4)', @@ -30,7 +29,8 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-04', { attributes: { content: { type: 'array', - source: children( 'p' ) + source: 'children', + selector: 'p', } }, @@ -91,7 +91,6 @@ const { AlignmentToolbar, source } = wp.blocks; -const { children } = source; registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', { title: 'Hello World (Step 4)', @@ -103,7 +102,8 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', { attributes: { content: { type: 'array', - source: children( 'p' ), + source: 'children', + selector: 'p', }, }, diff --git a/docs/blocks-editable.md b/docs/blocks-editable.md index 484b8f99644480..7a5a9ce3fa77e4 100644 --- a/docs/blocks-editable.md +++ b/docs/blocks-editable.md @@ -13,8 +13,7 @@ One challenge of maintaining the representation of a block as a JavaScript objec ```js var el = wp.element.createElement, registerBlockType = wp.blocks.registerBlockType, - Editable = wp.blocks.Editable, - children = wp.blocks.source.children; + Editable = wp.blocks.Editable; registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-03', { title: 'Hello World (Step 3)', @@ -26,7 +25,8 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-03', { attributes: { content: { type: 'array', - source: children( 'p' ) + source: 'children', + selector: 'p', } }, @@ -61,7 +61,6 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-03', { {% ESNext %} ```js const { registerBlockType, Editable, source } = wp.blocks; -const { children } = source; registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', { title: 'Hello World (Step 3)', @@ -73,7 +72,8 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-03', { attributes: { content: { type: 'array', - source: children( 'p' ), + source: 'children', + selector: 'p', }, }, From 07c0bad1d65c14eec95aa2bbf0b1abae1fc9e6a0 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 17 Oct 2017 10:17:34 +0100 Subject: [PATCH 07/13] Blocks API: Simplify logic using lodash's reduce --- blocks/api/parser.js | 7 +++---- blocks/api/registration.js | 4 ++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index f1154bfe69e53c..135ef0fd134747 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -2,7 +2,7 @@ * External dependencies */ import { parse as hpqParse } from 'hpq'; -import { keys } from 'lodash'; +import { keys, reduce } from 'lodash'; /** * Internal dependencies @@ -124,11 +124,10 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com * @return {Object} All block attributes */ export function getBlockAttributes( blockType, innerHTML, attributes ) { - const blockAttributes = keys( blockType.attributes ).reduce( ( memo, attributeKey ) => { - const attributeSchema = blockType.attributes[ attributeKey ]; + const blockAttributes = reduce( blockType.attributes, ( memo, attributeSchema, attributeKey ) => { memo[ attributeKey ] = getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes ); return memo; - }, {} ) || {}; + }, {} ); // If the block supports a custom className parse it if ( blockType.className !== false && attributes && attributes.className ) { diff --git a/blocks/api/registration.js b/blocks/api/registration.js index 9996c22d0c98ab..f16380c6675d9b 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -3,7 +3,11 @@ /** * External dependencies */ +<<<<<<< HEAD import { get, isFunction, some, mapValues } from 'lodash'; +======= +import { get, isFunction, some, reduce } from 'lodash'; +>>>>>>> Blocks API: Simplify logic using lodash's reduce /** * WordPress dependencies From 7c300a21e3b0ad2a3de153a6adea6a82f4f8af2d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 23 Oct 2017 13:53:49 +0100 Subject: [PATCH 08/13] Parser: Only support `query` with object nesting --- blocks/api/parser.js | 8 +-- blocks/api/registration.js | 4 -- blocks/library/gallery/index.js | 25 ++++---- blocks/library/pullquote/index.js | 17 ++++-- blocks/library/quote/index.js | 59 ++++++++++++------- blocks/library/text-columns/index.js | 10 ++-- blocks/test/fixtures/core__pullquote.json | 12 +++- .../core__pullquote__multi-paragraph.json | 42 +++++++++---- .../test/fixtures/core__quote__style-1.json | 12 +++- .../test/fixtures/core__quote__style-2.json | 12 +++- blocks/test/fixtures/core__text-columns.json | 16 +++-- docs/attributes.md | 7 +-- 12 files changed, 146 insertions(+), 78 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 135ef0fd134747..04523e9962d6e0 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -73,12 +73,12 @@ export function matcherFromSource( sourceConfig ) { case 'node': return node( sourceConfig.selector ); case 'query': - return query( sourceConfig.selector, matcherFromSource( sourceConfig.query ) ); - case 'object': - return keys( sourceConfig.object ).reduce( ( memo, key ) => { - memo[ key ] = matcherFromSource( sourceConfig.object[ key ] ); + const subMatchers = keys( sourceConfig.query ).reduce( ( memo, key ) => { + memo[ key ] = matcherFromSource( sourceConfig.query[ key ] ); return memo; }, {} ); + + return query( sourceConfig.selector, subMatchers ); default: // eslint-disable-next-line no-console console.error( `Unkown source type "${ sourceConfig.source }"` ); diff --git a/blocks/api/registration.js b/blocks/api/registration.js index f16380c6675d9b..9996c22d0c98ab 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -3,11 +3,7 @@ /** * External dependencies */ -<<<<<<< HEAD import { get, isFunction, some, mapValues } from 'lodash'; -======= -import { get, isFunction, some, reduce } from 'lodash'; ->>>>>>> Blocks API: Simplify logic using lodash's reduce /** * WordPress dependencies diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index d275526415e5a3..1d607a9cc07ba8 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -33,20 +33,17 @@ registerBlockType( 'core/gallery', { source: 'query', selector: 'div.wp-block-gallery figure.blocks-gallery-image img', query: { - source: 'object', - object: { - url: { - source: 'attribute', - attribute: 'src', - }, - alt: { - source: 'attribute', - attribute: 'alt', - }, - id: { - source: 'attribute', - attribute: 'data-id', - }, + url: { + source: 'attribute', + attribute: 'src', + }, + alt: { + source: 'attribute', + attribute: 'alt', + }, + id: { + source: 'attribute', + attribute: 'data-id', }, }, }, diff --git a/blocks/library/pullquote/index.js b/blocks/library/pullquote/index.js index 655756d2d0b14c..d1369ca6637f07 100644 --- a/blocks/library/pullquote/index.js +++ b/blocks/library/pullquote/index.js @@ -15,6 +15,11 @@ import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; +const toEditableValue = value => value.map( ( subValue => subValue.children ) ); +const fromEditableValue = value => value.map( ( subValue ) => ( { + children: subValue, +} ) ); + registerBlockType( 'core/pullquote', { title: __( 'Pullquote' ), @@ -29,7 +34,9 @@ registerBlockType( 'core/pullquote', { source: 'query', selector: 'blockquote > p', query: { - source: 'node', + children: { + source: 'node', + }, }, }, citation: { @@ -73,10 +80,10 @@ registerBlockType( 'core/pullquote', {
setAttributes( { - value: nextValue, + value: fromEditableValue( nextValue ), } ) } placeholder={ __( 'Write quote…' ) } @@ -107,7 +114,9 @@ registerBlockType( 'core/pullquote', { return (
- { value && value.map( ( paragraph, i ) =>

{ paragraph.props.children }

) } + { value && value.map( ( paragraph, i ) => +

{ paragraph.children && paragraph.children.props.children }

+ ) } { citation && citation.length > 0 && (
{ citation }
) } diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index 1ebdf652a5cb3d..aa19ee93111b3f 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { isString, isObject } from 'lodash'; +import { isString } from 'lodash'; /** * WordPress dependencies @@ -21,6 +21,11 @@ import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; +const toEditableValue = value => value.map( ( subValue => subValue.children ) ); +const fromEditableValue = value => value.map( ( subValue ) => ( { + children: subValue, +} ) ); + registerBlockType( 'core/quote', { title: __( 'Quote' ), icon: 'format-quote', @@ -32,7 +37,9 @@ registerBlockType( 'core/quote', { source: 'query', selector: 'blockquote > p', query: { - source: 'node', + children: { + source: 'node', + }, }, default: [], }, @@ -58,7 +65,7 @@ registerBlockType( 'core/quote', { transform: ( { content } ) => { return createBlock( 'core/quote', { value: [ -

{ content }

, + { children:

{ content }

}, ], } ); }, @@ -69,7 +76,7 @@ registerBlockType( 'core/quote', { transform: ( { content } ) => { return createBlock( 'core/quote', { value: [ -

{ content }

, + { children:

{ content }

}, ], } ); }, @@ -80,7 +87,7 @@ registerBlockType( 'core/quote', { transform: ( { content } ) => { return createBlock( 'core/quote', { value: [ -

{ content }

, + { children:

{ content }

}, ], } ); }, @@ -101,7 +108,9 @@ registerBlockType( 'core/quote', { content: citation, } ); } - const textContent = isString( textElement ) ? textElement : textElement.props.children; + const textContent = isString( textElement.children ) ? + textElement.children : + textElement.children.props.children; if ( Array.isArray( value ) || citation ) { const text = createBlock( 'core/paragraph', { content: textContent, @@ -109,7 +118,9 @@ registerBlockType( 'core/quote', { const quote = createBlock( 'core/quote', { ...attrs, citation, - value: Array.isArray( value ) ? value.slice( 1 ) : '', + value: Array.isArray( value ) ? + value.slice( 1 ) : + [], } ); return [ text, quote ]; @@ -123,25 +134,31 @@ registerBlockType( 'core/quote', { type: 'block', blocks: [ 'core/heading' ], transform: ( { value, citation, ...attrs } ) => { - const isMultiParagraph = Array.isArray( value ) && isObject( value[ 0 ] ) && value[ 0 ].type === 'p'; - const headingElement = isMultiParagraph ? value[ 0 ] : value; - const headingContent = isObject( headingElement ) && value[ 0 ].type === 'p' ? - headingElement.props.children : - headingElement; - if ( isMultiParagraph || citation ) { - const heading = createBlock( 'core/heading', { - content: headingContent, + const textElement = value[ 0 ]; + if ( ! textElement ) { + return createBlock( 'core/heading', { + content: citation, + } ); + } + const textContent = isString( textElement.children ) ? + textElement.children : + textElement.children.props.children; + if ( Array.isArray( value ) || citation ) { + const text = createBlock( 'core/heading', { + content: textContent, } ); const quote = createBlock( 'core/quote', { ...attrs, citation, - value: Array.isArray( value ) ? value.slice( 1 ) : '', + value: Array.isArray( value ) ? + value.slice( 1 ) : + [], } ); - return [ heading, quote ]; + return [ text, quote ]; } return createBlock( 'core/heading', { - content: headingContent, + content: textContent, } ); }, }, @@ -184,10 +201,10 @@ registerBlockType( 'core/quote', { > setAttributes( { - value: nextValue, + value: fromEditableValue( nextValue ), } ) } focus={ focusedEditable === 'value' ? focus : null } @@ -223,7 +240,7 @@ registerBlockType( 'core/quote', { style={ { textAlign: align ? align : null } } > { value.map( ( paragraph, i ) => ( -

{ paragraph.props.children }

+

{ paragraph.children && paragraph.children.props.children }

) ) } { citation && citation.length > 0 && (
{ citation }
diff --git a/blocks/library/text-columns/index.js b/blocks/library/text-columns/index.js index 3843af938c9bac..4fda12711b3e13 100644 --- a/blocks/library/text-columns/index.js +++ b/blocks/library/text-columns/index.js @@ -34,7 +34,9 @@ registerBlockType( 'core/text-columns', { source: 'query', selector: 'p', query: { - source: 'children', + children: { + source: 'children', + }, }, default: [ [], [] ], }, @@ -86,12 +88,12 @@ registerBlockType( 'core/text-columns', {
{ setAttributes( { content: [ ...content.slice( 0, index ), - nextContent, + { children: nextContent }, ...content.slice( index + 1 ), ], } ); @@ -112,7 +114,7 @@ registerBlockType( 'core/text-columns', {
{ times( columns, ( index ) =>
-

{ content && content[ index ] }

+

{ content && content[ index ].children }

) }
diff --git a/blocks/test/fixtures/core__pullquote.json b/blocks/test/fixtures/core__pullquote.json index 5844ee2aff7735..83c8ec4ec2acf7 100644 --- a/blocks/test/fixtures/core__pullquote.json +++ b/blocks/test/fixtures/core__pullquote.json @@ -6,8 +6,16 @@ "attributes": { "value": [ { - "type": "p", - "children": "Testing pullquote block..." + "children": { + "type": "p", + "key": null, + "ref": null, + "props": { + "children": "Testing pullquote block..." + }, + "_owner": null, + "_store": {} + } } ], "citation": [ diff --git a/blocks/test/fixtures/core__pullquote__multi-paragraph.json b/blocks/test/fixtures/core__pullquote__multi-paragraph.json index c2a016ee23d88c..060480767a2996 100644 --- a/blocks/test/fixtures/core__pullquote__multi-paragraph.json +++ b/blocks/test/fixtures/core__pullquote__multi-paragraph.json @@ -6,18 +6,40 @@ "attributes": { "value": [ { - "type": "p", - "children": [ - "Paragraph ", - { - "type": "strong", - "children": "one" - } - ] + "children": { + "type": "p", + "key": null, + "ref": null, + "props": { + "children": [ + "Paragraph ", + { + "type": "strong", + "key": "_domReact68", + "ref": null, + "props": { + "children": "one" + }, + "_owner": null, + "_store": {} + } + ] + }, + "_owner": null, + "_store": {} + } }, { - "type": "p", - "children": "Paragraph two" + "children": { + "type": "p", + "key": null, + "ref": null, + "props": { + "children": "Paragraph two" + }, + "_owner": null, + "_store": {} + } } ], "citation": [ diff --git a/blocks/test/fixtures/core__quote__style-1.json b/blocks/test/fixtures/core__quote__style-1.json index 7ac056d77ea5db..c4587aa2988038 100644 --- a/blocks/test/fixtures/core__quote__style-1.json +++ b/blocks/test/fixtures/core__quote__style-1.json @@ -6,8 +6,16 @@ "attributes": { "value": [ { - "type": "p", - "children": "The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery." + "children": { + "type": "p", + "key": null, + "ref": null, + "props": { + "children": "The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery." + }, + "_owner": null, + "_store": {} + } } ], "citation": [ diff --git a/blocks/test/fixtures/core__quote__style-2.json b/blocks/test/fixtures/core__quote__style-2.json index b17ca871c30192..e5edab1803ea81 100644 --- a/blocks/test/fixtures/core__quote__style-2.json +++ b/blocks/test/fixtures/core__quote__style-2.json @@ -6,8 +6,16 @@ "attributes": { "value": [ { - "type": "p", - "children": "There is no greater agony than bearing an untold story inside you." + "children": { + "type": "p", + "key": null, + "ref": null, + "props": { + "children": "There is no greater agony than bearing an untold story inside you." + }, + "_owner": null, + "_store": {} + } } ], "citation": [ diff --git a/blocks/test/fixtures/core__text-columns.json b/blocks/test/fixtures/core__text-columns.json index 7b4d9a7baa68e7..ef3ee780fa930f 100644 --- a/blocks/test/fixtures/core__text-columns.json +++ b/blocks/test/fixtures/core__text-columns.json @@ -5,12 +5,16 @@ "isValid": true, "attributes": { "content": [ - [ - "One" - ], - [ - "Two" - ] + { + "children": [ + "One" + ] + }, + { + "children": [ + "Two" + ] + } ], "columns": 2, "width": "center" diff --git a/docs/attributes.md b/docs/attributes.md index e742b16c77690c..ce1d993d0b3360 100644 --- a/docs/attributes.md +++ b/docs/attributes.md @@ -121,11 +121,8 @@ _Example_: Extract `src` and `alt` from each image element in the block's markup source: 'query' selector: 'img', query: { - source: 'object', - object: { - url: { source: 'attribute', attribute: 'src' }, - alt: { source: 'attribute', attribute: 'alt' }, - }, + url: { source: 'attribute', attribute: 'src' }, + alt: { source: 'attribute', attribute: 'alt' }, } } } From 2873c6587e35bb9966803f3b9035eab150c51338 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 7 Nov 2017 10:06:28 +0100 Subject: [PATCH 09/13] Parser: Avoid explicit handling of non-content attributes --- blocks/api/parser.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index 04523e9962d6e0..c6aaeb0ef85f26 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -2,7 +2,7 @@ * External dependencies */ import { parse as hpqParse } from 'hpq'; -import { keys, reduce } from 'lodash'; +import { keys, mapValues } from 'lodash'; /** * Internal dependencies @@ -99,17 +99,18 @@ export function matcherFromSource( sourceConfig ) { export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, commentAttributes ) { let value; switch ( attributeSchema.source ) { - case 'meta': - break; case 'comment': value = commentAttributes ? commentAttributes[ attributeKey ] : undefined; break; - default: { - // Coerce value to specified type - const matcher = matcherFromSource( attributeSchema ); - value = hpqParse( innerHTML, matcher ); + case 'attribute': + case 'property': + case 'html': + case 'text': + case 'children': + case 'node': + case 'query': + value = hpqParse( innerHTML, matcherFromSource( attributeSchema ) ); break; - } } return value === undefined ? attributeSchema.default : asType( value, attributeSchema.type ); @@ -124,13 +125,12 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com * @return {Object} All block attributes */ export function getBlockAttributes( blockType, innerHTML, attributes ) { - const blockAttributes = reduce( blockType.attributes, ( memo, attributeSchema, attributeKey ) => { - memo[ attributeKey ] = getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes ); - return memo; - }, {} ); + const blockAttributes = mapValues( blockType.attributes, ( attributeSchema, attributeKey ) => { + return getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes ); + } ); // If the block supports a custom className parse it - if ( blockType.className !== false && attributes && attributes.className ) { + if ( false !== blockType.className && attributes && attributes.className ) { blockAttributes.className = attributes.className; } @@ -151,7 +151,7 @@ export function createBlockWithFallback( name, innerHTML, attributes ) { // Convert 'core/text' blocks in existing content to the new // 'core/paragraph'. - if ( name === 'core/text' || name === 'core/cover-text' ) { + if ( 'core/text' === name || 'core/cover-text' === name ) { name = 'core/paragraph'; } From 254a351d7b4aeea67320bfe0f10e22f19618bfd2 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 8 Nov 2017 10:49:40 +0100 Subject: [PATCH 10/13] Parser: Treat attributes with "undefined" source as "comment" attributes --- blocks/api/parser.js | 3 ++- blocks/api/raw-handling/shortcode-converter.js | 5 +---- blocks/api/registration.js | 9 +++------ blocks/api/serializer.js | 2 +- blocks/api/test/parser.js | 3 --- blocks/api/test/registration.js | 1 - blocks/api/test/serializer.js | 4 ---- 7 files changed, 7 insertions(+), 20 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index c6aaeb0ef85f26..fdb0e4d5fbaace 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -99,7 +99,8 @@ export function matcherFromSource( sourceConfig ) { export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, commentAttributes ) { let value; switch ( attributeSchema.source ) { - case 'comment': + // undefined source means that it's an attribute serialized to the block's "comment" + case undefined: value = commentAttributes ? commentAttributes[ attributeKey ] : undefined; break; case 'attribute': diff --git a/blocks/api/raw-handling/shortcode-converter.js b/blocks/api/raw-handling/shortcode-converter.js index 71f775c29af503..0b429b8063dce9 100644 --- a/blocks/api/raw-handling/shortcode-converter.js +++ b/blocks/api/raw-handling/shortcode-converter.js @@ -41,10 +41,7 @@ export default function( HTML ) { getBlockAttributes( { ...blockType, - attributes: mapValues( transform.attributes, attribute => ( { - source: 'comment', - ...attribute, - } ) ), + attributes: transform.attributes, }, match.shortcode.content, attributes, diff --git a/blocks/api/registration.js b/blocks/api/registration.js index 9996c22d0c98ab..13eeaecca67777 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -3,7 +3,7 @@ /** * External dependencies */ -import { get, isFunction, some, mapValues } from 'lodash'; +import { get, isFunction, some } from 'lodash'; /** * WordPress dependencies @@ -121,15 +121,12 @@ export function registerBlockType( name, settings ) { const attributes = settings.attributes ? settings.attributes : - get( window._wpBlocksAttributes, name ); + get( window._wpBlocksAttributes, name, {} ); let block = blocks[ name ] = { ...settings, name, - attributes: mapValues( attributes, ( attribute ) => ( { - source: 'comment', - ...attribute, - } ) ), + attributes, }; block = applyFilters( 'registerBlockType', block, name ); diff --git a/blocks/api/serializer.js b/blocks/api/serializer.js index f26863f00f630d..e8a4e46c54c779 100644 --- a/blocks/api/serializer.js +++ b/blocks/api/serializer.js @@ -99,7 +99,7 @@ export function getCommentAttributes( allAttributes, blockType ) { } // Ignore values sources from content and post meta - if ( attributeSchema.source !== 'comment' ) { + if ( attributeSchema.source !== undefined ) { return result; } diff --git a/blocks/api/test/parser.js b/blocks/api/test/parser.js index 619c6241c7eb7c..577fc93b9e161f 100644 --- a/blocks/api/test/parser.js +++ b/blocks/api/test/parser.js @@ -83,7 +83,6 @@ describe( 'block parser', () => { 'number', { type: 'number', - source: 'comment', }, '', { number: 10 } @@ -138,12 +137,10 @@ describe( 'block parser', () => { }, align: { type: 'string', - source: 'comment', }, topic: { type: 'string', default: 'none', - source: 'comment', }, }, }; diff --git a/blocks/api/test/registration.js b/blocks/api/test/registration.js index a2deb51659956f..6f4d1c2df161c6 100644 --- a/blocks/api/test/registration.js +++ b/blocks/api/test/registration.js @@ -161,7 +161,6 @@ describe( 'blocks', () => { title: 'block title', icon: 'block-default', attributes: { ok: { - source: 'comment', type: 'boolean', } }, } ); diff --git a/blocks/api/test/serializer.js b/blocks/api/test/serializer.js index 93862a77e47ddc..d0f65d6eb6c41f 100644 --- a/blocks/api/test/serializer.js +++ b/blocks/api/test/serializer.js @@ -160,11 +160,9 @@ describe( 'block serializer', () => { }, category: { type: 'string', - source: 'comment', }, ripeness: { type: 'string', - source: 'comment', }, } } ); @@ -181,11 +179,9 @@ describe( 'block serializer', () => { }, { attributes: { fruit: { type: 'string', - source: 'comment', }, ripeness: { type: 'string', - source: 'comment', }, } } ); From a6ffcaa90da91054d04e8bb0b2ceca7dcdf0093a Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 10 Nov 2017 09:50:22 +0100 Subject: [PATCH 11/13] Remove duplicate docs and keep property matcher undocumented --- blocks/library/freeform/index.js | 3 +-- docs/attributes.md | 34 -------------------------------- 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/blocks/library/freeform/index.js b/blocks/library/freeform/index.js index 2bb358e4cd1293..cfd8b9f2723b0d 100644 --- a/blocks/library/freeform/index.js +++ b/blocks/library/freeform/index.js @@ -20,8 +20,7 @@ registerBlockType( 'core/freeform', { attributes: { content: { type: 'string', - source: 'property', - property: 'innerHTML', + source: 'html', }, }, diff --git a/docs/attributes.md b/docs/attributes.md index ce1d993d0b3360..059250a34d3f09 100644 --- a/docs/attributes.md +++ b/docs/attributes.md @@ -25,40 +25,6 @@ _Example_: Extract the `src` attribute from an image found in the block's markup // { "url": "https://lorempixel.com/1200/800/" } ``` -### `attribute` - -Use `attribute` to extract the value of an attribute from markup. - -_Example_: Extract the `src` attribute from an image found in the block's markup. - -```js -{ - url: { - source: 'attribute', - selector: 'img', - attribute: 'src', - } -} -// { "url": "https://lorempixel.com/1200/800/" } -``` - -### `property` - -Use `property` to extract the value of a property of a DOM Node from markup. - -_Example_: Extract the `nodeName` property from a heading's node. - -```js -{ - tagName: { - source: 'property', - selector: 'h1,h2,h3,h4,h5,h6', - property: 'nodeName', - } -} -// { "tagName": "h2" } -``` - ### `text` Use `text` to extract the inner text from markup. From 032ddc43a51f3699ab4cc9a235b3c5537fa5c203 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2017 17:52:46 +0100 Subject: [PATCH 12/13] Parser: Fix small code style per review --- blocks/api/parser.js | 10 +++------- blocks/api/serializer.js | 3 ++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/blocks/api/parser.js b/blocks/api/parser.js index fdb0e4d5fbaace..f04d4c23b1ce33 100644 --- a/blocks/api/parser.js +++ b/blocks/api/parser.js @@ -2,7 +2,7 @@ * External dependencies */ import { parse as hpqParse } from 'hpq'; -import { keys, mapValues } from 'lodash'; +import { mapValues } from 'lodash'; /** * Internal dependencies @@ -73,11 +73,7 @@ export function matcherFromSource( sourceConfig ) { case 'node': return node( sourceConfig.selector ); case 'query': - const subMatchers = keys( sourceConfig.query ).reduce( ( memo, key ) => { - memo[ key ] = matcherFromSource( sourceConfig.query[ key ] ); - return memo; - }, {} ); - + const subMatchers = mapValues( sourceConfig.query, matcherFromSource ); return query( sourceConfig.selector, subMatchers ); default: // eslint-disable-next-line no-console @@ -131,7 +127,7 @@ export function getBlockAttributes( blockType, innerHTML, attributes ) { } ); // If the block supports a custom className parse it - if ( false !== blockType.className && attributes && attributes.className ) { + if ( blockType.className !== false && attributes && attributes.className ) { blockAttributes.className = attributes.className; } diff --git a/blocks/api/serializer.js b/blocks/api/serializer.js index e8a4e46c54c779..4e3628147904db 100644 --- a/blocks/api/serializer.js +++ b/blocks/api/serializer.js @@ -98,7 +98,8 @@ export function getCommentAttributes( allAttributes, blockType ) { return result; } - // Ignore values sources from content and post meta + // Ignore all attributes but the ones with an "undefined" source + // "undefined" source refers to attributes saved in the block comment if ( attributeSchema.source !== undefined ) { return result; } From 2aeb51a51f5f5d0cbd34ecac7620a8b4786d78c9 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2017 17:53:12 +0100 Subject: [PATCH 13/13] Extensibility: Fix the anchor extension after rebase --- blocks/api/registration.js | 14 +++++--------- blocks/hooks/anchor.js | 6 ++++-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/blocks/api/registration.js b/blocks/api/registration.js index 13eeaecca67777..cd7b5e546cad3e 100644 --- a/blocks/api/registration.js +++ b/blocks/api/registration.js @@ -119,19 +119,15 @@ export function registerBlockType( name, settings ) { settings.icon = 'block-default'; } - const attributes = settings.attributes ? - settings.attributes : - get( window._wpBlocksAttributes, name, {} ); - - let block = blocks[ name ] = { - ...settings, + settings = { name, - attributes, + attributes: get( window._wpBlocksAttributes, name, {} ), + ...settings, }; - block = applyFilters( 'registerBlockType', block, name ); + settings = applyFilters( 'registerBlockType', settings, name ); - return blocks[ name ] = block; + return blocks[ name ] = settings; } /** diff --git a/blocks/hooks/anchor.js b/blocks/hooks/anchor.js index 00274520932e8b..a674a6ba57bf5d 100644 --- a/blocks/hooks/anchor.js +++ b/blocks/hooks/anchor.js @@ -12,7 +12,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { source, hasBlockSupport } from '../api'; +import { hasBlockSupport } from '../api'; import InspectorControls from '../inspector-controls'; /** @@ -35,7 +35,9 @@ export function addAttribute( settings ) { settings.attributes = assign( settings.attributes, { anchor: { type: 'string', - source: source.attr( '*', 'id' ), + source: 'attribute', + attribute: 'id', + selector: '*', }, } ); }