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>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

360
node_modules/metaviewport-parser/index.js generated vendored Normal file
View File

@@ -0,0 +1,360 @@
exports.getRenderingDataFromViewport = function (viewportProperties, uaDeviceWidth, uaDeviceHeight, uaMaxZoom, uaMinZoom) {
var vw = uaDeviceWidth / 100;
var vh = uaDeviceHeight / 100;
// Following https://www.w3.org/TR/css-device-adapt/#handling-auto-zoom
// 'auto' is mapped to null by convention
var maxZoom = null;
var minZoom = null;
var zoom = null;
var minWidth = null;
var minHeight = null;
var maxWidth = null;
var maxHeight = null;
var width = null, height = null;
var initialWidth = uaDeviceWidth;
var initialHeight = uaDeviceHeight;
var userZoom = "zoom";
var interactiveWidget = "resizes-visual";
if (viewportProperties["maximum-scale"] !== undefined) {
maxZoom = translateZoomProperty(viewportProperties["maximum-scale"]);
}
if (viewportProperties["minimum-scale"] !== undefined) {
minZoom = translateZoomProperty(viewportProperties["minimum-scale"]);
}
if (viewportProperties["initial-scale"] !== undefined) {
zoom = translateZoomProperty(viewportProperties["initial-scale"]);
}
/* For a viewport META element that translates into an @viewport rule
with no max-zoom declaration and a non-auto min-zoom value
that is larger than the max-zoom value of the UA stylesheet,
the min-zoom declaration value is clamped to the UA stylesheet
max-zoom value. */
if (minZoom !== null && maxZoom === null) {
minZoom = min(uaMaxZoom, translateZoomProperty(viewportProperties["minimum-scale"]));
}
if (viewportProperties["width"] !== undefined) {
minWidth = "extend-to-zoom";
maxWidth = translateLengthProperty(viewportProperties["width"], vw, vh);
}
if (viewportProperties["height"] !== undefined) {
minHeight = "extend-to-zoom";
maxHeight = translateLengthProperty(viewportProperties["height"], vw, vh);
}
// Following https://www.w3.org/TR/css-device-adapt/#user-scalable
if (viewportProperties["user-scalable"] !== undefined) {
userZoom = viewportProperties["user-scalable"];
if (typeof userZoom === "number") {
if (userZoom >=1 || userZoom <= -1) {
userZoom = "zoom";
} else {
userZoom = "fixed";
}
} else {
switch(userZoom) {
case "yes":
case "device-width":
case "device-height":
userZoom = "zoom";
break;
case "no":
default:
userZoom = "fixed";
break;
}
}
}
// Following https://w3c.github.io/csswg-drafts/css-viewport/#interactive-widget-section
if (viewportProperties["interactive-widget"] !== undefined) {
switch(viewportProperties["interactive-widget"]) {
case "overlays-content":
case "resizes-content":
case "resizes-visual":
interactiveWidget = viewportProperties["interactive-widget"];
break;
default:
interactiveWidget = "resizes-visual";
break;
}
}
/* For a viewport META element that translates into an @viewport rule
with a non-auto zoom declaration and no width declaration: */
if (zoom !== null &&
(viewportProperties["width"] === undefined || width === undefined)) {
if (viewportProperties["height"] !== undefined) {
// If it adds a height descriptor, add: width: auto;
minWidth = null;
maxWidth = null;
} else {
// Otherwise, add: width: extend-to-zoom;
minWidth = "extend-to-zoom";
maxWidth = "extend-to-zoom";
}
}
// Following https://www.w3.org/TR/css-device-adapt/#constraining
// If min-zoom is not auto and max-zoom is not auto,
// set max-zoom = MAX(min-zoom, max-zoom)
if (minZoom !== null && maxZoom !== null) {
maxZoom = max(minZoom, maxZoom);
}
// If zoom is not auto, set zoom = MAX(min-zoom, MIN(max-zoom, zoom))
if (zoom !== null) {
zoom = clamp(zoom, minZoom, maxZoom);
}
// from "Resolving extend-to-zoom"
var extendZoom = (zoom === null && maxZoom === null ? null : min(zoom, maxZoom));
var extendWidth, extendHeight;
if (extendZoom === null) {
if (maxWidth === "extend-to-zoom") {
maxWidth = null;
}
if (maxHeight === "extend-to-zoom") {
maxHeight = null;
}
if (minWidth === "extend-to-zoom") {
minWidth = maxWidth;
}
if (minHeight === "extend-to-zoom") {
minHeight = maxHeight;
}
} else {
extendWidth = initialWidth / extendZoom;
extendHeight = initialHeight / extendZoom;
if (maxWidth === "extend-to-zoom") {
maxWidth = extendWidth;
}
if (maxHeight === "extend-to-zoom") {
maxHeight = extendHeight;
}
if (minWidth === "extend-to-zoom") {
minWidth = max(extendWidth, maxWidth);
}
if (minHeight === "extend-to-zoom") {
minHeight = max(extendHeight, maxHeight);
}
}
// Resolve initial width and height from min/max descriptors
if (minWidth !== null || maxWidth !== null) {
width = max(minWidth, min(maxWidth, initialWidth));
}
if (minHeight !== null || maxHeight !== null) {
height = max(minHeight, min(maxHeight, initialHeight));
}
// Resolve width value
if (width === null) {
if (height === null) {
width = initialWidth;
} else {
if (initialHeight !== 0) {
width = Math.round(height * (initialWidth / initialHeight));
} else {
width = initialWidth;
}
}
}
if (height === null) {
if (initialWidth !== 0) {
height = Math.round(width * (initialHeight / initialWidth));
} else {
height = initialHeight;
}
}
return { zoom: zoom, width: width, height: height, userZoom: userZoom, interactiveWidget: interactiveWidget};
};
function min(a, b) {
if (a === null) return b;
if (b === null) return a;
return Math.min(a,b);
}
function max(a, b) {
if (a === null) return b;
if (b === null) return a;
return Math.max(a,b);
}
function translateLengthProperty(prop, vw, vh) {
// based on http://dev.w3.org/csswg/css-device-adapt/#width2
if (typeof prop === "number") {
if (prop >= 0) {
// Non-negative number values are translated to pixel lengths, clamped to the range: [1px, 10000px]
return clamp(prop, 1, 10000);
} else {
return undefined;
}
}
if (prop === "device-width") {
return 100*vw;
}
if (prop === "device-height") {
return 100*vh;
}
return 1;
}
function translateZoomProperty(prop) {
// based on http://dev.w3.org/csswg/css-device-adapt/#initial-scale0
if (typeof prop === "number") {
if (prop >= 0) {
// Non-negative number values are translated to <number> values, clamped to the range [0.1, 10]
return clamp(prop, 0.1, 10);
} else {
return undefined;
}
}
if (prop === "yes") {
return 1;
}
if (prop === "device-width" || prop === "device-height") {
return 10;
}
if (prop === "no" || prop === null) {
return 0.1;
}
}
// return value if min <= value <= max, or the closest from min or max
function clamp(value, minv, maxv) {
return max(min(value, maxv), minv);
}
/*
from http://dev.w3.org/csswg/css-device-adapt/#viewport-meta
Parse-Content(S)
i ← 1
while i ≤ length[S]
do while i ≤ length[S] and S[i] in [whitespace, separator, '=']
do i ← i + 1
if i ≤ length[S]
then i ← Parse-Property(S, i)
Parse-Property(S, i)
start ← i
while i ≤ length[S] and S[i] not in [whitespace, separator, '=']
do i ← i + 1
if i > length[S] or S[i] in [separator]
then return i
property-name ← S[start .. (i - 1)]
while i ≤ length[S] and S[i] not in [separator, '=']
do i ← i + 1
if i > length[S] or S[i] in [separator]
then return i
while i ≤ length[S] and S[i] in [whitespace, '=']
do i ← i + 1
if i > length[S] or S[i] in [separator]
then return i
start ← i
while i ≤ length[S] and S[i] not in [whitespace, separator, '=']
do i ← i + 1
property-value ← S[start .. (i - 1)]
Set-Property(property-name, property-value)
return i */
exports.parseMetaViewPortContent = function (S) {
var parsedContent = {
validProperties : {},
unknownProperties: {},
invalidValues : {}
};
var i = 1;
while (i <= S.length) {
while (i <= S.length && RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) {
i++;
}
if (i <= S.length) {
i = parseProperty(parsedContent, S, i);
}
}
return parsedContent;
};
var propertyNames = ["width", "height", "initial-scale", "minimum-scale", "maximum-scale", "user-scalable", "shrink-to-fit", "viewport-fit", "interactive-widget"];
function parseProperty(parsedContent, S, i) {
var start = i;
while (i <= S.length && !RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) {
i++;
}
if (i > S.length || RegExp(',|;').test(S[i-1])) {
return i;
}
var propertyName = S.slice(start - 1, i-1);
while (i <= S.length && !RegExp(',|;|=').test(S[i-1])) {
i++;
}
if (i > S.length || RegExp(',|;').test(S[i-1])) {
return i;
}
while (i <= S.length && RegExp(' |\x0A|\x09|\0d|=').test(S[i-1])) {
i++;
}
if (i > S.length || RegExp(',|;').test(S[i-1])) {
return i;
}
start = i;
while (i <= S.length && !RegExp(' |\x0A|\x09|\0d|,|;|=').test(S[i-1])) {
i++;
}
var propertyValue = S.slice(start - 1, i-1);
setProperty(parsedContent, propertyName, propertyValue);
return i;
}
function setProperty(parsedContent, name, value) {
if (propertyNames.indexOf(name) >= 0) {
var number = parseFloat(value);
if (!isNaN(number)) {
parsedContent.validProperties[name] = number;
return;
}
var string = value.toLowerCase();
if (string === "yes" || string === "no" || string === "device-width" || string === "device-height" ||
// https://webkit.org/blog/7929/designing-websites-for-iphone-x/
(name.toLowerCase() === 'viewport-fit' && (string === 'auto' || string === 'cover')) ||
(name.toLowerCase() === 'interactive-widget' && (exports.expectedValues["interactive-widget"].includes(string)))
) {
parsedContent.validProperties[name] = string;
return;
}
parsedContent.validProperties[name] = null;
parsedContent.invalidValues[name] = value;
} else {
parsedContent.unknownProperties[name] = value;
}
}
exports.expectedValues = {
"width": ["device-width", "device-height", "a positive number"],
"height": ["device-width", "device-height", "a positive number"],
"initial-scale": ["a positive number"],
"minimum-scale": ["a positive number"],
"maximum-scale": ["a positive number"],
"user-scalable": ["yes", "no", "0", "1"],
"shrink-to-fit": ["yes", "no"],
"viewport-fit": ["auto", "cover"],
"interactive-widget": ["overlays-content", "resizes-content", "resizes-visual"]
};