Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Block Tunes API #1596

Merged
merged 29 commits into from
Apr 4, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
24dc069
Add internal wrappers for tools classes
gohabereg Mar 14, 2021
224dd3b
FIx lint
gohabereg Mar 14, 2021
83e17bb
Change tools collections to map
gohabereg Mar 15, 2021
1ffcbed
Apply some more refactoring
gohabereg Mar 15, 2021
3d743f3
Make tool instance private field
gohabereg Mar 15, 2021
e56579c
Add some docs
gohabereg Mar 15, 2021
0069a2a
Fix eslint
gohabereg Mar 15, 2021
d407e32
Basic implementation for Block Tunes
gohabereg Mar 15, 2021
a0160ef
Small fix for demo
gohabereg Mar 15, 2021
dde3bd4
Review changes
gohabereg Mar 16, 2021
28bfacf
Merge branch 'next' of github.com:codex-team/editor.js into reafctori…
gohabereg Mar 16, 2021
ca1aef3
Fix
gohabereg Mar 16, 2021
a459ab5
Merge branch 'reafctoring/tools' of github.com:codex-team/editor.js i…
gohabereg Mar 16, 2021
6ecc3ac
Add common tunes and ToolsCollection class
gohabereg Mar 17, 2021
1f9c5f1
Fixes after review
gohabereg Mar 18, 2021
c81b9a0
Merge branch 'reafctoring/tools' of github.com:codex-team/editor.js i…
gohabereg Mar 18, 2021
b8ba38c
Rename tools collections
gohabereg Mar 18, 2021
aea3158
Readonly fix
gohabereg Mar 18, 2021
82f3bfa
Merge branch 'reafctoring/tools' of github.com:codex-team/editor.js i…
gohabereg Mar 18, 2021
a3bb039
Some fixes after review
gohabereg Mar 27, 2021
41274fb
Merge branch 'next' of github.com:codex-team/editor.js into feature/b…
gohabereg Mar 31, 2021
13b64eb
Apply suggestions from code review
gohabereg Apr 2, 2021
4e9a098
Fixes after review
gohabereg Apr 2, 2021
ebc8b3f
Add docs and changelog
gohabereg Apr 2, 2021
cad9691
Update docs/block-tunes.md
gohabereg Apr 2, 2021
66feab7
Apply suggestions from code review
gohabereg Apr 2, 2021
8ce77a8
Update src/components/block/index.ts
gohabereg Apr 4, 2021
94bfd10
[Dev] Tools utils tests (#1602)
gohabereg Apr 4, 2021
5fe699c
Fix test & bump version
gohabereg Apr 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add common tunes and ToolsCollection class
  • Loading branch information
gohabereg committed Mar 17, 2021
commit 6ecc3ac75103e5df7a02caed5f047164b75911b9
7 changes: 5 additions & 2 deletions example/example-dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@

<script src="./tools/marker/dist/bundle.js"></script><!-- Marker -->
<script src="./tools/inline-code/dist/bundle.js"></script><!-- Inline Code -->
<script src="./tunes/favorite/index.js"></script><!-- Inline Code -->
<script src="./tunes/favorite/index.js"></script>
<script src="./tunes/anchor/index.js"></script>

<!-- Load Editor.js's Core -->
<script src="../dist/editor.js" onload="document.getElementById('hint-core').hidden = true;"></script>
Expand Down Expand Up @@ -115,6 +116,7 @@
*/
tools: {
favorite: FavoriteTune,
anchor: AnchorTune,

/**
* Each Tool is a Plugin. Pass them via 'class' option with necessary settings {@link docs/tools.md}
Expand All @@ -126,7 +128,7 @@
placeholder: 'Header'
},
shortcut: 'CMD+SHIFT+H',
tunes: ['favorite']
tunes: ['favorite', 'anchor']
},

/**
Expand Down Expand Up @@ -187,6 +189,7 @@
},

},
tunes: ['favorite'],

/**
* This Tool will be used as default
Expand Down
72 changes: 72 additions & 0 deletions example/tunes/anchor/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
class AnchorTune {
static get isTune() {
return true
}

constructor({api, block, data = false}) {
this.anchor = data;
this.api = api;
this.indicator = this.makeIndicator()
}

render() {
this.button = document.createElement('div');

this.button.classList.add('ce-settings__button');

this.button.innerHTML = '&#x1f517;';

this.button.addEventListener('click', () => this.onClick());

return this.button;
}

onClick() {
const defaultAnchor = this.wrapper
.textContent
.replace(/[^a-zA-Z0-9]+/g, '-')
.substr(0, 50)
.toLowerCase();

this.anchor = prompt('Please enter an anchor for this block', defaultAnchor) || this.anchor;

if (!this.anchor) {
this.indicator.remove();

return;
}

this.indicator.innerHTML = `#${this.anchor}`;

this.wrapper.appendChild(this.indicator);
}

wrap(pluginsContent) {
this.wrapper = document.createElement('div');

this.wrapper.style.position = 'relative';

this.wrapper.appendChild(pluginsContent);

if (this.anchor) {
this.wrapper.appendChild(this.indicator);
}

return this.wrapper;
}

makeIndicator() {
const indicator = document.createElement('div')

indicator.style.position = 'absolute';
indicator.style.top = '40%';

indicator.innerHTML = `#${this.anchor}`;

return indicator;
}

save() {
return this.anchor;
}
}
4 changes: 3 additions & 1 deletion src/components/block-tunes/block-tune-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import $ from '../dom';
*
*/
export default class DeleteTune implements BlockTune {

/**
* Set Tool is Tune
*/
public static readonly isTune = true;

/**
Expand Down
4 changes: 3 additions & 1 deletion src/components/block-tunes/block-tune-move-down.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { API, BlockTune } from '../../../types';
*
*/
export default class MoveDownTune implements BlockTune {

/**
* Set Tool is Tune
*/
public static readonly isTune = true;

/**
Expand Down
5 changes: 3 additions & 2 deletions src/components/block-tunes/block-tune-move-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import { API, BlockTune } from '../../../types';
*
*/
export default class MoveUpTune implements BlockTune {


/**
* Set Tool is Tune
*/
public static readonly isTune = true;

/**
Expand Down
106 changes: 53 additions & 53 deletions src/components/block/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
BlockToolConstructable,
BlockToolData,
BlockTune as IBlockTune,
BlockTuneConstructable,
SanitizerConfig,
ToolConfig,
ToolSettings
Expand All @@ -15,16 +14,13 @@ import $ from '../dom';
import * as _ from '../utils';
import ApiModules from '../modules/api';
import BlockAPI from './api';
import { ToolType } from '../modules/tools';
import SelectionUtils from '../selection';
import BlockTool from '../tools/block';

/** Import default tunes */
import MoveUpTune from '../block-tunes/block-tune-move-up';
import DeleteTune from '../block-tunes/block-tune-delete';
import MoveDownTune from '../block-tunes/block-tune-move-down';
import BlockTune from '../tools/tune';
import {BlockTuneData} from "../../../types/block-tunes/block-tune-data";
import { BlockTuneData } from '../../../types/block-tunes/block-tune-data';
import ToolsCollection from '../tools/collection';

/**
* Interface describes Block class constructor argument
Expand All @@ -50,8 +46,14 @@ interface BlockConstructorOptions {
*/
readOnly: boolean;

tunes: BlockTune[];
/**
* Tunes for current Block
*/
tunes: ToolsCollection<BlockTune>;

/**
* Tunes data for current Block
*/
tunesData: {[name: string]: BlockTuneData};
}

Expand Down Expand Up @@ -127,7 +129,7 @@ export default class Block {
/**
* Tunes used by Tool
*/
public readonly tunes: BlockTune[];
public readonly tunes: ToolsCollection<BlockTune>;

/**
* Tool's user configuration
Expand All @@ -147,6 +149,8 @@ export default class Block {
private readonly toolInstance: IBlockTool;

private readonly tunesInstances: Map<string, IBlockTune> = new Map();
private readonly defaultTunesInstances: Map<string, IBlockTune> = new Map();
private unavailableTunesData: {[name: string]: BlockTuneData} = {};
neSpecc marked this conversation as resolved.
Show resolved Hide resolved

/**
* Editor`s API module
Expand Down Expand Up @@ -228,9 +232,7 @@ export default class Block {
*/
this.tunes = tunes;

tunes.forEach((tune) => {
this.tunesInstances.set(tune.name, tune.instance(tunesData[tune.name], this.blockAPI))
});
this.composeTunes(tunesData);

this.holder = this.compose();
}
Expand Down Expand Up @@ -534,13 +536,15 @@ export default class Block {
*/
public async save(): Promise<void|SavedData> {
const extractedBlock = await this.toolInstance.save(this.pluginsContent as HTMLElement);
const tunesData: {[name: string]: BlockTuneData} = {}
const tunesData: {[name: string]: BlockTuneData} = this.unavailableTunesData;

Array
.from(this.tunesInstances.entries())
[
...this.tunesInstances.entries(),
...this.defaultTunesInstances.entries(),
]
.forEach(([name, tune]) => {
if (_.isFunction(tune.save)) {
tunesData[name] = tune.save()
tunesData[name] = tune.save();
}
});

Expand Down Expand Up @@ -586,52 +590,23 @@ export default class Block {
return isValid;
}

/**
* Make an array with default settings
* Each block has default tune instance that have states
*
* @returns {BlockTune[]}
*/
public makeTunes(): IBlockTune[] {
const tunesList = [
{
name: 'moveUp',
Tune: MoveUpTune,
},
{
name: 'delete',
Tune: DeleteTune,
},
{
name: 'moveDown',
Tune: MoveDownTune,
},
];

// Pluck tunes list and return tune instances with passed Editor API and settings
return tunesList.map(({ name, Tune }: {name: string; Tune: BlockTuneConstructable}) => {
return new Tune({
api: this.api.getMethodsForTool(name, ToolType.Tune),
settings: this.config,
block: this.blockAPI,
data: {}
});
});
}

/**
* Enumerates initialized tunes and returns fragment that can be appended to the toolbars area
*
* @returns {DocumentFragment}
gohabereg marked this conversation as resolved.
Show resolved Hide resolved
*/
public renderTunes(): DocumentFragment {
public renderTunes(): [DocumentFragment, DocumentFragment] {
const tunesElement = document.createDocumentFragment();
const defaultTunesElement = document.createDocumentFragment();

this.tunesInstances.forEach((tune) => {
$.append(tunesElement, tune.render());
});
this.defaultTunesInstances.forEach((tune) => {
$.append(defaultTunesElement, tune.render());
});

return tunesElement;
return [tunesElement, defaultTunesElement];
}

/**
Expand Down Expand Up @@ -713,11 +688,10 @@ export default class Block {

let wrappedContentNode: HTMLElement = contentNode;
neSpecc marked this conversation as resolved.
Show resolved Hide resolved

Array
.from(this.tunesInstances.values())
[...this.tunesInstances.values(), ...this.defaultTunesInstances.values()]
.forEach((tune) => {
if (_.isFunction(tune.wrap)) {
wrappedContentNode = tune.wrap(wrappedContentNode)
wrappedContentNode = tune.wrap(wrappedContentNode);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to add try-catch statement here? To avoid rendering problems in case of an error on the tune side?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing at the save() method

}
});

Expand All @@ -726,6 +700,32 @@ export default class Block {
return wrapper;
}

/**
* Instantiate Block Tunes
*
* @param tunesData - current Block tunes data
* @private
*/
private composeTunes(tunesData: {[name: string]: BlockTuneData}): void {
[
...this.tunes.external.values(),
...this.tunes.internal.values(),
].forEach((tune) => {
const collection = tune.isInternal ? this.defaultTunesInstances : this.tunesInstances;
neSpecc marked this conversation as resolved.
Show resolved Hide resolved

collection.set(tune.name, tune.instance(tunesData[tune.name], this.blockAPI));
});

/**
* Check if there is some data for not available tunes
*/
Object.entries(tunesData).forEach(([name, data]) => {
if (!this.tunesInstances.has(name)) {
this.unavailableTunesData[name] = data;
}
});
}

/**
* Is fired when text input or contentEditable is focused
*/
Expand Down
24 changes: 10 additions & 14 deletions src/components/modules/api/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { I18n } from '../../../../types/api';
import I18nInternal from '../../i18n';
import { ToolType } from '../tools';
import { logLabeled } from '../../utils';
import Module from '../../__module';
import { ToolClass } from '../../tools/collection';

/**
* Provides methods for working with i18n
Expand All @@ -11,17 +11,14 @@ export default class I18nAPI extends Module {
/**
* Return namespace section for tool or block tune
*
* @param toolName - name of tool. Used to provide dictionary only for this tool
* @param toolType - 'block' for Block Tool, 'inline' for Inline Tool, 'tune' for Block Tunes
* @param tool - tool object
*/
private static getNamespace(toolName: string, toolType: ToolType): string {
switch (toolType) {
case ToolType.Block:
case ToolType.Inline:
return `tools.${toolName}`;
case ToolType.Tune:
return `blockTunes.${toolName}`;
private static getNamespace(tool: ToolClass): string {
if (tool.isTune) {
return `blockTunes.${tool.name}`;
}

return `tools.${tool.name}`;
}

/**
Expand All @@ -40,15 +37,14 @@ export default class I18nAPI extends Module {
/**
* Return I18n API methods with tool namespaced dictionary
*
* @param toolName - name of tool. Used to provide dictionary only for this tool
* @param toolType - 'block' for Block Tool, 'inline' for Inline Tool, 'tune' for Block Tunes
* @param tool - Tool object
*/
public getMethodsForTool(toolName: string, toolType: ToolType): I18n {
public getMethodsForTool(tool: ToolClass): I18n {
return Object.assign(
this.methods,
{
t: (dictKey: string): string => {
return I18nInternal.t(I18nAPI.getNamespace(toolName, toolType), dictKey);
return I18nInternal.t(I18nAPI.getNamespace(tool), dictKey);
},
});
}
Expand Down
Loading