Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ private function collectBlockNavigationLandmarks(array $blocks, array &$counts):
continue;
}

if ( 'core/group' === ($block['blockName'] ?? '') && 'nav' === strtolower((string) ($block['attrs']['tagName'] ?? '')) ) {
++$counts['nav'];
continue;
}

if ( 'core/navigation' === ($block['blockName'] ?? '') ) {
++$counts['nav'];
}
Expand Down Expand Up @@ -601,9 +606,45 @@ private function collectBlockNavigationMenus(array $blocks, string $path, array
}

$blockPath = $path . '.' . $index;
$innerBlocks = is_array($block['innerBlocks'] ?? null) ? $block['innerBlocks'] : array();
if ( 'core/group' === ($block['blockName'] ?? '')
&& 'nav' === strtolower((string) ($block['attrs']['tagName'] ?? ''))
&& $this->containsBlockName($innerBlocks, 'core/list')
&& ! $this->containsBlockName($innerBlocks, 'core/navigation')
) {
$items = array();
$seen = array();
$this->collectBlockAnchorItems($innerBlocks, $items, $seen);
$menus[] = array(
'block_path' => $blockPath,
'represented_as_native_list_navigation' => true,
'item_count' => count($items),
'items' => $items,
);
continue;
}

if ( 'core/group' === ($block['blockName'] ?? '')
&& 'nav' === strtolower((string) ($block['attrs']['tagName'] ?? ''))
&& ! $this->containsBlockName($innerBlocks, 'core/navigation')
) {
$items = array();
$seen = array();
$this->collectBlockAnchorItems($innerBlocks, $items, $seen);
if ( array() !== $items ) {
$menus[] = array(
'block_path' => $blockPath,
'represented_as_native_group_navigation' => true,
'item_count' => count($items),
'items' => $items,
);
continue;
}
}

if ( 'core/navigation' === ($block['blockName'] ?? '') ) {
$items = array();
$this->collectBlockNavigationItems(is_array($block['innerBlocks'] ?? null) ? $block['innerBlocks'] : array(), $items);
$this->collectBlockNavigationItems($innerBlocks, $items);
$menus[] = array(
'block_path' => $blockPath,
'represented_as_core_navigation' => true,
Expand All @@ -622,6 +663,24 @@ private function collectBlockNavigationMenus(array $blocks, string $path, array
}
}

/** @param array<int, array<string, mixed>> $blocks */
private function containsBlockName(array $blocks, string $name): bool
{
foreach ( $blocks as $block ) {
if ( ! is_array($block) ) {
continue;
}
if ( $name === ($block['blockName'] ?? '') ) {
return true;
}
if ( is_array($block['innerBlocks'] ?? null) && $this->containsBlockName($block['innerBlocks'], $name) ) {
return true;
}
}

return false;
}

/**
* A navigation whose landmark is a core/group{tagName:"nav"} carrier shares
* that landmark with blocks hoisted out of the menu — a branding anchor, for
Expand Down Expand Up @@ -877,7 +936,10 @@ private function semanticParityFindings(array $sourceLandmarks, array $blockLand
continue;
}

if ( true !== ($blockMenu['represented_as_core_navigation'] ?? false) ) {
if ( true !== ($blockMenu['represented_as_core_navigation'] ?? false)
&& true !== ($blockMenu['represented_as_native_list_navigation'] ?? false)
&& true !== ($blockMenu['represented_as_native_group_navigation'] ?? false)
) {
$findings[] = array(
'code' => 'navigation_core_block_missing',
'severity' => 'warning',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public function select(DOMElement $select): ?array
*
* @return array<string, mixed>|null
*/
public function input(DOMElement $input): ?array
public function input(DOMElement $input, ?DOMElement $label = null, bool $preserveDataAttributes = false): ?array
{
if ( array() === ($this->structuralPresentationDeclarations)($input) ) {
return null;
Expand All @@ -125,7 +125,11 @@ public function input(DOMElement $input): ?array
'disabled' => $input->hasAttribute('disabled'),
'readOnly' => $input->hasAttribute('readonly'),
'checked' => $input->hasAttribute('checked'),
), static fn (mixed $value): bool => is_bool($value) ? $value : '' !== $value);
'dataAttributes' => $preserveDataAttributes ? $this->dataAttributes($input) : array(),
'label' => $label instanceof DOMElement ? $this->metadataBuilder->labelText($label) : '',
'labelClassName' => $label instanceof DOMElement ? SourceDom::attr($label, 'class') : '',
'labelStyle' => $label instanceof DOMElement ? SourceDom::attr($label, 'style') : '',
), static fn (mixed $value): bool => is_array($value) ? array() !== $value : (is_bool($value) ? $value : '' !== $value));
$markup = $generator->markup($attrs);

return array(
Expand All @@ -137,6 +141,23 @@ public function input(DOMElement $input): ?array
);
}

/** @return array<string, string> */
private function dataAttributes(DOMElement $input): array
{
$attributes = array();
foreach ( $input->attributes as $attribute ) {
$name = strtolower($attribute->nodeName);
if ( 1 !== preg_match('/^data-(?!wp-)[a-z0-9_.:-]+$/', $name) ) {
continue;
}
$attributes[$name] = $attribute->nodeValue ?? '';
}

ksort($attributes);

return $attributes;
}

/**
* @param array<int, array<string, mixed>> $options
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ public function convert(DOMElement $element): ?array
return null;
}

if ( ($this->isRuntimeDomTarget)($element) ) {
$this->runtimeIslandRecorder->recordControl($element);
if ( 'input' === $tagName ) {
$inputBlock = $this->authoredBlockConverter->input($element, null, true);
if ( null !== $inputBlock ) {
return $inputBlock;
}
}

return ($this->htmlPreservationBlock)($element);
}

if ( 'input' === $tagName && 'search' === FormControlClassifier::controlType($element) ) {
$label = $this->metadataBuilder->label($element);
if ( '' === $label ) {
Expand All @@ -61,11 +73,6 @@ public function convert(DOMElement $element): ?array
return ($this->htmlPreservationBlock)($element);
}

if ( ($this->isRuntimeDomTarget)($element) ) {
$this->runtimeIslandRecorder->recordControl($element);
return ($this->htmlPreservationBlock)($element);
}

if ( 'select' === $tagName ) {
$selectBlock = $this->authoredBlockConverter->select($element);
if ( null !== $selectBlock ) {
Expand Down Expand Up @@ -101,6 +108,12 @@ private function convertLabel(DOMElement $element): ?array

if ( ($this->isRuntimeDomTarget)($control) ) {
$this->runtimeIslandRecorder->recordControl($control);
if ( 1 === count($controls) && 'input' === strtolower($control->tagName) ) {
$inputBlock = $this->authoredBlockConverter->input($control, $element, true);
if ( null !== $inputBlock ) {
return $inputBlock;
}
}
return ($this->htmlPreservationBlock)($element);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public function blockJson(): array
'disabled' => array( 'type' => 'boolean', 'default' => false ),
'readOnly' => array( 'type' => 'boolean', 'default' => false ),
'checked' => array( 'type' => 'boolean', 'default' => false ),
'dataAttributes' => array( 'type' => 'object', 'default' => array() ),
'label' => array( 'type' => 'string', 'default' => '' ),
'labelClassName' => array( 'type' => 'string', 'default' => '' ),
'labelStyle' => array( 'type' => 'string', 'default' => '' ),
),
'supports' => array( 'html' => false ),
);
Expand All @@ -49,8 +53,11 @@ public function assets(): array
var createElement = element.createElement;
var attributes = __BLOCK_ATTRIBUTES__;
function escapeAttribute( value ) { return String( value || '' ).replace( /&/g, '&amp;' ).replace( /"/g, '&quot;' ).replace( /</g, '&lt;' ).replace( />/g, '&gt;' ); }
function markup( attrs ) { var output = '<input'; [ 'type', 'id', 'name', 'value', 'placeholder', 'ariaLabel', 'className', 'style', 'min', 'max', 'step' ].forEach( function( key ) { if ( attrs[ key ] ) output += ' ' + ( 'className' === key ? 'class' : ( 'ariaLabel' === key ? 'aria-label' : key ) ) + '="' + escapeAttribute( attrs[ key ] ) + '"'; } ); [ 'required', 'disabled', 'readOnly', 'checked' ].forEach( function( key ) { if ( attrs[ key ] ) output += ' ' + ( 'readOnly' === key ? 'readonly' : key ); } ); return output + '>'; }
function edit( props ) { var attrs = props.attributes; return createElement( 'input', { type: attrs.type || 'text', id: attrs.id || undefined, name: attrs.name || undefined, value: attrs.value || undefined, placeholder: attrs.placeholder || undefined, 'aria-label': attrs.ariaLabel || undefined, className: attrs.className || undefined, style: attrs.style || undefined, min: attrs.min || undefined, max: attrs.max || undefined, step: attrs.step || undefined, required: attrs.required, disabled: attrs.disabled, readOnly: attrs.readOnly, checked: attrs.checked, onChange: function( event ) { var next = { value: event.target.value }; if ( 'checkbox' === attrs.type || 'radio' === attrs.type ) next.checked = event.target.checked; props.setAttributes( next ); } } ); }
function styleObject( value ) { if ( ! value ) return undefined; return String( value ).split( ';' ).reduce( function( output, declaration ) { var separator = declaration.indexOf( ':' ); if ( separator < 1 ) return output; var name = declaration.slice( 0, separator ).trim(); var property = name.indexOf( '--' ) === 0 ? name : name.replace( /-([a-z])/g, function( _, letter ) { return letter.toUpperCase(); } ); output[ property ] = declaration.slice( separator + 1 ).trim(); return output; }, {} ); }
function dataAttributes( attrs ) { return Object.keys( attrs.dataAttributes || {} ).reduce( function( output, name ) { if ( /^data-(?!wp-)[a-z0-9_.:-]+$/.test( name ) ) output[ name ] = attrs.dataAttributes[ name ]; return output; }, {} ); }
function inputProps( attrs ) { return Object.assign( { type: attrs.type || 'text', id: attrs.id || undefined, name: attrs.name || undefined, value: attrs.value || undefined, placeholder: attrs.placeholder || undefined, 'aria-label': attrs.ariaLabel || undefined, className: attrs.className || undefined, style: styleObject( attrs.style ), min: attrs.min || undefined, max: attrs.max || undefined, step: attrs.step || undefined, required: attrs.required, disabled: attrs.disabled, readOnly: attrs.readOnly, checked: attrs.checked }, dataAttributes( attrs ) ); }
function markup( attrs ) { var output = '<input'; [ 'type', 'id', 'name', 'value', 'placeholder', 'ariaLabel', 'className', 'style', 'min', 'max', 'step' ].forEach( function( key ) { if ( attrs[ key ] ) output += ' ' + ( 'className' === key ? 'class' : ( 'ariaLabel' === key ? 'aria-label' : key ) ) + '="' + escapeAttribute( attrs[ key ] ) + '"'; } ); Object.keys( dataAttributes( attrs ) ).sort().forEach( function( name ) { output += ' ' + name + '="' + escapeAttribute( attrs.dataAttributes[ name ] ) + '"'; } ); [ 'required', 'disabled', 'readOnly', 'checked' ].forEach( function( key ) { if ( attrs[ key ] ) output += ' ' + ( 'readOnly' === key ? 'readonly' : key ); } ); output += '>'; if ( attrs.label ) output = '<label' + ( attrs.labelClassName ? ' class="' + escapeAttribute( attrs.labelClassName ) + '"' : '' ) + ( attrs.labelStyle ? ' style="' + escapeAttribute( attrs.labelStyle ) + '"' : '' ) + '>' + escapeAttribute( attrs.label ) + output + '</label>'; return output; }
function edit( props ) { var attrs = props.attributes; var input = createElement( 'input', Object.assign( inputProps( attrs ), { onChange: function( event ) { var next = { value: event.target.value }; if ( 'checkbox' === attrs.type || 'radio' === attrs.type ) next.checked = event.target.checked; props.setAttributes( next ); } } ) ); return attrs.label ? createElement( 'label', { className: attrs.labelClassName || undefined, style: styleObject( attrs.labelStyle ) }, attrs.label, input ) : input; }
function save( props ) { return createElement( element.RawHTML, null, markup( props.attributes ) ); }
blocks.registerBlockType( 'blocks-engine/authored-input', { attributes: attributes, supports: { html: false }, edit: edit, save: save } );
} )( window.wp.blocks, window.wp.element );
Expand Down Expand Up @@ -78,7 +85,27 @@ public function markup(array $attrs): string
}
}

return $markup . '>';
$dataAttributes = is_array($attrs['dataAttributes'] ?? null) ? $attrs['dataAttributes'] : array();
ksort($dataAttributes);
foreach ( $dataAttributes as $name => $value ) {
if ( 1 === preg_match('/^data-(?!wp-)[a-z0-9_.:-]+$/', (string) $name) ) {
$markup .= ' ' . $name . '="' . $escape($value) . '"';
}
}

$markup .= '>';
if ( '' !== (string) ($attrs['label'] ?? '') ) {
$labelAttributes = '';
if ( '' !== (string) ($attrs['labelClassName'] ?? '') ) {
$labelAttributes .= ' class="' . $escape($attrs['labelClassName']) . '"';
}
if ( '' !== (string) ($attrs['labelStyle'] ?? '') ) {
$labelAttributes .= ' style="' . $escape($attrs['labelStyle']) . '"';
}
$markup = '<label' . $labelAttributes . '>' . $escape($attrs['label']) . $markup . '</label>';
}

return $markup;
}

/** @return array<string, mixed> */
Expand Down
Loading
Loading