diff --git a/src/formheader/formheaderview.js b/src/formheader/formheaderview.js new file mode 100644 index 00000000..cddc3078 --- /dev/null +++ b/src/formheader/formheaderview.js @@ -0,0 +1,96 @@ +/** + * @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/formheader/formheaderview + */ + +import View from '../view'; + +import '../../theme/components/formheader/formheader.css'; + +/** + * The class component representing a form header view. It should be used in more advanced forms to + * describe the main purpose of the form. + * + * By default the component contains a bolded label view that has to be set. The label is usually a short (at most 3-word) string. + * The component can also be extended by any other elements, like: icons, dropdowns, etc. + * + * It is used i.a. + * by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} + * and {@link module:special-characters/ui/specialcharactersnavigationview~SpecialCharactersNavigationView}. + * + * The latter is an example, where the component has been extended by {@link module:ui/dropdown/dropdownview~DropdownView} view. + * + * @extends module:ui/view~View + */ +export default class FormHeaderView extends View { + /** + * Creates an instance of the form header class. + * + * @param {module:utils/locale~Locale} locale The locale instance. + * @param {Object} options + * @param {String} [options.label] A label. + * @param {String} [options.class] An additional class. + */ + constructor( locale, options = {} ) { + super( locale ); + + const bind = this.bindTemplate; + + /** + * The label of the header. + * + * @observable + * @member {String} #label + */ + this.set( 'label', options.label || '' ); + + /** + * An additional CSS class added to the {@link #element}. + * + * @observable + * @member {String} #class + */ + this.set( 'class', options.class || null ); + + /** + * A collection of header items. + * + * @readonly + * @member {module:ui/viewcollection~ViewCollection} + */ + this.children = this.createCollection(); + + this.setTemplate( { + tag: 'div', + attributes: { + class: [ + 'ck', + 'ck-form__header', + bind.to( 'class' ) + ] + }, + children: this.children + } ); + + const label = new View( locale ); + + label.setTemplate( { + tag: 'span', + attributes: { + class: [ + 'ck', + 'ck-form__header__label' + ] + }, + children: [ + { text: bind.to( 'label' ) } + ] + } ); + + this.children.add( label ); + } +} diff --git a/tests/formheader/formheaderview.js b/tests/formheader/formheaderview.js new file mode 100644 index 00000000..9d8959f1 --- /dev/null +++ b/tests/formheader/formheaderview.js @@ -0,0 +1,98 @@ +/** + * @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 ViewCollection from '../../src/viewcollection'; +import FormHeaderView from '../../src/formheader/formheaderview'; + +describe( 'FormHeaderView', () => { + let view, locale; + + beforeEach( () => { + locale = { t: val => val }; + view = new FormHeaderView( locale ); + view.render(); + } ); + + afterEach( () => { + view.element.remove(); + } ); + + describe( 'constructor()', () => { + it( 'should set view#locale', () => { + expect( view.locale ).to.equal( locale ); + } ); + + it( 'should create view#children collection', () => { + expect( view.children ).to.be.instanceOf( ViewCollection ); + expect( view.children ).to.have.length( 1 ); + } ); + + it( 'should set view#label', () => { + expect( view.label ).to.equal( '' ); + } ); + + it( 'should set view#class', () => { + expect( view.class ).to.be.null; + } ); + + it( 'should set the template', () => { + expect( view.element.classList.contains( 'ck' ) ).to.be.true; + expect( view.element.classList.contains( 'ck-form__header' ) ).to.be.true; + } ); + + describe( 'options', () => { + it( 'should set view#class when class was passed', () => { + const view = new FormHeaderView( locale, { + class: 'foo' + } ); + + expect( view.class ).to.equal( 'foo' ); + + view.destroy(); + } ); + + it( 'should use a label text when passed', () => { + const view = new FormHeaderView( locale, { + label: 'foo' + } ); + + view.render(); + + expect( view.element.firstChild.classList.contains( 'ck' ) ).to.be.true; + expect( view.element.firstChild.classList.contains( 'ck-form__header__label' ) ).to.be.true; + expect( view.element.firstChild.textContent ).to.equal( 'foo' ); + + view.destroy(); + } ); + } ); + + describe( 'template bindings', () => { + it( 'should bind #class to the template', () => { + view.class = 'foo'; + expect( view.element.classList.contains( 'foo' ) ).to.be.true; + } ); + + it( 'should bind #label to the template', () => { + view.label = 'bar'; + expect( view.element.firstChild.textContent ).to.equal( 'bar' ); + + view.label = 'baz'; + expect( view.element.firstChild.textContent ).to.equal( 'baz' ); + } ); + + it( 'should bind #children to the template', () => { + const child = new View(); + child.setTemplate( { tag: 'div' } ); + + view.children.add( child ); + + expect( view.element.childNodes[ 1 ] ).to.equal( child.element ); + + view.destroy(); + } ); + } ); + } ); +} ); diff --git a/theme/components/formheader/formheader.css b/theme/components/formheader/formheader.css new file mode 100644 index 00000000..417c5324 --- /dev/null +++ b/theme/components/formheader/formheader.css @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +:root { + --ck-table-form-header-height: 38px; +} + +.ck.ck-form__header { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + padding: var(--ck-spacing-small) var(--ck-spacing-large); + height: var(--ck-table-form-header-height); + line-height: var(--ck-table-form-header-height); + border-bottom: 1px solid var(--ck-color-base-border); + + & .ck-form__header__label { + font-weight: bold; + } +}