--- a/src/pyams_content/zmi/tinymce.py Tue Dec 11 13:50:27 2018 +0100
+++ b/src/pyams_content/zmi/tinymce.py Wed Dec 12 10:18:31 2018 +0100
@@ -12,18 +12,57 @@
__docformat__ = 'restructuredtext'
+import json
-# import standard library
+import tinycss2
+from tinycss2.ast import Comment, IdentToken, QualifiedRule, WhitespaceToken
+from zope.dublincore.interfaces import IZopeDublinCore
-# import interfaces
from pyams_content.zmi import pyams_content
from pyams_form.interfaces.form import IForm
+from pyams_skin.interfaces import ISkinnable
from pyams_skin.interfaces.tinymce import ITinyMCEConfiguration
from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.adapter import ContextRequestAdapter, adapter_config
+from pyams_utils.fanstatic import get_resource_path
+from pyams_utils.traversing import get_parent
+from pyams_utils.url import absolute_url
-# import packages
-from pyams_utils.adapter import adapter_config, ContextRequestAdapter
-from pyams_utils.fanstatic import get_resource_path
+
+def parse_css(data):
+ """Parse given CSS data to extract required styles"""
+ result = []
+ label = None
+ rules, encoding = tinycss2.parse_stylesheet_bytes(data, skip_whitespace=True)
+ for rule in rules:
+ if isinstance(rule, Comment):
+ label = rule.value.strip()
+ if ':' in label:
+ label, selector = label.split(':', 1)
+ elif isinstance(rule, QualifiedRule):
+ ident_token = class_token = None
+ tokens = iter(rule.prelude)
+ for token in tokens:
+ if isinstance(token, IdentToken):
+ ident_token = token
+ break
+ for token in tokens:
+ if isinstance(token, IdentToken):
+ class_token = token
+ break
+ token_id = ''.join((token.value for token in rule.prelude
+ if not isinstance(token, WhitespaceToken)))
+ result.append({
+ 'title': label or token_id,
+ 'classes': class_token.value,
+ 'block': ident_token.lower_value if ident_token and
+ (ident_token.lower_value in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'section', 'p', 'div',
+ 'blockquote', 'pre')) else None,
+ 'inline': ident_token.lower_value if ident_token and
+ (ident_token.lower_value in ('span',)) else None
+ })
+ label = None
+ return result
@adapter_config(context=(IForm, IPyAMSLayer), provides=ITinyMCEConfiguration)
@@ -32,9 +71,18 @@
@property
def configuration(self):
- return {
+ result = {
'ams-plugins': 'pyams_content',
'ams-plugin-pyams_content-src': get_resource_path(pyams_content),
'ams-plugin-pyams_content-async': 'false',
'ams-tinymce-init-callback': 'PyAMS_content.TinyMCE.initEditor'
}
+ skinnable = get_parent(self.context.context, ISkinnable)
+ if skinnable is not None:
+ editor_stylesheet = skinnable.editor_stylesheet
+ if editor_stylesheet:
+ modified = IZopeDublinCore(editor_stylesheet).modified
+ result['ams-tinymce-content-css'] = absolute_url(editor_stylesheet, self.request,
+ query={'_': modified.timestamp()})
+ result['ams-tinymce-editor-styles'] = json.dumps(parse_css(editor_stylesheet.data))
+ return result