Skip to content

Commit

Permalink
Merge pull request #10 from regniets/feature/blockstyles
Browse files Browse the repository at this point in the history
Feature/blockstyles
  • Loading branch information
regniets authored Jul 30, 2020
2 parents 79eacc3 + 4b72301 commit 4948cdc
Show file tree
Hide file tree
Showing 13 changed files with 952 additions and 42,805 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
node_modules
yarn.lock
4 changes: 3 additions & 1 deletion Configuration/NodeTypes.Override.BaseMixins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
# editorOptions:
# inlineStyling:
# fontColor: true
# fontSize: true
# fontSize: true
# blockStyling:
# indent: true
14 changes: 14 additions & 0 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@
# '':
# label: 'unset size'
# cssClass: null
# BlockStyles:
# presets:
# 'indent':
# label: 'Indentation'
# options:
# 'primary':
# label: '2 rem'
# cssClass: 'indent-2'
# 'secondary':
# label: '4 rem'
# cssClass: 'indent-4'
# '':
# label: 'remove indent'
# cssClass: null

Neos:
Neos:
Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# TechDivision.CkStyles

This package allows to add different styles(with your own classes) for the CkEditor in Neos. The styles and classes
depend on your implementation.
This package allows to add different styles based on your css-classes for the CkEditor in Neos.
You can define the classes in you yaml configuration.
Styles can be applied both on block- and element level.


**Demo:**
Expand All @@ -13,7 +14,7 @@ depend on your implementation.
![Example output](Documentation/assets/ExampleOutput.png "Example output")

```html
<p>
<p class="my-class-indent-2">
This is an
<span class="my-class-size-large">awesome</span>
inline editable
Expand All @@ -22,7 +23,10 @@ depend on your implementation.
</p>
```

But why? Often customers want to highlight some text for example with font size but don't use a headline for SEO reasons
## Benefits

In most projects there are requirements that you cannot achieve with tags alone and you need classes under editorial control -
e.g. if you want to highlight some text with font size but don't use a headline for SEO reasons
or want to add an icon, adjust the font color ...

## Getting started
Expand Down Expand Up @@ -56,11 +60,27 @@ TechDivision:
'big':
label: 'Large'
cssClass: 'my-class-size-large'
BlockStyles:
presets:
'indent':
label: 'Indentation'
options:
'primary':
label: '2 rem'
cssClass: 'my-class-indent-2'
'secondary':
label: '4 rem'
cssClass: 'my-class-indent-4'
'':
label: 'remove indent'
cssClass: null
```
Example: [Configuration/Settings.yaml](Configuration/Settings.yaml)

_Note: Using an empty class (cssClass: null) to unset the value might cause errors during rendering in the backend.
The select boxes of this package contain an "x" button for resetting the value._
The select boxes of this package contain an "x" button for resetting the value._
_BlockStyles cannot be combined at the moment. Other than InlineStyles, you can only set one blockstyle per block._


Activate the preset for your inline editable NodeType property:
```
Expand All @@ -74,6 +94,8 @@ Activate the preset for your inline editable NodeType property:
inlineStyling:
fontColor: true
fontSize: true
blockStyling:
indent: true
```
Example: [Configuration/NodeTypes.Override.BaseMixins.yaml](Configuration/NodeTypes.Override.BaseMixins.yaml)

Expand All @@ -91,6 +113,13 @@ Add the styling for your presets in your scss, less or css:
.my-class-size-large {
font-size: 25px;
}
.my-class-indent-2 {
text-indent: 2rem;
}
.my-class-indent-4 {
text-indent: 4rem;
}
```

## Development
Expand Down
98 changes: 79 additions & 19 deletions Resources/Private/JavaScript/CkStyles/src/BlockStyleCommand.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,95 @@
import Command from '@ckeditor/ckeditor5-core/src/command';
// Originally taken from https://raw.githubusercontent.com/ckeditor/ckeditor5/master/packages/ckeditor5-basic-styles/src/attributecommand.js and adjusted
import { Command } from 'ckeditor5-exports';

/**
* Sets a class a given attribute on the top most blocks.
* Set a key-value block style; e.g. "fontColor=red".
*/
export default class BlockStyleCommand extends Command {

export default class BlockStyleCommand extends Command {
/**
* @inheritDoc
* @param {module:core/editor/editor~Editor} editor
* @param {String} attributeKey Attribute that will be set by the command.
*/
execute(options = {}) {
constructor(editor, attributeKey) {
super(editor);

/**
* The attribute that will be set by the command.
*
* @readonly
* @member {String}
*/
this.attributeKey = attributeKey;

/**
* Flag indicating whether the command is active. The command is active when the
* {@link module:engine/model/selection~Selection#hasAttribute selection has the attribute} which means that:
*
* @observable
* @readonly
* @member {Boolean} #value
*/
}

/**
* Updates the command's {@link #value} and {@link #isEnabled}.
*/
refresh() {
const model = this.editor.model;
const doc = model.document;
const blocksToChange = Array.from( doc.selection.getSelectedBlocks() );

const blocksToChange = getBlocksToChange( model );
this.value = this._getValueFromBlockNode();
for ( const block of blocksToChange ) {
if(model.schema.checkAttribute(block, this.attributeKey)) {
this.isEnabled = true;
}
}
}

/**
* Executes the command &mdash; sets the attribute to the desired value. If there is no desired valued, removes the
* attribute on each block.
*
* @fires execute
* @param {Object} [options] Command options.
* @param {String} [options.value] The value to be set; if null or not existing, the attribute will be removed.
*/
execute(options = {}) {
const model = this.editor.model;
const doc = model.document;
const selection = doc.selection;
const value = options.value;
const blocksToChange = Array.from( selection.getSelectedBlocks() );
model.change( writer => {
for ( const block of blocksToChange ) {
writer.setAttribute( options.key, options.value, block );
if (value) {
writer.setAttribute(this.attributeKey, value, block);
} else {
writer.removeAttribute(this.attributeKey, block);
}
}
} );
});
}
}

/**
* Returns the top most blocks of the given model
*
* @param model
* @returns {*}
*/
function getBlocksToChange( model ) {
const selection = model.document.selection;
const schema = model.schema;
return Array.from( selection.getTopMostBlocks() );
/**
* Checks the attribute value of the parent block node(s)
*
* @private
* @returns {String} The attribute value.
*/
_getValueFromBlockNode() {
const model = this.editor.model;
const schema = model.schema;
const selection = model.document.selection;
const blocks = Array.from( selection.getSelectedBlocks() );

for (const block of blocks) {
if (schema.checkAttribute(block, this.attributeKey)) {
return block.getAttribute(this.attributeKey);
}
}

return undefined;
}
}
38 changes: 15 additions & 23 deletions Resources/Private/JavaScript/CkStyles/src/BlockStyleEditing.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,32 @@ import BlockStyleCommand from "./BlockStyleCommand";
*/
export default (presetIdentifier, presetConfiguration) =>
class BlockStyleEditing extends Plugin {

init() {
this.editor.model.schema.extend('$block', {allowAttributes: presetIdentifier});

const editor = this.editor;
this.editor.model.schema.extend(
'$block',
{ allowAttributes: `blockStyles:${presetIdentifier}`}
);

// Model configuration
var model = {
key: presetIdentifier,
values: []
const config = {
model: {
key: `blockStyles:${presetIdentifier}`,
values: Object.keys(presetConfiguration.options),
},
view: {}
};

// View configuration
var view = {};
Object.keys(presetConfiguration.options).forEach(optionIdentifier => {
model.values.push(optionIdentifier);
view[optionIdentifier] = {
config.view[optionIdentifier] = {
key: 'class',
value: presetConfiguration.options[optionIdentifier].cssClass
};
});

editor.model.schema.register(presetIdentifier, {
inheritAllFrom: '$block',
isBlock: true,
allowIn: '$root'
}
});

// Convert the model to view correctly
editor.conversion.attributeToAttribute({
model: model,
view: view
});
this.editor.conversion.attributeToAttribute(config);

editor.commands.add(`blockStyles:${presetIdentifier}`, new BlockStyleCommand(editor));
this.editor.commands.add(`blockStyles:${presetIdentifier}`, new BlockStyleCommand(this.editor, `blockStyles:${presetIdentifier}`));
}
}
}
21 changes: 2 additions & 19 deletions Resources/Private/JavaScript/CkStyles/src/InlineStylesCommand.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
// Originally taken from https://raw.githubusercontent.com/ckeditor/ckeditor5-basic-styles/ccf591b0cea61ffd65a5ffaab48272e8dc0d5e6e/src/attributecommand.js and adjusted
// Originally taken from https://raw.githubusercontent.com/ckeditor/ckeditor5/master/packages/ckeditor5-basic-styles/src/attributecommand.js and adjusted
import { Command } from 'ckeditor5-exports';

/**
* Set a key-value inline style; e.g. "fontColor=red".
*
* `InlineStylesCommand` uses {@link module:engine/model/document~Document#selection}
* to decide which nodes (if any) should be changed, and applies or removes the attribute from them.
*
* The command checks the {@link module:engine/model/model~Model#schema} to decide if it can be enabled
* for the current selection and to which nodes the attribute can be applied.
*/
export default class InlineStylesCommand extends Command {
/**
Expand All @@ -29,11 +24,7 @@ export default class InlineStylesCommand extends Command {
/**
* Flag indicating whether the command is active. The command is active when the
* {@link module:engine/model/selection~Selection#hasAttribute selection has the attribute} which means that:
*
* * If the selection is not empty &ndash; That the attribute is set on the first node in the selection that allows this attribute.
* * If the selection is empty &ndash; That the selection has the attribute itself (which means that newly typed
* text will have this attribute, too).
*
**
* @observable
* @readonly
* @member {Boolean} #value
Expand All @@ -55,14 +46,6 @@ export default class InlineStylesCommand extends Command {
* Executes the command &mdash; sets the attribute to the desired value. If there is no desired valued, removes the
* attribute.
*
* The execution result differs, depending on the {@link module:engine/model/document~Document#selection}:
*
* * If the selection is on a range, the command applies the attribute to all nodes in that range
* (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}).
* * If the selection is collapsed in a non-empty node, the command applies the attribute to the
* {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection).
* * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note
* that the selection inherits all attributes from a node if it is in an empty node).
* @fires execute
* @param {Object} [options] Command options.
* @param {String} [options.value] The value to be set; if null or not existing, the attribute will be removed.
Expand Down
13 changes: 7 additions & 6 deletions Resources/Private/JavaScript/CkStyles/src/InlineStylesEditing.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// instead of the following line, we have to import from 'ckeditor5-exports'.
//import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { Plugin } from 'ckeditor5-exports';
import InlineStylesCommand from './InlineStylesCommand';

Expand All @@ -10,12 +8,15 @@ import InlineStylesCommand from './InlineStylesCommand';
export default (presetIdentifier, presetConfiguration) =>
class InlineStylesEditing extends Plugin {
init() {
this.editor.model.schema.extend('$text', { allowAttributes: presetIdentifier });
this.editor.model.schema.extend(
'$text',
{ allowAttributes: `inlineStyles:${presetIdentifier}` }
);

// Model configuration
const config = {
model: {
key: presetIdentifier,
key: `inlineStyles:${presetIdentifier}`,
values: Object.keys(presetConfiguration.options),
},
view: {}
Expand All @@ -32,6 +33,6 @@ export default (presetIdentifier, presetConfiguration) =>
// Convert the model to view correctly
this.editor.conversion.attributeToElement(config);

this.editor.commands.add(`inlineStyles:${presetIdentifier}`, new InlineStylesCommand(this.editor, presetIdentifier));
this.editor.commands.add(`inlineStyles:${presetIdentifier}`, new InlineStylesCommand(this.editor, `inlineStyles:${presetIdentifier}`));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ export default class BlockStyleSelector extends PureComponent {
handleOnSelect(optionIdentifier) {
CkEditorApi.executeCommand(
`blockStyles:${this.props.presetIdentifier}`,
{
key: this.props.presetIdentifier,
value: optionIdentifier
}
{ value: optionIdentifier }
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ export default class InlineStyleSelector extends PureComponent {
{ value: optionIdentifier }
);
}
}
}
Loading

0 comments on commit 4948cdc

Please sign in to comment.