UNPKG

5.78 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4 */
5/**
6 * @module table/ui/inserttableview
7 */
8import { View, ButtonView, addKeyboardHandlingForGrid } from 'ckeditor5/src/ui';
9import { KeystrokeHandler, FocusTracker } from 'ckeditor5/src/utils';
10import './../../theme/inserttable.css';
11/**
12 * The table size view.
13 *
14 * It renders a 10x10 grid to choose the inserted table size.
15 */
16export default class InsertTableView extends View {
17 /**
18 * @inheritDoc
19 */
20 constructor(locale) {
21 super(locale);
22 const bind = this.bindTemplate;
23 this.items = this._createGridCollection();
24 this.keystrokes = new KeystrokeHandler();
25 this.focusTracker = new FocusTracker();
26 this.set('rows', 0);
27 this.set('columns', 0);
28 this.bind('label').to(this, 'columns', this, 'rows', (columns, rows) => `${rows} × ${columns}`);
29 this.setTemplate({
30 tag: 'div',
31 attributes: {
32 class: ['ck']
33 },
34 children: [
35 {
36 tag: 'div',
37 attributes: {
38 class: ['ck-insert-table-dropdown__grid']
39 },
40 on: {
41 'mouseover@.ck-insert-table-dropdown-grid-box': bind.to('boxover')
42 },
43 children: this.items
44 },
45 {
46 tag: 'div',
47 attributes: {
48 class: [
49 'ck',
50 'ck-insert-table-dropdown__label'
51 ],
52 'aria-hidden': true
53 },
54 children: [
55 {
56 text: bind.to('label')
57 }
58 ]
59 }
60 ],
61 on: {
62 mousedown: bind.to(evt => {
63 evt.preventDefault();
64 }),
65 click: bind.to(() => {
66 this.fire('execute');
67 })
68 }
69 });
70 // #rows and #columns are set via changes to #focusTracker on mouse over.
71 this.on('boxover', (evt, domEvt) => {
72 const { row, column } = domEvt.target.dataset;
73 this.items.get((parseInt(row, 10) - 1) * 10 + (parseInt(column, 10) - 1)).focus();
74 });
75 // This allows the #rows and #columns to be updated when:
76 // * the user navigates the grid using the keyboard,
77 // * the user moves the mouse over grid items.
78 this.focusTracker.on('change:focusedElement', (evt, name, focusedElement) => {
79 if (!focusedElement) {
80 return;
81 }
82 const { row, column } = focusedElement.dataset;
83 // As row & column indexes are zero-based transform it to number of selected rows & columns.
84 this.set({
85 rows: parseInt(row),
86 columns: parseInt(column)
87 });
88 });
89 this.on('change:columns', () => this._highlightGridBoxes());
90 this.on('change:rows', () => this._highlightGridBoxes());
91 }
92 render() {
93 super.render();
94 addKeyboardHandlingForGrid({
95 keystrokeHandler: this.keystrokes,
96 focusTracker: this.focusTracker,
97 gridItems: this.items,
98 numberOfColumns: 10,
99 uiLanguageDirection: this.locale && this.locale.uiLanguageDirection
100 });
101 for (const item of this.items) {
102 this.focusTracker.add(item.element);
103 }
104 this.keystrokes.listenTo(this.element);
105 }
106 /**
107 * @inheritDoc
108 */
109 focus() {
110 this.items.get(0).focus();
111 }
112 /**
113 * @inheritDoc
114 */
115 focusLast() {
116 this.items.get(0).focus();
117 }
118 /**
119 * Highlights grid boxes depending on rows and columns selected.
120 */
121 _highlightGridBoxes() {
122 const rows = this.rows;
123 const columns = this.columns;
124 this.items.map((boxView, index) => {
125 // Translate box index to the row & column index.
126 const itemRow = Math.floor(index / 10);
127 const itemColumn = index % 10;
128 // Grid box is highlighted when its row & column index belongs to selected number of rows & columns.
129 const isOn = itemRow < rows && itemColumn < columns;
130 boxView.set('isOn', isOn);
131 });
132 }
133 /**
134 * Creates a new Button for the grid.
135 *
136 * @param locale The locale instance.
137 * @param row Row number.
138 * @param column Column number.
139 * @param label The grid button label.
140 */
141 _createGridButton(locale, row, column, label) {
142 const button = new ButtonView(locale);
143 button.set({
144 label,
145 class: 'ck-insert-table-dropdown-grid-box'
146 });
147 button.extendTemplate({
148 attributes: {
149 'data-row': row,
150 'data-column': column
151 }
152 });
153 return button;
154 }
155 /**
156 * @returns A view collection containing boxes to be placed in a table grid.
157 */
158 _createGridCollection() {
159 const boxes = [];
160 // Add grid boxes to table selection view.
161 for (let index = 0; index < 100; index++) {
162 const row = Math.floor(index / 10);
163 const column = index % 10;
164 const label = `${row + 1} × ${column + 1}`;
165 boxes.push(this._createGridButton(this.locale, row + 1, column + 1, label));
166 }
167 return this.createCollection(boxes);
168 }
169}