Skip to content

Commit

Permalink
Restaurant Menu CPT: Replace most jQuery with Javascript (#40645)
Browse files Browse the repository at this point in the history
  • Loading branch information
coder-karen authored Dec 18, 2024
1 parent 64ab237 commit 829b8dc
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: other

Restaurant Menu CPT: Convert much of the jQuery usage to JavaScript
207 changes: 120 additions & 87 deletions projects/plugins/jetpack/modules/custom-post-types/js/many-items.js
Original file line number Diff line number Diff line change
@@ -1,111 +1,144 @@
( function ( $ ) {
var menuSelector, nonceInput, methods;

methods = {
init: function ( /*options*/ ) {
var $this = this,
tbody,
row;

this.on( 'keypress.manyItemsTable', function ( event ) {
if ( 13 !== event.which ) {
return;
}
( function () {
let menuSelector, nonceInput;
const initializedTables = new Set();

const methods = {
init: function ( table ) {
let tbody = table.lastElementChild;
while ( tbody && tbody.tagName !== 'TBODY' ) {
tbody = tbody.previousElementSibling;
}
const row = tbody.querySelector( 'tr:first-child' ).cloneNode( true );

table.dataset.form = table.closest( 'form' );
table.dataset.tbody = tbody;
table.dataset.row = row;
table.dataset.currentRow = row;

menuSelector = document.getElementById( 'nova-menu-tax' );
nonceInput = document.getElementById( '_wpnonce' );

table.addEventListener( 'keypress', function ( event ) {
if ( event.which !== 13 ) return;

event.preventDefault();
if ( 'function' === typeof FormData ) {
methods.submitRow.apply( $this );
if ( typeof FormData === 'function' ) {
methods.submitRow.call( table );
}
methods.addRow.apply( $this );
} ).on( 'focus.manyItemsTable', ':input', function ( /*event*/ ) {
$this.data( 'currentRow', $( this ).parents( 'tr:first' ) );
methods.addRow.call( table );
} );

tbody = this.find( 'tbody:last' );
row = tbody.find( 'tr:first' ).clone();

this.data( 'form', this.parents( 'form:first' ) );
this.data( 'tbody', tbody );
this.data( 'row', row );
this.data( 'currentRow', row );

menuSelector = $( '#nova-menu-tax' );
nonceInput = $( '#_wpnonce' );
table.addEventListener( 'focusin', function ( event ) {
if ( event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA' ) {
table.dataset.currentRow = event.target.closest( 'tr' );
}
} );

return this;
initializedTables.add( table );
return table;
},

destroy: function () {
this.off( '.manyItemsTable' );

return this;
destroy: function ( table ) {
if ( this.observer ) {
this.observer.disconnect();
}
table.removeEventListener( 'keypress', methods.keypressHandler );
table.removeEventListener( 'focusin', methods.focusinHandler );
initializedTables.delete( table );
return table;
},

submitRow: function () {
var submittedRow, currentInputs, allInputs, partialFormData;
submitRow: function ( table ) {
const submittedRow = table.dataset.currentRow;
const currentInputs = submittedRow.querySelectorAll( 'input, textarea, select' );
const form = document.querySelector( table.dataset.form );
const allInputs = Array.from( form.querySelectorAll( 'input, textarea, select' ) );

submittedRow = this.data( 'currentRow' );
currentInputs = submittedRow.find( ':input' );
allInputs = this.data( 'form' )
.find( ':input' )
.not( currentInputs )
.attr( 'disabled', true )
.end();
currentInputs.forEach( input => ( input.disabled = true ) );
allInputs
.filter( input => ! currentInputs.includes( input ) )
.forEach( input => ( input.disabled = true ) );

partialFormData = new FormData( this.data( 'form' ).get( 0 ) );
const partialFormData = new FormData( form );
partialFormData.append( 'ajax', '1' );
partialFormData.append( 'nova_menu_tax', menuSelector.val() );
partialFormData.append( '_wpnonce', nonceInput.val() );

allInputs.attr( 'disabled', false );

$.ajax( {
url: '',
type: 'POST',
data: partialFormData,
processData: false,
contentType: false,
} ).complete( function ( xhr ) {
submittedRow.html( xhr.responseText );
} );
partialFormData.append( 'nova_menu_tax', menuSelector.value );
partialFormData.append( '_wpnonce', nonceInput.value );

currentInputs.attr( 'disabled', true );
fetch( '', {
method: 'POST',
body: partialFormData,
} )
.then( response => response.text() )
.then( responseText => {
submittedRow.innerHTML = responseText;
} );

return this;
allInputs.forEach( input => ( input.disabled = false ) );

return table;
},

addRow: function () {
var row = this.data( 'row' ).clone();
row.appendTo( this.data( 'tbody' ) );
row.find( ':input:first' ).focus();
addRow: function ( table ) {
const row = table.dataset.row.cloneNode( true );

const tbody = table.dataset.tbody;
tbody.appendChild( row );

const firstInput = row.querySelector( 'input, textarea, select' );
if ( firstInput ) firstInput.focus();

return this;
return table;
},
};

$.fn.manyItemsTable = function ( method ) {
// Method calling logic
if ( methods[ method ] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
}
$.error( 'Method ' + method + ' does not exist on jQuery.manyItemsTable' );
return this;
clickAddRow: function ( table ) {
let tbody = table.lastElementChild;

while ( tbody && tbody.tagName !== 'TBODY' ) {
tbody = tbody.previousElementSibling;
}
const row = tbody.querySelector( 'tr:first-child' ).cloneNode( true );

row.querySelectorAll( 'input, textarea' ).forEach( input => {
input.value = '';
} );

tbody.appendChild( row );
},
};

$.fn.clickAddRow = function () {
var tbody = this.find( 'tbody:last' ),
row = tbody.find( 'tr:first' ).clone();
const observeTableRemoval = function ( list ) {
const observer = new MutationObserver( mutations => {
mutations.forEach( mutation => {
mutation.removedNodes.forEach( node => {
if ( node.matches && node.matches( '.many-items-table' ) ) {
methods.destroy( node );
}
} );
} );
} );

$( row ).find( 'input, textarea' ).val( '' );
$( row ).appendTo( tbody );
observer.observe( list, { childList: true, subtree: true } );
};
} )( jQuery );

jQuery( '.many-items-table' ).one( 'focus', ':input', function ( event ) {
jQuery( event.delegateTarget ).manyItemsTable();
} );
jQuery( '.many-items-table' ).on( 'click', 'a.nova-new-row', function ( event ) {
jQuery( event.delegateTarget ).clickAddRow();
} );

// Initialization for many-items-table
document.addEventListener( 'focusin', event => {
const table = event.target.closest( '.many-items-table' );
if ( table && ! initializedTables.has( table ) ) {
methods.init( table );
}
} );

document.addEventListener( 'click', event => {
if ( event.target.matches( 'a.nova-new-row' ) ) {
const table = event.target.closest( '.many-items-table' );
if ( table ) {
event.preventDefault();
methods.clickAddRow( table );
}
}
} );
const list = document.querySelector( '#the-list' ); // Scope to the specific table
if ( list ) {
observeTableRemoval( list );
}
} )();
Original file line number Diff line number Diff line change
@@ -1,48 +1,75 @@
( function ( $ ) {
var NovaCheckBoxes = {
( function () {
const NovaCheckBoxes = {
inputs: null,
popInputs: null,

initialize: function () {
NovaCheckBoxes.popInputs = $( '#nova_menuchecklist-pop' ).find( ':checkbox' );
// Get all checkboxes in the "nova_menuchecklist-pop"
NovaCheckBoxes.popInputs = document.querySelectorAll(
'#nova_menuchecklist-pop input[type="checkbox"]'
);

NovaCheckBoxes.inputs = $( '#nova_menuchecklist' )
.find( ':checkbox' )
.change( NovaCheckBoxes.checkOne )
.change( NovaCheckBoxes.syncPop );
// Get all checkboxes in the "nova_menuchecklist" and add event listeners
NovaCheckBoxes.inputs = document.querySelectorAll(
'#nova_menuchecklist input[type="checkbox"]'
);
NovaCheckBoxes.inputs.forEach( input => {
input.addEventListener( 'change', NovaCheckBoxes.checkOne );
input.addEventListener( 'change', NovaCheckBoxes.syncPop );
} );

// If no checkboxes are checked, check the first one
if ( ! NovaCheckBoxes.isChecked() ) {
NovaCheckBoxes.checkFirst();
}

// Sync the state of the "pop" inputs
NovaCheckBoxes.syncPop();
},

syncPop: function () {
NovaCheckBoxes.popInputs.each( function () {
var $this = $( this );
$this.prop( 'checked', $( '#in-nova_menu-' + $this.val() ).is( ':checked' ) );
NovaCheckBoxes.popInputs.forEach( popInput => {
const linkedInput = document.querySelector( `#in-nova_menu-${ popInput.value }` );
popInput.checked = linkedInput ? linkedInput.checked : false;
} );
},

isChecked: function () {
return NovaCheckBoxes.inputs.is( ':checked' );
return Array.from( NovaCheckBoxes.inputs ).some( input => input.checked );
},

checkFirst: function () {
NovaCheckBoxes.inputs.first().prop( 'checked', true );
const firstInput = NovaCheckBoxes.inputs[ 0 ];
if ( firstInput ) {
firstInput.checked = true;
}
},

checkOne: function ( /*event*/ ) {
if ( $( this ).is( ':checked' ) ) {
return NovaCheckBoxes.inputs.not( this ).prop( 'checked', false );
checkOne: function () {
const currentInput = this;

// If the current checkbox is checked, uncheck all other checkboxes
if ( currentInput.checked ) {
NovaCheckBoxes.inputs.forEach( input => {
if ( input !== currentInput ) {
input.checked = false;
}
} );
return;
}
if ( $( this ).closest( '#nova_menuchecklist' ).find( ':checked' ).length > 0 ) {
return $( this ).prop( 'checked', false );
const checklist = document.querySelector( '#nova_menuchecklist' );

// If at least one checkbox is still checked, uncheck the current one
if ( checklist.querySelectorAll( 'input[type="checkbox"]:checked' ).length > 0 ) {
currentInput.checked = false;
return;
}
return NovaCheckBoxes.checkFirst();

// Otherwise, check the first checkbox
NovaCheckBoxes.checkFirst();
},
};

$( NovaCheckBoxes.initialize );
} )( jQuery );
// Initialize when the DOM is fully loaded
document.addEventListener( 'DOMContentLoaded', NovaCheckBoxes.initialize );
} )();
4 changes: 2 additions & 2 deletions projects/plugins/jetpack/modules/custom-post-types/nova.php
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ public function add_admin_menus() {
'_inc/build/custom-post-types/js/menu-checkboxes.min.js',
'modules/custom-post-types/js/menu-checkboxes.js'
),
array( 'jquery' ),
array(),
$this->version,
true
);
Expand Down Expand Up @@ -1146,7 +1146,7 @@ public function enqueue_many_items_scripts() {
'_inc/build/custom-post-types/js/many-items.min.js',
'modules/custom-post-types/js/many-items.js'
),
array( 'jquery' ),
array(),
$this->version,
true
);
Expand Down

0 comments on commit 829b8dc

Please sign in to comment.