@silexlabs/silex 3.0.0-alpha.39 → 3.0.0-alpha.41

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 (110) hide show
  1. package/.silex.js +38 -8
  2. package/dist/client/client/config.d.ts +11 -41
  3. package/dist/client/client/grapesjs/LoginDialog.d.ts +13 -0
  4. package/dist/client/client/grapesjs/PublicationManager.d.ts +69 -0
  5. package/dist/client/client/grapesjs/PublicationUi.d.ts +58 -0
  6. package/dist/client/client/grapesjs/index.d.ts +18 -44
  7. package/dist/client/client/grapesjs/storage.d.ts +1 -0
  8. package/dist/client/client/services.d.ts +35 -0
  9. package/dist/client/constants.d.ts +17 -0
  10. package/dist/client/css/admin.css +86 -3
  11. package/dist/client/js/main.js +201 -90
  12. package/dist/client/js/main.js.LICENSE.txt +6 -0
  13. package/dist/client/types.d.ts +200 -29
  14. package/dist/constants.d.ts +21 -0
  15. package/dist/constants.js +38 -1
  16. package/dist/constants.js.map +1 -0
  17. package/dist/events.d.ts +2 -0
  18. package/dist/events.js +17 -0
  19. package/dist/events.js.map +1 -0
  20. package/dist/plugins/AuthPlugin.d.ts +1 -0
  21. package/dist/plugins/AuthPlugin.js +38 -0
  22. package/dist/plugins/AuthPlugin.js.map +1 -0
  23. package/dist/plugins/Cache.d.ts +2 -0
  24. package/dist/plugins/Cache.js +32 -0
  25. package/dist/plugins/Cache.js.map +1 -0
  26. package/dist/plugins/FtpBackend.d.ts +92 -0
  27. package/dist/plugins/FtpBackend.js +604 -0
  28. package/dist/plugins/FtpBackend.js.map +1 -0
  29. package/dist/plugins/HooksPlugin.d.ts +7 -0
  30. package/dist/plugins/HooksPlugin.js +76 -0
  31. package/dist/plugins/HooksPlugin.js.map +1 -0
  32. package/dist/plugins/PublicationPlugin.d.ts +17 -0
  33. package/dist/plugins/PublicationPlugin.js +170 -0
  34. package/dist/plugins/PublicationPlugin.js.map +1 -0
  35. package/dist/plugins/SslPlugin.d.ts +1 -0
  36. package/dist/plugins/SslPlugin.js +86 -0
  37. package/dist/plugins/SslPlugin.js.map +1 -0
  38. package/dist/plugins/StaticPlugin.d.ts +1 -0
  39. package/dist/plugins/StaticPlugin.js +66 -0
  40. package/dist/plugins/StaticPlugin.js.map +1 -0
  41. package/dist/plugins/WebsitePlugin.d.ts +14 -0
  42. package/dist/plugins/WebsitePlugin.js +302 -0
  43. package/dist/plugins/WebsitePlugin.js.map +1 -0
  44. package/dist/server/backends/FsBackend.d.ts +42 -0
  45. package/dist/server/backends/FsBackend.js +269 -0
  46. package/dist/server/backends/FsBackend.js.map +1 -0
  47. package/dist/server/backends/index.d.ts +95 -0
  48. package/dist/server/backends/index.js +255 -0
  49. package/dist/server/backends/index.js.map +1 -0
  50. package/dist/server/cli.js +0 -1
  51. package/dist/server/config.d.ts +58 -0
  52. package/dist/server/config.js +128 -24
  53. package/dist/server/config.js.map +1 -0
  54. package/dist/server/express.js +31 -3
  55. package/dist/server/index.js +9 -20
  56. package/dist/server/jobs.d.ts +6 -0
  57. package/dist/server/jobs.js +75 -0
  58. package/dist/server/jobs.js.map +1 -0
  59. package/dist/server/utils/validation.d.ts +7 -0
  60. package/dist/server/utils/validation.js +37 -0
  61. package/dist/server/utils/validation.js.map +1 -0
  62. package/dist/types.d.ts +270 -0
  63. package/dist/types.js +35 -28
  64. package/dist/types.js.map +1 -0
  65. package/package.json +19 -8
  66. package/public/silex.js +17 -0
  67. package/src/css/dialog.scss +9 -2
  68. package/src/css/grapesjs.scss +79 -0
  69. package/src/css/project-bar.scss +2 -2
  70. package/src/example-client-config.js +17 -0
  71. package/src/html/templates/includes.pug +0 -1
  72. package/src/ts/client/config.ts +7 -6
  73. package/src/ts/client/grapesjs/LoginDialog.ts +190 -0
  74. package/src/ts/client/grapesjs/PublicationManager.ts +333 -0
  75. package/src/ts/client/grapesjs/PublicationUi.ts +320 -0
  76. package/src/ts/client/grapesjs/index.ts +88 -85
  77. package/src/ts/client/grapesjs/storage.ts +110 -0
  78. package/src/ts/client/index.ts +5 -7
  79. package/src/ts/client/services.ts +129 -0
  80. package/src/ts/constants.ts +21 -0
  81. package/src/ts/plugins/AuthPlugin.ts +38 -0
  82. package/src/ts/plugins/Cache.ts +28 -0
  83. package/src/ts/plugins/FtpBackend.ts +689 -0
  84. package/src/ts/plugins/HooksPlugin.ts +79 -0
  85. package/src/ts/plugins/PublicationPlugin.ts +170 -0
  86. package/src/{plugins/SslPlugin.js → ts/plugins/SslPlugin.ts} +24 -6
  87. package/src/ts/plugins/StaticPlugin.ts +68 -0
  88. package/src/ts/plugins/WebsitePlugin.ts +318 -0
  89. package/src/ts/server/backends/FsBackend.ts +266 -0
  90. package/src/ts/server/backends/index.ts +309 -0
  91. package/src/ts/server/cli.ts +0 -2
  92. package/src/ts/server/config.ts +103 -33
  93. package/src/ts/server/express.ts +37 -3
  94. package/src/ts/server/index.ts +24 -14
  95. package/src/ts/server/jobs.test.ts +74 -0
  96. package/src/ts/server/jobs.ts +77 -0
  97. package/src/ts/server/utils/validation.ts +33 -0
  98. package/src/ts/types.ts +167 -59
  99. package/dist/client/client/grapesjs/publish.d.ts +0 -18
  100. package/dist/page.js +0 -15
  101. package/src/plugins/AuthPlugin.js +0 -21
  102. package/src/plugins/Cache.js +0 -11
  103. package/src/plugins/DefaultBackend.js +0 -149
  104. package/src/plugins/ExpressPlugin.js +0 -39
  105. package/src/plugins/HooksPlugin.js +0 -58
  106. package/src/plugins/PublishPlugin.js +0 -69
  107. package/src/plugins/StaticPlugin.js +0 -48
  108. package/src/plugins/WebsitePlugin.js +0 -207
  109. package/src/ts/client/grapesjs/publish.ts +0 -403
  110. /package/.silex/default/{.silex.data.json → website.json} +0 -0
@@ -1,207 +0,0 @@
1
- const { Router } = require('express')
2
- const { resolve } = require('path')
3
- const formidable = require('formidable')
4
-
5
- const { noCache } = require('./Cache')
6
- const { defaultSite } = require('../../')
7
-
8
- const EVENT_READ_START = 'EVENT_READ_START'
9
- const EVENT_READ_END = 'EVENT_READ_END'
10
- const EVENT_DELETE_START = 'EVENT_WRITE_START'
11
- const EVENT_DELETE_END = 'EVENT_WRITE_END'
12
- const EVENT_WRITE_START = 'EVENT_WRITE_START'
13
- const EVENT_WRITE_END = 'EVENT_WRITE_END'
14
- const EVENT_ASSET_READ_START = 'EVENT_ASSET_READ_START'
15
- const EVENT_ASSET_READ_END = 'EVENT_ASSET_READ_END'
16
- const EVENT_ASSET_WRITE_START = 'EVENT_ASSET_WRITE_START'
17
- const EVENT_ASSET_WRITE_END = 'EVENT_ASSET_WRITE_END'
18
-
19
- module.exports = async function(config, opts = {}) {
20
- // Options with defaults
21
- const options = {
22
- // Defaults
23
- backend: 'src/plugins/DefaultBackend.js',
24
- // Default data for new websites
25
- defaultSite,
26
- // Options
27
- ...opts
28
- }
29
-
30
- // Link to the desired backend
31
- const backend = resolve(__dirname, '../..', options.backend)
32
- const { assetsDir, assetUrl, init, writeData, readData, list, del } = require(backend)
33
-
34
- config.on('silex:startup:start', ({app}) => {
35
- const router = Router()
36
-
37
- // website specials
38
- router.get('/website', readWebsite)
39
- router.post('/website', writeWebsite)
40
- router.delete('/website', deleteWebsite)
41
- router.get(/\/assets\/(.*)/, readAsset)
42
- router.post('/assets', writeAsset)
43
-
44
- app.use(noCache, router)
45
- })
46
-
47
- async function readWebsite(req, res) {
48
- const { id } = req.query
49
- if(id) {
50
- // Returns a website data
51
- try {
52
- config.emit(EVENT_READ_START, { req, id })
53
- const data = await readData(id)
54
- config.emit(EVENT_READ_END, { req, res, data, id })
55
- res
56
- .type('application/json')
57
- .send({
58
- ...options.defaultSite,
59
- ...data,
60
- })
61
- } catch (err) {
62
- if(err.code === 'ENOENT') {
63
- console.error('Read file error, website does not exist', err)
64
- res.status(404).json({ message: 'Read file error, website does not exist: ' + err.message, code: err.code})
65
- } else {
66
- console.error('Read file error', err)
67
- res.status(400).json({ message: err.message, code: err.code})
68
- }
69
- }
70
- } else {
71
- // list websites
72
- try {
73
- config.emit(EVENT_READ_START, { req, id })
74
- const data = await list()
75
- config.emit(EVENT_READ_END, { req, res, data, id })
76
- res
77
- .type('application/json')
78
- .send(data)
79
- } catch (err) {
80
- console.error('List sites error', err)
81
- res.status(400).json({ message: err.message, code: err.code })
82
- }
83
- }
84
- }
85
-
86
- function fromBody(body) {
87
- try {
88
- return [{
89
- assets: body.assets,
90
- pages: body.pages,
91
- files: body.files,
92
- styles: body.styles,
93
- settings: body.settings,
94
- publication: body.publication,
95
- name: body.name,
96
- fonts: body.fonts,
97
- symbols: body.symbols,
98
- }, null]
99
- } catch(err) {
100
- console.error('Could not parse body data', body, err)
101
- return [null, err]
102
- }
103
- }
104
-
105
- async function writeWebsite(req, res) {
106
- const id = req.query.id
107
- const [data, err] = fromBody(req.body)
108
- if(err) {
109
- res.status(400).json({ message: 'Error writing data file, could not parse the provided body: ' + err.message, code: err.code})
110
- return
111
- }
112
- config.emit(EVENT_WRITE_START, { req, id, data })
113
- try {
114
- await init(id)
115
- await writeData(id, data)
116
- } catch (err) {
117
- console.error('Error writing data file', err)
118
- res.status(500).json({ message: 'Error writing data file: ' + err.message, code: err.code})
119
- return
120
- }
121
-
122
- config.emit(EVENT_WRITE_END, { res, req, id, data })
123
-
124
- res.json({
125
- message: 'OK',
126
- })
127
- }
128
-
129
- async function deleteWebsite(req, res) {
130
- const { id } = req.query
131
- if(id) {
132
- try {
133
- config.emit(EVENT_DELETE_START, { req, id })
134
- const data = await del(id)
135
- config.emit(EVENT_DELETE_END, { req, res, data, id })
136
- res
137
- .type('application/json')
138
- .send(data)
139
- } catch (err) {
140
- if(err.code === 'ENOENT') {
141
- console.error('Delete file error, website does not exist', err)
142
- res.status(404).json({ message: 'Delete file error, website does not exist: ' + err.message, code: err.code})
143
- } else {
144
- console.error('Delete file error', err)
145
- res.status(400).json({ message: err.message, code: err.code})
146
- }
147
- }
148
- } else {
149
- // list websites
150
- try {
151
- config.emit(EVENT_DELETE_START, { req, id })
152
- const data = await list()
153
- config.emit(EVENT_DELETE_END, { req, res, data, id })
154
- res
155
- .type('application/json')
156
- .send(data)
157
- } catch (err) {
158
- console.error('List sites error', err)
159
- res.status(400).json({ message: err.message, code: err.code })
160
- }
161
- }
162
- }
163
-
164
- async function readAsset(req, res) {
165
- const id = req.query.id
166
- const fileName = req.params[0]
167
- const uploadDir = await assetsDir(id)
168
- config.emit(EVENT_ASSET_READ_START, { req, id, fileName, uploadDir })
169
- res.sendFile(`${uploadDir}/${fileName}`)
170
- config.emit(EVENT_ASSET_READ_END, { req, id, fileName, uploadDir })
171
- }
172
-
173
- async function writeAsset(req, res) {
174
- const id = req.query.id
175
- // FIXME: assetsDir and assetsUrl will both download the site settings file => get both in 1 call
176
- const uploadDir = await assetsDir(id)
177
-
178
- const form = formidable({
179
- uploadDir,
180
- filename: (name, ext, part, _form) => `${name}${ext}`,
181
- multiples: true,
182
- keepExtensions: true,
183
- })
184
-
185
- form.parse(req, async (err, fields, files) => {
186
- if (err) {
187
- console.error('Error parsing upload data', err)
188
- res
189
- .status(400)
190
- .json({ message: 'Error parsing upload data: ' + err.message, code: err.code})
191
- return
192
- }
193
- Promise.all(
194
- [].concat(files['files[]']) // may be an array or 1 element
195
- .map(file => {
196
- const { originalFilename, filepath } = file
197
- return assetUrl(id, originalFilename)
198
- })
199
- )
200
- .then(data => {
201
- config.emit(EVENT_ASSET_WRITE_START, { req, id, uploadDir, form, data })
202
- res.json({ data })
203
- config.emit(EVENT_ASSET_WRITE_END, { res, req, id, uploadDir, form, data })
204
- })
205
- })
206
- }
207
- }
@@ -1,403 +0,0 @@
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 {html, render} from 'lit-html'
19
- import {map} from 'lit-html/directives/map.js'
20
- import grapesjs from 'grapesjs/dist/grapes.min.js'
21
- import { getPageSlug } from '../../page'
22
- import { onAll } from '../utils'
23
-
24
- // constants
25
- const pluginName = 'publish'
26
- export const cmdPublish = 'publish-open-dialog'
27
- let _token = null
28
- let id
29
- let rootUrl
30
-
31
- // plugin code
32
- export const publishPlugin = grapesjs.plugins.add(pluginName, (editor, opts) => {
33
- opts = {
34
- appendTo: 'options',
35
- ...opts,
36
- }
37
- // Global config
38
- rootUrl = opts.rootUrl
39
- id = opts.id
40
- // Keep track of the token
41
- editor.on('login:success', async ({ getUser, getToken }) => {
42
- _token = await getToken()
43
- })
44
- // add publication settings to the website
45
- editor.on('storage:start:store', (data) => {
46
- data.publication = editor.getModel().get('publication')
47
- })
48
- editor.on('storage:end:load', (data) => {
49
- const model = editor.getModel()
50
- model.set('publication', data.publication || {})
51
- })
52
- editor.Panels.addButton(opts.appendTo, {
53
- id: 'publish-button',
54
- className: 'silex-button--size publish-button',
55
- command: cmdPublish,
56
- attributes: { title: 'Publish' },
57
- label: '<span class="fa fa-rocket"></span><span class="silex-button--small">Publish</span>',
58
- })
59
- editor.Commands.add(cmdPublish, {
60
- run(editor) { openDialog(editor) },
61
- stop(editor) { closeDialog(editor) },
62
- })
63
- })
64
-
65
- export function getDialogElements() {
66
- const el = document.querySelector('#publish-dialog')
67
- return el ? {
68
- dialog: el,
69
- primary: el.querySelector('#publish-button--primary'),
70
- secondary: el.querySelector('#publish-button--secondary'),
71
- } : null
72
- }
73
- function createDialogElements() {
74
- const el = document.createElement('div')
75
- el.id = 'publish-dialog'
76
- el.className = 'silex-dialog-inline silex-dialog gjs-two-color'
77
- document.body.append(el)
78
- return getDialogElements()
79
- }
80
- function move(rect) {
81
- Object.keys(rect).forEach(key => dialog.style[key] = rect[key] + 'px')
82
- }
83
- function update(editor) {
84
- render(html`
85
- ${ open ? html`
86
- <main>
87
- ${ status === STATUS_PENDING ? html`
88
- <p>Publication in progress</p>
89
- ` : ''}
90
- ${ status === STATUS_SUCCESS ? html`
91
- <p>Publication success</p>
92
- ${ url ? html`<a href="${url}" target="_blank">Click here to view the published website</a>` : ''}
93
- ` : ''}
94
- ${ status === STATUS_ERROR ? html`
95
- <p>Publication error</p>
96
- <div>${ errorMessage }</div>
97
- ` : ''}
98
- ${ state?.running ? html`
99
- <progress
100
- value=""
101
- style="width: 100%;"
102
- ></progress>
103
- ` : ''}
104
- ${ state.logs?.length ? html`
105
- <details>
106
- <summary>Logs</summary>
107
- <pre style="
108
- max-width: 100%;
109
- max-height: 50vh;
110
- overflow: auto;
111
- font-size: x-small;
112
- "
113
- >${ cleanup(state.logs) }
114
- </pre>
115
- </details>
116
- ` : '' }
117
- ${ state.errors?.length ? html`
118
- <details>
119
- <summary>Errors</summary>
120
- <pre style="
121
- max-width: 100%;
122
- max-height: 50vh;
123
- overflow: auto;
124
- font-size: x-small;
125
- "
126
- >${ cleanup(state.errors) }
127
- </pre>
128
- </details>
129
- ` : '' }
130
- </main>
131
- <footer>
132
- ${ status === STATUS_PENDING ? '' : html`
133
- <button
134
- class="silex-button silex-button--primary"
135
- id="publish-button--primary"
136
- @click=${() => startPublication(editor)}
137
- >Publish</button>
138
- `}
139
- <button
140
- class="silex-button silex-button--secondary"
141
- id="publish-button--secondary"
142
- @click=${() => editor.Commands.stop(cmdPublish)}
143
- >Close</button>
144
- </footer>
145
- ` : ''}
146
- `, dialog)
147
- if(open) {
148
- dialog.classList.remove('silex-dialog-hide')
149
- } else {
150
- dialog.classList.add('silex-dialog-hide')
151
- }
152
- }
153
- export const STATUS_NONE='STATUS_NONE'
154
- export const STATUS_PENDING='STATUS_PENDING'
155
- export const STATUS_ERROR='STATUS_ERROR'
156
- export const STATUS_SUCCESS='STATUS_SUCCESS'
157
- export let status = STATUS_NONE
158
- export let open = false
159
- let errorMessage = ''
160
- let dialog
161
- let url // from the result of the first fetch when publishing
162
- let state = {
163
- queued: false,
164
- error: false,
165
- running: false,
166
- logs: [],
167
- errors: [],
168
- }
169
-
170
- function cleanup(arr: string[][]): string {
171
- return arr[arr.length-1]
172
- ?.map(str => str.replace(/\[.*\]/g, '').trim())
173
- ?.filter(str => !!str)
174
- ?.join('\n')
175
- }
176
-
177
- function displayError(editor, message) {
178
- console.error(message)
179
- errorMessage = message
180
- status = STATUS_ERROR
181
- update(editor)
182
- }
183
- export async function closeDialog(editor) {
184
- open = false
185
- update(editor)
186
- }
187
- export async function toggleDialog(editor) {
188
- if(open) closeDialog(editor)
189
- else openDialog(editor)
190
- }
191
- export async function openDialog(editor) {
192
- open = true
193
-
194
- // Position
195
- const buttonEl = editor.Panels.getPanel('options').view.el
196
- .querySelector('.publish-button')
197
- const rect = buttonEl.getBoundingClientRect()
198
-
199
- const width = 450
200
- const padding = 10 * 2
201
- const minHeight = 50
202
- if(!dialog) dialog = createDialogElements().dialog
203
- move({
204
- left: rect.right - width - padding,
205
- top: rect.bottom + 10,
206
- width,
207
- minHeight,
208
- })
209
-
210
- // Publication
211
- if(status === STATUS_NONE) {
212
- startPublication(editor)
213
- } else {
214
- update(editor)
215
- }
216
- }
217
- export async function startPublication(editor) {
218
- if(status === STATUS_PENDING) throw new Error('Publication is already in progress')
219
- status = STATUS_PENDING
220
- update(editor)
221
- editor.trigger('publish:before')
222
- const projectData = editor.getProjectData()
223
- const siteSettings = editor.getModel().get('settings')
224
- const publicationSettings = editor.getModel().get('publication')
225
- // Update assets URL to display outside the editor
226
- const assetsFolderUrl = publicationSettings?.assets?.url
227
- if(assetsFolderUrl) {
228
- const publishedUrl = path => `${assetsFolderUrl}/${path.split('/').pop()}`
229
- // New URLs for assets, according to site config
230
- onAll(editor, c => {
231
- // Attributes
232
- if(c.get('type') === 'image') {
233
- const path = c.get('src')
234
- c.set('tmp-src', path)
235
- c.set('src', publishedUrl(path))
236
- }
237
- //// Inline styles
238
- //// This is handled by the editor.Css.getAll loop
239
- //const bgUrl = c.getStyle()['background-image']?.match(/url\('(.*)'\)/)?.pop()
240
- //if(bgUrl) {
241
- // c.set('tmp-bg-url', bgUrl)
242
- // c.setStyle({
243
- // ...c.getStyle(),
244
- // 'background-image': `url('${publishedUrl(bgUrl)}')`,
245
- // })
246
- //}
247
- })
248
- editor.Css.getAll()
249
- .forEach(c => {
250
- const bgUrl = c.getStyle()['background-image']?.match(/url\('(.*)'\)/)?.pop()
251
- if(bgUrl) {
252
- c.setStyle({
253
- ...c.getStyle(),
254
- 'background-image': `url('${publishedUrl(bgUrl)}')`,
255
- })
256
- c.set('tmp-bg-url-css', bgUrl)
257
- }
258
- })
259
- }
260
- // Build the files structure
261
- const files = await getFiles(editor, {siteSettings, publicationSettings})
262
-
263
- // Create the data to send to the server
264
- const data = {
265
- ...projectData,
266
- settings: siteSettings,
267
- publication: publicationSettings,
268
- id,
269
- files,
270
- }
271
- // Reset asset URLs
272
- if(assetsFolderUrl) {
273
- onAll(editor, c => {
274
- if(c.get('type') === 'image' && c.has('tmp-src')) {
275
- c.set('src', c.get('tmp-src'))
276
- c.set('tmp-src')
277
- }
278
- //// This is handled by the editor.Css.getAll loop
279
- //if(c.getStyle()['background-image'] && c.has('tmp-bg-url')) {
280
- // c.setStyle({
281
- // ...c.getStyle(),
282
- // 'background-image': `url('${c.get('tmp-bg-url')}')`,
283
- // })
284
- // c.set('tmp-bg-url')
285
- //}
286
- })
287
- editor.Css.getAll()
288
- .forEach(c => {
289
- if(c.has('tmp-bg-url-css')) {
290
- c.setStyle({
291
- ...c.getStyle(),
292
- 'background-image': `url('${c.get('tmp-bg-url-css')}')`,
293
- })
294
- c.set('tmp-bg-url-css')
295
- }
296
- })
297
- }
298
- editor.trigger('publish:start', data)
299
- let res
300
- let json
301
- try {
302
- res = await fetch(`${ rootUrl }publish`, {
303
- method: 'POST',
304
- body: JSON.stringify({
305
- data,
306
- token: _token,
307
- }),
308
- headers: {
309
- 'Content-Type': 'application/json'
310
- },
311
- })
312
- } catch(e) {
313
- displayError(editor, `An error occured, your site is not published. ${e.message}`)
314
- editor.trigger('publish:stop', {success: false, message: e.message})
315
- return
316
- }
317
- try {
318
- json = await res.json()
319
- } catch(e) {
320
- displayError(editor, `Could not parse the server response, your site may be published. ${e.message}`)
321
- editor.trigger('publish:stop', {success: false, message: e.message})
322
- return
323
- }
324
- if(!res.ok) {
325
- displayError(editor, `An network error occured, your site is not published. ${json.message}`)
326
- editor.trigger('publish:stop', {success: false, message: json.message})
327
- return
328
- }
329
- url = json.url
330
- if(json.statusUrl) {
331
- trackProgress(editor, json.statusUrl)
332
- } else {
333
- status = STATUS_SUCCESS
334
- update(editor)
335
- editor.trigger('publish:stop', {success: true})
336
- }
337
- }
338
-
339
- async function getFiles(editor, {siteSettings, publicationSettings, }) {
340
- return editor.Pages.getAll().map(page => {
341
- const pageSettings = page.get('settings')
342
- const pageName = publicationSettings?.autoHomePage !== false && page.get('type') === 'main' ? 'index' : (page.get('name') || page.get('type'))
343
- function getSetting(name) {
344
- return (pageSettings || {})[name] || (siteSettings || [])[name] || ''
345
- }
346
- const component = page.getMainComponent()
347
- const slug = getPageSlug(pageName)
348
- return {
349
- html: `
350
- <!DOCTYPE html>
351
- <html lang="${ getSetting('lang') }">
352
- <head>
353
- <link rel="stylesheet" href="${publicationSettings?.css?.url || ''}/${slug}.css" />
354
- ${ siteSettings?.head || '' }
355
- ${ pageSettings?.head || '' }
356
- <title>${ getSetting('title') }</title>
357
- <link rel="icon" href="${ getSetting('favicon') }" />
358
- ${
359
- ['description', 'og:title', 'og:description', 'og:image']
360
- .map(prop => `<meta property="${ prop }" content="${ getSetting(prop) }"/>`)
361
- .join('\n')
362
- }
363
- </head>
364
- ${ editor.getHtml({ component }) }
365
- </html>
366
- `,
367
- css: editor.getCss({ component }),
368
- cssPath: `${ publicationSettings?.css?.path || '' }/${slug}${publicationSettings?.css?.ext || '.css'}`,
369
- htmlPath: `${ publicationSettings?.html?.path || '' }/${slug}${publicationSettings?.html?.ext || '.html'}`,
370
- }
371
- })
372
- }
373
-
374
- export async function trackProgress(editor, statusUrl) {
375
- let res
376
- let json
377
- try {
378
- res = await fetch(statusUrl)
379
- } catch(e) {
380
- displayError(editor, `An error occured, your site is not published. ${e.message}`)
381
- editor.trigger('publish:stop', {success: false, message: e.message})
382
- return
383
- }
384
- try {
385
- state = await res.json()
386
- } catch(e) {
387
- displayError(editor, `Could not parse the server response, your site may be published. ${e.message}`)
388
- editor.trigger('publish:stop', {success: false, message: e.message})
389
- return
390
- }
391
- if(!res.ok) {
392
- displayError(editor, `An network error occured, your site is not published. ${res.statusText}`)
393
- editor.trigger('publish:stop', {success: false, message: `An network error occured, your site is not published. ${res.statusText}`})
394
- return
395
- }
396
- if(state.running) {
397
- setTimeout(() => trackProgress(editor, statusUrl), 2000)
398
- } else {
399
- status = state.error ? STATUS_ERROR : STATUS_SUCCESS
400
- editor.trigger('publish:stop', {success: state.error})
401
- }
402
- update(editor)
403
- }