def getObjectDefaultView(context): """Get the id of an object's default view """ # courtesy of Producs.CacheSetup browserDefault = IBrowserDefault(context, None) if browserDefault is not None: try: return stripLeadingCharacters(browserDefault.defaultView()) except AttributeError: # Might happen if FTI didn't migrate yet. pass if not IDynamicType.providedBy(context): return None fti = context.getTypeInfo() try: # XXX: This isn't quite right since it assumes the action starts #with ${object_url} action = fti.getActionInfo('object/view')['url'].split('/')[-1] except ValueError: # If the action doesn't exist, stop return None # Try resolving method aliases because we need a real template_id here if action: action = fti.queryMethodID(action, default = action, context = context) else: action = fti.queryMethodID('(Default)', default = action, context = context) return stripLeadingCharacters(action)
def _lookupTypeActionTemplate(self, actionId): context = aq_inner(self.context) if not IDynamicType.providedBy(context): # No type info available, so no actions to consult return None fti = context.getTypeInfo() actions = fti.listActionInfos(actionId, context, False, False, False) if not actions: # Action doesn't exist return None url = actions[0]['url'] if url.rstrip('/') == self.object_url().rstrip('/'): # (Default) action action = '(Default)' else: # XXX: This isn't quite right since it assumes the action starts # with ${object_url} action = url.split('/')[-1] # Try resolving method aliases because we need a real template_id here action = fti.queryMethodID(action, default=action, context=context) # Strip off leading / if action and action[0] == '/': action = action[1:] return action
def _lookupTypeActionTemplate(self, actionId): context = aq_inner(self.context) if not IDynamicType.providedBy(context): # No type info available, so no actions to consult return None fti = context.getTypeInfo() actions = fti.listActionInfos(actionId, context, False, False, False) if not actions: # Action doesn't exist return None url = actions[0]['url'] if url.rstrip('/') == self.object_url().rstrip('/'): # (Default) action action = '(Default)' else: # XXX: This isn't quite right since it assumes the action starts with ${object_url} action = url.split('/')[-1] # Try resolving method aliases because we need a real template_id here action = fti.queryMethodID(action, default=action, context=context) # Strip off leading / if action and action[0] == '/': action = action[1:] return action
def __call__(self): if DebugModeActive: alsoProvides(self.request, IGlowormLayer) # TODO What was this for again? from plone.app.layout.globals.interfaces import IViewView alsoProvides(self.request, IViewView) # Apply debug flags to the request self.request.debug = DebugFlags() self.request.debug.showTAL = True self.request.debug.sourceAnnotations = True # Find the actual content object in the context # Calling @@inspect on object/view results in view being self.context contentObject = self.context while not IDynamicType.providedBy(contentObject): contentObject = contentObject.aq_inner.aq_parent context_state = getMultiAdapter((contentObject, self.request), name='plone_context_state') templateId = context_state.view_template_id() template = contentObject.unrestrictedTraverse(templateId) # template = contentObject.unrestrictedTraverse(templateId and '@@%s' % templateId) renderedTemplate = template() # Insert the GloWorm panel and wrap the page content in a wrapper div so that we # can break the two into two different panels. To do that, we're forced to # do some ill-conceived html parsing. BeautifulSoup appears to be changing pages # with the TAL included, closing some tags that it shouldn't be and that breaks # the page layout. Javascript methods do the same. So, for now, we're stuck with # REGEX. glowormPanel = self.glowormPanelTemplate(self.context, self.request) regexp = r"(\</?body[^\>]*\>)([\S\s]*)(</body>)" replace = r""" \1 <div id='glowormPageWrapper' class='kssattr-insideInspectableArea-True'> \2 </div> <!-- Close glowormPageWrapper --> %s \3 """ % glowormPanel updatedTemplate = re.sub(regexp, replace, renderedTemplate) # For cross-browser compatability (ie. everything, not just Firefox), we need to: # 1) Remove anything before the doctype docString = re.search(r'(<!DOCTYPE[^\>]*\>)', updatedTemplate).group() # 2) Remove anything between the doctype and <html> declaration # 3) Remove anything after the closing </html> htmlBlock = re.search(r'\<html[\S\s]*\<\/html>', updatedTemplate).group() updatedTemplate = docString + htmlBlock # 4) Insert the metal and tal namespaces into the html declaration updatedTemplate = re.sub(r"(\<html[^\>]*)([\>])", r"""\1 xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:tal="http://xml.zope.org/namespaces/tal"\2""", updatedTemplate) return updatedTemplate else: return "Please enable Zope debug/development mode to continue."
def isDiscussionAllowedFor( self, content ): """ Get boolean indicating whether discussion is allowed for content. """ if hasattr( aq_base(content), 'allow_discussion' ): return bool(content.allow_discussion) if IDynamicType.providedBy(content): # Grabbing type information objects only works for dynamic types typeInfo = content.getTypeInfo() if typeInfo: return bool( typeInfo.allowDiscussion() ) return False
def isDiscussionAllowedFor(self, content): """ Get boolean indicating whether discussion is allowed for content. """ if hasattr(aq_base(content), 'allow_discussion'): return bool(content.allow_discussion) if IDynamicType.providedBy(content): # Grabbing type information objects only works for dynamic types typeInfo = content.getTypeInfo() if typeInfo: return bool(typeInfo.allowDiscussion()) return False
def up_info(self): up_obj = self.context.aq_inner.aq_parent mtool = self._getTool('portal_membership') allowed = mtool.checkPermission(ListFolderContents, up_obj) if allowed: if IDynamicType.providedBy(up_obj): up_url = up_obj.getActionInfo('object/folderContents')['url'] return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(), 'id': up_obj.getId(), 'url': up_url} else: return {'icon': '', 'id': 'Root', 'url': ''} else: return {}
def up_info(self): """Link to the contens view of the parent object""" up_obj = aq_parent(aq_inner(self.context)) mtool = getUtility(IMembershipTool) allowed = mtool.checkPermission(ListFolderContents, up_obj) if allowed: if IDynamicType.providedBy(up_obj): up_url = up_obj.getActionInfo('object/folderContents')['url'] return {'icon': '%s/UpFolder_icon.gif' % self._getPortalURL(), 'id': up_obj.getId(), 'url': up_url} else: return {'icon': '', 'id': 'Root', 'url': ''} else: return {}
def getObjectDefaultView(context): """Get the id of an object's default view """ # courtesy of Producs.CacheSetup browserDefault = IBrowserDefault(context, None) if browserDefault is not None: try: return browserDefault.defaultView() except AttributeError: # Might happen if FTI didn't migrate yet. pass if not IDynamicType.providedBy(context): return None fti = context.getTypeInfo() try: # XXX: This isn't quite right since it assumes the action starts with ${object_url} action = fti.getActionInfo('object/view')['url'].split('/')[-1] except ValueError: # If the action doesn't exist, stop return None # Try resolving method aliases because we need a real template_id here if action: action = fti.queryMethodID(action, default=action, context=context) else: action = fti.queryMethodID('(Default)', default=action, context=context) # Strip off leading / and/or @@ if action and action[0] == '/': action = action[1:] if action and action.startswith('@@'): action = action[2:] return action
def update(self): self.path = '/'.join(self.context.getPhysicalPath()) self.cls = self.context.__class__ self.fti = None self.methodAliases = None if IDynamicType.providedBy(self.context): self.fti = self.context.getTypeInfo() self.methodAliases = sorted(self.fti.getMethodAliases().items()) self.defaultView = None self.viewMethods = [] if IDynamicViewTypeInformation.providedBy(self.fti): self.defaultView = self.fti.defaultView(self.context) self.viewMethods = self.fti.getAvailableViewMethods(self.context) directly_provided = directlyProvidedBy(self.context) self.provided = list(providedBy(self.context).flattened()) self.provided.sort(key=lambda i: i.__identifier__) self.provided = ({ 'dottedname': i.__identifier__, 'is_marker': i in directly_provided } for i in self.provided) self.views = [] generator = getAdapters(( self.context, self.request, ), Interface) while True: try: name, view = generator.next() if not IView.providedBy(view): continue cls = view.__class__ module = cls.__module__ template = None if isinstance(view, ViewMixinForTemplates): template = view.index.filename else: for attr in ('index', 'template', '__call__'): pt = getattr(view, attr, None) if hasattr(pt, 'filename'): template = pt.filename break # Deal with silly Five metaclasses if (module == 'Products.Five.metaclass' and len(cls.__bases__) > 0): cls = cls.__bases__[0] elif cls == ViewMixinForTemplates: cls = None self.views.append({ 'name': name, 'class': cls, 'template': template, }) except StopIteration: break except: # Some adapters don't initialise cleanly pass self.views.sort(key=lambda v: v['name']) self.methods = [] self.variables = [] _marker = object() for name in sorted(dir(aq_base(self.context))): attr = getattr(aq_base(self.context), name, _marker) if attr is _marker: continue # FIXME: Should we include ComputedAttribute here ? [glenfant] if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)): self.variables.append({ 'name': name, 'primitive': True, 'value': attr, }) elif (isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or attr.__class__.__name__ == 'method-wrapper', ): source = None if name.endswith('__roles__'): # name without '__roles__' is the last in self.methods since we're in a sorted(...) loop if callable(attr): secu_infos = attr() else: secu_infos = attr if secu_infos is None: secu_label = 'Public' else: secu_label = '' try: secu_label += 'Roles: ' + ', '.join( [r for r in secu_infos[:-1]]) except TypeError: # Avoid "TypeError: sequence index must be # integer, not 'slice'", which occurs with the # ``C`` security implementation. This is a rare # case. In development you normally use the # ``Python`` security implementation, where this # error doesn't occur. pass secu_label += '. Permission: ' + secu_infos[-1][ 1:-11] # _x_Permission -> x self.methods[-1]['secu_infos'] = secu_label else: try: source = inspect.getsourcefile(attr) except TypeError: None signature = name + "()" try: signature = name + inspect.formatargspec( *inspect.getargspec(attr)) except TypeError: pass self.methods.append({ 'signature': signature, 'filename': source, 'help': inspect.getdoc(attr), }) else: self.variables.append({ 'name': name, 'primitive': False, 'value': str(attr), })
def update(self): # Tell BeautifulSoup that viewlets and viewletmanagers can be nested. BeautifulSoup.NESTABLE_TAGS['tal:viewlet']=['tal:viewletmanager'] BeautifulSoup.NESTABLE_TAGS['tal:viewletmanager']=['tal:viewlet'] # Render the current page and strip out everything but the <tal:viewletmanager> and <tal:viewlet> tags. # TODO We probably don't need BeautifulSoup anymore since we've got such a simple parsetree. # We need the GloWorm specific browser layer in there so that we can see the tal:viewlet* tags. alsoProvides(self.request, IGlowormLayer) # Find the object providing IDynamicType, that's what we want to inspect # Otherwise, we get errors relating to getTypeInfo() contentObject = self.context while not IDynamicType.providedBy(contentObject): contentObject = contentObject.aq_inner.aq_parent context_state = getMultiAdapter((contentObject, self.request), name='plone_context_state') templateId = context_state.view_template_id() # There are instances in which the enclosing view is named 'index' that calling a traverse to 'index' # actually gets this viewlet's index method. Prepending the '@@' seems to take care of that. # So, either traverse to @@templateId or nothing depending on the value of templateId. try: template = contentObject.unrestrictedTraverse(templateId and '@@%s' % templateId) except AttributeError: # The template isn't a view, just call it without the @@ template = contentObject.unrestrictedTraverse(templateId) renderedTemplate = template() strippedHTML = ''.join((re.findall('(<\/?tal:viewlet/?[^\>]*>)', renderedTemplate))) # Soupify the simplified HTML soup = BeautifulSoup(strippedHTML) self.documentTree = [] self.outstr = "" def getChildViewletManagers(node): """ Find all viewletmanagers within this node """ all = node.findAll('tal:viewletmanager') stripped = [] self.outstr += "<ol class='viewletmanager-tree'>" for v in all: if not(stripped and v.findParent('tal:viewletmanager') and stripped[-1] in v.findParents('tal:viewletmanager')): rawname = v.attrs[0][1][27:] # 27 = len('kssattr-viewletmanagername-') # Break off any extra class names # TODO We should really be safe and check for classes before and after. rawname = rawname.split(' ',1)[0] name = rawname.replace('-','.') # Get the viewletmanager object managerObj = findViewletManager(self, name) if managerObj and not IAmIgnoredByGloworm.providedBy(managerObj): self.outstr += "<li><a href='#' title='Viewlet Manager %s' class='inspectViewletManager kssattr-forviewletmanager-%s'>%s</a>" % (name, name.replace('.', '-'), name) # Look up the viewlets attached to this viewlet manager. # We do it this way because calling viewletManager.viewlets won't see the hidden viewlets... containedViewlets = getAdapters((self.context, self.request, managerObj.__parent__, managerObj),IViewlet) containedViewlets = managerObj.sort([vl for vl in containedViewlets]) stripped.append(v) getChildViewlets(v, containedViewlets) self.outstr += "</li>" self.outstr += "</ol>" return stripped def getChildViewlets(node, allViewlets=[]): """ Find all viewlets within this node """ all = node.findAll('tal:viewlet') stripped = [] self.outstr += "<ol class='viewlet-tree'>" def writeHiddenViewlet(viewlet): """ Create a list item HTML bit for a hidden viewlet """ name = viewlet[0] managerObj = viewlet[1].manager viewletHash = hashViewletInfo(name, managerObj.__name__, getProvidedForViewlet(name, managerObj)) return "<li><a href='#' title='Hidden viewlet %s' class='viewletMoreInfo hiddenViewlet kssattr-forviewlet-%s'>%s</a></li>" % (name, viewletHash, name) for v in all: if not(stripped and v.findParent('tal:viewlet') and stripped[-1] in v.findParents('tal:viewlet')): viewletHash = v.attrs[0][1][20:] # 20 = len('kssattr-viewlethash-') # Break off any extra class names # TODO We should really be safe and check for classes before and after. viewletHash = viewletHash.split(' ',1)[0] reg = findTemplateViewRegistrationFromHash(viewletHash) if reg: while allViewlets and reg.name != allViewlets[0][0]: self.outstr += writeHiddenViewlet(allViewlets[0]) allViewlets.pop(0) if not IAmIgnoredByGloworm.providedBy(allViewlets[0][1]): self.outstr += "<li><a href='#' title='Visible viewlet %s' class='viewletMoreInfo kssattr-forviewlet-%s'>%s</a>" % (reg.name, viewletHash, reg.name) stripped.append(v) getChildViewletManagers(v) self.outstr += "</li>" allViewlets.pop(0) # Remove the current viewlet from the allViewlets list # Collect any remaining hidden viewletss if allViewlets: for vlt in allViewlets: self.outstr += writeHiddenViewlet(vlt) self.outstr += "</ol>" return stripped getChildViewletManagers(soup)
def update(self): self.path = '/'.join(self.context.getPhysicalPath()) self.cls = self.context.__class__ self.fti = None self.methodAliases = None if IDynamicType.providedBy(self.context): self.fti = self.context.getTypeInfo() self.methodAliases = sorted(self.fti.getMethodAliases().items()) self.defaultView = None self.viewMethods = [] if IDynamicViewTypeInformation.providedBy(self.fti): self.defaultView = self.fti.defaultView(self.context) self.viewMethods = self.fti.getAvailableViewMethods(self.context) directly_provided = directlyProvidedBy(self.context) self.provided = list(providedBy(self.context).flattened()) self.provided.sort(key=lambda i: i.__identifier__) self.provided = ({'dottedname': i.__identifier__, 'is_marker': i in directly_provided} for i in self.provided) self.views = [] generator = getAdapters((self.context, self.request,), Interface) while True: try: name, view = generator.next() if not IView.providedBy(view): continue cls = view.__class__ module = cls.__module__ template = None if isinstance(view, ViewMixinForTemplates): template = view.index.filename else: for attr in ('index', 'template', '__call__'): pt = getattr(view, attr, None) if hasattr(pt, 'filename'): template = pt.filename break # Deal with silly Five metaclasses if ( module == 'Products.Five.metaclass' and len(cls.__bases__) > 0 ): cls = cls.__bases__[0] elif cls == ViewMixinForTemplates: cls = None self.views.append({ 'name': name, 'class': cls, 'template': template, }) except StopIteration: break except: # Some adapters don't initialise cleanly pass self.views.sort(key=lambda v: v['name']) self.methods = [] self.variables = [] _marker = object() for name in sorted(dir(aq_base(self.context))): attr = getattr(aq_base(self.context), name, _marker) if attr is _marker: continue # FIXME: Should we include ComputedAttribute here ? [glenfant] if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)): self.variables.append({ 'name': name, 'primitive': True, 'value': attr, }) elif ( isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or attr.__class__.__name__ == 'method-wrapper', ): source = None if name.endswith('__roles__'): # name without '__roles__' is the last in self.methods since we're in a sorted(...) loop if callable(attr): secu_infos = attr() else: secu_infos = attr if secu_infos is None: secu_label = 'Public' else: secu_label = '' try: secu_label += 'Roles: ' + ', '.join([r for r in secu_infos[:-1]]) except TypeError: # Avoid "TypeError: sequence index must be # integer, not 'slice'", which occurs with the # ``C`` security implementation. This is a rare # case. In development you normally use the # ``Python`` security implementation, where this # error doesn't occur. pass secu_label += '. Permission: ' + secu_infos[-1][1:-11] # _x_Permission -> x self.methods[-1]['secu_infos'] = secu_label else: try: source = inspect.getsourcefile(attr) except TypeError: None signature = name + "()" try: signature = name + inspect.formatargspec(*inspect.getargspec(attr)) except TypeError: pass self.methods.append({ 'signature': signature, 'filename': source, 'help': inspect.getdoc(attr), }) else: self.variables.append({ 'name': name, 'primitive': False, 'value': str(attr), })
def update(self): self.path = '/'.join(self.context.getPhysicalPath()) self.cls = self.context.__class__ self.fti = None self.methodAliases = None if IDynamicType.providedBy(self.context): self.fti = self.context.getTypeInfo() self.methodAliases = sorted(self.fti.getMethodAliases().items()) self.defaultView = None self.viewMethods = [] if IDynamicViewTypeInformation.providedBy(self.fti): self.defaultView = self.fti.defaultView(self.context) self.viewMethods = self.fti.getAvailableViewMethods(self.context) self.provided = list(providedBy(self.context).flattened()) self.provided.sort(key=lambda i: i.__identifier__) self.views = [] generator = getAdapters((self.context, self.request,), Interface) while True: try: name, view = generator.next() if not IView.providedBy(view): continue cls = view.__class__ module = cls.__module__ template = None if isinstance(view, ViewMixinForTemplates): template = view.index.filename else: for attr in ('index', 'template', '__call__'): pt = getattr(view, attr, None) if hasattr(pt, 'filename'): template = pt.filename break # Deal with silly Five metaclasses if ( module == 'Products.Five.metaclass' and len(cls.__bases__) > 0 ): cls = cls.__bases__[0] elif cls == ViewMixinForTemplates: cls = None self.views.append({ 'name': name, 'class': cls, 'template': template, }) except StopIteration: break except: # Some adapters don't initialise cleanly pass self.views.sort(key=lambda v: v['name']) self.methods = [] self.variables = [] _marker = object() for name in sorted(dir(aq_base(self.context))): attr = getattr(aq_base(self.context), name, _marker) if attr is _marker: continue if isinstance(attr, (int, long, float, basestring, bool, list, tuple, dict, set, frozenset)): self.variables.append({ 'name': name, 'primitive': True, 'value': attr, }) elif ( isinstance(attr, (types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType)) or attr.__class__.__name__ == 'method-wrapper', ): source = None try: source = inspect.getsourcefile(attr) except TypeError: None signature = name + "()" try: signature = name + inspect.formatargspec(*inspect.getargspec(attr)) except TypeError: pass self.methods.append({ 'signature': signature, 'filename': source, 'help': inspect.getdoc(attr), }) else: self.variables.append({ 'name': name, 'primitive': False, 'value': str(attr), })