5htp-core 0.4.9-2 → 0.4.9-5

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.
Files changed (25) hide show
  1. package/package.json +4 -1
  2. package/src/client/assets/css/components/lists.less +3 -3
  3. package/src/client/components/Form.ts +1 -1
  4. package/src/client/components/Select/ChoiceElement.tsx +20 -27
  5. package/src/client/components/Select/index.tsx +24 -42
  6. package/src/client/components/inputv3/Rte/Editor.tsx +16 -8
  7. package/src/client/components/inputv3/Rte/ToolbarPlugin/index.tsx +6 -1
  8. package/src/client/components/inputv3/Rte/plugins/DraggableBlockPlugin/index.css +23 -23
  9. package/src/client/components/inputv3/Rte/plugins/DraggableBlockPlugin/index.tsx +26 -24
  10. package/src/client/components/inputv3/Rte/plugins/FloatingLinkEditorPlugin/index.css +10 -38
  11. package/src/client/components/inputv3/Rte/plugins/FloatingLinkEditorPlugin/index.tsx +349 -356
  12. package/src/client/components/inputv3/Rte/plugins/FloatingTextFormatToolbarPlugin/index.css +80 -84
  13. package/src/client/components/inputv3/Rte/plugins/FloatingTextFormatToolbarPlugin/index.tsx +308 -347
  14. package/src/client/components/inputv3/Rte/style.less +0 -2
  15. package/src/client/components/inputv3/Rte/themes/PlaygroundEditorTheme.ts +1 -1
  16. package/src/client/components/inputv3/base.less +0 -6
  17. package/src/client/components/inputv3/file/index.tsx +50 -48
  18. package/src/client/components/inputv3/index.tsx +1 -1
  19. package/src/client/services/router/request/api.ts +29 -13
  20. package/src/common/router/request/api.ts +6 -4
  21. package/src/server/services/disks/driver.ts +2 -0
  22. package/src/server/services/disks/drivers/s3/index.ts +30 -1
  23. package/src/server/utils/rte.ts +217 -59
  24. package/src/server/utils/slug.ts +67 -0
  25. package/src/server/services/schema/rte.ts +0 -110
@@ -0,0 +1,67 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import escapeStringRegexp from 'escape-regexp';
7
+ import slugify from 'slugify';
8
+ import { removeStopwords, eng } from 'stopword';
9
+
10
+ // Core
11
+ import type SQL from "@server/services/database";
12
+
13
+ /*----------------------------------
14
+ - TYPES
15
+ ----------------------------------*/
16
+
17
+ /*----------------------------------
18
+ - SERVICE
19
+ ----------------------------------*/
20
+ export class Slug {
21
+
22
+ public async generate( label: string );
23
+ public async generate( label: string, SQL: SQL, table: string, column: string );
24
+ public async generate( label: string, SQL?: SQL, table?: string, column?: string ) {
25
+
26
+ // Generate slug
27
+ let slug = slugify(label, {
28
+ replacement: '-', // replace spaces with replacement character, defaults to `-`
29
+ remove: undefined, // remove characters that match regex, defaults to `undefined`
30
+ lower: true, // convert to lower case, defaults to `false`
31
+ strict: false, // strip special characters except replacement, defaults to `false`
32
+ locale: 'vi', // language code of the locale to use
33
+ trim: true // trim leading and trailing replacement chars, defaults to `true`
34
+ });
35
+
36
+ slug = removeStopwords( slug.split('-'), eng).join('-');
37
+
38
+ // Check if already existing
39
+ if (SQL !== undefined) {
40
+
41
+ const escapedSlug = escapeStringRegexp(slug);
42
+
43
+ const duplicates = await SQL.selectVal<number>(`
44
+ SELECT
45
+ IF( ${column} LIKE ${SQL.esc(slug)},
46
+ 1,
47
+ CAST(SUBSTRING_INDEX(slug, '-', -1) AS UNSIGNED)
48
+ ) AS duplicates
49
+ FROM ${table}
50
+ WHERE
51
+ ${column} LIKE ${SQL.esc(slug)}
52
+ OR
53
+ ${column} REGEXP '^${escapedSlug}-[0-9]+$'
54
+ ORDER BY duplicates DESC
55
+ LIMIT 1
56
+ `);
57
+
58
+ if (duplicates && duplicates > 0)
59
+ slug += `-${duplicates + 1}`;
60
+ }
61
+
62
+ return slug;
63
+ }
64
+
65
+ }
66
+
67
+ export default new Slug;
@@ -1,110 +0,0 @@
1
- /*----------------------------------
2
- - DEPENDANCES
3
- ----------------------------------*/
4
-
5
- // Node
6
- import path from 'path';
7
- import md5 from 'md5';
8
- import { fromBuffer } from 'file-type';
9
-
10
- // Npm
11
- import type { SerializedEditorState, SerializedLexicalNode } from 'lexical';
12
-
13
- // Core
14
- import type Driver from '@server/services/disks/driver';
15
-
16
- type SerializedLexicalNodeWithSrc = SerializedLexicalNode & { src: string };
17
-
18
- /*----------------------------------
19
- - METHODS
20
- ----------------------------------*/
21
- const uploadAttachments = async (
22
- value: SerializedEditorState,
23
- disk: Driver,
24
- destination: string,
25
- oldState?: SerializedEditorState
26
- ) => {
27
-
28
- const usedFilesUrl: string[] = [];
29
-
30
- // Deep check for images / files
31
- const findFiles = async (
32
- node: SerializedLexicalNode,
33
- callback: (node: SerializedLexicalNodeWithSrc) => Promise<void>
34
- ) => {
35
-
36
- // Attachment
37
- if (node.type === 'image' || node.type === 'file') {
38
- if (typeof node.src === 'string') {
39
- await callback(node as SerializedLexicalNodeWithSrc);
40
- }
41
- // Recursion
42
- } else if (node.children) {
43
- for (const child of node.children) {
44
- await findFiles(child, callback);
45
- }
46
- }
47
- }
48
-
49
- const uploadFile = async (node: SerializedLexicalNodeWithSrc) => {
50
-
51
- // Already uploaded
52
- if (!node.src.startsWith('data:')) {
53
- usedFilesUrl.push(node.src);
54
- return node.src;
55
- }
56
-
57
- // Transform into buffer
58
- node.src = node.src.replace(/^data:\w+\/\w+;base64,/, '');
59
- const fileData = Buffer.from(node.src, 'base64');
60
-
61
- // Parse file type from buffer
62
- const fileType = await fromBuffer(fileData);
63
- if (!fileType)
64
- throw new Error('Failed to detect file type');
65
-
66
- // Upload file to disk
67
- const fileName = md5(node.src) + '.' + fileType.ext;
68
- const filePath = path.join(destination, fileName);
69
- const upoadedFile = await disk.outputFile('data', filePath, fileData, {
70
- encoding: 'binary'
71
- });
72
-
73
- // Replace node.src with url
74
- node.src = upoadedFile.path;
75
- usedFilesUrl.push(node.src);
76
- }
77
-
78
- const deleteUnusedFile = async (node: SerializedLexicalNodeWithSrc) => {
79
-
80
- // Should be a URL
81
- if (node.src.startsWith('data:') || !node.src.startsWith('http'))
82
- return;
83
-
84
- // This file is used
85
- if (usedFilesUrl.includes(node.src))
86
- return;
87
-
88
- // Extract file name
89
- const fileName = path.basename(node.src);
90
- const filePath = path.join(destination, fileName);
91
-
92
- // Delete file from disk
93
- await disk.delete('data', filePath);
94
- console.log('Deleted file:', filePath);
95
- }
96
-
97
- // Find files in the editor state
98
- for (const child of value.root.children) {
99
- await findFiles(child, uploadFile);
100
- }
101
-
102
- // Old state given: remove unused attachments
103
- if (oldState !== undefined) {
104
- for (const child of oldState.root.children) {
105
- await findFiles(child, deleteUnusedFile);
106
- }
107
- }
108
- }
109
-
110
- export default { uploadAttachments }