Skip to content

Commit b97f7d1

Browse files
authored
Merge pull request #269 from editor-js/feature/enable-tune-selection
Support for selecting and enabling specific tunes in ImageTool
2 parents 5d1c57c + d5d98f3 commit b97f7d1

File tree

6 files changed

+129
-15
lines changed

6 files changed

+129
-15
lines changed

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Image Block for the [Editor.js](https://editorjs.io).
1212
- Pasting copied content from the web
1313
- Pasting images by drag-n-drop
1414
- Pasting files and screenshots from Clipboard
15-
- Allows adding a border, and a background
15+
- Allows adding a border, a background and a caption
1616
- Allows stretching an image to the container's full-width
1717

1818
**Notes**
@@ -83,6 +83,7 @@ Image Tool supports these configuration parameters:
8383
| buttonContent | `string` | Allows to override HTML content of «Select file» button |
8484
| uploader | `{{uploadByFile: function, uploadByUrl: function}}` | Optional custom uploading methods. See details below. |
8585
| actions | `array` | Array with custom actions to show in the tool's settings menu. See details below. |
86+
| features | `object` | Allows you to enable/disable additional features such as border, background tunes and caption. See details below. |
8687

8788
Note that if you don't implement your custom uploader methods, the `endpoints` param is required.
8889

@@ -96,6 +97,8 @@ Note that if you don't implement your custom uploader methods, the `endpoints` p
9697

9798
3. Add background
9899

100+
4. Add caption
101+
99102
Add extra setting-buttons by adding them to the `actions`-array in the configuration:
100103
```js
101104
actions: [
@@ -113,6 +116,17 @@ actions: [
113116

114117
**_NOTE:_** return value of `action` callback for settings whether action button should be toggled or not is *deprecated*. Consider using `toggle` option instead.
115118

119+
You can disable features such as border, background tunes and caption by defining `features` in the configuration:
120+
```js
121+
features: {
122+
border: false,
123+
caption: 'optional',
124+
stretch: false
125+
}
126+
```
127+
128+
**_NOTE:_** set caption to `optional` in order to configure caption as a tune.
129+
116130
## Output data
117131

118132
This Tool returns `data` with following format
@@ -136,7 +150,7 @@ This Tool returns `data` with following format
136150
"caption" : "Roadster // tesla.com",
137151
"withBorder" : false,
138152
"withBackground" : false,
139-
"stretched" : true
153+
"stretched" : true,
140154
}
141155
}
142156
```

dev/index.html

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Image Plugin Test | EditorJS</title>
7+
</head>
8+
<body>
9+
<div id="editorjs"></div>
10+
<script src="https://cdn.jsdelivr.net/npm/@editorjs/editorjs@latest/dist/editor.js"></script>
11+
<script src="../dist/image.umd.js"></script>
12+
<script>
13+
const editor = new EditorJS({
14+
holder: "editorjs",
15+
tools: {
16+
code: {
17+
class: ImageTool,
18+
config: {
19+
endpoints: {
20+
byFile: "http://localhost:8008/uploadFile",
21+
byUrl: "http://localhost:8008/fetchUrl",
22+
},
23+
features: {
24+
// caption: false,
25+
border: false,
26+
background: false,
27+
stretch: false,
28+
},
29+
},
30+
},
31+
},
32+
});
33+
</script>
34+
</body>
35+
</html>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@editorjs/image",
3-
"version": "2.9.3",
3+
"version": "2.10.0",
44
"keywords": [
55
"codex editor",
66
"image",

src/index.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
}
4545

4646
&__caption {
47+
display: none;
48+
4749
&[contentEditable="true"][data-placeholder]::before {
4850
position: absolute !important;
4951
content: attr(data-placeholder);
@@ -86,7 +88,7 @@
8688
margin: 0 6px 0 0;
8789
}
8890
}
89-
91+
9092
&--filled {
9193
.cdx-button {
9294
display: none;
@@ -147,13 +149,19 @@
147149
}
148150
}
149151

152+
&--caption {
153+
^&__caption {
154+
display: block;
155+
}
156+
}
150157
}
151158

152159
@keyframes image-preloader-spin {
153160
0% {
154161
transform: rotate(0deg);
155162
}
163+
156164
100% {
157165
transform: rotate(360deg);
158166
}
159-
}
167+
}

src/index.ts

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* 1) index.ts — main Tool's interface, public API and methods for working with data
1010
* 2) uploader.ts — module that has methods for sending files via AJAX: from device, by URL or File pasting
1111
* 3) ui.ts — module for UI manipulations: render, showing preloader, etc
12-
* 4) tunes.js — working with Block Tunes: render buttons, handle clicks
1312
*
1413
* For debug purposes there is a testing server
1514
* that can save uploaded files and return a Response {@link UploadResponseFormat}
@@ -36,8 +35,8 @@ import './index.css';
3635
import Ui from './ui';
3736
import Uploader from './uploader';
3837

39-
import { IconAddBorder, IconStretch, IconAddBackground, IconPicture } from '@codexteam/icons';
40-
import type { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, HTMLPasteEventDetailExtended, ImageSetterParam } from './types/types';
38+
import { IconAddBorder, IconStretch, IconAddBackground, IconPicture, IconText } from '@codexteam/icons';
39+
import type { ActionConfig, UploadResponseFormat, ImageToolData, ImageConfig, HTMLPasteEventDetailExtended, ImageSetterParam, FeaturesConfig } from './types/types';
4140

4241
type ImageToolConstructorOptions = BlockToolConstructorOptions<ImageToolData, ImageConfig>;
4342

@@ -50,11 +49,6 @@ export default class ImageTool implements BlockTool {
5049
*/
5150
private api: API;
5251

53-
/**
54-
* Flag indicating read-only mode
55-
*/
56-
private readOnly: boolean;
57-
5852
/**
5953
* Current Block API instance
6054
*/
@@ -90,7 +84,6 @@ export default class ImageTool implements BlockTool {
9084
*/
9185
constructor({ data, config, api, readOnly, block }: ImageToolConstructorOptions) {
9286
this.api = api;
93-
this.readOnly = readOnly;
9487
this.block = block;
9588

9689
/**
@@ -106,6 +99,7 @@ export default class ImageTool implements BlockTool {
10699
buttonContent: config.buttonContent,
107100
uploader: config.uploader,
108101
actions: config.actions,
102+
features: config.features || {},
109103
};
110104

111105
/**
@@ -197,6 +191,10 @@ export default class ImageTool implements BlockTool {
197191
* Renders Block content
198192
*/
199193
public render(): HTMLDivElement {
194+
if (this.config.features?.caption === true || this.config.features?.caption === undefined || (this.config.features?.caption === 'optional' && this.data.caption)) {
195+
this.ui.applyTune('caption', true);
196+
}
197+
200198
return this.ui.render(this.data) as HTMLDivElement;
201199
}
202200

@@ -228,8 +226,33 @@ export default class ImageTool implements BlockTool {
228226
// Merge default tunes with the ones that might be added by user
229227
// @see https://github.com/editor-js/image/pull/49
230228
const tunes = ImageTool.tunes.concat(this.config.actions || []);
229+
const featureTuneMap: Record<string, string> = {
230+
border: 'withBorder',
231+
background: 'withBackground',
232+
stretch: 'stretched',
233+
caption: 'caption',
234+
};
235+
236+
if (this.config.features?.caption === 'optional') {
237+
tunes.push({
238+
name: 'caption',
239+
icon: IconText,
240+
title: 'With caption',
241+
toggle: true,
242+
});
243+
}
244+
245+
const availableTunes = tunes.filter((tune) => {
246+
const featureKey = Object.keys(featureTuneMap).find(key => featureTuneMap[key] === tune.name);
247+
248+
if (featureKey === 'caption') {
249+
return this.config.features?.caption !== false;
250+
}
231251

232-
return tunes.map(tune => ({
252+
return featureKey == null || this.config.features?.[featureKey as keyof FeaturesConfig] !== false;
253+
});
254+
255+
return availableTunes.map(tune => ({
233256
icon: tune.icon,
234257
label: this.api.i18n.t(tune.title),
235258
name: tune.name,
@@ -398,6 +421,12 @@ export default class ImageTool implements BlockTool {
398421
private tuneToggled(tuneName: keyof ImageToolData): void {
399422
// inverse tune state
400423
this.setTune(tuneName, !(this._data[tuneName] as boolean));
424+
425+
// reset caption on toggle
426+
if (tuneName === 'caption' && !this._data[tuneName]) {
427+
this._data.caption = '';
428+
this.ui.fillCaption('');
429+
}
401430
}
402431

403432
/**

src/types/types.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,29 @@ export type ImageToolData<Actions = {}, AdditionalFileData = {}> = {
100100
} & AdditionalFileData;
101101
} & (Actions extends Record<string, boolean> ? Actions : {});
102102

103+
/**
104+
* @description Allows to enable or disable features.
105+
*/
106+
export type FeaturesConfig = {
107+
/**
108+
* Flag to enable/disable tune - background.
109+
*/
110+
background?: boolean;
111+
/**
112+
* Flag to enable/disable tune - border.
113+
*/
114+
border?: boolean;
115+
/**
116+
* Flag to enable/disable caption.
117+
* Can be set to 'optional' to allow users to toggle via block tunes.
118+
*/
119+
caption?: boolean | 'optional';
120+
/**
121+
* Flag to enable/disable tune - stretched
122+
*/
123+
stretch?: boolean;
124+
};
125+
103126
/**
104127
*
105128
* @description Config supported by Tool
@@ -171,6 +194,11 @@ export interface ImageConfig {
171194
* Additional actions for the tool.
172195
*/
173196
actions?: ActionConfig[];
197+
198+
/**
199+
* Tunes to be enabled.
200+
*/
201+
features?: FeaturesConfig;
174202
}
175203

176204
/**

0 commit comments

Comments
 (0)