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

I/6049: Introduced the table cell properties UI #227

Merged
merged 38 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
39d9228
First implementation of the cell properties form.
oleq Jan 13, 2020
1c236ce
Added some space to the table cell form. Attached the form to the edi…
oleq Jan 14, 2020
ab6f0cf
Code refactoring.
oleq Jan 14, 2020
b96df24
Used LabeledView in the cell properties form.
oleq Jan 14, 2020
9453c51
Code refactoring.
oleq Jan 15, 2020
afb59d0
Code refactoring and docs.
oleq Jan 15, 2020
b9f2c49
Moved alignment icons to ckeditor5-core. Updated paths to icons.
oleq Jan 15, 2020
176d8f7
Docs.
oleq Jan 15, 2020
df19000
Docs.
oleq Jan 15, 2020
128edef
Removed the obsolete TableStyleUI plugin.
oleq Jan 15, 2020
a86246a
Tests: Added TableCellPropertiesView tests. Code refactoring.
oleq Jan 17, 2020
268a598
Tests: Added tests for the FormRowView.
oleq Jan 17, 2020
e1b263f
Tests: Added TableCellPropertiesUI presence assertion to TableCellPro…
oleq Jan 17, 2020
158179d
Tests: Added tests for UI utils.
oleq Jan 17, 2020
19963df
Code refactoring.
oleq Jan 17, 2020
a19f0c9
Aligned cell properties UI to the latest UI framework API.
oleq Jan 20, 2020
b8461a9
Tests: Partial TableCellPropertiesUI tests.
oleq Jan 21, 2020
25573f4
Merge remote-tracking branch 'origin/i/3287' into i/6049
oleq Jan 21, 2020
f8689d9
Fixed wrong module paths.
oleq Jan 21, 2020
7be0348
Code refactoring.
oleq Jan 21, 2020
f165c95
Tests: Code refactoring.
oleq Jan 21, 2020
e4dfae1
Tests: Finished the TableCellPropertiesUI tests.
oleq Jan 21, 2020
3b139f0
Docs: Fixed broken module paths.
oleq Jan 21, 2020
6580667
Docs: Fixed broken links.
oleq Jan 21, 2020
85d0ce6
Docs: Improved TableCellPropertiesView docs.
oleq Jan 21, 2020
82dae2d
Tests: Aligned tests to the latest TableCellPropertiesView API.
oleq Jan 22, 2020
2aee83a
Added contexts.json entries for the table cell properties UI.
oleq Jan 22, 2020
782e3c5
Code refactoring.
oleq Jan 22, 2020
6bea932
Tests: Code refactoring.
oleq Jan 22, 2020
ca4661d
Merge remote-tracking branch 'origin/i/3287' into i/6049
oleq Jan 22, 2020
cecd9d6
Merge branch 'master' into i/6049
oleq Jan 24, 2020
c6e9716
Merge branch 'master' into i/6049
jodator Jan 27, 2020
ccc7e0c
Code refactoring in the TableCellPropertiesUI class.
oleq Jan 28, 2020
579f7ea
Code refactoring in the TableCellPropertiesUI class.
oleq Jan 28, 2020
08667fb
Update src/tablecellproperties/ui/tablecellpropertiesview.js
oleq Jan 28, 2020
1e9d558
Update src/tablecellproperties/ui/tablecellpropertiesview.js
oleq Jan 28, 2020
21f11d1
Update src/tablecellproperties/ui/tablecellpropertiesview.js
oleq Jan 28, 2020
10ab4ae
Merge branch 'master' into i/6049
oleq Jan 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion lang/contexts.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,33 @@
"Split cell vertically": "Label for the split table cell vertically button.",
"Split cell horizontally": "Label for the split table cell horizontally button.",
"Merge cells": "Label for the merge table cells button.",
"Table toolbar": "The label used by assistive technologies describing a table toolbar attached to a table widget."
"Table toolbar": "The label used by assistive technologies describing a table toolbar attached to a table widget.",
"Cell properties": "The label describing the form allowing to specify the properties of a selected table cell.",
"Border": "The label describing a group of border–related form fields (border style, color, etc.).",
"Style": "The label for the dropdown that allows configuring the border style of a table or a table cell.",
"Width": "The label for the input that allows configuring the border width of a table or a table cell.",
"Color": "The label for the input that allows configuring the border color of a table or a table cell.",
"Background": "The label for the input that allows configuring the background color of a table or a table cell.",
"Padding": "The label for the input that allows configuring the padding of a table cell.",
"Text alignment": "The label for the group of toolbars that allows configuring the text alignment in a table cell.",
"Horizontal text alignment toolbar": "The label used by assistive technologies describing a toolbar that allows configuring the horizontal text alignment in a table cell.",
"Vertical text alignment toolbar": "The label used by assistive technologies describing a toolbar that allows configuring the vertical text alignment in a table cell.",
"Save": "The label for the button that saves the changes made to the table or table cell properties.",
"Cancel": "The label for the button that rejects the changes made to the table or table cell properties.",
"None": "The label for the border style dropdown when no style is applied to a table or a table cell.",
"Solid": "The label for the border style dropdown when the solid border is applied to a table or a table cell.",
"Dotted": "The label for the border style dropdown when the dotted border is applied to a table or a table cell.",
"Dashed": "The label for the border style dropdown when the dashed border is applied to a table or a table cell.",
"Double": "The label for the border style dropdown when the double border is applied to a table or a table cell.",
"Groove": "The label for the border style dropdown when the groove border is applied to a table or a table cell.",
"Ridge": "The label for the border style dropdown when the ridge border is applied to a table or a table cell.",
"Inset": "The label for the border style dropdown when the inset border is applied to a table or a table cell.",
"Outset": "The label for the border style dropdown when the outset border is applied to a table or a table cell.",
"Align cell text to the left": "The label used by assistive technologies describing a button that aligns the table cell text to the left.",
"Align cell text to the center": "The label used by assistive technologies describing a button that aligns the table cell text to the center.",
"Align cell text to the right": "The label used by assistive technologies describing a button that aligns the table cell text to the right.",
"Justify cell text": "The label used by assistive technologies describing a button that justifies the table cell text.",
"Align cell text to the top": "The label used by assistive technologies describing a button that aligns the table cell text to the top.",
"Align cell text to the middle": "The label used by assistive technologies describing a button that aligns the table cell text to the middle.",
"Align cell text to the bottom": "The label used by assistive technologies describing a button that aligns the table cell text to the bottom."
}
8 changes: 4 additions & 4 deletions src/tablecellproperties.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
*/

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import TableCellPropertiesUI from './tablecellproperties/tablecellpropertiesui';
import TableCellPropertiesEditing from './tablecellproperties/tablecellpropertiesediting';

/**
* The table cell properties feature.
*
* This is a "glue" plugin which loads the
* {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing table properties editing feature} and
* table cell properties UI feature.
* {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing table cell properties editing feature} and
* the {@link module:table/tablecellproperties/tablecellpropertiesui~TableCellPropertiesUI table cell properties UI feature}.
*
* @extends module:core/plugin~Plugin
*/
Expand All @@ -32,6 +32,6 @@ export default class TableCellProperties extends Plugin {
* @inheritDoc
*/
static get requires() {
return [ TableCellPropertiesEditing ];
return [ TableCellPropertiesEditing, TableCellPropertiesUI ];
}
}
278 changes: 278 additions & 0 deletions src/tablecellproperties/tablecellpropertiesui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/**
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module table/tablecellproperties/tablecellpropertiesui
*/

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import { getTableWidgetAncestor } from '../utils';
import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
import TableCellPropertiesView from './ui/tablecellpropertiesview';
import tableCellProperties from './../../theme/icons/table-cell-properties.svg';
import { repositionContextualBalloon, getBalloonCellPositionData } from '../ui/utils';

const DEFAULT_BORDER_STYLE = 'none';
const DEFAULT_HORIZONTAL_ALIGNMENT = 'left';
const DEFAULT_VERTICAL_ALIGNMENT = 'middle';

/**
* The table cell properties UI plugin. It introduces the `'tableCellProperties'` button
* that opens a form allowing to specify visual styling of a table cell.
*
* It uses the
* {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
*
* @extends module:core/plugin~Plugin
*/
export default class TableCellPropertiesUI extends Plugin {
/**
* @inheritDoc
*/
static get requires() {
return [ ContextualBalloon ];
}

/**
* @inheritDoc
*/
static get pluginName() {
return 'TableCellPropertiesUI';
}

/**
* @inheritDoc
*/
init() {
const editor = this.editor;
const t = editor.t;

/**
* The contextual balloon plugin instance.
*
* @private
* @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}
*/
this._balloon = editor.plugins.get( ContextualBalloon );

/**
* The cell properties form view displayed inside the balloon.
*
* @member {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}
*/
this.view = this._createPropertiesView();

/**
* The batch used to undo all changes made by the form (which are live, as the user types)
* when "Cancel" was pressed. Each time the view is shown, a new batch is created.
*
* @protected
* @member {module:engine/model/batch~Batch}
*/
this._undoStepBatch = null;

editor.ui.componentFactory.add( 'tableCellProperties', locale => {
const view = new ButtonView( locale );

view.set( {
label: t( 'Cell properties' ),
icon: tableCellProperties,
tooltip: true
} );

this.listenTo( view, 'execute', () => this._showView() );

return view;
} );
}

/**
* @inheritDoc
*/
destroy() {
super.destroy();

// Destroy created UI components as they are not automatically destroyed.
// See https://github.com/ckeditor/ckeditor5/issues/1341.
this.view.destroy();
}

/**
* Creates the {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} instance.
*
* @private
* @returns {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} The cell
* properties form view instance.
*/
_createPropertiesView() {
const editor = this.editor;
const viewDocument = editor.editing.view.document;
const view = new TableCellPropertiesView( editor.locale );

// Render the view so its #element is available for the clickOutsideHandler.
view.render();

this.listenTo( view, 'submit', () => {
this._hideView();
} );

this.listenTo( view, 'cancel', () => {
editor.execute( 'undo', this._undoStepBatch );
this._hideView();
} );

// Close the balloon on Esc key press.
view.keystrokes.set( 'Esc', ( data, cancel ) => {
this._hideView();
cancel();
} );

// Reposition the balloon or hide the form if a table cell is no longer selected.
this.listenTo( editor.ui, 'update', () => {
if ( !getTableWidgetAncestor( viewDocument.selection ) ) {
this._hideView();
} else if ( this._isViewVisible ) {
repositionContextualBalloon( editor );
}
} );

// Close on click outside of balloon panel element.
clickOutsideHandler( {
emitter: view,
activator: () => this._isViewInBalloon,
contextElements: [ this._balloon.view.element ],
callback: () => this._hideView()
} );

// Create the "UI -> editor data" binding.
// These listeners update the editor data (via table commands) when any observable
// property of the view has changed. This makes the view live, which means the changes are
// visible in the editing as soon as the user types or changes fields' values.
view.on( 'change:borderStyle', this._getPropertyChangeCallback( 'tableCellBorderStyle' ) );
view.on( 'change:borderColor', this._getPropertyChangeCallback( 'tableCellBorderColor' ) );
view.on( 'change:borderWidth', this._getPropertyChangeCallback( 'tableCellBorderWidth' ) );
view.on( 'change:padding', this._getPropertyChangeCallback( 'tableCellPadding' ) );
view.on( 'change:backgroundColor', this._getPropertyChangeCallback( 'tableCellBackgroundColor' ) );
view.on( 'change:horizontalAlignment', this._getPropertyChangeCallback( 'tableCellHorizontalAlignment' ) );
view.on( 'change:verticalAlignment', this._getPropertyChangeCallback( 'tableCellVerticalAlignment' ) );

return view;
}

/**
* In this method the "editor data -> UI" binding is happening.
*
* When executed, this method obtains selected cell property values from various table commands
* and passes them to the {@link #view}.
*
* This way, the UI stays up–to–date with the editor data.
*
* @private
*/
_fillViewFormFromCommandValues() {
const commands = this.editor.commands;

this.view.set( {
borderStyle: commands.get( 'tableCellBorderStyle' ).value || DEFAULT_BORDER_STYLE,
borderColor: commands.get( 'tableCellBorderColor' ).value || '',
borderWidth: commands.get( 'tableCellBorderWidth' ).value || '',
padding: commands.get( 'tableCellPadding' ).value || '',
backgroundColor: commands.get( 'tableCellBackgroundColor' ).value || '',
horizontalAlignment: commands.get( 'tableCellHorizontalAlignment' ).value || DEFAULT_HORIZONTAL_ALIGNMENT,
verticalAlignment: commands.get( 'tableCellVerticalAlignment' ).value || DEFAULT_VERTICAL_ALIGNMENT,
} );
}

/**
* Shows the {@link #view} in the {@link #_balloon}.
*
* **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains
* all changes made to the document when the view is visible, allowing a single undo step
* for all of them.
*
* @protected
*/
_showView() {
const editor = this.editor;

this._balloon.add( {
view: this.view,
position: getBalloonCellPositionData( editor )
} );

// Create a new batch. Clicking "Cancel" will undo this batch.
this._undoStepBatch = editor.model.createBatch();

// Update the view with the model values.
this._fillViewFormFromCommandValues();

// Basic a11y.
this.view.focus();
}

/**
* Removes the {@link #view} from the {@link #_balloon}.
*
* @protected
*/
_hideView() {
if ( !this._isViewInBalloon ) {
return;
}

const editor = this.editor;

this.stopListening( editor.ui, 'update' );

// Blur any input element before removing it from DOM to prevent issues in some browsers.
// See https://github.com/ckeditor/ckeditor5/issues/1501.
this.view.saveButtonView.focus();

this._balloon.remove( this.view );

// Make sure the focus is not lost in the process by putting it directly
// into the editing view.
this.editor.editing.view.focus();
}

/**
* Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.
*
* @private
* @type {Boolean}
*/
get _isViewVisible() {
return this._balloon.visibleView === this.view;
}

/**
* Returns `true` when the {@link #view} is in the {@link #_balloon}.
*
* @private
* @type {Boolean}
*/
get _isViewInBalloon() {
return this._balloon.hasView( this.view );
}

/**
* Creates a callback that when executed upon {@link #view view's} property change
* executes a related editor command with the new property value.
*
* @private
* @param {String} commandName
* @returns {Function}
*/
_getPropertyChangeCallback( commandName ) {
return ( evt, propertyName, newValue ) => {
this.editor.execute( commandName, {
value: newValue,
batch: this._undoStepBatch
} );
};
}
}
Loading