Skip to content
This repository was archived by the owner on Mar 12, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
/local
/.tx
/translations
__pycache__
/.DS_Store
build/
dist/
wagtailtinymce.egg-info/
100 changes: 95 additions & 5 deletions wagtailtinymce/rich_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,92 @@
from wagtail.utils.widgets import WidgetWithScript
from wagtail.wagtailadmin.edit_handlers import RichTextFieldPanel
from wagtail.wagtailcore.rich_text import DbWhitelister
from wagtail.wagtailcore.rich_text import expand_db_html
from wagtail.wagtailcore.rich_text import expand_db_html, get_link_handler, get_embed_handler
from wagtail.wagtailcore.whitelist import allow_without_attributes, attribute_rule, check_url


class DbTinymceWhitelister(DbWhitelister):
Copy link
Copy Markdown

@maxpeterson maxpeterson Apr 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The recommended method for updating the whitelisted is to use a construct-whitelister-element-rules hook - this would remove the need for the DbWhitelister subclass

@hooks.register('construct_whitelister_element_rules')
def whitelister_element_rules():
    common = {
        'style': True,
        'width': True,
        'margin-left': True,
        'margin-right': True,
        'height': True,
        'border-color': True,
        'text-align': True,
        'background-color': True,
        'vertical-align': True,
        'font-family': True,
        'valign': True,
    }
    table_rule = attribute_rule(dict(common, **{
        'border': True,
        'cellpadding': True,
        'cellspacing': True,
    }))
    row_rule = attribute_rule(common)
    cell_rule = attribute_rule(dict(common, **{
        'colspan': True,
        'scope': True,
        'rowspan': True,
    }))

    return {
        'blockquote': allow_without_attributes,
        'pre': allow_without_attributes,
        'span': allow_without_attributes,
        'code': allow_without_attributes,

        'table': table_rule,
        'thead': allow_without_attributes,
        'tfoot': allow_without_attributes,
        'tbody': allow_without_attributes,
        'colgroup': allow_without_attributes,
        'col': allow_without_attributes,
        'caption': allow_without_attributes,
        'tr': row_rule,
        'th': cell_rule,
        'td': cell_rule,
    }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added #15

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,i closed the PR.

"""
A custom whitelisting engine to convert the HTML as returned by the rich text editor
into the pseudo-HTML format stored in the database (in which images, documents and other
linked objects are identified by ID rather than URL):

* implements a 'construct_whitelister_element_rules' hook so that other apps can modify
the whitelist ruleset (e.g. to permit additional HTML elements beyond those in the base
Whitelister module);
* replaces any element with a 'data-embedtype' attribute with an <embed> element, with
attributes supplied by the handler for that type as defined in EMBED_HANDLERS;
* rewrites the attributes of any <a> element with a 'data-linktype' attribute, as
determined by the handler for that type defined in LINK_HANDLERS, while keeping the
element content intact.
"""
allow_attr = {'border': True, 'cellpadding': True, 'cellspacing': True, 'style': True, 'width': True, 'border': True,
'colspan': True, 'margin-left': True, 'margin-right': True, 'height': True, 'border-color': True,
'text-align': True, 'background-color': True, 'vertical-align': True, 'scope': True, 'font-family': True,
'rowspan': True, 'valign': True}
element_rules = {
'[document]': allow_without_attributes,
'a': attribute_rule({'href': check_url}),
'b': allow_without_attributes,
'br': allow_without_attributes,
'div': attribute_rule(allow_attr),
'em': attribute_rule(allow_attr),
'h1': attribute_rule(allow_attr),
'h2': attribute_rule(allow_attr),
'h3': attribute_rule(allow_attr),
'h4': attribute_rule(allow_attr),
'h5': attribute_rule(allow_attr),
'h6': attribute_rule(allow_attr),
'hr': allow_without_attributes,
'i': allow_without_attributes,
'img': attribute_rule({'src': check_url, 'width': True, 'height': True,
'alt': True}),
'li': attribute_rule(allow_attr),
'ol': attribute_rule(allow_attr),
'p': attribute_rule(allow_attr),
'strong': attribute_rule(allow_attr),
'sub': attribute_rule(allow_attr),
'sup': attribute_rule(allow_attr),
'ul': attribute_rule(allow_attr),

'blockquote': attribute_rule(allow_attr),
'pre': attribute_rule(allow_attr),
'span': attribute_rule(allow_attr),
'code': attribute_rule(allow_attr),

'table': attribute_rule(allow_attr),
'caption': attribute_rule(allow_attr),
'tbody': attribute_rule(allow_attr),
'th': attribute_rule(allow_attr),
'tr': attribute_rule(allow_attr),
'td': attribute_rule(allow_attr),
}

@classmethod
def clean_tag_node(cls, doc, tag):
if 'data-embedtype' in tag.attrs:
embed_type = tag['data-embedtype']
# fetch the appropriate embed handler for this embedtype
embed_handler = get_embed_handler(embed_type)
embed_attrs = embed_handler.get_db_attributes(tag)
embed_attrs['embedtype'] = embed_type

embed_tag = doc.new_tag('embed', **embed_attrs)
embed_tag.can_be_empty_element = True
tag.replace_with(embed_tag)
elif tag.name == 'a' and 'data-linktype' in tag.attrs:
# first, whitelist the contents of this tag
for child in tag.contents:
cls.clean_node(doc, child)

link_type = tag['data-linktype']
link_handler = get_link_handler(link_type)
link_attrs = link_handler.get_db_attributes(tag)
link_attrs['linktype'] = link_type
tag.attrs.clear()
tag.attrs.update(**link_attrs)
else:
super(DbWhitelister, cls).clean_tag_node(doc, tag)


class TinyMCERichTextArea(WidgetWithScript, widgets.Textarea):
Expand All @@ -52,11 +137,11 @@ def getDefaultArgs(cls):
['pastetext', 'fullscreen'],
]
],
'menus': False,
'language': translation.to_locale(translation.get_language() or 'en'),
'menus': ['edit', 'insert', 'view', 'format', 'table', 'tools'],
'options': {
'browser_spellcheck': True,
'noneditable_leave_contenteditable': True,
'language': translation.to_locale(translation.get_language()),
'language_load': True,
},
}
Expand Down Expand Up @@ -91,6 +176,10 @@ def render_js_init(self, id_, name, value):
for rows in self.kwargs['buttons']
]

if 'language' in self.kwargs:
if self.kwargs['language'] == 'zh_Hans':
kwargs['language'] = 'zh_CN'

if 'menus' in self.kwargs:
if self.kwargs['menus'] is False:
kwargs['menubar'] = False
Expand All @@ -100,7 +189,8 @@ def render_js_init(self, id_, name, value):
return "makeTinyMCEEditable({0}, {1});".format(json.dumps(id_), json.dumps(kwargs))

def value_from_datadict(self, data, files, name):
original_value = super(TinyMCERichTextArea, self).value_from_datadict(data, files, name)
original_value = super(TinyMCERichTextArea,
self).value_from_datadict(data, files, name)
if original_value is None:
return None
return DbWhitelister.clean(original_value)
return DbTinymceWhitelister.clean(original_value)
4 changes: 2 additions & 2 deletions wagtailtinymce/static/wagtailtinymce/js/tinymce-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

'use strict';

var mcePlugins = ['hr', 'code', 'fullscreen', 'noneditable', 'paste', 'table'],
var mcePlugins = ['hr', 'code', 'fullscreen', 'noneditable', 'paste', 'table', 'advlist', 'lists', 'contextmenu'],
mceTools = ['inserttable'],
mceExternalPlugins = {};

Expand Down Expand Up @@ -60,6 +60,6 @@ function makeTinyMCEEditable(id, kwargs) {
});
}
});

tinymce.suffix = '.min'
tinymce.init(kwargs);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading