Skip to content

Commit

Permalink
Merge pull request #624 from WordPress/update/608-remove-attributes-dom
Browse files Browse the repository at this point in the history
Remove and prevent DOM access in block attributes matchers
  • Loading branch information
aduth authored May 5, 2017
2 parents 8106aa6 + 3e14439 commit 6f5deec
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 38 deletions.
21 changes: 15 additions & 6 deletions blocks/api/parser.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* External dependencies
*/
import * as query from 'hpq';
import { escape, unescape } from 'lodash';
import { parse as hpqParse } from 'hpq';
import { escape, unescape, pickBy } from 'lodash';

/**
* Internal dependencies
Expand All @@ -19,10 +19,19 @@ import { createBlock } from './factory';
* @return {Object} Block attributes
*/
export function parseBlockAttributes( rawContent, blockSettings ) {
if ( 'function' === typeof blockSettings.attributes ) {
return blockSettings.attributes( rawContent );
} else if ( blockSettings.attributes ) {
return query.parse( rawContent, blockSettings.attributes );
const { attributes } = blockSettings;
if ( 'function' === typeof attributes ) {
return attributes( rawContent );
} else if ( attributes ) {
// Matchers are implemented as functions that receive a DOM node from
// which to select data. Use of the DOM is incidental and we shouldn't
// guarantee a contract that this be provided, else block implementers
// may feel compelled to use the node. Instead, matchers are intended
// as a generic interface to query data from any tree shape. Here we
// pick only matchers which include an internal flag.
const knownMatchers = pickBy( attributes, '_wpBlocksKnownMatcher' );

return hpqParse( rawContent, knownMatchers );
}

return {};
Expand Down
31 changes: 28 additions & 3 deletions blocks/api/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,35 @@
* External dependencies
*/
import { nodeListToReact } 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 * from 'hpq';
/**
* Given a matcher function creator, returns a new function which applies an
* internal flag to the created matcher.
*
* @param {Function} fn Original matcher function creator
* @return {Function} Modified matcher function creator
*/
function withKnownMatcherFlag( fn ) {
return flow( fn, ( matcher ) => {
matcher._wpBlocksKnownMatcher = true;
return matcher;
} );
}

export function children( selector ) {
export const attr = withKnownMatcherFlag( originalAttr );
export const prop = withKnownMatcherFlag( originalProp );
export const html = withKnownMatcherFlag( originalHtml );
export const text = withKnownMatcherFlag( originalText );
export const query = withKnownMatcherFlag( originalQuery );
export const children = withKnownMatcherFlag( ( selector ) => {
return ( node ) => {
let match = node;

Expand All @@ -19,4 +44,4 @@ export function children( selector ) {

return [];
};
}
} );
5 changes: 3 additions & 2 deletions blocks/api/test/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* External dependencies
*/
import { expect } from 'chai';
import { text } from 'hpq';

/**
* Internal dependencies
*/
import { text } from '../query';
import {
getBlockAttributes,
parseBlockAttributes,
Expand Down Expand Up @@ -47,7 +47,8 @@ describe( 'block parser', () => {
it( 'should use the query object implementation', () => {
const blockSettings = {
attributes: {
emphasis: text( 'strong' )
emphasis: text( 'strong' ),
ignoredDomMatcher: ( node ) => node.innerHTML
}
};

Expand Down
13 changes: 10 additions & 3 deletions blocks/api/test/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@
* External dependencies
*/
import { expect } from 'chai';
import { parse } from 'hpq';

/**
* Internal dependencies
*/
import { parse, children } from '../query';
import * as query from '../query';

describe( 'query', () => {
it( 'should generate matchers which apply internal flag', () => {
for ( const matcherFn in query ) {
expect( query[ matcherFn ]()._wpBlocksKnownMatcher ).to.be.true();
}
} );

describe( 'children()', () => {
it( 'should return a matcher function', () => {
const matcher = children();
const matcher = query.children();

expect( matcher ).to.be.a( 'function' );
} );
Expand All @@ -20,7 +27,7 @@ describe( 'query', () => {
// Assumption here is that we can cleanly convert back and forth
// between a string and WPElement representation
const html = '<blockquote><p>A delicious sundae dessert</p></blockquote>';
const match = parse( html, children() );
const match = parse( html, query.children() );

expect( wp.element.renderToString( match ) ).to.equal( html );
} );
Expand Down
3 changes: 1 addition & 2 deletions blocks/library/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ registerBlock( 'core/button', {
attributes: {
url: attr( 'a', 'href' ),
title: attr( 'a', 'title' ),
text: children( 'a' ),
align: ( node ) => ( node.className.match( /\balign(\S+)/ ) || [] )[ 1 ]
text: children( 'a' )
},

controls: [
Expand Down
3 changes: 1 addition & 2 deletions blocks/library/image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ registerBlock( 'core/image', {
attributes: {
url: attr( 'img', 'src' ),
alt: attr( 'img', 'alt' ),
caption: children( 'figcaption' ),
align: ( node ) => ( node.className.match( /\balign(\S+)/ ) || [] )[ 1 ]
caption: children( 'figcaption' )
},

controls: [
Expand Down
19 changes: 3 additions & 16 deletions blocks/library/quote/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import './style.scss';
import { registerBlock, query as hpq } from 'api';
import Editable from 'components/editable';

const { children, query, attr } = hpq;
const { children, query } = hpq;

registerBlock( 'core/quote', {
title: wp.i18n.__( 'Quote' ),
Expand All @@ -14,26 +14,13 @@ registerBlock( 'core/quote', {

attributes: {
value: query( 'blockquote > p', children() ),
citation: children( 'footer' ),
style: ( node ) => {
const value = attr( 'blockquote', 'class' )( node );
if ( ! value ) {
return;
}

const match = value.match( /\bblocks-quote-style-(\d+)\b/ );
if ( ! match ) {
return;
}

return Number( match[ 1 ] );
}
citation: children( 'footer' )
},

controls: [ 1, 2 ].map( ( variation ) => ( {
icon: 'format-quote',
title: wp.i18n.sprintf( wp.i18n.__( 'Quote style %d' ), variation ),
isActive: ( { style = 1 } ) => style === variation,
isActive: ( { style = 1 } ) => Number( style ) === variation,
onClick( attributes, setAttributes ) {
setAttributes( { style: variation } );
},
Expand Down
8 changes: 4 additions & 4 deletions post-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ window._wpGutenbergPost = {
'<p>Handling images and media with the utmost care is a primary focus of the new editor. Hopefully you\'ll find aspects like adding captions or going full-width with your pictures much easier and robust than before.</p>',
'<!-- /wp:core/text -->',

'<!-- wp:core/image -->',
'<!-- wp:core/image align="center" -->',
'<figure><img src="https://cldup.com/E4PzNdrFSQ.jpg" class="aligncenter"/><figcaption><p>Give it a try. Press the &quot;really wide&quot; button on the image toolbar.</p></figcaption></figure>',
'<!-- /wp:core/image -->',

Expand Down Expand Up @@ -57,7 +57,7 @@ window._wpGutenbergPost = {
'<p>If you want to learn more about how to build additional blocks, or if you are interested in helping with the project, head over to the <a href="https://github.com/WordPress/gutenberg">GitHub repository</a>.</p>',
'<!-- /wp:core/text -->',

'<!-- wp:core/button -->',
'<!-- wp:core/button align="center" -->',
'<div class="aligncenter"><a href="https://github.com/WordPress/gutenberg"><span>Help build Gutenberg</span></a></div>',
'<!-- /wp:core/button -->',

Expand All @@ -73,7 +73,7 @@ window._wpGutenbergPost = {
'<p>A huge benefit of blocks is that you can edit them in place and manipulate you content directly. Instead of having fields for editing things like the source of a quote, or the text of a button, you can directly change the content. Try editing the following quote:</p>',
'<!-- /wp:core/text -->',

'<!-- wp:core/quote -->',
'<!-- wp:core/quote style="1" -->',
'<blockquote class="blocks-quote-style-1"><p>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.</p><footer><p>Matt Mullenweg, 2017</p></footer></blockquote>',
'<!-- /wp:core/quote -->',

Expand All @@ -85,7 +85,7 @@ window._wpGutenbergPost = {
'<p>Blocks can be anything you need. For instance, you may want to insert a subdued quote as part of the composition of your text, or you may prefer to display a giant stylized one. All of these options are available in the inserter.</p>',
'<!-- /wp:core/text -->',

'<!-- wp:core/quote -->',
'<!-- wp:core/quote style="2" -->',
'<blockquote class="blocks-quote-style-2"><p>There is no greater agony than bearing an untold story inside you.</p><footer><p>Maya Angelou</p></footer></blockquote>',
'<!-- /wp:core/quote -->',

Expand Down

0 comments on commit 6f5deec

Please sign in to comment.