diff --git a/lib/client-assets.php b/lib/client-assets.php
index 2bee5c2c7d8ac7..437bdfe20e2992 100644
--- a/lib/client-assets.php
+++ b/lib/client-assets.php
@@ -554,7 +554,6 @@ function gutenberg_register_scripts_and_styles() {
array(
'lodash',
'tinymce-latest-lists',
- 'tinymce-latest-table',
'wp-a11y',
'wp-api-fetch',
'wp-blob',
@@ -796,11 +795,6 @@ function gutenberg_register_vendor_scripts() {
'https://unpkg.com/tinymce@' . $tinymce_version . '/plugins/lists/plugin' . $suffix . '.js',
array( 'wp-tinymce' )
);
- gutenberg_register_vendor_script(
- 'tinymce-latest-table',
- 'https://unpkg.com/tinymce@' . $tinymce_version . '/plugins/table/plugin' . $suffix . '.js',
- array( 'wp-tinymce' )
- );
gutenberg_register_vendor_script(
'lodash',
'https://unpkg.com/lodash@4.17.5/lodash' . $suffix . '.js'
diff --git a/packages/block-library/package.json b/packages/block-library/package.json
index 2a4ff968c3d971..ccda95f0e8b06a 100644
--- a/packages/block-library/package.json
+++ b/packages/block-library/package.json
@@ -46,6 +46,7 @@
"url": "^0.11.0"
},
"devDependencies": {
+ "deep-freeze": "^0.0.1",
"enzyme": "^3.3.0",
"react-test-renderer": "^16.4.1"
},
diff --git a/packages/block-library/src/table/edit.js b/packages/block-library/src/table/edit.js
new file mode 100644
index 00000000000000..f733d988138ae5
--- /dev/null
+++ b/packages/block-library/src/table/edit.js
@@ -0,0 +1,418 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { Fragment, Component } from '@wordpress/element';
+import { InspectorControls, BlockControls, RichText } from '@wordpress/editor';
+import { __ } from '@wordpress/i18n';
+import {
+ PanelBody,
+ ToggleControl,
+ TextControl,
+ Button,
+ Toolbar,
+ DropdownMenu,
+} from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import {
+ createTable,
+ updateCellContent,
+ insertRow,
+ deleteRow,
+ insertColumn,
+ deleteColumn,
+} from './state';
+
+export default class TableEdit extends Component {
+ constructor() {
+ super( ...arguments );
+
+ this.onCreateTable = this.onCreateTable.bind( this );
+ this.onChangeFixedLayout = this.onChangeFixedLayout.bind( this );
+ this.onChange = this.onChange.bind( this );
+ this.onChangeInitialColumnCount = this.onChangeInitialColumnCount.bind( this );
+ this.onChangeInitialRowCount = this.onChangeInitialRowCount.bind( this );
+ this.renderSection = this.renderSection.bind( this );
+ this.getTableControls = this.getTableControls.bind( this );
+ this.onInsertRow = this.onInsertRow.bind( this );
+ this.onInsertRowBefore = this.onInsertRowBefore.bind( this );
+ this.onInsertRowAfter = this.onInsertRowAfter.bind( this );
+ this.onDeleteRow = this.onDeleteRow.bind( this );
+ this.onInsertColumn = this.onInsertColumn.bind( this );
+ this.onInsertColumnBefore = this.onInsertColumnBefore.bind( this );
+ this.onInsertColumnAfter = this.onInsertColumnAfter.bind( this );
+ this.onDeleteColumn = this.onDeleteColumn.bind( this );
+
+ this.state = {
+ initialRowCount: 2,
+ initialColumnCount: 2,
+ selectedCell: null,
+ };
+ }
+
+ /**
+ * Updates the initial column count used for table creation.
+ *
+ * @param {number} initialColumnCount New initial column count.
+ */
+ onChangeInitialColumnCount( initialColumnCount ) {
+ this.setState( { initialColumnCount } );
+ }
+
+ /**
+ * Updates the initial row count used for table creation.
+ *
+ * @param {number} initialRowCount New initial row count.
+ */
+ onChangeInitialRowCount( initialRowCount ) {
+ this.setState( { initialRowCount } );
+ }
+
+ /**
+ * Creates a table based on dimensions in local state.
+ */
+ onCreateTable() {
+ const { setAttributes } = this.props;
+ let { initialRowCount, initialColumnCount } = this.state;
+
+ initialRowCount = parseInt( initialRowCount, 10 ) || 2;
+ initialColumnCount = parseInt( initialColumnCount, 10 ) || 2;
+
+ setAttributes( createTable( {
+ rowCount: initialRowCount,
+ columnCount: initialColumnCount,
+ } ) );
+ }
+
+ /**
+ * Toggles whether the table has a fixed layout or not.
+ */
+ onChangeFixedLayout() {
+ const { attributes, setAttributes } = this.props;
+ const { hasFixedLayout } = attributes;
+
+ setAttributes( { hasFixedLayout: ! hasFixedLayout } );
+ }
+
+ /**
+ * Changes the content of the currently selected cell.
+ *
+ * @param {Array} content A RichText content value.
+ */
+ onChange( content ) {
+ const { selectedCell } = this.state;
+
+ if ( ! selectedCell ) {
+ return;
+ }
+
+ const { attributes, setAttributes } = this.props;
+ const { section, rowIndex, columnIndex } = selectedCell;
+
+ setAttributes( updateCellContent( attributes, {
+ section,
+ rowIndex,
+ columnIndex,
+ content,
+ } ) );
+ }
+
+ /**
+ * Inserts a row at the currently selected row index, plus `delta`.
+ *
+ * @param {number} delta Offset for selected row index at which to insert.
+ */
+ onInsertRow( delta ) {
+ const { selectedCell } = this.state;
+
+ if ( ! selectedCell ) {
+ return;
+ }
+
+ const { attributes, setAttributes } = this.props;
+ const { section, rowIndex } = selectedCell;
+
+ this.setState( { selectedCell: null } );
+ setAttributes( insertRow( attributes, {
+ section,
+ rowIndex: rowIndex + delta,
+ } ) );
+ }
+
+ /**
+ * Inserts a row before the currently selected row.
+ */
+ onInsertRowBefore() {
+ this.onInsertRow( 0 );
+ }
+
+ /**
+ * Inserts a row after the currently selected row.
+ */
+ onInsertRowAfter() {
+ this.onInsertRow( 1 );
+ }
+
+ /**
+ * Deletes the currently selected row.
+ */
+ onDeleteRow() {
+ const { selectedCell } = this.state;
+
+ if ( ! selectedCell ) {
+ return;
+ }
+
+ const { attributes, setAttributes } = this.props;
+ const { section, rowIndex } = selectedCell;
+
+ this.setState( { selectedCell: null } );
+ setAttributes( deleteRow( attributes, { section, rowIndex } ) );
+ }
+
+ /**
+ * Inserts a column at the currently selected column index, plus `delta`.
+ *
+ * @param {number} delta Offset for selected column index at which to insert.
+ */
+ onInsertColumn( delta = 0 ) {
+ const { selectedCell } = this.state;
+
+ if ( ! selectedCell ) {
+ return;
+ }
+
+ const { attributes, setAttributes } = this.props;
+ const { section, columnIndex } = selectedCell;
+
+ this.setState( { selectedCell: null } );
+ setAttributes( insertColumn( attributes, {
+ section,
+ columnIndex: columnIndex + delta,
+ } ) );
+ }
+
+ /**
+ * Inserts a column before the currently selected column.
+ */
+ onInsertColumnBefore() {
+ this.onInsertColumn( 0 );
+ }
+
+ /**
+ * Inserts a column after the currently selected column.
+ */
+ onInsertColumnAfter() {
+ this.onInsertColumn( 1 );
+ }
+
+ /**
+ * Deletes the currently selected column.
+ */
+ onDeleteColumn() {
+ const { selectedCell } = this.state;
+
+ if ( ! selectedCell ) {
+ return;
+ }
+
+ const { attributes, setAttributes } = this.props;
+ const { section, columnIndex } = selectedCell;
+
+ this.setState( { selectedCell: null } );
+ setAttributes( deleteColumn( attributes, { section, columnIndex } ) );
+ }
+
+ /**
+ * Creates an onFocus handler for a specified cell.
+ *
+ * @param {Object} selectedCell Object with `section`, `rowIndex`, and
+ * `columnIndex` properties.
+ *
+ * @return {Function} Function to call on focus.
+ */
+ createOnFocus( selectedCell ) {
+ return () => {
+ this.setState( { selectedCell } );
+ };
+ }
+
+ /**
+ * Gets the table controls to display in the block toolbar.
+ *
+ * @return {Array} Table controls.
+ */
+ getTableControls() {
+ const { selectedCell } = this.state;
+
+ return [
+ {
+ icon: 'table-row-before',
+ title: __( 'Add Row Before' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onInsertRowBefore,
+ },
+ {
+ icon: 'table-row-after',
+ title: __( 'Add Row After' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onInsertRowAfter,
+ },
+ {
+ icon: 'table-row-delete',
+ title: __( 'Delete Row' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onDeleteRow,
+ },
+ {
+ icon: 'table-col-before',
+ title: __( 'Add Column Before' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onInsertColumnBefore,
+ },
+ {
+ icon: 'table-col-after',
+ title: __( 'Add Column After' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onInsertColumnAfter,
+ },
+ {
+ icon: 'table-col-delete',
+ title: __( 'Delete Column' ),
+ isDisabled: ! selectedCell,
+ onClick: this.onDeleteColumn,
+ },
+ ];
+ }
+
+ /**
+ * Renders a table section.
+ *
+ * @param {string} options.type Section type: head, body, or foot.
+ * @param {Array} options.rows The rows to render.
+ *
+ * @return {Object} React element for the section.
+ */
+ renderSection( { type, rows } ) {
+ if ( ! rows.length ) {
+ return null;
+ }
+
+ const Tag = `t${ type }`;
+ const { selectedCell } = this.state;
+
+ return (
+
+ { cells.map( ( { content, tag: CellTag }, columnIndex ) => {
+ const isSelected = selectedCell && (
+ type === selectedCell.section &&
+ rowIndex === selectedCell.rowIndex &&
+ columnIndex === selectedCell.columnIndex
+ );
+
+ const cell = {
+ section: type,
+ rowIndex,
+ columnIndex,
+ };
+
+ const classes = classnames( {
+ 'is-selected': isSelected,
+ } );
+
+ return (
+
+ ) }
+
Version | Musician | Date |
---|---|---|
.70 | No musician chosen. | May 27, 2003 |
1.0 | Miles Davis | January 3, 2004 |
Lots of versions skipped, see the full list | … | … |
4.4 | Clifford Brown | December 8, 2015 |
4.5 | Coleman Hawkins | April 12, 2016 |
4.6 | Pepper Adams | August 16, 2016 |
4.7 | Sarah Vaughan | December 6, 2016 |