Skip to content

Commit

Permalink
Merge branch 'master' into update/class-editor-block-description
Browse files Browse the repository at this point in the history
* master: (45 commits)
  Parser: Hide the core namespace in serialised data (WordPress#2950)
  fix: Undefined index warning (WordPress#2982)
  navigation via keydown
  PHPCS improvements (WordPress#2914)
  Update/html block description (WordPress#2917)
  Framework: Merge EditorSettingsProvider into EditorProvider
  Framework: Move the store initialization to a dedicated component
  Rotate header ellipsis to match block ellipsis
  add/459: Added support for ins, sub and sup
  Refresh nonce with heartbeat (WordPress#2790)
  Paste: add table support
  Bump version to 1.4.0. (WordPress#2954)
  Blocks: The custom classname should be persisted properly in the block's comment
  Editor: Fix the scroll position when reordering blocks
  Polish spacing in block ellipsis menu (WordPress#2955)
  Editor: HTML Editor per block (WordPress#2797)
  Show most frequently used blocks next to inserter (WordPress#2877)
  add/459: Added light grey background to selected inline boundaries
  Extend inline boundaries to other elements
  Move markdown fix to own plugin-compatibility file
  ...
  • Loading branch information
DevinWalker committed Oct 12, 2017
2 parents ec7f1a9 + d715d61 commit 79a29f6
Show file tree
Hide file tree
Showing 127 changed files with 2,016 additions and 839 deletions.
2 changes: 1 addition & 1 deletion blocks/README.md
Expand Up @@ -33,7 +33,7 @@ function myplugin_enqueue_block_editor_assets() {
wp_enqueue_script(
'myplugin-block',
plugins_url( 'block.js', __FILE__ ),
array( 'wp-blocks', wp-element' )
array( 'wp-blocks', 'wp-element' )
);
}
add_action( 'enqueue_block_editor_assets', 'myplugin_enqueue_block_editor_assets' );
Expand Down
7 changes: 7 additions & 0 deletions blocks/api/factory.js
Expand Up @@ -39,10 +39,17 @@ export function createBlock( name, blockAttributes = {} ) {

return result;
}, {} );

// Keep the anchor if the block supports it
if ( blockType.supportAnchor && blockAttributes.anchor ) {
attributes.anchor = blockAttributes.anchor;
}

// Keep the className if the block supports it
if ( blockType.className !== false && blockAttributes.className ) {
attributes.className = blockAttributes.className;
}

// Blocks are stored with a unique ID, the assigned type name,
// and the block attributes.
return {
Expand Down
5 changes: 3 additions & 2 deletions blocks/api/index.js
Expand Up @@ -5,9 +5,10 @@ import * as source from './source';

export { source };
export { createBlock, switchToBlockType } from './factory';
export { default as parse } from './parser';
export { default as parse, getSourcedAttributes } from './parser';
export { default as pasteHandler } from './paste';
export { default as serialize, getBlockDefaultClassname } from './serializer';
export { default as serialize, getBlockDefaultClassname, getBlockContent } from './serializer';
export { isValidBlock } from './validation';
export { getCategories } from './categories';
export {
registerBlockType,
Expand Down
5 changes: 5 additions & 0 deletions blocks/api/parser.js
Expand Up @@ -153,6 +153,11 @@ export function getBlockAttributes( blockType, rawContent, attributes ) {
blockAttributes.anchor = hpqParse( rawContent, attr( '*', 'id' ) );
}

// If the block supports a custom className parse it
if ( blockType.className !== false && attributes && attributes.className ) {
blockAttributes.className = attributes.className;
}

return blockAttributes;
}

Expand Down
8 changes: 7 additions & 1 deletion blocks/api/paste/create-unwrapper.js
Expand Up @@ -13,7 +13,7 @@ function unwrap( node ) {
parent.removeChild( node );
}

export default function( predicate ) {
export default function( predicate, after ) {
return ( node ) => {
if ( node.nodeType !== ELEMENT_NODE ) {
return;
Expand All @@ -23,6 +23,12 @@ export default function( predicate ) {
return;
}

const afterNode = after && after( node );

if ( afterNode ) {
node.appendChild( afterNode );
}

unwrap( node );
};
}
13 changes: 9 additions & 4 deletions blocks/api/paste/index.js
Expand Up @@ -19,7 +19,9 @@ import msListConverter from './ms-list-converter';
import listMerger from './list-merger';
import imageCorrector from './image-corrector';
import blockquoteNormaliser from './blockquote-normaliser';
import { deepFilter, isInvalidInline, isNotWhitelisted, isPlain, isInline } from './utils';
import tableNormaliser from './table-normaliser';
import inlineContentConverter from './inline-content-converter';
import { deepFilterHTML, isInvalidInline, isNotWhitelisted, isPlain, isInline } from './utils';
import showdown from 'showdown';

export default function( { HTML, plainText, inline } ) {
Expand All @@ -34,16 +36,17 @@ export default function( { HTML, plainText, inline } ) {
const converter = new showdown.Converter();

converter.setOption( 'noHeaderId', true );
converter.setOption( 'tables', true );

HTML = converter.makeHtml( plainText );
} else {
// Context dependent filters. Needs to run before we remove nodes.
HTML = deepFilter( HTML, [
HTML = deepFilterHTML( HTML, [
msListConverter,
] );
}

HTML = deepFilter( HTML, [
HTML = deepFilterHTML( HTML, [
listMerger,
imageCorrector,
// Add semantic formatting before attributes are stripped.
Expand All @@ -52,6 +55,8 @@ export default function( { HTML, plainText, inline } ) {
commentRemover,
createUnwrapper( ( node ) => isNotWhitelisted( node ) || ( inline && ! isInline( node ) ) ),
blockquoteNormaliser,
tableNormaliser,
inlineContentConverter,
] );

// Inline paste.
Expand All @@ -62,7 +67,7 @@ export default function( { HTML, plainText, inline } ) {
return HTML;
}

HTML = deepFilter( HTML, [
HTML = deepFilterHTML( HTML, [
createUnwrapper( isInvalidInline ),
] );

Expand Down
27 changes: 27 additions & 0 deletions blocks/api/paste/inline-content-converter.js
@@ -0,0 +1,27 @@
/**
* Browser dependencies
*/
const { ELEMENT_NODE } = window.Node;

/**
* Internal dependencies
*/
import { isInlineWrapper, isInline, isAllowedBlock, deepFilterNodeList } from './utils';
import createUnwrapper from './create-unwrapper';

export default function( node, doc ) {
if ( node.nodeType !== ELEMENT_NODE ) {
return;
}

if ( ! isInlineWrapper( node ) ) {
return;
}

deepFilterNodeList( node.childNodes, [
createUnwrapper(
( childNode ) => ! isInline( childNode ) && ! isAllowedBlock( node, childNode ),
( childNode ) => childNode.nextElementSibling && doc.createElement( 'BR' )
),
], doc );
}
26 changes: 26 additions & 0 deletions blocks/api/paste/readme.md
@@ -0,0 +1,26 @@
# Paste

This folder contains all paste specific logic (filters, converters, normalisers...). Each module is tested on their own, and in addition we have some integration tests for frequently used editors.

## Support table

| Source | Formatting | Headings | Lists | Image | Separator | Table |
| ---------------- | ---------- | -------- | ----- | ----- | --------- | ----- |
| Google Docs |||||||
| Apple Pages ||[1] ||[1] | n/a ||
| MS Word ||||[2] | n/a ||
| MS Word Online ||[3] ||| n/a ||
| Markdown |||||||
| Legacy WordPress ||||[4] |||
| Web |||||||


1. Apple Pages does not pass heading and image information.
2. MS Word only provides a local file path, which cannot be accessed in JavaScript for security reasons.
3. Still to do for MS Word Online.
4. For caption and gallery shortcodes, see #2874.

## Other notable capabilities

* Filters out analytics trackers in the form of images.
* Direct image data pasting coming soon.
18 changes: 18 additions & 0 deletions blocks/api/paste/table-normaliser.js
@@ -0,0 +1,18 @@
/**
* Browser dependencies
*/
const { TEXT_NODE } = window.Node;

export default function( node ) {
if ( node.nodeType !== TEXT_NODE ) {
return;
}

const parentNode = node.parentNode;

if ( [ 'TR', 'TBODY', 'THEAD', 'TFOOT', 'TABLE' ].indexOf( parentNode.nodeName ) === -1 ) {
return;
}

parentNode.removeChild( node );
}
4 changes: 2 additions & 2 deletions blocks/api/paste/test/blockquote-normaliser.js
Expand Up @@ -7,12 +7,12 @@ import { equal } from 'assert';
* Internal dependencies
*/
import blockquoteNormaliser from '../blockquote-normaliser';
import { deepFilter } from '../utils';
import { deepFilterHTML } from '../utils';

describe( 'blockquoteNormaliser', () => {
it( 'should normalise blockquote', () => {
const input = '<blockquote>test</blockquote>';
const output = '<blockquote><p>test</p></blockquote>';
equal( deepFilter( input, [ blockquoteNormaliser ] ), output );
equal( deepFilterHTML( input, [ blockquoteNormaliser ] ), output );
} );
} );
8 changes: 4 additions & 4 deletions blocks/api/paste/test/comment-remover.js
Expand Up @@ -7,14 +7,14 @@ import { equal } from 'assert';
* Internal dependencies
*/
import commentRemover from '../comment-remover';
import { deepFilter } from '../utils';
import { deepFilterHTML } from '../utils';

describe( 'stripWrappers', () => {
describe( 'commentRemover', () => {
it( 'should remove comments', () => {
equal( deepFilter( '<!-- test -->', [ commentRemover ] ), '' );
equal( deepFilterHTML( '<!-- test -->', [ commentRemover ] ), '' );
} );

it( 'should deep remove comments', () => {
equal( deepFilter( '<p>test<!-- test --></p>', [ commentRemover ] ), '<p>test</p>' );
equal( deepFilterHTML( '<p>test<!-- test --></p>', [ commentRemover ] ), '<p>test</p>' );
} );
} );
22 changes: 15 additions & 7 deletions blocks/api/paste/test/create-unwrapper.js
Expand Up @@ -7,28 +7,36 @@ import { equal } from 'assert';
* Internal dependencies
*/
import createUnwrapper from '../create-unwrapper';
import { deepFilter } from '../utils';
import { deepFilterHTML } from '../utils';

const unwrapper = createUnwrapper( ( node ) => node.nodeName === 'SPAN' );
const unwrapperWithAfter = createUnwrapper(
( node ) => node.nodeName === 'P',
() => document.createElement( 'BR' )
);

describe( 'stripWrappers', () => {
describe( 'createUnwrapper', () => {
it( 'should remove spans', () => {
equal( deepFilter( '<span>test</span>', [ unwrapper ] ), 'test' );
equal( deepFilterHTML( '<span>test</span>', [ unwrapper ] ), 'test' );
} );

it( 'should remove wrapped spans', () => {
equal( deepFilter( '<p><span>test</span></p>', [ unwrapper ] ), '<p>test</p>' );
equal( deepFilterHTML( '<p><span>test</span></p>', [ unwrapper ] ), '<p>test</p>' );
} );

it( 'should remove spans with attributes', () => {
equal( deepFilter( '<p><span id="test">test</span></p>', [ unwrapper ] ), '<p>test</p>' );
equal( deepFilterHTML( '<p><span id="test">test</span></p>', [ unwrapper ] ), '<p>test</p>' );
} );

it( 'should remove nested spans', () => {
equal( deepFilter( '<p><span><span>test</span></span></p>', [ unwrapper ] ), '<p>test</p>' );
equal( deepFilterHTML( '<p><span><span>test</span></span></p>', [ unwrapper ] ), '<p>test</p>' );
} );

it( 'should remove spans, but preserve nested structure', () => {
equal( deepFilter( '<p><span><em>test</em> <em>test</em></span></p>', [ unwrapper ] ), '<p><em>test</em> <em>test</em></p>' );
equal( deepFilterHTML( '<p><span><em>test</em> <em>test</em></span></p>', [ unwrapper ] ), '<p><em>test</em> <em>test</em></p>' );
} );

it( 'should remove paragraphs and insert line break', () => {
equal( deepFilterHTML( '<p>test</p>', [ unwrapperWithAfter ] ), 'test<br>' );
} );
} );
8 changes: 4 additions & 4 deletions blocks/api/paste/test/formatting-transformer.js
Expand Up @@ -7,18 +7,18 @@ import { equal } from 'assert';
* Internal dependencies
*/
import formattingTransformer from '../formatting-transformer';
import { deepFilter } from '../utils';
import { deepFilterHTML } from '../utils';

describe( 'formattingTransformer', () => {
it( 'should transform font weight', () => {
equal( deepFilter( '<span style="font-weight:bold">test</span>', [ formattingTransformer ] ), '<strong>test</strong>' );
equal( deepFilterHTML( '<span style="font-weight:bold">test</span>', [ formattingTransformer ] ), '<strong>test</strong>' );
} );

it( 'should transform numeric font weight', () => {
equal( deepFilter( '<span style="font-weight:700">test</span>', [ formattingTransformer ] ), '<strong>test</strong>' );
equal( deepFilterHTML( '<span style="font-weight:700">test</span>', [ formattingTransformer ] ), '<strong>test</strong>' );
} );

it( 'should transform font style', () => {
equal( deepFilter( '<span style="font-style:italic">test</span>', [ formattingTransformer ] ), '<em>test</em>' );
equal( deepFilterHTML( '<span style="font-style:italic">test</span>', [ formattingTransformer ] ), '<em>test</em>' );
} );
} );
6 changes: 3 additions & 3 deletions blocks/api/paste/test/image-corrector.js
Expand Up @@ -7,18 +7,18 @@ import { equal } from 'assert';
* Internal dependencies
*/
import imageCorrector from '../image-corrector';
import { deepFilter } from '../utils';
import { deepFilterHTML } from '../utils';

describe( 'imageCorrector', () => {
it( 'should correct image source', () => {
const input = '<img src="file:LOW-RES.png">';
const output = '<img src="">';
equal( deepFilter( input, [ imageCorrector ] ), output );
equal( deepFilterHTML( input, [ imageCorrector ] ), output );
} );

it( 'should remove trackers', () => {
const input = '<img src="" height="1" width="1">';
const output = '';
equal( deepFilter( input, [ imageCorrector ] ), output );
equal( deepFilterHTML( input, [ imageCorrector ] ), output );
} );
} );
19 changes: 19 additions & 0 deletions blocks/api/paste/test/inline-content-converter.js
@@ -0,0 +1,19 @@
/**
* External dependencies
*/
import { equal } from 'assert';

/**
* Internal dependencies
*/
import inlineContentConverter from '../inline-content-converter';
import { deepFilterHTML } from '../utils';

describe( 'inlineContentConverter', () => {
it( 'should remove non-inline content from inline wrapper', () => {
equal(
deepFilterHTML( '<figcaption><p>test</p><p>test</p></figcaption>', [ inlineContentConverter ] ),
'<figcaption>test<br>test</figcaption>'
);
} );
} );

0 comments on commit 79a29f6

Please sign in to comment.