diff --git a/gen/__init__.py b/gen/__init__.py index af7c7f7..013fccb 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -1172,9 +1172,8 @@ class String(Type): # Default width, height and maxChars vary according to String format if width == None: if format == String.TEXT: self.width = 60 - # This width corresponds to the standard width of an Appy page, - # minus the portlet. - if format == String.XHTML: self.width = 750 + # This width corresponds to the standard width of an Appy page. + if format == String.XHTML: self.width = 870 else: self.width = 30 if height == None: if format == String.TEXT: self.height = 5 diff --git a/gen/layout.py b/gen/layout.py index ad56b7e..5cf8f07 100644 --- a/gen/layout.py +++ b/gen/layout.py @@ -217,13 +217,13 @@ class Table(LayoutElement): # Some base layouts to use, for fields and pages ------------------------------- # The default layouts for pages defaultPageLayouts = { - 'view': Table('n!-w|-b|', align="center"), + 'view': Table('w|-b|', align="center"), 'edit': Table('w|-b|', width=None)} # A layout for pages, containing the page summary. -summaryPageLayouts = {'view': Table('s-n!-w|-b|', align="center"), +summaryPageLayouts = {'view': Table('s-w|-b|', align="center"), 'edit': Table('w|-b|', width=None)} widePageLayouts = { - 'view': Table('n!-w|-b|', align="center"), + 'view': Table('w|-b|', align="center"), 'edit': Table('w|-b|') } # The default layout for fields. Alternative layouts may exist and are declared diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index a4cd8e2..3450d59 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -245,7 +245,10 @@ class ToolMixin(BaseMixin): elems = sortMethod(elems) return [importParams['headers'], elems] - def showPortlet(self, context): + def showPortlet(self, context, layoutType): + '''When must the portlet be shown?''' + # Not on 'edit' pages. + if layoutType == 'edit': return if context.id == 'ui': context = context.getParentNode() res = True if hasattr(context.aq_base, 'appy'): @@ -424,17 +427,29 @@ class ToolMixin(BaseMixin): return '%s' % \ (text, uText[:width].encode('utf-8') + '...') - def getPublishedObject(self): + def getLayoutType(self): + '''Guess the current layout type, according to actual URL.''' + actualUrl = self.REQUEST['ACTUAL_URL'] + res = '' + if actualUrl.endswith('/ui/view'): + res = 'view' + elif actualUrl.endswith('/ui/edit') or actualUrl.endswith('/do'): + res = 'edit' + return res + + def getPublishedObject(self, layoutType): '''Gets the currently published object, if its meta_class is among application classes.''' - req = self.REQUEST - # If we are querying object, there is no published object (the truth is: - # the tool is the currently published object but we don't want to - # consider it this way). - if not req['ACTUAL_URL'].endswith('/ui/view'): return + # In some situations (ie, we are querying objects), the published object + # according to Zope is the tool, but we don't want to consider it that + # way. + if layoutType not in ('edit', 'view'): return obj = self.REQUEST['PUBLISHED'] - parent = obj.getParentNode() - if parent.id == 'ui': obj = parent.getParentNode() + # If URL is a /do, published object is the "do" method. + if type(obj) == types.MethodType: obj = obj.im_self + else: + parent = obj.getParentNode() + if parent.id == 'ui': obj = parent.getParentNode() if obj.meta_type in self.getProductConfig().attributes: return obj def getZopeClass(self, name): diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index 2fafb9c..ff28176 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -822,6 +822,11 @@ class BaseMixin: break return phase else: + # Return an empty list if we have a single, link-free page within + # a single phase. + if (len(res) == 1) and (len(res[0]['pages']) == 1) and \ + not res[0]['pagesInfo'][res[0]['pages'][0]].get('links'): + return None return res def getIcons(self): @@ -1434,7 +1439,16 @@ class BaseMixin: # Not-Managers can't navigate back to the tool if (parent.id == 'config') and not self.getUser().has_role('Manager'): return False - if parent.meta_type != 'Folder': return parent + if parent.meta_type not in ('Folder', 'Temporary Folder'): return parent + + def getBreadCrumb(self): + '''Gets breadcrumb info about this object and its parents.''' + res = [{'url': self.absolute_url(), + 'title': self.getFieldValue('title', layoutType='view')}] + parent = self.getParent() + if parent: + res = parent.getBreadCrumb() + res + return res def index_html(self): '''Redirects to /ui.''' diff --git a/gen/ui/appy.css b/gen/ui/appy.css index e7f298e..80b775b 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -57,6 +57,9 @@ img { border: 0; vertical-align: middle} .userStripText { font-size: 110%; padding: 0 0.3em 0 0.3em; color: white } .userStrip a { color: #e7e7e7 } .userStrip a:visited { color: #e7e7e7 } +.navigate { border-bottom: 1px solid #5F7983; + background-color: #dbdde1; font-weight: bold } +.navigate td { padding: 4px 9px } .login { margin-top: 2px; margin-bottom: 2px; color: black;} .buttons { margin-left: 4px;} .fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0; @@ -73,7 +76,7 @@ img { border: 0; vertical-align: middle} .lostPassword a { font-size: 90%; color: white; padding-left: 1em;} .portlet { width: 150px; border-right: 1px solid #5F7983; background-color: #ededed} -.portletContent { margin: 9px; } +.portletContent { margin: 4px 9px } .portletTitle { font-weight: bold; font-size: 110%; margin-bottom: 4px;} .portletCurrent { font-weight: bold; } .portletSep { border-top: 1px solid #5F7983; margin-top: 2px;} @@ -113,21 +116,20 @@ img { border: 0; vertical-align: middle} text-align: center; color: white; } .odd { background-color: #f9f9f9; } .even { background-color: #f4f4f4; } -.summary {margin-bottom: 5px;} +.summary { margin-bottom: 5px; background-color: #e9e9e9; + border: 1px dashed grey } .objectTitle { font-size: 11pt; border-bottom: 3px solid grey; font-weight: bold;} -.by { padding-top: 5px; color: grey; font-size: 97% } -.underTitle { background-color: #e9e9e9 } -.objectNavigate { margin-top: 3px;} +.by { padding: 5px; color: grey; font-size: 97% } .underline { border-bottom: 1px dotted grey;} .state { font-weight: bold; border-bottom: 1px dashed grey;} .historyLabel { font-variant: small-caps; font-weight: bold;} -.history td { border-top: 1px solid grey;} -.history th { font-style: italic; text-align; left;} +.history td { border-top: 1px solid grey; padding: 0 5px 0 5px } +.history th { font-style: italic; text-align: left; padding: 0 5px 0 5px } .topSpace { margin-top: 15px;} .bottomSpace { margin-bottom: 15px;} .discreet { color: grey} -.pageLink { padding-left: 6px; font-style: italic} +.pageLink { padding-left: 8px } .footer { font-size: 95% } .footer td { background-color: #CBCBC9; border-top: 1px solid grey; padding: 0.4em 1em 0.5em } diff --git a/gen/ui/edit.pt b/gen/ui/edit.pt index fe6f7db..e4a8a05 100644 --- a/gen/ui/edit.pt +++ b/gen/ui/edit.pt @@ -1,10 +1,8 @@ -
- - Buttons for going to next/previous elements if this one is among bunch of referenced or searched objects. - currentNumber starts with 1. - - - - Go to the source URL (search or referred object) - - Go to the first page - - Go to the previous page - - Explain which element is currently shown - - Go to the next page - - Go to the last page - - -
  -  // -    -
-
+ + Buttons for going to next/previous elements if this one is among bunch of referenced or searched objects. + currentNumber starts with 1. + + +
+ Go to the source URL (search or referred object) + + Go to the first page + + Go to the previous page + + Explain which element is currently shown +   +  // +    + + Go to the next page + + Go to the last page + +
+
+ + + + + + + This macro displays up/down arrows in a table header column for sorting a given column. diff --git a/gen/ui/page.pt b/gen/ui/page.pt index 68e800e..35d0146 100644 --- a/gen/ui/page.pt +++ b/gen/ui/page.pt @@ -183,14 +183,8 @@ Information that is common to all tabs (object title, state, etc) - Title - - - Object history - +
- - -
+ Creator and last modification date Plus/minus icon for accessing history @@ -225,7 +219,7 @@
diff --git a/gen/ui/portlet.pt b/gen/ui/portlet.pt index ac71fa3..bec1410 100644 --- a/gen/ui/portlet.pt +++ b/gen/ui/portlet.pt @@ -50,25 +50,19 @@ appUrl app/absolute_url; currentSearch req/search|nothing; currentClass req/className|nothing; - contextObj tool/getPublishedObject; - rootClasses tool/getRootClasses"> + rootClasses tool/getRootClasses; + phases python: contextObj and contextObj.getAppyPhases() or None"> -
-
- - - - -
+ -
+ One section for every searchable root class. A separator if required
+ tal:condition="python: (nb != 1) or ((nb == 1) and phases)">
Section title (link triggers the default search), with action icons @@ -119,9 +113,8 @@ This macro displays, within the portlet, the navigation tree for the currently shown object, made of phases and contained pages. - The box containing phase-related information diff --git a/gen/ui/template.pt b/gen/ui/template.pt index 86a6235..10f3921 100644 --- a/gen/ui/template.pt +++ b/gen/ui/template.pt @@ -10,6 +10,8 @@ req python: request; resp req/RESPONSE; lang tool/getUserLanguage; + layoutType tool/getLayoutType; + contextObj python: tool.getPublishedObject(layoutType); dir python: tool.getLanguageDirection(lang); dleft python: (dir == 'ltr') and 'left' or 'right'; dright python: (dir == 'ltr') and 'right' or 'left'; @@ -35,7 +37,7 @@
- +
Links to main pages + The navigation strip + + +
Portlet - Page content diff --git a/gen/ui/view.pt b/gen/ui/view.pt index 172994b..0e3d108 100644 --- a/gen/ui/view.pt +++ b/gen/ui/view.pt @@ -1,10 +1,8 @@
+