@silexlabs/silex 3.0.0-alpha.100

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 (282) hide show
  1. package/.env.default +19 -0
  2. package/.silex.js +37 -0
  3. package/LICENSE +661 -0
  4. package/README.md +96 -0
  5. package/dist/client/client/api.d.ts +85 -0
  6. package/dist/client/client/assetUrl.d.ts +51 -0
  7. package/dist/client/client/config.d.ts +58 -0
  8. package/dist/client/client/events.d.ts +14 -0
  9. package/dist/client/client/expose.d.ts +8 -0
  10. package/dist/client/client/grapesjs/LoginDialog.d.ts +15 -0
  11. package/dist/client/client/grapesjs/PublicationManager.d.ts +72 -0
  12. package/dist/client/client/grapesjs/PublicationUi.d.ts +62 -0
  13. package/dist/client/client/grapesjs/blocks.d.ts +1 -0
  14. package/dist/client/client/grapesjs/breadcrumbs.d.ts +1 -0
  15. package/dist/client/client/grapesjs/footer.d.ts +2 -0
  16. package/dist/client/client/grapesjs/index.d.ts +5 -0
  17. package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
  18. package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  19. package/dist/client/client/grapesjs/openImport.d.ts +9 -0
  20. package/dist/client/client/grapesjs/page-panel.d.ts +3 -0
  21. package/dist/client/client/grapesjs/project-bar.d.ts +1 -0
  22. package/dist/client/client/grapesjs/rich-text.d.ts +1 -0
  23. package/dist/client/client/grapesjs/semantic.d.ts +1 -0
  24. package/dist/client/client/grapesjs/settings.d.ts +2 -0
  25. package/dist/client/client/grapesjs/storage.d.ts +1 -0
  26. package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  27. package/dist/client/client/index.d.ts +5 -0
  28. package/dist/client/client/publication-transformers.d.ts +41 -0
  29. package/dist/client/client/utils.d.ts +2 -0
  30. package/dist/client/constants.d.ts +29 -0
  31. package/dist/client/css/admin.css +4491 -0
  32. package/dist/client/index.html +9 -0
  33. package/dist/client/js/main.js +321 -0
  34. package/dist/client/js/main.js.LICENSE.txt +24 -0
  35. package/dist/client/page.d.ts +2 -0
  36. package/dist/client/types.d.ts +334 -0
  37. package/dist/plugins/client/client/api.d.ts +85 -0
  38. package/dist/plugins/client/client/api.js +114 -0
  39. package/dist/plugins/client/client/api.js.map +1 -0
  40. package/dist/plugins/client/client/assetUrl.d.ts +51 -0
  41. package/dist/plugins/client/client/assetUrl.js +224 -0
  42. package/dist/plugins/client/client/assetUrl.js.map +1 -0
  43. package/dist/plugins/client/client/config.d.ts +58 -0
  44. package/dist/plugins/client/client/config.js +90 -0
  45. package/dist/plugins/client/client/config.js.map +1 -0
  46. package/dist/plugins/client/client/events.d.ts +14 -0
  47. package/dist/plugins/client/client/events.js +34 -0
  48. package/dist/plugins/client/client/events.js.map +1 -0
  49. package/dist/plugins/client/client/grapesjs/LoginDialog.d.ts +15 -0
  50. package/dist/plugins/client/client/grapesjs/LoginDialog.js +195 -0
  51. package/dist/plugins/client/client/grapesjs/LoginDialog.js.map +1 -0
  52. package/dist/plugins/client/client/grapesjs/PublicationManager.d.ts +72 -0
  53. package/dist/plugins/client/client/grapesjs/PublicationManager.js +356 -0
  54. package/dist/plugins/client/client/grapesjs/PublicationManager.js.map +1 -0
  55. package/dist/plugins/client/client/grapesjs/PublicationUi.d.ts +62 -0
  56. package/dist/plugins/client/client/grapesjs/PublicationUi.js +336 -0
  57. package/dist/plugins/client/client/grapesjs/PublicationUi.js.map +1 -0
  58. package/dist/plugins/client/client/grapesjs/blocks.d.ts +1 -0
  59. package/dist/plugins/client/client/grapesjs/blocks.js +37 -0
  60. package/dist/plugins/client/client/grapesjs/blocks.js.map +1 -0
  61. package/dist/plugins/client/client/grapesjs/breadcrumbs.d.ts +1 -0
  62. package/dist/plugins/client/client/grapesjs/breadcrumbs.js +75 -0
  63. package/dist/plugins/client/client/grapesjs/breadcrumbs.js.map +1 -0
  64. package/dist/plugins/client/client/grapesjs/footer.d.ts +2 -0
  65. package/dist/plugins/client/client/grapesjs/footer.js +28 -0
  66. package/dist/plugins/client/client/grapesjs/footer.js.map +1 -0
  67. package/dist/plugins/client/client/grapesjs/index.d.ts +5 -0
  68. package/dist/plugins/client/client/grapesjs/index.js +313 -0
  69. package/dist/plugins/client/client/grapesjs/index.js.map +1 -0
  70. package/dist/plugins/client/client/grapesjs/internal-links.d.ts +1 -0
  71. package/dist/plugins/client/client/grapesjs/internal-links.js +219 -0
  72. package/dist/plugins/client/client/grapesjs/internal-links.js.map +1 -0
  73. package/dist/plugins/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  74. package/dist/plugins/client/client/grapesjs/new-page-dialog.js +83 -0
  75. package/dist/plugins/client/client/grapesjs/new-page-dialog.js.map +1 -0
  76. package/dist/plugins/client/client/grapesjs/openImport.d.ts +9 -0
  77. package/dist/plugins/client/client/grapesjs/openImport.js +74 -0
  78. package/dist/plugins/client/client/grapesjs/openImport.js.map +1 -0
  79. package/dist/plugins/client/client/grapesjs/page-panel.d.ts +3 -0
  80. package/dist/plugins/client/client/grapesjs/page-panel.js +113 -0
  81. package/dist/plugins/client/client/grapesjs/page-panel.js.map +1 -0
  82. package/dist/plugins/client/client/grapesjs/project-bar.d.ts +1 -0
  83. package/dist/plugins/client/client/grapesjs/project-bar.js +104 -0
  84. package/dist/plugins/client/client/grapesjs/project-bar.js.map +1 -0
  85. package/dist/plugins/client/client/grapesjs/rich-text.d.ts +1 -0
  86. package/dist/plugins/client/client/grapesjs/rich-text.js +31 -0
  87. package/dist/plugins/client/client/grapesjs/rich-text.js.map +1 -0
  88. package/dist/plugins/client/client/grapesjs/semantic.d.ts +1 -0
  89. package/dist/plugins/client/client/grapesjs/semantic.js +110 -0
  90. package/dist/plugins/client/client/grapesjs/semantic.js.map +1 -0
  91. package/dist/plugins/client/client/grapesjs/settings.d.ts +2 -0
  92. package/dist/plugins/client/client/grapesjs/settings.js +198 -0
  93. package/dist/plugins/client/client/grapesjs/settings.js.map +1 -0
  94. package/dist/plugins/client/client/grapesjs/storage.d.ts +1 -0
  95. package/dist/plugins/client/client/grapesjs/storage.js +126 -0
  96. package/dist/plugins/client/client/grapesjs/storage.js.map +1 -0
  97. package/dist/plugins/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  98. package/dist/plugins/client/client/grapesjs/symbolDialogs.js +36 -0
  99. package/dist/plugins/client/client/grapesjs/symbolDialogs.js.map +1 -0
  100. package/dist/plugins/client/client/publication-transformers.d.ts +41 -0
  101. package/dist/plugins/client/client/publication-transformers.js +238 -0
  102. package/dist/plugins/client/client/publication-transformers.js.map +1 -0
  103. package/dist/plugins/client/client/utils.d.ts +2 -0
  104. package/dist/plugins/client/client/utils.js +25 -0
  105. package/dist/plugins/client/client/utils.js.map +1 -0
  106. package/dist/plugins/client/constants.d.ts +29 -0
  107. package/dist/plugins/client/constants.js +46 -0
  108. package/dist/plugins/client/constants.js.map +1 -0
  109. package/dist/plugins/client/page.d.ts +2 -0
  110. package/dist/plugins/client/page.js +31 -0
  111. package/dist/plugins/client/page.js.map +1 -0
  112. package/dist/plugins/client/plugins/client/11ty.d.ts +17 -0
  113. package/dist/plugins/client/plugins/client/11ty.js +86 -0
  114. package/dist/plugins/client/plugins/client/11ty.js.map +1 -0
  115. package/dist/plugins/client/plugins/client/publicationRenderer.d.ts +2 -0
  116. package/dist/plugins/client/plugins/client/publicationRenderer.js +170 -0
  117. package/dist/plugins/client/plugins/client/publicationRenderer.js.map +1 -0
  118. package/dist/plugins/client/plugins/client/template.d.ts +2 -0
  119. package/dist/plugins/client/plugins/client/template.js +183 -0
  120. package/dist/plugins/client/plugins/client/template.js.map +1 -0
  121. package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
  122. package/dist/plugins/client/plugins/client/website-info.js +72 -0
  123. package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
  124. package/dist/plugins/client/types.d.ts +334 -0
  125. package/dist/plugins/client/types.js +74 -0
  126. package/dist/plugins/client/types.js.map +1 -0
  127. package/dist/plugins/server/constants.d.ts +29 -0
  128. package/dist/plugins/server/constants.js +49 -0
  129. package/dist/plugins/server/constants.js.map +1 -0
  130. package/dist/plugins/server/plugins/server/AuthPlugin.d.ts +1 -0
  131. package/dist/plugins/server/plugins/server/AuthPlugin.js +40 -0
  132. package/dist/plugins/server/plugins/server/AuthPlugin.js.map +1 -0
  133. package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
  134. package/dist/plugins/server/plugins/server/Cache.js +32 -0
  135. package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
  136. package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
  137. package/dist/plugins/server/plugins/server/DownloadConnector.js +129 -0
  138. package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
  139. package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
  140. package/dist/plugins/server/plugins/server/FtpConnector.js +526 -0
  141. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
  142. package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +87 -0
  143. package/dist/plugins/server/plugins/server/GitlabConnector.js +564 -0
  144. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
  145. package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
  146. package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
  147. package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
  148. package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
  149. package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
  150. package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
  151. package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +1 -0
  152. package/dist/plugins/server/plugins/server/StaticPlugin.js +78 -0
  153. package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
  154. package/dist/plugins/server/server/config.d.ts +59 -0
  155. package/dist/plugins/server/server/config.js +181 -0
  156. package/dist/plugins/server/server/config.js.map +1 -0
  157. package/dist/plugins/server/server/connectors/FsHosting.d.ts +13 -0
  158. package/dist/plugins/server/server/connectors/FsHosting.js +54 -0
  159. package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
  160. package/dist/plugins/server/server/connectors/FsStorage.d.ts +43 -0
  161. package/dist/plugins/server/server/connectors/FsStorage.js +257 -0
  162. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
  163. package/dist/plugins/server/server/connectors/connectors.d.ts +87 -0
  164. package/dist/plugins/server/server/connectors/connectors.js +127 -0
  165. package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
  166. package/dist/plugins/server/server/events.d.ts +26 -0
  167. package/dist/plugins/server/server/events.js +31 -0
  168. package/dist/plugins/server/server/events.js.map +1 -0
  169. package/dist/plugins/server/server/jobs.d.ts +12 -0
  170. package/dist/plugins/server/server/jobs.js +77 -0
  171. package/dist/plugins/server/server/jobs.js.map +1 -0
  172. package/dist/plugins/server/server/utils/validation.d.ts +7 -0
  173. package/dist/plugins/server/server/utils/validation.js +38 -0
  174. package/dist/plugins/server/server/utils/validation.js.map +1 -0
  175. package/dist/plugins/server/types.d.ts +334 -0
  176. package/dist/plugins/server/types.js +78 -0
  177. package/dist/plugins/server/types.js.map +1 -0
  178. package/dist/server/constants.js +29 -0
  179. package/dist/server/plugins/server/Cache.js +15 -0
  180. package/dist/server/server/api/api.js +20 -0
  181. package/dist/server/server/api/connectorApi.js +216 -0
  182. package/dist/server/server/api/publicationApi.js +108 -0
  183. package/dist/server/server/api/websiteApi.js +296 -0
  184. package/dist/server/server/cli.js +68 -0
  185. package/dist/server/server/config.js +120 -0
  186. package/dist/server/server/connectors/FsHosting.js +35 -0
  187. package/dist/server/server/connectors/FsStorage.js +225 -0
  188. package/dist/server/server/connectors/connectors.js +89 -0
  189. package/dist/server/server/events.js +14 -0
  190. package/dist/server/server/expose.js +27 -0
  191. package/dist/server/server/express.js +47 -0
  192. package/dist/server/server/index.js +90 -0
  193. package/dist/server/server/jobs.js +48 -0
  194. package/dist/server/server/utils/validation.js +15 -0
  195. package/dist/server/types.js +34 -0
  196. package/package.json +209 -0
  197. package/public/assets/container.png +0 -0
  198. package/public/assets/favicon.png +0 -0
  199. package/public/assets/logo-silex-small.png +0 -0
  200. package/public/robots.txt +2 -0
  201. package/public/silex.js +24 -0
  202. package/src/css/_mixins.scss +8 -0
  203. package/src/css/_variables.scss +33 -0
  204. package/src/css/dialog.scss +41 -0
  205. package/src/css/footer.scss +12 -0
  206. package/src/css/grapesjs-light.scss +180 -0
  207. package/src/css/grapesjs.scss +152 -0
  208. package/src/css/index.scss +32 -0
  209. package/src/css/light.scss +7 -0
  210. package/src/css/loader.scss +12 -0
  211. package/src/css/page-panel.scss +65 -0
  212. package/src/css/project-bar.scss +102 -0
  213. package/src/css/silex.scss +189 -0
  214. package/src/css/website-info.scss +14 -0
  215. package/src/html/debug.pug +8 -0
  216. package/src/html/index.pug +39 -0
  217. package/src/html/templates/includes.pug +1 -0
  218. package/src/html/templates/workspace.pug +2 -0
  219. package/src/ts/client/api.ts +144 -0
  220. package/src/ts/client/assetUrl.test.ts +125 -0
  221. package/src/ts/client/assetUrl.ts +235 -0
  222. package/src/ts/client/config.ts +105 -0
  223. package/src/ts/client/events.ts +34 -0
  224. package/src/ts/client/expose.ts +30 -0
  225. package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
  226. package/src/ts/client/grapesjs/PublicationManager.ts +370 -0
  227. package/src/ts/client/grapesjs/PublicationUi.ts +342 -0
  228. package/src/ts/client/grapesjs/blocks.ts +37 -0
  229. package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
  230. package/src/ts/client/grapesjs/eleventy.ts +47 -0
  231. package/src/ts/client/grapesjs/footer.ts +27 -0
  232. package/src/ts/client/grapesjs/index.ts +335 -0
  233. package/src/ts/client/grapesjs/internal-links.test.ts +105 -0
  234. package/src/ts/client/grapesjs/internal-links.ts +225 -0
  235. package/src/ts/client/grapesjs/new-page-dialog.ts +90 -0
  236. package/src/ts/client/grapesjs/openImport.ts +81 -0
  237. package/src/ts/client/grapesjs/page-panel.ts +118 -0
  238. package/src/ts/client/grapesjs/project-bar.ts +107 -0
  239. package/src/ts/client/grapesjs/rich-text.ts +33 -0
  240. package/src/ts/client/grapesjs/semantic.ts +114 -0
  241. package/src/ts/client/grapesjs/settings.ts +208 -0
  242. package/src/ts/client/grapesjs/storage.ts +121 -0
  243. package/src/ts/client/grapesjs/symbolDialogs.ts +38 -0
  244. package/src/ts/client/index.ts +98 -0
  245. package/src/ts/client/publication-transformers.test.ts +199 -0
  246. package/src/ts/client/publication-transformers.ts +263 -0
  247. package/src/ts/client/utils.ts +28 -0
  248. package/src/ts/constants.ts +52 -0
  249. package/src/ts/externs.ts +18 -0
  250. package/src/ts/page.ts +31 -0
  251. package/src/ts/plugins/client/11ty.ts +104 -0
  252. package/src/ts/plugins/client/publicationRenderer.ts +174 -0
  253. package/src/ts/plugins/client/template.ts +192 -0
  254. package/src/ts/plugins/client/website-info.ts +84 -0
  255. package/src/ts/plugins/server/AuthPlugin.ts +38 -0
  256. package/src/ts/plugins/server/Cache.ts +28 -0
  257. package/src/ts/plugins/server/DownloadConnector.ts +148 -0
  258. package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
  259. package/src/ts/plugins/server/FtpConnector.ts +609 -0
  260. package/src/ts/plugins/server/GitlabConnector.ts +644 -0
  261. package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
  262. package/src/ts/plugins/server/SslPlugin.ts +84 -0
  263. package/src/ts/plugins/server/StaticPlugin.ts +79 -0
  264. package/src/ts/server/api/api.ts +19 -0
  265. package/src/ts/server/api/connectorApi.ts +345 -0
  266. package/src/ts/server/api/publicationApi.ts +159 -0
  267. package/src/ts/server/api/websiteApi.ts +432 -0
  268. package/src/ts/server/cli.ts +65 -0
  269. package/src/ts/server/config.ts +189 -0
  270. package/src/ts/server/connectors/FsHosting.ts +60 -0
  271. package/src/ts/server/connectors/FsStorage.test.ts +51 -0
  272. package/src/ts/server/connectors/FsStorage.ts +261 -0
  273. package/src/ts/server/connectors/connectors.ts +203 -0
  274. package/src/ts/server/events.ts +37 -0
  275. package/src/ts/server/expose.ts +19 -0
  276. package/src/ts/server/express.ts +70 -0
  277. package/src/ts/server/index.ts +100 -0
  278. package/src/ts/server/jobs.test.ts +75 -0
  279. package/src/ts/server/jobs.ts +87 -0
  280. package/src/ts/server/utils/BackwardCompat.ts +552 -0
  281. package/src/ts/server/utils/validation.ts +34 -0
  282. package/src/ts/types.ts +339 -0
@@ -0,0 +1,192 @@
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
+ // Silex serves /clients
19
+ // @ts-ignore
20
+ import { onAll } from '../client/utils.js'
21
+ // @ts-ignore
22
+ import { ClientEvent } from '../client/events.js'
23
+
24
+ // You need to serve lit-html at /js/lit-html/
25
+ // @ts-ignore
26
+ import {html, render} from '../js/lit-html/lit-html.js'
27
+ // @ts-ignore
28
+ import {styleMap} from '../js/lit-html/directives/style-map.js'
29
+
30
+ const silex = window['silex']
31
+
32
+ const pluginName = 'template'
33
+ const templateType = 'templateType'
34
+ const templateKey = 'template'
35
+
36
+ export default async (config, opts: any = {}) => {
37
+ config.on(ClientEvent.GRAPESJS_END, () => {
38
+ const editor = silex.getEditor()
39
+ // Add the new trait to all component types
40
+ editor.DomComponents.getTypes().map(type => {
41
+ const originalType = editor.DomComponents.getType(type.id)
42
+ editor.DomComponents.addType(type.id, {
43
+ model: {
44
+ defaults: {
45
+ traits: [
46
+ // Keep the type original traits
47
+ ...originalType.model.prototype.defaults.traits,
48
+ // Add the new trait
49
+ {
50
+ label: false,
51
+ type: templateType,
52
+ name: pluginName,
53
+ },
54
+ ]
55
+ }
56
+ }
57
+ })
58
+ })
59
+
60
+ function doRender(el) {
61
+ const template = editor.getSelected()?.get(templateKey) || {}
62
+ const taStyle = opts.styles?.textarea ?? styleMap({
63
+ backgroundColor: 'var(--darkerPrimaryColor)',
64
+ })
65
+ const sepStyle = opts.styles?.sep ?? styleMap({ height: '10px' })
66
+ const labels = {
67
+ before: html`<strong>Before</strong> the element`,
68
+ replace: html`<strong>Replace</strong> the element's children`,
69
+ after: html`<strong>After</strong> the element`,
70
+ attributes: html`HTML attributes`,
71
+ classname: html`CSS classes`,
72
+ style: html`CSS styles`,
73
+ }
74
+ render(html`
75
+ <div>
76
+ <h3>Template</h3>
77
+ <p>This will be inserted in the published version</p>
78
+ </div>
79
+ ${['classname', 'attributes', 'style'].map(id => html`
80
+ <label>
81
+ ${labels[id]}
82
+ <input
83
+ id="template-${id}"
84
+ .value=${template[id] || ''}
85
+ style=${taStyle}
86
+ />
87
+ </label>
88
+ `)}
89
+ ${['before', 'replace', 'after'].map(id => html`
90
+ <label
91
+ for="template-${id}"
92
+ >${labels[id]}</label>
93
+ <textarea
94
+ id="template-${id}"
95
+ style=${taStyle}
96
+ .value=${template[id] || ''}
97
+ ></textarea>
98
+ `)}
99
+ `, el)
100
+ }
101
+
102
+ editor.TraitManager.addType(templateType, {
103
+ createInput({ trait }) {
104
+ // Create a new element container and add some content
105
+ const el = document.createElement('div')
106
+ el.classList.add('gjs-one-bg')
107
+ // update the UI when a page is added/renamed/removed
108
+ editor.on('page', () => doRender(el))
109
+ doRender(el)
110
+ // this will be the element passed to onEvent and onUpdate
111
+ return el
112
+ },
113
+ // Update the component based on UI changes
114
+ // `elInput` is the result HTMLElement you get from `createInput`
115
+ onEvent({ elInput, component, event }) {
116
+ const template = {
117
+ before: elInput.querySelector('#template-before').value,
118
+ replace: elInput.querySelector('#template-replace').value,
119
+ after: elInput.querySelector('#template-after').value,
120
+ attributes: elInput.querySelector('#template-attributes').value,
121
+ classname: elInput.querySelector('#template-classname').value,
122
+ style: elInput.querySelector('#template-style').value,
123
+ }
124
+
125
+ // Store the new template
126
+ if (Object.values(template).filter(val => !!val && !!cleanup(val)).length > 0) {
127
+ component.set(templateKey, template)
128
+ } else {
129
+ component.set(templateKey)
130
+ }
131
+ },
132
+ // Update UI on the component change
133
+ onUpdate({ elInput, component }) {
134
+ doRender(elInput)
135
+ },
136
+ })
137
+
138
+ // Make html attribute
139
+ // Quote strings, no values for boolean
140
+ function makeAttribute(key, value) {
141
+ switch (typeof value) {
142
+ case 'boolean': return value ? key : ''
143
+ default: return `${key}="${value}"`
144
+ }
145
+ }
146
+ // Remove empty lines in templates
147
+ function cleanup(template) {
148
+ return template
149
+ // split in lines
150
+ .split('\n')
151
+ // remove lines with only spaces
152
+ .map(line => line.trim())
153
+ .filter(line => !!line)
154
+ // put back together
155
+ .join('\n')
156
+ }
157
+ editor.on(ClientEvent.PUBLISH_START, () => {
158
+ // Insert templates
159
+ onAll(editor, c => {
160
+ const template = c.get(templateKey)
161
+ const toHTML = c.toHTML
162
+ const classes = c.getClasses()
163
+ const before = cleanup(template?.before || '')
164
+ const replace = cleanup(template?.replace || '')
165
+ const after = cleanup(template?.after || '')
166
+ const classname = cleanup(template?.classname || '')
167
+ const style = cleanup(template?.style || '')
168
+ const attributes = cleanup(template?.attributes || '')
169
+ // Store the initial method
170
+ if (!c.has('tmpHtml')) c.set('tmpHtml', toHTML)
171
+ // Override the method
172
+ c.toHTML = () => {
173
+ return `${before
174
+ }${c.get('tagName') ? `<${c.get('tagName')}
175
+ ${Object.entries(c.get('attributes') as object).map(([key, value]) => makeAttribute(key, value)).join(' ')}
176
+ ${classes.length || classname ? `class="${classes.join(' ')} ${classname}"` : ''}
177
+ ${attributes}
178
+ ${style ? `style="${style}"` : ''}
179
+ >` : ''}${replace || c.getInnerHTML()
180
+ }${c.get('tagName') ? `</${c.get('tagName')}>` : ''}${after
181
+ }`
182
+ }
183
+ })
184
+ })
185
+ editor.on(ClientEvent.PUBLISH_END, () => {
186
+ onAll(editor, c => {
187
+ // Restore the original method
188
+ c.toHTML = c.get('tmpHtml')
189
+ })
190
+ })
191
+ })
192
+ }
@@ -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
+ }
@@ -0,0 +1,38 @@
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 express from 'express'
19
+ // import { Directus } from '@directus/sdk'
20
+
21
+ export default async function(config, opts = {}) {
22
+ // config.on('silex:startup:start', ({app}) => {
23
+ // const router = express.Router()
24
+ // router.post(['/publish', '/website', '/assets'], async function(req, res, next) {
25
+ // try {
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
+ // })
38
+ }
@@ -0,0 +1,28 @@
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
+ export function noCache (req, res, next) {
19
+ res.header('Cache-Control', 'private,no-cache,no-store,must-revalidate,proxy-revalidate')
20
+ res.header('Expires', '-1')
21
+ res.header('Pragma', 'no-cache')
22
+ next()
23
+ }
24
+
25
+ export function withCache(req, res, next) {
26
+ res.header('Cache-Control', 'public,max-age=86400,immutable') // 24h
27
+ next()
28
+ }
@@ -0,0 +1,148 @@
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 svg = '<svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 384 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M64 464c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h48c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16h48v80c0 17.7 14.3 32 32 32h80V448c0 8.8-7.2 16-16 16H64zM64 0C28.7 0 0 28.7 0 64V448c0 35.3 28.7 64 64 64H320c35.3 0 64-28.7 64-64V154.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0H64zm48 112c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H128c-8.8 0-16 7.2-16 16zm0 64c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16s-7.2-16-16-16H128c-8.8 0-16 7.2-16 16zm-6.3 71.8L82.1 335.9c-1.4 5.4-2.1 10.9-2.1 16.4c0 35.2 28.8 63.7 64 63.7s64-28.5 64-63.7c0-5.5-.7-11.1-2.1-16.4l-23.5-88.2c-3.7-14-16.4-23.8-30.9-23.8H136.6c-14.5 0-27.2 9.7-30.9 23.8zM128 336h32c8.8 0 16 7.2 16 16s-7.2 16-16 16H128c-8.8 0-16-7.2-16-16s7.2-16 16-16z"/></svg>'
17
+ const encodedSvg = encodeURIComponent(svg)
18
+ const ZIP_ICON = `data:image/svg+xml,${encodedSvg}`
19
+
20
+ export default class implements HostingConnector<DownloadConnectorSession> {
21
+ connectorId = 'download-connector'
22
+ displayName = 'Download zip file'
23
+ icon = ZIP_ICON
24
+ disableLogout = false
25
+ options: DownloadConnectorOptions
26
+ connectorType = ConnectorType.HOSTING
27
+ color = '#ffffff'
28
+ background = '#006400'
29
+
30
+ constructor(config: ServerConfig) {
31
+ // Add a route to serve the zip file
32
+ config.on(ServerEvent.STARTUP_END, ({app}) => {
33
+ app.get('/download/:tmpZipFile', async (req: Request, res: Response) => {
34
+ const path = `${tmpdir()}/${req.params.tmpZipFile}`
35
+ res.sendFile(path, {}, (err) => {
36
+ if (err) {
37
+ console.error('[DownloadConnector] Error while sending file', err)
38
+ res.status(500).send(`
39
+ <h1>Error</h1>
40
+ <p>There was an error while getting the zip file of your website</p>
41
+ <p>${err.message}</p>
42
+ `)
43
+ }
44
+ })
45
+ })
46
+ })
47
+ }
48
+
49
+ getOptions(formData: object): ConnectorOptions {
50
+ return {}
51
+ }
52
+
53
+ async getOAuthUrl(session: DownloadConnectorSession): Promise<null> { return null }
54
+
55
+ async getLoginForm(session: DownloadConnectorSession, redirectTo: string): Promise<string | null> {
56
+ return null
57
+ }
58
+ async getSettingsForm(session: DownloadConnectorSession, redirectTo: string): Promise<string | null> {
59
+ return null
60
+ }
61
+
62
+ async isLoggedIn(session: DownloadConnectorSession): Promise<boolean> {
63
+ return true
64
+ }
65
+
66
+ async setToken(session: DownloadConnectorSession, query: object): Promise<void> {}
67
+
68
+ async logout(session: DownloadConnectorSession): Promise<void> {}
69
+
70
+ async getUser(session: DownloadConnectorSession): Promise<ConnectorUser | null> {
71
+ return null
72
+ }
73
+
74
+ async publish(session: DownloadConnectorSession, websiteId: WebsiteId, files: ConnectorFile[], jobManager: JobManager): Promise<JobData> {
75
+ const job = jobManager.startJob(`Publishing to ${this.displayName}`) as PublicationJobData
76
+ this.startPublishingInBackground(session, websiteId, files, job)
77
+ return job
78
+ }
79
+
80
+ async startPublishingInBackground(session: DownloadConnectorSession, websiteId: WebsiteId, files: ConnectorFile[], job: PublicationJobData): Promise<void> {
81
+ const fileName = `${websiteId}-${Date.now()}-${Math.random().toString(36).substring(7)}.zip`
82
+ return new Promise<string>((resolve, reject) => {
83
+ let resolved = false
84
+ try {
85
+ // Generate a temporary path for the zip file, in the OS tmp folder, with the website id, the date and random string
86
+ const path = `${tmpdir()}/${fileName}`
87
+ // create a file to stream archive data to.
88
+ const output = createWriteStream(path)
89
+ const archive = archiver('zip', {
90
+ zlib: { level: 9 } // Sets the compression level.
91
+ })
92
+
93
+ // Listen to archive events
94
+ // listen for all archive data to be written
95
+ // 'close' event is fired only when a file descriptor is involved
96
+ output.on('close', function () {
97
+ !resolved && resolve(path)
98
+ resolved = true
99
+ })
100
+
101
+ // good practice to catch warnings (ie stat failures and other non-blocking errors)
102
+ archive.on('warning', function (err) {
103
+ if (err.code === 'ENOENT') {
104
+ // log warning
105
+ } else {
106
+ !resolved && reject(err)
107
+ resolved = true
108
+ }
109
+ })
110
+
111
+ // good practice to catch this error explicitly
112
+ archive.on('error', function (err) {
113
+ !resolved && reject(err)
114
+ resolved = true
115
+ })
116
+
117
+ // pipe archive data to the filey
118
+ archive.pipe(output)
119
+
120
+ // append files
121
+ for (const file of files) {
122
+ job.message = `Adding ${file.path} to the zip file`
123
+ // Handle content as string, buffer or readable
124
+ archive.append(file.content, { name: file.path })
125
+ }
126
+
127
+ // finalize the archive (ie we are done appending files but streams have to finish yet)
128
+ job.message = 'Finalizing the zip file'
129
+ return archive.finalize()
130
+ .then(() => path)
131
+ } catch (err) {
132
+ console.error('Error while creating the zip file', err)
133
+ job.message = `Error while creating the zip file: ${err.message}`
134
+ job.status = JobStatus.ERROR
135
+ !resolved && reject(err)
136
+ resolved = true
137
+ }
138
+ })
139
+ .then(path => {
140
+ job.message = `Zip file created, <a href="/download/${fileName}" target="_blank">download it now</a>`
141
+ job.status = JobStatus.SUCCESS
142
+ })
143
+ }
144
+
145
+ async getUrl(session: DownloadConnectorSession, websiteId: WebsiteId): Promise<string> {
146
+ return ''
147
+ }
148
+ }
@@ -0,0 +1,82 @@
1
+ import { ServerConfig } from '../../server/config'
2
+ import { expect, jest, beforeEach, afterEach, it, describe } from '@jest/globals'
3
+ import { ConnectorType, WebsiteData, WebsiteId } from '../../types'
4
+ import { Readable } from 'stream'
5
+
6
+ const mocks = {
7
+ access: jest.fn(),
8
+ close: jest.fn(),
9
+ trackProgress: jest.fn(),
10
+ uploadFrom: jest.fn(),
11
+ }
12
+ function mockClient() {
13
+ jest.mock('basic-ftp', () => ({
14
+ Client: jest.fn().mockImplementation(() => mocks),
15
+ }))
16
+ }
17
+ mockClient()
18
+
19
+ const FtpConnector = (await import('./FtpConnector')).default
20
+
21
+ let connector
22
+ const storageRootPath = 'dummy storageRootPath'
23
+ const assetsFolder = 'dummy assetsFolder'
24
+ const dummySession = {
25
+ [`ftp-${ConnectorType.STORAGE}`]: {
26
+ host: 'dummy host',
27
+ user: 'dummy user',
28
+ pass: 'dummy pass',
29
+ port: 1234,
30
+ secure: false,
31
+ storageRootPath,
32
+ },
33
+ }
34
+ const dummyId: WebsiteId = 'dummy id'
35
+ const dummyWebsite: WebsiteData = {
36
+ pages: [],
37
+ assets: [],
38
+ styles: [],
39
+ settings: {},
40
+ fonts: [],
41
+ symbols: [],
42
+ publication: {},
43
+ }
44
+
45
+ beforeEach(() => {
46
+ mockClient()
47
+ connector = new FtpConnector({} as ServerConfig, {
48
+ type: ConnectorType.STORAGE,
49
+ assetsFolder,
50
+ })
51
+ })
52
+
53
+ afterEach(async () => {
54
+ // FIXME: This removes the mock of Client
55
+ //await jest.resetAllMocks()
56
+ // Reset each mock
57
+ Object.keys(mocks).forEach(key => {
58
+ mocks[key].mockClear()
59
+ })
60
+ })
61
+
62
+ describe('FtpConnector website', () => {
63
+ it('should write to FTP', async () => {
64
+ await connector.updateWebsite(dummySession, dummyId, dummyWebsite)
65
+ expect(mocks.uploadFrom).toHaveBeenCalledTimes(1)
66
+ expect(mocks.uploadFrom.mock.calls[0][0]).toBeInstanceOf(Readable)
67
+ expect(mocks.uploadFrom.mock.calls[0][1]).toBe(`${storageRootPath}/${dummyId}/website.json`)
68
+ })
69
+ })
70
+
71
+ describe('FtpConnector assets', () => {
72
+ it('should write an asset to FTP', async () => {
73
+ const assets = [{
74
+ path: 'dummy path',
75
+ content: 'dummy content',
76
+ }]
77
+ await connector.writeAssets(dummySession, dummyId, assets)
78
+ expect(mocks.uploadFrom).toHaveBeenCalledTimes(1)
79
+ expect(mocks.uploadFrom.mock.calls[0][0]).toBeInstanceOf(Readable)
80
+ expect(mocks.uploadFrom.mock.calls[0][1]).toBe(`${storageRootPath}/${dummyId}/${assetsFolder}/${assets[0].path}`)
81
+ })
82
+ })