pxt-core 11.4.25 → 11.4.27
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 -3
- package/built/pxt.js +121 -16
- package/built/pxtblocks/plugins/comments/bubble.d.ts +2 -1
- package/built/pxtblocks/plugins/comments/textinput_bubble.d.ts +2 -5
- package/built/pxtlib.d.ts +11 -2
- package/built/pxtlib.js +53 -0
- package/built/pxtsim.d.ts +11 -0
- package/built/pxtsim.js +64 -13
- package/built/target.js +1 -1
- package/built/targetlight.js +1 -1
- package/built/tests/blocksrunner.js +45 -31
- package/built/tests/blockssetup.js +45 -31
- package/built/web/icons.css +13 -10
- package/built/web/icons.html +1 -0
- package/built/web/main.js +1 -1
- package/built/web/pxtapp.js +1 -1
- package/built/web/pxtasseteditor.js +1 -1
- package/built/web/pxtembed.js +1 -1
- package/built/web/pxtlib.js +1 -1
- package/built/web/pxtsim.js +1 -1
- package/built/web/pxtworker.js +1 -1
- package/built/web/rtlsemantic.css +2 -2
- package/built/web/runnerembed.js +1 -1
- package/built/web/semantic.css +2 -2
- package/localtypings/pxtarget.d.ts +6 -2
- package/localtypings/pxteditor.d.ts +2 -2
- package/localtypings/pxtpackage.d.ts +1 -0
- package/package.json +1 -1
- package/theme/errorList.less +4 -0
- package/theme/toolbox.less +3 -0
package/built/cli.js
CHANGED
|
@@ -1200,8 +1200,9 @@ function uploadCoreAsync(opts) {
|
|
|
1200
1200
|
opts.fileList = U.values(U.toDictionary(opts.fileList, uploadFileName));
|
|
1201
1201
|
// check size
|
|
1202
1202
|
const maxSize = checkFileSize(opts.fileList);
|
|
1203
|
-
|
|
1204
|
-
|
|
1203
|
+
const maxAllowedFileSize = (pxt.appTarget.cloud.maxFileSize || (30000000)); // default to 30Mb
|
|
1204
|
+
if (maxSize > maxAllowedFileSize)
|
|
1205
|
+
U.userError(`file too big for upload: ${maxSize} bytes, max is ${maxAllowedFileSize} bytes`);
|
|
1205
1206
|
pxt.log('');
|
|
1206
1207
|
if (opts.localDir)
|
|
1207
1208
|
return U.promisePoolAsync(15, opts.fileList, uploadFileAsync)
|
|
@@ -5457,7 +5458,7 @@ function internalCheckDocsAsync(compileSnippets, re, fix, pycheck) {
|
|
|
5457
5458
|
let snippets = [];
|
|
5458
5459
|
const maxFileSize = checkFileSize(nodeutil.allFiles("docs", { maxDepth: 10, allowMissing: true, includeDirs: true, ignoredFileMarker: ".ignorelargefiles" }));
|
|
5459
5460
|
if (!pxt.appTarget.ignoreDocsErrors
|
|
5460
|
-
&& maxFileSize > (pxt.appTarget.cloud.maxFileSize || (
|
|
5461
|
+
&& maxFileSize > (pxt.appTarget.cloud.maxFileSize || (30000000)))
|
|
5461
5462
|
U.userError(`files too big in docs folder`);
|
|
5462
5463
|
// scan and fix image links
|
|
5463
5464
|
nodeutil.allFiles("docs", { ignoredFileMarker: ignoredFoldersKey })
|
package/built/pxt.js
CHANGED
|
@@ -100797,6 +100797,26 @@ var ts;
|
|
|
100797
100797
|
}
|
|
100798
100798
|
}
|
|
100799
100799
|
Util.bresenhamLine = bresenhamLine;
|
|
100800
|
+
/**
|
|
100801
|
+
* Check if the specified feature is enabled for the user (based on pxtarget configuration and region).
|
|
100802
|
+
*/
|
|
100803
|
+
function isFeatureEnabled(featureKey) {
|
|
100804
|
+
var _a, _b;
|
|
100805
|
+
const feature = (_b = (_a = pxt.appTarget.appTheme) === null || _a === void 0 ? void 0 : _a.enabledFeatures) === null || _b === void 0 ? void 0 : _b[featureKey];
|
|
100806
|
+
if (!feature)
|
|
100807
|
+
return false;
|
|
100808
|
+
let enabled = true;
|
|
100809
|
+
const regionNormalised = pxt.Cloud.getRegion() ? pxt.Cloud.getRegion().toUpperCase() : undefined;
|
|
100810
|
+
if (feature.includeRegions) {
|
|
100811
|
+
enabled = regionNormalised && feature.includeRegions.some(r => r.toUpperCase() == regionNormalised);
|
|
100812
|
+
}
|
|
100813
|
+
// Include and exclude shouldn't really be used together, but if they are, exclude takes precedence
|
|
100814
|
+
if (enabled && feature.excludeRegions) {
|
|
100815
|
+
enabled = regionNormalised && !feature.excludeRegions.some(r => r.toUpperCase() == regionNormalised);
|
|
100816
|
+
}
|
|
100817
|
+
return enabled;
|
|
100818
|
+
}
|
|
100819
|
+
Util.isFeatureEnabled = isFeatureEnabled;
|
|
100800
100820
|
})(Util = pxtc.Util || (pxtc.Util = {}));
|
|
100801
100821
|
})(pxtc = ts.pxtc || (ts.pxtc = {}));
|
|
100802
100822
|
})(ts || (ts = {}));
|
|
@@ -103969,6 +103989,7 @@ var pxt;
|
|
|
103969
103989
|
const DEV_BACKEND_STAGING = "https://staging.pxt.io";
|
|
103970
103990
|
const DEV_BACKEND_LOCALHOST = "http://localhost:8080";
|
|
103971
103991
|
cloud.DEV_BACKEND = DEV_BACKEND_STAGING;
|
|
103992
|
+
cloud.DEV_REGION = "US";
|
|
103972
103993
|
function devBackendType() {
|
|
103973
103994
|
if (cloud.DEV_BACKEND === DEV_BACKEND_PROD)
|
|
103974
103995
|
return "prod";
|
|
@@ -104043,6 +104064,7 @@ var pxt;
|
|
|
104043
104064
|
WebUSBPairResult[WebUSBPairResult["Failed"] = 0] = "Failed";
|
|
104044
104065
|
WebUSBPairResult[WebUSBPairResult["Success"] = 1] = "Success";
|
|
104045
104066
|
WebUSBPairResult[WebUSBPairResult["UserRejected"] = 2] = "UserRejected";
|
|
104067
|
+
WebUSBPairResult[WebUSBPairResult["DownloadOnly"] = 3] = "DownloadOnly";
|
|
104046
104068
|
})(WebUSBPairResult = commands.WebUSBPairResult || (commands.WebUSBPairResult = {}));
|
|
104047
104069
|
commands.deployCoreAsync = undefined;
|
|
104048
104070
|
commands.deployFallbackAsync = undefined;
|
|
@@ -123044,6 +123066,7 @@ var pxt;
|
|
|
123044
123066
|
Cloud.localToken = "";
|
|
123045
123067
|
let _isOnline = true;
|
|
123046
123068
|
Cloud.onOffline = () => { };
|
|
123069
|
+
let region = undefined;
|
|
123047
123070
|
function offlineError(url) {
|
|
123048
123071
|
let e = new Error(Util.lf("Cannot access {0} while offline", url));
|
|
123049
123072
|
e.isOffline = true;
|
|
@@ -123330,6 +123353,36 @@ var pxt;
|
|
|
123330
123353
|
return undefined;
|
|
123331
123354
|
}
|
|
123332
123355
|
Cloud.parseScriptId = parseScriptId;
|
|
123356
|
+
async function initRegionAsync() {
|
|
123357
|
+
var _a;
|
|
123358
|
+
if (pxt.BrowserUtils.isLocalHost()) {
|
|
123359
|
+
region = pxt.cloud.DEV_REGION;
|
|
123360
|
+
return;
|
|
123361
|
+
}
|
|
123362
|
+
if (region !== undefined || !((_a = pxt.webConfig) === null || _a === void 0 ? void 0 : _a.cdnUrl)) {
|
|
123363
|
+
return;
|
|
123364
|
+
}
|
|
123365
|
+
const url = new URL("geo", pxt.webConfig.cdnUrl).toString();
|
|
123366
|
+
const options = { url };
|
|
123367
|
+
try {
|
|
123368
|
+
const response = await Util.requestAsync(options);
|
|
123369
|
+
if (response.statusCode !== 200) {
|
|
123370
|
+
pxt.error(`Failed to get region: ${response.statusCode}`);
|
|
123371
|
+
}
|
|
123372
|
+
region = response.text.trim();
|
|
123373
|
+
}
|
|
123374
|
+
catch (e) {
|
|
123375
|
+
handleNetworkError(options, e);
|
|
123376
|
+
}
|
|
123377
|
+
}
|
|
123378
|
+
Cloud.initRegionAsync = initRegionAsync;
|
|
123379
|
+
function getRegion() {
|
|
123380
|
+
if (!region) {
|
|
123381
|
+
pxt.error("Accessing region before it is initialized. Call initRegionAsync first.");
|
|
123382
|
+
}
|
|
123383
|
+
return region;
|
|
123384
|
+
}
|
|
123385
|
+
Cloud.getRegion = getRegion;
|
|
123333
123386
|
})(Cloud = pxt.Cloud || (pxt.Cloud = {}));
|
|
123334
123387
|
})(pxt || (pxt = {}));
|
|
123335
123388
|
var ts;
|
|
@@ -154379,6 +154432,7 @@ var pxsim;
|
|
|
154379
154432
|
let isFloat = fmt >= NumberFormat.Float32LE;
|
|
154380
154433
|
return { size, signed, swap, isFloat };
|
|
154381
154434
|
}
|
|
154435
|
+
BufferMethods.fmtInfo = fmtInfo;
|
|
154382
154436
|
function getNumber(buf, fmt, offset) {
|
|
154383
154437
|
typeCheck(buf);
|
|
154384
154438
|
let inf = fmtInfo(fmt);
|
|
@@ -157929,6 +157983,11 @@ var pxsim;
|
|
|
157929
157983
|
return node;
|
|
157930
157984
|
}
|
|
157931
157985
|
class Channel {
|
|
157986
|
+
constructor() {
|
|
157987
|
+
this.gain = context().createGain();
|
|
157988
|
+
this.gain.connect(destination);
|
|
157989
|
+
this.gain.gain.value = 0;
|
|
157990
|
+
}
|
|
157932
157991
|
disconnectNodes() {
|
|
157933
157992
|
if (this.gain)
|
|
157934
157993
|
disconnectVca(this.gain, this.generator);
|
|
@@ -158032,14 +158091,8 @@ var pxsim;
|
|
|
158032
158091
|
let nodes = [];
|
|
158033
158092
|
let nextTime = context().currentTime;
|
|
158034
158093
|
let allScheduled = false;
|
|
158035
|
-
const channel =
|
|
158036
|
-
channel.gain = context().createGain();
|
|
158037
|
-
channel.gain.gain.value = 0;
|
|
158094
|
+
const channel = getChannel();
|
|
158038
158095
|
channel.gain.gain.setValueAtTime(volume, context().currentTime);
|
|
158039
|
-
channel.gain.connect(destination);
|
|
158040
|
-
if (channels.length > 20)
|
|
158041
|
-
channels[0].remove();
|
|
158042
|
-
channels.push(channel);
|
|
158043
158096
|
const checkCancel = () => {
|
|
158044
158097
|
if (isCancelled && isCancelled() || !channel.gain) {
|
|
158045
158098
|
if (resolve)
|
|
@@ -158107,13 +158160,8 @@ var pxsim;
|
|
|
158107
158160
|
AudioContextManager.soundEventCallback === null || AudioContextManager.soundEventCallback === void 0 ? void 0 : AudioContextManager.soundEventCallback("playinstructions", instructions);
|
|
158108
158161
|
let resolved = false;
|
|
158109
158162
|
let ctx = context();
|
|
158110
|
-
let channel =
|
|
158111
|
-
if (channels.length > 20)
|
|
158112
|
-
channels[0].remove();
|
|
158113
|
-
channels.push(channel);
|
|
158114
|
-
channel.gain = ctx.createGain();
|
|
158163
|
+
let channel = getChannel();
|
|
158115
158164
|
channel.gain.gain.value = 1;
|
|
158116
|
-
channel.gain.connect(destination);
|
|
158117
158165
|
const oscillators = {};
|
|
158118
158166
|
const gains = {};
|
|
158119
158167
|
let startTime = ctx.currentTime;
|
|
@@ -158253,6 +158301,62 @@ var pxsim;
|
|
|
158253
158301
|
}
|
|
158254
158302
|
}
|
|
158255
158303
|
AudioContextManager.sendMidiMessage = sendMidiMessage;
|
|
158304
|
+
function startSamplePlayback(sample, format, sampleRange, sampleRate, gain) {
|
|
158305
|
+
let channel;
|
|
158306
|
+
let _resolve;
|
|
158307
|
+
const cancel = () => {
|
|
158308
|
+
if (!channel)
|
|
158309
|
+
return;
|
|
158310
|
+
channel.remove();
|
|
158311
|
+
channel = undefined;
|
|
158312
|
+
_resolve();
|
|
158313
|
+
};
|
|
158314
|
+
const promise = new Promise(resolve => {
|
|
158315
|
+
_resolve = resolve;
|
|
158316
|
+
let playbackRate = 1;
|
|
158317
|
+
// chrome errors out if the sample rate is outside [3000, 768000]
|
|
158318
|
+
if (sampleRate < 3000) {
|
|
158319
|
+
playbackRate = sampleRate / 3000;
|
|
158320
|
+
sampleRate = 3000;
|
|
158321
|
+
}
|
|
158322
|
+
else if (sampleRate > 768000) {
|
|
158323
|
+
playbackRate = sampleRate / 768000;
|
|
158324
|
+
sampleRate = 768000;
|
|
158325
|
+
}
|
|
158326
|
+
const size = pxsim.BufferMethods.fmtInfo(format).size;
|
|
158327
|
+
const buf = context().createBuffer(1, sample.data.length / size, sampleRate);
|
|
158328
|
+
const data = buf.getChannelData(0);
|
|
158329
|
+
for (let i = 0; i < buf.length; i++) {
|
|
158330
|
+
data[i] = (pxsim.BufferMethods.getNumber(sample, format, i * size) / sampleRange) * 2 - 1;
|
|
158331
|
+
}
|
|
158332
|
+
channel = getChannel();
|
|
158333
|
+
const node = context().createBufferSource();
|
|
158334
|
+
;
|
|
158335
|
+
node.playbackRate.value = playbackRate;
|
|
158336
|
+
channel.gain.gain.value = gain;
|
|
158337
|
+
channel.generator = node;
|
|
158338
|
+
channel.generator.buffer = buf;
|
|
158339
|
+
channel.generator.connect(channel.gain);
|
|
158340
|
+
channel.generator.start(0);
|
|
158341
|
+
channel.generator.addEventListener("ended", () => {
|
|
158342
|
+
channel.remove();
|
|
158343
|
+
channel = undefined;
|
|
158344
|
+
resolve();
|
|
158345
|
+
});
|
|
158346
|
+
});
|
|
158347
|
+
return {
|
|
158348
|
+
promise,
|
|
158349
|
+
cancel
|
|
158350
|
+
};
|
|
158351
|
+
}
|
|
158352
|
+
AudioContextManager.startSamplePlayback = startSamplePlayback;
|
|
158353
|
+
function getChannel() {
|
|
158354
|
+
if (channels.length > 20)
|
|
158355
|
+
channels[0].remove();
|
|
158356
|
+
const channel = new Channel();
|
|
158357
|
+
channels.push(channel);
|
|
158358
|
+
return channel;
|
|
158359
|
+
}
|
|
158256
158360
|
})(AudioContextManager = pxsim.AudioContextManager || (pxsim.AudioContextManager = {}));
|
|
158257
158361
|
function isTouchEnabled() {
|
|
158258
158362
|
return typeof window !== "undefined" &&
|
|
@@ -163165,8 +163269,9 @@ function uploadCoreAsync(opts) {
|
|
|
163165
163269
|
opts.fileList = U.values(U.toDictionary(opts.fileList, uploadFileName));
|
|
163166
163270
|
// check size
|
|
163167
163271
|
const maxSize = checkFileSize(opts.fileList);
|
|
163168
|
-
|
|
163169
|
-
|
|
163272
|
+
const maxAllowedFileSize = (pxt.appTarget.cloud.maxFileSize || (30000000)); // default to 30Mb
|
|
163273
|
+
if (maxSize > maxAllowedFileSize)
|
|
163274
|
+
U.userError(`file too big for upload: ${maxSize} bytes, max is ${maxAllowedFileSize} bytes`);
|
|
163170
163275
|
pxt.log('');
|
|
163171
163276
|
if (opts.localDir)
|
|
163172
163277
|
return U.promisePoolAsync(15, opts.fileList, uploadFileAsync)
|
|
@@ -167422,7 +167527,7 @@ function internalCheckDocsAsync(compileSnippets, re, fix, pycheck) {
|
|
|
167422
167527
|
let snippets = [];
|
|
167423
167528
|
const maxFileSize = checkFileSize(nodeutil.allFiles("docs", { maxDepth: 10, allowMissing: true, includeDirs: true, ignoredFileMarker: ".ignorelargefiles" }));
|
|
167424
167529
|
if (!pxt.appTarget.ignoreDocsErrors
|
|
167425
|
-
&& maxFileSize > (pxt.appTarget.cloud.maxFileSize || (
|
|
167530
|
+
&& maxFileSize > (pxt.appTarget.cloud.maxFileSize || (30000000)))
|
|
167426
167531
|
U.userError(`files too big in docs folder`);
|
|
167427
167532
|
// scan and fix image links
|
|
167428
167533
|
nodeutil.allFiles("docs", { ignoredFileMarker: ignoredFoldersKey })
|
|
@@ -38,6 +38,7 @@ export declare abstract class Bubble implements Blockly.IDeletable, Blockly.IBub
|
|
|
38
38
|
/** The position of the left of the bubble realtive to its anchor. */
|
|
39
39
|
private relativeLeft;
|
|
40
40
|
private dragStrategy;
|
|
41
|
+
private focusableElement;
|
|
41
42
|
private topBar;
|
|
42
43
|
protected deleteIcon: SVGImageElement;
|
|
43
44
|
private collapseIcon;
|
|
@@ -51,7 +52,7 @@ export declare abstract class Bubble implements Blockly.IDeletable, Blockly.IBub
|
|
|
51
52
|
* @param ownerRect An optional rect we don't want the bubble to overlap with
|
|
52
53
|
* when automatically positioning.
|
|
53
54
|
*/
|
|
54
|
-
constructor(workspace: Blockly.WorkspaceSvg, anchor: Blockly.utils.Coordinate, ownerRect?: Blockly.utils.Rect);
|
|
55
|
+
constructor(workspace: Blockly.WorkspaceSvg, anchor: Blockly.utils.Coordinate, ownerRect?: Blockly.utils.Rect, overriddenFocusableElement?: SVGElement | HTMLElement);
|
|
55
56
|
/** Dispose of this bubble. */
|
|
56
57
|
dispose(): void;
|
|
57
58
|
/**
|
|
@@ -55,7 +55,8 @@ export declare class TextInputBubble extends Bubble {
|
|
|
55
55
|
/** Adds a change listener to be notified when this bubble's size changes. */
|
|
56
56
|
addSizeChangeListener(listener: () => void): void;
|
|
57
57
|
addPositionChangeListener(listener: () => void): void;
|
|
58
|
-
|
|
58
|
+
private static createTextArea;
|
|
59
|
+
/** Creates and returns the UI container element for this bubble's editor. */
|
|
59
60
|
private createEditor;
|
|
60
61
|
/** Binds events to the text area element. */
|
|
61
62
|
private bindTextAreaEvents;
|
|
@@ -79,10 +80,6 @@ export declare class TextInputBubble extends Bubble {
|
|
|
79
80
|
private onResizePointerUp;
|
|
80
81
|
/** Handles pointer move events on the resize target. */
|
|
81
82
|
private onResizePointerMove;
|
|
82
|
-
/**
|
|
83
|
-
* Handles starting an edit of the text area. Brings the bubble to the front.
|
|
84
|
-
*/
|
|
85
|
-
private onStartEdit;
|
|
86
83
|
/** Handles a text change event for the text area. Calls event listeners. */
|
|
87
84
|
private onTextChange;
|
|
88
85
|
/** Handles a size change event for the text area. Calls event listeners. */
|
package/built/pxtlib.d.ts
CHANGED
|
@@ -496,6 +496,10 @@ declare namespace ts.pxtc.Util {
|
|
|
496
496
|
export function isExperienceSupported(experienceId: string): boolean;
|
|
497
497
|
export function ocvEnabled(): string;
|
|
498
498
|
export function bresenhamLine(x0: number, y0: number, x1: number, y1: number, handler: (x: number, y: number) => void): void;
|
|
499
|
+
/**
|
|
500
|
+
* Check if the specified feature is enabled for the user (based on pxtarget configuration and region).
|
|
501
|
+
*/
|
|
502
|
+
export function isFeatureEnabled(featureKey: string): boolean;
|
|
499
503
|
export {};
|
|
500
504
|
}
|
|
501
505
|
declare namespace ts.pxtc.BrowserImpl {
|
|
@@ -992,6 +996,7 @@ declare namespace pxt.cloud {
|
|
|
992
996
|
const DEV_BACKEND_LOCALHOST = "http://localhost:8080";
|
|
993
997
|
type BackendUrls = typeof DEV_BACKEND_PROD | typeof DEV_BACKEND_STAGING | typeof DEV_BACKEND_LOCALHOST;
|
|
994
998
|
export const DEV_BACKEND: BackendUrls;
|
|
999
|
+
export const DEV_REGION = "US";
|
|
995
1000
|
export function devBackendType(): DevBackendType;
|
|
996
1001
|
export type CloudStatus = "none" | "synced" | "justSynced" | "offline" | "syncing" | "conflict" | "localEdits";
|
|
997
1002
|
export type CloudStatusInfo = {
|
|
@@ -1011,7 +1016,8 @@ declare namespace pxt.commands {
|
|
|
1011
1016
|
enum WebUSBPairResult {
|
|
1012
1017
|
Failed = 0,
|
|
1013
1018
|
Success = 1,
|
|
1014
|
-
UserRejected = 2
|
|
1019
|
+
UserRejected = 2,
|
|
1020
|
+
DownloadOnly = 3
|
|
1015
1021
|
}
|
|
1016
1022
|
interface RecompileOptions {
|
|
1017
1023
|
recompile: boolean;
|
|
@@ -2486,7 +2492,8 @@ declare namespace ts.pxtc.service {
|
|
|
2486
2492
|
}
|
|
2487
2493
|
interface ExtensionMeta {
|
|
2488
2494
|
name: string;
|
|
2489
|
-
|
|
2495
|
+
displayName?: string;
|
|
2496
|
+
fullRepo?: string;
|
|
2490
2497
|
description?: string;
|
|
2491
2498
|
imageUrl?: string;
|
|
2492
2499
|
type?: ExtensionType;
|
|
@@ -3890,6 +3897,8 @@ declare namespace pxt.Cloud {
|
|
|
3890
3897
|
function getServiceUrl(): string;
|
|
3891
3898
|
function getUserId(): string;
|
|
3892
3899
|
function parseScriptId(uri: string): string;
|
|
3900
|
+
function initRegionAsync(): Promise<void>;
|
|
3901
|
+
function getRegion(): string;
|
|
3893
3902
|
interface JsonIdObject {
|
|
3894
3903
|
kind: string;
|
|
3895
3904
|
id: string;
|
package/built/pxtlib.js
CHANGED
|
@@ -3111,6 +3111,26 @@ var ts;
|
|
|
3111
3111
|
}
|
|
3112
3112
|
}
|
|
3113
3113
|
Util.bresenhamLine = bresenhamLine;
|
|
3114
|
+
/**
|
|
3115
|
+
* Check if the specified feature is enabled for the user (based on pxtarget configuration and region).
|
|
3116
|
+
*/
|
|
3117
|
+
function isFeatureEnabled(featureKey) {
|
|
3118
|
+
var _a, _b;
|
|
3119
|
+
const feature = (_b = (_a = pxt.appTarget.appTheme) === null || _a === void 0 ? void 0 : _a.enabledFeatures) === null || _b === void 0 ? void 0 : _b[featureKey];
|
|
3120
|
+
if (!feature)
|
|
3121
|
+
return false;
|
|
3122
|
+
let enabled = true;
|
|
3123
|
+
const regionNormalised = pxt.Cloud.getRegion() ? pxt.Cloud.getRegion().toUpperCase() : undefined;
|
|
3124
|
+
if (feature.includeRegions) {
|
|
3125
|
+
enabled = regionNormalised && feature.includeRegions.some(r => r.toUpperCase() == regionNormalised);
|
|
3126
|
+
}
|
|
3127
|
+
// Include and exclude shouldn't really be used together, but if they are, exclude takes precedence
|
|
3128
|
+
if (enabled && feature.excludeRegions) {
|
|
3129
|
+
enabled = regionNormalised && !feature.excludeRegions.some(r => r.toUpperCase() == regionNormalised);
|
|
3130
|
+
}
|
|
3131
|
+
return enabled;
|
|
3132
|
+
}
|
|
3133
|
+
Util.isFeatureEnabled = isFeatureEnabled;
|
|
3114
3134
|
})(Util = pxtc.Util || (pxtc.Util = {}));
|
|
3115
3135
|
})(pxtc = ts.pxtc || (ts.pxtc = {}));
|
|
3116
3136
|
})(ts || (ts = {}));
|
|
@@ -6283,6 +6303,7 @@ var pxt;
|
|
|
6283
6303
|
const DEV_BACKEND_STAGING = "https://staging.pxt.io";
|
|
6284
6304
|
const DEV_BACKEND_LOCALHOST = "http://localhost:8080";
|
|
6285
6305
|
cloud.DEV_BACKEND = DEV_BACKEND_STAGING;
|
|
6306
|
+
cloud.DEV_REGION = "US";
|
|
6286
6307
|
function devBackendType() {
|
|
6287
6308
|
if (cloud.DEV_BACKEND === DEV_BACKEND_PROD)
|
|
6288
6309
|
return "prod";
|
|
@@ -6357,6 +6378,7 @@ var pxt;
|
|
|
6357
6378
|
WebUSBPairResult[WebUSBPairResult["Failed"] = 0] = "Failed";
|
|
6358
6379
|
WebUSBPairResult[WebUSBPairResult["Success"] = 1] = "Success";
|
|
6359
6380
|
WebUSBPairResult[WebUSBPairResult["UserRejected"] = 2] = "UserRejected";
|
|
6381
|
+
WebUSBPairResult[WebUSBPairResult["DownloadOnly"] = 3] = "DownloadOnly";
|
|
6360
6382
|
})(WebUSBPairResult = commands.WebUSBPairResult || (commands.WebUSBPairResult = {}));
|
|
6361
6383
|
commands.deployCoreAsync = undefined;
|
|
6362
6384
|
commands.deployFallbackAsync = undefined;
|
|
@@ -25358,6 +25380,7 @@ var pxt;
|
|
|
25358
25380
|
Cloud.localToken = "";
|
|
25359
25381
|
let _isOnline = true;
|
|
25360
25382
|
Cloud.onOffline = () => { };
|
|
25383
|
+
let region = undefined;
|
|
25361
25384
|
function offlineError(url) {
|
|
25362
25385
|
let e = new Error(Util.lf("Cannot access {0} while offline", url));
|
|
25363
25386
|
e.isOffline = true;
|
|
@@ -25644,6 +25667,36 @@ var pxt;
|
|
|
25644
25667
|
return undefined;
|
|
25645
25668
|
}
|
|
25646
25669
|
Cloud.parseScriptId = parseScriptId;
|
|
25670
|
+
async function initRegionAsync() {
|
|
25671
|
+
var _a;
|
|
25672
|
+
if (pxt.BrowserUtils.isLocalHost()) {
|
|
25673
|
+
region = pxt.cloud.DEV_REGION;
|
|
25674
|
+
return;
|
|
25675
|
+
}
|
|
25676
|
+
if (region !== undefined || !((_a = pxt.webConfig) === null || _a === void 0 ? void 0 : _a.cdnUrl)) {
|
|
25677
|
+
return;
|
|
25678
|
+
}
|
|
25679
|
+
const url = new URL("geo", pxt.webConfig.cdnUrl).toString();
|
|
25680
|
+
const options = { url };
|
|
25681
|
+
try {
|
|
25682
|
+
const response = await Util.requestAsync(options);
|
|
25683
|
+
if (response.statusCode !== 200) {
|
|
25684
|
+
pxt.error(`Failed to get region: ${response.statusCode}`);
|
|
25685
|
+
}
|
|
25686
|
+
region = response.text.trim();
|
|
25687
|
+
}
|
|
25688
|
+
catch (e) {
|
|
25689
|
+
handleNetworkError(options, e);
|
|
25690
|
+
}
|
|
25691
|
+
}
|
|
25692
|
+
Cloud.initRegionAsync = initRegionAsync;
|
|
25693
|
+
function getRegion() {
|
|
25694
|
+
if (!region) {
|
|
25695
|
+
pxt.error("Accessing region before it is initialized. Call initRegionAsync first.");
|
|
25696
|
+
}
|
|
25697
|
+
return region;
|
|
25698
|
+
}
|
|
25699
|
+
Cloud.getRegion = getRegion;
|
|
25647
25700
|
})(Cloud = pxt.Cloud || (pxt.Cloud = {}));
|
|
25648
25701
|
})(pxt || (pxt = {}));
|
|
25649
25702
|
var ts;
|
package/built/pxtsim.d.ts
CHANGED
|
@@ -1016,6 +1016,12 @@ declare namespace pxsim {
|
|
|
1016
1016
|
Float32BE = 15,
|
|
1017
1017
|
Float64BE = 16
|
|
1018
1018
|
}
|
|
1019
|
+
function fmtInfo(fmt: NumberFormat): {
|
|
1020
|
+
size: number;
|
|
1021
|
+
signed: boolean;
|
|
1022
|
+
swap: boolean;
|
|
1023
|
+
isFloat: boolean;
|
|
1024
|
+
};
|
|
1019
1025
|
function getNumber(buf: RefBuffer, fmt: NumberFormat, offset: number): number;
|
|
1020
1026
|
function setNumber(buf: RefBuffer, fmt: NumberFormat, offset: number, r: number): void;
|
|
1021
1027
|
function createBuffer(size: number): RefBuffer;
|
|
@@ -1595,6 +1601,11 @@ declare namespace pxsim {
|
|
|
1595
1601
|
function playPCMBufferStreamAsync(pull: () => Float32Array, sampleRate: number, volume?: number, isCancelled?: () => boolean): Promise<void>;
|
|
1596
1602
|
function playInstructionsAsync(instructions: Uint8Array, isCancelled?: () => boolean, onPull?: (freq: number, volume: number) => void): Promise<void>;
|
|
1597
1603
|
function sendMidiMessage(buf: RefBuffer): void;
|
|
1604
|
+
interface PlaySampleResult {
|
|
1605
|
+
promise: Promise<void>;
|
|
1606
|
+
cancel: () => void;
|
|
1607
|
+
}
|
|
1608
|
+
function startSamplePlayback(sample: RefBuffer, format: BufferMethods.NumberFormat, sampleRange: number, sampleRate: number, gain: number): PlaySampleResult;
|
|
1598
1609
|
}
|
|
1599
1610
|
interface IPointerEvents {
|
|
1600
1611
|
up: string;
|
package/built/pxtsim.js
CHANGED
|
@@ -4234,6 +4234,7 @@ var pxsim;
|
|
|
4234
4234
|
let isFloat = fmt >= NumberFormat.Float32LE;
|
|
4235
4235
|
return { size, signed, swap, isFloat };
|
|
4236
4236
|
}
|
|
4237
|
+
BufferMethods.fmtInfo = fmtInfo;
|
|
4237
4238
|
function getNumber(buf, fmt, offset) {
|
|
4238
4239
|
typeCheck(buf);
|
|
4239
4240
|
let inf = fmtInfo(fmt);
|
|
@@ -7784,6 +7785,11 @@ var pxsim;
|
|
|
7784
7785
|
return node;
|
|
7785
7786
|
}
|
|
7786
7787
|
class Channel {
|
|
7788
|
+
constructor() {
|
|
7789
|
+
this.gain = context().createGain();
|
|
7790
|
+
this.gain.connect(destination);
|
|
7791
|
+
this.gain.gain.value = 0;
|
|
7792
|
+
}
|
|
7787
7793
|
disconnectNodes() {
|
|
7788
7794
|
if (this.gain)
|
|
7789
7795
|
disconnectVca(this.gain, this.generator);
|
|
@@ -7887,14 +7893,8 @@ var pxsim;
|
|
|
7887
7893
|
let nodes = [];
|
|
7888
7894
|
let nextTime = context().currentTime;
|
|
7889
7895
|
let allScheduled = false;
|
|
7890
|
-
const channel =
|
|
7891
|
-
channel.gain = context().createGain();
|
|
7892
|
-
channel.gain.gain.value = 0;
|
|
7896
|
+
const channel = getChannel();
|
|
7893
7897
|
channel.gain.gain.setValueAtTime(volume, context().currentTime);
|
|
7894
|
-
channel.gain.connect(destination);
|
|
7895
|
-
if (channels.length > 20)
|
|
7896
|
-
channels[0].remove();
|
|
7897
|
-
channels.push(channel);
|
|
7898
7898
|
const checkCancel = () => {
|
|
7899
7899
|
if (isCancelled && isCancelled() || !channel.gain) {
|
|
7900
7900
|
if (resolve)
|
|
@@ -7962,13 +7962,8 @@ var pxsim;
|
|
|
7962
7962
|
AudioContextManager.soundEventCallback === null || AudioContextManager.soundEventCallback === void 0 ? void 0 : AudioContextManager.soundEventCallback("playinstructions", instructions);
|
|
7963
7963
|
let resolved = false;
|
|
7964
7964
|
let ctx = context();
|
|
7965
|
-
let channel =
|
|
7966
|
-
if (channels.length > 20)
|
|
7967
|
-
channels[0].remove();
|
|
7968
|
-
channels.push(channel);
|
|
7969
|
-
channel.gain = ctx.createGain();
|
|
7965
|
+
let channel = getChannel();
|
|
7970
7966
|
channel.gain.gain.value = 1;
|
|
7971
|
-
channel.gain.connect(destination);
|
|
7972
7967
|
const oscillators = {};
|
|
7973
7968
|
const gains = {};
|
|
7974
7969
|
let startTime = ctx.currentTime;
|
|
@@ -8108,6 +8103,62 @@ var pxsim;
|
|
|
8108
8103
|
}
|
|
8109
8104
|
}
|
|
8110
8105
|
AudioContextManager.sendMidiMessage = sendMidiMessage;
|
|
8106
|
+
function startSamplePlayback(sample, format, sampleRange, sampleRate, gain) {
|
|
8107
|
+
let channel;
|
|
8108
|
+
let _resolve;
|
|
8109
|
+
const cancel = () => {
|
|
8110
|
+
if (!channel)
|
|
8111
|
+
return;
|
|
8112
|
+
channel.remove();
|
|
8113
|
+
channel = undefined;
|
|
8114
|
+
_resolve();
|
|
8115
|
+
};
|
|
8116
|
+
const promise = new Promise(resolve => {
|
|
8117
|
+
_resolve = resolve;
|
|
8118
|
+
let playbackRate = 1;
|
|
8119
|
+
// chrome errors out if the sample rate is outside [3000, 768000]
|
|
8120
|
+
if (sampleRate < 3000) {
|
|
8121
|
+
playbackRate = sampleRate / 3000;
|
|
8122
|
+
sampleRate = 3000;
|
|
8123
|
+
}
|
|
8124
|
+
else if (sampleRate > 768000) {
|
|
8125
|
+
playbackRate = sampleRate / 768000;
|
|
8126
|
+
sampleRate = 768000;
|
|
8127
|
+
}
|
|
8128
|
+
const size = pxsim.BufferMethods.fmtInfo(format).size;
|
|
8129
|
+
const buf = context().createBuffer(1, sample.data.length / size, sampleRate);
|
|
8130
|
+
const data = buf.getChannelData(0);
|
|
8131
|
+
for (let i = 0; i < buf.length; i++) {
|
|
8132
|
+
data[i] = (pxsim.BufferMethods.getNumber(sample, format, i * size) / sampleRange) * 2 - 1;
|
|
8133
|
+
}
|
|
8134
|
+
channel = getChannel();
|
|
8135
|
+
const node = context().createBufferSource();
|
|
8136
|
+
;
|
|
8137
|
+
node.playbackRate.value = playbackRate;
|
|
8138
|
+
channel.gain.gain.value = gain;
|
|
8139
|
+
channel.generator = node;
|
|
8140
|
+
channel.generator.buffer = buf;
|
|
8141
|
+
channel.generator.connect(channel.gain);
|
|
8142
|
+
channel.generator.start(0);
|
|
8143
|
+
channel.generator.addEventListener("ended", () => {
|
|
8144
|
+
channel.remove();
|
|
8145
|
+
channel = undefined;
|
|
8146
|
+
resolve();
|
|
8147
|
+
});
|
|
8148
|
+
});
|
|
8149
|
+
return {
|
|
8150
|
+
promise,
|
|
8151
|
+
cancel
|
|
8152
|
+
};
|
|
8153
|
+
}
|
|
8154
|
+
AudioContextManager.startSamplePlayback = startSamplePlayback;
|
|
8155
|
+
function getChannel() {
|
|
8156
|
+
if (channels.length > 20)
|
|
8157
|
+
channels[0].remove();
|
|
8158
|
+
const channel = new Channel();
|
|
8159
|
+
channels.push(channel);
|
|
8160
|
+
return channel;
|
|
8161
|
+
}
|
|
8111
8162
|
})(AudioContextManager = pxsim.AudioContextManager || (pxsim.AudioContextManager = {}));
|
|
8112
8163
|
function isTouchEnabled() {
|
|
8113
8164
|
return typeof window !== "undefined" &&
|