This repository has been archived by the owner on Jun 26, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #537 from ckeditor/i/6049
Feature: Created the `LabeledView` class (see ckeditor/ckeditor5-table#227). Also added `id` properties to the `DropdownView` and `LabelView` for compatibility with the `LabeledView`.
- Loading branch information
Showing
11 changed files
with
666 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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/labeledview/labeledview | ||
*/ | ||
|
||
import View from '../view'; | ||
import uid from '@ckeditor/ckeditor5-utils/src/uid'; | ||
import LabelView from '../label/labelview'; | ||
import '../../theme/components/labeledview/labeledview.css'; | ||
|
||
/** | ||
* The labeled 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 LabeledView( locale, ( labeledView, viewUid, statusUid ) => { | ||
* const inputView = new InputTextView( labeledView.locale ); | ||
* | ||
* inputView.set( { | ||
* id: viewUid, | ||
* ariaDescribedById: statusUid | ||
* } ); | ||
* | ||
* inputView.bind( 'isReadOnly' ).to( labeledView, 'isEnabled', value => !value ); | ||
* inputView.bind( 'hasError' ).to( labeledView, '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/labeledview/utils} to discover ready–to–use labeled input helpers for common | ||
* UI components. | ||
* | ||
* @extends module:ui/view~View | ||
*/ | ||
export default class LabeledView extends View { | ||
/** | ||
* Creates an instance of the labeled 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. | ||
*/ | ||
constructor( locale, viewCreator ) { | ||
super( locale ); | ||
|
||
const viewUid = `ck-labeled-view-${ uid() }`; | ||
const statusUid = `ck-labeled-view-status-${ uid() }`; | ||
|
||
/** | ||
* The view that gets labeled. | ||
* | ||
* @member {module:ui/view~View} #view | ||
*/ | ||
this.view = 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 #view} 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`. | ||
* | ||
* @observable | ||
* @member {String|null} #errorText | ||
*/ | ||
this.set( 'errorText', null ); | ||
|
||
/** | ||
* The additional information text displayed next to the {@link #view} 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 #view}. 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.view, | ||
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 #view}. See {@link #_statusText}. | ||
* | ||
* @private | ||
* @param {String} statusUid Unique id of the status, shared with the {@link #view 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 #view}. | ||
*/ | ||
focus() { | ||
this.view.focus(); | ||
} | ||
} |
Oops, something went wrong.