From 5384ec567d86b7bc789011a57f2cfff54513b9cc Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Fri, 13 Apr 2018 21:46:19 -0700 Subject: [PATCH] split editors (#516) * spliteditor --- editor/extension.ts | 129 -------- fieldeditors/extension.ts | 145 +++++++++ .../field_brickbuttons.ts | 0 {editor => fieldeditors}/field_color.ts | 0 {editor => fieldeditors}/field_motors.ts | 2 +- {editor => fieldeditors}/field_ports.ts | 0 {editor => fieldeditors}/field_speed.ts | 0 {editor => fieldeditors}/field_turnratio.ts | 0 fieldeditors/tsconfig.json | 14 + fieldeditors/wrap.ts | 285 ++++++++++++++++++ package-lock.json | 50 +-- package.json | 2 +- pxtarget.json | 1 + 13 files changed, 479 insertions(+), 149 deletions(-) create mode 100644 fieldeditors/extension.ts rename {editor => fieldeditors}/field_brickbuttons.ts (100%) rename {editor => fieldeditors}/field_color.ts (100%) rename {editor => fieldeditors}/field_motors.ts (99%) rename {editor => fieldeditors}/field_ports.ts (100%) rename {editor => fieldeditors}/field_speed.ts (100%) rename {editor => fieldeditors}/field_turnratio.ts (100%) create mode 100644 fieldeditors/tsconfig.json create mode 100644 fieldeditors/wrap.ts diff --git a/editor/extension.ts b/editor/extension.ts index 62ca5ce9..d5c589da 100644 --- a/editor/extension.ts +++ b/editor/extension.ts @@ -2,36 +2,10 @@ /// import { deployCoreAsync, initAsync } from "./deploy"; -import { FieldPorts } from "./field_ports"; -import { FieldMotors } from "./field_motors"; -import { FieldSpeed } from "./field_speed"; -import { FieldBrickButtons } from "./field_brickbuttons"; -import { FieldTurnRatio } from "./field_turnratio"; -import { FieldColorEnum } from "./field_color"; pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { pxt.debug('loading pxt-ev3 target extensions...') - updateBlocklyShape(); const res: pxt.editor.ExtensionResult = { - fieldEditors: [{ - selector: "ports", - editor: FieldPorts - }, { - selector: "motors", - editor: FieldMotors - }, { - selector: "speed", - editor: FieldSpeed - }, { - selector: "brickbuttons", - editor: FieldBrickButtons - }, { - selector: "turnratio", - editor: FieldTurnRatio - }, { - selector: "colorenum", - editor: FieldColorEnum - }], deployCoreAsync, showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise) => { let resolve: (thenableOrResult?: void | PromiseLike) => void; @@ -115,109 +89,6 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P return Promise.resolve(res); } -/** - * Update the shape of Blockly blocks with square corners - */ -function updateBlocklyShape() { - - /** - * Rounded corner radius. - * @const - */ - (Blockly.BlockSvg as any).CORNER_RADIUS = 0 * (Blockly.BlockSvg as any).GRID_UNIT; - - /** - * Inner space between edge of statement input and notch. - * @const - */ - (Blockly.BlockSvg as any).STATEMENT_INPUT_INNER_SPACE = 3 * (Blockly.BlockSvg as any).GRID_UNIT; - /** - * SVG path for drawing next/previous notch from left to right. - * @const - */ - (Blockly.BlockSvg as any).NOTCH_PATH_LEFT = ( - 'l 8,8 ' + - 'h 16 ' + - 'l 8,-8 ' - ); - - /** - * SVG path for drawing next/previous notch from right to left. - * @const - */ - (Blockly.BlockSvg as any).NOTCH_PATH_RIGHT = ( - 'l -8,8 ' + - 'h -16 ' + - 'l -8,-8 ' - ); - - /** - * SVG start point for drawing the top-left corner. - * @const - */ - (Blockly.BlockSvg as any).TOP_LEFT_CORNER_START = - 'm 0,' + 0; - - /** - * SVG path for drawing the rounded top-left corner. - * @const - */ - (Blockly.BlockSvg as any).TOP_LEFT_CORNER = - 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0 '; - - /** - * SVG path for drawing the rounded top-right corner. - * @const - */ - (Blockly.BlockSvg as any).TOP_RIGHT_CORNER = - 'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS; - - /** - * SVG path for drawing the rounded bottom-right corner. - * @const - */ - (Blockly.BlockSvg as any).BOTTOM_RIGHT_CORNER = - 'l 0,' + (Blockly.BlockSvg as any).CORNER_RADIUS; - - /** - * SVG path for drawing the rounded bottom-left corner. - * @const - */ - (Blockly.BlockSvg as any).BOTTOM_LEFT_CORNER = - 'l -' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0'; - - /** - * SVG path for drawing the top-left corner of a statement input. - * @const - */ - (Blockly.BlockSvg as any).INNER_TOP_LEFT_CORNER = - 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',-' + 0; - - /** - * SVG path for drawing the bottom-left corner of a statement input. - * Includes the rounded inside corner. - * @const - */ - (Blockly.BlockSvg as any).INNER_BOTTOM_LEFT_CORNER = - 'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS * 2 + - 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',' + 0; - - /** - * Corner radius of the flyout background. - * @type {number} - * @const - */ - (Blockly as any).Flyout.prototype.CORNER_RADIUS = 0; - - /** - * Margin around the edges of the blocks in the flyout. - * @type {number} - * @const - */ - (Blockly as any).Flyout.prototype.MARGIN = 8; - -} - // When require()d from node, bind the global pxt namespace // namespace pxt { // export const dummyExport = 1; diff --git a/fieldeditors/extension.ts b/fieldeditors/extension.ts new file mode 100644 index 00000000..8e854911 --- /dev/null +++ b/fieldeditors/extension.ts @@ -0,0 +1,145 @@ +/// +/// + +import { FieldPorts } from "./field_ports"; +import { FieldMotors } from "./field_motors"; +import { FieldSpeed } from "./field_speed"; +import { FieldBrickButtons } from "./field_brickbuttons"; +import { FieldTurnRatio } from "./field_turnratio"; +import { FieldColorEnum } from "./field_color"; + +pxt.editor.initFieldExtensionsAsync = function (opts: pxt.editor.FieldExtensionOptions): Promise { + pxt.debug('loading pxt-ev3 target extensions...') + updateBlocklyShape(); + const res: pxt.editor.FieldExtensionResult = { + fieldEditors: [{ + selector: "ports", + editor: FieldPorts + }, { + selector: "motors", + editor: FieldMotors + }, { + selector: "speed", + editor: FieldSpeed + }, { + selector: "brickbuttons", + editor: FieldBrickButtons + }, { + selector: "turnratio", + editor: FieldTurnRatio + }, { + selector: "colorenum", + editor: FieldColorEnum + }] + }; + return Promise.resolve(res); +} + +/** + * Update the shape of Blockly blocks with square corners + */ +function updateBlocklyShape() { + + /** + * Rounded corner radius. + * @const + */ + (Blockly.BlockSvg as any).CORNER_RADIUS = 0 * (Blockly.BlockSvg as any).GRID_UNIT; + + /** + * Inner space between edge of statement input and notch. + * @const + */ + (Blockly.BlockSvg as any).STATEMENT_INPUT_INNER_SPACE = 3 * (Blockly.BlockSvg as any).GRID_UNIT; + /** + * SVG path for drawing next/previous notch from left to right. + * @const + */ + (Blockly.BlockSvg as any).NOTCH_PATH_LEFT = ( + 'l 8,8 ' + + 'h 16 ' + + 'l 8,-8 ' + ); + + /** + * SVG path for drawing next/previous notch from right to left. + * @const + */ + (Blockly.BlockSvg as any).NOTCH_PATH_RIGHT = ( + 'l -8,8 ' + + 'h -16 ' + + 'l -8,-8 ' + ); + + /** + * SVG start point for drawing the top-left corner. + * @const + */ + (Blockly.BlockSvg as any).TOP_LEFT_CORNER_START = + 'm 0,' + 0; + + /** + * SVG path for drawing the rounded top-left corner. + * @const + */ + (Blockly.BlockSvg as any).TOP_LEFT_CORNER = + 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0 '; + + /** + * SVG path for drawing the rounded top-right corner. + * @const + */ + (Blockly.BlockSvg as any).TOP_RIGHT_CORNER = + 'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS; + + /** + * SVG path for drawing the rounded bottom-right corner. + * @const + */ + (Blockly.BlockSvg as any).BOTTOM_RIGHT_CORNER = + 'l 0,' + (Blockly.BlockSvg as any).CORNER_RADIUS; + + /** + * SVG path for drawing the rounded bottom-left corner. + * @const + */ + (Blockly.BlockSvg as any).BOTTOM_LEFT_CORNER = + 'l -' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0'; + + /** + * SVG path for drawing the top-left corner of a statement input. + * @const + */ + (Blockly.BlockSvg as any).INNER_TOP_LEFT_CORNER = + 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',-' + 0; + + /** + * SVG path for drawing the bottom-left corner of a statement input. + * Includes the rounded inside corner. + * @const + */ + (Blockly.BlockSvg as any).INNER_BOTTOM_LEFT_CORNER = + 'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS * 2 + + 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',' + 0; + + /** + * Corner radius of the flyout background. + * @type {number} + * @const + */ + (Blockly as any).Flyout.prototype.CORNER_RADIUS = 0; + + /** + * Margin around the edges of the blocks in the flyout. + * @type {number} + * @const + */ + (Blockly as any).Flyout.prototype.MARGIN = 8; + +} + +// When require()d from node, bind the global pxt namespace +// namespace pxt { +// export const dummyExport = 1; +// } +// eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt") diff --git a/editor/field_brickbuttons.ts b/fieldeditors/field_brickbuttons.ts similarity index 100% rename from editor/field_brickbuttons.ts rename to fieldeditors/field_brickbuttons.ts diff --git a/editor/field_color.ts b/fieldeditors/field_color.ts similarity index 100% rename from editor/field_color.ts rename to fieldeditors/field_color.ts diff --git a/editor/field_motors.ts b/fieldeditors/field_motors.ts similarity index 99% rename from editor/field_motors.ts rename to fieldeditors/field_motors.ts index 4ae0779e..6c438531 100644 --- a/editor/field_motors.ts +++ b/fieldeditors/field_motors.ts @@ -30,7 +30,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC this.itemWidth_ = 75; this.backgroundColour_ = pxtblockly.parseColour(options.colour); this.itemColour_ = "rgba(255, 255, 255, 0.6)"; - this.borderColour_ = Blockly.PXTUtils.fadeColour(this.backgroundColour_, 0.4, false); + this.borderColour_ = pxt.toolbox.fadeColor(this.backgroundColour_, 0.4, false); } init() { diff --git a/editor/field_ports.ts b/fieldeditors/field_ports.ts similarity index 100% rename from editor/field_ports.ts rename to fieldeditors/field_ports.ts diff --git a/editor/field_speed.ts b/fieldeditors/field_speed.ts similarity index 100% rename from editor/field_speed.ts rename to fieldeditors/field_speed.ts diff --git a/editor/field_turnratio.ts b/fieldeditors/field_turnratio.ts similarity index 100% rename from editor/field_turnratio.ts rename to fieldeditors/field_turnratio.ts diff --git a/fieldeditors/tsconfig.json b/fieldeditors/tsconfig.json new file mode 100644 index 00000000..9f5342cb --- /dev/null +++ b/fieldeditors/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es5", + "noImplicitAny": false, + "noImplicitReturns": true, + "module": "commonjs", + "outDir": "../built/fieldeditors", + "rootDir": ".", + "newLine": "LF", + "sourceMap": false, + "allowSyntheticDefaultImports": true, + "declaration": true + } +} \ No newline at end of file diff --git a/fieldeditors/wrap.ts b/fieldeditors/wrap.ts new file mode 100644 index 00000000..d27f6bf1 --- /dev/null +++ b/fieldeditors/wrap.ts @@ -0,0 +1,285 @@ +namespace pxt.editor { + import HF2 = pxt.HF2 + import U = pxt.U + + function log(msg: string) { + pxt.log("EWRAP: " + msg) + } + + export interface DirEntry { + name: string; + md5?: string; + size?: number; + } + + const runTemplate = "C00882010084XX0060640301606400" + const usbMagic = 0x3d3f + + export class Ev3Wrapper { + msgs = new U.PromiseBuffer() + private cmdSeq = U.randomUint32() & 0xffff; + private lock = new U.PromiseQueue(); + isStreaming = false; + dataDump = false; + + constructor(public io: pxt.HF2.PacketIO) { + io.onData = buf => { + buf = buf.slice(0, HF2.read16(buf, 0) + 2) + if (HF2.read16(buf, 4) == usbMagic) { + let code = HF2.read16(buf, 6) + let payload = buf.slice(8) + if (code == 1) { + let str = U.uint8ArrayToString(payload) + if (Util.isNodeJS) + console.log("SERIAL: " + str.replace(/\n+$/, "")) + else + window.postMessage({ + type: 'serial', + id: 'n/a', // TODO? + data: str + }, "*") + } else + console.log("Magic: " + code + ": " + U.toHex(payload)) + return + } + if (this.dataDump) + log("RECV: " + U.toHex(buf)) + this.msgs.push(buf) + } + } + + private allocCore(addSize: number, replyType: number) { + let len = 5 + addSize + let buf = new Uint8Array(len) + HF2.write16(buf, 0, len - 2) // pktLen + HF2.write16(buf, 2, this.cmdSeq++) // msgCount + buf[4] = replyType + return buf + } + + private allocSystem(addSize: number, cmd: number, replyType = 1) { + let buf = this.allocCore(addSize + 1, replyType) + buf[5] = cmd + return buf + } + + private allocCustom(code: number, addSize = 0) { + let buf = this.allocCore(1 + 2 + addSize, 0) + HF2.write16(buf, 4, usbMagic) + HF2.write16(buf, 6, code) + return buf + } + + stopAsync() { + return this.isVmAsync() + .then(vm => { + if (vm) return Promise.resolve(); + log(`stopping PXT app`) + let buf = this.allocCustom(2) + return this.justSendAsync(buf) + .then(() => Promise.delay(500)) + }) + } + + dmesgAsync() { + log(`asking for DMESG buffer over serial`) + let buf = this.allocCustom(3) + return this.justSendAsync(buf) + } + + runAsync(path: string) { + let codeHex = runTemplate.replace("XX", U.toHex(U.stringToUint8Array(path))) + let code = U.fromHex(codeHex) + let pkt = this.allocCore(2 + code.length, 0) + HF2.write16(pkt, 5, 0x0800) + U.memcpy(pkt, 7, code) + log(`run ${path}`) + return this.justSendAsync(pkt) + } + + justSendAsync(buf: Uint8Array) { + return this.lock.enqueue("talk", () => { + this.msgs.drain() + if (this.dataDump) + log("SEND: " + U.toHex(buf)) + return this.io.sendPacketAsync(buf) + }) + } + + talkAsync(buf: Uint8Array, altResponse = 0) { + return this.lock.enqueue("talk", () => { + this.msgs.drain() + if (this.dataDump) + log("TALK: " + U.toHex(buf)) + return this.io.sendPacketAsync(buf) + .then(() => this.msgs.shiftAsync(1000)) + .then(resp => { + if (resp[2] != buf[2] || resp[3] != buf[3]) + U.userError("msg count de-sync") + if (buf[4] == 1) { + if (altResponse != -1 && resp[5] != buf[5]) + U.userError("cmd de-sync") + if (altResponse != -1 && resp[6] != 0 && resp[6] != altResponse) + U.userError("cmd error: " + resp[6]) + } + return resp + }) + }) + } + + flashAsync(path: string, file: Uint8Array) { + log(`write ${file.length} bytes to ${path}`) + + let handle = -1 + + let loopAsync = (pos: number): Promise => { + if (pos >= file.length) return Promise.resolve() + let size = file.length - pos + if (size > 1000) size = 1000 + let upl = this.allocSystem(1 + size, 0x93, 0x1) + upl[6] = handle + U.memcpy(upl, 6 + 1, file, pos, size) + return this.talkAsync(upl, 8) // 8=EOF + .then(() => loopAsync(pos + size)) + } + + let begin = this.allocSystem(4 + path.length + 1, 0x92) + HF2.write32(begin, 6, file.length) // fileSize + U.memcpy(begin, 10, U.stringToUint8Array(path)) + return this.lock.enqueue("file", () => + this.talkAsync(begin) + .then(resp => { + handle = resp[7] + return loopAsync(0) + })) + } + + lsAsync(path: string): Promise { + let lsReq = this.allocSystem(2 + path.length + 1, 0x99) + HF2.write16(lsReq, 6, 1024) // maxRead + U.memcpy(lsReq, 8, U.stringToUint8Array(path)) + + return this.talkAsync(lsReq, 8) + .then(resp => + U.uint8ArrayToString(resp.slice(12)).split(/\n/).map(s => { + if (!s) return null as DirEntry + let m = /^([A-F0-9]+) ([A-F0-9]+) ([^\/]*)$/.exec(s) + if (m) + return { + md5: m[1], + size: parseInt(m[2], 16), + name: m[3] + } + else + return { + name: s.replace(/\/$/, "") + } + }).filter(v => !!v)) + } + + rmAsync(path: string): Promise { + log(`rm ${path}`) + let rmReq = this.allocSystem(path.length + 1, 0x9c) + U.memcpy(rmReq, 6, U.stringToUint8Array(path)) + + return this.talkAsync(rmReq, 5) + .then(resp => { }) + } + + isVmAsync(): Promise { + let path = "/no/such/dir" + let mkdirReq = this.allocSystem(path.length + 1, 0x9b) + U.memcpy(mkdirReq, 6, U.stringToUint8Array(path)) + return this.talkAsync(mkdirReq, -1) + .then(resp => { + let isVM = resp[6] == 0x05 + log(`${isVM ? "PXT app" : "VM"} running`) + return isVM + }) + } + + private streamFileOnceAsync(path: string, cb: (d: Uint8Array) => void) { + let fileSize = 0 + let filePtr = 0 + let handle = -1 + let resp = (buf: Uint8Array): Promise => { + if (buf[6] == 2) { + // handle not ready - file is missing + this.isStreaming = false + return Promise.resolve() + } + + if (buf[6] != 0 && buf[6] != 8) + U.userError("bad response when streaming file: " + buf[6] + " " + U.toHex(buf)) + + this.isStreaming = true + fileSize = HF2.read32(buf, 7) + if (handle == -1) { + handle = buf[11] + log(`stream on, handle=${handle}`) + } + let data = buf.slice(12) + filePtr += data.length + if (data.length > 0) + cb(data) + + if (buf[6] == 8) { + // end of file + this.isStreaming = false + return this.rmAsync(path) + } + + let contFileReq = this.allocSystem(1 + 2, 0x97) + HF2.write16(contFileReq, 7, 1000) // maxRead + contFileReq[6] = handle + return Promise.delay(data.length > 0 ? 0 : 500) + .then(() => this.talkAsync(contFileReq, -1)) + .then(resp) + } + + let getFileReq = this.allocSystem(2 + path.length + 1, 0x96) + HF2.write16(getFileReq, 6, 1000) // maxRead + U.memcpy(getFileReq, 8, U.stringToUint8Array(path)) + return this.talkAsync(getFileReq, -1).then(resp) + } + + streamFileAsync(path: string, cb: (d: Uint8Array) => void) { + let loop = (): Promise => + this.lock.enqueue("file", () => + this.streamFileOnceAsync(path, cb)) + .then(() => Promise.delay(500)) + .then(loop) + return loop() + } + + + downloadFileAsync(path: string, cb: (d: Uint8Array) => void) { + return this.lock.enqueue("file", () => + this.streamFileOnceAsync(path, cb)) + } + + + private initAsync() { + return Promise.resolve() + } + + private resetState() { + + } + + reconnectAsync(first = false): Promise { + this.resetState() + if (first) return this.initAsync() + log(`reconnect`); + return this.io.reconnectAsync() + .then(() => this.initAsync()) + } + + disconnectAsync() { + log(`disconnect`); + return this.io.disconnectAsync() + } + } + + +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f67aa327..0e43ebec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1977,15 +1977,6 @@ "verror": "1.10.0" } }, - "keytar": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-3.0.2.tgz", - "integrity": "sha1-TcFd01I/4wYx+dOIV4pAFRpgWG8=", - "optional": true, - "requires": { - "nan": "2.3.2" - } - }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -2437,7 +2428,8 @@ "nan": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.2.tgz", - "integrity": "sha1-TU7PF+HaTpie+08nPY0AIBytCH4=" + "integrity": "sha1-TU7PF+HaTpie+08nPY0AIBytCH4=", + "dev": true }, "neatequal": { "version": "1.0.0", @@ -2748,6 +2740,11 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "pngjs": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.3.2.tgz", + "integrity": "sha512-bVNd3LMXRzdo6s4ehr4XW2wFMu9cb40nPgHEjSSppm8/++Xc+g0b2QQb+SeDesgfANXbjydOr1or9YQ+pcCZPQ==" + }, "pointer-symbol": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", @@ -3274,19 +3271,19 @@ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "pxt-common-packages": { - "version": "0.20.14", - "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-0.20.14.tgz", - "integrity": "sha512-DlZIDfDSH5jGq5K4k+9QtALzcedT+lYBNnxUWrbAK/GOxkqXZxhwGGvi1O2p6eFOfCWBuH0kjBlui3dzxeF0LA==", + "version": "0.20.38", + "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-0.20.38.tgz", + "integrity": "sha512-jtJrd9XwX9T/bOC/9uZyPB4SdvDfhxbnl8c8Gzyy+HiGbW1SMcABgTevJFpLli/ifszl+R+9ZLspFGle84jXkA==", "requires": { "autoprefixer": "6.7.7", - "pxt-core": "3.5.11", + "pxt-core": "3.8.13", "rtlcss": "2.2.1" } }, "pxt-core": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-3.5.11.tgz", - "integrity": "sha512-niFvx2PbvWqNPikB0uyR22Pnsc7ipOfWsB656KvnenK4lRNUMEFcxUg4B+65+NZZQypEHk5OxsD3nbE62749EA==", + "version": "3.8.13", + "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-3.8.13.tgz", + "integrity": "sha512-F7+P5X/TB6SXtXIkEujHccAxcbMCAKyUqT/VgaQBi2vRo3YdH1IswsMSgXDKG0H12sWOVL297TLdQSiBOuIvXA==", "requires": { "bluebird": "3.5.1", "browserify": "13.3.0", @@ -3294,10 +3291,11 @@ "faye-websocket": "0.11.1", "fuse.js": "2.6.1", "highlight.js": "9.12.0", - "keytar": "3.0.2", + "keytar": "4.2.1", "lzma": "2.3.2", "marked": "0.3.12", "node-hid": "0.5.7", + "pngjs": "3.3.2", "postcss": "6.0.21", "request": "2.83.0", "rimraf": "2.5.4", @@ -3329,6 +3327,22 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "keytar": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-4.2.1.tgz", + "integrity": "sha1-igamV3/fY3PgqmsRInfmPex3/RI=", + "optional": true, + "requires": { + "nan": "2.8.0", + "prebuild-install": "2.4.1" + } + }, + "nan": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "optional": true + }, "postcss": { "version": "6.0.21", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz", diff --git a/package.json b/package.json index 6a1af653..c5c6d2aa 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ }, "dependencies": { "pxt-common-packages": "0.20.38", - "pxt-core": "3.8.15" + "pxt-core": "3.9.1" }, "scripts": { "test": "node node_modules/pxt-core/built/pxt.js travis" diff --git a/pxtarget.json b/pxtarget.json index 7ba707e5..d8b4c0da 100644 --- a/pxtarget.json +++ b/pxtarget.json @@ -136,6 +136,7 @@ "hasAudio": true, "usbHelp": [], "extendEditor": true, + "extendFieldEditors": true, "disableBlockIcons": true, "blocklyOptions": { "grid": {