WY Image Plugin for Redactor

Status: Production Ready
Version: 1.0.0
Last Updated: January 2025

Overview

The WY Image plugin enables rich image insertion in the Redactor editor with full ImageKit transformation support. Users can select images from the library, customize cropping/sizing/effects, and insert optimized images with proper srcset attributes for responsive delivery.

Architecture

┌──────────────┐    Select    ┌──────────────────┐   Configure   ┌─────────────────┐
│  WY Image    │─────────────►│   Image Picker   │──────────────►│  Image Options  │
│  Toolbar Btn │              │   Modal          │               │  Editor Modal   │
└──────────────┘              └──────────────────┘               └────────┬────────┘
                                                                          │
                              ┌──────────────────┐                        │ Insert
                              │   oEmbed API     │◄───────────────────────┘
                              │   /api/v1/oembed │
                              │   /image         │
                              └────────┬─────────┘
                                       │
                              ┌────────▼─────────┐
                              │  ImageKit URL    │
                              │  with transforms │
                              └──────────────────┘

Features

Image Picker Modal

  • Search modes: Keyword, AI semantic, Hybrid
  • Filters: Tags, source, colorspace, dimensions, product line
  • Tom Select: Searchable multi-select dropdowns
  • Infinite scroll: Loads more results on scroll
  • Filter badge: Shows count of active filters

Image Options Editor

Tab Options
Basic Caption, alt text, size presets, custom dimensions
Crop Visual cropping with Cropper.js
Advanced Format, quality, blur, border, background color, lazy loading, srcset

Live Preview

  • Preview updates in real-time as options change
  • ImageKit URL displayed and copy-able
  • Lightbox for full-size preview

oEmbed Integration

Images are inserted via an internal oEmbed endpoint that generates the full HTML:

<figure class="wy-image-embed" data-wy-image-id="12345" data-wy-image-options='{"width":800}'>
  <img src="https://ik.warmlyyours.com/img/..." 
       srcset="..." 
       sizes="..."
       alt="..." 
       class="img-fluid"
       loading="lazy">
  <figcaption class="figure-caption">Optional caption</figcaption>
</figure>

Usage

Inserting a New Image

  1. Click WY Image button in toolbar
  2. Search/filter to find the image
  3. Click image thumbnail to select
  4. Configure options in the editor modal
  5. Click Insert Image

Editing an Existing Image

  1. Click on an embedded image in the editor
  2. Select WY Image from context menu
  3. Modify options in the editor modal
  4. Click Update Image

Image Options

Size Presets

Preset Dimensions Use Case
Small 400px Thumbnails, inline
Medium 800px Standard content
Large 1200px Hero images
Full Width 2000px Full-bleed layouts
Custom User-defined Specific requirements

Cropping

The visual cropper uses Cropper.js with coordinate scaling:

// Coordinates are scaled from displayed size to original dimensions
const scaleX = originalWidth / displayedWidth
const scaleY = originalHeight / displayedHeight

cropParams = {
  x: Math.round(cropData.x * scaleX),
  y: Math.round(cropData.y * scaleY),
  w: Math.round(cropData.width * scaleX),
  h: Math.round(cropData.height * scaleY)
}

Advanced Options

Option Description Values
Format Output format Auto, JPEG, PNG, WebP, AVIF
Quality Compression 1-100 (default: 80)
Blur Gaussian blur 0-100
Border Border width 0-20px
Border Color Border color Hex color
Background Pad color Hex color
Lazy Load Native lazy loading On/Off
Include srcset Responsive images On/Off

API Endpoints

Image Picker Modal

GET /redactor/image_picker_modal
Parameters:
  - callback: JavaScript callback function name

Image Options Modal

GET /redactor/image_options_modal
Parameters:
  - image_id: Selected image ID
  - callback: JavaScript callback function name
  - caption: Pre-fill caption (for editing)
  - alt: Pre-fill alt text (for editing)

oEmbed Image

GET /api/v1/oembed/image
Parameters:
  - image_id: Image record ID
  - caption: Figure caption
  - alt: Alt text
  - width: Max width
  - height: Max height
  - crop_x, crop_y, crop_w, crop_h: Crop region
  - format: Output format
  - quality: Compression quality
  - blur: Blur amount
  - border: Border width
  - border_color: Border color
  - background: Background color
  - lazy: Enable lazy loading
  - srcset: Include srcset attribute

Files

File Purpose
client/js/common/wyimage4.js Redactor plugin
app/javascript/controllers/image_picker_controller.js Picker modal logic
app/javascript/controllers/image_editor_controller.js Options editor logic
app/views/crm/redactor_image_picker/_modal.html.erb Picker modal view
app/views/crm/redactor_image_picker/_options_modal.html.erb Options modal view
app/controllers/crm/redactor_image_picker_controller.rb Modal endpoints
app/controllers/api/v1/oembed_controller.rb oEmbed endpoint
app/services/oembed/image_provider.rb Image HTML generation

Stimulus Controllers

image_picker_controller

Targets:

  • searchInput, results, loading
  • modeButton, modeIcon, searchButton
  • filterBadge, tagsFilter, excludeTagsFilter
  • sourceFilter, colorspaceFilter, productLineFilter
  • minWidthFilter, minHeightFilter

Values:

  • callback: Callback function name
  • searchUrl: Image search endpoint
  • searchMode: keyword | ai | hybrid
  • placeholders: Mode-specific placeholder text
  • icons: Mode-specific icons

image_editor_controller

Targets:

  • preview, urlDisplay, urlCopied, copyBtn
  • caption, alt, sizePreset, customDimensions
  • width, height, lockAspect, link, linkTarget
  • cropperContainer, cropperImage, cropInfo
  • format, quality, qualityValue, blur, blurValue
  • border, borderColor, bgColor, lazyload, includeSrcset

Values:

  • imageId: Selected image ID
  • imageUrl: Full image URL
  • baseUrl: Raw ImageKit URL
  • imageWidth, imageHeight: Original dimensions
  • imageAlt: Default alt text
  • callback: Insert callback function name

Troubleshooting

Image Not Inserting

Cause: oEmbed endpoint error
Fix: Check browser console for API errors, verify image_id is valid

Cropping Ignored

Cause: Coordinate scaling mismatch
Fix: Ensure original dimensions are passed via data attributes

Preview Not Updating

Cause: Debounce delay or missing target
Fix: Check updatePreview() is called and targets exist

Tom Select Not Initializing

Cause: DOM not ready when controller connects
Fix: Ensure Tom Select controller is on the select element

Related Documentation