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