def test_isMixedIn(self): self.assertTrue(isinstance(self.af, BrowserDefaultMixin), "ISelectableBrowserDefault was not mixed in to ATFolder") self.assertTrue(ZopeTwoISelectableBrowserDefault.providedBy(self.af), "ISelectableBrowserDefault not implemented by ATFolder instance") self.assertTrue(ISelectableBrowserDefault.providedBy(self.af), "ISelectableBrowserDefault not implemented by ATFolder instance")
def rename_default_page(obj, event): newParent = event.newParent if newParent != event.oldParent: return elif ISelectableBrowserDefault.providedBy(newParent): default_page_id = newParent.getProperty('default_page', '') if default_page_id == event.oldName: ISelectableBrowserDefault(newParent).setDefaultPage(event.newName)
def _context_selected_layout(self): """Return the current layout for the layout aware context if we are on the layout aware context """ if not ILayoutAware(self.context, None): return '' selectable_layout = ISelectableBrowserDefault(self.context, None) if not selectable_layout: return '' return selectable_layout.getLayout()
def test_isMixedIn(self): self.assertTrue( isinstance(self.af, BrowserDefaultMixin), "ISelectableBrowserDefault was not mixed in to ATFolder") self.assertTrue( ZopeTwoISelectableBrowserDefault.providedBy(self.af), "ISelectableBrowserDefault not implemented by ATFolder instance") self.assertTrue( ISelectableBrowserDefault.providedBy(self.af), "ISelectableBrowserDefault not implemented by ATFolder instance")
def rename_default_page(obj, event): """event subscriber, rename default page if targte was renamed used by default for zope.lifecycleevent.interfaces.IObjectMovedEvent """ newParent = event.newParent if newParent != event.oldParent: return elif ISelectableBrowserDefault.providedBy(newParent): default_page_id = newParent.getProperty('default_page', '') if default_page_id == event.oldName: ISelectableBrowserDefault(newParent).setDefaultPage(event.newName)
def menuItems(self): menu = getUtility(IBrowserMenu, name='plone_displayviews') layouts = ISelectableBrowserDefault(self.context).getAvailableLayouts() actions = [layout[0] for layout in layouts] items = menu.getMenuItems(self.context, self.request) return sorted([item for item in items if item['action'].strip('@') in actions], key=lambda x: x['action'])
def get_target_object_layout(self, target): """ Returns target object 'view' action page template """ if ISelectableBrowserDefault.providedBy(target): return target.getLayout() else: return 'base_view'
def available(self): if self.disabled(): return False isDefaultPage = self.context_state.is_default_page() folder = None context = None folderLayouts = [] contextLayouts = [] # If this is a default page, also get menu items relative to the parent if isDefaultPage: folder = ISelectableBrowserDefault(utils.parent(self.context), None) context = ISelectableBrowserDefault(self.context, None) folderLayouts = [] folderCanSetLayout = False folderCanSetDefaultPage = False if folder is not None: folderLayouts = folder.getAvailableLayouts() folderCanSetLayout = folder.canSetLayout() folderCanSetDefaultPage = folder.canSetDefaultPage() contextLayouts = [] contextCanSetLayout = False contextCanSetDefaultPage = False if context is not None: contextLayouts = context.getAvailableLayouts() contextCanSetLayout = context.canSetLayout() contextCanSetDefaultPage = context.canSetDefaultPage() # Show the menu if we either can set a default-page, or we have more # than one layout to choose from. if (folderCanSetDefaultPage) or \ (folderCanSetLayout and len(folderLayouts) > 1) or \ (folder is None and contextCanSetDefaultPage) or \ (contextCanSetLayout and len(contextLayouts) > 1): return True else: return False
def check_default_page(obj, event): """event subscriber, unset default page if target no longer exists used by default for zope.container.interfaces.IContainerModifiedEvent """ container = obj default_page_id = container.getProperty('default_page', '') if default_page_id and not (default_page_id in container.objectIds()): ISelectableBrowserDefault(container).setDefaultPage(None)
def upgrade_9_to_10(context): from Products.CMFDynamicViewFTI.interfaces import ISelectableBrowserDefault types_tool = getToolByName(context, 'portal_types') pc = getToolByName(context, 'portal_catalog') # Iterate through all Dexterity content type all_ftis = types_tool.listTypeInfo() dx_ftis = [x for x in all_ftis if getattr(x, 'behaviors', False)] for fti in dx_ftis: if not (LAYOUT_BEHAVIORS & set(fti.behaviors)): continue results = pc.unrestrictedSearchResults(portal_type=fti.id) for brain in results: ob = brain._unrestrictedGetObject() ob_default = ISelectableBrowserDefault(ob, None) if ob_default is None: continue if ob_default.getLayout() in ['view', '@@view']: ob_default.setLayout('layout_view')
def rename_default_page(obj, event): """event subscriber, rename default page if targte was renamed used by default for zope.lifecycleevent.interfaces.IObjectMovedEvent """ newParent = event.newParent if newParent != event.oldParent: return elif ISelectableBrowserDefault.providedBy(newParent): default_page_id = newParent.getProperty("default_page", "") if default_page_id == event.oldName: ISelectableBrowserDefault(newParent).setDefaultPage(event.newName)
def getTargetObjectLayout(self, target): """ Returns target object 'view' action page template """ if HAS_ISBD and ISelectableBrowserDefault.isImplementedBy(target): return target.getLayout() else: view = target.getTypeInfo().getActionById('view') or 'base_view' # If view action is view, try to guess correct template if view == 'view': view = target.portal_type.lower() + '_view' return view
def test_default_page_is_kept_in_folder(self): # Ensure that a default page that is checked out and back in is still # the default page. folder = self.portal.docs doc = folder.doc1 from Products.CMFDynamicViewFTI.interfaces import ISelectableBrowserDefault # noqa: C901 ISelectableBrowserDefault(folder).setDefaultPage('doc1') self.assertEqual(folder.getProperty('default_page', ''), 'doc1') self.assertEqual(folder.getDefaultPage(), 'doc1') # Note: when checking out to self.portal.workarea it surprisingly works # without changes. But the default behavior in Plone is to check a # document out in its original folder, so that is what we check here. wc = ICheckinCheckoutPolicy(doc).checkout(folder) doc = ICheckinCheckoutPolicy(wc).checkin('updated') self.assertEqual(folder.getProperty('default_page', ''), 'doc1') self.assertEqual(folder.getDefaultPage(), 'doc1')
def getMenuItems(self, obj, request): """Return menu item entries in a TAL-friendly form.""" results = [] context_state = getMultiAdapter( (obj, request), name='plone_context_state' ) isDefaultPage = context_state.is_default_page() parent = None folder = None if isDefaultPage: # If this is a default page, also get menu items relative to thr # parent parent = utils.parent(obj) folder = ISelectableBrowserDefault(parent, None) folderLayouts = [] folderCanSetLayout = False folderCanSetDefaultPage = False if folder is not None: folderLayouts = folder.getAvailableLayouts() folderCanSetLayout = folder.canSetLayout() folderCanSetDefaultPage = folder.canSetDefaultPage() contextLayouts = [] contextCanSetLayout = False contextCanSetDefaultPage = False context = ISelectableBrowserDefault(obj, None) if context is not None: contextLayouts = context.getAvailableLayouts() contextCanSetLayout = context.canSetLayout() contextCanSetDefaultPage = context.canSetDefaultPage() # Short circuit if neither folder nor object will provide us with # items if not (folderCanSetLayout or folderCanSetDefaultPage or contextCanSetLayout or contextCanSetDefaultPage): return [] # Only show the block "Folder display" and "Item display" separators if # they are necessars useSeparators = False if folderCanSetLayout or folderCanSetDefaultPage: if (contextCanSetLayout and len(contextLayouts) > 1) or \ contextCanSetDefaultPage: useSeparators = True # 1. If this is a default-page, first render folder options if folder is not None: folderUrl = parent.absolute_url() if useSeparators: results.append({ 'title': _(u'label_current_folder_views', default=u'Folder display'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': {'id': 'folderHeader', 'separator': 'actionSeparator', 'class': ''}, 'submenu': None, }) if folderCanSetLayout: for id, title in folderLayouts: results.append({ 'title': title, 'description': '', 'action': addTokenToUrl( '%s/selectViewTemplate?templateId=%s' % ( folderUrl, id,), request), 'selected': False, 'icon': None, 'extra': { 'id': 'folder-' + id, 'separator': None, 'class': ''}, 'submenu': None, }) # Display the selected item (i.e. the context) results.append({ 'title': _(u'label_item_selected', default=u'Item: ${contentitem}', mapping={'contentitem': escape( utils.safe_unicode(obj.Title()))}), 'description': '', 'action': None, 'selected': True, 'icon': None, 'extra': { 'id': 'folderDefaultPageDisplay', 'separator': 'actionSeparator', 'class': 'actionMenuSelected'}, 'submenu': None, }) # Let the user change the selection if folderCanSetDefaultPage: results.append({ 'title': _(u'label_change_default_item', default=u'Change content item as default ' u'view...'), 'description': _(u'title_change_default_view_item', default=u'Change the item used as default' u' view in this folder'), 'action': '%s/select_default_page' % (folderUrl,), 'selected': False, 'icon': None, 'extra': { 'id': 'folderChangeDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal'}, 'submenu': None, }) # 2. Render context options if context is not None: contextUrl = obj.absolute_url() selected = context.getLayout() defaultPage = context.getDefaultPage() layouts = context.getAvailableLayouts() if useSeparators: results.append({ 'title': _(u'label_current_item_views', default=u'Item display'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': { 'id': 'contextHeader', 'separator': 'actionSeparator', 'class': ''}, 'submenu': None, }) # If context is a default-page in a folder, that folder's views # will be shown. Only show context views if there are any to show. showLayouts = False if not isDefaultPage: showLayouts = True elif len(layouts) > 1: showLayouts = True if showLayouts and contextCanSetLayout: for id, title in contextLayouts: is_selected = (defaultPage is None and id == selected) results.append({ 'title': title, 'description': '', 'action': addTokenToUrl( '%s/selectViewTemplate?templateId=%s' % ( contextUrl, id,), request), 'selected': is_selected, 'icon': None, 'extra': { 'id': 'plone-contentmenu-display-' + id, 'separator': None, 'class': is_selected and 'actionMenuSelected' or '' }, 'submenu': None, }) # Allow setting / changing the default-page, unless this is a # default-page in a parent folder. if not INonStructuralFolder.providedBy(obj): if defaultPage is None: if contextCanSetDefaultPage: results.append({ 'title': _(u'label_choose_item', default=u'Select a content item\n' u'as default view...'), 'description': _( u'title_select_default_view_item', default=u'Select an item to be used as ' u'default view in this folder...'), 'action': addTokenToUrl( '%s/select_default_page' % (contextUrl,), request), 'selected': False, 'icon': None, 'extra': { 'id': 'contextSetDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal'}, 'submenu': None, }) else: defaultPageObj = getattr(obj, defaultPage, None) defaultPageTitle = u"" if defaultPageObj is not None: if hasattr(aq_base(defaultPageObj), 'Title'): defaultPageTitle = defaultPageObj.Title() else: defaultPageTitle = getattr(aq_base(defaultPageObj), 'title', u'') results.append({ 'title': _(u'label_item_selected', default=u'Item: ${contentitem}', mapping={'contentitem': escape( utils.safe_unicode(defaultPageTitle))}), 'description': '', 'action': None, 'selected': True, 'icon': None, 'extra': { 'id': 'contextDefaultPageDisplay', 'separator': 'actionSeparator', 'class': ''}, 'submenu': None, }) if contextCanSetDefaultPage: results.append({ 'title': _(u'label_change_item', default=u'Change content item\nas ' u'default view...'), 'description': _( u'title_change_default_view_item', default=u'Change the item used as default ' u'view in this folder'), 'action': '%s/select_default_page' % (contextUrl,), 'selected': False, 'icon': None, 'extra': { 'id': 'contextChangeDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal'}, 'submenu': None, }) return results
def check_default_page(obj, event): container = obj default_page_id = container.getDefaultPage() if default_page_id and not (default_page_id in container.objectIds()): ISelectableBrowserDefault(container).setDefaultPage(None)
def test_extendsInterface(self): self.failUnless(ISelectableBrowserDefault.extends(IBrowserDefault))
def getMenuItems(self, obj, request): """Return menu item entries in a TAL-friendly form.""" results = [] context_state = getMultiAdapter((obj, request), name='plone_context_state') isDefaultPage = context_state.is_default_page() parent = None folder = None if isDefaultPage: # If this is a default page, also get menu items relative to thr # parent parent = utils.parent(obj) folder = ISelectableBrowserDefault(parent, None) folderLayouts = [] folderCanSetLayout = False folderCanSetDefaultPage = False if folder is not None: folderLayouts = folder.getAvailableLayouts() folderCanSetLayout = folder.canSetLayout() folderCanSetDefaultPage = folder.canSetDefaultPage() contextLayouts = [] contextCanSetLayout = False contextCanSetDefaultPage = False context = ISelectableBrowserDefault(obj, None) if context is not None: contextLayouts = context.getAvailableLayouts() contextCanSetLayout = context.canSetLayout() contextCanSetDefaultPage = context.canSetDefaultPage() # Short circuit if neither folder nor object will provide us with # items if not (folderCanSetLayout or folderCanSetDefaultPage or contextCanSetLayout or contextCanSetDefaultPage): return [] # Only show the block "Folder display" and "Item display" separators if # they are necessars useSeparators = False if folderCanSetLayout or folderCanSetDefaultPage: if (contextCanSetLayout and len(contextLayouts) > 1) or \ contextCanSetDefaultPage: useSeparators = True # 1. If this is a default-page, first render folder options if folder is not None: folderUrl = parent.absolute_url() if useSeparators: results.append({ 'title': _(u'label_current_folder_views', default=u'Folder display'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': { 'id': 'folderHeader', 'separator': 'actionSeparator', 'class': '' }, 'submenu': None, }) if folderCanSetLayout: for id, title in folderLayouts: results.append({ 'title': title, 'description': '', 'action': addTokenToUrl( '%s/selectViewTemplate?templateId=%s' % ( folderUrl, id, ), request), 'selected': False, 'icon': None, 'extra': { 'id': 'folder-' + id, 'separator': None, 'class': '' }, 'submenu': None, }) # Display the selected item (i.e. the context) results.append({ 'title': _(u'label_item_selected', default=u'Item: ${contentitem}', mapping={ 'contentitem': escape(utils.safe_unicode(obj.Title())) }), 'description': '', 'action': None, 'selected': True, 'icon': None, 'extra': { 'id': 'folderDefaultPageDisplay', 'separator': 'actionSeparator', 'class': 'actionMenuSelected' }, 'submenu': None, }) # Let the user change the selection if folderCanSetDefaultPage: results.append({ 'title': _(u'label_change_default_item', default=u'Change content item as default ' u'view...'), 'description': _(u'title_change_default_view_item', default=u'Change the item used as default' u' view in this folder'), 'action': '%s/select_default_page' % (folderUrl, ), 'selected': False, 'icon': None, 'extra': { 'id': 'folderChangeDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal' }, 'submenu': None, }) # 2. Render context options if context is not None: contextUrl = obj.absolute_url() selected = context.getLayout() defaultPage = context.getDefaultPage() layouts = context.getAvailableLayouts() if useSeparators: results.append({ 'title': _(u'label_current_item_views', default=u'Item display'), 'description': '', 'action': None, 'selected': False, 'icon': None, 'extra': { 'id': 'contextHeader', 'separator': 'actionSeparator', 'class': '' }, 'submenu': None, }) # If context is a default-page in a folder, that folder's views # will be shown. Only show context views if there are any to show. showLayouts = False if not isDefaultPage: showLayouts = True elif len(layouts) > 1: showLayouts = True if showLayouts and contextCanSetLayout: for id, title in contextLayouts: is_selected = (defaultPage is None and id == selected) results.append({ 'title': title, 'description': '', 'action': addTokenToUrl( '%s/selectViewTemplate?templateId=%s' % ( contextUrl, id, ), request), 'selected': is_selected, 'icon': None, 'extra': { 'id': 'plone-contentmenu-display-' + id, 'separator': None, 'class': is_selected and 'actionMenuSelected' or '' }, 'submenu': None, }) # Allow setting / changing the default-page, unless this is a # default-page in a parent folder. if not INonStructuralFolder.providedBy(obj): if defaultPage is None: if contextCanSetDefaultPage: results.append({ 'title': _(u'label_choose_item', default=u'Select a content item\n' u'as default view...'), 'description': _(u'title_select_default_view_item', default=u'Select an item to be used as ' u'default view in this folder...'), 'action': addTokenToUrl( '%s/select_default_page' % (contextUrl, ), request), 'selected': False, 'icon': None, 'extra': { 'id': 'contextSetDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal' }, 'submenu': None, }) else: defaultPageObj = getattr(obj, defaultPage, None) defaultPageTitle = u"" if defaultPageObj is not None: if hasattr(aq_base(defaultPageObj), 'Title'): defaultPageTitle = defaultPageObj.Title() else: defaultPageTitle = getattr(aq_base(defaultPageObj), 'title', u'') results.append({ 'title': _(u'label_item_selected', default=u'Item: ${contentitem}', mapping={ 'contentitem': escape(utils.safe_unicode(defaultPageTitle)) }), 'description': '', 'action': None, 'selected': True, 'icon': None, 'extra': { 'id': 'contextDefaultPageDisplay', 'separator': 'actionSeparator', 'class': '' }, 'submenu': None, }) if contextCanSetDefaultPage: results.append({ 'title': _(u'label_change_item', default=u'Change content item\nas ' u'default view...'), 'description': _(u'title_change_default_view_item', default=u'Change the item used as default ' u'view in this folder'), 'action': '%s/select_default_page' % (contextUrl, ), 'selected': False, 'icon': None, 'extra': { 'id': 'contextChangeDefaultPage', 'separator': 'actionSeparator', 'class': 'pat-plone-modal' }, 'submenu': None, }) return results
def test_extendsInterface(self): self.assertTrue(ISelectableBrowserDefault.extends(IBrowserDefault))
def getMenuItems(self, context, request): # Check required parameters if context is None or request is None: return [] # Get layout vocabulary factory vocab_factory = getUtility(IVocabularyFactory, name='plone.availableDisplayLayouts') # Get context state API context_state = getMultiAdapter((context, request), name='plone_context_state') # Get folder layout options when this is a default page folder_layout = '' folder_methods = [] folder_results = [] folder_url = '' folder_vocab = [] if context_state.is_default_page(): folder = parent(context) if folder is not None: folder_methods = getAvailableViewMethods(folder) folder_url = folder.absolute_url() folder_vocab = vocab_factory(folder) folder_default = ISelectableBrowserDefault(folder, None) if folder_default is not None: folder_layout = folder_default.getLayout() for term in folder_vocab or []: if term.value in folder_methods: is_selected = term.value == folder_layout id_ = term.value.split('++')[-1] actionUrl = '%s/selectViewTemplate?templateId=%s' % ( folder_url, quote(term.value), ), if HAS_PLONE_PROTECT: actionUrl = addTokenToUrl(actionUrl, request) folder_results.append({ 'title': term.title, 'description': '', 'action': actionUrl, 'selected': is_selected, 'icon': None, 'extra': { 'id': 'folder-layout-' + id_, 'separator': None, 'class': is_selected and 'actionMenuSelected' or '' }, 'submenu': None, }) # Get context layout options context_methods = getAvailableViewMethods(context) context_results = [] context_url = context.absolute_url() context_vocab = vocab_factory(context) context_default = ISelectableBrowserDefault(context, None) if context_default is not None: context_layout = context_default.getLayout() for term in context_vocab: if term.value in context_methods: is_selected = term.value == context_layout id_ = term.value.split('++')[-1] actionUrl = '%s/selectViewTemplate?templateId=%s' % ( context_url, quote(term.value), ) if HAS_PLONE_PROTECT: actionUrl = addTokenToUrl(actionUrl, request) context_results.append({ 'title': term.title, 'description': '', 'action': actionUrl, 'selected': is_selected, 'icon': None, 'extra': { 'id': 'plone-contentmenu-layout-' + id_, 'separator': None, 'class': is_selected and 'actionMenuSelected' or '' }, 'submenu': None, }) # Merge the results with the original display meny menu = getUtility(IBrowserMenu, 'plone_contentmenu_display') results = [] for result in menu.getMenuItems(context, request): id_ = (result.get('extra') or {}).get('id') sep = (result.get('extra') or {}).get('separator') # Extend results with layouts if id_ in ('folderHeader', 'contextHeader'): pass elif sep and id_.startswith('folder') and folder_results: results.extend(folder_results) folder_results = [] elif sep and id_.startswith('context') and context_results: results.extend(context_results) context_results = [] # Move 'Custom layout' into bottom if id_ in ['folder-view', 'folder-@@view']: folder_results.append(result) elif id_ in [ 'plone-contentmenu-display-view', 'plone-contentmenu-display-@@view' ]: context_results.append(result) else: results.append(result) # Flush the remaining options if folder_results: results.extend(folder_results) if context_results: results.extend(context_results) return results
def getMenuItems(self, context, request): # Check required parameters if context is None or request is None: return [] # Get layout vocabulary factory vocab_factory = getUtility(IVocabularyFactory, name='plone.availableDisplayLayouts') # Get context state API context_state = getMultiAdapter((context, request), name='plone_context_state') # Get folder layout options when this is a default page folder_layout = '' folder_methods = [] folder_results = [] folder_url = '' folder_vocab = [] if context_state.is_default_page(): folder = parent(context) if folder is not None: folder_methods = getAvailableViewMethods(folder) folder_url = folder.absolute_url() folder_vocab = vocab_factory(folder) folder_default = ISelectableBrowserDefault(folder, None) if folder_default is not None: folder_layout = folder_default.getLayout() for term in folder_vocab or []: if term.value in folder_methods: is_selected = term.value == folder_layout id_ = term.value.split('++')[-1] actionUrl = '%s/selectViewTemplate?templateId=%s' % ( folder_url, quote(term.value),), if HAS_PLONE_PROTECT: actionUrl = addTokenToUrl(actionUrl, request) folder_results.append({ 'title': term.title, 'description': '', 'action': actionUrl, 'selected': is_selected, 'icon': None, 'extra': { 'id': 'folder-layout-' + id_, 'separator': None, 'class': is_selected and 'actionMenuSelected' or ''}, 'submenu': None, }) # Get context layout options context_methods = getAvailableViewMethods(context) context_results = [] context_url = context.absolute_url() context_vocab = vocab_factory(context) context_default = ISelectableBrowserDefault(context, None) if context_default is not None: context_layout = context_default.getLayout() for term in context_vocab: if term.value in context_methods: is_selected = term.value == context_layout id_ = term.value.split('++')[-1] actionUrl = '%s/selectViewTemplate?templateId=%s' % ( context_url, quote(term.value),) if HAS_PLONE_PROTECT: actionUrl = addTokenToUrl(actionUrl, request) context_results.append({ 'title': term.title, 'description': '', 'action': actionUrl, 'selected': is_selected, 'icon': None, 'extra': { 'id': 'plone-contentmenu-layout-' + id_, 'separator': None, 'class': is_selected and 'actionMenuSelected' or ''}, 'submenu': None, }) # Merge the results with the original display meny menu = getUtility(IBrowserMenu, 'plone_contentmenu_display') results = [] for result in menu.getMenuItems(context, request): id_ = (result.get('extra') or {}).get('id') sep = (result.get('extra') or {}).get('separator') # Extend results with layouts if id_ in ('folderHeader', 'contextHeader'): pass elif sep and id_.startswith('folder') and folder_results: results.extend(folder_results) folder_results = [] elif sep and id_.startswith('context') and context_results: results.extend(context_results) context_results = [] # Move 'Custom layout' into bottom if id_ in ['folder-view', 'folder-@@view']: folder_results.append(result) elif id_ in ['plone-contentmenu-display-view', 'plone-contentmenu-display-@@view']: context_results.append(result) else: results.append(result) # Flush the remaining options if folder_results: results.extend(folder_results) if context_results: results.extend(context_results) return results
def set_layout(self, obj, name): ISelectableBrowserDefault(obj).setLayout(name)