scratch-blocks 2.1.2 → 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.
- package/dist/main.mjs +1 -1
- package/dist/types/src/blocks/procedures.d.ts.map +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/package.json +6 -5
- package/src/blocks/procedures.ts +115 -17
- package/src/blocks/vertical_extensions.ts +1 -1
- package/src/css.ts +15 -2
- package/src/index.ts +10 -2
- package/src/scratch_connection_checker.ts +7 -0
- package/dist/types/src/shadows.d.ts +0 -12
- package/dist/types/src/shadows.d.ts.map +0 -1
- package/src/shadows.ts +0 -60
|
@@ -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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,iBAAiB,CAAA;AACxB,OAAO,kBAAkB,CAAA;AACzB,OAAO,eAAe,CAAA;AACtB,OAAO,gBAAgB,CAAA;AACvB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,iBAAiB,CAAA;AACxB,OAAO,iBAAiB,CAAA;AACxB,OAAO,eAAe,CAAA;AACtB,OAAO,oBAAoB,CAAA;AAC3B,OAAO,qBAAqB,CAAA;AAC5B,OAAO,kBAAkB,CAAA;AACzB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,gBAAgB,MAAM,sBAAsB,CAAA;AACxD,OAAO,OAAO,CAAA;AACd,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wCAAwC,CAAA;AAC/C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,oCAAoC,CAAA;AAC3C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,yCAAyC,CAAA;AAChD,OAAO,EAA6B,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAE3F,OAAO,EAAqB,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQlE,OAAO,wBAAwB,CAAA;AAC/B,OAAO,EAAmB,SAAS,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,yBAAyB,CAAA;AAChC,OAAO,qBAAqB,CAAA;AAE5B,OAAO,KAAK,kBAAkB,MAAM,wBAAwB,CAAA;AAC5D,OAAO,wBAAwB,CAAA;AAC/B,OAAO,8BAA8B,CAAA;AAGrC,OAAO,mBAAmB,CAAA;AAC1B,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wBAAwB,CAAA;AAC/B,OAAO,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC,OAAO,iBAAiB,CAAA;AACxB,OAAO,kBAAkB,CAAA;AACzB,OAAO,eAAe,CAAA;AACtB,OAAO,gBAAgB,CAAA;AACvB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,iBAAiB,CAAA;AACxB,OAAO,iBAAiB,CAAA;AACxB,OAAO,eAAe,CAAA;AACtB,OAAO,oBAAoB,CAAA;AAC3B,OAAO,qBAAqB,CAAA;AAC5B,OAAO,kBAAkB,CAAA;AACzB,OAAO,gBAAgB,CAAA;AACvB,OAAO,eAAe,CAAA;AACtB,OAAO,8BAA8B,CAAA;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,KAAK,gBAAgB,MAAM,sBAAsB,CAAA;AACxD,OAAO,OAAO,CAAA;AACd,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wCAAwC,CAAA;AAC/C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,oCAAoC,CAAA;AAC3C,OAAO,sCAAsC,CAAA;AAC7C,OAAO,yCAAyC,CAAA;AAChD,OAAO,EAA6B,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAE3F,OAAO,EAAqB,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQlE,OAAO,wBAAwB,CAAA;AAC/B,OAAO,EAAmB,SAAS,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,yBAAyB,CAAA;AAChC,OAAO,qBAAqB,CAAA;AAE5B,OAAO,KAAK,kBAAkB,MAAM,wBAAwB,CAAA;AAC5D,OAAO,wBAAwB,CAAA;AAC/B,OAAO,8BAA8B,CAAA;AAGrC,OAAO,mBAAmB,CAAA;AAC1B,OAAO,sCAAsC,CAAA;AAC7C,OAAO,wBAAwB,CAAA;AAC/B,OAAO,0BAA0B,CAAA;AAGjC,OAAO,KAAK,gBAAgB,MAAM,aAAa,CAAA;AAE/C,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA;AAC5B,cAAc,wBAAwB,CAAA;AACtC,cAAc,aAAa,CAAA;AAC3B,OAAO,EAAE,SAAS,EAAE,CAAA;AACpB,OAAO,EAAE,kBAAkB,EAAE,CAAA;AAC7B,OAAO,EAAE,yBAAyB,EAAE,CAAA;AACpC,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAClF,cAAc,OAAO,CAAA;AAErB,UAAU,oBAAqB,SAAQ,OAAO,CAAC,cAAc;IAC3D;;;OAGG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;CAClC;AASD,wBAAgB,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,wBAkDvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scratch-blocks",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "Scratch Blocks is a library for building creative computing interfaces.",
|
|
5
5
|
"author": "Massachusetts Institute of Technology",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"prepare": "husky || true",
|
|
25
25
|
"start": "webpack serve --open --mode development",
|
|
26
26
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
27
|
-
"test:lint": "eslint && prettier --check ."
|
|
27
|
+
"test:lint": "eslint && prettier --check .",
|
|
28
|
+
"watch": "webpack --mode development --watch"
|
|
28
29
|
},
|
|
29
30
|
"dependencies": {
|
|
30
31
|
"@blockly/continuous-toolbox": "^7.0.8",
|
|
@@ -32,10 +33,10 @@
|
|
|
32
33
|
"blockly": "^12.4.1"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
|
-
"@commitlint/cli": "20.
|
|
36
|
-
"@commitlint/config-conventional": "20.
|
|
36
|
+
"@commitlint/cli": "20.5.0",
|
|
37
|
+
"@commitlint/config-conventional": "20.5.0",
|
|
37
38
|
"eslint": "9.39.4",
|
|
38
|
-
"eslint-config-scratch": "14.0.
|
|
39
|
+
"eslint-config-scratch": "14.0.11",
|
|
39
40
|
"husky": "9.1.7",
|
|
40
41
|
"prettier": "3.8.1",
|
|
41
42
|
"scratch-semantic-release-config": "4.0.1",
|
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]
|
|
@@ -876,6 +938,26 @@ function updateArgumentReporterNames_(
|
|
|
876
938
|
}
|
|
877
939
|
}
|
|
878
940
|
|
|
941
|
+
/**
|
|
942
|
+
* Override showContextMenu on an argument reporter block so that right-clicks
|
|
943
|
+
* while the block is seated inside a procedures_prototype delegate up to the
|
|
944
|
+
* prototype (which in turn delegates to the parent procedures_definition).
|
|
945
|
+
* When the reporter has been dragged out and lives elsewhere, it keeps its
|
|
946
|
+
* normal context menu.
|
|
947
|
+
* @param block The argument reporter block to configure.
|
|
948
|
+
*/
|
|
949
|
+
function delegateContextMenuToPrototypeParent(block: Blockly.BlockSvg) {
|
|
950
|
+
const origShowContextMenu = block.showContextMenu.bind(block)
|
|
951
|
+
block.showContextMenu = function (this: Blockly.BlockSvg, e: Event) {
|
|
952
|
+
const parent = this.getParent()
|
|
953
|
+
if (parent?.type === 'procedures_prototype') {
|
|
954
|
+
parent.showContextMenu(e)
|
|
955
|
+
} else {
|
|
956
|
+
origShowContextMenu(e)
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
879
961
|
Blockly.Blocks.procedures_definition = {
|
|
880
962
|
/**
|
|
881
963
|
* Block for defining a procedure with no return value.
|
|
@@ -943,12 +1025,25 @@ Blockly.Blocks.procedures_prototype = {
|
|
|
943
1025
|
this.setDeletable(false)
|
|
944
1026
|
this.setDragStrategy(new DelegateToParentDraggable(this))
|
|
945
1027
|
|
|
1028
|
+
// Delegate right-clicks to the parent define block so that "Add Comment",
|
|
1029
|
+
// "Edit", etc. act on the definition rather than the prototype itself.
|
|
1030
|
+
const protoOrigShowContextMenu = this.showContextMenu.bind(this)
|
|
1031
|
+
this.showContextMenu = function (this: Blockly.BlockSvg, e: Event) {
|
|
1032
|
+
const parent = this.getParent()
|
|
1033
|
+
if (parent) {
|
|
1034
|
+
parent.showContextMenu(e)
|
|
1035
|
+
} else {
|
|
1036
|
+
protoOrigShowContextMenu(e)
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
946
1040
|
/* Data known about the procedure. */
|
|
947
1041
|
this.procCode_ = ''
|
|
948
1042
|
this.displayNames_ = []
|
|
949
1043
|
this.argumentIds_ = []
|
|
950
1044
|
this.argumentDefaults_ = []
|
|
951
1045
|
this.warp_ = false
|
|
1046
|
+
this.skipArgumentReporters_ = false
|
|
952
1047
|
|
|
953
1048
|
// Shared.
|
|
954
1049
|
this.getProcCode = getProcCode.bind(this)
|
|
@@ -1038,6 +1133,7 @@ Blockly.Blocks.argument_reporter_boolean = {
|
|
|
1038
1133
|
extensions: ['colours_more', 'output_boolean'],
|
|
1039
1134
|
})
|
|
1040
1135
|
this.setDragStrategy(new DuplicateOnDragDraggable(this))
|
|
1136
|
+
delegateContextMenuToPrototypeParent(this)
|
|
1041
1137
|
},
|
|
1042
1138
|
}
|
|
1043
1139
|
|
|
@@ -1055,6 +1151,7 @@ Blockly.Blocks.argument_reporter_string_number = {
|
|
|
1055
1151
|
extensions: ['colours_more', 'output_number', 'output_string'],
|
|
1056
1152
|
})
|
|
1057
1153
|
this.setDragStrategy(new DuplicateOnDragDraggable(this))
|
|
1154
|
+
delegateContextMenuToPrototypeParent(this)
|
|
1058
1155
|
},
|
|
1059
1156
|
}
|
|
1060
1157
|
|
|
@@ -1139,6 +1236,7 @@ interface ProcedureCallBlock extends ProcedureBlock {
|
|
|
1139
1236
|
interface ProcedurePrototypeBlock extends ProcedureBlock {
|
|
1140
1237
|
displayNames_: string[]
|
|
1141
1238
|
argumentDefaults_: string[]
|
|
1239
|
+
skipArgumentReporters_: boolean
|
|
1142
1240
|
createArgumentReporter_: (argumentType: ArgumentType, displayName: string) => Blockly.BlockSvg
|
|
1143
1241
|
updateArgumentReporterNames_: (prevArgIds: string[], prevDisplayNames: string[]) => void
|
|
1144
1242
|
}
|
|
@@ -182,7 +182,7 @@ const PROCEDURE_DEF_CONTEXTMENU = function (this: Blockly.Block) {
|
|
|
182
182
|
|
|
183
183
|
// Find and remove the duplicate option
|
|
184
184
|
for (let i = 0, option; (option = menuOptions[i]); i++) {
|
|
185
|
-
if (option.text == Blockly.Msg.
|
|
185
|
+
if (option.text == Blockly.Msg.DUPLICATE_BLOCK) {
|
|
186
186
|
menuOptions.splice(i, 1)
|
|
187
187
|
break
|
|
188
188
|
}
|
package/src/css.ts
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
import * as Blockly from 'blockly/core'
|
|
20
|
+
import { Colours } from './colours'
|
|
20
21
|
|
|
21
22
|
const styles = `
|
|
22
23
|
.blocklySvg {
|
|
@@ -287,9 +288,12 @@ const styles = `
|
|
|
287
288
|
cursor: -moz-grabbing;
|
|
288
289
|
}
|
|
289
290
|
|
|
290
|
-
/* All the blocks being dragged get the blocklyDragging class, so match only the root one
|
|
291
|
+
/* All the blocks being dragged get the blocklyDragging class, so match only the root one.
|
|
292
|
+
Using a CSS drop-shadow rather than an SVG filter reference avoids a Safari bug where
|
|
293
|
+
url("#blocklyDragShadowFilter") fails to resolve across SVG document boundaries when
|
|
294
|
+
the block is on the drag surface (a separate <svg> from the main workspace). */
|
|
291
295
|
:not(.blocklyDragging) > .blocklyDragging {
|
|
292
|
-
filter:
|
|
296
|
+
filter: drop-shadow(0px 0px 6px rgba(0, 0, 0, ${Colours.dragShadowOpacity}));
|
|
293
297
|
}
|
|
294
298
|
|
|
295
299
|
/* Changes cursor on mouse down. Not effective in Firefox because of
|
|
@@ -1208,6 +1212,15 @@ const styles = `
|
|
|
1208
1212
|
.blocklyInsertionMarker > g:not(:last-child) {
|
|
1209
1213
|
visibility: hidden;
|
|
1210
1214
|
}
|
|
1215
|
+
|
|
1216
|
+
/* Safari does not expand SVG elements to fill their absolutely-positioned
|
|
1217
|
+
container using top/left/right/bottom alone — it uses the SVG intrinsic
|
|
1218
|
+
size (300x150) instead. Explicit width/height ensures the drag surface SVG
|
|
1219
|
+
fills the injection div so dragged blocks are not clipped. */
|
|
1220
|
+
.blocklyBlockDragSurface, .blocklyAnimationLayer {
|
|
1221
|
+
width: 100%;
|
|
1222
|
+
height: 100%;
|
|
1223
|
+
}
|
|
1211
1224
|
`
|
|
1212
1225
|
|
|
1213
1226
|
Blockly.Css.register(styles)
|
package/src/index.ts
CHANGED
|
@@ -56,7 +56,6 @@ import './scratch_insertion_marker_previewer'
|
|
|
56
56
|
import './scratch_variable_map'
|
|
57
57
|
import './scratch_variable_model'
|
|
58
58
|
import { ScratchZoomControls } from './scratch_zoom_controls'
|
|
59
|
-
import { buildShadowFilter } from './shadows'
|
|
60
59
|
import { registerStatusIndicatorLabelFlyoutInflater } from './status_indicator_label_flyout_inflater'
|
|
61
60
|
import * as ScratchVariables from './variables'
|
|
62
61
|
|
|
@@ -120,7 +119,6 @@ export function inject(container: Element, options: ScratchBlocksOptions) {
|
|
|
120
119
|
const workspace = Blockly.inject(container, options)
|
|
121
120
|
|
|
122
121
|
buildGlowFilter(workspace)
|
|
123
|
-
buildShadowFilter(workspace)
|
|
124
122
|
|
|
125
123
|
// Replace Blockly's sprite-sheet zoom controls with SVG-file-based ones so
|
|
126
124
|
// each button is a separate file and the correct set is picked up via
|
|
@@ -167,6 +165,16 @@ Blockly.FlyoutButton.TEXT_MARGIN_Y = 10
|
|
|
167
165
|
Blockly.ContextMenuRegistry.registry.unregister('blockDisable')
|
|
168
166
|
Blockly.ContextMenuRegistry.registry.unregister('blockInline')
|
|
169
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
|
+
}
|
|
170
178
|
Blockly.ContextMenuRegistry.registry.unregister('blockDelete')
|
|
171
179
|
contextMenuItems.registerDeleteBlock()
|
|
172
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
|
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2024 Google LLC
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import * as Blockly from 'blockly/core';
|
|
6
|
-
/**
|
|
7
|
-
* Creates an SVG filter to apply drop shadows to blocks being dragged and
|
|
8
|
-
* inserts it into the DOM.
|
|
9
|
-
* @param workspace The workspace whose SVG will receive the filter definition.
|
|
10
|
-
*/
|
|
11
|
-
export declare function buildShadowFilter(workspace: Blockly.WorkspaceSvg): void;
|
|
12
|
-
//# sourceMappingURL=shadows.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shadows.d.ts","sourceRoot":"","sources":["../../../src/shadows.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAGvC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,QA+ChE"}
|
package/src/shadows.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright 2024 Google LLC
|
|
3
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
*/
|
|
5
|
-
import * as Blockly from 'blockly/core'
|
|
6
|
-
import { Colours } from './colours'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Creates an SVG filter to apply drop shadows to blocks being dragged and
|
|
10
|
-
* inserts it into the DOM.
|
|
11
|
-
* @param workspace The workspace whose SVG will receive the filter definition.
|
|
12
|
-
*/
|
|
13
|
-
export function buildShadowFilter(workspace: Blockly.WorkspaceSvg) {
|
|
14
|
-
const svg = workspace.getParentSvg()
|
|
15
|
-
const defs = Blockly.utils.dom.createSvgElement(Blockly.utils.Svg.DEFS, {}, svg)
|
|
16
|
-
// Adjust these width/height, x/y properties to stop the shadow from clipping
|
|
17
|
-
const dragShadowFilter = Blockly.utils.dom.createSvgElement(
|
|
18
|
-
'filter',
|
|
19
|
-
{
|
|
20
|
-
id: 'blocklyDragShadowFilter',
|
|
21
|
-
height: '140%',
|
|
22
|
-
width: '140%',
|
|
23
|
-
y: '-20%',
|
|
24
|
-
x: '-20%',
|
|
25
|
-
},
|
|
26
|
-
defs,
|
|
27
|
-
)
|
|
28
|
-
Blockly.utils.dom.createSvgElement(
|
|
29
|
-
'feGaussianBlur',
|
|
30
|
-
{
|
|
31
|
-
in: 'SourceAlpha',
|
|
32
|
-
stdDeviation: '6',
|
|
33
|
-
},
|
|
34
|
-
dragShadowFilter,
|
|
35
|
-
)
|
|
36
|
-
const componentTransfer = Blockly.utils.dom.createSvgElement(
|
|
37
|
-
'feComponentTransfer',
|
|
38
|
-
{ result: 'offsetBlur' },
|
|
39
|
-
dragShadowFilter,
|
|
40
|
-
)
|
|
41
|
-
// Shadow opacity is specified in the adjustable colour library,
|
|
42
|
-
// since the darkness of the shadow largely depends on the workspace colour.
|
|
43
|
-
Blockly.utils.dom.createSvgElement(
|
|
44
|
-
'feFuncA',
|
|
45
|
-
{
|
|
46
|
-
type: 'linear',
|
|
47
|
-
slope: Colours.dragShadowOpacity,
|
|
48
|
-
},
|
|
49
|
-
componentTransfer,
|
|
50
|
-
)
|
|
51
|
-
Blockly.utils.dom.createSvgElement(
|
|
52
|
-
'feComposite',
|
|
53
|
-
{
|
|
54
|
-
in: 'SourceGraphic',
|
|
55
|
-
in2: 'offsetBlur',
|
|
56
|
-
operator: 'over',
|
|
57
|
-
},
|
|
58
|
-
dragShadowFilter,
|
|
59
|
-
)
|
|
60
|
-
}
|