Skip to content

Commit

Permalink
Add React UI Table Heading button
Browse files Browse the repository at this point in the history
Fixes #259
  • Loading branch information
jbalsas authored and ipeychev committed Jun 29, 2015
1 parent 1d8462d commit 47c294f
Show file tree
Hide file tree
Showing 11 changed files with 324 additions and 8 deletions.
5 changes: 5 additions & 0 deletions src/ui/react/language-template.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ AlloyEditor.Strings = {
columnInsertAfter: CKEDITOR.lang['{lang}'].table.column.insertAfter,
columnInsertBefore: CKEDITOR.lang['{lang}'].table.column.insertBefore,
deleteTable: CKEDITOR.lang['{lang}'].table.deleteTable,
headers: CKEDITOR.lang['{lang}'].table.headers,
headersBoth: CKEDITOR.lang['{lang}'].table.headersBoth,
headersColumn: CKEDITOR.lang['{lang}'].table.headersColumn,
headersNone: CKEDITOR.lang['{lang}'].table.headersNone,
headersRow: CKEDITOR.lang['{lang}'].table.headersRow,
row: CKEDITOR.lang['{lang}'].table.row.menu,
rowDelete: CKEDITOR.lang['{lang}'].table.row.deleteRow,
rowInsertAfter: CKEDITOR.lang['{lang}'].table.row.insertAfter,
Expand Down
13 changes: 10 additions & 3 deletions src/ui/react/src/assets/sass/alloy-editor-core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ IE10-PLUS::-ms-reveal, [class*=alloy-editor-toolbar] {
}
}

.alloy-editor-container-styles {
.alloy-editor-container-dropdown, [class*=alloy-editor-container-dropdown-] {
float: left $IE9-ONLY;
width: 5 * $base-button-width;

Expand All @@ -254,24 +254,31 @@ IE10-PLUS::-ms-reveal, [class*=alloy-editor-toolbar] {
float: right $IE9-ONLY;
}

.alloy-editor-selected-style {
.alloy-editor-container-dropdown-selected-item {
@include flex(1);

display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

position: relative $IE9-ONLY;
top: 50% $IE9-ONLY;
transform: translateY(-50%) $IE9-ONLY;
}

IE10-PLUS::-ms-reveal, .alloy-editor-selected-style {
IE10-PLUS::-ms-reveal, .alloy-editor-container-dropdown-selected-item {
top: 0;
transform: translateY(0);
}
}
}
}

.alloy-editor-container-dropdown-xl {
width: 8 * $base-button-width;
}

.alloy-editor-twitter-link {
padding: 0 5px;

Expand Down
4 changes: 2 additions & 2 deletions src/ui/react/src/components/buttons/button-styles.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@
}

return (
<div className="alloy-editor-container-styles alloy-editor-has-dropdown">
<div className="alloy-editor-container-dropdown alloy-editor-has-dropdown">
<button aria-expanded={this.props.expanded} aria-label={AlloyEditor.Strings.styles + ' ' + activeStyle} className="alloy-editor-toolbar-element" onClick={this.props.toggleDropdown} role="combobox" tabIndex={this.props.tabIndex} title={AlloyEditor.Strings.styles + ' ' + activeStyle}>
<div className="alloy-editor-container">
<span className="alloy-editor-selected-style">{activeStyle}</span>
<span className="alloy-editor-container-dropdown-selected-item">{activeStyle}</span>
<span className="alloy-editor-icon-arrow"></span>
</div>
</button>
Expand Down
130 changes: 130 additions & 0 deletions src/ui/react/src/components/buttons/button-table-heading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
(function () {
'use strict';

/**
* The ButtonTableHeading class provides functionality to work with table heading.
*
* @class ButtonTableHeading
*/
var ButtonTableHeading = React.createClass({
// Allows validating props being passed to the component.
propTypes: {
/**
* List of the commands the button is able to handle.
*
* @property {Array} commands
*/
commands: React.PropTypes.arrayOf(React.PropTypes.object),

/**
* The editor instance where the component is being used.
*
* @property {Object} editor
*/
editor: React.PropTypes.object.isRequired,

/**
* Indicates whether the styles list is expanded or not.
*
* @property {Boolean} expanded
*/
expanded: React.PropTypes.bool,

/**
* The label that should be used for accessibility purposes.
*
* @property {String} label
*/
label: React.PropTypes.string,

/**
* The tabIndex of the button in its toolbar current state. A value other than -1
* means that the button has focus and is the active element.
*
* @property {Number} tabIndex
*/
tabIndex: React.PropTypes.number,

/**
* Callback provided by the button host to notify when the styles list has been expanded.
*
* @property {Function} toggleDropdown
*/
toggleDropdown: React.PropTypes.func
},

// Lifecycle. Provides static properties to the widget.
statics: {
/**
* The name which will be used as an alias of the button in the configuration.
*
* @static
* @property {String} key
* @default tableRow
*/
key: 'tableHeading'
},

/**
* Lifecycle. Renders the UI of the button.
*
* @method render
* @return {Object} The content which should be rendered.
*/
render: function() {
var buttonCommandsList;
var buttonCommandsListId;

if (this.props.expanded) {
buttonCommandsListId = ButtonTableHeading.key + 'List';
buttonCommandsList = <AlloyEditor.ButtonCommandsList commands={this._getCommands()} editor={this.props.editor} listId={buttonCommandsListId} onDismiss={this.props.toggleDropdown} />
}

var activeHeading = new CKEDITOR.Table(this.props.editor.get('nativeEditor')).getHeading();
var activeHeadingIntro = AlloyEditor.Strings.headers + ':';
var activeHeadingLabel = AlloyEditor.Strings['headers' + activeHeading];

return (
<div className="alloy-editor-container-dropdown-xl alloy-editor-has-dropdown">
<button aria-expanded={this.props.expanded} aria-label="" className="alloy-editor-toolbar-element" onClick={this.props.toggleDropdown} role="combobox" tabIndex={this.props.tabIndex} title="">
<div className="alloy-editor-container">
<span className="alloy-editor-container-dropdown-selected-item">{activeHeadingIntro} <strong>{activeHeadingLabel}</strong></span>
<span className="alloy-editor-icon-arrow"></span>
</div>
</button>
{buttonCommandsList}
</div>
);
},

/**
* Returns a list of commands. If a list of commands was passed
* as property `commands`, it will take a precedence over the default ones.
*
* @method _getCommands
* @return {Array} The list of available commands.
*/
_getCommands: function () {
return this.props.commands || [
{
command: 'tableHeadingNone',
label: AlloyEditor.Strings.headersNone
},
{
command: 'tableHeadingRow',
label: AlloyEditor.Strings.headersRow
},
{
command: 'tableHeadingColumn',
label: AlloyEditor.Strings.headersColumn
},
{
command: 'tableHeadingBoth',
label: AlloyEditor.Strings.headersBoth
}
];
}
});

AlloyEditor.Buttons[ButtonTableHeading.key] = AlloyEditor.ButtonTableHeading = ButtonTableHeading;
}());
2 changes: 1 addition & 1 deletion src/ui/react/src/selections/selections.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
test: AlloyEditor.SelectionTest.text
}, {
name: 'table',
buttons: ['tableRow', 'tableColumn', 'tableCell', 'tableRemove'],
buttons: ['tableHeading', 'tableRow', 'tableColumn', 'tableCell', 'tableRemove'],
getArrowBoxClasses: AlloyEditor.SelectionGetArrowBoxClasses.table,
setPosition: AlloyEditor.SelectionSetPosition.table,
test: AlloyEditor.SelectionTest.table
Expand Down
86 changes: 86 additions & 0 deletions src/ui/react/test/button-table-heading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
(function() {
'use strict';

var assert = chai.assert;
var TestUtils = React.addons.TestUtils;

var selectTable = function() {
var tableElement = this.nativeEditor.element.find('table').getItem(0);

this.nativeEditor.getSelection().selectElement(tableElement);
};

describe('ButtonTableHeading', function() {
this.timeout(35000);

before(Utils.createAlloyEditor);

after(Utils.destroyAlloyEditor);

beforeEach(Utils.beforeEach);

afterEach(Utils.afterEach);

it('should render just the menu button when not expanded', function() {
var buttonTableHeading = React.render(<AlloyEditor.ButtonTableHeading editor={this.editor} expanded={false} />, this.container);

var menuButton = TestUtils.findRenderedDOMComponentWithTag(buttonTableHeading, 'button');

var dropdown = TestUtils.scryRenderedDOMComponentsWithClass(buttonTableHeading, 'alloy-editor-dropdown');

assert.ok(menuButton);
assert.equal(0, dropdown.length);
});

it('should show a dropdown with the action buttons when expanded', function() {
var buttonTableHeading = React.render(<AlloyEditor.ButtonTableHeading editor={this.editor} expanded={true} />, this.container);

var dropdown = TestUtils.findRenderedDOMComponentWithClass(buttonTableHeading, 'alloy-editor-dropdown');
var actionButtons = TestUtils.scryRenderedDOMComponentsWithTag(dropdown, 'button');

assert.ok(dropdown);
assert.ok(actionButtons.length);
});

it('should switch from any given heading setting to any possible setting properly', function() {
var HEADING_NONE = CKEDITOR.Table.HEADING_NONE,
HEADING_COL = CKEDITOR.Table.HEADING_COL,
HEADING_ROW = CKEDITOR.Table.HEADING_ROW,
HEADING_BOTH = CKEDITOR.Table.HEADING_BOTH;

var headingFixtures = {};

headingFixtures[HEADING_NONE] = '3_by_3_table_no_heading.html';
headingFixtures[HEADING_ROW] = '3_by_3_table_row_heading.html';
headingFixtures[HEADING_COL] = '3_by_3_table_col_heading.html';
headingFixtures[HEADING_BOTH] = '3_by_3_table_both_heading.html';

var testMatrix = [
{initial: HEADING_NONE, expected: HEADING_ROW},
{initial: HEADING_NONE, expected: HEADING_COL},
{initial: HEADING_NONE, expected: HEADING_BOTH},
{initial: HEADING_ROW, expected: HEADING_NONE},
{initial: HEADING_ROW, expected: HEADING_COL},
{initial: HEADING_ROW, expected: HEADING_BOTH},
{initial: HEADING_COL, expected: HEADING_NONE},
{initial: HEADING_COL, expected: HEADING_ROW},
{initial: HEADING_COL, expected: HEADING_BOTH},
{initial: HEADING_BOTH, expected: HEADING_NONE},
{initial: HEADING_BOTH, expected: HEADING_ROW},
{initial: HEADING_BOTH, expected: HEADING_COL}
];

testMatrix.forEach(function(testData) {
var errorMessage = 'Changing table heading from ' + testData.initial + ' to ' + testData.expected + ' did not produce the expected result';
var initialFixture = headingFixtures[testData.initial];
var expectedFixture = headingFixtures[testData.expected];
var buttonDropdown = React.render(<AlloyEditor.ButtonTableHeading editor={this.editor} expanded={true} />, this.container);
var buttonCommand = 'tableHeading' + testData.expected;

Utils.assertDropdownCommandButtonResult.call(this,
initialFixture, buttonDropdown, buttonCommand, expectedFixture, selectTable, errorMessage
);
}.bind(this));
});
});
}());
22 changes: 22 additions & 0 deletions src/ui/react/test/fixtures/3_by_3_table_both_heading.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<table>
<thead>
<tr>
<th scope="col">&nbsp;</th>
<th scope="col">&nbsp;</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">&nbsp;</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th scope="row">&nbsp;</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
20 changes: 20 additions & 0 deletions src/ui/react/test/fixtures/3_by_3_table_col_heading.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<table>
<tbody>
<tr>
<th scope="row">&nbsp;</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th scope="row">&nbsp;</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<th scope="row">&nbsp;</th>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
20 changes: 20 additions & 0 deletions src/ui/react/test/fixtures/3_by_3_table_no_heading.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<table>
<tbody>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
22 changes: 22 additions & 0 deletions src/ui/react/test/fixtures/3_by_3_table_row_heading.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<table>
<thead>
<tr>
<th scope="col">&nbsp;</th>
<th scope="col">&nbsp;</th>
<th scope="col">&nbsp;</th>
</tr>
</thead>
<tbody>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
Loading

0 comments on commit 47c294f

Please sign in to comment.