panda-cms 0.7.0 → 0.7.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.
- checksums.yaml +4 -4
 - data/app/assets/builds/panda.cms.css +0 -50
 - data/app/components/panda/cms/admin/table_component.html.erb +4 -1
 - data/app/components/panda/cms/code_component.rb +2 -1
 - data/app/components/panda/cms/rich_text_component.html.erb +86 -2
 - data/app/components/panda/cms/rich_text_component.rb +131 -20
 - data/app/controllers/panda/cms/admin/block_contents_controller.rb +18 -7
 - data/app/controllers/panda/cms/admin/files_controller.rb +22 -12
 - data/app/controllers/panda/cms/admin/posts_controller.rb +33 -11
 - data/app/controllers/panda/cms/pages_controller.rb +29 -0
 - data/app/controllers/panda/cms/posts_controller.rb +26 -4
 - data/app/helpers/panda/cms/admin/posts_helper.rb +23 -32
 - data/app/helpers/panda/cms/posts_helper.rb +32 -0
 - data/app/javascript/panda/cms/controllers/dashboard_controller.js +0 -1
 - data/app/javascript/panda/cms/controllers/editor_form_controller.js +134 -11
 - data/app/javascript/panda/cms/controllers/editor_iframe_controller.js +395 -130
 - data/app/javascript/panda/cms/controllers/slug_controller.js +33 -43
 - data/app/javascript/panda/cms/editor/editor_js_config.js +202 -73
 - data/app/javascript/panda/cms/editor/editor_js_initializer.js +243 -194
 - data/app/javascript/panda/cms/editor/plain_text_editor.js +1 -1
 - data/app/javascript/panda/cms/editor/resource_loader.js +89 -0
 - data/app/javascript/panda/cms/editor/rich_text_editor.js +162 -0
 - data/app/models/panda/cms/page.rb +18 -0
 - data/app/models/panda/cms/post.rb +61 -3
 - data/app/models/panda/cms/redirect.rb +2 -2
 - data/app/views/panda/cms/admin/posts/_form.html.erb +15 -4
 - data/app/views/panda/cms/admin/posts/index.html.erb +5 -3
 - data/config/routes.rb +34 -6
 - data/db/migrate/20250106223303_add_author_id_to_panda_cms_posts.rb +5 -0
 - data/lib/panda/cms/editor_js_content.rb +14 -1
 - data/lib/panda/cms/engine.rb +4 -0
 - data/lib/panda-cms/version.rb +1 -1
 - metadata +5 -2
 
| 
         @@ -8,6 +8,10 @@ export default class extends Controller { 
     | 
|
| 
       8 
8 
     | 
    
         
             
                "output_text",
         
     | 
| 
       9 
9 
     | 
    
         
             
              ];
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
              static values = {
         
     | 
| 
      
 12 
     | 
    
         
            +
                addDatePrefix: { type: Boolean, default: false }
         
     | 
| 
      
 13 
     | 
    
         
            +
              }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       11 
15 
     | 
    
         
             
              connect() {
         
     | 
| 
       12 
16 
     | 
    
         
             
                console.debug("[Panda CMS] Slug handler connected...");
         
     | 
| 
       13 
17 
     | 
    
         
             
                // Generate path on initial load if title exists
         
     | 
| 
         @@ -17,29 +21,27 @@ export default class extends Controller { 
     | 
|
| 
       17 
21 
     | 
    
         
             
              }
         
     | 
| 
       18 
22 
     | 
    
         | 
| 
       19 
23 
     | 
    
         
             
              generatePath() {
         
     | 
| 
       20 
     | 
    
         
            -
                 
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                  // For posts, we want to store just the slug part
         
     | 
| 
       23 
     | 
    
         
            -
                  const prefix = this.output_textTarget.dataset.prefix || "";
         
     | 
| 
       24 
     | 
    
         
            -
                  this.output_textTarget.value = "/" + slug;
         
     | 
| 
      
 24 
     | 
    
         
            +
                const title = this.input_textTarget.value;
         
     | 
| 
      
 25 
     | 
    
         
            +
                if (!title) return;
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                        span.className = 'prefix';
         
     | 
| 
       32 
     | 
    
         
            -
                        this.output_textTarget.parentNode.insertBefore(span, this.output_textTarget);
         
     | 
| 
       33 
     | 
    
         
            -
                        return span;
         
     | 
| 
       34 
     | 
    
         
            -
                      })();
         
     | 
| 
       35 
     | 
    
         
            -
                    prefixSpan.textContent = prefix;
         
     | 
| 
       36 
     | 
    
         
            -
                  }
         
     | 
| 
      
 27 
     | 
    
         
            +
                // Convert title to slug format
         
     | 
| 
      
 28 
     | 
    
         
            +
                const slug = title
         
     | 
| 
      
 29 
     | 
    
         
            +
                  .toLowerCase()
         
     | 
| 
      
 30 
     | 
    
         
            +
                  .replace(/[^a-z0-9]+/g, "-")
         
     | 
| 
      
 31 
     | 
    
         
            +
                  .replace(/^-+|-+$/g, "");
         
     | 
| 
       37 
32 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                 
     | 
| 
       40 
     | 
    
         
            -
                   
     | 
| 
       41 
     | 
    
         
            -
                   
     | 
| 
       42 
     | 
    
         
            -
                   
     | 
| 
      
 33 
     | 
    
         
            +
                // Only add year/month prefix for posts
         
     | 
| 
      
 34 
     | 
    
         
            +
                if (this.addDatePrefixValue) {
         
     | 
| 
      
 35 
     | 
    
         
            +
                  // Get current date for year/month
         
     | 
| 
      
 36 
     | 
    
         
            +
                  const now = new Date();
         
     | 
| 
      
 37 
     | 
    
         
            +
                  const year = now.getFullYear();
         
     | 
| 
      
 38 
     | 
    
         
            +
                  const month = String(now.getMonth() + 1).padStart(2, "0");
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  // Add leading slash and use date format
         
     | 
| 
      
 41 
     | 
    
         
            +
                  this.output_textTarget.value = `/${year}/${month}/${slug}`;
         
     | 
| 
      
 42 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 43 
     | 
    
         
            +
                  // Add leading slash for regular pages
         
     | 
| 
      
 44 
     | 
    
         
            +
                  this.output_textTarget.value = `/${slug}`;
         
     | 
| 
       43 
45 
     | 
    
         
             
                }
         
     | 
| 
       44 
46 
     | 
    
         
             
              }
         
     | 
| 
       45 
47 
     | 
    
         | 
| 
         @@ -49,37 +51,25 @@ export default class extends Controller { 
     | 
|
| 
       49 
51 
     | 
    
         
             
                  if (match) {
         
     | 
| 
       50 
52 
     | 
    
         
             
                    this.parent_slugs = match[1];
         
     | 
| 
       51 
53 
     | 
    
         
             
                    const prePath = (this.existing_rootTarget.value + this.parent_slugs).replace(/\/$/, "");
         
     | 
| 
       52 
     | 
    
         
            -
                     
     | 
| 
       53 
     | 
    
         
            -
                     
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                    }
         
     | 
| 
       56 
     | 
    
         
            -
                    console.log("Have set the pre-path to: " + prePath);
         
     | 
| 
      
 54 
     | 
    
         
            +
                    // Ensure we don't double up slashes
         
     | 
| 
      
 55 
     | 
    
         
            +
                    const currentPath = this.output_textTarget.value.replace(/^\//, "");
         
     | 
| 
      
 56 
     | 
    
         
            +
                    this.output_textTarget.value = `${prePath}/${currentPath}`;
         
     | 
| 
       57 
57 
     | 
    
         
             
                  }
         
     | 
| 
       58 
     | 
    
         
            -
                } catch ( 
     | 
| 
       59 
     | 
    
         
            -
                  console.error("Error setting pre-path:",  
     | 
| 
      
 58 
     | 
    
         
            +
                } catch (e) {
         
     | 
| 
      
 59 
     | 
    
         
            +
                  console.error("[Panda CMS] Error setting pre-path:", e);
         
     | 
| 
       60 
60 
     | 
    
         
             
                }
         
     | 
| 
       61 
61 
     | 
    
         
             
              }
         
     | 
| 
       62 
62 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
              // TODO: Invoke a library or helper which can be shared with the backend
         
     | 
| 
       64 
     | 
    
         
            -
              // and check for uniqueness at the same time
         
     | 
| 
       65 
63 
     | 
    
         
             
              createSlug(input) {
         
     | 
| 
       66 
     | 
    
         
            -
                 
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                var str = input
         
     | 
| 
      
 64 
     | 
    
         
            +
                return input
         
     | 
| 
       69 
65 
     | 
    
         
             
                  .toLowerCase()
         
     | 
| 
       70 
     | 
    
         
            -
                  . 
     | 
| 
       71 
     | 
    
         
            -
                  .replace( 
     | 
| 
       72 
     | 
    
         
            -
                  .replace(/&/g, "and")
         
     | 
| 
       73 
     | 
    
         
            -
                  .replace(/[\s_-]+/g, "-")
         
     | 
| 
       74 
     | 
    
         
            -
                  .trim();
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
                return this.trimStartEnd(str, "-");
         
     | 
| 
      
 66 
     | 
    
         
            +
                  .replace(/[^a-z0-9]+/g, "-")
         
     | 
| 
      
 67 
     | 
    
         
            +
                  .replace(/^-+|-+$/g, "");
         
     | 
| 
       77 
68 
     | 
    
         
             
              }
         
     | 
| 
       78 
69 
     | 
    
         | 
| 
       79 
70 
     | 
    
         
             
              trimStartEnd(str, ch) {
         
     | 
| 
       80 
     | 
    
         
            -
                 
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                let start = 0,
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end = str.length;
         
     | 
| 
       83 
73 
     | 
    
         
             
                while (start < end && str[start] === ch) ++start;
         
     | 
| 
       84 
74 
     | 
    
         
             
                while (end > start && str[end - 1] === ch) --end;
         
     | 
| 
       85 
75 
     | 
    
         
             
                return start > 0 || end < str.length ? str.substring(start, end) : str;
         
     | 
| 
         @@ -15,69 +15,177 @@ if (window.PANDA_CMS_EDITOR_JS_RESOURCES) { 
     | 
|
| 
       15 
15 
     | 
    
         
             
            }
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
            export const EDITOR_JS_CSS = `
         
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
               
     | 
| 
       21 
     | 
    
         
            -
               
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            . 
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
            }
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
               
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
            .ce- 
     | 
| 
       54 
     | 
    
         
            -
               
     | 
| 
       55 
     | 
    
         
            -
               
     | 
| 
       56 
     | 
    
         
            -
               
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
               
     | 
| 
       63 
     | 
    
         
            -
               
     | 
| 
       64 
     | 
    
         
            -
            }
         
     | 
| 
      
 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; }
         
     | 
| 
       65 
69 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
            . 
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            +
              }
         
     | 
| 
       70 
174 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
            /* Ensure  
     | 
| 
       72 
     | 
    
         
            -
            .ce- 
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
            }
         
     | 
| 
      
 175 
     | 
    
         
            +
              /* Ensure last block has bottom spacing */
         
     | 
| 
      
 176 
     | 
    
         
            +
              .ce-block:last-child {
         
     | 
| 
      
 177 
     | 
    
         
            +
                padding-bottom: 2em;
         
     | 
| 
      
 178 
     | 
    
         
            +
              }
         
     | 
| 
       75 
179 
     | 
    
         | 
| 
       76 
     | 
    
         
            -
            /*  
     | 
| 
       77 
     | 
    
         
            -
            .ce- 
     | 
| 
       78 
     | 
    
         
            -
               
     | 
| 
       79 
     | 
    
         
            -
               
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            +
            `
         
     | 
| 
       81 
189 
     | 
    
         | 
| 
       82 
190 
     | 
    
         
             
            export const getEditorConfig = (elementId, previousData, doc = document) => {
         
     | 
| 
       83 
191 
     | 
    
         
             
              // Validate holder element exists
         
     | 
| 
         @@ -86,14 +194,34 @@ export const getEditorConfig = (elementId, previousData, doc = document) => { 
     | 
|
| 
       86 
194 
     | 
    
         
             
                throw new Error(`Editor holder element ${elementId} not found`)
         
     | 
| 
       87 
195 
     | 
    
         
             
              }
         
     | 
| 
       88 
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 
     | 
    
         
            +
             
     | 
| 
       89 
203 
     | 
    
         
             
              const config = {
         
     | 
| 
       90 
204 
     | 
    
         
             
                holder: elementId,
         
     | 
| 
       91 
205 
     | 
    
         
             
                data: previousData || {},
         
     | 
| 
       92 
206 
     | 
    
         
             
                placeholder: 'Click the + button to add content...',
         
     | 
| 
       93 
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 
     | 
    
         
            +
                },
         
     | 
| 
       94 
222 
     | 
    
         
             
                tools: {
         
     | 
| 
       95 
223 
     | 
    
         
             
                  header: {
         
     | 
| 
       96 
     | 
    
         
            -
                    class:  
     | 
| 
      
 224 
     | 
    
         
            +
                    class: win.Header,
         
     | 
| 
       97 
225 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       98 
226 
     | 
    
         
             
                    config: {
         
     | 
| 
       99 
227 
     | 
    
         
             
                      placeholder: 'Enter a header',
         
     | 
| 
         @@ -102,44 +230,45 @@ export const getEditorConfig = (elementId, previousData, doc = document) => { 
     | 
|
| 
       102 
230 
     | 
    
         
             
                    }
         
     | 
| 
       103 
231 
     | 
    
         
             
                  },
         
     | 
| 
       104 
232 
     | 
    
         
             
                  paragraph: {
         
     | 
| 
       105 
     | 
    
         
            -
                    class:  
     | 
| 
      
 233 
     | 
    
         
            +
                    class: win.Paragraph,
         
     | 
| 
       106 
234 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       107 
235 
     | 
    
         
             
                    config: {
         
     | 
| 
       108 
236 
     | 
    
         
             
                      placeholder: 'Start writing or press Tab to add content...'
         
     | 
| 
       109 
237 
     | 
    
         
             
                    }
         
     | 
| 
       110 
238 
     | 
    
         
             
                  },
         
     | 
| 
       111 
239 
     | 
    
         
             
                  list: {
         
     | 
| 
       112 
     | 
    
         
            -
                    class:  
     | 
| 
      
 240 
     | 
    
         
            +
                    class: win.NestedList,
         
     | 
| 
       113 
241 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       114 
242 
     | 
    
         
             
                    config: {
         
     | 
| 
       115 
     | 
    
         
            -
                      defaultStyle: 'unordered'
         
     | 
| 
      
 243 
     | 
    
         
            +
                      defaultStyle: 'unordered',
         
     | 
| 
      
 244 
     | 
    
         
            +
                      enableLineBreaks: true
         
     | 
| 
       116 
245 
     | 
    
         
             
                    }
         
     | 
| 
       117 
246 
     | 
    
         
             
                  },
         
     | 
| 
       118 
247 
     | 
    
         
             
                  quote: {
         
     | 
| 
       119 
     | 
    
         
            -
                    class:  
     | 
| 
      
 248 
     | 
    
         
            +
                    class: win.Quote,
         
     | 
| 
       120 
249 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       121 
250 
     | 
    
         
             
                    config: {
         
     | 
| 
       122 
251 
     | 
    
         
             
                      quotePlaceholder: 'Enter a quote',
         
     | 
| 
       123 
252 
     | 
    
         
             
                      captionPlaceholder: 'Quote\'s author'
         
     | 
| 
       124 
253 
     | 
    
         
             
                    }
         
     | 
| 
       125 
254 
     | 
    
         
             
                  },
         
     | 
| 
       126 
     | 
    
         
            -
                   
     | 
| 
       127 
     | 
    
         
            -
                    class:  
     | 
| 
      
 255 
     | 
    
         
            +
                  image: {
         
     | 
| 
      
 256 
     | 
    
         
            +
                    class: win.SimpleImage,
         
     | 
| 
       128 
257 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       129 
258 
     | 
    
         
             
                    config: {
         
     | 
| 
       130 
     | 
    
         
            -
                       
     | 
| 
       131 
     | 
    
         
            -
                      cols: 2
         
     | 
| 
      
 259 
     | 
    
         
            +
                      placeholder: 'Paste an image URL...'
         
     | 
| 
       132 
260 
     | 
    
         
             
                    }
         
     | 
| 
       133 
261 
     | 
    
         
             
                  },
         
     | 
| 
       134 
     | 
    
         
            -
                   
     | 
| 
       135 
     | 
    
         
            -
                    class:  
     | 
| 
      
 262 
     | 
    
         
            +
                  table: {
         
     | 
| 
      
 263 
     | 
    
         
            +
                    class: win.Table,
         
     | 
| 
       136 
264 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       137 
265 
     | 
    
         
             
                    config: {
         
     | 
| 
       138 
     | 
    
         
            -
                       
     | 
| 
      
 266 
     | 
    
         
            +
                      rows: 2,
         
     | 
| 
      
 267 
     | 
    
         
            +
                      cols: 2
         
     | 
| 
       139 
268 
     | 
    
         
             
                    }
         
     | 
| 
       140 
269 
     | 
    
         
             
                  },
         
     | 
| 
       141 
270 
     | 
    
         
             
                  embed: {
         
     | 
| 
       142 
     | 
    
         
            -
                    class:  
     | 
| 
      
 271 
     | 
    
         
            +
                    class: win.Embed,
         
     | 
| 
       143 
272 
     | 
    
         
             
                    inlineToolbar: true,
         
     | 
| 
       144 
273 
     | 
    
         
             
                    config: {
         
     | 
| 
       145 
274 
     | 
    
         
             
                      services: {
         
     |