Back to index

plone3  3.1.7
CSSRegistry.py
Go to the documentation of this file.
00001 from Globals import InitializeClass
00002 from AccessControl import ClassSecurityInfo
00003 
00004 from zope.interface import implements
00005 
00006 from Products.CMFCore.utils import getToolByName
00007 
00008 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
00009 
00010 from Products.ResourceRegistries import config
00011 from Products.ResourceRegistries import permissions
00012 from Products.ResourceRegistries.interfaces import ICSSRegistry
00013 from Products.ResourceRegistries.tools.BaseRegistry import BaseRegistryTool
00014 from Products.ResourceRegistries.tools.BaseRegistry import Resource
00015 
00016 from packer import CSSPacker
00017 
00018 
00019 class Stylesheet(Resource):
00020     security = ClassSecurityInfo()
00021 
00022     def __init__(self, id, **kwargs):
00023         Resource.__init__(self, id, **kwargs)
00024         self._data['media'] = kwargs.get('media', '')
00025         self._data['rel'] = kwargs.get('rel', 'stylesheet')
00026         self._data['title'] = kwargs.get('title', '')
00027         self._data['rendering'] = kwargs.get('rendering', 'import')
00028         self._data['compression'] = kwargs.get('compression', 'safe')
00029 
00030     security.declarePublic('getMedia')
00031     def getMedia(self):
00032         result = self._data['media']
00033         if result == "":
00034             result = None
00035         return result
00036 
00037     security.declareProtected(permissions.ManagePortal, 'setMedia')
00038     def setMedia(self, media):
00039         self._data['media'] = media
00040 
00041     security.declarePublic('getRel')
00042     def getRel(self):
00043         return self._data['rel']
00044 
00045     security.declareProtected(permissions.ManagePortal, 'setRel')
00046     def setRel(self, rel):
00047         self._data['rel'] = rel
00048 
00049     security.declarePublic('getTitle')
00050     def getTitle(self):
00051         result = self._data['title']
00052         if result == "":
00053             result = None
00054         return result
00055 
00056     security.declareProtected(permissions.ManagePortal, 'setTitle')
00057     def setTitle(self, title):
00058         self._data['title'] = title
00059 
00060     security.declarePublic('getRendering')
00061     def getRendering(self):
00062         return self._data['rendering']
00063 
00064     security.declareProtected(permissions.ManagePortal, 'setRendering')
00065     def setRendering(self, rendering):
00066         self._data['rendering'] = rendering
00067 
00068     security.declarePublic('getCompression')
00069     def getCompression(self):
00070         # as this is a new property, old instance might not have that value, so
00071         # return 'safe' as default
00072         compression = self._data.get('compression', 'safe')
00073         if compression in config.CSS_COMPRESSION_METHODS:
00074             return compression
00075         return 'none'
00076 
00077     security.declareProtected(permissions.ManagePortal, 'setCompression')
00078     def setCompression(self, compression):
00079         self._data['compression'] = compression
00080 
00081 InitializeClass(Stylesheet)
00082 
00083 
00084 class CSSRegistryTool(BaseRegistryTool):
00085     """A Plone registry for managing the linking to css files."""
00086 
00087     id = config.CSSTOOLNAME
00088     meta_type = config.CSSTOOLTYPE
00089     title = 'CSS Registry'
00090 
00091     security = ClassSecurityInfo()
00092 
00093     implements(ICSSRegistry)
00094     __implements__ = BaseRegistryTool.__implements__
00095 
00096     #
00097     # ZMI stuff
00098     #
00099 
00100     manage_cssForm = PageTemplateFile('www/cssconfig', config.GLOBALS)
00101     manage_cssComposition = PageTemplateFile('www/csscomposition', config.GLOBALS)
00102 
00103     manage_options = (
00104         {
00105             'label': 'CSS Registry',
00106             'action': 'manage_cssForm',
00107         },
00108         {
00109             'label': 'Merged CSS Composition',
00110             'action': 'manage_cssComposition',
00111         },
00112     ) + BaseRegistryTool.manage_options
00113 
00114     attributes_to_compare = ('getExpression', 'getCookable',
00115                              'getCacheable', 'getRel', 'getRendering')
00116     filename_base = 'ploneStyles'
00117     filename_appendix = '.css'
00118     merged_output_prefix = u''
00119     cache_duration = config.CSS_CACHE_DURATION
00120     resource_class = Stylesheet
00121 
00122     #
00123     # Private Methods
00124     #
00125 
00126     security.declarePrivate('storeResource')
00127     def storeResource(self, resource, skipCooking=False):
00128         """Store a resource."""
00129         self.validateId(resource.getId(), self.getResources())
00130         resources = list(self.getResources())
00131         if len(resources) and resources[-1].getId() == 'ploneCustom.css':
00132             # ploneCustom.css should be the last item
00133             resources.insert(-1, resource)
00134         else:
00135             resources.append(resource)
00136         self.resources = tuple(resources)
00137         if not skipCooking:
00138             self.cookResources()
00139 
00140     security.declarePrivate('clearStylesheets')
00141     def clearStylesheets(self):
00142         self.clearResources()
00143 
00144     security.declarePrivate('compareResources')
00145     def compareResources(self, sheet1, sheet2 ):
00146         """Check if two resources are compatible."""
00147         for attr in self.attributes_to_compare:
00148             if getattr(sheet1, attr)() != getattr(sheet2, attr)():
00149                 return False
00150             if 'alternate' in sheet1.getRel():
00151                 return False
00152                 # this part needs a test
00153         return True
00154 
00155     security.declarePrivate('finalizeResourceMerging')
00156     def finalizeResourceMerging(self, resource, previtem):
00157         """Finalize the resource merging with the previous item."""
00158         if previtem.getMedia() != resource.getMedia():
00159             previtem.setMedia(None)
00160 
00161     def _compressCSS(self, content, level='safe'):
00162         if level == 'full':
00163             return CSSPacker('full').pack(content)
00164         elif level == 'safe':
00165             return CSSPacker('safe').pack(content)
00166         else:
00167             return content
00168 
00169     security.declarePrivate('finalizeContent')
00170     def finalizeContent(self, resource, content):
00171         """Finalize the resource content."""
00172         compression = resource.getCompression()
00173         if compression != 'none' and not self.getDebugMode():
00174             orig_url = "%s/%s?original=1" % (self.absolute_url(), resource.getId())
00175             content = "/* %s */\n%s" % (orig_url,
00176                                      self._compressCSS(content, compression))
00177 
00178         m = resource.getMedia()
00179         if m:
00180             content = '@media %s {\n%s\n}\n' % (m, content)
00181 
00182         return content
00183 
00184     #
00185     # ZMI Methods
00186     #
00187 
00188     security.declareProtected(permissions.ManagePortal, 'manage_addStylesheet')
00189     def manage_addStylesheet(self, id, expression='', media='',
00190                              rel='stylesheet', title='', rendering='import',
00191                              enabled=False, cookable=True, compression='safe',
00192                              cacheable=True, REQUEST=None):
00193         """Register a stylesheet from a TTW request."""
00194         self.registerStylesheet(id, expression, media, rel, title,
00195                                 rendering, enabled, cookable, compression, cacheable)
00196         if REQUEST:
00197             REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
00198 
00199     security.declareProtected(permissions.ManagePortal, 'manage_saveStylesheets')
00200     def manage_saveStylesheets(self, REQUEST=None):
00201         """Save stylesheets from the ZMI.
00202 
00203         Updates the whole sequence. For editing and reordering.
00204         """
00205         debugmode = REQUEST.get('debugmode',False)
00206         self.setDebugMode(debugmode)
00207         autogroupingmode = REQUEST.get('autogroupingmode', False)
00208         self.setAutoGroupingMode(autogroupingmode)
00209         records = REQUEST.get('stylesheets')
00210         records.sort(lambda a, b: a.sort - b.sort)
00211         self.resources = ()
00212         stylesheets = []
00213         for r in records:
00214             stylesheet = Stylesheet(r.get('id'),
00215                                     expression=r.get('expression', ''),
00216                                     media=r.get('media', ''),
00217                                     rel=r.get('rel', 'stylesheet'),
00218                                     title=r.get('title', ''),
00219                                     rendering=r.get('rendering', 'import'),
00220                                     enabled=r.get('enabled', False),
00221                                     cookable=r.get('cookable', False),
00222                                     cacheable=r.get('cacheable', False),
00223                                     compression=r.get('compression', 'safe'))
00224             stylesheets.append(stylesheet)
00225         self.resources = tuple(stylesheets)
00226         self.cookResources()
00227         if REQUEST:
00228             REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
00229 
00230     security.declareProtected(permissions.ManagePortal, 'manage_removeStylesheet')
00231     def manage_removeStylesheet(self, id, REQUEST=None):
00232         """Remove stylesheet from the ZMI."""
00233         self.unregisterResource(id)
00234         if REQUEST:
00235             REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
00236 
00237     #
00238     # Protected Methods
00239     #
00240 
00241     security.declareProtected(permissions.ManagePortal, 'registerStylesheet')
00242     def registerStylesheet(self, id, expression='', media='', rel='stylesheet',
00243                            title='', rendering='import',  enabled=1,
00244                            cookable=True, compression='safe', cacheable=True,
00245                            skipCooking=False):
00246         """Register a stylesheet."""
00247         stylesheet = Stylesheet(id,
00248                                 expression=expression,
00249                                 media=media,
00250                                 rel=rel,
00251                                 title=title,
00252                                 rendering=rendering,
00253                                 enabled=enabled,
00254                                 cookable=cookable,
00255                                 compression=compression,
00256                                 cacheable=cacheable)
00257         self.storeResource(stylesheet, skipCooking=skipCooking)
00258 
00259     security.declareProtected(permissions.ManagePortal, 'updateStylesheet')
00260     def updateStylesheet(self, id, **data):
00261         stylesheet = self.getResourcesDict().get(id, None)
00262         if stylesheet is None:
00263             raise ValueError, 'Invalid resource id %s' % (id)
00264         
00265         if data.get('expression', None) is not None:
00266             stylesheet.setExpression(data['expression'])
00267         if data.get('media', None) is not None:
00268             stylesheet.setMedia(data['media'])
00269         if data.get('rel', None) is not None:
00270             stylesheet.setRel(data['rel'])
00271         if data.get('title', None) is not None:
00272             stylesheet.setTitle(data['title'])
00273         if data.get('rendering', None) is not None:
00274             stylesheet.setRendering(data['rendering'])
00275         if data.get('enabled', None) is not None:
00276             stylesheet.setEnabled(data['enabled'])
00277         if data.get('cookable', None) is not None:
00278             stylesheet.setCookable(data['cookable'])
00279         if data.get('compression', None) is not None:
00280             stylesheet.setCompression(data['compression'])
00281         if data.get('cacheable', None) is not None:
00282             stylesheet.setCacheable(data['cacheable'])
00283 
00284     security.declareProtected(permissions.ManagePortal, 'getRenderingOptions')
00285     def getRenderingOptions(self):
00286         """Rendering methods for use in ZMI forms."""
00287         return config.CSS_RENDER_METHODS
00288 
00289     security.declareProtected(permissions.ManagePortal, 'getCompressionOptions')
00290     def getCompressionOptions(self):
00291         """Compression methods for use in ZMI forms."""
00292         return config.CSS_COMPRESSION_METHODS
00293 
00294     security.declareProtected(permissions.View, 'getContentType')
00295     def getContentType(self):
00296         """Return the registry content type."""
00297         plone_utils = getToolByName(self, 'plone_utils')
00298         try:
00299             encoding = plone_utils.getSiteEncoding()
00300         except AttributeError:
00301             # For Plone < 2.1
00302             pprop = getToolByName(self, 'portal_properties')
00303             default = 'utf-8'
00304             try:
00305                 encoding = pprop.site_properties.getProperty('default_charset', default)
00306             except AttributeError:
00307                 encoding = default
00308         return 'text/css;charset=%s' % encoding
00309 
00310 
00311 InitializeClass(CSSRegistryTool)