Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic category, Variable support, buttons update #27

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/lib/blocks/Javascript/Loops.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BlockShape, BlockType, DropdownType } from "$lib/enums/BlockTypes";
import type { BlockDefinition } from "$lib/types/BlockDefinition";
import type { CategoryDefinition } from "$lib/types/CategoryDefinition";
import Dropdown from "$lib/utils/BlockGen/Inputs/Dropdown";
import DropdownInput from "$lib/utils/BlockGen/Inputs/Dropdown";
import StatementInput from "$lib/utils/BlockGen/Inputs/StatementInput";
import ValueInput from "$lib/utils/BlockGen/Inputs/ValueInput";
import rgbToHex from "$lib/utils/helpers/rgbToHex";
Expand All @@ -25,7 +25,7 @@ const blocks: BlockDefinition[] = [
id: "repeat_while",
text: "Repeat {WHILE} {CONDITION}\n {INPUT}",
args: [
new Dropdown("WHILE", DropdownType.Auto, {
new DropdownInput("WHILE", DropdownType.Auto, {
while: "while",
until: "until"
}),
Expand Down Expand Up @@ -92,7 +92,7 @@ const blocks: BlockDefinition[] = [
id: "break",
text: "{ACTION} of loop",
args: [
new Dropdown("ACTION", DropdownType.Auto, {
new DropdownInput("ACTION", DropdownType.Auto, {
break: "break",
continue: "continue"
})
Expand Down
10 changes: 5 additions & 5 deletions src/lib/blocks/Javascript/logic.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BlockShape, BlockType, DropdownType, WarningType } from "$lib/enums/BlockTypes";
import type { BlockDefinition } from "$lib/types/BlockDefinition";
import type { CategoryDefinition } from "$lib/types/CategoryDefinition";
import Dropdown from "$lib/utils/BlockGen/Inputs/Dropdown";
import DropdownInput from "$lib/utils/BlockGen/Inputs/Dropdown";
import ValueInput from "$lib/utils/BlockGen/Inputs/ValueInput";
import Warning from "$lib/utils/BlockGen/Warnings/Warning";
import rgbToHex from "$lib/utils/helpers/rgbToHex";
Expand Down Expand Up @@ -60,7 +60,7 @@ const blocks: BlockDefinition[] = [
text: "{A} {CONDITION} {B}",
args: [
new ValueInput("A", BlockType.Any),
new Dropdown("CONDITION", DropdownType.Auto, {
new DropdownInput("CONDITION", DropdownType.Auto, {
"=": "===",
"≠": "!=",
"<": "<",
Expand Down Expand Up @@ -93,7 +93,7 @@ const blocks: BlockDefinition[] = [
text: "{A} {CONDITION} {B}",
args: [
new ValueInput("A", BlockType.Boolean),
new Dropdown("CONDITION", DropdownType.Auto, { and: "&&", or: "||" }),
new DropdownInput("CONDITION", DropdownType.Auto, { and: "&&", or: "||" }),
new ValueInput("B", BlockType.Boolean)
],
warnings: [
Expand Down Expand Up @@ -134,7 +134,7 @@ const blocks: BlockDefinition[] = [
id: "values",
text: "{INPUT}",
args: [
new Dropdown("INPUT", DropdownType.Auto, {
new DropdownInput("INPUT", DropdownType.Auto, {
true: "true",
false: "false",
null: "null",
Expand Down Expand Up @@ -195,7 +195,7 @@ const blocks: BlockDefinition[] = [
text: "typeof types {TYPE}",
args: [
// new ValueInput("OPERAND", BlockType.Any),
new Dropdown("TYPE", DropdownType.Auto, {
new DropdownInput("TYPE", DropdownType.Auto, {
string: "string",
number: "number",
boolean: "boolean",
Expand Down
151 changes: 151 additions & 0 deletions src/lib/blocks/Test Blocks/variables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@

import type { BlockDefinition } from "$lib/types/BlockDefinition";
import type { CategoryDefinition } from "$lib/types/CategoryDefinition";
import Blockly from "blockly"
import { BlockShape, BlockType, DropdownType } from "$lib/enums/BlockTypes";
import DropdownInput from "$lib/utils/BlockGen/Inputs/Dropdown";
import ValueInput from "$lib/utils/BlockGen/Inputs/ValueInput";
import VariableInput from "$lib/utils/BlockGen/Inputs/VariableInput";

function fixVariableName(variable: string): string {
// Remove non-alphabetic characters from the start and end
let fixedVariable = variable.replace(/^[^a-zA-Z]+|[^a-zA-Z0-9]+$/g, '');

// Replace non-alphabetic characters in the middle with underscores
fixedVariable = fixedVariable.replace(/[^a-zA-Z0-9]+/g, '_');

return fixedVariable;
}
const blocks: BlockDefinition[] = [
{
kind: "button",
text: "Create a variable...",
callbackKey: "CREATE_VARIABLE_OUR",
callback(p1) {
Blockly.Variables.createVariableButtonHandler(p1.getTargetWorkspace(), undefined, '');
// let pro = prompt("New variable:")
// p1.getTargetWorkspace().createVariable(pro as string, "any", pro)
},
},
{
id: "variable_get_discodes",
text: "{VAR}",
args: [
new VariableInput("VAR", "")
],
code(args) {

const varName = fixVariableName(args.VAR as string)
console.log(varName, args.VAR)
return varName

},
output: BlockType.Any,
shape: BlockShape.Value,
inline: false, // This is "inputsInline"
colour: "#A55B99",
tooltip: "variable block",
helpUrl: ""
},
{
id: "variable_set_discodes",
text: "set {VAR} to {INPUT}",
args: [
new VariableInput("VAR", ""),
new ValueInput("INPUT", BlockType.Any)
],
code(args) {
const varName = fixVariableName(args.VAR as string)

return `${varName}${args.INPUT !== ""? " =" : ";"} ${args.INPUT !== ""? args.INPUT+";": ""}\n`
},
shape: BlockShape.Action,
inline: true, // This is "inputsInline"
colour: "#A55B99",
tooltip: "variable block",
helpUrl: ""
},
{
id: "variable_change_discodes",
text: "change {VAR} by {DROPDOWN} {INPUT}",
args: [
new VariableInput("VAR", ""),
new DropdownInput("DROPDOWN", DropdownType.Auto,
{
"adding": "+",
"subtracting": "-",
"multiplying": "*",
"dividing": "/",
}
),
new ValueInput("INPUT", BlockType.Any)

],
code(args) {
const varName = fixVariableName(args.VAR as string)
console.log(varName)
return `${varName}${args.INPUT !== ""? " "+ args.DROPDOWN + "=" : ";"} ${args.INPUT !== ""? args.INPUT+";": ""}\n`

},
shape: BlockShape.Action,
inline: true, // This is "inputsInline"
colour: "#A55B99",
tooltip: "variable block",
helpUrl: ""
}
];

const category: CategoryDefinition = {
name: "Variables",
colour: "#db5c53",
custom: "VARIABLE_DYNAMIC_OUR",
customFunction(workspace) {
let variableModelList = workspace.getAllVariables()
let blocklist = [];
blocklist.push({
"kind": "button",
"text": "Create a variable...",
"callbackKey": "CREATE_VARIABLE_OUR"
})
if(variableModelList.length !== 0) {
const lastVariable = variableModelList[variableModelList.length-1]
blocklist.push({
"kind": "block",
"type": "variable_set_discodes",
"fields": {
"VAR": {
"name": lastVariable.name,
"type": lastVariable.type,
}
},
})
blocklist.push({
"kind": "block",
"type": "variable_change_discodes",
"fields": {
"VAR": {
"name": lastVariable.name,
"type": lastVariable.type,
}
},
})
}
variableModelList.sort(Blockly.VariableModel.compareByName);

for(const value of variableModelList) {
blocklist.push( {
"kind": "block",
"fields": {
"VAR": {
"name": value.name,
"type": value.type,
}
},
"type": "variable_get_discodes",
})
}
return blocklist;
},
};

export default { blocks, category };
12 changes: 8 additions & 4 deletions src/lib/components/Workspace.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@
import loadBlocks from "$lib/utils/helpers/loadBlocks";
import { warnings } from "$lib/utils/BlockGen/Warnings/WarningsList";
import { imports, wipeImports } from "$lib/utils/BlockGen/Blocks/importsList";
import type Toolbox from "$lib/utils/ToolboxGen/Toolbox";

export let workspace: Blockly.WorkspaceSvg;
export let options: typeof OPTIONS;
export let toolbox: Blockly.utils.toolbox.ToolboxDefinition;
export let toolboxJson: Blockly.utils.toolbox.ToolboxDefinition;
export let toolbox: Toolbox;

Blockly.setLocale({
...En
});

onMount(async() => {
await loadBlocks();
workspace = Blockly.inject("blocklyDiv", { ...options, toolbox: toolbox });

await loadBlocks();
workspace = Blockly.inject("blocklyDiv", { ...options, toolbox: toolboxJson });
toolbox.registerCallbacks(workspace)
// workspace.refreshToolboxSelection();
// Only console log the code and warnings when debug mode is enabled.
const supportedEvents = new Set([
Blockly.Events.BLOCK_CHANGE,
Expand All @@ -48,6 +51,7 @@
}
}
workspace.addChangeListener(updateCode);

});
</script>

Expand Down
3 changes: 2 additions & 1 deletion src/lib/enums/BlockTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export enum BlockShape {
Event, //Block shape for a floating block with an input inside. Can be replaced with FLOATING, but keeps code consistent.
Floating, //Block shape for a block that cannot have any parent blocks.
Bottom, //Block shape for a block with no blocks allowed to attach after.
Top //Block shape for a block that cannot have any blocks attached before it.
Top, //Block shape for a block that cannot have any blocks attached before it.
Value // Block shape for a block that is a value and is placed inside inputs
}

// This is used for the toolbox generation, it translates to kind:"block" in the blockly shadows.
Expand Down
9 changes: 8 additions & 1 deletion src/lib/types/BlockDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type BaseInput from "$lib/utils/BlockGen/Inputs/BaseInput";
import type {Mutator} from "$lib/utils/BlockGen/Mutators/Mutator";
import type Warning from "$lib/utils/BlockGen/Warnings/Warning";
import type Placeholder from "$lib/utils/ToolboxGen/Placeholder";
import {FlyoutButton} from "blockly";

export type Argument = BaseInput;

Expand All @@ -30,7 +31,13 @@ export type BlockDefinition =
| {
label: true;
text: string;
};
} |
{
kind: "button";
text: string;
callbackKey: string;
callback: (p1: FlyoutButton) => void;
};

export interface MutatorBlock {
// What inputs it adds to the block
Expand Down
4 changes: 4 additions & 0 deletions src/lib/types/CategoryDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import Blockly from "blockly"
export type CategoryDefinition = {
name: string;
colour: string;
hidden?: boolean;
weight?: number;
custom?: string; // add if you want to make dynamic categories
// eslint-disable-next-line no-use-before-define
customFunction?: (workspace: Blockly.WorkspaceSvg) => any[]; // used in pair with custom

Check failure on line 9 in src/lib/types/CategoryDefinition.ts

View workflow job for this annotation

GitHub Actions / Run eslint

Unexpected any. Specify a different type

Check failure on line 9 in src/lib/types/CategoryDefinition.ts

View workflow job for this annotation

GitHub Actions / Run eslint

Unexpected any. Specify a different type
};
15 changes: 11 additions & 4 deletions src/lib/utils/BlockGen/Blocks/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,28 @@ export default class Block {
}

addWarning(warning: Warning): void {
if (this._blockDefinition.kind) throw new Error("Cannot add a warning to a input/button");

if (this._blockDefinition.label) throw new Error("Cannot add a warning to a label");
if (warningsObj[this._block.id] && warningsObj[this._block.id][warning.data.fieldName]) return;
this._blockDefinition.warnings = this._blockDefinition.warnings ? [...this._blockDefinition.warnings, warning] : [warning];
}

removeWarning(fieldName: string): void {
if (this._blockDefinition.label) throw new Error("Cannot remove a warning form a label");
if (this._blockDefinition.kind) throw new Error("Cannot remove a warning from a input/button");

if (this._blockDefinition.label) throw new Error("Cannot remove a warning from a label");
if ((!warningsObj[this._block.id] || !warningsObj[this._block.id][fieldName]) && this._blockDefinition.warnings !== undefined) return;
this._blockDefinition.warnings = this._blockDefinition.warnings?.filter(warning => warning.data.fieldName !== fieldName);
}

generate(): void {
if (this._blockDefinition.label) return;
if (this._blockDefinition.label || this._blockDefinition.kind) return;

// eslint-disable-next-line @typescript-eslint/no-this-alias
const blockClass = this; // Used because `this` is overwritten in the blockly functions.


const code = this._blockDefinition.code;
const shape = this._blockDefinition.shape;
const output = this._blockDefinition.output;
Expand Down Expand Up @@ -121,6 +126,10 @@ export default class Block {
// opposite of terminal
this.setNextStatement(true);
break;
case BlockShape.Value:
this.setPreviousStatement(false);
this.setNextStatement(false);
break;
}

// Here we add an output if needed
Expand Down Expand Up @@ -220,11 +229,9 @@ export default class Block {
const argName: string = blockDef.args0[arg].name as string;
args[argName] = getInputValue(block, argName, argValue.type);
}

//parse mutator values
for(const propertyKey of Object.keys(propertyMap)) {
const property = propertyMap[propertyKey];
console.log(propertyMap)
for (const add of property.adds) {
const valueList: string[] = [];
let i = 1;
Expand Down
3 changes: 1 addition & 2 deletions src/lib/utils/BlockGen/Inputs/Dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface DropdownJSON {
* @class Dropdown
* @extends {BaseInput}
*/
export default class Dropdown extends BaseInput {
export default class DropdownInput extends BaseInput {

private readonly _options: Array<Array<string>>;
private _dropdownType: DropdownType;
Expand Down Expand Up @@ -52,7 +52,6 @@ export default class Dropdown extends BaseInput {
// Automatically swaps between grid and list type depending on the length of the arguments.
this._dropdownType = this._options.length > 10 ? DropdownType.Grid : DropdownType.List;
}
console.log(this._options)
return {
type: this._dropdownType,
name: super.name,
Expand Down
Loading
Loading