@silexlabs/silex 3.0.0-alpha.97 → 3.0.0
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/.env.default +2 -1
- package/README.md +31 -9
- package/dist/client/client/api.d.ts +5 -0
- package/dist/client/client/assetUrl.d.ts +3 -0
- package/dist/client/client/config.d.ts +31 -0
- package/dist/client/client/events.d.ts +7 -1
- package/dist/client/client/grapesjs/PublicationManager.d.ts +2 -1
- package/dist/client/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/client/grapesjs/img.d.ts +6 -0
- package/dist/client/client/grapesjs/index.d.ts +2 -2
- package/dist/client/client/grapesjs/new-page-dialog.d.ts +1 -1
- package/dist/client/client/grapesjs/page-panel.d.ts +1 -1
- package/dist/client/client/grapesjs/project-bar.d.ts +16 -0
- package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/client/grapesjs/rich-text.d.ts +4 -1
- package/dist/client/client/grapesjs/semantic.d.ts +1 -1
- package/dist/client/client/grapesjs/settings-sections.d.ts +15 -0
- package/dist/client/client/grapesjs/settings.d.ts +3 -1
- package/dist/client/client/grapesjs/symbolDialogs.d.ts +1 -1
- package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/client/index.d.ts +10 -0
- package/dist/client/client/publication-transformers.d.ts +4 -3
- package/dist/client/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/client/publish-fonts.d.ts +4 -0
- package/dist/client/client/utils.d.ts +4 -0
- package/dist/client/constants.d.ts +1 -0
- package/dist/client/css/admin.css +273 -32
- package/dist/client/index.html +2 -1
- package/dist/client/js/main.js +164 -123
- package/dist/client/js/main.js.LICENSE.txt +15 -1
- package/dist/client/types.d.ts +12 -7
- package/dist/plugins/client/client/events.d.ts +7 -1
- package/dist/plugins/client/client/events.js +7 -1
- package/dist/plugins/client/client/events.js.map +1 -1
- package/dist/plugins/client/plugins/client/template.js +108 -58
- package/dist/plugins/client/plugins/client/template.js.map +1 -1
- package/dist/plugins/client/types.d.ts +12 -7
- package/dist/plugins/client/types.js +6 -0
- package/dist/plugins/client/types.js.map +1 -1
- package/dist/plugins/server/constants.d.ts +1 -0
- package/dist/plugins/server/constants.js +2 -1
- package/dist/plugins/server/constants.js.map +1 -1
- package/dist/plugins/server/plugins/server/FtpConnector.d.ts +1 -0
- package/dist/plugins/server/plugins/server/FtpConnector.js +12 -1
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
- package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +3 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.js +72 -35
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
- package/dist/plugins/server/server/config.js +3 -3
- package/dist/plugins/server/server/config.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsHosting.d.ts +1 -0
- package/dist/plugins/server/server/connectors/FsHosting.js +13 -1
- package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsStorage.d.ts +2 -1
- package/dist/plugins/server/server/connectors/FsStorage.js +29 -25
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
- package/dist/plugins/server/server/connectors/connectors.d.ts +1 -0
- package/dist/plugins/server/server/jobs.js +4 -2
- package/dist/plugins/server/server/jobs.js.map +1 -1
- package/dist/plugins/server/types.d.ts +12 -7
- package/dist/plugins/server/types.js +7 -1
- package/dist/plugins/server/types.js.map +1 -1
- package/dist/server/constants.js +2 -1
- package/dist/server/server/api/publicationApi.js +3 -5
- package/dist/server/server/api/websiteApi.js +22 -3
- package/dist/server/server/cli.js +9 -6
- package/dist/server/server/config.js +3 -3
- package/dist/server/server/connectors/FsHosting.js +13 -1
- package/dist/server/server/connectors/FsStorage.js +28 -25
- package/dist/server/server/jobs.js +4 -2
- package/dist/server/types.js +7 -1
- package/package.json +34 -30
- package/public/assets/favicon.ico +0 -0
- package/public/assets/favicon.png +0 -0
- package/public/assets/logo-silex-small.png +0 -0
- package/src/css/_variables.scss +5 -3
- package/src/css/dialog.scss +22 -1
- package/src/css/fonts.scss +31 -0
- package/src/css/footer.scss +1 -1
- package/src/css/grapesjs-plugins.scss +34 -0
- package/src/css/grapesjs.scss +26 -11
- package/src/css/index.scss +1 -0
- package/src/css/project-bar.scss +11 -7
- package/src/css/silex.scss +58 -5
- package/src/html/index.pug +2 -2
- package/src/ts/client/api.ts +14 -9
- package/src/ts/client/assetUrl.test.ts +39 -0
- package/src/ts/client/assetUrl.ts +24 -5
- package/src/ts/client/config.ts +85 -4
- package/src/ts/client/events.ts +15 -9
- package/src/ts/client/grapesjs/PublicationManager.ts +71 -38
- package/src/ts/client/grapesjs/PublicationUi.ts +13 -11
- package/src/ts/client/grapesjs/css-props.ts +544 -0
- package/src/ts/client/grapesjs/eleventy.ts +2 -5
- package/src/ts/client/grapesjs/footer.ts +24 -9
- package/src/ts/client/grapesjs/img.ts +147 -0
- package/src/ts/client/grapesjs/index.ts +63 -25
- package/src/ts/client/grapesjs/internal-links.test.ts +2 -1
- package/src/ts/client/grapesjs/internal-links.ts +0 -1
- package/src/ts/client/grapesjs/new-page-dialog.ts +2 -3
- package/src/ts/client/grapesjs/page-panel.ts +28 -3
- package/src/ts/client/grapesjs/project-bar.ts +83 -64
- package/src/ts/client/grapesjs/resize-panel.ts +20 -0
- package/src/ts/client/grapesjs/rich-text.ts +21 -13
- package/src/ts/client/grapesjs/semantic.ts +3 -3
- package/src/ts/client/grapesjs/settings-sections.ts +117 -0
- package/src/ts/client/grapesjs/settings.ts +120 -77
- package/src/ts/client/grapesjs/symbolDialogs.ts +2 -3
- package/src/ts/client/grapesjs/view-buttons.ts +42 -0
- package/src/ts/client/index.ts +13 -6
- package/src/ts/client/publication-transformers.test.ts +13 -5
- package/src/ts/client/publication-transformers.ts +60 -47
- package/{dist/plugins/client/client/utils.js → src/ts/client/publish-custom-code-block.ts} +14 -8
- package/{dist/plugins/client/page.js → src/ts/client/publish-fonts.ts} +19 -14
- package/src/ts/client/utils.ts +18 -0
- package/src/ts/constants.ts +1 -0
- package/src/ts/plugins/client/template.ts +112 -60
- package/src/ts/plugins/server/FtpConnector.ts +14 -2
- package/src/ts/plugins/server/GitlabConnector.ts +71 -32
- package/src/ts/server/api/publicationApi.ts +5 -5
- package/src/ts/server/api/websiteApi.ts +39 -9
- package/src/ts/server/cli.ts +7 -5
- package/src/ts/server/config.ts +4 -4
- package/src/ts/server/connectors/FsHosting.ts +11 -5
- package/src/ts/server/connectors/FsStorage.ts +33 -4
- package/src/ts/server/connectors/connectors.ts +1 -1
- package/src/ts/server/jobs.ts +4 -2
- package/src/ts/types.ts +10 -7
- package/dist/plugins/client/client/api.d.ts +0 -85
- package/dist/plugins/client/client/api.js +0 -114
- package/dist/plugins/client/client/api.js.map +0 -1
- package/dist/plugins/client/client/assetUrl.d.ts +0 -51
- package/dist/plugins/client/client/assetUrl.js +0 -224
- package/dist/plugins/client/client/assetUrl.js.map +0 -1
- package/dist/plugins/client/client/config.d.ts +0 -58
- package/dist/plugins/client/client/config.js +0 -90
- package/dist/plugins/client/client/config.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/LoginDialog.d.ts +0 -15
- package/dist/plugins/client/client/grapesjs/LoginDialog.js +0 -195
- package/dist/plugins/client/client/grapesjs/LoginDialog.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/PublicationManager.d.ts +0 -72
- package/dist/plugins/client/client/grapesjs/PublicationManager.js +0 -356
- package/dist/plugins/client/client/grapesjs/PublicationManager.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/PublicationUi.d.ts +0 -62
- package/dist/plugins/client/client/grapesjs/PublicationUi.js +0 -336
- package/dist/plugins/client/client/grapesjs/PublicationUi.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/blocks.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/blocks.js +0 -37
- package/dist/plugins/client/client/grapesjs/blocks.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/breadcrumbs.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/breadcrumbs.js +0 -75
- package/dist/plugins/client/client/grapesjs/breadcrumbs.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/footer.d.ts +0 -2
- package/dist/plugins/client/client/grapesjs/footer.js +0 -28
- package/dist/plugins/client/client/grapesjs/footer.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/index.d.ts +0 -5
- package/dist/plugins/client/client/grapesjs/index.js +0 -313
- package/dist/plugins/client/client/grapesjs/index.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/internal-links.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/internal-links.js +0 -219
- package/dist/plugins/client/client/grapesjs/internal-links.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/new-page-dialog.d.ts +0 -2
- package/dist/plugins/client/client/grapesjs/new-page-dialog.js +0 -83
- package/dist/plugins/client/client/grapesjs/new-page-dialog.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/openImport.d.ts +0 -9
- package/dist/plugins/client/client/grapesjs/openImport.js +0 -74
- package/dist/plugins/client/client/grapesjs/openImport.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/page-panel.d.ts +0 -3
- package/dist/plugins/client/client/grapesjs/page-panel.js +0 -113
- package/dist/plugins/client/client/grapesjs/page-panel.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/project-bar.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/project-bar.js +0 -104
- package/dist/plugins/client/client/grapesjs/project-bar.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/rich-text.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/rich-text.js +0 -31
- package/dist/plugins/client/client/grapesjs/rich-text.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/semantic.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/semantic.js +0 -110
- package/dist/plugins/client/client/grapesjs/semantic.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/settings.d.ts +0 -2
- package/dist/plugins/client/client/grapesjs/settings.js +0 -198
- package/dist/plugins/client/client/grapesjs/settings.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/storage.d.ts +0 -1
- package/dist/plugins/client/client/grapesjs/storage.js +0 -126
- package/dist/plugins/client/client/grapesjs/storage.js.map +0 -1
- package/dist/plugins/client/client/grapesjs/symbolDialogs.d.ts +0 -3
- package/dist/plugins/client/client/grapesjs/symbolDialogs.js +0 -36
- package/dist/plugins/client/client/grapesjs/symbolDialogs.js.map +0 -1
- package/dist/plugins/client/client/publication-transformers.d.ts +0 -41
- package/dist/plugins/client/client/publication-transformers.js +0 -238
- package/dist/plugins/client/client/publication-transformers.js.map +0 -1
- package/dist/plugins/client/client/utils.d.ts +0 -2
- package/dist/plugins/client/client/utils.js.map +0 -1
- package/dist/plugins/client/constants.d.ts +0 -29
- package/dist/plugins/client/constants.js +0 -46
- package/dist/plugins/client/constants.js.map +0 -1
- package/dist/plugins/client/page.d.ts +0 -2
- package/dist/plugins/client/page.js.map +0 -1
- package/dist/plugins/client/plugins/client/11ty.d.ts +0 -17
- package/dist/plugins/client/plugins/client/11ty.js +0 -86
- package/dist/plugins/client/plugins/client/11ty.js.map +0 -1
- package/dist/plugins/client/plugins/client/publicationRenderer.d.ts +0 -2
- package/dist/plugins/client/plugins/client/publicationRenderer.js +0 -170
- package/dist/plugins/client/plugins/client/publicationRenderer.js.map +0 -1
- package/src/ts/plugins/client/11ty.ts +0 -104
- package/src/ts/plugins/client/publicationRenderer.ts +0 -174
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { Component, CssRule, Editor, ObjectStrings, Page } from 'grapesjs'
|
|
19
|
-
import { ClientSideFile, ClientSideFileType, ClientSideFileWithPermalink, PublicationData } from '../types'
|
|
19
|
+
import { ClientSideFile, ClientSideFileType, ClientSideFileWithPermalink, Initiator, PublicationData } from '../types'
|
|
20
20
|
import { onAll } from './utils'
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -47,11 +47,42 @@ export interface PublicationTransformer {
|
|
|
47
47
|
// Transform files after they are rendered and before they are published
|
|
48
48
|
transformFile?(file: ClientSideFile): ClientSideFile
|
|
49
49
|
// Define files URLs
|
|
50
|
-
transformPermalink?(link: string, type: ClientSideFileType): string
|
|
50
|
+
transformPermalink?(link: string, type: ClientSideFileType, initiator: Initiator): string
|
|
51
51
|
// Define where files are published
|
|
52
52
|
transformPath?(path: string, type: ClientSideFileType): string
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
export const publicationTransformerDefault: PublicationTransformer = {
|
|
56
|
+
// Override how components render at publication by grapesjs
|
|
57
|
+
renderComponent(component: Component, toHtml: () => string): string | undefined {
|
|
58
|
+
return toHtml()
|
|
59
|
+
},
|
|
60
|
+
// Override how styles render at publication by grapesjs
|
|
61
|
+
renderCssRule(rule: CssRule, initialRule: () => ObjectStrings): ObjectStrings | undefined {
|
|
62
|
+
return initialRule()
|
|
63
|
+
},
|
|
64
|
+
// Define where files are published
|
|
65
|
+
transformPath(path: string, type: ClientSideFileType): string {
|
|
66
|
+
return path
|
|
67
|
+
},
|
|
68
|
+
// Define files URLs
|
|
69
|
+
transformPermalink(link: string, type: ClientSideFileType, initiator: Initiator): string {
|
|
70
|
+
switch(initiator) {
|
|
71
|
+
case Initiator.HTML:
|
|
72
|
+
return link
|
|
73
|
+
case Initiator.CSS:
|
|
74
|
+
// In case of a link from a CSS file, we need to go up one level
|
|
75
|
+
return `../${link.replace(/^\//, '')}`
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`Unknown initiator ${initiator}`)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
// Define how files are named
|
|
81
|
+
transformFile(file: ClientSideFile): ClientSideFile {
|
|
82
|
+
return file
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
55
86
|
export function validatePublicationTransformer(transformer: PublicationTransformer): void {
|
|
56
87
|
// List all the properties
|
|
57
88
|
const allowedProperties = [
|
|
@@ -77,7 +108,6 @@ export function validatePublicationTransformer(transformer: PublicationTransform
|
|
|
77
108
|
})
|
|
78
109
|
}
|
|
79
110
|
|
|
80
|
-
|
|
81
111
|
/**
|
|
82
112
|
* Alter the components rendering
|
|
83
113
|
* Exported for unit tests
|
|
@@ -97,7 +127,7 @@ export function renderComponents(editor: Editor) {
|
|
|
97
127
|
c[ATTRIBUTE_METHOD_STORE_HREF] = href
|
|
98
128
|
c.set('attributes', {
|
|
99
129
|
...c.get('attributes'),
|
|
100
|
-
href: transformPermalink(editor, href, ClientSideFileType.HTML),
|
|
130
|
+
href: transformPermalink(editor, href, ClientSideFileType.HTML, Initiator.HTML),
|
|
101
131
|
})
|
|
102
132
|
}
|
|
103
133
|
// Handle both c.attributes.src and c.attributes.attributes.src
|
|
@@ -105,7 +135,7 @@ export function renderComponents(editor: Editor) {
|
|
|
105
135
|
// Especially when the component is not on the current page, we need c.attributes.attributes.src
|
|
106
136
|
if(c.get('attributes').src) {
|
|
107
137
|
c[ATTRIBUTE_METHOD_STORE_SRC] = c.get('attributes').src
|
|
108
|
-
const src = transformPermalink(editor, c.get('attributes').src, ClientSideFileType.ASSET)
|
|
138
|
+
const src = transformPermalink(editor, c.get('attributes').src, ClientSideFileType.ASSET, Initiator.HTML)
|
|
109
139
|
c.set('attributes', {
|
|
110
140
|
...c.get('attributes'),
|
|
111
141
|
src,
|
|
@@ -113,17 +143,12 @@ export function renderComponents(editor: Editor) {
|
|
|
113
143
|
}
|
|
114
144
|
if(c.get('src')) {
|
|
115
145
|
c[ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC] = c.get('src')
|
|
116
|
-
const src = transformPermalink(editor, c.get('src'), ClientSideFileType.ASSET)
|
|
146
|
+
const src = transformPermalink(editor, c.get('src'), ClientSideFileType.ASSET, Initiator.HTML)
|
|
117
147
|
c.set('src', src)
|
|
118
148
|
}
|
|
119
149
|
c.toHTML = () => {
|
|
120
150
|
return config.publicationTransformers.reduce((html: string, transformer: PublicationTransformer) => {
|
|
121
|
-
|
|
122
|
-
return transformer.renderComponent ? transformer.renderComponent(c, () => html) ?? html : html
|
|
123
|
-
} catch (e) {
|
|
124
|
-
console.error('Publication transformer: error rendering component', c, e)
|
|
125
|
-
return html
|
|
126
|
-
}
|
|
151
|
+
return transformer.renderComponent ? transformer.renderComponent(c, () => html) ?? html : html
|
|
127
152
|
}, initialToHTML())
|
|
128
153
|
}
|
|
129
154
|
c.getStyle = () => transformBgImage(editor, initialGetStyle())
|
|
@@ -144,17 +169,13 @@ export function renderCssRules(editor: Editor) {
|
|
|
144
169
|
const initialGetStyle = style.getStyle.bind(style)
|
|
145
170
|
style[ATTRIBUTE_METHOD_STORE_CSS] = style.getStyle
|
|
146
171
|
style.getStyle = () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
} catch (e) {
|
|
155
|
-
console.error('Publication transformer: error rendering style', style, e)
|
|
156
|
-
return initialGetStyle()
|
|
157
|
-
}
|
|
172
|
+
const initialStyle = transformBgImage(editor, initialGetStyle())
|
|
173
|
+
const result = config.publicationTransformers.reduce((s: CssRule, transformer: PublicationTransformer) => {
|
|
174
|
+
return {
|
|
175
|
+
...transformer.renderCssRule ? transformer.renderCssRule(s, () => initialStyle) ?? s : s,
|
|
176
|
+
}
|
|
177
|
+
}, initialStyle)
|
|
178
|
+
return result
|
|
158
179
|
}
|
|
159
180
|
}
|
|
160
181
|
})
|
|
@@ -164,12 +185,19 @@ export function renderCssRules(editor: Editor) {
|
|
|
164
185
|
* Transform background image url according to the transformed path of assets
|
|
165
186
|
*/
|
|
166
187
|
export function transformBgImage(editor: Editor, style: ObjectStrings): ObjectStrings {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
188
|
+
const cssValue = style['background-image']
|
|
189
|
+
if (cssValue) {
|
|
190
|
+
const newCssValue = cssValue.replace(/url\(([^)]+)\)/g, (match, url) => {
|
|
191
|
+
// Support URLs with or without quotes
|
|
192
|
+
const cleanUrl = url.replace(/['"]/g, '')
|
|
193
|
+
// Transform URLs
|
|
194
|
+
const newUrl = transformPermalink(editor, cleanUrl, ClientSideFileType.ASSET, Initiator.CSS)
|
|
195
|
+
// Return the new URL with url keyword
|
|
196
|
+
return `url(${newUrl})`
|
|
197
|
+
})
|
|
170
198
|
return {
|
|
171
199
|
...style,
|
|
172
|
-
'background-image':
|
|
200
|
+
'background-image': newCssValue,
|
|
173
201
|
}
|
|
174
202
|
}
|
|
175
203
|
return style
|
|
@@ -183,13 +211,8 @@ export function transformFiles(editor: Editor, data: PublicationData) {
|
|
|
183
211
|
const config = editor.getModel().get('config')
|
|
184
212
|
data.files = config.publicationTransformers.reduce((files: ClientSideFile[], transformer: PublicationTransformer) => {
|
|
185
213
|
return files.map((file, idx) => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return transformer.transformFile ? transformer.transformFile(file) as ClientSideFile ?? file : file
|
|
189
|
-
} catch (e) {
|
|
190
|
-
console.error('Publication transformer: error transforming file', file, e)
|
|
191
|
-
return file
|
|
192
|
-
}
|
|
214
|
+
const page = data.pages[idx] ?? null
|
|
215
|
+
return transformer.transformFile ? transformer.transformFile(file) as ClientSideFile ?? file : file
|
|
193
216
|
})
|
|
194
217
|
}, data.files)
|
|
195
218
|
}
|
|
@@ -198,27 +221,17 @@ export function transformFiles(editor: Editor, data: PublicationData) {
|
|
|
198
221
|
* Transform files paths
|
|
199
222
|
* Exported for unit tests
|
|
200
223
|
*/
|
|
201
|
-
export function transformPermalink(editor: Editor, path: string, type: ClientSideFileType): string {
|
|
224
|
+
export function transformPermalink(editor: Editor, path: string, type: ClientSideFileType, initiator: Initiator): string {
|
|
202
225
|
const config = editor.getModel().get('config')
|
|
203
226
|
return config.publicationTransformers.reduce((result: string, transformer: PublicationTransformer) => {
|
|
204
|
-
|
|
205
|
-
return transformer.transformPermalink ? transformer.transformPermalink(result, type) ?? result : result
|
|
206
|
-
} catch (e) {
|
|
207
|
-
console.error('Publication transformer: error transforming path', result, e)
|
|
208
|
-
return result
|
|
209
|
-
}
|
|
227
|
+
return transformer.transformPermalink ? transformer.transformPermalink(result, type, initiator) ?? result : result
|
|
210
228
|
}, path)
|
|
211
229
|
}
|
|
212
230
|
|
|
213
231
|
export function transformPath(editor: Editor, path: string, type: ClientSideFileType): string {
|
|
214
232
|
const config = editor.getModel().get('config')
|
|
215
233
|
return config.publicationTransformers.reduce((result: string, transformer: PublicationTransformer) => {
|
|
216
|
-
|
|
217
|
-
return transformer.transformPath ? transformer.transformPath(result, type) ?? result : result
|
|
218
|
-
} catch (e) {
|
|
219
|
-
console.error('Publication transformer: error transforming path', result, e)
|
|
220
|
-
return result
|
|
221
|
-
}
|
|
234
|
+
return transformer.transformPath ? transformer.transformPath(result, type) ?? result : result
|
|
222
235
|
}, path)
|
|
223
236
|
}
|
|
224
237
|
|
|
@@ -14,12 +14,18 @@
|
|
|
14
14
|
* You should have received a copy of the GNU Affero General Public License
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @fileoverview Make sure custom script blocks include script tags when published
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export default async function (config) {
|
|
23
|
+
config.addPublicationTransformers({
|
|
24
|
+
renderComponent(component, toHtml) {
|
|
25
|
+
if (component.get('type') === 'custom-code' && component.get('custom-code-plugin__code')) {
|
|
26
|
+
return component.get('custom-code-plugin__code')
|
|
27
|
+
}
|
|
28
|
+
return toHtml()
|
|
29
|
+
},
|
|
30
|
+
})
|
|
24
31
|
}
|
|
25
|
-
//# sourceMappingURL=utils.js.map
|
|
@@ -14,18 +14,23 @@
|
|
|
14
14
|
* You should have received a copy of the GNU Affero General Public License
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
|
|
18
|
+
import { ClientSideFile, ClientSideFileType, ClientSideFileWithContent } from '../types'
|
|
19
|
+
import { cmdGetHtml } from '@silexlabs/grapesjs-fonts'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @fileoverview Make sure custom script blocks include script tags when published
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export default async function (config) {
|
|
26
|
+
config.addPublicationTransformers({
|
|
27
|
+
transformFile(file: ClientSideFile): ClientSideFile {
|
|
28
|
+
const fileWithContent = file as ClientSideFileWithContent
|
|
29
|
+
if(fileWithContent.type === ClientSideFileType.HTML && fileWithContent.content) {
|
|
30
|
+
const htmlLinks = config.getEditor().runCommand(cmdGetHtml)
|
|
31
|
+
fileWithContent.content = fileWithContent.content.replace(/<\/head>/, `${htmlLinks}</head>`)
|
|
32
|
+
}
|
|
33
|
+
return file
|
|
34
|
+
},
|
|
35
|
+
})
|
|
30
36
|
}
|
|
31
|
-
//# sourceMappingURL=page.js.map
|
package/src/ts/client/utils.ts
CHANGED
|
@@ -26,3 +26,21 @@ export function onAll(editor: Editor, cbk: (c: Component) => void) {
|
|
|
26
26
|
.onAll(c => cbk(c))
|
|
27
27
|
})
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* SHA256 hash a string
|
|
32
|
+
*/
|
|
33
|
+
export async function hashString(str: string): Promise<string> {
|
|
34
|
+
// Convert the string to an ArrayBuffer
|
|
35
|
+
const encoder = new TextEncoder()
|
|
36
|
+
const data = encoder.encode(str)
|
|
37
|
+
|
|
38
|
+
// Hash the data with SHA-256
|
|
39
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
|
40
|
+
|
|
41
|
+
// Convert the ArrayBuffer to hex string
|
|
42
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
43
|
+
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
44
|
+
|
|
45
|
+
return hashHex
|
|
46
|
+
}
|
package/src/ts/constants.ts
CHANGED
|
@@ -45,6 +45,7 @@ export const API_WEBSITE_READ = '/'
|
|
|
45
45
|
export const API_WEBSITE_WRITE = '/'
|
|
46
46
|
export const API_WEBSITE_CREATE = '/'
|
|
47
47
|
export const API_WEBSITE_DELETE = '/'
|
|
48
|
+
export const API_WEBSITE_DUPLICATE = '/duplicate'
|
|
48
49
|
export const API_WEBSITE_LIST = '/'
|
|
49
50
|
export const API_WEBSITE_ASSET_READ = '/assets'
|
|
50
51
|
export const API_WEBSITE_ASSETS_WRITE = '/assets'
|
|
@@ -33,9 +33,43 @@ const pluginName = 'template'
|
|
|
33
33
|
const templateType = 'templateType'
|
|
34
34
|
const templateKey = 'template'
|
|
35
35
|
|
|
36
|
+
function createCodeEditor(editor, mode = 'htmlmixed', singleLine = false) {
|
|
37
|
+
const options = {
|
|
38
|
+
readOnly: false,
|
|
39
|
+
codeName: mode,
|
|
40
|
+
} as any
|
|
41
|
+
if(singleLine) {
|
|
42
|
+
options.lineWrapping = false
|
|
43
|
+
options.lineNumbers = false
|
|
44
|
+
options.indentWithTabs = false
|
|
45
|
+
} else {
|
|
46
|
+
options.lineNumbers = true
|
|
47
|
+
options.lineWrapping = true
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return editor.CodeManager.createViewer(options)
|
|
51
|
+
}
|
|
52
|
+
|
|
36
53
|
export default async (config, opts: any = {}) => {
|
|
37
54
|
config.on(ClientEvent.GRAPESJS_END, () => {
|
|
38
55
|
const editor = silex.getEditor()
|
|
56
|
+
// Get the necessary code editors
|
|
57
|
+
const editors = {
|
|
58
|
+
before: createCodeEditor(editor),
|
|
59
|
+
replace: createCodeEditor(editor),
|
|
60
|
+
after: createCodeEditor(editor),
|
|
61
|
+
attributes: createCodeEditor(editor, 'text', true),
|
|
62
|
+
classname: createCodeEditor(editor, 'text', true),
|
|
63
|
+
style: createCodeEditor(editor, 'css', true),
|
|
64
|
+
}
|
|
65
|
+
const is1line = {
|
|
66
|
+
before: false,
|
|
67
|
+
replace: false,
|
|
68
|
+
after: false,
|
|
69
|
+
attributes: true,
|
|
70
|
+
classname: true,
|
|
71
|
+
style: true,
|
|
72
|
+
}
|
|
39
73
|
// Add the new trait to all component types
|
|
40
74
|
editor.DomComponents.getTypes().map(type => {
|
|
41
75
|
const originalType = editor.DomComponents.getType(type.id)
|
|
@@ -60,7 +94,7 @@ export default async (config, opts: any = {}) => {
|
|
|
60
94
|
function doRender(el) {
|
|
61
95
|
const template = editor.getSelected()?.get(templateKey) || {}
|
|
62
96
|
const taStyle = opts.styles?.textarea ?? styleMap({
|
|
63
|
-
|
|
97
|
+
xxbackgroundColor: 'var(--darkerPrimaryColor)',
|
|
64
98
|
})
|
|
65
99
|
const sepStyle = opts.styles?.sep ?? styleMap({ height: '10px' })
|
|
66
100
|
const labels = {
|
|
@@ -72,31 +106,61 @@ export default async (config, opts: any = {}) => {
|
|
|
72
106
|
style: html`CSS styles`,
|
|
73
107
|
}
|
|
74
108
|
render(html`
|
|
109
|
+
<style>
|
|
110
|
+
.CodeMirror {
|
|
111
|
+
height: 100%;
|
|
112
|
+
}
|
|
113
|
+
</style>
|
|
75
114
|
<div>
|
|
76
115
|
<h3>Template</h3>
|
|
77
116
|
<p>This will be inserted in the published version</p>
|
|
78
117
|
</div>
|
|
79
|
-
${[
|
|
80
|
-
|
|
118
|
+
${[
|
|
119
|
+
'classname',
|
|
120
|
+
'attributes',
|
|
121
|
+
'style',
|
|
122
|
+
'before',
|
|
123
|
+
'replace',
|
|
124
|
+
'after',
|
|
125
|
+
].map(id => html`
|
|
126
|
+
<label data-contain="${id}" class="template-wrapper-${id}">
|
|
81
127
|
${labels[id]}
|
|
82
|
-
<input
|
|
83
|
-
id="template-${id}"
|
|
84
|
-
.value=${template[id] || ''}
|
|
85
|
-
style=${taStyle}
|
|
86
|
-
/>
|
|
87
128
|
</label>
|
|
88
129
|
`)}
|
|
89
|
-
${['before', 'replace', 'after'].map(id => html`
|
|
90
|
-
<label
|
|
91
|
-
for="template-${id}"
|
|
92
|
-
>${labels[id]}</label>
|
|
93
|
-
<textarea
|
|
94
|
-
id="template-${id}"
|
|
95
|
-
style=${taStyle}
|
|
96
|
-
.value=${template[id] || ''}
|
|
97
|
-
></textarea>
|
|
98
|
-
`)}
|
|
99
130
|
`, el)
|
|
131
|
+
el.querySelectorAll('[data-contain]').forEach(container => {
|
|
132
|
+
const id = container.getAttribute('data-contain')
|
|
133
|
+
const codeEditor = editors[id]
|
|
134
|
+
container.appendChild(codeEditor.getElement())
|
|
135
|
+
codeEditor.getElement().style.display = 'block'
|
|
136
|
+
codeEditor.getElement().style.height = is1line[id] ? '' : '200px'
|
|
137
|
+
codeEditor.getElement().style.width = '100%'
|
|
138
|
+
codeEditor.setContent(template[id] ?? '')
|
|
139
|
+
codeEditor.refresh()
|
|
140
|
+
})
|
|
141
|
+
// Make sure we apply the changes when the user presses any key
|
|
142
|
+
// The events should be triggered by the trait manager (call onEvent) but it doesn't work for "delete" key for example
|
|
143
|
+
el.onkeyup = () => {
|
|
144
|
+
applyChanges(editor.getSelected())
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function applyChanges(component) {
|
|
149
|
+
const template = {
|
|
150
|
+
before: editors.before.getContent(),
|
|
151
|
+
replace: editors.replace.getContent(),
|
|
152
|
+
after: editors.after.getContent(),
|
|
153
|
+
attributes: editors.attributes.getContent(),
|
|
154
|
+
classname: editors.classname.getContent(),
|
|
155
|
+
style: editors.style.getContent(),
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Store the new template
|
|
159
|
+
if (Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) {
|
|
160
|
+
component.set(templateKey, template)
|
|
161
|
+
} else {
|
|
162
|
+
component.set(templateKey)
|
|
163
|
+
}
|
|
100
164
|
}
|
|
101
165
|
|
|
102
166
|
editor.TraitManager.addType(templateType, {
|
|
@@ -113,21 +177,7 @@ export default async (config, opts: any = {}) => {
|
|
|
113
177
|
// Update the component based on UI changes
|
|
114
178
|
// `elInput` is the result HTMLElement you get from `createInput`
|
|
115
179
|
onEvent({ elInput, component, event }) {
|
|
116
|
-
|
|
117
|
-
before: elInput.querySelector('#template-before').value,
|
|
118
|
-
replace: elInput.querySelector('#template-replace').value,
|
|
119
|
-
after: elInput.querySelector('#template-after').value,
|
|
120
|
-
attributes: elInput.querySelector('#template-attributes').value,
|
|
121
|
-
classname: elInput.querySelector('#template-classname').value,
|
|
122
|
-
style: elInput.querySelector('#template-style').value,
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Store the new template
|
|
126
|
-
if (Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) {
|
|
127
|
-
component.set(templateKey, template)
|
|
128
|
-
} else {
|
|
129
|
-
component.set(templateKey)
|
|
130
|
-
}
|
|
180
|
+
applyChanges(component)
|
|
131
181
|
},
|
|
132
182
|
// Update UI on the component change
|
|
133
183
|
onUpdate({ elInput, component }) {
|
|
@@ -154,39 +204,41 @@ export default async (config, opts: any = {}) => {
|
|
|
154
204
|
// put back together
|
|
155
205
|
.join('\n')
|
|
156
206
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
207
|
+
if (opts.publication !== false) {
|
|
208
|
+
editor.on(ClientEvent.PUBLISH_START, () => {
|
|
209
|
+
// Insert templates
|
|
210
|
+
onAll(editor, c => {
|
|
211
|
+
const template = c.get(templateKey)
|
|
212
|
+
const toHTML = c.toHTML
|
|
213
|
+
const classes = c.getClasses()
|
|
214
|
+
const before = cleanup(template?.before || '')
|
|
215
|
+
const replace = cleanup(template?.replace || '')
|
|
216
|
+
const after = cleanup(template?.after || '')
|
|
217
|
+
const classname = cleanup(template?.classname || '')
|
|
218
|
+
const style = cleanup(template?.style || '')
|
|
219
|
+
const attributes = cleanup(template?.attributes || '')
|
|
220
|
+
// Store the initial method
|
|
221
|
+
if (!c.has('tmpHtml')) c.set('tmpHtml', toHTML)
|
|
222
|
+
// Override the method
|
|
223
|
+
c.toHTML = () => {
|
|
224
|
+
return `${before
|
|
225
|
+
}${c.get('tagName') ? `<${c.get('tagName')}
|
|
175
226
|
${Object.entries(c.get('attributes') as object).map(([key, value]) => makeAttribute(key, value)).join(' ')}
|
|
176
227
|
${classes.length || classname ? `class="${classes.join(' ')} ${classname}"` : ''}
|
|
177
228
|
${attributes}
|
|
178
229
|
${style ? `style="${style}"` : ''}
|
|
179
230
|
>` : ''}${replace || c.getInnerHTML()
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
231
|
+
}${c.get('tagName') ? `</${c.get('tagName')}>` : ''}${after
|
|
232
|
+
}`
|
|
233
|
+
}
|
|
234
|
+
})
|
|
183
235
|
})
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
236
|
+
editor.on(ClientEvent.PUBLISH_END, () => {
|
|
237
|
+
onAll(editor, c => {
|
|
238
|
+
// Restore the original method
|
|
239
|
+
c.toHTML = c.get('tmpHtml')
|
|
240
|
+
})
|
|
189
241
|
})
|
|
190
|
-
}
|
|
242
|
+
}
|
|
191
243
|
})
|
|
192
244
|
}
|
|
@@ -23,9 +23,10 @@ import { WEBSITE_DATA_FILE, WEBSITE_META_DATA_FILE } from '../../constants'
|
|
|
23
23
|
import { ConnectorType, ConnectorUser, WebsiteMeta, FileMeta, JobData, JobStatus, WebsiteId, PublicationJobData, WebsiteMetaFileContent, defaultWebsiteData, WebsiteData, ConnectorOptions } from '../../types'
|
|
24
24
|
import { ServerConfig } from '../../server/config'
|
|
25
25
|
import { join } from 'path'
|
|
26
|
-
import {
|
|
26
|
+
import { tmpdir } from 'os'
|
|
27
27
|
import { v4 as uuid } from 'uuid'
|
|
28
28
|
import { JobManager } from '../../server/jobs'
|
|
29
|
+
import { mkdtemp } from 'fs/promises'
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* @fileoverview FTP connector for Silex
|
|
@@ -338,7 +339,6 @@ export default class FtpConnector implements StorageConnector<FtpSession> {
|
|
|
338
339
|
|
|
339
340
|
async getLoginForm(session: FtpSession, redirectTo: string): Promise<string | null> {
|
|
340
341
|
const { host, user, pass, port, secure, publicationPath, storageRootPath, websiteUrl } = this.sessionData(session)
|
|
341
|
-
requiredParam(type, 'connector type')
|
|
342
342
|
return `
|
|
343
343
|
<style>
|
|
344
344
|
${formCss}
|
|
@@ -491,6 +491,18 @@ export default class FtpConnector implements StorageConnector<FtpSession> {
|
|
|
491
491
|
this.closeClient(ftp)
|
|
492
492
|
}
|
|
493
493
|
|
|
494
|
+
async duplicateWebsite(session: FtpSession, websiteId: string): Promise<void> {
|
|
495
|
+
const newWebsiteId = uuid()
|
|
496
|
+
const storageRootPath = this.rootPath(session)
|
|
497
|
+
const ftp = await this.getClient(this.sessionData(session))
|
|
498
|
+
const websitePath = join(storageRootPath, websiteId)
|
|
499
|
+
const newWebsitePath = join(storageRootPath, newWebsiteId)
|
|
500
|
+
const tempDir = await mkdtemp(tmpdir())
|
|
501
|
+
await ftp.downloadToDir(websitePath, tempDir)
|
|
502
|
+
await ftp.uploadFromDir(tempDir, newWebsitePath)
|
|
503
|
+
this.closeClient(ftp)
|
|
504
|
+
}
|
|
505
|
+
|
|
494
506
|
async writeAssets(
|
|
495
507
|
session: any,
|
|
496
508
|
id: WebsiteId,
|