I'd like to render an object's view in place of another object and yet keep the canonical path as the one originally traversed to so breadcrumbs and object tabs, etc all still act the same.
I know how to render the other object in place of the canonical one, but it almost seems impossible to override what is used for the canonical object unless I perhaps override the "canonical_object" method in the "plone_context_state" browser view.
Here is the code I have my view call method for rendering the other object:
item = aq_base(default_item).__of__(self.context)
layout = item.getLayout() or item.getDefaultLayout()
try:
return aq_acquire(item, layout)(*args, **kwargs)
except AttributeError:
try:
return getMultiAdapter((item, self.request), name=layout)(*args, **kwargs)
except: pass
return super(DefaultItemEnabledView, self).__call__(*args, **kwargs)
Now, is it possible to make the canonical object used by plone the originally traversed one so breadcrumbs, object tabs, etc are applied appropriately?
I am afraid that what you want is an impossible task; you are rendering the full chrome for a new context and everything will thus render using that context. You'd have to redo everything; breadcrumbs, actions, portlets, any other context-sensitive viewlets.
I am not sure what your use-case is that you have to support all possible layouts of arbitrary objects, you may have to rethink your options here.
If you do not have a use-case that requires all possible layouts to work, then you can just create a custom view for your canonical object that just re-renders the content well for the other object. Many views for content already include macros you can re-use, for example. Take a look at skins/plone_content/folder_full_view_item.pt for an example template that reuses such macros to render items in a folder for the folder_full_view template.
bda.contentproxy was a product that make this, but be aware... is a very complex task, full of problems behind the corner
Related
I have a Plone 4 site where I currently use the following method to embed objects (e.g. images, videos, tables …) in user-editable HTML content:
I have a custom transform browser which takes HTML text and transforms all a and img elements which refer to an element by UID (i.e., which have an href="…/resolveuid/abc123…" or src="…/resolveuid/abc123…").
My view templates read the text field and let that browser transform it;
the browser has a Python dict TYPE2TEMPLATE which has portal_type keys and template_id values;
for each a or img which refers to an object by UID,
the object is fetched by o = brain._unrestrictedGetObject()
the template id t_id is taken from the TYPE2TEMPLATE dict
the "embed" method is fetched by method = o.unrestrictedTraverse(t_id)
that method is called (in some cases with some keyword arguments), and the result - which is contained in one top HTML element - replaces the "raw" a or img element.
Now that I'm developing an additional customization package (which contains new object types, now using Dexterity), I wonder whether there is some more "plonish" way. Is there, for example, some embed action?
i don't know of a package that does the same and what you're doing sounds sane to me ;-)
i just would use https://pypi.python.org/pypi/plone.outputfilters instead of your transform BrowserView.
if it's possible to explicitly mark links that should not be auto-embedded (eg via span.noEmbed a.internal-link selector) this could become a useful addon.
i guess for portal_type=='File' you'll need to check the mimetype too in order to decide if you're embedding a video file or something else...
other products i know of embed content outside of your plone site (eg. collective.embedly)
another approach would be a to use a tinymce plugin to genereate the proper embed html when editing the html-body of your page (i personally would not go this route because there are different tiny versions to support for 4.3 and 5.0 and we're not sure if tiny woun't be replaced as default editor in the future)
I have installed eea.facetednavigation and it works fine so far. But I want to register a new result view and don't know how to hook here.
Do I have to use a non-grokked view? Or is there a special interface that could be used for grok.context (This is what I've tried so far with IFacetedNavigable, but no success)
Update
As recommended, I declared my view with faceted:view in my configure.zcml
It does not work at all. I am on Plone4.3. I'm pretty shure that I declared the view as described in the example, but cannot select it in the dropdown. When I construct a request that tries to set my custom view, I get an Invalid view id error.
I can test the view, by appending the view name to a url with a folderish content. It works. Just the registration is not done entirely. I get some kss errors too, when I reinstall the affected addon. There may be a relation.
Update II
After deactivating and activating facetednavigation, the view appeared.
Look in eea.facetednavigation.views there is an example. Basically you'll need to register your view with zcml faceted:view meta directive.
I customized the eea.facetednavigation view only once, but it was really simple by using z3c.jbot (no need of ZCML or grok in this case).
I am writing a common Razor TBB, which will use in Component Template and Page template as per my requirement.
So that, I need a Page and Component object in the razor TBB according to applying TBB on Page Template and component Template
My requirement to display/use the metadata field values from Page/Component in specific area of the page.
That's why, i want to access metadata values by the object but unable to get the object,
Please also follow-up my comments with Frank.
Can any one suggest me?
Did you have a look at the (remarkably helpful) documentation that is available for the Razor mediator?
http://code.google.com/p/razor-mediator-4-tridion/
http://code.google.com/p/razor-mediator-4-tridion/downloads/detail?name=RazorMediatorDocumentation_v1.2.docx
These are full of examples that access the current Component and the Page. Just my 10 second search gives these fragments:
<body class=”#Page.Metadata.BodyClass”>
<div class=”#Component.Fields.NewsStyle”>
<img src=”#Fields.HeaderImage.ID” alt=”#Fields.HeaderImage.AltText” />
Edit: I see you added some more details in your follow-up comment. You might want to do as Bart suggests and add those details to the question. In the meantime, I'll spend a few more minutes searching the documentation for you.
The official documentation (the Word document I linked above), contains this example that seems to process metadata:
#foreach (var keyword in Publication.MetaData.SomeKeywordFields) {
<li>#keyword.Title (#keyword.Id)</li>
}
The output of the Razor template will become the Output item in the Package. So it doesn't make any sense to use a Razor mediator to process the Output item. For that you might as well use a regular C# (fragment or assembly) TBB.
Another edit: It seems that the Razor mediator's implicit Fields variable always maps to the Component fields and the Metadata variable always maps to the Component's meatadata fields. I've linked the above names to the relevant fragments on Google code for your convenience.
So you seem to have two options:
detect whether you are in Page or Component (e.g. by looking at whether the implicit Page variable is null or not) and then have conditional expressions everywhere (isInPage ? Page.Metadata : Metadata)
fix this limitation of the Razor mediator code yourself or hire someone to fix it for you
While working on a dexterity based project I needed one of my content types to support collective.quickupload by marking it with the IQuickUploadCapable interface.
What I'm currently doing is adding an 'implements' to my configure.zcml file:
`<class class="plone.dexterity.content.Container">
<implements interface="collective.quickupload.browser.interfaces.IQuickUploadCapable" />
</class>`
Since my content type is a Container this works however my first inclination was to use a grok style approach instead of declaring it in ZCML. What's the grok/dexterity way to tell my dexterity content type that it implements an additional interface, or should I stick to the current approach?
Also I tried adding the interface as a behaviour in my profiles/default/types/my.dexterity.content.xml file but this didn't work (I didn't really expect it to as behaviours serve a different purpose).
Sean's answer is good. The other way is to create a behaviour and apply that. You need to register the behaviour with:
<plone:behavior
title="Quickupload"
provides="collective.quickupload.browser.interfaces.IQuickUploadCapable"
/>
You can then add 'collective.quickupload.browser.interfaces.IQuickUploadCapable' to your list of behaviours in the FTI.
Your approach using is not good because it means all Container-based Dexterity types get the marker interface, not just your type.
Why not just subclass IQuickUploadCapable as a mixin after form.Schema in your type interface?
You can not use it as a behaviour because it doesn't claim to be used in that way.
As I read from pypi, is intended to be used in a portlet or in a viewlet.
To add it in a grok style you should:
from collective.quickupload.browser.interfaces import IQuickUploadCapable
from plone.directives import form
class IMyContent(form.schema):
grok.implements(IQuickUploadCapable)
And that's it!
Be sure that your content type allows files to be added inside it, so is both folderish and it allows files to be added (or it just doesn't restrict to any specific content type).
I have a dynamic PHP stylesheet, but I can't find a way to send variables to it so I used sessions instead. Figured this kinda sucked, so I'm going to give it another try but could need some help. It's an external stylesheet where a variable has effect through the whole document.
You probably want to use an embedded stylesheet (a <style> block) in the page: it increases the size of the main page, but solves the variable access issue without needing sessions and reduces your number of requests. You can just load your dynamic stylesheet into the main page's view using load->view.
EDIT: Ah, massive amounts of CSS would be one problem. Well, two alternatives are to:
Turn on the $_GET support in your CI install, you COULD pass in a request parameter in the CSS link and then check for the request parameter in the PHP controller or view file that generates the actual CSS. Not visually the tidiest option, but it does work.
Put in a cookie that you check in the controller that gets called for the CSS: you can then check that in the controller or view and do the right thing. Visually much tidier than the request parameter option, but a bit more involved.