pxt-core 7.3.7 → 7.3.11
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 +4 -1
- package/built/pxt.js +42 -13
- package/built/pxtcompiler.js +7 -3
- package/built/pxteditor.d.ts +1 -1
- package/built/pxtlib.d.ts +11 -1
- package/built/pxtlib.js +31 -9
- package/built/target.js +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/pxtcompiler.js +1 -1
- package/built/web/pxtembed.js +1 -1
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/react-common.css +303 -0
- package/built/web/rtlsemantic.css +3 -3
- package/built/web/semantic.css +3 -3
- package/built/web/skillmap/css/main.70954d9b.chunk.css +1 -0
- package/built/web/skillmap/js/2.c64f6be2.chunk.js +2 -0
- package/built/web/skillmap/js/main.a47f7899.chunk.js +1 -0
- package/localtypings/pxtarget.d.ts +30 -0
- package/package.json +1 -1
- package/theme/common.less +0 -28
- package/theme/highcontrast.less +14 -0
- package/theme/pxt.less +1 -0
- package/theme/themes/pxt/modules/dropdown.overrides +2 -1
- package/webapp/public/skillmap.html +3 -2
- package/built/web/skillmap/css/main.90d453fd.chunk.css +0 -1
- package/built/web/skillmap/js/2.fbe3f08f.chunk.js +0 -2
- package/built/web/skillmap/js/main.e8ffa077.chunk.js +0 -1
package/built/cli.js
CHANGED
|
@@ -1768,7 +1768,9 @@ function buildSemanticUIAsync(parsed) {
|
|
|
1768
1768
|
// Append icons.css to semantic.css (custom pxt icons)
|
|
1769
1769
|
const iconsFile = (pkg["name"] == "pxt-core") ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
|
|
1770
1770
|
const iconsCss = fs.readFileSync(iconsFile, "utf-8");
|
|
1771
|
-
|
|
1771
|
+
const reactCommonFile = (pkg["name"] == "pxt-core") ? 'built/web/react-common.css' : 'node_modules/pxt-core/built/web/react-common.css';
|
|
1772
|
+
const reactCommonCss = fs.readFileSync(reactCommonFile, "utf-8");
|
|
1773
|
+
semCss = semCss + "\n" + iconsCss + "\n" + reactCommonCss;
|
|
1772
1774
|
nodeutil.writeFileSync('built/web/semantic.css', semCss);
|
|
1773
1775
|
}).then(() => {
|
|
1774
1776
|
// generate blockly css
|
|
@@ -1836,6 +1838,7 @@ function buildSkillMapAsync(parsed) {
|
|
|
1836
1838
|
nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
|
|
1837
1839
|
nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
|
|
1838
1840
|
nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
|
|
1841
|
+
nodeutil.cp("node_modules/pxt-core/built/web/react-common.css", `${skillmapRoot}/public/blb`);
|
|
1839
1842
|
// copy 'assets' over from docs/static
|
|
1840
1843
|
nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
|
|
1841
1844
|
if (docsPath) {
|
package/built/pxt.js
CHANGED
|
@@ -97876,14 +97876,15 @@ var pxt;
|
|
|
97876
97876
|
let _client;
|
|
97877
97877
|
function client() { return _client; }
|
|
97878
97878
|
auth.client = client;
|
|
97879
|
-
const PREFERENCES_DEBOUNCE_MS =
|
|
97880
|
-
const PREFERENCES_DEBOUNCE_MAX_MS =
|
|
97879
|
+
const PREFERENCES_DEBOUNCE_MS = 1 * 1000;
|
|
97880
|
+
const PREFERENCES_DEBOUNCE_MAX_MS = 10 * 1000;
|
|
97881
97881
|
let debouncePreferencesChangedTimeout = 0;
|
|
97882
97882
|
let debouncePreferencesChangedStarted = 0;
|
|
97883
97883
|
class AuthClient {
|
|
97884
97884
|
constructor() {
|
|
97885
97885
|
this.initialUserPreferences_ = undefined;
|
|
97886
97886
|
this.initialAuthCheck_ = undefined;
|
|
97887
|
+
this.prefPatchOps = [];
|
|
97887
97888
|
pxt.Util.assert(!_client);
|
|
97888
97889
|
// Set global instance.
|
|
97889
97890
|
_client = this;
|
|
@@ -98073,7 +98074,7 @@ var pxt;
|
|
|
98073
98074
|
}
|
|
98074
98075
|
return result.success;
|
|
98075
98076
|
}
|
|
98076
|
-
async patchUserPreferencesAsync(ops) {
|
|
98077
|
+
async patchUserPreferencesAsync(ops, immediate = false) {
|
|
98077
98078
|
ops = Array.isArray(ops) ? ops : [ops];
|
|
98078
98079
|
if (!ops.length) {
|
|
98079
98080
|
return;
|
|
@@ -98086,10 +98087,15 @@ var pxt;
|
|
|
98086
98087
|
return;
|
|
98087
98088
|
}
|
|
98088
98089
|
// If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
|
|
98090
|
+
// Accumulate the ops and send to cloud in batch.
|
|
98091
|
+
this.prefPatchOps.push(...ops);
|
|
98089
98092
|
clearTimeout(debouncePreferencesChangedTimeout);
|
|
98090
98093
|
const savePrefs = async () => {
|
|
98091
98094
|
debouncePreferencesChangedStarted = 0;
|
|
98092
|
-
|
|
98095
|
+
// Clear queued patch ops before send.
|
|
98096
|
+
const prefPatchOps = this.prefPatchOps;
|
|
98097
|
+
this.prefPatchOps = [];
|
|
98098
|
+
const result = await this.apiAsync('/api/user/preferences', prefPatchOps, 'PATCH');
|
|
98093
98099
|
if (result.success) {
|
|
98094
98100
|
pxt.debug("Updating local user preferences w/ cloud data after result of POST");
|
|
98095
98101
|
// Set user profile from returned value so we stay in-sync
|
|
@@ -98099,14 +98105,19 @@ var pxt;
|
|
|
98099
98105
|
pxt.reportError("identity", "update preferences failed", result);
|
|
98100
98106
|
}
|
|
98101
98107
|
};
|
|
98102
|
-
if (
|
|
98103
|
-
debouncePreferencesChangedStarted = pxt.U.now();
|
|
98104
|
-
}
|
|
98105
|
-
if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
|
|
98108
|
+
if (immediate) {
|
|
98106
98109
|
await savePrefs();
|
|
98107
98110
|
}
|
|
98108
98111
|
else {
|
|
98109
|
-
|
|
98112
|
+
if (!debouncePreferencesChangedStarted) {
|
|
98113
|
+
debouncePreferencesChangedStarted = pxt.U.now();
|
|
98114
|
+
}
|
|
98115
|
+
if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
|
|
98116
|
+
await savePrefs();
|
|
98117
|
+
}
|
|
98118
|
+
else {
|
|
98119
|
+
debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
|
|
98120
|
+
}
|
|
98110
98121
|
}
|
|
98111
98122
|
}
|
|
98112
98123
|
/*protected*/ hasUserId() {
|
|
@@ -98356,6 +98367,17 @@ var pxt;
|
|
|
98356
98367
|
}
|
|
98357
98368
|
}
|
|
98358
98369
|
auth.generateUserProfilePicDataUrl = generateUserProfilePicDataUrl;
|
|
98370
|
+
/**
|
|
98371
|
+
* Checks only the ID and sourceURL
|
|
98372
|
+
*/
|
|
98373
|
+
function badgeEquals(badgeA, badgeB) {
|
|
98374
|
+
return badgeA.id === badgeB.id && badgeA.sourceURL === badgeB.sourceURL;
|
|
98375
|
+
}
|
|
98376
|
+
auth.badgeEquals = badgeEquals;
|
|
98377
|
+
function hasBadge(preferences, badge) {
|
|
98378
|
+
return preferences.badges.some(toCheck => badgeEquals(toCheck, badge));
|
|
98379
|
+
}
|
|
98380
|
+
auth.hasBadge = hasBadge;
|
|
98359
98381
|
})(auth = pxt.auth || (pxt.auth = {}));
|
|
98360
98382
|
})(pxt || (pxt = {}));
|
|
98361
98383
|
// Needs to be in its own file to avoid a circular dependency: util.ts -> main.ts -> util.ts
|
|
@@ -139048,6 +139070,7 @@ var ts;
|
|
|
139048
139070
|
}
|
|
139049
139071
|
service.snippetAddsDefinitions = snippetAddsDefinitions;
|
|
139050
139072
|
function getSnippet(context, fn, decl, python, recursionDepth = 0) {
|
|
139073
|
+
var _a;
|
|
139051
139074
|
// TODO: a lot of this is duplicate logic with blocklyloader.ts:buildBlockFromDef; we should
|
|
139052
139075
|
// unify these approaches
|
|
139053
139076
|
let { apis, takenNames, blocksInfo, screenSize, checker } = context;
|
|
@@ -139080,10 +139103,15 @@ var ts;
|
|
|
139080
139103
|
if (attrs.shim === "TD_ID" && recursionDepth && decl.parameters.length) {
|
|
139081
139104
|
return getParameterDefault(decl.parameters[0]);
|
|
139082
139105
|
}
|
|
139106
|
+
const element = fn;
|
|
139107
|
+
const params = pxt.blocks.compileInfo(element);
|
|
139083
139108
|
const blocksById = blocksInfo.blocksById;
|
|
139084
139109
|
// TODO: move out of getSnippet for general reuse
|
|
139110
|
+
const blockParameters = ((_a = attrs._def) === null || _a === void 0 ? void 0 : _a.parameters.filter(param => !!params.definitionNameToParam[param.name]).map(param => params.definitionNameToParam[param.name].actualName)) || [];
|
|
139085
139111
|
const includedParameters = decl.parameters ? decl.parameters
|
|
139086
|
-
|
|
139112
|
+
// Only keep required parameters and parameters included in the blockdef
|
|
139113
|
+
.filter(param => (!param.initializer && !param.questionToken)
|
|
139114
|
+
|| (blockParameters.indexOf(param.name.getText()) >= 0)) : [];
|
|
139087
139115
|
const args = includedParameters
|
|
139088
139116
|
.map(getParameterDefault)
|
|
139089
139117
|
.map(p =>
|
|
@@ -139093,7 +139121,6 @@ var ts;
|
|
|
139093
139121
|
default: p,
|
|
139094
139122
|
isLiteral: true
|
|
139095
139123
|
}));
|
|
139096
|
-
const element = fn;
|
|
139097
139124
|
if (element.attributes.block) {
|
|
139098
139125
|
if (element.attributes.defaultInstance) {
|
|
139099
139126
|
snippetPrefix = element.attributes.defaultInstance;
|
|
@@ -139141,7 +139168,6 @@ var ts;
|
|
|
139141
139168
|
isInstance = true;
|
|
139142
139169
|
}
|
|
139143
139170
|
else if (element.kind == 1 /* Method */ || element.kind == 2 /* Property */) {
|
|
139144
|
-
const params = pxt.blocks.compileInfo(element);
|
|
139145
139171
|
if (params.thisParameter) {
|
|
139146
139172
|
let varName = undefined;
|
|
139147
139173
|
if (params.thisParameter.definitionName) {
|
|
@@ -157637,7 +157663,9 @@ function buildSemanticUIAsync(parsed) {
|
|
|
157637
157663
|
// Append icons.css to semantic.css (custom pxt icons)
|
|
157638
157664
|
const iconsFile = (pkg["name"] == "pxt-core") ? 'built/web/icons.css' : 'node_modules/pxt-core/built/web/icons.css';
|
|
157639
157665
|
const iconsCss = fs.readFileSync(iconsFile, "utf-8");
|
|
157640
|
-
|
|
157666
|
+
const reactCommonFile = (pkg["name"] == "pxt-core") ? 'built/web/react-common.css' : 'node_modules/pxt-core/built/web/react-common.css';
|
|
157667
|
+
const reactCommonCss = fs.readFileSync(reactCommonFile, "utf-8");
|
|
157668
|
+
semCss = semCss + "\n" + iconsCss + "\n" + reactCommonCss;
|
|
157641
157669
|
nodeutil.writeFileSync('built/web/semantic.css', semCss);
|
|
157642
157670
|
}).then(() => {
|
|
157643
157671
|
// generate blockly css
|
|
@@ -157705,6 +157733,7 @@ function buildSkillMapAsync(parsed) {
|
|
|
157705
157733
|
nodeutil.cp("node_modules/pxt-core/built/pxtlib.js", `${skillmapRoot}/public/blb`);
|
|
157706
157734
|
nodeutil.cp("built/web/semantic.css", `${skillmapRoot}/public/blb`);
|
|
157707
157735
|
nodeutil.cp("node_modules/pxt-core/built/web/icons.css", `${skillmapRoot}/public/blb`);
|
|
157736
|
+
nodeutil.cp("node_modules/pxt-core/built/web/react-common.css", `${skillmapRoot}/public/blb`);
|
|
157708
157737
|
// copy 'assets' over from docs/static
|
|
157709
157738
|
nodeutil.cpR("docs/static/skillmap/assets", `${skillmapRoot}/public/assets`);
|
|
157710
157739
|
if (docsPath) {
|
package/built/pxtcompiler.js
CHANGED
|
@@ -18255,6 +18255,7 @@ var ts;
|
|
|
18255
18255
|
}
|
|
18256
18256
|
service.snippetAddsDefinitions = snippetAddsDefinitions;
|
|
18257
18257
|
function getSnippet(context, fn, decl, python, recursionDepth = 0) {
|
|
18258
|
+
var _a;
|
|
18258
18259
|
// TODO: a lot of this is duplicate logic with blocklyloader.ts:buildBlockFromDef; we should
|
|
18259
18260
|
// unify these approaches
|
|
18260
18261
|
let { apis, takenNames, blocksInfo, screenSize, checker } = context;
|
|
@@ -18287,10 +18288,15 @@ var ts;
|
|
|
18287
18288
|
if (attrs.shim === "TD_ID" && recursionDepth && decl.parameters.length) {
|
|
18288
18289
|
return getParameterDefault(decl.parameters[0]);
|
|
18289
18290
|
}
|
|
18291
|
+
const element = fn;
|
|
18292
|
+
const params = pxt.blocks.compileInfo(element);
|
|
18290
18293
|
const blocksById = blocksInfo.blocksById;
|
|
18291
18294
|
// TODO: move out of getSnippet for general reuse
|
|
18295
|
+
const blockParameters = ((_a = attrs._def) === null || _a === void 0 ? void 0 : _a.parameters.filter(param => !!params.definitionNameToParam[param.name]).map(param => params.definitionNameToParam[param.name].actualName)) || [];
|
|
18292
18296
|
const includedParameters = decl.parameters ? decl.parameters
|
|
18293
|
-
|
|
18297
|
+
// Only keep required parameters and parameters included in the blockdef
|
|
18298
|
+
.filter(param => (!param.initializer && !param.questionToken)
|
|
18299
|
+
|| (blockParameters.indexOf(param.name.getText()) >= 0)) : [];
|
|
18294
18300
|
const args = includedParameters
|
|
18295
18301
|
.map(getParameterDefault)
|
|
18296
18302
|
.map(p =>
|
|
@@ -18300,7 +18306,6 @@ var ts;
|
|
|
18300
18306
|
default: p,
|
|
18301
18307
|
isLiteral: true
|
|
18302
18308
|
}));
|
|
18303
|
-
const element = fn;
|
|
18304
18309
|
if (element.attributes.block) {
|
|
18305
18310
|
if (element.attributes.defaultInstance) {
|
|
18306
18311
|
snippetPrefix = element.attributes.defaultInstance;
|
|
@@ -18348,7 +18353,6 @@ var ts;
|
|
|
18348
18353
|
isInstance = true;
|
|
18349
18354
|
}
|
|
18350
18355
|
else if (element.kind == 1 /* Method */ || element.kind == 2 /* Property */) {
|
|
18351
|
-
const params = pxt.blocks.compileInfo(element);
|
|
18352
18356
|
if (params.thisParameter) {
|
|
18353
18357
|
let varName = undefined;
|
|
18354
18358
|
if (params.thisParameter.definitionName) {
|
package/built/pxteditor.d.ts
CHANGED
|
@@ -543,7 +543,7 @@ declare namespace pxt.editor {
|
|
|
543
543
|
message?: string;
|
|
544
544
|
data?: Map<string | number>;
|
|
545
545
|
}
|
|
546
|
-
type EditorMessageTutorialEventRequest = EditorMessageTutorialProgressEventRequest | EditorMessageTutorialCompletedEventRequest | EditorMessageTutorialLoadedEventRequest;
|
|
546
|
+
type EditorMessageTutorialEventRequest = EditorMessageTutorialProgressEventRequest | EditorMessageTutorialCompletedEventRequest | EditorMessageTutorialLoadedEventRequest | EditorMessageTutorialExitEventRequest;
|
|
547
547
|
interface EditorMessageTutorialProgressEventRequest extends EditorMessageRequest {
|
|
548
548
|
action: "tutorialevent";
|
|
549
549
|
tutorialEvent: "progress";
|
package/built/pxtlib.d.ts
CHANGED
|
@@ -54,6 +54,9 @@ declare namespace pxt.auth {
|
|
|
54
54
|
mapProgress: any;
|
|
55
55
|
completedTags: any;
|
|
56
56
|
};
|
|
57
|
+
type UserBadgeState = {
|
|
58
|
+
badges: Badge[];
|
|
59
|
+
};
|
|
57
60
|
/**
|
|
58
61
|
* User preference state that should be synced with the cloud.
|
|
59
62
|
*/
|
|
@@ -62,6 +65,7 @@ declare namespace pxt.auth {
|
|
|
62
65
|
highContrast?: boolean;
|
|
63
66
|
reader?: string;
|
|
64
67
|
skillmap?: UserSkillmapState;
|
|
68
|
+
badges?: UserBadgeState;
|
|
65
69
|
};
|
|
66
70
|
const DEFAULT_USER_PREFERENCES: () => UserPreferences;
|
|
67
71
|
/**
|
|
@@ -120,7 +124,8 @@ declare namespace pxt.auth {
|
|
|
120
124
|
username?: string;
|
|
121
125
|
avatarUrl?: string;
|
|
122
126
|
}): Promise<boolean>;
|
|
123
|
-
|
|
127
|
+
private prefPatchOps;
|
|
128
|
+
patchUserPreferencesAsync(ops: ts.pxtc.jsonPatch.PatchOperation | ts.pxtc.jsonPatch.PatchOperation[], immediate?: boolean): Promise<void>;
|
|
124
129
|
hasUserId(): boolean;
|
|
125
130
|
private fetchUserAsync;
|
|
126
131
|
private setUserProfileAsync;
|
|
@@ -165,6 +170,11 @@ declare namespace pxt.auth {
|
|
|
165
170
|
function userName(user: pxt.auth.UserProfile): string;
|
|
166
171
|
function userInitials(user: pxt.auth.UserProfile): string;
|
|
167
172
|
function generateUserProfilePicDataUrl(profile: pxt.auth.UserProfile): void;
|
|
173
|
+
/**
|
|
174
|
+
* Checks only the ID and sourceURL
|
|
175
|
+
*/
|
|
176
|
+
function badgeEquals(badgeA: pxt.auth.Badge, badgeB: pxt.auth.Badge): boolean;
|
|
177
|
+
function hasBadge(preferences: pxt.auth.UserBadgeState, badge: pxt.auth.Badge): boolean;
|
|
168
178
|
}
|
|
169
179
|
declare namespace pxt {
|
|
170
180
|
interface TelemetryEventOptions {
|
package/built/pxtlib.js
CHANGED
|
@@ -190,14 +190,15 @@ var pxt;
|
|
|
190
190
|
let _client;
|
|
191
191
|
function client() { return _client; }
|
|
192
192
|
auth.client = client;
|
|
193
|
-
const PREFERENCES_DEBOUNCE_MS =
|
|
194
|
-
const PREFERENCES_DEBOUNCE_MAX_MS =
|
|
193
|
+
const PREFERENCES_DEBOUNCE_MS = 1 * 1000;
|
|
194
|
+
const PREFERENCES_DEBOUNCE_MAX_MS = 10 * 1000;
|
|
195
195
|
let debouncePreferencesChangedTimeout = 0;
|
|
196
196
|
let debouncePreferencesChangedStarted = 0;
|
|
197
197
|
class AuthClient {
|
|
198
198
|
constructor() {
|
|
199
199
|
this.initialUserPreferences_ = undefined;
|
|
200
200
|
this.initialAuthCheck_ = undefined;
|
|
201
|
+
this.prefPatchOps = [];
|
|
201
202
|
pxt.Util.assert(!_client);
|
|
202
203
|
// Set global instance.
|
|
203
204
|
_client = this;
|
|
@@ -387,7 +388,7 @@ var pxt;
|
|
|
387
388
|
}
|
|
388
389
|
return result.success;
|
|
389
390
|
}
|
|
390
|
-
async patchUserPreferencesAsync(ops) {
|
|
391
|
+
async patchUserPreferencesAsync(ops, immediate = false) {
|
|
391
392
|
ops = Array.isArray(ops) ? ops : [ops];
|
|
392
393
|
if (!ops.length) {
|
|
393
394
|
return;
|
|
@@ -400,10 +401,15 @@ var pxt;
|
|
|
400
401
|
return;
|
|
401
402
|
}
|
|
402
403
|
// If the user is logged in, save to cloud, but debounce the api call as this can be called frequently from skillmaps
|
|
404
|
+
// Accumulate the ops and send to cloud in batch.
|
|
405
|
+
this.prefPatchOps.push(...ops);
|
|
403
406
|
clearTimeout(debouncePreferencesChangedTimeout);
|
|
404
407
|
const savePrefs = async () => {
|
|
405
408
|
debouncePreferencesChangedStarted = 0;
|
|
406
|
-
|
|
409
|
+
// Clear queued patch ops before send.
|
|
410
|
+
const prefPatchOps = this.prefPatchOps;
|
|
411
|
+
this.prefPatchOps = [];
|
|
412
|
+
const result = await this.apiAsync('/api/user/preferences', prefPatchOps, 'PATCH');
|
|
407
413
|
if (result.success) {
|
|
408
414
|
pxt.debug("Updating local user preferences w/ cloud data after result of POST");
|
|
409
415
|
// Set user profile from returned value so we stay in-sync
|
|
@@ -413,14 +419,19 @@ var pxt;
|
|
|
413
419
|
pxt.reportError("identity", "update preferences failed", result);
|
|
414
420
|
}
|
|
415
421
|
};
|
|
416
|
-
if (
|
|
417
|
-
debouncePreferencesChangedStarted = pxt.U.now();
|
|
418
|
-
}
|
|
419
|
-
if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
|
|
422
|
+
if (immediate) {
|
|
420
423
|
await savePrefs();
|
|
421
424
|
}
|
|
422
425
|
else {
|
|
423
|
-
|
|
426
|
+
if (!debouncePreferencesChangedStarted) {
|
|
427
|
+
debouncePreferencesChangedStarted = pxt.U.now();
|
|
428
|
+
}
|
|
429
|
+
if (PREFERENCES_DEBOUNCE_MAX_MS < pxt.U.now() - debouncePreferencesChangedStarted) {
|
|
430
|
+
await savePrefs();
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
debouncePreferencesChangedTimeout = setTimeout(savePrefs, PREFERENCES_DEBOUNCE_MS);
|
|
434
|
+
}
|
|
424
435
|
}
|
|
425
436
|
}
|
|
426
437
|
/*protected*/ hasUserId() {
|
|
@@ -670,6 +681,17 @@ var pxt;
|
|
|
670
681
|
}
|
|
671
682
|
}
|
|
672
683
|
auth.generateUserProfilePicDataUrl = generateUserProfilePicDataUrl;
|
|
684
|
+
/**
|
|
685
|
+
* Checks only the ID and sourceURL
|
|
686
|
+
*/
|
|
687
|
+
function badgeEquals(badgeA, badgeB) {
|
|
688
|
+
return badgeA.id === badgeB.id && badgeA.sourceURL === badgeB.sourceURL;
|
|
689
|
+
}
|
|
690
|
+
auth.badgeEquals = badgeEquals;
|
|
691
|
+
function hasBadge(preferences, badge) {
|
|
692
|
+
return preferences.badges.some(toCheck => badgeEquals(toCheck, badge));
|
|
693
|
+
}
|
|
694
|
+
auth.hasBadge = hasBadge;
|
|
673
695
|
})(auth = pxt.auth || (pxt.auth = {}));
|
|
674
696
|
})(pxt || (pxt = {}));
|
|
675
697
|
// Needs to be in its own file to avoid a circular dependency: util.ts -> main.ts -> util.ts
|