-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add iframe raw handling (e.g. Google Maps) #4660
Conversation
blocks/editable/index.js
Outdated
|
||
export default withContext( 'editor' )( | ||
( settings ) => ( { | ||
unfilteredHTML: settings && settings.unfilteredHTML, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@iseulde Do you think it would be better to use the withAPIData
component and check user.data.capabilities.unfiltered_html
? example here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, didn't think of that. Will try tomorrow.
I tested this in latest Chrome on macOS and it works! :-)
I think you mean author, right? If so, this is working correctly. Editors can post unfiltered HTML. |
Yes, sorry. Didn't realise editors have the cap as well. I updated the PR, but since the |
If someone could review, that'd be great! :) |
|
||
let wrapper = node; | ||
|
||
while ( wrapper.nodeName !== 'P' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you might need while( wrapper && wrapper.nodeName )
here, because the final iteration might be a node with parentElement
= null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I changed it from while ( wrapper.nodeName !== 'P' && ( wrapper = wrapper.parentElement ) ) {}
and forgot to add the check. 🙈 Nice catch.
e901e18
to
43a94ba
Compare
Rebased after |
lib/client-assets.php
Outdated
@@ -909,6 +909,10 @@ function gutenberg_editor_scripts_and_styles( $hook ) { | |||
'colors' => $color_palette, | |||
'blockTypes' => $allowed_block_types, | |||
'titlePlaceholder' => apply_filters( 'enter_title_here', __( 'Add title', 'gutenberg' ), $post ), | |||
'alignWide' => $align_wide || ! empty( $gutenberg_theme_support[0]['wide-images'] ), // Backcompat. Use `align-wide` outside of `gutenberg` array. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PHPCS warnings from misaligned arrows here (causing the build failure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think these are duplicated and need to be removed. Maybe from a bad rebase?
onReplace( block.uid, rawHandler( { | ||
HTML: serialize( block ), | ||
mode: 'BLOCKS', | ||
allowIframes: get( user, 'data.capabilities.unfiltered_html', false ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: String argument to get
requires additional parsing and is slightly less performant than passing as an array, e.g.:
allowIframes: get( user, [ 'data', 'capabilities', 'unfiltered_html' ], false ),
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me wonder if we should have some equivalent of selectors for withAPIData
too, rather than working with the REST properties directly, something like a currentUserCan
@@ -122,6 +123,12 @@ export class BlockListBlock extends Component { | |||
}; | |||
} | |||
|
|||
getChildContext() { | |||
return { | |||
unfilteredHTML: get( this.props.user, 'data.capabilities.unfiltered_html', false ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name unfilteredHTML
isn't entirely clear to me: At first, I thought this was passing some HTML string, not a true
/ false
permissions thing. Maybe allowUnfilteredHTML
? isUnfilteredHTMLAllowed
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
canUserUseUnfilteredHTML
? It's a mouthful, but a recognizable phrasing.
import inlineBlockCorrector from '../inline-block-corrector'; | ||
import { deepFilterHTML } from '../utils'; | ||
|
||
describe( 'inlineContentConverter', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name doesn't match the folder.
import { deepFilterHTML } from '../utils'; | ||
|
||
describe( 'inlineContentConverter', () => { | ||
it( 'should move inline-block content from paragraph', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful to have some of these behaviors documented (README.md
and/or JSDoc on the functions themselves). By the name inlineBlockCorrector
, I had no idea what to expect from its behavior.
I'm coming to this mostly unfamiliar with the raw handlers, so I expect it'd be a common sentiment.
blocks/api/raw-handling/utils.js
Outdated
@@ -110,6 +115,10 @@ export function isClassWhitelisted( tag, name ) { | |||
); | |||
} | |||
|
|||
export function isInlineBlock( node ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocks/api/raw-handling/index.js
Outdated
piece = deepFilterHTML( piece, [ | ||
listMerger, | ||
imageCorrector, | ||
// Add semantic formatting before attributes are stripped. | ||
formattingTransformer, | ||
stripAttributes, | ||
commentRemover, | ||
...iframeUnwrapper, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're already dealing with an array (the one provided to deepFilterHTML
), we can simplify this:
deepFilterHTML( piece, compact( [
…
allowIframes && unwrapper,
inlineBlockCorrector,
…
] ) )
Alternatively, we could use .filter( Boolean )
.
*/ | ||
const { ELEMENT_NODE } = window.Node; | ||
|
||
export default function( node ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a comment and a high-level explanation of what and why.
const hasImage = node.querySelector( 'img' ); | ||
|
||
return tag === 'img' || ( hasImage && ! hasText ) || ( hasImage && tag === 'figure' ); | ||
return tag === 'img' || ( hasImage && tag === 'figure' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know this to be an improvement? For instance, pasting <p>Behold my picture: <img src="..."> Isn't it amazing?</p>
yields Image<…> + Paragraph<Behold…amazing?>
.
I ask because it change seems tangential to the iframe support. Should we try this separately?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the same fix is needed for iframes as well as images. Otherwise the image just ends up inside a paragraph. Most of the time, this structure goes together with alignment, so it is not visually clear where the image was anchored.
blocks/api/raw-handling/utils.js
Outdated
@@ -31,6 +31,11 @@ const inlineWhitelist = { | |||
br: {}, | |||
}; | |||
|
|||
const inlineBlockWhiteList = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit concerned that all these lists and moving parts in raw-handling
grow hard to keep track of, e.g. "inline" vs "inline wrapper" vs. "inline block". Docs in this file would help.
@@ -122,6 +123,12 @@ export class BlockListBlock extends Component { | |||
}; | |||
} | |||
|
|||
getChildContext() { | |||
return { | |||
unfilteredHTML: get( this.props.user, 'data.capabilities.unfiltered_html', false ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
canUserUseUnfilteredHTML
? It's a mouthful, but a recognizable phrasing.
1c29b3e
to
6d56c2d
Compare
I think I addressed all concerns. |
6d56c2d
to
2f30eeb
Compare
Rebased. |
2f30eeb
to
6a54e94
Compare
This PR also indirectly fixes a bug where multiple images in a paragraph are all removed except for the first. |
/** | ||
* External dependencies | ||
*/ | ||
import { equal } from 'assert'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why we're using the built-in assert
lib here rather than Jest?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been used all over this paste module since the beginning. I can change this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a fan of the globals :|
blocks/api/raw-handling/utils.js
Outdated
@@ -63,7 +68,7 @@ const whitelist = { | |||
}; | |||
|
|||
export function isWhitelisted( element ) { | |||
return !! whitelist[ element.nodeName.toLowerCase() ]; | |||
return !! whitelist.hasOwnProperty( element.nodeName.toLowerCase() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type coercion is unnecessary (hasOwnProperty
will certainly return a boolean).
blocks/api/raw-handling/utils.js
Outdated
@@ -99,7 +104,7 @@ function isInlineForTag( nodeName, tagName ) { | |||
|
|||
export function isInline( node, tagName ) { | |||
const nodeName = node.nodeName.toLowerCase(); | |||
return !! inlineWhitelist[ nodeName ] || isInlineForTag( nodeName, tagName ); | |||
return !! inlineWhitelist.hasOwnProperty( nodeName ) || isInlineForTag( nodeName, tagName ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type coercion is unnecessary (hasOwnProperty
will certainly return a boolean).
blocks/api/raw-handling/utils.js
Outdated
* @return {boolean} True if embedded content, false if not. | ||
*/ | ||
export function isEmbedded( node ) { | ||
return !! embeddedWhiteList.hasOwnProperty( node.nodeName.toLowerCase() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type coercion is unnecessary (hasOwnProperty
will certainly return a boolean).
blocks/api/raw-handling/utils.js
Outdated
export function isInlineWrapper( node ) { | ||
return !! inlineWrapperWhiteList[ node.nodeName.toLowerCase() ]; | ||
return !! inlineWrapperWhiteList.hasOwnProperty( node.nodeName.toLowerCase() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type coercion is unnecessary (hasOwnProperty
will certainly return a boolean).
blocks/rich-text/index.js
Outdated
@@ -371,6 +371,7 @@ export default class RichText extends Component { | |||
plainText: this.pastedPlainText, | |||
mode, | |||
tagName: this.props.tagName, | |||
allowIframes: this.context.canUserUseUnfilteredHTML, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we ever expecting allowScript
, allowInput
, allowStyle
?
Maybe we just pass the canUserUseUnfilteredHTML
verbatim as the property name?
Thanks @aduth, feedback addressed. :) |
bbb2e78
to
fedb8d0
Compare
After reviews from 3 people in the last two weeks, I think this is ready for merge. |
Description
How Has This Been Tested?