Skip to content

Commit

Permalink
new strategy for duplicate on drag blocks (#10343)
Browse files Browse the repository at this point in the history
  • Loading branch information
riknoll committed Jan 21, 2025
1 parent 0fda63d commit 8e16ac3
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 8 deletions.
3 changes: 3 additions & 0 deletions pxtblocks/builtins/loops.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import * as Blockly from "blockly";
import { installBuiltinHelpInfo, setBuiltinHelpInfo, setHelpResources } from "../help";
import { setDuplicateOnDrag } from "../plugins/duplicateOnDrag";

export function initLoops() {
const msg = Blockly.Msg;
Expand Down Expand Up @@ -104,6 +105,7 @@ export function initLoops() {
}
}
};
setDuplicateOnDrag(pxtControlsForId, "VAR");

// controls_simple_for
const controlsSimpleForId = "controls_simple_for";
Expand Down Expand Up @@ -313,6 +315,7 @@ export function initLoops() {
);
}
};
setDuplicateOnDrag(pxtControlsForOfId, "VAR");

// controls_for_of
const controlsForOfId = "controls_for_of";
Expand Down
7 changes: 6 additions & 1 deletion pxtblocks/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { initOnStart } from "./builtins/misc";
import { initContextMenu } from "./contextMenu";
import { renderCodeCard } from "./codecardRenderer";
import { FieldDropdown } from "./fields/field_dropdown";
import { setDraggableShadowBlocks, setDuplicateOnDragStrategy } from "./plugins/duplicateOnDrag";
import { setDraggableShadowBlocks, setDuplicateOnDrag, setDuplicateOnDragStrategy } from "./plugins/duplicateOnDrag";
import { applyPolyfills } from "./polyfills";


Expand Down Expand Up @@ -259,6 +259,11 @@ function initBlock(block: Blockly.Block, info: pxtc.BlocksInfo, fn: pxtc.SymbolI
} else {
i.setCheck("Variable");
}

});

comp.handlerArgs.forEach(arg => {
setDuplicateOnDrag(block.type, "HANDLER_DRAG_PARAM_" + arg.name);
});
}
else {
Expand Down
4 changes: 2 additions & 2 deletions pxtblocks/plugins/duplicateOnDrag/connectionChecker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as Blockly from "blockly";
import { isDuplicateOnDragBlock } from "./duplicateOnDrag";
import { shouldDuplicateOnDrag } from "./duplicateOnDrag";


const OPPOSITE_TYPE: number[] = [];
Expand All @@ -16,7 +16,7 @@ export class DuplicateOnDragConnectionChecker extends Blockly.ConnectionChecker

const replacedBlock = b.targetBlock();

if (replacedBlock && isDuplicateOnDragBlock(replacedBlock)) return false;
if (replacedBlock && shouldDuplicateOnDrag(replacedBlock)) return false;

return true;
}
Expand Down
4 changes: 2 additions & 2 deletions pxtblocks/plugins/duplicateOnDrag/dragStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as Blockly from "blockly";

import { DUPLICATE_ON_DRAG_MUTATION_KEY, isAllowlistedShadow } from "./duplicateOnDrag";
import { DUPLICATE_ON_DRAG_MUTATION_KEY, isAllowlistedShadow, shouldDuplicateOnDrag } from "./duplicateOnDrag";
import eventUtils = Blockly.Events;
import Coordinate = Blockly.utils.Coordinate;
import dom = Blockly.utils.dom;
Expand Down Expand Up @@ -160,7 +160,7 @@ export class DuplicateOnDragStrategy implements Blockly.IDragStrategy {

const mutation = this.block.mutationToDom?.();

if (mutation?.getAttribute(DUPLICATE_ON_DRAG_MUTATION_KEY)?.toLowerCase() === "true" || (isAllowlistedShadow(this.block) && isShadow)) {
if (shouldDuplicateOnDrag(this.block)) {
const output = this.block.outputConnection;

if (!output?.targetConnection) return;
Expand Down
70 changes: 68 additions & 2 deletions pxtblocks/plugins/duplicateOnDrag/duplicateOnDrag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,87 @@ import * as Blockly from "blockly";
export const DUPLICATE_ON_DRAG_MUTATION_KEY = "duplicateondrag";

let draggableShadowAllowlist: string[];
let duplicateRefs: DuplicateOnDragRef[];

export function isDuplicateOnDragBlock(block: Blockly.Block) {
return block.mutationToDom?.()?.getAttribute(DUPLICATE_ON_DRAG_MUTATION_KEY)?.toLowerCase() === "true";
interface DuplicateOnDragRef {
parentBlockType: string;
inputName?: string;
childBlockType?: string;
}

export function setDraggableShadowBlocks(ids: string[]) {
draggableShadowAllowlist = ids;
}

/**
* Configures duplicate on drag for a block's child inputs
*
* @param parentBlockType The type of the parent block
* @param inputName The value input to duplicate blocks on when dragged. If not
* specified, all child value inputs will be duplicated
* @param childBlockType The type of the child block to be duplicated. If not specified,
* any block attached to the input will be duplicated on drag
* regardless of type
*/
export function setDuplicateOnDrag(parentBlockType: string, inputName?: string, childBlockType?: string) {
if (!duplicateRefs) {
duplicateRefs = [];
}

const existing = duplicateRefs.some(ref => ref.parentBlockType === parentBlockType && ref.inputName === inputName && ref.childBlockType === childBlockType);
if (existing) {
return;
}

duplicateRefs.push({
parentBlockType,
inputName,
childBlockType
});
}

export function isAllowlistedShadow(block: Blockly.Block) {
if (draggableShadowAllowlist) {
if (draggableShadowAllowlist.indexOf(block.type) !== -1) {
return true;
}
}
return false;
}

export function shouldDuplicateOnDrag(block: Blockly.Block) {
if (block.isShadow() && isAllowlistedShadow(block)) {
return true;
}

if (duplicateRefs) {
const parent = block.outputConnection?.targetBlock();

if (parent) {
const refs = duplicateRefs.filter(r => r.parentBlockType === parent.type);

for (const ref of refs) {
if (ref && (!ref.childBlockType || ref.childBlockType === block.type)) {
if (ref.inputName) {
const targetConnection = block.outputConnection.targetConnection;
if (targetConnection.getParentInput().name === ref.inputName) {
return true;
}
}
else {
return true;
}
}
}
}
}

if (block.mutationToDom) {
const mutation = block.mutationToDom();
if (mutation?.getAttribute(DUPLICATE_ON_DRAG_MUTATION_KEY)?.toLowerCase() === "true") {
return true;
}
}

return false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { MsgKey } from "../msg";
import { FunctionManager } from "../functionManager";
import { COLLAPSE_IMAGE_DATAURI } from "../svgs";
import { ArgumentReporterBlock } from "./argumentReporterBlocks";
import { DUPLICATE_ON_DRAG_MUTATION_KEY } from "../../duplicateOnDrag";
import { DUPLICATE_ON_DRAG_MUTATION_KEY, setDuplicateOnDrag } from "../../duplicateOnDrag";

interface FunctionDefinitionMixin extends CommonFunctionMixin {
createArgumentReporter_(arg: FunctionArgument): ArgumentReporterBlock;
Expand Down Expand Up @@ -205,6 +205,8 @@ Blockly.Blocks[FUNCTION_DEFINITION_BLOCK_TYPE] = {
},
};

setDuplicateOnDrag(FUNCTION_DEFINITION_BLOCK_TYPE);


function editFunctionCallback(block: CommonFunctionBlock) {
// Edit can come from either the function definition or a function call.
Expand Down

0 comments on commit 8e16ac3

Please sign in to comment.