diff --git a/pxtblocks/fields/field_animation.ts b/pxtblocks/fields/field_animation.ts index c554c8186f7..d6c804b9830 100644 --- a/pxtblocks/fields/field_animation.ts +++ b/pxtblocks/fields/field_animation.ts @@ -11,6 +11,8 @@ namespace pxtblockly { filter?: string; lightMode: boolean; + + taggedTemplate?: string; } export interface ParsedFieldAnimationOptions { @@ -19,6 +21,8 @@ namespace pxtblockly { disableResize: boolean; filter?: string; lightMode: boolean; + + taggedTemplate?: string; } // 32 is specifically chosen so that we can scale the images for the default @@ -71,7 +75,7 @@ namespace pxtblockly { const existing = pxt.lookupProjectAssetByTSReference(text, project); if (existing) return existing; - const frames = parseImageArrayString(text); + const frames = parseImageArrayString(text, this.params.taggedTemplate); if (frames && frames.length) { const id = this.sourceBlock_.id; @@ -115,7 +119,7 @@ namespace pxtblockly { if (this.isTemporaryAsset()) { return "[" + this.asset.frames.map(frame => - pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(frame), pxt.editor.FileType.TypeScript) + pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(frame), pxt.editor.FileType.TypeScript, this.params.taggedTemplate) ).join(",") + "]" } @@ -236,6 +240,7 @@ namespace pxtblockly { parsed.initWidth = withDefault(opts.initWidth, parsed.initWidth); parsed.initHeight = withDefault(opts.initHeight, parsed.initHeight); + parsed.taggedTemplate = opts.taggedTemplate; return parsed; @@ -248,10 +253,10 @@ namespace pxtblockly { } } - function parseImageArrayString(str: string): pxt.sprite.BitmapData[] { + function parseImageArrayString(str: string, templateLiteral?: string): pxt.sprite.BitmapData[] { if (str.indexOf("[") === -1) return null; str = str.replace(/[\[\]]/mg, ""); - return str.split(",").map(s => pxt.sprite.imageLiteralToBitmap(s).data()).filter(b => b.height && b.width); + return str.split(",").map(s => pxt.sprite.imageLiteralToBitmap(s, templateLiteral).data()).filter(b => b.height && b.width); } function isNumberType(type: string) { diff --git a/pxtblocks/fields/field_sprite.ts b/pxtblocks/fields/field_sprite.ts index b063d1b9328..5453e4c69a7 100644 --- a/pxtblocks/fields/field_sprite.ts +++ b/pxtblocks/fields/field_sprite.ts @@ -17,6 +17,8 @@ namespace pxtblockly { filter?: string; lightMode: boolean; + + taggedTemplate?: string; } interface ParsedSpriteEditorOptions { @@ -26,6 +28,7 @@ namespace pxtblockly { disableResize: boolean; filter?: string; lightMode: boolean; + taggedTemplate?: string; } export class FieldSpriteEditor extends FieldAssetEditor { @@ -45,7 +48,7 @@ namespace pxtblockly { return project.lookupAsset(pxt.AssetType.Image, this.getBlockData()); } - const bmp = text ? pxt.sprite.imageLiteralToBitmap(text) : new pxt.sprite.Bitmap(this.params.initWidth, this.params.initHeight); + const bmp = text ? pxt.sprite.imageLiteralToBitmap(text, this.params.taggedTemplate) : new pxt.sprite.Bitmap(this.params.initWidth, this.params.initHeight); if (!bmp) { this.isGreyBlock = true; @@ -72,7 +75,7 @@ namespace pxtblockly { if (this.asset && !this.isTemporaryAsset()) { return pxt.getTSReferenceForAsset(this.asset); } - return pxt.sprite.bitmapToImageLiteral(this.asset && pxt.sprite.Bitmap.fromData((this.asset as pxt.ProjectImage).bitmap), pxt.editor.FileType.TypeScript); + return pxt.sprite.bitmapToImageLiteral(this.asset && pxt.sprite.Bitmap.fromData((this.asset as pxt.ProjectImage).bitmap), pxt.editor.FileType.TypeScript, this.params.taggedTemplate); } protected parseFieldOptions(opts: FieldSpriteEditorOptions): ParsedSpriteEditorOptions { @@ -139,6 +142,8 @@ namespace pxtblockly { parsed.initWidth = withDefault(opts.initWidth, parsed.initWidth); parsed.initHeight = withDefault(opts.initHeight, parsed.initHeight); + parsed.taggedTemplate = opts.taggedTemplate; + return parsed; function withDefault(raw: string, def: number) { diff --git a/pxtlib/package.ts b/pxtlib/package.ts index 61eacbb7353..0b3639e5b17 100644 --- a/pxtlib/package.ts +++ b/pxtlib/package.ts @@ -996,7 +996,7 @@ namespace pxt { return r; } - protected patchAppTargetPalette() { + patchAppTargetPalette() { if (this.config.palette && appTarget.runtime) { appTarget.runtime.palette = U.clone(this.config.palette); if (this.config.paletteNames) appTarget.runtime.paletteNames = this.config.paletteNames; @@ -1294,6 +1294,10 @@ namespace pxt { const functionOpts = pxt.appTarget.runtime && pxt.appTarget.runtime.functionsOptions; opts.allowedArgumentTypes = functionOpts && functionOpts.extraFunctionEditorTypes && functionOpts.extraFunctionEditorTypes.map(info => info.typeName).concat("number", "boolean", "string"); + for (const dep of this.sortedDeps()) { + dep.patchAppTargetPalette(); + } + this.patchAppTargetPalette(); return opts; } diff --git a/pxtlib/spriteutils.ts b/pxtlib/spriteutils.ts index a9c54d897bb..0be7956ce07 100644 --- a/pxtlib/spriteutils.ts +++ b/pxtlib/spriteutils.ts @@ -601,11 +601,12 @@ namespace pxt.sprite { return result; } - export function imageLiteralToBitmap(text: string): Bitmap { + export function imageLiteralToBitmap(text: string, templateLiteral = "img"): Bitmap { // Strip the tagged template string business and the whitespace. We don't have to exhaustively // replace encoded characters because the compiler will catch any disallowed characters and throw // an error before the decompilation happens. 96 is backtick and 9 is tab text = text.replace(/[ `]|(?:`)|(?: )|(?:img)/g, "").trim(); + text = text.replaceAll(templateLiteral, ""); text = text.replace(/^["`\(\)]*/, '').replace(/["`\(\)]*$/, ''); text = text.replace(/ /g, "\n"); @@ -733,14 +734,14 @@ namespace pxt.sprite { pxt.sprite.trimTilemapTileset(result); } - function imageLiteralPrologue(fileType: "typescript" | "python"): string { + function imageLiteralPrologue(fileType: "typescript" | "python", templateLiteral = "img"): string { let res = ''; switch (fileType) { case "python": - res = "img(\"\"\""; + res = `${templateLiteral}("""`; break; default: - res = "img`"; + res = `${templateLiteral}\``; break; } return res; @@ -776,10 +777,10 @@ namespace pxt.sprite { return res; } - export function bitmapToImageLiteral(bitmap: Bitmap, fileType: "typescript" | "python"): string { + export function bitmapToImageLiteral(bitmap: Bitmap, fileType: "typescript" | "python", templateLiteral = "img"): string { if (!bitmap || bitmap.height === 0 || bitmap.width === 0) return ""; - let res = imageLiteralPrologue(fileType); + let res = imageLiteralPrologue(fileType, templateLiteral); if (bitmap) { const paddingBetweenPixels = (bitmap.width * bitmap.height > 300) ? "" : " "; diff --git a/pxtlib/tsconfig.json b/pxtlib/tsconfig.json index 3e8468af3af..25e5cc86b6b 100644 --- a/pxtlib/tsconfig.json +++ b/pxtlib/tsconfig.json @@ -13,7 +13,8 @@ "dom.iterable", "scripthost", "es2017", - "ES2018.Promise" + "ES2018.Promise", + "ES2021.String" ], "types": [ "highlight.js",