Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tinymce Bundle Laravel Package

eckinox/tinymce-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require eckinox/tinymce-bundle
    

    Ensure config/packages/tinymce.yaml exists (auto-generated by the bundle).

  2. First Use Case:

    • Form Integration:
      // src/Form/PostType.php
      public function buildForm(FormBuilderInterface $builder, array $options): void
      {
          $builder->add('content', TinymceType::class, [
              'attr' => ['toolbar' => 'bold italic | bullist numlist']
          ]);
      }
      
    • Twig Template:
      {{ form_start(postForm) }}
          {{ form_row(postForm.content) }}
      {{ form_end(postForm) }}
      
  3. Verify:

    • Visit a page with the form to see TinyMCE loaded automatically.
    • Check browser console for TinyMCE initialization logs.

Where to Look First

  • Configuration: config/packages/tinymce.yaml (default settings).
  • Form Type: src/Form/TinymceType.php (if extending).
  • Twig Functions: {{ tinymce() }} and {{ tinymce_scripts() }} in templates.
  • File Uploads: docs/file-upload-example.md (reference implementation).

Implementation Patterns

1. Form-Centric Workflows

  • Dynamic Configuration:
    $builder->add('description', TinymceType::class, [
        'attr' => [
            'plugins' => 'lists link image',
            'toolbar' => 'undo redo | styleselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image',
            'images_upload_handler' => 'custom_handler', // Route name
        ],
        'mapped' => false, // For non-persisted fields (e.g., preview)
    ]);
    
  • Model Binding: Use data_class in the form builder to bind directly to Eloquent models:
    $builder->setAttribute('data_class', Post::class);
    

2. Template-Driven Patterns

  • Reusable Components:

    {% macro tinymceEditor(fieldName, config = {}) %}
        {{ tinymce(form[fieldName].value, {
            name: fieldName,
            skin: app.tinymce.skin,
            ...config
        }) }}
    {% endmacro %}
    

    Usage:

    {{ _self.tinymceEditor('bio', {'toolbar': 'bold italic'}) }}
    
  • Conditional Loading:

    {% if app.user.isAdmin %}
        {{ tinymce_scripts() }}
    {% endif %}
    

3. JavaScript Integration

  • Programmatic Initialization:
    document.addEventListener('DOMContentLoaded', () => {
        const editor = document.querySelector('tinymce-editor');
        if (editor) {
            editor.setAttribute('init', JSON.stringify({
                setup: (editorApi) => {
                    editorApi.ui.registry.addButton('customButton', {
                        text: 'Custom Action',
                        onAction: () => alert('Triggered!')
                    });
                }
            }));
        }
    });
    

4. File Upload Integration

  • Route-Based Uploads:
    # config/packages/tinymce.yaml
    tinymce:
        images_upload_route: 'app.tinymce_upload'
        images_upload_route_params: { _locale: '%locale%' }
    
    Controller:
    #[Route('/upload', name: 'app.tinymce_upload', methods: ['POST'])]
    public function upload(Request $request): JsonResponse
    {
        $file = $request->files->get('file');
        $path = $this->uploadService->save($file);
        return $this->json(['location' => $path]);
    }
    

5. Laravel-Specific Extensions

  • Blade Directives: Add to app/Providers/AppServiceProvider.php:

    Blade::directive('tinymce', function ($expression) {
        return "<?php echo \Symfony\UX\TwigComponent\tinymce($expression); ?>";
    });
    

    Usage in Blade:

    @tinymce($post->content)
    
  • Validation:

    $builder->add('content', TinymceType::class, [
        'constraints' => [
            new Length(['min' => 100]),
            new Assert\Regex('/<p[^>]*>.*<\/p>/', 'Content must include a paragraph.')
        ]
    ]);
    

Gotchas and Tips

Pitfalls

  1. Script Loading Conflicts:

    • Issue: TinyMCE scripts may load twice if tinymce_scripts() is called manually after a form renders.
    • Fix: Use Twig’s {% block tinymce_scripts %}{% endblock %} to centralize script inclusion.
  2. CORS Errors in Uploads:

    • Issue: File uploads fail with CORS errors if Access-Control-Allow-Origin headers are missing.
    • Fix: Ensure the upload route includes:
      $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
      $response->headers->set('Access-Control-Allow-Credentials', 'true');
      
  3. Form Data Binding:

    • Issue: TinyMCE’s web component may not auto-bind to form fields if name attributes are missing.
    • Fix: Explicitly set name in attr:
      'attr' => ['name' => 'post_content']
      
  4. Skin/Theme Mismatches:

    • Issue: Custom skins (e.g., appstack) may not render correctly if CSS paths are wrong.
    • Fix: Verify content_css in tinymce.yaml matches the skin’s assets:
      tinymce:
          skin: appstack
          content_css: "bundles/tinymce/css/appstack.css"
      
  5. Plugin Dependencies:

    • Issue: Plugins like image require TinyMCE’s images_upload_url to be set, even if unused.
    • Fix: Omit unused plugins from the plugins config to reduce bundle size.

Debugging Tips

  • Console Logs: TinyMCE emits initialization logs to the browser console. Check for errors like:
    console.error(tinymce.init.instance); // Debug editor instance
    
  • Network Tab: Verify scripts/CSS are loaded (e.g., tinymce.min.js, appstack.css).
  • Form Data: Use {{ dump(form.vars) }} in Twig to inspect form field configurations.

Extension Points

  1. Custom Plugins:

    • Extend TinyMCE’s web component by adding plugins via init:
      'attr' => [
          'init' => json_encode([
              'plugins' => 'customPlugin',
              'customPlugin' => 'path/to/plugin.js'
          ])
      ]
      
  2. Event Listeners:

    • Hook into TinyMCE events via JavaScript:
      document.querySelector('tinymce-editor').addEventListener('init', (e) => {
          e.detail.editor.on('NodeChange', () => {
              console.log('Content changed:', e.detail.editor.getContent());
          });
      });
      
  3. Laravel Service Providers:

    • Override default configurations dynamically:
      public function boot(): void
      {
          $this->app['tinymce.options']->set('toolbar', 'custom|toolbars');
      }
      
  4. Asset Management:

    • Publish bundle assets for customization:
      php artisan vendor:publish --tag=tinymce-assets
      
    • Modify published files in public/bundles/tinymce/.

Performance Quirks

  • Lazy Loading: Defer TinyMCE initialization until the editor is visible:
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                tinymce.init({ selector: 'tinymce-editor' });
                observer.unobserve(entry.target);
            }
        });
    });
    observer.observe(document.querySelector('tinymce-editor'));
    
  • Bundle Size: Exclude unused plugins/themes from config/packages/tinymce.yaml to reduce payload.

Laravel-Specific Gotchas

  1. Route Caching:
    • Clear route cache after adding upload routes:
      php artisan route:clear
      
  2. Asset Versioning:
    • Ensure TinyMCE assets are versioned in config/packages/tinymce.yaml:
      assets_version: '{{ env("ASSET_VERSION") }}
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager