Deregister core cart/checkout scripts and styles when rendering the blocks (https://github.com/woocommerce/woocommerce-blocks/pull/2842)

* Deregister core cart/checkout scripts and styles when rendering the blocks

* Fix regression: redirect to full cart when adding a product from empty cart

* Make it so it scrolls to the top

* Update assets/js/base/utils/legacy-events.js

Co-authored-by: Darren Ethier <darren@roughsmootheng.in>

* Add check for jQuery availability

* Listen to removed from cart event too

* Remove unnecessary useEffect dependency

* Remove jQuery event subscriptions on component unmount

* Fix tests

Co-authored-by: Darren Ethier <darren@roughsmootheng.in>
This commit is contained in:
Albert Juhé Lluveras 2020-07-14 21:46:44 +02:00 committed by GitHub
parent d894fed1df
commit 8bfb95c808
6 changed files with 121 additions and 15 deletions

View File

@ -16,6 +16,7 @@ module.exports = {
context: true,
jestPuppeteer: true,
fetchMock: true,
jQuery: 'readonly',
},
plugins: [ 'jest', 'woocommerce' ],
rules: {

View File

@ -1,19 +1,63 @@
const Event = window.Event || null;
/**
* Wrapper function to dispatch an event so it's compatible with IE11.
*
* @param {string} name Name of the event to dispatch.
* @param {boolean} bubbles Whether the event bubbles.
* @param {boolean} cancelable Whether the event is cancelable.
*/
const dispatchEvent = ( name, bubbles = false, cancelable = false ) => {
// In IE, Event is an object and can't be instantiated with `new Event()`.
if ( typeof Event === 'function' ) {
const event = new Event( name, {
bubbles,
cancelable,
} );
document.body.dispatchEvent( event );
} else {
const event = document.createEvent( 'Event' );
event.initEvent( name, bubbles, cancelable );
document.body.dispatchEvent( event );
}
};
// This is a hack to trigger cart updates till we migrate to block based cart
// that relies on the store, see
// https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/1247
export const triggerFragmentRefresh = () => {
// In IE, Event is an object and can't be instantiated with `new Event()`.
if ( typeof Event === 'function' ) {
const event = new Event( 'wc_fragment_refresh', {
bubbles: true,
cancelable: true,
} );
document.body.dispatchEvent( event );
} else {
const event = document.createEvent( 'Event' );
event.initEvent( 'wc_fragment_refresh', true, true );
document.body.dispatchEvent( event );
}
dispatchEvent( 'wc_fragment_refresh', true, true );
};
/**
* Function that listens to a jQuery event and dispatches a native JS event.
* Useful to convert WC Core events into events that can be read by blocks.
*
* @param {string} jQueryEventName Name of the jQuery event to listen to.
* @param {string} nativeEventName Name of the native event to dispatch.
* @param {boolean} bubbles Whether the event bubbles.
* @param {boolean} cancelable Whether the event is cancelable.
*
* @returns {Function} Function to remove the jQuery event handler. Ideally it
* should be used when the component is unmounted.
*/
export const translateJQueryEventToNative = (
jQueryEventName,
nativeEventName,
bubbles = false,
cancelable = false
) => {
// @ts-ignore -- jQuery is window global
if ( typeof jQuery !== 'function' ) {
return () => void null;
}
const eventDispatcher = () => {
dispatchEvent( nativeEventName, bubbles, cancelable );
};
// @ts-ignore -- jQuery is window global
jQuery( document ).on( jQueryEventName, eventDispatcher );
// @ts-ignore -- jQuery is window global
return () => jQuery( document ).off( jQueryEventName, eventDispatcher );
};

View File

@ -1,22 +1,66 @@
/**
* External dependencies
*/
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
import { dispatch } from '@wordpress/data';
import { useStoreCart } from '@woocommerce/base-hooks';
import { RawHTML } from '@wordpress/element';
import { useEffect, RawHTML } from '@wordpress/element';
import LoadingMask from '@woocommerce/base-components/loading-mask';
import {
ValidationContextProvider,
CartProvider,
} from '@woocommerce/base-context';
import { translateJQueryEventToNative } from '@woocommerce/base-utils';
import withScrollToTop from '@woocommerce/base-hocs/with-scroll-to-top';
/**
* Internal dependencies
*/
import FullCart from './full-cart';
const Block = ( { emptyCart, attributes } ) => {
const Block = ( { emptyCart, attributes, scrollToTop } ) => {
const { cartItems, cartIsLoading } = useStoreCart();
useEffect( () => {
const invalidateCartData = () => {
dispatch( storeKey ).invalidateResolutionForStore();
scrollToTop();
};
// Make it so we can read jQuery events triggered by WC Core elements.
const removeJQueryAddedToCartEvent = translateJQueryEventToNative(
'added_to_cart',
'wc-blocks_added_to_cart'
);
const removeJQueryRemovedFromCartEvent = translateJQueryEventToNative(
'removed_from_cart',
'wc-blocks_removed_from_cart'
);
document.body.addEventListener(
'wc-blocks_added_to_cart',
invalidateCartData
);
document.body.addEventListener(
'wc-blocks_removed_from_cart',
invalidateCartData
);
return () => {
removeJQueryAddedToCartEvent();
removeJQueryRemovedFromCartEvent();
document.body.removeEventListener(
'wc-blocks_added_to_cart',
invalidateCartData
);
document.body.removeEventListener(
'wc-blocks_removed_from_cart',
invalidateCartData
);
};
}, [ scrollToTop ] );
return (
<>
{ ! cartIsLoading && cartItems.length === 0 ? (
@ -34,4 +78,4 @@ const Block = ( { emptyCart, attributes } ) => {
);
};
export default Block;
export default withScrollToTop( Block );

View File

@ -63,6 +63,12 @@ class Cart extends AbstractBlock {
}
);
// Deregister core cart scripts and styles.
wp_deregister_script( 'wc-cart' );
wp_deregister_script( 'wc-password-strength-meter' );
wp_deregister_script( 'selectWoo' );
wp_deregister_style( 'select2' );
return $this->inject_html_data_attributes( $content . $this->get_skeleton(), $block_attributes );
}

View File

@ -60,6 +60,12 @@ class Checkout extends AbstractBlock {
$this->enqueue_assets( $block_attributes );
do_action( 'woocommerce_blocks_enqueue_checkout_block_scripts_after' );
// Deregister core checkout scripts and styles.
wp_deregister_script( 'wc-checkout' );
wp_deregister_script( 'wc-password-strength-meter' );
wp_deregister_script( 'selectWoo' );
wp_deregister_style( 'select2' );
return $this->inject_html_data_attributes( $content . $this->get_skeleton(), $block_attributes );
}

View File

@ -30,6 +30,11 @@ global.wcSettings = {
},
};
global.jQuery = () => ( {
on: () => void null,
off: () => void null,
} );
const wordPressPackages = [
'blocks',
'components',