i'm trying to set portlet preferences, without touch the portlet.xml.
Here is my portlet :
-myportletclass
-myportletjsp
-myconclass
-myconfjsp
When I click on preferences, I can see the confjsp, wich display a form for my preferences. And, when I submit it, set the preferences to the values in the form.
But I don't have any default values, without modify the portlet.xml.
What shoul I add and where?
I saw some do it in the render of the config class, but it doesn't work their way.
Regards.
Thank you.
edit : the way i set my preferences :
first, i have a simple form i my conf jsp, basic, no need to add it;
Then, i have the ConfController :
#Controller
#RequestMapping("EDIT")
public class ConfigurationController {
#ModelAttribute("validatePref")
public ValidatePrefForm getValidatePrefForm() {
ValidatePrefForm form = new ValidatePrefForm();
return form;
}
#ActionMapping(params = "action=validatePref")
public void processAction(#ModelAttribute("validatePref") ValidatePrefForm form,
PortletPreferences portletPreferences, ActionResponse response)
throws Exception {
String mylink = form.getMylink();
if (null != mylink && !mylink .equals("")) {
portletPreferences.setValue("mylink ", mylink );
}
portletPreferences.store();
}
#RenderMapping
public String render() throws Exception {
return "myportletjsp.jsp";
}
}
And then, in my portlet i have this to get the value:
mylink= preferences.getValue("mylink", mylink);
if(null==mylink){
mylink= mydefaultUrl;
}
And then i can use mylink
First of all: portlet.xml is an excellent place to have default portlet preferences.
If you absolutely don't want this for some reason, of course you can check if the preference is null, then assume your defaults. Simply do this whereever you retrieve the portlet preferences - in the action-, render-, event- or resource-phase.
Related
I'm using Orchard 1.9.3 and have set up a couple of custom ContentTypes that mimic the standard Page type with an Autoroute and Layout Part etc.
These types of pages should never be set as the homepage so I want to hide just the Set as home page field of the Autoroute part but only for my custom types. I'm not sure what the most efficient way is to go about this. Can I target this field specifically in a placement file?
You can override the Parts.Autoroute.Edit.cshtml and include some custom logic:
#{
var canSetAsHomePage = true;
var myTypesToDisableHomePageFor = ["MyCustomContentType", "AnotherCustomContentType"];
if (myTypesToDisableHomePageFor.Contains(Model.ContentType)) {
canSetAsHomePage = false;
}
}
// ..
#if (!Model.IsHomePage && canSetAsHomePage) {
if (AuthorizedFor(Permissions.SetHomePage)) {
// ..
For this to work you also have to add an extra property to Orchard.Autoroute.ViewModels.AutoroutePartEditViewModel:
public class AutoroutePartEditViewModel {
...
public string ContentType { get; set; }
}
and make sure to set it in the Editor method of Orchard.Autoroute.Drivers.AutoroutePartDriver:
var viewModel = new AutoroutePartEditViewModel {
CurrentUrl = part.DisplayAlias,
Settings = settings,
ContentType = part.ContentItem.ContentType
};
I have created my navigation menus in Orchard using a mix of Content Item and Custom Link Elements (parts of the website are outside the scope of the CMS). Now there are a couple of links that I need to open in a new window/tab, basically the target="_blank" behaviour.
SInce the original Custom Link does not have any parameters I tried to create an extended version of it. In the admin backend I went to "Content definition" looked up Custom Link and tried to create a copy of it, then add a target field that I could check for and use in my theme's Menu.cshtml file.
However I can't even get the basic carbon copy of the Custom Link item working. It has the same stereotype, same Parts, same Forms (none) as the original Custom Link, and it does appear in the list of items on the admin -> navigation window. However the item does not have a field for the URL/link. It only has the field for Menu Text, nothing else.
So my question is 2-tiered:
How can I get a carbon copy of the Custom Link item type working in my Orchard backend navigation?
When I have my copy of the Custom Link working and add a text field named target, how can I access its value in the Menu.cshtml view?
(I tried simply adding a URL field to my copy, that would then show up in the navigation editor, however the navigation itself would ignore it in the output and create a link to the content item id instead).
Any help is greatly appreciated!
Edit: Here are some screenshots to better illustrate the problem, maybe they can help pin down the problem.
Seems like you've done everything right. Please double check if MenuItemPart is there. This part is responsible for holding the URL information and displaying an editor for it. Not sure if this part is attachable though - if it's not, then make it so in the Content Definition\Parts pane.
Instead of hardwiring things inside Menu.cshtml, you should create a file named MenuItemLink-[YourTypeName].cshtml. This shape file will be used to display your custom menu items. Then you can access any fields via Model.Content object, eg. Model.Content.YourTypeName.FieldWithTargetName.Value.
You need to use the MenuItemPart because it has a few important functions integrated into Orchard.Core.
This works fine:
AdvancedMenuItemPartRecord:
public class AdvancedMenuItemPartRecord : ContentPartRecord
{
public virtual string Target { get; set; }
public virtual string Classes { get; set; }
}
AdvancedMenuItemPart:
public class AdvancedMenuItemPart : ContentPart<AdvancedMenuItemPartRecord>
{
public string Target
{
get { return Retrieve(x => x.Target); }
set { Store(x => x.Target, value); }
}
public string Classes
{
get { return Retrieve(x => x.Classes); }
set { Store(x => x.Classes, value); }
}
}
AdvancedMenuItemPartDriver:
public class AdvancedMenuItemPartDriver : ContentPartDriver<AdvancedMenuItemPart>
{
protected override string Prefix
{
get { return "AdvancedMenuItem"; }
}
protected override DriverResult Editor(AdvancedMenuItemPart part, dynamic shapeHelper)
{
return ContentShape("Parts_AdvancedMenuItem_Edit", () => shapeHelper.EditorTemplate(TemplateName: "Parts/AdvancedMenuItem", Model: part, Prefix: Prefix));
}
protected override DriverResult Editor(AdvancedMenuItemPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
AdvancedMenuItemPartHandler (ActivatingFilter add MenuItemPart to your AdvancedMenuItem dynamicaly):
public class AdvancedMenuItemPartHandler : ContentHandler
{
public AdvancedMenuItemPartHandler(IRepository<AdvancedMenuItemPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
Filters.Add(new ActivatingFilter<MenuItemPart>("AdvancedMenuItem"));
}
}
Placement.info:
<Place Parts_AdvancedMenuItem_Edit="Content:11"/>
Migrations:
public int UpdateFrom2()
{
SchemaBuilder.CreateTable("AdvancedMenuItemPartRecord",
table => table
.ContentPartRecord()
.Column<string>("Target")
.Column<string>("Classes")
);
ContentDefinitionManager.AlterPartDefinition("AdvancedMenuItemPart", part => part
.WithDescription(""));
ContentDefinitionManager.AlterTypeDefinition("AdvancedMenuItem", cfg => cfg
.WithPart("AdvancedMenuItemPart")
.WithPart("MenuPart")
.WithPart("CommonPart")
.WithIdentity()
.DisplayedAs("Custom Link Advanced")
.WithSetting("Description", "Custom Link with target and classes fields")
.WithSetting("Stereotype", "MenuItem")
// We don't want our menu items to be draftable
.Draftable(false)
// We don't want the user to be able to create new ActionLink items outside of the context of a menu
.Creatable(false)
);
return 3;
}
MenuItemLink-AdvancedMenuItem.cshtml:
#{
var advancedPart = Model.Content.AdvancedMenuItemPart;
var tag = new TagBuilder("a");
tag.InnerHtml = WebUtility.HtmlDecode(Model.Text.Text);
tag.MergeAttribute("href", Model.Href);
if (!string.IsNullOrWhiteSpace(advancedPart.Target)) {
tag.MergeAttribute("target", advancedPart.Target);
}
if (!string.IsNullOrWhiteSpace(advancedPart.Classes))
{
tag.AddCssClass(advancedPart.Classes);
}
}
#Html.Raw(tag.ToString(TagRenderMode.Normal))
How does liferay list out the portlet to be shown in the control panel menu?
Can any body list the classes and JSP involved in the same?
Refer to file in your liferay source at location : \portal-web\docroot\html\portlet\control_panel_menu\view.jsp
You will get idea how liferay shows its control panel menu.
Link for code of this jsp.
All of the portlets are saved in the portlet table while we deploy them. Then once the control panel is accessed then liferay loads all of the portlet which are having the control panel entry in them. For better explanation see the below code in
com.liferay.portal.util.PortalImpl
#Override
public Set<Portlet> getControlPanelPortlets(long companyId, String category)
throws SystemException {
Set<Portlet> portletsSet = new TreeSet<Portlet>(
new PortletControlPanelWeightComparator());
if (Validator.isNull(category)) {
return portletsSet;
}
List<Portlet> portletsList = PortletLocalServiceUtil.getPortlets(
companyId);
for (Portlet portlet : portletsList) {
String portletCategory = portlet.getControlPanelEntryCategory();
if (category.equals(portletCategory) ||
(category.endsWith(StringPool.PERIOD) &&
StringUtil.startsWith(portletCategory, category))) {
portletsSet.add(portlet);
}
}
return portletsSet;
}
#Override
public List<Portlet> getControlPanelPortlets(
String category, ThemeDisplay themeDisplay)
throws SystemException {
Set<Portlet> portlets = getControlPanelPortlets(
themeDisplay.getCompanyId(), category);
return filterControlPanelPortlets(portlets, themeDisplay);
}
The above code is called from the
\portal-web\docroot\html\portlet\control_panel_menu\view.jsp
Map<String, List<Portlet>> siteAdministrationCategoriesMap = PortalUtil.getSiteAdministrationCategoriesMap(request);
Help taken from pankaj-kathiriya answer. Thanks for the same.
I was attending an interview last week and interviewer asked me, how you add a portlet in liferay?
I just replied, while creating a plugin project in eclipse a option appears Add to control panel that is the way i use to add portlet in control panel.
and he asked again when you do that what liferay does initially and i was like unanswered.
can any one please explain it?
All of the portlets are saved in the portlet table while we deploy them. Then once the control panel is accessed then liferay loads all of the portlet which are having the control panel entry in them. For better explanation see the below code in
com.liferay.portal.util.PortalImpl
#Override
public Set<Portlet> getControlPanelPortlets(long companyId, String category)
throws SystemException {
Set<Portlet> portletsSet = new TreeSet<Portlet>(
new PortletControlPanelWeightComparator());
if (Validator.isNull(category)) {
return portletsSet;
}
List<Portlet> portletsList = PortletLocalServiceUtil.getPortlets(
companyId);
for (Portlet portlet : portletsList) {
String portletCategory = portlet.getControlPanelEntryCategory();
if (category.equals(portletCategory) ||
(category.endsWith(StringPool.PERIOD) &&
StringUtil.startsWith(portletCategory, category))) {
portletsSet.add(portlet);
}
}
return portletsSet;
}
#Override
public List<Portlet> getControlPanelPortlets(
String category, ThemeDisplay themeDisplay)
throws SystemException {
Set<Portlet> portlets = getControlPanelPortlets(
themeDisplay.getCompanyId(), category);
return filterControlPanelPortlets(portlets, themeDisplay);
}
The above code is called from the
\portal-web\docroot\html\portlet\control_panel_menu\view.jsp
Map<String, List<Portlet>> siteAdministrationCategoriesMap = PortalUtil.getSiteAdministrationCategoriesMap(request);
Experts pl correct me if I am wrong.
I've got the following problem:
I created a WebPart with a ToolPart,
this toolpart has multiple controls (textbox, dropdownlist, ...)
when I fill in everything and apply, it all goes ok,
even when i press ok. But when i go back to
edit -> modify webpart, all my data i've entered is gone.
How can i solve this?
Thanks
You'll need to save the values from the Toolpart in the webpart's properties. For example, lets say I want to save a string for "Title"... in the webpart define a property:
private const string DEFAULT_WPPColumnTitle = "Title";
private string _WPPColumnTitle = DEFAULT_WPPColumnTitle;
[Browsable(false)]
[WebPartStorage(Storage.Shared)]
public string WPPColumnTitle
{
get { return this._WPPColumnTitle; }
set { this._WPPColumnTitle = value; }
}
I always use the prefix "WPP" to keep all the web part properties together.
Then, in the Toolpart's ApplyChanges override, save the control's value (_ddlColumnsTitle) to the webpart (WPPColumnTitle):
/// <summary>
/// Called by the tool pane to apply property changes to
/// the selected Web Part.
/// </summary>
public override void ApplyChanges()
{
// get our webpart and set it's properties
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
et.WPPColumnTitle = _ddlColumnsTitle.SelectedValue;
}
Lastly, if the user edited the properties already, we want the Toolpart to be pre-populated with the user's configuration. In the CreateChildControls() method of your Toolpart, initialize the controls:
protected override void CreateChildControls()
{
try
{
MyCustomWebPart et = (MyCustomWebPart)ParentToolPane.SelectedWebPart;
// ... code to create _ddlColumnsTitle and add it to the Controls
// default our dropdown to the user's selection
ListItem currentItem = _ddlColumnsTitle.Items.FindByValue(et.WPPColumnTitle);
if (null != currentItem)
{
_ddlColumnsTitle.SelectedValue = currentItem.Value;
}
}
catch (Exception ex)
{
_errorMessage = "Error adding edit controls. " + ex.ToString();
}
}
Open up the debugger and double check that the values are getting applied to your propertries on Apply (i.e. WPPColumnTitle is set).
If so then problem is that SharePoint is not serializing/deserializing the value from the property (WPPColumnTitle) to the database and back - verify by writing out this property on the web part - as soon as you leave the page and come back it will be empty.
If so then check things like this on class
[XmlRoot(Namespace = "YourNamespace")]
and this (not strictly necessary) on properties
[XmlElement(ElementName = "ColumnTitle")]
I've also seen problems if you name your web part class "WebPart" so call it MyWebPart
I've solved it with adding a property in my webpart "IsNeverSet" (bool)
and when i go to the "CreateControls()" of my toolpart, I get this property
and if it's false, I load all the properties from my webpart and fill them in the toolpart.
So I found it with the help of Kit Menke