@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
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
import {html, render} from 'lit-html'
|
|
19
19
|
import {map} from 'lit-html/directives/map.js'
|
|
20
|
-
import grapesjs from 'grapesjs/dist/grapes.min.js'
|
|
21
20
|
|
|
22
21
|
// constants
|
|
23
22
|
const pluginName = 'semantic'
|
|
@@ -48,7 +47,7 @@ const tags = [
|
|
|
48
47
|
]
|
|
49
48
|
|
|
50
49
|
// plugin code
|
|
51
|
-
export const semanticPlugin =
|
|
50
|
+
export const semanticPlugin = (editor, opts) => {
|
|
52
51
|
// Add the new trait to all component types
|
|
53
52
|
editor.DomComponents.getTypes().map(type => {
|
|
54
53
|
editor.DomComponents.addType(type.id, {
|
|
@@ -61,6 +60,7 @@ export const semanticPlugin = grapesjs.plugins.add(pluginName, (editor, opts) =>
|
|
|
61
60
|
{
|
|
62
61
|
label: 'Tag name',
|
|
63
62
|
type: 'tag-name',
|
|
63
|
+
name: 'tag-name',
|
|
64
64
|
},
|
|
65
65
|
]
|
|
66
66
|
}
|
|
@@ -111,4 +111,4 @@ export const semanticPlugin = grapesjs.plugins.add(pluginName, (editor, opts) =>
|
|
|
111
111
|
doRender(elInput, tagName)
|
|
112
112
|
},
|
|
113
113
|
})
|
|
114
|
-
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {live} from 'lit-html/directives/live.js'
|
|
2
|
+
import {html, TemplateResult} from 'lit-html'
|
|
3
|
+
import { WebsiteSettings } from '../../types'
|
|
4
|
+
|
|
5
|
+
// ID of the code editor wrapper
|
|
6
|
+
export const idCodeWrapper = 'settings-head-wrapper'
|
|
7
|
+
|
|
8
|
+
// Is the model a site or a page?
|
|
9
|
+
export function isSite(model: any) { return !!model.getHtml }
|
|
10
|
+
|
|
11
|
+
export interface SettingsSection {
|
|
12
|
+
id: string
|
|
13
|
+
label: string
|
|
14
|
+
render: (settings: WebsiteSettings, model: Backbone.Model) => TemplateResult
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* This is the settings dialog default sections
|
|
19
|
+
* Each section has an entry in the sidebar
|
|
20
|
+
* Each section render as part of the settings form
|
|
21
|
+
* The form is submitted to save the settings with all FormData
|
|
22
|
+
*/
|
|
23
|
+
export const defaultSections: SettingsSection[] = [{
|
|
24
|
+
id: 'general',
|
|
25
|
+
label: 'General',
|
|
26
|
+
render: (settings, model) => html`
|
|
27
|
+
<div id="settings-general" class="silex-hideable">
|
|
28
|
+
<div class="gjs-sm-sector-title">General</div>
|
|
29
|
+
<div class="silex-form__group col2">
|
|
30
|
+
<label class="silex-form__element">
|
|
31
|
+
<h3>${isSite(model) ? 'Site name' : 'Page name'}</h3>
|
|
32
|
+
<p class="silex-help">${isSite(model) ? 'The project name in the editor, for you to remember what it is about.' : 'Label of the page in the editor, and file name of the published HTML page.'}</p>
|
|
33
|
+
<input type="text" name="name" .value=${live(model.get('name') || '')}/>
|
|
34
|
+
</label>
|
|
35
|
+
<label class="silex-form__element">
|
|
36
|
+
<h3>Website language</h3>
|
|
37
|
+
<p class="silex-help">This is the default language code for this website. Example: en, fr, es...</p>
|
|
38
|
+
<input type="text" name="lang" .value=${live(settings.lang || '')}/>
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
`,
|
|
43
|
+
}, {
|
|
44
|
+
id: 'seo',
|
|
45
|
+
label: 'SEO',
|
|
46
|
+
render: (settings, model) => html`
|
|
47
|
+
<div id="settings-seo" class="silex-hideable silex-hidden">
|
|
48
|
+
<div class="gjs-sm-sector-title">SEO</div>
|
|
49
|
+
<div class="silex-form__group col2">
|
|
50
|
+
<label class="silex-form__element">
|
|
51
|
+
<h3>Title</h3>
|
|
52
|
+
<p class="silex-help">Title of the browser window, and title in the search engines results. It is used by search engines to find out what your site is talking about. The title should be a maximum of 70 characters long, including spaces.</p>
|
|
53
|
+
<input type="text" name="title" .value=${live(settings.title || '')}/>
|
|
54
|
+
</label>
|
|
55
|
+
<label class="silex-form__element">
|
|
56
|
+
<h3>Description</h3>
|
|
57
|
+
<p class="silex-help">Description displayed by the search engines in search results. It is used by search engines to find out what your site is talking about. It is best to keep meta descriptions between 150 and 160 characters.</p>
|
|
58
|
+
<input type="text" name="description" .value=${live(settings.description || '')}/>
|
|
59
|
+
</label>
|
|
60
|
+
<label class="silex-form__element">
|
|
61
|
+
<h3>Favicon</h3>
|
|
62
|
+
<p class="silex-help">Small image displayed in the browser's address bar and in tabs. The recommended size is 16×16 or 32×32 pixels. This can be a URL or a relative path.</p>
|
|
63
|
+
<input type="text" name="favicon" .value=${live(settings.favicon || '')}/>
|
|
64
|
+
</label>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
`,
|
|
68
|
+
}, {
|
|
69
|
+
id: 'social',
|
|
70
|
+
label: 'Social',
|
|
71
|
+
render: (settings, model) => html`
|
|
72
|
+
<div id="settings-social" class="silex-hideable silex-hidden">
|
|
73
|
+
<div class="gjs-sm-sector-title">Social</div>
|
|
74
|
+
<div class="silex-help">
|
|
75
|
+
<p>Once your website is live, you can use these tools to test sharing: <a target="_blank" href="https://developers.facebook.com/tools/debug/">Facebook</a>,
|
|
76
|
+
<a target="_blank" href="https://cards-dev.twitter.com/validator">Twitter</a>,
|
|
77
|
+
<a target="_blank" href="https://www.linkedin.com/post-inspector/inspect/">Linkedin</a></p>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="silex-form__group col2">
|
|
80
|
+
<label class="silex-form__element">
|
|
81
|
+
<h3>Title</h3>
|
|
82
|
+
<p class="silex-help">The title of your website displayed when a user shares your website on a social network.
|
|
83
|
+
Do not include any branding in this title, just eye-catching phrase, e.g. "Learn everything about fishing".
|
|
84
|
+
Title should be between 60 and 90 characters long.</p>
|
|
85
|
+
<input type="text" name="og:title" .value=${live(settings['og:title'] || '')}/>
|
|
86
|
+
</label>
|
|
87
|
+
<label class="silex-form__element">
|
|
88
|
+
<h3>Description</h3>
|
|
89
|
+
<p class="silex-help">Description displayed when a user shares your website on a social network. Make it catchy, and invite readers to visit your website too, e.g. "Sam's website about fishing, check it out!" Title should be between 60 and 90 characters long.</p>
|
|
90
|
+
<input type="text" name="og:description" .value=${live(settings['og:description'] || '')}/>
|
|
91
|
+
</label>
|
|
92
|
+
<label class="silex-form__element">
|
|
93
|
+
<h3>Image</h3>
|
|
94
|
+
<div class="silex-help">
|
|
95
|
+
<p>Thumbnail image which is displayed when your website is shared on a social network. The optimal size is 1200×627 pixels. At this size, your thumbnail will be big and stand out from the crowd. But do not exceed the 5MB size limit. If you use an image that is smaller than 400 pixels x 209 pixels, it will render as a much smaller thumbnail.</p>
|
|
96
|
+
<p>Please enter the full URL here, e.g. "http://mysite.com/path/to/image.jpg"</p>
|
|
97
|
+
</div>
|
|
98
|
+
<input type="text" name="og:image" .value=${live(settings['og:image'] || '')}/>
|
|
99
|
+
</label>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
`,
|
|
103
|
+
}, {
|
|
104
|
+
id: 'code',
|
|
105
|
+
label: 'Code',
|
|
106
|
+
render: (settings, model) => html`
|
|
107
|
+
<div id="settings-code" class="silex-hideable silex-hidden">
|
|
108
|
+
<div class="gjs-sm-sector-title">Code</div>
|
|
109
|
+
<div class="silex-form__group">
|
|
110
|
+
<label class="silex-form__element" id="${idCodeWrapper}">
|
|
111
|
+
<h3>HTML head</h3>
|
|
112
|
+
<p class="silex-help">HTML code which will be inserted in the HEAD tag.</p>
|
|
113
|
+
</label>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
`,
|
|
117
|
+
}]
|
|
@@ -15,30 +15,27 @@
|
|
|
15
15
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {html, render} from 'lit-html'
|
|
19
|
-
import {
|
|
20
|
-
|
|
18
|
+
import {html, render, TemplateResult} from 'lit-html'
|
|
19
|
+
import {defaultSections, idCodeWrapper, isSite, SettingsSection} from './settings-sections'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @fileoverview This file contains the settings dialog. The config API lets plugins add sections to the settings dialog.
|
|
23
|
+
*/
|
|
21
24
|
|
|
22
25
|
import { WebsiteSettings } from '../../types'
|
|
26
|
+
import { ClientEvent } from '../events'
|
|
27
|
+
import { SILEX_VERSION } from '../../constants'
|
|
28
|
+
|
|
29
|
+
const sectionsSite = [...defaultSections]
|
|
30
|
+
const sectionsPage = [...defaultSections]
|
|
23
31
|
|
|
24
|
-
const pluginName = 'settings-dialog'
|
|
25
32
|
const el = document.createElement('div')
|
|
26
33
|
let modal
|
|
27
34
|
|
|
28
|
-
// Get version from webpack (see plugin in webpack.config.js)
|
|
29
|
-
declare const VERSION: string
|
|
30
|
-
|
|
31
35
|
export const cmdOpenSettings = 'open-settings'
|
|
32
36
|
|
|
33
|
-
let
|
|
34
|
-
export const settingsDialog =
|
|
35
|
-
// Display Silex version from package.json
|
|
36
|
-
try {
|
|
37
|
-
version = VERSION
|
|
38
|
-
} catch (error) {
|
|
39
|
-
// Cannot get version from webpack (see plugin in webpack.config.js)
|
|
40
|
-
}
|
|
41
|
-
console.log('Silex version:', version)
|
|
37
|
+
let headEditor = null
|
|
38
|
+
export const settingsDialog = (editor, opts) => {
|
|
42
39
|
editor.Commands.add(cmdOpenSettings, {
|
|
43
40
|
run: (_, sender, {page}) => {
|
|
44
41
|
modal = editor.Modal.open({
|
|
@@ -47,6 +44,7 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
|
|
|
47
44
|
attributes: { class: 'settings-dialog' },
|
|
48
45
|
})
|
|
49
46
|
.onceClose(() => {
|
|
47
|
+
sender?.set && sender.set('active', 0) // Deactivate the button to make it ready to be clicked again, only in case of a grapesjs button (not in the pages panel)
|
|
50
48
|
editor.stopCommand(cmdOpenSettings) // apparently this is needed to be able to run the command several times
|
|
51
49
|
})
|
|
52
50
|
displaySettings(editor, opts, page)
|
|
@@ -54,14 +52,20 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
|
|
|
54
52
|
const form = el.querySelector('form')
|
|
55
53
|
form.onsubmit = event => {
|
|
56
54
|
event.preventDefault()
|
|
55
|
+
editor.trigger(ClientEvent.SETTINGS_SAVE_START, page)
|
|
57
56
|
saveSettings(editor, opts, page)
|
|
57
|
+
editor.trigger(ClientEvent.SETTINGS_SAVE_END, page)
|
|
58
58
|
editor.stopCommand(cmdOpenSettings)
|
|
59
59
|
}
|
|
60
60
|
form.querySelector('input')?.focus()
|
|
61
|
+
// Notify other plugins
|
|
62
|
+
editor.trigger(ClientEvent.SETTINGS_OPEN, page)
|
|
63
|
+
// Return the dialog
|
|
61
64
|
return modal
|
|
62
65
|
},
|
|
63
66
|
stop: () => {
|
|
64
67
|
modal.close()
|
|
68
|
+
editor.trigger(ClientEvent.SETTINGS_CLOSE)
|
|
65
69
|
},
|
|
66
70
|
})
|
|
67
71
|
// add settings to the website
|
|
@@ -73,93 +77,156 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
|
|
|
73
77
|
const model = editor.getModel()
|
|
74
78
|
model.set('settings', data.settings || {})
|
|
75
79
|
model.set('name', data.name)
|
|
80
|
+
editor.once('canvas:frame:load', () => {
|
|
81
|
+
updateDom(editor)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
// Normal way to apply the head content to the DOM
|
|
85
|
+
// fix #1559 Custom <head> code must be reapplied
|
|
86
|
+
editor.on('canvas:frame:load', () => {
|
|
76
87
|
updateDom(editor)
|
|
77
88
|
})
|
|
89
|
+
// When the page changes, update the dom
|
|
78
90
|
editor.on('page', (e) => {
|
|
79
|
-
editor
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
updateDom(editor)
|
|
92
|
+
})
|
|
93
|
+
headEditor = editor.CodeManager.createViewer({
|
|
94
|
+
readOnly: false,
|
|
95
|
+
codeName: 'htmlmixed',
|
|
96
|
+
lineNumbers: true,
|
|
97
|
+
lineWrapping: true,
|
|
98
|
+
autoFormat: false,
|
|
82
99
|
})
|
|
83
|
-
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function showSection(item: SettingsSection) {
|
|
103
|
+
// **
|
|
104
|
+
// Handle the side bar
|
|
105
|
+
const aside = el.querySelector('aside.silex-bar') as HTMLElement
|
|
106
|
+
const ul = aside.querySelector('ul.silex-list--menu') as HTMLUListElement
|
|
107
|
+
const li = ul.querySelector('li#settings-sidebar-' + item.id) as HTMLLIElement
|
|
108
|
+
currentSection = item
|
|
109
|
+
if(!li) {
|
|
110
|
+
console.warn('Cannot find section', item.id, 'in the side bar, fallback to the first section')
|
|
111
|
+
if(!defaultSections[0] || defaultSections[0].id === item.id) {
|
|
112
|
+
console.error('Cannot find the default section in the side bar')
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
showSection(defaultSections[0]) // Fallback to the first section
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
// Update active
|
|
119
|
+
Array.from(ul.querySelectorAll('.active')).forEach(el => el.classList.remove('active'))
|
|
120
|
+
li.classList.add('active')
|
|
121
|
+
// **
|
|
122
|
+
// Handle the main section
|
|
123
|
+
const main = el.querySelector('main#settings__main') as HTMLElement
|
|
124
|
+
const mainItem = main.querySelector(`#settings-${item.id}`)
|
|
125
|
+
if(!mainItem) {
|
|
126
|
+
console.warn('Cannot find section', item.id, 'in the settings dialog, fallback to the first section')
|
|
127
|
+
if(!defaultSections[0] || defaultSections[0].id === item.id) {
|
|
128
|
+
console.error('Cannot find the default section in the settings dialog')
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
showSection(defaultSections[0]) // Fallback to the first section
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
// Update hidden
|
|
135
|
+
Array.from(main.querySelectorAll('.silex-hideable')).forEach(el => el.classList.add('silex-hidden'))
|
|
136
|
+
mainItem.classList.remove('silex-hidden')
|
|
137
|
+
// This messes up with the save / cancel mechanism
|
|
138
|
+
// displaySettings(editor, config, model)
|
|
139
|
+
// Refresh the code editor just in case it went from hidden to visible
|
|
140
|
+
// This makes it ready to be used when the user clicks on the tab
|
|
141
|
+
headEditor.refresh()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function addSection(section, siteOrPage: 'site' | 'page', position: 'first' | 'last' | number) {
|
|
145
|
+
const sections = siteOrPage === 'site' ? sectionsSite : sectionsPage
|
|
146
|
+
if (position === 'first') {
|
|
147
|
+
sections.unshift(section)
|
|
148
|
+
} else if (position === 'last') {
|
|
149
|
+
sections.push(section)
|
|
150
|
+
} else if (typeof position === 'number') {
|
|
151
|
+
sections.splice(position, 0, section)
|
|
152
|
+
} else {
|
|
153
|
+
throw new Error('Invalid position for settings section')
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function removeSection(id, siteOrPage: 'site' | 'page') {
|
|
158
|
+
const sections = siteOrPage === 'site' ? sectionsSite : sectionsPage
|
|
159
|
+
const index = sections.findIndex(section => section.id === id)
|
|
160
|
+
if(index === -1) throw new Error(`Cannot find section with id ${id}`)
|
|
161
|
+
sections.splice(index, 1)
|
|
162
|
+
}
|
|
84
163
|
|
|
85
|
-
// Is the model a site or a page?
|
|
86
|
-
function isSite(model) { return !!model.getHtml }
|
|
87
164
|
|
|
165
|
+
let currentSection
|
|
88
166
|
function displaySettings(editor, config, model = editor.getModel()) {
|
|
167
|
+
// Update the model with the current settings
|
|
89
168
|
const settings = model.get('settings') || {} as WebsiteSettings
|
|
90
169
|
model.set('settings', settings)
|
|
170
|
+
// Get the current sections for page or site
|
|
171
|
+
const menuItemsCurrent = isSite(model) ? sectionsSite : sectionsPage
|
|
172
|
+
// Init the current section selection
|
|
173
|
+
currentSection = currentSection || menuItemsCurrent[0]
|
|
174
|
+
const sections: TemplateResult[] = menuItemsCurrent.map(item => {
|
|
175
|
+
try {
|
|
176
|
+
return item.render(settings, model)
|
|
177
|
+
} catch (e) {
|
|
178
|
+
console.error('Error rendering settings section', item.id, e)
|
|
179
|
+
return html`<div class="silex-error">Error rendering settings section ${item.id}</div>`
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
// Render the settings dialog
|
|
91
183
|
render(html`
|
|
92
|
-
<p>The page settings will override site settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
|
|
93
184
|
<form class="silex-form">
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<h3>Website language</h3>
|
|
103
|
-
<p>This is the default language code for this website. Example: en, fr, es...</p>
|
|
104
|
-
<input type="text" name="lang" .value=${live(settings.lang || '')}/>
|
|
105
|
-
</label>
|
|
106
|
-
<label class="silex-form__element">
|
|
107
|
-
<h3>Title</h3>
|
|
108
|
-
<p>Title of the browser window, and title in the search engines results. It is used by search engines to find out what your site is talking about. The title should be a maximum of 70 characters long, including spaces.</p>
|
|
109
|
-
<input type="text" name="title" .value=${live(settings.title || '')}/>
|
|
110
|
-
</label>
|
|
111
|
-
<label class="silex-form__element">
|
|
112
|
-
<h3>Description</h3>
|
|
113
|
-
<p>Description displayed by the search engines in search results. It is used by search engines to find out what your site is talking about. It is best to keep meta descriptions between 150 and 160 characters.</p>
|
|
114
|
-
<input type="text" name="description" .value=${live(settings.description || '')}/>
|
|
115
|
-
</label>
|
|
116
|
-
<label class="silex-form__element">
|
|
117
|
-
<h3>Favicon</h3>
|
|
118
|
-
<p>Small image displayed in the browser's address bar and in tabs. The recommended size is 16×16 or 32×32 pixels. This can be a URL or a relative path.</p>
|
|
119
|
-
<input type="text" name="favicon" .value=${live(settings.favicon || '')}/>
|
|
120
|
-
</label>
|
|
121
|
-
</div>
|
|
122
|
-
<h2>Social networks sharing</h2>
|
|
123
|
-
<div>
|
|
124
|
-
<p>Once your website is live, you can use these tools to test sharing: <a target="_blank" href="https://developers.facebook.com/tools/debug/">Facebook</a>,
|
|
125
|
-
<a target="_blank" href="https://cards-dev.twitter.com/validator">Twitter</a>,
|
|
126
|
-
<a target="_blank" href="https://www.linkedin.com/post-inspector/inspect/">Linkedin</a></p>
|
|
127
|
-
</div>
|
|
128
|
-
<div class="silex-form__group col2">
|
|
129
|
-
<label class="silex-form__element">
|
|
130
|
-
<h3>Title</h3>
|
|
131
|
-
<p>The title of your website displayed when a user shares your website on a social network.
|
|
132
|
-
Do not include any branding in this title, just eye-catching phrase, e.g. "Learn everything about fishing".
|
|
133
|
-
Title should be between 60 and 90 characters long.</p>
|
|
134
|
-
<input type="text" name="og:title" .value=${live(settings['og:title'] || '')}/>
|
|
135
|
-
</label>
|
|
136
|
-
<label class="silex-form__element">
|
|
137
|
-
<h3>Description</h3>
|
|
138
|
-
<p>Description displayed when a user shares your website on a social network. Make it catchy, and invite readers to visit your website too, e.g. "Sam's website about fishing, check it out!" Title should be between 60 and 90 characters long.</p>
|
|
139
|
-
<input type="text" name="og:description" .value=${live(settings['og:description'] || '')}/>
|
|
140
|
-
</label>
|
|
141
|
-
<label class="silex-form__element">
|
|
142
|
-
<h3>Image</h3>
|
|
143
|
-
<p>Thumbnail image which is displayed when your website is shared on a social network. The optimal size is 1200×627 pixels. At this size, your thumbnail will be big and stand out from the crowd. But do not exceed the 5MB size limit. If you use an image that is smaller than 400 pixels x 209 pixels, it will render as a much smaller thumbnail.</p>
|
|
144
|
-
<p>Please enter the full URL here, e.g. "http://mysite.com/path/to/image.jpg"</p>
|
|
145
|
-
<input type="text" name="og:image" .value=${live(settings['og:image'] || '')}/>
|
|
146
|
-
</label>
|
|
147
|
-
</div>
|
|
148
|
-
<h2>Code</h2>
|
|
149
|
-
<div class="silex-form__group">
|
|
150
|
-
<label class="silex-form__element">
|
|
151
|
-
<h3>HTML head</h3>
|
|
152
|
-
<p>HTML code which will be inserted in the HEAD tag.</p>
|
|
153
|
-
<textarea name="head" .value=${live(settings.head || '')}></textarea>
|
|
154
|
-
</label>
|
|
185
|
+
<div class="silex-help">
|
|
186
|
+
${isSite(model) ? html`
|
|
187
|
+
<p>Here you can set the name of your website, SEO and social networks sharing data.</p>
|
|
188
|
+
<p>These settings are overriden by the page settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
|
|
189
|
+
` : html`
|
|
190
|
+
<p>Here you can set the name of your page, SEO and social networks sharing data.</p>
|
|
191
|
+
<p>These settings override the site settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
|
|
192
|
+
`}
|
|
155
193
|
</div>
|
|
194
|
+
<section class="silex-sidebar-dialog">
|
|
195
|
+
<aside class="silex-bar">
|
|
196
|
+
<ul class="silex-list silex-list--menu">
|
|
197
|
+
${menuItemsCurrent.map(item => html`
|
|
198
|
+
<li
|
|
199
|
+
id="settings-sidebar-${item.id}"
|
|
200
|
+
class=${item.id === currentSection.id ? 'active' : ''}
|
|
201
|
+
@click=${e => {
|
|
202
|
+
e.preventDefault()
|
|
203
|
+
// Show the new section
|
|
204
|
+
showSection(item)
|
|
205
|
+
// Notify other plugins
|
|
206
|
+
editor.trigger(ClientEvent.SETTINGS_SECTION_CHANGE, item.id)
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
${item.label}
|
|
210
|
+
</li>
|
|
211
|
+
`)}
|
|
212
|
+
</ul>
|
|
213
|
+
</aside>
|
|
214
|
+
<main id="settings__main">
|
|
215
|
+
${ sections }
|
|
216
|
+
</main>
|
|
217
|
+
</section>
|
|
156
218
|
<footer>
|
|
157
|
-
<p class="silex-version">Silex ${
|
|
219
|
+
<p class="silex-version">Silex ${SILEX_VERSION}</p>
|
|
158
220
|
<input class="silex-button" type="button" @click=${e => editor.stopCommand(cmdOpenSettings)} value="Cancel">
|
|
159
|
-
<input class="silex-button" type="submit" value="
|
|
221
|
+
<input class="silex-button" type="submit" value="Apply">
|
|
160
222
|
</footer>
|
|
161
223
|
</form>
|
|
162
224
|
`, el)
|
|
225
|
+
// Display the current section
|
|
226
|
+
showSection(currentSection)
|
|
227
|
+
// Init the code editor
|
|
228
|
+
el.querySelector(`#${idCodeWrapper}`)?.appendChild(headEditor.getElement())
|
|
229
|
+
headEditor.setContent(settings.head || '')
|
|
163
230
|
}
|
|
164
231
|
|
|
165
232
|
function saveSettings(editor, config, model = editor.getModel()) {
|
|
@@ -167,13 +234,19 @@ function saveSettings(editor, config, model = editor.getModel()) {
|
|
|
167
234
|
const formData = new FormData(form)
|
|
168
235
|
const data = Array.from(formData as any)
|
|
169
236
|
.reduce((aggregate, [key, value]) => {
|
|
170
|
-
|
|
237
|
+
// Keep only the values that are set
|
|
238
|
+
if(value !== '') {
|
|
239
|
+
aggregate[key] = value
|
|
240
|
+
}
|
|
171
241
|
return aggregate
|
|
172
242
|
}, {}) as {[key: string]: any}
|
|
173
|
-
|
|
243
|
+
// take the name out to the main model (by design in grapesjs pages)
|
|
174
244
|
const { name, ...settings } = data
|
|
175
245
|
model.set({
|
|
176
|
-
settings
|
|
246
|
+
settings: {
|
|
247
|
+
...data,
|
|
248
|
+
head: headEditor.getContent(),
|
|
249
|
+
},
|
|
177
250
|
name,
|
|
178
251
|
})
|
|
179
252
|
// save if auto save is on
|
|
@@ -193,13 +266,18 @@ function getHeadContainer(doc, className) {
|
|
|
193
266
|
}
|
|
194
267
|
function updateDom(editor) {
|
|
195
268
|
const doc = editor.Canvas.getDocument()
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
269
|
+
const settings = editor.getModel().get('settings')
|
|
270
|
+
const pageSettings = editor.Pages.getSelected().get('settings')
|
|
271
|
+
if(doc && settings) {
|
|
272
|
+
// Delay the update to let the DOM be ready
|
|
273
|
+
setTimeout(() => {
|
|
274
|
+
// Site head
|
|
275
|
+
getHeadContainer(doc, 'site-head')
|
|
276
|
+
.innerHTML = settings.head || ''
|
|
277
|
+
// Pages head
|
|
278
|
+
getHeadContainer(doc, 'page-head')
|
|
279
|
+
.innerHTML = pageSettings?.head || ''
|
|
280
|
+
})
|
|
203
281
|
} else {
|
|
204
282
|
// No document??
|
|
205
283
|
}
|
|
@@ -18,57 +18,122 @@
|
|
|
18
18
|
import { ConnectorId, WebsiteId, WebsiteData, ConnectorUser, ConnectorType, ApiError } from '../../types'
|
|
19
19
|
import { websiteLoad, websiteSave } from '../api'
|
|
20
20
|
import { cmdLogin, eventLoggedIn, eventLoggedOut, getCurrentUser, updateUser } from './LoginDialog'
|
|
21
|
+
import { addTempDataToPages, addTempDataToAssetUrl, addTempDataToStyles, removeTempDataFromAssetUrl, removeTempDataFromPages, removeTempDataFromStyles } from '../assetUrl'
|
|
22
|
+
import { PublicationStatus } from './PublicationManager'
|
|
23
|
+
import { ClientEvent } from '../events'
|
|
24
|
+
|
|
25
|
+
export const cmdPauseAutoSave = 'pause-auto-save'
|
|
26
|
+
|
|
27
|
+
// Mechanism to keep only the last save during publication
|
|
28
|
+
let lastPendingSaving: WebsiteData = null
|
|
29
|
+
|
|
30
|
+
// Mechanism to avoid concurrent saving
|
|
31
|
+
// Note: there is already such a mechanism in grapesjs but it fails when the save is delayed by the publication
|
|
32
|
+
let isSaving = false
|
|
21
33
|
|
|
22
|
-
async function wait(ms: number) {
|
|
23
|
-
return new Promise((resolve) => {
|
|
24
|
-
setTimeout(resolve, ms)
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
34
|
export const storagePlugin = (editor) => {
|
|
35
|
+
// Add useful commands
|
|
36
|
+
editor.Commands.add(cmdPauseAutoSave, {
|
|
37
|
+
run: () => {
|
|
38
|
+
if(!editor.StorageManager.isAutosave()) throw new Error('Autosave is not enabled')
|
|
39
|
+
editor.StorageManager.setAutosave(false)
|
|
40
|
+
},
|
|
41
|
+
stop: () => {
|
|
42
|
+
editor.editor.set('changesCount', 0)
|
|
43
|
+
editor.UndoManager.clear()
|
|
44
|
+
editor.StorageManager.setAutosave(true)
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
// Add the storage connector
|
|
28
48
|
editor.Storage.add('connector', {
|
|
29
49
|
async load(options: { id: WebsiteId, connectorId: ConnectorId }): Promise<WebsiteData> {
|
|
30
50
|
try {
|
|
31
|
-
console.log('storage get user')
|
|
32
51
|
const user: ConnectorUser = await getCurrentUser(editor) ?? await updateUser(editor, ConnectorType.STORAGE, options.connectorId)
|
|
33
|
-
if(user)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
})
|
|
50
|
-
|
|
52
|
+
if (!user) throw new ApiError('Not logged in', 401)
|
|
53
|
+
const data = await websiteLoad({ websiteId: options.id, connectorId: user.storage.connectorId }) as WebsiteData
|
|
54
|
+
if (data.assets) data.assets = addTempDataToAssetUrl(data.assets, options.id, user.storage.connectorId)
|
|
55
|
+
if (data.pages) data.pages = addTempDataToPages(data.pages, options.id, user.storage.connectorId)
|
|
56
|
+
if (data.styles) data.styles = addTempDataToStyles(data.styles, options.id, user.storage.connectorId)
|
|
57
|
+
return data
|
|
58
|
+
|
|
59
|
+
} catch (err) {
|
|
60
|
+
editor.UndoManager.clear()
|
|
61
|
+
if (err.httpStatusCode === 401) {
|
|
62
|
+
editor.once(eventLoggedIn, async () => {
|
|
63
|
+
try {
|
|
64
|
+
editor.runCommand(cmdPauseAutoSave)
|
|
65
|
+
const data = await editor.Storage.load(options)
|
|
66
|
+
editor.once('canvas:frame:load', () => editor.stopCommand(cmdPauseAutoSave))
|
|
67
|
+
editor.loadProjectData(data)
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error('connectorPlugin load error', err)
|
|
70
|
+
throw err
|
|
71
|
+
}
|
|
51
72
|
})
|
|
73
|
+
editor.Commands.run(cmdLogin)
|
|
52
74
|
}
|
|
53
|
-
} catch (err) {
|
|
54
75
|
console.error('connectorPlugin load error', err)
|
|
55
76
|
throw err
|
|
56
77
|
}
|
|
57
78
|
},
|
|
58
79
|
|
|
59
80
|
async store(data: WebsiteData, options: { id: WebsiteId, connectorId: ConnectorId }) {
|
|
81
|
+
// Be sure that it is immutable
|
|
82
|
+
const myData = { ...data }
|
|
83
|
+
return await this.addToQueue(myData, options)
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
async addToQueue(data: WebsiteData, options) {
|
|
87
|
+
// Handle concurrent saving
|
|
88
|
+
if (lastPendingSaving && lastPendingSaving !== data) {
|
|
89
|
+
// Cancel previous saving
|
|
90
|
+
}
|
|
91
|
+
lastPendingSaving = data
|
|
92
|
+
// Go ahaed and save
|
|
93
|
+
return this.doStore(lastPendingSaving, options)
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
async doStore(data, options) {
|
|
97
|
+
if (editor.PublicationManager?.status === PublicationStatus.STATUS_PENDING) {
|
|
98
|
+
// Publication is pending, save is delayed
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
editor.once(ClientEvent.PUBLISH_END, () => {
|
|
101
|
+
resolve(this.doStore(data, options))
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
}
|
|
60
105
|
try {
|
|
61
|
-
if
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
editor.once(eventLoggedIn, () => {
|
|
66
|
-
return editor.Storage.save(options)
|
|
106
|
+
if (isSaving) {
|
|
107
|
+
// Concurrent saving, save is delayed
|
|
108
|
+
editor.once('storage:start:store', () => {
|
|
109
|
+
this.doStore(data, options)
|
|
67
110
|
})
|
|
68
|
-
|
|
111
|
+
} else {
|
|
112
|
+
if (lastPendingSaving === data) {
|
|
113
|
+
lastPendingSaving = null
|
|
114
|
+
isSaving = true
|
|
115
|
+
const user = await getCurrentUser(editor)
|
|
116
|
+
if (user) {
|
|
117
|
+
data.assets = removeTempDataFromAssetUrl(data.assets)
|
|
118
|
+
data.pages = removeTempDataFromPages(data.pages)
|
|
119
|
+
data.styles = removeTempDataFromStyles(data.styles)
|
|
120
|
+
await websiteSave({ websiteId: options.id, connectorId: user.storage.connectorId, data })
|
|
121
|
+
isSaving = false
|
|
122
|
+
} else {
|
|
123
|
+
// Not logged in save is delayed
|
|
124
|
+
editor.once(eventLoggedIn, () => {
|
|
125
|
+
isSaving = false
|
|
126
|
+
return editor.Storage.store()
|
|
127
|
+
})
|
|
128
|
+
editor.Commands.run(cmdLogin)
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// Canceled saving
|
|
132
|
+
}
|
|
69
133
|
}
|
|
70
134
|
} catch (err) {
|
|
71
135
|
console.error('connectorPlugin store error', err)
|
|
136
|
+
isSaving = false
|
|
72
137
|
throw err
|
|
73
138
|
}
|
|
74
139
|
}
|
|
@@ -81,7 +146,7 @@ export const storagePlugin = (editor) => {
|
|
|
81
146
|
handleError(err)
|
|
82
147
|
})
|
|
83
148
|
editor.on('asset:upload:end', (err: Error) => {
|
|
84
|
-
editor.
|
|
149
|
+
editor.store()
|
|
85
150
|
})
|
|
86
151
|
editor.on('asset:upload:error', (err: Error) => {
|
|
87
152
|
handleError(err)
|