From 27faf862d98f3f655dde615b3c95eee372c89cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20R?= Date: Tue, 13 Jun 2017 15:51:03 +0100 Subject: [PATCH] EZP-26516: As an editor, I want to be able to add/edit tabular data in RichText editor (#772) * Add Table button and disable embed and image inside table * Add support for table headings Missign alloy menu item, and as we support table headings now we can add this. * Add Richtext table styling when border is used * [Tests] Adjust image and embed tests * [Tests] Add test for table button * [Trasnlation] Add string for table button * Fix the click test on table button * Cleanup based on review, jshint & cleanup of jsdoc * Refactor to avoid duplicated isDisabled logic --- Resources/config/yui.yml | 4 + Resources/public/css/modules/richtext.css | 6 + .../public/css/theme/modules/richtext.css | 8 ++ .../public/js/alloyeditor/buttons/embed.js | 14 ++- .../public/js/alloyeditor/buttons/embed.jsx | 14 ++- .../public/js/alloyeditor/buttons/image.js | 14 ++- .../public/js/alloyeditor/buttons/image.jsx | 14 ++- .../public/js/alloyeditor/buttons/table.js | 58 +++++++++ .../public/js/alloyeditor/buttons/table.jsx | 53 ++++++++ .../public/js/alloyeditor/plugins/embed.js | 8 ++ .../js/alloyeditor/toolbars/config/table.js | 1 + .../js/views/fields/ez-richtext-editview.js | 2 +- Resources/translations/onlineeditor.en.xlf | 6 + .../ez-alloyeditor-button-embed-tests.jsx | 51 +++++++- .../ez-alloyeditor-button-image-tests.jsx | 51 +++++++- .../ez-alloyeditor-button-table-tests.jsx | 113 ++++++++++++++++++ .../buttons/ez-alloyeditor-button-table.html | 45 +++++++ .../ez-alloyeditor-plugin-embed-tests.js | 62 +++++++++- 18 files changed, 505 insertions(+), 19 deletions(-) create mode 100644 Resources/public/js/alloyeditor/buttons/table.js create mode 100644 Resources/public/js/alloyeditor/buttons/table.jsx create mode 100644 Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-table-tests.jsx create mode 100644 Tests/js/alloyeditor/buttons/ez-alloyeditor-button-table.html diff --git a/Resources/config/yui.yml b/Resources/config/yui.yml index d50bf161c..8cadcc60b 100644 --- a/Resources/config/yui.yml +++ b/Resources/config/yui.yml @@ -81,6 +81,9 @@ system: ez-alloyeditor-button-paragraph: requires: ['ez-alloyeditor', 'ez-translator'] path: "%ez_platformui.public_dir%/js/alloyeditor/buttons/paragraph.js" + ez-alloyeditor-button-table: + requires: ['ez-alloyeditor', 'ez-translator'] + path: "%ez_platformui.public_dir%/js/alloyeditor/buttons/table.js" ez-alloyeditor-button-list: requires: ['ez-alloyeditor', 'ez-translator'] path: "%ez_platformui.public_dir%/js/alloyeditor/buttons/list.js" @@ -947,6 +950,7 @@ system: - 'ez-alloyeditor-button-paragraph' - 'ez-alloyeditor-button-list' - 'ez-alloyeditor-button-embed' + - 'ez-alloyeditor-button-table' - 'ez-alloyeditor-button-image' - 'ez-alloyeditor-button-imagevariation' - 'ez-alloyeditor-button-embedcenter' diff --git a/Resources/public/css/modules/richtext.css b/Resources/public/css/modules/richtext.css index 8e435d87a..7b2c26480 100644 --- a/Resources/public/css/modules/richtext.css +++ b/Resources/public/css/modules/richtext.css @@ -7,3 +7,9 @@ margin: 1em 0; line-height: 1.4; } + +/* To be able to put cursor in empty cells during edit, and more clearly see empty cells in view */ +.ez-richtext-content table td, +.ez-richtext-content table th { + padding: 3px; +} diff --git a/Resources/public/css/theme/modules/richtext.css b/Resources/public/css/theme/modules/richtext.css index 8139a174b..3f3f1b55c 100644 --- a/Resources/public/css/theme/modules/richtext.css +++ b/Resources/public/css/theme/modules/richtext.css @@ -9,3 +9,11 @@ .ez-richtext-content table:not([border]) th { border: 1px dotted #888; } + +/* To get rid of the 3d effect on outer border and make it "flat" */ +.ez-richtext-content table[border="1"], +.ez-richtext-content table[border="1"] tr, +.ez-richtext-content table[border="1"] td, +.ez-richtext-content table[border="1"] th { + border: 1px solid #888; +} diff --git a/Resources/public/js/alloyeditor/buttons/embed.js b/Resources/public/js/alloyeditor/buttons/embed.js index b9e04694d..5e71e3c41 100644 --- a/Resources/public/js/alloyeditor/buttons/embed.js +++ b/Resources/public/js/alloyeditor/buttons/embed.js @@ -55,6 +55,16 @@ YUI.add('ez-alloyeditor-button-embed', function (Y) { return Y.eZ.trans('select.a.content.to.embed', {}, 'onlineeditor'); }, + /** + * Checks if the command is disabled in the current selection. + * + * @method isDisabled + * @return {Boolean} True if the command is disabled, false otherwise. + */ + isDisabled: function () { + return !this.props.editor.get('nativeEditor').ezembed.canBeAdded(); + }, + /** * Executes the command generated by the ezembed plugin and set the * correct value based on the choosen content. @@ -75,10 +85,10 @@ YUI.add('ez-alloyeditor-button-embed', function (Y) { }, render: function () { - var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(); + var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(), disabled = this.isDisabled(); return ( - React.createElement("button", {className: css, onClick: this._chooseContent, tabIndex: this.props.tabIndex}, + React.createElement("button", {className: css, disabled: disabled, onClick: this._chooseContent, tabIndex: this.props.tabIndex}, React.createElement("span", {className: "ez-ae-icon ez-ae-icon-embed ez-font-icon"}), React.createElement("p", {className: "ez-ae-label"}, Y.eZ.trans('embed', {}, 'onlineeditor')) ) diff --git a/Resources/public/js/alloyeditor/buttons/embed.jsx b/Resources/public/js/alloyeditor/buttons/embed.jsx index f0d12a541..ec1113322 100644 --- a/Resources/public/js/alloyeditor/buttons/embed.jsx +++ b/Resources/public/js/alloyeditor/buttons/embed.jsx @@ -50,6 +50,16 @@ YUI.add('ez-alloyeditor-button-embed', function (Y) { return Y.eZ.trans('select.a.content.to.embed', {}, 'onlineeditor'); }, + /** + * Checks if the command is disabled in the current selection. + * + * @method isDisabled + * @return {Boolean} True if the command is disabled, false otherwise. + */ + isDisabled: function () { + return !this.props.editor.get('nativeEditor').ezembed.canBeAdded(); + }, + /** * Executes the command generated by the ezembed plugin and set the * correct value based on the choosen content. @@ -70,10 +80,10 @@ YUI.add('ez-alloyeditor-button-embed', function (Y) { }, render: function () { - var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(); + var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(), disabled = this.isDisabled(); return ( - diff --git a/Resources/public/js/alloyeditor/buttons/image.js b/Resources/public/js/alloyeditor/buttons/image.js index 13ba62c74..22650693b 100644 --- a/Resources/public/js/alloyeditor/buttons/image.js +++ b/Resources/public/js/alloyeditor/buttons/image.js @@ -59,6 +59,16 @@ YUI.add('ez-alloyeditor-button-image', function (Y) { return Y.eZ.trans('select.an.image.to.embed', {}, 'onlineeditor'); }, + /** + * Checks if the command is disabled in the current selection. + * + * @method isDisabled + * @return {Boolean} True if the command is disabled, false otherwise. + */ + isDisabled: function () { + return !this.props.editor.get('nativeEditor').ezembed.canBeAdded(); + }, + /** * Executes the command generated by the ezembed plugin and set the * correct value based on the choosen image. @@ -82,10 +92,10 @@ YUI.add('ez-alloyeditor-button-image', function (Y) { }, render: function () { - var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(); + var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(), disabled = this.isDisabled(); return ( - React.createElement("button", {className: css, onClick: this._chooseContent, tabIndex: this.props.tabIndex}, + React.createElement("button", {className: css, disabled: disabled, onClick: this._chooseContent, tabIndex: this.props.tabIndex}, React.createElement("span", {className: "ez-ae-icon ez-ae-icon-image ez-font-icon"}), React.createElement("p", {className: "ez-ae-label"}, Y.eZ.trans('image', {}, 'onlineeditor')) ) diff --git a/Resources/public/js/alloyeditor/buttons/image.jsx b/Resources/public/js/alloyeditor/buttons/image.jsx index e01655e6d..dde9aff7c 100644 --- a/Resources/public/js/alloyeditor/buttons/image.jsx +++ b/Resources/public/js/alloyeditor/buttons/image.jsx @@ -54,6 +54,16 @@ YUI.add('ez-alloyeditor-button-image', function (Y) { return Y.eZ.trans('select.an.image.to.embed', {}, 'onlineeditor'); }, + /** + * Checks if the command is disabled in the current selection. + * + * @method isDisabled + * @return {Boolean} True if the command is disabled, false otherwise. + */ + isDisabled: function () { + return !this.props.editor.get('nativeEditor').ezembed.canBeAdded(); + }, + /** * Executes the command generated by the ezembed plugin and set the * correct value based on the choosen image. @@ -77,10 +87,10 @@ YUI.add('ez-alloyeditor-button-image', function (Y) { }, render: function () { - var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(); + var css = "ae-button ez-ae-labeled-button" + this.getStateClasses(), disabled = this.isDisabled(); return ( - diff --git a/Resources/public/js/alloyeditor/buttons/table.js b/Resources/public/js/alloyeditor/buttons/table.js new file mode 100644 index 000000000..45254eb18 --- /dev/null +++ b/Resources/public/js/alloyeditor/buttons/table.js @@ -0,0 +1,58 @@ +/* + * Copyright (C) eZ Systems AS. All rights reserved. + * For full copyright and license information view LICENSE file distributed with this source code. + */ +// **NOTICE:** +// THIS IS AN AUTO-GENERATED FILE +// DO YOUR MODIFICATIONS IN THE CORRESPONDING .jsx FILE +// AND REGENERATE IT WITH: grunt jsx +// END OF NOTICE +YUI.add('ez-alloyeditor-button-table', function (Y) { + "use strict"; + + var AlloyEditor = Y.eZ.AlloyEditor, + React = Y.eZ.React, + ButtonTable; + + /** + * The ButtonTable class provides functionality for creating and editing a table in a document. ButtonTable + * renders in two different modes: + * + * - Normal: Just a button that allows to switch to the edition mode + * - Exclusive: The ButtonTableEdit UI with all the table edition controls. + * + * This component is a copy of AlloyEditor.ButtonTable, with slightly different render() logic. + * + * @class ButtonTable + */ + ButtonTable = React.createClass({displayName: "ButtonTable", + propTypes: { + editor: React.PropTypes.object.isRequired, + label: React.PropTypes.string, + tabIndex: React.PropTypes.number, + }, + + statics: { + key: 'eztable' + }, + + render: function () { + if (this.props.renderExclusive) { + return ( + React.createElement(AlloyEditor.ButtonTableEdit, React.__spread({}, this.props)) + ); + } + + var css = "ae-button ez-ae-labeled-button"; + + return ( + React.createElement("button", {className: css, onClick: this.props.requestExclusive, tabIndex: this.props.tabIndex}, + React.createElement("span", {className: "ez-ae-icon ez-ae-icon-table ae-icon-table"}), + React.createElement("p", {className: "ez-ae-label"}, Y.eZ.trans('table', {}, 'onlineeditor')) + ) + ); + }, + }); + + AlloyEditor.Buttons[ButtonTable.key] = AlloyEditor.ButtonTable = ButtonTable; +}); diff --git a/Resources/public/js/alloyeditor/buttons/table.jsx b/Resources/public/js/alloyeditor/buttons/table.jsx new file mode 100644 index 000000000..7f9bada96 --- /dev/null +++ b/Resources/public/js/alloyeditor/buttons/table.jsx @@ -0,0 +1,53 @@ +/* + * Copyright (C) eZ Systems AS. All rights reserved. + * For full copyright and license information view LICENSE file distributed with this source code. + */ +YUI.add('ez-alloyeditor-button-table', function (Y) { + "use strict"; + + var AlloyEditor = Y.eZ.AlloyEditor, + React = Y.eZ.React, + ButtonTable; + + /** + * The ButtonTable class provides functionality for creating and editing a table in a document. ButtonTable + * renders in two different modes: + * + * - Normal: Just a button that allows to switch to the edition mode + * - Exclusive: The ButtonTableEdit UI with all the table edition controls. + * + * This component is a copy of AlloyEditor.ButtonTable, with slightly different render() logic. + * + * @class ButtonTable + */ + ButtonTable = React.createClass({ + propTypes: { + editor: React.PropTypes.object.isRequired, + label: React.PropTypes.string, + tabIndex: React.PropTypes.number, + }, + + statics: { + key: 'eztable' + }, + + render: function () { + if (this.props.renderExclusive) { + return ( + + ); + } + + var css = "ae-button ez-ae-labeled-button"; + + return ( + + ); + }, + }); + + AlloyEditor.Buttons[ButtonTable.key] = AlloyEditor.ButtonTable = ButtonTable; +}); diff --git a/Resources/public/js/alloyeditor/plugins/embed.js b/Resources/public/js/alloyeditor/plugins/embed.js index 72ca2c637..f8f430604 100644 --- a/Resources/public/js/alloyeditor/plugins/embed.js +++ b/Resources/public/js/alloyeditor/plugins/embed.js @@ -25,6 +25,14 @@ YUI.add('ez-alloyeditor-plugin-embed', function (Y) { requires: 'widget,ezaddcontent', init: function (editor) { + editor.ezembed = { + canBeAdded: function () { + var path = editor.elementPath(); + + return !path || path.contains('table', true) === null; + } + }; + editor.widgets.add('ezembed', { defaults: { href: "ezcontent://57", diff --git a/Resources/public/js/alloyeditor/toolbars/config/table.js b/Resources/public/js/alloyeditor/toolbars/config/table.js index 8388e8dd0..dbda7a2fd 100644 --- a/Resources/public/js/alloyeditor/toolbars/config/table.js +++ b/Resources/public/js/alloyeditor/toolbars/config/table.js @@ -24,6 +24,7 @@ YUI.add('ez-alloyeditor-toolbar-config-table', function (Y) { buttons: [ 'ezmoveup', 'ezmovedown', + 'tableHeading', 'tableRow', 'tableColumn', 'tableCell', diff --git a/Resources/public/js/views/fields/ez-richtext-editview.js b/Resources/public/js/views/fields/ez-richtext-editview.js index cca1b146e..d66f69c1b 100644 --- a/Resources/public/js/views/fields/ez-richtext-editview.js +++ b/Resources/public/js/views/fields/ez-richtext-editview.js @@ -450,7 +450,7 @@ YUI.add('ez-richtext-editview', function (Y) { tabIndex: 1 }, ezadd: { - buttons: ['ezheading', 'ezparagraph', 'ezlist', 'ezimage', 'ezembed'], + buttons: ['ezheading', 'ezparagraph', 'ezlist', 'ezimage', 'ezembed', 'eztable'], tabIndex: 2, }, }; diff --git a/Resources/translations/onlineeditor.en.xlf b/Resources/translations/onlineeditor.en.xlf index 94c067fcb..dd9497dd8 100644 --- a/Resources/translations/onlineeditor.en.xlf +++ b/Resources/translations/onlineeditor.en.xlf @@ -142,6 +142,12 @@ Resources/public/js/alloyeditor/toolbars/config/heading.js Resources/public/js/alloyeditor/toolbars/config/paragraph.js + + Table + Table + key: table + Resources/public/js/alloyeditor/buttons/table.js + Remove this block Remove this block diff --git a/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-embed-tests.jsx b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-embed-tests.jsx index 0c68f14a6..83947f465 100644 --- a/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-embed-tests.jsx +++ b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-embed-tests.jsx @@ -15,17 +15,60 @@ YUI.add('ez-alloyeditor-button-embed-tests', function (Y) { setUp: function () { this.container = Y.one('.container').getDOMNode(); - this.editor = {}; + this.editor = new Mock(); + this.nativeEditor = new Mock(); + this.nativeEditor.ezembed = new Mock(); + + Mock.expect(this.editor, { + method: 'get', + args: ['nativeEditor'], + returns: this.nativeEditor + }); }, tearDown: function () { ReactDOM.unmountComponentAtNode(this.container); delete this.editor; + delete this.nativeEditor; + }, + + "Should render a enabled button": function () { + var button; + + Mock.expect(this.nativeEditor.ezembed, { + method: 'canBeAdded', + args: [], + returns: true, + }); + + button = ReactDOM.render( + , + this.container + ); + + Assert.isNotNull( + ReactDOM.findDOMNode(button), + "The button should be rendered" + ); + Assert.areEqual( + "BUTTON", ReactDOM.findDOMNode(button).tagName, + "The component should generate a button" + ); + Assert.areEqual( + false, ReactDOM.findDOMNode(button).disabled, + "The button should not be disabled" + ); }, - "Should render a button": function () { + "Should render a disabled button": function () { var button; + Mock.expect(this.nativeEditor.ezembed, { + method: 'canBeAdded', + args: [], + returns: false, + }); + button = ReactDOM.render( , this.container @@ -39,6 +82,10 @@ YUI.add('ez-alloyeditor-button-embed-tests', function (Y) { "BUTTON", ReactDOM.findDOMNode(button).tagName, "The component should generate a button" ); + Assert.areEqual( + true, ReactDOM.findDOMNode(button).disabled, + "The button should be disabled" + ); }, }); diff --git a/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-image-tests.jsx b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-image-tests.jsx index 2f77510f0..c49ee4a80 100644 --- a/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-image-tests.jsx +++ b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-image-tests.jsx @@ -15,17 +15,32 @@ YUI.add('ez-alloyeditor-button-image-tests', function (Y) { setUp: function () { this.container = Y.one('.container').getDOMNode(); - this.editor = {}; + this.editor = new Mock(); + this.nativeEditor = new Mock(); + this.nativeEditor.ezembed = new Mock(); + + Mock.expect(this.editor, { + method: 'get', + args: ['nativeEditor'], + returns: this.nativeEditor + }); }, tearDown: function () { ReactDOM.unmountComponentAtNode(this.container); delete this.editor; + delete this.nativeEditor; }, - "Should render a button": function () { + "Should render a enabled button": function () { var button; + Mock.expect(this.nativeEditor.ezembed, { + method: 'canBeAdded', + args: [], + returns: true, + }); + button = ReactDOM.render( , this.container @@ -39,6 +54,38 @@ YUI.add('ez-alloyeditor-button-image-tests', function (Y) { "BUTTON", ReactDOM.findDOMNode(button).tagName, "The component should generate a button" ); + Assert.areEqual( + false, ReactDOM.findDOMNode(button).disabled, + "The button should not be disabled" + ); + }, + + "Should render a disabled button": function () { + var button; + + Mock.expect(this.nativeEditor.ezembed, { + method: 'canBeAdded', + args: [], + returns: false, + }); + + button = ReactDOM.render( + , + this.container + ); + + Assert.isNotNull( + ReactDOM.findDOMNode(button), + "The button should be rendered" + ); + Assert.areEqual( + "BUTTON", ReactDOM.findDOMNode(button).tagName, + "The component should generate a button" + ); + Assert.areEqual( + true, ReactDOM.findDOMNode(button).disabled, + "The button should be disabled" + ); }, }); diff --git a/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-table-tests.jsx b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-table-tests.jsx new file mode 100644 index 000000000..8cbc7e145 --- /dev/null +++ b/Tests/js/alloyeditor/buttons/assets/ez-alloyeditor-button-table-tests.jsx @@ -0,0 +1,113 @@ +/* + * Copyright (C) eZ Systems AS. All rights reserved. + * For full copyright and license information view LICENSE file distributed with this source code. + */ +YUI.add('ez-alloyeditor-button-table-tests', function (Y) { + var renderTest, clickTest, + AlloyEditor = Y.eZ.AlloyEditor, + ReactDOM = Y.eZ.ReactDOM, + React = Y.eZ.React, + Assert = Y.Assert; + + renderTest = new Y.Test.Case({ + name: "eZ AlloyEditor table button render test", + + setUp: function () { + this.container = Y.one('.container').getDOMNode(); + this.editor = {}; + }, + + tearDown: function () { + ReactDOM.unmountComponentAtNode(this.container); + delete this.editor; + }, + + "Should render a button": function () { + var button; + + button = ReactDOM.render( + , + this.container + ); + + Assert.isNotNull( + ReactDOM.findDOMNode(button), + "The button should be rendered" + ); + + Assert.areEqual( + "BUTTON", ReactDOM.findDOMNode(button).tagName, + "The component should generate a button" + ); + }, + + "Should render a toolbar on renderExclusive": function () { + var node; + + node = ReactDOM.render( + , + this.container + ); + + Assert.isNotNull( + ReactDOM.findDOMNode(node), + "The toolbar should be rendered" + ); + + Assert.areEqual( + "DIV", ReactDOM.findDOMNode(node).tagName, + "The component should generate a div for the toolbar" + ); + }, + }); + + clickTest= new Y.Test.Case({ + name: "eZ AlloyEditor table button click test", + + "async:init": function () { + var startTest = this.callback(); + + this.container = Y.one('.container'); + this.editor = AlloyEditor.editable( + Y.one('.editorContainer').getDOMNode() + ); + this.editor.get('nativeEditor').on('instanceReady', function () { + startTest(); + }); + }, + + destroy: function () { + this.editor.destroy(); + }, + + tearDown: function () { + ReactDOM.unmountComponentAtNode(this.container.getDOMNode()); + }, + + "Should generate table context menu on click": function () { + var button, + exclusive = false, + requestExclusive = function () { + exclusive = true; + }; + + button = ReactDOM.render( + , + this.container.getDOMNode() + ); + + this.container.one('button').simulate('click'); + Assert.isTrue( + exclusive, + "The button should have requested the exclusive state" + ); + }, + }); + + Y.Test.Runner.setName("eZ AlloyEditor table button tests"); + Y.Test.Runner.add(renderTest); + Y.Test.Runner.add(clickTest); +}, '', {requires: ['test', 'node', 'node-event-simulate', 'ez-alloyeditor-button-table']}); diff --git a/Tests/js/alloyeditor/buttons/ez-alloyeditor-button-table.html b/Tests/js/alloyeditor/buttons/ez-alloyeditor-button-table.html new file mode 100644 index 000000000..750966dc2 --- /dev/null +++ b/Tests/js/alloyeditor/buttons/ez-alloyeditor-button-table.html @@ -0,0 +1,45 @@ + + + +eZ AlloyEditor table button tests + + + +
+
+ + + + + + + + diff --git a/Tests/js/alloyeditor/plugins/assets/ez-alloyeditor-plugin-embed-tests.js b/Tests/js/alloyeditor/plugins/assets/ez-alloyeditor-plugin-embed-tests.js index e08bc2541..223c6521b 100644 --- a/Tests/js/alloyeditor/plugins/assets/ez-alloyeditor-plugin-embed-tests.js +++ b/Tests/js/alloyeditor/plugins/assets/ez-alloyeditor-plugin-embed-tests.js @@ -16,10 +16,22 @@ YUI.add('ez-alloyeditor-plugin-embed-tests', function (Y) { setUp: function () { this.editor = {}; this.editor.widgets = new Mock(); + this.elementPath = new Mock(); }, tearDown: function () { delete this.editor; + delete this.elementPath; + }, + + _initWithMock: function() { + var plugin = CKEDITOR.plugins.get('ezembed'); + + Mock.expect(this.editor.widgets, { + method: 'add', + args: ['ezembed', Mock.Value.Object], + }); + plugin.init(this.editor); }, "Should define the embed plugin": function () { @@ -37,15 +49,53 @@ YUI.add('ez-alloyeditor-plugin-embed-tests', function (Y) { }, "Should define the ezembed widget": function () { - var plugin = CKEDITOR.plugins.get('ezembed'); + this._initWithMock(); + Mock.verify(this.editor.widgets); + }, - Mock.expect(this.editor.widgets, { - method: 'add', - args: ['ezembed', Mock.Value.Object], + "Should define the ezembed.canBeAdded function": function () { + this._initWithMock(); + + Assert.isObject(this.editor.ezembed, "this.editor.ezembed should be an object"); + Assert.isFunction(this.editor.ezembed.canBeAdded, "this.editor.ezembed.canBeAdded should be a Function"); + }, + + + "ezembed.canBeAdded() should return true when there is no table": function () { + this._initWithMock(); + + Mock.expect(this.editor, { + method: 'elementPath', + returns: this.elementPath, }); - plugin.init(this.editor); - Mock.verify(this.editor.widgets); + + Mock.expect(this.elementPath, { + method: 'contains', + args: ['table', true], + returns: null, + }); + + Assert.isTrue(this.editor.ezembed.canBeAdded(), "Should be able to add ezembed with *no* table in path"); }, + + + "ezembed.canBeAdded() should return false when there is a table": function () { + this._initWithMock(); + + Mock.expect(this.editor, { + method: 'elementPath', + returns: this.elementPath, + }); + + Mock.expect(this.elementPath, { + method: 'contains', + args: ['table', true], + returns: [], + }); + + Assert.isFalse(this.editor.ezembed.canBeAdded(), "Should be able to add ezembed with *a* table in path"); + }, + }); embedWidgetTest = new Y.Test.Case({