From 713e85ad8b3e1de58cbab35067663dd871413d2c Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 19 Mar 2020 14:44:22 +0100 Subject: [PATCH 01/12] Change name LabeledView -> LabeledFieldView. The commit also changes references #view -> #field. --- .../labeledfieldview.js} | 50 +++--- .../utils.js | 38 ++-- tests/labeledfieldview/labeledfieldview.js | 166 ++++++++++++++++++ tests/labeledfieldview/utils.js | 108 ++++++++++++ tests/labeledview/labeledview.js | 166 ------------------ tests/labeledview/utils.js | 108 ------------ .../labeledfieldview.css} | 0 7 files changed, 318 insertions(+), 318 deletions(-) rename src/{labeledview/labeledview.js => labeledfieldview/labeledfieldview.js} (78%) rename src/{labeledview => labeledfieldview}/utils.js (55%) create mode 100644 tests/labeledfieldview/labeledfieldview.js create mode 100644 tests/labeledfieldview/utils.js delete mode 100644 tests/labeledview/labeledview.js delete mode 100644 tests/labeledview/utils.js rename theme/components/{labeledview/labeledview.css => labeledfieldview/labeledfieldview.css} (100%) diff --git a/src/labeledview/labeledview.js b/src/labeledfieldview/labeledfieldview.js similarity index 78% rename from src/labeledview/labeledview.js rename to src/labeledfieldview/labeledfieldview.js index 62b9377a..c5be3222 100644 --- a/src/labeledview/labeledview.js +++ b/src/labeledfieldview/labeledfieldview.js @@ -4,16 +4,16 @@ */ /** - * @module ui/labeledview/labeledview + * @module ui/labeledfieldview/labeledfieldview */ import View from '../view'; import uid from '@ckeditor/ckeditor5-utils/src/uid'; import LabelView from '../label/labelview'; -import '../../theme/components/labeledview/labeledview.css'; +import '../../theme/components/labeledfieldview/labeledfieldview.css'; /** - * The labeled view class. It can be used to enhance any view with the following features: + * The labeled field view class. It can be used to enhance any view with the following features: * * * a label, * * (optional) an error message, @@ -25,16 +25,16 @@ import '../../theme/components/labeledview/labeledview.css'; * The constructor of this class requires a callback that returns a view to be labeled. The callback * is called with unique ids that allow binding of DOM properties: * - * const labeledInputView = new LabeledView( locale, ( labeledView, viewUid, statusUid ) => { - * const inputView = new InputTextView( labeledView.locale ); + * const labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { + * const inputView = new InputTextView( labeledFieldView.locale ); * * inputView.set( { * id: viewUid, * ariaDescribedById: statusUid * } ); * - * inputView.bind( 'isReadOnly' ).to( labeledView, 'isEnabled', value => !value ); - * inputView.bind( 'hasError' ).to( labeledView, 'errorText', value => !!value ); + * inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); + * inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); * * return inputView; * } ); @@ -45,23 +45,23 @@ import '../../theme/components/labeledview/labeledview.css'; * * document.body.append( labeledInputView.element ); * - * See {@link module:ui/labeledview/utils} to discover ready–to–use labeled input helpers for common + * See {@link module:ui/labeledfieldview/utils} to discover ready–to–use labeled input helpers for common * UI components. * * @extends module:ui/view~View */ -export default class LabeledView extends View { +export default class LabeledFieldView extends View { /** - * Creates an instance of the labeled view class using a provided creator function + * Creates an instance of the labeled field view class using a provided creator function * that provides the view to be labeled. * * @param {module:utils/locale~Locale} locale The locale instance. * @param {Function} viewCreator A function that returns a {@link module:ui/view~View} * that will be labeled. The following arguments are passed to the creator function: * - * * an instance of the `LabeledView` to allow binding observable properties, - * * an UID string that connects the {@link #labelView label} and the labeled view in DOM, - * * an UID string that connects the {@link #statusView status} and the labeled view in DOM. + * * an instance of the `LabeledFieldView` to allow binding observable properties, + * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM, + * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM. */ constructor( locale, viewCreator ) { super( locale ); @@ -70,11 +70,11 @@ export default class LabeledView extends View { const statusUid = `ck-labeled-view-status-${ uid() }`; /** - * The view that gets labeled. + * The field that gets labeled. * - * @member {module:ui/view~View} #view + * @member {module:ui/view~View} #field */ - this.view = viewCreator( this, viewUid, statusUid ); + this.field = viewCreator( this, viewUid, statusUid ); /** * The text of the label. @@ -94,11 +94,11 @@ export default class LabeledView extends View { /** * The validation error text. When set, it will be displayed - * next to the {@link #view} as a typical validation error message. + * next to the {@link #field} as a typical validation error message. * Set it to `null` to hide the message. * * **Note:** Setting this property to anything but `null` will automatically - * make the `hasError` of the {@link #view} `true`. + * make the `hasError` of the {@link #field} `true`. * * @observable * @member {String|null} #errorText @@ -106,7 +106,7 @@ export default class LabeledView extends View { this.set( 'errorText', null ); /** - * The additional information text displayed next to the {@link #view} which can + * The additional information text displayed next to the {@link #field} which can * be used to inform the user about its purpose, provide help or hints. * * Set it to `null` to hide the message. @@ -136,7 +136,7 @@ export default class LabeledView extends View { this.labelView = this._createLabelView( viewUid ); /** - * The status view for the {@link #view}. It displays {@link #errorText} and + * The status view for the {@link #field}. It displays {@link #errorText} and * {@link #infoText}. * * @member {module:ui/view~View} #statusView @@ -175,7 +175,7 @@ export default class LabeledView extends View { }, children: [ this.labelView, - this.view, + this.field, this.statusView ] } ); @@ -199,10 +199,10 @@ export default class LabeledView extends View { /** * Creates the status view instance. It displays {@link #errorText} and {@link #infoText} - * next to the {@link #view}. See {@link #_statusText}. + * next to the {@link #field}. See {@link #_statusText}. * * @private - * @param {String} statusUid Unique id of the status, shared with the {@link #view view's} + * @param {String} statusUid Unique id of the status, shared with the {@link #field view's} * `aria-describedby` attribute. * @returns {module:ui/view~View} */ @@ -233,9 +233,9 @@ export default class LabeledView extends View { } /** - * Focuses the {@link #view}. + * Focuses the {@link #field}. */ focus() { - this.view.focus(); + this.field.focus(); } } diff --git a/src/labeledview/utils.js b/src/labeledfieldview/utils.js similarity index 55% rename from src/labeledview/utils.js rename to src/labeledfieldview/utils.js index 3bd0747b..45722090 100644 --- a/src/labeledview/utils.js +++ b/src/labeledfieldview/utils.js @@ -4,7 +4,7 @@ */ /** - * @module ui/labeledview/utils + * @module ui/labeledfieldview/utils */ import InputTextView from '../inputtext/inputtextview'; @@ -14,7 +14,7 @@ import { createDropdown } from '../dropdown/utils'; * A helper for creating labeled inputs. * * It creates an instance of a {@link module:ui/inputtext/inputtextview~InputTextView input text} that is - * logically related to a {@link module:ui/labeledview/labeledview~LabeledView labeled view} in DOM. + * logically related to a {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView labeled view} in DOM. * * The helper does the following: * @@ -25,31 +25,31 @@ import { createDropdown } from '../dropdown/utils'; * * Usage: * - * const labeledInputView = new LabeledView( locale, createLabeledDropdown ); + * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); * console.log( labeledInputView.view ); // An input instance. * - * @param {module:ui/labeledview/labeledview~LabeledView} labeledView The instance of the labeled view. + * @param {module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. * @param {String} viewUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledview/labeledview~LabeledView#labelView labeled view's label} and the input. + * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input. * @param {String} statusUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledview/labeledview~LabeledView#statusView labeled view's status} and the input. + * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#statusView labeled view's status} and the input. * @returns {module:ui/inputtext/inputtextview~InputTextView} The input text view instance. */ -export function createLabeledInputText( labeledView, viewUid, statusUid ) { - const inputView = new InputTextView( labeledView.locale ); +export function createLabeledInputText( labeledFieldView, viewUid, statusUid ) { + const inputView = new InputTextView( labeledFieldView.locale ); inputView.set( { id: viewUid, ariaDescribedById: statusUid } ); - inputView.bind( 'isReadOnly' ).to( labeledView, 'isEnabled', value => !value ); - inputView.bind( 'hasError' ).to( labeledView, 'errorText', value => !!value ); + inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); + inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); inputView.on( 'input', () => { // UX: Make the error text disappear and disable the error indicator as the user // starts fixing the errors. - labeledView.errorText = null; + labeledFieldView.errorText = null; } ); return inputView; @@ -59,7 +59,7 @@ export function createLabeledInputText( labeledView, viewUid, statusUid ) { * A helper for creating labeled dropdowns. * * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is - * logically related to a {@link module:ui/labeledview/labeledview~LabeledView labeled view}. + * logically related to a {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView labeled view}. * * The helper does the following: * @@ -68,25 +68,25 @@ export function createLabeledInputText( labeledView, viewUid, statusUid ) { * * Usage: * - * const labeledInputView = new LabeledView( locale, createLabeledDropdown ); + * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); * console.log( labeledInputView.view ); // A dropdown instance. * - * @param {module:ui/labeledview/labeledview~LabeledView} labeledView The instance of the labeled view. + * @param {module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. * @param {String} viewUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledview/labeledview~LabeledView#labelView labeled view label} and the dropdown. + * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown. * @param {String} statusUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledview/labeledview~LabeledView#statusView labeled view status} and the dropdown. + * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#statusView labeled view status} and the dropdown. * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance. */ -export function createLabeledDropdown( labeledView, viewUid, statusUid ) { - const dropdownView = createDropdown( labeledView.locale ); +export function createLabeledDropdown( labeledFieldView, viewUid, statusUid ) { + const dropdownView = createDropdown( labeledFieldView.locale ); dropdownView.set( { id: viewUid, ariaDescribedById: statusUid } ); - dropdownView.bind( 'isEnabled' ).to( labeledView ); + dropdownView.bind( 'isEnabled' ).to( labeledFieldView ); return dropdownView; } diff --git a/tests/labeledfieldview/labeledfieldview.js b/tests/labeledfieldview/labeledfieldview.js new file mode 100644 index 00000000..10602b99 --- /dev/null +++ b/tests/labeledfieldview/labeledfieldview.js @@ -0,0 +1,166 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import View from '../../src/view'; +import LabeledFieldView from '../../src/labeledfieldview/labeledfieldview'; +import LabelView from '../../src/label/labelview'; + +describe( 'LabeledFieldView', () => { + const locale = {}; + + let labeledFieldView, view; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { + view = new View( locale ); + view.setTemplate( { tag: 'div' } ); + view.focus = () => {}; + view.viewUid = viewUid; + view.statusUid = statusUid; + + return view; + } ); + + labeledFieldView.render(); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + describe( 'constructor()', () => { + it( 'should set labeledFieldView#locale', () => { + expect( labeledFieldView.locale ).to.deep.equal( locale ); + } ); + + it( 'should set labeledFieldView#field', () => { + expect( labeledFieldView.field ).to.equal( view ); + } ); + + it( 'should set labeledFieldView#label', () => { + expect( labeledFieldView.label ).to.be.undefined; + } ); + + it( 'should set labeledFieldView#isEnabled', () => { + expect( labeledFieldView.isEnabled ).to.be.true; + } ); + + it( 'should set labeledFieldView#errorText', () => { + expect( labeledFieldView.errorText ).to.be.null; + } ); + + it( 'should set labeledFieldView#infoText', () => { + expect( labeledFieldView.infoText ).to.be.null; + } ); + + it( 'should set labeledFieldView#class', () => { + expect( labeledFieldView.class ).to.be.undefined; + } ); + + it( 'should create labeledFieldView#labelView', () => { + expect( labeledFieldView.labelView ).to.instanceOf( LabelView ); + } ); + + it( 'should create labeledFieldView#statusView', () => { + expect( labeledFieldView.statusView ).to.instanceOf( View ); + + expect( labeledFieldView.statusView.element.tagName ).to.equal( 'DIV' ); + expect( labeledFieldView.statusView.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledFieldView.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; + } ); + + it( 'should allow pairing #view and #labelView by unique id', () => { + expect( labeledFieldView.labelView.for ).to.equal( view.viewUid ); + } ); + + it( 'should allow pairing #view and #statusView by unique id', () => { + expect( view.statusUid ).to.equal( labeledFieldView.statusView.element.id ); + } ); + } ); + + describe( 'template', () => { + it( 'should have the CSS class', () => { + expect( labeledFieldView.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledFieldView.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; + } ); + + it( 'should have #labeledFieldView', () => { + expect( labeledFieldView.template.children[ 0 ] ).to.equal( labeledFieldView.labelView ); + } ); + + it( 'should have #view', () => { + expect( labeledFieldView.template.children[ 1 ] ).to.equal( view ); + } ); + + it( 'should have the #statusView container', () => { + expect( labeledFieldView.template.children[ 2 ] ).to.equal( labeledFieldView.statusView ); + } ); + + describe( 'DOM bindings', () => { + describe( 'class', () => { + it( 'should react on labeledFieldView#class', () => { + labeledFieldView.class = 'foo'; + expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.true; + + labeledFieldView.class = 'bar'; + expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.false; + expect( labeledFieldView.element.classList.contains( 'bar' ) ).to.be.true; + } ); + } ); + + describe( 'status container', () => { + it( 'should react on labeledFieldView#errorText', () => { + const statusElement = labeledFieldView.statusView.element; + + labeledFieldView.errorText = ''; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( '' ); + + labeledFieldView.errorText = 'foo'; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.true; + expect( statusElement.getAttribute( 'role' ) ).to.equal( 'alert' ); + expect( statusElement.innerHTML ).to.equal( 'foo' ); + } ); + + it( 'should react on labeledFieldView#infoText', () => { + const statusElement = labeledFieldView.statusView.element; + + labeledFieldView.infoText = ''; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( '' ); + + labeledFieldView.infoText = 'foo'; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( 'foo' ); + } ); + } ); + } ); + } ); + + describe( 'binding', () => { + it( 'should bind labeledFieldView#label to labeledFieldView.labelView#label', () => { + labeledFieldView.label = 'Foo bar'; + + expect( labeledFieldView.labelView.text ).to.equal( 'Foo bar' ); + } ); + } ); + + describe( 'focus()', () => { + it( 'should focus the #view in DOM', () => { + const spy = sinon.spy( view, 'focus' ); + + labeledFieldView.focus(); + + sinon.assert.calledOnce( spy ); + } ); + } ); +} ); diff --git a/tests/labeledfieldview/utils.js b/tests/labeledfieldview/utils.js new file mode 100644 index 00000000..73e8a41d --- /dev/null +++ b/tests/labeledfieldview/utils.js @@ -0,0 +1,108 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import { + createLabeledInputText, + createLabeledDropdown +} from '../../src/labeledfieldview/utils'; + +import LabeledFieldView from '../../src/labeledfieldview/labeledfieldview'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import InputTextView from '../../src/inputtext/inputtextview'; +import DropdownView from '../../src/dropdown/dropdownview'; + +describe( 'LabeledFieldView utils', () => { + let locale; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + locale = { t: val => val }; + } ); + + describe( 'createLabeledInputText()', () => { + let labeledFieldView; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, createLabeledInputText ); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + it( 'should create an InputTextView instance', () => { + expect( labeledFieldView.field ).to.be.instanceOf( InputTextView ); + } ); + + it( 'should pass the Locale to the input', () => { + expect( labeledFieldView.field.locale ).to.equal( locale ); + } ); + + it( 'should set input #id and #ariaDescribedById', () => { + labeledFieldView.render(); + + expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); + expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + } ); + + it( 'should bind input\'s #isReadOnly to LabeledFieldView#isEnabled', () => { + labeledFieldView.isEnabled = true; + expect( labeledFieldView.field.isReadOnly ).to.be.false; + + labeledFieldView.isEnabled = false; + expect( labeledFieldView.field.isReadOnly ).to.be.true; + } ); + + it( 'should bind input\'s #hasError to LabeledFieldView#errorText', () => { + labeledFieldView.errorText = 'some error'; + expect( labeledFieldView.field.hasError ).to.be.true; + + labeledFieldView.errorText = null; + expect( labeledFieldView.field.hasError ).to.be.false; + } ); + + it( 'should clean LabeledFieldView#errorText upon input\'s DOM "update" event', () => { + labeledFieldView.errorText = 'some error'; + labeledFieldView.field.fire( 'input' ); + expect( labeledFieldView.errorText ).to.be.null; + } ); + } ); + + describe( 'createLabeledDropdown', () => { + let labeledFieldView; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, createLabeledDropdown ); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + it( 'should create a DropdownView', () => { + expect( labeledFieldView.field ).to.be.instanceOf( DropdownView ); + } ); + + it( 'should pass the Locale to the dropdown', () => { + expect( labeledFieldView.field.locale ).to.equal( locale ); + } ); + + it( 'should set dropdown\'s #id and #ariaDescribedById', () => { + labeledFieldView.render(); + + expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); + expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + } ); + + it( 'should bind dropdown\'s #isEnabled to the labeled view', () => { + labeledFieldView.isEnabled = true; + expect( labeledFieldView.field.isEnabled ).to.be.true; + + labeledFieldView.isEnabled = false; + expect( labeledFieldView.field.isEnabled ).to.be.false; + } ); + } ); +} ); diff --git a/tests/labeledview/labeledview.js b/tests/labeledview/labeledview.js deleted file mode 100644 index 45873129..00000000 --- a/tests/labeledview/labeledview.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import View from '../../src/view'; -import LabeledView from '../../src/labeledview/labeledview'; -import LabelView from '../../src/label/labelview'; - -describe( 'LabeledView', () => { - const locale = {}; - - let labeledView, view; - - beforeEach( () => { - labeledView = new LabeledView( locale, ( labeledView, viewUid, statusUid ) => { - view = new View( locale ); - view.setTemplate( { tag: 'div' } ); - view.focus = () => {}; - view.viewUid = viewUid; - view.statusUid = statusUid; - - return view; - } ); - - labeledView.render(); - } ); - - afterEach( () => { - labeledView.destroy(); - } ); - - describe( 'constructor()', () => { - it( 'should set labeledView#locale', () => { - expect( labeledView.locale ).to.deep.equal( locale ); - } ); - - it( 'should set labeledView#view', () => { - expect( labeledView.view ).to.equal( view ); - } ); - - it( 'should set labeledView#label', () => { - expect( labeledView.label ).to.be.undefined; - } ); - - it( 'should set labeledView#isEnabled', () => { - expect( labeledView.isEnabled ).to.be.true; - } ); - - it( 'should set labeledView#errorText', () => { - expect( labeledView.errorText ).to.be.null; - } ); - - it( 'should set labeledView#infoText', () => { - expect( labeledView.infoText ).to.be.null; - } ); - - it( 'should set labeledView#class', () => { - expect( labeledView.class ).to.be.undefined; - } ); - - it( 'should create labeledView#labelView', () => { - expect( labeledView.labelView ).to.instanceOf( LabelView ); - } ); - - it( 'should create labeledView#statusView', () => { - expect( labeledView.statusView ).to.instanceOf( View ); - - expect( labeledView.statusView.element.tagName ).to.equal( 'DIV' ); - expect( labeledView.statusView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledView.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; - } ); - - it( 'should allow pairing #view and #labelView by unique id', () => { - expect( labeledView.labelView.for ).to.equal( view.viewUid ); - } ); - - it( 'should allow pairing #view and #statusView by unique id', () => { - expect( view.statusUid ).to.equal( labeledView.statusView.element.id ); - } ); - } ); - - describe( 'template', () => { - it( 'should have the CSS class', () => { - expect( labeledView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledView.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; - } ); - - it( 'should have #labeledView', () => { - expect( labeledView.template.children[ 0 ] ).to.equal( labeledView.labelView ); - } ); - - it( 'should have #view', () => { - expect( labeledView.template.children[ 1 ] ).to.equal( view ); - } ); - - it( 'should have the #statusView container', () => { - expect( labeledView.template.children[ 2 ] ).to.equal( labeledView.statusView ); - } ); - - describe( 'DOM bindings', () => { - describe( 'class', () => { - it( 'should react on labeledView#class', () => { - labeledView.class = 'foo'; - expect( labeledView.element.classList.contains( 'foo' ) ).to.be.true; - - labeledView.class = 'bar'; - expect( labeledView.element.classList.contains( 'foo' ) ).to.be.false; - expect( labeledView.element.classList.contains( 'bar' ) ).to.be.true; - } ); - } ); - - describe( 'status container', () => { - it( 'should react on labeledView#errorText', () => { - const statusElement = labeledView.statusView.element; - - labeledView.errorText = ''; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( '' ); - - labeledView.errorText = 'foo'; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.true; - expect( statusElement.getAttribute( 'role' ) ).to.equal( 'alert' ); - expect( statusElement.innerHTML ).to.equal( 'foo' ); - } ); - - it( 'should react on labeledView#infoText', () => { - const statusElement = labeledView.statusView.element; - - labeledView.infoText = ''; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( '' ); - - labeledView.infoText = 'foo'; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( 'foo' ); - } ); - } ); - } ); - } ); - - describe( 'binding', () => { - it( 'should bind labeledView#label to labeledView.labelView#label', () => { - labeledView.label = 'Foo bar'; - - expect( labeledView.labelView.text ).to.equal( 'Foo bar' ); - } ); - } ); - - describe( 'focus()', () => { - it( 'should focus the #view in DOM', () => { - const spy = sinon.spy( view, 'focus' ); - - labeledView.focus(); - - sinon.assert.calledOnce( spy ); - } ); - } ); -} ); diff --git a/tests/labeledview/utils.js b/tests/labeledview/utils.js deleted file mode 100644 index 29ca8094..00000000 --- a/tests/labeledview/utils.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import { - createLabeledInputText, - createLabeledDropdown -} from '../../src/labeledview/utils'; - -import LabeledView from '../../src/labeledview/labeledview'; -import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; -import InputTextView from '../../src/inputtext/inputtextview'; -import DropdownView from '../../src/dropdown/dropdownview'; - -describe( 'LabeledView utils', () => { - let locale; - - testUtils.createSinonSandbox(); - - beforeEach( () => { - locale = { t: val => val }; - } ); - - describe( 'createLabeledInputText()', () => { - let labeledView; - - beforeEach( () => { - labeledView = new LabeledView( locale, createLabeledInputText ); - } ); - - afterEach( () => { - labeledView.destroy(); - } ); - - it( 'should create an InputTextView instance', () => { - expect( labeledView.view ).to.be.instanceOf( InputTextView ); - } ); - - it( 'should pass the Locale to the input', () => { - expect( labeledView.view.locale ).to.equal( locale ); - } ); - - it( 'should set input #id and #ariaDescribedById', () => { - labeledView.render(); - - expect( labeledView.view.id ).to.equal( labeledView.labelView.for ); - expect( labeledView.view.ariaDescribedById ).to.equal( labeledView.statusView.element.id ); - } ); - - it( 'should bind input\'s #isReadOnly to LabeledView#isEnabled', () => { - labeledView.isEnabled = true; - expect( labeledView.view.isReadOnly ).to.be.false; - - labeledView.isEnabled = false; - expect( labeledView.view.isReadOnly ).to.be.true; - } ); - - it( 'should bind input\'s #hasError to LabeledView#errorText', () => { - labeledView.errorText = 'some error'; - expect( labeledView.view.hasError ).to.be.true; - - labeledView.errorText = null; - expect( labeledView.view.hasError ).to.be.false; - } ); - - it( 'should clean LabeledView#errorText upon input\'s DOM "update" event', () => { - labeledView.errorText = 'some error'; - labeledView.view.fire( 'input' ); - expect( labeledView.errorText ).to.be.null; - } ); - } ); - - describe( 'createLabeledDropdown', () => { - let labeledView; - - beforeEach( () => { - labeledView = new LabeledView( locale, createLabeledDropdown ); - } ); - - afterEach( () => { - labeledView.destroy(); - } ); - - it( 'should create a DropdownView', () => { - expect( labeledView.view ).to.be.instanceOf( DropdownView ); - } ); - - it( 'should pass the Locale to the dropdown', () => { - expect( labeledView.view.locale ).to.equal( locale ); - } ); - - it( 'should set dropdown\'s #id and #ariaDescribedById', () => { - labeledView.render(); - - expect( labeledView.view.id ).to.equal( labeledView.labelView.for ); - expect( labeledView.view.ariaDescribedById ).to.equal( labeledView.statusView.element.id ); - } ); - - it( 'should bind dropdown\'s #isEnabled to the labeled view', () => { - labeledView.isEnabled = true; - expect( labeledView.view.isEnabled ).to.be.true; - - labeledView.isEnabled = false; - expect( labeledView.view.isEnabled ).to.be.false; - } ); - } ); -} ); diff --git a/theme/components/labeledview/labeledview.css b/theme/components/labeledfieldview/labeledfieldview.css similarity index 100% rename from theme/components/labeledview/labeledview.css rename to theme/components/labeledfieldview/labeledfieldview.css From f6422c5297b8c3119dc0c89ff51867519df1732c Mon Sep 17 00:00:00 2001 From: panr Date: Thu, 19 Mar 2020 16:09:12 +0100 Subject: [PATCH 02/12] Deprecate LabeledInputView component --- src/labeledinput/labeledinputview.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/labeledinput/labeledinputview.js b/src/labeledinput/labeledinputview.js index c94d2e12..3cf46131 100644 --- a/src/labeledinput/labeledinputview.js +++ b/src/labeledinput/labeledinputview.js @@ -7,6 +7,8 @@ * @module ui/labeledinput/labeledinputview */ +/* globals console */ + import View from '../view'; import uid from '@ckeditor/ckeditor5-utils/src/uid'; import LabelView from '../label/labelview'; @@ -15,6 +17,8 @@ import '../../theme/components/labeledinput/labeledinput.css'; /** * The labeled input view class. * + * @deprecated The component has been marked as deprecated since v18.0.0 and will be removed in v19.0.0. + * * @extends module:ui/view~View */ export default class LabeledInputView extends View { @@ -27,6 +31,9 @@ export default class LabeledInputView extends View { constructor( locale, InputView ) { super( locale ); + // Deprecation warning. + console.warn( ' The LabeledInputView component has been marked as deprecated since v18.0.0 and will be removed in v19.0.0. ' ); + const inputUid = `ck-input-${ uid() }`; const statusUid = `ck-status-${ uid() }`; From 9c0f1460aa7a007cc94b0ee551c76abe5a16fd25 Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 13:04:07 +0100 Subject: [PATCH 03/12] Change deprecation warning and fix CI by stubbing console.warn --- src/labeledinput/labeledinputview.js | 7 +++++-- tests/labeledinput/labeledinputview.js | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/labeledinput/labeledinputview.js b/src/labeledinput/labeledinputview.js index 3cf46131..a42fbc49 100644 --- a/src/labeledinput/labeledinputview.js +++ b/src/labeledinput/labeledinputview.js @@ -17,7 +17,8 @@ import '../../theme/components/labeledinput/labeledinput.css'; /** * The labeled input view class. * - * @deprecated The component has been marked as deprecated since v18.0.0 and will be removed in v19.0.0. + * @deprecated The LabeledInputView component has been marked as deprecated and will be removed in the next major release. + * Please use {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} component instead. * * @extends module:ui/view~View */ @@ -32,7 +33,9 @@ export default class LabeledInputView extends View { super( locale ); // Deprecation warning. - console.warn( ' The LabeledInputView component has been marked as deprecated since v18.0.0 and will be removed in v19.0.0. ' ); + console.warn( 'The LabeledInputView component has been marked as deprecated' + + 'and will be removed in the next major release.' + + 'Please use LabeledFieldView component instead.' ); const inputUid = `ck-input-${ uid() }`; const statusUid = `ck-status-${ uid() }`; diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index 68751490..ddaa0304 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -3,6 +3,8 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ +/* globals console */ + import View from '../../src/view'; import LabeledInputView from '../../src/labeledinput/labeledinputview'; import InputView from '../../src/inputtext/inputtextview'; @@ -11,15 +13,26 @@ import LabelView from '../../src/label/labelview'; describe( 'LabeledInputView', () => { const locale = {}; - let view; + let view, deprecatedWarning; beforeEach( () => { + deprecatedWarning = sinon.stub( console, 'warn' ); view = new LabeledInputView( locale, InputView ); view.render(); } ); describe( 'constructor()', () => { + describe( 'deprecation warning', () => { + it( 'should be shown in the console after component initialization', () => { + sinon.assert.calledOnce( deprecatedWarning ); + } ); + + it( 'should inform about using LabeledFieldView instead of LabeledInputView', () => { + sinon.assert.calledWithMatch( deprecatedWarning, 'Please use LabeledFieldView component instead' ); + } ); + } ); + it( 'should set view#locale', () => { expect( view.locale ).to.deep.equal( locale ); } ); From 71d9975f133329ed5c83edf3c26c662c3c8f91ba Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 13:07:52 +0100 Subject: [PATCH 04/12] Fix typo --- src/labeledinput/labeledinputview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/labeledinput/labeledinputview.js b/src/labeledinput/labeledinputview.js index a42fbc49..c5168c2a 100644 --- a/src/labeledinput/labeledinputview.js +++ b/src/labeledinput/labeledinputview.js @@ -34,7 +34,7 @@ export default class LabeledInputView extends View { // Deprecation warning. console.warn( 'The LabeledInputView component has been marked as deprecated' + - 'and will be removed in the next major release.' + + 'and will be removed in the next major release. ' + 'Please use LabeledFieldView component instead.' ); const inputUid = `ck-input-${ uid() }`; From 3a44063153600970c861f73a50f85da345b4c782 Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 13:27:40 +0100 Subject: [PATCH 05/12] Test deprecation warning with testUtils --- tests/labeledinput/labeledinputview.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index ddaa0304..91186bfe 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -10,13 +10,17 @@ import LabeledInputView from '../../src/labeledinput/labeledinputview'; import InputView from '../../src/inputtext/inputtextview'; import LabelView from '../../src/label/labelview'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; + describe( 'LabeledInputView', () => { const locale = {}; + testUtils.createSinonSandbox(); + let view, deprecatedWarning; beforeEach( () => { - deprecatedWarning = sinon.stub( console, 'warn' ); + deprecatedWarning = testUtils.sinon.stub( console, 'warn' ); view = new LabeledInputView( locale, InputView ); view.render(); @@ -25,11 +29,12 @@ describe( 'LabeledInputView', () => { describe( 'constructor()', () => { describe( 'deprecation warning', () => { it( 'should be shown in the console after component initialization', () => { - sinon.assert.calledOnce( deprecatedWarning ); + expect( deprecatedWarning.called ).to.be.true; + expect( deprecatedWarning.callCount ).to.be.equal( 1 ); } ); it( 'should inform about using LabeledFieldView instead of LabeledInputView', () => { - sinon.assert.calledWithMatch( deprecatedWarning, 'Please use LabeledFieldView component instead' ); + expect( deprecatedWarning.calledWithMatch( 'Please use LabeledFieldView component instead' ) ).to.be.true; } ); } ); From 404d99a4349a9fdef98a1a21df85e4f1d16c0dcc Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 15:56:01 +0100 Subject: [PATCH 06/12] Switch back to sinon and restore stub after each test --- tests/labeledinput/labeledinputview.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index 91186bfe..c47dc9f5 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -26,6 +26,10 @@ describe( 'LabeledInputView', () => { view.render(); } ); + afterEach( () => { + sinon.restore(); + } ); + describe( 'constructor()', () => { describe( 'deprecation warning', () => { it( 'should be shown in the console after component initialization', () => { From 13853b94acc29e70d819f9cbd838e18c26ebd683 Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 15:57:06 +0100 Subject: [PATCH 07/12] Revert "Test deprecation warning with testUtils" This reverts commit 3a44063153600970c861f73a50f85da345b4c782. --- tests/labeledinput/labeledinputview.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index c47dc9f5..03782c67 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -10,17 +10,13 @@ import LabeledInputView from '../../src/labeledinput/labeledinputview'; import InputView from '../../src/inputtext/inputtextview'; import LabelView from '../../src/label/labelview'; -import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; - describe( 'LabeledInputView', () => { const locale = {}; - testUtils.createSinonSandbox(); - let view, deprecatedWarning; beforeEach( () => { - deprecatedWarning = testUtils.sinon.stub( console, 'warn' ); + deprecatedWarning = sinon.stub( console, 'warn' ); view = new LabeledInputView( locale, InputView ); view.render(); @@ -33,12 +29,11 @@ describe( 'LabeledInputView', () => { describe( 'constructor()', () => { describe( 'deprecation warning', () => { it( 'should be shown in the console after component initialization', () => { - expect( deprecatedWarning.called ).to.be.true; - expect( deprecatedWarning.callCount ).to.be.equal( 1 ); + sinon.assert.calledOnce( deprecatedWarning ); } ); it( 'should inform about using LabeledFieldView instead of LabeledInputView', () => { - expect( deprecatedWarning.calledWithMatch( 'Please use LabeledFieldView component instead' ) ).to.be.true; + sinon.assert.calledWithMatch( deprecatedWarning, 'Please use LabeledFieldView component instead' ); } ); } ); From cc6487b18ec6c7ae83d3ec685bc7ecde3519ee5d Mon Sep 17 00:00:00 2001 From: panr Date: Mon, 23 Mar 2020 16:29:18 +0100 Subject: [PATCH 08/12] Revert all changes related to deprecation of the LabeledInputView component. The changes will appear in a separate PR. --- src/labeledinput/labeledinputview.js | 10 ---------- tests/labeledinput/labeledinputview.js | 19 +------------------ 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/labeledinput/labeledinputview.js b/src/labeledinput/labeledinputview.js index c5168c2a..c94d2e12 100644 --- a/src/labeledinput/labeledinputview.js +++ b/src/labeledinput/labeledinputview.js @@ -7,8 +7,6 @@ * @module ui/labeledinput/labeledinputview */ -/* globals console */ - import View from '../view'; import uid from '@ckeditor/ckeditor5-utils/src/uid'; import LabelView from '../label/labelview'; @@ -17,9 +15,6 @@ import '../../theme/components/labeledinput/labeledinput.css'; /** * The labeled input view class. * - * @deprecated The LabeledInputView component has been marked as deprecated and will be removed in the next major release. - * Please use {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} component instead. - * * @extends module:ui/view~View */ export default class LabeledInputView extends View { @@ -32,11 +27,6 @@ export default class LabeledInputView extends View { constructor( locale, InputView ) { super( locale ); - // Deprecation warning. - console.warn( 'The LabeledInputView component has been marked as deprecated' + - 'and will be removed in the next major release. ' + - 'Please use LabeledFieldView component instead.' ); - const inputUid = `ck-input-${ uid() }`; const statusUid = `ck-status-${ uid() }`; diff --git a/tests/labeledinput/labeledinputview.js b/tests/labeledinput/labeledinputview.js index 03782c67..68751490 100644 --- a/tests/labeledinput/labeledinputview.js +++ b/tests/labeledinput/labeledinputview.js @@ -3,8 +3,6 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -/* globals console */ - import View from '../../src/view'; import LabeledInputView from '../../src/labeledinput/labeledinputview'; import InputView from '../../src/inputtext/inputtextview'; @@ -13,30 +11,15 @@ import LabelView from '../../src/label/labelview'; describe( 'LabeledInputView', () => { const locale = {}; - let view, deprecatedWarning; + let view; beforeEach( () => { - deprecatedWarning = sinon.stub( console, 'warn' ); view = new LabeledInputView( locale, InputView ); view.render(); } ); - afterEach( () => { - sinon.restore(); - } ); - describe( 'constructor()', () => { - describe( 'deprecation warning', () => { - it( 'should be shown in the console after component initialization', () => { - sinon.assert.calledOnce( deprecatedWarning ); - } ); - - it( 'should inform about using LabeledFieldView instead of LabeledInputView', () => { - sinon.assert.calledWithMatch( deprecatedWarning, 'Please use LabeledFieldView component instead' ); - } ); - } ); - it( 'should set view#locale', () => { expect( view.locale ).to.deep.equal( locale ); } ); From ad0e8914b8b09ec75c9928de6111bf37cc3b32f2 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 25 Mar 2020 15:43:35 +0100 Subject: [PATCH 09/12] Change module path --- src/labeledfieldview/labeledfieldview.js | 241 ------------------ src/labeledfieldview/utils.js | 92 ------- tests/labeledfieldview/labeledfieldview.js | 166 ------------ tests/labeledfieldview/utils.js | 108 -------- .../labeledfieldview/labeledfieldview.css | 10 - 5 files changed, 617 deletions(-) delete mode 100644 src/labeledfieldview/labeledfieldview.js delete mode 100644 src/labeledfieldview/utils.js delete mode 100644 tests/labeledfieldview/labeledfieldview.js delete mode 100644 tests/labeledfieldview/utils.js delete mode 100644 theme/components/labeledfieldview/labeledfieldview.css diff --git a/src/labeledfieldview/labeledfieldview.js b/src/labeledfieldview/labeledfieldview.js deleted file mode 100644 index c5be3222..00000000 --- a/src/labeledfieldview/labeledfieldview.js +++ /dev/null @@ -1,241 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/** - * @module ui/labeledfieldview/labeledfieldview - */ - -import View from '../view'; -import uid from '@ckeditor/ckeditor5-utils/src/uid'; -import LabelView from '../label/labelview'; -import '../../theme/components/labeledfieldview/labeledfieldview.css'; - -/** - * The labeled field view class. It can be used to enhance any view with the following features: - * - * * a label, - * * (optional) an error message, - * * (optional) an info (status) text, - * - * all bound logically by proper DOM attributes for UX and accessibility. It also provides an interface - * (e.g. observable properties) that allows controlling those additional features. - * - * The constructor of this class requires a callback that returns a view to be labeled. The callback - * is called with unique ids that allow binding of DOM properties: - * - * const labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { - * const inputView = new InputTextView( labeledFieldView.locale ); - * - * inputView.set( { - * id: viewUid, - * ariaDescribedById: statusUid - * } ); - * - * inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); - * inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); - * - * return inputView; - * } ); - * - * labeledInputView.label = 'User name'; - * labeledInputView.infoText = 'Full name like for instance, John Doe.'; - * labeledInputView.render(); - * - * document.body.append( labeledInputView.element ); - * - * See {@link module:ui/labeledfieldview/utils} to discover ready–to–use labeled input helpers for common - * UI components. - * - * @extends module:ui/view~View - */ -export default class LabeledFieldView extends View { - /** - * Creates an instance of the labeled field view class using a provided creator function - * that provides the view to be labeled. - * - * @param {module:utils/locale~Locale} locale The locale instance. - * @param {Function} viewCreator A function that returns a {@link module:ui/view~View} - * that will be labeled. The following arguments are passed to the creator function: - * - * * an instance of the `LabeledFieldView` to allow binding observable properties, - * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM, - * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM. - */ - constructor( locale, viewCreator ) { - super( locale ); - - const viewUid = `ck-labeled-view-${ uid() }`; - const statusUid = `ck-labeled-view-status-${ uid() }`; - - /** - * The field that gets labeled. - * - * @member {module:ui/view~View} #field - */ - this.field = viewCreator( this, viewUid, statusUid ); - - /** - * The text of the label. - * - * @observable - * @member {String} #label - */ - this.set( 'label' ); - - /** - * Controls whether the component is in read-only mode. - * - * @observable - * @member {Boolean} #isEnabled - */ - this.set( 'isEnabled', true ); - - /** - * The validation error text. When set, it will be displayed - * next to the {@link #field} as a typical validation error message. - * Set it to `null` to hide the message. - * - * **Note:** Setting this property to anything but `null` will automatically - * make the `hasError` of the {@link #field} `true`. - * - * @observable - * @member {String|null} #errorText - */ - this.set( 'errorText', null ); - - /** - * The additional information text displayed next to the {@link #field} which can - * be used to inform the user about its purpose, provide help or hints. - * - * Set it to `null` to hide the message. - * - * **Note:** This text will be displayed in the same place as {@link #errorText} but the - * latter always takes precedence: if the {@link #errorText} is set, it replaces - * {@link #infoText}. - * - * @observable - * @member {String|null} #infoText - */ - this.set( 'infoText', null ); - - /** - * (Optional) The additional CSS class set on the dropdown {@link #element}. - * - * @observable - * @member {String} #class - */ - this.set( 'class' ); - - /** - * The label view instance that describes the entire view. - * - * @member {module:ui/label/labelview~LabelView} #labelView - */ - this.labelView = this._createLabelView( viewUid ); - - /** - * The status view for the {@link #field}. It displays {@link #errorText} and - * {@link #infoText}. - * - * @member {module:ui/view~View} #statusView - */ - this.statusView = this._createStatusView( statusUid ); - - /** - * The combined status text made of {@link #errorText} and {@link #infoText}. - * Note that when present, {@link #errorText} always takes precedence in the - * status. - * - * @see #errorText - * @see #infoText - * @see #statusView - * @private - * @observable - * @member {String|null} #_statusText - */ - this.bind( '_statusText' ).to( - this, 'errorText', - this, 'infoText', - ( errorText, infoText ) => errorText || infoText - ); - - const bind = this.bindTemplate; - - this.setTemplate( { - tag: 'div', - attributes: { - class: [ - 'ck', - 'ck-labeled-view', - bind.to( 'class' ), - bind.if( 'isEnabled', 'ck-disabled', value => !value ) - ] - }, - children: [ - this.labelView, - this.field, - this.statusView - ] - } ); - } - - /** - * Creates label view class instance and bind with view. - * - * @private - * @param {String} id Unique id to set as labelView#for attribute. - * @returns {module:ui/label/labelview~LabelView} - */ - _createLabelView( id ) { - const labelView = new LabelView( this.locale ); - - labelView.for = id; - labelView.bind( 'text' ).to( this, 'label' ); - - return labelView; - } - - /** - * Creates the status view instance. It displays {@link #errorText} and {@link #infoText} - * next to the {@link #field}. See {@link #_statusText}. - * - * @private - * @param {String} statusUid Unique id of the status, shared with the {@link #field view's} - * `aria-describedby` attribute. - * @returns {module:ui/view~View} - */ - _createStatusView( statusUid ) { - const statusView = new View( this.locale ); - const bind = this.bindTemplate; - - statusView.setTemplate( { - tag: 'div', - attributes: { - class: [ - 'ck', - 'ck-labeled-view__status', - bind.if( 'errorText', 'ck-labeled-view__status_error' ), - bind.if( '_statusText', 'ck-hidden', value => !value ) - ], - id: statusUid, - role: bind.if( 'errorText', 'alert' ) - }, - children: [ - { - text: bind.to( '_statusText' ) - } - ] - } ); - - return statusView; - } - - /** - * Focuses the {@link #field}. - */ - focus() { - this.field.focus(); - } -} diff --git a/src/labeledfieldview/utils.js b/src/labeledfieldview/utils.js deleted file mode 100644 index 45722090..00000000 --- a/src/labeledfieldview/utils.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/** - * @module ui/labeledfieldview/utils - */ - -import InputTextView from '../inputtext/inputtextview'; -import { createDropdown } from '../dropdown/utils'; - -/** - * A helper for creating labeled inputs. - * - * It creates an instance of a {@link module:ui/inputtext/inputtextview~InputTextView input text} that is - * logically related to a {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView labeled view} in DOM. - * - * The helper does the following: - * - * * It sets input's `id` and `ariaDescribedById` attributes. - * * It binds input's `isReadOnly` to the labeled view. - * * It binds input's `hasError` to the labeled view. - * * It enables a logic that cleans up the error when user starts typing in the input.. - * - * Usage: - * - * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); - * console.log( labeledInputView.view ); // An input instance. - * - * @param {module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. - * @param {String} viewUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input. - * @param {String} statusUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#statusView labeled view's status} and the input. - * @returns {module:ui/inputtext/inputtextview~InputTextView} The input text view instance. - */ -export function createLabeledInputText( labeledFieldView, viewUid, statusUid ) { - const inputView = new InputTextView( labeledFieldView.locale ); - - inputView.set( { - id: viewUid, - ariaDescribedById: statusUid - } ); - - inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); - inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); - - inputView.on( 'input', () => { - // UX: Make the error text disappear and disable the error indicator as the user - // starts fixing the errors. - labeledFieldView.errorText = null; - } ); - - return inputView; -} - -/** - * A helper for creating labeled dropdowns. - * - * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is - * logically related to a {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView labeled view}. - * - * The helper does the following: - * - * * It sets dropdown's `id` and `ariaDescribedById` attributes. - * * It binds input's `isEnabled` to the labeled view. - * - * Usage: - * - * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); - * console.log( labeledInputView.view ); // A dropdown instance. - * - * @param {module:ui/labeledfieldview/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. - * @param {String} viewUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown. - * @param {String} statusUid An UID string that allows DOM logical connection between the - * {@link module:ui/labeledfieldview/labeledfieldview~LabeledFieldView#statusView labeled view status} and the dropdown. - * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance. - */ -export function createLabeledDropdown( labeledFieldView, viewUid, statusUid ) { - const dropdownView = createDropdown( labeledFieldView.locale ); - - dropdownView.set( { - id: viewUid, - ariaDescribedById: statusUid - } ); - - dropdownView.bind( 'isEnabled' ).to( labeledFieldView ); - - return dropdownView; -} diff --git a/tests/labeledfieldview/labeledfieldview.js b/tests/labeledfieldview/labeledfieldview.js deleted file mode 100644 index 10602b99..00000000 --- a/tests/labeledfieldview/labeledfieldview.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import View from '../../src/view'; -import LabeledFieldView from '../../src/labeledfieldview/labeledfieldview'; -import LabelView from '../../src/label/labelview'; - -describe( 'LabeledFieldView', () => { - const locale = {}; - - let labeledFieldView, view; - - beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { - view = new View( locale ); - view.setTemplate( { tag: 'div' } ); - view.focus = () => {}; - view.viewUid = viewUid; - view.statusUid = statusUid; - - return view; - } ); - - labeledFieldView.render(); - } ); - - afterEach( () => { - labeledFieldView.destroy(); - } ); - - describe( 'constructor()', () => { - it( 'should set labeledFieldView#locale', () => { - expect( labeledFieldView.locale ).to.deep.equal( locale ); - } ); - - it( 'should set labeledFieldView#field', () => { - expect( labeledFieldView.field ).to.equal( view ); - } ); - - it( 'should set labeledFieldView#label', () => { - expect( labeledFieldView.label ).to.be.undefined; - } ); - - it( 'should set labeledFieldView#isEnabled', () => { - expect( labeledFieldView.isEnabled ).to.be.true; - } ); - - it( 'should set labeledFieldView#errorText', () => { - expect( labeledFieldView.errorText ).to.be.null; - } ); - - it( 'should set labeledFieldView#infoText', () => { - expect( labeledFieldView.infoText ).to.be.null; - } ); - - it( 'should set labeledFieldView#class', () => { - expect( labeledFieldView.class ).to.be.undefined; - } ); - - it( 'should create labeledFieldView#labelView', () => { - expect( labeledFieldView.labelView ).to.instanceOf( LabelView ); - } ); - - it( 'should create labeledFieldView#statusView', () => { - expect( labeledFieldView.statusView ).to.instanceOf( View ); - - expect( labeledFieldView.statusView.element.tagName ).to.equal( 'DIV' ); - expect( labeledFieldView.statusView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledFieldView.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; - } ); - - it( 'should allow pairing #view and #labelView by unique id', () => { - expect( labeledFieldView.labelView.for ).to.equal( view.viewUid ); - } ); - - it( 'should allow pairing #view and #statusView by unique id', () => { - expect( view.statusUid ).to.equal( labeledFieldView.statusView.element.id ); - } ); - } ); - - describe( 'template', () => { - it( 'should have the CSS class', () => { - expect( labeledFieldView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledFieldView.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; - } ); - - it( 'should have #labeledFieldView', () => { - expect( labeledFieldView.template.children[ 0 ] ).to.equal( labeledFieldView.labelView ); - } ); - - it( 'should have #view', () => { - expect( labeledFieldView.template.children[ 1 ] ).to.equal( view ); - } ); - - it( 'should have the #statusView container', () => { - expect( labeledFieldView.template.children[ 2 ] ).to.equal( labeledFieldView.statusView ); - } ); - - describe( 'DOM bindings', () => { - describe( 'class', () => { - it( 'should react on labeledFieldView#class', () => { - labeledFieldView.class = 'foo'; - expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.true; - - labeledFieldView.class = 'bar'; - expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.false; - expect( labeledFieldView.element.classList.contains( 'bar' ) ).to.be.true; - } ); - } ); - - describe( 'status container', () => { - it( 'should react on labeledFieldView#errorText', () => { - const statusElement = labeledFieldView.statusView.element; - - labeledFieldView.errorText = ''; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( '' ); - - labeledFieldView.errorText = 'foo'; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.true; - expect( statusElement.getAttribute( 'role' ) ).to.equal( 'alert' ); - expect( statusElement.innerHTML ).to.equal( 'foo' ); - } ); - - it( 'should react on labeledFieldView#infoText', () => { - const statusElement = labeledFieldView.statusView.element; - - labeledFieldView.infoText = ''; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( '' ); - - labeledFieldView.infoText = 'foo'; - expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; - expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; - expect( statusElement.hasAttribute( 'role' ) ).to.be.false; - expect( statusElement.innerHTML ).to.equal( 'foo' ); - } ); - } ); - } ); - } ); - - describe( 'binding', () => { - it( 'should bind labeledFieldView#label to labeledFieldView.labelView#label', () => { - labeledFieldView.label = 'Foo bar'; - - expect( labeledFieldView.labelView.text ).to.equal( 'Foo bar' ); - } ); - } ); - - describe( 'focus()', () => { - it( 'should focus the #view in DOM', () => { - const spy = sinon.spy( view, 'focus' ); - - labeledFieldView.focus(); - - sinon.assert.calledOnce( spy ); - } ); - } ); -} ); diff --git a/tests/labeledfieldview/utils.js b/tests/labeledfieldview/utils.js deleted file mode 100644 index 73e8a41d..00000000 --- a/tests/labeledfieldview/utils.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import { - createLabeledInputText, - createLabeledDropdown -} from '../../src/labeledfieldview/utils'; - -import LabeledFieldView from '../../src/labeledfieldview/labeledfieldview'; -import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; -import InputTextView from '../../src/inputtext/inputtextview'; -import DropdownView from '../../src/dropdown/dropdownview'; - -describe( 'LabeledFieldView utils', () => { - let locale; - - testUtils.createSinonSandbox(); - - beforeEach( () => { - locale = { t: val => val }; - } ); - - describe( 'createLabeledInputText()', () => { - let labeledFieldView; - - beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, createLabeledInputText ); - } ); - - afterEach( () => { - labeledFieldView.destroy(); - } ); - - it( 'should create an InputTextView instance', () => { - expect( labeledFieldView.field ).to.be.instanceOf( InputTextView ); - } ); - - it( 'should pass the Locale to the input', () => { - expect( labeledFieldView.field.locale ).to.equal( locale ); - } ); - - it( 'should set input #id and #ariaDescribedById', () => { - labeledFieldView.render(); - - expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); - expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); - } ); - - it( 'should bind input\'s #isReadOnly to LabeledFieldView#isEnabled', () => { - labeledFieldView.isEnabled = true; - expect( labeledFieldView.field.isReadOnly ).to.be.false; - - labeledFieldView.isEnabled = false; - expect( labeledFieldView.field.isReadOnly ).to.be.true; - } ); - - it( 'should bind input\'s #hasError to LabeledFieldView#errorText', () => { - labeledFieldView.errorText = 'some error'; - expect( labeledFieldView.field.hasError ).to.be.true; - - labeledFieldView.errorText = null; - expect( labeledFieldView.field.hasError ).to.be.false; - } ); - - it( 'should clean LabeledFieldView#errorText upon input\'s DOM "update" event', () => { - labeledFieldView.errorText = 'some error'; - labeledFieldView.field.fire( 'input' ); - expect( labeledFieldView.errorText ).to.be.null; - } ); - } ); - - describe( 'createLabeledDropdown', () => { - let labeledFieldView; - - beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, createLabeledDropdown ); - } ); - - afterEach( () => { - labeledFieldView.destroy(); - } ); - - it( 'should create a DropdownView', () => { - expect( labeledFieldView.field ).to.be.instanceOf( DropdownView ); - } ); - - it( 'should pass the Locale to the dropdown', () => { - expect( labeledFieldView.field.locale ).to.equal( locale ); - } ); - - it( 'should set dropdown\'s #id and #ariaDescribedById', () => { - labeledFieldView.render(); - - expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); - expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); - } ); - - it( 'should bind dropdown\'s #isEnabled to the labeled view', () => { - labeledFieldView.isEnabled = true; - expect( labeledFieldView.field.isEnabled ).to.be.true; - - labeledFieldView.isEnabled = false; - expect( labeledFieldView.field.isEnabled ).to.be.false; - } ); - } ); -} ); diff --git a/theme/components/labeledfieldview/labeledfieldview.css b/theme/components/labeledfieldview/labeledfieldview.css deleted file mode 100644 index 12134c3b..00000000 --- a/theme/components/labeledfieldview/labeledfieldview.css +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/* - * Note: This file should contain the wireframe styles only. But since there are no such styles, - * it acts as a message to the builder telling that it should look for the corresponding styles - * **in the theme** when compiling the editor. - */ From e89d8be55cb74741aaa63852c761f57761cf413d Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 25 Mar 2020 15:44:26 +0100 Subject: [PATCH 10/12] Change folder name by removing `view` from the end --- src/labeledfield/labeledfieldview.js | 241 ++++++++++++++++++ src/labeledfield/utils.js | 92 +++++++ tests/labeledfield/labeledfieldview.js | 166 ++++++++++++ tests/labeledfield/utils.js | 108 ++++++++ .../labeledfield/labeledfieldview.css | 10 + 5 files changed, 617 insertions(+) create mode 100644 src/labeledfield/labeledfieldview.js create mode 100644 src/labeledfield/utils.js create mode 100644 tests/labeledfield/labeledfieldview.js create mode 100644 tests/labeledfield/utils.js create mode 100644 theme/components/labeledfield/labeledfieldview.css diff --git a/src/labeledfield/labeledfieldview.js b/src/labeledfield/labeledfieldview.js new file mode 100644 index 00000000..90aa546b --- /dev/null +++ b/src/labeledfield/labeledfieldview.js @@ -0,0 +1,241 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module ui/labeledfield/labeledfieldview + */ + +import View from '../view'; +import uid from '@ckeditor/ckeditor5-utils/src/uid'; +import LabelView from '../label/labelview'; +import '../../theme/components/labeledfield/labeledfieldview.css'; + +/** + * The labeled field view class. It can be used to enhance any view with the following features: + * + * * a label, + * * (optional) an error message, + * * (optional) an info (status) text, + * + * all bound logically by proper DOM attributes for UX and accessibility. It also provides an interface + * (e.g. observable properties) that allows controlling those additional features. + * + * The constructor of this class requires a callback that returns a view to be labeled. The callback + * is called with unique ids that allow binding of DOM properties: + * + * const labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { + * const inputView = new InputTextView( labeledFieldView.locale ); + * + * inputView.set( { + * id: viewUid, + * ariaDescribedById: statusUid + * } ); + * + * inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); + * inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); + * + * return inputView; + * } ); + * + * labeledInputView.label = 'User name'; + * labeledInputView.infoText = 'Full name like for instance, John Doe.'; + * labeledInputView.render(); + * + * document.body.append( labeledInputView.element ); + * + * See {@link module:ui/labeledfield/utils} to discover ready–to–use labeled input helpers for common + * UI components. + * + * @extends module:ui/view~View + */ +export default class LabeledFieldView extends View { + /** + * Creates an instance of the labeled field view class using a provided creator function + * that provides the view to be labeled. + * + * @param {module:utils/locale~Locale} locale The locale instance. + * @param {Function} viewCreator A function that returns a {@link module:ui/view~View} + * that will be labeled. The following arguments are passed to the creator function: + * + * * an instance of the `LabeledFieldView` to allow binding observable properties, + * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM, + * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM. + */ + constructor( locale, viewCreator ) { + super( locale ); + + const viewUid = `ck-labeled-view-${ uid() }`; + const statusUid = `ck-labeled-view-status-${ uid() }`; + + /** + * The field that gets labeled. + * + * @member {module:ui/view~View} #field + */ + this.field = viewCreator( this, viewUid, statusUid ); + + /** + * The text of the label. + * + * @observable + * @member {String} #label + */ + this.set( 'label' ); + + /** + * Controls whether the component is in read-only mode. + * + * @observable + * @member {Boolean} #isEnabled + */ + this.set( 'isEnabled', true ); + + /** + * The validation error text. When set, it will be displayed + * next to the {@link #field} as a typical validation error message. + * Set it to `null` to hide the message. + * + * **Note:** Setting this property to anything but `null` will automatically + * make the `hasError` of the {@link #field} `true`. + * + * @observable + * @member {String|null} #errorText + */ + this.set( 'errorText', null ); + + /** + * The additional information text displayed next to the {@link #field} which can + * be used to inform the user about its purpose, provide help or hints. + * + * Set it to `null` to hide the message. + * + * **Note:** This text will be displayed in the same place as {@link #errorText} but the + * latter always takes precedence: if the {@link #errorText} is set, it replaces + * {@link #infoText}. + * + * @observable + * @member {String|null} #infoText + */ + this.set( 'infoText', null ); + + /** + * (Optional) The additional CSS class set on the dropdown {@link #element}. + * + * @observable + * @member {String} #class + */ + this.set( 'class' ); + + /** + * The label view instance that describes the entire view. + * + * @member {module:ui/label/labelview~LabelView} #labelView + */ + this.labelView = this._createLabelView( viewUid ); + + /** + * The status view for the {@link #field}. It displays {@link #errorText} and + * {@link #infoText}. + * + * @member {module:ui/view~View} #statusView + */ + this.statusView = this._createStatusView( statusUid ); + + /** + * The combined status text made of {@link #errorText} and {@link #infoText}. + * Note that when present, {@link #errorText} always takes precedence in the + * status. + * + * @see #errorText + * @see #infoText + * @see #statusView + * @private + * @observable + * @member {String|null} #_statusText + */ + this.bind( '_statusText' ).to( + this, 'errorText', + this, 'infoText', + ( errorText, infoText ) => errorText || infoText + ); + + const bind = this.bindTemplate; + + this.setTemplate( { + tag: 'div', + attributes: { + class: [ + 'ck', + 'ck-labeled-view', + bind.to( 'class' ), + bind.if( 'isEnabled', 'ck-disabled', value => !value ) + ] + }, + children: [ + this.labelView, + this.field, + this.statusView + ] + } ); + } + + /** + * Creates label view class instance and bind with view. + * + * @private + * @param {String} id Unique id to set as labelView#for attribute. + * @returns {module:ui/label/labelview~LabelView} + */ + _createLabelView( id ) { + const labelView = new LabelView( this.locale ); + + labelView.for = id; + labelView.bind( 'text' ).to( this, 'label' ); + + return labelView; + } + + /** + * Creates the status view instance. It displays {@link #errorText} and {@link #infoText} + * next to the {@link #field}. See {@link #_statusText}. + * + * @private + * @param {String} statusUid Unique id of the status, shared with the {@link #field view's} + * `aria-describedby` attribute. + * @returns {module:ui/view~View} + */ + _createStatusView( statusUid ) { + const statusView = new View( this.locale ); + const bind = this.bindTemplate; + + statusView.setTemplate( { + tag: 'div', + attributes: { + class: [ + 'ck', + 'ck-labeled-view__status', + bind.if( 'errorText', 'ck-labeled-view__status_error' ), + bind.if( '_statusText', 'ck-hidden', value => !value ) + ], + id: statusUid, + role: bind.if( 'errorText', 'alert' ) + }, + children: [ + { + text: bind.to( '_statusText' ) + } + ] + } ); + + return statusView; + } + + /** + * Focuses the {@link #field}. + */ + focus() { + this.field.focus(); + } +} diff --git a/src/labeledfield/utils.js b/src/labeledfield/utils.js new file mode 100644 index 00000000..02681a42 --- /dev/null +++ b/src/labeledfield/utils.js @@ -0,0 +1,92 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module ui/labeledfield/utils + */ + +import InputTextView from '../inputtext/inputtextview'; +import { createDropdown } from '../dropdown/utils'; + +/** + * A helper for creating labeled inputs. + * + * It creates an instance of a {@link module:ui/inputtext/inputtextview~InputTextView input text} that is + * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view} in DOM. + * + * The helper does the following: + * + * * It sets input's `id` and `ariaDescribedById` attributes. + * * It binds input's `isReadOnly` to the labeled view. + * * It binds input's `hasError` to the labeled view. + * * It enables a logic that cleans up the error when user starts typing in the input.. + * + * Usage: + * + * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); + * console.log( labeledInputView.view ); // An input instance. + * + * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. + * @param {String} viewUid An UID string that allows DOM logical connection between the + * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input. + * @param {String} statusUid An UID string that allows DOM logical connection between the + * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view's status} and the input. + * @returns {module:ui/inputtext/inputtextview~InputTextView} The input text view instance. + */ +export function createLabeledInputText( labeledFieldView, viewUid, statusUid ) { + const inputView = new InputTextView( labeledFieldView.locale ); + + inputView.set( { + id: viewUid, + ariaDescribedById: statusUid + } ); + + inputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value ); + inputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value ); + + inputView.on( 'input', () => { + // UX: Make the error text disappear and disable the error indicator as the user + // starts fixing the errors. + labeledFieldView.errorText = null; + } ); + + return inputView; +} + +/** + * A helper for creating labeled dropdowns. + * + * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is + * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view}. + * + * The helper does the following: + * + * * It sets dropdown's `id` and `ariaDescribedById` attributes. + * * It binds input's `isEnabled` to the labeled view. + * + * Usage: + * + * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); + * console.log( labeledInputView.view ); // A dropdown instance. + * + * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. + * @param {String} viewUid An UID string that allows DOM logical connection between the + * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown. + * @param {String} statusUid An UID string that allows DOM logical connection between the + * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view status} and the dropdown. + * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance. + */ +export function createLabeledDropdown( labeledFieldView, viewUid, statusUid ) { + const dropdownView = createDropdown( labeledFieldView.locale ); + + dropdownView.set( { + id: viewUid, + ariaDescribedById: statusUid + } ); + + dropdownView.bind( 'isEnabled' ).to( labeledFieldView ); + + return dropdownView; +} diff --git a/tests/labeledfield/labeledfieldview.js b/tests/labeledfield/labeledfieldview.js new file mode 100644 index 00000000..561fd548 --- /dev/null +++ b/tests/labeledfield/labeledfieldview.js @@ -0,0 +1,166 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import View from '../../src/view'; +import LabeledFieldView from '../../src/labeledfield/labeledfieldview'; +import LabelView from '../../src/label/labelview'; + +describe( 'LabeledFieldView', () => { + const locale = {}; + + let labeledFieldView, view; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { + view = new View( locale ); + view.setTemplate( { tag: 'div' } ); + view.focus = () => {}; + view.viewUid = viewUid; + view.statusUid = statusUid; + + return view; + } ); + + labeledFieldView.render(); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + describe( 'constructor()', () => { + it( 'should set labeledFieldView#locale', () => { + expect( labeledFieldView.locale ).to.deep.equal( locale ); + } ); + + it( 'should set labeledFieldView#field', () => { + expect( labeledFieldView.field ).to.equal( view ); + } ); + + it( 'should set labeledFieldView#label', () => { + expect( labeledFieldView.label ).to.be.undefined; + } ); + + it( 'should set labeledFieldView#isEnabled', () => { + expect( labeledFieldView.isEnabled ).to.be.true; + } ); + + it( 'should set labeledFieldView#errorText', () => { + expect( labeledFieldView.errorText ).to.be.null; + } ); + + it( 'should set labeledFieldView#infoText', () => { + expect( labeledFieldView.infoText ).to.be.null; + } ); + + it( 'should set labeledFieldView#class', () => { + expect( labeledFieldView.class ).to.be.undefined; + } ); + + it( 'should create labeledFieldView#labelView', () => { + expect( labeledFieldView.labelView ).to.instanceOf( LabelView ); + } ); + + it( 'should create labeledFieldView#statusView', () => { + expect( labeledFieldView.statusView ).to.instanceOf( View ); + + expect( labeledFieldView.statusView.element.tagName ).to.equal( 'DIV' ); + expect( labeledFieldView.statusView.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledFieldView.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; + } ); + + it( 'should allow pairing #view and #labelView by unique id', () => { + expect( labeledFieldView.labelView.for ).to.equal( view.viewUid ); + } ); + + it( 'should allow pairing #view and #statusView by unique id', () => { + expect( view.statusUid ).to.equal( labeledFieldView.statusView.element.id ); + } ); + } ); + + describe( 'template', () => { + it( 'should have the CSS class', () => { + expect( labeledFieldView.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledFieldView.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; + } ); + + it( 'should have #labeledFieldView', () => { + expect( labeledFieldView.template.children[ 0 ] ).to.equal( labeledFieldView.labelView ); + } ); + + it( 'should have #view', () => { + expect( labeledFieldView.template.children[ 1 ] ).to.equal( view ); + } ); + + it( 'should have the #statusView container', () => { + expect( labeledFieldView.template.children[ 2 ] ).to.equal( labeledFieldView.statusView ); + } ); + + describe( 'DOM bindings', () => { + describe( 'class', () => { + it( 'should react on labeledFieldView#class', () => { + labeledFieldView.class = 'foo'; + expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.true; + + labeledFieldView.class = 'bar'; + expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.false; + expect( labeledFieldView.element.classList.contains( 'bar' ) ).to.be.true; + } ); + } ); + + describe( 'status container', () => { + it( 'should react on labeledFieldView#errorText', () => { + const statusElement = labeledFieldView.statusView.element; + + labeledFieldView.errorText = ''; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( '' ); + + labeledFieldView.errorText = 'foo'; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.true; + expect( statusElement.getAttribute( 'role' ) ).to.equal( 'alert' ); + expect( statusElement.innerHTML ).to.equal( 'foo' ); + } ); + + it( 'should react on labeledFieldView#infoText', () => { + const statusElement = labeledFieldView.statusView.element; + + labeledFieldView.infoText = ''; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( '' ); + + labeledFieldView.infoText = 'foo'; + expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; + expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; + expect( statusElement.hasAttribute( 'role' ) ).to.be.false; + expect( statusElement.innerHTML ).to.equal( 'foo' ); + } ); + } ); + } ); + } ); + + describe( 'binding', () => { + it( 'should bind labeledFieldView#label to labeledFieldView.labelView#label', () => { + labeledFieldView.label = 'Foo bar'; + + expect( labeledFieldView.labelView.text ).to.equal( 'Foo bar' ); + } ); + } ); + + describe( 'focus()', () => { + it( 'should focus the #view in DOM', () => { + const spy = sinon.spy( view, 'focus' ); + + labeledFieldView.focus(); + + sinon.assert.calledOnce( spy ); + } ); + } ); +} ); diff --git a/tests/labeledfield/utils.js b/tests/labeledfield/utils.js new file mode 100644 index 00000000..86ababeb --- /dev/null +++ b/tests/labeledfield/utils.js @@ -0,0 +1,108 @@ +/** + * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import { + createLabeledInputText, + createLabeledDropdown +} from '../../src/labeledfield/utils'; + +import LabeledFieldView from '../../src/labeledfield/labeledfieldview'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import InputTextView from '../../src/inputtext/inputtextview'; +import DropdownView from '../../src/dropdown/dropdownview'; + +describe( 'LabeledFieldView utils', () => { + let locale; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + locale = { t: val => val }; + } ); + + describe( 'createLabeledInputText()', () => { + let labeledFieldView; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, createLabeledInputText ); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + it( 'should create an InputTextView instance', () => { + expect( labeledFieldView.field ).to.be.instanceOf( InputTextView ); + } ); + + it( 'should pass the Locale to the input', () => { + expect( labeledFieldView.field.locale ).to.equal( locale ); + } ); + + it( 'should set input #id and #ariaDescribedById', () => { + labeledFieldView.render(); + + expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); + expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + } ); + + it( 'should bind input\'s #isReadOnly to LabeledFieldView#isEnabled', () => { + labeledFieldView.isEnabled = true; + expect( labeledFieldView.field.isReadOnly ).to.be.false; + + labeledFieldView.isEnabled = false; + expect( labeledFieldView.field.isReadOnly ).to.be.true; + } ); + + it( 'should bind input\'s #hasError to LabeledFieldView#errorText', () => { + labeledFieldView.errorText = 'some error'; + expect( labeledFieldView.field.hasError ).to.be.true; + + labeledFieldView.errorText = null; + expect( labeledFieldView.field.hasError ).to.be.false; + } ); + + it( 'should clean LabeledFieldView#errorText upon input\'s DOM "update" event', () => { + labeledFieldView.errorText = 'some error'; + labeledFieldView.field.fire( 'input' ); + expect( labeledFieldView.errorText ).to.be.null; + } ); + } ); + + describe( 'createLabeledDropdown', () => { + let labeledFieldView; + + beforeEach( () => { + labeledFieldView = new LabeledFieldView( locale, createLabeledDropdown ); + } ); + + afterEach( () => { + labeledFieldView.destroy(); + } ); + + it( 'should create a DropdownView', () => { + expect( labeledFieldView.field ).to.be.instanceOf( DropdownView ); + } ); + + it( 'should pass the Locale to the dropdown', () => { + expect( labeledFieldView.field.locale ).to.equal( locale ); + } ); + + it( 'should set dropdown\'s #id and #ariaDescribedById', () => { + labeledFieldView.render(); + + expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); + expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + } ); + + it( 'should bind dropdown\'s #isEnabled to the labeled view', () => { + labeledFieldView.isEnabled = true; + expect( labeledFieldView.field.isEnabled ).to.be.true; + + labeledFieldView.isEnabled = false; + expect( labeledFieldView.field.isEnabled ).to.be.false; + } ); + } ); +} ); diff --git a/theme/components/labeledfield/labeledfieldview.css b/theme/components/labeledfield/labeledfieldview.css new file mode 100644 index 00000000..12134c3b --- /dev/null +++ b/theme/components/labeledfield/labeledfieldview.css @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* + * Note: This file should contain the wireframe styles only. But since there are no such styles, + * it acts as a message to the builder telling that it should look for the corresponding styles + * **in the theme** when compiling the editor. + */ From f76842e9ceabb15fe9b5731d8cee8aecae01cc51 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 25 Mar 2020 16:03:35 +0100 Subject: [PATCH 11/12] Change #field to #fieldView --- src/labeledfield/labeledfieldview.js | 6 +- tests/labeledfield/labeledfieldview.js | 102 ++++++++++++------------- tests/labeledfield/utils.js | 68 ++++++++--------- 3 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/labeledfield/labeledfieldview.js b/src/labeledfield/labeledfieldview.js index 90aa546b..793de6a4 100644 --- a/src/labeledfield/labeledfieldview.js +++ b/src/labeledfield/labeledfieldview.js @@ -74,7 +74,7 @@ export default class LabeledFieldView extends View { * * @member {module:ui/view~View} #field */ - this.field = viewCreator( this, viewUid, statusUid ); + this.fieldView = viewCreator( this, viewUid, statusUid ); /** * The text of the label. @@ -175,7 +175,7 @@ export default class LabeledFieldView extends View { }, children: [ this.labelView, - this.field, + this.fieldView, this.statusView ] } ); @@ -236,6 +236,6 @@ export default class LabeledFieldView extends View { * Focuses the {@link #field}. */ focus() { - this.field.focus(); + this.fieldView.focus(); } } diff --git a/tests/labeledfield/labeledfieldview.js b/tests/labeledfield/labeledfieldview.js index 561fd548..21d709cb 100644 --- a/tests/labeledfield/labeledfieldview.js +++ b/tests/labeledfield/labeledfieldview.js @@ -10,10 +10,10 @@ import LabelView from '../../src/label/labelview'; describe( 'LabeledFieldView', () => { const locale = {}; - let labeledFieldView, view; + let labeledInput, view; beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => { + labeledInput = new LabeledFieldView( locale, ( labeledInput, viewUid, statusUid ) => { view = new View( locale ); view.setTemplate( { tag: 'div' } ); view.focus = () => {}; @@ -23,120 +23,120 @@ describe( 'LabeledFieldView', () => { return view; } ); - labeledFieldView.render(); + labeledInput.render(); } ); afterEach( () => { - labeledFieldView.destroy(); + labeledInput.destroy(); } ); describe( 'constructor()', () => { - it( 'should set labeledFieldView#locale', () => { - expect( labeledFieldView.locale ).to.deep.equal( locale ); + it( 'should set labeledInput#locale', () => { + expect( labeledInput.locale ).to.deep.equal( locale ); } ); - it( 'should set labeledFieldView#field', () => { - expect( labeledFieldView.field ).to.equal( view ); + it( 'should set labeledInput#field', () => { + expect( labeledInput.fieldView ).to.equal( view ); } ); - it( 'should set labeledFieldView#label', () => { - expect( labeledFieldView.label ).to.be.undefined; + it( 'should set labeledInput#label', () => { + expect( labeledInput.label ).to.be.undefined; } ); - it( 'should set labeledFieldView#isEnabled', () => { - expect( labeledFieldView.isEnabled ).to.be.true; + it( 'should set labeledInput#isEnabled', () => { + expect( labeledInput.isEnabled ).to.be.true; } ); - it( 'should set labeledFieldView#errorText', () => { - expect( labeledFieldView.errorText ).to.be.null; + it( 'should set labeledInput#errorText', () => { + expect( labeledInput.errorText ).to.be.null; } ); - it( 'should set labeledFieldView#infoText', () => { - expect( labeledFieldView.infoText ).to.be.null; + it( 'should set labeledInput#infoText', () => { + expect( labeledInput.infoText ).to.be.null; } ); - it( 'should set labeledFieldView#class', () => { - expect( labeledFieldView.class ).to.be.undefined; + it( 'should set labeledInput#class', () => { + expect( labeledInput.class ).to.be.undefined; } ); - it( 'should create labeledFieldView#labelView', () => { - expect( labeledFieldView.labelView ).to.instanceOf( LabelView ); + it( 'should create labeledInput#labelView', () => { + expect( labeledInput.labelView ).to.instanceOf( LabelView ); } ); - it( 'should create labeledFieldView#statusView', () => { - expect( labeledFieldView.statusView ).to.instanceOf( View ); + it( 'should create labeledInput#statusView', () => { + expect( labeledInput.statusView ).to.instanceOf( View ); - expect( labeledFieldView.statusView.element.tagName ).to.equal( 'DIV' ); - expect( labeledFieldView.statusView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledFieldView.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; + expect( labeledInput.statusView.element.tagName ).to.equal( 'DIV' ); + expect( labeledInput.statusView.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledInput.statusView.element.classList.contains( 'ck-labeled-view__status' ) ).to.be.true; } ); it( 'should allow pairing #view and #labelView by unique id', () => { - expect( labeledFieldView.labelView.for ).to.equal( view.viewUid ); + expect( labeledInput.labelView.for ).to.equal( view.viewUid ); } ); it( 'should allow pairing #view and #statusView by unique id', () => { - expect( view.statusUid ).to.equal( labeledFieldView.statusView.element.id ); + expect( view.statusUid ).to.equal( labeledInput.statusView.element.id ); } ); } ); describe( 'template', () => { it( 'should have the CSS class', () => { - expect( labeledFieldView.element.classList.contains( 'ck' ) ).to.be.true; - expect( labeledFieldView.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; + expect( labeledInput.element.classList.contains( 'ck' ) ).to.be.true; + expect( labeledInput.element.classList.contains( 'ck-labeled-view' ) ).to.be.true; } ); - it( 'should have #labeledFieldView', () => { - expect( labeledFieldView.template.children[ 0 ] ).to.equal( labeledFieldView.labelView ); + it( 'should have #labeledInput', () => { + expect( labeledInput.template.children[ 0 ] ).to.equal( labeledInput.labelView ); } ); it( 'should have #view', () => { - expect( labeledFieldView.template.children[ 1 ] ).to.equal( view ); + expect( labeledInput.template.children[ 1 ] ).to.equal( view ); } ); it( 'should have the #statusView container', () => { - expect( labeledFieldView.template.children[ 2 ] ).to.equal( labeledFieldView.statusView ); + expect( labeledInput.template.children[ 2 ] ).to.equal( labeledInput.statusView ); } ); describe( 'DOM bindings', () => { describe( 'class', () => { - it( 'should react on labeledFieldView#class', () => { - labeledFieldView.class = 'foo'; - expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.true; + it( 'should react on labeledInput#class', () => { + labeledInput.class = 'foo'; + expect( labeledInput.element.classList.contains( 'foo' ) ).to.be.true; - labeledFieldView.class = 'bar'; - expect( labeledFieldView.element.classList.contains( 'foo' ) ).to.be.false; - expect( labeledFieldView.element.classList.contains( 'bar' ) ).to.be.true; + labeledInput.class = 'bar'; + expect( labeledInput.element.classList.contains( 'foo' ) ).to.be.false; + expect( labeledInput.element.classList.contains( 'bar' ) ).to.be.true; } ); } ); describe( 'status container', () => { - it( 'should react on labeledFieldView#errorText', () => { - const statusElement = labeledFieldView.statusView.element; + it( 'should react on labeledInput#errorText', () => { + const statusElement = labeledInput.statusView.element; - labeledFieldView.errorText = ''; + labeledInput.errorText = ''; expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; expect( statusElement.hasAttribute( 'role' ) ).to.be.false; expect( statusElement.innerHTML ).to.equal( '' ); - labeledFieldView.errorText = 'foo'; + labeledInput.errorText = 'foo'; expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.true; expect( statusElement.getAttribute( 'role' ) ).to.equal( 'alert' ); expect( statusElement.innerHTML ).to.equal( 'foo' ); } ); - it( 'should react on labeledFieldView#infoText', () => { - const statusElement = labeledFieldView.statusView.element; + it( 'should react on labeledInput#infoText', () => { + const statusElement = labeledInput.statusView.element; - labeledFieldView.infoText = ''; + labeledInput.infoText = ''; expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.true; expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; expect( statusElement.hasAttribute( 'role' ) ).to.be.false; expect( statusElement.innerHTML ).to.equal( '' ); - labeledFieldView.infoText = 'foo'; + labeledInput.infoText = 'foo'; expect( statusElement.classList.contains( 'ck-hidden' ) ).to.be.false; expect( statusElement.classList.contains( 'ck-labeled-view__status_error' ) ).to.be.false; expect( statusElement.hasAttribute( 'role' ) ).to.be.false; @@ -147,10 +147,10 @@ describe( 'LabeledFieldView', () => { } ); describe( 'binding', () => { - it( 'should bind labeledFieldView#label to labeledFieldView.labelView#label', () => { - labeledFieldView.label = 'Foo bar'; + it( 'should bind labeledInput#label to labeledInput.labelView#label', () => { + labeledInput.label = 'Foo bar'; - expect( labeledFieldView.labelView.text ).to.equal( 'Foo bar' ); + expect( labeledInput.labelView.text ).to.equal( 'Foo bar' ); } ); } ); @@ -158,7 +158,7 @@ describe( 'LabeledFieldView', () => { it( 'should focus the #view in DOM', () => { const spy = sinon.spy( view, 'focus' ); - labeledFieldView.focus(); + labeledInput.focus(); sinon.assert.calledOnce( spy ); } ); diff --git a/tests/labeledfield/utils.js b/tests/labeledfield/utils.js index 86ababeb..72bb84b4 100644 --- a/tests/labeledfield/utils.js +++ b/tests/labeledfield/utils.js @@ -23,86 +23,86 @@ describe( 'LabeledFieldView utils', () => { } ); describe( 'createLabeledInputText()', () => { - let labeledFieldView; + let labeledInput; beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, createLabeledInputText ); + labeledInput = new LabeledFieldView( locale, createLabeledInputText ); } ); afterEach( () => { - labeledFieldView.destroy(); + labeledInput.destroy(); } ); it( 'should create an InputTextView instance', () => { - expect( labeledFieldView.field ).to.be.instanceOf( InputTextView ); + expect( labeledInput.fieldView ).to.be.instanceOf( InputTextView ); } ); it( 'should pass the Locale to the input', () => { - expect( labeledFieldView.field.locale ).to.equal( locale ); + expect( labeledInput.fieldView.locale ).to.equal( locale ); } ); it( 'should set input #id and #ariaDescribedById', () => { - labeledFieldView.render(); + labeledInput.render(); - expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); - expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + expect( labeledInput.fieldView.id ).to.equal( labeledInput.labelView.for ); + expect( labeledInput.fieldView.ariaDescribedById ).to.equal( labeledInput.statusView.element.id ); } ); - it( 'should bind input\'s #isReadOnly to LabeledFieldView#isEnabled', () => { - labeledFieldView.isEnabled = true; - expect( labeledFieldView.field.isReadOnly ).to.be.false; + it( 'should bind input\'s #isReadOnly to labeledInput#isEnabled', () => { + labeledInput.isEnabled = true; + expect( labeledInput.fieldView.isReadOnly ).to.be.false; - labeledFieldView.isEnabled = false; - expect( labeledFieldView.field.isReadOnly ).to.be.true; + labeledInput.isEnabled = false; + expect( labeledInput.fieldView.isReadOnly ).to.be.true; } ); - it( 'should bind input\'s #hasError to LabeledFieldView#errorText', () => { - labeledFieldView.errorText = 'some error'; - expect( labeledFieldView.field.hasError ).to.be.true; + it( 'should bind input\'s #hasError to labeledInput#errorText', () => { + labeledInput.errorText = 'some error'; + expect( labeledInput.fieldView.hasError ).to.be.true; - labeledFieldView.errorText = null; - expect( labeledFieldView.field.hasError ).to.be.false; + labeledInput.errorText = null; + expect( labeledInput.fieldView.hasError ).to.be.false; } ); - it( 'should clean LabeledFieldView#errorText upon input\'s DOM "update" event', () => { - labeledFieldView.errorText = 'some error'; - labeledFieldView.field.fire( 'input' ); - expect( labeledFieldView.errorText ).to.be.null; + it( 'should clean labeledInput#errorText upon input\'s DOM "update" event', () => { + labeledInput.errorText = 'some error'; + labeledInput.fieldView.fire( 'input' ); + expect( labeledInput.errorText ).to.be.null; } ); } ); describe( 'createLabeledDropdown', () => { - let labeledFieldView; + let labeledDropdown; beforeEach( () => { - labeledFieldView = new LabeledFieldView( locale, createLabeledDropdown ); + labeledDropdown = new LabeledFieldView( locale, createLabeledDropdown ); } ); afterEach( () => { - labeledFieldView.destroy(); + labeledDropdown.destroy(); } ); it( 'should create a DropdownView', () => { - expect( labeledFieldView.field ).to.be.instanceOf( DropdownView ); + expect( labeledDropdown.fieldView ).to.be.instanceOf( DropdownView ); } ); it( 'should pass the Locale to the dropdown', () => { - expect( labeledFieldView.field.locale ).to.equal( locale ); + expect( labeledDropdown.fieldView.locale ).to.equal( locale ); } ); it( 'should set dropdown\'s #id and #ariaDescribedById', () => { - labeledFieldView.render(); + labeledDropdown.render(); - expect( labeledFieldView.field.id ).to.equal( labeledFieldView.labelView.for ); - expect( labeledFieldView.field.ariaDescribedById ).to.equal( labeledFieldView.statusView.element.id ); + expect( labeledDropdown.fieldView.id ).to.equal( labeledDropdown.labelView.for ); + expect( labeledDropdown.fieldView.ariaDescribedById ).to.equal( labeledDropdown.statusView.element.id ); } ); it( 'should bind dropdown\'s #isEnabled to the labeled view', () => { - labeledFieldView.isEnabled = true; - expect( labeledFieldView.field.isEnabled ).to.be.true; + labeledDropdown.isEnabled = true; + expect( labeledDropdown.fieldView.isEnabled ).to.be.true; - labeledFieldView.isEnabled = false; - expect( labeledFieldView.field.isEnabled ).to.be.false; + labeledDropdown.isEnabled = false; + expect( labeledDropdown.fieldView.isEnabled ).to.be.false; } ); } ); } ); From c5f7e820c4bfbee3371b8ed596bb8220ea5565b2 Mon Sep 17 00:00:00 2001 From: panr Date: Wed, 25 Mar 2020 16:21:20 +0100 Subject: [PATCH 12/12] Fix docs references --- src/labeledfield/labeledfieldview.js | 18 +++++++++--------- src/labeledfield/utils.js | 6 +++--- tests/labeledfield/labeledfieldview.js | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/labeledfield/labeledfieldview.js b/src/labeledfield/labeledfieldview.js index 793de6a4..ec741643 100644 --- a/src/labeledfield/labeledfieldview.js +++ b/src/labeledfield/labeledfieldview.js @@ -70,9 +70,9 @@ export default class LabeledFieldView extends View { const statusUid = `ck-labeled-view-status-${ uid() }`; /** - * The field that gets labeled. + * The field view that gets labeled. * - * @member {module:ui/view~View} #field + * @member {module:ui/view~View} #fieldView */ this.fieldView = viewCreator( this, viewUid, statusUid ); @@ -94,11 +94,11 @@ export default class LabeledFieldView extends View { /** * The validation error text. When set, it will be displayed - * next to the {@link #field} as a typical validation error message. + * next to the {@link #fieldView} as a typical validation error message. * Set it to `null` to hide the message. * * **Note:** Setting this property to anything but `null` will automatically - * make the `hasError` of the {@link #field} `true`. + * make the `hasError` of the {@link #fieldView} `true`. * * @observable * @member {String|null} #errorText @@ -106,7 +106,7 @@ export default class LabeledFieldView extends View { this.set( 'errorText', null ); /** - * The additional information text displayed next to the {@link #field} which can + * The additional information text displayed next to the {@link #fieldView} which can * be used to inform the user about its purpose, provide help or hints. * * Set it to `null` to hide the message. @@ -136,7 +136,7 @@ export default class LabeledFieldView extends View { this.labelView = this._createLabelView( viewUid ); /** - * The status view for the {@link #field}. It displays {@link #errorText} and + * The status view for the {@link #fieldView}. It displays {@link #errorText} and * {@link #infoText}. * * @member {module:ui/view~View} #statusView @@ -199,10 +199,10 @@ export default class LabeledFieldView extends View { /** * Creates the status view instance. It displays {@link #errorText} and {@link #infoText} - * next to the {@link #field}. See {@link #_statusText}. + * next to the {@link #fieldView}. See {@link #_statusText}. * * @private - * @param {String} statusUid Unique id of the status, shared with the {@link #field view's} + * @param {String} statusUid Unique id of the status, shared with the {@link #fieldView view's} * `aria-describedby` attribute. * @returns {module:ui/view~View} */ @@ -233,7 +233,7 @@ export default class LabeledFieldView extends View { } /** - * Focuses the {@link #field}. + * Focuses the {@link #fieldView}. */ focus() { this.fieldView.focus(); diff --git a/src/labeledfield/utils.js b/src/labeledfield/utils.js index 02681a42..24f95c86 100644 --- a/src/labeledfield/utils.js +++ b/src/labeledfield/utils.js @@ -28,7 +28,7 @@ import { createDropdown } from '../dropdown/utils'; * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); * console.log( labeledInputView.view ); // An input instance. * - * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. + * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view. * @param {String} viewUid An UID string that allows DOM logical connection between the * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input. * @param {String} statusUid An UID string that allows DOM logical connection between the @@ -59,7 +59,7 @@ export function createLabeledInputText( labeledFieldView, viewUid, statusUid ) { * A helper for creating labeled dropdowns. * * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is - * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view}. + * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled field view}. * * The helper does the following: * @@ -71,7 +71,7 @@ export function createLabeledInputText( labeledFieldView, viewUid, statusUid ) { * const labeledInputView = new LabeledFieldView( locale, createLabeledDropdown ); * console.log( labeledInputView.view ); // A dropdown instance. * - * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled view. + * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view. * @param {String} viewUid An UID string that allows DOM logical connection between the * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown. * @param {String} statusUid An UID string that allows DOM logical connection between the diff --git a/tests/labeledfield/labeledfieldview.js b/tests/labeledfield/labeledfieldview.js index 21d709cb..44109102 100644 --- a/tests/labeledfield/labeledfieldview.js +++ b/tests/labeledfield/labeledfieldview.js @@ -35,7 +35,7 @@ describe( 'LabeledFieldView', () => { expect( labeledInput.locale ).to.deep.equal( locale ); } ); - it( 'should set labeledInput#field', () => { + it( 'should set labeledInput#fieldView', () => { expect( labeledInput.fieldView ).to.equal( view ); } );