ref: 81d1e4e01d7001e6a0107792e6167136787295d6
dir: /core.js/
import {MakeBlock, MakeSlot, complement} from "./model.js" // slots export let TextSlot = MakeSlot() export let BooleanSlot = MakeSlot({numeric: true, normalise: () => "", canFit: block => block.type.output === "boolean"}) export let NumberSlot = MakeSlot({numeric: true, normalise: n => Number.isFinite(Number(n)) ? String(n) : ""}) export let IntegerSlot = MakeSlot({numeric: true, normalise: n => Number.isInteger(Number(n)) ? String(n) : ""}) export let PositiveSlot = MakeSlot({numeric: true, normalise: n => { let m = Number(n) ; return Number.isFinite(m) && m >= 0 ? String(n) : "" }}) export let NaturalSlot = MakeSlot({numeric: true, normalise: n => { let m = Number(n) ; return Number.isInteger(m) && m >= 0 ? String(n) : "" }}) export function EnumeratedSlot(options, type = {}) { return MakeSlot({canFit: () => false, ...type, normalise: n => String(options.includes(String(n)) ? n : options[0]), options}) } // events export let WhenFlagClicked = MakeBlock({hat: true, name: () => ["when", [getIcon(), "green flag", "flag", "gf", "@greenFlag"], "clicked"], category: "events"}) // control export let Else = MakeBlock({stack: true, name: () => ["else"]}) export let If = MakeBlock({slots: [BooleanSlot], stack: true, name: condition => ["if", condition, "then"], category: "control", complement: Else.type}) export let Forever = MakeBlock({stack: true, name: () => ["forever"], category: "control", loop: true, cap: true}) export let WaitUntil = MakeBlock({slots: [BooleanSlot], name: condition => ["wait until", condition], category: "control"}) export let RepeatUntil = MakeBlock({slots: [BooleanSlot], stack: true, name: condition => ["repeat until", condition], category: "control", loop: true}) export let Repeat = MakeBlock({slots: [NaturalSlot], stack: true, name: seconds => ["repeat", seconds], category: "control", defaults: [10], loop: true}) export let Stop = MakeBlock({name: () => ["stop this script"], category: "control", cap: true}) export function IfElse(...args) { let block = If(...args) complement(block, Else()) return block } // operators export let Add = MakeBlock({shape: "reporter", slots: [NumberSlot, NumberSlot], name: (a, b) => [a, "+", b], category: "operators", output: "number"}) export let Subtract = MakeBlock({shape: "reporter", slots: [NumberSlot, NumberSlot], name: (a, b) => [a, "-", b], category: "operators", output: "number"}) export let Multiply = MakeBlock({shape: "reporter", slots: [NumberSlot, NumberSlot], name: (a, b) => [a, "*", b], category: "operators", output: "number"}) export let Divide = MakeBlock({shape: "reporter", slots: [NumberSlot, NumberSlot], name: (a, b) => [a, "/", b], category: "operators", output: "number"}) export let Modulo = MakeBlock({shape: "reporter", slots: [NumberSlot, NumberSlot], name: (a, b) => [a, "mod", b], category: "operators", output: "number"}) export let LessThan = MakeBlock({shape: "reporter", slots: [TextSlot, TextSlot], name: (a, b) => [a, "<", b], category: "operators", defaults: ["", 50], output: "boolean"}) export let GreaterThan = MakeBlock({shape: "reporter", slots: [TextSlot, TextSlot], name: (a, b) => [a, ">", b], category: "operators", defaults: ["", 50], output: "boolean"}) export let Equals = MakeBlock({shape: "reporter", slots: [TextSlot, TextSlot], name: (a, b) => [a, "=", b], category: "operators", defaults: ["", 50], output: "boolean"}) export let And = MakeBlock({shape: "reporter", slots: [BooleanSlot, BooleanSlot], name: (a, b) => [a, "and", b], category: "operators", output: "boolean"}) export let Or = MakeBlock({shape: "reporter", slots: [BooleanSlot, BooleanSlot], name: (a, b) => [a, "or", b], category: "operators", output: "boolean"}) export let Not = MakeBlock({shape: "reporter", slots: [BooleanSlot], name: a => ["not", a], category: "operators", output: "boolean"}) export let Join = MakeBlock({shape: "reporter", slots: [TextSlot, TextSlot], name: (a, b) => ["join", a, b], category: "operators", defaults: ["apple ", "banana"], output: "text"}) export let TextIndex = MakeBlock({shape: "reporter", slots: [TextSlot, NaturalSlot], name: (a, b) => ["letter", b, "of", a], category: "operators", defaults: ["apple", 1], output: "text"}) export let TextLength = MakeBlock({shape: "reporter", slots: [TextSlot], name: a => ["length of", a], category: "operators", defaults: ["apple"], output: "natural"}) export let TextContains = MakeBlock({shape: "reporter", slots: [TextSlot, TextSlot], name: (a, b) => [a, "contains", b, "?"], category: "operators", defaults: ["apple", "a"], output: "boolean"}) // variables export let Variable = MakeBlock({shape: "reporter", category: "variables", references: ["variable"]}) export let SetVariable = MakeBlock({slots: [TextSlot], name: (name, value) => ["set", name, "to", value], category: "variables", references: ["variable"], defaults: [0]}) export let ChangeVariable = MakeBlock({slots: [NumberSlot], name: (name, value) => ["change", name, "by", value], category: "variables", references: ["variable"], defaults: [1]}) // lists export let List = MakeBlock({shape: "reporter", category: "lists", references: ["list"], output: "text"}) export let Append = MakeBlock({slots: [TextSlot], name: (name, value) => ["add", value, "to", name], category: "lists", references: ["list"], defaults: ["thing"]}) export let Delete = MakeBlock({slots: [NaturalSlot], name: (name, index) => ["delete", index, "of", name], category: "lists", references: ["list"], defaults: [1]}) export let Clear = MakeBlock({name: name => ["delete all of", name], category: "lists", references: ["list"]}) export let Insert = MakeBlock({slots: [NaturalSlot, TextSlot], name: (name, index, value) => ["insert", value, "at", index, "of", name], category: "lists", references: ["list"], defaults: [1, "thing"]}) export let Replace = MakeBlock({slots: [NaturalSlot, TextSlot], name: (name, index, value) => ["replace item", index, "of", name, "with", value], category: "lists", references: ["list"], defaults: [1, "thing"]}) export let Index = MakeBlock({shape: "reporter", slots: [NaturalSlot], name: (name, index) => ["item", index, "of", name], category: "lists", references: ["list"], defaults: [1]}) export let Find = MakeBlock({shape: "reporter", slots: [TextSlot], name: (name, value) => ["item # of", value, "in", name], category: "lists", references: ["list"], defaults: ["thing"], output: "natural"}) export let Length = MakeBlock({shape: "reporter", name: name => ["length of", name], category: "lists", references: ["list"], output: "natural"}) export let Contains = MakeBlock({shape: "reporter", slots: [TextSlot], name: (name, value) => [name, "contains", value, "?"], category: "lists", references: ["list"], defaults: ["thing"], output: "boolean"}) // my blocks export let Define = MakeBlock({hat: true, category: "custom", references: ["custom"], complete: block => block.atomic = false, name: prototype => ["define", prototype]}) export let TextParameter = MakeBlock({shape: "reporter", category: "custom", references: ["text-parameter"]}) export let BooleanParameter = MakeBlock({shape: "reporter", category: "custom", references: ["boolean-parameter"], output: "boolean"}) function MakeCustom(name) { return MakeBlock({ category: "custom", name: (...inputs) => { let name1 = [] let i = 0 for (let part of name) { if (typeof part === "string") name1.push(part) else name1.push(inputs[i++]) } return name1 }, slots: name.filter(part => typeof part !== "string").map(part => part.type === "boolean" ? BooleanSlot : TextSlot), references: ["custom"], defaults: name.filter(part => typeof part !== "string").map(() => ""), }) } export function Custom(name, ...inputs) { return MakeCustom(name)(name, ...inputs) } let variableFns = [SetVariable, ChangeVariable] let listFns = [Append, Delete, Clear, Insert, Replace, Index, Find, Length, Contains] export let library = [ WhenFlagClicked, Repeat, Forever, If, IfElse, WaitUntil, RepeatUntil, Stop, Add, Subtract, Multiply, Divide, Modulo, GreaterThan, LessThan, Equals, And, Or, Not, Join, TextIndex, TextLength, TextContains, ...variableFns, ...listFns, ] export function VariableLibrary(names) { if (names.length === 0) return [] let name = names[0] return [ ...names.map(name => () => Variable(name)), ...variableFns.map(fn => () => fn(name)), ] } export function ListLibrary(names) { if (names.length === 0) return [] let name = names[0] return [ ...names.map(name => () => List(name)), ...listFns.map(fn => () => fn(name)), ] } export function compareName(name0, name1) { if (name0.length !== name1.length) return false for (let [i, part] of name0.entries()) { let part1 = name1[i] if ((typeof part === "string") !== (typeof part1 === "string")) return false if (typeof part === "string") { if (part !== part1) return false } else { if (part.type !== part1.type) return false } } return true } let icon = `<svg viewbox="0 0 24 24" fill="#6C6" stroke="#444"><path d="M20.45,5.37C20.71,4.71,20.23,4,19.52,4H13h-1H7V3c0-0.55-0.45-1-1-1h0C5.45,2,5,2.45,5,3v1v10v8h2v-8h4h1h7.52 c0.71,0,1.19-0.71,0.93-1.37L19,9L20.45,5.37z"/></svg>` function getIcon() { let span = document.createElement("span") span.insertAdjacentHTML("beforeend", icon) let svg = span.querySelector("svg") svg.style.setProperty("height", "1.5em") svg.style.setProperty("vertical-align", "middle") return span }