codeplay-common 4.5.5 → 4.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/files/finalrelease +8 -4
- package/files/take-screen-image.js +180 -99
- package/package.json +1 -1
package/files/finalrelease
CHANGED
|
@@ -194,12 +194,16 @@ function applyFlowchartStoreApi(storeId) {
|
|
|
194
194
|
if (String(_appUniqueId) !== String(FLOWCHART_API_APP_ID) || !flowchartSharedOriginal) return false;
|
|
195
195
|
const apiBase = String(storeId) === '1' ? FLOWCHART_PLAY_API_BASE : FLOWCHART_OTHER_STORE_API_BASE;
|
|
196
196
|
const accessHash = String(storeId) === '1' ? '' : FLOWCHART_OTHER_STORE_API_HASH;
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (
|
|
197
|
+
const apiBaseMarker = /const FLOWCHART_API_BASE = "[^"]*";/;
|
|
198
|
+
const accessHashMarker = /const FLOWCHART_API_ACCESS_HASH = "[^"]*";/;
|
|
199
|
+
|
|
200
|
+
if (!apiBaseMarker.test(flowchartSharedOriginal) || !accessHashMarker.test(flowchartSharedOriginal)) {
|
|
201
201
|
throw new Error(`Flowchart API configuration markers were not found in ${FLOWCHART_SHARED_PATH}.`);
|
|
202
202
|
}
|
|
203
|
+
|
|
204
|
+
const updated = flowchartSharedOriginal
|
|
205
|
+
.replace(apiBaseMarker, `const FLOWCHART_API_BASE = "${apiBase}";`)
|
|
206
|
+
.replace(accessHashMarker, `const FLOWCHART_API_ACCESS_HASH = "${accessHash}";`);
|
|
203
207
|
writeFileSync(FLOWCHART_SHARED_PATH, updated, 'utf8');
|
|
204
208
|
console.log(`✅ App 228 API endpoint configured for Store ID ${storeId}.`);
|
|
205
209
|
return true;
|
|
@@ -590,13 +590,6 @@ async function getPageDetails(client) {
|
|
|
590
590
|
async function capturePageSnapshot(client) {
|
|
591
591
|
const evaluation = await client.send('Runtime.evaluate', {
|
|
592
592
|
expression: `(async () => {
|
|
593
|
-
const clonedRoot = document.documentElement.cloneNode(true);
|
|
594
|
-
const originalElements = [
|
|
595
|
-
document.documentElement,
|
|
596
|
-
...document.documentElement.querySelectorAll('*'),
|
|
597
|
-
];
|
|
598
|
-
const clonedElements = [clonedRoot, ...clonedRoot.querySelectorAll('*')];
|
|
599
|
-
|
|
600
593
|
const blobToDataUrl = (blob) => new Promise((resolve, reject) => {
|
|
601
594
|
const reader = new FileReader();
|
|
602
595
|
reader.onload = () => resolve(reader.result);
|
|
@@ -617,109 +610,147 @@ async function capturePageSnapshot(client) {
|
|
|
617
610
|
return canvas.toDataURL('image/png');
|
|
618
611
|
};
|
|
619
612
|
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
const
|
|
613
|
+
const serializeDocument = async (sourceDocument) => {
|
|
614
|
+
const clonedRoot = sourceDocument.documentElement.cloneNode(true);
|
|
615
|
+
const originalElements = [
|
|
616
|
+
sourceDocument.documentElement,
|
|
617
|
+
...sourceDocument.documentElement.querySelectorAll('*'),
|
|
618
|
+
];
|
|
619
|
+
const clonedElements = [clonedRoot, ...clonedRoot.querySelectorAll('*')];
|
|
623
620
|
|
|
624
|
-
|
|
621
|
+
clonedRoot.setAttribute(
|
|
622
|
+
'data-responsive-window-scroll-y',
|
|
623
|
+
String(sourceDocument.defaultView?.scrollY || 0),
|
|
624
|
+
);
|
|
625
625
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
clone
|
|
629
|
-
}
|
|
626
|
+
for (let index = 0; index < originalElements.length; index += 1) {
|
|
627
|
+
const original = originalElements[index];
|
|
628
|
+
const clone = clonedElements[index];
|
|
630
629
|
|
|
631
|
-
|
|
632
|
-
clone.setAttribute('data-responsive-swiper-width', String(original.clientWidth));
|
|
633
|
-
clone.setAttribute('data-responsive-swiper-height', String(original.clientHeight));
|
|
634
|
-
}
|
|
630
|
+
if (!clone) continue;
|
|
635
631
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
} else if (original instanceof HTMLTextAreaElement) {
|
|
640
|
-
clone.textContent = original.value;
|
|
641
|
-
} else if (original instanceof HTMLSelectElement) {
|
|
642
|
-
for (let optionIndex = 0; optionIndex < original.options.length; optionIndex += 1) {
|
|
643
|
-
clone.options[optionIndex].selected = original.options[optionIndex].selected;
|
|
644
|
-
}
|
|
645
|
-
} else if (original instanceof HTMLCanvasElement) {
|
|
646
|
-
try {
|
|
647
|
-
clone.style.setProperty(
|
|
648
|
-
'background-image',
|
|
649
|
-
'url("' + original.toDataURL('image/png') + '")',
|
|
650
|
-
'important',
|
|
651
|
-
);
|
|
652
|
-
clone.style.setProperty('background-position', 'center', 'important');
|
|
653
|
-
clone.style.setProperty('background-repeat', 'no-repeat', 'important');
|
|
654
|
-
clone.style.setProperty('background-size', '100% 100%', 'important');
|
|
655
|
-
} catch {
|
|
656
|
-
// Keep the canvas element when its pixels cannot be exported.
|
|
632
|
+
if (original.scrollTop || original.scrollLeft) {
|
|
633
|
+
clone.setAttribute('data-responsive-scroll-top', String(original.scrollTop));
|
|
634
|
+
clone.setAttribute('data-responsive-scroll-left', String(original.scrollLeft));
|
|
657
635
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
replacement.alt = original.getAttribute('aria-label') || '';
|
|
663
|
-
replacement.setAttribute('style', original.getAttribute('style') || '');
|
|
664
|
-
clone.replaceWith(replacement);
|
|
665
|
-
} catch {
|
|
666
|
-
clone.setAttribute('poster', original.poster || '');
|
|
636
|
+
|
|
637
|
+
if (original.classList.contains('swiper-initialized')) {
|
|
638
|
+
clone.setAttribute('data-responsive-swiper-width', String(original.clientWidth));
|
|
639
|
+
clone.setAttribute('data-responsive-swiper-height', String(original.clientHeight));
|
|
667
640
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
clone.
|
|
641
|
+
|
|
642
|
+
const tagName = original.tagName?.toLowerCase();
|
|
643
|
+
|
|
644
|
+
if (tagName === 'input') {
|
|
645
|
+
clone.setAttribute('value', original.value);
|
|
646
|
+
clone.toggleAttribute('checked', original.checked);
|
|
647
|
+
} else if (tagName === 'textarea') {
|
|
648
|
+
clone.textContent = original.value;
|
|
649
|
+
} else if (tagName === 'select') {
|
|
650
|
+
for (let optionIndex = 0; optionIndex < original.options.length; optionIndex += 1) {
|
|
651
|
+
clone.options[optionIndex].selected = original.options[optionIndex].selected;
|
|
652
|
+
}
|
|
653
|
+
} else if (tagName === 'canvas') {
|
|
654
|
+
try {
|
|
655
|
+
clone.style.setProperty(
|
|
656
|
+
'background-image',
|
|
657
|
+
'url("' + original.toDataURL('image/png') + '")',
|
|
658
|
+
'important',
|
|
659
|
+
);
|
|
660
|
+
clone.style.setProperty('background-position', 'center', 'important');
|
|
661
|
+
clone.style.setProperty('background-repeat', 'no-repeat', 'important');
|
|
662
|
+
clone.style.setProperty('background-size', '100% 100%', 'important');
|
|
663
|
+
} catch {
|
|
664
|
+
// Keep the canvas element when its pixels cannot be exported.
|
|
665
|
+
}
|
|
666
|
+
} else if (tagName === 'video' && original.readyState >= 2) {
|
|
667
|
+
try {
|
|
668
|
+
const replacement = sourceDocument.createElement('img');
|
|
669
|
+
replacement.src = imageToDataUrl(original);
|
|
670
|
+
replacement.alt = original.getAttribute('aria-label') || '';
|
|
671
|
+
replacement.setAttribute('style', original.getAttribute('style') || '');
|
|
672
|
+
clone.replaceWith(replacement);
|
|
673
|
+
} catch {
|
|
674
|
+
clone.setAttribute('poster', original.poster || '');
|
|
675
|
+
}
|
|
676
|
+
} else if (tagName === 'img' && original.complete) {
|
|
677
|
+
try {
|
|
678
|
+
clone.setAttribute('src', imageToDataUrl(original) || original.currentSrc || original.src);
|
|
679
|
+
clone.removeAttribute('srcset');
|
|
680
|
+
} catch {
|
|
681
|
+
clone.setAttribute('src', original.currentSrc || original.src);
|
|
682
|
+
}
|
|
683
|
+
} else if (tagName === 'iframe') {
|
|
684
|
+
try {
|
|
685
|
+
const frameDocument = original.contentDocument;
|
|
686
|
+
|
|
687
|
+
if (frameDocument?.documentElement) {
|
|
688
|
+
const frameHtml = await serializeDocument(frameDocument);
|
|
689
|
+
clone.removeAttribute('src');
|
|
690
|
+
clone.setAttribute('srcdoc', '<!doctype html>' + frameHtml);
|
|
691
|
+
}
|
|
692
|
+
} catch {
|
|
693
|
+
// Cross-origin frames cannot be serialized and keep their original source.
|
|
694
|
+
}
|
|
674
695
|
}
|
|
675
696
|
}
|
|
676
|
-
}
|
|
677
697
|
|
|
678
|
-
|
|
679
|
-
|
|
698
|
+
const stylesheetLinks = [...sourceDocument.querySelectorAll('link[rel="stylesheet"]')];
|
|
699
|
+
const clonedStylesheetLinks = [...clonedRoot.querySelectorAll('link[rel="stylesheet"]')];
|
|
680
700
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
+
await Promise.all(stylesheetLinks.map(async (link, index) => {
|
|
702
|
+
try {
|
|
703
|
+
const response = await fetch(link.href);
|
|
704
|
+
if (!response.ok) return;
|
|
705
|
+
|
|
706
|
+
const cssText = (await response.text()).replace(
|
|
707
|
+
/url\\(\\s*(['"]?)(?!data:|blob:|#)([^'"\\)]+)\\1\\s*\\)/gi,
|
|
708
|
+
(match, quote, resourceUrl) => {
|
|
709
|
+
try {
|
|
710
|
+
return 'url("' + new URL(resourceUrl.trim(), link.href).href + '")';
|
|
711
|
+
} catch {
|
|
712
|
+
return match;
|
|
713
|
+
}
|
|
714
|
+
},
|
|
715
|
+
);
|
|
716
|
+
const style = sourceDocument.createElement('style');
|
|
717
|
+
style.textContent = cssText;
|
|
718
|
+
clonedStylesheetLinks[index].replaceWith(style);
|
|
719
|
+
} catch {
|
|
720
|
+
clonedStylesheetLinks[index].href = link.href;
|
|
721
|
+
}
|
|
722
|
+
}));
|
|
723
|
+
|
|
724
|
+
clonedRoot.querySelectorAll('script, link[rel="modulepreload"]').forEach(
|
|
725
|
+
(element) => element.remove(),
|
|
726
|
+
);
|
|
727
|
+
clonedRoot.querySelectorAll('meta[http-equiv="Content-Security-Policy"]').forEach(
|
|
728
|
+
(element) => element.remove(),
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
const head = clonedRoot.querySelector('head');
|
|
732
|
+
|
|
733
|
+
if (head) {
|
|
734
|
+
const base = sourceDocument.createElement('base');
|
|
735
|
+
base.href = sourceDocument.location.href;
|
|
736
|
+
head.prepend(base);
|
|
737
|
+
|
|
738
|
+
const replayStyle = sourceDocument.createElement('style');
|
|
739
|
+
replayStyle.textContent = [
|
|
740
|
+
'*,*::before,*::after{animation:none!important;transition:none!important;}',
|
|
741
|
+
'*{scrollbar-width:none!important;}',
|
|
742
|
+
'*::-webkit-scrollbar{width:0!important;height:0!important;display:none!important;}',
|
|
743
|
+
].join('');
|
|
744
|
+
head.append(replayStyle);
|
|
701
745
|
}
|
|
702
|
-
}));
|
|
703
746
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
(element) => element.remove(),
|
|
707
|
-
);
|
|
708
|
-
|
|
709
|
-
const base = document.createElement('base');
|
|
710
|
-
base.href = location.href;
|
|
711
|
-
clonedRoot.querySelector('head').prepend(base);
|
|
747
|
+
return clonedRoot.outerHTML;
|
|
748
|
+
};
|
|
712
749
|
|
|
713
|
-
const
|
|
714
|
-
replayStyle.textContent = [
|
|
715
|
-
'*,*::before,*::after{animation-play-state:paused!important;}',
|
|
716
|
-
'*{scrollbar-width:none!important;}',
|
|
717
|
-
'*::-webkit-scrollbar{width:0!important;height:0!important;display:none!important;}',
|
|
718
|
-
].join('');
|
|
719
|
-
clonedRoot.querySelector('head').append(replayStyle);
|
|
750
|
+
const html = await serializeDocument(document);
|
|
720
751
|
|
|
721
752
|
return {
|
|
722
|
-
html: '<!doctype html>' +
|
|
753
|
+
html: '<!doctype html>' + html,
|
|
723
754
|
scrollY,
|
|
724
755
|
};
|
|
725
756
|
})()`,
|
|
@@ -876,7 +907,43 @@ async function closeReplayBrowser(browser) {
|
|
|
876
907
|
async function waitForReplayLayout(client, snapshot) {
|
|
877
908
|
const evaluation = await client.send('Runtime.evaluate', {
|
|
878
909
|
expression: `(async () => {
|
|
879
|
-
const
|
|
910
|
+
const collectDocuments = (rootDocument) => {
|
|
911
|
+
const documents = [rootDocument];
|
|
912
|
+
|
|
913
|
+
rootDocument.querySelectorAll('iframe').forEach((frame) => {
|
|
914
|
+
try {
|
|
915
|
+
if (frame.contentDocument?.documentElement) {
|
|
916
|
+
documents.push(...collectDocuments(frame.contentDocument));
|
|
917
|
+
}
|
|
918
|
+
} catch {
|
|
919
|
+
// Cross-origin frames cannot participate in replay layout restoration.
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
return documents;
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
const frameDeadline = Date.now() + 5000;
|
|
927
|
+
|
|
928
|
+
while (Date.now() < frameDeadline) {
|
|
929
|
+
const frames = [...document.querySelectorAll('iframe')];
|
|
930
|
+
const framesReady = frames.every((frame) => {
|
|
931
|
+
try {
|
|
932
|
+
return frame.contentDocument?.readyState === 'complete';
|
|
933
|
+
} catch {
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
if (framesReady) break;
|
|
939
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const replayDocuments = collectDocuments(document);
|
|
943
|
+
const replayImages = replayDocuments.flatMap((replayDocument) => (
|
|
944
|
+
[...replayDocument.images]
|
|
945
|
+
));
|
|
946
|
+
const assetWait = Promise.all(replayImages.map((image) => {
|
|
880
947
|
if (image.complete) return Promise.resolve();
|
|
881
948
|
return new Promise((resolve) => {
|
|
882
949
|
image.addEventListener('load', resolve, { once: true });
|
|
@@ -885,11 +952,18 @@ async function waitForReplayLayout(client, snapshot) {
|
|
|
885
952
|
}));
|
|
886
953
|
|
|
887
954
|
await Promise.race([
|
|
888
|
-
Promise.all([
|
|
955
|
+
Promise.all([
|
|
956
|
+
...replayDocuments.map((replayDocument) => replayDocument.fonts.ready),
|
|
957
|
+
assetWait,
|
|
958
|
+
]),
|
|
889
959
|
new Promise((resolve) => setTimeout(resolve, 5000)),
|
|
890
960
|
]);
|
|
891
961
|
|
|
892
|
-
|
|
962
|
+
const replayElements = (selector) => replayDocuments.flatMap((replayDocument) => (
|
|
963
|
+
[...replayDocument.querySelectorAll(selector)]
|
|
964
|
+
));
|
|
965
|
+
|
|
966
|
+
replayElements('[data-responsive-swiper-width]').forEach((swiper) => {
|
|
893
967
|
const wrapper = [...swiper.children].find((element) => (
|
|
894
968
|
element.classList.contains('swiper-wrapper')
|
|
895
969
|
));
|
|
@@ -947,10 +1021,17 @@ async function waitForReplayLayout(client, snapshot) {
|
|
|
947
1021
|
}
|
|
948
1022
|
});
|
|
949
1023
|
|
|
950
|
-
|
|
1024
|
+
replayElements('[data-responsive-scroll-top]').forEach((element) => {
|
|
951
1025
|
element.scrollTop = Number(element.dataset.responsiveScrollTop);
|
|
952
1026
|
element.scrollLeft = Number(element.dataset.responsiveScrollLeft);
|
|
953
1027
|
});
|
|
1028
|
+
|
|
1029
|
+
replayDocuments.forEach((replayDocument) => {
|
|
1030
|
+
replayDocument.defaultView?.scrollTo(
|
|
1031
|
+
0,
|
|
1032
|
+
Number(replayDocument.documentElement.dataset.responsiveWindowScrollY) || 0,
|
|
1033
|
+
);
|
|
1034
|
+
});
|
|
954
1035
|
scrollTo(0, ${Number(snapshot.scrollY) || 0});
|
|
955
1036
|
|
|
956
1037
|
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
|