panda-cms 0.7.4 → 0.8.0

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 (192) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -2
  3. data/Rakefile +2 -0
  4. data/app/components/panda/cms/admin/statistics_component.rb +1 -2
  5. data/app/components/panda/cms/admin/user_activity_component.html.erb +3 -1
  6. data/app/components/panda/cms/admin/user_activity_component.rb +3 -5
  7. data/app/components/panda/cms/admin/user_display_component.html.erb +1 -1
  8. data/app/components/panda/cms/admin/user_display_component.rb +2 -2
  9. data/app/components/panda/cms/code_component.rb +8 -4
  10. data/app/components/panda/cms/menu_component.rb +7 -6
  11. data/app/components/panda/cms/page_menu_component.rb +15 -17
  12. data/app/components/panda/cms/rich_text_component.rb +10 -11
  13. data/app/components/panda/cms/text_component.rb +6 -7
  14. data/app/controllers/panda/cms/admin/base_controller.rb +18 -0
  15. data/app/controllers/panda/cms/admin/block_contents_controller.rb +1 -2
  16. data/app/controllers/panda/cms/admin/dashboard_controller.rb +14 -9
  17. data/app/controllers/panda/cms/admin/files_controller.rb +1 -3
  18. data/app/controllers/panda/cms/admin/forms_controller.rb +3 -6
  19. data/app/controllers/panda/cms/admin/menus_controller.rb +2 -3
  20. data/app/controllers/panda/cms/admin/pages_controller.rb +9 -8
  21. data/app/controllers/panda/cms/admin/posts_controller.rb +9 -11
  22. data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +32 -25
  23. data/app/controllers/panda/cms/admin/settings_controller.rb +13 -10
  24. data/app/controllers/panda/cms/application_controller.rb +19 -6
  25. data/app/controllers/panda/cms/errors_controller.rb +5 -2
  26. data/app/controllers/panda/cms/form_submissions_controller.rb +2 -0
  27. data/app/controllers/panda/cms/pages_controller.rb +34 -31
  28. data/app/controllers/panda/cms/posts_controller.rb +2 -0
  29. data/app/helpers/panda/cms/admin/files_helper.rb +5 -1
  30. data/app/helpers/panda/cms/admin/pages_helper.rb +5 -1
  31. data/app/helpers/panda/cms/application_helper.rb +3 -3
  32. data/app/helpers/panda/cms/asset_helper.rb +195 -0
  33. data/app/helpers/panda/cms/pages_helper.rb +2 -0
  34. data/app/helpers/panda/cms/posts_helper.rb +2 -0
  35. data/app/helpers/panda/cms/theme_helper.rb +2 -0
  36. data/app/javascript/panda/cms/application_panda_cms.js +2 -34
  37. data/app/javascript/panda/cms/controllers/editor_form_controller.js +59 -6
  38. data/app/javascript/panda/cms/controllers/index.js +8 -24
  39. data/app/javascript/panda/cms/stimulus-loading.js +39 -0
  40. data/app/javascript/panda_cms/stimulus-loading.js +39 -0
  41. data/app/jobs/panda/cms/application_job.rb +2 -0
  42. data/app/jobs/panda/cms/record_visit_job.rb +2 -0
  43. data/app/mailers/panda/cms/application_mailer.rb +2 -0
  44. data/app/mailers/panda/cms/form_mailer.rb +3 -1
  45. data/app/models/panda/cms/application_record.rb +2 -0
  46. data/app/models/panda/cms/block.rb +4 -1
  47. data/app/models/panda/cms/block_content.rb +3 -1
  48. data/app/models/panda/cms/current.rb +5 -12
  49. data/app/models/panda/cms/form.rb +2 -0
  50. data/app/models/panda/cms/form_submission.rb +2 -0
  51. data/app/models/panda/cms/menu.rb +12 -9
  52. data/app/models/panda/cms/menu_item.rb +10 -6
  53. data/app/models/panda/cms/page.rb +14 -12
  54. data/app/models/panda/cms/post.rb +12 -8
  55. data/app/models/panda/cms/redirect.rb +6 -3
  56. data/app/models/panda/cms/template.rb +12 -7
  57. data/app/models/panda/cms/visit.rb +3 -1
  58. data/app/models/panda/social/instagram_post.rb +2 -0
  59. data/app/services/panda/social/instagram_feed_service.rb +3 -1
  60. data/app/views/layouts/different_page.html.erb +6 -0
  61. data/app/views/layouts/homepage.html.erb +37 -0
  62. data/app/views/layouts/page.html.erb +18 -0
  63. data/app/views/layouts/panda/cms/application.html.erb +2 -1
  64. data/app/views/panda/cms/admin/dashboard/show.html.erb +2 -2
  65. data/app/views/panda/cms/admin/files/index.html.erb +1 -1
  66. data/app/views/panda/cms/admin/forms/index.html.erb +4 -4
  67. data/app/views/panda/cms/admin/forms/new.html.erb +2 -2
  68. data/app/views/panda/cms/admin/forms/show.html.erb +1 -1
  69. data/app/views/panda/cms/admin/menus/index.html.erb +4 -4
  70. data/app/views/panda/cms/admin/pages/edit.html.erb +6 -6
  71. data/app/views/panda/cms/admin/pages/index.html.erb +5 -5
  72. data/app/views/panda/cms/admin/pages/new.html.erb +16 -10
  73. data/app/views/panda/cms/admin/posts/_form.html.erb +1 -1
  74. data/app/views/panda/cms/admin/posts/edit.html.erb +2 -2
  75. data/app/views/panda/cms/admin/posts/index.html.erb +5 -5
  76. data/app/views/panda/cms/admin/posts/new.html.erb +1 -1
  77. data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +1 -1
  78. data/app/views/panda/cms/admin/settings/index.html.erb +4 -4
  79. data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +3 -3
  80. data/app/views/panda/cms/admin/shared/_flash.html.erb +1 -1
  81. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +8 -8
  82. data/app/views/panda/cms/shared/_header.html.erb +10 -2
  83. data/app/views/panda/cms/shared/_importmap.html.erb +1 -1
  84. data/app/views/shared/_footer.html.erb +3 -0
  85. data/app/views/shared/_header.html.erb +11 -0
  86. data/config/importmap.rb +2 -0
  87. data/config/initializers/inflections.rb +2 -0
  88. data/config/initializers/panda/cms/form_errors.rb +20 -21
  89. data/config/initializers/panda/cms/healthcheck_log_silencer.rb +2 -0
  90. data/config/initializers/panda/cms.rb +8 -3
  91. data/config/initializers/zeitwork.rb +2 -0
  92. data/config/puma/test.rb +3 -1
  93. data/config/routes.rb +11 -19
  94. data/db/migrate/20240205223709_create_panda_cms_pages.rb +2 -0
  95. data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +2 -0
  96. data/db/migrate/20240303002805_create_panda_cms_templates.rb +4 -1
  97. data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +2 -0
  98. data/db/migrate/20240303022441_create_panda_cms_blocks.rb +4 -1
  99. data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +2 -0
  100. data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +2 -0
  101. data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +2 -0
  102. data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +2 -0
  103. data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +2 -0
  104. data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +7 -5
  105. data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +2 -0
  106. data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +3 -1
  107. data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +2 -0
  108. data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +2 -0
  109. data/db/migrate/20240317010532_create_panda_cms_users.rb +2 -0
  110. data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +2 -0
  111. data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +2 -0
  112. data/db/migrate/20240317214827_create_panda_cms_redirects.rb +2 -0
  113. data/db/migrate/20240317230622_create_panda_cms_visits.rb +2 -0
  114. data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +5 -2
  115. data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +2 -0
  116. data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +8 -6
  117. data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +2 -0
  118. data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +2 -0
  119. data/db/migrate/20240804235210_create_panda_cms_forms.rb +2 -0
  120. data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +2 -0
  121. data/db/migrate/20240805121123_create_panda_cms_posts.rb +3 -1
  122. data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +2 -0
  123. data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +2 -0
  124. data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +2 -0
  125. data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +2 -0
  126. data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +6 -4
  127. data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +2 -0
  128. data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +2 -0
  129. data/db/migrate/20241120000419_remove_post_tag_references.rb +2 -0
  130. data/db/migrate/20241120110943_add_editor_js_to_posts.rb +2 -0
  131. data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +2 -0
  132. data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +2 -0
  133. data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +5 -1
  134. data/db/migrate/20250120235542_remove_paper_trail.rb +5 -4
  135. data/db/migrate/20250126234001_create_panda_social_instagram_posts.rb +4 -0
  136. data/db/migrate/20250809231125_migrate_users_to_panda_core.rb +111 -0
  137. data/db/migrate/20250811111000_make_post_user_references_nullable.rb +11 -0
  138. data/db/seeds.rb +2 -0
  139. data/lib/generators/panda/cms/install_generator.rb +2 -0
  140. data/lib/panda/cms/asset_loader.rb +390 -0
  141. data/lib/panda/cms/bulk_editor.rb +7 -3
  142. data/lib/panda/cms/demo_site_generator.rb +2 -0
  143. data/lib/panda/cms/engine.rb +57 -116
  144. data/lib/panda/cms/exceptions_app.rb +2 -0
  145. data/lib/panda/cms/railtie.rb +2 -0
  146. data/lib/panda/cms/slug.rb +3 -1
  147. data/lib/panda-cms/version.rb +3 -1
  148. data/lib/panda-cms.rb +54 -42
  149. data/lib/tasks/assets.rake +587 -0
  150. data/lib/tasks/panda/cms/install.rake +2 -0
  151. data/lib/tasks/panda/cms/migrations.rake +13 -0
  152. data/lib/tasks/panda/social/instagram.rake +2 -0
  153. data/lib/tasks/panda_cms.rake +3 -30
  154. data/public/panda-cms-assets/manifest.json +20 -0
  155. data/public/panda-cms-assets/panda-cms-0.7.4.css +26 -0
  156. data/public/panda-cms-assets/panda-cms-0.7.4.js +150 -0
  157. metadata +186 -49
  158. data/app/builders/panda/cms/form_builder.rb +0 -217
  159. data/app/components/panda/cms/admin/button_component.rb +0 -70
  160. data/app/components/panda/cms/admin/container_component.rb +0 -13
  161. data/app/components/panda/cms/admin/flash_message_component.rb +0 -47
  162. data/app/components/panda/cms/admin/heading_component.rb +0 -45
  163. data/app/components/panda/cms/admin/panel_component.rb +0 -13
  164. data/app/components/panda/cms/admin/table_component.rb +0 -46
  165. data/app/components/panda/cms/admin/tag_component.rb +0 -35
  166. data/app/constraints/panda/cms/admin_constraint.rb +0 -18
  167. data/app/controllers/panda/cms/admin/my_profile_controller.rb +0 -43
  168. data/app/controllers/panda/cms/admin/sessions_controller.rb +0 -94
  169. data/app/javascript/panda/cms/controllers/theme_form_controller.js +0 -9
  170. data/app/javascript/panda/cms/editor/css_extractor.js +0 -80
  171. data/app/javascript/panda/cms/editor/editor_js_config.js +0 -306
  172. data/app/javascript/panda/cms/editor/editor_js_initializer.js +0 -334
  173. data/app/javascript/panda/cms/editor/plain_text_editor.js +0 -110
  174. data/app/javascript/panda/cms/editor/resource_loader.js +0 -204
  175. data/app/javascript/panda/cms/editor/rich_text_editor.js +0 -162
  176. data/app/models/panda/cms/breadcrumb.rb +0 -12
  177. data/app/models/panda/cms/user.rb +0 -31
  178. data/app/services/panda/cms/html_to_editor_js_converter.rb +0 -193
  179. data/app/views/panda/cms/admin/my_profile/edit.html.erb +0 -35
  180. data/app/views/panda/cms/admin/sessions/new.html.erb +0 -17
  181. data/db/migrate/20250504221812_add_current_theme_to_panda_cms_users.rb +0 -5
  182. data/lib/panda/cms/editor_js/blocks/alert.rb +0 -34
  183. data/lib/panda/cms/editor_js/blocks/base.rb +0 -33
  184. data/lib/panda/cms/editor_js/blocks/header.rb +0 -15
  185. data/lib/panda/cms/editor_js/blocks/image.rb +0 -36
  186. data/lib/panda/cms/editor_js/blocks/list.rb +0 -32
  187. data/lib/panda/cms/editor_js/blocks/paragraph.rb +0 -15
  188. data/lib/panda/cms/editor_js/blocks/quote.rb +0 -41
  189. data/lib/panda/cms/editor_js/blocks/table.rb +0 -50
  190. data/lib/panda/cms/editor_js/renderer.rb +0 -124
  191. data/lib/panda/cms/editor_js.rb +0 -16
  192. data/lib/panda/cms/editor_js_content.rb +0 -55
@@ -1,80 +0,0 @@
1
- export class CSSExtractor {
2
- /**
3
- * Extracts CSS rules from within a specific selector and transforms them for EditorJS
4
- * @param {string} css - The CSS content to parse
5
- * @returns {string} The extracted and transformed CSS rules
6
- */
7
- static extractStyles(css) {
8
- const rules = []
9
- let inComponents = false
10
- let inContentRule = false
11
- let braceCount = 0
12
- let currentRule = ''
13
-
14
- // Split CSS into lines and process each line
15
- const lines = css.split('\n')
16
-
17
- for (const line of lines) {
18
- const trimmedLine = line.trim()
19
-
20
- // Check if we're entering components layer
21
- if (trimmedLine === '@layer components {') {
22
- inComponents = true
23
- continue
24
- }
25
-
26
- // Only process lines within components layer
27
- if (!inComponents) continue
28
-
29
- // If we find the .content selector
30
- if (!inContentRule && trimmedLine.startsWith('.content')) {
31
- inContentRule = true
32
- braceCount++
33
- // Transform the selector for EditorJS
34
- currentRule = '.codex-editor__redactor .ce-block .ce-block__content'
35
- if (trimmedLine.includes('{')) {
36
- currentRule += ' {'
37
- }
38
- continue
39
- }
40
-
41
- // If we're inside a content rule
42
- if (inContentRule) {
43
- // Transform selectors for EditorJS
44
- let transformedLine = line
45
- .replace(/\.content\s+/g, '.codex-editor__redactor .ce-block .ce-block__content ')
46
- .replace(/\bh1\b(?![-_])/g, 'h1.ce-header')
47
- .replace(/\bh2\b(?![-_])/g, 'h2.ce-header')
48
- .replace(/\bh3\b(?![-_])/g, 'h3.ce-header')
49
- .replace(/\bul\b(?![-_])/g, 'ul.cdx-list')
50
- .replace(/\bol\b(?![-_])/g, 'ol.cdx-list')
51
- .replace(/\bli\b(?![-_])/g, 'li.cdx-list__item')
52
- .replace(/\bblockquote\b(?![-_])/g, '.cdx-quote')
53
-
54
- currentRule += '\n' + transformedLine
55
-
56
- // Count braces to handle nested rules
57
- braceCount += (trimmedLine.match(/{/g) || []).length
58
- braceCount -= (trimmedLine.match(/}/g) || []).length
59
-
60
- // If braces are balanced, we've found the end of the rule
61
- if (braceCount === 0) {
62
- rules.push(currentRule)
63
- inContentRule = false
64
- currentRule = ''
65
- }
66
- }
67
- }
68
-
69
- return rules.join('\n\n')
70
- }
71
-
72
- /**
73
- * Gets all styles from a stylesheet that apply to the editor
74
- * @param {string} css - The CSS content to parse
75
- * @returns {string} The extracted CSS rules
76
- */
77
- static getEditorStyles(css) {
78
- return this.extractStyles(css)
79
- }
80
- }
@@ -1,306 +0,0 @@
1
- export const EDITOR_JS_RESOURCES = [
2
- "https://cdn.jsdelivr.net/npm/@editorjs/editorjs@2.28.2",
3
- "https://cdn.jsdelivr.net/npm/@editorjs/paragraph@2.11.3",
4
- "https://cdn.jsdelivr.net/npm/@editorjs/header@2.8.1",
5
- "https://cdn.jsdelivr.net/npm/@editorjs/nested-list@1.4.2",
6
- "https://cdn.jsdelivr.net/npm/@editorjs/quote@2.6.0",
7
- "https://cdn.jsdelivr.net/npm/@editorjs/simple-image@1.6.0",
8
- "https://cdn.jsdelivr.net/npm/@editorjs/table@2.3.0",
9
- "https://cdn.jsdelivr.net/npm/@editorjs/embed@2.7.0"
10
- ]
11
-
12
- // Allow applications to add their own resources
13
- if (window.PANDA_CMS_EDITOR_JS_RESOURCES) {
14
- EDITOR_JS_RESOURCES.push(...window.PANDA_CMS_EDITOR_JS_RESOURCES)
15
- }
16
-
17
- export const EDITOR_JS_CSS = `
18
- .codex-editor {
19
- position: relative;
20
- }
21
- .codex-editor::before {
22
- content: '';
23
- position: absolute;
24
- left: 0;
25
- top: 0;
26
- bottom: 0;
27
- width: 65px;
28
- margin-right: 5px;
29
- background-color: #f9fafb;
30
- border-right: 2px dashed #e5e7eb;
31
- z-index: 0;
32
- }
33
- .ce-block {
34
- padding-left: 70px;
35
- position: relative;
36
- min-height: 40px;
37
- margin: 0;
38
- padding-bottom: 1em;
39
- }
40
- .ce-block__content {
41
- position: relative;
42
- max-width: none;
43
- margin: 0;
44
- }
45
- .ce-paragraph {
46
- padding: 0;
47
- line-height: 1.6;
48
- min-height: 1.6em;
49
- margin: 0;
50
- }
51
- /* Override inherited heading styles */
52
- .ce-header h1,
53
- .ce-header h2,
54
- .ce-header h3,
55
- .ce-header h4,
56
- .ce-header h5,
57
- .ce-header h6 {
58
- margin: 0;
59
- padding: 0;
60
- line-height: 1.6;
61
- font-weight: 600;
62
- }
63
- .ce-header h1 { font-size: 2em; }
64
- .ce-header h2 { font-size: 1.5em; }
65
- .ce-header h3 { font-size: 1.17em; }
66
- .ce-header h4 { font-size: 1em; }
67
- .ce-header h5 { font-size: 0.83em; }
68
- .ce-header h6 { font-size: 0.67em; }
69
-
70
- .codex-editor__redactor {
71
- padding-bottom: 150px !important;
72
- min-height: 100px !important;
73
- }
74
- /* Base toolbar styles */
75
- .ce-toolbar {
76
- left: 0 !important;
77
- right: auto !important;
78
- background: none !important;
79
- position: absolute !important;
80
- width: 65px !important;
81
- height: 40px !important;
82
- display: flex !important;
83
- align-items: center !important;
84
- justify-content: flex-start !important;
85
- padding: 0 !important;
86
- margin-left: -70px !important;
87
- margin-top: -5px !important;
88
- opacity: 1 !important;
89
- visibility: visible !important;
90
- pointer-events: all !important;
91
- z-index: 2 !important;
92
- }
93
- /* Ensure toolbar is visible for all blocks */
94
- .ce-block .ce-toolbar {
95
- display: flex !important;
96
- opacity: 1 !important;
97
- visibility: visible !important;
98
- }
99
- .ce-toolbar__content {
100
- max-width: none;
101
- left: 70px !important;
102
- display: flex !important;
103
- position: relative !important;
104
- }
105
- .ce-toolbar__actions {
106
- position: relative !important;
107
- left: 5px !important;
108
- opacity: 1 !important;
109
- visibility: visible !important;
110
- background: transparent !important;
111
- z-index: 2;
112
- display: flex !important;
113
- align-items: center !important;
114
- gap: 5px !important;
115
- height: 40px !important;
116
- padding: 0 !important;
117
- }
118
- .ce-toolbar__plus {
119
- position: relative !important;
120
- left: 0px !important;
121
- opacity: 1 !important;
122
- visibility: visible !important;
123
- background: transparent !important;
124
- border: none !important;
125
- z-index: 2;
126
- display: block !important;
127
- }
128
- .ce-toolbar__settings-btn {
129
- position: relative !important;
130
- left: -10px !important;
131
- opacity: 1 !important;
132
- visibility: visible !important;
133
- background: transparent !important;
134
- border: none !important;
135
- z-index: 2;
136
- display: block !important;
137
- }
138
- /* Style the search input */
139
- .ce-popover__search {
140
- padding-left: 3px !important;
141
- }
142
- .ce-popover__search input {
143
- outline: none !important;
144
- box-shadow: none !important;
145
- border: none !important;
146
- }
147
- .ce-popover__search input::placeholder {
148
- content: 'Search';
149
- }
150
- /* Ensure popups still work */
151
- .ce-popover {
152
- z-index: 4;
153
- }
154
- .ce-inline-toolbar {
155
- z-index: 3;
156
- }
157
- /* Override any hiding behavior */
158
- .ce-toolbar--closed,
159
- .ce-toolbar--opened,
160
- .ce-toolbar--showed {
161
- display: flex !important;
162
- opacity: 1 !important;
163
- visibility: visible !important;
164
- }
165
- /* Force toolbar to show on every block */
166
- .ce-block:not(:focus):not(:hover) .ce-toolbar,
167
- .ce-block--selected .ce-toolbar,
168
- .ce-block--focused .ce-toolbar,
169
- .ce-block--hover .ce-toolbar {
170
- opacity: 1 !important;
171
- visibility: visible !important;
172
- display: flex !important;
173
- }
174
-
175
- /* Ensure last block has bottom spacing */
176
- .ce-block:last-child {
177
- padding-bottom: 2em;
178
- }
179
-
180
- /* Reset all block type margins */
181
- .ce-header,
182
- .ce-paragraph,
183
- .ce-quote,
184
- .ce-list {
185
- margin: 0 !important;
186
- padding: 0 !important;
187
- }
188
- `
189
-
190
- export const getEditorConfig = (elementId, previousData, doc = document) => {
191
- // Validate holder element exists
192
- const holder = doc.getElementById(elementId)
193
- if (!holder) {
194
- throw new Error(`Editor holder element ${elementId} not found`)
195
- }
196
-
197
- // Get the correct window context
198
- const win = doc.defaultView || window
199
-
200
- // Ensure we have a clean holder element
201
- holder.innerHTML = ""
202
-
203
- const config = {
204
- holder: elementId,
205
- data: previousData || {},
206
- placeholder: 'Click the + button to add content...',
207
- inlineToolbar: true,
208
- onChange: () => {
209
- // Ensure the editor is properly initialized before handling changes
210
- if (holder && holder.querySelector('.codex-editor')) {
211
- const event = new Event('editor:change', { bubbles: true })
212
- holder.dispatchEvent(event)
213
- }
214
- },
215
- i18n: {
216
- toolbar: {
217
- filter: {
218
- placeholder: 'Search'
219
- }
220
- }
221
- },
222
- tools: {
223
- header: {
224
- class: win.Header,
225
- inlineToolbar: true,
226
- config: {
227
- placeholder: 'Enter a header',
228
- levels: [1, 2, 3, 4, 5, 6],
229
- defaultLevel: 2
230
- }
231
- },
232
- paragraph: {
233
- class: win.Paragraph,
234
- inlineToolbar: true,
235
- config: {
236
- placeholder: 'Start writing or press Tab to add content...'
237
- }
238
- },
239
- list: {
240
- class: win.NestedList,
241
- inlineToolbar: true,
242
- config: {
243
- defaultStyle: 'unordered',
244
- enableLineBreaks: true
245
- }
246
- },
247
- quote: {
248
- class: win.Quote,
249
- inlineToolbar: true,
250
- config: {
251
- quotePlaceholder: 'Enter a quote',
252
- captionPlaceholder: 'Quote\'s author'
253
- }
254
- },
255
- image: {
256
- class: win.SimpleImage,
257
- inlineToolbar: true,
258
- config: {
259
- placeholder: 'Paste an image URL...'
260
- }
261
- },
262
- table: {
263
- class: win.Table,
264
- inlineToolbar: true,
265
- config: {
266
- rows: 2,
267
- cols: 2
268
- }
269
- },
270
- embed: {
271
- class: win.Embed,
272
- inlineToolbar: true,
273
- config: {
274
- services: {
275
- youtube: true,
276
- vimeo: true
277
- }
278
- }
279
- }
280
- }
281
- }
282
-
283
- // Remove any undefined tools from the config
284
- config.tools = Object.fromEntries(
285
- Object.entries(config.tools)
286
- .filter(([_, value]) => value?.class !== undefined)
287
- .map(([name, tool]) => {
288
- if (!tool.class) {
289
- throw new Error(`Tool ${name} has no class defined`)
290
- }
291
- return [name, tool]
292
- })
293
- )
294
-
295
- // Allow applications to customize the config through Ruby
296
- if (window.PANDA_CMS_EDITOR_JS_CONFIG) {
297
- Object.assign(config.tools, window.PANDA_CMS_EDITOR_JS_CONFIG)
298
- }
299
-
300
- // Allow applications to customize the config through JavaScript
301
- if (typeof window.customizeEditorJS === 'function') {
302
- window.customizeEditorJS(config)
303
- }
304
-
305
- return config
306
- }