Пример #1
0
class CoverSettingsEditForm(controlpanel.RegistryEditForm):
    schema = ICoverSettings
    label = _(u'Cover Settings')
    description = _(u'Settings for the scmos.cover package')

    # def updateFields(self):
    #     super(CoverSettingsEditForm, self).updateFields()
    #     self.fields['layouts'].widgetFactory = TextLinesFieldWidget

    def updateWidgets(self):
        super(CoverSettingsEditForm, self).updateWidgets()
        self.widgets['available_tiles'].style = u'min-width: 200px;'
        self.widgets['searchable_content_types'].style = u'min-width: 200px;'
        self.widgets['styles'].rows = 6
        self.widgets['styles'].style = u'max-width: 250px;'
Пример #2
0
class IContentBodyTile(IPersistentCoverTile):

    uuid = schema.TextLine(
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #3
0
class PFGTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/pfg.pt')

    is_editable = True
    is_configurable = True
    short_name = _(u'msg_short_name_pfg', default=u'FormGen')

    def body(self):
        body = ''
        uuid = self.data.get('uuid', None)
        try:
            obj = uuid and uuidToObject(uuid)
            if obj is not None:
                body = obj.restrictedTraverse('fg_embedded_view_p3')()
        except Unauthorized:
            body = ''
        return body

    def populate_with_object(self, obj):
        super(PFGTile, self).populate_with_object(obj)

        data = {
            'title': safe_unicode(obj.Title()),
            'description': safe_unicode(obj.Description()),
            'uuid': IUUID(obj),
        }

        data_mgr = ITileDataManager(self)
        data_mgr.set(data)

    def accepted_ct(self):
        """Return 'FormFolder' as the only content type accepted in the tile.
        """
        return ['FormFolder']
Пример #4
0
    def handleSave(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        # Traverse to a new tile in the context, with no data
        typeName = self.tileType.__name__
        tile = self.context.restrictedTraverse('@@{0}/{1}'.format(
            typeName, self.tileId))
        tile_conf_adapter = getMultiAdapter((self.context, self.request, tile),
                                            ITilesConfigurationScreen)
        tile_conf_adapter.set_configuration(data)

        # notify about modification
        notify(ObjectModifiedEvent(self.context))
        api.portal.show_message(_(u'Tile configuration saved.'),
                                self.request,
                                type='info')

        # Look up the URL - We need to redirect to the layout view, since
        # there's the only way from where a user would access the configuration
        contextURL = absoluteURL(tile.context, self.request)
        layoutURL = '{0}/layoutedit'.format(contextURL)
        self.request.response.redirect(layoutURL)
Пример #5
0
    def handleCancel(self, action):
        api.portal.show_message(_(u'Tile configuration cancelled.'),
                                self.request,
                                type='info')

        contextURL = absoluteURL(self.context, self.request)
        layoutURL = '{0}/layoutedit'.format(contextURL)
        self.request.response.redirect(layoutURL)
Пример #6
0
class IEmbedTile(IPersistentCoverTile):

    write_permission(embed='scmos.cover.EmbedCode')
    embed = schema.Text(
        title=_(u'Embedding code'),
        required=False,
    )

    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    description = schema.Text(
        title=_(u'Description'),
        required=False,
    )
Пример #7
0
class IRefresh(model.Schema):
    """Reload the current page after a certain amount of time."""

    model.fieldset('settings', fields=['enable_refresh', 'ttl'])

    enable_refresh = schema.Bool(
        title=_(u'Enable refresh'),
        description=_(u'Enable refresh of the current page.'),
        default=False,
    )

    ttl = schema.Int(
        title=_(u'Time to live'),
        description=_(
            u'Number of seconds after which to reload the current page.'),
        default=300,
    )
Пример #8
0
class IPFGTile(IPersistentCoverTile):

    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    description = schema.Text(
        title=_(u'Description'),
        required=False,
    )

    uuid = schema.TextLine(
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #9
0
class IBannerTile(IPersistentCoverTile):

    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    form.omitted(IDefaultConfigureForm, 'remote_url')
    remote_url = schema.URI(
        title=_(u'label_remote_url', default=u'URL'),
        description=_(u'help_remote_url', default=u'Use absolute links only.'),
        required=False,
    )

    image = field.NamedBlobImage(
        title=_(u'Image'),
        required=False,
    )

    form.omitted(IDefaultConfigureForm, 'alt_text')
    alt_text = schema.TextLine(
        title=_(u'label_alt_text', default=u'Alternative Text'),
        description=_(
            u'help_alt_text',
            default=
            u'Provides a textual alternative to non-text content in web pages.'
        ),  # noqa E501
        required=False,
    )

    uuid = schema.TextLine(  # FIXME: this must be schema.ASCIILine()
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #10
0
class IRichTextTile(IPersistentCoverTile):

    text = RichText(title=u'Text')

    uuid = schema.TextLine(
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #11
0
    def update(self):
        super(CustomEditForm, self).update()

        tile = self.getTile()

        if (not IDeferSecurityCheck.providedBy(self.request)
                and not tile.isAllowedToEdit()):
            # if IDeferSecurityCheck is provided by the request,
            # we're not going to worry about security, perms not set up yet
            raise Unauthorized(
                _(u'You are not allowed to add this kind of tile'))
Пример #12
0
class ContentBodyTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/contentbody.pt')

    is_editable = False
    is_configurable = False
    short_name = _(u'msg_short_name_contentbody', default=u'Content Body')

    @property
    def is_empty(self):
        return not self.data.get('uuid', False)

    def body(self):
        """Return the body text of the related object."""
        uuid = self.data.get('uuid', None)
        try:
            obj = uuid and uuidToObject(uuid)
        except Unauthorized:
            return  # TODO: handle exception and show message on template

        if obj is None:
            return ''  # obj was deleted

        try:
            return obj.getText()  # Archetypes
        except AttributeError:
            return obj.text.output if obj.text is not None else ''  # Dexterity

    def populate_with_object(self, obj):
        super(ContentBodyTile, self).populate_with_object(obj)

        data = {
            'uuid': IUUID(obj),
        }

        data_mgr = ITileDataManager(self)
        data_mgr.set(data)

    def accepted_ct(self):
        """Return 'Document' and 'News Item' as the only content types
        accepted in the tile.
        """
        return ['Document', 'News Item']

    def item_url(self):
        uuid = self.data.get('uuid', None)
        try:
            obj = uuidToObject(uuid)
        except Unauthorized:
            obj = None

        if obj:
            return obj.absolute_url()
Пример #13
0
class IFileTile(IPersistentCoverTile):

    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    description = schema.Text(
        title=_(u'Description'),
        required=False,
    )

    download = schema.TextLine(
        title=_(u'Download link'),
        required=False,
        readonly=True,  # this field can not be edited or configured
    )

    uuid = schema.TextLine(
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #14
0
    def populate_with_object(self, obj):
        super(CollectionTile,
              self).populate_with_object(obj)  # check permission

        if obj.portal_type in self.accepted_ct():
            header = safe_unicode(
                obj.Title())  # use collection's title as header
            footer = _(u'More…')  # XXX: can we use field's default?

            data_mgr = ITileDataManager(self)
            data_mgr.set({
                'header': header,
                'footer': footer,
                'uuid': IUUID(obj),
            })
Пример #15
0
    def replace_with_uuids(self, uuids):
        """ Replaces the whole list of items with a new list of items

        :param uuids: The list of objects' UUIDs to be used
        :type uuids: List of strings
        """
        if not self.isAllowedToEdit():
            raise Unauthorized(
                _('You are not allowed to add content to this tile'))
        data_mgr = ITileDataManager(self)
        old_data = data_mgr.get()
        # Clean old data
        old_data['uuids'] = dict()
        data_mgr.set(old_data)
        # Repopulate with clean list
        self.populate_with_uuids(uuids)
Пример #16
0
class Bootstrap2(BaseGrid):

    """Bootstrap 2 grid system (12 columns)."""

    ncolumns = 12
    title = _(u'Bootstrap 2')

    def columns_formatter(self, columns):
        prefix = 'span'
        for column in columns:
            width = column.get('column-size', 1)
            column['class'] = self.column_class + ' ' + (prefix + str(width))
            if 'css-class' in column:
                column['class'] += ' {0}'.format(
                    column['css-class'])

        return columns
Пример #17
0
    def populate_with_uuids(self, uuids):
        """ Add a list of elements to the list of items. This method will
        append new elements to the already existing list of items

        :param uuids: The list of objects' UUIDs to be used
        :type uuids: List of strings
        """
        if not self.isAllowedToEdit():
            raise Unauthorized(
                _('You are not allowed to add content to this tile'))
        self.set_limit()
        data_mgr = ITileDataManager(self)

        old_data = data_mgr.get()
        if old_data['uuids'] is None:
            # If there is no content yet, just assign an empty dict
            old_data['uuids'] = dict()

        uuids_dict = old_data.get('uuids')
        if not isinstance(uuids_dict, dict):
            # Make sure this is a dict
            uuids_dict = old_data['uuids'] = dict()

        if uuids_dict and len(uuids_dict) > self.limit:
            # Do not allow adding more objects than the defined limit
            return

        order_list = [int(val.get('order', 0))
                      for key, val in uuids_dict.items()]
        if len(order_list) == 0:
            # First entry
            order = 0
        else:
            # Get last order position and increment 1
            order_list.sort()
            order = order_list.pop() + 1

        for uuid in uuids:
            if uuid not in uuids_dict:
                entry = dict()
                entry[u'order'] = six.text_type(order)
                uuids_dict[uuid] = entry
                order += 1

        old_data['uuids'] = uuids_dict
        data_mgr.set(old_data)
Пример #18
0
class EmbedTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/embed.pt')

    is_configurable = True
    is_editable = True
    is_droppable = False
    short_name = _(u'msg_short_name_embed', default=u'Embed')

    def is_empty(self):
        return not (self.data.get('embed', None) or
                    self.data.get('title', None) or
                    self.data.get('description', None))

    def accepted_ct(self):
        """Return an empty list as no content types are accepted."""
        return []
Пример #19
0
class RichTextTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/richtext.pt')

    is_configurable = True
    short_name = _(u'msg_short_name_richtext', default=u'Rich Text')

    def getText(self):
        """ Return the rich text stored in the tile.
        """
        text = ''
        if self.data['text']:
            text = self.data['text']
            # We expect that the text has a mimeType and an output
            # attribute, but someone may be using a different widget
            # returning a simple unicode, so check that.
            if not isinstance(text, six.string_types):
                transformer = ITransformer(self.context, None)
                if transformer is not None:
                    text = transformer(text, 'text/x-html-safe')
        return text

    def populate_with_object(self, obj):
        super(RichTextTile, self).populate_with_object(obj)

        if safe_hasattr(obj, 'getRawText'):
            text = obj.getRawText().decode('utf-8')
        else:
            # Probably a dexterity item.  This is already unicode.
            text = obj.text.raw

        value = RichTextValue(raw=text,
                              mimeType='text/x-html-safe',
                              outputMimeType='text/x-html-safe')

        data = {
            'text': value,
            'uuid': IUUID(obj),
        }
        data_mgr = ITileDataManager(self)
        data_mgr.set(data)

    def accepted_ct(self):
        """Return 'Document' as the only content type accepted in the tile."""
        return ['Document']
Пример #20
0
class Deco16Grid(BaseGrid):

    """Deco grid system (16 columns)."""

    title = _(u'Deco (16 columns)')
    ncolumns = 16
    column_class = 'cell'

    def columns_formatter(self, columns):
        w = 'width-'
        p = 'position-'
        offset = 0
        for column in columns:
            width = column.get('column-size', 1)
            column['class'] = self.column_class + ' ' + (w + str(width)) + ' ' + (p + str(offset))
            if 'css-class' in column:
                column['class'] += ' {0}'.format(
                    column['css-class'])
            offset = offset + width
        return columns
Пример #21
0
    def handleSave(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return

        tile = self.getTile()

        # We need to check first for existing content in order not not loose
        # fields that weren't sent with the form
        dataManager = ITileDataManager(tile)
        old_data = dataManager.get()
        for item in data:
            old_data[item] = data[item]
        dataManager.set(old_data)

        api.portal.show_message(_(u'Tile saved'), self.request, type='info')

        # Look up the URL - we need to do this after we've set the data to
        # correctly account for transient tiles
        tileURL = absoluteURL(tile, self.request)
        self.request.response.redirect(tileURL)
Пример #22
0
 def validate(self, value):
     """Validate the value on time to live input"""
     if value <= 0:
         raise Invalid(_(u'Value must be greater than zero.'))
Пример #23
0
class IBasicTile(IPersistentCoverTile):

    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    description = schema.Text(
        title=_(u'Description'),
        required=False,
    )

    form.omitted(IDefaultConfigureForm, 'remote_url')
    remote_url = schema.URI(
        title=_(u'label_remote_url', default=u'URL'),
        description=_(
            u'help_remote_url',
            default=u'Leave this field empty to use the URL of the referenced content. '
                    u'Enter a URL to override it (use absolute links only).'),
        required=False,
    )

    image = NamedImage(
        title=_(u'Image'),
        required=False,
    )

    form.omitted(IDefaultConfigureForm, 'alt_text')
    alt_text = schema.TextLine(
        title=_(
            u'label_alt_text',
            default=u'Alternative Text'),
        description=_(
            u'help_alt_text',
            default=u'Provides a textual alternative to non-text content in web pages.'),  # noqa E501
        required=False,
    )

    form.omitted('date')
    form.no_omit(IDefaultConfigureForm, 'date')
    date = schema.Datetime(
        title=_(u'Date'),
        required=False,
        readonly=False,
    )

    form.omitted('subjects')
    form.no_omit(IDefaultConfigureForm, 'subjects')
    form.widget(subjects='z3c.form.browser.textarea.TextAreaFieldWidget')
    subjects = schema.Tuple(
        title=_(u'label_categories', default=u'Categories'),
        required=False,
        value_type=schema.TextLine(),
        missing_value=(),
    )

    uuid = schema.TextLine(
        title=_(u'UUID'),
        required=False,
        readonly=True,
    )
Пример #24
0
class ListTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/list.pt')

    is_configurable = True
    is_droppable = True
    is_editable = True
    short_name = _(u'msg_short_name_list', default=u'List')
    limit = 5

    def results(self):
        """Return the list of objects stored in the tile as UUID. If an UUID
        has no object associated with it, removes the UUID from the list.

        :returns: a list of objects.
        """
        self.set_limit()

        # always get the latest data
        uuids = ITileDataManager(self).get().get('uuids', None)

        results = list()
        if uuids:
            ordered_uuids = [(k, v) for k, v in uuids.items()]
            ordered_uuids.sort(key=lambda x: int(x[1]['order']))

            for uuid in [i[0] for i in ordered_uuids]:
                obj = uuidToObject(uuid)
                if obj:
                    results.append(obj)
                else:
                    # maybe the user has no permission to access the object
                    # so we try to get it bypassing the restrictions
                    catalog = api.portal.get_tool('portal_catalog')
                    brain = catalog.unrestrictedSearchResults(UID=uuid)
                    if not brain:
                        # the object was deleted; remove it from the tile
                        self.remove_item(uuid)
                        logger.debug(
                            'Non-existent object {0} removed from tile'.format(uuid))  # noqa: E501

        return results[:self.limit]

    def is_empty(self):
        return self.results() == []

    def Date(self, obj):
        # XXX: different from Collection tile, List tile returns objects
        #      instead of brains in its `results` function. I think we
        #      were looking for some performace gains there but in this
        #      case we need to go back to brains to avoid crazy stuff on
        #      trying to guess the name of the method returning the
        #      start date of an Event or an Event-like content type. We
        #      probably want to rewrite the `results` funtion but we have
        #      to be careful because there must be tiles derived from it,
        #      like the Carousel tile
        catalog = api.portal.get_tool('portal_catalog')
        brain = catalog(UID=self.get_uuid(obj))
        assert len(brain) == 1  # nosec
        return super(ListTile, self).Date(brain[0])

    # TODO: get rid of this by replacing it with the 'count' field
    def set_limit(self):
        for field in self.get_configured_fields():
            if field and field.get('id') == 'uuids':
                self.limit = int(field.get('size', self.limit))

    def populate_with_object(self, obj):
        """ Add an object to the list of items

        :param obj: [required] The object to be added
        :type obj: Content object
        """
        super(ListTile, self).populate_with_object(obj)  # check permission
        self.populate_with_uuids([self.get_uuid(obj)])

    def populate_with_uuids(self, uuids):
        """ Add a list of elements to the list of items. This method will
        append new elements to the already existing list of items

        :param uuids: The list of objects' UUIDs to be used
        :type uuids: List of strings
        """
        if not self.isAllowedToEdit():
            raise Unauthorized(
                _('You are not allowed to add content to this tile'))
        self.set_limit()
        data_mgr = ITileDataManager(self)

        old_data = data_mgr.get()
        if old_data['uuids'] is None:
            # If there is no content yet, just assign an empty dict
            old_data['uuids'] = dict()

        uuids_dict = old_data.get('uuids')
        if not isinstance(uuids_dict, dict):
            # Make sure this is a dict
            uuids_dict = old_data['uuids'] = dict()

        if uuids_dict and len(uuids_dict) > self.limit:
            # Do not allow adding more objects than the defined limit
            return

        order_list = [int(val.get('order', 0))
                      for key, val in uuids_dict.items()]
        if len(order_list) == 0:
            # First entry
            order = 0
        else:
            # Get last order position and increment 1
            order_list.sort()
            order = order_list.pop() + 1

        for uuid in uuids:
            if uuid not in uuids_dict:
                entry = dict()
                entry[u'order'] = six.text_type(order)
                uuids_dict[uuid] = entry
                order += 1

        old_data['uuids'] = uuids_dict
        data_mgr.set(old_data)

    def replace_with_uuids(self, uuids):
        """ Replaces the whole list of items with a new list of items

        :param uuids: The list of objects' UUIDs to be used
        :type uuids: List of strings
        """
        if not self.isAllowedToEdit():
            raise Unauthorized(
                _('You are not allowed to add content to this tile'))
        data_mgr = ITileDataManager(self)
        old_data = data_mgr.get()
        # Clean old data
        old_data['uuids'] = dict()
        data_mgr.set(old_data)
        # Repopulate with clean list
        self.populate_with_uuids(uuids)

    def remove_item(self, uuid):
        """ Removes an item from the list

        :param uuid: [required] uuid for the object that wants to be removed
        :type uuid: string
        """
        super(ListTile, self).remove_item(uuid)  # check permission
        data_mgr = ITileDataManager(self)
        old_data = data_mgr.get()
        uuids = data_mgr.get()['uuids']
        if uuid in uuids.keys():
            del uuids[uuid]
        old_data['uuids'] = uuids
        data_mgr.set(old_data)

    def get_uuid(self, obj):
        """Return the UUID of the object.

        :param obj: [required]
        :type obj: content object
        :returns: the object's UUID
        """
        return IUUID(obj, None)

    def get_alt(self, obj):
        """Return the alt attribute for the image in the obj."""
        return obj.Description() or obj.Title()

    # XXX: refactoring the tile's schema should be a way to avoid this
    def get_configured_fields(self):
        # Override this method, since we are not storing anything
        # in the fields, we just use them for configuration
        tileType = queryUtility(ITileType, name=self.__name__)
        conf = self.get_tile_configuration()

        fields = getFieldsInOrder(tileType.schema)

        results = []
        for name, obj in fields:
            field = {'id': name,
                     'title': obj.title}
            if name in conf:
                field_conf = conf[name]
                if ('visibility' in field_conf and field_conf['visibility'] == u'off'):
                    # If the field was configured to be invisible, then just
                    # ignore it
                    continue

                if 'htmltag' in field_conf:
                    # If this field has the capability to change its html tag
                    # render, save it here
                    field['htmltag'] = field_conf['htmltag']

                if 'format' in field_conf:
                    field['format'] = field_conf['format']

                if 'imgsize' in field_conf:
                    field['scale'] = field_conf['imgsize']

                if 'size' in field_conf:
                    field['size'] = field_conf['size']

            results.append(field)

        return results

    def thumbnail(self, item):
        """Return the thumbnail of an image if the item has an image field and
        the field is visible in the tile.

        :param item: [required]
        :type item: content object
        """
        if self._has_image_field(item) and self._field_is_visible('image'):
            tile_conf = self.get_tile_configuration()
            image_conf = tile_conf.get('image', None)
            if image_conf:
                scaleconf = image_conf['imgsize']
                # scale string is something like: 'mini 200:200' and
                # we need the name only: 'mini'
                if scaleconf == '_original':
                    scale = None
                else:
                    scale = scaleconf.split(' ')[0]
                scales = item.restrictedTraverse('@@images')
                return scales.scale('image', scale)

    def _get_image_position(self):
        """Return the image position as configured on the tile.

        :returns: 'left' or 'right'
        """
        tile_conf = self.get_tile_configuration()
        image_conf = tile_conf.get('image', None)
        if image_conf:
            return image_conf.get('position', u'left')

    @property
    def tile_title(self):
        return self.data['tile_title']

    @property
    def more_link(self):
        if not (self.data['more_link'] and self.data['more_link_text']):
            return None

        pc = api.portal.get_tool('portal_catalog')
        brainz = pc(UID=self.data['more_link'])
        if not len(brainz):
            return None

        return {
            'href': brainz[0].getURL(),
            'text': self.data['more_link_text'],
        }

    @view.memoize
    def get_image_position(self):
        return self._get_image_position()

    def _get_title_tag(self, item):
        """Return the HTML code used for the title as configured on the tile.

        :param item: [required]
        :type item: content object
        """
        tag = '<{heading}><a href="{href}">{title}</a></{heading}>'
        if self._field_is_visible('title'):
            tile_conf = self.get_tile_configuration()
            title_conf = tile_conf.get('title', None)
            if title_conf:
                heading = title_conf.get('htmltag', 'h2')
                href = item.absolute_url()
                title = item.Title()
                return tag.format(heading=heading, href=href, title=title)

    @view.memoize
    def get_title_tag(self, item):
        return self._get_title_tag(item)
Пример #25
0
class ICoverSettings(model.Schema):
    """ Interface for the control panel form.
    """

    layouts = schema.Dict(
        title=_(u'Layouts'),
        required=True,
        key_type=schema.TextLine(title=_(u'Name')),
        value_type=schema.TextLine(title=_(u'Layout')),
        readonly=True,  # FIXME: we have no widget for this field yet
    )

    available_tiles = schema.List(
        title=_(u'Available tiles'),
        description=_(u'This tiles will be available for layout creation.'),
        required=True,
        default=DEFAULT_AVAILABLE_TILES,
        value_type=schema.Choice(vocabulary='scmos.cover.EnabledTiles'),
    )

    searchable_content_types = schema.List(
        title=_(u'Searchable Content Types'),
        description=_(u'Only objects of these content types will be searched '
                      u'on the content chooser.'),
        required=False,
        default=DEFAULT_SEARCHABLE_CONTENT_TYPES,
        # we are going to list only the main content types in the widget
        value_type=schema.Choice(
            vocabulary='scmos.cover.AvailableContentTypes'),
    )

    form.widget(styles='z3c.form.browser.textlines.TextLinesFieldWidget')
    styles = schema.Set(
        title=_(u'Styles'),
        description=_(
            u'Enter a list of styles to appear in the style pulldown. '
            u'Format is title|className, one per line.'),
        required=False,
        default=set(),
        value_type=schema.ASCIILine(title=_(u'CSS Classes')),
    )

    grid_system = schema.Choice(
        title=_(u'Grid System'),
        description=_(u'Choose a grid system'),
        required=True,
        default=DEFAULT_GRID_SYSTEM,
        vocabulary='scmos.cover.GridSystems',
    )
Пример #26
0
class IListTile(IPersistentCoverTile):

    uuids = schema.Dict(
        title=_(u'Elements'),
        key_type=schema.TextLine(),
        value_type=schema.Dict(
            key_type=schema.TextLine(),
            value_type=schema.TextLine(),
        ),
        required=False,
    )
    form.omitted('uuids')

    # XXX: this field should be used to replace the 'limit' attribute
    form.omitted('count')
    form.no_omit(IDefaultConfigureForm, 'count')
    count = schema.Int(
        title=_(u'Number of items to display'),
        required=False,
        default=5,
    )

    form.omitted('title')
    form.no_omit(IDefaultConfigureForm, 'title')
    title = schema.TextLine(
        title=_(u'Title'),
        required=False,
    )

    form.omitted('description')
    form.no_omit(IDefaultConfigureForm, 'description')
    description = schema.Text(
        title=_(u'Description'),
        required=False,
    )

    form.omitted('image')
    form.no_omit(IDefaultConfigureForm, 'image')
    image = NamedBlobImage(
        title=_(u'Image'),
        required=False,
    )

    form.omitted('date')
    form.no_omit(IDefaultConfigureForm, 'date')
    date = schema.Datetime(
        title=_(u'Date'),
        required=False,
    )

    tile_title = schema.TextLine(title=_(u'Tile Title'), required=False)
    form.omitted('tile_title')
    form.no_omit(ITileEditForm, 'tile_title')

    more_link = schema.TextLine(title=_('Show more... link'), required=False)
    form.omitted('more_link')
    form.no_omit(ITileEditForm, 'more_link')
    form.widget(more_link='scmos.cover.tiles.edit_widgets.more_link.MoreLinkFieldWidget')

    more_link_text = schema.TextLine(title=_('Show more... link text'), required=False)
    form.omitted('more_link_text')
    form.no_omit(ITileEditForm, 'more_link_text')
Пример #27
0
class BasicTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/basic.pt')
    is_configurable = True
    short_name = _(u'msg_short_name_basic', default=u'Basic')

    @memoizedproperty
    def brain(self):
        uuid = self.data.get('uuid')
        results = api.content.find(UID=uuid)
        assert len(results) <= 1  # nosec
        return results[0] if results else None

    def Date(self):
        # self.brain is None when the tile was populated by editing it
        if self.brain:
            return super(BasicTile, self).Date(self.brain)

    def is_empty(self):
        """Check if there is content to be shown respecting permissions."""
        if self.brain:
            return False

        # we have two different use cases here:
        # * the user has no permission to access the content (e.g. Private state)
        # * the tile was manually populated without dropping content on it
        catalog = api.portal.get_tool('portal_catalog')
        uuid = self.data.get('uuid')
        results = catalog.unrestrictedSearchResults(UID=uuid)
        assert len(results) <= 1
        if results:
            return True  # user has no permission to access the content

        # check if tile was manually populated
        return not [i for i in self.data.values() if i]

    def getURL(self):
        """Return the URL of the referenced object or the value stored
        in remote_url field.
        """
        remote_url = self.data.get('remote_url')
        if remote_url:
            return remote_url

        if self.brain:
            return self.brain.getURL()

    def Subject(self):
        """ Return the categories of the original object (AKA keywords, tags
            or labels).
        """
        if self.brain:
            return self.brain.Subject

    def populate_with_object(self, obj):
        super(BasicTile, self).populate_with_object(obj)

        title = safe_unicode(obj.Title())
        description = safe_unicode(obj.Description())

        image = self.get_image_data(obj)
        if image:
            # clear scales if new image is getting saved
            self.clear_scales()

        # initialize the tile with all fields needed for its rendering
        # note that we include here 'date' and 'subjects', but we do not
        # really care about their value: they came directly from the catalog
        # brain
        data = {
            'title': title,
            'description': description,
            'uuid': IUUID(obj),
            'date': True,
            'subjects': True,
            'image': image,
            # FIXME: https://github.com/scmos.scmos.cover/issues/778
            'alt_text': description or title,
        }

        data_mgr = ITileDataManager(self)
        data_mgr.set(data)

        msg = 'tile "{0}"" populated with data: {1}'
        logger.debug(msg.format(self.id, data))

    @property
    def alt(self):
        """Return alternative text dealing with form init issues."""
        alt_text = self.data['alt_text']
        return alt_text if alt_text is not None else u''
Пример #28
0
class FileTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/file.pt')

    is_configurable = False  # TODO: make the tile configurable
    is_editable = True
    is_droppable = True
    short_name = _(u'msg_short_name_file', default=u'File')

    def get_content_type(self, obj):
        """Return MIME type for both, Archetypes and Dexterity items."""
        try:
            return obj.getContentType()  # Archetypes
        except AttributeError:
            return obj.file.contentType  # Dexterity

    def getBestIcon(self, obj):
        """Find most specific icon for a Dexterity object.

        This is a simplified version of the `getBestIcon` script
        included in Products.Archetypes `archetypes` skin.
        Should be probably included in plone.app.contenttypes.
        """
        mtr = api.portal.get_tool('mimetypes_registry')
        content_type = obj.file.contentType

        try:
            lookup = mtr.lookup(content_type)
        except MimeTypeException:
            return None

        if lookup:
            mti = lookup[0]
            return mti.icon_path

        return None

    def download_widget(self):
        """ Returns a download link for the file associated with the tile.
        """
        obj = uuidToObject(self.data['uuid'])
        if obj:
            url = obj.absolute_url()
            portal_url = obj.portal_url()
            content_type = self.get_content_type(obj)

            try:
                # Archetypes
                icon = obj.getBestIcon()
                mime = obj.lookupMime(content_type)
                size = obj.get_size()
            except AttributeError:
                # Dexterity
                icon = self.getBestIcon(obj)
                mime = lookupMime(obj, content_type)
                size = obj.file.size

            return get_download_html(url, portal_url, icon, mime, size)

    def is_empty(self):
        return not (self.data.get('title', None) or self.data.get(
            'description', None) or self.data.get('uuid', None))

    def populate_with_object(self, obj):
        super(FileTile, self).populate_with_object(obj)  # check permissions

        if obj.portal_type not in self.accepted_ct():
            return
        data = {
            'title': safe_unicode(obj.Title()),
            'description': safe_unicode(obj.Description()),
            'download': True,
            'uuid': IUUID(obj),
        }
        data_mgr = ITileDataManager(self)
        data_mgr.set(data)

    def accepted_ct(self):
        """Return 'File' as the only content type accepted in the tile."""
        return ['File']
Пример #29
0
class BannerTile(PersistentCoverTile):

    index = ViewPageTemplateFile('templates/banner.pt')
    is_configurable = True
    is_editable = True
    is_droppable = True
    short_name = _(u'msg_short_name_banner', default=u'Banner')

    def populate_with_object(self, obj):
        """Tile can be populated with any content type with image
        or getImage attribute; in this case we're not
        going to take care of any modification of the original object; we just
        copy the data to the tile and deal with it.
        """
        if obj.portal_type not in self.accepted_ct():
            return

        super(BannerTile, self).populate_with_object(obj)  # check permissions

        if obj.portal_type == 'Link':
            try:
                remote_url = obj.getRemoteUrl()  # Archetypes
            except AttributeError:
                remote_url = obj.remoteUrl  # Dexterity
        else:
            remote_url = obj.absolute_url()
            if obj.portal_type in get_types_use_view_action_in_listings():
                remote_url += '/view'

        image = self.get_image_data(obj)
        if image:
            # clear scales if new image is getting saved
            self.clear_scales()

        obj = aq_base(obj)  # avoid acquisition
        title = safe_unicode(obj.Title())
        description = safe_unicode(obj.Description())

        data_mgr = ITileDataManager(self)
        data_mgr.set({
            'title': title,
            'description': description,
            'uuid': IUUID(obj),
            'image': image,
            # FIXME: https://github.com/scmos.scmos.cover/issues/778
            'alt_text': description or title,
            'remote_url': remote_url,
        })

    def getRemoteUrl(self):
        """Return the remote URL field."""
        return self.data.get('remote_url') or u''  # deal with None values

    @property
    def is_empty(self):
        return not (self.data.get('title') or self.has_image
                    or self.getRemoteUrl())

    @property
    def css_class(self):
        tile_conf = self.get_tile_configuration()
        image_conf = tile_conf.get('image', None)
        if image_conf:
            css_class = image_conf['position']
            return css_class

    @property
    def htmltag(self):
        tile_conf = self.get_tile_configuration()
        title_conf = tile_conf.get('title', None)
        if title_conf:
            htmltag = title_conf['htmltag']
            return htmltag

    @property
    def alt(self):
        """Return alternative text dealing with form init issues."""
        alt_text = self.data['alt_text']
        return alt_text if alt_text is not None else u''
Пример #30
0
class CalendarTile(PersistentCoverTile):
    """Calendar Tile code is coppied from plone.app.portlet Portlet Calendar
    """

    index = ViewPageTemplateFile('templates/calendar.pt')

    is_configurable = False
    is_editable = False
    is_droppable = False
    short_name = _(u'msg_short_name_calendar', default=u'Calendar')

    def __init__(self, context, request):
        super(CalendarTile, self).__init__(context, request)
        self._setup()

    def _setup(self):
        context = aq_inner(self.context)
        self.calendar = getToolByName(context, 'portal_calendar')
        self._ts = getToolByName(context, 'translation_service')
        self.url_quote_plus = quote_plus

        self.now = localtime()
        self.yearmonth = yearmonth = self.getYearAndMonthToDisplay()
        self.year = year = yearmonth[0]
        self.month = month = yearmonth[1]

        self.showPrevMonth = yearmonth > (self.now[0] - 1, self.now[1])
        self.showNextMonth = yearmonth < (self.now[0] + 1, self.now[1])

        self.prevMonthYear, self.prevMonthMonth = self.getPreviousMonth(year, month)
        self.nextMonthYear, self.nextMonthMonth = self.getNextMonth(year, month)

        self.monthName = PLMF(self._ts.month_msgid(month),
                              default=self._ts.month_english(month))

    def accepted_ct(self):
        """Return an empty list as no content types are accepted."""
        return []

    def getEventsForCalendar(self):
        context = aq_inner(self.context)
        year = self.year
        month = self.month
        portal_state = getMultiAdapter((self.context, self.request), name='plone_portal_state')
        navigation_root_path = portal_state.navigation_root_path()
        weeks = self.calendar.getEventsForCalendar(month, year, path=navigation_root_path)
        for week in weeks:
            for day in week:
                daynumber = day['day']
                if daynumber == 0:
                    continue
                day['is_today'] = self.isToday(daynumber)
                if day['event']:
                    cur_date = DateTime(year, month, daynumber)
                    localized_date = [self._ts.ulocalized_time(cur_date, context=context, request=self.request)]
                    day['eventstring'] = '\n'.join(localized_date + [
                        ' {0}'.format(self.getEventString(e)) for e in day['eventslist']])
                    day['date_string'] = '{0}-{1}-{2}'.format(year, month, daynumber)

        return weeks

    def getEventString(self, event):
        start = event['start'] and ':'.join(event['start'].split(':')[:2]) or ''
        end = event['end'] and ':'.join(event['end'].split(':')[:2]) or ''
        title = safe_unicode(event['title']) or u'event'

        if start and end:
            eventstring = '{0}-{1} {2}'.format(start, end, title)
        elif start:  # can assume not event['end']
            eventstring = '{0} - {1}'.format(start, title)
        elif event['end']:  # can assume not event['start']
            eventstring = '{0} - {1}'.format(title, end)
        else:  # can assume not event['start'] and not event['end']
            eventstring = title

        return eventstring

    def getYearAndMonthToDisplay(self):
        session = None
        request = self.request

        # First priority goes to the data in the REQUEST
        year = request.get('year', None)
        month = request.get('month', None)

        # Next get the data from the SESSION
        if self.calendar.getUseSession():
            session = request.get('SESSION', None)
            if session:
                if not year:
                    year = session.get('calendar_year', None)
                if not month:
                    month = session.get('calendar_month', None)

        # Last resort to today
        if not year:
            year = self.now[0]
        if not month:
            month = self.now[1]

        # try to transform to number but fall back to current
        # date if this is ambiguous
        try:
            year, month = int(year), int(month)
        except (TypeError, ValueError):
            year, month = self.now[:2]

        # Store the results in the session for next time
        if session:
            session.set('calendar_year', year)
            session.set('calendar_month', month)

        # Finally return the results
        return year, month

    def getPreviousMonth(self, year, month):
        if month == 0 or month == 1:
            month, year = 12, year - 1
        else:
            month -= 1
        return (year, month)

    def getNextMonth(self, year, month):
        if month == 12:
            month, year = 1, year + 1
        else:
            month += 1
        return (year, month)

    def getWeekdays(self):
        """Returns a list of Messages for the weekday names."""
        weekdays = []
        # list of ordered weekdays as numbers
        for day in self.calendar.getDayNumbers():
            weekdays.append(PLMF(self._ts.day_msgid(day, format='s'),
                                 default=self._ts.weekday_english(day, format='a')))

        return weekdays

    def isToday(self, day):
        """Returns True if the given day and the current month and year equals
           today, otherwise False.
        """
        return (
            self.now[2] == day and self.now[1] == self.month and self.now[0] == self.year)

    def getReviewStateString(self):
        states = self.calendar.getCalendarStates()
        return ''.join(map(lambda x: 'review_state={0}&amp;'.format(self.url_quote_plus(x)), states))

    def getEventTypes(self):
        types = self.calendar.getCalendarTypes()
        return ''.join(map(lambda x: 'Type={0}&amp;'.format(self.url_quote_plus(x)), types))

    def getQueryString(self):
        request = self.request
        query_string = request.get('orig_query',
                                   request.get('QUERY_STRING', None))
        if len(query_string) == 0:
            query_string = ''
        else:
            query_string = '{0}&amp;'.format(query_string)
        return query_string