fix: circular dependencies (#6281)

* chore: fix circular dependencies w/ static workspace funcs

* remove preserved imports that aren't currently necessary (probably)

* fix circular dependency with workspaces and block using stub

* fix dependency between variables and xml by moving function to utils

* add stub for trashcan as well

* fix line endings from rebase

* fix goog/base order

* add trashcan patch

* fix: types of compose and decompose in block

* fix: workspace naming in toolbox

* chore: add jsdoc

* chore: restore registry comments to better positions

* chore: remove implementations in goog.js

* chore: fix types of stubs

* chore: remove added AnyDuringMigration casts

* chore: remove modifications to xml and variables

* chore: format

* chore: remove event requirements in workspace comments

* chore: fix circular dependency with xml and workspace comments

* fixup remove ContextMenu import

* chore: fix dependency between mutator and workspace

* chore: break circular dependency between names and procedures

* chore: get tests to run?

* chore: pr comments'

* chore: fix stubbing field registry fromJson

* chore: fix spying on fire

* chore: fix stubbing parts of connection checker

* chore: fix stubbing dialog

* chore: fix stubbing style

* chore: fix spying on duplicate

* chore: fix stubbing variables

* chore: fix stubbing copy

* chore: fix stubbing in workspace

* chore: remove unnecessary stubs

* chore: fix formatting

* chore: fix other formatting

* chore: add backwards compatible static properties to workspace

* chore: move static type properties

* chore: move and comment stubs

* chore: add newlines at EOF

* chore: improve errors for monkey patched functions

* chore: update comment with a pointer to the doc

* chore: update comment with a pointer to the doc

* chore: format
This commit is contained in:
Beka Westberg
2022-07-28 22:26:38 +00:00
committed by GitHub
parent aa61f2d547
commit 9d5dcc6e46
72 changed files with 526 additions and 336 deletions
+2 -2
View File
@@ -617,8 +617,8 @@ goog.declareModuleId = function(namespace) {
'within an ES6 module');
}
if (goog.moduleLoaderState_ && goog.moduleLoaderState_.moduleName) {
throw new Error(
'goog.declareModuleId may only be called once per module.');
// throw new Error(
// 'goog.declareModuleId may only be called once per module.');
}
if (namespace in goog.loadedModules_) {
throw new Error(
+44 -39
View File
@@ -36,48 +36,53 @@
* goog.require calls.
*/
export const global = goog.global;
export const require = goog.require;
export const define = goog.define;
export const DEBUG = goog.DEBUG;
export const LOCALE = goog.LOCALE;
export const TRUSTED_SITE = goog.TRUSTED_SITE;
export const DISALLOW_TEST_ONLY_CODE = goog.DISALLOW_TEST_ONLY_CODE;
export const getGoogModule = goog.module.get;
export const setTestOnly = goog.setTestOnly;
export const forwardDeclare = goog.forwardDeclare;
export const getObjectByName = goog.getObjectByName;
export const basePath = goog.basePath;
export const addSingletonGetter = goog.addSingletonGetter;
export const typeOf = goog.typeOf;
export const isArrayLike = goog.isArrayLike;
export const isDateLike = goog.isDateLike;
export const isObject = goog.isObject;
export const getUid = goog.getUid;
export const hasUid = goog.hasUid;
export const removeUid = goog.removeUid;
export const now = Date.now;
export const globalEval = goog.globalEval;
export const getCssName = goog.getCssName;
export const setCssNameMapping = goog.setCssNameMapping;
export const getMsg = goog.getMsg;
export const getMsgWithFallback = goog.getMsgWithFallback;
export const exportSymbol = goog.exportSymbol;
export const exportProperty = goog.exportProperty;
export const abstractMethod = goog.abstractMethod;
export const cloneObject = goog.cloneObject;
export const bind = goog.bind;
export const partial = goog.partial;
export const inherits = goog.inherits;
export const scope = goog.scope;
export const defineClass = goog.defineClass;
export const declareModuleId = goog.declareModuleId;
export const global = globalThis;
// export const require = goog.require;
// export const define = goog.define;
// export const DEBUG = goog.DEBUG;
// export const LOCALE = goog.LOCALE;
// export const TRUSTED_SITE = goog.TRUSTED_SITE;
// export const DISALLOW_TEST_ONLY_CODE = goog.DISALLOW_TEST_ONLY_CODE;
// export const getGoogModule = goog.module.get;
// export const setTestOnly = goog.setTestOnly;
// export const forwardDeclare = goog.forwardDeclare;
// export const getObjectByName = goog.getObjectByName;
// export const basePath = goog.basePath;
// export const addSingletonGetter = goog.addSingletonGetter;
// export const typeOf = goog.typeOf;
// export const isArrayLike = goog.isArrayLike;
// export const isDateLike = goog.isDateLike;
// export const isObject = goog.isObject;
// export const getUid = goog.getUid;
// export const hasUid = goog.hasUid;
// export const removeUid = goog.removeUid;
// export const now = Date.now;
// export const globalEval = goog.globalEval;
// export const getCssName = goog.getCssName;
// export const setCssNameMapping = goog.setCssNameMapping;
// export const getMsg = goog.getMsg;
// export const getMsgWithFallback = goog.getMsgWithFallback;
// export const exportSymbol = goog.exportSymbol;
// export const exportProperty = goog.exportProperty;
// export const abstractMethod = goog.abstractMethod;
// export const cloneObject = goog.cloneObject;
// export const bind = goog.bind;
// export const partial = goog.partial;
// export const inherits = goog.inherits;
// export const scope = goog.scope;
// export const defineClass = goog.defineClass;
export const declareModuleId = function(namespace) {
if (window.goog && window.goog.declareModuleId) {
window.goog.declareModuleId.call(this, namespace);
}
};
// Export select properties of module. Do not export the function itself or
// goog.module.declareLegacyNamespace.
export const module = {
get: goog.module.get,
};
// export const module = {
// get: goog.module.get,
// };
// Omissions include:
// goog.ENABLE_DEBUG_LOADER - define only used in base.
+2 -2
View File
@@ -17,11 +17,11 @@ goog.declareModuleId('Blockly.BlockSvg');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './theme.js';
// import './theme.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_selected.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './touch.js';
// import './touch.js';
import {Block} from './block.js';
import * as blockAnimations from './block_animations.js';
+53
View File
@@ -571,6 +571,59 @@ export const VARIABLE_DYNAMIC_CATEGORY_NAME: string =
export const PROCEDURE_CATEGORY_NAME: string =
(Procedures as AnyDuringMigration).CATEGORY_NAME;
// Context for why we need to monkey-patch in these functions (internal):
// https://docs.google.com/document/d/1MbO0LEA-pAyx1ErGLJnyUqTLrcYTo-5zga9qplnxeXo/edit?usp=sharing&resourcekey=0-5h_32-i-dHwHjf_9KYEVKg
// clang-format off
Workspace.prototype.newBlock =
function(prototypeName: string, opt_id?: string): Block {
return new Block(this, prototypeName, opt_id);
}
WorkspaceSvg.prototype.newBlock =
function(prototypeName: string, opt_id?: string): BlockSvg {
return new BlockSvg(this, prototypeName, opt_id);
}
WorkspaceSvg.newTrashcan = function(workspace: WorkspaceSvg): Trashcan {
return new Trashcan(workspace);
}
WorkspaceCommentSvg.prototype.showContextMenu =
function(this: WorkspaceCommentSvg, e: Event) {
if (this.workspace.options.readOnly) {
return;
}
// Save the current workspace comment in a variable for use in closures.
const comment = this;
const menuOptions = [];
if (this.isDeletable() && this.isMovable()) {
menuOptions.push(ContextMenu.commentDuplicateOption(comment));
menuOptions.push(ContextMenu.commentDeleteOption(comment));
}
ContextMenu.show(e, menuOptions, this.RTL);
}
Mutator.prototype.newWorkspaceSvg =
function(options: Options): WorkspaceSvg {
return new WorkspaceSvg(options);
}
Names.prototype.populateProcedures =
function(this: Names, workspace: Workspace) {
let procedures = Procedures.allProcedures(workspace);
// Flatten the return vs no-return procedure lists.
let flattenedProcedures: AnyDuringMigration[][] =
procedures[0].concat(procedures[1]);
for (let i = 0; i < flattenedProcedures.length; i++) {
this.getName(flattenedProcedures[i][0], Names.NameType.PROCEDURE);
}
}
// clang-format on
// Re-export submodules that no longer declareLegacyNamespace.
export {browserEvents};
export {ContextMenu};
+2 -2
View File
@@ -17,9 +17,9 @@ goog.declareModuleId('Blockly.Bubble');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './metrics_manager.js';
// import './metrics_manager.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './workspace.js';
// import './workspace.js';
import type {BlockDragSurfaceSvg} from './block_drag_surface.js';
import type {BlockSvg} from './block_svg.js';
+2 -2
View File
@@ -16,9 +16,9 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.BubbleDragger');
// Unused import preserved for side-effects. Remove if unneeded.
import './bubble.js';
// import './bubble.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './constants.js';
// import './constants.js';
import type {BlockDragSurfaceSvg} from './block_drag_surface.js';
import {ComponentManager} from './component_manager.js';
+19
View File
@@ -28,6 +28,13 @@ let copyData: CopyData|null = null;
* @internal
*/
export function copy(toCopy: ICopyable) {
TEST_ONLY.copyInternal(toCopy);
}
/**
* Private version of copy for stubbing in tests.
*/
function copyInternal(toCopy: ICopyable) {
copyData = toCopy.toCopyData();
}
@@ -63,9 +70,21 @@ export function paste(): ICopyable|null {
* @internal
*/
export function duplicate(toDuplicate: ICopyable): ICopyable|null {
return TEST_ONLY.duplicateInternal(toDuplicate);
}
/**
* Private version of duplicate for stubbing in tests.
*/
function duplicateInternal(toDuplicate: ICopyable): ICopyable|null {
const oldCopyData = copyData;
copy(toDuplicate);
const pastedThing = toDuplicate.toCopyData().source.paste(copyData!.saveInfo);
copyData = oldCopyData;
return pastedThing;
}
export const TEST_ONLY = {
duplicateInternal,
copyInternal,
}
+3 -3
View File
@@ -17,16 +17,16 @@ goog.declareModuleId('Blockly.Comment');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './block.js';
// import './block.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './workspace_svg.js';
// import './workspace_svg.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_block_change.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_bubble_open.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './warning.js';
// import './warning.js';
import type {CommentModel} from './block.js';
import type {BlockSvg} from './block_svg.js';
+42
View File
@@ -26,6 +26,39 @@ import type {Workspace} from './workspace.js';
import type {WorkspaceSvg} from './workspace_svg.js';
/** Database of all workspaces. */
const WorkspaceDB_ = Object.create(null);
/**
* Find the workspace with the specified ID.
* @param id ID of workspace to find.
* @return The sought after workspace or null if not found.
*/
export function getWorkspaceById(id: string): Workspace|null {
return WorkspaceDB_[id] || null;
}
/**
* Find all workspaces.
* @return Array of workspaces.
*/
export function getAllWorkspaces(): Workspace[] {
const workspaces = [];
for (const workspaceId in WorkspaceDB_) {
workspaces.push(WorkspaceDB_[workspaceId]);
}
return workspaces;
}
export function registerWorkspace(workspace: Workspace) {
WorkspaceDB_[workspace.id] = workspace;
}
export function unregisterWorkpace(workspace: Workspace) {
delete WorkspaceDB_[workspace.id];
}
/**
* The main workspace most recently used.
* Set by Blockly.WorkspaceSvg.prototype.markFocused
@@ -196,6 +229,13 @@ function jsonInitFactory(jsonDef: AnyDuringMigration): () => void {
* @alias Blockly.common.defineBlocksWithJsonArray
*/
export function defineBlocksWithJsonArray(jsonArray: AnyDuringMigration[]) {
TEST_ONLY.defineBlocksWithJsonArrayInternal(jsonArray);
}
/**
* Private version of defineBlocksWithJsonArray for stubbing in tests.
*/
function defineBlocksWithJsonArrayInternal(jsonArray: AnyDuringMigration[]) {
defineBlocks(createBlockDefinitionsFromJsonArray(jsonArray));
}
@@ -245,3 +285,5 @@ export function defineBlocks(blocks: {[key: string]: BlockDefinition}) {
Blocks[type] = definition;
}
}
export const TEST_ONLY = {defineBlocksWithJsonArrayInternal};
+1 -1
View File
@@ -16,7 +16,7 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.Connection');
// Unused import preserved for side-effects. Remove if unneeded.
import './constants.js';
// import './constants.js';
import type {Block} from './block.js';
import {ConnectionType} from './connection_type.js';
+6 -6
View File
@@ -20,7 +20,7 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.ConnectionDB');
// Unused import preserved for side-effects. Remove if unneeded.
import './constants.js';
// import './constants.js';
import {ConnectionType} from './connection_type.js';
import type {IConnectionChecker} from './interfaces/i_connection_checker.js';
@@ -39,10 +39,10 @@ export class ConnectionDB {
private readonly connections_: RenderedConnection[] = [];
/**
* @param checker The workspace's connection type checker, used to decide if
* connections are valid during a drag.
* @param connectionChecker The workspace's connection type checker, used to
* decide if connections are valid during a drag.
*/
constructor(private readonly checker: IConnectionChecker) {}
constructor(private readonly connectionChecker: IConnectionChecker) {}
/**
* Add a connection to the database. Should not already exist in the database.
@@ -248,7 +248,7 @@ export class ConnectionDB {
let pointerMin = closestIndex - 1;
while (pointerMin >= 0 && this.isInYRange_(pointerMin, conn.y, maxRadius)) {
temp = this.connections_[pointerMin];
if (this.checker.canConnect(conn, temp, true, bestRadius)) {
if (this.connectionChecker.canConnect(conn, temp, true, bestRadius)) {
bestConnection = temp;
// AnyDuringMigration because: Argument of type 'RenderedConnection' is
// not assignable to parameter of type 'Connection'.
@@ -261,7 +261,7 @@ export class ConnectionDB {
while (pointerMax < this.connections_.length &&
this.isInYRange_(pointerMax, conn.y, maxRadius)) {
temp = this.connections_[pointerMax];
if (this.checker.canConnect(conn, temp, true, bestRadius)) {
if (this.connectionChecker.canConnect(conn, temp, true, bestRadius)) {
bestConnection = temp;
// AnyDuringMigration because: Argument of type 'RenderedConnection' is
// not assignable to parameter of type 'Connection'.
+13
View File
@@ -69,9 +69,18 @@ export function setAlert(
*/
export function confirm(
message: string, callback: (p1: boolean) => AnyDuringMigration) {
TEST_ONLY.confirmInternal(message, callback);
}
/**
* Private version of confirm for stubbing in tests.
*/
function confirmInternal(
message: string, callback: (p1: boolean) => AnyDuringMigration) {
confirmImplementation(message, callback);
}
/**
* Sets the function to be run when Blockly.dialog.confirm() is called.
* @param confirmFunction The function to be run.
@@ -112,3 +121,7 @@ export function setPrompt(
AnyDuringMigration) {
promptImplementation = promptFunction;
}
export const TEST_ONLY = {
confirmInternal,
}
+3 -2
View File
@@ -17,7 +17,8 @@
import * as goog from '../../closure/goog/goog.js';
goog.declareModuleId('Blockly.Events.Abstract');
import {Workspace} from '../workspace.js';
import * as common from '../common.js';
import type {Workspace} from '../workspace.js';
import * as eventUtils from './utils.js';
@@ -99,7 +100,7 @@ export abstract class Abstract {
getEventWorkspace_(): Workspace {
let workspace;
if (this.workspaceId) {
workspace = Workspace.getById(this.workspaceId);
workspace = common.getWorkspaceById(this.workspaceId);
}
if (!workspace) {
throw Error(
+21 -3
View File
@@ -18,9 +18,10 @@ import * as goog from '../../closure/goog/goog.js';
goog.declareModuleId('Blockly.Events.utils');
import type {Block} from '../block.js';
import * as common from '../common.js';
import * as registry from '../registry.js';
import * as idGenerator from '../utils/idgenerator.js';
import {Workspace} from '../workspace.js';
import type {Workspace} from '../workspace.js';
import type {WorkspaceSvg} from '../workspace_svg.js';
import type {Abstract} from './events_abstract.js';
@@ -245,6 +246,13 @@ const FIRE_QUEUE: Abstract[] = [];
* @alias Blockly.Events.utils.fire
*/
export function fire(event: Abstract) {
TEST_ONLY.fireInternal(event);
}
/**
* Private version of fireInternal for stubbing in tests.
*/
function fireInternal(event: Abstract) {
if (!isEnabled()) {
return;
}
@@ -255,6 +263,7 @@ export function fire(event: Abstract) {
FIRE_QUEUE.push(event);
}
/** Fire all queued events. */
function fireNow() {
const queue = filter(FIRE_QUEUE, true);
@@ -263,7 +272,7 @@ function fireNow() {
if (!event.workspaceId) {
continue;
}
const eventWorkspace = Workspace.getById(event.workspaceId);
const eventWorkspace = common.getWorkspaceById(event.workspaceId);
if (eventWorkspace) {
eventWorkspace.fireChangeListener(event);
}
@@ -409,6 +418,13 @@ export function getGroup(): string {
* @alias Blockly.Events.utils.setGroup
*/
export function setGroup(state: boolean|string) {
TEST_ONLY.setGroupInternal(state);
}
/**
* Private version of setGroup for stubbing in tests.
*/
function setGroupInternal(state: boolean|string) {
if (typeof state === 'boolean') {
group = state ? idGenerator.genUid() : '';
} else {
@@ -478,7 +494,7 @@ export function disableOrphans(event: Abstract) {
return;
}
const eventWorkspace =
Workspace.getById(blockEvent.workspaceId) as WorkspaceSvg;
common.getWorkspaceById(blockEvent.workspaceId) as WorkspaceSvg;
let block = eventWorkspace.getBlockById(blockEvent.blockId);
if (block) {
// Changing blocks as part of this event shouldn't be undoable.
@@ -509,4 +525,6 @@ export function disableOrphans(event: Abstract) {
export const TEST_ONLY = {
FIRE_QUEUE,
fireNow,
fireInternal,
setGroupInternal,
};
+1 -1
View File
@@ -22,7 +22,7 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.Extensions');
// Unused import preserved for side-effects. Remove if unneeded.
import './mutator.js';
// import './mutator.js';
import type {Block} from './block.js';
import type {BlockSvg} from './block_svg.js';
+2 -2
View File
@@ -21,11 +21,11 @@ goog.declareModuleId('Blockly.Field');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './shortcut_registry.js';
// import './shortcut_registry.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_block_change.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './gesture.js';
// import './gesture.js';
import type {Block} from './block.js';
import type {BlockSvg} from './block_svg.js';
+11
View File
@@ -60,6 +60,13 @@ export function unregister(type: string) {
* @internal
*/
export function fromJson(options: AnyDuringMigration): Field|null {
return TEST_ONLY.fromJsonInternal(options);
}
/**
* Private version of fromJson for stubbing in tests.
*/
function fromJsonInternal(options: AnyDuringMigration): Field|null {
const fieldObject =
registry.getObject(registry.Type.FIELD, options['type']) as
IRegistrableField |
@@ -74,3 +81,7 @@ export function fromJson(options: AnyDuringMigration): Field|null {
}
return fieldObject.fromJson(options);
}
export const TEST_ONLY = {
fromJsonInternal,
}
+2 -2
View File
@@ -16,9 +16,9 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.VerticalFlyout');
// Unused import preserved for side-effects. Remove if unneeded.
import './block.js';
// import './block.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './constants.js';
// import './constants.js';
import * as browserEvents from './browser_events.js';
import * as dropDownDiv from './dropdowndiv.js';
+2 -3
View File
@@ -18,7 +18,7 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.Gesture');
// Unused import preserved for side-effects. Remove if unneeded.
import './block_dragger.js';
// import './block_dragger.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_click.js';
@@ -38,7 +38,6 @@ import * as registry from './registry.js';
import * as Tooltip from './tooltip.js';
import * as Touch from './touch.js';
import {Coordinate} from './utils/coordinate.js';
import {Workspace} from './workspace.js';
import {WorkspaceCommentSvg} from './workspace_comment_svg.js';
import {WorkspaceDragger} from './workspace_dragger.js';
import type {WorkspaceSvg} from './workspace_svg.js';
@@ -936,7 +935,7 @@ export class Gesture {
* @return True if gesture is occurring.
*/
static inProgress(): boolean {
const workspaces = Workspace.getAll();
const workspaces = common.getAllWorkspaces();
for (let i = 0, workspace; workspace = workspaces[i]; i++) {
// Not actually necessarily a WorkspaceSvg, but it doesn't matter b/c
// we're just checking if the property exists. Theoretically we would
+1 -1
View File
@@ -315,7 +315,7 @@ let documentEventsBound = false;
function bindDocumentEvents() {
if (!documentEventsBound) {
browserEvents.conditionalBind(document, 'scroll', null, function() {
const workspaces = Workspace.getAll();
const workspaces = common.getAllWorkspaces();
for (let i = 0, workspace; workspace = workspaces[i]; i++) {
if (workspace instanceof WorkspaceSvg) {
workspace.updateInverseScreenCTM();
@@ -19,7 +19,7 @@ goog.declareModuleId('Blockly.IASTNodeLocationWithBlock');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../block.js';
// import '../block.js';
import type {IASTNodeLocation} from './i_ast_node_location.js';
+2 -2
View File
@@ -17,10 +17,10 @@ goog.declareModuleId('Blockly.IBlockDragger');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../block_svg.js';
// import '../block_svg.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/coordinate.js';
// import '../utils/coordinate.js';
/**
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.IBoundedElement');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/rect.js';
// import '../utils/rect.js';
/**
+2 -2
View File
@@ -17,10 +17,10 @@ goog.declareModuleId('Blockly.IBubble');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../block_drag_surface.js';
// import '../block_drag_surface.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/coordinate.js';
// import '../utils/coordinate.js';
import type {IContextMenu} from './i_contextmenu.js';
import type {IDraggable} from './i_draggable.js';
@@ -18,7 +18,7 @@ goog.declareModuleId('Blockly.ICollapsibleToolboxItem');
/* eslint-disable-next-line no-unused-vars */
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './i_toolbox_item.js';
// import './i_toolbox_item.js';
import type {ISelectableToolboxItem} from './i_selectable_toolbox_item.js';
+2 -2
View File
@@ -19,10 +19,10 @@ goog.declareModuleId('Blockly.IConnectionChecker');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../connection.js';
// import '../connection.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../rendered_connection.js';
// import '../rendered_connection.js';
/**
+1 -1
View File
@@ -20,7 +20,7 @@ goog.declareModuleId('Blockly.IDeleteArea');
/* eslint-disable-next-line no-unused-vars */
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './i_draggable.js';
// import './i_draggable.js';
import type {IDragTarget} from './i_drag_target.js';
+2 -2
View File
@@ -20,10 +20,10 @@ goog.declareModuleId('Blockly.IDragTarget');
/* eslint-disable-next-line no-unused-vars */
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './i_draggable.js';
// import './i_draggable.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/rect.js';
// import '../utils/rect.js';
import type {IComponent} from './i_component.js';
+4 -4
View File
@@ -17,16 +17,16 @@ goog.declareModuleId('Blockly.IFlyout');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/toolbox.js';
// import '../utils/toolbox.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../block_svg.js';
// import '../block_svg.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/coordinate.js';
// import '../utils/coordinate.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/svg.js';
// import '../utils/svg.js';
import type {WorkspaceSvg} from '../workspace_svg.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.IKeyboardAccessible');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../shortcut_registry.js';
// import '../shortcut_registry.js';
/**
+3 -3
View File
@@ -17,13 +17,13 @@ goog.declareModuleId('Blockly.IMetricsManager');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../metrics_manager.js';
// import '../metrics_manager.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/metrics.js';
// import '../utils/metrics.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/size.js';
// import '../utils/size.js';
/**
+2 -2
View File
@@ -18,10 +18,10 @@ goog.declareModuleId('Blockly.IPositionable');
/* eslint-disable-next-line no-unused-vars */
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../metrics_manager.js';
// import '../metrics_manager.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/rect.js';
// import '../utils/rect.js';
import type {IComponent} from './i_component.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.ISelectableToolboxItem');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/toolbox.js';
// import '../utils/toolbox.js';
import type {IToolboxItem} from './i_toolbox_item.js';
+4 -4
View File
@@ -17,16 +17,16 @@ goog.declareModuleId('Blockly.IToolbox');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../utils/toolbox.js';
// import '../utils/toolbox.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './i_flyout.js';
// import './i_flyout.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './i_toolbox_item.js';
// import './i_toolbox_item.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../workspace_svg.js';
// import '../workspace_svg.js';
import type {IRegistrable} from './i_registrable.js';
+11 -2
View File
@@ -36,7 +36,7 @@ import * as dom from './utils/dom.js';
import {Svg} from './utils/svg.js';
import * as toolbox from './utils/toolbox.js';
import * as xml from './utils/xml.js';
import {WorkspaceSvg} from './workspace_svg.js';
import type {WorkspaceSvg} from './workspace_svg.js';
/**
@@ -190,7 +190,7 @@ export class Mutator extends Icon {
if (hasFlyout) {
workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
}
this.workspace_ = new WorkspaceSvg(workspaceOptions);
this.workspace_ = this.newWorkspaceSvg(workspaceOptions);
this.workspace_.isMutator = true;
this.workspace_.addChangeListener(eventUtils.disableOrphans);
@@ -214,6 +214,15 @@ export class Mutator extends Icon {
return this.svgDialog_ as AnyDuringMigration;
}
/**
* @internal
*/
newWorkspaceSvg(options: Options): WorkspaceSvg {
throw new Error(
'The implementation of newWorkspaceSvg should be ' +
'monkey-patched in by blockly.ts');
}
/** Add or remove the UI indicating if this icon may be clicked or not. */
override updateEditable() {
super.updateEditable();
+5 -9
View File
@@ -16,10 +16,10 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.Names');
// Unused import preserved for side-effects. Remove if unneeded.
import './procedures.js';
// import './procedures.js';
import {Msg} from './msg.js';
import * as Procedures from './procedures.js';
// import * as Procedures from './procedures.js';
import type {VariableMap} from './variable_map.js';
import * as Variables from './variables.js';
import type {Workspace} from './workspace.js';
@@ -129,13 +129,9 @@ export class Names {
* @param workspace Workspace to generate procedures from.
*/
populateProcedures(workspace: Workspace) {
let procedures = Procedures.allProcedures(workspace);
// Flatten the return vs no-return procedure lists.
let flattenedProcedures: AnyDuringMigration[][] =
procedures[0].concat(procedures[1]);
for (let i = 0; i < flattenedProcedures.length; i++) {
this.getName(flattenedProcedures[i][0], NameType.PROCEDURE);
}
throw new Error(
'The implementation of populateProcedures should be ' +
'monkey-patched in by blockly.ts');
}
/**
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.uiPosition');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './metrics_manager.js';
// import './metrics_manager.js';
import type {UiMetrics} from './metrics_manager.js';
import {Scrollbar} from './scrollbar.js';
+4 -3
View File
@@ -21,6 +21,7 @@ import './events/events_block_change.js';
import type {Block} from './block.js';
import type {BlockSvg} from './block_svg.js';
import {Blocks} from './blocks.js';
import * as common from './common.js';
import type {Abstract} from './events/events_abstract.js';
import type {BubbleOpen} from './events/events_bubble_open.js';
import * as eventUtils from './events/utils.js';
@@ -29,7 +30,7 @@ import {Msg} from './msg.js';
import {Names} from './names.js';
import * as utilsXml from './utils/xml.js';
import * as Variables from './variables.js';
import {Workspace} from './workspace.js';
import type {Workspace} from './workspace.js';
import type {WorkspaceSvg} from './workspace_svg.js';
import * as Xml from './xml.js';
@@ -333,7 +334,7 @@ export function mutatorOpenListener(e: Abstract) {
return;
}
const workspaceId = (bubbleEvent.workspaceId);
const block = Workspace.getById(workspaceId)!.getBlockById(
const block = common.getWorkspaceById(workspaceId)!.getBlockById(
bubbleEvent.blockId) as BlockSvg;
const type = block.type;
if (type !== 'procedures_defnoreturn' && type !== 'procedures_defreturn') {
@@ -355,7 +356,7 @@ function mutatorChangeListener(e: Abstract) {
return;
}
const workspaceId = e.workspaceId as string;
const workspace = Workspace.getById(workspaceId) as WorkspaceSvg;
const workspace = common.getWorkspaceById(workspaceId) as WorkspaceSvg;
updateMutatorFlyout(workspace);
}
+11 -17
View File
@@ -61,6 +61,17 @@ export const DEFAULT = 'default';
* @alias Blockly.registry.Type
*/
export class Type<T> {
/** @param name The name of the registry type. */
constructor(private readonly name: string) {}
/**
* Returns the name of the type.
* @return The name.
*/
toString(): string {
return this.name;
}
static CONNECTION_CHECKER = new Type<IConnectionChecker>('connectionChecker');
static CURSOR = new Type<Cursor>('cursor');
@@ -88,25 +99,8 @@ export class Type<T> {
/** @internal */
static SERIALIZER = new Type<ISerializer>('serializer');
/** @param name The name of the registry type. */
constructor(private readonly name: string) {}
/**
* Returns the name of the type.
* @return The name.
*/
toString(): string {
return this.name;
}
}
/**
* Registers a class based on a type and name.
* @param type The type of the plugin.
+3 -3
View File
@@ -19,13 +19,13 @@ goog.declareModuleId('Blockly.blockRendering.IPathObject');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../block_svg.js';
// import '../../block_svg.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../connection.js';
// import '../../connection.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../theme.js';
// import '../../theme.js';
import type {BlockStyle} from '../../theme.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.blockRendering.PathObject');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../theme.js';
// import '../../theme.js';
import type {BlockSvg} from '../../block_svg.js';
import type {Connection} from '../../connection.js';
+1 -1
View File
@@ -19,7 +19,7 @@ goog.declareModuleId('Blockly.geras.Highlighter');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './renderer.js';
// import './renderer.js';
import * as svgPaths from '../../utils/svg_paths.js';
import type {ConstantProvider} from '../common/constants.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.geras.PathObject');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../theme.js';
// import '../../theme.js';
import type {BlockSvg} from '../../block_svg.js';
import type {BlockStyle} from '../../theme.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.geras.Renderer');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../common/constants.js';
// import '../common/constants.js';
import type {BlockSvg} from '../../block_svg.js';
import type {BlockStyle, Theme} from '../../theme.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.zelos.PathObject');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../theme.js';
// import '../../theme.js';
import type {BlockSvg} from '../../block_svg.js';
import type {Connection} from '../../connection.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.zelos.Renderer');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../../theme.js';
// import '../../theme.js';
import type {BlockSvg} from '../../block_svg.js';
import type {Connection} from '../../connection.js';
+2 -2
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.Toolbox');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../shortcut_registry.js';
// import '../shortcut_registry.js';
// Unused import preserved for side-effects. Remove if unneeded.
import '../events/events_toolbox_item_select.js';
@@ -107,7 +107,7 @@ export class Toolbox extends DeleteArea implements IAutoHideable,
protected boundEvents_: browserEvents.Data[] = [];
override wouldDelete_: AnyDuringMigration;
/** The workspace this toolbox is on. */
/** The workspace this toolbox is on. */
protected readonly workspace_: WorkspaceSvg;
/** @param workspace The workspace in which to create new blocks. */
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.Trashcan');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './metrics_manager.js';
// import './metrics_manager.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_trashcan_open.js';
+12
View File
@@ -32,6 +32,13 @@ import {Size} from './size.js';
* @alias Blockly.utils.style.getSize
*/
export function getSize(element: Element): Size {
return TEST_ONLY.getSizeInternal(element);
}
/**
* Private version of getSize for stubbing in tests.
*/
function getSizeInternal(element: Element): Size {
if (getStyle(element, 'display') !== 'none') {
return getSizeWithDisplay(element);
}
@@ -57,6 +64,7 @@ export function getSize(element: Element): Size {
return new Size(offsetWidth, offsetHeight);
}
/**
* Gets the height and width of an element when the display is not none.
* @param element Element to get size of.
@@ -292,3 +300,7 @@ export function getContainerOffsetToScrollInto(
}
return new Coordinate(scrollLeft, scrollTop);
}
export const TEST_ONLY = {
getSizeInternal,
}
+13 -2
View File
@@ -17,10 +17,10 @@ goog.declareModuleId('Blockly.utils.toolbox');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../toolbox/category.js';
// import '../toolbox/category.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import '../toolbox/separator.js';
// import '../toolbox/separator.js';
import type {ConnectionState} from '../serialization/blocks.js';
import type {CssConfig as CategoryCssConfig} from '../toolbox/category.js';
@@ -278,6 +278,13 @@ export function convertFlyoutDefToJsonArray(flyoutDef: FlyoutDefinition|
* @internal
*/
export function hasCategories(toolboxJson: ToolboxInfo|null): boolean {
return TEST_ONLY.hasCategoriesInternal(toolboxJson);
}
/**
* Private version of hasCategories for stubbing in tests.
*/
function hasCategoriesInternal(toolboxJson: ToolboxInfo|null): boolean {
if (!toolboxJson) {
return false;
}
@@ -420,3 +427,7 @@ export function parseToolboxTree(toolboxDef: Element|null|string): Element|
}
return toolboxDef;
}
export const TEST_ONLY = {
hasCategoriesInternal,
}
+11
View File
@@ -217,6 +217,13 @@ export const VAR_LETTER_OPTIONS = 'ijkmnopqrstuvwxyzabcdefgh';
* @alias Blockly.Variables.generateUniqueName
*/
export function generateUniqueName(workspace: Workspace): string {
return TEST_ONLY.generateUniqueNameInternal(workspace);
}
/**
* Private version of generateUniqueName for stubbing in tests.
*/
function generateUniqueNameInternal(workspace: Workspace): string {
return generateUniqueNameFromOptions(
VAR_LETTER_OPTIONS.charAt(0), workspace.getAllVariableNames());
}
@@ -587,3 +594,7 @@ export function getAddedVariables(
}
return addedVariables;
}
export const TEST_ONLY = {
generateUniqueNameInternal,
}
+9 -13
View File
@@ -18,10 +18,11 @@ goog.declareModuleId('Blockly.Workspace');
// Unused import preserved for side-effects. Remove if unneeded.
import './connection_checker.js';
import {Block} from './block.js';
import type {Block} from './block.js';
import type {BlocklyOptions} from './blockly_options.js';
import type {ConnectionDB} from './connection_db.js';
import type {Abstract} from './events/events_abstract.js';
import * as common from './common.js';
import * as eventUtils from './events/utils.js';
import type {IASTNodeLocation} from './interfaces/i_ast_node_location.js';
import type {IConnectionChecker} from './interfaces/i_connection_checker.js';
@@ -36,9 +37,6 @@ import type {VariableModel} from './variable_model.js';
import type {WorkspaceComment} from './workspace_comment.js';
/** Database of all workspaces. */
const WorkspaceDB_ = Object.create(null);
/**
* Class for a workspace. This is a data structure that contains blocks.
* There is no UI, and can be created headlessly.
@@ -112,7 +110,7 @@ export class Workspace implements IASTNodeLocation {
/** @param opt_options Dictionary of options. */
constructor(opt_options?: Options) {
this.id = idGenerator.genUid();
WorkspaceDB_[this.id] = this;
common.registerWorkspace(this);
this.options = opt_options || new Options(({} as BlocklyOptions));
this.RTL = !!this.options.RTL;
this.horizontalLayout = !!this.options.horizontalLayout;
@@ -145,7 +143,7 @@ export class Workspace implements IASTNodeLocation {
this.listeners_.length = 0;
this.clear();
// Remove from workspace database.
delete WorkspaceDB_[this.id];
common.unregisterWorkpace(this);
}
/**
@@ -511,7 +509,9 @@ export class Workspace implements IASTNodeLocation {
* @return The created block.
*/
newBlock(prototypeName: string, opt_id?: string): Block {
return new Block(this, prototypeName, opt_id);
throw new Error(
'The implementation of newBlock should be ' +
'monkey-patched in by blockly.ts');
}
/**
@@ -778,7 +778,7 @@ export class Workspace implements IASTNodeLocation {
* @return The sought after workspace or null if not found.
*/
static getById(id: string): Workspace|null {
return WorkspaceDB_[id] || null;
return common.getWorkspaceById(id);
}
/**
@@ -786,10 +786,6 @@ export class Workspace implements IASTNodeLocation {
* @return Array of workspaces.
*/
static getAll(): Workspace[] {
const workspaces = [];
for (const workspaceId in WorkspaceDB_) {
workspaces.push(WorkspaceDB_[workspaceId]);
}
return workspaces;
return common.getAllWorkspaces();
}
}
+3 -3
View File
@@ -16,11 +16,11 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.WorkspaceComment');
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_comment_change.js';
// import './events/events_comment_change.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_comment_create.js';
// import './events/events_comment_create.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_comment_delete.js';
// import './events/events_comment_delete.js';
import type {CommentMove} from './events/events_comment_move.js';
import * as eventUtils from './events/utils.js';
+6 -16
View File
@@ -16,16 +16,16 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.WorkspaceCommentSvg');
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_comment_create.js';
// import './events/events_comment_create.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_comment_delete.js';
// import './events/events_comment_delete.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_selected.js';
import type {BlockDragSurfaceSvg} from './block_drag_surface.js';
import * as browserEvents from './browser_events.js';
import * as common from './common.js';
import * as ContextMenu from './contextmenu.js';
// import * as ContextMenu from './contextmenu.js';
import * as Css from './css.js';
import type {CommentMove} from './events/events_comment_move.js';
import * as eventUtils from './events/utils.js';
@@ -210,19 +210,9 @@ export class WorkspaceCommentSvg extends WorkspaceComment implements
* @internal
*/
showContextMenu(e: Event) {
if (this.workspace.options.readOnly) {
return;
}
// Save the current workspace comment in a variable for use in closures.
const comment = this;
const menuOptions = [];
if (this.isDeletable() && this.isMovable()) {
menuOptions.push(ContextMenu.commentDuplicateOption(comment));
menuOptions.push(ContextMenu.commentDeleteOption(comment));
}
ContextMenu.show(e, menuOptions, this.RTL);
throw new Error(
'The implementation of showContextMenu should be ' +
'monkey-patched in by blockly.ts');
}
/**
+24 -12
View File
@@ -17,19 +17,19 @@ goog.declareModuleId('Blockly.WorkspaceSvg');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './procedures.js';
// import './procedures.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './variables.js';
// import './variables.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './variables_dynamic.js';
// import './variables_dynamic.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './rendered_connection.js';
// import './rendered_connection.js';
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './zoom_controls.js';
// import './zoom_controls.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_block_create.js';
// Unused import preserved for side-effects. Remove if unneeded.
@@ -37,13 +37,13 @@ import './events/events_theme_change.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_viewport.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './metrics_manager.js';
// import './metrics_manager.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './msg.js';
// import './msg.js';
import type {Block} from './block.js';
import type {BlockDragSurfaceSvg} from './block_drag_surface.js';
import {BlockSvg} from './block_svg.js';
import type {BlockSvg} from './block_svg.js';
import type {BlocklyOptions} from './blockly_options.js';
import * as browserEvents from './browser_events.js';
import * as common from './common.js';
@@ -79,7 +79,7 @@ import {Classic} from './theme/classic.js';
import {ThemeManager} from './theme_manager.js';
import * as Tooltip from './tooltip.js';
import {TouchGesture} from './touch_gesture.js';
import {Trashcan} from './trashcan.js';
import type {Trashcan} from './trashcan.js';
import * as utils from './utils.js';
import * as arrayUtils from './utils/array.js';
import {Coordinate} from './utils/coordinate.js';
@@ -954,11 +954,20 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg {
* @internal
*/
addTrashcan() {
this.trashcan = new Trashcan(this);
this.trashcan = WorkspaceSvg.newTrashcan(this);
const svgTrashcan = this.trashcan.createDom();
this.svgGroup_.insertBefore(svgTrashcan, this.svgBlockCanvas_);
}
/**
* @internal
*/
static newTrashcan(workspace: WorkspaceSvg): Trashcan {
throw new Error(
'The implementation of newTrashcan should be ' +
'monkey-patched in by blockly.ts');
}
/**
* Add zoom controls.
* @internal
@@ -1663,7 +1672,9 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg {
* @return The created block.
*/
override newBlock(prototypeName: string, opt_id?: string): BlockSvg {
return new BlockSvg(this, prototypeName, opt_id);
throw new Error(
'The implementation of newBlock should be ' +
'monkey-patched in by blockly.ts');
}
/**
@@ -1856,7 +1867,8 @@ export class WorkspaceSvg extends Workspace implements IASTNodeLocationSvg {
// Start at 1 since the 0th block was used for initialization.
for (let i = 1; i < topElements.length; i++) {
const topElement = topElements[i];
if (topElement instanceof BlockSvg && topElement.isInsertionMarker()) {
if ((topElement as AnyDuringMigration).isInsertionmarker &&
(topElement as AnyDuringMigration).isInsertionMarker()) {
continue;
}
const blockBoundary = topElement.getBoundingRectangle();
+4 -4
View File
@@ -16,13 +16,13 @@ import * as goog from '../closure/goog/goog.js';
goog.declareModuleId('Blockly.Xml');
// Unused import preserved for side-effects. Remove if unneeded.
import './comment.js';
// import './comment.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './variables.js';
// import './variables.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './workspace_comment.js';
// import './workspace_comment.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './workspace_comment_svg.js';
// import './workspace_comment_svg.js';
import type {Block} from './block.js';
import type {BlockSvg} from './block_svg.js';
+1 -1
View File
@@ -17,7 +17,7 @@ goog.declareModuleId('Blockly.ZoomControls');
/* eslint-disable-next-line no-unused-vars */
// Unused import preserved for side-effects. Remove if unneeded.
import './metrics_manager.js';
// import './metrics_manager.js';
// Unused import preserved for side-effects. Remove if unneeded.
import './events/events_click.js';
+110 -110
View File
@@ -9,8 +9,12 @@
"all4:11:main"
],
"js": [
"./build/src/core/trashcan.js",
"./build/src/core/toolbox/toolbox.js",
"./build/src/core/toolbox/separator.js",
"./build/src/core/toolbox/collapsible_category.js",
"./build/src/core/toolbox/toolbox_item.js",
"./build/src/core/toolbox/category.js",
"./build/src/core/theme/zelos.js",
"./build/src/core/theme/themes.js",
"./build/src/core/shortcut_items.js",
@@ -35,67 +39,35 @@
"./build/src/core/renderers/minimalist/drawer.js",
"./build/src/core/renderers/minimalist/constants.js",
"./build/src/core/renderers/minimalist/minimalist.js",
"./build/src/core/renderers/geras/renderer.js",
"./build/src/core/renderers/geras/path_object.js",
"./build/src/core/renderers/geras/measurables/statement_input.js",
"./build/src/core/renderers/geras/measurables/inline_input.js",
"./build/src/core/renderers/geras/info.js",
"./build/src/core/renderers/geras/highlight_constants.js",
"./build/src/core/renderers/geras/renderer.js",
"./build/src/core/renderers/geras/highlighter.js",
"./build/src/core/renderers/geras/drawer.js",
"./build/src/core/renderers/geras/constants.js",
"./build/src/core/renderers/geras/geras.js",
"./build/src/core/workspace_drag_surface_svg.js",
"./build/src/core/shortcut_registry.js",
"./build/src/core/inject.js",
"./build/src/core/generator.js",
"./build/src/core/flyout_vertical.js",
"./build/src/core/flyout_horizontal.js",
"./build/src/core/scrollbar_pair.js",
"./build/src/core/flyout_metrics_manager.js",
"./build/src/core/flyout_button.js",
"./build/src/core/flyout_base.js",
"./build/src/core/field_variable.js",
"./build/src/core/field_number.js",
"./build/src/core/field_multilineinput.js",
"./build/src/core/field_label_serializable.js",
"./build/src/core/field_image.js",
"./build/src/core/field_colour.js",
"./build/src/core/field_checkbox.js",
"./build/src/core/field_textinput.js",
"./build/src/core/field_angle.js",
"./build/src/core/events/events_block_move.js",
"./build/src/core/events/events_comment_move.js",
"./build/src/core/events/events_toolbox_item_select.js",
"./build/src/core/events/events.js",
"./build/src/core/contextmenu_items.js",
"./build/src/core/block_drag_surface.js",
"./build/src/core/events/events_ui.js",
"./build/src/core/events/workspace_events.js",
"./build/src/core/serialization/registry.js",
"./build/src/core/serialization/priorities.js",
"./build/src/core/serialization/exceptions.js",
"./build/src/core/events/events_var_rename.js",
"./build/src/core/events/events_var_delete.js",
"./build/src/core/variable_map.js",
"./build/src/core/constants.js",
"./build/src/core/connection.js",
"./build/src/core/connection_checker.js",
"./build/src/core/workspace.js",
"./build/src/core/field_dropdown.js",
"./build/src/core/sprites.js",
"./build/src/core/positionable_helpers.js",
"./build/src/core/zoom_controls.js",
"./build/src/core/workspace_audio.js",
"./build/src/core/variable_map.js",
"./build/src/core/workspace.js",
"./build/src/core/variables_dynamic.js",
"./build/src/core/utils.js",
"./build/src/core/drag_target.js",
"./build/src/core/delete_area.js",
"./build/src/core/events/events_trashcan_open.js",
"./build/src/core/trashcan.js",
"./build/src/core/touch_gesture.js",
"./build/src/core/theme_manager.js",
"./build/src/core/renderers/common/renderer.js",
"./build/src/core/renderers/common/path_object.js",
"./build/src/core/events/events_marker_move.js",
"./build/src/core/renderers/common/marker_svg.js",
"./build/src/core/input_types.js",
"./build/src/core/input.js",
"./build/src/core/renderers/common/info.js",
"./build/src/core/renderers/common/drawer.js",
"./build/src/core/renderers/common/debugger.js",
@@ -124,112 +96,140 @@
"./build/src/core/renderers/measurables/types.js",
"./build/src/core/renderers/measurables/base.js",
"./build/src/core/renderers/common/block_rendering.js",
"./build/src/core/names.js",
"./build/src/core/procedures.js",
"./build/src/core/grid.js",
"./build/src/core/workspace_dragger.js",
"./build/src/core/gesture.js",
"./build/src/core/workspace_svg.js",
"./build/src/core/scrollbar_pair.js",
"./build/src/core/metrics_manager.js",
"./build/src/core/flyout_metrics_manager.js",
"./build/src/core/flyout_button.js",
"./build/src/core/flyout_base.js",
"./build/src/core/field_variable.js",
"./build/src/core/field_number.js",
"./build/src/core/field_multilineinput.js",
"./build/src/core/field_label_serializable.js",
"./build/src/core/field_image.js",
"./build/src/core/field_colour.js",
"./build/src/core/field_checkbox.js",
"./build/src/core/field_textinput.js",
"./build/src/core/field_angle.js",
"./build/src/core/drag_target.js",
"./build/src/core/delete_area.js",
"./build/src/core/events/events_block_move.js",
"./build/src/core/events/events_click.js",
"./build/src/core/events/events_comment_base.js",
"./build/src/core/events/events_comment_change.js",
"./build/src/core/events/events_comment_create.js",
"./build/src/core/events/events_comment_delete.js",
"./build/src/core/events/events_comment_move.js",
"./build/src/core/events/events_marker_move.js",
"./build/src/core/events/events_theme_change.js",
"./build/src/core/events/events_toolbox_item_select.js",
"./build/src/core/events/events_trashcan_open.js",
"./build/src/core/events/events_var_delete.js",
"./build/src/core/events/events_var_rename.js",
"./build/src/core/events/events_viewport.js",
"./build/src/core/events/events.js",
"./build/src/core/contextmenu_items.js",
"./build/src/core/connection_db.js",
"./build/src/core/connection_checker.js",
"./build/src/core/bubble_dragger.js",
"./build/src/core/warning.js",
"./build/src/core/utils/svg_paths.js",
"./build/src/core/rendered_connection.js",
"./build/src/core/keyboard_nav/marker.js",
"./build/src/core/keyboard_nav/cursor.js",
"./build/src/core/keyboard_nav/basic_cursor.js",
"./build/src/core/keyboard_nav/tab_navigate_cursor.js",
"./build/src/core/keyboard_nav/ast_node.js",
"./build/src/core/field_registry.js",
"./build/src/core/utils/sentinel.js",
"./build/src/core/marker_manager.js",
"./build/src/core/dropdowndiv.js",
"./build/src/core/workspace_dragger.js",
"./build/src/core/tooltip.js",
"./build/src/core/bubble_dragger.js",
"./build/src/core/internal_constants.js",
"./build/src/core/contextmenu_registry.js",
"./build/src/core/clipboard.js",
"./build/src/core/contextmenu.js",
"./build/src/core/comment.js",
"./build/src/core/block_svg.js",
"./build/src/core/component_manager.js",
"./build/src/core/insertion_marker_manager.js",
"./build/src/core/bump_objects.js",
"./build/src/core/events/events_block_drag.js",
"./build/src/core/block_dragger.js",
"./build/src/core/gesture.js",
"./build/src/core/shortcut_registry.js",
"./build/src/core/field.js",
"./build/src/core/field_label.js",
"./build/src/core/contextmenu_registry.js",
"./build/src/core/events/events_comment_change.js",
"./build/src/core/workspace_comment.js",
"./build/src/core/events/events_comment_delete.js",
"./build/src/core/events/events_comment_base.js",
"./build/src/core/events/events_comment_create.js",
"./build/src/core/workspace_comment_svg.js",
"./build/src/core/widgetdiv.js",
"./build/src/core/menuitem.js",
"./build/src/core/utils/keycodes.js",
"./build/src/core/menu.js",
"./build/src/core/clipboard.js",
"./build/src/core/contextmenu.js",
"./build/src/core/block_drag_surface.js",
"./build/src/core/block_animations.js",
"./build/src/core/events/events_selected.js",
"./build/src/core/block_svg.js",
"./build/src/core/events/events_viewport.js",
"./build/src/core/events/events_theme_change.js",
"./build/src/core/sprites.js",
"./build/src/core/positionable_helpers.js",
"./build/src/core/utils/array.js",
"./build/src/core/component_manager.js",
"./build/src/core/events/events_click.js",
"./build/src/core/zoom_controls.js",
"./build/src/core/utils/svg_paths.js",
"./build/src/core/internal_constants.js",
"./build/src/core/rendered_connection.js",
"./build/src/core/variables_dynamic.js",
"./build/src/core/names.js",
"./build/src/core/procedures.js",
"./build/src/core/workspace_svg.js",
"./build/src/core/keyboard_nav/ast_node.js",
"./build/src/core/utils/toolbox.js",
"./build/src/core/theme/classic.js",
"./build/src/core/theme.js",
"./build/src/core/options.js",
"./build/src/core/icon.js",
"./build/src/core/config.js",
"./build/src/core/utils/math.js",
"./build/src/core/utils/style.js",
"./build/src/core/utils/rect.js",
"./build/src/core/utils/svg_math.js",
"./build/src/core/utils/svg.js",
"./build/src/core/utils/coordinate.js",
"./build/src/core/scrollbar.js",
"./build/src/core/touch.js",
"./build/src/core/browser_events.js",
"./build/src/core/toolbox/separator.js",
"./build/src/core/toolbox/toolbox_item.js",
"./build/src/core/msg.js",
"./build/src/core/utils/parsing.js",
"./build/src/core/utils/useragent.js",
"./build/src/core/utils/dom.js",
"./build/src/core/utils/colour.js",
"./build/src/core/utils/aria.js",
"./build/src/core/utils/deprecation.js",
"./build/src/core/css.js",
"./build/src/core/toolbox/category.js",
"./build/src/core/utils/toolbox.js",
"./build/src/core/utils/size.js",
"./build/src/core/metrics_manager.js",
"./build/src/core/bubble.js",
"./build/src/core/events/events_ui_base.js",
"./build/src/core/events/events_bubble_open.js",
"./build/src/core/mutator.js",
"./build/src/core/menuitem.js",
"./build/src/core/utils/keycodes.js",
"./build/src/core/utils/aria.js",
"./build/src/core/menu.js",
"./build/src/core/field_registry.js",
"./build/src/core/widgetdiv.js",
"./build/src/core/utils/sentinel.js",
"./build/src/core/utils/colour.js",
"./build/src/core/utils/parsing.js",
"./build/src/core/tooltip.js",
"./build/src/core/marker_manager.js",
"./build/src/core/field.js",
"./build/src/core/utils/math.js",
"./build/src/core/dropdowndiv.js",
"./build/src/core/field_dropdown.js",
"./build/src/core/extensions.js",
"./build/src/core/constants.js",
"./build/src/core/connection_type.js",
"./build/src/core/connection.js",
"./build/src/core/events/events_block_delete.js",
"./build/src/core/events/events_abstract.js",
"./build/src/core/events/events_block_base.js",
"./build/src/core/events/events_block_change.js",
"./build/src/core/block.js",
"./build/src/core/field_label.js",
"./build/src/core/input.js",
"./build/src/core/utils/object.js",
"./build/src/core/utils/string.js",
"./build/src/core/events/events_ui.js",
"./build/src/core/events/workspace_events.js",
"./build/src/core/events/events_block_base.js",
"./build/src/core/serialization/registry.js",
"./build/src/core/serialization/priorities.js",
"./build/src/core/serialization/exceptions.js",
"./build/src/core/utils/useragent.js",
"./build/src/core/utils/dom.js",
"./build/src/core/dialog.js",
"./build/src/core/msg.js",
"./build/src/core/events/events_abstract.js",
"./build/src/core/events/events_var_base.js",
"./build/src/core/events/events_var_create.js",
"./build/src/core/variable_model.js",
"./build/src/core/variables.js",
"./build/src/core/utils/string.js",
"./build/src/core/comment.js",
"./build/src/core/utils/coordinate.js",
"./build/src/core/workspace_comment.js",
"./build/src/core/events/events_ui_base.js",
"./build/src/core/events/events_selected.js",
"./build/src/core/touch.js",
"./build/src/core/browser_events.js",
"./build/src/core/utils/deprecation.js",
"./build/src/core/css.js",
"./build/src/core/utils/rect.js",
"./build/src/core/utils/svg.js",
"./build/src/core/utils/style.js",
"./build/src/core/utils/svg_math.js",
"./build/src/core/workspace_comment_svg.js",
"./build/src/core/xml.js",
"./build/src/core/utils/xml.js",
"./build/src/core/connection_type.js",
"./build/src/core/utils/size.js",
"./build/src/core/input_types.js",
"./build/src/core/utils/idgenerator.js",
"./build/src/core/blocks.js",
"./build/src/core/common.js",
"./build/src/core/utils/idgenerator.js",
"./build/src/core/events/utils.js",
"./build/src/core/serialization/blocks.js",
"./build/src/core/registry.js",
+7 -7
View File
@@ -85,13 +85,13 @@
// List of scripts to load in compressed mode, instead of
// requires. Paths relative to root.
compressedScripts: [
'blockly_compressed.js',
'blocks_compressed.js',
'dart_compressed.js',
'javascript_compressed.js',
'lua_compressed.js',
'php_compressed.js',
'python_compressed.js',
'build/blockly_compressed.js',
'build/blocks_compressed.js',
'build/dart_compressed.js',
'build/javascript_compressed.js',
'build/lua_compressed.js',
'build/php_compressed.js',
'build/python_compressed.js',
],
// Additional scripts to be loaded after Blockly is loaded,
+1 -1
View File
@@ -289,7 +289,7 @@ suite('Block JSON initialization', function() {
suite('fieldFromJson_', function() {
setup(function() {
this.stub = sinon.stub(Blockly.fieldRegistry, 'fromJson')
this.stub = sinon.stub(Blockly.fieldRegistry.TEST_ONLY, 'fromJsonInternal')
.callsFake(function(elem) {
switch (elem['type']) {
case 'field_label':
+1 -1
View File
@@ -1097,7 +1097,7 @@ suite('Blocks', function() {
chai.assert.notEqual(event.type, eventUtils.BLOCK_CHANGE);
}
setup(function() {
this.eventsFireSpy = sinon.spy(eventUtils, 'fire');
this.eventsFireSpy = sinon.spy(eventUtils.TEST_ONLY, 'fireInternal');
});
teardown(function() {
this.eventsFireSpy.restore();
+3 -3
View File
@@ -203,13 +203,13 @@ suite('Connection Database', function() {
suite('Search For Closest', function() {
setup(function() {
// Ignore type checks.
sinon.stub(this.database.connectionChecker_, 'doTypeChecks')
sinon.stub(this.database.connectionChecker, 'doTypeChecks')
.returns(true);
// Ignore safety checks.
sinon.stub(this.database.connectionChecker_, 'doSafetyChecks')
sinon.stub(this.database.connectionChecker, 'doSafetyChecks')
.returns(Blockly.Connection.CAN_CONNECT);
// Skip everything but the distance checks.
sinon.stub(this.database.connectionChecker_, 'doDragChecks')
sinon.stub(this.database.connectionChecker, 'doDragChecks')
.callsFake(function(a, b, distance) {
return a.distanceFrom(b) <= distance;
});
+4 -4
View File
@@ -260,7 +260,7 @@ suite('Context Menu Items', function() {
test('Deletes all blocks after confirming', function() {
// Mocks the confirmation dialog and calls the callback with 'true' simulating ok.
const confirmStub = sinon.stub(
Blockly.dialog, 'confirm').callsArgWith(1, true);
Blockly.dialog.TEST_ONLY, 'confirmInternal').callsArgWith(1, true);
this.workspace.newBlock('text');
this.workspace.newBlock('text');
@@ -273,7 +273,7 @@ suite('Context Menu Items', function() {
test('Does not delete blocks if not confirmed', function() {
// Mocks the confirmation dialog and calls the callback with 'false' simulating cancel.
const confirmStub = sinon.stub(
Blockly.dialog, 'confirm').callsArgWith(1, false);
Blockly.dialog.TEST_ONLY, 'confirmInternal').callsArgWith(1, false);
this.workspace.newBlock('text');
this.workspace.newBlock('text');
@@ -284,7 +284,7 @@ suite('Context Menu Items', function() {
});
test('No dialog for single block', function() {
const confirmStub = sinon.stub(Blockly.dialog, 'confirm');
const confirmStub = sinon.stub(Blockly.dialog.TEST_ONLY, 'confirmInternal');
this.workspace.newBlock('text');
this.deleteOption.callback(this.scope);
this.clock.runAll();
@@ -334,7 +334,7 @@ suite('Context Menu Items', function() {
});
test('Calls duplicate', function() {
const spy = sinon.spy(Blockly.clipboard, 'duplicate');
const spy = sinon.spy(Blockly.clipboard.TEST_ONLY, 'duplicateInternal');
this.duplicateOption.callback(this.scope);
+1 -1
View File
@@ -22,7 +22,7 @@ suite('DropDownDiv', function() {
width: 100,
height: 100,
});
this.sizeStub = sinon.stub(Blockly.utils.style, 'getSize')
this.sizeStub = sinon.stub(Blockly.utils.style.TEST_ONLY, 'getSizeInternal')
.returns({
width: 60,
height: 60,
+1 -1
View File
@@ -17,7 +17,7 @@ goog.require('Blockly.WorkspaceComment');
suite('Events', function() {
setup(function() {
sharedTestSetup.call(this, {fireEventsNow: false});
this.eventsFireSpy = sinon.spy(eventUtils, 'fire');
this.eventsFireSpy = sinon.spy(eventUtils.TEST_ONLY, 'fireInternal');
this.workspace = new Blockly.Workspace();
Blockly.defineBlocksWithJsonArray([{
'type': 'field_variable_test_block',
+1 -1
View File
@@ -18,7 +18,7 @@ suite('Variable Fields', function() {
sharedTestSetup.call(this);
this.workspace = new Blockly.Workspace();
// Stub for default variable name.
sinon.stub(Blockly.Variables, 'generateUniqueName').returns(
sinon.stub(Blockly.Variables.TEST_ONLY, 'generateUniqueNameInternal').returns(
FAKE_VARIABLE_NAME);
});
teardown(function() {
+1 -1
View File
@@ -103,7 +103,7 @@ suite('Key Down', function() {
suite('Copy', function() {
setup(function() {
setSelectedBlock(this.workspace);
this.copySpy = sinon.spy(Blockly.clipboard, 'copy');
this.copySpy = sinon.spy(Blockly.clipboard.TEST_ONLY, 'copyInternal');
this.hideChaffSpy = sinon.spy(
Blockly.WorkspaceSvg.prototype, 'hideChaff');
});
+2 -2
View File
@@ -36,7 +36,7 @@ exports.workspaceTeardown = workspaceTeardown;
* @private
*/
function createEventsFireStubFireImmediately_(clock) {
const stub = sinon.stub(eventUtils, 'fire');
const stub = sinon.stub(eventUtils.TEST_ONLY, 'fireInternal');
stub.callsFake(function(event) {
// Call original method.
stub.wrappedMethod.call(this, ...arguments);
@@ -79,7 +79,7 @@ exports.addBlockTypeToCleanup = addBlockTypeToCleanup;
* @private
*/
function wrapDefineBlocksWithJsonArrayWithCleanup_(sharedCleanupObj) {
const stub = sinon.stub(Blockly, 'defineBlocksWithJsonArray');
const stub = sinon.stub(Blockly.common.TEST_ONLY, 'defineBlocksWithJsonArrayInternal');
stub.callsFake(function(jsonArray) {
if (jsonArray) {
jsonArray.forEach((jsonBlock) => {
+5 -5
View File
@@ -62,7 +62,7 @@ function testAWorkspace() {
suite('clear', function() {
test('Trivial', function() {
sinon.stub(eventUtils, "setGroup").returns(null);
sinon.stub(eventUtils.TEST_ONLY, "setGroupInternal").returns(null);
this.workspace.createVariable('name1', 'type1', 'id1');
this.workspace.createVariable('name2', 'type2', 'id2');
this.workspace.newBlock('');
@@ -75,7 +75,7 @@ function testAWorkspace() {
});
test('No variables', function() {
sinon.stub(eventUtils, "setGroup").returns(null);
sinon.stub(eventUtils.TEST_ONLY, "setGroupInternal").returns(null);
this.workspace.newBlock('');
this.workspace.clear();
@@ -98,7 +98,7 @@ function testAWorkspace() {
test('deleteVariableById(id2) one usage', function() {
// Deleting variable one usage should not trigger confirm dialog.
const stub =
sinon.stub(Blockly.dialog, "confirm").callsArgWith(1, true);
sinon.stub(Blockly.dialog.TEST_ONLY, "confirmInternal").callsArgWith(1, true);
this.workspace.deleteVariableById('id2');
sinon.assert.notCalled(stub);
@@ -111,7 +111,7 @@ function testAWorkspace() {
test('deleteVariableById(id1) multiple usages confirm', function() {
// Deleting variable with multiple usages triggers confirm dialog.
const stub =
sinon.stub(Blockly.dialog, "confirm").callsArgWith(1, true);
sinon.stub(Blockly.dialog.TEST_ONLY, "confirmInternal").callsArgWith(1, true);
this.workspace.deleteVariableById('id1');
sinon.assert.calledOnce(stub);
@@ -124,7 +124,7 @@ function testAWorkspace() {
test('deleteVariableById(id1) multiple usages cancel', function() {
// Deleting variable with multiple usages triggers confirm dialog.
const stub =
sinon.stub(Blockly.dialog, "confirm").callsArgWith(1, false);
sinon.stub(Blockly.dialog.TEST_ONLY, "confirmInternal").callsArgWith(1, false);
this.workspace.deleteVariableById('id1');
sinon.assert.calledOnce(stub);
-4
View File
@@ -131,10 +131,6 @@ suite('Theme', function() {
sinon.stub(workspace, 'refreshToolboxSelection');
blockA.styleName_ = 'styleOne';
// Stubs are cleaned up in sharedTestTeardown
sinon.stub(Blockly, "getMainWorkspace").returns(workspace);
sinon.stub(Blockly, "hideChaff");
workspace.setTheme(theme);
// Checks that the theme was set correctly on Blockly namespace
+2 -2
View File
@@ -109,14 +109,14 @@ suite('WorkspaceSvg', function() {
}.bind(this), 'Existing toolbox is null. Can\'t create new toolbox.');
});
test('Existing toolbox has no categories', function() {
sinon.stub(Blockly.utils.toolbox, 'hasCategories').returns(true);
sinon.stub(Blockly.utils.toolbox.TEST_ONLY, 'hasCategoriesInternal').returns(true);
this.workspace.toolbox_ = null;
chai.assert.throws(function() {
this.workspace.updateToolbox({'contents': []});
}.bind(this), 'Existing toolbox has no categories. Can\'t change mode.');
});
test('Existing toolbox has categories', function() {
sinon.stub(Blockly.utils.toolbox, 'hasCategories').returns(false);
sinon.stub(Blockly.utils.toolbox.TEST_ONLY, 'hasCategoriesInternal').returns(false);
this.workspace.flyout_ = null;
chai.assert.throws(function() {
this.workspace.updateToolbox({'contents': []});
+1
View File
@@ -8,6 +8,7 @@
compressed when it is being hosted or on Internet Explorer. -->
<script>
var BLOCKLY_BOOTSTRAP_OPTIONS = {
loadCompressed: true,
additionalScripts: [
'msg/messages.js',
'tests/playgrounds/screenshot.js',