diff --git a/core/blockly.ts b/core/blockly.ts index 71db6e3aa..9def99fdf 100644 --- a/core/blockly.ts +++ b/core/blockly.ts @@ -50,12 +50,6 @@ import { FieldValidator, UnattachedFieldError, } from './field.js'; -import { - FieldAngle, - FieldAngleConfig, - FieldAngleFromJsonConfig, - FieldAngleValidator, -} from './field_angle.js'; import { FieldCheckbox, FieldCheckboxConfig, @@ -509,12 +503,6 @@ export {DeleteArea}; export {DragTarget}; export const DropDownDiv = dropDownDiv; export {Field, FieldConfig, FieldValidator, UnattachedFieldError}; -export { - FieldAngle, - FieldAngleConfig, - FieldAngleFromJsonConfig, - FieldAngleValidator, -}; export { FieldCheckbox, FieldCheckboxConfig, diff --git a/core/field_angle.ts b/core/field_angle.ts deleted file mode 100644 index 2069881ed..000000000 --- a/core/field_angle.ts +++ /dev/null @@ -1,595 +0,0 @@ -/** - * @license - * Copyright 2013 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * Angle input field. - * - * @class - */ -import * as goog from '../closure/goog/goog.js'; -goog.declareModuleId('Blockly.FieldAngle'); - -import {BlockSvg} from './block_svg.js'; -import * as browserEvents from './browser_events.js'; -import * as Css from './css.js'; -import * as dropDownDiv from './dropdowndiv.js'; -import {Field, UnattachedFieldError} from './field.js'; -import * as fieldRegistry from './field_registry.js'; -import { - FieldInput, - FieldInputConfig, - FieldInputValidator, -} from './field_input.js'; -import * as dom from './utils/dom.js'; -import * as math from './utils/math.js'; -import {Svg} from './utils/svg.js'; -import * as userAgent from './utils/useragent.js'; -import * as WidgetDiv from './widgetdiv.js'; - -/** - * Class for an editable angle field. - */ -export class FieldAngle extends FieldInput { - /** Half the width of protractor image. */ - static readonly HALF = 100 / 2; - - /** - * Radius of protractor circle. Slightly smaller than protractor size since - * otherwise SVG crops off half the border at the edges. - */ - static readonly RADIUS: number = FieldAngle.HALF - 1; - - /** - * Default property describing which direction makes an angle field's value - * increase. Angle increases clockwise (true) or counterclockwise (false). - */ - static readonly CLOCKWISE = false; - - /** - * The default offset of 0 degrees (and all angles). Always offsets in the - * counterclockwise direction, regardless of the field's clockwise property. - * Usually either 0 (0 = right) or 90 (0 = up). - */ - static readonly OFFSET = 0; - - /** - * The default maximum angle to allow before wrapping. - * Usually either 360 (for 0 to 359.9) or 180 (for -179.9 to 180). - */ - static readonly WRAP = 360; - - /** - * The default amount to round angles to when using a mouse or keyboard nav - * input. Must be a positive integer to support keyboard navigation. - */ - static readonly ROUND = 15; - - /** - * Whether the angle should increase as the angle picker is moved clockwise - * (true) or counterclockwise (false). - */ - private clockwise = FieldAngle.CLOCKWISE; - - /** - * The offset of zero degrees (and all other angles). - */ - private offset = FieldAngle.OFFSET; - - /** - * The maximum angle to allow before wrapping. - */ - private wrap = FieldAngle.WRAP; - - /** - * The amount to round angles to when using a mouse or keyboard nav input. - */ - private round = FieldAngle.ROUND; - - /** - * Array holding info needed to unbind events. - * Used for disposing. - * Ex: [[node, name, func], [node, name, func]]. - */ - private boundEvents: browserEvents.Data[] = []; - - /** Dynamic red line pointing at the value's angle. */ - private line: SVGLineElement | null = null; - - /** Dynamic pink area extending from 0 to the value's angle. */ - private gauge: SVGPathElement | null = null; - - /** The degree symbol for this field. */ - protected symbol_: SVGTSpanElement | null = null; - - /** - * @param value The initial value of the field. Should cast to a number. - * Defaults to 0. Also accepts Field.SKIP_SETUP if you wish to skip setup - * (only used by subclasses that want to handle configuration and setting - * the field value after their own constructors have run). - * @param validator A function that is called to validate changes to the - * field's value. Takes in a number & returns a validated number, or null - * to abort the change. - * @param config A map of options used to configure the field. - * See the [field creation documentation]{@link - * https://developers.google.com/blockly/guides/create-custom-blocks/fields/built-in-fields/angle#creation} - * for a list of properties this parameter supports. - */ - constructor( - value?: string | number | typeof Field.SKIP_SETUP, - validator?: FieldAngleValidator, - config?: FieldAngleConfig - ) { - super(Field.SKIP_SETUP); - - if (value === Field.SKIP_SETUP) return; - if (config) { - this.configure_(config); - } - this.setValue(value); - if (validator) { - this.setValidator(validator); - } - } - - /** - * Configure the field based on the given map of options. - * - * @param config A map of options to configure the field based on. - */ - protected override configure_(config: FieldAngleConfig) { - super.configure_(config); - - switch (config.mode) { - case Mode.COMPASS: - this.clockwise = true; - this.offset = 90; - break; - case Mode.PROTRACTOR: - // This is the default mode, so we could do nothing. But just to - // future-proof, we'll set it anyway. - this.clockwise = false; - this.offset = 0; - break; - } - - // Allow individual settings to override the mode setting. - if (config.clockwise) this.clockwise = config.clockwise; - if (config.offset) this.offset = config.offset; - if (config.wrap) this.wrap = config.wrap; - if (config.round) this.round = config.round; - } - - /** - * Create the block UI for this field. - * - * @internal - */ - override initView() { - super.initView(); - // Add the degree symbol to the left of the number, - // even in RTL (issue #2380). - this.symbol_ = dom.createSvgElement(Svg.TSPAN, {}); - this.symbol_.appendChild(document.createTextNode('°')); - this.getTextElement().appendChild(this.symbol_); - } - - /** Updates the angle when the field rerenders. */ - protected override render_() { - super.render_(); - this.updateGraph(); - } - - /** - * Create and show the angle field's editor. - * - * @param e Optional mouse event that triggered the field to open, - * or undefined if triggered programmatically. - */ - protected override showEditor_(e?: Event) { - // Mobile browsers have issues with in-line textareas (focus & keyboards). - const noFocus = userAgent.MOBILE || userAgent.ANDROID || userAgent.IPAD; - super.showEditor_(e, noFocus); - - const editor = this.dropdownCreate(); - dropDownDiv.getContentDiv().appendChild(editor); - - if (this.sourceBlock_ instanceof BlockSvg) { - dropDownDiv.setColour( - this.sourceBlock_.style.colourPrimary, - this.sourceBlock_.style.colourTertiary - ); - } - - dropDownDiv.showPositionedByField(this, this.dropdownDispose.bind(this)); - - this.updateGraph(); - } - - /** - * Creates the angle dropdown editor. - * - * @returns The newly created slider. - */ - private dropdownCreate(): SVGSVGElement { - const svg = dom.createSvgElement(Svg.SVG, { - 'xmlns': dom.SVG_NS, - 'xmlns:html': dom.HTML_NS, - 'xmlns:xlink': dom.XLINK_NS, - 'version': '1.1', - 'height': FieldAngle.HALF * 2 + 'px', - 'width': FieldAngle.HALF * 2 + 'px', - 'style': 'touch-action: none', - }); - const circle = dom.createSvgElement( - Svg.CIRCLE, - { - 'cx': FieldAngle.HALF, - 'cy': FieldAngle.HALF, - 'r': FieldAngle.RADIUS, - 'class': 'blocklyAngleCircle', - }, - svg - ); - this.gauge = dom.createSvgElement( - Svg.PATH, - {'class': 'blocklyAngleGauge'}, - svg - ); - this.line = dom.createSvgElement( - Svg.LINE, - { - 'x1': FieldAngle.HALF, - 'y1': FieldAngle.HALF, - 'class': 'blocklyAngleLine', - }, - svg - ); - // Draw markers around the edge. - for (let angle = 0; angle < 360; angle += 15) { - dom.createSvgElement( - Svg.LINE, - { - 'x1': FieldAngle.HALF + FieldAngle.RADIUS, - 'y1': FieldAngle.HALF, - 'x2': - FieldAngle.HALF + FieldAngle.RADIUS - (angle % 45 === 0 ? 10 : 5), - 'y2': FieldAngle.HALF, - 'class': 'blocklyAngleMarks', - 'transform': - 'rotate(' + - angle + - ',' + - FieldAngle.HALF + - ',' + - FieldAngle.HALF + - ')', - }, - svg - ); - } - - // The angle picker is different from other fields in that it updates on - // mousemove even if it's not in the middle of a drag. In future we may - // change this behaviour. - this.boundEvents.push( - browserEvents.conditionalBind(svg, 'click', this, this.hide) - ); - // On touch devices, the picker's value is only updated with a drag. Add - // a click handler on the drag surface to update the value if the surface - // is clicked. - this.boundEvents.push( - browserEvents.conditionalBind( - circle, - 'pointerdown', - this, - this.onMouseMove_, - true - ) - ); - this.boundEvents.push( - browserEvents.conditionalBind( - circle, - 'pointermove', - this, - this.onMouseMove_, - true - ) - ); - return svg; - } - - /** Disposes of events and DOM-references belonging to the angle editor. */ - private dropdownDispose() { - for (const event of this.boundEvents) { - browserEvents.unbind(event); - } - this.boundEvents.length = 0; - this.gauge = null; - this.line = null; - } - - /** Hide the editor. */ - private hide() { - dropDownDiv.hideIfOwner(this); - WidgetDiv.hide(); - } - - /** - * Set the angle to match the mouse's position. - * - * @param e Mouse move event. - */ - protected onMouseMove_(e: PointerEvent) { - // Calculate angle. - const bBox = this.gauge!.ownerSVGElement!.getBoundingClientRect(); - const dx = e.clientX - bBox.left - FieldAngle.HALF; - const dy = e.clientY - bBox.top - FieldAngle.HALF; - let angle = Math.atan(-dy / dx); - if (isNaN(angle)) { - // This shouldn't happen, but let's not let this error propagate further. - return; - } - angle = math.toDegrees(angle); - // 0: East, 90: North, 180: West, 270: South. - if (dx < 0) { - angle += 180; - } else if (dy > 0) { - angle += 360; - } - - // Do offsetting. - if (this.clockwise) { - angle = this.offset + 360 - angle; - } else { - angle = 360 - (this.offset - angle); - } - - this.displayMouseOrKeyboardValue(angle); - } - - /** - * Handles and displays values that are input via mouse or arrow key input. - * These values need to be rounded and wrapped before being displayed so - * that the text input's value is appropriate. - * - * @param angle New angle. - */ - private displayMouseOrKeyboardValue(angle: number) { - if (this.round) { - angle = Math.round(angle / this.round) * this.round; - } - angle = this.wrapValue(angle); - if (angle !== this.value_) { - this.setEditorValue_(angle); - } - } - - /** Redraw the graph with the current angle. */ - private updateGraph() { - if (!this.gauge || !this.line) { - return; - } - // Always display the input (i.e. getText) even if it is invalid. - let angleDegrees = Number(this.getText()) + this.offset; - angleDegrees %= 360; - let angleRadians = math.toRadians(angleDegrees); - const path = ['M ', FieldAngle.HALF, ',', FieldAngle.HALF]; - let x2 = FieldAngle.HALF; - let y2 = FieldAngle.HALF; - if (!isNaN(angleRadians)) { - const clockwiseFlag = Number(this.clockwise); - const angle1 = math.toRadians(this.offset); - const x1 = Math.cos(angle1) * FieldAngle.RADIUS; - const y1 = Math.sin(angle1) * -FieldAngle.RADIUS; - if (clockwiseFlag) { - angleRadians = 2 * angle1 - angleRadians; - } - x2 += Math.cos(angleRadians) * FieldAngle.RADIUS; - y2 -= Math.sin(angleRadians) * FieldAngle.RADIUS; - // Don't ask how the flag calculations work. They just do. - let largeFlag = Math.abs( - Math.floor((angleRadians - angle1) / Math.PI) % 2 - ); - if (clockwiseFlag) { - largeFlag = 1 - largeFlag; - } - path.push( - ' l ', - x1, - ',', - y1, - ' A ', - FieldAngle.RADIUS, - ',', - FieldAngle.RADIUS, - ' 0 ', - largeFlag, - ' ', - clockwiseFlag, - ' ', - x2, - ',', - y2, - ' z' - ); - } - this.gauge.setAttribute('d', path.join('')); - this.line.setAttribute('x2', `${x2}`); - this.line.setAttribute('y2', `${y2}`); - } - - /** - * Handle key down to the editor. - * - * @param e Keyboard event. - */ - protected override onHtmlInputKeyDown_(e: KeyboardEvent) { - super.onHtmlInputKeyDown_(e); - const block = this.getSourceBlock(); - if (!block) { - throw new UnattachedFieldError(); - } - - let multiplier = 0; - switch (e.key) { - case 'ArrowLeft': - // decrement (increment in RTL) - multiplier = block.RTL ? 1 : -1; - break; - case 'ArrowRight': - // increment (decrement in RTL) - multiplier = block.RTL ? -1 : 1; - break; - case 'ArrowDown': - // decrement - multiplier = -1; - break; - case 'ArrowUp': - // increment - multiplier = 1; - break; - } - if (multiplier) { - const value = this.getValue() as number; - this.displayMouseOrKeyboardValue(value + multiplier * this.round); - e.preventDefault(); - e.stopPropagation(); - } - } - - /** - * Ensure that the input value is a valid angle. - * - * @param newValue The input value. - * @returns A valid angle, or null if invalid. - */ - protected override doClassValidation_(newValue?: any): number | null { - const value = Number(newValue); - if (isNaN(value) || !isFinite(value)) { - return null; - } - return this.wrapValue(value); - } - - /** - * Wraps the value so that it is in the range (-360 + wrap, wrap). - * - * @param value The value to wrap. - * @returns The wrapped value. - */ - private wrapValue(value: number): number { - value %= 360; - if (value < 0) { - value += 360; - } - if (value > this.wrap) { - value -= 360; - } - return value; - } - - /** - * Construct a FieldAngle from a JSON arg object. - * - * @param options A JSON object with options (angle). - * @returns The new field instance. - * @nocollapse - * @internal - */ - static fromJson(options: FieldAngleFromJsonConfig): FieldAngle { - // `this` might be a subclass of FieldAngle if that class doesn't override - // the static fromJson method. - return new this(options.angle, undefined, options); - } -} - -fieldRegistry.register('field_angle', FieldAngle); - -FieldAngle.prototype.DEFAULT_VALUE = 0; - -/** - * CSS for angle field. - */ -Css.register(` -.blocklyAngleCircle { - stroke: #444; - stroke-width: 1; - fill: #ddd; - fill-opacity: 0.8; -} - -.blocklyAngleMarks { - stroke: #444; - stroke-width: 1; -} - -.blocklyAngleGauge { - fill: #f88; - fill-opacity: 0.8; - pointer-events: none; -} - -.blocklyAngleLine { - stroke: #f00; - stroke-width: 2; - stroke-linecap: round; - pointer-events: none; -} -`); - -/** - * The two main modes of the angle field. - * Compass specifies: - * - clockwise: true - * - offset: 90 - * - wrap: 0 - * - round: 15 - * - * Protractor specifies: - * - clockwise: false - * - offset: 0 - * - wrap: 0 - * - round: 15 - */ -export enum Mode { - COMPASS = 'compass', - PROTRACTOR = 'protractor', -} - -/** - * Extra configuration options for the angle field. - */ -export interface FieldAngleConfig extends FieldInputConfig { - mode?: Mode; - clockwise?: boolean; - offset?: number; - wrap?: number; - round?: number; -} - -/** - * fromJson configuration options for the angle field. - */ -export interface FieldAngleFromJsonConfig extends FieldAngleConfig { - angle?: number; -} - -/** - * A function that is called to validate changes to the field's value before - * they are set. - * - * @see {@link https://developers.google.com/blockly/guides/create-custom-blocks/fields/validators#return_values} - * @param newValue The value to be validated. - * @returns One of three instructions for setting the new value: `T`, `null`, - * or `undefined`. - * - * - `T` to set this function's returned value instead of `newValue`. - * - * - `null` to invoke `doValueInvalid_` and not set a value. - * - * - `undefined` to set `newValue` as is. - */ -export type FieldAngleValidator = FieldInputValidator; diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js deleted file mode 100644 index 067a91c3c..000000000 --- a/tests/mocha/field_angle_test.js +++ /dev/null @@ -1,391 +0,0 @@ -/** - * @license - * Copyright 2019 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -goog.declareModuleId('Blockly.test.fieldAngle'); - -import * as Blockly from '../../build/src/core/blockly.js'; -import { - assertFieldValue, - runConstructorSuiteTests, - runFromJsonSuiteTests, - runSetValueTests, -} from './test_helpers/fields.js'; -import { - createTestBlock, - defineRowBlock, -} from './test_helpers/block_definitions.js'; -import { - sharedTestSetup, - sharedTestTeardown, - workspaceTeardown, -} from './test_helpers/setup_teardown.js'; - -suite('Angle Fields', function () { - setup(function () { - sharedTestSetup.call(this); - }); - teardown(function () { - sharedTestTeardown.call(this); - }); - /** - * Configuration for field tests with invalid values. - * @type {!Array} - */ - const invalidValueTestCases = [ - {title: 'Undefined', value: undefined}, - {title: 'Null', value: null}, - {title: 'NaN', value: NaN}, - {title: 'Non-Parsable String', value: 'bad'}, - {title: 'Infinity', value: Infinity, expectedValue: Infinity}, - {title: 'Negative Infinity', value: -Infinity, expectedValue: -Infinity}, - {title: 'Infinity String', value: 'Infinity', expectedValue: Infinity}, - { - title: 'Negative Infinity String', - value: '-Infinity', - expectedValue: -Infinity, - }, - ]; - /** - * Configuration for field tests with valid values. - * @type {!Array} - */ - - const validValueTestCases = [ - {title: 'Integer', value: 1, expectedValue: 1}, - {title: 'Float', value: 1.5, expectedValue: 1.5}, - {title: 'Integer String', value: '1', expectedValue: 1}, - {title: 'Float String', value: '1.5', expectedValue: 1.5}, - {title: '> 360°', value: 362, expectedValue: 2}, - ]; - const addArgsAndJson = function (testCase) { - testCase.args = [testCase.value]; - testCase.json = {'angle': testCase.value}; - }; - invalidValueTestCases.forEach(addArgsAndJson); - validValueTestCases.forEach(addArgsAndJson); - - /** - * The expected default value for the field being tested. - * @type {*} - */ - const defaultFieldValue = 0; - /** - * Asserts that the field property values are set to default. - * @param {FieldTemplate} field The field to check. - */ - const assertFieldDefault = function (field) { - assertFieldValue(field, defaultFieldValue); - }; - /** - * Asserts that the field properties are correct based on the test case. - * @param {!Blockly.FieldAngle} field The field to check. - * @param {!FieldValueTestCase} testCase The test case. - */ - const validTestCaseAssertField = function (field, testCase) { - assertFieldValue(field, testCase.expectedValue); - }; - - runConstructorSuiteTests( - Blockly.FieldAngle, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault - ); - - runFromJsonSuiteTests( - Blockly.FieldAngle, - validValueTestCases, - invalidValueTestCases, - validTestCaseAssertField, - assertFieldDefault - ); - - suite('setValue', function () { - suite('Empty -> New Value', function () { - setup(function () { - this.field = new Blockly.FieldAngle(); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - defaultFieldValue - ); - test('With source block', function () { - this.field.setSourceBlock(createTestBlock()); - this.field.setValue(2.5); - assertFieldValue(this.field, 2.5); - }); - }); - suite('Value -> New Value', function () { - const initialValue = 1; - setup(function () { - this.field = new Blockly.FieldAngle(initialValue); - }); - runSetValueTests( - validValueTestCases, - invalidValueTestCases, - initialValue - ); - test('With source block', function () { - this.field.setSourceBlock(createTestBlock()); - this.field.setValue(2.5); - assertFieldValue(this.field, 2.5); - }); - }); - }); - suite('Validators', function () { - setup(function () { - this.field = new Blockly.FieldAngle(1); - this.field.htmlInput_ = document.createElement('input'); - this.field.htmlInput_.setAttribute('data-old-value', '1'); - this.field.htmlInput_.setAttribute('data-untyped-default-value', '1'); - this.stub = sinon.stub(this.field, 'resizeEditor_'); - }); - teardown(function () { - sinon.restore(); - }); - const testSuites = [ - { - title: 'Null Validator', - validator: function () { - return null; - }, - value: 2, - expectedValue: '1', - }, - { - title: 'Force Mult of 30 Validator', - validator: function (newValue) { - return Math.round(newValue / 30) * 30; - }, - value: 25, - expectedValue: 30, - }, - { - title: 'Returns Undefined Validator', - validator: function () {}, - value: 2, - expectedValue: 2, - }, - ]; - testSuites.forEach(function (suiteInfo) { - suite(suiteInfo.title, function () { - setup(function () { - this.field.setValidator(suiteInfo.validator); - }); - test('When Editing', function () { - this.field.isBeingEdited_ = true; - this.field.htmlInput_.value = String(suiteInfo.value); - this.field.onHtmlInputChange_(null); - assertFieldValue( - this.field, - suiteInfo.expectedValue, - String(suiteInfo.value) - ); - }); - test('When Not Editing', function () { - this.field.setValue(suiteInfo.value); - assertFieldValue(this.field, +suiteInfo.expectedValue); - }); - }); - }); - }); - suite('Customizations', function () { - suite('Clockwise', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - clockwise: true, - }); - chai.assert.isTrue(field.clockwise); - }); - test('JSON Definition', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - clockwise: true, - }); - chai.assert.isTrue(field.clockwise); - }); - test('Constant', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.CLOCKWISE = true; - const field = new Blockly.FieldAngle(); - chai.assert.isTrue(field.clockwise); - }); - }); - suite('Offset', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - offset: 90, - }); - chai.assert.equal(field.offset, 90); - }); - test('JSON Definition', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - offset: 90, - }); - chai.assert.equal(field.offset, 90); - }); - test('Constant', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.OFFSET = 90; - const field = new Blockly.FieldAngle(); - chai.assert.equal(field.offset, 90); - }); - test('Null', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.OFFSET = 90; - const field = Blockly.FieldAngle.fromJson({ - value: 0, - offset: null, - }); - chai.assert.equal(field.offset, 90); - }); - }); - suite('Wrap', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - wrap: 180, - }); - chai.assert.equal(field.wrap, 180); - }); - test('JSON Definition', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - wrap: 180, - }); - chai.assert.equal(field.wrap, 180); - }); - test('Constant', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.WRAP = 180; - const field = new Blockly.FieldAngle(); - chai.assert.equal(field.wrap, 180); - }); - test('Null', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.WRAP = 180; - const field = Blockly.FieldAngle.fromJson({ - value: 0, - wrap: null, - }); - chai.assert.equal(field.wrap, 180); - }); - }); - suite('Round', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - round: 30, - }); - chai.assert.equal(field.round, 30); - }); - test('JSON Definition', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - round: 30, - }); - chai.assert.equal(field.round, 30); - }); - test('Constant', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.ROUND = 30; - const field = new Blockly.FieldAngle(); - chai.assert.equal(field.round, 30); - }); - test('Null', function () { - // Note: Generally constants should be set at compile time, not - // runtime (since they are constants) but for testing purposes we - // can do this. - Blockly.FieldAngle.ROUND = 30; - const field = Blockly.FieldAngle.fromJson({ - value: 0, - round: null, - }); - chai.assert.equal(field.round, 30); - }); - }); - suite('Mode', function () { - suite('Compass', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - mode: 'compass', - }); - chai.assert.equal(field.offset, 90); - chai.assert.isTrue(field.clockwise); - }); - test('JS Configuration', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - mode: 'compass', - }); - chai.assert.equal(field.offset, 90); - chai.assert.isTrue(field.clockwise); - }); - }); - suite('Protractor', function () { - test('JS Configuration', function () { - const field = new Blockly.FieldAngle(0, null, { - mode: 'protractor', - }); - chai.assert.equal(field.offset, 0); - chai.assert.isFalse(field.clockwise); - }); - test('JS Configuration', function () { - const field = Blockly.FieldAngle.fromJson({ - value: 0, - mode: 'protractor', - }); - chai.assert.equal(field.offset, 0); - chai.assert.isFalse(field.clockwise); - }); - }); - }); - }); - - suite('Serialization', function () { - setup(function () { - this.workspace = new Blockly.Workspace(); - defineRowBlock(); - - this.assertValue = (value) => { - const block = this.workspace.newBlock('row_block'); - const field = new Blockly.FieldAngle(value); - block.getInput('INPUT').appendField(field, 'ANGLE'); - const jso = Blockly.serialization.blocks.save(block); - chai.assert.deepEqual(jso['fields'], {'ANGLE': value}); - }; - }); - - teardown(function () { - workspaceTeardown.call(this, this.workspace); - }); - - test('Simple', function () { - this.assertValue(90); - }); - - test('Max precision', function () { - this.assertValue(1.000000000000001); - }); - - test('Smallest number', function () { - this.assertValue(5e-324); - }); - }); -}); diff --git a/tests/mocha/index.html b/tests/mocha/index.html index 2d83837e1..e3583cd5f 100644 --- a/tests/mocha/index.html +++ b/tests/mocha/index.html @@ -82,7 +82,6 @@ 'Blockly.test.eventVarRename', 'Blockly.test.eventViewportChange', 'Blockly.test.extensions', - 'Blockly.test.fieldAngle', 'Blockly.test.fieldCheckbox', 'Blockly.test.fieldColour', 'Blockly.test.fieldDropdown', diff --git a/tests/mocha/serializer_test.js b/tests/mocha/serializer_test.js index 9f9f545fe..b7b91b63e 100644 --- a/tests/mocha/serializer_test.js +++ b/tests/mocha/serializer_test.js @@ -225,55 +225,6 @@ Serializer.Attributes.testSuites = [ Serializer.Fields = new SerializerTestSuite('Fields'); -Serializer.Fields.Angle = new SerializerTestSuite('Angle'); -Serializer.Fields.Angle.Simple = new SerializerTestCase( - 'Simple', - '' + - '' + - '90' + - '' + - '' -); -Serializer.Fields.Angle.Negative = new SerializerTestCase( - 'Negative', - '' + - '' + - '-90' + - '' + - '' -); -Serializer.Fields.Angle.Decimals = new SerializerTestCase( - 'Decimals', - '' + - '' + - '1.5' + - '' + - '' -); -Serializer.Fields.Angle.MaxPrecision = new SerializerTestCase( - 'MaxPrecision', - '' + - '' + - '1.000000000000001' + - '' + - '' -); -Serializer.Fields.Angle.SmallestNumber = new SerializerTestCase( - 'SmallestNumber', - '' + - '' + - '5e-324' + - '' + - '' -); -Serializer.Fields.Angle.testCases = [ - Serializer.Fields.Angle.Simple, - Serializer.Fields.Angle.Negative, - Serializer.Fields.Angle.Decimals, - Serializer.Fields.Angle.MaxPrecision, - Serializer.Fields.Angle.SmallestNumber, -]; - Serializer.Fields.Checkbox = new SerializerTestSuite('Checkbox'); Serializer.Fields.Checkbox.True = new SerializerTestCase( 'True', @@ -1072,7 +1023,6 @@ Serializer.Fields.Variable.Id.testSuites = [ Serializer.Fields.Variable.testSuites = [Serializer.Fields.Variable.Id]; Serializer.Fields.testSuites = [ - Serializer.Fields.Angle, Serializer.Fields.Checkbox, Serializer.Fields.Colour, Serializer.Fields.Dropdown, diff --git a/tests/mocha/xml_test.js b/tests/mocha/xml_test.js index 085984ed7..325649798 100644 --- a/tests/mocha/xml_test.js +++ b/tests/mocha/xml_test.js @@ -129,27 +129,6 @@ suite('XML', function () { workspaceTeardown.call(this, this.workspace); }); suite('Fields', function () { - test('Angle', function () { - Blockly.defineBlocksWithJsonArray([ - { - 'type': 'field_angle_test_block', - 'message0': '%1', - 'args0': [ - { - 'type': 'field_angle', - 'name': 'ANGLE', - 'angle': 90, - }, - ], - }, - ]); - const block = new Blockly.Block( - this.workspace, - 'field_angle_test_block' - ); - const resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0]; - assertNonVariableField(resultFieldDom, 'ANGLE', '90'); - }); test('Checkbox', function () { Blockly.defineBlocksWithJsonArray([ {