committed by
					
						
						Sam El-Husseini
					
				
			
			
				
	
			
			
			
						parent
						
							6ea8a59f58
						
					
				
				
					commit
					5384ec567d
				
			@@ -2,36 +2,10 @@
 | 
				
			|||||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
 | 
					/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { deployCoreAsync, initAsync } from "./deploy";
 | 
					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.editor.ExtensionResult> {
 | 
					pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
 | 
				
			||||||
    pxt.debug('loading pxt-ev3 target extensions...')
 | 
					    pxt.debug('loading pxt-ev3 target extensions...')
 | 
				
			||||||
    updateBlocklyShape();
 | 
					 | 
				
			||||||
    const res: pxt.editor.ExtensionResult = {
 | 
					    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,
 | 
					        deployCoreAsync,
 | 
				
			||||||
        showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
 | 
					        showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
 | 
				
			||||||
            let resolve: (thenableOrResult?: void | PromiseLike<void>) => void;
 | 
					            let resolve: (thenableOrResult?: void | PromiseLike<void>) => void;
 | 
				
			||||||
@@ -115,109 +89,6 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P
 | 
				
			|||||||
    return Promise.resolve<pxt.editor.ExtensionResult>(res);
 | 
					    return Promise.resolve<pxt.editor.ExtensionResult>(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
 | 
					// When require()d from node, bind the global pxt namespace
 | 
				
			||||||
// namespace pxt {
 | 
					// namespace pxt {
 | 
				
			||||||
//     export const dummyExport = 1;
 | 
					//     export const dummyExport = 1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										145
									
								
								fieldeditors/extension.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								fieldeditors/extension.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
				
			|||||||
 | 
					/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
 | 
				
			||||||
 | 
					/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.editor.FieldExtensionResult> {
 | 
				
			||||||
 | 
					    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<pxt.editor.FieldExtensionResult>(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")
 | 
				
			||||||
@@ -30,7 +30,7 @@ export class FieldMotors extends Blockly.FieldDropdown implements Blockly.FieldC
 | 
				
			|||||||
        this.itemWidth_ = 75;
 | 
					        this.itemWidth_ = 75;
 | 
				
			||||||
        this.backgroundColour_ = pxtblockly.parseColour(options.colour);
 | 
					        this.backgroundColour_ = pxtblockly.parseColour(options.colour);
 | 
				
			||||||
        this.itemColour_ = "rgba(255, 255, 255, 0.6)";
 | 
					        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() {
 | 
					    init() {
 | 
				
			||||||
							
								
								
									
										14
									
								
								fieldeditors/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								fieldeditors/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										285
									
								
								fieldeditors/wrap.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								fieldeditors/wrap.ts
									
									
									
									
									
										Normal file
									
								
							@@ -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<Uint8Array>()
 | 
				
			||||||
 | 
					        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<void> => {
 | 
				
			||||||
 | 
					                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<DirEntry[]> {
 | 
				
			||||||
 | 
					            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<void> {
 | 
				
			||||||
 | 
					            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<boolean> {
 | 
				
			||||||
 | 
					            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<void> => {
 | 
				
			||||||
 | 
					                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<void> =>
 | 
				
			||||||
 | 
					                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<void> {
 | 
				
			||||||
 | 
					            this.resetState()
 | 
				
			||||||
 | 
					            if (first) return this.initAsync()
 | 
				
			||||||
 | 
					            log(`reconnect`);
 | 
				
			||||||
 | 
					            return this.io.reconnectAsync()
 | 
				
			||||||
 | 
					                .then(() => this.initAsync())
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        disconnectAsync() {
 | 
				
			||||||
 | 
					            log(`disconnect`);
 | 
				
			||||||
 | 
					            return this.io.disconnectAsync()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										50
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1977,15 +1977,6 @@
 | 
				
			|||||||
        "verror": "1.10.0"
 | 
					        "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": {
 | 
					    "kind-of": {
 | 
				
			||||||
      "version": "3.2.2",
 | 
					      "version": "3.2.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
 | 
				
			||||||
@@ -2437,7 +2428,8 @@
 | 
				
			|||||||
    "nan": {
 | 
					    "nan": {
 | 
				
			||||||
      "version": "2.3.2",
 | 
					      "version": "2.3.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.2.tgz",
 | 
				
			||||||
      "integrity": "sha1-TU7PF+HaTpie+08nPY0AIBytCH4="
 | 
					      "integrity": "sha1-TU7PF+HaTpie+08nPY0AIBytCH4=",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "neatequal": {
 | 
					    "neatequal": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
@@ -2748,6 +2740,11 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
 | 
					      "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": {
 | 
					    "pointer-symbol": {
 | 
				
			||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz",
 | 
				
			||||||
@@ -3274,19 +3271,19 @@
 | 
				
			|||||||
      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
 | 
					      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "pxt-common-packages": {
 | 
					    "pxt-common-packages": {
 | 
				
			||||||
      "version": "0.20.14",
 | 
					      "version": "0.20.38",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-0.20.14.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/pxt-common-packages/-/pxt-common-packages-0.20.38.tgz",
 | 
				
			||||||
      "integrity": "sha512-DlZIDfDSH5jGq5K4k+9QtALzcedT+lYBNnxUWrbAK/GOxkqXZxhwGGvi1O2p6eFOfCWBuH0kjBlui3dzxeF0LA==",
 | 
					      "integrity": "sha512-jtJrd9XwX9T/bOC/9uZyPB4SdvDfhxbnl8c8Gzyy+HiGbW1SMcABgTevJFpLli/ifszl+R+9ZLspFGle84jXkA==",
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "autoprefixer": "6.7.7",
 | 
					        "autoprefixer": "6.7.7",
 | 
				
			||||||
        "pxt-core": "3.5.11",
 | 
					        "pxt-core": "3.8.13",
 | 
				
			||||||
        "rtlcss": "2.2.1"
 | 
					        "rtlcss": "2.2.1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "pxt-core": {
 | 
					    "pxt-core": {
 | 
				
			||||||
      "version": "3.5.11",
 | 
					      "version": "3.8.13",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-3.5.11.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/pxt-core/-/pxt-core-3.8.13.tgz",
 | 
				
			||||||
      "integrity": "sha512-niFvx2PbvWqNPikB0uyR22Pnsc7ipOfWsB656KvnenK4lRNUMEFcxUg4B+65+NZZQypEHk5OxsD3nbE62749EA==",
 | 
					      "integrity": "sha512-F7+P5X/TB6SXtXIkEujHccAxcbMCAKyUqT/VgaQBi2vRo3YdH1IswsMSgXDKG0H12sWOVL297TLdQSiBOuIvXA==",
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "bluebird": "3.5.1",
 | 
					        "bluebird": "3.5.1",
 | 
				
			||||||
        "browserify": "13.3.0",
 | 
					        "browserify": "13.3.0",
 | 
				
			||||||
@@ -3294,10 +3291,11 @@
 | 
				
			|||||||
        "faye-websocket": "0.11.1",
 | 
					        "faye-websocket": "0.11.1",
 | 
				
			||||||
        "fuse.js": "2.6.1",
 | 
					        "fuse.js": "2.6.1",
 | 
				
			||||||
        "highlight.js": "9.12.0",
 | 
					        "highlight.js": "9.12.0",
 | 
				
			||||||
        "keytar": "3.0.2",
 | 
					        "keytar": "4.2.1",
 | 
				
			||||||
        "lzma": "2.3.2",
 | 
					        "lzma": "2.3.2",
 | 
				
			||||||
        "marked": "0.3.12",
 | 
					        "marked": "0.3.12",
 | 
				
			||||||
        "node-hid": "0.5.7",
 | 
					        "node-hid": "0.5.7",
 | 
				
			||||||
 | 
					        "pngjs": "3.3.2",
 | 
				
			||||||
        "postcss": "6.0.21",
 | 
					        "postcss": "6.0.21",
 | 
				
			||||||
        "request": "2.83.0",
 | 
					        "request": "2.83.0",
 | 
				
			||||||
        "rimraf": "2.5.4",
 | 
					        "rimraf": "2.5.4",
 | 
				
			||||||
@@ -3329,6 +3327,22 @@
 | 
				
			|||||||
          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 | 
					          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
 | 
				
			||||||
          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
 | 
					          "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": {
 | 
					        "postcss": {
 | 
				
			||||||
          "version": "6.0.21",
 | 
					          "version": "6.0.21",
 | 
				
			||||||
          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz",
 | 
					          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "pxt-common-packages": "0.20.38",
 | 
					    "pxt-common-packages": "0.20.38",
 | 
				
			||||||
    "pxt-core": "3.8.15"
 | 
					    "pxt-core": "3.9.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "node node_modules/pxt-core/built/pxt.js travis"
 | 
					    "test": "node node_modules/pxt-core/built/pxt.js travis"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,6 +136,7 @@
 | 
				
			|||||||
        "hasAudio": true,
 | 
					        "hasAudio": true,
 | 
				
			||||||
        "usbHelp": [],
 | 
					        "usbHelp": [],
 | 
				
			||||||
        "extendEditor": true,
 | 
					        "extendEditor": true,
 | 
				
			||||||
 | 
					        "extendFieldEditors": true,
 | 
				
			||||||
        "disableBlockIcons": true,
 | 
					        "disableBlockIcons": true,
 | 
				
			||||||
        "blocklyOptions": {
 | 
					        "blocklyOptions": {
 | 
				
			||||||
            "grid": {
 | 
					            "grid": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user