src/pyams_content/zmi/tinymce.py
changeset 1155 f944a4efb65b
parent 1070 ea0c7ac589c4
--- 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