Customizing Martor Widgets ========================== Martor provides powerful widget classes that can be customized to fit your specific needs. This guide covers widget customization, configuration, and advanced usage patterns. Available Widgets ----------------- Martor provides two main widget classes: * **MartorWidget**: For use in regular forms * **AdminMartorWidget**: For use in Django Admin Basic Widget Usage ------------------ Standard Widget ~~~~~~~~~~~~~~~ .. code-block:: python from django import forms from martor.widgets import MartorWidget class MyForm(forms.Form): content = forms.CharField(widget=MartorWidget()) Admin Widget ~~~~~~~~~~~~ .. code-block:: python from django.contrib import admin from django.db import models from martor.widgets import AdminMartorWidget class MyModelAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {'widget': AdminMartorWidget}, } Widget Configuration -------------------- Martor widgets can be configured through several methods: HTML Attributes ~~~~~~~~~~~~~~~ Configure the widget using HTML data attributes: .. code-block:: python from martor.widgets import MartorWidget widget = MartorWidget(attrs={ # Upload configuration 'data-upload-url': '/custom-upload-endpoint/', 'data-search-users-url': '/custom-user-search/', 'data-base-emoji-url': 'https://example.com/emojis/', # Editor behavior 'data-save-timeout': 2000, # milliseconds 'placeholder': 'Start writing...', 'rows': 15, 'class': 'my-custom-editor', # Feature toggles (override global settings) 'data-enable-configs': { 'emoji': 'true', 'imgur': 'false', 'mention': 'true', 'living': 'false', 'spellcheck': 'true', 'hljs': 'true', } }) Available Data Attributes ~~~~~~~~~~~~~~~~~~~~~~~~~ * ``data-upload-url``: Custom image upload endpoint * ``data-search-users-url``: Custom user search endpoint * ``data-base-emoji-url``: Custom emoji base URL * ``data-save-timeout``: Preview update delay (milliseconds) * ``data-markdownfy-url``: Custom markdown conversion endpoint * ``data-enable-configs``: Override global feature settings Advanced Widget Customization ------------------------------ Custom Widget Class ~~~~~~~~~~~~~~~~~~~ Create your own widget class for reusable customizations: .. code-block:: python from martor.widgets import MartorWidget class BlogMartorWidget(MartorWidget): def __init__(self, *args, **kwargs): # Set default attributes default_attrs = { 'data-upload-url': '/blog/upload-image/', 'data-search-users-url': '/blog/search-users/', 'placeholder': 'Write your blog post...', 'rows': 20, 'class': 'blog-editor', 'data-enable-configs': { 'emoji': 'true', 'imgur': 'false', 'mention': 'true', 'living': 'true', 'spellcheck': 'true', 'hljs': 'true', } } # Merge with any provided attrs attrs = kwargs.get('attrs', {}) default_attrs.update(attrs) kwargs['attrs'] = default_attrs super().__init__(*args, **kwargs) # Usage class BlogPostForm(forms.Form): content = forms.CharField(widget=BlogMartorWidget()) Conditional Widget Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Configure the widget based on context: .. code-block:: python class ContextualMartorWidget(MartorWidget): def __init__(self, user=None, *args, **kwargs): attrs = kwargs.get('attrs', {}) # Configure based on user permissions if user and user.has_perm('myapp.can_upload_images'): attrs['data-upload-url'] = '/secure-upload/' else: attrs['data-upload-url'] = '' # Disable uploads # Configure mentions based on user if user and user.is_staff: attrs['data-search-users-url'] = '/admin/search-users/' attrs['data-enable-configs'] = { 'mention': 'true' } else: attrs['data-enable-configs'] = { 'mention': 'false' } kwargs['attrs'] = attrs super().__init__(*args, **kwargs) # Usage in form class PostForm(forms.Form): def __init__(self, user=None, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['content'] = forms.CharField( widget=ContextualMartorWidget(user=user) ) Theme-Specific Widgets ---------------------- Bootstrap Widget ~~~~~~~~~~~~~~~~ .. code-block:: python class BootstrapMartorWidget(MartorWidget): def __init__(self, *args, **kwargs): attrs = kwargs.get('attrs', {}) attrs.update({ 'class': 'form-control martor-bootstrap', 'data-theme': 'bootstrap' }) kwargs['attrs'] = attrs super().__init__(*args, **kwargs) Semantic UI Widget ~~~~~~~~~~~~~~~~~~ .. code-block:: python class SemanticMartorWidget(MartorWidget): def __init__(self, *args, **kwargs): attrs = kwargs.get('attrs', {}) attrs.update({ 'class': 'ui input martor-semantic', 'data-theme': 'semantic' }) kwargs['attrs'] = attrs super().__init__(*args, **kwargs) Widget Media Configuration -------------------------- The widget automatically includes necessary CSS and JavaScript files. You can customize this: .. code-block:: python class CustomMartorWidget(MartorWidget): class Media: css = { 'all': ( 'plugins/css/ace.min.css', 'plugins/css/highlight.min.css', 'martor/css/martor.bootstrap.min.css', 'custom/my-martor-theme.css', # Your custom CSS ) } js = ( 'plugins/js/ace.js', 'plugins/js/mode-markdown.js', 'plugins/js/ext-language_tools.js', 'plugins/js/theme-github.js', 'plugins/js/highlight.min.js', 'plugins/js/emojis.min.js', 'martor/js/martor.bootstrap.min.js', 'custom/my-martor-extensions.js', # Your custom JS ) Widget Templates ---------------- Martor uses templates for rendering. You can override these: **Template Structure:** :: martor/ ├── bootstrap/ │ ├── editor.html │ ├── emoji.html │ ├── guide.html │ └── toolbar.html └── semantic/ ├── editor.html ├── emoji.html ├── guide.html └── toolbar.html **Custom Template Example:** .. code-block:: html