Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/blockly/core/widgetdiv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,13 @@ export function hideIfOwnerIsInWorkspace(workspace: WorkspaceSvg) {
let ownerIsInWorkspace = ownerWorkspace === null;
// Check if the given workspace is a parent workspace of the one containing
// our owner.
let currentWorkspace: WorkspaceSvg | null = workspace;
let currentWorkspace: WorkspaceSvg | null = ownerWorkspace;
while (!ownerIsInWorkspace && currentWorkspace) {
if (currentWorkspace === workspace) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check was always true first time as the currentWorkspace was workspace only because of the assignment on line 262. Thus an ownership check would always return true

ownerIsInWorkspace = true;
break;
}
currentWorkspace = workspace.options.parentWorkspace;
currentWorkspace = currentWorkspace.options.parentWorkspace;
}

if (ownerIsInWorkspace) {
Expand Down
62 changes: 62 additions & 0 deletions packages/blockly/tests/mocha/widget_div_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,4 +477,66 @@ suite('WidgetDiv', function () {
);
});
});

suite('hideIfOwnerIsInWorkspace()', function () {
let otherDiv: HTMLDivElement;
let otherWorkspace: Blockly.WorkspaceSvg;

setup(function () {
otherDiv = document.createElement('div');
document.body.appendChild(otherDiv);
otherWorkspace = Blockly.inject(otherDiv, DEFAULT_INJECT_OPTIONS);
});

teardown(function () {
otherWorkspace.dispose();
otherDiv.remove();
});

async function openMutatorWorkspace() {
const block = workspace.newBlock('controls_if');
block.initSvg();
block.render();
const icon = block.getIcon(Blockly.icons.MutatorIcon.TYPE);
assert.isDefined(icon);
await icon.setBubbleVisible(true);
const mutatorWorkspace = icon.getWorkspace();
assert.isDefined(mutatorWorkspace);
return mutatorWorkspace;
}

test('hides div owned by the given workspace', function () {
Blockly.WidgetDiv.show({}, false, () => {}, workspace);

Blockly.WidgetDiv.hideIfOwnerIsInWorkspace(workspace);

assert.isFalse(Blockly.WidgetDiv.isVisible());
});

test('does not hide div owned by an unrelated workspace', function () {
Blockly.WidgetDiv.show({}, false, () => {}, workspace);

Blockly.WidgetDiv.hideIfOwnerIsInWorkspace(otherWorkspace);

assert.isTrue(Blockly.WidgetDiv.isVisible());
});

test('hides div owned by a child mutator workspace', async function () {
const mutatorWorkspace = await openMutatorWorkspace();
Blockly.WidgetDiv.show({}, false, () => {}, mutatorWorkspace);

Blockly.WidgetDiv.hideIfOwnerIsInWorkspace(workspace);

assert.isFalse(Blockly.WidgetDiv.isVisible());
});

test('does not hide div owned by the parent of a mutator workspace', async function () {
const mutatorWorkspace = await openMutatorWorkspace();
Blockly.WidgetDiv.show({}, false, () => {}, workspace);

Blockly.WidgetDiv.hideIfOwnerIsInWorkspace(mutatorWorkspace);

assert.isTrue(Blockly.WidgetDiv.isVisible());
});
});
});
41 changes: 41 additions & 0 deletions packages/plugins/workspace-minimap/test/minimap_tests.mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -441,13 +441,22 @@ suite('Mirroring events', function () {
'<!DOCTYPE html><div id="blocklyDiv"></div>',
);
global.SVGElement = window.SVGElement;
global.FocusEvent = window.FocusEvent;
window.HTMLCanvasElement.prototype.getContext = () => ({
measureText: () => ({
width: '',
fontBoundingBoxAscent: 12,
fontBoundingBoxDescent: 4,
}),
});
// jsdom does not implement CSS.escape, which keyboard navigation uses to
// look up elements by ID.
global.CSS = {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically doing a tab on a keyboard, tries to use the querySelector('#' + escaped) to find the next tab-able input. without this, an id starting with numbers or having characters like @ would throw invalid selector error. A bit of overengineering because blockly produces ids.
otherwise even escape: (s) => s would have worked

escape: (id) =>
id.replace(/^\d|[^\w-]/g, (char, offset) =>
offset === 0 && /\d/.test(char) ? `\\3${char} ` : `\\${char}`,
),
};
this.clock = sinon.useFakeTimers();
window.requestAnimationFrame = (callback) => setTimeout(callback, 0);
window.cancelAnimationFrame = (id) => clearTimeout(id);
Expand All @@ -463,6 +472,7 @@ suite('Mirroring events', function () {
this.workspace.dispose();
this.clock.runAll();
sinon.restore();
delete global.CSS;
this.jsdomCleanup();
});

Expand All @@ -481,6 +491,37 @@ suite('Mirroring events', function () {
'Minimap block should show the renamed variable',
);
});

test('Tabbing between edited fields keeps the next editor open', async function () {
const block = Blockly.serialization.blocks.append(
{
type: 'controls_for',
inputs: {
FROM: {shadow: {type: 'math_number', fields: {NUM: 1}}},
TO: {shadow: {type: 'math_number', fields: {NUM: 10}}},
},
},
this.workspace,
);
await this.clock.runAllAsync();
const fromField = block.getInputTargetBlock('FROM').getField('NUM');
const toField = block.getInputTargetBlock('TO').getField('NUM');

fromField.showEditor();
fromField.setValue(2);
document
.querySelector('.blocklyHtmlInput')
.dispatchEvent(
new window.KeyboardEvent('keydown', {key: 'Tab', bubbles: true}),
);
// Let the minimap mirror the change and zoom to fit.
await this.clock.runAllAsync();

assert.isTrue(
toField.isBeingEdited_,
'The editor opened by Tab should stay open after the minimap updates',
);
});
});

suite('Keyboard navigation', function () {
Expand Down
Loading