@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
|
@@ -15,12 +15,11 @@
|
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import * as grapesjs from 'grapesjs/dist/grapes.min.js'
|
|
19
18
|
import { cmdAddSymbol } from '@silexlabs/grapesjs-symbols'
|
|
20
19
|
|
|
21
20
|
export const cmdPromptAddSymbol = 'symbol-prompt-add'
|
|
22
21
|
|
|
23
|
-
export default
|
|
22
|
+
export default (editor, opts) => {
|
|
24
23
|
function getNext(prefix) {
|
|
25
24
|
let idx = 1
|
|
26
25
|
while(editor.Symbols.find(s => s.get('label') === prefix + idx)) {
|
|
@@ -31,8 +30,8 @@ export default grapesjs.plugins.add(name, (editor, opts) => {
|
|
|
31
30
|
editor.Commands.add(cmdPromptAddSymbol, {
|
|
32
31
|
run: (_, sender) => {
|
|
33
32
|
const label = prompt('Label', getNext('Symbol '))
|
|
34
|
-
const icon =
|
|
33
|
+
const icon = 'fa-gem'
|
|
35
34
|
editor.runCommand(cmdAddSymbol, { label, icon })
|
|
36
35
|
}
|
|
37
36
|
})
|
|
38
|
-
}
|
|
37
|
+
}
|
|
@@ -13,26 +13,30 @@
|
|
|
13
13
|
*
|
|
14
14
|
* You should have received a copy of the GNU Affero General Public License
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const pasteBtnClass = 'fa fa-fw fa-paste silex-button'
|
|
20
|
+
const disabledClass = ' disabled'
|
|
21
|
+
|
|
22
|
+
export default function(editor) {
|
|
23
|
+
// Add copy/paste buttons in the top bar
|
|
24
|
+
const [copyBtn, pasteBtn] = editor.Panels.addButton('options', [{
|
|
25
|
+
id: 'copy',
|
|
26
|
+
className: 'fa fa-fw fa-copy',
|
|
27
|
+
command: 'core:copy',
|
|
28
|
+
attributes: { title: 'Copy (Ctrl+C)' },
|
|
29
|
+
}, {
|
|
30
|
+
id: 'paste',
|
|
31
|
+
className: pasteBtnClass + disabledClass,
|
|
32
|
+
command: 'core:paste',
|
|
33
|
+
attributes: { title: 'Paste (Ctrl+V)' },
|
|
34
|
+
active: false,
|
|
35
|
+
}])
|
|
20
36
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// const token = req.body.token || opts.directusToken
|
|
27
|
-
// const directus = new Directus(opts.directusUrl)
|
|
28
|
-
// directus.storage.auth_token = token
|
|
29
|
-
// const me = await directus.users.me.read()
|
|
30
|
-
// next()
|
|
31
|
-
// } catch(err) {
|
|
32
|
-
// console.error('Publish failed in auth module. Did you provide a directus token?', err.message)
|
|
33
|
-
// res.status(403).json({ message: err.message })
|
|
34
|
-
// }
|
|
35
|
-
// })
|
|
36
|
-
// app.use(router)
|
|
37
|
-
// })
|
|
37
|
+
// Disable paste button if clipboard is empty
|
|
38
|
+
editor.EditorModel.on('change:clipboard', (model, value) => {
|
|
39
|
+
const hasClipboard = value && value.length > 0
|
|
40
|
+
pasteBtn.set('className', pasteBtnClass + (hasClipboard ? '' : disabledClass))
|
|
41
|
+
})
|
|
38
42
|
}
|
package/src/ts/client/index.ts
CHANGED
|
@@ -21,18 +21,28 @@
|
|
|
21
21
|
*
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { DEV_MESSAGE } from '../constants'
|
|
24
25
|
import { ClientConfig } from './config'
|
|
25
26
|
import { ClientEvent } from './events'
|
|
26
27
|
import { initEditor, getEditor } from './grapesjs/index'
|
|
28
|
+
import { cmdPauseAutoSave } from './grapesjs/storage'
|
|
27
29
|
|
|
28
30
|
// Expose API to calling app as window.silex
|
|
29
31
|
export * from './expose'
|
|
30
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Expose the config object
|
|
35
|
+
*/
|
|
36
|
+
export let config: ClientConfig
|
|
37
|
+
|
|
31
38
|
/**
|
|
32
39
|
* Start Silex, called from host HTML page with window.silex.start()
|
|
33
40
|
*/
|
|
34
|
-
export async function start(options = {}) {
|
|
35
|
-
|
|
41
|
+
export async function start(options = {}): Promise<void> {
|
|
42
|
+
// Log Silex version for devs - it is also displayed in te settings
|
|
43
|
+
console.info(DEV_MESSAGE)
|
|
44
|
+
// Create the config object
|
|
45
|
+
config = new ClientConfig()
|
|
36
46
|
Object.assign(config, options)
|
|
37
47
|
|
|
38
48
|
// Config file in root folder which may be generated by the server
|
|
@@ -50,6 +60,8 @@ export async function start(options = {}) {
|
|
|
50
60
|
config.initGrapesConfig()
|
|
51
61
|
|
|
52
62
|
// Start grapesjs
|
|
63
|
+
// Here you can change the config before passing it to grapesjs
|
|
64
|
+
config.emit(ClientEvent.GRAPESJS_START)
|
|
53
65
|
try{
|
|
54
66
|
await initEditor(config.grapesJsConfig)
|
|
55
67
|
} catch(e) {
|
|
@@ -57,18 +69,25 @@ export async function start(options = {}) {
|
|
|
57
69
|
throw e
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
config.emit(ClientEvent.GRAPESJS_START)
|
|
61
72
|
const editor = getEditor()
|
|
73
|
+
|
|
74
|
+
// Store the config in the editor
|
|
75
|
+
editor.getModel().set('config', config)
|
|
76
|
+
|
|
77
|
+
// Notify plugins
|
|
62
78
|
config.emit(ClientEvent.GRAPESJS_END, { editor })
|
|
63
79
|
|
|
64
80
|
// Init internationalization module
|
|
65
81
|
editor.I18n.setLocale(config.lang)
|
|
66
82
|
|
|
83
|
+
// Add default plugins
|
|
84
|
+
await config.addDefaultPlugins()
|
|
85
|
+
|
|
67
86
|
// Load the site
|
|
68
|
-
editor.StorageManager.setAutosave(false)
|
|
69
|
-
console.log('before load')
|
|
70
87
|
try {
|
|
88
|
+
editor.runCommand(cmdPauseAutoSave)
|
|
71
89
|
await editor.load(null)
|
|
90
|
+
editor.once('canvas:frame:load', () => editor.stopCommand(cmdPauseAutoSave))
|
|
72
91
|
} catch(e) {
|
|
73
92
|
if(e.httpStatusCode === 401) {
|
|
74
93
|
// Unauthorized, will try to login
|
|
@@ -76,16 +95,16 @@ export async function start(options = {}) {
|
|
|
76
95
|
// Will display an error message, see in storage.ts
|
|
77
96
|
}
|
|
78
97
|
} finally {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
editor.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// This needs time for the loader to be hidden
|
|
86
|
-
document.querySelector('.silex-loader').classList.add('silex-dialog-hide')
|
|
87
|
-
document.querySelector('#gjs').classList.remove('silex-dialog-hide')
|
|
88
|
-
config.emit(ClientEvent.STARTUP_END, { editor, config })
|
|
89
|
-
}, 100)
|
|
98
|
+
if(editor.getModel().getCurrentFrame().loaded) {
|
|
99
|
+
loaded(editor)
|
|
100
|
+
} else {
|
|
101
|
+
editor.once('canvas:frame:load', () => loaded(editor))
|
|
102
|
+
}
|
|
90
103
|
}
|
|
91
104
|
}
|
|
105
|
+
|
|
106
|
+
function loaded(editor) {
|
|
107
|
+
document.querySelector('.silex-loader').classList.add('silex-dialog-hide')
|
|
108
|
+
document.querySelector('#gjs').classList.remove('silex-dialog-hide')
|
|
109
|
+
config.emit(ClientEvent.STARTUP_END, { editor, config })
|
|
110
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { jest, expect, describe, it, beforeEach } from '@jest/globals'
|
|
2
|
+
import { Mock } from 'jest-mock'
|
|
3
|
+
import {
|
|
4
|
+
renderComponents,
|
|
5
|
+
renderCssRules,
|
|
6
|
+
resetRenderComponents,
|
|
7
|
+
resetRenderCssRules,
|
|
8
|
+
PublicationTransformer,
|
|
9
|
+
transformFiles,
|
|
10
|
+
transformBgImage
|
|
11
|
+
} from './publication-transformers'
|
|
12
|
+
import { ClientConfig } from './config'
|
|
13
|
+
import grapesjs, { Component, Editor, StyleProps, Page } from 'grapesjs'
|
|
14
|
+
import { ClientSideFile, ClientSideFileType, PublicationData } from '../types'
|
|
15
|
+
|
|
16
|
+
describe('publication-transformers', () => {
|
|
17
|
+
let mockConfig: ClientConfig
|
|
18
|
+
let mockFile: ClientSideFile
|
|
19
|
+
let mockData: PublicationData
|
|
20
|
+
let transformer: PublicationTransformer
|
|
21
|
+
|
|
22
|
+
let editor: Editor
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
// Initialize your mocks here
|
|
26
|
+
/* @ts-ignore */
|
|
27
|
+
editor = grapesjs.init({
|
|
28
|
+
headless: true,
|
|
29
|
+
storageManager: { autoload: false },
|
|
30
|
+
})
|
|
31
|
+
expect(editor).not.toBeUndefined()
|
|
32
|
+
editor.addComponents(`
|
|
33
|
+
<nav class="parent">
|
|
34
|
+
<div class="child">Hello world</div>
|
|
35
|
+
<nav>
|
|
36
|
+
`)
|
|
37
|
+
editor.addStyle(`
|
|
38
|
+
.parent {
|
|
39
|
+
color: red;
|
|
40
|
+
}
|
|
41
|
+
.child {
|
|
42
|
+
color: blue;
|
|
43
|
+
}
|
|
44
|
+
`)
|
|
45
|
+
mockFile = {
|
|
46
|
+
path: 'test path',
|
|
47
|
+
content: 'test content',
|
|
48
|
+
} as ClientSideFile
|
|
49
|
+
mockData = {
|
|
50
|
+
files: [mockFile],
|
|
51
|
+
pages: [{} as Page],
|
|
52
|
+
} as any as PublicationData
|
|
53
|
+
transformer = {
|
|
54
|
+
renderComponent: jest.fn(),
|
|
55
|
+
renderCssRule: jest.fn(),
|
|
56
|
+
transformFile: jest.fn(),
|
|
57
|
+
transformPermalink: jest.fn(),
|
|
58
|
+
transformPath: jest.fn(),
|
|
59
|
+
} as PublicationTransformer
|
|
60
|
+
mockConfig = { getEditor: jest.fn(() => editor), publicationTransformers: [transformer] } as unknown as ClientConfig
|
|
61
|
+
editor.getModel().set('config', mockConfig)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should transform components', () => {
|
|
65
|
+
const renderComponent = transformer.renderComponent as Mock
|
|
66
|
+
renderComponent.mockReturnValue('mockHtml')
|
|
67
|
+
renderComponents(editor)
|
|
68
|
+
const html = editor.getHtml()
|
|
69
|
+
expect(renderComponent).toBeCalledTimes(6)
|
|
70
|
+
const results = renderComponent.mock.calls.map(call => call[0] as Component)
|
|
71
|
+
const parent = results.find(c => c.getClasses()[0] === 'parent')
|
|
72
|
+
expect(parent).not.toBeUndefined()
|
|
73
|
+
const child = results.find(c => c.getClasses()[0] === 'child')
|
|
74
|
+
expect(child).not.toBeUndefined()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should reset transformed pages', () => {
|
|
78
|
+
const renderComponent = transformer.renderComponent as Mock
|
|
79
|
+
renderComponent.mockReturnValue('mockHtml')
|
|
80
|
+
renderComponents(editor)
|
|
81
|
+
resetRenderComponents(editor)
|
|
82
|
+
const html = editor.getHtml()
|
|
83
|
+
expect(renderComponent).toBeCalledTimes(0)
|
|
84
|
+
expect(html).toContain('Hello world')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should transform styles', () => {
|
|
88
|
+
const transformCssRule = transformer.renderCssRule as Mock
|
|
89
|
+
transformCssRule.mockImplementation((rule: any) => {
|
|
90
|
+
return { color: 'test'+rule.color } as StyleProps
|
|
91
|
+
})
|
|
92
|
+
renderCssRules(editor)
|
|
93
|
+
const css = editor.getCss()
|
|
94
|
+
expect(transformCssRule).toBeCalledTimes(2)
|
|
95
|
+
const results = transformCssRule.mock.results.map(r => r.value as StyleProps)
|
|
96
|
+
const parent = results.find(c => c.color === 'testred')
|
|
97
|
+
expect(parent).not.toBeUndefined()
|
|
98
|
+
const child = results.find(c => c.color === 'testblue')
|
|
99
|
+
expect(child).not.toBeUndefined()
|
|
100
|
+
expect(css).toContain('color:test')
|
|
101
|
+
expect(css).not.toContain('color:blue')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should reset transformed styles', () => {
|
|
105
|
+
const renderCssRule = transformer.renderCssRule as Mock
|
|
106
|
+
const returned = {color: 'test'} as StyleProps
|
|
107
|
+
renderCssRule.mockReturnValue(returned)
|
|
108
|
+
renderCssRules(editor)
|
|
109
|
+
resetRenderCssRules(editor)
|
|
110
|
+
const css = editor.getCss()
|
|
111
|
+
expect(renderCssRule).toBeCalledTimes(0)
|
|
112
|
+
expect(css).toContain('color:blue')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should transform files', () => {
|
|
116
|
+
const transformFile = transformer.transformFile as Mock
|
|
117
|
+
const returned = {path: 'test path changed', content: 'test content changed'} as ClientSideFile
|
|
118
|
+
transformFile.mockReturnValue(returned)
|
|
119
|
+
expect(mockData.files?.length).toBe(1)
|
|
120
|
+
if (mockData.files?.length) { // To avoid ! operator on mockData.files and make the lint happy
|
|
121
|
+
expect(mockData.files[0]).toBe(mockFile)
|
|
122
|
+
transformFiles(editor, mockData)
|
|
123
|
+
expect(transformFile).toBeCalledTimes(1)
|
|
124
|
+
expect(mockData.files[0]).toBe(returned)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
it('should transform permalinks of images src', () => {
|
|
128
|
+
editor.addComponents(`
|
|
129
|
+
<img src="test.png">
|
|
130
|
+
`)
|
|
131
|
+
const transformPermalink = transformer.transformPermalink as Mock
|
|
132
|
+
const transformedSrc = 'transformed.png'
|
|
133
|
+
transformPermalink.mockReturnValue(transformedSrc)
|
|
134
|
+
renderComponents(editor)
|
|
135
|
+
const html = editor.getHtml()
|
|
136
|
+
expect(transformPermalink).toBeCalledTimes(2) // 2x because of c.attributes.src and c.attributes.attributes.src
|
|
137
|
+
expect(transformPermalink.mock.calls[0][0]).toBe('test.png')
|
|
138
|
+
expect(transformPermalink.mock.calls[0][1]).toBe('asset')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should transform a style rule with background image', () => {
|
|
142
|
+
expect(transformBgImage(editor, { 'background-image': 'url(test.png)' })).toEqual({ 'background-image': 'url(test.png)' })
|
|
143
|
+
const transformPermalink = transformer.transformPermalink as Mock
|
|
144
|
+
const transformedSrc = 'transformed.png'
|
|
145
|
+
const transformedSrc2 = 'transformed2.png'
|
|
146
|
+
transformPermalink.mockImplementation((url, type) => (url as string).replace('test.png', transformedSrc).replace('test2.png', transformedSrc2))
|
|
147
|
+
expect(transformBgImage(editor, { 'background-image': 'url(test.png)' })).toEqual({ 'background-image': `url(${transformedSrc})` })
|
|
148
|
+
expect(transformBgImage(editor, { 'background-image': 'url("test.png")' })).toEqual({ 'background-image': `url(${transformedSrc})` })
|
|
149
|
+
expect(transformBgImage(editor, {
|
|
150
|
+
'background-image': 'linear-gradient(to right, rgb(30 75 115 / 100%), url(test.png), linear-gradient(to left, rgb(30 75 115 / 10%), url(test2.png), rgb(255 255 255 / 0%));',
|
|
151
|
+
})).toEqual({
|
|
152
|
+
'background-image': `linear-gradient(to right, rgb(30 75 115 / 100%), url(${transformedSrc}), linear-gradient(to left, rgb(30 75 115 / 10%), url(${transformedSrc2}), rgb(255 255 255 / 0%));`,
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should transform permalinks of background images in inline css', () => {
|
|
157
|
+
const el = document.createElement('div')
|
|
158
|
+
const [comp] = editor.addComponents(el)
|
|
159
|
+
comp.setStyle({ 'background-image': 'url(test.png)' })
|
|
160
|
+
//editor.addComponents(`
|
|
161
|
+
// <div style="color: black; background-image: url(test.png);"></div>
|
|
162
|
+
//`)
|
|
163
|
+
const transformPermalink = transformer.transformPermalink as Mock
|
|
164
|
+
const transformedSrc = 'transformed.png'
|
|
165
|
+
transformPermalink.mockReturnValue(transformedSrc)
|
|
166
|
+
renderComponents(editor)
|
|
167
|
+
const css = editor.getCss()
|
|
168
|
+
expect(transformPermalink).toBeCalledTimes(1)
|
|
169
|
+
expect(transformPermalink.mock.calls[0][0]).toBe('test.png')
|
|
170
|
+
expect(transformPermalink.mock.calls[0][1]).toBe('asset')
|
|
171
|
+
expect(css).toContain('url(test.png)')
|
|
172
|
+
})
|
|
173
|
+
it('should transform permalinks of background images in styles', () => {
|
|
174
|
+
editor.addComponents(`
|
|
175
|
+
<div class="test"></div>
|
|
176
|
+
`)
|
|
177
|
+
editor.addStyle(`
|
|
178
|
+
.test {
|
|
179
|
+
background-image: url(test.png);
|
|
180
|
+
}
|
|
181
|
+
`)
|
|
182
|
+
const transformPermalink = transformer.transformPermalink as Mock
|
|
183
|
+
const transformedSrc = 'transformed.png'
|
|
184
|
+
transformPermalink.mockReturnValue(transformedSrc)
|
|
185
|
+
renderCssRules(editor)
|
|
186
|
+
const css = editor.getCss()
|
|
187
|
+
expect(transformPermalink).toBeCalledTimes(1)
|
|
188
|
+
expect(transformPermalink.mock.calls[0][0]).toBe('test.png')
|
|
189
|
+
expect(transformPermalink.mock.calls[0][1]).toBe('asset')
|
|
190
|
+
expect(css).toContain(`url(${transformedSrc})`)
|
|
191
|
+
})
|
|
192
|
+
it('should transform links to pages to match permalinks ', () => {
|
|
193
|
+
editor.addComponents(`
|
|
194
|
+
<a href="./index.html">test</a>
|
|
195
|
+
`)
|
|
196
|
+
const transformPermalink = transformer.transformPermalink as Mock
|
|
197
|
+
const transformedPermalink = './transformed-page.html'
|
|
198
|
+
transformPermalink.mockReturnValue(transformedPermalink)
|
|
199
|
+
renderComponents(editor)
|
|
200
|
+
const html = editor.getHtml()
|
|
201
|
+
expect(transformPermalink).toBeCalledTimes(1)
|
|
202
|
+
expect((transformPermalink.mock.calls[0][0])).toBe('./index.html')
|
|
203
|
+
expect((transformPermalink.mock.calls[0][1])).toBe(ClientSideFileType.HTML)
|
|
204
|
+
expect(html).not.toContain('href="./index.html"')
|
|
205
|
+
expect(html).toContain(`href="${transformedPermalink}"`)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
@@ -0,0 +1,280 @@
|
|
|
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 { Component, CssRule, StyleProps, Editor } from 'grapesjs'
|
|
19
|
+
import { ClientSideFile, ClientSideFileType, Initiator, PublicationData } from '../types'
|
|
20
|
+
import { onAll } from './utils'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @fileoverview Silex publication transformers are used to control how the site is rendered and published
|
|
24
|
+
* Here we call path the path on the connector (either storage or hosting)
|
|
25
|
+
* We call permalink the path at which the resource is served
|
|
26
|
+
* This is where pages and assets paths and permalinks are set
|
|
27
|
+
* Here we also update background images urls, assets url and links to match the new permalinks
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// Properties names used to store the original methods on the components and styles
|
|
31
|
+
const ATTRIBUTE_METHOD_STORE_HTML = 'tmp-pre-publication-transformer-tohtml'
|
|
32
|
+
const ATTRIBUTE_METHOD_STORE_SRC = 'tmp-pre-publication-transformer-src'
|
|
33
|
+
const ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC = 'tmp-pre-publication-transformer-attributes-src'
|
|
34
|
+
const ATTRIBUTE_METHOD_STORE_INLINE_CSS = 'tmp-pre-publication-transformer-inline-css'
|
|
35
|
+
const ATTRIBUTE_METHOD_STORE_HREF = 'tmp-pre-publication-transformer-href'
|
|
36
|
+
const ATTRIBUTE_METHOD_STORE_CSS = 'tmp-pre-publication-transformer-tocss'
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Interface for publication transformers
|
|
40
|
+
* They are added to the config object with config.addPublicationTransformer()
|
|
41
|
+
*/
|
|
42
|
+
export interface PublicationTransformer {
|
|
43
|
+
// Temporarily override how components render at publication by grapesjs
|
|
44
|
+
renderComponent?(component: Component, toHtml: () => string): string | undefined
|
|
45
|
+
// Temporarily override how styles render at publication by grapesjs
|
|
46
|
+
renderCssRule?(rule: CssRule, initialRule: () => StyleProps): StyleProps | undefined
|
|
47
|
+
// Transform files after they are rendered and before they are published
|
|
48
|
+
transformFile?(file: ClientSideFile): ClientSideFile
|
|
49
|
+
// Define files URLs
|
|
50
|
+
transformPermalink?(link: string, type: ClientSideFileType, initiator: Initiator): string
|
|
51
|
+
// Define where files are published
|
|
52
|
+
transformPath?(path: string, type: ClientSideFileType): string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const publicationTransformerDefault: PublicationTransformer = {
|
|
56
|
+
// Override how components render at publication by grapesjs
|
|
57
|
+
renderComponent(component: Component, toHtml: () => string): string | undefined {
|
|
58
|
+
return toHtml()
|
|
59
|
+
},
|
|
60
|
+
// Override how styles render at publication by grapesjs
|
|
61
|
+
renderCssRule(rule: CssRule, initialRule: () => StyleProps): StyleProps | undefined {
|
|
62
|
+
return initialRule()
|
|
63
|
+
},
|
|
64
|
+
// Define where files are published
|
|
65
|
+
transformPath(path: string, type: ClientSideFileType): string {
|
|
66
|
+
return path
|
|
67
|
+
},
|
|
68
|
+
// Define files URLs
|
|
69
|
+
transformPermalink(link: string, type: ClientSideFileType, initiator: Initiator): string {
|
|
70
|
+
switch(initiator) {
|
|
71
|
+
case Initiator.HTML:
|
|
72
|
+
return link
|
|
73
|
+
case Initiator.CSS:
|
|
74
|
+
// In case of a link from a CSS file, we need to go up one level
|
|
75
|
+
return `../${link.replace(/^\//, '')}`
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`Unknown initiator ${initiator}`)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
// Define how files are named
|
|
81
|
+
transformFile(file: ClientSideFile): ClientSideFile {
|
|
82
|
+
return file
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function validatePublicationTransformer(transformer: PublicationTransformer): void {
|
|
87
|
+
// List all the properties
|
|
88
|
+
const allowedProperties = [
|
|
89
|
+
'renderComponent',
|
|
90
|
+
'renderCssRule',
|
|
91
|
+
'transformFile',
|
|
92
|
+
'transformPermalink',
|
|
93
|
+
'transformPath',
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
// Check that there are no unknown properties
|
|
97
|
+
Object.keys(transformer).forEach(key => {
|
|
98
|
+
if(!allowedProperties.includes(key)) {
|
|
99
|
+
throw new Error(`Publication transformer: unknown property ${key}`)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
// Check that the methods are functions
|
|
104
|
+
allowedProperties.forEach(key => {
|
|
105
|
+
if(typeof transformer[key] !== 'function' && transformer[key] !== undefined) {
|
|
106
|
+
throw new Error(`Publication transformer: ${key} must be a function`)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Alter the components rendering
|
|
113
|
+
* Exported for unit tests
|
|
114
|
+
*/
|
|
115
|
+
export function renderComponents(editor: Editor) {
|
|
116
|
+
const config = editor.getModel().get('config')
|
|
117
|
+
onAll(editor, (c: Component) => {
|
|
118
|
+
if (c.get(ATTRIBUTE_METHOD_STORE_HTML)) {
|
|
119
|
+
console.warn('Publication transformer: HTML transform already altered', c)
|
|
120
|
+
} else {
|
|
121
|
+
const initialToHTML = c.toHTML.bind(c)
|
|
122
|
+
c[ATTRIBUTE_METHOD_STORE_HTML] = c.toHTML
|
|
123
|
+
const initialGetStyle = c.getStyle.bind(c)
|
|
124
|
+
c[ATTRIBUTE_METHOD_STORE_INLINE_CSS] = c.getStyle
|
|
125
|
+
const href = c.get('attributes').href as string | undefined
|
|
126
|
+
if(href?.startsWith('./')) {
|
|
127
|
+
c[ATTRIBUTE_METHOD_STORE_HREF] = href
|
|
128
|
+
c.set('attributes', {
|
|
129
|
+
...c.get('attributes'),
|
|
130
|
+
href: transformPermalink(editor, href, ClientSideFileType.HTML, Initiator.HTML),
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
// Handle both c.attributes.src and c.attributes.attributes.src
|
|
134
|
+
// For some reason we need both
|
|
135
|
+
// Especially when the component is not on the current page, we need c.attributes.attributes.src
|
|
136
|
+
if(c.get('attributes').src) {
|
|
137
|
+
c[ATTRIBUTE_METHOD_STORE_SRC] = c.get('attributes').src
|
|
138
|
+
const src = transformPermalink(editor, c.get('attributes').src, ClientSideFileType.ASSET, Initiator.HTML)
|
|
139
|
+
c.set('attributes', {
|
|
140
|
+
...c.get('attributes'),
|
|
141
|
+
src,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
if(c.get('src')) {
|
|
145
|
+
c[ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC] = c.get('src')
|
|
146
|
+
const src = transformPermalink(editor, c.get('src'), ClientSideFileType.ASSET, Initiator.HTML)
|
|
147
|
+
c.set('src', src)
|
|
148
|
+
}
|
|
149
|
+
c.toHTML = () => {
|
|
150
|
+
return config.publicationTransformers.reduce((html: string, transformer: PublicationTransformer) => {
|
|
151
|
+
return transformer.renderComponent ? transformer.renderComponent(c, () => html) ?? html : html
|
|
152
|
+
}, initialToHTML())
|
|
153
|
+
}
|
|
154
|
+
c.getStyle = () => transformBgImage(editor, initialGetStyle())
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Alter the styles rendering
|
|
161
|
+
* Exported for unit tests
|
|
162
|
+
*/
|
|
163
|
+
export function renderCssRules(editor: Editor) {
|
|
164
|
+
const config = editor.getModel().get('config')
|
|
165
|
+
editor.Css.getAll().forEach((style: CssRule) => {
|
|
166
|
+
if (style[ATTRIBUTE_METHOD_STORE_CSS]) {
|
|
167
|
+
console.warn('Publication transformer: CSS transform already altered', style)
|
|
168
|
+
} else {
|
|
169
|
+
const initialGetStyle = style.getStyle.bind(style)
|
|
170
|
+
style[ATTRIBUTE_METHOD_STORE_CSS] = style.getStyle
|
|
171
|
+
style.getStyle = () => {
|
|
172
|
+
const initialStyle = transformBgImage(editor, initialGetStyle())
|
|
173
|
+
const result = config.publicationTransformers.reduce((s: CssRule, transformer: PublicationTransformer) => {
|
|
174
|
+
return {
|
|
175
|
+
...transformer.renderCssRule ? transformer.renderCssRule(s, () => initialStyle) ?? s : s,
|
|
176
|
+
}
|
|
177
|
+
}, initialStyle)
|
|
178
|
+
return result
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function doTransformPermalink(editor: Editor, cssValue: string): string {
|
|
185
|
+
return cssValue.replace(/url\(([^)]+)\)/g, (match, url) => {
|
|
186
|
+
// Support URLs with or without quotes
|
|
187
|
+
const cleanUrl = url.replace(/['"]/g, '')
|
|
188
|
+
// Transform URLs
|
|
189
|
+
const newUrl = transformPermalink(editor, cleanUrl, ClientSideFileType.ASSET, Initiator.CSS)
|
|
190
|
+
// Return the new URL with url keyword
|
|
191
|
+
return `url(${newUrl})`
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Transform background image url according to the transformed path of assets
|
|
197
|
+
*/
|
|
198
|
+
export function transformBgImage(editor: Editor, style: StyleProps): StyleProps {
|
|
199
|
+
const cssValue = style['background-image']
|
|
200
|
+
if (cssValue) {
|
|
201
|
+
const newCssValue = typeof cssValue === 'string' ? doTransformPermalink(editor, cssValue) : cssValue.map(value => doTransformPermalink(editor, value))
|
|
202
|
+
return {
|
|
203
|
+
...style,
|
|
204
|
+
'background-image': newCssValue,
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return style
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Transform files
|
|
212
|
+
* Exported for unit tests
|
|
213
|
+
*/
|
|
214
|
+
export function transformFiles(editor: Editor, data: PublicationData) {
|
|
215
|
+
const config = editor.getModel().get('config')
|
|
216
|
+
data.files = config.publicationTransformers.reduce((files: ClientSideFile[], transformer: PublicationTransformer) => {
|
|
217
|
+
return files.map((file, idx) => {
|
|
218
|
+
const page = data.pages[idx] ?? null
|
|
219
|
+
return transformer.transformFile ? transformer.transformFile(file) as ClientSideFile ?? file : file
|
|
220
|
+
})
|
|
221
|
+
}, data.files)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Transform files paths
|
|
226
|
+
* Exported for unit tests
|
|
227
|
+
*/
|
|
228
|
+
export function transformPermalink(editor: Editor, path: string, type: ClientSideFileType, initiator: Initiator): string {
|
|
229
|
+
const config = editor.getModel().get('config')
|
|
230
|
+
return config.publicationTransformers.reduce((result: string, transformer: PublicationTransformer) => {
|
|
231
|
+
return transformer.transformPermalink ? transformer.transformPermalink(result, type, initiator) ?? result : result
|
|
232
|
+
}, path)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function transformPath(editor: Editor, path: string, type: ClientSideFileType): string {
|
|
236
|
+
const config = editor.getModel().get('config')
|
|
237
|
+
return config.publicationTransformers.reduce((result: string, transformer: PublicationTransformer) => {
|
|
238
|
+
return transformer.transformPath ? transformer.transformPath(result, type) ?? result : result
|
|
239
|
+
}, path)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function resetRenderComponents(editor: Editor) {
|
|
243
|
+
onAll(editor, (c: Component) => {
|
|
244
|
+
if (c[ATTRIBUTE_METHOD_STORE_HTML]) {
|
|
245
|
+
c.toHTML = c[ATTRIBUTE_METHOD_STORE_HTML]
|
|
246
|
+
delete c[ATTRIBUTE_METHOD_STORE_HTML]
|
|
247
|
+
}
|
|
248
|
+
if (c[ATTRIBUTE_METHOD_STORE_INLINE_CSS]) {
|
|
249
|
+
c.getStyle = c[ATTRIBUTE_METHOD_STORE_INLINE_CSS]
|
|
250
|
+
delete c[ATTRIBUTE_METHOD_STORE_INLINE_CSS]
|
|
251
|
+
}
|
|
252
|
+
if(c[ATTRIBUTE_METHOD_STORE_SRC]) {
|
|
253
|
+
c.set('attributes', {
|
|
254
|
+
...c.get('attributes'),
|
|
255
|
+
src: c[ATTRIBUTE_METHOD_STORE_SRC],
|
|
256
|
+
})
|
|
257
|
+
delete c[ATTRIBUTE_METHOD_STORE_SRC]
|
|
258
|
+
}
|
|
259
|
+
if(c[ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC]) {
|
|
260
|
+
c.set('src', c[ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC])
|
|
261
|
+
delete c[ATTRIBUTE_METHOD_STORE_ATTRIBUTES_SRC]
|
|
262
|
+
}
|
|
263
|
+
if(c[ATTRIBUTE_METHOD_STORE_HREF]) {
|
|
264
|
+
c.set('attributes', {
|
|
265
|
+
...c.get('attributes'),
|
|
266
|
+
href: c[ATTRIBUTE_METHOD_STORE_HREF],
|
|
267
|
+
})
|
|
268
|
+
delete c[ATTRIBUTE_METHOD_STORE_HREF]
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function resetRenderCssRules(editor: Editor) {
|
|
274
|
+
editor.Css.getAll().forEach(c => {
|
|
275
|
+
if (c[ATTRIBUTE_METHOD_STORE_CSS]) {
|
|
276
|
+
c.getStyle = c[ATTRIBUTE_METHOD_STORE_CSS]
|
|
277
|
+
delete c[ATTRIBUTE_METHOD_STORE_CSS]
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
}
|
|
@@ -14,12 +14,18 @@
|
|
|
14
14
|
* You should have received a copy of the GNU Affero General Public License
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @fileoverview Make sure custom script blocks include script tags when published
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export default async function (config) {
|
|
23
|
+
config.addPublicationTransformers({
|
|
24
|
+
renderComponent(component, toHtml) {
|
|
25
|
+
if (component.get('type') === 'custom-code' && component.get('custom-code-plugin__code')) {
|
|
26
|
+
return component.get('custom-code-plugin__code')
|
|
27
|
+
}
|
|
28
|
+
return toHtml()
|
|
29
|
+
},
|
|
30
|
+
})
|
|
24
31
|
}
|
|
25
|
-
//# sourceMappingURL=utils.js.map
|