scratch-blocks 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../../../../src/blocks/procedures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH;;GAEG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAIvC;;GAEG;AACH,KAAK,aAAa,GAAG,MAAM,CACzB,MAAM,EACN;IACE,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAA;CACxB,GAAG,IAAI,CACT,CAAA;AAED;;GAEG;AACH,aAAK,YAAY;IACf,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,OAAO,MAAM;CACd;
|
|
1
|
+
{"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../../../../src/blocks/procedures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH;;GAEG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAIvC;;GAEG;AACH,KAAK,aAAa,GAAG,MAAM,CACzB,MAAM,EACN;IACE,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAA;CACxB,GAAG,IAAI,CACT,CAAA;AAED;;GAEG;AACH,aAAK,YAAY;IACf,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,OAAO,MAAM;CACd;AAgoCD,UAAU,cAAe,SAAQ,OAAO,CAAC,QAAQ;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,MAAM,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,oBAAoB,EAAE,MAAM,aAAa,CAAA;IACzC,sBAAsB,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAA;IAC9D,gBAAgB,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAA;IACxD,cAAc,EAAE,MAAM,IAAI,CAAA;IAC1B,iBAAiB,EAAE,CACjB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,aAAa,EAC5B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,KAAK,KACjB,IAAI,CAAA;IACT,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3C;AAED,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAC/D,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,mBAAmB,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,IAAI,CAAA;IACnD,qBAAqB,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAA;IAC5F,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,OAAO,EAAE,MAAM,OAAO,CAAA;IACtB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,uBAAuB,EAAE,MAAM,IAAI,CAAA;IACnC,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB"}
|
package/package.json
CHANGED
package/src/blocks/procedures.ts
CHANGED
|
@@ -79,13 +79,20 @@ class DelegateToParentDraggable implements Blockly.IDraggable {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Class representing a draggable block that copies itself on drag
|
|
82
|
+
* Class representing a draggable block that copies itself on drag, but only
|
|
83
|
+
* when the block is directly connected to a procedures_prototype block.
|
|
84
|
+
* When dragged from any other position, it behaves like a normal block.
|
|
83
85
|
*/
|
|
84
86
|
class DuplicateOnDragDraggable implements Blockly.IDraggable {
|
|
85
87
|
/**
|
|
86
|
-
* The newly-created duplicate
|
|
88
|
+
* The block being dragged: a newly-created duplicate when dragging from a
|
|
89
|
+
* prototype, or the original block when dragging from elsewhere.
|
|
87
90
|
*/
|
|
88
91
|
private copy?: Blockly.BlockSvg
|
|
92
|
+
/**
|
|
93
|
+
* Whether this drag is duplicating the block (true) or moving it (false).
|
|
94
|
+
*/
|
|
95
|
+
private isDuplicating_ = false
|
|
89
96
|
constructor(private block: Blockly.BlockSvg) {}
|
|
90
97
|
|
|
91
98
|
/**
|
|
@@ -97,23 +104,41 @@ class DuplicateOnDragDraggable implements Blockly.IDraggable {
|
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
/**
|
|
100
|
-
* Handles the start of a drag.
|
|
107
|
+
* Handles the start of a drag. If the block is directly connected to a
|
|
108
|
+
* procedures_prototype, creates a duplicate and drags that. Otherwise,
|
|
109
|
+
* switches to a normal drag strategy and drags the original block.
|
|
101
110
|
* @param e The event that triggered the drag.
|
|
102
111
|
*/
|
|
103
112
|
startDrag(e: PointerEvent) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
const parent = this.block.getParent()
|
|
114
|
+
this.isDuplicating_ = parent?.type === 'procedures_prototype'
|
|
115
|
+
|
|
116
|
+
if (this.isDuplicating_) {
|
|
117
|
+
const data = this.block.toCopyData()
|
|
118
|
+
if (!data) {
|
|
119
|
+
console.warn(
|
|
120
|
+
'DuplicateOnDragDraggable.startDrag: failed to serialize block for copy',
|
|
121
|
+
this.block.type,
|
|
122
|
+
this.block.id,
|
|
123
|
+
)
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
this.copy = Blockly.clipboard.paste(data, this.block.workspace) as Blockly.BlockSvg
|
|
127
|
+
this.copy.setDeletable(true)
|
|
128
|
+
this.copy.setDragStrategy(new Blockly.dragging.BlockDragStrategy(this.copy))
|
|
129
|
+
this.copy.startDrag(e)
|
|
130
|
+
} else {
|
|
131
|
+
// Not in a prototype: drag the original block normally and replace this
|
|
132
|
+
// drag strategy so future drags also behave normally.
|
|
133
|
+
// Also ensure the block is deletable — reporters created by createArgumentReporter_
|
|
134
|
+
// are non-deletable by default, but one that has escaped a prototype should be
|
|
135
|
+
// cleanable by the user.
|
|
136
|
+
this.block.setDeletable(true)
|
|
137
|
+
const normalStrategy = new Blockly.dragging.BlockDragStrategy(this.block)
|
|
138
|
+
this.block.setDragStrategy(normalStrategy)
|
|
139
|
+
this.copy = this.block
|
|
140
|
+
normalStrategy.startDrag(e)
|
|
112
141
|
}
|
|
113
|
-
this.copy = Blockly.clipboard.paste(data, this.block.workspace) as Blockly.BlockSvg
|
|
114
|
-
this.copy.setDeletable(true)
|
|
115
|
-
this.copy.setDragStrategy(new Blockly.dragging.BlockDragStrategy(this.copy))
|
|
116
|
-
this.copy.startDrag(e)
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
drag(newLoc: Blockly.utils.Coordinate, e?: PointerEvent) {
|
|
@@ -135,7 +160,11 @@ class DuplicateOnDragDraggable implements Blockly.IDraggable {
|
|
|
135
160
|
}
|
|
136
161
|
|
|
137
162
|
revertDrag() {
|
|
138
|
-
this.
|
|
163
|
+
if (this.isDuplicating_) {
|
|
164
|
+
this.copy?.dispose()
|
|
165
|
+
} else {
|
|
166
|
+
this.copy?.revertDrag()
|
|
167
|
+
}
|
|
139
168
|
}
|
|
140
169
|
|
|
141
170
|
getRelativeToSurfaceXY() {
|
|
@@ -210,7 +239,34 @@ function definitionDomToMutation(this: ProcedurePrototypeBlock | ProcedureDeclar
|
|
|
210
239
|
this.argumentIds_ = JSON.parse(xmlElement.getAttribute('argumentids')!)
|
|
211
240
|
this.displayNames_ = JSON.parse(xmlElement.getAttribute('argumentnames')!)
|
|
212
241
|
this.argumentDefaults_ = JSON.parse(xmlElement.getAttribute('argumentdefaults')!)
|
|
213
|
-
|
|
242
|
+
|
|
243
|
+
// During full XML deserialization (Blockly.Xml.domToWorkspace), the mutation element
|
|
244
|
+
// is part of the parsed XML tree and its parent element also contains <value> children
|
|
245
|
+
// for the argument reporters. Blockly will connect those child blocks AFTER the
|
|
246
|
+
// mutation runs. To avoid creating duplicate reporters here that would immediately
|
|
247
|
+
// be orphaned when the XML children connect, skip reporter creation and let the
|
|
248
|
+
// XML children provide them.
|
|
249
|
+
// We detect this case by checking that the parent element has <value> children.
|
|
250
|
+
// This distinguishes full deserialization from:
|
|
251
|
+
// - Programmatic mutation (xmlElement.parentElement is null — freshly created element)
|
|
252
|
+
// - Block creation from partial XML with no <value> children (e.g. createProcedureCallbackFactory)
|
|
253
|
+
// - JSON serialization / undo-redo (xmlElement.parentElement is null — textToDom result)
|
|
254
|
+
const xmlParent = xmlElement.parentElement
|
|
255
|
+
const hasXmlArgReporters =
|
|
256
|
+
this.type === 'procedures_prototype' &&
|
|
257
|
+
xmlParent !== null &&
|
|
258
|
+
Array.from(xmlParent.children).some((el) => el.tagName.toLowerCase() === 'value')
|
|
259
|
+
if (hasXmlArgReporters) {
|
|
260
|
+
;(this as ProcedurePrototypeBlock).skipArgumentReporters_ = true
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
this.updateDisplay_()
|
|
264
|
+
} finally {
|
|
265
|
+
if (hasXmlArgReporters) {
|
|
266
|
+
;(this as ProcedurePrototypeBlock).skipArgumentReporters_ = false
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
214
270
|
if ('updateArgumentReporterNames_' in this) {
|
|
215
271
|
this.updateArgumentReporterNames_(prevArgIds, prevDisplayNames)
|
|
216
272
|
}
|
|
@@ -521,6 +577,12 @@ function populateArgumentOnPrototype_(
|
|
|
521
577
|
id: string,
|
|
522
578
|
input: Blockly.Input,
|
|
523
579
|
) {
|
|
580
|
+
// During XML deserialization, skip connecting argument reporters here.
|
|
581
|
+
// The block's <value> XML children will connect the reporters after the mutation runs.
|
|
582
|
+
if (this.skipArgumentReporters_) {
|
|
583
|
+
return
|
|
584
|
+
}
|
|
585
|
+
|
|
524
586
|
let oldBlock: Blockly.BlockSvg | null = null
|
|
525
587
|
if (connectionMap && id in connectionMap) {
|
|
526
588
|
const saveInfo = connectionMap[id]
|
|
@@ -981,6 +1043,7 @@ Blockly.Blocks.procedures_prototype = {
|
|
|
981
1043
|
this.argumentIds_ = []
|
|
982
1044
|
this.argumentDefaults_ = []
|
|
983
1045
|
this.warp_ = false
|
|
1046
|
+
this.skipArgumentReporters_ = false
|
|
984
1047
|
|
|
985
1048
|
// Shared.
|
|
986
1049
|
this.getProcCode = getProcCode.bind(this)
|
|
@@ -1173,6 +1236,7 @@ interface ProcedureCallBlock extends ProcedureBlock {
|
|
|
1173
1236
|
interface ProcedurePrototypeBlock extends ProcedureBlock {
|
|
1174
1237
|
displayNames_: string[]
|
|
1175
1238
|
argumentDefaults_: string[]
|
|
1239
|
+
skipArgumentReporters_: boolean
|
|
1176
1240
|
createArgumentReporter_: (argumentType: ArgumentType, displayName: string) => Blockly.BlockSvg
|
|
1177
1241
|
updateArgumentReporterNames_: (prevArgIds: string[], prevDisplayNames: string[]) => void
|
|
1178
1242
|
}
|
package/src/index.ts
CHANGED
|
@@ -165,6 +165,16 @@ Blockly.FlyoutButton.TEXT_MARGIN_Y = 10
|
|
|
165
165
|
Blockly.ContextMenuRegistry.registry.unregister('blockDisable')
|
|
166
166
|
Blockly.ContextMenuRegistry.registry.unregister('blockInline')
|
|
167
167
|
Blockly.ContextMenuItems.registerCommentOptions()
|
|
168
|
+
// Blockly hides "Add Comment" for simple reporters because comments can't be
|
|
169
|
+
// read in the default renderer. In Scratch they're shown differently, so
|
|
170
|
+
// remove that restriction by dropping the isFullBlockField check.
|
|
171
|
+
Blockly.ContextMenuRegistry.registry.getItem('blockComment')!.preconditionFn = (scope) => {
|
|
172
|
+
const block = scope.block
|
|
173
|
+
if (block && !block.isInFlyout && block.workspace.options.comments && !block.isCollapsed() && block.isEditable()) {
|
|
174
|
+
return 'enabled'
|
|
175
|
+
}
|
|
176
|
+
return 'hidden'
|
|
177
|
+
}
|
|
168
178
|
Blockly.ContextMenuRegistry.registry.unregister('blockDelete')
|
|
169
179
|
contextMenuItems.registerDeleteBlock()
|
|
170
180
|
contextMenuItems.registerDuplicateBlock()
|
|
@@ -38,6 +38,13 @@ class ScratchConnectionChecker extends Blockly.ConnectionChecker {
|
|
|
38
38
|
return false
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Prevent dragging any block into a procedures_prototype input. Argument
|
|
42
|
+
// reporters inside the prototype are managed programmatically and should
|
|
43
|
+
// not be displaceable by user drag-and-drop.
|
|
44
|
+
if (b.getSourceBlock().type === 'procedures_prototype') {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
return super.doDragChecks(a, b, distance)
|
|
42
49
|
}
|
|
43
50
|
}
|