pxt-core 7.4.6 → 7.4.10

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.
Files changed (42) hide show
  1. package/built/pxt.js +105 -39
  2. package/built/pxtblockly.js +1359 -1448
  3. package/built/pxtblocks.d.ts +4 -4
  4. package/built/pxtblocks.js +35 -80
  5. package/built/pxteditor.d.ts +1 -1
  6. package/built/pxtlib.d.ts +13 -1
  7. package/built/pxtlib.js +105 -39
  8. package/built/target.js +1 -1
  9. package/built/web/blockly.css +1 -1
  10. package/built/web/main.js +1 -1
  11. package/built/web/pxtapp.js +1 -1
  12. package/built/web/pxtasseteditor.js +1 -1
  13. package/built/web/pxtblockly.js +1 -1
  14. package/built/web/pxtblocks.js +1 -1
  15. package/built/web/pxtembed.js +1 -1
  16. package/built/web/pxtlib.js +1 -1
  17. package/built/web/pxtworker.js +1 -1
  18. package/built/web/react-common.css +85 -18
  19. package/built/web/rtlblockly.css +1 -1
  20. package/built/web/rtlsemantic.css +2 -2
  21. package/built/web/semantic.css +2 -2
  22. package/built/web/skillmap/css/main.96b1b3f1.chunk.css +1 -0
  23. package/built/web/skillmap/js/2.7dd06a3a.chunk.js +2 -0
  24. package/built/web/skillmap/js/main.d5bb4f6b.chunk.js +1 -0
  25. package/localtypings/blockly.d.ts +12268 -7535
  26. package/localtypings/pxtarget.d.ts +1 -0
  27. package/package.json +2 -2
  28. package/theme/blockly-core.less +22 -13
  29. package/theme/common.less +0 -28
  30. package/theme/highcontrast.less +4 -0
  31. package/theme/melodyeditor.less +2 -2
  32. package/theme/print.less +1 -1
  33. package/theme/pxt.less +0 -1
  34. package/theme/toolbox.less +1 -0
  35. package/webapp/public/blockly/blockly_compressed.js +1269 -1286
  36. package/webapp/public/blockly/blocks_compressed.js +47 -65
  37. package/webapp/public/blockly/msg/js/en.js +8 -17
  38. package/webapp/public/blockly/msg/json/en.json +6 -15
  39. package/webapp/public/skillmap.html +2 -2
  40. package/built/web/skillmap/css/main.2461a333.chunk.css +0 -1
  41. package/built/web/skillmap/js/2.9cb94aa0.chunk.js +0 -2
  42. package/built/web/skillmap/js/main.c49acd24.chunk.js +0 -1
package/built/pxt.js CHANGED
@@ -97871,19 +97871,21 @@ var pxt;
97871
97871
  highContrast: false,
97872
97872
  language: pxt.appTarget.appTheme.defaultLocale,
97873
97873
  reader: "",
97874
- skillmap: { mapProgress: {}, completedTags: {} }
97874
+ skillmap: { mapProgress: {}, completedTags: {} },
97875
+ email: false
97875
97876
  });
97876
97877
  let _client;
97877
97878
  function client() { return _client; }
97878
97879
  auth.client = client;
97879
- const PREFERENCES_DEBOUNCE_MS = 5 * 1000;
97880
- const PREFERENCES_DEBOUNCE_MAX_MS = 30 * 1000;
97880
+ const PREFERENCES_DEBOUNCE_MS = 1 * 1000;
97881
+ const PREFERENCES_DEBOUNCE_MAX_MS = 10 * 1000;
97881
97882
  let debouncePreferencesChangedTimeout = 0;
97882
97883
  let debouncePreferencesChangedStarted = 0;
97883
97884
  class AuthClient {
97884
97885
  constructor() {
97885
97886
  this.initialUserPreferences_ = undefined;
97886
97887
  this.initialAuthCheck_ = undefined;
97888
+ this.patchQueue = [];
97887
97889
  pxt.Util.assert(!_client);
97888
97890
  // Set global instance.
97889
97891
  _client = this;
@@ -98073,40 +98075,87 @@ var pxt;
98073
98075
  }
98074
98076
  return result.success;
98075
98077
  }
98076
- async patchUserPreferencesAsync(ops) {
98077
- ops = Array.isArray(ops) ? ops : [ops];
98078
- if (!ops.length) {
98079
- return;
98080
- }
98078
+ async patchUserPreferencesAsync(patchOps, opts = {}) {
98079
+ const defaultSuccessAsync = async () => ({ success: true, res: await this.userPreferencesAsync() });
98080
+ patchOps = Array.isArray(patchOps) ? patchOps : [patchOps];
98081
+ patchOps = patchOps.filter(op => !!op);
98082
+ if (!patchOps.length) {
98083
+ return await defaultSuccessAsync();
98084
+ }
98085
+ const patchDiff = (pSrc, ops, filter) => {
98086
+ // Apply patches to pDst and return the diff as a set of new patch ops.
98087
+ const pDst = pxt.U.deepCopy(pSrc);
98088
+ ts.pxtc.jsonPatch.patchInPlace(pDst, ops);
98089
+ let diff = ts.pxtc.jsonPatch.diff(pSrc, pDst);
98090
+ // Run caller-provided filter
98091
+ if (diff.length && filter) {
98092
+ diff = diff.filter(filter);
98093
+ }
98094
+ return diff;
98095
+ };
98096
+ // Process incoming patch operations to produce a more fine-grained set of diffs. Incoming patches may be overly destructive
98097
+ // Apply the patch in isolation and get the diff from original
98081
98098
  const curPref = await this.userPreferencesAsync();
98082
- ts.pxtc.jsonPatch.patchInPlace(curPref, ops);
98099
+ const diff = patchDiff(curPref, patchOps, opts.filter);
98100
+ if (!diff.length) {
98101
+ return await defaultSuccessAsync();
98102
+ }
98103
+ // Apply the new diff to the current state
98104
+ ts.pxtc.jsonPatch.patchInPlace(curPref, diff);
98083
98105
  await this.setUserPreferencesAsync(curPref);
98084
- // If we're not logged in, non-persistent local state is all we'll use
98106
+ // If the user is not logged in, non-persistent local state is all we'll use (no sync to cloud)
98085
98107
  if (!await this.loggedInAsync()) {
98086
- return;
98108
+ return await defaultSuccessAsync();
98087
98109
  }
98088
- // If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
98110
+ // If the user is logged in, sync to cloud, but debounce the api call as this can be called frequently from skillmaps
98111
+ // Queue the patch for sync with backend
98112
+ this.patchQueue.push({ ops: patchOps, filter: opts.filter });
98089
98113
  clearTimeout(debouncePreferencesChangedTimeout);
98090
- const savePrefs = async () => {
98114
+ const syncPrefs = async () => {
98091
98115
  debouncePreferencesChangedStarted = 0;
98092
- const result = await this.apiAsync('/api/user/preferences', ops, 'PATCH');
98093
- if (result.success) {
98094
- pxt.debug("Updating local user preferences w/ cloud data after result of POST");
98095
- // Set user profile from returned value so we stay in-sync
98096
- this.setUserPreferencesAsync(result.resp);
98116
+ if (!this.patchQueue.length) {
98117
+ return await defaultSuccessAsync();
98118
+ }
98119
+ // Fetch latest prefs from remote
98120
+ const getResult = await this.apiAsync('/api/user/preferences');
98121
+ if (!getResult.success) {
98122
+ pxt.reportError("identity", "failed to fetch preferences for patch", getResult);
98123
+ return { success: false, res: undefined };
98124
+ }
98125
+ // Apply queued patches to the remote state in isolation and develop a final diff to send to the backend
98126
+ const remotePrefs = pxt.U.deepCopy(getResult.resp);
98127
+ const patchQueue = this.patchQueue;
98128
+ this.patchQueue = []; // Reset the queue
98129
+ patchQueue.forEach(patch => {
98130
+ const diff = patchDiff(remotePrefs, patch.ops, patch.filter);
98131
+ ts.pxtc.jsonPatch.patchInPlace(remotePrefs, diff);
98132
+ });
98133
+ // Diff the original and patched remote states to get a final set of patch operations
98134
+ const finalOps = pxtc.jsonPatch.diff(getResult.resp, remotePrefs);
98135
+ const patchResult = await this.apiAsync('/api/user/preferences', finalOps, 'PATCH');
98136
+ if (patchResult.success) {
98137
+ // Set user profile from returned value so we stay in sync
98138
+ this.setUserPreferencesAsync(patchResult.resp);
98097
98139
  }
98098
98140
  else {
98099
- pxt.reportError("identity", "update preferences failed", result);
98141
+ pxt.reportError("identity", "failed to patch preferences", patchResult);
98100
98142
  }
98143
+ return { success: patchResult.success, res: patchResult.resp };
98101
98144
  };
98102
- if (!debouncePreferencesChangedStarted) {
98103
- debouncePreferencesChangedStarted = pxt.U.now();
98104
- }
98105
- if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
98106
- await savePrefs();
98145
+ if (opts.immediate) {
98146
+ return await syncPrefs();
98107
98147
  }
98108
98148
  else {
98109
- debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
98149
+ if (!debouncePreferencesChangedStarted) {
98150
+ debouncePreferencesChangedStarted = pxt.U.now();
98151
+ }
98152
+ if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
98153
+ return await syncPrefs();
98154
+ }
98155
+ else {
98156
+ debouncePreferencesChangedTimeout = setTimeout(syncPrefs, PREFERENCES_DEBOUNCE_MS);
98157
+ return { success: false, res: undefined }; // This needs to be implemented correctly to return a promise with the debouncer
98158
+ }
98110
98159
  }
98111
98160
  }
98112
98161
  /*protected*/ hasUserId() {
@@ -98900,6 +98949,18 @@ var ts;
98900
98949
  return arr;
98901
98950
  }
98902
98951
  Util.reversed = reversed;
98952
+ function arrayEquals(a, b, compare = (c, d) => c === d) {
98953
+ if (a == b)
98954
+ return true;
98955
+ if (!a && b || !b && a || a.length !== b.length)
98956
+ return false;
98957
+ for (let i = 0; i < a.length; i++) {
98958
+ if (!compare(a[i], b[i]))
98959
+ return false;
98960
+ }
98961
+ return true;
98962
+ }
98963
+ Util.arrayEquals = arrayEquals;
98903
98964
  function iterMap(m, f) {
98904
98965
  Object.keys(m).forEach(k => f(k, m[k]));
98905
98966
  }
@@ -99175,6 +99236,18 @@ var ts;
99175
99236
  return r;
99176
99237
  }
99177
99238
  Util.toSet = toSet;
99239
+ function deepCopy(src) {
99240
+ if (typeof src !== "object" || src === null) {
99241
+ return src;
99242
+ }
99243
+ const dst = Array.isArray(src) ? [] : {};
99244
+ for (const key in src) {
99245
+ const value = src[key];
99246
+ dst[key] = deepCopy(value);
99247
+ }
99248
+ return dst;
99249
+ }
99250
+ Util.deepCopy = deepCopy;
99178
99251
  function toArray(a) {
99179
99252
  if (Array.isArray(a)) {
99180
99253
  return a;
@@ -100723,6 +100796,10 @@ var ts;
100723
100796
  }
100724
100797
  }
100725
100798
  jsonPatch.patchInPlace = patchInPlace;
100799
+ function opsAreEqual(a, b) {
100800
+ return (a.op === b.op && pxtc.U.arrayEquals(a.path, b.path));
100801
+ }
100802
+ jsonPatch.opsAreEqual = opsAreEqual;
100726
100803
  })(jsonPatch = pxtc.jsonPatch || (pxtc.jsonPatch = {}));
100727
100804
  })(pxtc = ts.pxtc || (ts.pxtc = {}));
100728
100805
  })(ts || (ts = {}));
@@ -116191,8 +116268,8 @@ var pxt;
116191
116268
  if (a == b)
116192
116269
  return true;
116193
116270
  if (a.id !== b.id || a.type !== b.type ||
116194
- !arrayEquals(a.meta.tags, b.meta.tags) ||
116195
- !arrayEquals(a.meta.blockIDs, b.meta.blockIDs) ||
116271
+ !pxt.U.arrayEquals(a.meta.tags, b.meta.tags) ||
116272
+ !pxt.U.arrayEquals(a.meta.blockIDs, b.meta.blockIDs) ||
116196
116273
  a.meta.displayName !== b.meta.displayName)
116197
116274
  return false;
116198
116275
  switch (a.type) {
@@ -116201,7 +116278,7 @@ var pxt;
116201
116278
  return pxt.sprite.bitmapEquals(a.bitmap, b.bitmap);
116202
116279
  case "animation" /* Animation */:
116203
116280
  const bAnimation = b;
116204
- return a.interval === bAnimation.interval && arrayEquals(a.frames, bAnimation.frames, pxt.sprite.bitmapEquals);
116281
+ return a.interval === bAnimation.interval && pxt.U.arrayEquals(a.frames, bAnimation.frames, pxt.sprite.bitmapEquals);
116205
116282
  case "tilemap" /* Tilemap */:
116206
116283
  return a.data.equals(b.data);
116207
116284
  }
@@ -116323,17 +116400,6 @@ var pxt;
116323
116400
  }
116324
116401
  return id;
116325
116402
  }
116326
- function arrayEquals(a, b, compare = (c, d) => c === d) {
116327
- if (a == b)
116328
- return true;
116329
- if (!a && b || !b && a || a.length !== b.length)
116330
- return false;
116331
- for (let i = 0; i < a.length; i++) {
116332
- if (!compare(a[i], b[i]))
116333
- return false;
116334
- }
116335
- return true;
116336
- }
116337
116403
  function serializeTilemap(tilemap, id, name) {
116338
116404
  const tm = tilemap.tilemap.data();
116339
116405
  const data = new Uint8ClampedArray(5 + tm.data.length + tilemap.layers.data.length);