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
def get_display_options(): display_options = { 'headline': _(u'Headline'), 'abstract': _(u'Abstract'), 'text': _(u'Formatted Text'), 'link': _(u"Link") } return display_options
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)
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
def content_widget_types_details(): categories = { "general": _(u"General"), "image": _(u"Image"), "gallery": _(u"Gallery"), "summary": _(u"Summary"), "more": _(u"More") } return categories
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, )
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, )
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
class IAde25WidgetTextBlock(Interface): """ Content widget formatted text """ text = schema.Text( title=_("Text Content"), required=False )
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)
class IAde25WidgetTextFormatted(Interface): """ Content widget formatted text """ text = RichText( title=_(u"Text"), required=False )
class IAde25WidgetTextHtml(Interface): """ Content widget html text """ text = schema.Text( title=_("HTML Content"), required=False )
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, )
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)
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)
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
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)
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'], })
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' )
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
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
def processSetup(self): IStatusMessage(self.request).addStatusMessage(_(u'Setup initialized.'), 'info')
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")
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)
class IAde25WidgetImageUpload(Interface): """ Image field for uploading images stored in annotation """ image = named_file.NamedBlobImage(title=_(u"Cover Image"), required=False)
def generate_simple_term(widget, widget_term): term = SimpleTerm(value=widget, token=b2a_qp(widget.encode('utf-8')), title=_(widget_term)) return term
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")
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' )
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)
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)