[1822] | 1 | import re |
---|
[1788] | 2 | from zope.interface import Interface |
---|
| 3 | from zope.interface import implements |
---|
| 4 | from zope.component import adapts |
---|
[1958] | 5 | from zope.schema import Bool, Choice, Tuple, List |
---|
[1902] | 6 | from zope.schema import SourceText |
---|
[3549] | 7 | # BBB Support different versions of Plone |
---|
[3542] | 8 | getSite = None |
---|
[3541] | 9 | try: |
---|
[3550] | 10 | # Plone < 4.3 |
---|
[3542] | 11 | from zope.app.component import hooks |
---|
| 12 | getSite = hooks.getSite |
---|
[3541] | 13 | except ImportError: |
---|
[3550] | 14 | # Plone >= 4.3 |
---|
[3541] | 15 | from zope.component.hooks import getSite |
---|
[1788] | 16 | from zope.app.form.browser import TextAreaWidget |
---|
| 17 | |
---|
[1904] | 18 | from plone.fieldsets.fieldsets import FormFieldsets |
---|
[1788] | 19 | from plone.app.controlpanel.form import ControlPanelForm |
---|
| 20 | from plone.app.controlpanel.widgets import MultiCheckBoxThreeColumnWidget |
---|
| 21 | |
---|
| 22 | from Products.CMFCore.utils import getToolByName |
---|
[1902] | 23 | from Products.CMFPlone.utils import safe_unicode |
---|
[1788] | 24 | from Products.CMFDefault.formlib.schema import ProxyFieldProperty |
---|
| 25 | from Products.CMFDefault.formlib.schema import SchemaAdapterBase |
---|
| 26 | from Products.CMFPlone.interfaces import IPloneSiteRoot |
---|
| 27 | |
---|
| 28 | from quintagroup.seoptimizer import SeoptimizerMessageFactory as _ |
---|
| 29 | |
---|
| 30 | |
---|
[1904] | 31 | # Configlet schemas |
---|
| 32 | class ISEOConfigletBaseSchema(Interface): |
---|
[1883] | 33 | |
---|
[1788] | 34 | exposeDCMetaTags = Bool( |
---|
| 35 | title=_("label_exposeDCMetaTags", |
---|
[3547] | 36 | default='Expose <abbr title="Dublin Core">DC</abbr> ' |
---|
[3134] | 37 | 'meta tags'), |
---|
[1788] | 38 | description=_("description_seo_dc_metatags", |
---|
[3134] | 39 | default='Controls if <abbr title="Dublin Core">DC</abbr>' |
---|
| 40 | ' metatags are exposed to page header. They include ' |
---|
| 41 | 'DC.description, DC.type, DC.format, DC.creator and ' |
---|
| 42 | 'others.'), |
---|
[1788] | 43 | default=True, |
---|
| 44 | required=False) |
---|
| 45 | |
---|
[1822] | 46 | metatags_order = List( |
---|
[1788] | 47 | title=_("label_metatags_order", |
---|
| 48 | default='Meta tags order in the page.'), |
---|
| 49 | description=_("help_metatags_order", |
---|
[3134] | 50 | default='Fill in meta tags (one per line) in the order ' |
---|
| 51 | 'in which they will appear on site source pages. ' |
---|
| 52 | 'Example: "metaname accessor".'), |
---|
[1788] | 53 | required=False) |
---|
| 54 | |
---|
| 55 | types_seo_enabled = Tuple( |
---|
| 56 | title=_("label_content_type_title", default='Content Types'), |
---|
| 57 | description=_("description_seo_content_types", |
---|
[3547] | 58 | default='Select content types that will have SEO ' |
---|
| 59 | 'properties enabled.'), |
---|
[1788] | 60 | required=False, |
---|
| 61 | missing_value=tuple(), |
---|
| 62 | value_type=Choice( |
---|
| 63 | vocabulary="plone.app.vocabularies.ReallyUserFriendlyTypes")) |
---|
| 64 | |
---|
[1883] | 65 | default_custom_metatags = List( |
---|
[3134] | 66 | title=_("label_default_custom_metatags", |
---|
| 67 | default='Default custom metatags.'), |
---|
[1883] | 68 | description=_("help_default_custom_metatags", |
---|
[3547] | 69 | default='Fill in custom metatag names (one per line) ' |
---|
| 70 | 'which will appear on qseo_properties edit tab. ' |
---|
[3134] | 71 | 'Example: "metaname|metacontent" or "metaname".'), |
---|
[1883] | 72 | required=False) |
---|
[1788] | 73 | |
---|
[1904] | 74 | |
---|
| 75 | class ISEOConfigletAdvancedSchema(Interface): |
---|
[1902] | 76 | custom_script = SourceText( |
---|
| 77 | title=_("label_custom_script", default=u'Header JavaScript'), |
---|
| 78 | description=_("help_custom_script", |
---|
[3547] | 79 | default=u"This JavaScript code will be included in " |
---|
| 80 | "the rendered HTML as entered in the page header."), |
---|
[1902] | 81 | default=u'', |
---|
| 82 | required=False) |
---|
[1788] | 83 | |
---|
[1902] | 84 | fields = List( |
---|
[3134] | 85 | title=_("label_fields", default='Fields for keywords statistic ' |
---|
| 86 | 'calculation.'), |
---|
| 87 | description=_("help_fields", default='Fill in filds (one per line)' |
---|
| 88 | 'which statistics of keywords usage should ' |
---|
| 89 | 'be calculated for.'), |
---|
[1902] | 90 | required=False) |
---|
| 91 | |
---|
| 92 | stop_words = List( |
---|
| 93 | title=_("label_stop_words", default='Stop words.'), |
---|
[3134] | 94 | description=_("help_stop_words", default='Fill in stop words ' |
---|
| 95 | '(one per line) which will be excluded from kewords ' |
---|
| 96 | 'statistics calculation.'), |
---|
[1902] | 97 | required=False) |
---|
| 98 | |
---|
[2889] | 99 | external_keywords_test = Bool( |
---|
| 100 | title=_("label_external_keywords_test", |
---|
| 101 | default='External keywords check'), |
---|
| 102 | description=_("description_external_keywords_test", |
---|
[3547] | 103 | default='Make keywords test by opening context url as ' |
---|
| 104 | 'external resource with urllib2.openurl(). This is ' |
---|
| 105 | 'useful when xdv/Deliverance transformation is used ' |
---|
| 106 | 'on the site.'), |
---|
[2889] | 107 | default=False, |
---|
| 108 | required=False) |
---|
[1904] | 109 | |
---|
| 110 | |
---|
| 111 | class ISEOConfigletSchema(ISEOConfigletBaseSchema, |
---|
| 112 | ISEOConfigletAdvancedSchema): |
---|
| 113 | """Combined schema for the adapter lookup. |
---|
| 114 | """ |
---|
| 115 | |
---|
| 116 | |
---|
[1788] | 117 | class SEOConfigletAdapter(SchemaAdapterBase): |
---|
| 118 | |
---|
| 119 | adapts(IPloneSiteRoot) |
---|
| 120 | implements(ISEOConfigletSchema) |
---|
| 121 | |
---|
| 122 | def __init__(self, context): |
---|
| 123 | super(SEOConfigletAdapter, self).__init__(context) |
---|
| 124 | self.portal = getSite() |
---|
| 125 | pprop = getToolByName(self.portal, 'portal_properties') |
---|
| 126 | self.context = pprop.seo_properties |
---|
| 127 | self.siteprops = pprop.site_properties |
---|
| 128 | self.ttool = getToolByName(context, 'portal_types') |
---|
[1903] | 129 | self.encoding = pprop.site_properties.default_charset |
---|
[1788] | 130 | |
---|
| 131 | def getExposeDC(self): |
---|
| 132 | return self.siteprops.getProperty('exposeDCMetaTags') |
---|
| 133 | |
---|
| 134 | def setExposeDC(self, value): |
---|
| 135 | return self.siteprops._updateProperty('exposeDCMetaTags', bool(value)) |
---|
| 136 | |
---|
| 137 | def getTypesSEOEnabled(self): |
---|
| 138 | ct_with_seo = self.context.content_types_with_seoproperties |
---|
| 139 | return [t for t in self.ttool.listContentTypes() if t in ct_with_seo] |
---|
[1883] | 140 | |
---|
[1788] | 141 | def setTypesSEOEnabled(self, value): |
---|
| 142 | value = [t for t in self.ttool.listContentTypes() if t in value] |
---|
| 143 | self.context._updateProperty('content_types_with_seoproperties', value) |
---|
| 144 | |
---|
[1902] | 145 | def getCustomScript(self): |
---|
| 146 | description = getattr(self.context, 'custom_script', u'') |
---|
| 147 | return safe_unicode(description) |
---|
[1788] | 148 | |
---|
[1902] | 149 | def setCustomScript(self, value): |
---|
| 150 | if value is not None: |
---|
| 151 | self.context.custom_script = value.encode(self.encoding) |
---|
| 152 | else: |
---|
| 153 | self.context.custom_script = '' |
---|
| 154 | |
---|
[1788] | 155 | exposeDCMetaTags = property(getExposeDC, setExposeDC) |
---|
[3134] | 156 | seo_default_custom_metatag = ISEOConfigletSchema['default_custom_metatags'] |
---|
| 157 | default_custom_metatags = ProxyFieldProperty(seo_default_custom_metatag) |
---|
[1823] | 158 | metatags_order = ProxyFieldProperty(ISEOConfigletSchema['metatags_order']) |
---|
[1788] | 159 | types_seo_enabled = property(getTypesSEOEnabled, setTypesSEOEnabled) |
---|
[1902] | 160 | custom_script = property(getCustomScript, setCustomScript) |
---|
| 161 | fields = ProxyFieldProperty(ISEOConfigletSchema['fields']) |
---|
| 162 | stop_words = ProxyFieldProperty(ISEOConfigletSchema['stop_words']) |
---|
[3134] | 163 | seo_external_keywords_test = ISEOConfigletSchema['external_keywords_test'] |
---|
| 164 | external_keywords_test = ProxyFieldProperty(seo_external_keywords_test) |
---|
[1788] | 165 | |
---|
[1883] | 166 | |
---|
[1902] | 167 | class Text2ListWidget(TextAreaWidget): |
---|
[1788] | 168 | height = 5 |
---|
[3134] | 169 | splitter = re.compile(u'\\r?\\n', re.S | re.U) |
---|
[1788] | 170 | |
---|
[1847] | 171 | def _toFieldValue(self, input): |
---|
| 172 | if input == self._missing: |
---|
| 173 | return self.context._type() |
---|
| 174 | else: |
---|
| 175 | return self.context._type(filter(None, self.splitter.split(input))) |
---|
[1788] | 176 | |
---|
[1822] | 177 | def _toFormValue(self, value): |
---|
[3134] | 178 | if value == self.context.missing_value or \ |
---|
[3547] | 179 | value == self.context._type(): |
---|
[1847] | 180 | return self._missing |
---|
| 181 | else: |
---|
| 182 | return u'\r\n'.join(list(value)) |
---|
[1822] | 183 | |
---|
| 184 | |
---|
[1904] | 185 | # Fieldset configurations |
---|
| 186 | baseset = FormFieldsets(ISEOConfigletBaseSchema) |
---|
| 187 | baseset.id = 'seobase' |
---|
| 188 | baseset.label = _(u'label_seobase', default=u'Base') |
---|
| 189 | |
---|
| 190 | advancedset = FormFieldsets(ISEOConfigletAdvancedSchema) |
---|
| 191 | advancedset.id = 'seoadvanced' |
---|
| 192 | advancedset.label = _(u'label_seoadvanced', default=u'Advanced') |
---|
| 193 | |
---|
[3134] | 194 | |
---|
[1788] | 195 | class SEOConfiglet(ControlPanelForm): |
---|
| 196 | |
---|
[1904] | 197 | form_fields = FormFieldsets(baseset, advancedset) |
---|
[3134] | 198 | type_seo_enabled = MultiCheckBoxThreeColumnWidget |
---|
[1904] | 199 | |
---|
[1902] | 200 | form_fields['default_custom_metatags'].custom_widget = Text2ListWidget |
---|
| 201 | form_fields['metatags_order'].custom_widget = Text2ListWidget |
---|
[3134] | 202 | form_fields['types_seo_enabled'].custom_widget = type_seo_enabled |
---|
| 203 | form_fields['types_seo_enabled'].custom_widget.cssClass = 'label' |
---|
[1902] | 204 | form_fields['fields'].custom_widget = Text2ListWidget |
---|
| 205 | form_fields['stop_words'].custom_widget = Text2ListWidget |
---|
[1788] | 206 | |
---|
| 207 | label = _("Search Engine Optimizer configuration") |
---|
| 208 | description = _("seo_configlet_description", default="You can select what " |
---|
| 209 | "content types are qSEOptimizer-enabled, and control if " |
---|
[3134] | 210 | "Dublin Core metatags are exposed in the header of content" |
---|
| 211 | " pages.") |
---|
[1788] | 212 | form_name = _("") |
---|