@silexlabs/silex 3.0.1-alpha.0 → 3.0.2

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 (323) hide show
  1. package/.env.default +20 -0
  2. package/.silex.js +67 -8
  3. package/LICENSE +661 -203
  4. package/README.md +37 -35
  5. package/dist/client/client/api.d.ts +90 -0
  6. package/dist/client/client/assetUrl.d.ts +54 -0
  7. package/dist/client/client/config.d.ts +102 -0
  8. package/dist/client/client/events.d.ts +23 -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 +73 -0
  12. package/dist/client/client/grapesjs/PublicationUi.d.ts +59 -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/css-props.d.ts +6 -0
  16. package/dist/client/client/grapesjs/footer.d.ts +2 -0
  17. package/dist/client/client/grapesjs/img.d.ts +6 -0
  18. package/dist/client/client/grapesjs/index.d.ts +9 -0
  19. package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
  20. package/dist/client/client/grapesjs/keymaps.d.ts +123 -0
  21. package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  22. package/dist/client/client/grapesjs/openImport.d.ts +9 -0
  23. package/dist/client/client/grapesjs/page-panel.d.ts +9 -0
  24. package/dist/client/client/grapesjs/project-bar.d.ts +21 -0
  25. package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
  26. package/dist/client/client/grapesjs/rich-text.d.ts +4 -0
  27. package/dist/client/client/grapesjs/semantic.d.ts +1 -0
  28. package/dist/client/client/grapesjs/settings-sections.d.ts +16 -0
  29. package/dist/client/client/grapesjs/settings.d.ts +4 -0
  30. package/dist/client/client/grapesjs/storage.d.ts +2 -0
  31. package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  32. package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
  33. package/dist/client/client/index.d.ts +10 -0
  34. package/dist/client/client/publication-transformers.d.ts +42 -0
  35. package/dist/client/client/publish-custom-code-block.d.ts +4 -0
  36. package/dist/client/client/publish-fonts.d.ts +4 -0
  37. package/dist/client/client/utils.d.ts +22 -0
  38. package/dist/client/constants.d.ts +32 -0
  39. package/dist/client/css/admin.css +1114 -328
  40. package/dist/client/css/admin.css.map +1 -0
  41. package/dist/client/grapesjs-filter-styles/dist/index.d.ts +4 -0
  42. package/dist/client/grapesjs-fonts/dist/index.d.ts +4 -0
  43. package/dist/client/grapesjs-fonts/src/commands.d.ts +3 -0
  44. package/dist/client/grapesjs-fonts/src/fonts.d.ts +4 -0
  45. package/dist/client/grapesjs-storage-rate-limit/dist/index.d.ts +4 -0
  46. package/dist/client/grapesjs-ui-suggest-classes/dist/index.d.ts +4 -0
  47. package/dist/client/index.html +3 -2
  48. package/dist/client/js/main.js +356 -131
  49. package/dist/client/js/main.js.LICENSE.txt +15 -1
  50. package/dist/client/page.d.ts +2 -0
  51. package/dist/client/silex-lib/src/ts/client/api.d.ts +90 -0
  52. package/dist/client/silex-lib/src/ts/client/assetUrl.d.ts +54 -0
  53. package/dist/client/silex-lib/src/ts/client/config.d.ts +102 -0
  54. package/dist/client/silex-lib/src/ts/client/events.d.ts +23 -0
  55. package/dist/client/silex-lib/src/ts/client/expose.d.ts +8 -0
  56. package/dist/client/silex-lib/src/ts/client/grapesjs/LoginDialog.d.ts +15 -0
  57. package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationManager.d.ts +73 -0
  58. package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationUi.d.ts +59 -0
  59. package/dist/client/silex-lib/src/ts/client/grapesjs/blocks.d.ts +1 -0
  60. package/dist/client/silex-lib/src/ts/client/grapesjs/breadcrumbs.d.ts +1 -0
  61. package/dist/client/silex-lib/src/ts/client/grapesjs/css-props.d.ts +6 -0
  62. package/dist/client/silex-lib/src/ts/client/grapesjs/footer.d.ts +2 -0
  63. package/dist/client/silex-lib/src/ts/client/grapesjs/img.d.ts +6 -0
  64. package/dist/client/silex-lib/src/ts/client/grapesjs/index.d.ts +9 -0
  65. package/dist/client/silex-lib/src/ts/client/grapesjs/internal-links.d.ts +1 -0
  66. package/dist/client/silex-lib/src/ts/client/grapesjs/keymaps.d.ts +123 -0
  67. package/dist/client/silex-lib/src/ts/client/grapesjs/new-page-dialog.d.ts +2 -0
  68. package/dist/client/silex-lib/src/ts/client/grapesjs/openImport.d.ts +9 -0
  69. package/dist/client/silex-lib/src/ts/client/grapesjs/page-panel.d.ts +9 -0
  70. package/dist/client/silex-lib/src/ts/client/grapesjs/project-bar.d.ts +21 -0
  71. package/dist/client/silex-lib/src/ts/client/grapesjs/resize-panel.d.ts +1 -0
  72. package/dist/client/silex-lib/src/ts/client/grapesjs/rich-text.d.ts +4 -0
  73. package/dist/client/silex-lib/src/ts/client/grapesjs/semantic.d.ts +1 -0
  74. package/dist/client/silex-lib/src/ts/client/grapesjs/settings-sections.d.ts +16 -0
  75. package/dist/client/silex-lib/src/ts/client/grapesjs/settings.d.ts +4 -0
  76. package/dist/client/silex-lib/src/ts/client/grapesjs/storage.d.ts +2 -0
  77. package/dist/client/silex-lib/src/ts/client/grapesjs/symbolDialogs.d.ts +3 -0
  78. package/dist/client/silex-lib/src/ts/client/grapesjs/view-buttons.d.ts +1 -0
  79. package/dist/client/silex-lib/src/ts/client/index.d.ts +10 -0
  80. package/dist/client/silex-lib/src/ts/client/publication-transformers.d.ts +42 -0
  81. package/dist/client/silex-lib/src/ts/client/publish-custom-code-block.d.ts +4 -0
  82. package/dist/client/silex-lib/src/ts/client/publish-fonts.d.ts +4 -0
  83. package/dist/client/silex-lib/src/ts/client/utils.d.ts +22 -0
  84. package/dist/client/silex-lib/src/ts/constants.d.ts +32 -0
  85. package/dist/client/silex-lib/src/ts/page.d.ts +2 -0
  86. package/dist/client/silex-lib/src/ts/types.d.ts +339 -0
  87. package/dist/client/types.d.ts +339 -0
  88. package/dist/plugins/client/client/events.d.ts +23 -0
  89. package/dist/plugins/client/client/events.js +43 -0
  90. package/dist/plugins/client/client/events.js.map +1 -0
  91. package/dist/plugins/client/plugins/client/template.d.ts +2 -0
  92. package/dist/plugins/client/plugins/client/template.js +234 -0
  93. package/dist/plugins/client/plugins/client/template.js.map +1 -0
  94. package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
  95. package/dist/plugins/client/plugins/client/website-info.js +72 -0
  96. package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
  97. package/dist/plugins/client/types.d.ts +339 -0
  98. package/dist/plugins/client/types.js +80 -0
  99. package/dist/plugins/client/types.js.map +1 -0
  100. package/dist/plugins/server/constants.d.ts +32 -0
  101. package/dist/plugins/server/constants.js +76 -0
  102. package/dist/plugins/server/constants.js.map +1 -0
  103. package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
  104. package/dist/plugins/server/plugins/server/Cache.js +36 -0
  105. package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
  106. package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
  107. package/dist/plugins/server/plugins/server/DownloadConnector.js +127 -0
  108. package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
  109. package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
  110. package/dist/plugins/server/plugins/server/FtpConnector.js +536 -0
  111. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
  112. package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +135 -0
  113. package/dist/plugins/server/plugins/server/GitlabConnector.js +649 -0
  114. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
  115. package/dist/plugins/server/plugins/server/GitlabHostingConnector.d.ts +16 -0
  116. package/dist/plugins/server/plugins/server/GitlabHostingConnector.js +209 -0
  117. package/dist/plugins/server/plugins/server/GitlabHostingConnector.js.map +1 -0
  118. package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
  119. package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
  120. package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
  121. package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
  122. package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
  123. package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
  124. package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +8 -0
  125. package/dist/plugins/server/plugins/server/StaticPlugin.js +45 -0
  126. package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
  127. package/dist/plugins/server/server/config.d.ts +59 -0
  128. package/dist/plugins/server/server/config.js +181 -0
  129. package/dist/plugins/server/server/config.js.map +1 -0
  130. package/dist/plugins/server/server/connectors/FsHosting.d.ts +14 -0
  131. package/dist/plugins/server/server/connectors/FsHosting.js +66 -0
  132. package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
  133. package/dist/plugins/server/server/connectors/FsStorage.d.ts +44 -0
  134. package/dist/plugins/server/server/connectors/FsStorage.js +261 -0
  135. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
  136. package/dist/plugins/server/server/connectors/connectors.d.ts +86 -0
  137. package/dist/plugins/server/server/connectors/connectors.js +126 -0
  138. package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
  139. package/dist/plugins/server/server/events.d.ts +26 -0
  140. package/dist/plugins/server/server/events.js +31 -0
  141. package/dist/plugins/server/server/events.js.map +1 -0
  142. package/dist/plugins/server/server/jobs.d.ts +12 -0
  143. package/dist/plugins/server/server/jobs.js +79 -0
  144. package/dist/plugins/server/server/jobs.js.map +1 -0
  145. package/dist/plugins/server/server/utils/validation.d.ts +7 -0
  146. package/dist/plugins/server/server/utils/validation.js +37 -0
  147. package/dist/plugins/server/server/utils/validation.js.map +1 -0
  148. package/dist/plugins/server/types.d.ts +339 -0
  149. package/dist/plugins/server/types.js +84 -0
  150. package/dist/plugins/server/types.js.map +1 -0
  151. package/dist/server/constants.js +55 -0
  152. package/dist/server/plugins/server/Cache.js +19 -0
  153. package/dist/server/server/api/api.js +20 -0
  154. package/dist/server/server/api/connectorApi.js +334 -0
  155. package/dist/server/server/api/publicationApi.js +106 -0
  156. package/dist/server/server/api/websiteApi.js +315 -0
  157. package/dist/server/server/cli.js +71 -0
  158. package/dist/server/server/config.js +120 -0
  159. package/dist/server/server/connectors/FsHosting.js +47 -0
  160. package/dist/server/server/connectors/FsStorage.js +228 -0
  161. package/dist/server/server/connectors/connectors.js +88 -0
  162. package/dist/server/server/events.js +14 -0
  163. package/dist/server/server/expose.js +27 -0
  164. package/dist/server/server/express.js +46 -0
  165. package/dist/server/server/index.js +92 -0
  166. package/dist/server/server/jobs.js +50 -0
  167. package/dist/server/server/utils/validation.js +14 -0
  168. package/dist/server/types.js +40 -0
  169. package/package.json +99 -49
  170. package/public/assets/download.png +0 -0
  171. package/public/assets/favicon.ico +0 -0
  172. package/public/assets/favicon.png +0 -0
  173. package/public/assets/ftp.png +0 -0
  174. package/public/assets/gitlab.png +0 -0
  175. package/public/assets/gitlab2.png +0 -0
  176. package/public/assets/laptop.png +0 -0
  177. package/public/assets/logo-silex-small.png +0 -0
  178. package/public/silex.js +22 -23
  179. package/src/css/_variables.scss +24 -20
  180. package/src/css/dialog.scss +35 -2
  181. package/src/css/fonts.scss +31 -0
  182. package/src/css/footer.scss +12 -0
  183. package/src/css/grapesjs-light.scss +180 -0
  184. package/src/css/grapesjs-plugins.scss +227 -0
  185. package/src/css/grapesjs.scss +159 -1
  186. package/src/css/index.scss +12 -1
  187. package/src/css/light.scss +7 -0
  188. package/src/css/loader.scss +2 -0
  189. package/src/css/project-bar.scss +32 -16
  190. package/src/css/silex.scss +79 -5
  191. package/src/css/website-info.scss +14 -0
  192. package/src/html/index.pug +3 -3
  193. package/src/html/templates/includes.pug +0 -1
  194. package/src/ts/client/api.ts +156 -0
  195. package/src/ts/client/assetUrl.test.ts +164 -0
  196. package/src/ts/client/assetUrl.ts +254 -0
  197. package/src/ts/client/config.ts +175 -13
  198. package/src/ts/client/events.ts +43 -0
  199. package/src/ts/client/expose.ts +27 -1
  200. package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
  201. package/src/ts/client/grapesjs/PublicationManager.ts +433 -0
  202. package/src/ts/client/grapesjs/PublicationUi.ts +366 -0
  203. package/src/ts/client/grapesjs/blocks.ts +17 -0
  204. package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
  205. package/src/ts/client/grapesjs/css-props.ts +910 -0
  206. package/src/ts/client/grapesjs/eleventy.ts +30 -7
  207. package/src/ts/client/grapesjs/footer.ts +42 -0
  208. package/src/ts/client/grapesjs/img.ts +147 -0
  209. package/src/ts/client/grapesjs/index.ts +311 -122
  210. package/src/ts/client/grapesjs/internal-links.test.ts +19 -1
  211. package/src/ts/client/grapesjs/internal-links.ts +31 -7
  212. package/src/ts/client/grapesjs/keymaps.ts +207 -0
  213. package/src/ts/client/grapesjs/new-page-dialog.ts +19 -3
  214. package/src/ts/client/grapesjs/openImport.ts +22 -0
  215. package/src/ts/client/grapesjs/page-panel.ts +109 -7
  216. package/src/ts/client/grapesjs/project-bar.ts +133 -72
  217. package/src/ts/client/grapesjs/resize-panel.ts +20 -0
  218. package/src/ts/client/grapesjs/rich-text.ts +38 -13
  219. package/src/ts/client/grapesjs/semantic.ts +20 -3
  220. package/src/ts/client/grapesjs/settings-sections.ts +117 -0
  221. package/src/ts/client/grapesjs/settings.ts +191 -96
  222. package/src/ts/client/grapesjs/storage.ts +187 -0
  223. package/src/ts/client/grapesjs/symbolDialogs.ts +21 -5
  224. package/src/ts/client/grapesjs/view-buttons.ts +42 -0
  225. package/src/ts/client/index.ts +80 -21
  226. package/src/ts/client/publication-transformers.test.ts +207 -0
  227. package/src/ts/client/publication-transformers.ts +280 -0
  228. package/src/ts/client/publish-custom-code-block.ts +31 -0
  229. package/src/ts/client/publish-fonts.ts +36 -0
  230. package/src/ts/client/utils.ts +70 -1
  231. package/src/ts/constants.ts +78 -0
  232. package/src/ts/externs.ts +17 -0
  233. package/src/ts/page.ts +20 -3
  234. package/src/ts/plugins/client/template.ts +246 -0
  235. package/src/ts/plugins/client/website-info.ts +84 -0
  236. package/src/ts/plugins/server/Cache.ts +32 -0
  237. package/src/ts/plugins/server/DownloadConnector.ts +146 -0
  238. package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
  239. package/src/ts/plugins/server/FtpConnector.ts +621 -0
  240. package/src/ts/plugins/server/GitlabConnector.ts +749 -0
  241. package/src/ts/plugins/server/GitlabHostingConnector.ts +215 -0
  242. package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
  243. package/src/ts/plugins/server/SslPlugin.ts +84 -0
  244. package/src/ts/plugins/server/StaticPlugin.ts +45 -0
  245. package/src/ts/server/api/api.ts +19 -0
  246. package/src/ts/server/api/connectorApi.ts +464 -0
  247. package/src/ts/server/api/publicationApi.ts +159 -0
  248. package/src/ts/server/api/websiteApi.ts +462 -0
  249. package/src/ts/server/cli.ts +48 -14
  250. package/src/ts/server/config.ts +158 -60
  251. package/src/ts/server/connectors/FsHosting.ts +66 -0
  252. package/src/ts/server/connectors/FsStorage.test.ts +51 -0
  253. package/src/ts/server/connectors/FsStorage.ts +290 -0
  254. package/src/ts/server/connectors/connectors.ts +203 -0
  255. package/src/ts/server/events.ts +37 -0
  256. package/src/ts/server/expose.ts +19 -0
  257. package/src/ts/server/express.ts +57 -5
  258. package/src/ts/server/index.ts +80 -19
  259. package/src/ts/server/jobs.test.ts +75 -0
  260. package/src/ts/server/jobs.ts +89 -0
  261. package/src/ts/server/utils/BackwardCompat.ts +546 -528
  262. package/src/ts/server/utils/validation.ts +34 -0
  263. package/src/ts/types.ts +295 -85
  264. package/.dockerignore +0 -5
  265. package/.editorconfig +0 -14
  266. package/.eslintrc.json +0 -43
  267. package/.github/FUNDING.yml +0 -13
  268. package/.github/workflows/docker-hub-publish.yml +0 -36
  269. package/.github/workflows/npm-publish.yml +0 -19
  270. package/.github/workflows/test.yml +0 -26
  271. package/.nvmrc +0 -1
  272. package/.silex/default/.silex.data.json +0 -1
  273. package/CODE_OF_CONDUCT.md +0 -128
  274. package/CONTRIBUTING.md +0 -131
  275. package/Dockerfile +0 -15
  276. package/directus.silex.js +0 -7
  277. package/dist/constants.js +0 -4
  278. package/dist/events.js +0 -5
  279. package/dist/page.js +0 -15
  280. package/dist/server/cli.js +0 -43
  281. package/dist/server/config.js +0 -70
  282. package/dist/server/express.js +0 -18
  283. package/dist/server/index.js +0 -58
  284. package/dist/types.js +0 -34
  285. package/jest.config.js +0 -10
  286. package/logos/logo_by_ceubri/silex-icon-2018@200px.png +0 -0
  287. package/logos/logo_by_ceubri/silex-icon-2018@4x.png +0 -0
  288. package/logos/logo_by_ceubri/silex-logo-2018-white-transp.pdf +0 -0
  289. package/logos/logo_by_ceubri/silex-logo-2018-white.jpg +0 -0
  290. package/logos/logo_by_ceubri/silex-logo-2018-white.pdf +0 -0
  291. package/logos/logo_by_ceubri/silex-logo-2018-white.png +0 -0
  292. package/logos/logo_by_ceubri/silex-logo-2018-white@0.5x.png +0 -0
  293. package/logos/logo_by_ceubri/silex-logo-2018-white@0.75x.png +0 -0
  294. package/logos/logo_by_ceubri/silex-logo-2018-white@4x.jpg +0 -0
  295. package/logos/logo_by_ceubri/silex-logo-2018-white@4x.png +0 -0
  296. package/logos/logo_by_ceubri/silex-logo-2018.ai +5 -2521
  297. package/logos/logo_by_ceubri/silex-logo-2018.jpg +0 -0
  298. package/logos/logo_by_ceubri/silex-logo-2018.pdf +0 -0
  299. package/logos/logo_by_ceubri/silex-logo-2018.png +0 -0
  300. package/logos/logo_by_ceubri/silex-logo-2018@0.5x.png +0 -0
  301. package/logos/logo_by_ceubri/silex-logo-2018@0.75x.png +0 -0
  302. package/logos/logo_by_ceubri/silex-logo-2018@4x.jpg +0 -0
  303. package/logos/logo_by_ceubri/silex-logo-2018@4x.png +0 -0
  304. package/logos/silexlabs.png +0 -0
  305. package/src/example-client-config.js +0 -47
  306. package/src/plugins/AuthPlugin.js +0 -21
  307. package/src/plugins/Cache.js +0 -11
  308. package/src/plugins/DefaultBackend.js +0 -149
  309. package/src/plugins/ExpressPlugin.js +0 -39
  310. package/src/plugins/HooksPlugin.js +0 -58
  311. package/src/plugins/PublishPlugin.js +0 -69
  312. package/src/plugins/SslPlugin.js +0 -66
  313. package/src/plugins/StaticPlugin.js +0 -48
  314. package/src/plugins/WebsitePlugin.js +0 -207
  315. package/src/ts/client/grapesjs/publish.ts +0 -386
  316. package/src/ts/client/grapesjs/template.ts +0 -166
  317. package/src/ts/events.ts +0 -2
  318. package/tsconfig-server-debug.json +0 -19
  319. package/tsconfig-server-release.json +0 -19
  320. package/tsconfig.jest.json +0 -9
  321. package/tsconfig.json +0 -26
  322. package/webpack.config.js +0 -28
  323. package/webpack.debug.config.js +0 -8
@@ -1,27 +1,41 @@
1
- import {html, render} from 'lit-html'
2
- import {live} from 'lit-html/directives/live.js'
3
- import * as grapesjs from 'grapesjs/dist/grapes.min.js'
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 {html, render, TemplateResult} from 'lit-html'
19
+ import {defaultSections, idCodeWrapper, isSite, SettingsSection} from './settings-sections'
20
+
21
+ /**
22
+ * @fileoverview This file contains the settings dialog. The config API lets plugins add sections to the settings dialog.
23
+ */
4
24
 
5
25
  import { WebsiteSettings } from '../../types'
26
+ import { ClientEvent } from '../events'
27
+ import { SILEX_VERSION } from '../../constants'
28
+
29
+ const sectionsSite = [...defaultSections]
30
+ const sectionsPage = [...defaultSections]
6
31
 
7
- const pluginName = 'settings-dialog'
8
32
  const el = document.createElement('div')
9
33
  let modal
10
34
 
11
- // Get version from webpack (see plugin in webpack.config.js)
12
- declare const VERSION: string
13
-
14
35
  export const cmdOpenSettings = 'open-settings'
15
36
 
16
- let version = 'v3'
17
- export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) => {
18
- // Display Silex version from package.json
19
- try {
20
- version = VERSION
21
- } catch (error) {
22
- // Cannot get version from webpack (see plugin in webpack.config.js)
23
- }
24
- console.log('Silex version:', version)
37
+ let headEditor = null
38
+ export const settingsDialog = (editor, opts) => {
25
39
  editor.Commands.add(cmdOpenSettings, {
26
40
  run: (_, sender, {page}) => {
27
41
  modal = editor.Modal.open({
@@ -30,6 +44,7 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
30
44
  attributes: { class: 'settings-dialog' },
31
45
  })
32
46
  .onceClose(() => {
47
+ sender?.set && sender.set('active', 0) // Deactivate the button to make it ready to be clicked again, only in case of a grapesjs button (not in the pages panel)
33
48
  editor.stopCommand(cmdOpenSettings) // apparently this is needed to be able to run the command several times
34
49
  })
35
50
  displaySettings(editor, opts, page)
@@ -37,14 +52,20 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
37
52
  const form = el.querySelector('form')
38
53
  form.onsubmit = event => {
39
54
  event.preventDefault()
55
+ editor.trigger(ClientEvent.SETTINGS_SAVE_START, page)
40
56
  saveSettings(editor, opts, page)
57
+ editor.trigger(ClientEvent.SETTINGS_SAVE_END, page)
41
58
  editor.stopCommand(cmdOpenSettings)
42
59
  }
43
60
  form.querySelector('input')?.focus()
61
+ // Notify other plugins
62
+ editor.trigger(ClientEvent.SETTINGS_OPEN, page)
63
+ // Return the dialog
44
64
  return modal
45
65
  },
46
66
  stop: () => {
47
67
  modal.close()
68
+ editor.trigger(ClientEvent.SETTINGS_CLOSE)
48
69
  },
49
70
  })
50
71
  // add settings to the website
@@ -56,93 +77,156 @@ export const settingsDialog = grapesjs.plugins.add(pluginName, (editor, opts) =>
56
77
  const model = editor.getModel()
57
78
  model.set('settings', data.settings || {})
58
79
  model.set('name', data.name)
80
+ editor.once('canvas:frame:load', () => {
81
+ updateDom(editor)
82
+ })
83
+ })
84
+ // Normal way to apply the head content to the DOM
85
+ // fix #1559 Custom <head> code must be reapplied
86
+ editor.on('canvas:frame:load', () => {
59
87
  updateDom(editor)
60
88
  })
89
+ // When the page changes, update the dom
61
90
  editor.on('page', (e) => {
62
- editor.Canvas.getFrameEl().addEventListener('load', () => {
63
- updateDom(editor)
64
- })
91
+ updateDom(editor)
92
+ })
93
+ headEditor = editor.CodeManager.createViewer({
94
+ readOnly: false,
95
+ codeName: 'htmlmixed',
96
+ lineNumbers: true,
97
+ lineWrapping: true,
98
+ autoFormat: false,
65
99
  })
66
- })
100
+ }
101
+
102
+ function showSection(item: SettingsSection) {
103
+ // **
104
+ // Handle the side bar
105
+ const aside = el.querySelector('aside.silex-bar') as HTMLElement
106
+ const ul = aside.querySelector('ul.silex-list--menu') as HTMLUListElement
107
+ const li = ul.querySelector('li#settings-sidebar-' + item.id) as HTMLLIElement
108
+ currentSection = item
109
+ if(!li) {
110
+ console.warn('Cannot find section', item.id, 'in the side bar, fallback to the first section')
111
+ if(!defaultSections[0] || defaultSections[0].id === item.id) {
112
+ console.error('Cannot find the default section in the side bar')
113
+ return
114
+ }
115
+ showSection(defaultSections[0]) // Fallback to the first section
116
+ return
117
+ }
118
+ // Update active
119
+ Array.from(ul.querySelectorAll('.active')).forEach(el => el.classList.remove('active'))
120
+ li.classList.add('active')
121
+ // **
122
+ // Handle the main section
123
+ const main = el.querySelector('main#settings__main') as HTMLElement
124
+ const mainItem = main.querySelector(`#settings-${item.id}`)
125
+ if(!mainItem) {
126
+ console.warn('Cannot find section', item.id, 'in the settings dialog, fallback to the first section')
127
+ if(!defaultSections[0] || defaultSections[0].id === item.id) {
128
+ console.error('Cannot find the default section in the settings dialog')
129
+ return
130
+ }
131
+ showSection(defaultSections[0]) // Fallback to the first section
132
+ return
133
+ }
134
+ // Update hidden
135
+ Array.from(main.querySelectorAll('.silex-hideable')).forEach(el => el.classList.add('silex-hidden'))
136
+ mainItem.classList.remove('silex-hidden')
137
+ // This messes up with the save / cancel mechanism
138
+ // displaySettings(editor, config, model)
139
+ // Refresh the code editor just in case it went from hidden to visible
140
+ // This makes it ready to be used when the user clicks on the tab
141
+ headEditor.refresh()
142
+ }
143
+
144
+ export function addSection(section, siteOrPage: 'site' | 'page', position: 'first' | 'last' | number) {
145
+ const sections = siteOrPage === 'site' ? sectionsSite : sectionsPage
146
+ if (position === 'first') {
147
+ sections.unshift(section)
148
+ } else if (position === 'last') {
149
+ sections.push(section)
150
+ } else if (typeof position === 'number') {
151
+ sections.splice(position, 0, section)
152
+ } else {
153
+ throw new Error('Invalid position for settings section')
154
+ }
155
+ }
156
+
157
+ export function removeSection(id, siteOrPage: 'site' | 'page') {
158
+ const sections = siteOrPage === 'site' ? sectionsSite : sectionsPage
159
+ const index = sections.findIndex(section => section.id === id)
160
+ if(index === -1) throw new Error(`Cannot find section with id ${id}`)
161
+ sections.splice(index, 1)
162
+ }
67
163
 
68
- // Is the model a site or a page?
69
- function isSite(model) { return !!model.getHtml }
70
164
 
165
+ let currentSection
71
166
  function displaySettings(editor, config, model = editor.getModel()) {
167
+ // Update the model with the current settings
72
168
  const settings = model.get('settings') || {} as WebsiteSettings
73
169
  model.set('settings', settings)
170
+ // Get the current sections for page or site
171
+ const menuItemsCurrent = isSite(model) ? sectionsSite : sectionsPage
172
+ // Init the current section selection
173
+ currentSection = currentSection || menuItemsCurrent[0]
174
+ const sections: TemplateResult[] = menuItemsCurrent.map(item => {
175
+ try {
176
+ return item.render(settings, model)
177
+ } catch (e) {
178
+ console.error('Error rendering settings section', item.id, e)
179
+ return html`<div class="silex-error">Error rendering settings section ${item.id}</div>`
180
+ }
181
+ })
182
+ // Render the settings dialog
74
183
  render(html`
75
- <p>The page settings will override site settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
76
184
  <form class="silex-form">
77
- <h2>General settings</h2>
78
- <div class="silex-form__group col2">
79
- <label class="silex-form__element">
80
- <h3>${isSite(model) ? 'Site name' : 'Page name'}</h3>
81
- <p>${isSite(model) ? 'The project name in the editor, for you and your team.' : 'Label of the page in the editor, and file name of the HTML page.'}</p>
82
- <input type="text" name="name" .value=${live(model.get('name') || '')}/>
83
- </label>
84
- <label class="silex-form__element">
85
- <h3>Website language</h3>
86
- <p>This is the default language code for this website. Example: en, fr, es...</p>
87
- <input type="text" name="lang" .value=${live(settings.lang || '')}/>
88
- </label>
89
- <label class="silex-form__element">
90
- <h3>Title</h3>
91
- <p>Title of the browser window, and title in the search engines results. It is used by search engines to find out what your site is talking about. The title should be a maximum of 70 characters long, including spaces.</p>
92
- <input type="text" name="title" .value=${live(settings.title || '')}/>
93
- </label>
94
- <label class="silex-form__element">
95
- <h3>Description</h3>
96
- <p>Description displayed by the search engines in search results. It is used by search engines to find out what your site is talking about. It is best to keep meta descriptions between 150 and 160 characters.</p>
97
- <input type="text" name="description" .value=${live(settings.description || '')}/>
98
- </label>
99
- <label class="silex-form__element">
100
- <h3>Favicon</h3>
101
- <p>Small image displayed in the browser's address bar and in tabs. The recommended size is 16×16 or 32×32 pixels. This can be a URL or a relative path.</p>
102
- <input type="text" name="favicon" .value=${live(settings.favicon || '')}/>
103
- </label>
104
- </div>
105
- <h2>Social networks sharing</h2>
106
- <div>
107
- <p>Once your website is live, you can use these tools to test sharing:&nbsp;<a target="_blank" href="https://developers.facebook.com/tools/debug/">Facebook</a>,
108
- <a target="_blank" href="https://cards-dev.twitter.com/validator">Twitter</a>,
109
- <a target="_blank" href="https://www.linkedin.com/post-inspector/inspect/">Linkedin</a></p>
110
- </div>
111
- <div class="silex-form__group col2">
112
- <label class="silex-form__element">
113
- <h3>Title</h3>
114
- <p>The title of your website displayed when a user shares your website on a social network.
115
- Do not include any branding in this title, just eye-catching phrase, e.g. "Learn everything about fishing".
116
- Title should be between 60 and 90 characters long.</p>
117
- <input type="text" name="og:title" .value=${live(settings['og:title'] || '')}/>
118
- </label>
119
- <label class="silex-form__element">
120
- <h3>Description</h3>
121
- <p>Description displayed when a user shares your website on a social network. Make it catchy, and invite readers to visit your website too, e.g. "Sam's website about fishing, check it out!" Title should be between 60 and 90 characters long.</p>
122
- <input type="text" name="og:description" .value=${live(settings['og:description'] || '')}/>
123
- </label>
124
- <label class="silex-form__element">
125
- <h3>Image</h3>
126
- <p>Thumbnail image which is displayed when your website is shared on a social network. The optimal size is 1200×627 pixels. At this size, your thumbnail will be big and stand out from the crowd. But do not exceed the 5MB size limit. If you use an image that is smaller than 400 pixels x 209 pixels, it will render as a much smaller thumbnail.</p>
127
- <p>Please enter the full URL here, e.g. "http://mysite.com/path/to/image.jpg"</p>
128
- <input type="text" name="og:image" .value=${live(settings['og:image'] || '')}/>
129
- </label>
130
- </div>
131
- <h2>Code</h2>
132
- <div class="silex-form__group">
133
- <label class="silex-form__element">
134
- <h3>HTML head</h3>
135
- <p>HTML code which will be inserted in the HEAD tag.</p>
136
- <textarea name="head" .value=${live(settings.head || '')}></textarea>
137
- </label>
185
+ <div class="silex-help">
186
+ ${isSite(model) ? html`
187
+ <p>Here you can set the name of your website, SEO and social networks sharing data.</p>
188
+ <p>These settings are overriden by the page settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
189
+ ` : html`
190
+ <p>Here you can set the name of your page, SEO and social networks sharing data.</p>
191
+ <p>These settings override the site settings, <a href="https://github.com/silexlabs/Silex/wiki/Settings" target="_blank">more info about settings here</a>.</p>
192
+ `}
138
193
  </div>
194
+ <section class="silex-sidebar-dialog">
195
+ <aside class="silex-bar">
196
+ <ul class="silex-list silex-list--menu">
197
+ ${menuItemsCurrent.map(item => html`
198
+ <li
199
+ id="settings-sidebar-${item.id}"
200
+ class=${item.id === currentSection.id ? 'active' : ''}
201
+ @click=${e => {
202
+ e.preventDefault()
203
+ // Show the new section
204
+ showSection(item)
205
+ // Notify other plugins
206
+ editor.trigger(ClientEvent.SETTINGS_SECTION_CHANGE, item.id)
207
+ }}
208
+ >
209
+ ${item.label}
210
+ </li>
211
+ `)}
212
+ </ul>
213
+ </aside>
214
+ <main id="settings__main">
215
+ ${ sections }
216
+ </main>
217
+ </section>
139
218
  <footer>
140
- <p class="silex-version">Silex ${version}</p>
219
+ <p class="silex-version">Silex ${SILEX_VERSION}</p>
141
220
  <input class="silex-button" type="button" @click=${e => editor.stopCommand(cmdOpenSettings)} value="Cancel">
142
- <input class="silex-button" type="submit" value="Ok">
221
+ <input class="silex-button" type="submit" value="Apply">
143
222
  </footer>
144
223
  </form>
145
224
  `, el)
225
+ // Display the current section
226
+ showSection(currentSection)
227
+ // Init the code editor
228
+ el.querySelector(`#${idCodeWrapper}`)?.appendChild(headEditor.getElement())
229
+ headEditor.setContent(settings.head || '')
146
230
  }
147
231
 
148
232
  function saveSettings(editor, config, model = editor.getModel()) {
@@ -150,13 +234,19 @@ function saveSettings(editor, config, model = editor.getModel()) {
150
234
  const formData = new FormData(form)
151
235
  const data = Array.from(formData as any)
152
236
  .reduce((aggregate, [key, value]) => {
153
- aggregate[key] = value
237
+ // Keep only the values that are set
238
+ if(value !== '') {
239
+ aggregate[key] = value
240
+ }
154
241
  return aggregate
155
242
  }, {}) as {[key: string]: any}
156
- // take the name out to the main model (by design in grapesjs pages)
243
+ // take the name out to the main model (by design in grapesjs pages)
157
244
  const { name, ...settings } = data
158
245
  model.set({
159
- settings,
246
+ settings: {
247
+ ...data,
248
+ head: headEditor.getContent(),
249
+ },
160
250
  name,
161
251
  })
162
252
  // save if auto save is on
@@ -176,13 +266,18 @@ function getHeadContainer(doc, className) {
176
266
  }
177
267
  function updateDom(editor) {
178
268
  const doc = editor.Canvas.getDocument()
179
- if(doc) {
180
- // Site head
181
- getHeadContainer(doc, 'site-head')
182
- .innerHTML = editor.getModel().get('settings').head || ''
183
- // Pages head
184
- getHeadContainer(doc, 'page-head')
185
- .innerHTML = editor.Pages.getSelected().get('settings')?.head || ''
269
+ const settings = editor.getModel().get('settings')
270
+ const pageSettings = editor.Pages.getSelected().get('settings')
271
+ if(doc && settings) {
272
+ // Delay the update to let the DOM be ready
273
+ setTimeout(() => {
274
+ // Site head
275
+ getHeadContainer(doc, 'site-head')
276
+ .innerHTML = settings.head || ''
277
+ // Pages head
278
+ getHeadContainer(doc, 'page-head')
279
+ .innerHTML = pageSettings?.head || ''
280
+ })
186
281
  } else {
187
282
  // No document??
188
283
  }
@@ -0,0 +1,187 @@
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 { ConnectorId, WebsiteId, WebsiteData, ConnectorUser, ConnectorType, ApiError } from '../../types'
19
+ import { websiteLoad, websiteSave } from '../api'
20
+ import { cmdLogin, eventLoggedIn, eventLoggedOut, getCurrentUser, updateUser } from './LoginDialog'
21
+ import { addTempDataToPages, addTempDataToAssetUrl, addTempDataToStyles, removeTempDataFromAssetUrl, removeTempDataFromPages, removeTempDataFromStyles } from '../assetUrl'
22
+ import { PublicationStatus } from './PublicationManager'
23
+ import { ClientEvent } from '../events'
24
+
25
+ export const cmdPauseAutoSave = 'pause-auto-save'
26
+
27
+ // Mechanism to keep only the last save during publication
28
+ let lastPendingSaving: WebsiteData = null
29
+
30
+ // Mechanism to avoid concurrent saving
31
+ // Note: there is already such a mechanism in grapesjs but it fails when the save is delayed by the publication
32
+ let isSaving = false
33
+
34
+ export const storagePlugin = (editor) => {
35
+ // Add useful commands
36
+ editor.Commands.add(cmdPauseAutoSave, {
37
+ run: () => {
38
+ if(!editor.StorageManager.isAutosave()) throw new Error('Autosave is not enabled')
39
+ editor.StorageManager.setAutosave(false)
40
+ },
41
+ stop: () => {
42
+ editor.editor.set('changesCount', 0)
43
+ editor.UndoManager.clear()
44
+ editor.StorageManager.setAutosave(true)
45
+ },
46
+ })
47
+ // Add the storage connector
48
+ editor.Storage.add('connector', {
49
+ async load(options: { id: WebsiteId, connectorId: ConnectorId }): Promise<WebsiteData> {
50
+ try {
51
+ const user: ConnectorUser = await getCurrentUser(editor) ?? await updateUser(editor, ConnectorType.STORAGE, options.connectorId)
52
+ if (!user) throw new ApiError('Not logged in', 401)
53
+ const data = await websiteLoad({ websiteId: options.id, connectorId: user.storage.connectorId }) as WebsiteData
54
+ if (data.assets) data.assets = addTempDataToAssetUrl(data.assets, options.id, user.storage.connectorId)
55
+ if (data.pages) data.pages = addTempDataToPages(data.pages, options.id, user.storage.connectorId)
56
+ if (data.styles) data.styles = addTempDataToStyles(data.styles, options.id, user.storage.connectorId)
57
+ return data
58
+
59
+ } catch (err) {
60
+ editor.UndoManager.clear()
61
+ if (err.httpStatusCode === 401) {
62
+ editor.once(eventLoggedIn, async () => {
63
+ try {
64
+ editor.runCommand(cmdPauseAutoSave)
65
+ const data = await editor.Storage.load(options)
66
+ editor.once('canvas:frame:load', () => editor.stopCommand(cmdPauseAutoSave))
67
+ editor.loadProjectData(data)
68
+ } catch (err) {
69
+ console.error('connectorPlugin load error', err)
70
+ throw err
71
+ }
72
+ })
73
+ editor.Commands.run(cmdLogin)
74
+ }
75
+ console.error('connectorPlugin load error', err)
76
+ throw err
77
+ }
78
+ },
79
+
80
+ async store(data: WebsiteData, options: { id: WebsiteId, connectorId: ConnectorId }) {
81
+ // Be sure that it is immutable
82
+ const myData = { ...data }
83
+ return await this.addToQueue(myData, options)
84
+ },
85
+
86
+ async addToQueue(data: WebsiteData, options) {
87
+ // Handle concurrent saving
88
+ if (lastPendingSaving && lastPendingSaving !== data) {
89
+ // Cancel previous saving
90
+ }
91
+ lastPendingSaving = data
92
+ // Go ahaed and save
93
+ return this.doStore(lastPendingSaving, options)
94
+ },
95
+
96
+ async doStore(data, options) {
97
+ if (editor.PublicationManager?.status === PublicationStatus.STATUS_PENDING) {
98
+ // Publication is pending, save is delayed
99
+ return new Promise((resolve) => {
100
+ editor.once(ClientEvent.PUBLISH_END, () => {
101
+ resolve(this.doStore(data, options))
102
+ })
103
+ })
104
+ }
105
+ try {
106
+ if (isSaving) {
107
+ // Concurrent saving, save is delayed
108
+ editor.once('storage:start:store', () => {
109
+ this.doStore(data, options)
110
+ })
111
+ } else {
112
+ if (lastPendingSaving === data) {
113
+ lastPendingSaving = null
114
+ isSaving = true
115
+ const user = await getCurrentUser(editor)
116
+ if (user) {
117
+ data.assets = removeTempDataFromAssetUrl(data.assets)
118
+ data.pages = removeTempDataFromPages(data.pages)
119
+ data.styles = removeTempDataFromStyles(data.styles)
120
+ await websiteSave({ websiteId: options.id, connectorId: user.storage.connectorId, data })
121
+ isSaving = false
122
+ } else {
123
+ // Not logged in save is delayed
124
+ editor.once(eventLoggedIn, () => {
125
+ isSaving = false
126
+ return editor.Storage.store()
127
+ })
128
+ editor.Commands.run(cmdLogin)
129
+ }
130
+ } else {
131
+ // Canceled saving
132
+ }
133
+ }
134
+ } catch (err) {
135
+ console.error('connectorPlugin store error', err)
136
+ isSaving = false
137
+ throw err
138
+ }
139
+ }
140
+ })
141
+ // Handle errors
142
+ editor.on('storage:error:load', (err: Error) => {
143
+ handleError(err)
144
+ })
145
+ editor.on('storage:error:store', (err: Error) => {
146
+ handleError(err)
147
+ })
148
+ editor.on('asset:upload:end', (err: Error) => {
149
+ editor.store()
150
+ })
151
+ editor.on('asset:upload:error', (err: Error) => {
152
+ handleError(err)
153
+ })
154
+ function handleError(_err: Error | string) {
155
+ const err: Error = typeof _err === 'string' ? JSON.parse(_err) : _err
156
+ console.error('Error with loading or saving website or uploading asset', err, err instanceof ApiError)
157
+ if (err instanceof ApiError) {
158
+ console.error('ApiError', err.httpStatusCode, err.message)
159
+ switch (err.httpStatusCode) {
160
+ case 404:
161
+ return editor.Modal.open({
162
+ title: 'Website not found',
163
+
164
+ content: `This website could not be found.<br><hr>${err.message}`,
165
+ })
166
+ case 403:
167
+ return editor.Modal.open({
168
+ title: 'Access denied',
169
+ content: `You are not allowed to access this website.<br><hr>${err.message}`,
170
+ })
171
+ case 401:
172
+ editor.trigger(eventLoggedOut)
173
+ return
174
+ default:
175
+ return editor.Modal.open({
176
+ title: 'Error',
177
+ content: `An error occured.<br>${err.message}`,
178
+ })
179
+ }
180
+ } else {
181
+ return editor.Modal.open({
182
+ title: 'Error',
183
+ content: `An error occured.<br>${err.message}`,
184
+ })
185
+ }
186
+ }
187
+ }
@@ -1,9 +1,25 @@
1
- import * as grapesjs from 'grapesjs/dist/grapes.min.js'
2
- import { cmdAddSymbol } from '@silexlabs/grapesjs-symbols/src'
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 { cmdAddSymbol } from '@silexlabs/grapesjs-symbols'
3
19
 
4
20
  export const cmdPromptAddSymbol = 'symbol-prompt-add'
5
21
 
6
- export default grapesjs.plugins.add(name, (editor, opts) => {
22
+ export default (editor, opts) => {
7
23
  function getNext(prefix) {
8
24
  let idx = 1
9
25
  while(editor.Symbols.find(s => s.get('label') === prefix + idx)) {
@@ -14,8 +30,8 @@ export default grapesjs.plugins.add(name, (editor, opts) => {
14
30
  editor.Commands.add(cmdPromptAddSymbol, {
15
31
  run: (_, sender) => {
16
32
  const label = prompt('Label', getNext('Symbol '))
17
- const icon = prompt('Icon', 'fa-list')
33
+ const icon = 'fa-gem'
18
34
  editor.runCommand(cmdAddSymbol, { label, icon })
19
35
  }
20
36
  })
21
- })
37
+ }
@@ -0,0 +1,42 @@
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
+
19
+ const pasteBtnClass = 'fa fa-fw fa-paste silex-button'
20
+ const disabledClass = ' disabled'
21
+
22
+ export default function(editor) {
23
+ // Add copy/paste buttons in the top bar
24
+ const [copyBtn, pasteBtn] = editor.Panels.addButton('options', [{
25
+ id: 'copy',
26
+ className: 'fa fa-fw fa-copy',
27
+ command: 'core:copy',
28
+ attributes: { title: 'Copy (Ctrl+C)' },
29
+ }, {
30
+ id: 'paste',
31
+ className: pasteBtnClass + disabledClass,
32
+ command: 'core:paste',
33
+ attributes: { title: 'Paste (Ctrl+V)' },
34
+ active: false,
35
+ }])
36
+
37
+ // Disable paste button if clipboard is empty
38
+ editor.EditorModel.on('change:clipboard', (model, value) => {
39
+ const hasClipboard = value && value.length > 0
40
+ pasteBtn.set('className', pasteBtnClass + (hasClipboard ? '' : disabledClass))
41
+ })
42
+ }