Skip to content

Commit 4a33d19

Browse files
authored
Merge pull request #480 from DogeisCut/extension-dogeiscutYetAnotherStringExtension
YASE: Allow returning in string builders.
2 parents 2928360 + 4a88f30 commit 4a33d19

1 file changed

Lines changed: 146 additions & 22 deletions

File tree

static/extensions/DogeisCut/YetAnotherStringExtension.js

Lines changed: 146 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,115 @@
1010
throw new Error('\'Yet Another String Extension\' must run unsandboxed!');
1111
}
1212

13+
if (Scratch.gui) {
14+
Scratch.gui.getBlockly().then(ScratchBlocks => {
15+
function recursiveRender(block) {
16+
if (!block) return;
17+
while (block.parentBlock_ !== null) {
18+
if (block.parentBlock_ !== null) {
19+
block.render(false);
20+
block = block.parentBlock_;
21+
}
22+
}
23+
block.render(false);
24+
}
25+
ScratchBlocks.FieldCustom.registerInput(
26+
"multiline",
27+
(() => {
28+
const container = document.createElement('textarea');
29+
container.style.background = "#fff";
30+
container.style.color = "#404040";
31+
container.style.minWidth = "29px";
32+
container.style.minHeight = "27px";
33+
container.style.margin = "5px 0";
34+
container.style.padding = "5px";
35+
container.style.borderRadius = '8px';
36+
container.style.display = 'block';
37+
container.style.resize = "both";
38+
container.style.overflow = "auto";
39+
container.style.boxSizing = "border-box";
40+
41+
document.body.appendChild(container);
42+
43+
return container;
44+
})(),
45+
(field, input) => {
46+
if (!input) return;
47+
48+
let value;
49+
try {
50+
value = JSON.parse(field.getValue());
51+
} catch {
52+
value = field.getValue();
53+
}
54+
let str = "";
55+
let width = 120;
56+
let height = 80;
57+
58+
if (typeof value === "string") {
59+
str = value;
60+
} else if (value && typeof value === "object") {
61+
str = value['string'] || "";
62+
if (Array.isArray(value['size']) && value['size'].length === 2) {
63+
width = value['size'][0] || 120;
64+
height = value['size'][1] || 80;
65+
}
66+
}
67+
68+
input.value = str;
69+
input.style.width = width + "px";
70+
input.style.height = height + "px";
71+
field.setValue(JSON.stringify({ 'string': str, 'size': [width, height] }));
72+
let isPaused = false;
73+
input.addEventListener("keydown", function(event) {
74+
if (event.key === "Tab") {
75+
event.preventDefault();
76+
77+
let textarea = this;
78+
let cursorStart = textarea.selectionStart;
79+
let cursorEnd = textarea.selectionEnd;
80+
81+
textarea.value =
82+
textarea.value.substring(0, cursorStart) +
83+
"\t" +
84+
textarea.value.substring(cursorEnd);
85+
86+
textarea.selectionStart = textarea.selectionEnd = cursorStart + 1;
87+
}
88+
});
89+
const observer = new ResizeObserver(entries => {
90+
if (isPaused) return;
91+
for (const entry of entries) {
92+
isPaused = true;
93+
let { width, height } = entry.contentRect;
94+
//width = Math.max(100, width);
95+
//height = Math.max(32, height);
96+
97+
const foreignObject = input.parentNode;
98+
foreignObject.setAttribute("width", width);
99+
foreignObject.setAttribute("height", height);
100+
101+
field.size_.width = width + 15;
102+
field.size_.height = height + 25;
103+
input.style.border = `solid 1px ${field.sourceBlock_?.colourTertiary_}`;
104+
recursiveRender(field.sourceBlock_);
105+
requestAnimationFrame(() => { isPaused = false });
106+
field.setValue(JSON.stringify({ 'string': input.value, 'size': [width, height] }));
107+
}
108+
});
109+
110+
observer.observe(input);
111+
112+
input.addEventListener("change", () => {
113+
field.setValue(JSON.stringify({ 'string': input.value, 'size': [parseFloat(input.style.width), parseFloat(input.style.height)] }));
114+
})
115+
},
116+
(block) => { },
117+
(block) => { }
118+
);
119+
});
120+
}
121+
13122
class YetAnotherStringExtension {
14123
constructor() {
15124
vm.runtime.registerCompiledExtensionBlocks('dogeiscutyetanotherstringextension', this.getCompileInfo());
@@ -144,35 +253,46 @@
144253
},
145254
extensions: ["colours_operators"],
146255
},
256+
'---',
257+
/*UNFINISHED {
258+
opcode: 'multiline',
259+
text: '[STRING]',
260+
blockType: Scratch.BlockType.REPORTER,
261+
blockShape: Scratch.BlockShape.SQUARE,
262+
disableMonitor: true,
263+
arguments: {
264+
STRING: {
265+
type: Scratch.ArgumentType.CUSTOM,
266+
id: "multiline",
267+
defaultValue: "Multiple\nLines!\nYay!"
268+
}
269+
}
270+
}*/
147271
]
148272
}
149273
}
150274

151275
getCompileInfo() {
152276
return {
153277
ir: {
154-
builder: (generator, block) => ({
155-
kind: 'input',
156-
substack: generator.descendSubstack(block, 'SUBSTACK')
157-
}),
278+
builder: (generator, block) => {
279+
generator.script.yields = true
280+
return {
281+
kind: 'input',
282+
substack: generator.descendSubstack(block, 'SUBSTACK')
283+
}
284+
},
158285
},
159286
js: {
160287
builder: (node, compiler, imports) => {
161288
const originalSource = compiler.source;
162289

163-
compiler.source = '(yield* (function*() {';
164-
compiler.source += ' const __inner = (yield* (function*() {';
165-
compiler.source += ` thread._dogeiscutyetanotherstringextensionBuilderIndex ??= [];`;
166-
compiler.source += ` thread._dogeiscutyetanotherstringextensionBuilderIndex.push('');`;
290+
compiler.source = 'Scratch.Cast.toString(yield* (function*() {';
291+
compiler.source += ` thread._dogeiscutyetanotherstringextensionBuilderIndex ??= [];`;
292+
compiler.source += ` thread._dogeiscutyetanotherstringextensionBuilderIndex.push('');`;
167293
compiler.descendStack(node.substack, new imports.Frame(false, undefined, true));
168-
compiler.source += ` return new runtime.ext_dogeiscutyetanotherstringextension.BuilderReturnValue(thread._dogeiscutyetanotherstringextensionBuilderIndex.pop());`;
169-
compiler.source += ' })());';
170-
compiler.source += ' const __result = __inner;';
171-
compiler.source += ' if (!(__result instanceof runtime.ext_dogeiscutyetanotherstringextension.BuilderReturnValue)) {';
172-
compiler.source += ' throw "Return statements are not supported in builders.";';
173-
compiler.source += ' }';
174-
compiler.source += ' return __result.value;';
175-
compiler.source += '})())';
294+
compiler.source += ` return thread._dogeiscutyetanotherstringextensionBuilderIndex.pop();`;
295+
compiler.source += '})());';
176296

177297
const stackSource = compiler.source;
178298
compiler.source = originalSource;
@@ -182,12 +302,6 @@
182302
};
183303
}
184304

185-
BuilderReturnValue = class {
186-
constructor(value) {
187-
this.value = value
188-
}
189-
}
190-
191305
currentString({}, util) {
192306
if (util.thread._dogeiscutyetanotherstringextensionBuilderIndex && util.thread._dogeiscutyetanotherstringextensionBuilderIndex.length > 0) {
193307
return util.thread._dogeiscutyetanotherstringextensionBuilderIndex[util.thread._dogeiscutyetanotherstringextensionBuilderIndex.length-1]
@@ -297,6 +411,16 @@
297411
}
298412
return STRING.repeat(Math.round(INT));
299413
}
414+
415+
multiline({ STRING }) {
416+
let value;
417+
try {
418+
value = JSON.parse(STRING)['string'];
419+
} catch {
420+
throw 'Failed to get multiline string, this should never happen!'
421+
}
422+
return value;
423+
}
300424

301425
}
302426

0 commit comments

Comments
 (0)