Split editor extensions into multiple module loaded files. Re-using editor/deploy.ts for cmds. Fixing field ports

This commit is contained in:
Sam El-Husseini 2018-01-03 16:18:39 -08:00
parent d6d8b0655b
commit 4445acce7a
5 changed files with 373 additions and 371 deletions

View File

@ -2,7 +2,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
require("./editor") require("./editor/deploy")
declare namespace pxt.editor { declare namespace pxt.editor {
function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>; function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>;

133
editor/deploy.ts Normal file
View File

@ -0,0 +1,133 @@
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
import UF2 = pxtc.UF2;
export let ev3: pxt.editor.Ev3Wrapper
export function debug() {
return initAsync()
.then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v))))
}
function hf2Async() {
return pxt.HF2.mkPacketIOAsync()
.then(h => {
let w = new pxt.editor.Ev3Wrapper(h)
ev3 = w
return w.reconnectAsync(true)
.then(() => w)
})
}
let noHID = false
let initPromise: Promise<pxt.editor.Ev3Wrapper>
export function initAsync() {
if (initPromise)
return initPromise
let canHID = false
if (pxt.U.isNodeJS) {
canHID = true
} else {
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload)
canHID = true
}
if (noHID)
canHID = false
if (canHID) {
initPromise = hf2Async()
.catch(err => {
initPromise = null
noHID = true
return Promise.reject(err)
})
} else {
noHID = true
initPromise = Promise.reject(new Error("no HID"))
}
return initPromise
}
// this comes from aux/pxt.lms
const rbfTemplate = `
4c45474f580000006d000100000000001c000000000000000e000000821b038405018130813e8053
74617274696e672e2e2e0084006080XX00448581644886488405018130813e80427965210084000a
`
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
let w: pxt.editor.Ev3Wrapper
let filename = resp.downloadFileBaseName || "pxt"
filename = filename.replace(/^lego-/, "")
let fspath = "../prjs/BrkProg_SAVE/"
let elfPath = fspath + filename + ".elf"
let rbfPath = fspath + filename + ".rbf"
let rbfHex = rbfTemplate
.replace(/\s+/g, "")
.replace("XX", pxt.U.toHex(pxt.U.stringToUint8Array(elfPath)))
let rbfBIN = pxt.U.fromHex(rbfHex)
pxt.HF2.write16(rbfBIN, 4, rbfBIN.length)
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
let mkFile = (ext: string, data: Uint8Array = null) => {
let f = UF2.newBlockFile()
f.filename = "Projects/" + filename + ext
if (data)
UF2.writeBytes(f, 0, data)
return f
}
let elfUF2 = mkFile(".elf")
for (let b of origElfUF2) {
UF2.writeBytes(elfUF2, b.targetAddr, b.data)
}
let r = UF2.concatFiles([elfUF2, mkFile(".rbf", rbfBIN)])
let data = UF2.serializeFile(r)
resp.outfiles[pxtc.BINARY_UF2] = btoa(data)
let saveUF2Async = () => {
if (isCli || !pxt.commands.saveOnlyAsync) {
return Promise.resolve()
} else {
return pxt.commands.saveOnlyAsync(resp)
}
}
if (noHID) return saveUF2Async()
return initAsync()
.then(w_ => {
w = w_
if (w.isStreaming)
pxt.U.userError("please stop the program first")
return w.stopAsync()
})
.then(() => w.rmAsync(elfPath))
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
.then(() => w.flashAsync(rbfPath, rbfBIN))
.then(() => w.runAsync(rbfPath))
.then(() => {
if (isCli)
return w.disconnectAsync()
else
return Promise.resolve()
//return Promise.delay(1000).then(() => w.dmesgAsync())
}).catch(e => {
// if we failed to initalize, retry
if (noHID)
return saveUF2Async()
else
return Promise.reject(e)
})
}

View File

@ -1,246 +1,116 @@
/// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts" /> /// <reference path="../node_modules/pxt-core/built/pxteditor.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
// When require()d from node, bind the global pxt namespace import { deployCoreAsync, initAsync } from "./deploy";
namespace pxt { import { FieldPorts } from "./field_ports";
export const dummyExport = 1;
pxt.editor.initExtensionsAsync = function(opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
pxt.debug('loading pxt-ev3 target extensions...')
updateBlocklyShape();
const res: pxt.editor.ExtensionResult = {
fieldEditors: [{
selector: "ports",
editor: FieldPorts
}],
deployCoreAsync
};
initAsync().catch(e => {
// probably no HID - we'll try this again upon deployment
})
return Promise.resolve<pxt.editor.ExtensionResult>(res);
} }
eval("if (typeof process === 'object' && process + '' === '[object process]') pxt = global.pxt")
namespace pxt.editor { /**
import UF2 = pxtc.UF2; * Update the shape of Blockly blocks with square corners
*/
export let ev3: Ev3Wrapper function updateBlocklyShape() {
export function debug() {
return initAsync()
.then(w => w.downloadFileAsync("/tmp/dmesg.txt", v => console.log(pxt.Util.uint8ArrayToString(v))))
}
// this comes from aux/pxt.lms
const rbfTemplate = `
4c45474f580000006d000100000000001c000000000000000e000000821b038405018130813e8053
74617274696e672e2e2e0084006080XX00448581644886488405018130813e80427965210084000a
`
function hf2Async() {
return pxt.HF2.mkPacketIOAsync()
.then(h => {
let w = new Ev3Wrapper(h)
ev3 = w
return w.reconnectAsync(true)
.then(() => w)
})
}
let noHID = false
let initPromise: Promise<Ev3Wrapper>
function initAsync() {
if (initPromise)
return initPromise
let canHID = false
if (U.isNodeJS) {
canHID = true
} else {
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
if (Cloud.isLocalHost() && Cloud.localToken && !forceHexDownload)
canHID = true
}
if (noHID)
canHID = false
if (canHID) {
initPromise = hf2Async()
.catch(err => {
initPromise = null
noHID = true
return Promise.reject(err)
})
} else {
noHID = true
initPromise = Promise.reject(new Error("no HID"))
}
return initPromise
}
export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
let w: Ev3Wrapper
let filename = resp.downloadFileBaseName || "pxt"
filename = filename.replace(/^lego-/, "")
let fspath = "../prjs/BrkProg_SAVE/"
let elfPath = fspath + filename + ".elf"
let rbfPath = fspath + filename + ".rbf"
let rbfHex = rbfTemplate
.replace(/\s+/g, "")
.replace("XX", U.toHex(U.stringToUint8Array(elfPath)))
let rbfBIN = U.fromHex(rbfHex)
HF2.write16(rbfBIN, 4, rbfBIN.length)
let origElfUF2 = UF2.parseFile(U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
let mkFile = (ext: string, data: Uint8Array = null) => {
let f = UF2.newBlockFile()
f.filename = "Projects/" + filename + ext
if (data)
UF2.writeBytes(f, 0, data)
return f
}
let elfUF2 = mkFile(".elf")
for (let b of origElfUF2) {
UF2.writeBytes(elfUF2, b.targetAddr, b.data)
}
let r = UF2.concatFiles([elfUF2, mkFile(".rbf", rbfBIN)])
let data = UF2.serializeFile(r)
resp.outfiles[pxtc.BINARY_UF2] = btoa(data)
let saveUF2Async = () => {
if (isCli || !pxt.commands.saveOnlyAsync) {
return Promise.resolve()
} else {
return pxt.commands.saveOnlyAsync(resp)
}
}
if (noHID) return saveUF2Async()
return initAsync()
.then(w_ => {
w = w_
if (w.isStreaming)
U.userError("please stop the program first")
return w.stopAsync()
})
.then(() => w.rmAsync(elfPath))
.then(() => w.flashAsync(elfPath, UF2.readBytes(origElfUF2, 0, origElfUF2.length * 256)))
.then(() => w.flashAsync(rbfPath, rbfBIN))
.then(() => w.runAsync(rbfPath))
.then(() => {
if (isCli)
return w.disconnectAsync()
else
return Promise.resolve()
//return Promise.delay(1000).then(() => w.dmesgAsync())
}).catch(e => {
// if we failed to initalize, retry
if (noHID)
return saveUF2Async()
else
return Promise.reject(e)
})
}
/** /**
* Update the shape of Blockly blocks with square corners * Rounded corner radius.
* @const
*/ */
function updateBlocklyShape() { (Blockly.BlockSvg as any).CORNER_RADIUS = 0 * (Blockly.BlockSvg as any).GRID_UNIT;
/** /**
* Rounded corner radius. * Inner space between edge of statement input and notch.
* @const * @const
*/ */
(Blockly.BlockSvg as any).CORNER_RADIUS = 0 * (Blockly.BlockSvg as any).GRID_UNIT; (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 '
);
/** /**
* Inner space between edge of statement input and notch. * SVG path for drawing next/previous notch from right to left.
* @const * @const
*/ */
(Blockly.BlockSvg as any).STATEMENT_INPUT_INNER_SPACE = 3 * (Blockly.BlockSvg as any).GRID_UNIT; (Blockly.BlockSvg as any).NOTCH_PATH_RIGHT = (
/** 'l -8,8 ' +
* SVG path for drawing next/previous notch from left to right. 'h -16 ' +
* @const 'l -8,-8 '
*/ );
(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. * SVG start point for drawing the top-left corner.
* @const * @const
*/ */
(Blockly.BlockSvg as any).NOTCH_PATH_RIGHT = ( (Blockly.BlockSvg as any).TOP_LEFT_CORNER_START =
'l -8,8 ' + 'm 0,' + 0;
'h -16 ' +
'l -8,-8 '
);
/** /**
* SVG start point for drawing the top-left corner. * SVG path for drawing the rounded top-left corner.
* @const * @const
*/ */
(Blockly.BlockSvg as any).TOP_LEFT_CORNER_START = (Blockly.BlockSvg as any).TOP_LEFT_CORNER =
'm 0,' + 0; 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0 ';
/** /**
* SVG path for drawing the rounded top-left corner. * SVG path for drawing the rounded top-right corner.
* @const * @const
*/ */
(Blockly.BlockSvg as any).TOP_LEFT_CORNER = (Blockly.BlockSvg as any).TOP_RIGHT_CORNER =
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0 '; 'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS;
/** /**
* SVG path for drawing the rounded top-right corner. * SVG path for drawing the rounded bottom-right corner.
* @const * @const
*/ */
(Blockly.BlockSvg as any).TOP_RIGHT_CORNER = (Blockly.BlockSvg as any).BOTTOM_RIGHT_CORNER =
'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS; 'l 0,' + (Blockly.BlockSvg as any).CORNER_RADIUS;
/** /**
* SVG path for drawing the rounded bottom-right corner. * SVG path for drawing the rounded bottom-left corner.
* @const * @const
*/ */
(Blockly.BlockSvg as any).BOTTOM_RIGHT_CORNER = (Blockly.BlockSvg as any).BOTTOM_LEFT_CORNER =
'l 0,' + (Blockly.BlockSvg as any).CORNER_RADIUS; 'l -' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0';
/** /**
* SVG path for drawing the rounded bottom-left corner. * SVG path for drawing the top-left corner of a statement input.
* @const * @const
*/ */
(Blockly.BlockSvg as any).BOTTOM_LEFT_CORNER = (Blockly.BlockSvg as any).INNER_TOP_LEFT_CORNER =
'l -' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',0'; 'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',-' + 0;
/** /**
* SVG path for drawing the top-left corner of a statement input. * SVG path for drawing the bottom-left corner of a statement input.
* @const * Includes the rounded inside corner.
*/ * @const
(Blockly.BlockSvg as any).INNER_TOP_LEFT_CORNER = */
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',-' + 0; (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;
/**
* 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;
}
initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
pxt.debug('loading pxt-ev3 target extensions...')
updateBlocklyShape();
const res: pxt.editor.ExtensionResult = {
fieldEditors: [{
selector: "ports",
editor: FieldPorts
}],
deployCoreAsync
};
initAsync().catch(e => {
// probably no HID - we'll try this again upon deployment
})
return Promise.resolve<pxt.editor.ExtensionResult>(res);
}
} }
// 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")

View File

@ -1,150 +1,147 @@
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts" /> /// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/> /// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
namespace pxt.editor { export interface FieldPortsOptions extends Blockly.FieldCustomDropdownOptions {
columns?: string;
export interface FieldPortsOptions extends Blockly.FieldCustomDropdownOptions { width?: string;
columns?: string; }
width?: string;
} export class FieldPorts extends Blockly.FieldDropdown implements Blockly.FieldCustom {
public isFieldCustom_ = true;
export class FieldPorts extends Blockly.FieldDropdown implements Blockly.FieldCustom {
public isFieldCustom_ = true; // Width in pixels
private width_: number;
// Width in pixels
private width_: number; // Columns in grid
private columns_: number;
// Columns in grid
private columns_: number; private savedPrimary_: string;
private savedPrimary_: string; constructor(text: string, options: FieldPortsOptions, validator?: Function) {
super(options.data);
constructor(text: string, options: FieldPortsOptions, validator?: Function) {
super(options.data); this.columns_ = parseInt(options.columns) || 4;
this.width_ = parseInt(options.width) || 300;
this.columns_ = parseInt(options.columns) || 4; }
this.width_ = parseInt(options.width) || 300;
} /**
* Create a dropdown menu under the text.
/** * @private
* Create a dropdown menu under the text. */
* @private public showEditor_() {
*/ // If there is an existing drop-down we own, this is a request to hide the drop-down.
public showEditor_() { if (Blockly.DropDownDiv.hideIfOwner(this)) {
// If there is an existing drop-down we own, this is a request to hide the drop-down. return;
if (Blockly.DropDownDiv.hideIfOwner(this)) { }
return; // If there is an existing drop-down someone else owns, hide it immediately and clear it.
} Blockly.DropDownDiv.hideWithoutAnimation();
// If there is an existing drop-down someone else owns, hide it immediately and clear it. Blockly.DropDownDiv.clearContent();
Blockly.DropDownDiv.hideWithoutAnimation(); // Populate the drop-down with the icons for this field.
Blockly.DropDownDiv.clearContent(); let dropdownDiv = Blockly.DropDownDiv.getContentDiv();
// Populate the drop-down with the icons for this field. let contentDiv = document.createElement('div');
let dropdownDiv = Blockly.DropDownDiv.getContentDiv(); // Accessibility properties
let contentDiv = document.createElement('div'); contentDiv.setAttribute('role', 'menu');
// Accessibility properties contentDiv.setAttribute('aria-haspopup', 'true');
contentDiv.setAttribute('role', 'menu'); const options = this.getOptions();
contentDiv.setAttribute('aria-haspopup', 'true'); for (let i = 0, option: any; option = options[i]; i++) {
const options = this.getOptions(); let content = (options[i] as any)[0]; // Human-readable text or image.
for (let i = 0, option: any; option = options[i]; i++) { const value = (options[i] as any)[1]; // Language-neutral value.
let content = (options[i] as any)[0]; // Human-readable text or image. // Icons with the type property placeholder take up space but don't have any functionality
const value = (options[i] as any)[1]; // Language-neutral value. // Use for special-case layouts
// Icons with the type property placeholder take up space but don't have any functionality if (content.type == 'placeholder') {
// Use for special-case layouts let placeholder = document.createElement('span');
if (content.type == 'placeholder') { placeholder.setAttribute('class', 'blocklyDropDownPlaceholder');
let placeholder = document.createElement('span'); placeholder.style.width = content.width + 'px';
placeholder.setAttribute('class', 'blocklyDropDownPlaceholder'); placeholder.style.height = content.height + 'px';
placeholder.style.width = content.width + 'px'; contentDiv.appendChild(placeholder);
placeholder.style.height = content.height + 'px'; continue;
contentDiv.appendChild(placeholder); }
continue; let button = document.createElement('button');
} button.setAttribute('id', ':' + i); // For aria-activedescendant
let button = document.createElement('button'); button.setAttribute('role', 'menuitem');
button.setAttribute('id', ':' + i); // For aria-activedescendant button.setAttribute('class', 'blocklyDropDownButton');
button.setAttribute('role', 'menuitem'); button.title = content.alt;
button.setAttribute('class', 'blocklyDropDownButton'); if (this.columns_) {
button.title = content.alt; button.style.width = ((this.width_ / this.columns_) - 8) + 'px';
if (this.columns_) { button.style.height = ((this.width_ / this.columns_) - 8) + 'px';
button.style.width = ((this.width_ / this.columns_) - 8) + 'px'; } else {
button.style.height = ((this.width_ / this.columns_) - 8) + 'px'; button.style.width = content.width + 'px';
} else { button.style.height = content.height + 'px';
button.style.width = content.width + 'px'; }
button.style.height = content.height + 'px'; let backgroundColor = this.sourceBlock_.getColour();
} if (value == this.getValue()) {
let backgroundColor = this.sourceBlock_.getColour(); // This icon is selected, show it in a different colour
if (value == this.getValue()) { backgroundColor = this.sourceBlock_.getColourTertiary();
// This icon is selected, show it in a different colour button.setAttribute('aria-selected', 'true');
backgroundColor = this.sourceBlock_.getColourTertiary(); }
button.setAttribute('aria-selected', 'true'); button.style.backgroundColor = backgroundColor;
} button.style.borderColor = this.sourceBlock_.getColourTertiary();
button.style.backgroundColor = backgroundColor; Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
button.style.borderColor = this.sourceBlock_.getColourTertiary(); Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
Blockly.bindEvent_(button, 'click', this, this.buttonClick_); // These are applied manually instead of using the :hover pseudoclass
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_); // because Android has a bad long press "helper" menu and green highlight
// These are applied manually instead of using the :hover pseudoclass // that we must prevent with ontouchstart preventDefault
// because Android has a bad long press "helper" menu and green highlight Blockly.bindEvent_(button, 'mousedown', button, function (e) {
// that we must prevent with ontouchstart preventDefault this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
Blockly.bindEvent_(button, 'mousedown', button, function (e) { e.preventDefault();
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover'); });
e.preventDefault(); Blockly.bindEvent_(button, 'mouseover', button, function () {
}); this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover');
Blockly.bindEvent_(button, 'mouseover', button, function () { contentDiv.setAttribute('aria-activedescendant', this.id);
this.setAttribute('class', 'blocklyDropDownButton blocklyDropDownButtonHover'); });
contentDiv.setAttribute('aria-activedescendant', this.id); Blockly.bindEvent_(button, 'mouseout', button, function () {
}); this.setAttribute('class', 'blocklyDropDownButton');
Blockly.bindEvent_(button, 'mouseout', button, function () { contentDiv.removeAttribute('aria-activedescendant');
this.setAttribute('class', 'blocklyDropDownButton'); });
contentDiv.removeAttribute('aria-activedescendant'); let buttonImg = document.createElement('img');
}); buttonImg.src = content.src;
let buttonImg = document.createElement('img'); //buttonImg.alt = icon.alt;
buttonImg.src = content.src; // Upon click/touch, we will be able to get the clicked element as e.target
//buttonImg.alt = icon.alt; // Store a data attribute on all possible click targets so we can match it to the icon.
// Upon click/touch, we will be able to get the clicked element as e.target button.setAttribute('data-value', value);
// Store a data attribute on all possible click targets so we can match it to the icon. buttonImg.setAttribute('data-value', value);
button.setAttribute('data-value', value); button.appendChild(buttonImg);
buttonImg.setAttribute('data-value', value); contentDiv.appendChild(button);
button.appendChild(buttonImg); }
contentDiv.appendChild(button); contentDiv.style.width = this.width_ + 'px';
} dropdownDiv.appendChild(contentDiv);
contentDiv.style.width = this.width_ + 'px';
dropdownDiv.appendChild(contentDiv); Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary());
Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(), this.sourceBlock_.getColourTertiary()); // Calculate positioning based on the field position.
var scale = this.sourceBlock_.workspace.scale;
// Calculate positioning based on the field position. var bBox = { width: this.size_.width, height: this.size_.height };
var scale = this.sourceBlock_.workspace.scale; bBox.width *= scale;
var bBox = { width: this.size_.width, height: this.size_.height }; bBox.height *= scale;
bBox.width *= scale; var position = this.fieldGroup_.getBoundingClientRect();
bBox.height *= scale; var primaryX = position.left + bBox.width / 2;
var position = this.fieldGroup_.getBoundingClientRect(); var primaryY = position.top + bBox.height;
var primaryX = position.left + bBox.width / 2; var secondaryX = primaryX;
var primaryY = position.top + bBox.height; var secondaryY = position.top;
var secondaryX = primaryX; // Set bounds to workspace; show the drop-down.
var secondaryY = position.top; (Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
// Set bounds to workspace; show the drop-down. (Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode); this.onHide_.bind(this));
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY, }
this.onHide_.bind(this));
} /**
* Callback for when a button is clicked inside the drop-down.
/** * Should be bound to the FieldIconMenu.
* Callback for when a button is clicked inside the drop-down. * @param {Event} e DOM event for the click/touch
* Should be bound to the FieldIconMenu. * @private
* @param {Event} e DOM event for the click/touch */
* @private private buttonClick_ = function (e: any) {
*/ let value = e.target.getAttribute('data-value');
private buttonClick_ = function (e: any) { this.setValue(value);
let value = e.target.getAttribute('data-value'); Blockly.DropDownDiv.hide();
this.setValue(value); };
Blockly.DropDownDiv.hide();
}; /**
* Callback for when the drop-down is hidden.
/** */
* Callback for when the drop-down is hidden. private onHide_ = function () {
*/ Blockly.DropDownDiv.content_.removeAttribute('role');
private onHide_ = function () { Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
Blockly.DropDownDiv.content_.removeAttribute('role'); Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup'); };
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
};
}
} }

View File

@ -1,12 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"noImplicitAny": true, "noImplicitAny": false,
"noImplicitReturns": true, "noImplicitReturns": true,
"declaration": true, "module": "commonjs",
"out": "../built/editor.js", "outDir": "../built/editor",
"rootDir": ".", "rootDir": ".",
"newLine": "LF", "newLine": "LF",
"sourceMap": false "sourceMap": false,
"allowSyntheticDefaultImports": true,
"declaration": true
} }
} }