Jake Vanderwerf
8 days ago 3b83905603d44b1a08f8b2b36a605808ce686ad6
assets/js/concise/quill.js
@@ -1,5 +1,6 @@
window.jvbQuill = function(form) {
   const textareas = form.querySelectorAll('textarea[data-editor=true]');
   const instances = [];
   textareas.forEach(textarea => {
      let container, editor, toolbar;
@@ -12,7 +13,7 @@
         editor.className = 'editor';
         toolbar = document.createElement('div');
         toolbar.className = 'toolbar';
         const image = textarea.dataset.allowimage === true ? `<button type="button" class="ql-jvb_image">\n                    ${dashboardSettings.icons.image}\n                </button>` : '';
         const image = textarea.dataset.allowimage === true ? `<button type="button" class="ql-jvb_image">\n                    ${window.getIcon('image')}\n                </button>` : '';
         toolbar.id = `toolbar-${textarea.id}`;
         toolbar.innerHTML = `
                <span class="ql-formats">
@@ -93,22 +94,35 @@
                  h1: function() { this.quill.format('header', 1); },
                  h2: function() { this.quill.format('header', 2); },
                  h3: function() { this.quill.format('header', 3); },
                  jvb_bold: function() {this.quill.format('bold', true)},
                  jvb_italic: function() {this.quill.format('italic', true)},
                  jvb_strike: function() {this.quill.format('strike', true)},
                  jvb_underline: function() {this.quill.format('underline', true)},
                  'jvb_bold': function() {
                     const format = this.quill.getFormat();
                     this.quill.format('bold', !format.bold);
                  },
                  'jvb_italic': function() {
                     const format = this.quill.getFormat();
                     this.quill.format('italic', !format.italic);
                  },
                  'jvb_strike': function() {
                     const format = this.quill.getFormat();
                     this.quill.format('strike', !format.strike);
                  },
                  'jvb_underline': function() {
                     const format = this.quill.getFormat();
                     this.quill.format('underline', !format.underline);
                  },
                  'jvb_align': function(value) {
                     this.quill.format('align', value === this.quill.getFormat().list ? false : value);
                     const format = this.quill.getFormat();
                     this.quill.format('align', value === format.align ? false : value);
                  },
                  'jvb_list': function(value) {
                     this.quill.format('list', value === this.quill.getFormat().list ? false : value);
                     // value will be either "bullet" or "ordered" depending on which button was clicked
                     const format = this.quill.getFormat();
                     this.quill.format('list', value === format.list ? false : value);
                  },
                  'jvb_link': function(value) {
                     if (value) {
                        const range = this.quill.getSelection();
                        if (range == null || range.length === 0) return;
                        // Get the existing link if any
                        const preview = this.quill.getText(range.index, range.length);
                        const existingLink = this.quill.getFormat(range).link;
                        // Create modal for link input
@@ -167,6 +181,8 @@
                     }
                  },
                  'jvb_image': function() {
                     const objectID = textarea.dataset.postId || textarea.closest('form')?.dataset.postId;
                     const input = document.createElement('input');
                     input.setAttribute('type', 'file');
                     input.setAttribute('accept', 'image/jpeg,image/png,image/gif,image/webp');
@@ -196,18 +212,13 @@
                           formData.append('post_id', objectID);
                        }
                        // Show loading state
                        if (window.jvbLoading) {
                           window.jvbLoading.showLoading('Uploading image...', 'Processing Upload');
                        }
                        try {
                           const response = await fetch(
                              `${jvbSettings.api}uploads/`,
                              {
                                 method: 'POST',
                                 headers: {
                                    'X-WP-Nonce': jvbSettings.nonce
                                    'X-WP-Nonce': window.auth.getNonce()
                                 },
                                 body: formData
                              }
@@ -223,15 +234,12 @@
                           this.quill.insertEmbed(range.index, 'image', result.url);
                        } catch (error) {
                           this.handleError('Upload error:', error);
                           console.error('Upload error:', error);
                           this.quill.insertText(range.index, 'Failed to upload image. Please try again.', {
                              'color': '#f00',
                              'italic': true
                           }, true);
                        } finally {
                           if (window.jvbLoading) {
                              window.jvbLoading.hide();
                           }
                           input.remove();
                        }
                     };
@@ -250,10 +258,43 @@
         }
      });
      instances.push(quill);
      quill.on('selection-change', function(range) {
         if (!range) return;
         const format = quill.getFormat(range);
         // Update button states
         const formatButtons = {
            'ql-jvb_bold': 'bold',
            'ql-jvb_italic': 'italic',
            'ql-jvb_underline': 'underline',
            'ql-jvb_strike': 'strike'
         };
         Object.entries(formatButtons).forEach(([buttonClass, formatName]) => {
            const button = toolbar.querySelector(`.${buttonClass}`);
            if (button) {
               button.classList.toggle('active', !!format[formatName]);
            }
         });
         // Update list button states
         toolbar.querySelectorAll('.ql-jvb_list').forEach(button => {
            const value = button.getAttribute('value');
            button.classList.toggle('ql-active', format.list === value);
         });
         // Update alignment button states
         toolbar.querySelectorAll('.ql-jvb_align').forEach(button => {
            const value = button.getAttribute('value');
            button.classList.toggle('ql-active', format.align === value);
         });
         const alignmentTools = toolbar.querySelector('.ql-align');
         if (alignmentTools) {
            if (range && range.length === 0) {
            if (range.length === 0) {
               // Get the focused element
               const [leaf] = this.quill.getLeaf(range.index);
               if (leaf && leaf.domNode && leaf.domNode.tagName === 'IMG') {
@@ -270,4 +311,5 @@
         textarea.dispatchEvent(new Event('change', { bubbles: true }));
      });
   });
   return instances;
};