Makes it so language `scratch` will be parsed into Scratch blocks
// ==UserScript==
// @name Scratchblocks for github
// @namespace http://tampermonkey.net/
// @version 2024-03-19
// @description Makes it so language `scratch` will be parsed into Scratch blocks
// @author pooiod7
// @match https://github.com/*
// @icon https://static-00.iconduck.com/assets.00/scratch-icon-367x512-7uovo7mx.png
// @grant none
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
//// svelte supported version of scratchblocks
/// https://scratchblocks.github.io/
// scroll to the bottom to get past the lib
/**
* scratchblocks v3.6.3
* https://scratchblocks.github.io/
* Render scratchblocks code to SVG images.
*
* Copyright 2013–2023, Tim Radvan
*/// @license MIT
let scratchblocks = {};
scratchblocks.init = () => {
(function () {
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
enumerableOnly && (symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
})), keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = null != arguments[i] ? arguments[i] : {};
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
_defineProperty(target, key, source[key]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _createForOfIteratorHelper(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
var F = function () { };
return {
s: F,
n: function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
},
e: function (e) {
throw e;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var normalCompletion = true,
didErr = false,
err;
return {
s: function () {
it = it.call(o);
},
n: function () {
var step = it.next();
normalCompletion = step.done;
return step;
},
e: function (e) {
didErr = true;
err = e;
},
f: function () {
try {
if (!normalCompletion && it.return != null) it.return();
} finally {
if (didErr) throw err;
}
}
};
}
function _toPrimitive(input, hint) {
if (typeof input !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (typeof res !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return typeof key === "symbol" ? key : String(key);
}
/*
When a new extension is added:
1) Add it to extensions object
2) Add its blocks to commands.js
3) Add icon width/height to scratch3/blocks.js IconView
4) Add icon to scratch3/style.js
*/
// Moved extensions: key is scratch3, value is scratch2
var movedExtensions = {
pen: "pen",
video: "sensing",
music: "sound"
};
var extensions = _objectSpread2(_objectSpread2({}, movedExtensions), {}, {
tts: "tts",
translate: "translate",
microbit: "microbit",
wedo: "wedo",
makeymakey: "makeymakey",
ev3: "ev3",
boost: "boost",
gdxfor: "gdxfor"
});
// Alias extensions: unlike movedExtensions, this is handled for both scratch2 and scratch3.
// Key is alias, value is real extension name
var aliasExtensions = {
wedo2: "wedo",
text2speech: "tts"
};
var scratchCommands = [{
id: "MOTION_MOVESTEPS",
selector: "forward:",
spec: "move %1 steps",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_TURNRIGHT",
selector: "turnRight:",
spec: "turn @turnRight %1 degrees",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_TURNLEFT",
selector: "turnLeft:",
spec: "turn @turnLeft %1 degrees",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_POINTINDIRECTION",
selector: "heading:",
spec: "point in direction %1",
inputs: ["%d.direction"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_POINTTOWARDS",
selector: "pointTowards:",
spec: "point towards %1",
inputs: ["%m.spriteOrMouse"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_GOTOXY",
selector: "gotoX:y:",
spec: "go to x:%1 y:%2",
inputs: ["%n", "%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_GOTO",
selector: "gotoSpriteOrMouse:",
spec: "go to %1",
inputs: ["%m.location"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_GLIDESECSTOXY",
selector: "glideSecs:toX:y:elapsed:from:",
spec: "glide %1 secs to x:%2 y:%3",
inputs: ["%n", "%n", "%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_GLIDETO",
spec: "glide %1 secs to %2",
inputs: ["%n", "%m.location"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_CHANGEXBY",
selector: "changeXposBy:",
spec: "change x by %1",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_SETX",
selector: "xpos:",
spec: "set x to %1",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_CHANGEYBY",
selector: "changeYposBy:",
spec: "change y by %1",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_SETY",
selector: "ypos:",
spec: "set y to %1",
inputs: ["%n"],
shape: "stack",
category: "motion"
}, {
id: "MOTION_SETROTATIONSTYLE",
selector: "setRotationStyle",
spec: "set rotation style %1",
inputs: ["%m.rotationStyle"],
shape: "stack",
category: "motion"
}, {
id: "LOOKS_SAYFORSECS",
selector: "say:duration:elapsed:from:",
spec: "say %1 for %2 seconds",
inputs: ["%s", "%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SAY",
selector: "say:",
spec: "say %1",
inputs: ["%s"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_THINKFORSECS",
selector: "think:duration:elapsed:from:",
spec: "think %1 for %2 seconds",
inputs: ["%s", "%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_THINK",
selector: "think:",
spec: "think %1",
inputs: ["%s"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SHOW",
selector: "show",
spec: "show",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_HIDE",
selector: "hide",
spec: "hide",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SWITCHCOSTUMETO",
selector: "lookLike:",
spec: "switch costume to %1",
inputs: ["%m.costume"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_NEXTCOSTUME",
selector: "nextCostume",
spec: "next costume",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_NEXTBACKDROP_BLOCK",
selector: "nextScene",
spec: "next backdrop",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SWITCHBACKDROPTO",
selector: "startScene",
spec: "switch backdrop to %1",
inputs: ["%m.backdrop"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SWITCHBACKDROPTOANDWAIT",
selector: "startSceneAndWait",
spec: "switch backdrop to %1 and wait",
inputs: ["%m.backdrop"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_CHANGEEFFECTBY",
selector: "changeGraphicEffect:by:",
spec: "change %1 effect by %2",
inputs: ["%m.effect", "%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SETEFFECTTO",
selector: "setGraphicEffect:to:",
spec: "set %1 effect to %2",
inputs: ["%m.effect", "%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_CLEARGRAPHICEFFECTS",
selector: "filterReset",
spec: "clear graphic effects",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_CHANGESIZEBY",
selector: "changeSizeBy:",
spec: "change size by %1",
inputs: ["%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_SETSIZETO",
selector: "setSizeTo:",
spec: "set size to %1%",
inputs: ["%n"],
shape: "stack",
category: "looks"
}, {
selector: "comeToFront",
spec: "go to front",
inputs: [],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_GOTOFRONTBACK",
spec: "go to %1 layer",
inputs: ["%m"],
shape: "stack",
category: "looks"
}, {
selector: "goBackByLayers:",
spec: "go back %1 layers",
inputs: ["%n"],
shape: "stack",
category: "looks"
}, {
id: "LOOKS_GOFORWARDBACKWARDLAYERS",
spec: "go %1 %2 layers",
inputs: ["%m", "%n"],
shape: "stack",
category: "looks"
}, {
id: "SOUND_PLAY",
selector: "playSound:",
spec: "start sound %1",
inputs: ["%m.sound"],
shape: "stack",
category: "sound"
}, {
id: "SOUND_CHANGEEFFECTBY",
spec: "change %1 effect by %2",
inputs: ["%m", "%n"],
shape: "stack",
category: "sound"
}, {
id: "SOUND_SETEFFECTO",
// sic
spec: "set %1 effect to %2",
inputs: ["%m", "%n"],
shape: "stack",
category: "sound"
}, {
id: "SOUND_CLEAREFFECTS",
spec: "clear sound effects",
inputs: [],
shape: "stack",
category: "sound"
}, {
id: "SOUND_PLAYUNTILDONE",
selector: "doPlaySoundAndWait",
spec: "play sound %1 until done",
inputs: ["%m.sound"],
shape: "stack",
category: "sound"
}, {
id: "SOUND_STOPALLSOUNDS",
selector: "stopAllSounds",
spec: "stop all sounds",
inputs: [],
shape: "stack",
category: "sound"
}, {
id: "music.playDrumForBeats",
selector: "playDrum",
spec: "play drum %1 for %2 beats",
inputs: ["%d.drum", "%n"],
shape: "stack",
category: "music"
}, {
id: "music.restForBeats",
selector: "rest:elapsed:from:",
spec: "rest for %1 beats",
inputs: ["%n"],
shape: "stack",
category: "music"
}, {
id: "music.playNoteForBeats",
selector: "noteOn:duration:elapsed:from:",
spec: "play note %1 for %2 beats",
inputs: ["%d.note", "%n"],
shape: "stack",
category: "music"
}, {
id: "music.setInstrument",
selector: "instrument:",
spec: "set instrument to %1",
inputs: ["%d.instrument"],
shape: "stack",
category: "music"
}, {
id: "SOUND_CHANGEVOLUMEBY",
selector: "changeVolumeBy:",
spec: "change volume by %1",
inputs: ["%n"],
shape: "stack",
category: "sound"
}, {
id: "SOUND_SETVOLUMETO",
selector: "setVolumeTo:",
spec: "set volume to %1%",
inputs: ["%n"],
shape: "stack",
category: "sound"
}, {
id: "music.changeTempo",
selector: "changeTempoBy:",
spec: "change tempo by %1",
inputs: ["%n"],
shape: "stack",
category: "music"
}, {
selector: "setTempoTo:",
spec: "set tempo to %1 bpm",
inputs: ["%n"],
shape: "stack",
category: "sound"
}, {
id: "music.setTempo",
selector: "setTempoTo:",
spec: "set tempo to %1",
inputs: ["%n"],
shape: "stack",
category: "music"
}, {
id: "pen.clear",
selector: "clearPenTrails",
spec: "erase all",
inputs: [],
shape: "stack",
category: "pen"
}, {
id: "pen.stamp",
selector: "stampCostume",
spec: "stamp",
inputs: [],
shape: "stack",
category: "pen"
}, {
id: "pen.penDown",
selector: "putPenDown",
spec: "pen down",
inputs: [],
shape: "stack",
category: "pen"
}, {
id: "pen.penUp",
selector: "putPenUp",
spec: "pen up",
inputs: [],
shape: "stack",
category: "pen"
}, {
id: "pen.setColor",
selector: "penColor:",
spec: "set pen color to %1",
inputs: ["%c"],
shape: "stack",
category: "pen"
}, {
id: "pen.changeHue",
selector: "changePenHueBy:",
spec: "change pen color by %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.setColorParam",
spec: "set pen %1 to %2",
inputs: ["%m.color", "%c"],
shape: "stack",
category: "pen"
}, {
id: "pen.changeColorParam",
spec: "change pen %1 by %2",
inputs: ["%m.color", "%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.setHue",
selector: "setPenHueTo:",
spec: "set pen color to %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.changeShade",
selector: "changePenShadeBy:",
spec: "change pen shade by %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.setShade",
selector: "setPenShadeTo:",
spec: "set pen shade to %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.changeSize",
selector: "changePenSizeBy:",
spec: "change pen size by %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "pen.setSize",
selector: "penSize:",
spec: "set pen size to %1",
inputs: ["%n"],
shape: "stack",
category: "pen"
}, {
id: "EVENT_WHENFLAGCLICKED",
selector: "whenGreenFlag",
spec: "when @greenFlag clicked",
inputs: [],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENKEYPRESSED",
selector: "whenKeyPressed",
spec: "when %1 key pressed",
inputs: ["%m.key"],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENTHISSPRITECLICKED",
selector: "whenClicked",
spec: "when this sprite clicked",
inputs: [],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENSTAGECLICKED",
spec: "when stage clicked",
inputs: [],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENBACKDROPSWITCHESTO",
selector: "whenSceneStarts",
spec: "when backdrop switches to %1",
inputs: ["%m.backdrop"],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENGREATERTHAN",
selector: "whenSensorGreaterThan",
spec: "when %1 > %2",
inputs: ["%m.triggerSensor", "%n"],
shape: "hat",
category: "events"
}, {
id: "EVENT_WHENBROADCASTRECEIVED",
selector: "whenIReceive",
spec: "when I receive %1",
inputs: ["%m.broadcast"],
shape: "hat",
category: "events"
}, {
id: "EVENT_BROADCAST",
selector: "broadcast:",
spec: "broadcast %1",
inputs: ["%m.broadcast"],
shape: "stack",
category: "events"
}, {
id: "EVENT_BROADCASTANDWAIT",
selector: "doBroadcastAndWait",
spec: "broadcast %1 and wait",
inputs: ["%m.broadcast"],
shape: "stack",
category: "events"
}, {
id: "CONTROL_WAIT",
selector: "wait:elapsed:from:",
spec: "wait %1 seconds",
inputs: ["%n"],
shape: "stack",
category: "control"
}, {
id: "CONTROL_REPEAT",
selector: "doRepeat",
spec: "repeat %1",
inputs: ["%n"],
shape: "c-block",
category: "control",
hasLoopArrow: true
}, {
id: "CONTROL_FOREVER",
selector: "doForever",
spec: "forever",
inputs: [],
shape: "c-block cap",
category: "control",
hasLoopArrow: true
}, {
id: "CONTROL_IF",
selector: "doIf",
spec: "if %1 then",
inputs: ["%b"],
shape: "c-block",
category: "control"
}, {
id: "CONTROL_WAITUNTIL",
selector: "doWaitUntil",
spec: "wait until %1",
inputs: ["%b"],
shape: "stack",
category: "control"
}, {
id: "CONTROL_REPEATUNTIL",
selector: "doUntil",
spec: "repeat until %1",
inputs: ["%b"],
shape: "c-block",
category: "control",
hasLoopArrow: true
}, {
id: "CONTROL_STOP",
selector: "stopScripts",
spec: "stop %1",
inputs: ["%m.stop"],
shape: "cap",
category: "control"
}, {
id: "CONTROL_STARTASCLONE",
selector: "whenCloned",
spec: "when I start as a clone",
inputs: [],
shape: "hat",
category: "control"
}, {
id: "CONTROL_CREATECLONEOF",
selector: "createCloneOf",
spec: "create clone of %1",
inputs: ["%m.spriteOnly"],
shape: "stack",
category: "control"
}, {
id: "CONTROL_DELETETHISCLONE",
selector: "deleteClone",
spec: "delete this clone",
inputs: [],
shape: "cap",
category: "control"
}, {
id: "SENSING_ASKANDWAIT",
selector: "doAsk",
spec: "ask %1 and wait",
inputs: ["%s"],
shape: "stack",
category: "sensing"
}, {
id: "videoSensing.videoToggle",
selector: "setVideoState",
spec: "turn video %1",
inputs: ["%m.videoState"],
shape: "stack",
category: "video"
}, {
id: "videoSensing.setVideoTransparency",
selector: "setVideoTransparency",
spec: "set video transparency to %1%",
inputs: ["%n"],
shape: "stack",
category: "video"
}, {
id: "videoSensing.whenMotionGreaterThan",
spec: "when video motion > %1",
inputs: ["%n"],
shape: "hat",
category: "video"
}, {
id: "SENSING_RESETTIMER",
selector: "timerReset",
spec: "reset timer",
inputs: [],
shape: "stack",
category: "sensing"
}, {
id: "DATA_SETVARIABLETO",
selector: "setVar:to:",
spec: "set %1 to %2",
inputs: ["%m.var", "%s"],
shape: "stack",
category: "variables"
}, {
id: "DATA_CHANGEVARIABLEBY",
selector: "changeVar:by:",
spec: "change %1 by %2",
inputs: ["%m.var", "%n"],
shape: "stack",
category: "variables"
}, {
id: "DATA_SHOWVARIABLE",
selector: "showVariable:",
spec: "show variable %1",
inputs: ["%m.var"],
shape: "stack",
category: "variables"
}, {
id: "DATA_HIDEVARIABLE",
selector: "hideVariable:",
spec: "hide variable %1",
inputs: ["%m.var"],
shape: "stack",
category: "variables"
}, {
id: "DATA_ADDTOLIST",
selector: "append:toList:",
spec: "add %1 to %2",
inputs: ["%s", "%m.list"],
shape: "stack",
category: "list"
}, {
id: "DATA_DELETEOFLIST",
selector: "deleteLine:ofList:",
spec: "delete %1 of %2",
inputs: ["%d.listDeleteItem", "%m.list"],
shape: "stack",
category: "list"
}, {
id: "DATA_DELETEALLOFLIST",
spec: "delete all of %1",
inputs: ["%m.list"],
shape: "stack",
category: "list"
}, {
id: "MOTION_IFONEDGEBOUNCE",
selector: "bounceOffEdge",
spec: "if on edge, bounce",
inputs: [],
shape: "stack",
category: "motion"
}, {
id: "DATA_INSERTATLIST",
selector: "insert:at:ofList:",
spec: "insert %1 at %2 of %3",
inputs: ["%s", "%d.listItem", "%m.list"],
shape: "stack",
category: "list"
}, {
id: "DATA_REPLACEITEMOFLIST",
selector: "setLine:ofList:to:",
spec: "replace item %1 of %2 with %3",
inputs: ["%d.listItem", "%m.list", "%s"],
shape: "stack",
category: "list"
}, {
id: "DATA_SHOWLIST",
selector: "showList:",
spec: "show list %1",
inputs: ["%m.list"],
shape: "stack",
category: "list"
}, {
id: "DATA_HIDELIST",
selector: "hideList:",
spec: "hide list %1",
inputs: ["%m.list"],
shape: "stack",
category: "list"
}, {
id: "SENSING_OF_XPOSITION",
selector: "xpos",
spec: "x position",
inputs: [],
shape: "reporter",
category: "motion"
}, {
id: "SENSING_OF_YPOSITION",
selector: "ypos",
spec: "y position",
inputs: [],
shape: "reporter",
category: "motion"
}, {
id: "SENSING_OF_DIRECTION",
selector: "heading",
spec: "direction",
inputs: [],
shape: "reporter",
category: "motion"
}, {
id: "SENSING_OF_COSTUMENUMBER",
selector: "costumeIndex",
spec: "costume #",
inputs: [],
shape: "reporter",
category: "looks"
}, {
id: "LOOKS_COSTUMENUMBERNAME",
selector: "LOOKS_COSTUMENUMBERNAME",
spec: "costume %1",
inputs: ["%m"],
shape: "reporter",
category: "looks"
}, {
id: "SENSING_OF_SIZE",
selector: "scale",
spec: "size",
inputs: [],
shape: "reporter",
category: "looks"
}, {
id: "SENSING_OF_BACKDROPNAME",
selector: "sceneName",
spec: "backdrop name",
inputs: [],
shape: "reporter",
category: "looks"
}, {
id: "LOOKS_BACKDROPNUMBERNAME",
spec: "backdrop %1",
inputs: ["%m"],
shape: "reporter",
category: "looks"
}, {
id: "SENSING_OF_BACKDROPNUMBER",
selector: "backgroundIndex",
spec: "backdrop #",
inputs: [],
shape: "reporter",
category: "looks"
}, {
id: "SOUND_VOLUME",
selector: "volume",
spec: "volume",
inputs: [],
shape: "reporter",
category: "sound"
}, {
id: "music.getTempo",
selector: "tempo",
spec: "tempo",
inputs: [],
shape: "reporter",
category: "music"
}, {
id: "SENSING_TOUCHINGOBJECT",
selector: "touching:",
spec: "touching %1?",
inputs: ["%m.touching"],
shape: "boolean",
category: "sensing"
}, {
id: "SENSING_TOUCHINGCOLOR",
selector: "touchingColor:",
spec: "touching color %1?",
inputs: ["%c"],
shape: "boolean",
category: "sensing"
}, {
id: "SENSING_COLORISTOUCHINGCOLOR",
selector: "color:sees:",
spec: "color %1 is touching %2?",
inputs: ["%c", "%c"],
shape: "boolean",
category: "sensing"
}, {
id: "SENSING_DISTANCETO",
selector: "distanceTo:",
spec: "distance to %1",
inputs: ["%m.spriteOrMouse"],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_ANSWER",
selector: "answer",
spec: "answer",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_KEYPRESSED",
selector: "keyPressed:",
spec: "key %1 pressed?",
inputs: ["%m.key"],
shape: "boolean",
category: "sensing"
}, {
id: "SENSING_MOUSEDOWN",
selector: "mousePressed",
spec: "mouse down?",
inputs: [],
shape: "boolean",
category: "sensing"
}, {
id: "SENSING_MOUSEX",
selector: "mouseX",
spec: "mouse x",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_MOUSEY",
selector: "mouseY",
spec: "mouse y",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_SETDRAGMODE",
spec: "set drag mode %1",
inputs: ["%m"],
shape: "stack",
category: "sensing"
}, {
id: "SENSING_LOUDNESS",
selector: "soundLevel",
spec: "loudness",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "videoSensing.videoOn",
selector: "senseVideoMotion",
spec: "video %1 on %2",
inputs: ["%m.videoMotionType", "%m.stageOrThis"],
shape: "reporter",
category: "video"
}, {
id: "SENSING_TIMER",
selector: "timer",
spec: "timer",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_OF",
selector: "getAttribute:of:",
spec: "%1 of %2",
inputs: ["%m.attribute", "%m.spriteOrStage"],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_CURRENT",
selector: "timeAndDate",
spec: "current %1",
inputs: ["%m.timeAndDate"],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_DAYSSINCE2000",
selector: "timestamp",
spec: "days since 2000",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "SENSING_USERNAME",
selector: "getUserName",
spec: "username",
inputs: [],
shape: "reporter",
category: "sensing"
}, {
id: "OPERATORS_ADD",
selector: "+",
spec: "%1 + %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_SUBTRACT",
selector: "-",
spec: "%1 - %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_MULTIPLY",
selector: "*",
spec: "%1 * %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_DIVIDE",
selector: "/",
spec: "%1 / %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_RANDOM",
selector: "randomFrom:to:",
spec: "pick random %1 to %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_LT",
selector: "<",
spec: "%1 < %2",
inputs: ["%s", "%s"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_EQUALS",
selector: "=",
spec: "%1 = %2",
inputs: ["%s", "%s"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_GT",
selector: ">",
spec: "%1 > %2",
inputs: ["%s", "%s"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_AND",
selector: "&",
spec: "%1 and %2",
inputs: ["%b", "%b"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_OR",
selector: "|",
spec: "%1 or %2",
inputs: ["%b", "%b"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_NOT",
selector: "not",
spec: "not %1",
inputs: ["%b"],
shape: "boolean",
category: "operators"
}, {
id: "OPERATORS_JOIN",
selector: "concatenate:with:",
spec: "join %1 %2",
inputs: ["%s", "%s"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_LETTEROF",
selector: "letter:of:",
spec: "letter %1 of %2",
inputs: ["%n", "%s"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_LENGTH",
selector: "stringLength:",
spec: "length of %1",
inputs: ["%s"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_MOD",
selector: "%",
spec: "%1 mod %2",
inputs: ["%n", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_ROUND",
selector: "rounded",
spec: "round %1",
inputs: ["%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_MATHOP",
selector: "computeFunction:of:",
spec: "%1 of %2",
inputs: ["%m.mathOp", "%n"],
shape: "reporter",
category: "operators"
}, {
id: "OPERATORS_CONTAINS",
spec: "%1 contains %2?",
inputs: ["%s", "%s"],
shape: "boolean",
category: "operators"
}, {
id: "DATA_ITEMOFLIST",
selector: "getLine:ofList:",
spec: "item %1 of %2",
inputs: ["%d.listItem", "%m.list"],
shape: "reporter",
category: "list"
}, {
id: "DATA_ITEMNUMOFLIST",
spec: "item # of %1 in %2",
inputs: ["%s", "%m.list"],
shape: "reporter",
category: "list"
}, {
id: "DATA_LENGTHOFLIST",
selector: "lineCountOfList:",
spec: "length of %1",
inputs: ["%m.list"],
shape: "reporter",
category: "list"
}, {
id: "DATA_LISTCONTAINSITEM",
selector: "list:contains:",
spec: "%1 contains %2?",
inputs: ["%m.list", "%s"],
shape: "boolean",
category: "list"
}, {
id: "CONTROL_ELSE",
spec: "else",
inputs: [],
shape: "celse",
category: "control"
}, {
id: "scratchblocks:end",
spec: "end",
inputs: [],
shape: "cend",
category: "control"
}, {
id: "scratchblocks:ellipsis",
spec: ". . .",
inputs: [],
shape: "stack",
category: "grey"
}, {
id: "scratchblocks:addInput",
spec: "%1 @addInput",
inputs: ["%n"],
shape: "ring",
category: "grey"
}, {
id: "SENSING_USERID",
spec: "user id",
inputs: [],
shape: "reporter",
category: "obsolete"
}, {
selector: "doIf",
spec: "if %1",
inputs: ["%b"],
shape: "c-block",
category: "obsolete"
}, {
selector: "doForeverIf",
spec: "forever if %1",
inputs: ["%b"],
shape: "c-block cap",
category: "obsolete"
}, {
selector: "doReturn",
spec: "stop script",
inputs: [],
shape: "cap",
category: "obsolete"
}, {
selector: "stopAll",
spec: "stop all",
inputs: [],
shape: "cap",
category: "obsolete"
}, {
selector: "lookLike:",
spec: "switch to costume %1",
inputs: ["%m.costume"],
shape: "stack",
category: "obsolete"
}, {
selector: "nextScene",
spec: "next background",
inputs: [],
shape: "stack",
category: "obsolete"
}, {
selector: "startScene",
spec: "switch to background %1",
inputs: ["%m.backdrop"],
shape: "stack",
category: "obsolete"
}, {
selector: "backgroundIndex",
spec: "background #",
inputs: [],
shape: "reporter",
category: "obsolete"
}, {
id: "SENSING_LOUD",
selector: "isLoud",
spec: "loud?",
inputs: [],
shape: "boolean",
category: "obsolete"
},
// TODO define
{
id: "text2speech.speakAndWaitBlock",
spec: "speak %1",
inputs: ["%s"],
shape: "stack",
category: "tts"
}, {
id: "text2speech.setVoiceBlock",
spec: "set voice to %1",
inputs: ["%m"],
shape: "stack",
category: "tts"
}, {
id: "text2speech.setLanguageBlock",
spec: "set language to %1",
inputs: ["%m"],
shape: "stack",
category: "tts"
}, {
id: "translate.translateBlock",
spec: "translate %1 to %2",
inputs: ["%s", "%m"],
shape: "reporter",
category: "translate"
}, {
id: "translate.viewerLanguage",
spec: "language",
shape: "reporter",
category: "translate"
}, {
id: "makeymakey.whenKeyPressed",
spec: "when %1 key pressed",
inputs: ["%m"],
// this is not %m.key
shape: "hat",
category: "makeymakey"
}, {
id: "makeymakey.whenKeysPressedInOrder",
spec: "when %1 pressed in order",
inputs: ["%m"],
shape: "hat",
category: "makeymakey"
}, {
id: "microbit.whenButtonPressed",
spec: "when %1 button pressed",
inputs: ["%m"],
shape: "hat",
category: "microbit"
}, {
id: "microbit.isButtonPressed",
spec: "%1 button pressed?",
inputs: ["%m"],
shape: "boolean",
category: "microbit"
}, {
id: "microbit.whenGesture",
spec: "when %1",
inputs: ["%m"],
shape: "hat",
category: "microbit"
}, {
id: "microbit.displaySymbol",
spec: "display %1",
inputs: ["%m"],
// TODO add matrix support
shape: "stack",
category: "microbit"
}, {
id: "microbit.displayText",
spec: "display text %1",
inputs: ["%s"],
shape: "stack",
category: "microbit"
}, {
id: "microbit.clearDisplay",
spec: "clear display",
shape: "stack",
category: "microbit"
}, {
id: "microbit.whenTilted",
spec: "when tilted %1",
inputs: ["%m"],
shape: "hat",
category: "microbit"
}, {
id: "microbit.isTilted",
spec: "tilted %1?",
inputs: ["%m"],
shape: "boolean",
category: "microbit"
}, {
id: "microbit.tiltAngle",
spec: "tilt angle %1",
inputs: ["%m"],
shape: "reporter",
category: "microbit"
}, {
id: "microbit.whenPinConnected",
spec: "when pin %1 connected",
inputs: ["%m"],
shape: "hat",
category: "microbit"
}, {
id: "ev3.motorTurnClockwise",
spec: "motor %1 turn this way for %2 seconds",
inputs: ["%m", "%n"],
shape: "stack",
category: "ev3"
}, {
id: "ev3.motorTurnCounterClockwise",
spec: "motor %1 turn that way for %2 seconds",
inputs: ["%m", "%n"],
shape: "stack",
category: "ev3"
}, {
id: "ev3.motorSetPower",
spec: "motor %1 set power %2%",
inputs: ["%m", "%n"],
shape: "stack",
category: "ev3"
}, {
id: "ev3.getMotorPosition",
spec: "motor %1 position",
inputs: ["%m"],
shape: "reporter",
category: "ev3"
}, {
id: "ev3.whenButtonPressed",
spec: "when button %1 pressed",
inputs: ["%m"],
shape: "hat",
category: "ev3"
}, {
id: "ev3.whenDistanceLessThan",
spec: "when distance < %1",
inputs: ["%n"],
shape: "hat",
category: "ev3"
}, {
id: "ev3.whenBrightnessLessThan",
spec: "when brightness < %1",
inputs: ["%n"],
shape: "hat",
category: "ev3"
}, {
id: "ev3.buttonPressed",
spec: "button %1 pressed?",
inputs: ["%m"],
shape: "boolean",
category: "ev3"
}, {
id: "ev3.getDistance",
spec: "distance",
shape: "reporter",
category: "ev3"
}, {
id: "ev3.getBrightness",
spec: "brightness",
shape: "reporter",
category: "ev3"
}, {
id: "ev3.beepNote",
spec: "beep note %1 for %2 secs",
inputs: ["%d.note", "%n"],
// we can use %d.note here
shape: "stack",
category: "ev3"
}, {
id: "wedo2.motorOn",
spec: "turn %1 on",
inputs: ["%m.motor"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.motorOff",
spec: "turn %1 off",
inputs: ["%m.motor"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.startMotorPower",
spec: "set %1 power to %2",
inputs: ["%m.motor", "%n"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.setMotorDirection",
spec: "set %1 direction to %2",
inputs: ["%m.motor2", "%m.motorDirection"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.whenDistance",
spec: "when distance %1 %2",
inputs: ["%m.lessMore", "%n"],
shape: "hat",
category: "wedo"
}, {
id: "wedo2.getDistance",
spec: "distance",
inputs: [],
shape: "reporter",
category: "wedo"
}, {
id: "wedo2.motorOnFor",
spec: "turn %1 on for %2 seconds",
inputs: ["%m.motor", "%n"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.setLightHue",
spec: "set light color to %1",
inputs: ["%n"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.playNoteFor",
spec: "play note %1 for %2 seconds",
inputs: ["%n", "%n"],
shape: "stack",
category: "wedo"
}, {
id: "wedo2.whenTilted",
spec: "when tilted %1",
inputs: ["%m.xxx"],
shape: "hat",
category: "wedo"
}, {
id: "wedo2.isTilted",
spec: "tilted %1?",
inputs: ["%m"],
shape: "boolean",
category: "wedo"
}, {
id: "wedo2.getTiltAngle",
spec: "tilt angle %1",
inputs: ["%m.xxx"],
shape: "reporter",
category: "wedo"
}, {
id: "gdxfor.whenGesture",
spec: "when %1",
inputs: ["%m"],
shape: "hat",
category: "gdxfor"
}, {
id: "gdxfor.whenForcePushedOrPulled",
spec: "when force sensor %1",
inputs: ["%m"],
shape: "hat",
category: "gdxfor"
}, {
id: "gdxfor.getForce",
spec: "force",
shape: "reporter",
category: "gdxfor"
}, {
id: "gdxfor.whenTilted",
spec: "when tilted %1",
inputs: ["%m"],
shape: "hat",
category: "gdxfor"
}, {
id: "gdxfor.isTilted",
spec: "tilted %1?",
inputs: ["%m"],
shape: "boolean",
category: "gdxfor"
}, {
id: "gdxfor.getTilt",
spec: "tilt angle %1",
inputs: ["%m"],
shape: "reporter",
category: "gdxfor"
}, {
id: "gdxfor.isFreeFalling",
spec: "falling?",
shape: "boolean",
category: "gdxfor"
}, {
id: "gdxfor.getSpin",
spec: "spin speed %1",
inputs: ["%m"],
shape: "reporter",
category: "gdxfor"
}, {
id: "gdxfor.getAcceleration",
spec: "acceleration %1",
inputs: ["%m"],
shape: "reporter",
category: "gdxfor"
}, {
id: "boost.motorOnFor",
spec: "turn motor %1 for %2 seconds",
inputs: ["%m", "%n"],
shape: "stack",
category: "boost"
}, {
id: "boost.motorOnForRotation",
spec: "turn motor %1 for %2 rotations",
inputs: ["%m", "%n"],
shape: "stack",
category: "boost"
}, {
id: "boost.motorOn",
spec: "turn motor %1 on",
inputs: ["%m"],
shape: "stack",
category: "boost"
}, {
id: "boost.motorOff",
spec: "turn motor %1 off",
inputs: ["%m"],
shape: "stack",
category: "boost"
}, {
id: "boost.setMotorPower",
spec: "set motor %1 speed to %2%",
inputs: ["%m", "%n"],
shape: "stack",
category: "boost"
}, {
id: "boost.setMotorDirection",
spec: "set motor %1 direction %2",
inputs: ["%m", "%m"],
shape: "stack",
category: "boost"
}, {
id: "boost.getMotorPosition",
spec: "motor %1 position",
inputs: ["%m"],
shape: "reporter",
category: "boost"
}, {
id: "boost.whenColor",
spec: "when %1 brick seen",
inputs: ["%m"],
shape: "hat",
category: "boost"
}, {
id: "boost.seeingColor",
spec: "seeing %1 brick?",
inputs: ["%m"],
shape: "boolean",
category: "boost"
}, {
id: "boost.whenTilted",
spec: "when tilted %1",
inputs: ["%m"],
shape: "hat",
category: "boost"
}, {
id: "boost.getTiltAngle",
spec: "tilt angle %1",
inputs: ["%m"],
shape: "reporter",
category: "boost"
}, {
id: "boost.setLightHue",
spec: "set light color to %1",
inputs: ["%n"],
shape: "stack",
category: "boost"
}];
// List of classes we're allowed to override.
var overrideCategories = ["motion", "looks", "sound", "variables", "list", "events", "control", "sensing", "operators", "custom", "custom-arg", "extension", "grey", "obsolete"].concat(_toConsumableArray(Object.keys(extensions)), _toConsumableArray(Object.keys(aliasExtensions)));
var overrideShapes = ["hat", "cap", "stack", "boolean", "reporter", "ring", "cat"];
// languages that should be displayed right to left
var rtlLanguages = ["ar", "ckb", "fa", "he"];
var inputNumberPat = /%([0-9]+)/;
var inputPat = /(%[a-zA-Z0-9](?:\.[a-zA-Z0-9]+)?)/;
var inputPatGlobal = new RegExp(inputPat.source, "g");
var iconPat = /(@[a-zA-Z]+)/;
var splitPat = new RegExp(inputPat.source + "|" + iconPat.source + "| +", "g");
var hexColorPat = /^#(?:[0-9a-fA-F]{3}){1,2}?$/;
function parseInputNumber(part) {
var m = inputNumberPat.exec(part);
return m ? +m[1] : 0;
}
// used for procDefs
function parseSpec(spec) {
var parts = spec.split(splitPat).filter(function (x) {
return x;
});
var inputs = parts.filter(function (p) {
return inputPat.test(p);
});
return {
spec: spec,
parts: parts,
inputs: inputs,
hash: hashSpec(spec)
};
}
function hashSpec(spec) {
return minifyHash(spec.replace(inputPatGlobal, " _ "));
}
function minifyHash(hash) {
return hash.replace(/_/g, " _ ").replace(/ +/g, " ").replace(/[,%?:]/g, "").replace(/ß/g, "ss").replace(/ä/g, "a").replace(/ö/g, "o").replace(/ü/g, "u").replace(". . .", "...").replace(/^…$/, "...").trim().toLowerCase();
}
var blocksById = {};
var allBlocks = scratchCommands.map(function (def) {
if (!def.id) {
if (!def.selector) {
throw new Error("Missing ID: " + def.spec);
}
def.id = "sb2:" + def.selector;
}
if (!def.spec) {
throw new Error("Missing spec: " + def.id);
}
var info = {
id: def.id,
// Used for Scratch 3 translations
spec: def.spec,
// Used for Scratch 2 translations
parts: def.spec.split(splitPat).filter(function (x) {
return x;
}),
selector: def.selector || "sb3:" + def.id,
// Used for JSON marshalling
inputs: def.inputs == null ? [] : def.inputs,
shape: def.shape,
category: def.category,
hasLoopArrow: !!def.hasLoopArrow
};
if (blocksById[info.id]) {
throw new Error("Duplicate ID: " + info.id);
}
blocksById[info.id] = info;
return info;
});
var unicodeIcons = {
"@greenFlag": "âš‘",
"@turnRight": "↻",
"@turnLeft": "↺",
"@addInput": "â–¸",
"@delInput": "â—‚"
};
var allLanguages = {};
function loadLanguage(code, language) {
var blocksByHash = language.blocksByHash = {};
Object.keys(language.commands).forEach(function (blockId) {
var nativeSpec = language.commands[blockId];
var block = blocksById[blockId];
var nativeHash = hashSpec(nativeSpec);
if (!blocksByHash[nativeHash]) {
blocksByHash[nativeHash] = [];
}
blocksByHash[nativeHash].push(block);
// fallback image replacement, for languages without aliases
var m = iconPat.exec(block.spec);
if (m) {
var image = m[0];
var hash = nativeHash.replace(hashSpec(image), unicodeIcons[image]);
if (!blocksByHash[hash]) {
blocksByHash[hash] = [];
}
blocksByHash[hash].push(block);
}
});
language.nativeAliases = {};
Object.keys(language.aliases).forEach(function (alias) {
var blockId = language.aliases[alias];
var block = blocksById[blockId];
if (block === undefined) {
throw new Error("Invalid alias '" + blockId + "'");
}
var aliasHash = hashSpec(alias);
if (!blocksByHash[aliasHash]) {
blocksByHash[aliasHash] = [];
}
blocksByHash[aliasHash].push(block);
if (!language.nativeAliases[blockId]) {
language.nativeAliases[blockId] = [];
}
language.nativeAliases[blockId].push(alias);
});
// Some English blocks were renamed between Scratch 2 and Scratch 3. Wire them
// into language.blocksByHash
Object.keys(language.renamedBlocks || {}).forEach(function (alt) {
var id = language.renamedBlocks[alt];
if (!blocksById[id]) {
throw new Error("Unknown ID: " + id);
}
var block = blocksById[id];
var hash = hashSpec(alt);
if (!english.blocksByHash[hash]) {
english.blocksByHash[hash] = [];
}
english.blocksByHash[hash].push(block);
});
language.nativeDropdowns = {};
Object.keys(language.dropdowns).forEach(function (name) {
var nativeName = language.dropdowns[name];
language.nativeDropdowns[nativeName] = name;
});
language.code = code;
allLanguages[code] = language;
}
function loadLanguages(languages) {
Object.keys(languages).forEach(function (code) {
return loadLanguage(code, languages[code]);
});
}
var english = {
aliases: {
"turn ccw %1 degrees": "MOTION_TURNLEFT",
"turn left %1 degrees": "MOTION_TURNLEFT",
"turn cw %1 degrees": "MOTION_TURNRIGHT",
"turn right %1 degrees": "MOTION_TURNRIGHT",
"when flag clicked": "EVENT_WHENFLAGCLICKED",
"when gf clicked": "EVENT_WHENFLAGCLICKED",
"when green flag clicked": "EVENT_WHENFLAGCLICKED"
},
renamedBlocks: {
"say %1 for %2 secs": "LOOKS_SAYFORSECS",
"think %1 for %2 secs": "LOOKS_THINKFORSECS",
"play sound %1": "SOUND_PLAY",
"wait %1 secs": "CONTROL_WAIT",
clear: "pen.clear"
},
definePrefix: ["define"],
defineSuffix: [],
// For ignoring the lt sign in the "when distance < _" block
ignorelt: ["when distance"],
// Valid arguments to "of" dropdown, for resolving ambiguous situations
math: ["abs", "floor", "ceiling", "sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "ln", "log", "e ^", "10 ^"],
// Valid arguments to "sound effect" dropdown, for resolving ambiguous situations
soundEffects: ["pitch", "pan left/right"],
// Valid arguments to "microbit when" dropdown
microbitWhen: ["moved", "shaken", "jumped"],
// For detecting the "stop" cap / stack block
osis: ["other scripts in sprite", "other scripts in stage"],
dropdowns: {},
commands: {}
};
allBlocks.forEach(function (info) {
english.commands[info.id] = info.spec;
});
loadLanguages({
en: english
});
/*****************************************************************************/
function registerCheck(id, func) {
if (!blocksById[id]) {
throw new Error("Unknown ID: " + id);
}
blocksById[id].accepts = func;
}
function specialCase(id, func) {
if (!blocksById[id]) {
throw new Error("Unknown ID: " + id);
}
blocksById[id].specialCase = func;
}
function disambig(id1, id2, test) {
registerCheck(id1, function (_, children, lang) {
return test(children, lang);
});
registerCheck(id2, function (_, children, lang) {
return !test(children, lang);
});
}
disambig("OPERATORS_MATHOP", "SENSING_OF", function (children, lang) {
// Operators if math function, otherwise sensing "attribute of" block
var first = children[0];
if (!first.isInput) {
return;
}
var name = first.value;
return lang.math.includes(name);
});
disambig("SOUND_CHANGEEFFECTBY", "LOOKS_CHANGEEFFECTBY", function (children, lang) {
// Sound if sound effect, otherwise default to graphic effect
var _iterator = _createForOfIteratorHelper(children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child.shape === "dropdown") {
var name = child.value;
var _iterator2 = _createForOfIteratorHelper(lang.soundEffects),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var effect = _step2.value;
if (minifyHash(effect) === minifyHash(name)) {
return true;
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return false;
});
disambig("SOUND_SETEFFECTO", "LOOKS_SETEFFECTTO", function (children, lang) {
// Sound if sound effect, otherwise default to graphic effect
var _iterator3 = _createForOfIteratorHelper(children),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var child = _step3.value;
if (child.shape === "dropdown") {
var name = child.value;
var _iterator4 = _createForOfIteratorHelper(lang.soundEffects),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var effect = _step4.value;
if (minifyHash(effect) === minifyHash(name)) {
return true;
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
return false;
});
disambig("DATA_LENGTHOFLIST", "OPERATORS_LENGTH", function (children, _lang) {
// List block if dropdown, otherwise operators
var last = children[children.length - 1];
if (!last.isInput) {
return;
}
return last.shape === "dropdown";
});
disambig("DATA_LISTCONTAINSITEM", "OPERATORS_CONTAINS", function (children, _lang) {
// List block if dropdown, otherwise operators
var first = children[0];
if (!first.isInput) {
return;
}
return first.shape === "dropdown";
});
disambig("pen.setColor", "pen.setHue", function (children, _lang) {
// Color block if color input, otherwise numeric
var last = children[children.length - 1];
// If variable, assume color input, since the RGBA hack is common.
// TODO fix Scratch :P
return last.isInput && last.isColor || last.isBlock;
});
disambig("microbit.whenGesture", "gdxfor.whenGesture", function (children, lang) {
var _iterator5 = _createForOfIteratorHelper(children),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var child = _step5.value;
if (child.shape === "dropdown") {
var name = child.value;
// Yes, "when shaken" gdxfor block exists. But microbit is more common.
var _iterator6 = _createForOfIteratorHelper(lang.microbitWhen),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var effect = _step6.value;
if (minifyHash(effect) === minifyHash(name)) {
return true;
}
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
}
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
return false;
});
// This block does not need disambiguation in English;
// however, many other languages do require that.
disambig("ev3.buttonPressed", "microbit.isButtonPressed", function (children, _lang) {
var _iterator7 = _createForOfIteratorHelper(children),
_step7;
try {
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
var child = _step7.value;
if (child.shape === "dropdown") {
// EV3 "button pressed" block uses numeric identifier
// and does not support "any".
switch (minifyHash(child.value)) {
case "1":
case "2":
case "3":
case "4":
return true;
default:
}
}
}
} catch (err) {
_iterator7.e(err);
} finally {
_iterator7.f();
}
return false;
});
specialCase("CONTROL_STOP", function (_, children, lang) {
// Cap block unless argument is "other scripts in sprite"
var last = children[children.length - 1];
if (!last.isInput) {
return;
}
var value = last.value;
if (lang.osis.includes(value)) {
return _objectSpread2(_objectSpread2({}, blocksById.CONTROL_STOP), {}, {
shape: "stack"
});
}
});
function lookupHash(hash, info, children, languages) {
var _iterator8 = _createForOfIteratorHelper(languages),
_step8;
try {
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
var lang = _step8.value;
if (Object.prototype.hasOwnProperty.call(lang.blocksByHash, hash)) {
var collisions = lang.blocksByHash[hash];
var _iterator9 = _createForOfIteratorHelper(collisions),
_step9;
try {
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
var block = _step9.value;
if (info.shape === "reporter" && block.shape !== "reporter" && block.shape !== "ring") {
continue;
}
if (info.shape === "boolean" && block.shape !== "boolean") {
continue;
}
if (collisions.length > 1) {
// Only check in case of collision;
// perform "disambiguation"
if (block.accepts && !block.accepts(info, children, lang)) {
continue;
}
}
if (block.specialCase) {
block = block.specialCase(info, children, lang) || block;
}
return {
type: block,
lang: lang
};
}
} catch (err) {
_iterator9.e(err);
} finally {
_iterator9.f();
}
}
}
} catch (err) {
_iterator8.e(err);
} finally {
_iterator8.f();
}
}
function lookupDropdown(name, languages) {
var _iterator10 = _createForOfIteratorHelper(languages),
_step10;
try {
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
var lang = _step10.value;
if (Object.prototype.hasOwnProperty.call(lang.nativeDropdowns, name)) {
return lang.nativeDropdowns[name];
}
}
} catch (err) {
_iterator10.e(err);
} finally {
_iterator10.f();
}
}
function applyOverrides(info, overrides) {
var _iterator11 = _createForOfIteratorHelper(overrides),
_step11;
try {
for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
var name = _step11.value;
if (hexColorPat.test(name)) {
info.color = name;
info.category = "";
info.categoryIsDefault = false;
} else if (overrideCategories.includes(name)) {
info.category = name;
info.categoryIsDefault = false;
} else if (overrideShapes.includes(name)) {
info.shape = name;
} else if (name === "loop") {
info.hasLoopArrow = true;
} else if (name === "+" || name === "-") {
info.diff = name;
}
}
} catch (err) {
_iterator11.e(err);
} finally {
_iterator11.f();
}
}
function blockName(block) {
var words = [];
var _iterator12 = _createForOfIteratorHelper(block.children),
_step12;
try {
for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
var child = _step12.value;
if (!child.isLabel) {
return;
}
words.push(child.value);
}
} catch (err) {
_iterator12.e(err);
} finally {
_iterator12.f();
}
return words.join(" ");
}
function assert$2(bool, message) {
if (!bool) {
throw new Error("Assertion failed! " + (message || ""));
}
}
function indent(text) {
return text.split("\n").map(function (line) {
return " " + line;
}).join("\n");
}
var Label = /*#__PURE__*/function () {
function Label(value, cls) {
this.value = value;
this.cls = cls || "";
this.el = null;
this.height = 12;
this.metrics = null;
this.x = 0;
}
_createClass(Label, [{
key: "isLabel",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
if (this.value === "<" || this.value === ">") {
return this.value;
}
return this.value.replace(/([<>[\](){}])/g, "\\$1");
}
}]);
return Label;
}();
var Icon = /*#__PURE__*/function () {
function Icon(name) {
this.name = name;
this.isArrow = name === "loopArrow";
assert$2(Icon.icons[name], "no info for icon " + name);
}
_createClass(Icon, [{
key: "isIcon",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
return unicodeIcons["@" + this.name] || "";
}
}], [{
key: "icons",
get: function get() {
return {
greenFlag: true,
stopSign: true,
turnLeft: true,
turnRight: true,
loopArrow: true,
addInput: true,
delInput: true,
list: true
};
}
}]);
return Icon;
}();
var Input = /*#__PURE__*/function () {
function Input(shape, value, menu) {
this.shape = shape;
this.value = value;
this.menu = menu || null;
this.isRound = shape === "number" || shape === "number-dropdown";
this.isBoolean = shape === "boolean";
this.isStack = shape === "stack";
this.isInset = shape === "boolean" || shape === "stack" || shape === "reporter";
this.isColor = shape === "color";
this.hasArrow = shape === "dropdown" || shape === "number-dropdown";
this.isDarker = shape === "boolean" || shape === "stack" || shape === "dropdown";
this.isSquare = shape === "string" || shape === "color" || shape === "dropdown";
this.hasLabel = !(this.isColor || this.isInset);
this.label = this.hasLabel ? new Label(value, "literal-" + this.shape) : null;
this.x = 0;
}
_createClass(Input, [{
key: "isInput",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
if (this.isColor) {
assert$2(this.value[0] === "#");
return "[" + this.value + "]";
}
// Order sensitive; see #439
var text = (this.value ? String(this.value) : "").replace(/([\]\\])/g, "\\$1").replace(/ v$/, " \\v");
if (this.hasArrow) {
text += " v";
}
return this.isRound ? "(" + text + ")" : this.isSquare ? "[" + text + "]" : this.isBoolean ? "<>" : this.isStack ? "{}" : text;
}
}, {
key: "translate",
value: function translate(_lang) {
if (this.hasArrow) {
var value = this.menu || this.value;
this.value = value; // TODO translate dropdown value
this.label = new Label(this.value, "literal-" + this.shape);
}
}
}]);
return Input;
}();
var Block = /*#__PURE__*/function () {
function Block(info, children, comment) {
assert$2(info);
this.info = _objectSpread2({}, info);
this.children = children;
this.comment = comment || null;
this.diff = null;
var shape = this.info.shape;
this.isHat = shape === "hat" || shape === "cat" || shape === "define-hat";
this.hasPuzzle = shape === "stack" || shape === "hat" || shape === "cat" || shape === "c-block";
this.isFinal = /cap/.test(shape);
this.isCommand = shape === "stack" || shape === "cap" || /block/.test(shape);
this.isOutline = shape === "outline";
this.isReporter = shape === "reporter";
this.isBoolean = shape === "boolean";
this.isRing = shape === "ring";
this.hasScript = /block/.test(shape);
this.isElse = shape === "celse";
this.isEnd = shape === "cend";
}
_createClass(Block, [{
key: "isBlock",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify(extras) {
var firstInput = null;
var checkAlias = false;
var text = this.children.map(function (child) {
if (child.isIcon) {
checkAlias = true;
}
if (!firstInput && !(child.isLabel || child.isIcon)) {
firstInput = child;
}
return child.isScript ? "\n" + indent(child.stringify()) + "\n" : child.stringify().trim() + " ";
}).join("").trim();
var lang = this.info.language;
if (checkAlias && lang && this.info.selector) {
var aliases = lang.nativeAliases[this.info.id];
if (aliases && aliases.length) {
var alias = aliases[0];
// TODO make translate() not in-place, and use that
if (inputPat.test(alias) && firstInput) {
alias = alias.replace(inputPat, firstInput.stringify());
}
return alias;
}
}
var overrides = extras || "";
if (this.info.categoryIsDefault === false || this.info.category === "custom-arg" && (this.isReporter || this.isBoolean) || this.info.category === "custom" && this.info.shape === "stack") {
if (overrides) {
overrides += " ";
}
overrides += this.info.category;
}
if (overrides) {
text += " :: " + overrides;
}
return this.hasScript ? text + "\nend" : this.info.shape === "reporter" ? "(" + text + ")" : this.info.shape === "boolean" ? "<" + text + ">" : text;
}
}, {
key: "translate",
value: function translate(lang, isShallow) {
var _this = this;
if (!lang) {
throw new Error("Missing language");
}
var id = this.info.id;
if (!id) {
return;
}
if (id === "PROCEDURES_DEFINITION") {
// Find the first 'outline' child (there should be exactly one).
var outline = this.children.find(function (child) {
return child.isOutline;
});
this.children = [];
var _iterator = _createForOfIteratorHelper(lang.definePrefix),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var word = _step.value;
this.children.push(new Label(word));
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
this.children.push(outline);
var _iterator2 = _createForOfIteratorHelper(lang.defineSuffix),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _word = _step2.value;
this.children.push(new Label(_word));
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return;
}
var oldSpec = this.info.language.commands[id];
var nativeSpec = lang.commands[id];
if (!nativeSpec) {
return;
}
var nativeInfo = parseSpec(nativeSpec);
var rawArgs = this.children.filter(function (child) {
return !child.isLabel && !child.isIcon;
});
if (!isShallow) {
rawArgs.forEach(function (child) {
return child.translate(lang);
});
}
// Work out indexes of existing children
var oldParts = parseSpec(oldSpec).parts;
var oldInputOrder = oldParts.map(function (part) {
return parseInputNumber(part);
}).filter(function (x) {
return x;
});
var highestNumber = 0;
var args = oldInputOrder.map(function (number) {
highestNumber = Math.max(highestNumber, number);
return rawArgs[number - 1];
});
var remainingArgs = rawArgs.slice(highestNumber);
// Get new children by index
this.children = nativeInfo.parts.map(function (part) {
part = part.trim();
if (!part) {
return;
}
var number = parseInputNumber(part);
if (number) {
return args[number - 1];
}
return iconPat.test(part) ? new Icon(part.slice(1)) : new Label(part);
}).filter(function (x) {
return x;
});
// Push any remaining children, so we pick up C block bodies
remainingArgs.forEach(function (arg, index) {
if (index === 1 && _this.info.id === "CONTROL_IF") {
_this.children.push(new Label(lang.commands.CONTROL_ELSE));
}
_this.children.push(arg);
});
this.info.language = lang;
this.info.isRTL = rtlLanguages.includes(lang.code);
this.info.categoryIsDefault = true;
}
}]);
return Block;
}();
var Comment = /*#__PURE__*/function () {
function Comment(value, hasBlock) {
this.label = new Label(value, "comment-label");
this.width = null;
this.hasBlock = hasBlock;
}
_createClass(Comment, [{
key: "isComment",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
return "// " + this.label.value;
}
}]);
return Comment;
}();
var Glow = /*#__PURE__*/function () {
function Glow(child) {
assert$2(child);
this.child = child;
if (child.isBlock) {
this.shape = child.info.shape;
this.info = child.info;
} else {
this.shape = "stack";
}
}
_createClass(Glow, [{
key: "isGlow",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
if (this.child.isBlock) {
return this.child.stringify("+");
}
var lines = this.child.stringify().split("\n");
return lines.map(function (line) {
return "+ " + line;
}).join("\n");
}
}, {
key: "translate",
value: function translate(lang) {
this.child.translate(lang);
}
}]);
return Glow;
}();
var Script = /*#__PURE__*/function () {
function Script(blocks) {
this.blocks = blocks;
this.isEmpty = !blocks.length;
this.isFinal = !this.isEmpty && blocks[blocks.length - 1].isFinal;
}
_createClass(Script, [{
key: "isScript",
get: function get() {
return true;
}
}, {
key: "stringify",
value: function stringify() {
return this.blocks.map(function (block) {
var line = block.stringify();
if (block.comment) {
line += " " + block.comment.stringify();
}
return line;
}).join("\n");
}
}, {
key: "translate",
value: function translate(lang) {
this.blocks.forEach(function (block) {
return block.translate(lang);
});
}
}]);
return Script;
}();
var Document = /*#__PURE__*/function () {
function Document(scripts) {
this.scripts = scripts;
}
_createClass(Document, [{
key: "stringify",
value: function stringify() {
return this.scripts.map(function (script) {
return script.stringify();
}).join("\n\n");
}
}, {
key: "translate",
value: function translate(lang) {
this.scripts.forEach(function (script) {
return script.translate(lang);
});
}
}]);
return Document;
}();
function assert$1(bool, message) {
if (!bool) {
throw new Error("Assertion failed! " + (message || ""));
}
}
function paintBlock(info, children, languages) {
var overrides = [];
if (Array.isArray(children[children.length - 1])) {
overrides = children.pop();
}
// build hash
var words = [];
var _iterator = _createForOfIteratorHelper(children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child.isLabel) {
words.push(child.value);
} else if (child.isIcon) {
words.push("@" + child.name);
} else {
words.push("_");
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
var string = words.join(" ");
var shortHash = info.hash = minifyHash(string);
// paint
var o = lookupHash(shortHash, info, children, languages);
var lang;
var type;
if (o) {
lang = o.lang;
type = o.type;
info.language = lang;
info.isRTL = rtlLanguages.includes(lang.code);
if (type.shape === "ring" ? info.shape === "reporter" : info.shape === "stack") {
info.shape = type.shape;
}
info.category = type.category;
info.categoryIsDefault = true;
// store selector, used for translation among other things
if (type.selector) {
info.selector = type.selector;
}
if (type.id) {
info.id = type.id;
}
info.hasLoopArrow = type.hasLoopArrow;
// ellipsis block
if (type.spec === ". . .") {
children = [new Label(". . .")];
}
} else {
// The block was not recognised, so we check if it's a define block.
//
// We check for built-in blocks first to avoid ambiguity, e.g. the
// `defina o tamanho como (100) %` block in pt_BR.
var _iterator2 = _createForOfIteratorHelper(languages),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _lang = _step2.value;
if (!isDefineBlock(children, _lang)) {
continue;
}
// Setting the shape also triggers some logic in recogniseStuff.
info.shape = "define-hat";
info.category = "custom";
// Move the children of the define block into an "outline", transforming
// () and [] shapes as we go.
var outlineChildren = children.splice(_lang.definePrefix.length, children.length - _lang.defineSuffix.length).map(function (child) {
if (child.isInput && child.isBoolean) {
// Convert empty boolean slot to empty boolean argument.
child = paintBlock({
shape: "boolean",
argument: "boolean",
category: "custom-arg"
}, [new Label("")], languages);
} else if (child.isInput && (child.shape === "string" || child.shape === "number")) {
// Convert string inputs to string arguments, number inputs to number arguments.
var labels = child.value.split(/ +/g).map(function (word) {
return new Label(word);
});
child = paintBlock({
shape: "reporter",
argument: child.shape === "string" ? "string" : "number",
category: "custom-arg"
}, labels, languages);
} else if (child.isReporter || child.isBoolean) {
// Convert variables to number arguments, predicates to boolean arguments.
if (child.info.categoryIsDefault) {
child.info.category = "custom-arg";
child.info.argument = child.isBoolean ? "boolean" : "number";
}
}
return child;
});
var outlineInfo = {
shape: "outline",
category: "custom",
categoryIsDefault: true,
hasLoopArrow: false
};
var outline = new Block(outlineInfo, outlineChildren);
children.splice(_lang.definePrefix.length, 0, outline);
break;
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
// Apply overrides.
applyOverrides(info, overrides);
// loop arrows
if (info.hasLoopArrow) {
children.push(new Icon("loopArrow"));
}
var block = new Block(info, children);
// image replacement
if (type && iconPat.test(type.spec)) {
block.translate(lang, true);
}
// diffs
if (info.diff === "+") {
return new Glow(block);
}
block.diff = info.diff;
return block;
}
function isDefineBlock(children, lang) {
if (children.length < lang.definePrefix.length) {
return false;
}
if (children.length < lang.defineSuffix.length) {
return false;
}
for (var i = 0; i < lang.definePrefix.length; i++) {
var defineWord = lang.definePrefix[i];
var child = children[i];
if (!child.isLabel || minifyHash(child.value) !== minifyHash(defineWord)) {
return false;
}
}
for (var _i = 1; _i <= lang.defineSuffix.length; _i++) {
var _defineWord = lang.defineSuffix[lang.defineSuffix.length - _i];
var _child = children[children.length - _i];
if (!_child.isLabel || minifyHash(_child.value) !== minifyHash(_defineWord)) {
return false;
}
}
return true;
}
function parseLines(code, languages) {
var tok = code[0];
var index = 0;
function next() {
tok = code[++index];
}
function peek() {
return code[index + 1];
}
function peekNonWs() {
for (var i = index + 1; i < code.length; i++) {
if (code[i] !== " ") {
return code[i];
}
}
}
var sawNL;
var define = [];
languages.map(function (lang) {
define = define.concat(lang.define);
});
function makeBlock(shape, children) {
var hasInputs = children.filter(function (x) {
return !x.isLabel;
}).length;
var info = {
shape: shape,
category: shape === "reporter" && !hasInputs ? "variables" : "obsolete",
categoryIsDefault: true,
hasLoopArrow: false
};
return paintBlock(info, children, languages);
}
function makeMenu(shape, value) {
var menu = lookupDropdown(value, languages) || value;
return new Input(shape, value, menu);
}
function pParts(end) {
var children = [];
var label;
while (tok && tok !== "\n") {
// So that comparison operators `<()<()>` and `<()>()>` don't need the
// central <> escaped, we interpret it as a label if particular
// conditions are met.
if ((tok === "<" || tok === ">") && end === ">" &&
// We're parsing a predicate.
children.length === 1 &&
// There's exactly one AST node behind us.
!children[children.length - 1].isLabel // That node is not a label.
) {
var c = peekNonWs();
// The next token starts some kind of input.
if (c === "[" || c === "(" || c === "<" || c === "{") {
label = null;
children.push(new Label(tok));
next();
continue;
}
}
if (tok === end) {
break;
}
if (tok === "/" && peek() === "/" && !end) {
break;
}
switch (tok) {
case "[":
label = null;
children.push(pString());
break;
case "(":
label = null;
children.push(pReporter());
break;
case "<":
label = null;
children.push(pPredicate());
break;
case "{":
label = null;
children.push(pEmbedded());
break;
case " ":
case "\t":
next(); // Skip over whitespace.
label = null;
break;
case "â—‚":
case "â–¸":
children.push(pIcon());
label = null;
break;
case "@":
{
next();
var name = "";
while (tok && /[a-zA-Z]/.test(tok)) {
name += tok;
next();
}
if (name === "cloud") {
children.push(new Label("â˜"));
} else {
children.push(Object.prototype.hasOwnProperty.call(Icon.icons, name) ? new Icon(name) : new Label("@" + name));
}
label = null;
break;
}
case "\\":
next();
// escape character
// fallthrough
case ":":
if (tok === ":" && peek() === ":") {
children.push(pOverrides(end));
return children;
}
// fallthrough
default:
if (!label) {
children.push(label = new Label(""));
}
label.value += tok;
next();
}
}
return children;
}
function pString() {
next(); // '['
var s = "";
var escapeV = false;
while (tok && tok !== "]" && tok !== "\n") {
if (tok === "\\") {
next();
if (tok === "v") {
escapeV = true;
}
if (!tok) {
break;
}
} else {
escapeV = false;
}
s += tok;
next();
}
if (tok === "]") {
next();
}
if (hexColorPat.test(s)) {
return new Input("color", s);
}
return !escapeV && / v$/.test(s) ? makeMenu("dropdown", s.slice(0, s.length - 2)) : new Input("string", s);
}
function pBlock(end) {
var children = pParts(end);
if (tok && tok === "\n") {
sawNL = true;
next();
}
if (children.length === 0) {
return;
}
// standalone reporters
if (children.length === 1) {
var child = children[0];
if (child.isBlock && (child.isReporter || child.isBoolean || child.isRing)) {
return child;
}
}
return makeBlock("stack", children);
}
function pReporter() {
next(); // '('
// empty number-dropdown
if (tok === " ") {
next();
if (tok === "v" && peek() === ")") {
next();
next();
return new Input("number-dropdown", "");
}
}
var children = pParts(")");
if (tok && tok === ")") {
next();
}
// empty numbers
if (children.length === 0) {
return new Input("number", "");
}
// number
if (children.length === 1 && children[0].isLabel) {
var value = children[0].value;
if (/^[0-9e.-]*$/.test(value)) {
return new Input("number", value);
}
if (hexColorPat.test(value)) {
return new Input("color", value);
}
}
// number-dropdown
if (children.length > 1 && children.every(function (child) {
return child.isLabel;
})) {
var last = children[children.length - 1];
if (last.value === "v") {
children.pop();
var _value = children.map(function (l) {
return l.value;
}).join(" ");
return makeMenu("number-dropdown", _value);
}
}
var block = makeBlock("reporter", children);
// rings
if (block.info && block.info.shape === "ring") {
var first = block.children[0];
if (first && first.isInput && first.shape === "number" && first.value === "") {
block.children[0] = new Input("reporter");
} else if (first && first.isScript && first.isEmpty || first && first.isBlock && !first.children.length) {
block.children[0] = new Input("stack");
}
}
return block;
}
function pPredicate() {
next(); // '<'
var children = pParts(">");
if (tok && tok === ">") {
next();
}
if (children.length === 0) {
return new Input("boolean");
}
return makeBlock("boolean", children);
}
function pEmbedded() {
next(); // '{'
sawNL = false;
var f = function f() {
while (tok && tok !== "}") {
var block = pBlock("}");
if (block) {
return block;
}
}
};
var scripts = parseScripts(f);
var blocks = [];
scripts.forEach(function (script) {
blocks = blocks.concat(script.blocks);
});
if (tok === "}") {
next();
}
if (!sawNL) {
assert$1(blocks.length <= 1);
return blocks.length ? blocks[0] : makeBlock("stack", []);
}
return new Script(blocks);
}
function pIcon() {
var c = tok;
next();
switch (c) {
case "â–¸":
return new Icon("addInput");
case "â—‚":
return new Icon("delInput");
default:
return;
}
}
function pOverrides(end) {
next();
next();
var overrides = [];
var override = "";
while (tok && tok !== "\n" && tok !== end) {
if (tok === " ") {
if (override) {
overrides.push(override);
override = "";
}
} else if (tok === "/" && peek() === "/") {
break;
} else {
override += tok;
}
next();
}
if (override) {
overrides.push(override);
}
return overrides;
}
function pComment(end) {
next();
next();
var comment = "";
while (tok && tok !== "\n" && tok !== end) {
comment += tok;
next();
}
if (tok && tok === "\n") {
next();
}
return new Comment(comment, true);
}
function pLine() {
var diff;
if (tok === "+" || tok === "-") {
diff = tok;
next();
}
var block = pBlock();
if (tok === "/" && peek() === "/") {
var comment = pComment();
comment.hasBlock = block && block.children.length;
if (!comment.hasBlock) {
return comment;
}
block.comment = comment;
}
if (block) {
block.diff = diff;
}
return block;
}
return function () {
if (!tok) {
return undefined;
}
var line = pLine();
return line || "NL";
};
}
/* * */
function parseScripts(getLine) {
var line = getLine();
function next() {
line = getLine();
}
function pFile() {
while (line === "NL") {
next();
}
var scripts = [];
while (line) {
var blocks = [];
while (line && line !== "NL") {
var b = pLine();
var isGlow = b.diff === "+";
if (isGlow) {
b.diff = null;
}
if (b.isElse || b.isEnd) {
b = new Block(_objectSpread2(_objectSpread2({}, b.info), {}, {
shape: "stack"
}), b.children);
}
if (isGlow) {
var last = blocks[blocks.length - 1];
var children = [];
if (last && last.isGlow) {
blocks.pop();
children = last.child.isScript ? last.child.blocks : [last.child];
}
children.push(b);
blocks.push(new Glow(new Script(children)));
} else if (b.isHat) {
if (blocks.length) {
scripts.push(new Script(blocks));
}
blocks = [b];
} else if (b.isFinal) {
blocks.push(b);
break;
} else if (b.isCommand) {
blocks.push(b);
} else {
// reporter or predicate
if (blocks.length) {
scripts.push(new Script(blocks));
}
scripts.push(new Script([b]));
blocks = [];
break;
}
}
if (blocks.length) {
scripts.push(new Script(blocks));
}
while (line === "NL") {
next();
}
}
return scripts;
}
function pLine() {
var b = line;
next();
if (b.hasScript) {
while (true) {
var blocks = pMouth();
b.children.push(new Script(blocks));
if (line && line.isElse) {
var _iterator3 = _createForOfIteratorHelper(line.children),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var child = _step3.value;
b.children.push(child);
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
next();
continue;
}
if (line && line.isEnd) {
next();
}
break;
}
}
return b;
}
function pMouth() {
var blocks = [];
while (line) {
if (line === "NL") {
next();
continue;
}
if (!line.isCommand) {
return blocks;
}
var b = pLine();
var isGlow = b.diff === "+";
if (isGlow) {
b.diff = null;
}
if (isGlow) {
var last = blocks[blocks.length - 1];
var children = [];
if (last && last.isGlow) {
blocks.pop();
children = last.child.isScript ? last.child.blocks : [last.child];
}
children.push(b);
blocks.push(new Glow(new Script(children)));
} else {
blocks.push(b);
}
}
return blocks;
}
return pFile();
}
/* * */
function eachBlock(x, cb) {
if (x.isScript) {
x.blocks = x.blocks.map(function (block) {
eachBlock(block, cb);
return cb(block) || block;
});
} else if (x.isBlock) {
x.children = x.children.map(function (child) {
eachBlock(child, cb);
return cb(child) || child;
});
} else if (x.isGlow) {
eachBlock(x.child, cb);
}
}
var listBlocks = {
"append:toList:": 1,
"deleteLine:ofList:": 1,
"insert:at:ofList:": 2,
"setLine:ofList:to:": 1,
"showList:": 0,
"hideList:": 0
};
function recogniseStuff(scripts) {
var customBlocksByHash = Object.create(null);
var listNames = new Set();
scripts.forEach(function (script) {
var customArgs = new Set();
eachBlock(script, function (block) {
if (!block.isBlock) {
return;
}
// custom blocks
if (block.info.shape === "define-hat") {
// There should be exactly one `outline` child, added in paintBlock.
var outline = block.children.find(function (child) {
return child.isOutline;
});
if (!outline) {
return;
}
var names = [];
var parts = [];
var _iterator4 = _createForOfIteratorHelper(outline.children),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var child = _step4.value;
if (child.isLabel) {
parts.push(child.value);
} else if (child.isBlock) {
if (!child.info.argument) {
return;
}
parts.push({
number: "%n",
string: "%s",
boolean: "%b"
}[child.info.argument]);
var name = blockName(child);
names.push(name);
customArgs.add(name);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
var spec = parts.join(" ");
var hash = hashSpec(spec);
var info = {
spec: spec,
names: names
};
if (!customBlocksByHash[hash]) {
customBlocksByHash[hash] = info;
}
block.info.id = "PROCEDURES_DEFINITION";
block.info.selector = "procDef";
block.info.call = info.spec;
block.info.names = info.names;
block.info.category = "custom";
// custom arguments
} else if (block.info.categoryIsDefault && (block.isReporter || block.isBoolean)) {
var _name = blockName(block);
if (customArgs.has(_name)) {
block.info.category = "custom-arg";
block.info.categoryIsDefault = false;
block.info.selector = "getParam";
}
// list names
} else if (Object.prototype.hasOwnProperty.call(listBlocks, block.info.selector)) {
var argIndex = listBlocks[block.info.selector];
var inputs = block.children.filter(function (child) {
return !child.isLabel;
});
var input = inputs[argIndex];
if (input && input.isInput) {
listNames.add(input.value);
}
}
});
});
scripts.forEach(function (script) {
eachBlock(script, function (block) {
if (block.info && block.info.categoryIsDefault && block.info.category === "obsolete") {
// custom blocks
var _info = customBlocksByHash[block.info.hash];
if (_info) {
block.info.selector = "call";
block.info.call = _info.spec;
block.info.names = _info.names;
block.info.category = "custom";
}
return;
}
var name, info;
if (block.isReporter && block.info.category === "variables" && block.info.categoryIsDefault) {
// We set the selector here for some reason
block.info.selector = "readVariable";
name = blockName(block);
info = block.info;
}
if (!name) {
return;
}
// list reporters
if (listNames.has(name)) {
info.category = "list";
info.categoryIsDefault = false;
info.selector = "contentsOfList:";
}
return; // already done
});
});
}
function parse(code, options) {
options = _objectSpread2({
inline: false,
languages: ["en"]
}, options);
if (options.dialect) {
throw new Error("Option 'dialect' no longer supported");
}
code = code.replace(/</g, "<");
code = code.replace(/>/g, ">");
if (options.inline) {
code = code.replace(/\n/g, " ");
}
var languages = options.languages.map(function (code) {
var lang = allLanguages[code];
if (!lang) {
throw new Error("Unknown language: '" + code + "'");
}
return lang;
});
/* * */
var f = parseLines(code, languages);
var scripts = parseScripts(f);
recogniseStuff(scripts);
return new Document(scripts);
}
/* for constructing SVGs */
function assert(bool, message) {
if (!bool) {
throw new Error("Assertion failed! " + (message || ""));
}
}
// set by SVG.init
var document$1;
var xml$1;
var directProps$1 = {
textContent: true
};
var SVG$1 = /*#__PURE__*/function () {
function SVG() { }
_createClass(SVG, null, [{
key: "init",
value: function init(window) {
document$1 = window.document;
var DOMParser = window.DOMParser;
xml$1 = new DOMParser().parseFromString("<xml></xml>", "application/xml");
SVG.XMLSerializer = window.XMLSerializer;
}
}, {
key: "makeCanvas",
value: function makeCanvas() {
return document$1.createElement("canvas");
}
}, {
key: "cdata",
value: function cdata(content) {
return xml$1.createCDATASection(content);
}
}, {
key: "el",
value: function el(name, props) {
var el = document$1.createElementNS("http://www.w3.org/2000/svg", name);
return SVG.setProps(el, props);
}
}, {
key: "setProps",
value: function setProps(el, props) {
for (var key in props) {
var value = String(props[key]);
if (directProps$1[key]) {
el[key] = value;
} else if (props[key] != null && Object.prototype.hasOwnProperty.call(props, key)) {
el.setAttributeNS(null, key, value);
}
}
return el;
}
}, {
key: "withChildren",
value: function withChildren(el, children) {
var _iterator = _createForOfIteratorHelper(children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
el.appendChild(child);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return el;
}
}, {
key: "group",
value: function group(children) {
return SVG.withChildren(SVG.el("g"), children);
}
}, {
key: "newSVG",
value: function newSVG(width, height, scale) {
return SVG.el("svg", {
version: "1.1",
width: width * scale,
height: height * scale,
viewBox: "0 0 " + width + " " + height
});
}
}, {
key: "polygon",
value: function polygon(props) {
return SVG.el("polygon", _objectSpread2(_objectSpread2({}, props), {}, {
points: props.points.join(" ")
}));
}
}, {
key: "path",
value: function path(props) {
return SVG.el("path", _objectSpread2(_objectSpread2({}, props), {}, {
path: null,
d: props.path.join(" ")
}));
}
}, {
key: "text",
value: function text(x, y, content, props) {
var text = SVG.el("text", _objectSpread2(_objectSpread2({}, props), {}, {
x: x,
y: y,
textContent: content
}));
return text;
}
}, {
key: "symbol",
value: function symbol(href) {
return SVG.el("use", {
href: href
});
}
}, {
key: "move",
value: function move(dx, dy, el) {
SVG.setProps(el, {
transform: "translate(" + dx + " " + dy + ")"
});
return el;
}
// translatePath takes a path string such as "M 0 0 L 0 10 L 10 0 Z", fins
// the individual X/Y components, and translates them by dx/dy, so as to
// "move" the path.
//
// This is not a particularly good way of doing this, but given we control
// the inputs to it it works well enough I guess?
}, {
key: "translatePath",
value: function translatePath(dx, dy, path) {
var isX = true;
var parts = path.split(/\s+/);
var out = [];
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part === "A") {
var j = i + 5;
out.push("A");
while (i < j) {
out.push(parts[++i]);
}
continue;
} else if (/[A-Za-z]/.test(part)) {
// This assertion means the path was not a valid sequence of
// [operation, X coordinate, Y coordinate, ...].
//
// It could indicate missing whitespace between the coordinates and the
// operation.
assert(isX, "translatePath: invalid argument");
} else {
part = +part;
part += isX ? dx : dy;
isX = !isX;
}
out.push(part);
}
return out.join(" ");
}
/* shapes */
}, {
key: "rect",
value: function rect(w, h, props) {
return SVG.el("rect", _objectSpread2(_objectSpread2({}, props), {}, {
x: 0,
y: 0,
width: w,
height: h
}));
}
}, {
key: "ellipse",
value: function ellipse(w, h, props) {
return SVG.el("ellipse", _objectSpread2(_objectSpread2({}, props), {}, {
cx: w / 2,
cy: h / 2,
rx: w / 2,
ry: h / 2
}));
}
}, {
key: "arc",
value: function arc(p1x, p1y, p2x, p2y, rx, ry) {
return "L " + p1x + " " + p1y + " A " + rx + " " + ry + " 0 0 1 " + p2x + " " + p2y;
}
}, {
key: "arcw",
value: function arcw(p1x, p1y, p2x, p2y, rx, ry) {
return "L " + p1x + " " + p1y + " A " + rx + " " + ry + " 0 0 0 " + p2x + " " + p2y;
}
}, {
key: "roundedPath",
value: function roundedPath(w, h) {
var r = h / 2;
return ["M", r, 0, SVG.arc(w - r, 0, w - r, h, r, r), SVG.arc(r, h, r, 0, r, r), "Z"];
}
}, {
key: "roundedRect",
value: function roundedRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: SVG.roundedPath(w, h)
}));
}
}, {
key: "pointedPath",
value: function pointedPath(w, h) {
var r = h / 2;
return ["M", r, 0, "L", w - r, 0, w, r, "L", w, r, w - r, h, "L", r, h, 0, r, "L", 0, r, r, 0, "Z"];
}
}, {
key: "pointedRect",
value: function pointedRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: SVG.pointedPath(w, h)
}));
}
}, {
key: "getTop",
value: function getTop(w) {
return "M 0 3\n L 3 0\n L 13 0\n L 16 3\n L 24 3\n L 27 0\n L " + (w - 3) + " 0\n L " + w + " 3";
}
}, {
key: "getRingTop",
value: function getRingTop(w) {
return "M 0 3\n L 3 0\n L 7 0\n L 10 3\n L 16 3\n L 19 0\n L " + (w - 3) + " 0\n L " + w + " 3";
}
}, {
key: "getRightAndBottom",
value: function getRightAndBottom(w, y, hasNotch, inset) {
if (typeof inset === "undefined") {
inset = 0;
}
var arr = ["L", w, y - 3, "L", w - 3, y];
if (hasNotch) {
arr = arr.concat(["L", inset + 27, y, "L", inset + 24, y + 3, "L", inset + 16, y + 3, "L", inset + 13, y]);
}
if (inset > 0) {
arr = arr.concat(["L", inset + 2, y, "L", inset, y + 2]);
} else {
arr = arr.concat(["L", inset + 3, y, "L", 0, y - 3]);
}
return arr.join(" ");
}
}, {
key: "getArm",
value: function getArm(w, armTop) {
return "L 15 " + (armTop - 2) + "\n L 17 " + armTop + "\n L " + (w - 3) + " " + armTop + "\n L " + w + " " + (armTop + 3);
}
}, {
key: "stackRect",
value: function stackRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: [SVG.getTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"]
}));
}
}, {
key: "capPath",
value: function capPath(w, h) {
return [SVG.getTop(w), SVG.getRightAndBottom(w, h, false, 0), "Z"];
}
}, {
key: "capRect",
value: function capRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: SVG.capPath(w, h)
}));
}
}, {
key: "hatRect",
value: function hatRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: ["M", 0, 12, SVG.arc(0, 12, 80, 10, 80, 80), "L", w - 3, 10, "L", w, 10 + 3, SVG.getRightAndBottom(w, h, true), "Z"]
}));
}
}, {
key: "curve",
value: function curve(p1x, p1y, p2x, p2y, roundness) {
roundness = roundness || 0.42;
var midX = (p1x + p2x) / 2.0;
var midY = (p1y + p2y) / 2.0;
var cx = Math.round(midX + roundness * (p2y - p1y));
var cy = Math.round(midY - roundness * (p2x - p1x));
return cx + " " + cy + " " + p2x + " " + p2y;
}
}, {
key: "procHatBase",
value: function procHatBase(w, h, archRoundness, props) {
// TODO use arc()
archRoundness = Math.min(0.2, 35 / w);
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: ["M", 0, 15, "Q", SVG.curve(0, 15, w, 15, archRoundness), SVG.getRightAndBottom(w, h, true), "M", -1, 13, "Q", SVG.curve(-1, 13, w + 1, 13, archRoundness), "Q", SVG.curve(w + 1, 13, w, 16, 0.6), "Q", SVG.curve(w, 16, 0, 16, -archRoundness), "Q", SVG.curve(0, 16, -1, 13, 0.6), "Z"]
}));
}
}, {
key: "procHatCap",
value: function procHatCap(w, h, archRoundness) {
// TODO use arc()
// TODO this doesn't look quite right
return SVG.path({
path: ["M", -1, 13, "Q", SVG.curve(-1, 13, w + 1, 13, archRoundness), "Q", SVG.curve(w + 1, 13, w, 16, 0.6), "Q", SVG.curve(w, 16, 0, 16, -archRoundness), "Q", SVG.curve(0, 16, -1, 13, 0.6), "Z"],
class: "sb-define-hat-cap"
});
}
}, {
key: "procHatRect",
value: function procHatRect(w, h, props) {
var q = 52;
var y = h - q;
var archRoundness = Math.min(0.2, 35 / w);
return SVG.move(0, y, SVG.group([SVG.procHatBase(w, q, archRoundness, props), SVG.procHatCap(w, q, archRoundness)]));
}
}, {
key: "mouthRect",
value: function mouthRect(w, h, isFinal, lines, props) {
var y = lines[0].height;
var p = [SVG.getTop(w), SVG.getRightAndBottom(w, y, true, 15)];
for (var i = 1; i < lines.length; i += 2) {
var isLast = i + 2 === lines.length;
y += lines[i].height - 3;
p.push(SVG.getArm(w, y));
var hasNotch = !(isLast && isFinal);
var inset = isLast ? 0 : 15;
y += lines[i + 1].height + 3;
p.push(SVG.getRightAndBottom(w, y, hasNotch, inset));
}
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: p
}));
}
}, {
key: "ringRect",
value: function ringRect(w, h, cy, cw, ch, shape, props) {
var r = 8;
var func = shape === "reporter" ? SVG.roundedPath : shape === "boolean" ? SVG.pointedPath : SVG.capPath;
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: ["M", r, 0, SVG.arcw(r, 0, 0, r, r, r), SVG.arcw(0, h - r, r, h, r, r), SVG.arcw(w - r, h, w, h - r, r, r), SVG.arcw(w, r, w - r, 0, r, r), "Z", SVG.translatePath(4, cy || 4, func(cw, ch).join(" "))],
"fill-rule": "even-odd"
}));
}
}, {
key: "commentRect",
value: function commentRect(w, h, props) {
var r = 6;
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
class: "sb-comment",
path: ["M", r, 0, SVG.arc(w - r, 0, w, r, r, r), SVG.arc(w, h - r, w - r, h, r, r), SVG.arc(r, h, 0, h - r, r, r), SVG.arc(0, r, r, 0, r, r), "Z"]
}));
}
}, {
key: "commentLine",
value: function commentLine(width, props) {
return SVG.move(-width, 9, SVG.rect(width, 2, _objectSpread2(_objectSpread2({}, props), {}, {
class: "sb-comment-line"
})));
}
}, {
key: "strikethroughLine",
value: function strikethroughLine(w, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: ["M", 0, 0, "L", w, 0],
class: "sb-diff sb-diff-del"
}));
}
}]);
return SVG;
}();
var Filter = /*#__PURE__*/function () {
function Filter(id, props) {
this.el = SVG$1.el("filter", _objectSpread2(_objectSpread2({}, props), {}, {
id: id,
x0: "-50%",
y0: "-50%",
width: "200%",
height: "200%"
}));
this.highestId = 0;
}
_createClass(Filter, [{
key: "fe",
value: function fe(name, props, children) {
var shortName = name.toLowerCase().replace(/gaussian|osite/, "");
var id = shortName + "-" + ++this.highestId;
this.el.appendChild(SVG$1.withChildren(SVG$1.el("fe" + name, _objectSpread2(_objectSpread2({}, props), {}, {
result: id
})), children || []));
return id;
}
}, {
key: "comp",
value: function comp(op, in1, in2, props) {
return this.fe("Composite", _objectSpread2(_objectSpread2({}, props), {}, {
operator: op,
in: in1,
in2: in2
}));
}
}, {
key: "subtract",
value: function subtract(in1, in2) {
return this.comp("arithmetic", in1, in2, {
k2: +1,
k3: -1
});
}
}, {
key: "offset",
value: function offset(dx, dy, in1) {
return this.fe("Offset", {
in: in1,
dx: dx,
dy: dy
});
}
}, {
key: "flood",
value: function flood(color, opacity, in1) {
return this.fe("Flood", {
in: in1,
"flood-color": color,
"flood-opacity": opacity
});
}
}, {
key: "blur",
value: function blur(dev, in1) {
return this.fe("GaussianBlur", {
in: in1,
stdDeviation: dev + " " + dev
});
}
}, {
key: "colorMatrix",
value: function colorMatrix(in1, values) {
return this.fe("ColorMatrix", {
in: in1,
type: "matrix",
values: values.join(" ")
});
}
}, {
key: "merge",
value: function merge(children) {
this.fe("Merge", {}, children.map(function (name) {
return SVG$1.el("feMergeNode", {
in: name
});
}));
}
}]);
return Filter;
}();
var cssContent$1 = "\n.sb-label {\n font-family: Lucida Grande, Verdana, Arial, DejaVu Sans, sans-serif;\n font-weight: bold;\n fill: #fff;\n font-size: 10px;\n word-spacing: +1px;\n}\n\n.sb-obsolete {\n fill: #d42828;\n}\n.sb-motion {\n fill: #4a6cd4;\n}\n.sb-looks {\n fill: #8a55d7;\n}\n.sb-sound {\n fill: #bb42c3;\n}\n.sb-pen {\n fill: #0e9a6c;\n}\n.sb-events {\n fill: #c88330;\n}\n.sb-control {\n fill: #e1a91a;\n}\n.sb-sensing {\n fill: #2ca5e2;\n}\n.sb-operators {\n fill: #5cb712;\n}\n.sb-variables {\n fill: #ee7d16;\n}\n.sb-list {\n fill: #cc5b22;\n}\n.sb-custom {\n fill: #632d99;\n}\n.sb-custom-arg {\n fill: #5947b1;\n}\n.sb-extension {\n fill: #4b4a60;\n}\n.sb-grey {\n fill: #969696;\n}\n\n.sb-bevel {\n filter: url(#bevelFilter);\n}\n\n.sb-input {\n filter: url(#inputBevelFilter);\n}\n.sb-input-number,\n.sb-input-string,\n.sb-input-number-dropdown {\n fill: #fff;\n}\n.sb-literal-number,\n.sb-literal-string,\n.sb-literal-number-dropdown,\n.sb-literal-dropdown {\n font-weight: normal;\n font-size: 9px;\n word-spacing: 0;\n}\n.sb-literal-number,\n.sb-literal-string,\n.sb-literal-number-dropdown {\n fill: #000;\n}\n\n.sb-darker {\n filter: url(#inputDarkFilter);\n}\n\n.sb-outline {\n stroke: #fff;\n stroke-opacity: 0.2;\n stroke-width: 2;\n fill: none;\n}\n\n.sb-define-hat-cap {\n stroke: #632d99;\n stroke-width: 1;\n fill: #8e2ec2;\n}\n\n.sb-comment {\n fill: #ffffa5;\n stroke: #d0d1d2;\n stroke-width: 1;\n}\n.sb-comment-line {\n fill: #ffff80;\n}\n.sb-comment-label {\n font-family: Helvetica, Arial, DejaVu Sans, sans-serif;\n font-weight: bold;\n fill: #5c5d5f;\n word-spacing: 0;\n font-size: 12px;\n}\n\n.sb-diff {\n fill: none;\n stroke: #000;\n}\n.sb-diff-ins {\n stroke-width: 2px;\n}\n.sb-diff-del {\n stroke-width: 3px;\n}\n";
var Style$1 = /*#__PURE__*/function () {
function Style() { }
_createClass(Style, null, [{
key: "cssContent",
get: function get() {
return cssContent$1;
}
}, {
key: "makeIcons",
value: function makeIcons() {
return [SVG$1.el("path", {
d: "M1.504 21L0 19.493 4.567 0h1.948l-.5 2.418s1.002-.502 3.006 0c2.006.503 3.008 2.01 6.517 2.01 3.508 0 4.463-.545 4.463-.545l-.823 9.892s-2.137 1.005-5.144.696c-3.007-.307-3.007-2.007-6.014-2.51-3.008-.502-4.512.503-4.512.503L1.504 21z",
fill: "#3f8d15",
id: "greenFlag"
}), SVG$1.el("polygon", {
points: "6.3,0.4725 12.516,0.4725 18.585,6.3 18.585,12.495 12.495,18.585 6.3,18.585 0.483,12.495 0.483,6.3 ",
fill: "#bb0010",
id: "stopSign"
}), SVG$1.el("path", {
d: "M6.724 0C3.01 0 0 2.91 0 6.5c0 2.316 1.253 4.35 3.14 5.5H5.17v-1.256C3.364 10.126 2.07 8.46 2.07 6.5 2.07 4.015 4.152 2 6.723 2c1.14 0 2.184.396 2.993 1.053L8.31 4.13c-.45.344-.398.826.11 1.08L15 8.5 13.858.992c-.083-.547-.514-.714-.963-.37l-1.532 1.172A6.825 6.825 0 0 0 6.723 0z",
fill: "#fff",
id: "turnRight"
}), SVG$1.el("path", {
d: "M3.637 1.794A6.825 6.825 0 0 1 8.277 0C11.99 0 15 2.91 15 6.5c0 2.316-1.253 4.35-3.14 5.5H9.83v-1.256c1.808-.618 3.103-2.285 3.103-4.244 0-2.485-2.083-4.5-4.654-4.5-1.14 0-2.184.396-2.993 1.053L6.69 4.13c.45.344.398.826-.11 1.08L0 8.5 1.142.992c.083-.547.514-.714.963-.37l1.532 1.172z",
fill: "#fff",
id: "turnLeft"
}), SVG$1.el("path", {
d: "M0 0L4 4L0 8Z",
fill: "#111",
id: "addInput"
}), SVG$1.el("path", {
d: "M4 0L4 8L0 4Z",
fill: "#111",
id: "delInput"
}), SVG$1.setProps(SVG$1.group([SVG$1.el("path", {
d: "M8 0l2 -2l0 -3l3 0l-4 -5l-4 5l3 0l0 3l-8 0l0 2",
fill: "#000",
opacity: "0.3"
}), SVG$1.move(-1, -1, SVG$1.el("path", {
d: "M8 0l2 -2l0 -3l3 0l-4 -5l-4 5l3 0l0 3l-8 0l0 2",
fill: "#fff",
opacity: "0.9"
}))]), {
id: "loopArrow"
}), SVG$1.setProps(SVG$1.group([SVG$1.el("rect", {
x: "0",
y: "0",
width: "12",
height: "14",
fill: "#000",
opacity: "0.25"
}), SVG$1.el("rect", {
x: "1",
y: "1",
width: "1",
height: "13",
fill: "#fff"
}), SVG$1.el("rect", {
x: "11",
y: "1",
width: "1",
height: "13",
fill: "#fff"
}), SVG$1.el("rect", {
x: "2",
y: "1",
width: "9",
height: "1",
fill: "#fff"
}), SVG$1.el("rect", {
x: "2",
y: "5",
width: "9",
height: "1",
fill: "#fff"
}), SVG$1.el("rect", {
x: "2",
y: "9",
width: "9",
height: "1",
fill: "#fff"
}), SVG$1.el("rect", {
x: "2",
y: "13",
width: "9",
height: "1",
fill: "#fff"
}), SVG$1.el("rect", {
x: "2",
y: "2",
width: "9",
height: "2",
fill: "#ea8d1c"
}), SVG$1.el("rect", {
x: "2",
y: "6",
width: "9",
height: "2",
fill: "#ea8d1c"
}), SVG$1.el("rect", {
x: "2",
y: "10",
width: "9",
height: "2",
fill: "#ea8d1c"
}), SVG$1.el("rect", {
x: "11",
y: "0",
width: "1",
height: "1",
fill: "#ea8d1c"
}), SVG$1.el("rect", {
x: "0",
y: "13",
width: "1",
height: "1",
fill: "#ea8d1c"
})]), {
id: "list"
})];
}
}, {
key: "makeStyle",
value: function makeStyle() {
var style = SVG$1.el("style");
style.appendChild(SVG$1.cdata(Style.cssContent));
return style;
}
}, {
key: "bevelFilter",
value: function bevelFilter(id, inset) {
var f = new Filter(id);
var alpha = "SourceAlpha";
var s = inset ? -1 : 1;
var blur = f.blur(1, alpha);
f.merge(["SourceGraphic", f.comp("in", f.flood("#fff", 0.15), f.subtract(alpha, f.offset(+s, +s, blur))), f.comp("in", f.flood("#000", 0.7), f.subtract(alpha, f.offset(-s, -s, blur)))]);
return f.el;
}
}, {
key: "darkFilter",
value: function darkFilter(id) {
var f = new Filter(id);
f.merge(["SourceGraphic", f.comp("in", f.flood("#000", 0.2), "SourceAlpha")]);
return f.el;
}
}, {
key: "darkRect",
value: function darkRect(w, h, category, el) {
return SVG$1.setProps(SVG$1.group([SVG$1.setProps(el, {
class: "sb-" + category + " sb-darker"
})]), {
width: w,
height: h
});
}
}, {
key: "defaultFontFamily",
get: function get() {
return "Lucida Grande, Verdana, Arial, DejaVu Sans, sans-serif";
}
}]);
return Style;
}();
var defaultFontFamily = Style$1.defaultFontFamily,
makeStyle$3 = Style$1.makeStyle,
makeIcons = Style$1.makeIcons,
darkRect = Style$1.darkRect,
bevelFilter = Style$1.bevelFilter,
darkFilter = Style$1.darkFilter;
var LabelView$1 = /*#__PURE__*/function () {
function LabelView(label) {
_extends(this, label);
this.el = null;
this.height = 12;
this.metrics = null;
this.x = 0;
}
_createClass(LabelView, [{
key: "isLabel",
get: function get() {
return true;
}
}, {
key: "draw",
value: function draw() {
return this.el;
}
}, {
key: "width",
get: function get() {
return this.metrics.width;
}
}, {
key: "measure",
value: function measure() {
var value = this.value;
var cls = "sb-" + this.cls;
this.el = SVG$1.text(0, 10, value, {
class: "sb-label " + cls
});
var cache = LabelView.metricsCache[cls];
if (!cache) {
cache = LabelView.metricsCache[cls] = Object.create(null);
}
if (Object.hasOwnProperty.call(cache, value)) {
this.metrics = cache[value];
} else {
var font = /comment-label/.test(this.cls) ? "bold 12px Helvetica, Arial, DejaVu Sans, sans-serif" : /literal/.test(this.cls) ? "normal 9px " + defaultFontFamily : "bold 10px " + defaultFontFamily;
this.metrics = cache[value] = LabelView.measure(value, font);
// TODO: word-spacing? (fortunately it seems to have no effect!)
}
}
}], [{
key: "measure",
value: function measure(value, font) {
var context = LabelView.measuring;
context.font = font;
var textMetrics = context.measureText(value);
var width = textMetrics.width + 0.5 | 0;
return {
width: width
};
}
}]);
return LabelView;
}();
LabelView$1.metricsCache = {};
LabelView$1.toMeasure = [];
var IconView$1 = /*#__PURE__*/function () {
function IconView(icon) {
_extends(this, icon);
var info = IconView.icons[this.name];
if (!info) {
throw new Error("no info for icon: " + this.name);
}
_extends(this, info);
}
_createClass(IconView, [{
key: "isIcon",
get: function get() {
return true;
}
}, {
key: "draw",
value: function draw() {
return SVG$1.symbol("#" + this.name, {
width: this.width,
height: this.height
});
}
}], [{
key: "icons",
get: function get() {
return {
greenFlag: {
width: 20,
height: 21,
dy: -2
},
stopSign: {
width: 20,
height: 20
},
turnLeft: {
width: 15,
height: 12,
dy: +1
},
turnRight: {
width: 15,
height: 12,
dy: +1
},
loopArrow: {
width: 14,
height: 11
},
addInput: {
width: 4,
height: 8
},
delInput: {
width: 4,
height: 8
},
list: {
width: 12,
height: 14
}
};
}
}]);
return IconView;
}();
var InputView$1 = /*#__PURE__*/function () {
function InputView(input) {
_extends(this, input);
if (input.label) {
this.label = newView$1(input.label);
}
this.x = 0;
}
_createClass(InputView, [{
key: "measure",
value: function measure() {
if (this.hasLabel) {
this.label.measure();
}
}
}, {
key: "draw",
value: function draw(parent) {
var w;
var label;
if (this.hasLabel) {
label = this.label.draw();
w = Math.max(14, this.label.width + (this.shape === "string" || this.shape === "number-dropdown" ? 6 : 9));
} else {
w = this.isInset ? 30 : this.isColor ? 13 : null;
}
if (this.hasArrow) {
w += 10;
}
this.width = w;
var h = this.height = this.isRound || this.isColor ? 13 : 14;
var el = InputView.shapes[this.shape](w, h);
if (this.isColor) {
SVG$1.setProps(el, {
fill: this.value
});
} else if (this.isDarker) {
el = darkRect(w, h, parent.info.category, el);
if (parent.info.color) {
SVG$1.setProps(el, {
fill: parent.info.color
});
}
}
var result = SVG$1.group([SVG$1.setProps(el, {
class: "sb-input sb-input-" + this.shape
})]);
if (this.hasLabel) {
var x = this.isRound ? 5 : 4;
result.appendChild(SVG$1.move(x, 0, label));
}
if (this.hasArrow) {
var y = this.shape === "dropdown" ? 5 : 4;
result.appendChild(SVG$1.move(w - 10, y, SVG$1.polygon({
points: [7, 0, 3.5, 4, 0, 0],
fill: "#000",
opacity: "0.6"
})));
}
return result;
}
}], [{
key: "shapes",
get: function get() {
return {
string: SVG$1.rect,
number: SVG$1.roundedRect,
"number-dropdown": SVG$1.roundedRect,
color: SVG$1.rect,
dropdown: SVG$1.rect,
boolean: SVG$1.pointedRect,
stack: SVG$1.stackRect,
reporter: SVG$1.roundedRect
};
}
}]);
return InputView;
}();
var BlockView$1 = /*#__PURE__*/function () {
function BlockView(block) {
_extends(this, block);
this.children = block.children.map(newView$1);
this.comment = this.comment ? newView$1(this.comment) : null;
if (Object.prototype.hasOwnProperty.call(aliasExtensions, this.info.category)) {
// handle aliases first
this.info.category = aliasExtensions[this.info.category];
}
if (Object.prototype.hasOwnProperty.call(movedExtensions, this.info.category)) {
this.info.category = movedExtensions[this.info.category];
} else if (Object.prototype.hasOwnProperty.call(extensions, this.info.category)) {
this.info.category = "extension";
}
this.x = 0;
this.width = null;
this.height = null;
this.firstLine = null;
this.innerWidth = null;
}
_createClass(BlockView, [{
key: "isBlock",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
var _iterator = _createForOfIteratorHelper(this.children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child.measure) {
child.measure();
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (this.comment) {
this.comment.measure();
}
}
}, {
key: "drawSelf",
value: function drawSelf(w, h, lines) {
// mouths
if (lines.length > 1) {
return SVG$1.mouthRect(w, h, this.isFinal, lines, {
class: "sb-" + this.info.category + " sb-bevel"
});
}
// outlines
if (this.info.shape === "outline") {
return SVG$1.setProps(SVG$1.stackRect(w, h), {
class: "sb-outline"
});
}
// rings
if (this.isRing) {
var child = this.children[0];
// We use isStack for InputView; isBlock for BlockView; isScript for ScriptView.
if (child && (child.isStack || child.isBlock || child.isScript)) {
var shape = child.isScript ? "stack" : child.isStack ? child.shape : child.info.shape;
return SVG$1.ringRect(w, h, child.y, child.width, child.height, shape, {
class: "sb-" + this.info.category + " sb-bevel"
});
}
}
var func = BlockView.shapes[this.info.shape];
if (!func) {
throw new Error("no shape func: " + this.info.shape);
}
return func(w, h, {
class: "sb-" + this.info.category + " sb-bevel"
});
}
}, {
key: "minDistance",
value: function minDistance(child) {
if (this.isBoolean) {
return child.isReporter ? 4 + child.height / 4 | 0 : child.isLabel ? 5 + child.height / 2 | 0 : child.isBoolean || child.shape === "boolean" ? 5 : 2 + child.height / 2 | 0;
}
if (this.isReporter) {
return child.isInput && child.isRound || (child.isReporter || child.isBoolean) && !child.hasScript ? 0 : child.isLabel ? 2 + child.height / 2 | 0 : -2 + child.height / 2 | 0;
}
return 0;
}
}, {
key: "draw",
value: function draw() {
var isDefine = this.info.shape === "define-hat";
var children = this.children;
var padding = BlockView.padding[this.info.shape] || BlockView.padding.null;
var pt = padding[0];
var px = padding[1];
var pb = padding[2];
var y = 0;
var Line = function Line(y) {
this.y = y;
this.width = 0;
this.height = y ? 13 : 16;
this.children = [];
};
var innerWidth = 0;
var scriptWidth = 0;
var line = new Line(y);
var pushLine = function pushLine(isLast) {
if (lines.length === 0) {
line.height += pt + pb;
} else {
line.height += isLast ? 0 : +2;
line.y -= 1;
}
y += line.height;
lines.push(line);
};
if (this.info.isRTL) {
var start = 0;
var flip = function flip() {
children = children.slice(0, start).concat(children.slice(start, i).reverse()).concat(children.slice(i));
};
var i;
for (i = 0; i < children.length; i++) {
if (children[i].isScript) {
flip();
start = i + 1;
}
}
if (start < i) {
flip();
}
}
var lines = [];
for (var _i = 0; _i < children.length; _i++) {
var child = children[_i];
child.el = child.draw(this);
if (child.isScript && this.isCommand) {
this.hasScript = true;
pushLine();
child.y = y;
lines.push(child);
scriptWidth = Math.max(scriptWidth, Math.max(1, child.width));
child.height = Math.max(12, child.height) + 3;
y += child.height;
line = new Line(y);
} else if (child.isArrow) {
line.children.push(child);
} else {
var cmw = _i > 0 ? 30 : 0; // 27
var md = this.isCommand ? 0 : this.minDistance(child);
var mw = this.isCommand ? child.isBlock || child.isInput ? cmw : 0 : md;
if (mw && !lines.length && line.width < mw - px) {
line.width = mw - px;
}
child.x = line.width;
line.width += child.width;
innerWidth = Math.max(innerWidth, line.width + Math.max(0, md - px));
line.width += 4;
if (!child.isLabel) {
line.height = Math.max(line.height, child.height);
}
line.children.push(child);
}
}
pushLine(true);
innerWidth = Math.max(innerWidth + px * 2, this.isHat || this.hasScript ? 83 : this.isCommand || this.isOutline || this.isRing ? 39 : 20);
this.height = y;
this.width = scriptWidth ? Math.max(innerWidth, 15 + scriptWidth) : innerWidth;
if (isDefine) {
var p = Math.min(26, 3.5 + 0.13 * innerWidth | 0) - 18;
this.height += p;
pt += 2 * p;
}
this.firstLine = lines[0];
this.innerWidth = innerWidth;
var objects = [];
for (var _i2 = 0, _lines = lines; _i2 < _lines.length; _i2++) {
var _line = _lines[_i2];
if (_line.isScript) {
objects.push(SVG$1.move(15, _line.y, _line.el));
continue;
}
var h = _line.height;
var _iterator2 = _createForOfIteratorHelper(_line.children),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _child = _step2.value;
if (_child.isArrow) {
objects.push(SVG$1.move(innerWidth - 15, this.height - 3, _child.el));
continue;
}
var _y = pt + (h - _child.height - pt - pb) / 2 - 1;
if (isDefine && _child.isLabel) {
_y += 3;
} else if (_child.isIcon) {
_y += _child.dy | 0;
}
if (this.isRing) {
_child.y = _line.y + _y | 0;
if (_child.isInset) {
continue;
}
}
objects.push(SVG$1.move(px + _child.x, _line.y + _y | 0, _child.el));
if (_child.diff === "+") {
var ellipse = SVG$1.insEllipse(_child.width, _child.height);
objects.push(SVG$1.move(px + _child.x, _line.y + _y | 0, ellipse));
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
var el = this.drawSelf(innerWidth, this.height, lines);
objects.splice(0, 0, el);
if (this.info.color) {
SVG$1.setProps(el, {
fill: this.info.color
});
}
return SVG$1.group(objects);
}
}], [{
key: "shapes",
get: function get() {
return {
stack: SVG$1.stackRect,
"c-block": SVG$1.stackRect,
"if-block": SVG$1.stackRect,
celse: SVG$1.stackRect,
cend: SVG$1.stackRect,
cap: SVG$1.capRect,
reporter: SVG$1.roundedRect,
boolean: SVG$1.pointedRect,
hat: SVG$1.hatRect,
cat: SVG$1.hatRect,
"define-hat": SVG$1.procHatRect,
ring: SVG$1.roundedRect
};
}
}, {
key: "padding",
get: function get() {
return {
hat: [15, 6, 2],
cat: [15, 6, 2],
"define-hat": [21, 8, 9],
reporter: [3, 4, 1],
boolean: [3, 4, 2],
cap: [6, 6, 2],
"c-block": [3, 6, 2],
"if-block": [3, 6, 2],
ring: [4, 4, 2],
null: [4, 6, 2]
};
}
}]);
return BlockView;
}();
var CommentView$1 = /*#__PURE__*/function () {
function CommentView(comment) {
_extends(this, comment);
this.label = newView$1(comment.label);
this.width = null;
}
_createClass(CommentView, [{
key: "isComment",
get: function get() {
return true;
}
}, {
key: "height",
get: function get() {
return 20;
}
}, {
key: "measure",
value: function measure() {
this.label.measure();
}
}, {
key: "draw",
value: function draw() {
var labelEl = this.label.draw();
this.width = this.label.width + 16;
return SVG$1.group([SVG$1.commentLine(this.hasBlock ? CommentView.lineLength : 0, 6), SVG$1.commentRect(this.width, this.height, {
class: "sb-comment"
}), SVG$1.move(8, 4, labelEl)]);
}
}], [{
key: "lineLength",
get: function get() {
return 12;
}
}]);
return CommentView;
}();
var GlowView$1 = /*#__PURE__*/function () {
function GlowView(glow) {
_extends(this, glow);
this.child = newView$1(glow.child);
this.width = null;
this.height = null;
this.y = 0;
}
_createClass(GlowView, [{
key: "isGlow",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
this.child.measure();
}
}, {
key: "drawSelf",
value: function drawSelf() {
var c = this.child;
var el;
var w = this.width;
var h = this.height - 1;
if (c.isScript) {
if (!c.isEmpty && c.blocks[0].isHat) {
el = SVG$1.hatRect(w, h);
} else if (c.isFinal) {
el = SVG$1.capRect(w, h);
} else {
el = SVG$1.stackRect(w, h);
}
} else {
el = c.drawSelf(w, h, []);
}
return SVG$1.setProps(el, {
class: "sb-diff sb-diff-ins"
});
}
// TODO how can we always raise Glows above their parents?
}, {
key: "draw",
value: function draw() {
var c = this.child;
var el = c.isScript ? c.draw(true) : c.draw();
this.width = c.width;
this.height = c.isBlock && c.firstLine.height || c.height;
// encircle
return SVG$1.group([el, this.drawSelf()]);
}
}]);
return GlowView;
}();
var ScriptView$1 = /*#__PURE__*/function () {
function ScriptView(script) {
_extends(this, script);
this.blocks = script.blocks.map(newView$1);
this.y = 0;
}
_createClass(ScriptView, [{
key: "isScript",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
var _iterator3 = _createForOfIteratorHelper(this.blocks),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var block = _step3.value;
block.measure();
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
}, {
key: "draw",
value: function draw(inside) {
var children = [];
var y = 0;
this.width = 0;
var _iterator4 = _createForOfIteratorHelper(this.blocks),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var block = _step4.value;
var x = inside ? 0 : 2;
var child = block.draw();
children.push(SVG$1.move(x, y, child));
this.width = Math.max(this.width, block.width);
var diff = block.diff;
if (diff === "-") {
var dw = block.width;
var dh = block.firstLine.height || block.height;
children.push(SVG$1.move(x, y + dh / 2 + 1, SVG$1.strikethroughLine(dw)));
this.width = Math.max(this.width, block.width);
}
y += block.height;
var comment = block.comment;
if (comment) {
var line = block.firstLine;
var cx = block.innerWidth + 2 + CommentView$1.lineLength;
var cy = y - block.height + line.height / 2;
var el = comment.draw();
children.push(SVG$1.move(cx, cy - comment.height / 2, el));
this.width = Math.max(this.width, cx + comment.width);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
this.height = y;
if (!inside && !this.isFinal) {
this.height += 3;
}
var lastBlock = this.blocks[this.blocks.length - 1];
if (!inside && lastBlock.isGlow) {
this.height += 2; // TODO unbreak this
}
return SVG$1.group(children);
}
}]);
return ScriptView;
}();
var DocumentView$1 = /*#__PURE__*/function () {
function DocumentView(doc, options) {
_extends(this, doc);
this.scripts = doc.scripts.map(newView$1);
this.width = null;
this.height = null;
this.el = null;
this.defs = null;
this.scale = options.scale;
}
_createClass(DocumentView, [{
key: "measure",
value: function measure() {
this.scripts.forEach(function (script) {
return script.measure();
});
}
}, {
key: "render",
value: function render(cb) {
if (typeof cb === "function") {
throw new Error("render() no longer takes a callback");
}
// measure strings
this.measure();
// TODO: separate layout + render steps.
// render each script
var width = 0;
var height = 0;
var elements = [];
var _iterator5 = _createForOfIteratorHelper(this.scripts),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var script = _step5.value;
if (height) {
height += 10;
}
script.y = height;
elements.push(SVG$1.move(0, height, script.draw()));
height += script.height;
width = Math.max(width, script.width + 4);
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
this.width = width;
this.height = height;
// return SVG
var svg = SVG$1.newSVG(width, height, this.scale);
svg.appendChild(this.defs = SVG$1.withChildren(SVG$1.el("defs"), [bevelFilter("bevelFilter", false), bevelFilter("inputBevelFilter", true), darkFilter("inputDarkFilter")].concat(_toConsumableArray(makeIcons()))));
svg.appendChild(SVG$1.group(elements));
this.el = svg;
return svg;
}
/* Export SVG image as XML string */
}, {
key: "exportSVGString",
value: function exportSVGString() {
if (this.el == null) {
throw new Error("call draw() first");
}
var style = makeStyle$3();
this.defs.appendChild(style);
var xml = new SVG$1.XMLSerializer().serializeToString(this.el);
this.defs.removeChild(style);
return xml;
}
/* Export SVG image as data URI */
}, {
key: "exportSVG",
value: function exportSVG() {
var xml = this.exportSVGString();
return "data:image/svg+xml;utf8," + xml.replace(/[#]/g, encodeURIComponent);
}
}, {
key: "toCanvas",
value: function toCanvas(cb, exportScale) {
exportScale = exportScale || 1.0;
var canvas = SVG$1.makeCanvas();
canvas.width = Math.max(1, this.width * exportScale * this.scale);
canvas.height = Math.max(1, this.height * exportScale * this.scale);
var context = canvas.getContext("2d");
var image = new Image();
image.src = this.exportSVG();
image.onload = function () {
context.save();
context.scale(exportScale, exportScale);
context.drawImage(image, 0, 0);
context.restore();
cb(canvas);
};
}
}, {
key: "exportPNG",
value: function exportPNG(cb, scale) {
this.toCanvas(function (canvas) {
if (URL && URL.createObjectURL && Blob && canvas.toBlob) {
canvas.toBlob(function (blob) {
cb(URL.createObjectURL(blob));
}, "image/png");
} else {
cb(canvas.toDataURL("image/png"));
}
}, scale);
}
}]);
return DocumentView;
}();
var viewFor$1 = function viewFor(node) {
switch (node.constructor) {
case Label:
return LabelView$1;
case Icon:
return IconView$1;
case Input:
return InputView$1;
case Block:
return BlockView$1;
case Comment:
return CommentView$1;
case Glow:
return GlowView$1;
case Script:
return ScriptView$1;
case Document:
return DocumentView$1;
default:
throw new Error("no view for " + node.constructor.name);
}
};
var newView$1 = function newView(node, options) {
return new (viewFor$1(node))(node, options);
};
function init$2(window) {
SVG$1.init(window);
LabelView$1.measuring = SVG$1.makeCanvas().getContext("2d");
}
var makeStyle$2 = Style$1.makeStyle;
/* for constructing SVGs */
// set by SVG.init
var document;
var xml;
var directProps = {
textContent: true
};
var SVG = /*#__PURE__*/function () {
function SVG() { }
_createClass(SVG, null, [{
key: "init",
value: function init(window) {
document = window.document;
var DOMParser = window.DOMParser;
xml = new DOMParser().parseFromString("<xml></xml>", "application/xml");
SVG.XMLSerializer = window.XMLSerializer;
}
}, {
key: "makeCanvas",
value: function makeCanvas() {
return document.createElement("canvas");
}
}, {
key: "cdata",
value: function cdata(content) {
return xml.createCDATASection(content);
}
}, {
key: "el",
value: function el(name, props) {
var el = document.createElementNS("http://www.w3.org/2000/svg", name);
return SVG.setProps(el, props);
}
}, {
key: "setProps",
value: function setProps(el, props) {
for (var key in props) {
var value = String(props[key]);
if (directProps[key]) {
el[key] = value;
} else if (props[key] != null && Object.prototype.hasOwnProperty.call(props, key)) {
el.setAttributeNS(null, key, value);
}
}
return el;
}
}, {
key: "withChildren",
value: function withChildren(el, children) {
var _iterator = _createForOfIteratorHelper(children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
el.appendChild(child);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return el;
}
}, {
key: "group",
value: function group(children) {
return SVG.withChildren(SVG.el("g"), children);
}
}, {
key: "newSVG",
value: function newSVG(width, height, scale) {
return SVG.el("svg", {
version: "1.1",
width: width * scale,
height: height * scale,
viewBox: "0 0 " + width * scale + " " + height * scale
});
}
}, {
key: "polygon",
value: function polygon(props) {
return SVG.el("polygon", _objectSpread2(_objectSpread2({}, props), {}, {
points: props.points.join(" ")
}));
}
}, {
key: "path",
value: function path(props) {
return SVG.el("path", _objectSpread2(_objectSpread2({}, props), {}, {
path: null,
d: props.path.join(" ")
}));
}
}, {
key: "text",
value: function text(x, y, content, props) {
var text = SVG.el("text", _objectSpread2(_objectSpread2({}, props), {}, {
x: x,
y: y,
textContent: content
}));
return text;
}
}, {
key: "symbol",
value: function symbol(href) {
return SVG.el("use", {
href: href
});
}
}, {
key: "move",
value: function move(dx, dy, el) {
SVG.setProps(el, {
transform: "translate(" + dx + " " + dy + ")"
});
return el;
}
/* shapes */
}, {
key: "rect",
value: function rect(w, h, props) {
return SVG.el("rect", _objectSpread2(_objectSpread2({}, props), {}, {
x: 0,
y: 0,
width: w,
height: h
}));
}
}, {
key: "roundRect",
value: function roundRect(w, h, props) {
return SVG.rect(w, h, _objectSpread2(_objectSpread2({}, props), {}, {
rx: 4,
ry: 4
}));
}
}, {
key: "pillRect",
value: function pillRect(w, h, props) {
var r = h / 2;
return SVG.rect(w, h, _objectSpread2(_objectSpread2({}, props), {}, {
rx: r,
ry: r
}));
}
}, {
key: "pointedPath",
value: function pointedPath(w, h) {
var r = h / 2;
return ["M " + r + " 0", "L " + (w - r) + " 0 " + w + " " + r, "L " + w + " " + r + " " + (w - r) + " " + h, "L " + r + " " + h + " 0 " + r, "L 0 " + r + " " + r + " 0", "Z"];
}
}, {
key: "pointedRect",
value: function pointedRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: SVG.pointedPath(w, h)
}));
}
}, {
key: "topNotch",
value: function topNotch(w, y) {
return "c 2 0 3 1 4 2\n l 4 4\n c 1 1 2 2 4 2\n h 12\n c 2 0 3 -1 4 -2\n l 4 -4\n c 1 -1 2 -2 4 -2\n L " + (w - 4) + " " + y + "\n a 4 4 0 0 1 4 4";
}
}, {
key: "getTop",
value: function getTop(w) {
return "M 0 4\n A 4 4 0 0 1 4 0\n H 12 " + SVG.topNotch(w, 0);
}
}, {
key: "getRingTop",
value: function getRingTop(w) {
return "M 0 3\n L 3 0\n L 7 0\n L 10 3\n L 16 3\n L 19 0\n L " + (w - 3) + " 0\n L " + w + " 3";
}
}, {
key: "getRightAndBottom",
value: function getRightAndBottom(w, y, hasNotch, inset) {
if (typeof inset === "undefined") {
inset = 0;
}
var arr = ["L " + w + " " + (y - 4), "a 4 4 0 0 1 -4 4"];
if (hasNotch) {
arr = arr.concat(["L " + (inset + 48) + " " + y, "c -2 0 -3 1 -4 2", "l -4 4", "c -1 1 -2 2 -4 2", "h -12", "c -2 0 -3 -1 -4 -2", "l -4 -4", "c -1 -1 -2 -2 -4 -2"]);
}
if (inset === 0) {
arr.push("L", inset + 4, y);
arr.push("a 4 4 0 0 1 -4 -4");
} else {
arr.push("L", inset + 4, y);
arr.push("a 4 4 0 0 0 -4 4");
}
return arr.join(" ");
}
}, {
key: "getArm",
value: function getArm(w, armTop) {
return "L 16 " + (armTop - 4) + "\n a 4 4 0 0 0 4 4\n L 28 " + armTop + " " + SVG.topNotch(w, armTop);
}
}, {
key: "getArmNoNotch",
value: function getArmNoNotch(w, armTop) {
return "L 16 " + (armTop - 4) + "\n a 4 4 0 0 0 4 4\n L 28 " + armTop + " L " + (w - 4) + " " + armTop + "\n a 4 4 0 0 1 4 4";
}
}, {
key: "stackRect",
value: function stackRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: [SVG.getTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"]
}));
}
}, {
key: "capPath",
value: function capPath(w, h) {
return [SVG.getTop(w), SVG.getRightAndBottom(w, h, false, 0), "Z"];
}
}, {
key: "capRect",
value: function capRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: SVG.capPath(w, h)
}));
}
}, {
key: "getHatTop",
value: function getHatTop(w) {
return "M 0 16 c 25,-22 71,-22 96,0 L " + (w - 4) + " 16 a 4 4 0 0 1 4 4";
}
}, {
key: "getCatTop",
value: function getCatTop(w) {
return "M 0 32\n c2.6,-2.3 5.5,-4.3 8.5,-6.2c-1,-12.5 5.3,-23.3 8.4,-24.8c3.7,-1.8 16.5,13.1 18.4,15.4c8.4,-1.3 17,-1.3 25.4,0c1.9,-2.3 14.7,-17.2 18.4,-15.4c3.1,1.5 9.4,12.3 8.4,24.8c3,1.8 5.9,3.9 8.5,6.1\n L " + (w - 4) + " 32\n a 4 4 0 0 1 4 4";
}
}, {
key: "hatRect",
value: function hatRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: [SVG.getHatTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"]
}));
}
}, {
key: "catHat",
value: function catHat(w, h, props) {
return SVG.group([SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: [SVG.getCatTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"]
})), SVG.move(0, 32, SVG.setProps(SVG.group([SVG.el("circle", {
cx: 29.1,
cy: -3.3,
r: 3.4
}), SVG.el("circle", {
cx: 59.2,
cy: -3.3,
r: 3.4
}), SVG.el("path", {
d: "M45.6,0.1c-0.9,0-1.7-0.3-2.3-0.9c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.8-0.3-2.3-0.9c-1-1.1-1.1-2.6-1.1-2.8c0-0.5,0.5-1,1-1l0,0c0.6,0,1,0.5,1,1c0,0.4,0.1,1.7,1.4,1.7c0.5,0,0.7-0.2,0.8-0.3c0.3-0.3,0.4-1,0.4-1.3c0-0.1,0-0.1,0-0.2c0-0.5,0.5-1,1-1l0,0c0.5,0,1,0.4,1,1c0,0,0,0.1,0,0.2c0,0.3,0.1,0.9,0.4,1.2C44.8-2.2,45-2,45.5-2s0.7-0.2,0.8-0.3c0.3-0.4,0.4-1.1,0.3-1.3c0-0.5,0.4-1,0.9-1.1c0.5,0,1,0.4,1.1,0.9c0,0.2,0.1,1.8-0.8,2.8C47.5-0.4,46.8,0.1,45.6,0.1z"
})]), {
fill: "#000",
"fill-opacity": 0.6
})), SVG.move(0, 32, SVG.el("path", {
d: "M73.1-15.6c1.7-4.2,4.5-9.1,5.8-8.5c1.6,0.8,5.4,7.9,5,15.4c0,0.6-0.7,0.7-1.1,0.5c-3-1.6-6.4-2.8-8.6-3.6C72.8-12.3,72.4-13.7,73.1-15.6z",
fill: "#FFD5E6",
transform: "translate(0, 32)"
})), SVG.move(0, 32, SVG.el("path", {
d: "M22.4-15.6c-1.7-4.2-4.5-9.1-5.8-8.5c-1.6,0.8-5.4,7.9-5,15.4c0,0.6,0.7,0.7,1.1,0.5c3-1.6,6.4-2.8,8.6-3.6C22.8-12.3,23.2-13.7,22.4-15.6z",
fill: "#FFD5E6",
transform: "translate(0, 32)"
}))]);
}
}, {
key: "getProcHatTop",
value: function getProcHatTop(w) {
return "M 0 20 a 20 20 0 0 1 20 -20 L " + (w - 20) + " 0 a 20,20 0 0,1 20,20";
}
}, {
key: "procHatRect",
value: function procHatRect(w, h, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: [SVG.getProcHatTop(w), SVG.getRightAndBottom(w, h, true, 0), "Z"]
}));
}
}, {
key: "mouthRect",
value: function mouthRect(w, h, isFinal, lines, props) {
var y = lines[0].height;
var p = [SVG.getTop(w), SVG.getRightAndBottom(w, y, true, 16)];
for (var i = 1; i < lines.length; i += 2) {
var isLast = i + 2 === lines.length;
var line = lines[i];
y += line.height - 3;
if (line.isFinal) {
p.push(SVG.getArmNoNotch(w, y));
} else {
p.push(SVG.getArm(w, y));
}
var hasNotch = !(isLast && isFinal);
var inset = isLast ? 0 : 16;
y += lines[i + 1].height + 3;
p.push(SVG.getRightAndBottom(w, y, hasNotch, inset));
}
p.push("Z");
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: p
}));
}
}, {
key: "commentRect",
value: function commentRect(w, h, props) {
return SVG.roundRect(w, h, _objectSpread2(_objectSpread2({}, props), {}, {
class: "sb3-comment"
}));
}
}, {
key: "commentLine",
value: function commentLine(width, props) {
return SVG.move(-width, 9, SVG.rect(width, 2, _objectSpread2(_objectSpread2({}, props), {}, {
class: "sb3-comment-line"
})));
}
}, {
key: "strikethroughLine",
value: function strikethroughLine(w, props) {
return SVG.path(_objectSpread2(_objectSpread2({}, props), {}, {
path: ["M", 0, 0, "L", w, 0],
class: "sb3-diff sb3-diff-del"
}));
}
}]);
return SVG;
}();
var cssContent = "\n.sb3-label {\n font: 500 12pt Helvetica Neue, Helvetica, sans-serif;\n word-spacing: +1pt;\n}\n\n.sb3-literal-number,\n.sb3-literal-string,\n.sb3-literal-number-dropdown,\n.sb3-literal-dropdown {\n word-spacing: 0;\n}\n\n/* Note: comment colors are different from Scratch. */\n\n.sb3-comment {\n fill: #ffffa5;\n stroke: #d0d1d2;\n stroke-width: 1;\n}\n.sb3-comment-line {\n fill: #ffff80;\n}\n.sb3-comment-label {\n font: 400 12pt Helvetica Neue, Helvetica, sans-serif;\n fill: #000;\n word-spacing: 0;\n}\n\n.sb3-diff {\n fill: 000;\n stroke: #000;\n}\n.sb3-diff-ins {\n stroke-width: 2px;\n}\n.sb3-diff-del {\n stroke-width: 3px;\n}\n\n\nsvg .sb3-motion {\n fill: #4c97ff;\n stroke: #3373cc;\n}\nsvg .sb3-motion-alt {\n fill: #4280d7;\n}\nsvg .sb3-motion-dark {\n fill: #3373cc;\n}\n\n\nsvg .sb3-looks {\n fill: #9966ff;\n stroke: #774dcb;\n}\nsvg .sb3-looks-alt {\n fill: #855cd6;\n}\nsvg .sb3-looks-dark {\n fill: #774dcb;\n}\n\n\nsvg .sb3-sound {\n fill: #cf63cf;\n stroke: #bd42bd;\n}\nsvg .sb3-sound-alt {\n fill: #c94fc9;\n}\nsvg .sb3-sound-dark {\n fill: #bd42bd;\n}\n\n\nsvg .sb3-control {\n fill: #ffab19;\n stroke: #cf8b17;\n}\nsvg .sb3-control-alt {\n fill: #ec9c13;\n}\nsvg .sb3-control-dark {\n fill: #cf8b17;\n}\n\n\nsvg .sb3-events {\n fill: #ffbf00;\n stroke: #cc9900;\n}\nsvg .sb3-events-alt {\n fill: #e6ac00;\n}\nsvg .sb3-events-dark {\n fill: #cc9900;\n}\n\n\nsvg .sb3-sensing {\n fill: #5cb1d6;\n stroke: #2e8eb8;\n}\nsvg .sb3-sensing-alt {\n fill: #47a8d1;\n}\nsvg .sb3-sensing-dark {\n fill: #2e8eb8;\n}\n\n\nsvg .sb3-operators {\n fill: #59c059;\n stroke: #389438;\n}\nsvg .sb3-operators-alt {\n fill: #46b946;\n}\nsvg .sb3-operators-dark {\n fill: #389438;\n}\n\n\nsvg .sb3-variables {\n fill: #ff8c1a;\n stroke: #db6e00;\n}\nsvg .sb3-variables-alt {\n fill: #ff8000;\n}\nsvg .sb3-variables-dark {\n fill: #db6e00;\n}\n\n\nsvg .sb3-list {\n fill: #ff661a;\n stroke: #e64d00;\n}\nsvg .sb3-list-alt {\n fill: #ff5500;\n}\nsvg .sb3-list-dark {\n fill: #e64d00;\n}\n\n\nsvg .sb3-custom {\n fill: #ff6680;\n stroke: #ff3355;\n}\nsvg .sb3-custom-alt {\n fill: #ff4d6a;\n}\nsvg .sb3-custom-dark {\n fill: #ff3355;\n}\n\n\nsvg .sb3-extension {\n fill: #0fbd8c;\n stroke: #0b8e69;\n}\nsvg .sb3-extension-alt {\n fill: #0da57a;\n}\nsvg .sb3-extension-dark {\n fill: #0b8e69;\n}\n\n\nsvg .sb3-obsolete {\n fill: #ed4242;\n stroke: #ca2b2b;\n}\nsvg .sb3-obsolete-alt {\n fill: #db3333;\n}\nsvg .sb3-obsolete-dark {\n fill: #ca2b2b;\n}\n\n\nsvg .sb3-grey {\n fill: #bfbfbf;\n stroke: #909090;\n}\nsvg .sb3-grey-alt {\n fill: #b2b2b2;\n}\nsvg .sb3-grey-dark {\n fill: #909090;\n}\n\n\nsvg .sb3-label {\n fill: #fff;\n}\n\nsvg .sb3-input-color {\n stroke: #fff;\n}\n\nsvg .sb3-input-number,\nsvg .sb3-input-string {\n fill: #fff;\n}\nsvg .sb3-literal-number,\nsvg .sb3-literal-string {\n fill: #575e75;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-motion {\n fill: #80b5ff;\n stroke: #3373cc;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-motion-alt {\n fill: #b3d2ff;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-motion-dark {\n fill: #3373cc;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-looks {\n fill: #ccb3ff;\n stroke: #774dcb;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-looks-alt {\n fill: #ddccff;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-looks-dark {\n fill: #774dcb;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sound {\n fill: #e19de1;\n stroke: #bd42bd;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sound-alt {\n fill: #ffb3ff;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sound-dark {\n fill: #bd42bd;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-control {\n fill: #ffbe4c;\n stroke: #cf8b17;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-control-alt {\n fill: #ffda99;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-control-dark {\n fill: #cf8b17;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-events {\n fill: #ffd966;\n stroke: #cc9900;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-events-alt {\n fill: #ffecb3;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-events-dark {\n fill: #cc9900;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sensing {\n fill: #85c4e0;\n stroke: #2e8eb8;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sensing-alt {\n fill: #aed8ea;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-sensing-dark {\n fill: #2e8eb8;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-operators {\n fill: #7ece7e;\n stroke: #389438;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-operators-alt {\n fill: #b5e3b5;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-operators-dark {\n fill: #389438;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-variables {\n fill: #ffa54c;\n stroke: #db6e00;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-variables-alt {\n fill: #ffcc99;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-variables-dark {\n fill: #db6e00;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-list {\n fill: #ff9966;\n stroke: #e64d00;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-list-alt {\n fill: #ffcab0;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-list-dark {\n fill: #e64d00;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-custom {\n fill: #ff99aa;\n stroke: #e64d00;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-custom-alt {\n fill: #ffccd5;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-custom-dark {\n fill: #e64d00;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-extension {\n fill: #13ecaf;\n stroke: #0b8e69;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-extension-alt {\n fill: #75f0cd;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-extension-dark {\n fill: #0b8e69;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-obsolete {\n fill: #fc6666;\n stroke: #d32121;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-obsolete-alt {\n fill: #fcb0b0;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-obsolete-dark {\n fill: #d32121;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-grey {\n fill: #bfbfbf;\n stroke: #959595;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-grey-alt {\n fill: #b2b2b2;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-grey-dark {\n fill: #959595;\n}\n\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-label {\n fill: #000;\n}\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-input-color {\n stroke: #fff;\n}\n\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-input-number,\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-input-string {\n fill: #fff;\n}\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-literal-number,\nsvg.scratchblocks-style-scratch3-high-contrast .sb3-literal-string {\n fill: #000;\n}\n";
// Need to define here, as we cannot reference Style#makeNewIcons
// during JS loading phase.
var highContrastIcons = new Set(["dropdownArrow", "turnRight", "turnLeft", "loopArrow", "musicBlock", "penBlock", "videoBlock", "ttsBlock", "translationBlock"]);
var Style = /*#__PURE__*/function () {
function Style() { }
_createClass(Style, null, [{
key: "cssContent",
get: function get() {
return cssContent;
}
}, {
key: "makeCommonIcons",
value: function makeCommonIcons() {
return [SVG.setProps(SVG.group([SVG.el("path", {
d: "M20.8 3.7c-.4-.2-.9-.1-1.2.2-2 1.6-4.8 1.6-6.8 0-2.3-1.9-5.6-2.3-8.3-1v-.4c0-.6-.5-1-1-1s-1 .4-1 1v18.8c0 .5.5 1 1 1h.1c.5 0 1-.5 1-1v-6.4c1-.7 2.1-1.2 3.4-1.3 1.2 0 2.4.4 3.4 1.2 2.9 2.3 7 2.3 9.8 0 .3-.2.4-.5.4-.9V4.7c0-.5-.3-.9-.8-1zm-.3 10.2C18 16 14.4 16 11.9 14c-1.1-.9-2.5-1.4-4-1.4-1.2.1-2.3.5-3.4 1.1V4c2.5-1.4 5.5-1.1 7.7.6 2.4 1.9 5.7 1.9 8.1 0h.2l.1.1-.1 9.2z",
fill: "#45993d"
}), SVG.el("path", {
d: "M20.6 4.8l-.1 9.1v.1c-2.5 2-6.1 2-8.6 0-1.1-.9-2.5-1.4-4-1.4-1.2.1-2.3.5-3.4 1.1V4c2.5-1.4 5.5-1.1 7.7.6 2.4 1.9 5.7 1.9 8.1 0h.2c0 .1.1.1.1.2z",
fill: "#4cbf56"
})]), {
id: "sb3-greenFlag"
}), SVG.setProps(SVG.el("polygon", {
points: "6.6,0.5 13.12,0.5 19.5,6.6 19.5,13.12 13.12,19.5 6.6,19.5 0.5,13.12 0.5,6.6 ",
fill: "#ec5959",
stroke: "#b84848",
"stroke-linejoin": "round",
"stroke-linecap": "round"
}), {
id: "sb3-stopSign"
}), SVG.el("path", {
d: "M0 0L4 4L0 8Z",
fill: "#111",
id: "sb3-addInput"
}), SVG.el("path", {
d: "M4 0L4 8L0 4Z",
fill: "#111",
id: "sb3-delInput"
}), SVG.setProps(SVG.group([SVG.el("rect", {
x: "0",
y: "0",
width: "15",
height: "18",
fill: "#fff"
}), SVG.el("rect", {
x: "1",
y: "1",
width: "13",
height: "4",
fill: "#ff920f"
}), SVG.el("rect", {
x: "1",
y: "7",
width: "13",
height: "4",
fill: "#ff920f"
}), SVG.el("rect", {
x: "1",
y: "13",
width: "13",
height: "4",
fill: "#ff920f"
})]), {
id: "sb3-list"
}), SVG.el("image", {
id: "sb3-microbitBlock",
width: "40px",
height: "40px",
href: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAACmlBMVEUAAAArKysrIB8lJCNBRlY2O0U9X48sKCvOoBQzKzMnJyfrswi/xdDRoxN2dnbToxPosgnmsAq/lxo6MSq0kCLOoRXKnhbEmhc7LRooJCTcqQ7OoBXstAjpsgi9lhuvjCCPdSd4Zyg2NjZMi+Slhyq8lR5CR1fZqBG+lh3ttQjFnBnLnhbDmhqZore3kh5ARlW2kR6qiCGcfyU6QEtyYyd4ZSDSoxOGdDedgizLnhfgrA25kx9YXWqbgCxMUWDfqwzcqg/VphBBR1ecpLmcgSzHmxijq77BmRprYkOOlKZARlVGdbabo7m3kRxGcrKwjB9ARVSIjaCZobuVeyahgh+VdyE8XIOLayBIOydBR1f/vwBMl//m5+g+Q1JlanY6P0uCiJjj5OU9QVBARVQ/RFP9vgBFZpjk5ebwtgbzuAR0eotARlZITl3d3+KNlKRQVmRNUmGxs7mRlJtUW2nLnhfInRfpsQn1uQS/wsa0t7qlp62doKeKjpeBg41YXmxCSlvGyMtHb6xCUGlCTGBJgdJDSFVobXlMlPhLhtq/wchIesFGbqpDVXRXXGxCTGNiXEe+lh1LjuzP0dRJg9RIfslJfMW9v8RGbKRFY5Jzd4NdYm88QE1+bjrQpCHQohTxtwVLkPDa3OHd3t9If826vMCusLZHcrGIj6F6gpaDho9ESlpITFOQeTLcqhnEmhnqsw34uwVKkfNNhdi6vMRLUWBPUFC7lzDWpx31uQjutQj6vAP5+frZ29zZ2dvW2NtHc7JGbKVFaJx/hpl/hpdxd4hzd4JDWHpDUm5UWWiZhEh3aT6WfC/EnSqtiyW/lxzBmRpKi+VQgMhRermqq7BSdrCLjpVEXYVEW4A/SFtOT1BaV0pxZUCpjT2xkTcYNOUYAAAAWXRSTlMADBgV5DRLEdcIE+3Z2QLt6unOI/zp1dEcDf7z7eu9qVtFBPv7+/fx7u3p3NnOzcq0lXZENzD6+fj39vTm5uXk4t3c2tbS0c/NvrCopKKcm4yLbGpiTUA3JzDAPbYAAAQqSURBVFjD7dX1fxJhHMDxE+MIRRFrdnd3d3fr9ziwhsVsmC2K6HRTtzlb0ens2uzu7m79X3z4HufdwTNvj/qbfPYaPDe+vMf23AEXL168/6bBTfoWx5r0GskxVMhsoDfg3Lb12LlzIwz0zKZYzzy0lkPVKtXdutXw++o2a5UQ7SUMcqibGpA8kD09slX0azRkazwISB5Inn4D+ShwrNYjIHpQQA96mqPAYlqPgOhBAT0oUpgGyh6C6EHYWz11e7jbO9hAxUMQPezR6+wtW0nBlJzV7CB62nIyN/mB5H/ouM0G0j3ITIXsAMDUVMjcygbSPQgqrzCNDaR7sCEzO2cLKSvlLNP/ED1qgbRbh0m37viBAUSPvU/BYFZWcAMFRI+9HW/fOFLSgAaixw6erZWS5qeBVG+XKwlghWsuwALXHIA5rgUAc10r1KADvViwKNDaLO4EWCQuA5gnLgVYKs4DWCYuUoPoFRhcKa4FWCwuB1gizgeYLy4BWC4uBqWPq9Cjg55EJ5bogUi7J0wBmDwhMXzjBHBOmAyQSG4wnPd4cJ4Kejbem4gdTQL9NPN00Hlk0jRs//0p+puinaeDs0XxwMFtk8RZM6fob4pmPl/wxtqkOcemIai7Kco8HTx/88Ns8dBxgMcrEdTfFKcyP/9m1xhwwbV30sBGCdTPqczPu9Y5BoTzZODAg6S5kT9Zf1PU8+fz25TrTJuizOd32kjtL9CmaOfpJ/Zd5UTV3RTtfP6X3mfl0tNNuVSpILYp5xHL25ccFUQv9cwGhrcvPZB4jgiovyn6IHrrZFB/U/RBf6rD8f4sgqzRwTtZQfKZGPiXm4Kxb8rff6awgf9sU5jTB9O79G63BqTW1C5baQ9geNSwvnIEJ8s2PCkPXqhTtlM6HUxvWpiv3h6kyozmDY2egnzUkjc3/3X0bAjPt3gW+VWVxvFtSn6hgi9acxzfeI001yiBs46pI7/AkjzHVSgjg5XIkwvXB+xbcxNnGraHCmZUr8nxJS/g3AlC1KzujQgnOpo5axufDFasYLUa2gK2p2ohzlTtJB2sV6NCNSECCtUq1Kj3CxSq2luXlY8gufF4e9PkCLiwpWFULg38+qKiILgFYe9Lr++07zSur4SXr7zeV5Gj0z5vxt69GVcFt1vI874kS6/0pDIZsWB6crLgzhNI+wRhOrm7Sr5n4HIhWeW5yRJ/EBYuS4+5yUN5Vy9fuewT6GDouQq8qAFDITX4/XmuDF788eTJRQpoD4PTT6nAXA14KVcNhshgBDx16VTokk9oZo4Czf0JiEkgpoCYApJkEPMJwxOiQFONDn8DlrRbuWjRXrWEzWKzlOhnLNfHWN5S2Va5cndjufLG8uWMpRs0sFmqdMNliRKlS1nIlw2Xxh5kWaVKC0NNLiarqdAfZ+LixYsX77f9BFJt17cXqnnkAAAAAElFTkSuQmCC"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M23.513 11.17h-.73c-.319 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M24.91 11.17h-.73c-.319 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479z"
}), SVG.el("path", {
d: "M9.54 11.17h-.728c-.32 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.257-.479-.577-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M10.938 11.17h-.729c-.32 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.257-.479-.577-.479z"
}), SVG.el("path", {
d: "M26.305 11.17h-.73c-.318 0-.574.213-.574.478v1.08h1.882v-1.08c0-.265-.26-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M27.702 11.17h-.73c-.318 0-.574.213-.574.478v1.08h1.882v-1.08c0-.265-.26-.479-.578-.479z"
}), SVG.el("path", {
d: "M29.101 11.17h-.73c-.318 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M30.498 11.17h-.73c-.318 0-.576.213-.576.478v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479z"
}), SVG.el("path", {
d: "M17.925 11.17h-.73c-.319 0-.577.213-.577.478v1.08h1.883v-1.08c0-.265-.258-.479-.576-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M19.322 11.17h-.73c-.319 0-.577.213-.577.478v1.08h1.883v-1.08c0-.265-.258-.479-.576-.479z"
}), SVG.el("path", {
d: "M20.717 11.17h-.73c-.319 0-.575.213-.575.478v1.08h1.883v-1.08c0-.265-.26-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M22.114 11.17h-.73c-.319 0-.575.213-.575.478v1.08h1.883v-1.08c0-.265-.26-.479-.578-.479z"
}), SVG.el("path", {
d: "M15.129 11.17H14.4c-.32 0-.576.213-.576.478v1.08h1.883v-1.08c0-.265-.258-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M16.526 11.17h-.729c-.32 0-.576.213-.576.478v1.08h1.883v-1.08c0-.265-.258-.479-.578-.479z"
}), SVG.el("path", {
d: "M12.335 11.17h-.73c-.319 0-.575.213-.575.478v1.08h1.882v-1.08c0-.265-.26-.479-.577-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M13.732 11.17h-.73c-.319 0-.575.213-.575.478v1.08h1.883v-1.08c0-.265-.26-.479-.578-.479z"
}), SVG.el("path", {
d: "M31.893 11.17h-.73c-.318 0-.574.213-.574.478v1.08h1.882v-1.08c0-.265-.26-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M33.29 11.17h-.73c-.318 0-.574.213-.574.478v1.08h1.882v-1.08c0-.265-.26-.479-.578-.479z"
}), SVG.el("path", {
d: "M33.647 28.407H15.765V12.533h17.882c.52 0 .941.445.941.992v13.89c0 .547-.421.992-.94.992",
fill: "#FFF"
}), SVG.el("path", {
d: "M33.647 28.407H15.765V12.533h17.882c.52 0 .941.445.941.992v13.89c0 .547-.421.992-.94.992z",
stroke: "#7C87A5",
"stroke-width": ".893"
}), SVG.el("path", {
d: "M15.765 28.407H5.412c-.52 0-.941-.445-.941-.993V16.502c0-2.19 1.686-3.969 3.764-3.969h15.06-3.766c-2.078 0-3.764 1.778-3.764 3.969v11.905z",
fill: "#FFF"
}), SVG.el("path", {
d: "M15.765 28.407H5.412c-.52 0-.941-.445-.941-.993V16.502c0-2.19 1.686-3.969 3.764-3.969h15.06-3.766c-2.078 0-3.764 1.778-3.764 3.969v11.905z",
stroke: "#7C87A5",
"stroke-width": ".893"
}), SVG.el("path", {
d: "M12.941 12.533H11.06c-1.559 0-2.824 1.334-2.824 2.977v1.986c0 .547.422.992.941.992H12c.52 0 .941-.445.941-.992V15.51c0-1.643 1.265-2.977 2.824-2.977h.94-3.764z",
fill: "#4C97FF"
}), SVG.el("path", {
d: "M12.941 12.533H11.06c-1.559 0-2.824 1.334-2.824 2.977v1.986c0 .547.422.992.941.992H12c.52 0 .941-.445.941-.992V15.51c0-1.643 1.265-2.977 2.824-2.977h.94-3.764z",
stroke: "#3D79CC",
"stroke-width": ".893"
}), SVG.el("path", {
stroke: "#7C87A5",
"stroke-width": ".893",
d: "M4.47 20.474h27.961l2.157 2.974"
}), SVG.el("path", {
d: "M15.765 28.407H5.412c-.52 0-.941-.445-.941-.993V16.502c0-2.19 1.686-3.969 3.764-3.969h15.06-3.766c-2.078 0-3.764 1.778-3.764 3.969v11.905z",
stroke: "#7C87A5",
"stroke-width": ".893"
}), SVG.el("path", {
d: "M21.307 18.964h-.73c-.319 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M21.307 18.964h-.73c-.319 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.258-.479-.576-.479z"
}), SVG.el("path", {
d: "M24.178 18.964h-.728c-.32 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.258-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M24.178 18.964h-.728c-.32 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.258-.479-.578-.479z"
}), SVG.el("path", {
d: "M27.051 18.964h-.73c-.318 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.257-.479-.576-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M27.051 18.964h-.73c-.318 0-.576.214-.576.479v1.08h1.882v-1.08c0-.265-.257-.479-.576-.479z"
}), SVG.el("path", {
d: "M29.923 18.964h-.729c-.32 0-.576.214-.576.479v1.08h1.883v-1.08c0-.265-.258-.479-.578-.479",
fill: "#7C87A5"
}), SVG.el("path", {
d: "M29.923 18.964h-.729c-.32 0-.576.214-.576.479v1.08h1.883v-1.08c0-.265-.258-.479-.578-.479z"
}), SVG.el("path", {
d: "M33.647 28.407H15.765V20.47H32.43l2.157 2.978v3.966c0 .548-.421.993-.94.993",
fill: "#E6E7E8"
}), SVG.el("path", {
d: "M33.647 28.407H15.765V20.47H32.43l2.157 2.978v3.966c0 .548-.421.993-.94.993z",
stroke: "#7C87A5",
"stroke-width": ".893"
}), SVG.el("path", {
d: "M15.765 28.407H5.412c-.52 0-.941-.445-.941-.993V20.47h11.294v7.937z",
fill: "#E6E7E8"
}), SVG.el("path", {
d: "M15.765 28.407H5.412c-.52 0-.941-.445-.941-.993V20.47h11.294v7.937z",
stroke: "#7C87A5",
"stroke-width": ".893"
}), SVG.el("path", {
fill: "#E6E7E8",
d: "M19.53 24.438h11.294V20.47H19.529z"
}), SVG.el("path", {
stroke: "#7C87A5",
"stroke-width": ".893",
d: "M19.53 24.438h11.294V20.47H19.529zm12.902-3.964l2.157-2.794"
})]), {
id: "sb3-wedoBlock",
fill: "none"
}), SVG.setProps(SVG.group([SVG.el("rect", {
stroke: "#7C87A5",
fill: "#FFF",
x: ".5",
y: "3.59",
width: "28",
height: "25.81",
rx: "1"
}), SVG.el("rect", {
stroke: "#7C87A5",
fill: "#E6E7E8",
x: "2.5",
y: ".5",
width: "24",
height: "32",
rx: "1"
}), SVG.el("path", {
stroke: "#7C87A5",
fill: "#FFF",
d: "M2.5 14.5h24v13h-24z"
}), SVG.el("path", {
d: "M14.5 10.5v4",
stroke: "#7C87A5",
fill: "#E6E7E8"
}), SVG.el("rect", {
fill: "#414757",
x: "4.5",
y: "2.5",
width: "20",
height: "10",
rx: "1"
}), SVG.el("rect", {
fill: "#7C87A5",
opacity: ".5",
x: "13.5",
y: "20.13",
width: "2",
height: "2",
rx: ".5"
}), SVG.el("path", {
d: "M9.06 20.13h1.5a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-1.5a1 1 0 0 1 0-2zM19.93 22.13h-1.51a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h1.5a1 1 0 0 1 .01 2zM8.23 17.5H5a.5.5 0 0 1-.5-.5v-2.5h6l-1.85 2.78a.51.51 0 0 1-.42.22zM18.15 18.85l-.5.5a.49.49 0 0 0-.15.36V20a.5.5 0 0 1-.5.5h-.5a.5.5 0 0 1-.5-.5.5.5 0 0 0-.5-.5h-2a.5.5 0 0 0-.5.5.5.5 0 0 1-.5.5H12a.5.5 0 0 1-.5-.5v-.29a.49.49 0 0 0-.15-.36l-.5-.5a.51.51 0 0 1 0-.71l1.51-1.49a.47.47 0 0 1 .35-.15h3.58a.47.47 0 0 1 .35.15l1.51 1.49a.51.51 0 0 1 0 .71zM10.85 23.45l.5-.5a.49.49 0 0 0 .15-.36v-.29a.5.5 0 0 1 .5-.5h.5a.5.5 0 0 1 .5.5.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5.5.5 0 0 1 .5-.5h.5a.5.5 0 0 1 .5.5v.29a.49.49 0 0 0 .15.36l.5.5a.5.5 0 0 1 0 .7l-1.51 1.5a.47.47 0 0 1-.35.15h-3.58a.47.47 0 0 1-.35-.15l-1.51-1.5a.5.5 0 0 1 0-.7z",
fill: "#7C87A5",
opacity: ".5"
}), SVG.el("path", {
d: "M21.5 27.5h5v4a1 1 0 0 1-1 1h-4v-5z",
stroke: "#CC4C23",
fill: "#F15A29"
})]), {
transform: "translate(5.5 3.5)",
id: "sb3-ev3Block"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M35 28H5a1 1 0 0 1-1-1V12c0-.6.4-1 1-1h30c.5 0 1 .4 1 1v15c0 .5-.5 1-1 1z",
fill: "#fff"
}), SVG.el("path", {
fill: "red",
d: "M4 25h32v2.7H4zm9-1h-2.2a1 1 0 0 1-1-1v-9.7c0-.6.4-1 1-1H13c.6 0 1 .4 1 1V23c0 .6-.5 1-1 1z"
}), SVG.el("path", {
fill: "red",
d: "M6.1 19.3v-2.2c0-.5.4-1 1-1h9.7c.5 0 1 .5 1 1v2.2c0 .5-.5 1-1 1H7.1a1 1 0 0 1-1-1z"
}), SVG.el("circle", {
fill: "red",
cx: "22.8",
cy: "18.2",
r: "3.4"
}), SVG.el("circle", {
fill: "red",
cx: "30.6",
cy: "18.2",
r: "3.4"
}), SVG.el("path", {
fill: "red",
d: "M4.2 27h31.9v.7H4.2z"
}), SVG.el("circle", {
fill: "#e0e0e0",
cx: "22.8",
cy: "18.2",
r: "2.3"
}), SVG.el("circle", {
fill: "#e0e0e0",
cx: "30.6",
cy: "18.2",
r: "2.3"
}), SVG.el("path", {
fill: "#e0e0e0",
d: "M12.5 22.9h-1.2c-.3 0-.5-.2-.5-.5V14c0-.3.2-.5.5-.5h1.2c.3 0 .5.2.5.5v8.4c0 .3-.2.5-.5.5z"
}), SVG.el("path", {
fill: "#e0e0e0",
d: "M7.2 18.7v-1.2c0-.3.2-.5.5-.5h8.4c.3 0 .5.2.5.5v1.2c0 .3-.2.5-.5.5H7.7c-.3 0-.5-.2-.5-.5zM4 26h32v2H4z"
}), SVG.el("path", {
stroke: "#666",
"stroke-width": ".5",
d: "M35.2 27.9H4.8a1 1 0 0 1-1-1V12.1c0-.6.5-1 1-1h30.5c.5 0 1 .4 1 1V27a1 1 0 0 1-1.1.9z"
}), SVG.el("path", {
stroke: "#666",
"stroke-width": ".5",
d: "M35.2 27.9H4.8a1 1 0 0 1-1-1V12.1c0-.6.5-1 1-1h30.5c.5 0 1 .4 1 1V27a1 1 0 0 1-1.1.9z"
})]), {
id: "sb3-makeymakeyBlock",
fill: "none"
}), SVG.el("image", {
id: "sb3-gdxforBlock",
width: "40px",
height: "40px",
href: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAABAlBMVEUAAAABAQEAAAB9h6YAAAAAAAAAAAB8iKZ7iKaAjKvm5+h+iqhcXFxGR0d8iKbj5OV9iKZ8h6be3+Db3d19h6acnJ0AAAB7nrDh4uPh4uN9iabZ2tt9iKbX19nJycnExsZ8iKe+wMC7vL2Eka/g4ePU1dV8iKZ9iKZ9iKd+iKitra2RkZGLjo5wcHCLi7l0oqJV//9csdZ8h6WFkq//vwDm5+iEka79vgJ6iql9iaaHk6tgq9Btm71+iadmo8dzk7OCj6yAjKp/iqhiqc1qnsB4jKtgrNFwl7d1tLTgtCxpocN0krJ2j65ossWNtZSbt4LAulHWsDnasTTuvhXzvg9zk7TzqAfaAAAAMXRSTlMAJiLoFBwI8q4a+0c4M/nr3tnQwKxYDAnk2726tbGMh4J9dinXq56ddG9nT01ACwsDk/+seAAAAidJREFUWMPt2Olu2kAUhuE5NvuaBAhZm7TpvufgMXaBbmAghOzp/d9KD7RW6yaqPeL7YVV9/471aBgfCXnUH7ULNhtkF96qv1dgwwoxoM08cDsJcwfMdgwonoiJPRFjQXkscQM3Adhxk4NuJwkoDx0nSp5NDTiae958NEaBwzkvC4YYcOxx7fCoeJhnrwcBv7H9TklFm08R4JD5SEkiMg8B4IjXwsV1HgHAPu+EizsQcMbr2B0OufZz7X0NcIZSwC9+rD3nADI2/fCtrHEfAvZ8Liqp6PuIwZZO+ZmSnspcY8AZ55WU5xkElDwuK1Vm7xgFTjhfLud5AgPHAUvBGARKvYnnTXpp/gvAg9PLyykSPLt1nNszIHjuSOdAcNp1nO4UeYYXNzcX0UH62P+0AnjH8lgCgL8s/+uXzwZgrOV2JAMwxpIMwRjLHIyxzMEYyxyMWgAwYiHAzm99iLQ6eOJEul4d7Ea6WhG8W7rAE+fertHgVXp+clpB9Oet64M/wH2TKwI/FrRFTH6JIZ6NvmZpxoDtptlFULOtzGPWy+4/r//gvwKGgcC90NtTqIg2dIuyClaWDvTjKlDMLba4UaUMcIuVbd0gyiGwjGVlFuKWfkQZhEfSQnypd8mCvOHGvkA5quo6EQSs6yrlNumN3obs0KKGHJ70QD+hLOQMW7r0sFI5KJVeY+bGkr1JopKlEG0StXbrW/uvQGMookXLLPFAZYTMJju/7z6rRW1MZcnIAAAAAElFTkSuQmCC"
}), SVG.el("image", {
id: "sb3-boostBlock",
width: "40px",
height: "40px",
href: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQBAMAAAB8P++eAAAAKlBMVEUAAAD///98h6Xm5+iVnrb/Zhq+w9L5hk73+Pnf4eSQmbLr7Ozo39vp184hSCf6AAAAAXRSTlMAQObYZgAAAOFJREFUSMftlDEOgjAUhonhAi1sLvIk7NDJDTYu0LhzBzcXruHoDTyFB/BCNi30KU3InzioSb++hAS+vPfKa5pEIpHvk7a8gpf8ISWINtlg4i7ZFOKVTBlqsUR+ItYZJG7VzQQgMqGYd7zWRArpULEAe5Q/J9JMj4rluC7uleNw7TFRXcoREDnlinjX57eUsvRTn8+AE0/6OKV0g5buYTTyWFFr/XAp3aDzed4yFJWnKbhPbtaXXohDNYlDJWz4zSxEokkkEjb496AiVtqAbIYgYNGWBmhgES+NX6SRSORfeAJMWajr95DdqQAAAABJRU5ErkJggg=="
})];
}
}, {
key: "makeOriginalIcons",
value: function makeOriginalIcons() {
return [].concat(_toConsumableArray(Style.makeCommonIcons()), [SVG.setProps(SVG.group([SVG.el("path", {
d: "M12.71 2.44A2.41 2.41 0 0 1 12 4.16L8.08 8.08a2.45 2.45 0 0 1-3.45 0L.72 4.16A2.42 2.42 0 0 1 0 2.44 2.48 2.48 0 0 1 .71.71C1 .47 1.43 0 6.36 0s5.39.46 5.64.71a2.44 2.44 0 0 1 .71 1.73z",
fill: "#231f20",
opacity: ".1"
}), SVG.el("path", {
d: "M6.36 7.79a1.43 1.43 0 0 1-1-.42L1.42 3.45a1.44 1.44 0 0 1 0-2c.56-.56 9.31-.56 9.87 0a1.44 1.44 0 0 1 0 2L7.37 7.37a1.43 1.43 0 0 1-1.01.42z",
fill: "#fff"
})]), {
id: "sb3-dropdownArrow",
transform: "scale(0.944)"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M22.68 12.2a1.6 1.6 0 0 1-1.27.63h-7.69a1.59 1.59 0 0 1-1.16-2.58l1.12-1.41a4.82 4.82 0 0 0-3.14-.77 4.31 4.31 0 0 0-2 .8A4.25 4.25 0 0 0 7.2 10.6a5.06 5.06 0 0 0 .54 4.62A5.58 5.58 0 0 0 12 17.74a2.26 2.26 0 0 1-.16 4.52A10.25 10.25 0 0 1 3.74 18a10.14 10.14 0 0 1-1.49-9.22 9.7 9.7 0 0 1 2.83-4.14A9.92 9.92 0 0 1 9.66 2.5a10.66 10.66 0 0 1 7.72 1.68l1.08-1.35a1.57 1.57 0 0 1 1.24-.6 1.6 1.6 0 0 1 1.54 1.21l1.7 7.37a1.57 1.57 0 0 1-.26 1.39z",
fill: "#3d79cc"
}), SVG.el("path", {
d: "M21.38 11.83h-7.61a.59.59 0 0 1-.43-1l1.75-2.19a5.9 5.9 0 0 0-4.7-1.58 5.07 5.07 0 0 0-4.11 3.17A6 6 0 0 0 7 15.77a6.51 6.51 0 0 0 5 2.92 1.31 1.31 0 0 1-.08 2.62 9.3 9.3 0 0 1-7.35-3.82 9.16 9.16 0 0 1-1.4-8.37A8.51 8.51 0 0 1 5.71 5.4a8.76 8.76 0 0 1 4.11-1.92 9.71 9.71 0 0 1 7.75 2.07l1.67-2.1a.59.59 0 0 1 1 .21L22 11.08a.59.59 0 0 1-.62.75z",
fill: "#fff"
})]), {
id: "sb3-turnRight"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M20.34 18.21a10.24 10.24 0 0 1-8.1 4.22 2.26 2.26 0 0 1-.16-4.52 5.58 5.58 0 0 0 4.25-2.53 5.06 5.06 0 0 0 .54-4.62A4.25 4.25 0 0 0 15.55 9a4.31 4.31 0 0 0-2-.8 4.82 4.82 0 0 0-3.15.8l1.12 1.41A1.59 1.59 0 0 1 10.36 13H2.67a1.56 1.56 0 0 1-1.26-.63A1.54 1.54 0 0 1 1.13 11l1.72-7.43A1.59 1.59 0 0 1 4.38 2.4a1.57 1.57 0 0 1 1.24.6L6.7 4.35a10.66 10.66 0 0 1 7.72-1.68A9.88 9.88 0 0 1 19 4.81 9.61 9.61 0 0 1 21.83 9a10.08 10.08 0 0 1-1.49 9.21z",
fill: "#3d79cc"
}), SVG.el("path", {
d: "M19.56 17.65a9.29 9.29 0 0 1-7.35 3.83 1.31 1.31 0 0 1-.08-2.62 6.53 6.53 0 0 0 5-2.92 6.05 6.05 0 0 0 .67-5.51 5.32 5.32 0 0 0-1.64-2.16 5.21 5.21 0 0 0-2.48-1A5.86 5.86 0 0 0 9 8.84L10.74 11a.59.59 0 0 1-.43 1H2.7a.6.6 0 0 1-.6-.75l1.71-7.42a.59.59 0 0 1 1-.21l1.67 2.1a9.71 9.71 0 0 1 7.75-2.07 8.84 8.84 0 0 1 4.12 1.92 8.68 8.68 0 0 1 2.54 3.72 9.14 9.14 0 0 1-1.33 8.36z",
fill: "#fff"
})]), {
id: "sb3-turnLeft"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M23.3 11c-.3.6-.9 1-1.5 1h-1.6c-.1 1.3-.5 2.5-1.1 3.6-.9 1.7-2.3 3.2-4.1 4.1-1.7.9-3.6 1.2-5.5.9-1.8-.3-3.5-1.1-4.9-2.3-.7-.7-.7-1.9 0-2.6.6-.6 1.6-.7 2.3-.2H7c.9.6 1.9.9 2.9.9s1.9-.3 2.7-.9c1.1-.8 1.8-2.1 1.8-3.5h-1.5c-.9 0-1.7-.7-1.7-1.7 0-.4.2-.9.5-1.2l4.4-4.4c.7-.6 1.7-.6 2.4 0L23 9.2c.5.5.6 1.2.3 1.8z",
fill: "#cf8b17"
}), SVG.el("path", {
d: "M21.8 11h-2.6c0 1.5-.3 2.9-1 4.2-.8 1.6-2.1 2.8-3.7 3.6-1.5.8-3.3 1.1-4.9.8-1.6-.2-3.2-1-4.4-2.1-.4-.3-.4-.9-.1-1.2.3-.4.9-.4 1.2-.1 1 .7 2.2 1.1 3.4 1.1s2.3-.3 3.3-1c.9-.6 1.6-1.5 2-2.6.3-.9.4-1.8.2-2.8h-2.4c-.4 0-.7-.3-.7-.7 0-.2.1-.3.2-.4l4.4-4.4c.3-.3.7-.3.9 0L22 9.8c.3.3.4.6.3.9s-.3.3-.5.3z",
fill: "#fff"
})]), {
id: "sb3-loopArrow"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M28.456 21.675c-.009-.312-.087-.825-.256-1.702-.096-.495-.612-3.022-.753-3.73-.395-1.98-.76-3.92-1.142-6.113-.732-4.223-.693-6.05.344-6.527.502-.23 1.06-.081 1.842.35.413.227 2.181 1.365 2.07 1.296 1.993 1.243 3.463 1.775 4.928 1.549 1.527-.237 2.505-.06 2.877.618.348.635.015 1.416-.729 2.18-1.473 1.516-3.976 2.514-5.849 2.023-.822-.218-1.238-.464-2.38-1.266a9.737 9.737 0 0 0-.095-.066c.047.593.264 1.74.717 3.803.294 1.336 2.079 9.187 2.637 11.674l.002.012c.529 2.637-1.872 4.724-5.235 4.724-3.29 0-6.363-1.988-6.862-4.528-.53-2.64 1.873-4.734 5.233-4.734a8.411 8.411 0 0 1 2.65.437zM11.46 27.666c-.01-.319-.091-.84-.266-1.738-.09-.46-.595-2.937-.753-3.727-.39-1.96-.752-3.892-1.131-6.07-.732-4.224-.692-6.052.344-6.527.502-.23 1.06-.082 1.841.349.414.228 2.181 1.365 2.07 1.296 1.992 1.243 3.461 1.775 4.925 1.549 1.525-.24 2.504-.064 2.876.614.348.635.015 1.415-.728 2.18-1.474 1.517-3.977 2.513-5.847 2.017-.822-.218-1.237-.463-2.38-1.266a9.729 9.729 0 0 0-.094-.065c.047.593.264 1.74.717 3.802.294 1.337 2.078 9.19 2.636 11.675l.003.013c.517 2.638-1.884 4.732-5.234 4.732-3.286 0-6.359-1.993-6.87-4.54-.518-2.639 1.885-4.73 5.242-4.73.904 0 1.802.15 2.65.436z",
stroke: "#000",
"stroke-opacity": ".1"
}), SVG.el("path", {
d: "M32.18 25.874C32.636 28.157 30.512 30 27.433 30c-3.07 0-5.923-1.843-6.372-4.126-.458-2.285 1.665-4.136 4.743-4.136.647 0 1.283.084 1.89.234a7 7 0 0 1 .938.302c.87-.02-.104-2.294-1.835-12.229-2.134-12.303 3.06-1.87 8.768-2.753 5.708-.885.076 4.82-3.65 3.844-3.724-.987-4.65-7.153.263 14.738zm-16.998 5.99C15.63 34.148 13.507 36 10.439 36c-3.068 0-5.92-1.852-6.379-4.136-.448-2.284 1.674-4.135 4.751-4.135 1.002 0 1.974.197 2.854.544.822-.055-.15-2.377-1.862-12.228-2.133-12.303 3.059-1.87 8.764-2.753 5.706-.894.076 4.821-3.648 3.834-3.723-.987-4.648-7.152.263 14.738z",
fill: "#FFF"
})]), {
id: "sb3-musicBlock",
fill: "none"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M8.753 34.602l-4.251 1.779 1.784-4.236c1.218-2.892 2.907-5.423 5.03-7.538L31.066 4.93c.846-.842 2.65-.41 4.032.967 1.38 1.375 1.816 3.173.97 4.015L16.318 29.59c-2.123 2.116-4.664 3.799-7.565 5.012",
fill: "#FFF"
}), SVG.el("path", {
d: "M29.41 6.111s-4.45-2.379-8.202 5.771c-1.734 3.766-4.35 1.546-4.35 1.546"
}), SVG.el("path", {
d: "M36.42 8.825c0 .463-.14.873-.432 1.164l-9.335 9.301c.282-.29.41-.668.41-1.12 0-.874-.507-1.963-1.406-2.868-1.362-1.358-3.147-1.8-4.002-.99L30.99 5.01c.844-.84 2.65-.41 4.035.96.898.904 1.396 1.982 1.396 2.855M10.515 33.774a23.74 23.74 0 0 1-1.764.83L4.5 36.382l1.786-4.235c.258-.604.529-1.186.833-1.757.69.183 1.449.625 2.109 1.282.659.658 1.102 1.412 1.287 2.102",
fill: "#4C97FF"
}), SVG.el("path", {
d: "M36.498 8.748c0 .464-.141.874-.433 1.165l-19.742 19.68c-2.131 2.111-4.673 3.793-7.572 5.01L4.5 36.381l.974-2.317 1.925-.808c2.899-1.218 5.441-2.899 7.572-5.01l19.742-19.68c.292-.292.432-.702.432-1.165 0-.647-.27-1.4-.779-2.123.249.172.498.377.736.614.898.905 1.396 1.983 1.396 2.856",
fill: "#575E75",
opacity: ".15"
}), SVG.el("path", {
d: "M18.45 12.831a.904.904 0 1 1-1.807 0 .904.904 0 0 1 1.807 0z",
fill: "#575E75"
})]), {
id: "sb3-penBlock",
stroke: "#575E75",
fill: "none",
"stroke-linejoin": "round"
}), SVG.setProps(SVG.group([SVG.el("circle", {
opacity: 0.25,
cx: 32,
cy: 16,
r: 4.5
}), SVG.el("circle", {
opacity: 0.5,
cx: 32,
cy: 12,
r: 4.5
}), SVG.el("circle", {
opacity: 0.75,
cx: 32,
cy: 8,
r: 4.5
}), SVG.el("circle", {
cx: 32,
cy: 4,
r: 4.5
}), SVG.el("path", {
d: "M22.672 4.42l-6.172 4V6.1c0-2.01-1.563-3.6-3.5-3.6H4.1C2.076 2.5.5 4.076.5 6.1V14c0 1.927 1.584 3.512 3.6 3.6H13c1.902 0 3.5-1.653 3.5-3.6v-2.283l6.257 3.754.097.075c.02.02.098.054.146.054.267 0 .5-.217.5-.5V4.8c0 .037-.056-.094-.129-.243-.145-.242-.43-.299-.7-.137z",
fill: "#4D4D4D",
"stroke-linejoin": "round"
})]), {
id: "sb3-videoBlock",
stroke: "#000",
fill: "#FFF",
"stroke-opacity": 0.15
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M25.644 20.5c-1.667 1.937-4.539 3.429-5.977 3.429a1.25 1.25 0 0 1-.557-.137c-.372-.186-.61-.542-.61-1.03 0-.105.017-.207.05-.308.076-.236.624-.986.727-1.173.27-.484.462-1.075.566-1.865A8.5 8.5 0 0 1 24 3.5h4a8.5 8.5 0 1 1 0 17h-2.356z",
fill: "#FFF"
}), SVG.el("path", {
d: "M15.5 21.67c0-1.016-1.494-1.586-2.387-.782l-2.7 2.163A5.958 5.958 0 0 1 6.7 24.33h-.4c-1.035 0-1.8.69-1.8 1.573v4.235c0 .883.765 1.572 1.8 1.572h.4c1.458 0 2.754.423 3.82 1.287l2.598 2.161c.908.75 2.382.188 2.382-.876V21.67z",
fill: "#4D4D4D"
})]), {
id: "sb3-ttsBlock",
stroke: "#000",
"stroke-opacity": 0.15
}), SVG.el("image", {
id: "sb3-translateBlock",
width: "40px",
height: "40px",
href: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAA21BMVEUAAAAAAAAAAAAAAADS0tIAAABHR0cAAADX19cAAAAAAACkpKRqamq2traurq6WlpbV1dWEhITHx8fPz8/Ly8vDw8O9vb0AAABMTEz////Z2dlXXnVMl//g4ODu7u7m5ub4+PhPmf/x8fH09PT6+vri4uNRmv/r6+1uqv/0+P9Ynv/p8v+rrrphZ33S5f+51v9ho/+1uMKBhpfH3v+Wmqhrcoacxf+Pvv/KzNSgpLGLkKDd6/+rzf9npv/AwsuDtv98s/90rv9jpP9GieeOrtm5ubl2fI7Z4u56otk5hEFfAAAAGXRSTlMAJhgM1wYyHvIkEWpBhXhc5U+uybyhk0YvleQYgwAABDpJREFUWMPtmNl6mzAQhQMCBAYbvLX1GIwxi7e2TtosTdKk+/L+T1QBVoQtJHDby5yLROYTPzOagSM4e9az6oVUrDgKxh39//Bwb+QBkTZ2VL3hypYilKWicpY6gmWcTCbxIoSh0xHjOkZXA4m0rlGcrcBsslcSmrYq4qm2GczmE6Hms6A8W4GQHZ1BTxXweuTCErGz1TEEaTpLymML6HVq87VhIWPRs21yNu679guNXn9hOnWVMUwanzxG0yCTdYQQts195umwJmnUDSatFHQRPaVvljkl4CAuRlWrCfD9uiZEbR+ObrnjfRDhwHUtdAi0gK/vLtts+VqDVfIMjZSmLEycBuD1D4kK8MHc+Ju3/FFQaHdXc4rBU/8NiCE+OJyAIQKuz32qjA7O1xzwqMtiUETAXeRzinZcyoPgsPpDcco3q9WD729WhTI/e1itbriUzwwtqPI0Q5et4ZoA6SDj1pCWOeB44qJ88aOiIB8j/xMH5IiUJwG+jfyHPMCNH20FQEpkPGnbnBeFuI78Fd82VWJCeTyQCzHb3pMCb8VAQhxBCkPKkzf2Z9J9mR9dCxqb3tBO17EoTw4ky0f0VXSnUCGE6LDp1tvlwK0cyNQMJA1DlL3Px8TenvTjpcAN5cD7VVSsoR992c4oS+aGcuDbzxFBfVqvv5L/375DCzeUAXfnOW5TJHudffvdzg3FwPdZvnbX6/LXr+9t3ZCzAAaMNh/X9BdAWzcUm9T2vnrpk91QbqOhLEDeDZuNHkBSX94Nm7ciAJOWAkW8WZIDl1MikAD57ZwceJsDL0VAfsPJwgzzO5cHvsmBb2IJkAlhB5InntlXlJcc8MO00GMzsHTbsMJDdU+hOxIeCfKuXYQu7ZJ5oDmExwPjfAEvyZ9lGyDW9tOWMH6l1z4nLwjrQ572RRugAvMS57mq4MH7czq9Kgpz1QZoDcI4DsHrWUjw4E1JbLeTSZ5z2gLYMTTwBnaOEwBvS1Ke86UUyF7isKpLrIHkSvVGBORdUQx8nFb0KAUy38aSCO8I510hMrhrBOrGEFIYGToPZM+Fn+XwiraiAMh2Uwnb+3DAC9Z/t3TIA2W7MwZkYbH+uZIC+f0jD3z9+vXF05hIAJTtcK3TLIDnMSLnhqeZlDo8eksYqH/3UskWPz7aCuDTX3urMiA5ejHCp7+YV4W9gxBnMFJP/XRwKNT3IEhLZpIGQMp86seNY6LlutRQgrFr6dLPLyELjm44eemIWt6C+JP0A1HffCIm4GDEw2jvpNTxbIwQ0kUTUYUYkgYTSXfMBU1Ee+G6fSwkOlpA/RFcJCR2erRHkllKSjNWhdd+NQbqkJrgunyPhKBIprpeiZyLZtEeCRNWQdlUZPU8yF1yYJ1J1HGGEC5iknS8pN0tRtoDDzTSNDLpqjMu2s4b9fBZg/TcJVHjrA7GSl/JZz7rWbX6A0ZzUfwVEqfrAAAAAElFTkSuQmCC"
})]);
}
}, {
key: "makeHighContrastIcons",
value: function makeHighContrastIcons() {
// Make sure to update the highContrastIcons set above!
return [].concat(_toConsumableArray(Style.makeCommonIcons()), [
// https://github.com/scratchfoundation/scratch-gui/tree/beta/src/lib/themes/high-contrast/blocks-media
SVG.setProps(SVG.group([SVG.el("path", {
d: "M12.71 2.44A2.41 2.41 0 0 1 12 4.16L8.08 8.08a2.45 2.45 0 0 1-3.45 0L.72 4.16A2.42 2.42 0 0 1 0 2.44 2.48 2.48 0 0 1 .71.71C1 .47 1.43 0 6.36 0s5.39.46 5.64.71a2.44 2.44 0 0 1 .71 1.73z",
fill: "#231f20",
opacity: ".1"
}), SVG.el("path", {
d: "M6.36 7.79a1.43 1.43 0 0 1-1-.42L1.42 3.45a1.44 1.44 0 0 1 0-2c.56-.56 9.31-.56 9.87 0a1.44 1.44 0 0 1 0 2L7.37 7.37a1.43 1.43 0 0 1-1.01.42z",
fill: "#000"
})]), {
id: "sb3-dropdownArrow-high-contrast",
transform: "scale(0.944)"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M22.68 12.2a1.6 1.6 0 0 1-1.27.63h-7.69a1.59 1.59 0 0 1-1.16-2.58l1.12-1.41a4.82 4.82 0 0 0-3.14-.77 4.31 4.31 0 0 0-2 .8A4.25 4.25 0 0 0 7.2 10.6a5.06 5.06 0 0 0 .54 4.62A5.58 5.58 0 0 0 12 17.74a2.26 2.26 0 0 1-.16 4.52A10.25 10.25 0 0 1 3.74 18a10.14 10.14 0 0 1-1.49-9.22 9.7 9.7 0 0 1 2.83-4.14A9.92 9.92 0 0 1 9.66 2.5a10.66 10.66 0 0 1 7.72 1.68l1.08-1.35a1.57 1.57 0 0 1 1.24-.6 1.6 1.6 0 0 1 1.54 1.21l1.7 7.37a1.57 1.57 0 0 1-.26 1.39z",
fill: "#000"
}), SVG.el("path", {
d: "M21.38 11.83h-7.61a.59.59 0 0 1-.43-1l1.75-2.19a5.9 5.9 0 0 0-4.7-1.58 5.07 5.07 0 0 0-4.11 3.17A6 6 0 0 0 7 15.77a6.51 6.51 0 0 0 5 2.92 1.31 1.31 0 0 1-.08 2.62 9.3 9.3 0 0 1-7.35-3.82 9.16 9.16 0 0 1-1.4-8.37A8.51 8.51 0 0 1 5.71 5.4a8.76 8.76 0 0 1 4.11-1.92 9.71 9.71 0 0 1 7.75 2.07l1.67-2.1a.59.59 0 0 1 1 .21L22 11.08a.59.59 0 0 1-.62.75z",
fill: "#000"
})]), {
id: "sb3-turnRight-high-contrast"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M20.34 18.21a10.24 10.24 0 0 1-8.1 4.22 2.26 2.26 0 0 1-.16-4.52 5.58 5.58 0 0 0 4.25-2.53 5.06 5.06 0 0 0 .54-4.62A4.25 4.25 0 0 0 15.55 9a4.31 4.31 0 0 0-2-.8 4.82 4.82 0 0 0-3.15.8l1.12 1.41A1.59 1.59 0 0 1 10.36 13H2.67a1.56 1.56 0 0 1-1.26-.63A1.54 1.54 0 0 1 1.13 11l1.72-7.43A1.59 1.59 0 0 1 4.38 2.4a1.57 1.57 0 0 1 1.24.6L6.7 4.35a10.66 10.66 0 0 1 7.72-1.68A9.88 9.88 0 0 1 19 4.81 9.61 9.61 0 0 1 21.83 9a10.08 10.08 0 0 1-1.49 9.21z",
fill: "#000"
}), SVG.el("path", {
d: "M19.56 17.65a9.29 9.29 0 0 1-7.35 3.83 1.31 1.31 0 0 1-.08-2.62 6.53 6.53 0 0 0 5-2.92 6.05 6.05 0 0 0 .67-5.51 5.32 5.32 0 0 0-1.64-2.16 5.21 5.21 0 0 0-2.48-1A5.86 5.86 0 0 0 9 8.84L10.74 11a.59.59 0 0 1-.43 1H2.7a.6.6 0 0 1-.6-.75l1.71-7.42a.59.59 0 0 1 1-.21l1.67 2.1a9.71 9.71 0 0 1 7.75-2.07 8.84 8.84 0 0 1 4.12 1.92 8.68 8.68 0 0 1 2.54 3.72 9.14 9.14 0 0 1-1.33 8.36z",
fill: "#000"
})]), {
id: "sb3-turnLeft-high-contrast"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M23.3 11c-.3.6-.9 1-1.5 1h-1.6c-.1 1.3-.5 2.5-1.1 3.6-.9 1.7-2.3 3.2-4.1 4.1-1.7.9-3.6 1.2-5.5.9-1.8-.3-3.5-1.1-4.9-2.3-.7-.7-.7-1.9 0-2.6.6-.6 1.6-.7 2.3-.2H7c.9.6 1.9.9 2.9.9s1.9-.3 2.7-.9c1.1-.8 1.8-2.1 1.8-3.5h-1.5c-.9 0-1.7-.7-1.7-1.7 0-.4.2-.9.5-1.2l4.4-4.4c.7-.6 1.7-.6 2.4 0L23 9.2c.5.5.6 1.2.3 1.8z",
fill: "#000"
}), SVG.el("path", {
d: "M21.8 11h-2.6c0 1.5-.3 2.9-1 4.2-.8 1.6-2.1 2.8-3.7 3.6-1.5.8-3.3 1.1-4.9.8-1.6-.2-3.2-1-4.4-2.1-.4-.3-.4-.9-.1-1.2.3-.4.9-.4 1.2-.1 1 .7 2.2 1.1 3.4 1.1s2.3-.3 3.3-1c.9-.6 1.6-1.5 2-2.6.3-.9.4-1.8.2-2.8h-2.4c-.4 0-.7-.3-.7-.7 0-.2.1-.3.2-.4l4.4-4.4c.3-.3.7-.3.9 0L22 9.8c.3.3.4.6.3.9s-.3.3-.5.3z",
fill: "#000"
})]), {
id: "sb3-loopArrow-high-contrast"
}),
// https://github.com/scratchfoundation/scratch-gui/tree/beta/src/lib/themes/high-contrast/extensions
SVG.setProps(SVG.group([SVG.el("path", {
d: "M28.456 21.675c-.009-.312-.087-.825-.256-1.702-.096-.495-.612-3.022-.753-3.73-.395-1.98-.76-3.92-1.142-6.113-.732-4.223-.693-6.05.344-6.527.502-.23 1.06-.081 1.842.35.413.227 2.181 1.365 2.07 1.296 1.993 1.243 3.463 1.775 4.928 1.549 1.527-.237 2.505-.06 2.877.618.348.635.015 1.416-.729 2.18-1.473 1.516-3.976 2.514-5.849 2.023-.822-.218-1.238-.464-2.38-1.266a9.737 9.737 0 0 0-.095-.066c.047.593.264 1.74.717 3.803.294 1.336 2.079 9.187 2.637 11.674l.002.012c.529 2.637-1.872 4.724-5.235 4.724-3.29 0-6.363-1.988-6.862-4.528-.53-2.64 1.873-4.734 5.233-4.734a8.411 8.411 0 0 1 2.65.437zM11.46 27.666c-.01-.319-.091-.84-.266-1.738-.09-.46-.595-2.937-.753-3.727-.39-1.96-.752-3.892-1.131-6.07-.732-4.224-.692-6.052.344-6.527.502-.23 1.06-.082 1.841.349.414.228 2.181 1.365 2.07 1.296 1.992 1.243 3.461 1.775 4.925 1.549 1.525-.24 2.504-.064 2.876.614.348.635.015 1.415-.728 2.18-1.474 1.517-3.977 2.513-5.847 2.017-.822-.218-1.237-.463-2.38-1.266a9.729 9.729 0 0 0-.094-.065c.047.593.264 1.74.717 3.802.294 1.337 2.078 9.19 2.636 11.675l.003.013c.517 2.638-1.884 4.732-5.234 4.732-3.286 0-6.359-1.993-6.87-4.54-.518-2.639 1.885-4.73 5.242-4.73.904 0 1.802.15 2.65.436z",
stroke: "#000"
}), SVG.el("path", {
d: "M32.18 25.874C32.636 28.157 30.512 30 27.433 30c-3.07 0-5.923-1.843-6.372-4.126-.458-2.285 1.665-4.136 4.743-4.136.647 0 1.283.084 1.89.234a7 7 0 0 1 .938.302c.87-.02-.104-2.294-1.835-12.229-2.134-12.303 3.06-1.87 8.768-2.753 5.708-.885.076 4.82-3.65 3.844-3.724-.987-4.65-7.153.263 14.738zm-16.998 5.99C15.63 34.148 13.507 36 10.439 36c-3.068 0-5.92-1.852-6.379-4.136-.448-2.284 1.674-4.135 4.751-4.135 1.002 0 1.974.197 2.854.544.822-.055-.15-2.377-1.862-12.228-2.133-12.303 3.059-1.87 8.764-2.753 5.706-.894.076 4.821-3.648 3.834-3.723-.987-4.648-7.152.263 14.738z",
fill: "#000"
})]), {
id: "sb3-musicBlock-high-contrast",
fill: "none"
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M8.753 34.602l-4.251 1.779 1.784-4.236c1.218-2.892 2.907-5.423 5.03-7.538L31.066 4.93c.846-.842 2.65-.41 4.032.967 1.38 1.375 1.816 3.173.97 4.015L16.318 29.59c-2.123 2.116-4.664 3.799-7.565 5.012",
fill: "#FFF"
}), SVG.el("path", {
d: "M29.41 6.111s-4.45-2.379-8.202 5.771c-1.734 3.766-4.35 1.546-4.35 1.546"
}), SVG.el("path", {
d: "M36.42 8.825c0 .463-.14.873-.432 1.164l-9.335 9.301c.282-.29.41-.668.41-1.12 0-.874-.507-1.963-1.406-2.868-1.362-1.358-3.147-1.8-4.002-.99L30.99 5.01c.844-.84 2.65-.41 4.035.96.898.904 1.396 1.982 1.396 2.855M10.515 33.774a23.74 23.74 0 0 1-1.764.83L4.5 36.382l1.786-4.235c.258-.604.529-1.186.833-1.757.69.183 1.449.625 2.109 1.282.659.658 1.102 1.412 1.287 2.102",
fill: "#4C97FF"
}), SVG.el("path", {
d: "M36.498 8.748c0 .464-.141.874-.433 1.165l-19.742 19.68c-2.131 2.111-4.673 3.793-7.572 5.01L4.5 36.381l.974-2.317 1.925-.808c2.899-1.218 5.441-2.899 7.572-5.01l19.742-19.68c.292-.292.432-.702.432-1.165 0-.647-.27-1.4-.779-2.123.249.172.498.377.736.614.898.905 1.396 1.983 1.396 2.856",
fill: "#0b8e69",
opacity: ".15"
}), SVG.el("path", {
d: "M18.45 12.831a.904.904 0 1 1-1.807 0 .904.904 0 0 1 1.807 0z",
fill: "#0b8e69"
})]), {
id: "sb3-penBlock-high-contrast",
stroke: "#0b8e69",
fill: "none",
"stroke-linejoin": "round"
}), SVG.setProps(SVG.group([SVG.el("circle", {
opacity: 0.25,
cx: 32,
cy: 16,
r: 4.5
}), SVG.el("circle", {
opacity: 0.5,
cx: 32,
cy: 12,
r: 4.5
}), SVG.el("circle", {
opacity: 0.75,
cx: 32,
cy: 8,
r: 4.5
}), SVG.el("circle", {
cx: 32,
cy: 4,
r: 4.5
}), SVG.el("path", {
d: "M22.672 4.42l-6.172 4V6.1c0-2.01-1.563-3.6-3.5-3.6H4.1C2.076 2.5.5 4.076.5 6.1V14c0 1.927 1.584 3.512 3.6 3.6H13c1.902 0 3.5-1.653 3.5-3.6v-2.283l6.257 3.754.097.075c.02.02.098.054.146.054.267 0 .5-.217.5-.5V4.8c0 .037-.056-.094-.129-.243-.145-.242-.43-.299-.7-.137z",
fill: "#000",
"stroke-linejoin": "round"
})]), {
id: "sb3-videoBlock-high-contrast",
stroke: "#0b8e69",
fill: "#FFF",
"stroke-opacity": 0.15
}), SVG.setProps(SVG.group([SVG.el("path", {
d: "M25.644 20.5c-1.667 1.937-4.539 3.429-5.977 3.429a1.25 1.25 0 0 1-.557-.137c-.372-.186-.61-.542-.61-1.03 0-.105.017-.207.05-.308.076-.236.624-.986.727-1.173.27-.484.462-1.075.566-1.865A8.5 8.5 0 0 1 24 3.5h4a8.5 8.5 0 1 1 0 17h-2.356z",
fill: "#FFF",
stroke: "#0b8e69"
}), SVG.el("path", {
d: "M15.5 21.67c0-1.016-1.494-1.586-2.387-.782l-2.7 2.163A5.958 5.958 0 0 1 6.7 24.33h-.4c-1.035 0-1.8.69-1.8 1.573v4.235c0 .883.765 1.572 1.8 1.572h.4c1.458 0 2.754.423 3.82 1.287l2.598 2.161c.908.75 2.382.188 2.382-.876V21.67z",
fill: "#000"
})]), {
id: "sb3-ttsBlock-high-contrast",
"stroke-opacity": 0.15
}),
// The original icon is in PNG, but the high contrast version uses SVG.
// For consistency we use PNG in both places.
// https://github.com/scratchfoundation/scratch-gui/blob/beta/src/lib/themes/high-contrast/extensions/translateIcon.svg
// Exported via Inkscape and compressed
SVG.el("image", {
id: "sb3-translateBlock-high-contrast",
width: "40px",
height: "40px",
href: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAxoAAARjCAMAAADfFKLnAAABhlBMVEUAAAALjWkOj2oLjmkAAAAQj2wkmnkYlHILj2kLjmkAAAAAAABsu6VouaIJjmgimncAAAAAAAALjml0v6kAAAAAAAAAAAAATzhjt6A9pogVk28XlHAVk28ZlHEAAAAAAAAAAAANj2oAAAAJj2oAAAAAAAByvahsu6VVsZcqnXwAAAAAAAAAAAAMj2oQkWsAAAAPkGwAAABHqo4AAAAclnMcl3MKj2kXlHIXk3EAAAALj2gAAAD///8AAAB9w6+ExrONyrmHyLWrzv/3+/r8/v6Fx7VpqP/0+fh7s/9Ml//4/PvK59/4+//u9f/l8P/V5v9vrP9an/9Smv/o6OjMzMwrKysDAwPp8//e7P+w0f+axf9xrf9kpf9jpP9ho/9Nl//e3t7E5Nu+4dfT09OUzb2QzLuZmZlMrJKGhoYpnHxlZWVgYGBCQkINDQ30+P/J4P/D3P+11P+Nvf90rv9Jlvby8vLc3Nyl1cik1ce+vr6DxrKlpaWfn58xnJZBpJWJiYl+fn4fHx9PedmHAAAAPHRSTlMAd4OAxg/0wohyDv78+Tj16Ik6+ux+WAb79e7mvbCemW1rZDYXC/n39PTw39u8t7RVNvX11NLDm5qOWx0x5AFdAAAGd0lEQVR42uzbV3faQBCG4XGChMEU4wLujntv6WXXIUAwxd3Gvfea3nv+eQaBcgS5ztV8zwWMfsB7js7uiAAAAAAAAP6fgKfCwRMg1l49OBzqJgC5DLfZO+nQa7oNovq2Ia2rJwhArFZ/QpVI+Fspr57b8BKAUAEzrgpmXhSHjBmgvDGtQwQglKdWFaU27KnWQ0TekEvruvYwAYh08ym3ML0ei8V2NvlnfZofn98gorC2DBKASFYaq8md9MLW1kJ6O7lqp9Hj0qzqFgGIxGlYtjeUepPkwU6D20AZIJidRmxhZnbxtTMN8rpQBshlpzGdTL2dTzjSYJEnBCCVnYaaS++uqb9pAEhnpzGXXFycn1PZo2g0ejpiL410EYBQhTRepnZTs2vz776f+yYd/EG3QQAiWVd+s+nNV/yX+NEQVyXiDS0EIFKNmeAEZlRe9jyuysSDNQQgkrsvo4qOfOofvgoCEMloNWs/cgNTx9FT+7RqaUV/KI7PcFoFYgVG+7iMxpbK+19UwU+tfyENEC/SvK+yAw8cdxy5XO53AmmAdI8bD/qbxh13HMv67Ex/RhogXVfzvQ6DHGlc6L09fYk0AJgjjalrza7fIw2QrjtSksZXfXFycqm/IQ0QrrPK5XWmcbWylD+/vUIaIFtnldaFNjx+lbd8qNjhMq78QDQug7l6eAwE46pMxsSiCAhVpy1hYu7y9cKM300AMoXbOQ5XyEvMaAn6opbjKQ7jkw9L6SBZSOsxe66pqLSMNnIb/hG8TYFk3mqt66nMw4Gs2m+OEIBgE9zGcFtZHeNN/Qe3OwhAsu5HQ3fq2qiU0XG3Cd+GAwAAAAD8YQ8OBAAAAACA/F8bQVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYQ8OBAAAAACA/F8bQVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV2IMDAQAAAAAg/9dGUFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUV9uBAAAAAAADI/7URVFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWFPTgQAAAAAADyf20EVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVhDw4EAAAAAID8XxtBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVXYgwMBAAAAACD/10ZQVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVRX24EAAAAAAAMj/tRFUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYU9OBAAAAAAAPJ/bQRVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWEPDgQAAAAAgPxfG0FVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVdiDAwEAAAAAIP/XRlBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVFfbgQAAAAAAAyP+1EVRVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVhT04EAAAAAAA8n9tBFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYQ8OBAAAAACA/F8bQVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV2oNDAgAAAABB/1/7wgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMArKwCvdMdAc1YAAAAASUVORK5CYII="
})]);
}
/**
* @return the icon name with suffix, if a high contrast icon is defined
*/
}, {
key: "iconName",
value: function iconName(name, iconStyle) {
if (iconStyle === "high-contrast" && highContrastIcons.has(name)) {
return name + "-high-contrast";
}
return name;
}
}, {
key: "makeStyle",
value: function makeStyle() {
var style = SVG.el("style");
style.appendChild(SVG.cdata(Style.cssContent));
return style;
}
}, {
key: "defaultFont",
get: function get() {
return "500 12pt Helvetica Neue, Helvetica, sans-serif";
}
}, {
key: "commentFont",
get: function get() {
return "400 12pt Helvetica Neue, Helvetica, sans-serif";
}
}]);
return Style;
}();
var defaultFont = Style.defaultFont,
commentFont = Style.commentFont,
makeStyle$1 = Style.makeStyle,
makeOriginalIcons = Style.makeOriginalIcons,
makeHighContrastIcons = Style.makeHighContrastIcons,
iconName = Style.iconName;
var LabelView = /*#__PURE__*/function () {
function LabelView(label) {
_extends(this, label);
this.el = null;
this.height = 12;
this.metrics = null;
this.x = 0;
}
_createClass(LabelView, [{
key: "isLabel",
get: function get() {
return true;
}
}, {
key: "draw",
value: function draw(_iconStyle) {
return this.el;
}
}, {
key: "width",
get: function get() {
return this.metrics.width;
}
}, {
key: "measure",
value: function measure() {
var value = this.value;
var cls = "sb3-" + this.cls;
this.el = SVG.text(0, 13, value, {
class: "sb3-label " + cls
});
var cache = LabelView.metricsCache[cls];
if (!cache) {
cache = LabelView.metricsCache[cls] = Object.create(null);
}
if (Object.hasOwnProperty.call(cache, value)) {
this.metrics = cache[value];
} else {
var font = /comment-label/.test(this.cls) ? commentFont : defaultFont;
this.metrics = cache[value] = LabelView.measure(value, font);
// TODO: word-spacing? (fortunately it seems to have no effect!)
}
}
}], [{
key: "measure",
value: function measure(value, font) {
var context = LabelView.measuring;
context.font = font;
var textMetrics = context.measureText(value);
var width = textMetrics.width + 0.5 | 0;
return {
width: width
};
}
}]);
return LabelView;
}();
LabelView.metricsCache = {};
LabelView.toMeasure = [];
var IconView = /*#__PURE__*/function () {
function IconView(icon) {
_extends(this, icon);
var info = IconView.icons[this.name];
if (!info) {
throw new Error("no info for icon: " + this.name);
}
_extends(this, info);
}
_createClass(IconView, [{
key: "isIcon",
get: function get() {
return true;
}
}, {
key: "draw",
value: function draw(iconStyle) {
return SVG.symbol("#sb3-" + iconName(this.name, iconStyle), {
width: this.width,
height: this.height
});
}
}], [{
key: "icons",
get: function get() {
return {
greenFlag: {
width: 20,
height: 21,
dy: -2
},
stopSign: {
width: 20,
height: 20
},
turnLeft: {
width: 24,
height: 24
},
turnRight: {
width: 24,
height: 24
},
loopArrow: {
width: 24,
height: 24
},
addInput: {
width: 4,
height: 8
},
delInput: {
width: 4,
height: 8
},
list: {
width: 15,
height: 18
},
musicBlock: {
width: 40,
height: 40
},
penBlock: {
width: 40,
height: 40
},
videoBlock: {
width: 40,
height: 40,
dy: 10
},
ttsBlock: {
width: 40,
height: 40
},
translateBlock: {
width: 40,
height: 40
},
wedoBlock: {
width: 40,
height: 40
},
ev3Block: {
width: 40,
height: 40
},
microbitBlock: {
width: 40,
height: 40
},
makeymakeyBlock: {
width: 40,
height: 40
},
gdxforBlock: {
width: 40,
height: 40
},
boostBlock: {
width: 40,
height: 40
}
};
}
}]);
return IconView;
}();
var LineView = /*#__PURE__*/function () {
function LineView() {
this.width = 1;
this.height = 40;
this.x = 0;
}
_createClass(LineView, [{
key: "isLine",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() { }
}, {
key: "draw",
value: function draw(_iconStyle, parent) {
var category = parent.info.category;
return SVG.el("line", {
class: "sb3-" + category + "-line",
"stroke-linecap": "round",
x1: 0,
y1: 0,
x2: 0,
y2: 40
});
}
}]);
return LineView;
}();
var InputView = /*#__PURE__*/function () {
function InputView(input) {
_extends(this, input);
if (input.label) {
this.label = newView(input.label);
}
this.isBoolean = this.shape === "boolean";
this.isDropdown = this.shape === "dropdown";
this.isRound = !(this.isBoolean || this.isDropdown);
this.x = 0;
}
_createClass(InputView, [{
key: "isInput",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
if (this.hasLabel) {
this.label.measure();
}
}
}, {
key: "draw",
value: function draw(iconStyle, parent) {
var w;
var label;
if (this.isBoolean) {
w = 48;
} else if (this.isColor) {
w = 40;
} else if (this.hasLabel) {
label = this.label.draw(iconStyle);
// Minimum padding of 11
// Minimum width of 40, at which point we center the label
var px = this.label.width >= 18 ? 11 : (40 - this.label.width) / 2;
w = this.label.width + 2 * px;
label = SVG.move(px, 9, label);
} else {
w = this.isInset ? 30 : null;
}
if (this.hasArrow) {
w += 20;
}
this.width = w;
var h = this.height = 32;
var el = InputView.shapes[this.shape](w, h);
SVG.setProps(el, {
class: (this.isColor ? "" : "sb3-" + parent.info.category) + " sb3-input sb3-input-" + this.shape
});
if (this.isColor) {
SVG.setProps(el, {
fill: this.value
});
} else if (this.shape === "dropdown") {
// custom colors
if (parent.info.color) {
SVG.setProps(el, {
fill: parent.info.color,
stroke: "rgba(0, 0, 0, 0.2)"
});
}
} else if (this.shape === "number-dropdown") {
el.classList.add("sb3-" + parent.info.category + "-alt");
// custom colors
if (parent.info.color) {
SVG.setProps(el, {
fill: "rgba(0, 0, 0, 0.1)",
stroke: "rgba(0, 0, 0, 0.15)" // combines with fill...
});
}
} else if (this.shape === "boolean") {
el.classList.remove("sb3-" + parent.info.category);
el.classList.add("sb3-" + parent.info.category + "-dark");
// custom colors
if (parent.info.color) {
SVG.setProps(el, {
fill: "rgba(0, 0, 0, 0.15)"
});
}
}
var result = SVG.group([el]);
if (this.hasLabel) {
result.appendChild(label);
}
if (this.hasArrow) {
result.appendChild(SVG.move(w - 24, 13, SVG.symbol(iconStyle === "high-contrast" ? "#sb3-dropdownArrow-high-contrast" : "#sb3-dropdownArrow", {})));
}
return result;
}
}], [{
key: "shapes",
get: function get() {
return {
string: SVG.pillRect,
number: SVG.pillRect,
"number-dropdown": SVG.pillRect,
color: SVG.pillRect,
dropdown: SVG.roundRect,
boolean: SVG.pointedRect,
stack: SVG.stackRect,
reporter: SVG.pillRect
};
}
}]);
return InputView;
}();
var BlockView = /*#__PURE__*/function () {
function BlockView(block) {
_extends(this, block);
this.children = block.children.map(newView);
this.comment = this.comment ? newView(this.comment) : null;
this.isRound = this.isReporter;
// Avoid accidental mutation
this.info = _objectSpread2({}, block.info);
if (Object.prototype.hasOwnProperty.call(aliasExtensions, this.info.category)) {
this.info.category = aliasExtensions[this.info.category];
}
if (Object.prototype.hasOwnProperty.call(extensions, this.info.category)) {
this.children.unshift(new LineView());
this.children.unshift(new IconView({
name: this.info.category + "Block"
}));
this.info.category = "extension";
}
this.x = 0;
this.width = null;
this.height = null;
this.firstLine = null;
this.innerWidth = null;
}
_createClass(BlockView, [{
key: "isBlock",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
var _iterator = _createForOfIteratorHelper(this.children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child.measure) {
child.measure();
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (this.comment) {
this.comment.measure();
}
}
}, {
key: "drawSelf",
value: function drawSelf(iconStyle, w, h, lines) {
// mouths
if (lines.length > 1) {
return SVG.mouthRect(w, h, this.isFinal, lines, {
class: "sb3-" + this.info.category
});
}
// outlines
if (this.info.shape === "outline") {
return SVG.setProps(SVG.stackRect(w, h), {
class: "sb3-" + this.info.category + " sb3-" + this.info.category + "-alt"
});
}
// rings
if (this.isRing) {
var child = this.children[0];
if (child && (child.isInput || child.isBlock || child.isScript)) {
return SVG.roundRect(w, h, {
class: "sb3-" + this.info.category
});
}
}
var func = BlockView.shapes[this.info.shape];
if (!func) {
throw new Error("no shape func: " + this.info.shape);
}
return func(w, h, {
class: "sb3-" + this.info.category
});
}
}, {
key: "horizontalPadding",
value: function horizontalPadding(child) {
if (this.isRound) {
if (child.isIcon) {
return 16;
} else if (child.isLabel) {
return 12; // text in circle: 3 units
} else if (child.isDropdown) {
return 12; // square in circle: 3 units
} else if (child.isBoolean) {
return 12; // hexagon in circle: 3 units
} else if (child.isRound) {
return 4; // circle in circle: 1 unit
}
} else if (this.isBoolean) {
if (child.isIcon) {
return 24; // icon in hexagon: ???
} else if (child.isLabel) {
return 20; // text in hexagon: 5 units
} else if (child.isDropdown) {
return 20; // square in hexagon: 5 units
} else if (child.isRound && child.isBlock) {
return 24; // circle in hexagon: 5 + 1 units
} else if (child.isRound) {
return 20; // circle in hexagon: 5 units
} else if (child.isBoolean) {
return 8; // hexagon in hexagon: 2 units
}
}
return 8; // default: 2 units
}
}, {
key: "marginBetween",
value: function marginBetween(a, b) {
// Consecutive labels should be rendered as a single text element.
// For now, approximate the size of one space
if (a.isLabel && b.isLabel) {
return 5;
}
return 8; // default: 2 units
}
}, {
key: "draw",
value: function draw(iconStyle) {
var isDefine = this.info.shape === "define-hat";
var children = this.children;
var isCommand = this.isCommand;
var padding = BlockView.padding[this.info.shape] || BlockView.padding.null;
var pt = padding[0],
pb = padding[1];
var y = this.info.shape === "cat" ? 16 : 0;
var Line = function Line(y) {
this.y = y;
this.width = 0;
this.height = isCommand ? 40 : 32;
this.children = [];
};
var innerWidth = 0;
var scriptWidth = 0;
var line = new Line(y);
var pushLine = function pushLine() {
if (lines.length === 0) {
line.height += pt + pb;
} else {
line.height -= 11;
line.y -= 2;
}
y += line.height;
lines.push(line);
};
if (this.info.isRTL) {
var start = 0;
var flip = function flip() {
children = children.slice(0, start).concat(children.slice(start, i).reverse()).concat(children.slice(i));
};
var i;
for (i = 0; i < children.length; i++) {
if (children[i].isScript) {
flip();
start = i + 1;
}
}
if (start < i) {
flip();
}
}
var lines = [];
var previousChild;
var lastChild;
for (var _i = 0; _i < children.length; _i++) {
var child = children[_i];
child.el = child.draw(iconStyle, this);
if (child.isScript && this.isCommand) {
this.hasScript = true;
pushLine();
child.y = y - 1;
lines.push(child);
scriptWidth = Math.max(scriptWidth, Math.max(1, child.width));
child.height = Math.max(29, child.height + 3) - 2;
y += child.height;
line = new Line(y);
previousChild = null;
} else if (child.isArrow) {
line.children.push(child);
previousChild = child;
} else {
// Remember the last child on the first line
if (!lines.length) {
lastChild = child;
}
// Leave space between inputs
if (previousChild) {
line.width += this.marginBetween(previousChild, child);
}
// Align first input with right of notch
if (children[0] != null) {
var cmw = 48 - this.horizontalPadding(children[0]);
if ((this.isCommand || this.isOutline) && !child.isLabel && !child.isIcon && line.width < cmw) {
line.width = cmw;
}
}
// Align extension category icons below notch
if (child.isIcon && _i === 0 && this.isCommand) {
line.height = Math.max(line.height, child.height + 8);
}
child.x = line.width;
line.width += child.width;
innerWidth = Math.max(innerWidth, line.width);
if (!child.isLabel) {
line.height = Math.max(line.height, child.height);
}
line.children.push(child);
previousChild = child;
}
}
pushLine();
var padLeft = children.length ? this.horizontalPadding(children[0]) : 0;
var padRight = children.length ? this.horizontalPadding(lastChild) : 0;
innerWidth += padLeft + padRight;
// Commands have a minimum width
// The hat min-width is arbitrary (not sure of Scratch 3 value)
// Outline min-width is deliberately higher (because Scratch 3 looks silly)
var originalInnerWidth = innerWidth;
innerWidth = Math.max(this.hasScript ? 160 : this.isHat ? 108 : this.isCommand || this.isOutline ? 64 : this.isReporter ? 48 : 0, innerWidth);
// Center the label text inside small reporters.
if (this.isReporter) {
padLeft += (innerWidth - originalInnerWidth) / 2;
}
this.height = y;
this.width = scriptWidth ? Math.max(innerWidth, 15 + scriptWidth) : innerWidth;
this.firstLine = lines[0];
this.innerWidth = innerWidth;
var objects = [];
for (var _i2 = 0; _i2 < lines.length; _i2++) {
var _line = lines[_i2];
if (_line.isScript) {
objects.push(SVG.move(16, _line.y, _line.el));
continue;
}
var h = _line.height;
for (var j = 0; j < _line.children.length; j++) {
var _child = _line.children[j];
if (_child.isArrow) {
objects.push(SVG.move(innerWidth - 32, this.height - 28, _child.el));
continue;
}
var _y = pt + (h - _child.height - pt - pb) / 2;
if (_child.isLabel && _i2 === 0) {
// We only do this for the first line so that the `else` label is
// correctly aligned
_y -= 1;
} else if (isDefine && _child.isLabel) {
_y += 3;
} else if (_child.isIcon) {
_y += _child.dy | 0;
if (this.isCommand && _i2 === 0 && j === 0) {
_y += 4;
}
}
var x = padLeft + _child.x;
if (_child.dx) {
x += _child.dx;
}
objects.push(SVG.move(x, _line.y + _y | 0, _child.el));
}
}
var el = this.drawSelf(iconStyle, innerWidth, this.height, lines);
objects.splice(0, 0, el);
if (this.info.color) {
SVG.setProps(el, {
fill: this.info.color,
stroke: "rgba(0, 0, 0, 0.2)"
});
}
return SVG.group(objects);
}
}], [{
key: "shapes",
get: function get() {
return {
stack: SVG.stackRect,
"c-block": SVG.stackRect,
"if-block": SVG.stackRect,
celse: SVG.stackRect,
cend: SVG.stackRect,
cap: SVG.capRect,
reporter: SVG.pillRect,
boolean: SVG.pointedRect,
hat: SVG.hatRect,
cat: SVG.catHat,
"define-hat": SVG.procHatRect,
ring: SVG.pillRect
};
}
}, {
key: "padding",
get: function get() {
return {
hat: [24, 8],
cat: [24, 8],
"define-hat": [20, 16],
null: [4, 4]
};
}
}]);
return BlockView;
}();
var CommentView = /*#__PURE__*/function () {
function CommentView(comment) {
_extends(this, comment);
this.label = newView(comment.label);
this.width = null;
}
_createClass(CommentView, [{
key: "isComment",
get: function get() {
return true;
}
}, {
key: "height",
get: function get() {
return 20;
}
}, {
key: "measure",
value: function measure() {
this.label.measure();
}
}, {
key: "draw",
value: function draw(iconStyle) {
var labelEl = this.label.draw(iconStyle);
this.width = this.label.width + 16;
return SVG.group([SVG.commentLine(this.hasBlock ? CommentView.lineLength : 0, 6), SVG.commentRect(this.width, this.height, {
class: "sb3-comment"
}), SVG.move(8, 4, labelEl)]);
}
}], [{
key: "lineLength",
get: function get() {
return 12;
}
}]);
return CommentView;
}();
var GlowView = /*#__PURE__*/function () {
function GlowView(glow) {
_extends(this, glow);
this.child = newView(glow.child);
this.width = null;
this.height = null;
this.y = 0;
}
_createClass(GlowView, [{
key: "isGlow",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
this.child.measure();
}
}, {
key: "drawSelf",
value: function drawSelf() {
var c = this.child;
var el;
var w = this.width;
var h = this.height - 1;
if (c.isScript) {
if (!c.isEmpty && c.blocks[0].isHat) {
el = SVG.hatRect(w, h);
} else if (c.isFinal) {
el = SVG.capRect(w, h);
} else {
el = SVG.stackRect(w, h);
}
} else {
el = c.drawSelf(w, h, []);
}
return SVG.setProps(el, {
class: "sb3-diff sb3-diff-ins"
});
}
// TODO how can we always raise Glows above their parents?
}, {
key: "draw",
value: function draw(iconStyle) {
var c = this.child;
var el = c.isScript ? c.draw(iconStyle, true) : c.draw(iconStyle);
this.width = c.width;
this.height = c.isBlock && c.firstLine.height || c.height;
// encircle
return SVG.group([el, this.drawSelf()]);
}
}]);
return GlowView;
}();
var ScriptView = /*#__PURE__*/function () {
function ScriptView(script) {
_extends(this, script);
this.blocks = script.blocks.map(newView);
this.y = 0;
}
_createClass(ScriptView, [{
key: "isScript",
get: function get() {
return true;
}
}, {
key: "measure",
value: function measure() {
var _iterator2 = _createForOfIteratorHelper(this.blocks),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var block = _step2.value;
block.measure();
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
}, {
key: "draw",
value: function draw(iconStyle, inside) {
var children = [];
var y = 1;
this.width = 0;
var _iterator3 = _createForOfIteratorHelper(this.blocks),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var block = _step3.value;
var x = inside ? 0 : 2;
var child = block.draw(iconStyle);
children.push(SVG.move(x, y, child));
this.width = Math.max(this.width, block.width);
var diff = block.diff;
if (diff === "-") {
var dw = block.width;
var dh = block.firstLine.height || block.height;
children.push(SVG.move(x, y + dh / 2 + 1, SVG.strikethroughLine(dw)));
this.width = Math.max(this.width, block.width);
}
y += block.height;
var comment = block.comment;
if (comment) {
var line = block.firstLine;
var cx = block.innerWidth + 2 + CommentView.lineLength;
var cy = y - block.height + line.height / 2;
var el = comment.draw(iconStyle);
children.push(SVG.move(cx, cy - comment.height / 2, el));
this.width = Math.max(this.width, cx + comment.width);
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
var lastBlock = this.blocks[this.blocks.length - 1];
this.height = y + 1;
if (!inside && !this.isFinal) {
this.height += lastBlock.hasPuzzle ? 8 : 0;
}
if (!inside && lastBlock.isGlow) {
this.height += 7; // TODO unbreak this
}
return SVG.group(children);
}
}]);
return ScriptView;
}();
var DocumentView = /*#__PURE__*/function () {
function DocumentView(doc, options) {
_extends(this, doc);
this.scripts = doc.scripts.map(newView);
this.width = null;
this.height = null;
this.el = null;
this.defs = null;
this.scale = options.scale;
this.iconStyle = options.style.replace("scratch3-", "");
}
_createClass(DocumentView, [{
key: "measure",
value: function measure() {
this.scripts.forEach(function (script) {
script.measure();
});
}
}, {
key: "render",
value: function render(cb) {
if (typeof cb === "function") {
throw new Error("render() no longer takes a callback");
}
// measure strings
this.measure();
// TODO: separate layout + render steps.
// render each script
var width = 0;
var height = 0;
var elements = [];
for (var i = 0; i < this.scripts.length; i++) {
var script = this.scripts[i];
if (height) {
height += 10;
}
script.y = height;
elements.push(SVG.move(0, height, script.draw(this.iconStyle)));
height += script.height;
if (i !== this.scripts.length - 1) {
height += 36;
}
width = Math.max(width, script.width + 4);
}
this.width = width;
this.height = height;
// return SVG
var svg = SVG.newSVG(width, height, this.scale);
var icons = this.iconStyle === "high-contrast" ? makeHighContrastIcons() : makeOriginalIcons();
svg.appendChild(this.defs = SVG.withChildren(SVG.el("defs"), icons));
svg.appendChild(SVG.setProps(SVG.group(elements), {
style: "transform: scale(" + this.scale + ")"
}));
this.el = svg;
return svg;
}
/* Export SVG image as XML string */
}, {
key: "exportSVGString",
value: function exportSVGString() {
if (this.el == null) {
throw new Error("call draw() first");
}
var style = makeStyle$1();
this.defs.appendChild(style);
var xml = new SVG.XMLSerializer().serializeToString(this.el);
this.defs.removeChild(style);
return xml;
}
/* Export SVG image as data URI */
}, {
key: "exportSVG",
value: function exportSVG() {
var xml = this.exportSVGString();
return "data:image/svg+xml;utf8," + xml.replace(/[#]/g, encodeURIComponent);
}
}, {
key: "toCanvas",
value: function toCanvas(cb, exportScale) {
exportScale = exportScale || 1.0;
var canvas = SVG.makeCanvas();
canvas.width = Math.max(1, this.width * exportScale * this.scale);
canvas.height = Math.max(1, this.height * exportScale * this.scale);
var context = canvas.getContext("2d");
var image = new Image();
image.src = this.exportSVG();
image.onload = function () {
context.save();
context.scale(exportScale, exportScale);
context.drawImage(image, 0, 0);
context.restore();
cb(canvas);
};
}
}, {
key: "exportPNG",
value: function exportPNG(cb, scale) {
this.toCanvas(function (canvas) {
if (URL && URL.createObjectURL && Blob && canvas.toBlob) {
canvas.toBlob(function (blob) {
cb(URL.createObjectURL(blob));
}, "image/png");
} else {
cb(canvas.toDataURL("image/png"));
}
}, scale);
}
}]);
return DocumentView;
}();
var viewFor = function viewFor(node) {
switch (node.constructor) {
case Label:
return LabelView;
case Icon:
return IconView;
case Input:
return InputView;
case Block:
return BlockView;
case Comment:
return CommentView;
case Glow:
return GlowView;
case Script:
return ScriptView;
case Document:
return DocumentView;
default:
throw new Error("no view for " + node.constructor.name);
}
};
var newView = function newView(node, options) {
return new (viewFor(node))(node, options);
};
function init$1(window) {
SVG.init(window);
LabelView.measuring = SVG.makeCanvas().getContext("2d");
}
var makeStyle = Style.makeStyle;
function init(window) {
var document = window.document;
init$2(window);
init$1(window);
function appendStyles() {
document.head.appendChild(makeStyle$2());
document.head.appendChild(makeStyle());
}
function newView$2(doc, options) {
options = _objectSpread2({
style: "scratch2"
}, options);
options.scale = options.scale || 1;
if (options.style === "scratch2") {
return newView$1(doc, options);
} else if (/^scratch3($|-)/.test(options.style)) {
return newView(doc, options);
}
throw new Error("Unknown style: " + options.style);
}
function render(doc, options) {
if (typeof options === "function") {
throw new Error("render() no longer takes a callback");
}
var view = newView$2(doc, options);
var svg = view.render();
// Used in high contrast theme
svg.classList.add("scratchblocks-style-" + options.style);
return svg;
}
/*****************************************************************************/
/*** Render ***/
// read code from a DOM element
function readCode(el, options) {
options = _objectSpread2({
inline: false
}, options);
var html = el.innerHTML.replace(/<br>\s?|\n|\r\n|\r/gi, "\n");
var pre = document.createElement("pre");
pre.innerHTML = html;
var code = pre.textContent;
if (options.inline) {
code = code.replace("\n", "");
}
return code;
}
// insert 'svg' into 'el', with appropriate wrapper elements
function replace(el, svg, doc, options) {
var container;
if (options.inline) {
container = document.createElement("span");
var cls = "scratchblocks scratchblocks-inline";
if (doc.scripts[0] && !doc.scripts[0].isEmpty) {
cls += " scratchblocks-inline-" + doc.scripts[0].blocks[0].shape;
}
container.className = cls;
container.style.display = "inline-block";
container.style.verticalAlign = "middle";
} else {
container = document.createElement("div");
container.className = "scratchblocks";
}
container.appendChild(svg);
el.innerHTML = "";
el.appendChild(container);
}
/* Render all matching elements in page to shiny scratch blocks.
* Accepts a CSS selector as an argument.
*
* scratchblocks.renderMatching("pre.blocks");
*
* Like the old 'scratchblocks2.parse().
*/
var renderMatching = function renderMatching(selector, options) {
selector = selector || "pre.blocks";
options = _objectSpread2({
// Default values for the options
style: "scratch2",
inline: false,
languages: ["en"],
scale: 1,
read: readCode,
// function(el, options) => code
parse: parse,
// function(code, options) => doc
render: render,
// function(doc) => svg
replace: replace
}, options);
// find elements
var results = [].slice.apply(document.querySelectorAll(selector));
results.forEach(function (el) {
var code = options.read(el, options);
var doc = options.parse(code, options);
var svg = options.render(doc, options);
options.replace(el, svg, doc, options);
});
};
return {
allLanguages: allLanguages,
// read-only
loadLanguages: loadLanguages,
stringify: function stringify(doc) {
return doc.stringify();
},
Label: Label,
Icon: Icon,
Input: Input,
Block: Block,
Comment: Comment,
Script: Script,
Document: Document,
newView: newView$2,
read: readCode,
parse: parse,
replace: replace,
render: render,
renderMatching: renderMatching,
appendStyles: appendStyles
};
}
scratchblocks.module = init(window);
// add our CSS to the page
scratchblocks.module.appendStyles();
})();
};
// The main code starts here ---------------------------------------------------------------------------------------
function rescratch() {
document.querySelectorAll('pre[lang="scratch"]').forEach(function(pre) {
if (pre.querySelector('code')) {
pre.classList.add('renderblocks');
} else {
pre.classList.remove('renderblocks');
}
});
document.querySelectorAll('pre[lang="scratch2"]').forEach(function(pre) {
if (pre.querySelector('code')) {
pre.classList.add('renderblocks2');
} else {
pre.classList.remove('renderblocks2');
}
});
document.querySelectorAll('pre[lang="scratch3"]').forEach(function(pre) {
if (pre.querySelector('code')) {
pre.classList.add('renderblocks3');
} else {
pre.classList.remove('renderblocks3');
}
});
scratchblocks.init();
scratchblocks.module.renderMatching('.renderblocks', {
style: "scratch3",
});
scratchblocks.module.renderMatching('.renderblocks3', {
style: "scratch3",
});
scratchblocks.module.renderMatching('.renderblocks2', {
style: "scratch2",
});
} rescratch();
window.addEventListener('message', (event) => {
rescratch();
});
setInterval(rescratch, 1000);
})();