5htp-core 0.4.7 → 0.4.8-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -1
- package/src/client/assets/css/components/table.less +2 -0
- package/src/client/assets/css/text/titres.less +1 -1
- package/src/client/assets/css/utils/layouts.less +8 -2
- package/src/client/components/Dialog/Manager.tsx +65 -29
- package/src/client/components/Dialog/card.tsx +3 -1
- package/src/client/components/Dialog/index.less +1 -2
- package/src/client/components/Select/ChoiceSelector.tsx +7 -5
- package/src/client/components/Select/index.tsx +162 -130
- package/src/client/components/index.ts +2 -1
- package/src/client/components/inputv3/Rte/ExampleTheme.tsx +42 -0
- package/src/client/components/inputv3/Rte/ToolbarPlugin.tsx +167 -0
- package/src/client/components/inputv3/Rte/icons/LICENSE.md +5 -0
- package/src/client/components/inputv3/Rte/icons/arrow-clockwise.svg +4 -0
- package/src/client/components/inputv3/Rte/icons/arrow-counterclockwise.svg +4 -0
- package/src/client/components/inputv3/Rte/icons/journal-text.svg +5 -0
- package/src/client/components/inputv3/Rte/icons/justify.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/text-center.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/text-left.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/text-paragraph.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/text-right.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/type-bold.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/type-italic.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/type-strikethrough.svg +3 -0
- package/src/client/components/inputv3/Rte/icons/type-underline.svg +3 -0
- package/src/client/components/inputv3/Rte/index.tsx +163 -0
- package/src/client/components/inputv3/Rte/style.less +428 -0
- package/src/client/components/inputv3/base.less +20 -33
- package/src/client/components/inputv3/base.tsx +36 -2
- package/src/client/components/inputv3/file/index.tsx +11 -5
- package/src/client/components/inputv3/index.tsx +45 -44
- package/src/common/data/rte/index.ts +66 -0
- package/src/common/data/rte/nodes.ts +20 -0
- package/src/common/validation/validators.ts +49 -4
- package/src/server/services/auth/index.ts +0 -2
- package/src/server/services/database/index.ts +1 -1
- package/src/client/components/input/Rte/index.less +0 -13
- package/src/client/components/input/Rte/index.tsx +0 -143
- package/src/client/components/input/Rte/selection.ts +0 -34
- package/src/common/data/rte.tsx +0 -11
|
@@ -8,7 +8,7 @@ import { VNode, JSX } from 'preact';
|
|
|
8
8
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
9
9
|
|
|
10
10
|
// Core libs
|
|
11
|
-
import { useInput, InputBaseProps } from './base';
|
|
11
|
+
import { useInput, InputBaseProps, InputWrapper } from './base';
|
|
12
12
|
import { default as Validator } from '../../../common/validation/validator';
|
|
13
13
|
import type SchemaValidators from '@common/validation/validators';
|
|
14
14
|
|
|
@@ -47,17 +47,18 @@ type TInputElementProps = Omit<(
|
|
|
47
47
|
/*----------------------------------
|
|
48
48
|
- COMPOSANT
|
|
49
49
|
----------------------------------*/
|
|
50
|
-
export default ({
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
export default (props: Props & InputBaseProps<string> & TInputElementProps) => {
|
|
51
|
+
|
|
52
|
+
let {
|
|
53
|
+
// Decoration
|
|
54
|
+
icon, prefix, suffix, iconR, placeholder, size, className = '',
|
|
55
|
+
// State
|
|
56
|
+
inputRef, errors,
|
|
57
|
+
// Behavior
|
|
58
|
+
type, validator,
|
|
59
|
+
// Actions
|
|
60
|
+
onPressEnter
|
|
61
|
+
} = props;
|
|
61
62
|
|
|
62
63
|
/*----------------------------------
|
|
63
64
|
- INIT
|
|
@@ -128,7 +129,7 @@ export default ({
|
|
|
128
129
|
|
|
129
130
|
} else if (type === 'longtext') {
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
// No icon because not good looking ane we want as much space as possible
|
|
132
133
|
Tag = 'textarea';
|
|
133
134
|
className += ' multiline';
|
|
134
135
|
|
|
@@ -170,43 +171,43 @@ export default ({
|
|
|
170
171
|
/*----------------------------------
|
|
171
172
|
- RENDER
|
|
172
173
|
----------------------------------*/
|
|
173
|
-
return
|
|
174
|
-
<
|
|
174
|
+
return (
|
|
175
|
+
<InputWrapper {...props}>
|
|
176
|
+
<div class={className} onClick={() => refInput.current?.focus()}>
|
|
175
177
|
|
|
176
|
-
|
|
178
|
+
{prefix}
|
|
177
179
|
|
|
178
|
-
|
|
180
|
+
<div class="contValue">
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
// @ts-ignore: Property 'ref' does not exist on type 'IntrinsicAttributes'
|
|
182
|
-
ref={refInput}
|
|
183
|
-
value={value}
|
|
184
|
-
onFocus={() => setState({ focus: true })}
|
|
185
|
-
onBlur={() => setState({ focus: false })}
|
|
186
|
-
onChange={(e) => updateValue(e.target.value)}
|
|
182
|
+
<Tag {...fieldProps}
|
|
187
183
|
|
|
188
|
-
|
|
184
|
+
placeholder={placeholder || props.title}
|
|
189
185
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
186
|
+
// @ts-ignore: Property 'ref' does not exist on type 'IntrinsicAttributes'
|
|
187
|
+
ref={refInput}
|
|
188
|
+
value={value}
|
|
189
|
+
onFocus={() => setState({ focus: true })}
|
|
190
|
+
onBlur={() => setState({ focus: false })}
|
|
191
|
+
onChange={(e) => updateValue(e.target.value)}
|
|
192
|
+
onKeyDown={(e: KeyboardEvent) => {
|
|
196
193
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
194
|
+
if (onPressEnter && e.key === 'Enter' && value !== undefined) {
|
|
195
|
+
commitValue();
|
|
196
|
+
onPressEnter(value)
|
|
197
|
+
}
|
|
198
|
+
}}
|
|
199
|
+
/>
|
|
200
|
+
</div>
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
{suffix}
|
|
203
|
+
|
|
204
|
+
{errors?.length && (
|
|
205
|
+
<div class="bubble bg error bottom">
|
|
206
|
+
{errors.join('. ')}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
203
209
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
</div>
|
|
208
|
-
)}
|
|
209
|
-
|
|
210
|
-
</div>
|
|
211
|
-
</>
|
|
210
|
+
</div>
|
|
211
|
+
</InputWrapper>
|
|
212
|
+
)
|
|
212
213
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createHeadlessEditor } from '@lexical/headless';
|
|
2
|
+
import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html';
|
|
3
|
+
import { $getRoot } from 'lexical';
|
|
4
|
+
|
|
5
|
+
import { JSDOM } from 'jsdom';
|
|
6
|
+
|
|
7
|
+
import editorNodes from './nodes';
|
|
8
|
+
|
|
9
|
+
export const htmlToJson = async (htmlString: string) => {
|
|
10
|
+
|
|
11
|
+
const editor = createHeadlessEditor({
|
|
12
|
+
nodes: editorNodes
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await editor.update(() => {
|
|
16
|
+
|
|
17
|
+
const root = $getRoot();
|
|
18
|
+
|
|
19
|
+
// In a headless environment you can use a package such as JSDom to parse the HTML string.
|
|
20
|
+
const dom = new JSDOM(htmlString);
|
|
21
|
+
|
|
22
|
+
// Once you have the DOM instance it's easy to generate LexicalNodes.
|
|
23
|
+
const lexicalNodes = $generateNodesFromDOM(editor, dom.window.document);
|
|
24
|
+
|
|
25
|
+
lexicalNodes.forEach((node) => root.append(node));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const state = editor.getEditorState();
|
|
29
|
+
return state.toJSON();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const jsonToHtml = async (jsonString: string) => {
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const dom = new JSDOM(`<!DOCTYPE html><body></body>`);
|
|
36
|
+
global.window = dom.window;
|
|
37
|
+
global.document = dom.window.document;
|
|
38
|
+
global.DOMParser = dom.window.DOMParser;
|
|
39
|
+
global.MutationObserver = dom.window.MutationObserver;
|
|
40
|
+
|
|
41
|
+
// Create a headless Lexical editor instance
|
|
42
|
+
const editor = createHeadlessEditor({
|
|
43
|
+
namespace: 'headless',
|
|
44
|
+
editable: false,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Set the editor state from JSON
|
|
48
|
+
const state = editor.parseEditorState(jsonString);
|
|
49
|
+
if (state.isEmpty())
|
|
50
|
+
return null;
|
|
51
|
+
|
|
52
|
+
editor.setEditorState( state );
|
|
53
|
+
|
|
54
|
+
// Generate HTML from the Lexical nodes
|
|
55
|
+
const html = await editor.getEditorState().read(() => {
|
|
56
|
+
return $generateHtmlFromNodes(editor);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Clean up global variables set for JSDOM to avoid memory leaks
|
|
60
|
+
delete global.window;
|
|
61
|
+
delete global.document;
|
|
62
|
+
delete global.DOMParser;
|
|
63
|
+
delete global.MutationObserver;
|
|
64
|
+
|
|
65
|
+
return html;
|
|
66
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
|
|
3
|
+
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
|
|
4
|
+
import { ListItemNode, ListNode } from "@lexical/list";
|
|
5
|
+
import { CodeHighlightNode, CodeNode } from "@lexical/code";
|
|
6
|
+
import { AutoLinkNode, LinkNode } from "@lexical/link";
|
|
7
|
+
|
|
8
|
+
export default [
|
|
9
|
+
HeadingNode,
|
|
10
|
+
ListNode,
|
|
11
|
+
ListItemNode,
|
|
12
|
+
QuoteNode,
|
|
13
|
+
CodeNode,
|
|
14
|
+
CodeHighlightNode,
|
|
15
|
+
TableNode,
|
|
16
|
+
TableCellNode,
|
|
17
|
+
TableRowNode,
|
|
18
|
+
AutoLinkNode,
|
|
19
|
+
LinkNode
|
|
20
|
+
]
|
|
@@ -139,7 +139,7 @@ export default class SchemaValidators {
|
|
|
139
139
|
return undefined;
|
|
140
140
|
|
|
141
141
|
// Normalize for verifications
|
|
142
|
-
const choicesValues = choices?.map(v => v.value)
|
|
142
|
+
const choicesValues = choices?.map(v => typeof v === 'object' ? v.value : v)
|
|
143
143
|
|
|
144
144
|
const checkChoice = ( choice: any ) => {
|
|
145
145
|
|
|
@@ -350,6 +350,51 @@ export default class SchemaValidators {
|
|
|
350
350
|
...opts,
|
|
351
351
|
})
|
|
352
352
|
|
|
353
|
+
public richText = (opts: TValidator<string> & {
|
|
354
|
+
|
|
355
|
+
} = {}) => new Validator<string>('richText', (val, options, path) => {
|
|
356
|
+
|
|
357
|
+
// Check that the root exists and has a valid type
|
|
358
|
+
if (!val || typeof val !== 'object' || typeof val.root !== 'object' || val.root.type !== 'root')
|
|
359
|
+
throw new InputError("Invalid rich text value (1).");
|
|
360
|
+
|
|
361
|
+
// Check if root has children array
|
|
362
|
+
if (!Array.isArray(val.root.children))
|
|
363
|
+
throw new InputError("Invalid rich text value (2).");
|
|
364
|
+
|
|
365
|
+
// Recursive function to validate each node
|
|
366
|
+
function validateNode(node) {
|
|
367
|
+
// Each node should be an object with a `type` property
|
|
368
|
+
if (typeof node !== 'object' || !node.type || typeof node.type !== 'string')
|
|
369
|
+
throw new InputError("Invalid rich text value (3).");
|
|
370
|
+
|
|
371
|
+
// Validate text nodes
|
|
372
|
+
if (node.type === 'text') {
|
|
373
|
+
if (typeof node.text !== 'string')
|
|
374
|
+
throw new InputError("Invalid rich text value (4).");
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Validate paragraph, heading, or other structural nodes that may contain children
|
|
378
|
+
if (['paragraph', 'heading', 'list', 'listitem'].includes(node.type))
|
|
379
|
+
if (!Array.isArray(node.children) || !node.children.every(validateNode)) {
|
|
380
|
+
throw new InputError("Invalid rich text value (5).");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Validate each child node in root
|
|
387
|
+
for (const child of val.root.children) {
|
|
388
|
+
validateNode(child);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return val;
|
|
392
|
+
|
|
393
|
+
}, {
|
|
394
|
+
//defaut: new Date,
|
|
395
|
+
...opts,
|
|
396
|
+
})
|
|
397
|
+
|
|
353
398
|
/*----------------------------------
|
|
354
399
|
- FICHIER
|
|
355
400
|
----------------------------------*/
|
|
@@ -357,14 +402,14 @@ export default class SchemaValidators {
|
|
|
357
402
|
|
|
358
403
|
} = {}) => new Validator<FileToUpload>('file', (val, options, path) => {
|
|
359
404
|
|
|
360
|
-
if (!(val instanceof FileToUpload))
|
|
361
|
-
throw new InputError(`Must be a File (${typeof val} received)`);
|
|
362
|
-
|
|
363
405
|
// Chaine = url ancien fichier = exclusion de la valeur pour conserver l'ancien fichier
|
|
364
406
|
// NOTE: Si la valeur est présente mais undefined, alors on supprimera le fichier
|
|
365
407
|
if (typeof val === 'string')
|
|
366
408
|
return EXCLUDE_VALUE;
|
|
367
409
|
|
|
410
|
+
if (!(val instanceof FileToUpload))
|
|
411
|
+
throw new InputError(`Must be a File (${typeof val} received)`);
|
|
412
|
+
|
|
368
413
|
// MIME
|
|
369
414
|
if (type !== undefined) {
|
|
370
415
|
|
|
@@ -225,8 +225,6 @@ export default abstract class AuthService<
|
|
|
225
225
|
|
|
226
226
|
this.config.debug && console.warn(LogPrefix, `Check auth, role = ${role}. Current user =`, user?.name);
|
|
227
227
|
|
|
228
|
-
console.log({ entity, role, motivation });
|
|
229
|
-
|
|
230
228
|
if (user === undefined) {
|
|
231
229
|
|
|
232
230
|
throw new Error(`request.user has not been decoded.`);
|
|
@@ -256,7 +256,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
public equalities = (data: TObjetDonnees, keys = Object.keys(data)) =>
|
|
259
|
-
keys.map(k => '' + k + ' = ' +
|
|
259
|
+
keys.map(k => '' + k + ' = ' + this.esc( data[k] ))
|
|
260
260
|
|
|
261
261
|
/*----------------------------------
|
|
262
262
|
- OPERATIONS: LOW LEVELf
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
// INSPIRATION:
|
|
3
|
-
// https://github.com/sstur/react-rte
|
|
4
|
-
// https://drupalgutenberg.org/demo
|
|
5
|
-
|
|
6
|
-
/*----------------------------------
|
|
7
|
-
- DEPENDANCES
|
|
8
|
-
----------------------------------*/
|
|
9
|
-
|
|
10
|
-
// Npm
|
|
11
|
-
import React from 'react';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
Editor,
|
|
15
|
-
EditorState,
|
|
16
|
-
|
|
17
|
-
SelectionState,
|
|
18
|
-
|
|
19
|
-
convertToRaw,
|
|
20
|
-
KeyBindingUtil,
|
|
21
|
-
RawDraftContentState,
|
|
22
|
-
|
|
23
|
-
ContentBlock,
|
|
24
|
-
EditorBlock
|
|
25
|
-
} from 'draft-js';
|
|
26
|
-
|
|
27
|
-
// Libs
|
|
28
|
-
import Champ from '../Base';
|
|
29
|
-
import { getSelection, getSelectionRect } from './selection';
|
|
30
|
-
|
|
31
|
-
/*----------------------------------
|
|
32
|
-
- TYPES
|
|
33
|
-
----------------------------------*/
|
|
34
|
-
type TValeur = EditorState
|
|
35
|
-
const valeurDefaut = '' as string;
|
|
36
|
-
type TValeurDefaut = EditorState;
|
|
37
|
-
type TValeurOut = string;
|
|
38
|
-
|
|
39
|
-
export type Props = {
|
|
40
|
-
valeur: TValeur,
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/*----------------------------------
|
|
44
|
-
- COMPOSANT
|
|
45
|
-
----------------------------------*/
|
|
46
|
-
import './index.less';
|
|
47
|
-
export default Champ<Props, TValeurDefaut, TValeurOut>('rte', {
|
|
48
|
-
valeurDefaut,
|
|
49
|
-
saisieManuelle: true
|
|
50
|
-
}, ({
|
|
51
|
-
// Spread TOUTES les props dont on a besoin pour éviter les problèmes de référence avec props
|
|
52
|
-
placeholder, attrsChamp
|
|
53
|
-
}, { valeur, state, setState, commitCurrentValue }, rendre) => {
|
|
54
|
-
|
|
55
|
-
/*----------------------------------
|
|
56
|
-
- CONSTRUCTION CHAMP
|
|
57
|
-
----------------------------------*/
|
|
58
|
-
|
|
59
|
-
const refEditeur = React.useRef<Editor>(null);
|
|
60
|
-
|
|
61
|
-
// Init state
|
|
62
|
-
if (!valeur)
|
|
63
|
-
valeur = EditorState.createEmpty();
|
|
64
|
-
|
|
65
|
-
/*const updateToolbar = (selection: SelectionState) => {
|
|
66
|
-
|
|
67
|
-
if (selection.isCollapsed()) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
// eslint-disable-next-line no-undef
|
|
71
|
-
const nativeSelection = getSelection(window);
|
|
72
|
-
if (!nativeSelection.rangeCount) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const selectionBoundary = getSelectionRect(nativeSelection);
|
|
76
|
-
|
|
77
|
-
console.log('selectionBoundary', selectionBoundary);
|
|
78
|
-
|
|
79
|
-
const toolbarNode = document.getElementById('toolbar');
|
|
80
|
-
if (!toolbarNode) return;
|
|
81
|
-
const toolbarBoundary = toolbarNode.getBoundingClientRect();
|
|
82
|
-
|
|
83
|
-
// parent = conteneur éditeur draft
|
|
84
|
-
const parent = document.getElementById('toolbar');
|
|
85
|
-
if (!parent) return;
|
|
86
|
-
const parentBoundary = parent.getBoundingClientRect();
|
|
87
|
-
|
|
88
|
-
toolbarNode.style.top =
|
|
89
|
-
`${(selectionBoundary.top - parentBoundary.top - toolbarBoundary.height - 5)}px`;
|
|
90
|
-
toolbarNode.style.width = `${toolbarBoundary.width}px`;
|
|
91
|
-
|
|
92
|
-
// The left side of the tooltip should be:
|
|
93
|
-
// center of selection relative to parent - half width of toolbar
|
|
94
|
-
const selectionCenter = (selectionBoundary.left + (selectionBoundary.width / 2)) - parentBoundary.left;
|
|
95
|
-
let left = selectionCenter - (toolbarBoundary.width / 2);
|
|
96
|
-
const screenLeft = parentBoundary.left + left;
|
|
97
|
-
if (screenLeft < 0) {
|
|
98
|
-
// If the toolbar would be off-screen
|
|
99
|
-
// move it as far left as it can without going off-screen
|
|
100
|
-
left = -parentBoundary.left;
|
|
101
|
-
}
|
|
102
|
-
toolbarNode.style.left = `${left}px`;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}*/
|
|
106
|
-
|
|
107
|
-
const onChange = (state: EditorState) => {
|
|
108
|
-
|
|
109
|
-
/*const selection = state.getSelection();
|
|
110
|
-
updateToolbar(selection);*/
|
|
111
|
-
|
|
112
|
-
// Détection changement de contenu
|
|
113
|
-
/*const currentContentState = valeur.getCurrentContent()
|
|
114
|
-
const newContentState = state.getCurrentContent()
|
|
115
|
-
if (currentContentState === newContentState)*/
|
|
116
|
-
|
|
117
|
-
setState({ valeur: state });
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/*----------------------------------
|
|
122
|
-
- RENDU DU CHAMP
|
|
123
|
-
----------------------------------*/
|
|
124
|
-
return rendre((
|
|
125
|
-
<div className="champ typographie" onClick={() => refEditeur.current?.focus()}>
|
|
126
|
-
<Editor
|
|
127
|
-
ref={refEditeur}
|
|
128
|
-
editorState={valeur}
|
|
129
|
-
|
|
130
|
-
onChange={onChange}
|
|
131
|
-
onBlur={() => commitCurrentValue()}
|
|
132
|
-
|
|
133
|
-
placeholder={placeholder}
|
|
134
|
-
textAlignment="left"
|
|
135
|
-
textDirectionality="LTR"
|
|
136
|
-
|
|
137
|
-
/>
|
|
138
|
-
|
|
139
|
-
{/* <div id="toolbar">coucou</div> */}
|
|
140
|
-
</div>
|
|
141
|
-
// Les propétés modifiées sont passées ici
|
|
142
|
-
), { });
|
|
143
|
-
})
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// https://github.com/brijeshb42/medium-draft/blob/c5350bb76489fd4f2f90f1dc69db92224138d20a/src/util/index.js
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
Returns the `boundingClientRect` of the passed selection.
|
|
5
|
-
*/
|
|
6
|
-
export const getSelectionRect = (selected): DOMRect => {
|
|
7
|
-
const _rect = selected.getRangeAt(0).getBoundingClientRect();
|
|
8
|
-
// selected.getRangeAt(0).getBoundingClientRect()
|
|
9
|
-
let rect = _rect && _rect.top ? _rect : selected.getRangeAt(0).getClientRects()[0];
|
|
10
|
-
if (!rect) {
|
|
11
|
-
if (selected.anchorNode && selected.anchorNode.getBoundingClientRect) {
|
|
12
|
-
rect = selected.anchorNode.getBoundingClientRect();
|
|
13
|
-
rect.isEmptyline = true;
|
|
14
|
-
} else {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return rect;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/*
|
|
22
|
-
Returns the native selection node.
|
|
23
|
-
*/
|
|
24
|
-
export const getSelection = (root) => {
|
|
25
|
-
let t = null;
|
|
26
|
-
if (root.getSelection) {
|
|
27
|
-
t = root.getSelection();
|
|
28
|
-
} else if (root.document.getSelection) {
|
|
29
|
-
t = root.document.getSelection();
|
|
30
|
-
} else if (root.document.selection) {
|
|
31
|
-
t = root.document.selection.createRange().text;
|
|
32
|
-
}
|
|
33
|
-
return t;
|
|
34
|
-
};
|
package/src/common/data/rte.tsx
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import mediumDraftExporter from '@client/components/Rte/exporter';
|
|
2
|
-
import { convertFromRaw } from 'draft-js';
|
|
3
|
-
export { convertFromRaw } from 'draft-js';
|
|
4
|
-
|
|
5
|
-
export const convertir = (
|
|
6
|
-
state: any,
|
|
7
|
-
amp?: boolean
|
|
8
|
-
) => mediumDraftExporter(convertFromRaw( state ), amp);
|
|
9
|
-
|
|
10
|
-
export const versHtml = (state: any): string => convertir(state);
|
|
11
|
-
export const versAmp = (state: any): string => convertir(state, true);
|