Piranha CMS remove manager menu item - piranha-cms

In the documentation it states that you can remove default views from the interface. I have added a new menu item tab with the following code:
Piranha.WebPages.Manager.Menu.Where(m => m.InternalId == "Content").Single().Items.Add(
new Piranha.WebPages.Manager.MenuItem()
{
Name = "TSI Post",
Action = "Index",
Controller = "TSIPost",
Permission = "ADMIN_POST"
});
I want to remove the default Post tab.
I have attempted many variations of the following code.
Piranha.WebPages.Manager.Menu.Where(m => m.InternalId == "Content").Single().Items.Remove(
new Piranha.WebPages.Manager.MenuItem()
{
InternalId = "Posts",
Name = "Posts",
Action = "index",
Controller = "post",
Permission = "ADMIN_POST"
});
What would be the proper syntax to remove the tab?

The problem with your second chunk of code is that you're creating a totally new MenuItem that has not been added and then you try to remove it from the collection. This new object does not exist so nothing happens. To remove the default post page you'd probably need to write something like:
Manager.Menu.Where(m => m.InternalId == "Content")
.Single().Items.Remove(
Manager.Menu.Where(m => m.InternalId == "Content").Single()
.Items.Where(i => i.InternalId == "Posts").Single());
This statement removes the item with the internal id "Posts" present in the current menu collection.
Regards
HÃ¥kan

Related

MVC Viewbag correct Result count but displaying only item 1

Trying to use a viewbag on a create form (view) to let the user pick an "item" on the dropdown.
The dropdown displays and shows correct number of rows (tested) but only displays the first item for the X number of rows.
https://i.imgur.com/2179GTD.png "Image1"
Code of the view controller below as I didn't find any answers to this.
List<SelectListItem> Contracts = (from a in
db.v_xxx_yyyy_aaaa_contracts.Where(m => m.GroupID.ToString() ==
#group).Distinct().OrderBy(a => a.ContractID).ToList()
select new SelectListItem()
{
Value = a.ContractID,
Text = a.ContractID
}).ToList();
ViewBag.ContractID = Contracts;
Try something like
var contracts = db.v_xxx_yyyy_aaaa_contracts.Where(m => m.GroupID.ToString() == #group).Distinct().OrderBy(a => a.ContractID);
ViewBag.ContractID = new SelectList(contracts, "ContractID", "ContractID"); // here second one for display
The solution I found for this specific problem is found here!
Had to bypass the viewmodel with ViewData (SelectList) for it to work as I wanted.

MVC4 Razor DisplayTemplate called, HTML generated, but not rendered to browser

I've got a view that iterates a collection and calls DisplayFor() for each element in the collection.
I need to manually iterate (as opposed to passing the collection to DisplayFor) in order to tell the template if a break in the list should be drawn. The items in the list will only be of 2 types, ordered by them, so I only need to show this break once.
My template is found and called correctly.
I can see the HTML it generates correctly, ie: DisplayFor().ToHtmlString()
I can set this HTML as a scoped variable, ie: var html = DisplayFor().ToHtmlString() ..
But even Html.Raw(html) does not render it in the browser - the HTML has simply vanished.
What's going on?
var renderBreakInList = Model.Items.Any(x => x.IsSomeType);
foreach(var item in Model.Items)
{
var renderBreak = renderBreakInList && item.IsOtherType;
Html.DisplayFor(x => item, new { renderBreak = renderBreak });
if (renderBreak)
{
renderBreakInList = false;
}
}
The Html.DisplayFor method in itself does not render anything to the response just returns the generated HTML as a MvcHtmlString.
In order to actually write the rendered HTML to the response you need to tell this to Razor with using the # sign:
#Html.DisplayFor(x => item, new { renderBreak = renderBreak })
So your whole code should look like this:
#{
var renderBreakInList = Model.Items.Any(x => x.IsSomeType);
foreach(var item in Model.Items)
{
var renderBreak = renderBreakInList && item.IsOtherType;
#Html.DisplayFor(x => item, new { renderBreak = renderBreak })
if (renderBreak)
{
renderBreakInList = false;
}
}
}
Or you can use the WebPageBase.Write method (which gets called under the hood when using the # sign):
Write(Html.DisplayFor(x => item, new { renderBreak = renderBreak }));
finally figured this out after trying a lot of different things and reworking how I tell the Template to draw the break.
Rather than send a bool which I'd prefer to make the template more robust (if the order changes), I'm passing in the ID of the item that should draw the break.
#{
var breakItem = Model.Items.FirstOrDefault(x => renderBreakInList && x.IsSomeType);
var breakID = breakItem == null ? (long?)null : (long)breakItem.ID;
}
#Html.DisplayFor(x => x.Items, new { breakID = breakID })
Also like nemesv pointed out, Html.DisplayFor() needs to be prepended with #. I got out of the habit of doing this inside code blocks because I would always get the 'once inside a code block you don't need #` error..

Generate wrong outgoing url because of segment variable reuse in MVC 4

Here is my RouteConfig.cs
routes.MapRoute(null,
"{controller}/Page{page}",
new {controller = "Product", action = "Index", category = (string) null},
new {page = #"\d+"}
);
routes.MapRoute(null,
"{controller}/{category}",
new {controller = "Product", action = "Index", page = 1}
);
routes.MapRoute(null,
"{controller}/{category}/Page{page}",
new {controller = "Product", action = "Index"},
new {page = #"\d+"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And here is the code for generating url:
#Html.ActionLink("View Cart", "Index", "ShoppingCart", null, new { #class = "btn btn-orange" })
It works well when I navigate to, for example, Product/Page2, Product/Laptop, Product/Laptop/Page2. The problem is, whenever my current URL contains Page segment, it will try to reuse that segment for generating outgoing URL. So, if I'm at Product/Page2 the above generated URL would be ShoppingCart/Page2. I don't know how to avoid this.
Please help me. Thank you so much.
EDIT!!!
I've found a workaround way. Instead of using ActionLink, I use RouteLink like this:
#Html.RouteLink("View Cart", "Default", new { controller = "ShoppingCart", action = "Index" }, new { #class = "btn btn-orange" })
But I still want to use ActionLink, so please help me.
EDIT!!!
The workaround way doesn't work when I generate a link to ShoppingCart/Checkout. It still take me to Index action in ShoppingCart controller.
Create a new route pattern specific to ShoppingCart and make it the first route by placing it at the TOP.
routes.MapRoute(null,
"ShoppingCart/{action}",
new {controller = "Product"});
);
As a rule all the specific routes should come first.
This is because of the way the routing system tries to evaluate the value of segment variables when trying to match against a route.
So when the call to render the link occurs with the following arguments:
#Html.ActionLink("View Cart", "Index", "ShoppingCart", null, new { #class = "btn btn-orange" })
the framework when evaluating the route with template
{controller}/Page{page}
will resolve the controller segment variable to be ShoppingCart however when it cannot find a value for the page segment variable (via any of the arguments in the method call), it will then try and resolve that value from the RouteData object in the ViewContext. Since you have navigated to Product/Page2, the current value of page within the routes value dictionary is 2.
You can inspect this by looking at the value of ViewContext.RouteData.Values["page"] when rendering that view.

MVC routing error

I have a custom route defined:
routes.MapRoute(
"FabricDetails", // Route name
"fabric/details/{designerUrlFriendlyName}/{collectionUrlFriendlyName}/{fabricUrlFriendlyName}", // URL with parameters
new { controller = "Fabric", action = "Details", designerUrlFriendlyName = UrlParameter.Optional, collectionUrlFriendlyName = UrlParameter.Optional, fabricUrlFriendlyName = UrlParameter.Optional }, // Parameter defaults
new[] { "StashFabrics.Web.Controllers" }
);
I have two nearly identical actionlinks and one is working while the other is not
#Html.ActionLink(fabric.FabricName, "Details", "Fabric", new RouteValueDictionary(new { designerUrlFriendlyName = fabric.DesignerUrlFriendlyName, collectionUrlFriendlyName = fabric.CollectionUrlFriendlyName, fabricUrlFriendlyName = fabric.FabricUrlFriendlyName }), null)
#Html.ActionLink(fabric.FabricName, "Details", "Fabric", new RouteValueDictionary(new { designerUrlFriendlyName = fabric.DesignerUrlFriendlyName, collectionUrlFriendlyName = "grand_hotel", fabricUrlFriendlyName = fabric.FabricUrlFriendlyName }), null)
For whatever reason, as soon as I replace the hard coded value for collectionUrlFriendlyName the link doesn't get built correctly
http://localhost:55089/Fabric/Details?designerUrlFriendlyName=jenean_morrison&collectionUrlFriendlyName=grand_hotel&fabricUrlFriendlyName=ballroom_in_azure
http://localhost:55089/fabric/details/jenean_morrison/grand_hotel/ballroom_in_azure
This has me stumped. Any advice would be appreciated.
Well I figured it out.
In the model of the view I have collectionUrlFriendlyName defined at two different levels; first on the model itself and then again on the class to which the model has a list.
I wasn't defining a value for collectionUrlFriendlyName at the list level, where the URL was being formed. But I guess when constructing the URL it would later find the value at the upper level and use it to form the ugly url (thus hiding the problem that it wasn't populated on the lower level)
If that make sense.

how to load a create and load a new record into a form in extjs 4.0

I'm using mvc approach and extending the pandora example.
I would like to add a new record to a form. I need to pre-assign some properties. I have the following handler. Which fills out the form. However when i try and sync it does not post the new info. ie using fire bug i see that it post the records that were previously there. At what stage should i add it to the store.
onNewPartSelect: function (selModel, selection) {
var form = Ext.getCmp('partForm');
form.getForm().reset();
var part = new Pandora.model.Part({
Name: 'my new record'
});
form.loadRecord(part);
},
For loading a new record into the form:
var iUserForm = this.getUserDetailsForm(),
iRecord = Ext.create('BS.model.User');
iUserForm.loadRecord( iRecord );
And upon submit:
var iUserForm = this.getUserDetailsForm();
if (iUserForm.getForm().isValid())
{
var iRecord = iUserForm.getForm().getRecord(),
iValues = iUserForm.getForm().getValues(),
iRecord.set( iValues );
this.getUsersStore().insert(0, iRecord);
}