Skip to content
This repository has been archived by the owner on May 3, 2022. It is now read-only.

Commit

Permalink
Merge pull request #322 from ezsystems/ezp-24769_outline_block
Browse files Browse the repository at this point in the history
EZP-24769: Outline the focused block in the editor
  • Loading branch information
dpobel committed Sep 10, 2015
2 parents 25694be + c0450e9 commit 3852ee3
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 2 deletions.
4 changes: 4 additions & 0 deletions Resources/config/yui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ system:
ez-alloyeditor-plugin-embed:
requires: ['ez-alloyeditor']
path: %ez_platformui.public_dir%/js/alloyeditor/plugins/embed.js
ez-alloyeditor-plugin-focusblock:
requires: ['ez-alloyeditor']
path: %ez_platformui.public_dir%/js/alloyeditor/plugins/focusblock.js
ez-alloyeditor-button-heading:
requires: ['ez-alloyeditor']
path: %ez_platformui.public_dir%/js/alloyeditor/buttons/heading.js
Expand Down Expand Up @@ -472,6 +475,7 @@ system:
- 'ez-alloyeditor-plugin-embed'
- 'ez-alloyeditor-plugin-addcontent'
- 'ez-alloyeditor-plugin-removeblock'
- 'ez-alloyeditor-plugin-focusblock'
- 'ez-alloyeditor-toolbar-config-heading'
- 'ez-alloyeditor-button-heading'
- 'ez-alloyeditor-button-embed'
Expand Down
5 changes: 5 additions & 0 deletions Resources/public/css/theme/alloyeditor/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@
.ez-richtext-editable ezembed:after {
content: attr(href);
}

.ez-richtext-editable .is-block-focused {
outline: 2px dashed #aaa;
outline-offset: 3px;
}
2 changes: 1 addition & 1 deletion Resources/public/css/views/fields/edit/richtext.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
.ez-view-richtexteditview .ez-richtext-editor {
display: inline-block;
width: 100%;
padding: 0 0.4em;
padding: 0 0.5em;
box-sizing: border-box;
min-height: 5em;
}
Expand Down
50 changes: 50 additions & 0 deletions Resources/public/js/alloyeditor/plugins/focusblock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) eZ Systems AS. All rights reserved.
* For full copyright and license information view LICENSE file distributed with this source code.
*/
/* global CKEDITOR */
YUI.add('ez-alloyeditor-plugin-focusblock', function (Y) {
"use strict";

var FOCUSED_CLASS = 'is-block-focused';

if (CKEDITOR.plugins.get('ezfocusblock')) {
return;
}

function findFocusedBlock(editor) {
return editor.element.findOne('.' + FOCUSED_CLASS);
}

function updateFocusedBlock(e) {
var block = e.data.path.block,
oldBlock = findFocusedBlock(e.editor);

if ( oldBlock && block.$ !== oldBlock.$ ) {
oldBlock.removeClass(FOCUSED_CLASS);
}
block.addClass(FOCUSED_CLASS);
}

function clearFocusedBlock(e) {
var oldBlock = findFocusedBlock(e.editor);

if ( oldBlock ) {
oldBlock.removeClass(FOCUSED_CLASS);
}
}

/**
* CKEditor plugin to add/remove the focused class on the block holding the
* caret.
*
* @class CKEDITOR.plugins.ezfocusblock
* @constructor
*/
CKEDITOR.plugins.add('ezfocusblock', {
init: function (editor) {
editor.on('selectionChange', updateFocusedBlock);
editor.on('blur', clearFocusedBlock);
},
});
});
2 changes: 1 addition & 1 deletion Resources/public/js/views/fields/ez-richtext-editview.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ YUI.add('ez-richtext-editview', function (Y) {
editor = AlloyEditor.editable(
this.get('container').one('.ez-richtext-editor').getDOMNode(), {
toolbars: this.get('toolbarsConfig'),
extraPlugins: AlloyEditor.Core.ATTRS.extraPlugins.value + ',ezaddcontent,widget,ezembed,ezremoveblock',
extraPlugins: AlloyEditor.Core.ATTRS.extraPlugins.value + ',ezaddcontent,widget,ezembed,ezremoveblock,ezfocusblock',
eZ: {
editableRegion: '.ez-richtext-editable',
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (C) eZ Systems AS. All rights reserved.
* For full copyright and license information view LICENSE file distributed with this source code.
*/
/* global CKEDITOR, AlloyEditor */
YUI.add('ez-alloyeditor-plugin-focusblock-tests', function (Y) {
var definePluginTest, selectionChangeTest, blurTest,
Assert = Y.Assert, Mock = Y.Mock;

definePluginTest = new Y.Test.Case({
name: "eZ AlloyEditor focusblock plugin define test",

setUp: function () {
this.editor = new Mock();
},

tearDown: function () {
delete this.editor;
},

"Should define the focusblock plugin": function () {
var plugin = CKEDITOR.plugins.get('ezfocusblock');

Assert.isObject(
plugin,
"The ezfocusblock should be defined"
);
Assert.areEqual(
plugin.name,
"ezfocusblock",
"The plugin name should be ezfocusblock"
);
},
});

selectionChangeTest = new Y.Test.Case({
name: "eZ AlloyEditor focusblock plugin selectionChange test",

"async:init": function () {
var startTest = this.callback();

this.editor = AlloyEditor.editable(
Y.one('.container').getDOMNode(), {
extraPlugins: AlloyEditor.Core.ATTRS.extraPlugins.value + ',ezfocusblock',
}
);
this.editor.get('nativeEditor').on('instanceReady', function () {
startTest();
});
},

destroy: function () {
this.editor.destroy();
Y.one('.container').all('.is-block-focused').each(function (node) {
node.removeClass('is-block-focused');
});
},

_moveCaretToElement: function (editor, element) {
var range = editor.createRange();

range.moveToPosition(element, CKEDITOR.POSITION_AFTER_START);
editor.getSelection().selectRanges([range]);
},

"Should add the focus block class": function () {
var editor = this.editor.get('nativeEditor');

this._moveCaretToElement(editor, editor.element.findOne('blockquote'));

Assert.isTrue(
Y.one('blockquote').hasClass('is-block-focused'),
"The blockquote should have the focus class"
);
},

"Should move the focus block class to selected element": function () {
var editor = this.editor.get('nativeEditor');

this["Should add the focus block class"]();
this._moveCaretToElement(editor, editor.element.findOne('p'));

Assert.isFalse(
Y.one('blockquote').hasClass('is-block-focused'),
"The blockquote should NOT have the focus class"
);
Assert.isTrue(
Y.one('p').hasClass('is-block-focused'),
"The p should have the focus class"
);
},
});

blurTest = new Y.Test.Case({
name: "eZ AlloyEditor focusblock plugin blur test",

"async:init": function () {
var startTest = this.callback();

this.editor = AlloyEditor.editable(
Y.one('.container').getDOMNode(), {
extraPlugins: AlloyEditor.Core.ATTRS.extraPlugins.value + ',ezfocusblock',
}
);
this.editor.get('nativeEditor').on('instanceReady', function () {
startTest();
});
},

destroy: function () {
this.editor.destroy();
Y.one('.container').all('.is-block-focused').each(function (node) {
node.removeClass('is-block-focused');
});
},

"Should remove the focus block class": function () {
var editor = this.editor.get('nativeEditor');

Y.one('blockquote').addClass('is-block-focused');
editor.fire('blur');
Assert.isFalse(
Y.one('blockquote').hasClass('is-block-focused'),
"The blockquote should NOT have the focus class"
);
Assert.isFalse(
Y.one('p').hasClass('is-block-focused'),
"The p should NOT have the focus class"
);
},

"Should handle no focus block case": function () {
this.editor.get('nativeEditor').fire('blur');
Assert.isFalse(
Y.one('blockquote').hasClass('is-block-focused'),
"The blockquote should NOT have the focus class"
);
Assert.isFalse(
Y.one('p').hasClass('is-block-focused'),
"The p should NOT have the focus class"
);
},
});

Y.Test.Runner.setName("eZ AlloyEditor focusblock plugin tests");
Y.Test.Runner.add(definePluginTest);
Y.Test.Runner.add(selectionChangeTest);
Y.Test.Runner.add(blurTest);
}, '', {requires: ['test', 'node', 'ez-alloyeditor-plugin-focusblock']});
44 changes: 44 additions & 0 deletions Tests/js/alloyeditor/plugins/ez-alloyeditor-plugin-focusblock.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>eZ AlloyEditor focusblock plugin tests</title>
</head>
<body>

<div class="container">
<blockquote>I thought of that while riding my bike.</blockquote>
<p>Albert Einstein On the Theory of Relativity.</p>
</div>

<script type="text/javascript" src="../../assets/function.bind.polyfill.js"></script>
<script type="text/javascript" src="../../../../Resources/public/vendors/yui3/build/yui/yui.js"></script>
<script type="text/javascript" src="../../../../Resources/public/vendors/alloyeditor/dist/alloy-editor/alloy-editor-all.js"></script>
<script type="text/javascript" src="./assets/ez-alloyeditor-plugin-focusblock-tests.js"></script>
<script>
var filter = (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'raw',
loaderFilter;

if (filter == 'coverage') {
loaderFilter = {
searchExp : "/Resources/public/js/",
replaceStr: "/Tests/instrument/Resources/public/js/"
};
} else {
loaderFilter = filter;
}

YUI({
coverage: ['ez-alloyeditor-plugin-focusblock'],
filter: loaderFilter,
modules: {
"ez-alloyeditor-plugin-focusblock": {
fullpath: "../../../../Resources/public/js/alloyeditor/plugins/focusblock.js",
},
}
}).use('ez-alloyeditor-plugin-focusblock-tests', function (Y) {
Y.Test.Runner.run();
});
</script>
</body>
</html>
5 changes: 5 additions & 0 deletions Tests/js/views/fields/assets/ez-richtext-editview-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ YUI.add('ez-richtext-editview-tests', function (Y) {
CKEDITOR.plugins.add('ezaddcontent', {});
CKEDITOR.plugins.add('ezremoveblock', {});
CKEDITOR.plugins.add('ezembed', {});
CKEDITOR.plugins.add('ezfocusblock', {});

renderTest = new Y.Test.Case({
name: "eZ RichText View render test",
Expand Down Expand Up @@ -441,6 +442,10 @@ YUI.add('ez-richtext-editview-tests', function (Y) {
this._testExtraPlugins('ezembed');
},

"Should add the ezfocusblock plugin": function () {
this._testExtraPlugins('ezfocusblock');
},

"Should pass the `eZ` configuration": function () {
var eZConfig;

Expand Down

0 comments on commit 3852ee3

Please sign in to comment.