Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 105fbea

Browse files
authored
Merge pull request #414 from ckeditor/t/402
Feature: Implemented the `SwitchButtonView`. Closes #402. Closes #403. Also: * Simplified the `ListItemView` class, which is now just a container for `ButtonView` (and others), * Moved `ListItemView#style` and `#class` to the `ButtonView` (as `#class` and `#labelStyle`), * Enhanced the `addListToDropdown` utility with a better configuration (`ListDropdownItemDefinition`) and the support for buttons, switch buttons, and separators, * `.ck-button` and `.ck-list` became `flex` containers; the first one to allow complex inner structures (like the toggle) and the later to take control of complex list items (like `.ck-switchbutton`). BREAKING CHANGE: Most of the `ListItemView` functionality is now handled by the `ButtonView`, BREAKING CHANGE: The API of the `addListToDropdown` has changed; see `ListDropdownItemDefinition` to learn more, BREAKING CHANGE: The `.ck-button` and `.ck-list` classes are using `flex` which may have an impact on rendering.
2 parents 608525f + 221b7c8 commit 105fbea

File tree

14 files changed

+409
-308
lines changed

14 files changed

+409
-308
lines changed

src/button/button.jsdoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@
120120
* @member {String} #tabindex
121121
*/
122122

123+
/**
124+
* (Optional) The additional CSS class set on the button.
125+
*
126+
* @observable
127+
* @member {String} #class
128+
*/
129+
130+
/**
131+
* (Optional) The value of the `style` attribute of the label.
132+
*
133+
* @observable
134+
* @member {String} #labelStyle
135+
*/
136+
123137
/**
124138
* Fired when the button view is clicked. It won't be fired when the button {@link #isEnabled}
125139
* is `false`.

src/button/buttonview.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export default class ButtonView extends View {
4646
const ariaLabelUid = uid();
4747

4848
// Implement the Button interface.
49+
this.set( 'class' );
50+
this.set( 'labelStyle' );
4951
this.set( 'icon' );
5052
this.set( 'isEnabled', true );
5153
this.set( 'isOn', false );
@@ -120,6 +122,7 @@ export default class ButtonView extends View {
120122
class: [
121123
'ck',
122124
'ck-button',
125+
bind.to( 'class' ),
123126
bind.if( 'isEnabled', 'ck-disabled', value => !value ),
124127
bind.if( 'isVisible', 'ck-hidden', value => !value ),
125128
bind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),
@@ -201,6 +204,7 @@ export default class ButtonView extends View {
201204
*/
202205
_createLabelView( ariaLabelUid ) {
203206
const labelView = new View();
207+
const bind = this.bindTemplate;
204208

205209
labelView.setTemplate( {
206210
tag: 'span',
@@ -210,6 +214,7 @@ export default class ButtonView extends View {
210214
'ck',
211215
'ck-button__label'
212216
],
217+
style: bind.to( 'labelStyle' ),
213218
id: `ck-editor__aria-label_${ ariaLabelUid }`,
214219
},
215220

src/button/switchbuttonview.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md.
4+
*/
5+
6+
/**
7+
* @module ui/button/switchbuttonview
8+
*/
9+
10+
import View from '../view';
11+
import ButtonView from './buttonview';
12+
13+
import '../../theme/components/button/switchbutton.css';
14+
15+
/**
16+
* The switch button view class.
17+
*
18+
* const view = new SwitchButtonView();
19+
*
20+
* view.set( {
21+
* withText: true,
22+
* label: 'Switch me!'
23+
* } );
24+
*
25+
* view.render();
26+
*
27+
* document.body.append( view.element );
28+
*
29+
* @extends module:ui/buttonview~ButtonView
30+
*/
31+
export default class SwitchButtonView extends ButtonView {
32+
/**
33+
* @inheritDoc
34+
*/
35+
constructor( locale ) {
36+
super( locale );
37+
38+
/**
39+
* The toggle switch of the button.
40+
*
41+
* @readonly
42+
* @member {module:ui/view~View} #toggleSwitchView
43+
*/
44+
this.toggleSwitchView = this._createToggleView();
45+
46+
this.extendTemplate( {
47+
attributes: {
48+
class: 'ck-switchbutton'
49+
}
50+
} );
51+
}
52+
53+
/**
54+
* @inheritDoc
55+
*/
56+
render() {
57+
super.render();
58+
59+
this.children.add( this.toggleSwitchView );
60+
}
61+
62+
/**
63+
* Creates a toggle child view.
64+
*
65+
* @private
66+
* @returns {module:ui/view~View}
67+
*/
68+
_createToggleView() {
69+
const toggleSwitchView = new View();
70+
71+
toggleSwitchView.setTemplate( {
72+
tag: 'span',
73+
74+
attributes: {
75+
class: [
76+
'ck',
77+
'ck-button__toggle'
78+
],
79+
},
80+
81+
children: [
82+
{
83+
tag: 'span',
84+
85+
attributes: {
86+
class: [
87+
'ck',
88+
'ck-button__toggle__inner'
89+
],
90+
}
91+
}
92+
]
93+
} );
94+
95+
return toggleSwitchView;
96+
}
97+
}

src/dropdown/dropdownview.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ export default class DropdownView extends View {
188188
/**
189189
* Fired when the toolbar button or list item is executed.
190190
*
191-
* For {@link #listView} It fires when one of the list items has been
192-
* {@link module:ui/list/listitemview~ListItemView#event:execute executed}.
191+
* For {@link #listView} It fires when a child of some {@link module:ui/list/listitemview~ListItemView}
192+
* fired `execute`.
193193
*
194194
* For {@link #toolbarView} It fires when one of the buttons has been
195195
* {@link module:ui/button/buttonview~ButtonView#event:execute executed}.

src/dropdown/utils.js

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import ToolbarView from '../toolbar/toolbarview';
1414
import ListView from '../list/listview';
1515
import ListItemView from '../list/listitemview';
1616
import ListSeparatorView from '../list/listseparatorview';
17+
import ButtonView from '../button/buttonview';
18+
import SwitchButtonView from '../button/switchbuttonview';
1719

1820
import clickOutsideHandler from '../bindings/clickoutsidehandler';
1921

@@ -146,8 +148,15 @@ export function addToolbarToDropdown( dropdownView, buttons ) {
146148
*
147149
* const items = new Collection();
148150
*
149-
* items.add( new Model( { label: 'First item', style: 'color: red' } ) );
150-
* items.add( new Model( { label: 'Second item', style: 'color: green', class: 'foo' } ) );
151+
* items.add( {
152+
* type: 'button',
153+
* model: new Model( { label: 'First item', labelStyle: 'color: red' } )
154+
* } );
155+
*
156+
* items.add( {
157+
* type: 'button',
158+
* model: new Model( { label: 'Second item', labelStyle: 'color: green', class: 'foo' } )
159+
* } );
151160
*
152161
* const dropdown = createDropdown( locale );
153162
*
@@ -164,28 +173,34 @@ export function addToolbarToDropdown( dropdownView, buttons ) {
164173
* See {@link module:ui/dropdown/utils~createDropdown} and {@link module:list/list~List}.
165174
*
166175
* @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ListVIew` will be added.
167-
* @param {module:utils/collection~Collection} items
168-
* that the inner dropdown {@link module:ui/list/listview~ListView} children are created from.
169-
*
170-
* Usually, it is a collection of {@link module:ui/model~Model models}.
176+
* @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} items
177+
* A collection of the list item definitions to populate the list.
171178
*/
172179
export function addListToDropdown( dropdownView, items ) {
173180
const locale = dropdownView.locale;
174181
const listView = dropdownView.listView = new ListView( locale );
175182

176-
listView.items.bindTo( items ).using( itemModel => {
177-
let item;
183+
listView.items.bindTo( items ).using( ( { type, model } ) => {
184+
if ( type === 'separator' ) {
185+
return new ListSeparatorView( locale );
186+
} else if ( type === 'button' || type === 'switchbutton' ) {
187+
const listItemView = new ListItemView( locale );
188+
let buttonView;
178189

179-
if ( itemModel.isSeparator ) {
180-
item = new ListSeparatorView( locale );
181-
} else {
182-
item = new ListItemView( locale );
190+
if ( type === 'button' ) {
191+
buttonView = new ButtonView( locale );
192+
} else {
193+
buttonView = new SwitchButtonView( locale );
194+
}
183195

184-
// Bind all attributes of the model to the item view.
185-
item.bind( ...Object.keys( itemModel ) ).to( itemModel );
186-
}
196+
// Bind all model properties to the button view.
197+
buttonView.bind( ...Object.keys( model ) ).to( model );
198+
buttonView.delegate( 'execute' ).to( listItemView );
199+
200+
listItemView.children.add( buttonView );
187201

188-
return item;
202+
return listItemView;
203+
}
189204
} );
190205

191206
dropdownView.panelView.children.add( listView );
@@ -223,7 +238,12 @@ function closeDropdownOnBlur( dropdownView ) {
223238
// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
224239
function closeDropdownOnExecute( dropdownView ) {
225240
// Close the dropdown when one of the list items has been executed.
226-
dropdownView.on( 'execute', () => {
241+
dropdownView.on( 'execute', evt => {
242+
// Toggling a switch button view should not close the dropdown.
243+
if ( evt.source instanceof SwitchButtonView ) {
244+
return;
245+
}
246+
227247
dropdownView.isOpen = false;
228248
} );
229249
}
@@ -248,3 +268,14 @@ function focusDropdownContentsOnArrows( dropdownView ) {
248268
}
249269
} );
250270
}
271+
272+
/**
273+
* A definition of the list item used by the {@link module:ui/dropdown/utils~addListToDropdown}
274+
* utility.
275+
*
276+
* @typedef {Object} module:ui/dropdown/utils~ListDropdownItemDefinition
277+
*
278+
* @property {String} type Either `'separator'`, `'button'` or `'switchbutton'`.
279+
* @property {module:ui/model~Model} [model] Model of the item (when **not** `'separator'`).
280+
* Its properties fuel the newly created list item (or its children, depending on the `type`).
281+
*/

0 commit comments

Comments
 (0)