Add some blockquote buttons to Wagtail CMS’ WYSIWYG Editor

Wagtail is an amazing Django based open source CMS, find out more at http://wagtail.io/

Wagtail’s Editor is based on Hallo.js, we needed to add a normal blockquote button,and one with a class attribute for a pull out style quote.

There are two steps to doing this, firstly override the whitelister’s element rules (this stops certain tags from being saved in wagtail, if you don’t do this the Blockquote HTML tag gets stripped out. Secondly add the JS to introduce the custom buttons.

The editor icons are based on font awesome fonts, so it’s easy to pick whatever icon you want by changing the icon: ‘fa fa-stack-exchange’ value

To start add a wagtails_hooks.py file into the app folder of your wagtail project.

wagtail_hooks.py


from django.utils.safestring import mark_safe
from django.utils.html import format_html, format_html_join
from django.conf import settings
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.whitelist import attribute_rule, check_url, allow_without_attributes

def whitelister_element_rules():
    return {
        'a': attribute_rule({'href': check_url, 'target': True}),
        'blockquote': attribute_rule({'class': True}),
    }
hooks.register('construct_whitelister_element_rules', whitelister_element_rules)

def editor_js():
	js_files = [
		'yourapp/js/hallo-custombuttons.js',
	]
	js_includes = format_html_join('\n', '<script src="{0}{1}"></script>',
		((settings.STATIC_URL, filename) for filename in js_files)
	)

	return js_includes + format_html(
		"""
		<script>
			registerHalloPlugin('blockquotebutton');
      registerHalloPlugin('blockquotebuttonwithclass');
		</script>
		"""
	)

hooks.register('insert_editor_js', editor_js)

def editor_css():
	return format_html('<link rel="stylesheet" href="'+ settings.STATIC_URL + 'yourapp/css/vendor/font-awesome/css/font-awesome.min.css">')

hooks.register('insert_editor_css', editor_css)

Then add a JS file into your app’s static JS folder.

hallo_custombuttons.js


(function() {
    (function($) {
        return $.widget('IKS.blockquotebutton', {
            options: {
                uuid: '',
                editable: null
            },
            populateToolbar: function(toolbar) {
                var button, widget;

                widget = this;

                button = $('<span></span>');
                button.hallobutton({
                    uuid: this.options.uuid,
                    editable: this.options.editable,
                    label: 'Blockquote',
                    icon: 'fa fa-quote-left',
                    command: null
                });

                toolbar.append(button);

                button.on('click', function(event) {
                    return widget.options.editable.execute('formatBlock',
                                                           'blockquote');
                });
            }
        });
    })(jQuery);
}).call(this);

(function() {
  (function($) {
    return $.widget("IKS.blockquotebuttonwithclass", {
      options: {
        uuid: '',
        editable: null
      },
      populateToolbar: function(toolbar) {
        var button, widget;

        widget = this;
        button = $('<span></span>');
        button.hallobutton({
          uuid: this.options.uuid,
          editable: this.options.editable,
          label: 'Pull Out Quote',
          icon: 'fa fa-stack-exchange',
          command: null
        });
        toolbar.append(button);
        return button.on("click", function(event) {
          var insertionPoint, lastSelection;

          lastSelection = widget.options.editable.getSelection();
          insertionPoint = $(lastSelection.endContainer).parentsUntil('.richtext').last();
					var elem;
					elem = "<blockquote class='pullout'>" + lastSelection + "</blockquote>";

					var node = lastSelection.createContextualFragment(elem);

					lastSelection.deleteContents();
					lastSelection.insertNode(node);

					return widget.options.editable.element.trigger('change');
        });
      }
    });
  })(jQuery);

}).call(this);

There’s probably a more concise way to do this but it worked for me!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.