How notifier are delivered to the front end and displayed? - orchardcms

I have added message in Orchard.Notifier,I want to display this message to front page by custom,What should I do?
_notifier.Add(NotifyType.Error, T("An Exception has occured,error message:{0}", filterContext.Exception.Message));

The service that's responsible for adding notifications to the current page is NotifyFilter:
var messagesZone = _workContextAccessor.GetContext(filterContext).Layout.Zones["Messages"];
This adds the messages to a top-level layout zone called "Messages". As a consequence, all you have to do is add a zone called "Messages" to your theme's layout. You can see how the TheAdmin theme's Layout view is doing it here:
#if (Model.Messages != null) {
<div id="messages">
#Zone(Model.Messages)
</div>
}

Related

Orchard CMS - create vertical Navigation Menu next to Home

I am new to Orchard and trying to figure out how it works code-wise.
So, I have created a custom Content Type through the code and i am able to create Content Items under this Content Type. i have the 'Show on the Menu' checkbox on the editor page of the Content item. But when I check it and select the menu to which i want this newly created custom item to be added, it gets added as a vertical menu item whereas i need it to be added as a vertical submenu to one of the root items.
Please find images which describe what is happening now and what I need.
Current behavior
Expected behavior
Product2 is a custom content item and should be added as a entry in the vertical menu as shown in the 2nd image
This task is rather complex. There are several steps involved.
Understanding how to create a child theme
See the official documentation, create a child theme and enable it
Understanding the concept of shape alternates
See the official documentation
Configure the menu in admin area
Go to the admin area, click on Navigation in the menu and add some menu items and sub items, for example
[ Home (Content Menu Item) ]
[ Service (Content Menu Item) ]
[ Document Storage (Custom Link) ]
Once you have this structure Orchard renders this structure via a #Zone(Model.Navigation) call in a theme. You have to search where this call is located for yourself, it depends on the theme.
My child theme uses a Layout.cshtml alternate which calls #Zone(Model.Navigation) where needed like so
#{
Func<dynamic, dynamic> Zone = x => Display(x); // Zone as an alias for Display to help make it obvious when we're displaying zones
}
<div class="wrapper">
#* Navigation bar *#
#if (Model.Navigation != null)
{
<div id="layout-navigation" class="group navbar navbar-default" role="navigation">
#Zone(Model.Navigation)
</div>
}
...
</div>
Now, if Orchard renders the menu itself, it uses the Menu.cshtml shape template, thus the next step will be to provide a shape alternate for Menu.cshtml.
Creating a shape alternate for the menu in your child theme
Go to you child theme folder and add a file Views\Menu.cshtml and start rendering the menu there, for example
<ul class="nav navbar-nav">
#DisplayChildren(Model)
</ul>
The #DisplayChildren(Model) call will start rendering the menu items via the MenuItem.cshtml shape template, thus the next step will be to provide a shape alternate for MenuItem.cshtml.
Creating a shape alternate for menu items in your child theme
Go to you child theme folder and add a file Views\MenuItem.cshtml and start rendering the menu items. Here is the content of my MenuItem.cshtml file, which renders the menu items as <li> structure according to the bootstrap specs:
#*
this shape alternate is displayed when a <li> element is rendered
whereas the following code is based on Orchard.Core\Shapes\Views\Menu.cshtml
*#
#{
// odd formatting in this file is to cause more attractive results in the output.
var items = Enumerable.Cast<dynamic>((System.Collections.IEnumerable)Model);
}
#{
if (!HasText(Model.Text)) {
#DisplayChildren(Model)
}
else {
if ((bool) Model.Selected) {
Model.Classes.Add("current");
}
if (items.Any()) {
Model.Classes.Add("dropdown");
}
#* morphing the shape to keep Model untouched*#
Model.Metadata.Alternates.Clear();
Model.Metadata.Type = "MenuItemLink";
#* render the menu item only if it has some content *#
var renderedMenuItemLink = Display(Model);
if (HasText(renderedMenuItemLink)) {
var tag = Tag(Model, "li");
#tag.StartElement
#renderedMenuItemLink
if (items.Any()) {
<ul class="dropdown-menu">
#DisplayChildren(Model)
</ul>
}
#tag.EndElement
}
}
}
You can also provide alternates to override specific menu item types like the Custom Link. The file would then be MenuItemLink.cshtml with a content like
#*
this shape alternate is displayed when menu link is _not_ of type "Content Menu Item" otherwise MenuItemLink-ContentMenuItem.cshtml is used
whereas the following code is based on Orchard.Core\Shapes\Views\MenuItemLink.cshtml
*#
<a href="#Model.Href" #if (Model.Item.Items.Length > 0) { <text>class="dropdown-toggle" data-toggle="dropdown"</text> }>#Model.Text</a>
As you can see, a lot of work but pretty flexible.

Can a Url.Action specify a route in MVC5?

In our default layout we have our logo wrapped with a URL.Action to navigate back to the home screen. However, if we are in an Area, it tries to navigate to the home controller in that area, which doesn't exist.
Our home controller is Submission. Here is the link in the layout file:
<a class="navbar-brand custm-navbar-brand" href="#Url.Action("Index", "Submission")">
<img src="#Url.Content("~/Content/images/eed-main-logo.png")" alt="E-Editorial Discovery" width="335" height="56">
</a>
If I am in an area like this: /Admin/Security/Index
the above link tries to go to: /Admin/Submission/Index
but it should go to: /Submission/Index
I'm sure there's a better way, but I haven't found it yet.
Specify the area like you would a parameter. So your first line should be:
<a class="navbar-brand custm-navbar-brand" href="#Url.Action("Index", "Submission", new { Area = "AreaName" })">
You could specify the area in the Url.Action call but this can get messy.
Rather than having to specify the area, why not sort the route out itself so it knows to tie it down to that namespace:
context.MapRoute("ExpressCheckoutRoute",
"expresscheckout/stage/{stageName}/{id}",
new { controller = "ExpressCheckout", action = "Stage", area = "FrontEnd", id = UrlParameter.Optional },
new[] { "Web.Areas.FrontEnd.Controllers" }
).DataTokens["UseNamespaceFallback"] = false;
This sorted the issue out for me and I no longer have to specify the area paramter (take note of the last 2 parts to that mapping).

Main Menu Navigation Item not linked to a content item but collapsing a sub menu

I have got a multi level navigation in Orchard CMS which shows sub menu items on hovering. When I click, it opens a content menu item. This works well on a PC but not on a mobile device. In case of a mobile device or touch device in general it should collapse the menu instead of jumping to another page.
I am looking for an easy and clean approach to solve this.
Is there a way to create such a menu item only acting as an opener for the sub menu items instead of actually linking to a page?
Some background information: It is actually a theme based on twittter bootstrap 3
You can extend the MenuItem shape (~/Core/Shapes/Views/MenuItem.cshtml) to differentiate between parent and children
So first create under {YourTheme}/Views new view called MenuItem.cshtml and paste in the following code
#{
// odd formatting in this file is to cause more attractive results in the output.
var items = Enumerable.Cast<dynamic>((System.Collections.IEnumerable)Model);
}
#{
if (!HasText(Model.Text))
{
#DisplayChildren(Model)
}
else
{
if ((bool)Model.Selected)
{
Model.Classes.Add("current");
}
#* morphing the shape to keep Model untouched*#
Model.Metadata.Alternates.Clear();
if (items.Any())
{
Model.Classes.Add("dropdown");
Model.Metadata.Type = "MenuItemLinkParent";
}
else
{
Model.Metadata.Type = "MenuItemLink";
}
#* render the menu item only if it has some content *#
var renderedMenuItemLink = Display(Model);
if (HasText(renderedMenuItemLink))
{
var tag = Tag(Model, "li");
#tag.StartElement
#renderedMenuItemLink
if (items.Any())
{
<ul>
#DisplayChildren(Model)
</ul>
}
#tag.EndElement
}
}
}
Now just create another view called MenuItemLinkParent.cshtml and create simple hyperlink placeholder that doesn't link anywhere
<a>#Model.Text</a>
Now any MenuItem which becomes parent will lose it's href link (you can also edit html structure and classes this way, if necessary for bootstrap). Easy and clean enough? :)

Spotify apps tabs - update cache

I'm trying to display a div inside tab playlists if the href contains a spotifyURI. This will be used to display a playlist under a tab.
Step by step this is my problem:
Click playlist tab and then click the "My playlist1".
The href is displayed in the playlist container under the tab playlists. (perfect so far)
Click the start tab and then click the playlists tab.
Instead of displaying the list of playlists the playlist container is show again. So the last used url is cached?
Then if the playlists tab is clicked again the url will be "reseted" and the list of playlists will be shown and playlist container hidden.
I'd like 4. to show the playlist list right away instead.
Is there a way to reset or what am I missing?
<script>
$(document).ready(function() {
sp = getSpotifyApi(1);
var m = sp.require("sp://import/scripts/api/models");
updateTabs();
m.application.observe(m.EVENT.ARGUMENTSCHANGED, updateTabs);
function updateTabs()
{
console.log(m.application.arguments);
var args = m.application.arguments;
$('.section').hide();
if (args[1] == "spotify") $("#playlist").html("args:"+args).show();
else $("#"+args[0]).show();
}
});
</script>
<div id="playlist" class="section">Container for playlist content</div>
<div id="start" class="section">Welcome</div>
<div id="playlists" class="section">
My playlist1
My playlist2
</div>
Thanks alot for all replys!
Here is how I will proceed using JQuery.
First of all you need to use the Localstorage :
var stor = sp.require("sp://import/scripts/storage");
Then if for exemple you get a list of playlist you can build the list like this
for (var i=0; i<d.playlists.length; i++) {
$('#playlists').append('My <a id="p' + i + '"href="'+ d.playlists[i] +'">playlist1</a>');
$('#playlists #p'+i).live('click', function(e) {
e.preventdefault();
stor.set('choosenplaylist', d.playlists[i]);
});
}
This was for the storage now for when changing tad :
if (!stor.get('choosenplaylist')=='') {
location.href=stor.get('choosenplaylist');
}
Okay this is a suggestion and it need to be tested regarding to your app.
Im trying this out now, and i can reproduce your bug (im guessing it's a bug, the tab should replace the url in my opinion)
But, until it's fixed, my best guess is to capture the playlist links in an event handler and cancelling the original event, after cancelling you replace the content with the appropriate playlist view.
Tab test code (on gist.github.com)
I've abstracted the actual view binding from the event handler, and added a click event hook that calls the abstract view binder instead of the "real" one, this also supports deep linking into the an app

Orchard CMS: Logon Page doesn't work with my custom layout

I am very new to Orchard.
I have created a new theme, based on the Minty theme. The only real change is the layout, where I have adapted the html from an existing asp.net masterpage to match the orchard style razor layout.cshtml. I have experience with MVC and razor, so no problem on that side... unless I have missed something vital.
The problem is the login page. Clicking the sign in link takes me to the correct url without errors, but not login form gets rendered. I have checked that this is the case by Inspecting Element in google chrome.
I am aware that setting up widgets, etc, I can make content appear. However, I can't find how the login form gets inserted when the login url gets requested. I presume it uses the Orchard.Users module, but not sure how. Does it need a specific zone? I can't see why, but see how else.
As a result, I can't solve my problem...
Any pointers?
Any books or other learning media?
The code for my layout.cshtml is:
#functions {
// To support the layout classifaction below. Implementing as a razor function because we can, could otherwise be a Func<string[], string, string> in the code block following.
string CalcuClassify(string[] zoneNames, string classNamePrefix) {
var zoneCounter = 0;
var zoneNumsFilled = string.Join("", zoneNames.Select(zoneName => { ++zoneCounter; return Model[zoneName] != null ? zoneCounter.ToString() : "";}).ToArray());
return HasText(zoneNumsFilled) ? classNamePrefix + zoneNumsFilled : "";
}
}
#{
/* Global includes for the theme
***************************************************************/
SetMeta("X-UA-Compatible", "IE=edge,chrome=1");
Style.Include("http://fonts.googleapis.com/css?family=Handlee");
Style.Include("http://html5shiv.googlecode.com/svn/trunk/html5.js");
Style.Include("site.css");
Script.Require("jQuery").AtHead();
Script.Require("jQueryUI_Core").AtHead();
Script.Require("jQueryUI_Tabs").AtHead();
Script.Include("http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.0.4/modernizr.min.js").AtHead();
Style.Include("TagDefaults.css");
Style.Include("LayoutStructure.css");
Style.Include("LayoutStyling.css");
Style.Include("TopMenu.css");
Style.Include("LeftBlock.css");
Style.Include("RightBlock.css");
Style.Include("MenuAdapter.css");
Style.Include("Content.css");
Style.Include("FloatedBoxes.css");
Style.Include("Helen.css");
/* Some useful shortcuts or settings
***************************************************************/
Func<dynamic, dynamic> Zone = x => Display(x); // Zone as an alias for Display to help make it obvious when we're displaying zones
/* Layout classification based on filled zones
***************************************************************/
//Add classes to the wrapper div to toggle aside widget zones on and off
var asideClass = CalcuClassify(new [] {"Sidebar"}, "aside-"); // for aside-1, aside-2 or aside-12 if any of the aside zones are filled
if (HasText(asideClass)) {
Model.Classes.Add(asideClass);
}
//Add classes to the wrapper div to toggle tripel widget zones on and off
var tripelClass = CalcuClassify(new [] {"TripelFirst", "TripelSecond", "TripelThird"}, "tripel-"); // for tripel-1, triple-2, etc. if any of the tripel zones are filled
if (HasText(tripelClass)) {
Model.Classes.Add(tripelClass);
}
//Add classes to the wrapper div to toggle quad widget zones on and off
var footerQuadClass = CalcuClassify(new [] {"FooterQuadFirst", "FooterQuadSecond", "FooterQuadThird", "FooterQuadFourth"}, "split-"); // for quad-1, quad-2, etc. if any of the quad zones are filled
if (HasText(footerQuadClass)) {
Model.Classes.Add(footerQuadClass);
}
var slideshowClass = CalcuClassify(new[] {"HomeSlideshow"}, "slideshow-");
if (HasText(slideshowClass)) {
Model.Classes.Add(slideshowClass);
}
/* Inserting some ad hoc shapes
***************************************************************/
//WorkContext.Layout.Header.Add(New.Branding(), "5"); // Site name and link to the home page
//WorkContext.Layout.Footer.Add(New.BadgeOfHonor(), "5"); // Powered by Orchard
WorkContext.Layout.Footer.Add(New.User(), "10"); // Login and dashboard links
/* Last bit of code to prep the layout wrapper
***************************************************************/
Model.Id = "layout-wrapper";
var tag = Tag(Model, "div"); // using Tag so the layout div gets the classes, id and other attributes added to the Model
}
#tag.StartElement
<a name="top"></a>
<div id="SiteHeader">
</div>
<div id="PageContainer">
<div style="position: absolute; Left:-80px; top:-88px;z-index:1000;">
<img id="bird" title="Pheasant" src="/Themes/TheFarmsBlogs/Styles/Images/PositionedImages/pheasant.gif" />
</div>
<div class="SiteMenu"><p>Hello Menu</p></div>
<div id="Specialized">
<div id="PageName">
<!--
PageName NOT in use!
-->
</div>
#if (Model.RightColumn != null) {
<div id="RightCol">
#Zone(Model.RightColumn)
</div>
}
<!-- Page divided into two main columns, of which the left column is subdivided as necessary -->
<div id="LeftCol">
<div id="PageBanner">
<div id="PageBannerLeft">
#if (Model.MainImage != null) {
<div id="PageBannerImage">
#Zone(Model.MainImage)
</div>
}
#if(Model.TheStrip != null) {
<div id="TheStrip">
#Zone(Model.TheStrip)
</div>
}
</div>
</div>
<div id="SpecializedContent">
#if(#Model.content != null)
{
#Zone(Model.content)
}
</div>
</div>
<div id="SpecializedFooter">
</div>
</div>
<div id="PageFooter">
#if (Model.FooterPage != null){
#Zone(Model.FooterPage)
}
</div>
</div>
<div id="SiteFooter">
#Display(Model.Footer)
The Farms Ltd - © 2007
</div>
#tag.EndElement
PS: the branding and badge of honour are commented out as I am only enabling bit by bit to eliminate the source of errors. It will be in the live site.
ADDENDUM:
See Bertrand Le Roy's answer below. The Orchard.Users module requires a Content zone with a Capital C. That instantly cured the problem.
I added this as Bertrand's response was tentative, and I wanted to reinforce that the problem was the name of the zone.
In Orchard.Users, look for Controllers/AccountController.cs. In there, there is a LogOn action. It creates a LogOn shape that it then puts in a shape result. This then gets resolved as the Views/LogOn.cshtml template (which you can override in your theme by just dropping a file with the same name in there, for example a copy of the original that you can tweak). The LogOn template will be rendered within the theme's layout, in the Content zone. Does this answer your question?
I think the mistake you made was to name your Content zone content (notice the casing).

Resources