Skip to content
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

Paste Handler: convert lists inside of table cells to pseudo lists WIP #55651

Draft
wants to merge 4 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions packages/blocks/src/api/raw-handling/nested-list-converted.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
function isList( node ) {
return node.nodeName === 'OL' || node.nodeName === 'UL';
}

function createLineBreak( doc ) {
mpkelly marked this conversation as resolved.
Show resolved Hide resolved
return doc.createElement( 'br' );
}

function getDepth( listNode, depth = 2 ) {
if ( isList( listNode.parentElement ) ) {
return getDepth( listNode.parentElement, depth + 2 );
}
return depth;
}

function createSpace( length ) {
return (
Array.from( { length } )
// eslint-disable-next-line no-unused-vars
mpkelly marked this conversation as resolved.
Show resolved Hide resolved
.map( ( i ) => `\u00A0\u00A0` )
.join( ' ' )
);
}

function createBullet( doc, child, isNested ) {
const node = doc.createElement( 'pre' );
const isOrdered = child.parentElement.nodeName === 'OL';
let bullet = '- ';

if ( isOrdered ) {
const index = Array.from( child.parentElement.childNodes )
.filter( ( item ) => item.nodeName === 'LI' )
.indexOf( child );
bullet = `${ index + 1 }. `;
}
if ( isNested ) {
const space = createSpace( getDepth( child.parentElement ) );

bullet = `${ space }${ bullet }`;
}
node.innerText = bullet;
return node;
}

export default function nestedListedConverter( node, doc ) {
function transformList( list, result = [] ) {
const isNested = isList( node.parentElement );

Array.from( list.childNodes ).forEach( ( child ) => {
if ( child.nodeName === 'LI' ) {
result.push( createLineBreak( doc ) );
result.push( createBullet( doc, child, isNested ) );
result = result.concat( Array.from( child.childNodes ) );
} else {
result.push( child );
}
} );
return result;
}

if ( isList( node ) ) {
const nodes = transformList( node );
if ( nodes.length ) {
Copy link
Contributor Author

@mpkelly mpkelly Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read the comment above, specialCommentConverter, which mentions using a special block node, core/nextpage, to avoid further transformations.

As a POC, I used the same node and found that whitespace is now preserved. Can we use something like this as a basis for a solution to keeping whitespace, @ellatrix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this solution produces the final result we're after:

Screenshot 2566-11-06 at 12 02 15

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this work? Why are non breaking spaces otherwise stripped? What's responsible for that?

Copy link
Contributor Author

@mpkelly mpkelly Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this change isn't necessary:

const wrapper = doc.createElement( 'wp-block' );
wrapper.dataset.block = 'core/nextpage';

The way I added space characters (\u00A0) in this last commit seems to be enough by itself. Previously, I created a span with just a \u00A0, which didn't survive. In this commit, I append the space and bullet (\u00A0\u00A0-) together, and it works.

So I think I have a solution. All that remains is to write some tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, my earlier attempt used document.createTextNode( '\u00A0' ). I just tried that now, and it actually works too. 🤔

const wrapper = doc.createElement( 'wp-block' );
wrapper.dataset.block = 'core/nextpage';
nodes.forEach( ( child ) => {
wrapper.appendChild( child );
} );
node.replaceWith( wrapper );
}
}
}
3 changes: 3 additions & 0 deletions packages/blocks/src/api/raw-handling/paste-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import brRemover from './br-remover';
import { deepFilterHTML, isPlain, getBlockContentSchema } from './utils';
import emptyParagraphRemover from './empty-paragraph-remover';
import slackParagraphCorrector from './slack-paragraph-corrector';
import nestedListedConverter from './nested-list-converted';

/**
* Browser dependencies
Expand All @@ -50,6 +51,7 @@ function filterInlineHTML( HTML, preserveWhiteSpace ) {
HTML = deepFilterHTML( HTML, [
headRemover,
googleDocsUIDRemover,
nestedListedConverter,
msListIgnore,
phrasingContentReducer,
commentRemover,
Expand Down Expand Up @@ -189,6 +191,7 @@ export function pasteHandler( {
}

const filters = [
nestedListedConverter,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ellatrix in #46775, you mentioned updating filterInlineHTML, but I found that this is not always called. I registered a transformer function here - is this ok?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to add it both here and filterInlineHTML.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the transform function there too. Still need to test it though.

googleDocsUIDRemover,
msListConverter,
headRemover,
Expand Down
Loading