pxt-core 7.4.9 → 7.4.13
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/built/cli.js +94 -83
- package/built/pxt.js +180 -135
- package/built/pxtblockly.js +1509 -1508
- package/built/pxtblocks.d.ts +11 -4
- package/built/pxtblocks.js +126 -138
- package/built/pxtlib.d.ts +6 -2
- package/built/pxtlib.js +86 -52
- package/built/target.js +1 -1
- package/built/web/blockly.css +1 -1
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtblockly.js +53 -1
- package/built/web/pxtblocks.js +1 -1
- package/built/web/pxtembed.js +53 -1
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/react-common-skillmap.css +1 -0
- package/built/web/rtlblockly.css +1 -1
- package/built/web/rtlreact-common-skillmap.css +1 -0
- package/built/web/rtlsemantic.css +1 -1
- package/built/web/semantic.css +1 -1
- package/built/web/skillmap/js/main.b96caef3.chunk.js +1 -0
- package/docfiles/tracking.html +1 -1
- package/localtypings/blockly.d.ts +12268 -7535
- package/localtypings/pxtarget.d.ts +1 -0
- package/localtypings/pxtblockly.d.ts +37 -0
- package/package.json +6 -3
- package/react-common/components/Checkbox.tsx +25 -0
- package/react-common/components/Notification.tsx +82 -0
- package/react-common/components/profile/Badge.tsx +33 -0
- package/react-common/components/profile/BadgeInfo.tsx +74 -0
- package/react-common/components/profile/BadgeList.tsx +67 -0
- package/react-common/components/profile/Profile.tsx +42 -0
- package/react-common/components/profile/UserNotification.tsx +32 -0
- package/react-common/components/profile/UserPane.tsx +64 -0
- package/react-common/components/types.d.ts +29 -0
- package/react-common/components/util.tsx +35 -0
- package/{built/web/react-common.css → react-common/styles/profile/profile.less} +1 -0
- package/react-common/styles/react-common-skillmap-core.less +10 -0
- package/react-common/styles/react-common-skillmap.less +12 -0
- package/react-common/styles/react-common.less +1 -0
- package/react-common/tsconfig.json +36 -0
- package/theme/blockly-core.less +38 -13
- package/theme/common-components.less +7 -0
- package/theme/common.less +1 -1
- package/theme/highcontrast.less +4 -0
- package/theme/melodyeditor.less +2 -2
- package/theme/print.less +1 -1
- package/theme/pxt.less +2 -0
- package/theme/toolbox.less +1 -0
- package/theme/tutorial-sidebar.less +64 -6
- package/webapp/public/blockly/blockly_compressed.js +1271 -1288
- package/webapp/public/blockly/blocks_compressed.js +47 -65
- package/webapp/public/blockly/msg/js/en.js +8 -17
- package/webapp/public/blockly/msg/json/en.json +6 -15
- package/webapp/public/blockly/plugins.js +57 -0
- package/webapp/public/skillmap.html +2 -2
- package/built/web/skillmap/js/main.ea4b3e23.chunk.js +0 -1
package/built/pxtlib.d.ts
CHANGED
|
@@ -129,8 +129,11 @@ declare namespace pxt.auth {
|
|
|
129
129
|
username?: string;
|
|
130
130
|
avatarUrl?: string;
|
|
131
131
|
}): Promise<boolean>;
|
|
132
|
-
private
|
|
133
|
-
patchUserPreferencesAsync(
|
|
132
|
+
private patchQueue;
|
|
133
|
+
patchUserPreferencesAsync(patchOps: ts.pxtc.jsonPatch.PatchOperation | ts.pxtc.jsonPatch.PatchOperation[], opts?: {
|
|
134
|
+
immediate?: boolean;
|
|
135
|
+
filter?: (op: ts.pxtc.jsonPatch.PatchOperation) => boolean;
|
|
136
|
+
}): Promise<SetPrefResult>;
|
|
134
137
|
hasUserId(): boolean;
|
|
135
138
|
private fetchUserAsync;
|
|
136
139
|
private setUserProfileAsync;
|
|
@@ -302,6 +305,7 @@ declare namespace ts.pxtc.Util {
|
|
|
302
305
|
export function groupBy<T>(arr: T[], f: (t: T) => string): pxt.Map<T[]>;
|
|
303
306
|
export function toDictionary<T>(arr: T[], f: (t: T) => string): pxt.Map<T>;
|
|
304
307
|
export function toSet<T>(arr: T[], f: (t: T) => string): pxt.Map<boolean>;
|
|
308
|
+
export function deepCopy(src: any): any;
|
|
305
309
|
export interface ArrayLike<T> {
|
|
306
310
|
[index: number]: T;
|
|
307
311
|
length: number;
|
package/built/pxtlib.js
CHANGED
|
@@ -199,7 +199,7 @@ var pxt;
|
|
|
199
199
|
constructor() {
|
|
200
200
|
this.initialUserPreferences_ = undefined;
|
|
201
201
|
this.initialAuthCheck_ = undefined;
|
|
202
|
-
this.
|
|
202
|
+
this.patchQueue = [];
|
|
203
203
|
pxt.Util.assert(!_client);
|
|
204
204
|
// Set global instance.
|
|
205
205
|
_client = this;
|
|
@@ -389,63 +389,85 @@ var pxt;
|
|
|
389
389
|
}
|
|
390
390
|
return result.success;
|
|
391
391
|
}
|
|
392
|
-
async patchUserPreferencesAsync(
|
|
393
|
-
|
|
394
|
-
|
|
392
|
+
async patchUserPreferencesAsync(patchOps, opts = {}) {
|
|
393
|
+
const defaultSuccessAsync = async () => ({ success: true, res: await this.userPreferencesAsync() });
|
|
394
|
+
patchOps = Array.isArray(patchOps) ? patchOps : [patchOps];
|
|
395
|
+
patchOps = patchOps.filter(op => !!op);
|
|
396
|
+
if (!patchOps.length) {
|
|
397
|
+
return await defaultSuccessAsync();
|
|
398
|
+
}
|
|
399
|
+
const patchDiff = (pSrc, ops, filter) => {
|
|
400
|
+
// Apply patches to pDst and return the diff as a set of new patch ops.
|
|
401
|
+
const pDst = pxt.U.deepCopy(pSrc);
|
|
402
|
+
ts.pxtc.jsonPatch.patchInPlace(pDst, ops);
|
|
403
|
+
let diff = ts.pxtc.jsonPatch.diff(pSrc, pDst);
|
|
404
|
+
// Run caller-provided filter
|
|
405
|
+
if (diff.length && filter) {
|
|
406
|
+
diff = diff.filter(filter);
|
|
407
|
+
}
|
|
408
|
+
return diff;
|
|
409
|
+
};
|
|
410
|
+
// Process incoming patch operations to produce a more fine-grained set of diffs. Incoming patches may be overly destructive
|
|
411
|
+
// Apply the patch in isolation and get the diff from original
|
|
395
412
|
const curPref = await this.userPreferencesAsync();
|
|
396
|
-
|
|
397
|
-
|
|
413
|
+
const diff = patchDiff(curPref, patchOps, opts.filter);
|
|
414
|
+
if (!diff.length) {
|
|
415
|
+
return await defaultSuccessAsync();
|
|
398
416
|
}
|
|
399
|
-
|
|
417
|
+
// Apply the new diff to the current state
|
|
418
|
+
ts.pxtc.jsonPatch.patchInPlace(curPref, diff);
|
|
400
419
|
await this.setUserPreferencesAsync(curPref);
|
|
401
|
-
// If
|
|
420
|
+
// If the user is not logged in, non-persistent local state is all we'll use (no sync to cloud)
|
|
402
421
|
if (!await this.loggedInAsync()) {
|
|
403
|
-
return
|
|
422
|
+
return await defaultSuccessAsync();
|
|
404
423
|
}
|
|
405
|
-
// If the user is logged in,
|
|
406
|
-
//
|
|
407
|
-
|
|
408
|
-
this.prefPatchOps.some((existing, iExisting) => {
|
|
409
|
-
if (!ts.pxtc.jsonPatch.opsAreEqual(existing, incoming))
|
|
410
|
-
return false;
|
|
411
|
-
// Patches are equivalent, replace in queue
|
|
412
|
-
this.prefPatchOps[iExisting] = incoming;
|
|
413
|
-
// Clear from incoming so we don't add it below
|
|
414
|
-
ops[iIncoming] = null;
|
|
415
|
-
return true;
|
|
416
|
-
});
|
|
417
|
-
});
|
|
418
|
-
// Add remaining ops to the queue
|
|
419
|
-
ops.filter(op => !!op).forEach(op => this.prefPatchOps.push(op));
|
|
424
|
+
// If the user is logged in, sync to cloud, but debounce the api call as this can be called frequently from skillmaps
|
|
425
|
+
// Queue the patch for sync with backend
|
|
426
|
+
this.patchQueue.push({ ops: patchOps, filter: opts.filter });
|
|
420
427
|
clearTimeout(debouncePreferencesChangedTimeout);
|
|
421
|
-
const
|
|
428
|
+
const syncPrefs = async () => {
|
|
422
429
|
debouncePreferencesChangedStarted = 0;
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
430
|
+
if (!this.patchQueue.length) {
|
|
431
|
+
return await defaultSuccessAsync();
|
|
432
|
+
}
|
|
433
|
+
// Fetch latest prefs from remote
|
|
434
|
+
const getResult = await this.apiAsync('/api/user/preferences');
|
|
435
|
+
if (!getResult.success) {
|
|
436
|
+
pxt.reportError("identity", "failed to fetch preferences for patch", getResult);
|
|
437
|
+
return { success: false, res: undefined };
|
|
438
|
+
}
|
|
439
|
+
// Apply queued patches to the remote state in isolation and develop a final diff to send to the backend
|
|
440
|
+
const remotePrefs = pxt.U.deepCopy(getResult.resp) || auth.DEFAULT_USER_PREFERENCES();
|
|
441
|
+
const patchQueue = this.patchQueue;
|
|
442
|
+
this.patchQueue = []; // Reset the queue
|
|
443
|
+
patchQueue.forEach(patch => {
|
|
444
|
+
const diff = patchDiff(remotePrefs, patch.ops, patch.filter);
|
|
445
|
+
ts.pxtc.jsonPatch.patchInPlace(remotePrefs, diff);
|
|
446
|
+
});
|
|
447
|
+
// Diff the original and patched remote states to get a final set of patch operations
|
|
448
|
+
const finalOps = pxtc.jsonPatch.diff(getResult.resp, remotePrefs);
|
|
449
|
+
const patchResult = await this.apiAsync('/api/user/preferences', finalOps, 'PATCH');
|
|
450
|
+
if (patchResult.success) {
|
|
451
|
+
// Set user profile from returned value so we stay in sync
|
|
452
|
+
this.setUserPreferencesAsync(patchResult.resp);
|
|
431
453
|
}
|
|
432
454
|
else {
|
|
433
|
-
pxt.reportError("identity", "
|
|
455
|
+
pxt.reportError("identity", "failed to patch preferences", patchResult);
|
|
434
456
|
}
|
|
435
|
-
return { success:
|
|
457
|
+
return { success: patchResult.success, res: patchResult.resp };
|
|
436
458
|
};
|
|
437
|
-
if (immediate) {
|
|
438
|
-
return await
|
|
459
|
+
if (opts.immediate) {
|
|
460
|
+
return await syncPrefs();
|
|
439
461
|
}
|
|
440
462
|
else {
|
|
441
463
|
if (!debouncePreferencesChangedStarted) {
|
|
442
464
|
debouncePreferencesChangedStarted = pxt.U.now();
|
|
443
465
|
}
|
|
444
466
|
if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
|
|
445
|
-
return await
|
|
467
|
+
return await syncPrefs();
|
|
446
468
|
}
|
|
447
469
|
else {
|
|
448
|
-
debouncePreferencesChangedTimeout = setTimeout(
|
|
470
|
+
debouncePreferencesChangedTimeout = setTimeout(syncPrefs, PREFERENCES_DEBOUNCE_MS);
|
|
449
471
|
return { success: false, res: undefined }; // This needs to be implemented correctly to return a promise with the debouncer
|
|
450
472
|
}
|
|
451
473
|
}
|
|
@@ -1528,6 +1550,18 @@ var ts;
|
|
|
1528
1550
|
return r;
|
|
1529
1551
|
}
|
|
1530
1552
|
Util.toSet = toSet;
|
|
1553
|
+
function deepCopy(src) {
|
|
1554
|
+
if (typeof src !== "object" || src === null) {
|
|
1555
|
+
return src;
|
|
1556
|
+
}
|
|
1557
|
+
const dst = Array.isArray(src) ? [] : {};
|
|
1558
|
+
for (const key in src) {
|
|
1559
|
+
const value = src[key];
|
|
1560
|
+
dst[key] = deepCopy(value);
|
|
1561
|
+
}
|
|
1562
|
+
return dst;
|
|
1563
|
+
}
|
|
1564
|
+
Util.deepCopy = deepCopy;
|
|
1531
1565
|
function toArray(a) {
|
|
1532
1566
|
if (Array.isArray(a)) {
|
|
1533
1567
|
return a;
|
|
@@ -3947,7 +3981,7 @@ var pxt;
|
|
|
3947
3981
|
'pxt_controls_for': {
|
|
3948
3982
|
name: pxt.Util.lf("a loop that repeats the number of times you say"),
|
|
3949
3983
|
tooltip: pxt.Util.lf("Have the variable '{0}' take on the values from 0 to the end number, counting by 1, and do the specified blocks."),
|
|
3950
|
-
url: 'blocks/loops/for',
|
|
3984
|
+
url: '/blocks/loops/for',
|
|
3951
3985
|
category: 'loops',
|
|
3952
3986
|
block: {
|
|
3953
3987
|
message0: pxt.Util.lf("for %1 from 0 to %2"),
|
|
@@ -3958,7 +3992,7 @@ var pxt;
|
|
|
3958
3992
|
'controls_simple_for': {
|
|
3959
3993
|
name: pxt.Util.lf("a loop that repeats the number of times you say"),
|
|
3960
3994
|
tooltip: pxt.Util.lf("Have the variable '{0}' take on the values from 0 to the end number, counting by 1, and do the specified blocks."),
|
|
3961
|
-
url: 'blocks/loops/for',
|
|
3995
|
+
url: '/blocks/loops/for',
|
|
3962
3996
|
category: 'loops',
|
|
3963
3997
|
block: {
|
|
3964
3998
|
message0: pxt.Util.lf("for %1 from 0 to %2"),
|
|
@@ -3969,7 +4003,7 @@ var pxt;
|
|
|
3969
4003
|
'pxt_controls_for_of': {
|
|
3970
4004
|
name: pxt.Util.lf("a loop that repeats for each value in an array"),
|
|
3971
4005
|
tooltip: pxt.Util.lf("Have the variable '{0}' take the value of each item in the array one by one, and do the specified blocks."),
|
|
3972
|
-
url: 'blocks/loops/for-of',
|
|
4006
|
+
url: '/blocks/loops/for-of',
|
|
3973
4007
|
category: 'loops',
|
|
3974
4008
|
block: {
|
|
3975
4009
|
message0: pxt.Util.lf("for element %1 of %2"),
|
|
@@ -3980,7 +4014,7 @@ var pxt;
|
|
|
3980
4014
|
'controls_for_of': {
|
|
3981
4015
|
name: pxt.Util.lf("a loop that repeats for each value in an array"),
|
|
3982
4016
|
tooltip: pxt.Util.lf("Have the variable '{0}' take the value of each item in the array one by one, and do the specified blocks."),
|
|
3983
|
-
url: 'blocks/loops/for-of',
|
|
4017
|
+
url: '/blocks/loops/for-of',
|
|
3984
4018
|
category: 'loops',
|
|
3985
4019
|
block: {
|
|
3986
4020
|
message0: pxt.Util.lf("for element %1 of %2"),
|
|
@@ -4265,7 +4299,7 @@ var pxt;
|
|
|
4265
4299
|
'text': {
|
|
4266
4300
|
name: pxt.Util.lf("a piece of text"),
|
|
4267
4301
|
tooltip: pxt.Util.lf("A letter, word, or line of text."),
|
|
4268
|
-
url: 'types/string',
|
|
4302
|
+
url: '/types/string',
|
|
4269
4303
|
category: 'text',
|
|
4270
4304
|
block: {
|
|
4271
4305
|
search: pxt.Util.lf("a piece of text") // Only used for search; this string is not surfaced in the block's text
|
|
@@ -4274,7 +4308,7 @@ var pxt;
|
|
|
4274
4308
|
'text_length': {
|
|
4275
4309
|
name: pxt.Util.lf("number of characters in the string"),
|
|
4276
4310
|
tooltip: pxt.Util.lf("Returns the number of letters (including spaces) in the provided text."),
|
|
4277
|
-
url: 'reference/text/length',
|
|
4311
|
+
url: '/reference/text/length',
|
|
4278
4312
|
category: 'text',
|
|
4279
4313
|
block: {
|
|
4280
4314
|
TEXT_LENGTH_TITLE: pxt.Util.lf("length of %1")
|
|
@@ -4283,7 +4317,7 @@ var pxt;
|
|
|
4283
4317
|
'text_join': {
|
|
4284
4318
|
name: pxt.Util.lf("join items to create text"),
|
|
4285
4319
|
tooltip: pxt.Util.lf("Create a piece of text by joining together any number of items."),
|
|
4286
|
-
url: 'reference/text/join',
|
|
4320
|
+
url: '/reference/text/join',
|
|
4287
4321
|
category: 'text',
|
|
4288
4322
|
block: {
|
|
4289
4323
|
TEXT_JOIN_TITLE_CREATEWITH: pxt.Util.lf("join")
|
|
@@ -4292,7 +4326,7 @@ var pxt;
|
|
|
4292
4326
|
'procedures_defnoreturn': {
|
|
4293
4327
|
name: pxt.Util.lf("define the function"),
|
|
4294
4328
|
tooltip: pxt.Util.lf("Create a function."),
|
|
4295
|
-
url: 'types/function/define',
|
|
4329
|
+
url: '/types/function/define',
|
|
4296
4330
|
category: 'functions',
|
|
4297
4331
|
block: {
|
|
4298
4332
|
PROCEDURES_DEFNORETURN_TITLE: pxt.Util.lf("function"),
|
|
@@ -4302,7 +4336,7 @@ var pxt;
|
|
|
4302
4336
|
'procedures_callnoreturn': {
|
|
4303
4337
|
name: pxt.Util.lf("call the function"),
|
|
4304
4338
|
tooltip: pxt.Util.lf("Call the user-defined function."),
|
|
4305
|
-
url: 'types/function/call',
|
|
4339
|
+
url: '/types/function/call',
|
|
4306
4340
|
category: 'functions',
|
|
4307
4341
|
block: {
|
|
4308
4342
|
PROCEDURES_CALLNORETURN_TITLE: pxt.Util.lf("call function")
|
|
@@ -4311,7 +4345,7 @@ var pxt;
|
|
|
4311
4345
|
'function_return': {
|
|
4312
4346
|
name: pxt.Util.lf("return a value from within a function"),
|
|
4313
4347
|
tooltip: pxt.Util.lf("Return a value from within a user-defined function."),
|
|
4314
|
-
url: 'types/function/return',
|
|
4348
|
+
url: '/types/function/return',
|
|
4315
4349
|
category: 'functions',
|
|
4316
4350
|
block: {
|
|
4317
4351
|
message_with_value: pxt.Util.lf("return %1"),
|
|
@@ -4321,7 +4355,7 @@ var pxt;
|
|
|
4321
4355
|
'function_definition': {
|
|
4322
4356
|
name: pxt.Util.lf("define the function"),
|
|
4323
4357
|
tooltip: pxt.Util.lf("Create a function."),
|
|
4324
|
-
url: 'types/function/define',
|
|
4358
|
+
url: '/types/function/define',
|
|
4325
4359
|
category: 'functions',
|
|
4326
4360
|
block: {
|
|
4327
4361
|
FUNCTIONS_EDIT_OPTION: pxt.Util.lf("Edit Function")
|
|
@@ -4330,7 +4364,7 @@ var pxt;
|
|
|
4330
4364
|
'function_call': {
|
|
4331
4365
|
name: pxt.Util.lf("call the function"),
|
|
4332
4366
|
tooltip: pxt.Util.lf("Call the user-defined function."),
|
|
4333
|
-
url: 'types/function/call',
|
|
4367
|
+
url: '/types/function/call',
|
|
4334
4368
|
category: 'functions',
|
|
4335
4369
|
block: {
|
|
4336
4370
|
FUNCTIONS_CALL_TITLE: pxt.Util.lf("call"),
|
|
@@ -4340,7 +4374,7 @@ var pxt;
|
|
|
4340
4374
|
'function_call_output': {
|
|
4341
4375
|
name: pxt.Util.lf("call the function with a return value"),
|
|
4342
4376
|
tooltip: pxt.Util.lf("Call the user-defined function with a return value."),
|
|
4343
|
-
url: 'types/function/call',
|
|
4377
|
+
url: '/types/function/call',
|
|
4344
4378
|
category: 'functions',
|
|
4345
4379
|
block: {}
|
|
4346
4380
|
}
|