Skip to content

Commit 27cf8d0

Browse files
author
abdobargush
committed
Add support for editing meta data
1 parent f3d7235 commit 27cf8d0

3 files changed

Lines changed: 124 additions & 65 deletions

File tree

README.md

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ npm i --save-dev @editorjs/link
2525
Include module at your application
2626

2727
```javascript
28-
const LinkTool = require('@editorjs/link');
28+
const LinkTool = require("@editorjs/link");
2929
```
3030

3131
### Download to your project's source dir
@@ -67,33 +67,34 @@ const editor = EditorJS({
6767

6868
Link Tool supports these configuration parameters:
6969

70-
| Field | Type | Description |
71-
| ---------|-------------|------------------------------------------------|
72-
| endpoint | `string` | **Required:** the endpoint for link data fetching. |
70+
| Field | Type | Description |
71+
| ------------- | --------- | ---------------------------------------------------------- |
72+
| endpoint | `string` | **Required:** the endpoint for link data fetching. |
73+
| allowMetaEdit | `boolean` | **Optional:** Allow editing meta data after being fetched. |
7374

7475
## Output data
7576

7677
This Tool returns `data` with following format
7778

78-
| Field | Type | Description |
79-
| -------------- | --------- | ------------------------------- |
80-
| link | `string` | Pasted link's url |
81-
| meta | `object` | Fetched link's data. Any data got from the backend. Currently, the plugin's design supports the 'title', 'image', and 'description' fields. |
79+
| Field | Type | Description |
80+
| ----- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
81+
| link | `string` | Pasted link's url |
82+
| meta | `object` | Fetched link's data. Any data got from the backend. Currently, the plugin's design supports the 'title', 'image', and 'description' fields. |
8283

8384
```json
8485
{
85-
"type" : "linkTool",
86-
"data" : {
87-
"link" : "https://codex.so",
88-
"meta" : {
89-
"title" : "CodeX Team",
90-
"site_name" : "CodeX",
91-
"description" : "Club of web-development, design and marketing. We build team learning how to build full-valued projects on the world market.",
92-
"image" : {
93-
"url" : "https://codex.so/public/app/img/meta_img.png"
94-
}
95-
}
86+
"type": "linkTool",
87+
"data": {
88+
"link": "https://codex.so",
89+
"meta": {
90+
"title": "CodeX Team",
91+
"site_name": "CodeX",
92+
"description": "Club of web-development, design and marketing. We build team learning how to build full-valued projects on the world market.",
93+
"image": {
94+
"url": "https://codex.so/public/app/img/meta_img.png"
95+
}
9696
}
97+
}
9798
}
9899
```
99100

@@ -106,10 +107,10 @@ Backend response **should** cover following format:
106107

107108
```json5
108109
{
109-
"success" : 1,
110-
"meta": {
111-
// ... any fields you want
112-
}
110+
"success": 1,
111+
"meta": {
112+
// ... any fields you want
113+
},
113114
}
114115
```
115116

@@ -121,14 +122,14 @@ Currently, the plugin's design supports the 'title', 'image', and 'description'
121122

122123
```json5
123124
{
124-
"success" : 1,
125-
"meta": {
126-
"title" : "CodeX Team",
127-
"description" : "Club of web-development, design and marketing. We build team learning how to build full-valued projects on the world market.",
128-
"image" : {
129-
"url" : "https://codex.so/public/app/img/meta_img.png"
130-
}
131-
}
125+
"success": 1,
126+
"meta": {
127+
"title": "CodeX Team",
128+
"description": "Club of web-development, design and marketing. We build team learning how to build full-valued projects on the world market.",
129+
"image": {
130+
"url": "https://codex.so/public/app/img/meta_img.png",
131+
},
132+
},
132133
}
133134
```
134135

src/index.css

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,35 @@
1919
background-color: #fff3f6;
2020
border-color: #f3e0e0;
2121
color: #a95a5a;
22-
box-shadow: inset 0 1px 3px 0 rgba(146, 62, 62, .05);
22+
box-shadow: inset 0 1px 3px 0 rgba(146, 62, 62, 0.05);
2323
}
2424
}
2525
}
26+
}
27+
28+
[contentEditable="true"] {
29+
&:focus {
30+
outline: none;
31+
}
2632

27-
&[contentEditable=true][data-placeholder]::before{
33+
&[data-placeholder]::before {
2834
position: absolute;
2935
content: attr(data-placeholder);
3036
color: #707684;
3137
font-weight: normal;
3238
opacity: 0;
39+
cursor: text;
40+
pointer-events: none;
3341
}
3442

35-
&[contentEditable=true][data-placeholder]:empty {
36-
43+
&[data-placeholder]:empty {
3744
&::before {
3845
opacity: 1;
3946
}
4047

4148
&:focus::before {
42-
opacity: 0;
43-
}
49+
opacity: 0;
50+
}
4451
}
4552
}
4653

@@ -79,13 +86,13 @@
7986
&--rendered {
8087
background: #fff;
8188
border: 1px solid rgba(201, 201, 204, 0.48);
82-
box-shadow: 0 1px 3px rgba(0,0,0, .1);
89+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
8390
border-radius: 6px;
8491
will-change: filter;
8592
animation: link-in 450ms 1 cubic-bezier(0.215, 0.61, 0.355, 1);
8693

8794
&:hover {
88-
box-shadow: 0 0 3px rgba(0,0,0, .16);
95+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.16);
8996
}
9097
}
9198
}
@@ -123,7 +130,7 @@
123130
}
124131

125132
&__anchor {
126-
display: block;
133+
display: inline-block;
127134
font-size: 15px;
128135
line-height: 1em;
129136
color: #888 !important;

src/index.js

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
*/
1515

1616
// eslint-disable-next-line
17-
import css from './index.css';
17+
import css from "./index.css";
1818
import ToolboxIcon from './svg/toolbox.svg';
1919
import ajax from '@codexteam/ajax';
2020
// eslint-disable-next-line
21-
import polyfill from 'url-polyfill';
21+
import polyfill from "url-polyfill";
2222

2323
/**
2424
* @typedef {object} UploadResponseFormat
@@ -60,7 +60,7 @@ export default class LinkTool {
6060
* @public
6161
*/
6262
static get enableLineBreaks() {
63-
return true;
63+
return false;
6464
}
6565

6666
/**
@@ -72,12 +72,14 @@ export default class LinkTool {
7272
constructor({ data, config, api, readOnly }) {
7373
this.api = api;
7474
this.readOnly = readOnly;
75+
this.isDataSet = false;
7576

7677
/**
7778
* Tool's initial config
7879
*/
7980
this.config = {
8081
endpoint: config.endpoint || '',
82+
allowMetaEdit: config.allowMetaEdit || false,
8183
};
8284

8385
this.nodes = {
@@ -138,6 +140,11 @@ export default class LinkTool {
138140
* @returns {LinkToolData}
139141
*/
140142
save() {
143+
if (this.config.allowMetaEdit && this.isDataSet) {
144+
this.data.meta.title = this.nodes.linkTitle.innerHTML;
145+
this.data.meta.description = this.nodes.linkDescription.innerHTML;
146+
}
147+
141148
return this.data;
142149
}
143150

@@ -159,10 +166,13 @@ export default class LinkTool {
159166
* @param {LinkToolData} data
160167
*/
161168
set data(data) {
162-
this._data = Object.assign({}, {
163-
link: data.link || this._data.link,
164-
meta: data.meta || this._data.meta,
165-
});
169+
this._data = Object.assign(
170+
{},
171+
{
172+
link: data.link || this._data.link,
173+
meta: data.meta || this._data.meta,
174+
}
175+
);
166176
}
167177

168178
/**
@@ -299,15 +309,40 @@ export default class LinkTool {
299309
* @returns {HTMLElement}
300310
*/
301311
prepareLinkPreview() {
302-
const holder = this.make('a', this.CSS.linkContent, {
303-
target: '_blank',
304-
rel: 'nofollow noindex noreferrer',
305-
});
312+
let holder = null;
313+
314+
// if edit meta is allowed add as dev
315+
if (this.config.allowMetaEdit) {
316+
holder = this.make('div', this.CSS.linkContent);
317+
} else {
318+
// add as link
319+
holder = this.make('a', this.CSS.linkContent, {
320+
target: '_blank',
321+
rel: 'nofollow noindex noreferrer',
322+
});
323+
}
306324

307325
this.nodes.linkImage = this.make('div', this.CSS.linkImage);
308-
this.nodes.linkTitle = this.make('div', this.CSS.linkTitle);
309-
this.nodes.linkDescription = this.make('p', this.CSS.linkDescription);
310-
this.nodes.linkText = this.make('span', this.CSS.linkText);
326+
this.nodes.linkTitle = this.make('div', this.CSS.linkTitle, {
327+
contentEditable: this.config.allowMetaEdit,
328+
});
329+
this.nodes.linkDescription = this.make('p', this.CSS.linkDescription, {
330+
contentEditable: this.config.allowMetaEdit,
331+
});
332+
333+
// if edit meta is allowed add as link
334+
if (this.config.allowMetaEdit) {
335+
this.nodes.linkText = this.make('a', this.CSS.linkText, {
336+
target: '_blank',
337+
rel: 'nofollow noindex noreferrer',
338+
});
339+
} else {
340+
// add as span
341+
this.nodes.linkText = this.make('span', this.CSS.linkText);
342+
}
343+
344+
// Mark as data is set
345+
this.isDataSet = true;
311346

312347
return holder;
313348
}
@@ -325,22 +360,34 @@ export default class LinkTool {
325360
this.nodes.linkContent.appendChild(this.nodes.linkImage);
326361
}
327362

328-
if (title) {
329-
this.nodes.linkTitle.textContent = title;
363+
if (title || this.config.allowMetaEdit) {
364+
this.nodes.linkTitle.innerHTML = title;
365+
this.nodes.linkTitle.dataset.placeholder =
366+
this.api.i18n.t('Enter link title');
330367
this.nodes.linkContent.appendChild(this.nodes.linkTitle);
331368
}
332369

333-
if (description) {
334-
this.nodes.linkDescription.textContent = description;
370+
if (description || this.config.allowMetaEdit) {
371+
this.nodes.linkDescription.innerHTML = description;
372+
this.nodes.linkDescription.dataset.placeholder = this.api.i18n.t(
373+
'Enter link description'
374+
);
335375
this.nodes.linkContent.appendChild(this.nodes.linkDescription);
336376
}
337377

338378
this.nodes.linkContent.classList.add(this.CSS.linkContentRendered);
339-
this.nodes.linkContent.setAttribute('href', this.data.link);
379+
// if edit meta is not allowed add href to link content holder
380+
if (!this.allowMetaEdit) {
381+
this.nodes.linkContent.setAttribute('href', this.data.link);
382+
}
340383
this.nodes.linkContent.appendChild(this.nodes.linkText);
341384

385+
// if edit meta is allowed add href to link text
386+
if (this.config.allowMetaEdit) {
387+
this.nodes.linkText.setAttribute('href', this.data.link);
388+
}
342389
try {
343-
this.nodes.linkText.textContent = (new URL(this.data.link)).hostname;
390+
this.nodes.linkText.textContent = new URL(this.data.link).hostname;
344391
} catch (e) {
345392
this.nodes.linkText.textContent = this.data.link;
346393
}
@@ -383,16 +430,16 @@ export default class LinkTool {
383430
this.data = { link: url };
384431

385432
try {
386-
const { body } = await (ajax.get({
433+
const { body } = await ajax.get({
387434
url: this.config.endpoint,
388435
data: {
389436
url,
390437
},
391-
}));
438+
});
392439

393440
this.onFetch(body);
394441
} catch (error) {
395-
this.fetchingFailed(this.api.i18n.t('Couldn\'t fetch the link data'));
442+
this.fetchingFailed(this.api.i18n.t("Couldn't fetch the link data"));
396443
}
397444
}
398445

@@ -403,7 +450,9 @@ export default class LinkTool {
403450
*/
404451
onFetch(response) {
405452
if (!response || !response.success) {
406-
this.fetchingFailed(this.api.i18n.t('Couldn\'t get this link data, try the other one'));
453+
this.fetchingFailed(
454+
this.api.i18n.t("Couldn't get this link data, try the other one")
455+
);
407456

408457
return;
409458
}
@@ -413,7 +462,9 @@ export default class LinkTool {
413462
this.data = { meta: metaData };
414463

415464
if (!metaData) {
416-
this.fetchingFailed(this.api.i18n.t('Wrong response format from the server'));
465+
this.fetchingFailed(
466+
this.api.i18n.t('Wrong response format from the server')
467+
);
417468

418469
return;
419470
}

0 commit comments

Comments
 (0)