Skip to content
Open
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
1 change: 1 addition & 0 deletions packages/metaboxes/lib/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const PAGE_NOW_WIDGETS = 'widgets.php';
export const PAGE_NOW_CUSTOMIZE = 'customize.php';
export const PAGE_NOW_NAV = 'nav-menus.php';

export const CARBON_FIELDS_CONTAINER_ID_PREFIX = 'carbon_fields_container_';
export const CARBON_FIELDS_CONTAINER_WIDGET_ID_PREFIX = 'carbon_fields_';
7 changes: 6 additions & 1 deletion packages/metaboxes/monitors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { Fragment, render } from '@wordpress/element';
import SaveLock from './save-lock';
import ConditionalDisplay from './conditional-display';
import WidgetHandler from './widget-handler';
import NavMenuHandler from './nav-menu-handler';
import RevisionsFlag from './revisions-flag';
import isGutenberg from '../utils/is-gutenberg';
import { PAGE_NOW_WIDGETS, PAGE_NOW_CUSTOMIZE } from '../lib/constants';
import { PAGE_NOW_WIDGETS, PAGE_NOW_CUSTOMIZE, PAGE_NOW_NAV } from '../lib/constants';

/**
* Initializes the monitors.
Expand All @@ -32,6 +33,10 @@ export default function initializeMonitors( context ) {
<WidgetHandler />
) }

{ ( pagenow === PAGE_NOW_NAV ) && (
<NavMenuHandler />
) }

<ConditionalDisplay context={ context } />
</Fragment>,
document.createElement( 'div' )
Expand Down
147 changes: 147 additions & 0 deletions packages/metaboxes/monitors/nav-menu-handler/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/**
* External dependencies.
*/
import { dispatch, select } from '@wordpress/data';
import { unmountComponentAtNode } from '@wordpress/element';
import { flow } from 'lodash';
import { withEffects } from 'refract-callbag';
import {
map,
merge,
pipe,
filter
} from 'callbag-basics';

/**
* Internal dependencies.
*/
import urldecode from '../../utils/urldecode';
import flattenField from '../../utils/flatten-field';
import fromEventPattern from '../../utils/from-event-pattern';
import { renderContainer } from '../../containers';
import { CARBON_FIELDS_CONTAINER_ID_PREFIX } from '../../lib/constants';

/**
* Performs the re-initialization of nav menu items.
*
* @return {null}
*/
function NavMenuHandler() {
return null;
}

function hasCarbonFields( $node ) {
return $node.find( `[data-id^="${ CARBON_FIELDS_CONTAINER_ID_PREFIX }"]` ).length > 0;
}

/**
* The function that controls the stream of side effects.
*
* @return {Object}
*/
function aperture() {
return merge(
pipe(
fromEventPattern(
( handler ) => window.jQuery( document ).on( 'menu-item-added', handler ),
( handler ) => window.jQuery( document ).off( 'menu-item-added', handler ),
( event, $nodes ) => ( {
event,
$nodes
} )
),
filter( ( { $nodes } ) => {
return hasCarbonFields( $nodes );
} ),
map( ( payload ) => ( {
type: 'NAV_MENU_ITEMS_ADDED',
payload
} ) )
),

pipe(
fromEventPattern(
( handler ) => window.jQuery( document ).on( 'menu-removing-item', handler ),
( handler ) => window.jQuery( document ).off( 'menu-removing-item', handler ),
( event, $node ) => ( {
event,
$node
} )
),
filter( ( { $node } ) => {
return hasCarbonFields( $node );
} ),
map( ( payload ) => ( {
type: 'NAV_MENU_ITEM_DELETED',
payload
} ) )
)
);
}

/**
* The function that causes the side effects.
*
* @return {Function}
*/
function handler() {
return function( effect ) {
const { getContainerById } = select( 'carbon-fields/metaboxes' );
const {
addContainer,
removeContainer,
addFields,
removeFields
} = dispatch( 'carbon-fields/metaboxes' );

switch ( effect.type ) {
case 'NAV_MENU_ITEMS_ADDED': {
const { $nodes } = effect.payload;

const containers = $nodes.map( ( index, node ) => {
const $node = window.jQuery( node );
if ( $node.find( '[data-json]' ).length > 0 ) {
return flow(
urldecode,
JSON.parse
)( $node.find( '[data-json]' ).data( 'json' ) );
}
} );

containers.each( ( index, container ) => {
const fields = [];
container.fields = container.fields.map( ( field ) => flattenField( field, container, fields ) );

addFields( fields );
addContainer( container );

renderContainer( container, 'classic' );
} );

break;
}

case 'NAV_MENU_ITEM_DELETED': {
const { $node } = effect.payload;
const containerId = $node.find( `[data-id^="${ CARBON_FIELDS_CONTAINER_ID_PREFIX }"]` ).data( 'id' );

// Get the container from the store.
const container = getContainerById( containerId );

// Remove the current instance from DOM.
unmountComponentAtNode( document.querySelector( `.container-${ containerId }` ) );

// Get the fields that belongs to the container.
const fieldsIds = _.map( container.fields, 'id' );

// Remove everything from the store.
removeContainer( containerId );
removeFields( fieldsIds );

break;
}
}
};
}

export default withEffects( aperture, { handler } )( NavMenuHandler );