コード例 #1
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def get_display_options():
     display_options = {
         'width-50': _(u'2 card per row'),
         'width-33': _(u'3 cards per row (default)'),
         'width-25': _(u'4 cards per row')
     }
     return display_options
コード例 #2
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def get_display_options():
     display_options = {
         'headline': _(u'Headline'),
         'abstract': _(u'Abstract'),
         'text': _(u'Formatted Text'),
         'link': _(u"Link")
     }
     return display_options
コード例 #3
0
ファイル: widgetitem.py プロジェクト: ade25/ade25.widgets
class IContentWidgetItemSettings(model.Schema):

    is_public = schema.Bool(
        title=_(u"Public"),
        description=_(u"Select if this widget should be visible in the view "
                      u"or remain in a draft version."),
        default=True,
        required=False)
コード例 #4
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def get_display_options():
     display_options = {
         'content-widgets-page-header': _(u'Content Widgets Page Header'),
         'content-widgets-page-main':
         _(u'Content Widgets Main Content Area'),
         'content-widgets-page-footer': _(u'Content Widgets Page Footer')
     }
     return display_options
コード例 #5
0
ファイル: utils.py プロジェクト: ade25/ade25.widgets
def content_widget_types_details():
    categories = {
        "general": _(u"General"),
        "image": _(u"Image"),
        "gallery": _(u"Gallery"),
        "summary": _(u"Summary"),
        "more": _(u"More")
    }
    return categories
コード例 #6
0
ファイル: controlpanel.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetsControlPanel(Interface):

    content_widgets_header = schema.List(
        title=_(u"Content Widgets Page Header"),
        description=_(u"Select Content Widgets that should be available "
                      u"for the page header section."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.AvailableContentWidgets'),
        required=False)

    content_widgets_main = schema.List(
        title=_(u"Content Widgets Main Content Area"),
        description=_(u"Select Content Widgets that should be available "
                      u"for the main page content area."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.AvailableContentWidgets'),
        required=False)

    content_widgets_footer = schema.List(
        title=_(u"Content Widgets Page Footer"),
        description=_(u"Select Content Widgets that should be available "
                      u"for the page header section."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.AvailableContentWidgets'),
        required=False)

    widget_settings = schema.Text(
        title=_(u"Widget Settings JSON"),
        description=_(u"Widget configuration registry storing a string "
                      u"representation of a valid JSON settings array"),
        required=False,
    )
コード例 #7
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetPageHeader(Interface):
    """ Content Widget to display page header """

    headline = schema.TextLine(
        title=u"Page Headline",
        description=_(u"Please enter the main page headline."),
        required=False,
    )

    abstract = schema.Text(
        title=u"Page Abstract",
        description=_(u"Use the abstract to provide a short description of ."
                      u"the page content."),
        required=False,
    )
コード例 #8
0
 def widget_content(self):
     widget_content = self.widget_stored_data()
     data = {
         "title":
         self.get_widget_content("title", None),
         "batch":
         self.get_widget_content("display_batch", False),
         "images":
         self.get_widget_content("display_images", True),
         "abstract":
         self.get_widget_content("display_abstract", True),
         "limit":
         self.get_widget_content("display_limit", None),
         "read_more":
         self.get_widget_content("display_read_more", True),
         "read_more_value":
         self.get_widget_content("read_more_text", _(u"Read more")),
         "read_more_layout":
         self.get_widget_content("read_more_layout", "width-33"),
         "layout":
         self.get_widget_content("display_reverse", False),
         "items":
         self.content_items(),
     }
     return data
コード例 #9
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetTextBlock(Interface):
    """ Content widget formatted text """

    text = schema.Text(
        title=_("Text Content"),
        required=False
    )
コード例 #10
0
class IContentWidgetCollectionSettings(model.Schema):

    is_public = schema.Bool(title=_(
        u"This widget is public and will be displayed in the page "
        u"view"),
                            default=True,
                            required=False)
コード例 #11
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetTextFormatted(Interface):
    """ Content widget formatted text """

    text = RichText(
        title=_(u"Text"),
        required=False
    )
コード例 #12
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetTextHtml(Interface):
    """ Content widget html text """

    text = schema.Text(
        title=_("HTML Content"),
        required=False
    )
コード例 #13
0
class IAde25WidgetPartialContentMain(Interface):
    """ Content widget main elements """

    headline = schema.TextLine(title=_(u"Headline"), required=False)

    abstract = schema.Text(title=_(u"Abstract"), required=False)

    text = RichText(title=_(u"Text"), required=False)

    form.widget(link=LinkFieldWidget)
    link = schema.TextLine(
        title=_(u"Link"),
        description=_(u"Optional internal or external link that will be "
                      u"used as redirection target when section is accessed."
                      u"Logged in users will see the target link instead."),
        required=False,
    )
コード例 #14
0
 def render(self):
     msg = _(u"Panel configuration data not available")
     data = {"success": False, "message": msg}
     settings = self.handle_widget_collection_reorder()
     if settings:
         data = settings
     self.request.response.setHeader('Content-Type',
                                     'application/json; charset=utf-8')
     return json.dumps(data)
コード例 #15
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetImageBase(Interface):
    """ Base image metadata fields """

    image = named_file.NamedBlobImage(title=_(u"Cover Image"), required=False)

    image_related = RelationChoice(
        title=_(u"Cover Image Select"),
        description=_(u"Select existing image in the asset repository"),
        required=False,
        default=None,
        vocabulary='ade25.widgets.vocabularies.ContentWidgetAssets')

    directives.widget('image_related',
                      RelatedItemsFieldWidget,
                      pattern_options={
                          'recentlyUsed': False,
                          'basePath': asset_repository_path(),
                          'path': asset_repository_path(),
                          'mode': 'auto',
                          'favorites': [],
                          'folderTypes': [
                              'Folder',
                              'ade25.widgets.assetsfolder',
                          ],
                          'selectableTypes': ['Image'],
                      })

    image_alt = schema.TextLine(title=_(u"Image Alt Text"), required=False)

    image_title = schema.TextLine(title=_(u"Image Title Text"), required=False)

    image_caption = schema.TextLine(title=_(u"Image Copyright Information"),
                                    required=False)
コード例 #16
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def get_display_options():
     display_options = {
         "link": _(u'Plain Link'),
         "link-icon": _(u'Link with icon after the link text'),
         "link-icon-prefix": _(u'Link with icon before the link text'),
         "icon": _(u'Icon only'),
         "button": _(u'Button'),
         "button-icon": _(u'Button with icon after the link text'),
         "button-icon-prefix": _(u'Button with icon before the link text'),
     }
     return display_options
コード例 #17
0
ファイル: controlpanel.py プロジェクト: ade25/ade25.widgets
 def render(self):
     msg = _(u"JSON file could not be generated")
     data = {'success': False, 'message': msg}
     configuration = self._widget_configuration()
     if configuration:
         data = configuration
     widgets = {
         "items": data,
         "timestamp": six.text_type(int(time.time())),
         "updated": datetime.datetime.now().isoformat()
     }
     self.request.response.setHeader('Content-Type',
                                     'application/json; charset=utf-8')
     return json.dumps(widgets)
コード例 #18
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetImageRelated(Interface):
    """ Image field that allows selection from asset repository """

    image_related = RelationChoice(
        title=_(u"Cover Image Select"),
        description=_(u"Select existing image in the asset repository"),
        required=False,
        default=None,
        vocabulary='ade25.widgets.vocabularies.ContentWidgetAssets')

    directives.widget('image_related',
                      RelatedItemsFieldWidget,
                      pattern_options={
                          'recentlyUsed': False,
                          'basePath': asset_repository_path(),
                          'path': asset_repository_path(),
                          'mode': 'auto',
                          'favorites': [],
                          'folderTypes': [
                              'Folder',
                              'ade25.widgets.assetsfolder',
                          ],
                          'selectableTypes': ['Image'],
                      })
コード例 #19
0
class IAde25WidgetPartialReadMore(Interface):
    """ Content widget listing snippets """
    display_read_more = schema.Bool(title=_(u"Display Read More Link"),
                                    default=True,
                                    required=False)
    read_more_text = schema.TextLine(
        title=_(u"Read More Text"),
        description=_(u"Enter displayed text for read more element."),
        default=_(u'Read more'),
        required=False)
    form.widget('read_more_layout', klass='js-choices-selector')
    read_more_layout = schema.Choice(
        title=_(u"Read More Layout"),
        description=_(u"Select how the card footer link should be displayed."),
        required=False,
        default='link',
        vocabulary='ade25.widgets.vocabularies.ContentWidgetReadMeLayoutOptions'
    )
コード例 #20
0
    def handle_widget_collection_reorder(self):
        """ Update widget node ordering

        Should also update the stored session details to allow for smooth
        panel page editor workflow
        """
        # TODO: implement order storage
        context = aq_inner(self.context)
        payload = self.payload
        editor = self.panel_editor()
        editor_data = editor[context.UID()]
        storage = IContentWidgets(context)
        record = storage.read_widget(editor_data["widget_id"])
        item_order = record["item_order"]
        if item_order:
            updated_order = payload['node-order']
            if not isinstance(updated_order, list):
                updated_order = list()
            record["item_order"] = updated_order
            storage.store_widget(editor_data['widget_id'], record,
                                 self.request)
        msg = _(u"Collection node order updated")
        data = {"success": True, "message": msg}
        return data
コード例 #21
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def get_display_options():
     display_options = {
         'u-display--none': _(u'Hidden'),
         'u-display--block|u-display-sm--none': _(u'Hidden from 576px'),
         'u-display--block|u-display-md--none': _(u'Hidden from 768px'),
         'u-display--block|u-display-lg--none': _(u'Hidden from 992px'),
         'u-display--block|u-display-xl--none': _(u'Hidden from 1200px'),
         'u-display--block|u-display-xxl--none': _(u'Hidden from 1400px'),
         'u-display--block|u-display-xxxl--none': _(u'Hidden from 1600px'),
         'u-display--block': _(u'Visible'),
         'u-display--none|u-display-sm--block': _(u'Visible from 576px'),
         'u-display--none|u-display-md--block': _(u'Visible from 768px'),
         'u-display--none|u-display-lg--block': _(u'Visible from 992px'),
         'u-display--none|u-display-xl--block': _(u'Visible from 1200px'),
         'u-display--none|u-display-xxl--block': _(u'Visible from 1400px'),
         'u-display--none|u-display-xxxl--block': _(u'Visible from 1600px'),
     }
     return display_options
コード例 #22
0
ファイル: controlpanel.py プロジェクト: ade25/ade25.widgets
 def processSetup(self):
     IStatusMessage(self.request).addStatusMessage(_(u'Setup initialized.'),
                                                   'info')
コード例 #23
0
class ContentWidgetCollectionForm(AutoExtensibleForm, form.Form):
    """This search form enables you to find users by specifying one or more
    search criteria.
    """

    schema = IContentWidgetCollectionSettings
    ignoreContext = False
    css_class = 'o-form o-form--widget'

    label = _(u'Content Widget')
    enableCSRFProtection = True
    formErrorsMessage = _(u'There were errors.')

    submitted = False

    @property
    def panel_editor(self):
        tool = getUtility(IPanelEditor)
        return tool.get()

    @property
    def additionalSchemata(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        try:
            schema_interface = resolve(
                editor_data['widget_settings']['schema'])
            schemata = (schema_interface, )
            return schemata
        except ValueError:
            return ()

    def getContent(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        storage = IContentWidgets(context)
        stored_widget_data = storage.read_widget(editor_data['widget_id'])
        widget_content = dict()
        if stored_widget_data:
            schemata = self.additionalSchemata + (self.schema, )
            for widget_schema in schemata:
                fields = getFieldsInOrder(widget_schema)
                for key, value in fields:
                    if key == "image":
                        image_uid = stored_widget_data.get("image", None)
                        if image_uid:
                            asset = api.content.get(UID=image_uid)
                            widget_content[key] = getattr(asset, key, value)
                    else:
                        widget_content[key] = stored_widget_data.get(
                            key, value.title)
        return widget_content

    def settings(self):
        return self.params

    @property
    def edit_mode(self):
        if self.settings()['widget_mode'] == 'edit':
            return True
        return False

    @property
    def record(self):
        return self.settings()['widget_data']

    def widget_uid(self):
        try:
            widget_id = self.record['id']
        except (KeyError, TypeError):
            widget_id = str(uuid_tool.uuid4())
        return widget_id

    def rendered_widget(self):
        context = aq_inner(self.context)
        if self.settings()['widget_type']:
            view_name = '@@content-widget-{0}'.format(
                self.settings()['widget_type'])
            rendered_widget = context.restrictedTraverse(view_name)(
                widget_mode=self.settings()['widget_mode'],
                widget_data=self.settings()['widget_data'])
        else:
            view_name = '@@content-widget-base'
            rendered_widget = context.restrictedTraverse(view_name)()
        return rendered_widget

    @property
    def action(self):
        """ Rewrite HTTP POST action.
#        If the form is rendered embedded on the others pages we
        make sure the form is posted through the same view always,
        instead of making HTTP POST to the page where the form was rendered.
        """
        return self.context.absolute_url(
        ) + "/@@content-widget-collection-form"

    @staticmethod
    def prettify_key(entry_key):
        try:
            clean_key = entry_key.split(".")[-1]
            return clean_key
        except IndexError:
            return entry_key

    @staticmethod
    def generate_hash_from_filename(file_name):
        return hashlib.sha1(str(uuid.uuid4()) + file_name).hexdigest()

    def _process_image_asset(self, field_key, field_value):
        portal = api.portal.get()
        asset_repository = portal['asset-repository']
        widget_file = api.content.create(container=asset_repository,
                                         type="Image",
                                         title="Widget Asset {0}".format(
                                             self.generate_hash_from_filename(
                                                 field_value.filename), ),
                                         image=field_value)
        modified(widget_file)
        widget_file.reindexObject(idxs='modified')
        return widget_file.UID()

    def applyChanges(self, data):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        storage = IContentWidgets(context)
        record = storage.read_widget(editor_data["widget_id"])
        if record:
            item_order = record.get("item_order")
            if item_order:
                widget_content = record
        else:
            widget_content = editor_data["widget_content"]
        if not widget_content:
            widget_content = dict()
        for key, value in data.items():
            entry_key = self.prettify_key(key)
            if INamedBlobImage.providedBy(value):
                image_uid = self._process_image_asset(entry_key, value)
                widget_content[entry_key] = image_uid
            elif IRichTextValue.providedBy(value):
                # Handle rich text value that is not serializable
                text_value = value.output
                widget_content[entry_key] = text_value
            else:
                widget_content[entry_key] = value
        storage.store_widget(editor_data['widget_id'], record, self.request)
        next_url = '{url}/@@panel-edit?section={section}&panel={panel}'.format(
            url=context.absolute_url(),
            section=editor_data["content_section"],
            panel=editor_data["content_section_panel"])
        return self.request.response.redirect(next_url)

    @button.buttonAndHandler(_(u'cancel'), name='cancel')
    def handleCancel(self, action):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        next_url = '{url}/@@panel-edit?section={section}&panel={panel}'.format(
            url=context.absolute_url(),
            section=editor_data["content_section"],
            panel=editor_data["content_section_panel"])
        return self.request.response.redirect(addTokenToUrl(next_url))

    @button.buttonAndHandler(_(u'Update'), name='update')
    def handleApply(self, action):
        request = self.request
        data, errors = self.extractData()

        if errors:
            self.status = self.formErrorsMessage
            return

        if request.get('form.buttons.update', None):
            self.submitted = True
            self.applyChanges(data)
        self.status = "Thank you very much!"

    def updateActions(self):
        super(ContentWidgetCollectionForm, self).updateActions()
        self.actions["cancel"].addClass("c-button--default")
        self.actions["update"].addClass("c-button--primary")
コード例 #24
0
ファイル: controlpanel.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetsControlPanelWidgets(Interface):

    read_more_icon = schema.TextLine(
        title=_(u"Read More Icon Name"),
        description=_(
            u"Please enter icon to be used in read more links when "
            u"a layout with icon is selected. Note: the icon needs to "
            u"exist in the themes icon sprite for this to work."),
        default=u'chevron',
        required=False)

    form_directives.widget('listing_scale', klass='js-choices-selector')
    listing_scale = schema.Choice(
        title=_(u"Content Listing: Image Scale"),
        vocabulary='ade25.widgets.vocabularies.AvailableImageScales',
        default=u'ratio-4:3',
        required=False)
    listing_hidden_fields = schema.List(
        title=_(u"Content Listing: Hidden Elements"),
        description=_(u"Please select which elements should be hidden in the "
                      u"widget add and edit forms."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.ContentWidgetSchemaOptions'
        ),
        default=[
            'text',
            'link',
        ],
        required=False)

    form_directives.widget('listing_cards_scale', klass='js-choices-selector')
    listing_cards_scale = schema.Choice(
        title=_(u"Content Listing Cards: Image Scale"),
        vocabulary='ade25.widgets.vocabularies.AvailableImageScales',
        default=u'ratio-4:3',
        required=False)
    listing_cards_hidden_fields = schema.List(
        title=_(u"Content Listing Cards: Hidden Elements"),
        description=_(
            u"Please select which elements should not be available in the "
            u"widget add and edit forms."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.ContentWidgetSchemaOptions'
        ),
        default=[
            'text',
            'link',
        ],
        required=False)

    form_directives.widget('image_cover_scale', klass='js-choices-selector')
    image_cover_scale = schema.Choice(
        title=_(u"Cover Image: Image Scale"),
        vocabulary='ade25.widgets.vocabularies.AvailableImageScales',
        default=u'ratio-4:3',
        required=False)
    form_directives.widget('image_poster_scale', klass='js-choices-selector')
    image_poster_scale = schema.Choice(
        title=_(u"Poster Image: Image Scale"),
        vocabulary='ade25.widgets.vocabularies.AvailableImageScales',
        default=u'ratio-16:9',
        required=False)
    image_poster_hidden_fields = schema.List(
        title=_(u"Poster Image: Hidden Elements"),
        description=_(
            u"Please select which elements should be available in the "
            u"widget add and edit forms."),
        value_type=schema.Choice(
            vocabulary='ade25.widgets.vocabularies.ContentWidgetSchemaOptions'
        ),
        default=[
            'text',
            'link',
        ],
        required=False)
コード例 #25
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetImageUpload(Interface):
    """ Image field for uploading images stored in annotation """

    image = named_file.NamedBlobImage(title=_(u"Cover Image"), required=False)
コード例 #26
0
ファイル: vocabulary.py プロジェクト: ade25/ade25.widgets
 def generate_simple_term(widget, widget_term):
     term = SimpleTerm(value=widget,
                       token=b2a_qp(widget.encode('utf-8')),
                       title=_(widget_term))
     return term
コード例 #27
0
ファイル: widgetitem.py プロジェクト: ade25/ade25.widgets
class ContentWidgetItemForm(AutoExtensibleForm, form.Form):
    """This search form enables you to find users by specifying one or more
    search criteria.
    """

    schema = IContentWidgetItemSettings
    ignoreContext = False
    css_class = 'o-form o-form--widget'

    label = _(u'Content Widget Item')
    enableCSRFProtection = True
    formErrorsMessage = _(u'There were errors.')

    submitted = False

    @property
    def panel_editor(self):
        tool = getUtility(IPanelEditor)
        return tool.get()

    @property
    def additionalSchemata(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        try:
            schema_interface = resolve(
                editor_data['widget_settings']['node']['schema'])
            schemata = (schema_interface, )
            return schemata
        except ValueError:
            return ()

    def getContent(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        widget_node_id = editor_data["widget_node"]
        storage = IContentWidgets(context)
        stored_widget_data = storage.read_widget(editor_data['widget_id'])
        widget_content = dict()
        if stored_widget_data:
            widget_node = stored_widget_data["items"].get(widget_node_id, None)
            if widget_node:
                schemata = self.additionalSchemata + (self.schema, )
                for widget_schema in schemata:
                    fields = getFieldsInOrder(widget_schema)
                    for key, value in fields:
                        if key == "image":
                            image_uid = widget_node.get("image", None)
                            if image_uid:
                                asset = api.content.get(UID=image_uid)
                                widget_content[key] = getattr(
                                    asset, key, value)
                        elif key.endswith('_related'):
                            # Make sure we do not fall over old widget attribute values
                            widget_content[key] = RelationValue(None)
                        else:
                            widget_content[key] = widget_node.get(key, None)
        return widget_content

    def settings(self):
        return self.params

    @property
    def edit_mode(self):
        if self.settings()['widget_mode'] == 'edit':
            return True
        return False

    @property
    def record(self):
        return self.settings()['widget_data']

    def widget_uid(self):
        try:
            widget_id = self.record['id']
        except (KeyError, TypeError):
            widget_id = str(uuid_tool.uuid4())
        return widget_id

    @property
    def action(self):
        """ Rewrite HTTP POST action.
#        If the form is rendered embedded on the others pages we
        make sure the form is posted through the same view always,
        instead of making HTTP POST to the page where the form was rendered.
        """
        return self.context.absolute_url() + "/@@content-widget-item-form"

    @staticmethod
    def prettify_key(entry_key):
        try:
            clean_key = entry_key.split(".")[-1]
            return clean_key
        except IndexError:
            return entry_key

    @staticmethod
    def generate_hash_from_filename(file_name):
        return hashlib.sha1(
            (str(uuid.uuid4()) + file_name).encode("utf-8")).hexdigest()

    def _process_image_asset(self, field_key, field_value):
        portal = api.portal.get()
        asset_repository = portal['asset-repository']
        widget_file = api.content.create(container=asset_repository,
                                         type="Image",
                                         id="widget-asset-{0}".format(
                                             self.generate_hash_from_filename(
                                                 field_value.filename), ),
                                         title=field_value.filename,
                                         image=field_value)
        modified(widget_file)
        widget_file.reindexObject(idxs='modified')
        return widget_file.UID()

    @staticmethod
    def _process_relations(target_object):
        if target_object:
            int_ids = component.getUtility(IIntIds)
            return RelationValue(int_ids.getId(target_object))
        return RelationValue(None)

    def applyChanges(self, data):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        storage = IContentWidgets(context)
        record = storage.read_widget(editor_data["widget_id"])
        item_order = record["item_order"]
        if item_order:
            widget_content = record["items"]
        else:
            widget_content = editor_data["widget_content"]
        if not widget_content:
            widget_content = dict()
        widget_item = dict()
        widget_item_node = editor_data["widget_node"]
        for key, value in data.items():
            entry_key = self.prettify_key(key)
            # Additional schemata are posted as 'ISchemaInterface.field_name'
            # and need to be resolved to their original key
            field_key = key.split('.')[-1]
            if INamedBlobImage.providedBy(value):
                image_uid = self._process_image_asset(entry_key, value)
                widget_item[entry_key] = image_uid
            elif IRichTextValue.providedBy(value):
                # Handle rich text value that is not serializable
                text_value = value
                widget_item[entry_key] = text_value
            else:
                if value is NOT_CHANGED:
                    # Keep existing value for fields signaling as not updated
                    value = widget_content[widget_item_node][field_key]
                    # continue
                if entry_key.endswith('_related'):
                    # Handle asset relation choice
                    widget_item[entry_key] = self._process_relations(value)
                    source_entry_key = key.replace('_related', '')
                    source_value = data.get(source_entry_key, None)
                    if not source_value:
                        # Actual image uploads take preference. Only if no image has
                        # been uploaded write relation choice to image field.
                        widget_item[source_entry_key] = value.UID()
                widget_item[entry_key] = value
        if widget_item_node in item_order:
            widget_content[widget_item_node] = widget_item
        else:
            widget_content.update({widget_item_node: widget_item})
            item_order.append(widget_item_node)
            record["item_order"] = item_order
            record["items"] = widget_content
        storage.store_widget(editor_data['widget_id'], record, self.request)
        next_url = '{url}/@@panel-edit?section={section}&panel={panel}'.format(
            url=context.absolute_url(),
            section=editor_data["content_section"],
            panel=editor_data["content_section_panel"])
        return self.request.response.redirect(next_url)

    @button.buttonAndHandler(_(u'cancel'), name='cancel')
    def handleCancel(self, action):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        next_url = '{url}/@@panel-edit?section={section}&panel={panel}'.format(
            url=context.absolute_url(),
            section=editor_data["content_section"],
            panel=editor_data["content_section_panel"])
        return self.request.response.redirect(addTokenToUrl(next_url))

    @button.buttonAndHandler(_(u'Update'), name='update')
    def handleApply(self, action):
        request = self.request
        data, errors = self.extractData()

        if errors:
            self.status = self.formErrorsMessage
            return

        if request.get('form.buttons.update', None):
            self.submitted = True
            self.applyChanges(data)
        self.status = "Thank you very much!"

    def updateActions(self):
        super(ContentWidgetItemForm, self).updateActions()
        self.actions["cancel"].addClass(
            "c-button--default c-button--cancel c-button--panel")
        self.actions["update"].addClass("c-button--primary")
コード例 #28
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetListingCards(Interface):
    """ Content widget listing cards """

    title = schema.TextLine(
        title=_(u"Headline"),
        description=_(
            u"Enter optional headline to display above the listing."),
        required=False)
    display_limit = schema.TextLine(
        title=_(u"Display Limit"),
        description=_(u"Select maximum number of snippets to display. Leave "
                      u"empty when the widget should list all content items."),
        required=False,
        default=safe_unicode('20'))
    display_batch = schema.Bool(
        title=_(u"Display Pagination"),
        description=_(
            u"When selected the listing will show the contents divided "
            u"into pages and display batch navigation. The configured "
            u"display limit will refer to the maximum number of items"
            u" per page and the widget will always show all content."),
        default=False,
        required=False)
    display_images = schema.Bool(
        title=_(u"Cover Images"),
        description=_(u"Display lead images in content snippets."),
        default=True,
        required=False)
    display_abstract = schema.Bool(
        title=_(u"Display Abstract"),
        description=_(u"Select if the preview cards should also display the "
                      u"content item summary text next to the title."),
        default=True,
        required=False)
    form.widget('display_columns', klass='js-choices-selector')
    display_columns = schema.Choice(
        title=_(u"Listing Layout"),
        description=_(u"Select the number of cards that should be displayed "
                      u"per column if the screen size allows for horizontal "
                      u"alignment."),
        required=False,
        default='width-100',
        vocabulary='ade25.widgets.vocabularies.ContentWidgetLayoutOptions')
    display_read_more = schema.Bool(title=_(u"Display Read More Link"),
                                    default=True,
                                    required=False)
    read_more_text = schema.TextLine(
        title=_(u"Read More Text"),
        description=_(u"Enter displayed text for read more element."),
        default=_(u'Read more'),
        required=False)
    form.widget('read_more_layout', klass='js-choices-selector')
    read_more_layout = schema.Choice(
        title=_(u"Read More Layout"),
        description=_(u"Select how the card footer link should be displayed."),
        required=False,
        default='link',
        vocabulary='ade25.widgets.vocabularies.ContentWidgetReadMeLayoutOptions'
    )
コード例 #29
0
ファイル: interfaces.py プロジェクト: ade25/ade25.widgets
class IAde25WidgetImagePoster(Interface):
    """ Content widget image poster """

    image = named_file.NamedBlobImage(title=_(u"Poster Image"), required=True)
    image_caption = schema.TextLine(
        title=_(u"Poster Image Copyright Information"), required=False)
コード例 #30
0
ファイル: widget.py プロジェクト: ade25/ade25.widgets
class ContentWidgetForm(AutoExtensibleForm, form.Form):
    """This search form enables you to find users by specifying one or more
    search criteria.
    """

    schema = IContentWidgetSettings
    ignoreContext = False
    css_class = 'o-form o-form--widget'

    label = _(u'Content Widget')
    enableCSRFProtection = True
    formErrorsMessage = _(u'There were errors.')

    submitted = False

    @property
    def panel_editor(self):
        tool = getUtility(IPanelEditor)
        return tool.get()

    @property
    def additionalSchemata(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        try:
            schema_interface = resolve(
                editor_data['widget_settings']['schema'])
            schemata = (schema_interface, )
            additional_interfaces = editor_data['widget_settings'].get(
                'schemata', [])
            for additional_interface in additional_interfaces:
                schemata += (resolve(additional_interface), )
            return schemata
        except ValueError:
            return ()

    def getContent(self):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        storage = IContentWidgets(context)
        stored_widget_data = storage.read_widget(editor_data['widget_id'])
        widget_content = dict()
        if stored_widget_data:
            schemata = self.additionalSchemata + (self.schema, )
            for widget_schema in schemata:
                fields = getFieldsInOrder(widget_schema)
                for key, value in fields:
                    if key == "image":
                        image_uid = stored_widget_data.get("image", None)
                        if image_uid:
                            asset = api.content.get(UID=image_uid)
                            widget_content[key] = getattr(asset, key, value)
                    elif key.endswith('_related'):
                        # Make sure we do not fall over old widget attribute values
                        widget_content[key] = RelationValue(None)
                    else:
                        widget_content[key] = stored_widget_data.get(key, None)
        return widget_content

    def settings(self):
        return self.params

    @property
    def edit_mode(self):
        if self.settings()['widget_mode'] == 'edit':
            return True
        return False

    @property
    def record(self):
        return self.settings()['widget_data']

    def widget_uid(self):
        try:
            widget_id = self.record['id']
        except (KeyError, TypeError):
            widget_id = str(uuid_tool.uuid4())
        return widget_id

    def rendered_widget(self):
        context = aq_inner(self.context)
        if self.settings()['widget_type']:
            view_name = '@@content-widget-{0}'.format(
                self.settings()['widget_type'])
            try:
                rendered_widget = context.restrictedTraverse(view_name)(
                    widget_mode=self.settings()['widget_mode'],
                    widget_data=self.settings()['widget_data'])
            except:
                view_name = '@@content-widget-error'
                rendered_widget = context.restrictedTraverse(view_name)()
        else:
            view_name = '@@content-widget-base'
            rendered_widget = context.restrictedTraverse(view_name)()
        return rendered_widget

    @property
    def action(self):
        """ Rewrite HTTP POST action.
#        If the form is rendered embedded on the others pages we
        make sure the form is posted through the same view always,
        instead of making HTTP POST to the page where the form was rendered.
        """
        return self.context.absolute_url() + "/@@content-widget-form"

    @staticmethod
    def prettify_key(entry_key):
        try:
            clean_key = entry_key.split(".")[-1]
            return clean_key
        except IndexError:
            return entry_key

    @staticmethod
    def generate_hash_from_filename(file_name):
        return hashlib.sha1(
            (str(uuid.uuid4()) + file_name).encode("utf-8")).hexdigest()

    def _process_image_asset(self, field_key, field_value):
        portal = api.portal.get()
        asset_repository = portal['asset-repository']
        widget_file = api.content.create(container=asset_repository,
                                         type="Image",
                                         id="widget-asset-{0}".format(
                                             self.generate_hash_from_filename(
                                                 field_value.filename), ),
                                         title=field_value.filename,
                                         image=field_value)
        modified(widget_file)
        widget_file.reindexObject(idxs='modified')
        return widget_file.UID()

    @staticmethod
    def _process_relations(target_object):
        if target_object:
            int_ids = component.getUtility(IIntIds)
            return RelationValue(int_ids.getId(target_object))
        return RelationValue(None)

    def applyChanges(self, data):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        storage = IContentWidgets(context)
        widget_content = dict()
        for key, value in data.items():
            entry_key = self.prettify_key(key)
            # Additional schemata are posted as 'ISchemaInterface.field_name'
            # and need to be resolved to their original key
            field_key = key.split('.')[-1]
            # Handle image like content
            if INamedBlobImage.providedBy(value):
                image_uid = self._process_image_asset(entry_key, value)
                widget_content[entry_key] = image_uid
            else:
                if value is NOT_CHANGED:
                    # Keep existing value for fields signaling as not updated
                    stored_content = editor_data.get('widget_content')
                    if widget_content:
                        value = stored_content.get(field_key, None)
                if entry_key.endswith('_related'):
                    # Handle asset relation choice
                    widget_content[entry_key] = self._process_relations(value)
                    source_entry_key = key.replace('_related', '')
                    source_value = data.get(source_entry_key, None)
                    if not source_value:
                        # Actual image uploads take preference. Only if no image has
                        # been uploaded write relation choice to image field.
                        widget_content[source_entry_key] = value.UID()
                widget_content[entry_key] = value
        storage.store_widget(editor_data['widget_id'], widget_content,
                             self.request)
        next_url = '{0}/@@panel-page'.format(context.absolute_url())
        return self.request.response.redirect(next_url)

    @button.buttonAndHandler(_(u'cancel'), name='cancel')
    def handleCancel(self, action):
        context = aq_inner(self.context)
        next_url = '{0}/@@panel-page'.format(context.absolute_url())
        return self.request.response.redirect(next_url)

    @button.buttonAndHandler(_(u'Update'), name='update')
    def handleApply(self, action):
        request = self.request
        data, errors = self.extractData()

        if errors:
            self.status = self.formErrorsMessage
            return

        if request.get('form.buttons.update', None):
            self.submitted = True
            self.applyChanges(data)
        self.status = "Thank you very much!"

    def updateActions(self):
        super(ContentWidgetForm, self).updateActions()
        self.actions["cancel"].addClass("c-button--default")
        self.actions["update"].addClass("c-button--primary")

    def updateWidgets(self, prefix=None):
        context = aq_inner(self.context)
        editor_data = self.panel_editor[context.UID()]
        widget_type = editor_data['widget_settings']['widget']
        # Hidden fields can be configured via control panel
        try:
            content_widget_hidden_fields = api.portal.get_registry_record(
                'ade25.widgets.{0}_hidden_fields'.format(
                    widget_type.replace('-', '_')))
            for field in content_widget_hidden_fields:
                field_name = '{0}.{1}'.format(
                    editor_data['widget_settings']['schema'].split('.')[-1],
                    field)
                if field_name in self.widgets:
                    self.widgets[field_name].mode = HIDDEN_MODE
        except InvalidParameterError:
            # The content widget has no a registry setting
            pass
        super(ContentWidgetForm, self).updateWidgets(prefix=None)