@silexlabs/silex 3.0.1-0 → 3.0.1
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 +3 -2
- package/.silex.js +39 -1
- package/README.md +37 -35
- package/dist/client/client/api.d.ts +8 -1
- package/dist/client/client/assetUrl.d.ts +54 -0
- package/dist/client/client/config.d.ts +60 -1
- package/dist/client/client/events.d.ts +19 -10
- package/dist/client/client/grapesjs/PublicationManager.d.ts +6 -8
- package/dist/client/client/grapesjs/PublicationUi.d.ts +8 -10
- package/dist/client/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/client/grapesjs/img.d.ts +6 -0
- package/dist/client/client/grapesjs/index.d.ts +6 -2
- package/dist/client/client/grapesjs/internal-links.d.ts +1 -1
- package/dist/client/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/client/grapesjs/new-page-dialog.d.ts +1 -1
- package/dist/client/client/grapesjs/page-panel.d.ts +7 -1
- package/dist/client/client/grapesjs/project-bar.d.ts +20 -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 +16 -0
- package/dist/client/client/grapesjs/settings.d.ts +3 -1
- package/dist/client/client/grapesjs/storage.d.ts +1 -0
- 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 +5 -0
- package/dist/client/client/publication-transformers.d.ts +42 -0
- 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 +22 -1
- package/dist/client/constants.d.ts +3 -0
- package/dist/client/css/admin.css +1107 -411
- package/dist/client/css/admin.css.map +1 -0
- package/dist/client/grapesjs-filter-styles/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/src/commands.d.ts +3 -0
- package/dist/client/grapesjs-fonts/src/fonts.d.ts +4 -0
- package/dist/client/grapesjs-storage-rate-limit/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-ui-suggest-classes/dist/index.d.ts +4 -0
- package/dist/client/index.html +3 -2
- package/dist/client/js/main.js +305 -170
- package/dist/client/js/main.js.LICENSE.txt +21 -1
- package/dist/client/page.d.ts +1 -1
- package/dist/client/silex-lib/src/ts/client/api.d.ts +90 -0
- package/dist/client/silex-lib/src/ts/client/assetUrl.d.ts +54 -0
- package/dist/client/silex-lib/src/ts/client/config.d.ts +102 -0
- package/dist/client/silex-lib/src/ts/client/events.d.ts +23 -0
- package/dist/client/silex-lib/src/ts/client/expose.d.ts +8 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationManager.d.ts +73 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationUi.d.ts +59 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/blocks.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/img.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/index.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/openImport.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/page-panel.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/project-bar.d.ts +21 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/rich-text.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/semantic.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings-sections.d.ts +16 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/storage.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/index.d.ts +10 -0
- package/dist/client/silex-lib/src/ts/client/publication-transformers.d.ts +42 -0
- package/dist/client/silex-lib/src/ts/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/publish-fonts.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/utils.d.ts +22 -0
- package/dist/client/silex-lib/src/ts/constants.d.ts +32 -0
- package/dist/client/silex-lib/src/ts/page.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/types.d.ts +339 -0
- package/dist/client/types.d.ts +59 -35
- package/dist/plugins/client/client/events.d.ts +19 -10
- package/dist/plugins/client/client/events.js +11 -0
- package/dist/plugins/client/client/events.js.map +1 -1
- package/dist/plugins/client/plugins/client/template.js +119 -71
- package/dist/plugins/client/plugins/client/template.js.map +1 -1
- package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
- package/dist/plugins/client/plugins/client/website-info.js +72 -0
- package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
- package/dist/plugins/client/types.d.ts +59 -35
- package/dist/plugins/client/types.js +23 -0
- package/dist/plugins/client/types.js.map +1 -1
- package/dist/plugins/server/constants.d.ts +3 -0
- package/dist/plugins/server/constants.js +28 -1
- package/dist/plugins/server/constants.js.map +1 -1
- package/dist/plugins/server/plugins/server/Cache.js +9 -5
- package/dist/plugins/server/plugins/server/Cache.js.map +1 -1
- package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js +127 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/FtpConnector.d.ts +5 -2
- package/dist/plugins/server/plugins/server/FtpConnector.js +38 -23
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
- package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +63 -9
- package/dist/plugins/server/plugins/server/GitlabConnector.js +367 -91
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.d.ts +16 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js +209 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/SslPlugin.js +6 -6
- package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -1
- package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +8 -1
- package/dist/plugins/server/plugins/server/StaticPlugin.js +5 -31
- package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -1
- package/dist/plugins/server/server/config.js +8 -9
- package/dist/plugins/server/server/config.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsHosting.d.ts +3 -2
- package/dist/plugins/server/server/connectors/FsHosting.js +18 -7
- package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -1
- package/dist/plugins/server/server/connectors/FsStorage.d.ts +3 -1
- package/dist/plugins/server/server/connectors/FsStorage.js +35 -28
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
- package/dist/plugins/server/server/connectors/connectors.d.ts +7 -7
- package/dist/plugins/server/server/connectors/connectors.js +6 -7
- package/dist/plugins/server/server/connectors/connectors.js.map +1 -1
- package/dist/plugins/server/server/events.js +16 -0
- package/dist/plugins/server/server/events.js.map +1 -1
- package/dist/plugins/server/server/jobs.d.ts +6 -0
- package/dist/plugins/server/server/jobs.js +12 -8
- package/dist/plugins/server/server/jobs.js.map +1 -1
- package/dist/plugins/server/server/utils/validation.js +1 -2
- package/dist/plugins/server/server/utils/validation.js.map +1 -1
- package/dist/plugins/server/types.d.ts +59 -35
- package/dist/plugins/server/types.js +24 -1
- package/dist/plugins/server/types.js.map +1 -1
- package/dist/server/constants.js +27 -1
- package/dist/server/plugins/server/Cache.js +9 -5
- package/dist/server/server/api/api.js +1 -1
- package/dist/server/server/api/connectorApi.js +154 -25
- package/dist/server/server/api/publicationApi.js +17 -25
- package/dist/server/server/api/websiteApi.js +30 -8
- package/dist/server/server/cli.js +9 -6
- package/dist/server/server/config.js +8 -9
- package/dist/server/server/connectors/FsHosting.js +17 -7
- package/dist/server/server/connectors/FsStorage.js +34 -28
- package/dist/server/server/connectors/connectors.js +6 -7
- package/dist/server/server/express.js +4 -5
- package/dist/server/server/index.js +5 -1
- package/dist/server/server/jobs.js +11 -8
- package/dist/server/server/utils/validation.js +1 -2
- package/dist/server/types.js +13 -1
- package/package.json +56 -42
- package/public/assets/download.png +0 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/favicon.png +0 -0
- package/public/assets/ftp.png +0 -0
- package/public/assets/gitlab.png +0 -0
- package/public/assets/gitlab2.png +0 -0
- package/public/assets/laptop.png +0 -0
- package/public/assets/logo-silex-small.png +0 -0
- package/public/silex.js +5 -23
- package/src/css/_variables.scss +23 -20
- package/src/css/dialog.scss +27 -1
- package/src/css/fonts.scss +31 -0
- package/src/css/footer.scss +12 -0
- package/src/css/grapesjs-light.scss +180 -0
- package/src/css/grapesjs-plugins.scss +227 -0
- package/src/css/grapesjs.scss +84 -10
- package/src/css/index.scss +12 -1
- package/src/css/light.scss +7 -0
- package/src/css/project-bar.scss +32 -16
- package/src/css/silex.scss +79 -5
- package/src/css/website-info.scss +14 -0
- package/src/html/index.pug +3 -3
- package/src/ts/client/api.ts +38 -14
- package/src/ts/client/assetUrl.test.ts +164 -0
- package/src/ts/client/assetUrl.ts +254 -0
- package/src/ts/client/config.ts +133 -5
- package/src/ts/client/events.ts +21 -9
- package/src/ts/client/grapesjs/LoginDialog.ts +4 -2
- package/src/ts/client/grapesjs/PublicationManager.ts +180 -54
- package/src/ts/client/grapesjs/PublicationUi.ts +122 -86
- package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
- package/src/ts/client/grapesjs/css-props.ts +910 -0
- package/src/ts/client/grapesjs/eleventy.ts +11 -8
- package/{dist/plugins/client/page.js → src/ts/client/grapesjs/footer.ts} +24 -13
- package/src/ts/client/grapesjs/img.ts +147 -0
- package/src/ts/client/grapesjs/index.ts +234 -52
- package/src/ts/client/grapesjs/internal-links.test.ts +2 -1
- package/src/ts/client/grapesjs/internal-links.ts +14 -7
- package/src/ts/client/grapesjs/keymaps.ts +207 -0
- package/src/ts/client/grapesjs/new-page-dialog.ts +2 -3
- package/src/ts/client/grapesjs/page-panel.ts +92 -7
- package/src/ts/client/grapesjs/project-bar.ts +116 -72
- 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 +174 -96
- package/src/ts/client/grapesjs/storage.ts +98 -33
- package/src/ts/client/grapesjs/symbolDialogs.ts +3 -4
- package/src/ts/{plugins/server/AuthPlugin.ts → client/grapesjs/view-buttons.ts} +23 -19
- package/src/ts/client/index.ts +35 -16
- package/src/ts/client/publication-transformers.test.ts +207 -0
- package/src/ts/client/publication-transformers.ts +280 -0
- package/{dist/plugins/client/client/utils.js → src/ts/client/publish-custom-code-block.ts} +14 -8
- package/src/ts/client/publish-fonts.ts +36 -0
- package/src/ts/client/utils.ts +53 -1
- package/src/ts/constants.ts +31 -0
- package/src/ts/page.ts +2 -2
- package/src/ts/plugins/client/template.ts +125 -75
- package/src/ts/plugins/client/website-info.ts +84 -0
- package/src/ts/plugins/server/Cache.ts +6 -2
- package/src/ts/plugins/server/DownloadConnector.ts +146 -0
- package/src/ts/plugins/server/FtpConnector.ts +47 -21
- package/src/ts/plugins/server/GitlabConnector.ts +423 -108
- package/src/ts/plugins/server/GitlabHostingConnector.ts +215 -0
- package/src/ts/plugins/server/SslPlugin.ts +5 -5
- package/src/ts/plugins/server/StaticPlugin.ts +3 -30
- package/src/ts/server/api/connectorApi.ts +165 -28
- package/src/ts/server/api/publicationApi.ts +17 -24
- package/src/ts/server/api/websiteApi.ts +57 -14
- package/src/ts/server/cli.ts +7 -5
- package/src/ts/server/config.ts +9 -10
- package/src/ts/server/connectors/FsHosting.ts +14 -8
- package/src/ts/server/connectors/FsStorage.ts +40 -7
- package/src/ts/server/connectors/connectors.ts +8 -6
- package/src/ts/server/events.ts +17 -0
- package/src/ts/server/express.ts +2 -2
- package/src/ts/server/index.ts +6 -0
- package/src/ts/server/jobs.ts +14 -2
- package/src/ts/server/utils/BackwardCompat.ts +530 -529
- package/src/ts/types.ts +78 -34
- package/dist/plugins/client/client/utils.d.ts +0 -1
- package/dist/plugins/client/client/utils.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/publicationRenderer.d.ts +0 -2
- package/dist/plugins/client/plugins/client/publicationRenderer.js +0 -128
- package/dist/plugins/client/plugins/client/publicationRenderer.js.map +0 -1
- package/dist/plugins/server/plugins/server/AuthPlugin.d.ts +0 -1
- package/dist/plugins/server/plugins/server/AuthPlugin.js +0 -38
- package/dist/plugins/server/plugins/server/AuthPlugin.js.map +0 -1
- package/dist/plugins/server/plugins/server/HooksPlugin.d.ts +0 -7
- package/dist/plugins/server/plugins/server/HooksPlugin.js +0 -74
- package/dist/plugins/server/plugins/server/HooksPlugin.js.map +0 -1
- package/src/example-client-config.js +0 -64
- package/src/ts/plugins/client/publicationRenderer.ts +0 -128
- package/src/ts/plugins/server/HooksPlugin.ts +0 -76
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { ClientSideFile, ClientSideFileType, ClientSideFileWithContent } from '../types'
|
|
19
|
+
import { cmdGetHtml } from '@silexlabs/grapesjs-fonts/src/commands'
|
|
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
|
+
})
|
|
36
|
+
}
|
package/src/ts/client/utils.ts
CHANGED
|
@@ -15,12 +15,64 @@
|
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { Component, Editor } from 'grapesjs'
|
|
18
19
|
|
|
19
20
|
// Browse all elements of all pages
|
|
20
|
-
export function onAll(editor, cbk) {
|
|
21
|
+
export function onAll(editor: Editor, cbk: (c: Component) => void) {
|
|
21
22
|
editor.Pages.getAll()
|
|
22
23
|
.forEach(page => {
|
|
23
24
|
page.getMainComponent()
|
|
24
25
|
.onAll(c => cbk(c))
|
|
25
26
|
})
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* SHA256 hash a string
|
|
31
|
+
*/
|
|
32
|
+
export async function hashString(str: string): Promise<string> {
|
|
33
|
+
if (crypto.subtle != undefined) {
|
|
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
|
+
}
|
|
47
|
+
else {return 'local'}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Select the <body> element in the editor.
|
|
52
|
+
* @param editor The GrapesJS editor.
|
|
53
|
+
*/
|
|
54
|
+
export function selectBody(editor: Editor): void {
|
|
55
|
+
editor.select(editor.DomComponents.getWrapper())
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Checks if an element is a text or input field.
|
|
60
|
+
* @param element The element to check.
|
|
61
|
+
*/
|
|
62
|
+
export function isTextOrInputField(element: HTMLElement): boolean {
|
|
63
|
+
if(element.getAttribute('type') === 'submit') return false
|
|
64
|
+
const isInput: boolean = element.tagName === 'INPUT'
|
|
65
|
+
const isOtherFormElement: boolean = ['TEXTAREA', 'OPTION', 'OPTGROUP', 'SELECT', 'BUTTON'].includes(element.tagName)
|
|
66
|
+
|
|
67
|
+
return isInput || isOtherFormElement
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Makes every word in a string start with an uppercase letter.
|
|
72
|
+
* @param str The string to title-case.
|
|
73
|
+
* @param sep The separator between words.
|
|
74
|
+
*/
|
|
75
|
+
export function titleCase(str: string, sep: string = ' '): string {
|
|
76
|
+
const split = str.split(sep)
|
|
77
|
+
return split.map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(sep)
|
|
78
|
+
}
|
package/src/ts/constants.ts
CHANGED
|
@@ -45,8 +45,39 @@ 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'
|
|
51
52
|
export const API_WEBSITE_META_READ = '/meta'
|
|
52
53
|
export const API_WEBSITE_META_WRITE = '/meta'
|
|
54
|
+
|
|
55
|
+
// Env vars (build time)
|
|
56
|
+
// Get env vars from webpack
|
|
57
|
+
// @see webpack.config.js
|
|
58
|
+
declare const SILEX_VERSION_ENV: string
|
|
59
|
+
export let SILEX_VERSION
|
|
60
|
+
try { SILEX_VERSION = SILEX_VERSION_ENV } catch (e) {
|
|
61
|
+
// fallback to default value
|
|
62
|
+
SILEX_VERSION = SILEX_VERSION || '3.0.0'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const DEV_MESSAGE = `
|
|
66
|
+
__________________________________________________________
|
|
67
|
+
|
|
68
|
+
Create static websites visually, with dynamic content,
|
|
69
|
+
in the free spirit of the web.
|
|
70
|
+
|
|
71
|
+
███████ ██ ██ ███████ ██ ██ ██ ██ ██████
|
|
72
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
73
|
+
███████ ██ ██ █████ ███ ██ ██ █████
|
|
74
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
75
|
+
███████ ██ ███████ ███████ ██ ██ ████ ██████ ${SILEX_VERSION.slice(1)}
|
|
76
|
+
|
|
77
|
+
Users are expected to contribute:
|
|
78
|
+
|
|
79
|
+
* Web designers: https://docs.silex.me/en/user/contribute
|
|
80
|
+
* Developers: https://docs.silex.me/en/dev/contribute
|
|
81
|
+
|
|
82
|
+
__________________________________________________________
|
|
83
|
+
`
|
package/src/ts/page.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// Page related functions
|
|
19
19
|
// This is used on the client and the server
|
|
20
20
|
export function getPageSlug(pageName) {
|
|
21
|
-
return pageName
|
|
21
|
+
return (pageName || 'index')
|
|
22
22
|
.toLowerCase()
|
|
23
23
|
.replace(/[^a-z0-9 -]/g, '')
|
|
24
24
|
// Collapse whitespace and replace by -
|
|
@@ -26,6 +26,6 @@ export function getPageSlug(pageName) {
|
|
|
26
26
|
// Collapse dashes
|
|
27
27
|
.replace(/-+/g, '-')
|
|
28
28
|
}
|
|
29
|
-
export function getPageLink(pageName
|
|
29
|
+
export function getPageLink(pageName) {
|
|
30
30
|
return `./${getPageSlug(pageName)}.html`
|
|
31
31
|
}
|
|
@@ -15,16 +15,19 @@
|
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
//import {styleMap} from 'lit-html/directives/style-map.js'
|
|
20
|
-
//import { onAll } from '@silexlabs/silex/dist/client/utils.js'
|
|
21
|
-
import { onAll } from '../../client/utils.js'
|
|
22
|
-
import { ClientEvent } from '../../client/events.js'
|
|
18
|
+
throw new Error('This file is obsolete, templates have been replaced by Silex CMS plugin: https://github.com/silexlabs/silex-cms/')
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
//
|
|
20
|
+
// Silex serves /clients
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
import { onAll } from '../client/utils.js'
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
import { ClientEvent } from '../client/events.js'
|
|
25
|
+
|
|
26
|
+
// You need to serve lit-html at /js/lit-html/
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
import {html, render} from '../js/lit-html/lit-html.js'
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
import {styleMap} from '../js/lit-html/directives/style-map.js'
|
|
28
31
|
|
|
29
32
|
const silex = window['silex']
|
|
30
33
|
|
|
@@ -32,14 +35,43 @@ const pluginName = 'template'
|
|
|
32
35
|
const templateType = 'templateType'
|
|
33
36
|
const templateKey = 'template'
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
function createCodeEditor(editor, mode = 'htmlmixed', singleLine = false) {
|
|
39
|
+
const options = {
|
|
40
|
+
readOnly: false,
|
|
41
|
+
codeName: mode,
|
|
42
|
+
} as any
|
|
43
|
+
if(singleLine) {
|
|
44
|
+
options.lineWrapping = false
|
|
45
|
+
options.lineNumbers = false
|
|
46
|
+
options.indentWithTabs = false
|
|
47
|
+
} else {
|
|
48
|
+
options.lineNumbers = true
|
|
49
|
+
options.lineWrapping = true
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return editor.CodeManager.createViewer(options)
|
|
53
|
+
}
|
|
40
54
|
|
|
55
|
+
export default async (config, opts: any = {}) => {
|
|
41
56
|
config.on(ClientEvent.GRAPESJS_END, () => {
|
|
42
57
|
const editor = silex.getEditor()
|
|
58
|
+
// Get the necessary code editors
|
|
59
|
+
const editors = {
|
|
60
|
+
before: createCodeEditor(editor),
|
|
61
|
+
replace: createCodeEditor(editor),
|
|
62
|
+
after: createCodeEditor(editor),
|
|
63
|
+
attributes: createCodeEditor(editor, 'text', true),
|
|
64
|
+
classname: createCodeEditor(editor, 'text', true),
|
|
65
|
+
style: createCodeEditor(editor, 'css', true),
|
|
66
|
+
}
|
|
67
|
+
const is1line = {
|
|
68
|
+
before: false,
|
|
69
|
+
replace: false,
|
|
70
|
+
after: false,
|
|
71
|
+
attributes: true,
|
|
72
|
+
classname: true,
|
|
73
|
+
style: true,
|
|
74
|
+
}
|
|
43
75
|
// Add the new trait to all component types
|
|
44
76
|
editor.DomComponents.getTypes().map(type => {
|
|
45
77
|
const originalType = editor.DomComponents.getType(type.id)
|
|
@@ -64,7 +96,7 @@ export default async (config, opts: any = {}) => {
|
|
|
64
96
|
function doRender(el) {
|
|
65
97
|
const template = editor.getSelected()?.get(templateKey) || {}
|
|
66
98
|
const taStyle = opts.styles?.textarea ?? styleMap({
|
|
67
|
-
|
|
99
|
+
xxbackgroundColor: 'var(--darkerPrimaryColor)',
|
|
68
100
|
})
|
|
69
101
|
const sepStyle = opts.styles?.sep ?? styleMap({ height: '10px' })
|
|
70
102
|
const labels = {
|
|
@@ -76,31 +108,61 @@ export default async (config, opts: any = {}) => {
|
|
|
76
108
|
style: html`CSS styles`,
|
|
77
109
|
}
|
|
78
110
|
render(html`
|
|
111
|
+
<style>
|
|
112
|
+
.CodeMirror {
|
|
113
|
+
height: 100%;
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
79
116
|
<div>
|
|
80
117
|
<h3>Template</h3>
|
|
81
118
|
<p>This will be inserted in the published version</p>
|
|
82
119
|
</div>
|
|
83
|
-
${[
|
|
84
|
-
|
|
120
|
+
${[
|
|
121
|
+
'classname',
|
|
122
|
+
'attributes',
|
|
123
|
+
'style',
|
|
124
|
+
'before',
|
|
125
|
+
'replace',
|
|
126
|
+
'after',
|
|
127
|
+
].map(id => html`
|
|
128
|
+
<label data-contain="${id}" class="template-wrapper-${id}">
|
|
85
129
|
${labels[id]}
|
|
86
|
-
<input
|
|
87
|
-
id="template-${id}"
|
|
88
|
-
.value=${template[id] || ''}
|
|
89
|
-
style=${taStyle}
|
|
90
|
-
/>
|
|
91
130
|
</label>
|
|
92
131
|
`)}
|
|
93
|
-
${['before', 'replace', 'after'].map(id => html`
|
|
94
|
-
<label
|
|
95
|
-
for="template-${id}"
|
|
96
|
-
>${labels[id]}</label>
|
|
97
|
-
<textarea
|
|
98
|
-
id="template-${id}"
|
|
99
|
-
style=${taStyle}
|
|
100
|
-
.value=${template[id] || ''}
|
|
101
|
-
></textarea>
|
|
102
|
-
`)}
|
|
103
132
|
`, el)
|
|
133
|
+
el.querySelectorAll('[data-contain]').forEach(container => {
|
|
134
|
+
const id = container.getAttribute('data-contain')
|
|
135
|
+
const codeEditor = editors[id]
|
|
136
|
+
container.appendChild(codeEditor.getElement())
|
|
137
|
+
codeEditor.getElement().style.display = 'block'
|
|
138
|
+
codeEditor.getElement().style.height = is1line[id] ? '' : '200px'
|
|
139
|
+
codeEditor.getElement().style.width = '100%'
|
|
140
|
+
codeEditor.setContent(template[id] ?? '')
|
|
141
|
+
codeEditor.refresh()
|
|
142
|
+
})
|
|
143
|
+
// Make sure we apply the changes when the user presses any key
|
|
144
|
+
// The events should be triggered by the trait manager (call onEvent) but it doesn't work for "delete" key for example
|
|
145
|
+
el.onkeyup = () => {
|
|
146
|
+
applyChanges(editor.getSelected())
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function applyChanges(component) {
|
|
151
|
+
const template = {
|
|
152
|
+
before: editors.before.getContent(),
|
|
153
|
+
replace: editors.replace.getContent(),
|
|
154
|
+
after: editors.after.getContent(),
|
|
155
|
+
attributes: editors.attributes.getContent(),
|
|
156
|
+
classname: editors.classname.getContent(),
|
|
157
|
+
style: editors.style.getContent(),
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Store the new template
|
|
161
|
+
if (Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) {
|
|
162
|
+
component.set(templateKey, template)
|
|
163
|
+
} else {
|
|
164
|
+
component.set(templateKey)
|
|
165
|
+
}
|
|
104
166
|
}
|
|
105
167
|
|
|
106
168
|
editor.TraitManager.addType(templateType, {
|
|
@@ -117,21 +179,7 @@ export default async (config, opts: any = {}) => {
|
|
|
117
179
|
// Update the component based on UI changes
|
|
118
180
|
// `elInput` is the result HTMLElement you get from `createInput`
|
|
119
181
|
onEvent({ elInput, component, event }) {
|
|
120
|
-
|
|
121
|
-
before: elInput.querySelector('#template-before').value,
|
|
122
|
-
replace: elInput.querySelector('#template-replace').value,
|
|
123
|
-
after: elInput.querySelector('#template-after').value,
|
|
124
|
-
attributes: elInput.querySelector('#template-attributes').value,
|
|
125
|
-
classname: elInput.querySelector('#template-classname').value,
|
|
126
|
-
style: elInput.querySelector('#template-style').value,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Store the new template
|
|
130
|
-
if (Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) {
|
|
131
|
-
component.set(templateKey, template)
|
|
132
|
-
} else {
|
|
133
|
-
component.set(templateKey)
|
|
134
|
-
}
|
|
182
|
+
applyChanges(component)
|
|
135
183
|
},
|
|
136
184
|
// Update UI on the component change
|
|
137
185
|
onUpdate({ elInput, component }) {
|
|
@@ -158,39 +206,41 @@ export default async (config, opts: any = {}) => {
|
|
|
158
206
|
// put back together
|
|
159
207
|
.join('\n')
|
|
160
208
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
${
|
|
209
|
+
if (opts.publication !== false) {
|
|
210
|
+
editor.on(ClientEvent.PUBLISH_START, () => {
|
|
211
|
+
// Insert templates
|
|
212
|
+
onAll(editor, c => {
|
|
213
|
+
const template = c.get(templateKey)
|
|
214
|
+
const toHTML = c.toHTML
|
|
215
|
+
const classes = c.getClasses()
|
|
216
|
+
const before = cleanup(template?.before || '')
|
|
217
|
+
const replace = cleanup(template?.replace || '')
|
|
218
|
+
const after = cleanup(template?.after || '')
|
|
219
|
+
const classname = cleanup(template?.classname || '')
|
|
220
|
+
const style = cleanup(template?.style || '')
|
|
221
|
+
const attributes = cleanup(template?.attributes || '')
|
|
222
|
+
// Store the initial method
|
|
223
|
+
if (!c.has('tmpHtml')) c.set('tmpHtml', toHTML)
|
|
224
|
+
// Override the method
|
|
225
|
+
c.toHTML = () => {
|
|
226
|
+
return `${before
|
|
227
|
+
}${c.get('tagName') ? `<${c.get('tagName')}
|
|
228
|
+
${Object.entries(c.get('attributes') as object).map(([key, value]) => makeAttribute(key, value)).join(' ')}
|
|
180
229
|
${classes.length || classname ? `class="${classes.join(' ')} ${classname}"` : ''}
|
|
181
230
|
${attributes}
|
|
182
231
|
${style ? `style="${style}"` : ''}
|
|
183
232
|
>` : ''}${replace || c.getInnerHTML()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
233
|
+
}${c.get('tagName') ? `</${c.get('tagName')}>` : ''}${after
|
|
234
|
+
}`
|
|
235
|
+
}
|
|
236
|
+
})
|
|
187
237
|
})
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
238
|
+
editor.on(ClientEvent.PUBLISH_END, () => {
|
|
239
|
+
onAll(editor, c => {
|
|
240
|
+
// Restore the original method
|
|
241
|
+
c.toHTML = c.get('tmpHtml')
|
|
242
|
+
})
|
|
193
243
|
})
|
|
194
|
-
}
|
|
244
|
+
}
|
|
195
245
|
})
|
|
196
246
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { ClientEvent } from '../../client/events.js'
|
|
19
|
+
import { WebsiteMeta } from '../../types.js'
|
|
20
|
+
|
|
21
|
+
interface WebsiteInfoOptions {
|
|
22
|
+
websiteId: string
|
|
23
|
+
connectorId: string
|
|
24
|
+
appendTo: 'commands' | 'options' | 'views' | 'project-bar-container' | 'project-bar-panel' | 'views-container'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Silex plugin
|
|
28
|
+
export default async function(config) {
|
|
29
|
+
let websiteMeta: WebsiteMeta | null = null
|
|
30
|
+
config.on(ClientEvent.GRAPESJS_START, async () => {
|
|
31
|
+
// GrapesJs plugin
|
|
32
|
+
const grapesPlugin = (editor, opts: Partial<WebsiteInfoOptions>) => {
|
|
33
|
+
const options = {
|
|
34
|
+
appendTo: 'commands',
|
|
35
|
+
...opts,
|
|
36
|
+
} as WebsiteInfoOptions
|
|
37
|
+
editor.on('storage:end:load', async () => {
|
|
38
|
+
// Get website meta data
|
|
39
|
+
const { websiteId, connectorId } = options
|
|
40
|
+
// Get the website meta data
|
|
41
|
+
websiteMeta = await config.api.websiteMetaRead({ websiteId, connectorId })
|
|
42
|
+
displayWebsiteMeta()
|
|
43
|
+
})
|
|
44
|
+
return {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Add the plugin to the GrapeJS
|
|
48
|
+
config.grapesJsConfig.plugins.push(grapesPlugin)
|
|
49
|
+
config.grapesJsConfig.pluginsOpts[grapesPlugin.toString()] = {
|
|
50
|
+
websiteId: config.websiteId,
|
|
51
|
+
connectorId: config.storageId,
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
config.on(ClientEvent.GRAPESJS_END, async ({editor}) => {
|
|
56
|
+
// Detect when the page changes
|
|
57
|
+
editor.on('page:select', async () => {
|
|
58
|
+
displayWebsiteMeta()
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
// Display the website meta data
|
|
64
|
+
function displayWebsiteMeta() {
|
|
65
|
+
// Get or create the container
|
|
66
|
+
const container = document.querySelector('#gjs-website-meta') ?? (function() {
|
|
67
|
+
const c = document.createElement('div')
|
|
68
|
+
c.id = 'gjs-website-meta'
|
|
69
|
+
c.classList.add('gjs-website-meta')
|
|
70
|
+
// Add the container to the UI
|
|
71
|
+
// Add the name of the website in the top bar
|
|
72
|
+
const topBar = document.querySelector('.gjs-pn-devices-c')
|
|
73
|
+
topBar?.appendChild(c)
|
|
74
|
+
return c
|
|
75
|
+
})()
|
|
76
|
+
// Get the current page
|
|
77
|
+
const currentPage = config.getEditor().Pages?.getSelected()
|
|
78
|
+
// Display the website meta data
|
|
79
|
+
container.innerHTML = `
|
|
80
|
+
${websiteMeta?.imageUrl ? `<div class="gjs-website-meta-image" style="background: url(${websiteMeta?.imageUrl});"></div>` : ''}
|
|
81
|
+
<div class="gjs-website-meta-name">${websiteMeta?.name ?? 'Unknown'} | ${currentPage.get('name') ?? currentPage.get('type')}</div>
|
|
82
|
+
`
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -23,6 +23,10 @@ export function noCache (req, res, next) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function withCache(req, res, next) {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if (req.url.endsWith('.html') || req.url.endsWith('/')) {
|
|
27
|
+
noCache(req, res, next)
|
|
28
|
+
} else {
|
|
29
|
+
res.header('Cache-Control', 'public,max-age=86400,immutable') // 24h
|
|
30
|
+
next()
|
|
31
|
+
}
|
|
28
32
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createWriteStream } from 'fs'
|
|
2
|
+
import archiver from 'archiver'
|
|
3
|
+
import { ConnectorOptions, ConnectorType, ConnectorUser, JobData, JobStatus, PublicationJobData, WebsiteId } from '../../types'
|
|
4
|
+
import { ConnectorFile, ConnectorSession, HostingConnector } from '../../server/connectors/connectors'
|
|
5
|
+
import { tmpdir } from 'os'
|
|
6
|
+
import { JobManager } from '../../server/jobs'
|
|
7
|
+
import { ServerConfig } from '../../server/config'
|
|
8
|
+
import { ServerEvent } from '../../server/events'
|
|
9
|
+
|
|
10
|
+
import { Request, Response } from 'express'
|
|
11
|
+
|
|
12
|
+
type DownloadConnectorSession = ConnectorSession;
|
|
13
|
+
|
|
14
|
+
type DownloadConnectorOptions = object
|
|
15
|
+
|
|
16
|
+
const ZIP_ICON = '/assets/download.png'
|
|
17
|
+
|
|
18
|
+
export default class implements HostingConnector<DownloadConnectorSession> {
|
|
19
|
+
connectorId = 'download-connector'
|
|
20
|
+
displayName = 'Download zip file'
|
|
21
|
+
icon = ZIP_ICON
|
|
22
|
+
disableLogout = false
|
|
23
|
+
options: DownloadConnectorOptions
|
|
24
|
+
connectorType = ConnectorType.HOSTING
|
|
25
|
+
color = '#ffffff'
|
|
26
|
+
background = '#006400'
|
|
27
|
+
|
|
28
|
+
constructor(config: ServerConfig) {
|
|
29
|
+
// Add a route to serve the zip file
|
|
30
|
+
config.on(ServerEvent.STARTUP_END, ({app}) => {
|
|
31
|
+
app.get('/download/:tmpZipFile', async (req: Request, res: Response) => {
|
|
32
|
+
const path = `${tmpdir()}/${req.params.tmpZipFile}`
|
|
33
|
+
res.sendFile(path, {}, (err) => {
|
|
34
|
+
if (err) {
|
|
35
|
+
console.error('[DownloadConnector] Error while sending file', err)
|
|
36
|
+
res.status(500).send(`
|
|
37
|
+
<h1>Error</h1>
|
|
38
|
+
<p>There was an error while getting the zip file of your website</p>
|
|
39
|
+
<p>${err.message}</p>
|
|
40
|
+
`)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getOptions(formData: object): ConnectorOptions {
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async getOAuthUrl(session: DownloadConnectorSession): Promise<null> { return null }
|
|
52
|
+
|
|
53
|
+
async getLoginForm(session: DownloadConnectorSession, redirectTo: string): Promise<string | null> {
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
async getSettingsForm(session: DownloadConnectorSession, redirectTo: string): Promise<string | null> {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async isLoggedIn(session: DownloadConnectorSession): Promise<boolean> {
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async setToken(session: DownloadConnectorSession, query: object): Promise<void> {}
|
|
65
|
+
|
|
66
|
+
async logout(session: DownloadConnectorSession): Promise<void> {}
|
|
67
|
+
|
|
68
|
+
async getUser(session: DownloadConnectorSession): Promise<ConnectorUser | null> {
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async publish(session: DownloadConnectorSession, websiteId: WebsiteId, files: ConnectorFile[], jobManager: JobManager): Promise<JobData> {
|
|
73
|
+
const job = jobManager.startJob(`Publishing to ${this.displayName}`) as PublicationJobData
|
|
74
|
+
this.startPublishingInBackground(session, websiteId, files, job)
|
|
75
|
+
return job
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async startPublishingInBackground(session: DownloadConnectorSession, websiteId: WebsiteId, files: ConnectorFile[], job: PublicationJobData): Promise<void> {
|
|
79
|
+
const fileName = `${websiteId}-${Date.now()}-${Math.random().toString(36).substring(7)}.zip`
|
|
80
|
+
return new Promise<string>((resolve, reject) => {
|
|
81
|
+
let resolved = false
|
|
82
|
+
try {
|
|
83
|
+
// Generate a temporary path for the zip file, in the OS tmp folder, with the website id, the date and random string
|
|
84
|
+
const path = `${tmpdir()}/${fileName}`
|
|
85
|
+
// create a file to stream archive data to.
|
|
86
|
+
const output = createWriteStream(path)
|
|
87
|
+
const archive = archiver('zip', {
|
|
88
|
+
zlib: { level: 9 } // Sets the compression level.
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Listen to archive events
|
|
92
|
+
// listen for all archive data to be written
|
|
93
|
+
// 'close' event is fired only when a file descriptor is involved
|
|
94
|
+
output.on('close', function () {
|
|
95
|
+
!resolved && resolve(path)
|
|
96
|
+
resolved = true
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// good practice to catch warnings (ie stat failures and other non-blocking errors)
|
|
100
|
+
archive.on('warning', function (err) {
|
|
101
|
+
if (err.code === 'ENOENT') {
|
|
102
|
+
// log warning
|
|
103
|
+
} else {
|
|
104
|
+
!resolved && reject(err)
|
|
105
|
+
resolved = true
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// good practice to catch this error explicitly
|
|
110
|
+
archive.on('error', function (err) {
|
|
111
|
+
!resolved && reject(err)
|
|
112
|
+
resolved = true
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// pipe archive data to the filey
|
|
116
|
+
archive.pipe(output)
|
|
117
|
+
|
|
118
|
+
// append files
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
job.message = `Adding ${file.path} to the zip file`
|
|
121
|
+
// Handle content as string, buffer or readable
|
|
122
|
+
archive.append(file.content, { name: file.path })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// finalize the archive (ie we are done appending files but streams have to finish yet)
|
|
126
|
+
job.message = 'Finalizing the zip file'
|
|
127
|
+
return archive.finalize()
|
|
128
|
+
.then(() => path)
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error('Error while creating the zip file', err)
|
|
131
|
+
job.message = `Error while creating the zip file: ${err.message}`
|
|
132
|
+
job.status = JobStatus.ERROR
|
|
133
|
+
!resolved && reject(err)
|
|
134
|
+
resolved = true
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
.then(path => {
|
|
138
|
+
job.message = `Zip file created, <a href="/download/${fileName}" target="_blank">download it now</a>`
|
|
139
|
+
job.status = JobStatus.SUCCESS
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async getUrl(session: DownloadConnectorSession, websiteId: WebsiteId): Promise<string> {
|
|
144
|
+
return ''
|
|
145
|
+
}
|
|
146
|
+
}
|