Files
formipay/node_modules/@wordpress/undo-manager/src/index.js
dwindown e8fbfb14c1 fix: prevent asset conflicts between React and Grid.js versions
Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 17:02:14 +07:00

182 lines
4.4 KiB
JavaScript

/**
* WordPress dependencies
*/
import isShallowEqual from '@wordpress/is-shallow-equal';
/** @typedef {import('./types').HistoryRecord} HistoryRecord */
/** @typedef {import('./types').HistoryChange} HistoryChange */
/** @typedef {import('./types').HistoryChanges} HistoryChanges */
/** @typedef {import('./types').UndoManager} UndoManager */
/**
* Merge changes for a single item into a record of changes.
*
* @param {Record< string, HistoryChange >} changes1 Previous changes
* @param {Record< string, HistoryChange >} changes2 NextChanges
*
* @return {Record< string, HistoryChange >} Merged changes
*/
function mergeHistoryChanges( changes1, changes2 ) {
/**
* @type {Record< string, HistoryChange >}
*/
const newChanges = { ...changes1 };
Object.entries( changes2 ).forEach( ( [ key, value ] ) => {
if ( newChanges[ key ] ) {
newChanges[ key ] = { ...newChanges[ key ], to: value.to };
} else {
newChanges[ key ] = value;
}
} );
return newChanges;
}
/**
* Adds history changes for a single item into a record of changes.
*
* @param {HistoryRecord} record The record to merge into.
* @param {HistoryChanges} changes The changes to merge.
*/
const addHistoryChangesIntoRecord = ( record, changes ) => {
const existingChangesIndex = record?.findIndex(
( { id: recordIdentifier } ) => {
return typeof recordIdentifier === 'string'
? recordIdentifier === changes.id
: isShallowEqual( recordIdentifier, changes.id );
}
);
const nextRecord = [ ...record ];
if ( existingChangesIndex !== -1 ) {
// If the edit is already in the stack leave the initial "from" value.
nextRecord[ existingChangesIndex ] = {
id: changes.id,
changes: mergeHistoryChanges(
nextRecord[ existingChangesIndex ].changes,
changes.changes
),
};
} else {
nextRecord.push( changes );
}
return nextRecord;
};
/**
* Creates an undo manager.
*
* @return {UndoManager} Undo manager.
*/
export function createUndoManager() {
/**
* @type {HistoryRecord[]}
*/
let history = [];
/**
* @type {HistoryRecord}
*/
let stagedRecord = [];
/**
* @type {number}
*/
let offset = 0;
const dropPendingRedos = () => {
history = history.slice( 0, offset || undefined );
offset = 0;
};
const appendStagedRecordToLatestHistoryRecord = () => {
const index = history.length === 0 ? 0 : history.length - 1;
let latestRecord = history[ index ] ?? [];
stagedRecord.forEach( ( changes ) => {
latestRecord = addHistoryChangesIntoRecord( latestRecord, changes );
} );
stagedRecord = [];
history[ index ] = latestRecord;
};
/**
* Checks whether a record is empty.
* A record is considered empty if it the changes keep the same values.
* Also updates to function values are ignored.
*
* @param {HistoryRecord} record
* @return {boolean} Whether the record is empty.
*/
const isRecordEmpty = ( record ) => {
const filteredRecord = record.filter( ( { changes } ) => {
return Object.values( changes ).some(
( { from, to } ) =>
typeof from !== 'function' &&
typeof to !== 'function' &&
! isShallowEqual( from, to )
);
} );
return ! filteredRecord.length;
};
return {
/**
* Record changes into the history.
*
* @param {HistoryRecord=} record A record of changes to record.
* @param {boolean} isStaged Whether to immediately create an undo point or not.
*/
addRecord( record, isStaged = false ) {
const isEmpty = ! record || isRecordEmpty( record );
if ( isStaged ) {
if ( isEmpty ) {
return;
}
record.forEach( ( changes ) => {
stagedRecord = addHistoryChangesIntoRecord(
stagedRecord,
changes
);
} );
} else {
dropPendingRedos();
if ( stagedRecord.length ) {
appendStagedRecordToLatestHistoryRecord();
}
if ( isEmpty ) {
return;
}
history.push( record );
}
},
undo() {
if ( stagedRecord.length ) {
dropPendingRedos();
appendStagedRecordToLatestHistoryRecord();
}
const undoRecord = history[ history.length - 1 + offset ];
if ( ! undoRecord ) {
return;
}
offset -= 1;
return undoRecord;
},
redo() {
const redoRecord = history[ history.length + offset ];
if ( ! redoRecord ) {
return;
}
offset += 1;
return redoRecord;
},
hasUndo() {
return !! history[ history.length - 1 + offset ];
},
hasRedo() {
return !! history[ history.length + offset ];
},
};
}