@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,235 @@
1
+ import { API_PATH, API_WEBSITE_ASSET_READ, API_WEBSITE_PATH } from '../constants'
2
+ import { Asset, ClientSideFileType, Component, ConnectorId, Page, Style, WebsiteId } from '../types'
3
+
4
+ /**
5
+ * @fileoverview Helpers to manage assets URL
6
+ * Assets URLs are stored on storage in their "stored version": `/assets/image.webp`
7
+ * But the client side uses the "display version": `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
8
+ * After loading the site data we convert all URLs to the client side version
9
+ * Before saving the site data we convert all URLs to the storage version
10
+ * During publicationn we convert all URLs to the storage version and back
11
+ */
12
+
13
+ // Get the base URL where Silex is served
14
+ const baseUrl = window.location.pathname.replace(/\/$/, '')
15
+
16
+ // Orging and path, should we use config.rootUrl?
17
+ const SERVER_URL = window.location.origin
18
+
19
+ /**
20
+ * Function to convert a path from it stored version to the displayed version
21
+ * Stored version is like `/assets/image.webp`
22
+ * Grapesjs version is like `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
23
+ * Exported for unit tests
24
+ */
25
+ export function storedToDisplayed(path: string, websiteId: WebsiteId, storageId: ConnectorId): string {
26
+ // Check the path is a stored path
27
+ if (path.startsWith('/assets')) {
28
+ // Make an absolute URL
29
+ const url = new URL(path, SERVER_URL)
30
+ // Remove the assets folder as it is part of the saved path
31
+ url.pathname = url.pathname.replace(/^\/assets/, '')
32
+ // Add the API path and the connectorId and websiteId
33
+ url.pathname = `${baseUrl}${API_PATH}${API_WEBSITE_PATH}${API_WEBSITE_ASSET_READ}${url.pathname}`
34
+ // Add the GET params
35
+ url.searchParams.set('websiteId', websiteId)
36
+ url.searchParams.set('connectorId', storageId)
37
+ // Back to a relative URL, keep the path but not the origin
38
+ return `${decodeURIComponent(url.pathname)}${url.search}`
39
+ //const encodedPath = '/' + url.toString() // add a leading slash
40
+ // .replace(new RegExp(`^${SERVER_URL}`), '')
41
+ // .replace(/^\//, '') // remove the first slash if it exists
42
+ //return decodeURIComponent(encodedPath)
43
+ } else {
44
+ console.warn('storedToDisplayed: path is not a stored path', path)
45
+ return path
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Function to convert a path from the one we give to grapesjs to the stored version
51
+ * Grapesjs version is like `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
52
+ * Stored version is like `/assets/image.webp`
53
+ * @param path the path to convert
54
+ * @returns the converted path
55
+ * Exported for unit tests
56
+ */
57
+ export function displayedToStored(path: string): string {
58
+ // The path to the assets API
59
+ const apiPath = `${baseUrl}${API_PATH}${API_WEBSITE_PATH}${API_WEBSITE_ASSET_READ}`
60
+ // Check the path is a displayed path
61
+ if (path.startsWith(apiPath)) {
62
+ const url = new URL(path, SERVER_URL)
63
+ url.pathname = url.pathname.replace(new RegExp(`^${apiPath}`), '')
64
+ url.pathname = `${baseUrl}/assets${url.pathname}`
65
+ url.searchParams.delete('websiteId')
66
+ url.searchParams.delete('connectorId')
67
+ const encodedPath = '/' + url.toString() // add a leading slash
68
+ .replace(new RegExp(`^${SERVER_URL}${baseUrl}`), '')
69
+ .replace(/^\//, '') // remove the first slash if it exists
70
+ return decodeURIComponent(encodedPath)
71
+ } else {
72
+ console.warn('displayedToStored: path is not a displayed path', path)
73
+ return path
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Publication transformer to convert the asset URL during publication
79
+ */
80
+ export const assetsPublicationTransformer = {
81
+ transformPath(path: string, type: ClientSideFileType): string {
82
+ if(type === ClientSideFileType.ASSET) {
83
+ const result = displayedToStored(path)
84
+ return result
85
+ }
86
+ return undefined
87
+ },
88
+ transformPermalink(path: string, type: ClientSideFileType): string {
89
+ if(type === ClientSideFileType.ASSET) {
90
+ const result = displayedToStored(path)
91
+ return result
92
+ }
93
+ return undefined
94
+ },
95
+ }
96
+
97
+ /**
98
+ * Update asset URL to use the current storage connector and website ID
99
+ * Assets URLs are stored in the project data in the form `/assets/image.webp`
100
+ * This function adds the API path and the connectorId and websiteId like so: `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
101
+ */
102
+ export function addTempDataToAssetUrl(assets: Asset[], websiteId: WebsiteId, storageId: ConnectorId): Asset[] {
103
+ return assets.map((asset: Asset) => {
104
+ return asset.src ? {
105
+ ...asset,
106
+ src: storedToDisplayed(asset.src, websiteId, storageId),
107
+ } : asset
108
+ })
109
+ }
110
+
111
+ /**
112
+ * Remove the temporary data from the asset URL
113
+ * Remove the API path and the connectorId and websiteId like so: `/assets/image.webp`
114
+ */
115
+ export function removeTempDataFromAssetUrl(assets: Asset[]): Asset[] {
116
+ return assets.map((asset: Asset) => {
117
+ // Return the asset with the new URL
118
+ return asset.src ? {
119
+ ...asset,
120
+ src: displayedToStored(asset.src),
121
+ } : asset
122
+ })
123
+ }
124
+
125
+ /**
126
+ * Reucrsive function to update the asset URL in the components
127
+ */
128
+ function addTempDataToComponents(component: Component, websiteId: WebsiteId, storageId: ConnectorId): Component {
129
+ // Update the asset URL in the component
130
+ const newComponent = component.attributes?.src ? {
131
+ ...component,
132
+ attributes: {
133
+ ...component.attributes,
134
+ src: storedToDisplayed(component.attributes.src, websiteId, storageId),
135
+ },
136
+ } : component
137
+ // Update the asset URL in the children
138
+ if (newComponent.components) {
139
+ newComponent.components = newComponent.components.map((childComponent: Component) => {
140
+ return addTempDataToComponents(childComponent, websiteId, storageId)
141
+ })
142
+ }
143
+ return newComponent
144
+ }
145
+
146
+ /**
147
+ * Reucrsive function to update the asset URL in the components
148
+ */
149
+ function removeTempDataFromComponents(component: Component): Component {
150
+ // Update the asset URL in the component
151
+ const newComponent = component.attributes?.src ? {
152
+ ...component,
153
+ attributes: {
154
+ ...component.attributes,
155
+ src: displayedToStored(component.attributes.src),
156
+ },
157
+ } : component
158
+ // Update the asset URL in the children
159
+ if (newComponent.components) {
160
+ newComponent.components = newComponent.components.map((childComponent: Component) => {
161
+ return removeTempDataFromComponents(childComponent)
162
+ })
163
+ }
164
+ return newComponent
165
+ }
166
+
167
+ /**
168
+ * Add temp data to pages
169
+ */
170
+ export function addTempDataToPages(pages: Page[], websiteId: WebsiteId, storageId: ConnectorId): Page[] {
171
+ return pages.map((page: Page) => {
172
+ return {
173
+ ...page,
174
+ frames: page.frames.map(frame => ({
175
+ ...frame,
176
+ component: addTempDataToComponents(frame.component, websiteId, storageId),
177
+ }))
178
+ }
179
+ })
180
+ }
181
+
182
+ /**
183
+ * Remove temp data from asset URL in the components
184
+ */
185
+ export function removeTempDataFromPages(pages: Page[]): Page[] {
186
+ return pages.map((page: Page) => {
187
+ return {
188
+ ...page,
189
+ frames: page.frames.map(frame => ({
190
+ ...frame,
191
+ component: removeTempDataFromComponents(frame.component),
192
+ }))
193
+ }
194
+ })
195
+ }
196
+
197
+ /**
198
+ * Add data to stylesheets
199
+ */
200
+ export function addTempDataToStyles(styles: Style[], websiteId: WebsiteId, storageId: ConnectorId): Style[] {
201
+ const pattern = /url\((["']?)([^"']+?)\1\)/g
202
+ return styles.map((style: Style) => {
203
+ if (style.style && style.style['background-image']) {
204
+ const urls = [...style.style['background-image'].matchAll(pattern)].map(match => storedToDisplayed(match[2], websiteId, storageId))
205
+ return {
206
+ ...style,
207
+ style: {
208
+ ...style.style,
209
+ 'background-image': urls.map(url => `url('${url}')`).join(', '),
210
+ },
211
+ }
212
+ }
213
+ return style
214
+ })
215
+ }
216
+
217
+ /**
218
+ * Remove temp data from stylesheets
219
+ */
220
+ export function removeTempDataFromStyles(styles: Style[]): Style[] {
221
+ const pattern = /url\((["']?)([^"']+?)\1\)/g
222
+ return styles.map((style: Style) => {
223
+ if (style.style && style.style['background-image']) {
224
+ const urls = [...style.style['background-image'].matchAll(pattern)].map(match => displayedToStored(match[2]))
225
+ return {
226
+ ...style,
227
+ style: {
228
+ ...style.style,
229
+ 'background-image': urls.map(url => `url('${url}')`).join(', '),
230
+ },
231
+ }
232
+ }
233
+ return style
234
+ })
235
+ }
@@ -0,0 +1,105 @@
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 { Config } from '@silexlabs/silex-plugins'
19
+ import { getEditor, getEditorConfig } from './grapesjs'
20
+ import { CLIENT_CONFIG_FILE_NAME, DEFAULT_LANGUAGE, DEFAULT_WEBSITE_ID } from '../constants'
21
+ import { ConnectorId, WebsiteId } from '../types'
22
+ import { Editor, EditorConfig, Page } from 'grapesjs'
23
+ import { PublicationTransformer, validatePublicationTransformer } from './publication-transformers'
24
+ import * as api from './api'
25
+
26
+ /**
27
+ * @fileoverview Silex client side config
28
+ */
29
+
30
+ export class ClientConfig extends Config {
31
+ api = api
32
+
33
+ /**
34
+ * The website to load
35
+ * This is the id of the website in the storage connector
36
+ */
37
+ websiteId: WebsiteId = new URL(location.href).searchParams.get('id') ?? DEFAULT_WEBSITE_ID
38
+
39
+ /**
40
+ * The storage connector to use
41
+ * If not found in the URL and the user is not logged in to any storage, use the first storage
42
+ */
43
+ storageId: ConnectorId = new URL(location.href).searchParams.get('connectorId')
44
+
45
+ /**
46
+ * language for I18n module
47
+ */
48
+ lang = new URL(location.href).searchParams.get('lang') ?? DEFAULT_LANGUAGE
49
+
50
+ /**
51
+ * root url of Silex app
52
+ */
53
+ rootUrl = window.location.origin + window.location.pathname.replace(/\/$/, '')
54
+
55
+ /**
56
+ * debug mode
57
+ */
58
+ debug = false
59
+
60
+ /**
61
+ * Grapesjs config
62
+ */
63
+ grapesJsConfig: EditorConfig
64
+
65
+ /**
66
+ * Client config url
67
+ * This is the url of the config file which is a plugin
68
+ */
69
+ clientConfigUrl = `${this.rootUrl}/${CLIENT_CONFIG_FILE_NAME}`
70
+
71
+ /**
72
+ * Init GrapesJS config which depend on the config file properties
73
+ */
74
+ initGrapesConfig() {
75
+ this.grapesJsConfig = getEditorConfig(this.websiteId, this.storageId, this.rootUrl)
76
+ }
77
+
78
+ /**
79
+ * Get grapesjs editor
80
+ */
81
+ getEditor(): Editor {
82
+ return getEditor()
83
+ }
84
+
85
+ /**
86
+ * Publication transformers let plugins change files before they are published
87
+ */
88
+ publicationTransformers: Array<PublicationTransformer> = []
89
+
90
+ /**
91
+ * Add a publication transformer(s)
92
+ */
93
+ addPublicationTransformers(transformers: PublicationTransformer | PublicationTransformer[]) {
94
+ // Make sure it is an array
95
+ if (!Array.isArray(transformers)) {
96
+ transformers = [transformers]
97
+ }
98
+ // Validate
99
+ transformers.forEach(transformer => {
100
+ validatePublicationTransformer(transformer)
101
+ })
102
+ // Add to the list
103
+ this.publicationTransformers = this.publicationTransformers.concat(transformers)
104
+ }
105
+ }
@@ -0,0 +1,34 @@
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 enum ClientEvent {
19
+ // Sent on the config object
20
+ STARTUP_START = 'silex:startup:start',
21
+ STARTUP_END = 'silex:startup:end',
22
+ GRAPESJS_START = 'silex:grapesjs:start',
23
+ GRAPESJS_END = 'silex:grapesjs:end',
24
+
25
+ // Sent on the editor object
26
+ PUBLISH_START = 'silex:publish:start',
27
+ PUBLISH_DATA = 'silex:publish:data',
28
+ PUBLISH_END = 'silex:publish:end',
29
+ PUBLISH_ERROR = 'silex:publish:error',
30
+ PUBLISH_LOGIN_START = 'silex:publish:login:start',
31
+ PUBLISH_LOGIN_END = 'silex:publish:login:end',
32
+ ASSET_WRITE_END = 'silex:asset:write:end',
33
+ WRITE_END = 'silex:write:end',
34
+ }
@@ -0,0 +1,30 @@
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 * from './grapesjs/index'
19
+ export * from './config'
20
+
21
+ export * as constants from '../constants'
22
+ export * as utils from './utils'
23
+ export * as api from './api'
24
+ export * as events from './events'
25
+ export * as page from '../page'
26
+ export * as types from '../types'
27
+
28
+ console.info(`
29
+ Silex client loaded
30
+ `)
@@ -0,0 +1,204 @@
1
+ import { html, render } from 'lit-html'
2
+ import { Editor } from 'grapesjs'
3
+ import { ApiConnectorLoggedInPostMessage, ConnectorData, ConnectorId, ConnectorType, ConnectorUser } from '../../types'
4
+ import { connectorList, getUser, logout } from '../api'
5
+ import { WebsiteId } from '../../types'
6
+ import { API_CONNECTOR_LOGIN, API_CONNECTOR_PATH, API_PATH } from '../../constants'
7
+
8
+ export const cmdLogin = 'silex:auth:login'
9
+ export const cmdLogout = 'silex:auth:logout'
10
+ export const eventLoggingIn = 'silex:auth:logging-in'
11
+ export const eventLoggedIn = 'silex:auth:logged-in'
12
+ export const eventLoginFailed = 'silex:auth:login-failed'
13
+ export const eventLoggedOut = 'silex:auth:logged-out'
14
+
15
+ export interface LoginDialogOptions {
16
+ id: WebsiteId,
17
+ }
18
+
19
+ export async function getCurrentUser(editor: Editor): Promise<ConnectorUser> {
20
+ return editor.getModel().get('user') as ConnectorUser
21
+ }
22
+
23
+ export async function updateUser(editor: Editor, type: ConnectorType, connectorId?: ConnectorId): Promise<ConnectorUser> {
24
+ const user = await getUser({type, connectorId})
25
+ editor.getModel().set('user', user)
26
+ return user
27
+ }
28
+
29
+ // Orging and path, should we use config.rootUrl?
30
+ const SERVER_URL = window.location.origin + window.location.pathname.replace(/\/$/, '')
31
+
32
+ let open = false
33
+ let body: HTMLElement | null = null
34
+ export default function loginDialogPlugin(editor, opts) {
35
+ // Options
36
+ const options: LoginDialogOptions = {
37
+ ...opts,
38
+ }
39
+
40
+ // Commands and events
41
+ editor.Commands.add(cmdLogin, {
42
+ async run(editor: Editor) { await openDialog() },
43
+ stop(editor: Editor) { closeDialog() },
44
+ })
45
+ editor.Commands.add(cmdLogout, {
46
+ async run(editor: Editor) {
47
+ await logout({type: ConnectorType.STORAGE })
48
+ editor.getModel().set('user', null)
49
+ editor.trigger(eventLoggedOut)
50
+ },
51
+ })
52
+ editor.on(eventLoggedOut, async () => openDialog())
53
+
54
+ // Dialog API
55
+ function closeDialog() {
56
+ if (open) {
57
+ editor.Modal.close()
58
+ open = false
59
+ }
60
+ }
61
+ async function openDialog() {
62
+ editor.trigger(eventLoggingIn)
63
+ open = true
64
+ editor.Modal.open({
65
+ title: 'Login',
66
+ content: '<div id="LoginDialog__content"></div>',
67
+ }, {
68
+ closeOnConfirm: false,
69
+ closeOnEscape: false,
70
+ closeOnOverlayClick: false,
71
+ })
72
+ body = document.querySelector('#LoginDialog__content')
73
+ if (!body) {
74
+ throw new Error('Dialog creation failed')
75
+ }
76
+ render(html`Logging in...`, body)
77
+ return loadStorageList(async list => onStorageList(list))
78
+ }
79
+ async function onStorageList(list) {
80
+ const loggedIn = list.find(connector => connector.isLoggedIn)
81
+ if (loggedIn) {
82
+ try {
83
+ const status = await updateUser(editor, loggedIn.type, loggedIn.connectorId)
84
+ editor.trigger(eventLoggedIn, status)
85
+ return closeDialog()
86
+ } catch (err) {
87
+ console.error('Error with updating login status', err)
88
+ render(html`
89
+ <main>
90
+ <p>There was an error with updating the login status. ${err.message}</p>
91
+ </main>
92
+ <footer>
93
+ <button class="silex-button silex-button--primary" @click=${() => loadStorageList(async list => onStorageList(list))}>Retry</button>
94
+ <button class="silex-button" @click=${async () => {
95
+ await logout({type: loggedIn.type, connectorId: loggedIn.connectorId})
96
+ openDialog()
97
+ }}>Login with another connector</button>
98
+ </footer>
99
+ `, body)
100
+ }
101
+ return
102
+ }
103
+ // Display the list of storage and continue to login
104
+ render(html`
105
+ <main>
106
+ <p>Login and give Silex access to a file storage.</p>
107
+ ${list.map(connector => html`
108
+ <button
109
+ class="silex-button silex-button--primary"
110
+ id="publish-button--primary"
111
+ @click=${() => loginWithConnector(connector)}
112
+ >Login with ${connector.displayName}</button>
113
+ `)}
114
+ </main>
115
+ <footer>
116
+ </footer>
117
+ `, body)
118
+ }
119
+
120
+ // Auth management
121
+ async function loadStorageList(done: (list: ConnectorData[]) => Promise<void>) {
122
+ try {
123
+ const storageConnectors = await connectorList({type: ConnectorType.STORAGE})
124
+ await done(storageConnectors)
125
+ } catch (err) {
126
+ console.error('Error with loading storage connectors', err)
127
+ render(html`
128
+ <main>
129
+ An error occured while loading the storage connectors: ${err.message}
130
+ </main>
131
+ <footer>
132
+ <button type="button" class="gjs-btn-prim" @click=${() => loadStorageList(done)}>Retry</button>
133
+ </footer>
134
+ `, body)
135
+ }
136
+ }
137
+ async function loginWithConnector(connector: ConnectorData) {
138
+ const nonOAuthUrl = `${SERVER_URL}${API_PATH}${API_CONNECTOR_PATH}${API_CONNECTOR_LOGIN}?connectorId=${connector.connectorId}&type=${connector.type}`
139
+ window.open(connector.oauthUrl ?? nonOAuthUrl, '_blank')
140
+ return new Promise(resolve => {
141
+ render(html`
142
+ <main>
143
+ <p>Waiting for your authorization in popup window...</p>
144
+ </main>
145
+ <footer>
146
+ <button type="button" class="gjs-btn-prim" @click=${() => openDialog()}>Cancel</button>
147
+ </footer>
148
+ `, body)
149
+ const onMessage = async (event) => {
150
+ const data = event.data as ApiConnectorLoggedInPostMessage
151
+ if (data?.type === 'login') {
152
+ window.removeEventListener('message', onMessage)
153
+ const { connectorId, error, message } = data // TODO: use options from the connector? For now they are stored in the session
154
+ if (error) {
155
+ // Error, start over
156
+ console.error('login error', message)
157
+ render(html`
158
+ <main>
159
+ <p>Login failed with error: ${message}</p>
160
+ <footer>
161
+ <button type="button" class="gjs-btn-prim" @click=${() => openDialog()}>Retry</button>
162
+ ${ connectorId ? html`<button class="silex-button" @click=${async () => {
163
+ await logout({type: connector.type, connectorId})
164
+ openDialog()
165
+ }}>Login with another connector</button>` : '' }
166
+
167
+ </footer>
168
+ `, body)
169
+ editor.trigger(eventLoginFailed)
170
+ } else {
171
+ try {
172
+ render(html`
173
+ <main>
174
+ <p>Loging in...</p>
175
+ </main>
176
+ <footer>
177
+ </footer>
178
+ `, body)
179
+ const status = await updateUser(editor, connector.type, connectorId)
180
+ editor.trigger(eventLoggedIn, status)
181
+ closeDialog()
182
+ } catch (err) {
183
+ console.error('Error with loading login status', err)
184
+ render(html`
185
+ <main>
186
+ An error occured, could not get your data.
187
+ ${err.message}
188
+ </main>
189
+ <footer>
190
+ <button type="button" class="gjs-btn-prim" @click=${() => openDialog()}>Retry</button>
191
+ <button class="silex-button" @click=${async () => {
192
+ await logout({type: connector.type, connectorId})
193
+ openDialog()
194
+ }}>Login with another connector</button>
195
+ </footer>
196
+ `, body)
197
+ }
198
+ }
199
+ }
200
+ }
201
+ window.addEventListener('message', onMessage, false)
202
+ })
203
+ }
204
+ }