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>
270 lines
5.5 KiB
JavaScript
270 lines
5.5 KiB
JavaScript
var compile = (function () {
|
|
'use strict';
|
|
|
|
var PRECEDENCE, OPENERS, TERMINATORS, PATTERN;
|
|
|
|
/**
|
|
* Operator precedence mapping.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
PRECEDENCE = {
|
|
'(': 9,
|
|
'!': 8,
|
|
'*': 7,
|
|
'/': 7,
|
|
'%': 7,
|
|
'+': 6,
|
|
'-': 6,
|
|
'<': 5,
|
|
'<=': 5,
|
|
'>': 5,
|
|
'>=': 5,
|
|
'==': 4,
|
|
'!=': 4,
|
|
'&&': 3,
|
|
'||': 2,
|
|
'?': 1,
|
|
'?:': 1,
|
|
};
|
|
|
|
/**
|
|
* Characters which signal pair opening, to be terminated by terminators.
|
|
*
|
|
* @type {string[]}
|
|
*/
|
|
OPENERS = [ '(', '?' ];
|
|
|
|
/**
|
|
* Characters which signal pair termination, the value an array with the
|
|
* opener as its first member. The second member is an optional operator
|
|
* replacement to push to the stack.
|
|
*
|
|
* @type {string[]}
|
|
*/
|
|
TERMINATORS = {
|
|
')': [ '(' ],
|
|
':': [ '?', '?:' ],
|
|
};
|
|
|
|
/**
|
|
* Pattern matching operators and openers.
|
|
*
|
|
* @type {RegExp}
|
|
*/
|
|
PATTERN = /<=|>=|==|!=|&&|\|\||\?:|\(|!|\*|\/|%|\+|-|<|>|\?|\)|:/;
|
|
|
|
/**
|
|
* Given a C expression, returns the equivalent postfix (Reverse Polish)
|
|
* notation terms as an array.
|
|
*
|
|
* If a postfix string is desired, simply `.join( ' ' )` the result.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* import postfix from '@tannin/postfix';
|
|
*
|
|
* postfix( 'n > 1' );
|
|
* // ⇒ [ 'n', '1', '>' ]
|
|
* ```
|
|
*
|
|
* @param {string} expression C expression.
|
|
*
|
|
* @return {string[]} Postfix terms.
|
|
*/
|
|
function postfix( expression ) {
|
|
var terms = [],
|
|
stack = [],
|
|
match, operator, term, element;
|
|
|
|
while ( ( match = expression.match( PATTERN ) ) ) {
|
|
operator = match[ 0 ];
|
|
|
|
// Term is the string preceding the operator match. It may contain
|
|
// whitespace, and may be empty (if operator is at beginning).
|
|
term = expression.substr( 0, match.index ).trim();
|
|
if ( term ) {
|
|
terms.push( term );
|
|
}
|
|
|
|
while ( ( element = stack.pop() ) ) {
|
|
if ( TERMINATORS[ operator ] ) {
|
|
if ( TERMINATORS[ operator ][ 0 ] === element ) {
|
|
// Substitution works here under assumption that because
|
|
// the assigned operator will no longer be a terminator, it
|
|
// will be pushed to the stack during the condition below.
|
|
operator = TERMINATORS[ operator ][ 1 ] || operator;
|
|
break;
|
|
}
|
|
} else if ( OPENERS.indexOf( element ) >= 0 || PRECEDENCE[ element ] < PRECEDENCE[ operator ] ) {
|
|
// Push to stack if either an opener or when pop reveals an
|
|
// element of lower precedence.
|
|
stack.push( element );
|
|
break;
|
|
}
|
|
|
|
// For each popped from stack, push to terms.
|
|
terms.push( element );
|
|
}
|
|
|
|
if ( ! TERMINATORS[ operator ] ) {
|
|
stack.push( operator );
|
|
}
|
|
|
|
// Slice matched fragment from expression to continue match.
|
|
expression = expression.substr( match.index + operator.length );
|
|
}
|
|
|
|
// Push remainder of operand, if exists, to terms.
|
|
expression = expression.trim();
|
|
if ( expression ) {
|
|
terms.push( expression );
|
|
}
|
|
|
|
// Pop remaining items from stack into terms.
|
|
return terms.concat( stack.reverse() );
|
|
}
|
|
|
|
/**
|
|
* Operator callback functions.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
var OPERATORS = {
|
|
'!': function( a ) {
|
|
return ! a;
|
|
},
|
|
'*': function( a, b ) {
|
|
return a * b;
|
|
},
|
|
'/': function( a, b ) {
|
|
return a / b;
|
|
},
|
|
'%': function( a, b ) {
|
|
return a % b;
|
|
},
|
|
'+': function( a, b ) {
|
|
return a + b;
|
|
},
|
|
'-': function( a, b ) {
|
|
return a - b;
|
|
},
|
|
'<': function( a, b ) {
|
|
return a < b;
|
|
},
|
|
'<=': function( a, b ) {
|
|
return a <= b;
|
|
},
|
|
'>': function( a, b ) {
|
|
return a > b;
|
|
},
|
|
'>=': function( a, b ) {
|
|
return a >= b;
|
|
},
|
|
'==': function( a, b ) {
|
|
return a === b;
|
|
},
|
|
'!=': function( a, b ) {
|
|
return a !== b;
|
|
},
|
|
'&&': function( a, b ) {
|
|
return a && b;
|
|
},
|
|
'||': function( a, b ) {
|
|
return a || b;
|
|
},
|
|
'?:': function( a, b, c ) {
|
|
if ( a ) {
|
|
throw b;
|
|
}
|
|
|
|
return c;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Given an array of postfix terms and operand variables, returns the result of
|
|
* the postfix evaluation.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* import evaluate from '@tannin/evaluate';
|
|
*
|
|
* // 3 + 4 * 5 / 6 ⇒ '3 4 5 * 6 / +'
|
|
* const terms = [ '3', '4', '5', '*', '6', '/', '+' ];
|
|
*
|
|
* evaluate( terms, {} );
|
|
* // ⇒ 6.333333333333334
|
|
* ```
|
|
*
|
|
* @param {string[]} postfix Postfix terms.
|
|
* @param {Object} variables Operand variables.
|
|
*
|
|
* @return {*} Result of evaluation.
|
|
*/
|
|
function evaluate( postfix, variables ) {
|
|
var stack = [],
|
|
i, j, args, getOperatorResult, term, value;
|
|
|
|
for ( i = 0; i < postfix.length; i++ ) {
|
|
term = postfix[ i ];
|
|
|
|
getOperatorResult = OPERATORS[ term ];
|
|
if ( getOperatorResult ) {
|
|
// Pop from stack by number of function arguments.
|
|
j = getOperatorResult.length;
|
|
args = Array( j );
|
|
while ( j-- ) {
|
|
args[ j ] = stack.pop();
|
|
}
|
|
|
|
try {
|
|
value = getOperatorResult.apply( null, args );
|
|
} catch ( earlyReturn ) {
|
|
return earlyReturn;
|
|
}
|
|
} else if ( variables.hasOwnProperty( term ) ) {
|
|
value = variables[ term ];
|
|
} else {
|
|
value = +term;
|
|
}
|
|
|
|
stack.push( value );
|
|
}
|
|
|
|
return stack[ 0 ];
|
|
}
|
|
|
|
/**
|
|
* Given a C expression, returns a function which can be called to evaluate its
|
|
* result.
|
|
*
|
|
* @example
|
|
*
|
|
* ```js
|
|
* import compile from '@tannin/compile';
|
|
*
|
|
* const evaluate = compile( 'n > 1' );
|
|
*
|
|
* evaluate( { n: 2 } );
|
|
* // ⇒ true
|
|
* ```
|
|
*
|
|
* @param {string} expression C expression.
|
|
*
|
|
* @return {(variables?:{[variable:string]:*})=>*} Compiled evaluator.
|
|
*/
|
|
function compile( expression ) {
|
|
var terms = postfix( expression );
|
|
|
|
return function( variables ) {
|
|
return evaluate( terms, variables );
|
|
};
|
|
}
|
|
|
|
return compile;
|
|
|
|
}());
|