@patch-adams/core 1.4.37 → 1.5.0
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/dist/cli.cjs +307 -13
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +307 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +307 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +307 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -291,6 +291,8 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
291
291
|
/** Whether this plugin is enabled */
|
|
292
292
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
293
293
|
}, z.ZodTypeAny, "passthrough">>>>;
|
|
294
|
+
/** Optional skin name — adds 'pa-skinned' + skin class to <html>, loads skin CSS/JS after core files */
|
|
295
|
+
skin: z.ZodOptional<z.ZodString>;
|
|
294
296
|
}, "strip", z.ZodTypeAny, {
|
|
295
297
|
remoteDomain: string;
|
|
296
298
|
htmlClass: string;
|
|
@@ -341,6 +343,7 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
341
343
|
/** Whether this plugin is enabled */
|
|
342
344
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
343
345
|
}, z.ZodTypeAny, "passthrough">>;
|
|
346
|
+
skin?: string | undefined;
|
|
344
347
|
}, {
|
|
345
348
|
remoteDomain: string;
|
|
346
349
|
htmlClass?: string | undefined;
|
|
@@ -391,6 +394,7 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
391
394
|
/** Whether this plugin is enabled */
|
|
392
395
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
393
396
|
}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
397
|
+
skin?: string | undefined;
|
|
394
398
|
}>;
|
|
395
399
|
type PatchAdamsConfig = z.infer<typeof PatchAdamsConfigSchema>;
|
|
396
400
|
type LrsBridgeConfig = z.infer<typeof LrsBridgeConfigSchema>;
|
|
@@ -698,6 +702,14 @@ declare class HtmlInjector {
|
|
|
698
702
|
* Inject JS After loader at end of <body> (after __loadEntry)
|
|
699
703
|
*/
|
|
700
704
|
private injectJsAfter;
|
|
705
|
+
/**
|
|
706
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
707
|
+
*/
|
|
708
|
+
private injectSkinCss;
|
|
709
|
+
/**
|
|
710
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
711
|
+
*/
|
|
712
|
+
private injectSkinJs;
|
|
701
713
|
}
|
|
702
714
|
|
|
703
715
|
/**
|
|
@@ -770,6 +782,14 @@ declare class StorylineHtmlInjector {
|
|
|
770
782
|
* We inject before </body> so our code runs before the bootstrapper.
|
|
771
783
|
*/
|
|
772
784
|
private injectJsAfter;
|
|
785
|
+
/**
|
|
786
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
787
|
+
*/
|
|
788
|
+
private injectSkinCss;
|
|
789
|
+
/**
|
|
790
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
791
|
+
*/
|
|
792
|
+
private injectSkinJs;
|
|
773
793
|
}
|
|
774
794
|
|
|
775
795
|
interface ManifestPaths {
|
|
@@ -777,6 +797,8 @@ interface ManifestPaths {
|
|
|
777
797
|
cssAfter?: string;
|
|
778
798
|
jsBefore?: string;
|
|
779
799
|
jsAfter?: string;
|
|
800
|
+
skinCss?: string;
|
|
801
|
+
skinJs?: string;
|
|
780
802
|
}
|
|
781
803
|
/**
|
|
782
804
|
* Update manifest files to include injected assets
|
|
@@ -840,6 +862,8 @@ interface PatchOptions {
|
|
|
840
862
|
jsAfterContent?: string;
|
|
841
863
|
/** Skip fetching remote files even if fetchFallbacks is enabled in config */
|
|
842
864
|
skipFetch?: boolean;
|
|
865
|
+
/** Optional skin name — per-call override for config.skin */
|
|
866
|
+
skin?: string;
|
|
843
867
|
}
|
|
844
868
|
/**
|
|
845
869
|
* Main Patcher class for patching e-learning course packages
|
|
@@ -912,7 +936,7 @@ declare class Patcher {
|
|
|
912
936
|
* @param buffer - Input ZIP file as Buffer
|
|
913
937
|
* @returns Patched ZIP file as Buffer
|
|
914
938
|
*/
|
|
915
|
-
patchBuffer(buffer: Buffer): Promise<Buffer>;
|
|
939
|
+
patchBuffer(buffer: Buffer, options?: PatchOptions): Promise<Buffer>;
|
|
916
940
|
}
|
|
917
941
|
|
|
918
942
|
/**
|
|
@@ -1030,6 +1054,8 @@ interface JsBeforeOptions {
|
|
|
1030
1054
|
metadata: CourseMetadata | null;
|
|
1031
1055
|
/** LRS Bridge configuration */
|
|
1032
1056
|
lrsBridge: LrsBridgeOptions;
|
|
1057
|
+
/** Optional skin name */
|
|
1058
|
+
skin?: string;
|
|
1033
1059
|
}
|
|
1034
1060
|
/**
|
|
1035
1061
|
* Generate the blocking JS loader for the "before" slot
|
package/dist/index.d.ts
CHANGED
|
@@ -291,6 +291,8 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
291
291
|
/** Whether this plugin is enabled */
|
|
292
292
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
293
293
|
}, z.ZodTypeAny, "passthrough">>>>;
|
|
294
|
+
/** Optional skin name — adds 'pa-skinned' + skin class to <html>, loads skin CSS/JS after core files */
|
|
295
|
+
skin: z.ZodOptional<z.ZodString>;
|
|
294
296
|
}, "strip", z.ZodTypeAny, {
|
|
295
297
|
remoteDomain: string;
|
|
296
298
|
htmlClass: string;
|
|
@@ -341,6 +343,7 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
341
343
|
/** Whether this plugin is enabled */
|
|
342
344
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
343
345
|
}, z.ZodTypeAny, "passthrough">>;
|
|
346
|
+
skin?: string | undefined;
|
|
344
347
|
}, {
|
|
345
348
|
remoteDomain: string;
|
|
346
349
|
htmlClass?: string | undefined;
|
|
@@ -391,6 +394,7 @@ declare const PatchAdamsConfigSchema: z.ZodObject<{
|
|
|
391
394
|
/** Whether this plugin is enabled */
|
|
392
395
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
393
396
|
}, z.ZodTypeAny, "passthrough">> | undefined;
|
|
397
|
+
skin?: string | undefined;
|
|
394
398
|
}>;
|
|
395
399
|
type PatchAdamsConfig = z.infer<typeof PatchAdamsConfigSchema>;
|
|
396
400
|
type LrsBridgeConfig = z.infer<typeof LrsBridgeConfigSchema>;
|
|
@@ -698,6 +702,14 @@ declare class HtmlInjector {
|
|
|
698
702
|
* Inject JS After loader at end of <body> (after __loadEntry)
|
|
699
703
|
*/
|
|
700
704
|
private injectJsAfter;
|
|
705
|
+
/**
|
|
706
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
707
|
+
*/
|
|
708
|
+
private injectSkinCss;
|
|
709
|
+
/**
|
|
710
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
711
|
+
*/
|
|
712
|
+
private injectSkinJs;
|
|
701
713
|
}
|
|
702
714
|
|
|
703
715
|
/**
|
|
@@ -770,6 +782,14 @@ declare class StorylineHtmlInjector {
|
|
|
770
782
|
* We inject before </body> so our code runs before the bootstrapper.
|
|
771
783
|
*/
|
|
772
784
|
private injectJsAfter;
|
|
785
|
+
/**
|
|
786
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
787
|
+
*/
|
|
788
|
+
private injectSkinCss;
|
|
789
|
+
/**
|
|
790
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
791
|
+
*/
|
|
792
|
+
private injectSkinJs;
|
|
773
793
|
}
|
|
774
794
|
|
|
775
795
|
interface ManifestPaths {
|
|
@@ -777,6 +797,8 @@ interface ManifestPaths {
|
|
|
777
797
|
cssAfter?: string;
|
|
778
798
|
jsBefore?: string;
|
|
779
799
|
jsAfter?: string;
|
|
800
|
+
skinCss?: string;
|
|
801
|
+
skinJs?: string;
|
|
780
802
|
}
|
|
781
803
|
/**
|
|
782
804
|
* Update manifest files to include injected assets
|
|
@@ -840,6 +862,8 @@ interface PatchOptions {
|
|
|
840
862
|
jsAfterContent?: string;
|
|
841
863
|
/** Skip fetching remote files even if fetchFallbacks is enabled in config */
|
|
842
864
|
skipFetch?: boolean;
|
|
865
|
+
/** Optional skin name — per-call override for config.skin */
|
|
866
|
+
skin?: string;
|
|
843
867
|
}
|
|
844
868
|
/**
|
|
845
869
|
* Main Patcher class for patching e-learning course packages
|
|
@@ -912,7 +936,7 @@ declare class Patcher {
|
|
|
912
936
|
* @param buffer - Input ZIP file as Buffer
|
|
913
937
|
* @returns Patched ZIP file as Buffer
|
|
914
938
|
*/
|
|
915
|
-
patchBuffer(buffer: Buffer): Promise<Buffer>;
|
|
939
|
+
patchBuffer(buffer: Buffer, options?: PatchOptions): Promise<Buffer>;
|
|
916
940
|
}
|
|
917
941
|
|
|
918
942
|
/**
|
|
@@ -1030,6 +1054,8 @@ interface JsBeforeOptions {
|
|
|
1030
1054
|
metadata: CourseMetadata | null;
|
|
1031
1055
|
/** LRS Bridge configuration */
|
|
1032
1056
|
lrsBridge: LrsBridgeOptions;
|
|
1057
|
+
/** Optional skin name */
|
|
1058
|
+
skin?: string;
|
|
1033
1059
|
}
|
|
1034
1060
|
/**
|
|
1035
1061
|
* Generate the blocking JS loader for the "before" slot
|
package/dist/index.js
CHANGED
|
@@ -106,7 +106,9 @@ var PatchAdamsConfigSchema = z.object({
|
|
|
106
106
|
/** LRS Bridge configuration for xAPI/LRS communication with Bravais */
|
|
107
107
|
lrsBridge: LrsBridgeConfigSchema.default({}),
|
|
108
108
|
/** Plugin configurations - each plugin is keyed by its name */
|
|
109
|
-
plugins: PluginsConfigSchema
|
|
109
|
+
plugins: PluginsConfigSchema,
|
|
110
|
+
/** Optional skin name — adds 'pa-skinned' + skin class to <html>, loads skin CSS/JS after core files */
|
|
111
|
+
skin: z.string().min(1).optional()
|
|
110
112
|
});
|
|
111
113
|
|
|
112
114
|
// src/config/defaults.ts
|
|
@@ -4377,7 +4379,7 @@ function escapeJs(str) {
|
|
|
4377
4379
|
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
4378
4380
|
}
|
|
4379
4381
|
function generateJsBeforeLoader(options) {
|
|
4380
|
-
const { remoteUrl, localPath, htmlClass, loadingClass, metadata, lrsBridge } = options;
|
|
4382
|
+
const { remoteUrl, localPath, htmlClass, loadingClass, metadata, lrsBridge, skin } = options;
|
|
4381
4383
|
const lrsBridgeCode = generateLrsBridgeCode(lrsBridge);
|
|
4382
4384
|
const courseLines = [];
|
|
4383
4385
|
if (metadata) {
|
|
@@ -4420,12 +4422,13 @@ ${courseLines.join("\n")}
|
|
|
4420
4422
|
window.pa_patcher = window.pa_patcher || {
|
|
4421
4423
|
version: '1.0.25',
|
|
4422
4424
|
htmlClass: '${htmlClass}',
|
|
4423
|
-
loadingClass: '${loadingClass}',${
|
|
4425
|
+
loadingClass: '${loadingClass}',${skin ? `
|
|
4426
|
+
skin: '${escapeJs(skin)}',` : ""}${courseBlock}
|
|
4424
4427
|
loaded: {
|
|
4425
4428
|
cssBefore: false,
|
|
4426
4429
|
cssAfter: false,
|
|
4427
4430
|
jsBefore: false,
|
|
4428
|
-
jsAfter: false
|
|
4431
|
+
jsAfter: false${skin ? ",\n skinCss: false,\n skinJs: false" : ""}
|
|
4429
4432
|
}
|
|
4430
4433
|
};
|
|
4431
4434
|
|
|
@@ -4546,7 +4549,8 @@ function buildJsBeforeOptions(config, metadata) {
|
|
|
4546
4549
|
htmlClass: config.htmlClass,
|
|
4547
4550
|
loadingClass: config.loadingClass,
|
|
4548
4551
|
metadata: metadata ?? null,
|
|
4549
|
-
lrsBridge
|
|
4552
|
+
lrsBridge,
|
|
4553
|
+
skin: config.skin
|
|
4550
4554
|
};
|
|
4551
4555
|
}
|
|
4552
4556
|
|
|
@@ -4669,6 +4673,196 @@ function buildJsAfterOptions(config) {
|
|
|
4669
4673
|
};
|
|
4670
4674
|
}
|
|
4671
4675
|
|
|
4676
|
+
// src/templates/skin-css.ts
|
|
4677
|
+
function generateSkinCssLoader(options) {
|
|
4678
|
+
const { remoteUrl, localPath, timeout } = options;
|
|
4679
|
+
return `<!-- === PATCH-ADAMS: SKIN CSS (async with fallback) === -->
|
|
4680
|
+
<script data-pa="skin-css-loader">
|
|
4681
|
+
(function() {
|
|
4682
|
+
'use strict';
|
|
4683
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
4684
|
+
var LOCAL_PATH = "${localPath}";
|
|
4685
|
+
var TIMEOUT = ${timeout};
|
|
4686
|
+
|
|
4687
|
+
function loadCSS(url, onSuccess, onError) {
|
|
4688
|
+
var link = document.createElement('link');
|
|
4689
|
+
link.rel = 'stylesheet';
|
|
4690
|
+
link.href = url;
|
|
4691
|
+
link.setAttribute('data-pa', 'skin-css');
|
|
4692
|
+
|
|
4693
|
+
link.onload = function() {
|
|
4694
|
+
if (onSuccess) onSuccess();
|
|
4695
|
+
};
|
|
4696
|
+
|
|
4697
|
+
link.onerror = function() {
|
|
4698
|
+
if (onError) onError();
|
|
4699
|
+
};
|
|
4700
|
+
|
|
4701
|
+
document.head.appendChild(link);
|
|
4702
|
+
return link;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
function loadCSSWithFallback() {
|
|
4706
|
+
var loaded = false;
|
|
4707
|
+
var timeoutId;
|
|
4708
|
+
|
|
4709
|
+
// Try remote first
|
|
4710
|
+
var remoteLink = loadCSS(
|
|
4711
|
+
REMOTE_URL,
|
|
4712
|
+
function() {
|
|
4713
|
+
if (loaded) return;
|
|
4714
|
+
loaded = true;
|
|
4715
|
+
clearTimeout(timeoutId);
|
|
4716
|
+
console.log('[PA-Patcher] Skin CSS loaded from remote:', REMOTE_URL);
|
|
4717
|
+
},
|
|
4718
|
+
function() {
|
|
4719
|
+
if (loaded) return;
|
|
4720
|
+
loaded = true;
|
|
4721
|
+
clearTimeout(timeoutId);
|
|
4722
|
+
loadLocalFallback();
|
|
4723
|
+
}
|
|
4724
|
+
);
|
|
4725
|
+
|
|
4726
|
+
// Timeout fallback
|
|
4727
|
+
timeoutId = setTimeout(function() {
|
|
4728
|
+
if (loaded) return;
|
|
4729
|
+
loaded = true;
|
|
4730
|
+
console.warn('[PA-Patcher] Skin CSS timed out, using local fallback');
|
|
4731
|
+
if (remoteLink.parentNode) {
|
|
4732
|
+
document.head.removeChild(remoteLink);
|
|
4733
|
+
}
|
|
4734
|
+
loadLocalFallback();
|
|
4735
|
+
}, TIMEOUT);
|
|
4736
|
+
}
|
|
4737
|
+
|
|
4738
|
+
function loadLocalFallback() {
|
|
4739
|
+
loadCSS(
|
|
4740
|
+
LOCAL_PATH,
|
|
4741
|
+
function() {
|
|
4742
|
+
console.log('[PA-Patcher] Skin CSS loaded from local fallback:', LOCAL_PATH);
|
|
4743
|
+
},
|
|
4744
|
+
function() {
|
|
4745
|
+
console.error('[PA-Patcher] Skin CSS failed to load from both remote and local');
|
|
4746
|
+
}
|
|
4747
|
+
);
|
|
4748
|
+
}
|
|
4749
|
+
|
|
4750
|
+
// Execute immediately
|
|
4751
|
+
loadCSSWithFallback();
|
|
4752
|
+
})();
|
|
4753
|
+
</script>`;
|
|
4754
|
+
}
|
|
4755
|
+
function buildSkinCssOptions(config) {
|
|
4756
|
+
if (!config.skin) return null;
|
|
4757
|
+
return {
|
|
4758
|
+
remoteUrl: `${config.remoteDomain}/skin/${config.skin}.css`,
|
|
4759
|
+
localPath: `skin/${config.skin}.css`,
|
|
4760
|
+
timeout: config.cssAfter.timeout
|
|
4761
|
+
// reuse cssAfter timeout
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
|
|
4765
|
+
// src/templates/skin-js.ts
|
|
4766
|
+
function generateSkinJsLoader(options) {
|
|
4767
|
+
const { remoteUrl, localPath, timeout } = options;
|
|
4768
|
+
return `<!-- === PATCH-ADAMS: SKIN JS (async with fallback) === -->
|
|
4769
|
+
<script data-pa="skin-js-loader">
|
|
4770
|
+
(function() {
|
|
4771
|
+
'use strict';
|
|
4772
|
+
var REMOTE_URL = "${remoteUrl}";
|
|
4773
|
+
var LOCAL_PATH = "${localPath}";
|
|
4774
|
+
var TIMEOUT = ${timeout};
|
|
4775
|
+
|
|
4776
|
+
function loadJS(url, onSuccess, onError) {
|
|
4777
|
+
var script = document.createElement('script');
|
|
4778
|
+
script.src = url;
|
|
4779
|
+
script.async = true;
|
|
4780
|
+
script.setAttribute('data-pa', 'skin-js');
|
|
4781
|
+
|
|
4782
|
+
script.onload = function() {
|
|
4783
|
+
if (onSuccess) onSuccess();
|
|
4784
|
+
};
|
|
4785
|
+
|
|
4786
|
+
script.onerror = function() {
|
|
4787
|
+
if (onError) onError();
|
|
4788
|
+
};
|
|
4789
|
+
|
|
4790
|
+
document.body.appendChild(script);
|
|
4791
|
+
return script;
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4794
|
+
function loadJSWithFallback() {
|
|
4795
|
+
var loaded = false;
|
|
4796
|
+
var timeoutId;
|
|
4797
|
+
|
|
4798
|
+
// Try remote first
|
|
4799
|
+
var remoteScript = loadJS(
|
|
4800
|
+
REMOTE_URL,
|
|
4801
|
+
function() {
|
|
4802
|
+
if (loaded) return;
|
|
4803
|
+
loaded = true;
|
|
4804
|
+
clearTimeout(timeoutId);
|
|
4805
|
+
console.log('[PA-Patcher] Skin JS loaded from remote:', REMOTE_URL);
|
|
4806
|
+
if (window.pa_patcher && window.pa_patcher.loaded) {
|
|
4807
|
+
window.pa_patcher.loaded.skinJs = true;
|
|
4808
|
+
}
|
|
4809
|
+
},
|
|
4810
|
+
function() {
|
|
4811
|
+
if (loaded) return;
|
|
4812
|
+
loaded = true;
|
|
4813
|
+
clearTimeout(timeoutId);
|
|
4814
|
+
loadLocalFallback();
|
|
4815
|
+
}
|
|
4816
|
+
);
|
|
4817
|
+
|
|
4818
|
+
// Timeout fallback
|
|
4819
|
+
timeoutId = setTimeout(function() {
|
|
4820
|
+
if (loaded) return;
|
|
4821
|
+
loaded = true;
|
|
4822
|
+
console.warn('[PA-Patcher] Skin JS timed out, using local fallback');
|
|
4823
|
+
if (remoteScript.parentNode) {
|
|
4824
|
+
document.body.removeChild(remoteScript);
|
|
4825
|
+
}
|
|
4826
|
+
loadLocalFallback();
|
|
4827
|
+
}, TIMEOUT);
|
|
4828
|
+
}
|
|
4829
|
+
|
|
4830
|
+
function loadLocalFallback() {
|
|
4831
|
+
loadJS(
|
|
4832
|
+
LOCAL_PATH,
|
|
4833
|
+
function() {
|
|
4834
|
+
console.log('[PA-Patcher] Skin JS loaded from local fallback:', LOCAL_PATH);
|
|
4835
|
+
if (window.pa_patcher && window.pa_patcher.loaded) {
|
|
4836
|
+
window.pa_patcher.loaded.skinJs = true;
|
|
4837
|
+
}
|
|
4838
|
+
},
|
|
4839
|
+
function() {
|
|
4840
|
+
console.error('[PA-Patcher] Skin JS failed to load from both remote and local');
|
|
4841
|
+
}
|
|
4842
|
+
);
|
|
4843
|
+
}
|
|
4844
|
+
|
|
4845
|
+
// Execute after DOM is ready
|
|
4846
|
+
if (document.readyState === 'loading') {
|
|
4847
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
4848
|
+
setTimeout(loadJSWithFallback, 150);
|
|
4849
|
+
});
|
|
4850
|
+
} else {
|
|
4851
|
+
setTimeout(loadJSWithFallback, 150);
|
|
4852
|
+
}
|
|
4853
|
+
})();
|
|
4854
|
+
</script>`;
|
|
4855
|
+
}
|
|
4856
|
+
function buildSkinJsOptions(config) {
|
|
4857
|
+
if (!config.skin) return null;
|
|
4858
|
+
return {
|
|
4859
|
+
remoteUrl: `${config.remoteDomain}/skin/${config.skin}.js`,
|
|
4860
|
+
localPath: `skin/${config.skin}.js`,
|
|
4861
|
+
timeout: config.jsAfter.timeout
|
|
4862
|
+
// reuse jsAfter timeout
|
|
4863
|
+
};
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4672
4866
|
// src/patcher/html-injector.ts
|
|
4673
4867
|
var HtmlInjector = class {
|
|
4674
4868
|
config;
|
|
@@ -4732,6 +4926,10 @@ var HtmlInjector = class {
|
|
|
4732
4926
|
if (this.config.jsAfter.enabled) {
|
|
4733
4927
|
result = this.injectJsAfter(result);
|
|
4734
4928
|
}
|
|
4929
|
+
if (this.config.skin) {
|
|
4930
|
+
result = this.injectSkinCss(result);
|
|
4931
|
+
result = this.injectSkinJs(result);
|
|
4932
|
+
}
|
|
4735
4933
|
if (this.pluginAssets) {
|
|
4736
4934
|
result = this.injectPluginAssets(result);
|
|
4737
4935
|
}
|
|
@@ -4778,8 +4976,8 @@ ${pluginJs}
|
|
|
4778
4976
|
* Also adds data attributes for course metadata
|
|
4779
4977
|
*/
|
|
4780
4978
|
addHtmlAttributes(html) {
|
|
4781
|
-
const { htmlClass, loadingClass } = this.config;
|
|
4782
|
-
const classes = `${htmlClass} ${loadingClass}`;
|
|
4979
|
+
const { htmlClass, loadingClass, skin } = this.config;
|
|
4980
|
+
const classes = `${htmlClass} ${loadingClass}${skin ? ` pa-skinned ${skin}` : ""}`;
|
|
4783
4981
|
const dataAttrs = [];
|
|
4784
4982
|
if (this.metadata) {
|
|
4785
4983
|
dataAttrs.push(`data-pa-course-id="${this.escapeAttr(this.metadata.courseId)}"`);
|
|
@@ -4788,6 +4986,9 @@ ${pluginJs}
|
|
|
4788
4986
|
dataAttrs.push(`data-pa-title="${this.escapeAttr(this.metadata.title)}"`);
|
|
4789
4987
|
}
|
|
4790
4988
|
}
|
|
4989
|
+
if (skin) {
|
|
4990
|
+
dataAttrs.push(`data-pa-skin="${this.escapeAttr(skin)}"`);
|
|
4991
|
+
}
|
|
4791
4992
|
const dataAttrString = dataAttrs.length > 0 ? " " + dataAttrs.join(" ") : "";
|
|
4792
4993
|
const htmlTagPattern = /<html([^>]*)>/i;
|
|
4793
4994
|
const match = html.match(htmlTagPattern);
|
|
@@ -4866,6 +5067,26 @@ ${loader}`);
|
|
|
4866
5067
|
${loader}`);
|
|
4867
5068
|
}
|
|
4868
5069
|
return html.replace(/<\/body>/i, `${loader}
|
|
5070
|
+
</body>`);
|
|
5071
|
+
}
|
|
5072
|
+
/**
|
|
5073
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
5074
|
+
*/
|
|
5075
|
+
injectSkinCss(html) {
|
|
5076
|
+
const options = buildSkinCssOptions(this.config);
|
|
5077
|
+
if (!options) return html;
|
|
5078
|
+
const loader = generateSkinCssLoader(options);
|
|
5079
|
+
return html.replace(/<\/head>/i, `${loader}
|
|
5080
|
+
</head>`);
|
|
5081
|
+
}
|
|
5082
|
+
/**
|
|
5083
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
5084
|
+
*/
|
|
5085
|
+
injectSkinJs(html) {
|
|
5086
|
+
const options = buildSkinJsOptions(this.config);
|
|
5087
|
+
if (!options) return html;
|
|
5088
|
+
const loader = generateSkinJsLoader(options);
|
|
5089
|
+
return html.replace(/<\/body>/i, `${loader}
|
|
4869
5090
|
</body>`);
|
|
4870
5091
|
}
|
|
4871
5092
|
};
|
|
@@ -4909,6 +5130,10 @@ var StorylineHtmlInjector = class {
|
|
|
4909
5130
|
if (this.config.jsAfter.enabled) {
|
|
4910
5131
|
result = this.injectJsAfter(result);
|
|
4911
5132
|
}
|
|
5133
|
+
if (this.config.skin) {
|
|
5134
|
+
result = this.injectSkinCss(result);
|
|
5135
|
+
result = this.injectSkinJs(result);
|
|
5136
|
+
}
|
|
4912
5137
|
if (this.pluginAssets) {
|
|
4913
5138
|
result = this.injectPluginAssets(result);
|
|
4914
5139
|
}
|
|
@@ -4953,8 +5178,8 @@ ${pluginJs}
|
|
|
4953
5178
|
* Also adds data attributes for course metadata
|
|
4954
5179
|
*/
|
|
4955
5180
|
addHtmlAttributes(html) {
|
|
4956
|
-
const { htmlClass, loadingClass } = this.config;
|
|
4957
|
-
const classes = `${htmlClass} ${loadingClass}`;
|
|
5181
|
+
const { htmlClass, loadingClass, skin } = this.config;
|
|
5182
|
+
const classes = `${htmlClass} ${loadingClass}${skin ? ` pa-skinned ${skin}` : ""}`;
|
|
4958
5183
|
const dataAttrs = [];
|
|
4959
5184
|
if (this.metadata) {
|
|
4960
5185
|
dataAttrs.push(`data-pa-course-id="${this.escapeAttr(this.metadata.courseId)}"`);
|
|
@@ -4964,6 +5189,9 @@ ${pluginJs}
|
|
|
4964
5189
|
dataAttrs.push(`data-pa-title="${this.escapeAttr(this.metadata.title)}"`);
|
|
4965
5190
|
}
|
|
4966
5191
|
}
|
|
5192
|
+
if (skin) {
|
|
5193
|
+
dataAttrs.push(`data-pa-skin="${this.escapeAttr(skin)}"`);
|
|
5194
|
+
}
|
|
4967
5195
|
const dataAttrString = dataAttrs.length > 0 ? " " + dataAttrs.join(" ") : "";
|
|
4968
5196
|
const htmlTagPattern = /<html([^>]*)>/i;
|
|
4969
5197
|
const match = html.match(htmlTagPattern);
|
|
@@ -5041,6 +5269,26 @@ ${loader}`);
|
|
|
5041
5269
|
const options = buildJsAfterOptions(this.config);
|
|
5042
5270
|
const loader = generateJsAfterLoader(options);
|
|
5043
5271
|
return html.replace(/<\/body>/i, `${loader}
|
|
5272
|
+
</body>`);
|
|
5273
|
+
}
|
|
5274
|
+
/**
|
|
5275
|
+
* Inject Skin CSS loader after CSS After (before </head>)
|
|
5276
|
+
*/
|
|
5277
|
+
injectSkinCss(html) {
|
|
5278
|
+
const options = buildSkinCssOptions(this.config);
|
|
5279
|
+
if (!options) return html;
|
|
5280
|
+
const loader = generateSkinCssLoader(options);
|
|
5281
|
+
return html.replace(/<\/head>/i, `${loader}
|
|
5282
|
+
</head>`);
|
|
5283
|
+
}
|
|
5284
|
+
/**
|
|
5285
|
+
* Inject Skin JS loader after JS After (before </body>)
|
|
5286
|
+
*/
|
|
5287
|
+
injectSkinJs(html) {
|
|
5288
|
+
const options = buildSkinJsOptions(this.config);
|
|
5289
|
+
if (!options) return html;
|
|
5290
|
+
const loader = generateSkinJsLoader(options);
|
|
5291
|
+
return html.replace(/<\/body>/i, `${loader}
|
|
5044
5292
|
</body>`);
|
|
5045
5293
|
}
|
|
5046
5294
|
};
|
|
@@ -5091,7 +5339,9 @@ var ManifestUpdater = class {
|
|
|
5091
5339
|
paths.cssBefore,
|
|
5092
5340
|
paths.cssAfter,
|
|
5093
5341
|
paths.jsBefore,
|
|
5094
|
-
paths.jsAfter
|
|
5342
|
+
paths.jsAfter,
|
|
5343
|
+
paths.skinCss,
|
|
5344
|
+
paths.skinJs
|
|
5095
5345
|
].filter(Boolean);
|
|
5096
5346
|
if (filesToAdd.length === 0) {
|
|
5097
5347
|
return [];
|
|
@@ -5881,6 +6131,20 @@ var Patcher = class {
|
|
|
5881
6131
|
})
|
|
5882
6132
|
);
|
|
5883
6133
|
}
|
|
6134
|
+
if (this.config.skin) {
|
|
6135
|
+
const skinCssUrl = `${remoteDomain}/skin/${this.config.skin}.css`;
|
|
6136
|
+
fetchPromises.push(
|
|
6137
|
+
this.fetchFile(skinCssUrl).then((content) => {
|
|
6138
|
+
fetched.skinCss = content;
|
|
6139
|
+
})
|
|
6140
|
+
);
|
|
6141
|
+
const skinJsUrl = `${remoteDomain}/skin/${this.config.skin}.js`;
|
|
6142
|
+
fetchPromises.push(
|
|
6143
|
+
this.fetchFile(skinJsUrl).then((content) => {
|
|
6144
|
+
fetched.skinJs = content;
|
|
6145
|
+
})
|
|
6146
|
+
);
|
|
6147
|
+
}
|
|
5884
6148
|
await Promise.all(fetchPromises);
|
|
5885
6149
|
return fetched;
|
|
5886
6150
|
}
|
|
@@ -5964,6 +6228,16 @@ var Patcher = class {
|
|
|
5964
6228
|
console.log(`[Patcher] Wrote generated UUID to manifest identifier`);
|
|
5965
6229
|
}
|
|
5966
6230
|
}
|
|
6231
|
+
const effectiveSkin = options.skin || this.config.skin;
|
|
6232
|
+
if (options.skin && options.skin !== this.config.skin) {
|
|
6233
|
+
this.config.skin = options.skin;
|
|
6234
|
+
this.riseHtmlInjector = new HtmlInjector(this.config);
|
|
6235
|
+
this.storylineHtmlInjector = new StorylineHtmlInjector(this.config);
|
|
6236
|
+
console.log(`[Patcher] Using per-call skin override: ${options.skin}`);
|
|
6237
|
+
}
|
|
6238
|
+
if (effectiveSkin) {
|
|
6239
|
+
console.log(`[Patcher] Skin: ${effectiveSkin}`);
|
|
6240
|
+
}
|
|
5967
6241
|
const htmlInjector = this.getHtmlInjector(toolInfo.tool);
|
|
5968
6242
|
htmlInjector.setMetadata(metadata);
|
|
5969
6243
|
let fetchedFallbacks = {};
|
|
@@ -6092,7 +6366,11 @@ var Patcher = class {
|
|
|
6092
6366
|
buildManifestPaths(addedFiles) {
|
|
6093
6367
|
const paths = {};
|
|
6094
6368
|
for (const filePath of addedFiles) {
|
|
6095
|
-
if (filePath.endsWith(this.config.
|
|
6369
|
+
if (this.config.skin && filePath.endsWith(`skin/${this.config.skin}.css`)) {
|
|
6370
|
+
paths.skinCss = filePath;
|
|
6371
|
+
} else if (this.config.skin && filePath.endsWith(`skin/${this.config.skin}.js`)) {
|
|
6372
|
+
paths.skinJs = filePath;
|
|
6373
|
+
} else if (filePath.endsWith(this.config.cssBefore.filename)) {
|
|
6096
6374
|
paths.cssBefore = filePath;
|
|
6097
6375
|
} else if (filePath.endsWith(this.config.cssAfter.filename)) {
|
|
6098
6376
|
paths.cssAfter = filePath;
|
|
@@ -6176,6 +6454,22 @@ var Patcher = class {
|
|
|
6176
6454
|
added.push(path);
|
|
6177
6455
|
if (fetched.jsAfter) console.log(`[Patcher] Using fetched content for ${path}`);
|
|
6178
6456
|
}
|
|
6457
|
+
if (this.config.skin) {
|
|
6458
|
+
const skinCssPath = `${basePath}skin/${this.config.skin}.css`;
|
|
6459
|
+
const skinCssContent = fetched.skinCss ?? `/* PA-Patcher: Skin CSS (${this.config.skin}) */
|
|
6460
|
+
`;
|
|
6461
|
+
zip.addFile(skinCssPath, Buffer.from(skinCssContent, "utf-8"));
|
|
6462
|
+
added.push(skinCssPath);
|
|
6463
|
+
if (fetched.skinCss) console.log(`[Patcher] Using fetched skin CSS for ${skinCssPath}`);
|
|
6464
|
+
else console.log(`[Patcher] Added placeholder skin CSS: ${skinCssPath}`);
|
|
6465
|
+
const skinJsPath = `${basePath}skin/${this.config.skin}.js`;
|
|
6466
|
+
const skinJsContent = fetched.skinJs ?? `// PA-Patcher: Skin JS (${this.config.skin})
|
|
6467
|
+
`;
|
|
6468
|
+
zip.addFile(skinJsPath, Buffer.from(skinJsContent, "utf-8"));
|
|
6469
|
+
added.push(skinJsPath);
|
|
6470
|
+
if (fetched.skinJs) console.log(`[Patcher] Using fetched skin JS for ${skinJsPath}`);
|
|
6471
|
+
else console.log(`[Patcher] Added placeholder skin JS: ${skinJsPath}`);
|
|
6472
|
+
}
|
|
6179
6473
|
return added;
|
|
6180
6474
|
}
|
|
6181
6475
|
/**
|
|
@@ -6190,9 +6484,9 @@ var Patcher = class {
|
|
|
6190
6484
|
* @param buffer - Input ZIP file as Buffer
|
|
6191
6485
|
* @returns Patched ZIP file as Buffer
|
|
6192
6486
|
*/
|
|
6193
|
-
async patchBuffer(buffer) {
|
|
6487
|
+
async patchBuffer(buffer, options) {
|
|
6194
6488
|
console.log(`[Patcher] patchBuffer called with ${buffer.length} bytes`);
|
|
6195
|
-
const { buffer: patchedBuffer, result } = await this.patch(buffer);
|
|
6489
|
+
const { buffer: patchedBuffer, result } = await this.patch(buffer, options);
|
|
6196
6490
|
console.log(`[Patcher] Patch result:`, JSON.stringify(result, null, 2));
|
|
6197
6491
|
console.log(`[Patcher] Returning ${patchedBuffer.length} bytes`);
|
|
6198
6492
|
return patchedBuffer;
|