@@ -3,21 +3,87 @@ import * as Blockly from "blockly";
33export const DUPLICATE_ON_DRAG_MUTATION_KEY = "duplicateondrag" ;
44
55let draggableShadowAllowlist : string [ ] ;
6+ let duplicateRefs : DuplicateOnDragRef [ ] ;
67
7- export function isDuplicateOnDragBlock ( block : Blockly . Block ) {
8- return block . mutationToDom ?.( ) ?. getAttribute ( DUPLICATE_ON_DRAG_MUTATION_KEY ) ?. toLowerCase ( ) === "true" ;
8+ interface DuplicateOnDragRef {
9+ parentBlockType : string ;
10+ inputName ?: string ;
11+ childBlockType ?: string ;
912}
1013
1114export function setDraggableShadowBlocks ( ids : string [ ] ) {
1215 draggableShadowAllowlist = ids ;
1316}
1417
18+ /**
19+ * Configures duplicate on drag for a block's child inputs
20+ *
21+ * @param parentBlockType The type of the parent block
22+ * @param inputName The value input to duplicate blocks on when dragged. If not
23+ * specified, all child value inputs will be duplicated
24+ * @param childBlockType The type of the child block to be duplicated. If not specified,
25+ * any block attached to the input will be duplicated on drag
26+ * regardless of type
27+ */
28+ export function setDuplicateOnDrag ( parentBlockType : string , inputName ?: string , childBlockType ?: string ) {
29+ if ( ! duplicateRefs ) {
30+ duplicateRefs = [ ] ;
31+ }
32+
33+ const existing = duplicateRefs . some ( ref => ref . parentBlockType === parentBlockType && ref . inputName === inputName && ref . childBlockType === childBlockType ) ;
34+ if ( existing ) {
35+ return ;
36+ }
37+
38+ duplicateRefs . push ( {
39+ parentBlockType,
40+ inputName,
41+ childBlockType
42+ } ) ;
43+ }
44+
1545export function isAllowlistedShadow ( block : Blockly . Block ) {
1646 if ( draggableShadowAllowlist ) {
1747 if ( draggableShadowAllowlist . indexOf ( block . type ) !== - 1 ) {
1848 return true ;
1949 }
2050 }
51+ return false ;
52+ }
53+
54+ export function shouldDuplicateOnDrag ( block : Blockly . Block ) {
55+ if ( block . isShadow ( ) && isAllowlistedShadow ( block ) ) {
56+ return true ;
57+ }
58+
59+ if ( duplicateRefs ) {
60+ const parent = block . outputConnection ?. targetBlock ( ) ;
61+
62+ if ( parent ) {
63+ const refs = duplicateRefs . filter ( r => r . parentBlockType === parent . type ) ;
64+
65+ for ( const ref of refs ) {
66+ if ( ref && ( ! ref . childBlockType || ref . childBlockType === block . type ) ) {
67+ if ( ref . inputName ) {
68+ const targetConnection = block . outputConnection . targetConnection ;
69+ if ( targetConnection . getParentInput ( ) . name === ref . inputName ) {
70+ return true ;
71+ }
72+ }
73+ else {
74+ return true ;
75+ }
76+ }
77+ }
78+ }
79+ }
80+
81+ if ( block . mutationToDom ) {
82+ const mutation = block . mutationToDom ( ) ;
83+ if ( mutation ?. getAttribute ( DUPLICATE_ON_DRAG_MUTATION_KEY ) ?. toLowerCase ( ) === "true" ) {
84+ return true ;
85+ }
86+ }
2187
2288 return false ;
2389}
0 commit comments