@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.
- package/.silex.js +38 -8
- package/dist/client/client/config.d.ts +11 -41
- package/dist/client/client/grapesjs/LoginDialog.d.ts +13 -0
- package/dist/client/client/grapesjs/PublicationManager.d.ts +69 -0
- package/dist/client/client/grapesjs/PublicationUi.d.ts +58 -0
- package/dist/client/client/grapesjs/index.d.ts +18 -44
- package/dist/client/client/grapesjs/storage.d.ts +1 -0
- package/dist/client/client/services.d.ts +35 -0
- package/dist/client/constants.d.ts +17 -0
- package/dist/client/css/admin.css +86 -3
- package/dist/client/js/main.js +201 -90
- package/dist/client/js/main.js.LICENSE.txt +6 -0
- package/dist/client/types.d.ts +200 -29
- package/dist/constants.d.ts +21 -0
- package/dist/constants.js +38 -1
- package/dist/constants.js.map +1 -0
- package/dist/events.d.ts +2 -0
- package/dist/events.js +17 -0
- package/dist/events.js.map +1 -0
- package/dist/plugins/AuthPlugin.d.ts +1 -0
- package/dist/plugins/AuthPlugin.js +38 -0
- package/dist/plugins/AuthPlugin.js.map +1 -0
- package/dist/plugins/Cache.d.ts +2 -0
- package/dist/plugins/Cache.js +32 -0
- package/dist/plugins/Cache.js.map +1 -0
- package/dist/plugins/FtpBackend.d.ts +92 -0
- package/dist/plugins/FtpBackend.js +604 -0
- package/dist/plugins/FtpBackend.js.map +1 -0
- package/dist/plugins/HooksPlugin.d.ts +7 -0
- package/dist/plugins/HooksPlugin.js +76 -0
- package/dist/plugins/HooksPlugin.js.map +1 -0
- package/dist/plugins/PublicationPlugin.d.ts +17 -0
- package/dist/plugins/PublicationPlugin.js +170 -0
- package/dist/plugins/PublicationPlugin.js.map +1 -0
- package/dist/plugins/SslPlugin.d.ts +1 -0
- package/dist/plugins/SslPlugin.js +86 -0
- package/dist/plugins/SslPlugin.js.map +1 -0
- package/dist/plugins/StaticPlugin.d.ts +1 -0
- package/dist/plugins/StaticPlugin.js +66 -0
- package/dist/plugins/StaticPlugin.js.map +1 -0
- package/dist/plugins/WebsitePlugin.d.ts +14 -0
- package/dist/plugins/WebsitePlugin.js +302 -0
- package/dist/plugins/WebsitePlugin.js.map +1 -0
- package/dist/server/backends/FsBackend.d.ts +42 -0
- package/dist/server/backends/FsBackend.js +269 -0
- package/dist/server/backends/FsBackend.js.map +1 -0
- package/dist/server/backends/index.d.ts +95 -0
- package/dist/server/backends/index.js +255 -0
- package/dist/server/backends/index.js.map +1 -0
- package/dist/server/cli.js +0 -1
- package/dist/server/config.d.ts +58 -0
- package/dist/server/config.js +128 -24
- package/dist/server/config.js.map +1 -0
- package/dist/server/express.js +31 -3
- package/dist/server/index.js +9 -20
- package/dist/server/jobs.d.ts +6 -0
- package/dist/server/jobs.js +75 -0
- package/dist/server/jobs.js.map +1 -0
- package/dist/server/utils/validation.d.ts +7 -0
- package/dist/server/utils/validation.js +37 -0
- package/dist/server/utils/validation.js.map +1 -0
- package/dist/types.d.ts +270 -0
- package/dist/types.js +35 -28
- package/dist/types.js.map +1 -0
- package/package.json +19 -8
- package/public/silex.js +17 -0
- package/src/css/dialog.scss +9 -2
- package/src/css/grapesjs.scss +79 -0
- package/src/css/project-bar.scss +2 -2
- package/src/example-client-config.js +17 -0
- package/src/html/templates/includes.pug +0 -1
- package/src/ts/client/config.ts +7 -6
- package/src/ts/client/grapesjs/LoginDialog.ts +190 -0
- package/src/ts/client/grapesjs/PublicationManager.ts +333 -0
- package/src/ts/client/grapesjs/PublicationUi.ts +320 -0
- package/src/ts/client/grapesjs/index.ts +88 -85
- package/src/ts/client/grapesjs/storage.ts +110 -0
- package/src/ts/client/index.ts +5 -7
- package/src/ts/client/services.ts +129 -0
- package/src/ts/constants.ts +21 -0
- package/src/ts/plugins/AuthPlugin.ts +38 -0
- package/src/ts/plugins/Cache.ts +28 -0
- package/src/ts/plugins/FtpBackend.ts +689 -0
- package/src/ts/plugins/HooksPlugin.ts +79 -0
- package/src/ts/plugins/PublicationPlugin.ts +170 -0
- package/src/{plugins/SslPlugin.js → ts/plugins/SslPlugin.ts} +24 -6
- package/src/ts/plugins/StaticPlugin.ts +68 -0
- package/src/ts/plugins/WebsitePlugin.ts +318 -0
- package/src/ts/server/backends/FsBackend.ts +266 -0
- package/src/ts/server/backends/index.ts +309 -0
- package/src/ts/server/cli.ts +0 -2
- package/src/ts/server/config.ts +103 -33
- package/src/ts/server/express.ts +37 -3
- package/src/ts/server/index.ts +24 -14
- package/src/ts/server/jobs.test.ts +74 -0
- package/src/ts/server/jobs.ts +77 -0
- package/src/ts/server/utils/validation.ts +33 -0
- package/src/ts/types.ts +167 -59
- package/dist/client/client/grapesjs/publish.d.ts +0 -18
- package/dist/page.js +0 -15
- package/src/plugins/AuthPlugin.js +0 -21
- package/src/plugins/Cache.js +0 -11
- package/src/plugins/DefaultBackend.js +0 -149
- package/src/plugins/ExpressPlugin.js +0 -39
- package/src/plugins/HooksPlugin.js +0 -58
- package/src/plugins/PublishPlugin.js +0 -69
- package/src/plugins/StaticPlugin.js +0 -48
- package/src/plugins/WebsitePlugin.js +0 -207
- package/src/ts/client/grapesjs/publish.ts +0 -403
- /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
|
-
}
|
|
File without changes
|