How to place a sign / login / logout link at the top ?

Topics: General
Oct 13, 2011 at 2:12 PM

1) How to place a sign / login / logout link at the top above menu tabs ?

2) What's the location / path of all the master pages / layout pages ?

Coordinator
Oct 13, 2011 at 7:55 PM

The sign in stuff is added from the layout ususally, by a line that looks like this in the theme machine:

WorkContext.Layout.Footer.Add(New.User(), "10");

This is adding it to the footer, but you can direct it to the header or any top level zone. You can even have more than one.

The layout.cshtml file is usually in the views folder of the current theme. It uses a wrapper, document.cshtml, that is either in the same place or in the safe mode theme.

Oct 14, 2011 at 3:24 PM
Edited Oct 14, 2011 at 3:42 PM

Alright..so I added this line above the header in Layout.chtml and when I try to run the website instead of sign in link I see the code line like this

 

WorkContext.Layout.Footer.Add(New.User(), "10");

 

any help would be appreciated.....I really need sign in / signout link above my header along with welcome (username) text..

Oct 14, 2011 at 10:02 PM

anyone ?

Coordinator
Oct 14, 2011 at 10:14 PM

It is not where you put this line that matters, you need to replace "Footer" in there with the zone name hwere you want it.

By the way, if it takes us a few hours to respond, it's not necessary to ping again. We respond to pretty much everything here.

Oct 16, 2011 at 2:42 AM
Edited Oct 16, 2011 at 3:45 AM

I am sorry...my intention is not to spam this forum with my posts.. I was working on my website and waiting for the solution of this particular problem so I was in kind of rush due to urgency of my website work..

 

I tried but still don't see anything in the header.. this is the complete code of Layout.chtml and BOLD code is that I have added because I want sign in / logout link in footer as well as before header zone.

 

@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=Lobster&subset=latin");
    Style.Include("site.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 [] {"AsideFirst", "AsideSecond"}, "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);
    }

    /* 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


// this is what I have added

@WorkContext.Layout.BeforeHeader.Add(New.BadgeOfHonor(), "5");
// this is what I have added

 

@if (Model.Header != null) {
<header id="layout-header" class="group">

    <div id="header">
        @Zone(Model.Header)
    </div>
</header>
}
@if (Model.Navigation != null) {
<div id="layout-navigation" class="group">
    @Zone(Model.Navigation)
</div>
}
@if (Model.Featured != null) {
<div id="layout-featured" class="group">
    @Zone(Model.Featured)
</div>
}
@if (Model.BeforeMain != null) {
<div id="layout-before-main" class="group">
    @Zone(Model.BeforeMain)
</div>
}
<div id="layout-main-container">
<div id="layout-main" class="group">
    @if (Model.AsideFirst != null) {
    <aside id="aside-first" class="aside-first group">
        @Zone(Model.AsideFirst)
    </aside>
    }
    <div id="layout-content" class="group">
        @if (Model.Messages != null) {
        <div id="messages">
            @Zone(Model.Messages)
        </div>
        }
        @if (Model.BeforeContent != null) {
        <div id="before-content">
            @Zone(Model.BeforeContent)
        </div>
        }
        @* the model content for the page is in the Content zone @ the default position (nothing, zero, zilch) *@
        @if (Model.Content != null) {
        <div id="content" class="group">
            @Zone(Model.Content)
        </div>
        }
        @if (Model.AfterContent != null) {
        <div id="after-content">
            @Zone(Model.AfterContent)
        </div>
        }
    </div>
    @if (Model.AsideSecond != null) {
    <aside id="aside-second" class="aside-second">
        @Zone(Model.AsideSecond)
    </aside>
    }
</div>
</div>
@if (Model.AfterMain != null) {
<div id="layout-after-main" class="group">
    @Zone(Model.AfterMain)
</div>
}
@if (Model.TripelFirst != null || Model.TripelSecond != null || Model.TripelThird != null) {
<div id="layout-tripel-container">
<div id="layout-tripel" class="group">@* as in beer *@
    @if (Model.TripelFirst != null) {
    <div id="tripel-first">
        @Zone(Model.TripelFirst)
    </div>
    }
    @if (Model.TripelSecond != null) {
    <div id="tripel-second">
        @Zone(Model.TripelSecond)
    </div>
    }
    @if (Model.TripelThird != null) {
    <div id="tripel-third">
        @Zone(Model.TripelThird)
    </div>
    }
</div>
</div>
}
<div id="layout-footer" class="group">
    <footer id="footer">
        <div id="footer-quad" class="group">
            @if (Model.FooterQuadFirst != null) {
            <div id="footer-quad-first">
                @Zone(Model.FooterQuadFirst)
            </div>
            }
            @if (Model.FooterQuadSecond != null) {
            <div id="footer-quad-second">
                @Zone(Model.FooterQuadSecond)
            </div>
            }
            @if (Model.FooterQuadThird != null) {
            <div id="footer-quad-third">
                @Zone(Model.FooterQuadThird)
            </div>
            }
            @if (Model.FooterQuadFourth != null) {
            <div id="footer-quad-fourth">
                @Zone(Model.FooterQuadFourth)
            </div>
            }
        </div>
        @if(Model.Footer != null) {
        <div id="footer-sig" class="group">
            @Zone(Model.Footer)
        </div>
        }
    </footer>
</div>
@tag.EndElement

Coordinator
Oct 16, 2011 at 4:12 AM

Why did you add BadgeOfHonor and not User like I've told you in all previous messages?

Oct 16, 2011 at 12:20 PM

I am sorry bertrandleroy but I am totally confused...

Could you PLEASE give me...what exact code to add and where ?

Coordinator
Oct 16, 2011 at 5:30 PM

Dear codeplex_user,

Bertrand gave you exactly what you have to enter in your file since his first message:

WorkContext.Layout.Footer.Add(New.User(), "10");

This is some common ASP.NET Razor code in C#. He also told you that this exact code will render the sign in in the "Footer" zone ... by looking into this line of code, you might find where "Footer" is defined, let's say the 20th char beginning from left. Changing it to "Header" would then result in :

WorkContext.Layout.Header.Add(New.User(), "10");

Wooh ! that one was easy.

Then, OK, we should blame Bertrand because he did a big mistake, not telling you that the code in Orchard views are in Razor, so actually it won't render what you want but just a bunch of letters. However, if you had looked at some Razor tutorial before (you really should), then you would know that to execute this line of code it need to have an @ at its beginning:

@WorkContext.Layout.Header.Add(New.User(), "10");

 

Sebastien

Oct 17, 2011 at 1:56 PM

First of all thank you very much for the explaination..i deeply appreciate it.

I am new in MVC so thank you for your patience.

I did exactly what you mentioned above like this:

@tag.StartElement

@if (Model.Header != null) {
<header id="layout-header" class="group">

 

// this is what I have added

@WorkContext.Layout.Header.Add(New.User(), "10");

// this is what I have added

 

    @Zone(Model.BeforeHeader)
    @if (Model.SocialLinks != null) {
        <div id="socialLinks">

            @Zone(Model.SocialLinks)
        </div>
    }
    <div id="header">

        @Zone(Model.Header)


        @if (Model.Navigation != null) {
        <div id="layout-navigation" class="group">
            @Zone(Model.Navigation)
        </div>
        }
        @if (Model.HomeSlideshow != null) {
        <div id="featured-slideshow" class="group">
            @Zone(Model.HomeSlideshow)
        </div>
        }
    </div>
</header>

 

It does show the "Sign" link right below the site name heading on the header but above the header some weird number is being displayed like this: ZoneProxy744ecc41422845eda529ba5efd7cb835;

 

How to get rid of it and why this number is coming ? what does that mean ?

Coordinator
Oct 17, 2011 at 5:36 PM

Well, Sébastien was wrong on this one (it happens; rarely but it does). It should be: @{WorkContext.Layout.Header.Add(New.User(), "10");} and not a simple @. @ displays a string and if it can't find one it does ToString on the object you give it, hence the weird string here. @{ ... } executes code without rendering in place.

Coordinator
Oct 17, 2011 at 5:39 PM

CLAP, CLAP, CLAP ;)

Oct 17, 2011 at 5:58 PM

ummm...can anyone help me with what I posted above in my last post ?

Coordinator
Oct 17, 2011 at 6:14 PM

errr... I just did.

Oct 17, 2011 at 7:29 PM
Edited Oct 17, 2011 at 7:29 PM

Oh...I am sorry..my bad..

Yes it does work..looking great.. thanks a lot

Quick question: I am trying to format it but seems like it is not changing at all ?

 

That's exactly what I am using:

<div class="signinlink">
@{WorkContext.Layout.BeforeHeader.Add(New.User(), "10");}
</div>

 

In the css style sheet of my cuurent theme, I have mentioned this:

.signinlink
{
color: #ffffff;
    font-weight: bold;

text-align: right;

}

 

1) But I don't see any change, why ? how I can make changes in formatting ?

2) If I want to change the "Signin" link to a button, how to do that ?

 

Thank you very much sebastienros and bertrandleroy

 

 

Coordinator
Oct 17, 2011 at 7:37 PM

That line of code I gave you does not render in place, it creates a User shape that will be rendered in the BeforeHeader zone. To change the formatting, you'll have to override the user.cshtml template in your theme.

Oct 17, 2011 at 7:56 PM

I made changed in : Themes\The Admin \ Views \ User.cshtml

I did like this (changed div class name)

 

<div class="signinlink">@T("User:") @Model.CurrentUser.UserName | @Html.ActionLink(T("Logout").ToString(), "LogOff", new { Area = "Orchard.Users", Controller = "Account" })

and in The Admin Theme \ Style \ site.css

 

it is like this:

.signinlink
{
color: #ffffff;
    font-weight: bold;

text-align: right;

}

 

 

still no change... PLEASE correct me if I am wrong somewhere ?

Coordinator
Oct 17, 2011 at 8:02 PM

But that is the admin theme. You should not be working in there. You should create your own theme to override templates.

Oct 17, 2011 at 9:54 PM

The reason I was looking into the ADMIN theme because there is no "User.cshtml" in the view folder of front-end theme.

Lets say I want to use "The Time Machine" - there is no no "User.cshtml" in the view folder - so how to go about it ?

Coordinator
Oct 17, 2011 at 9:57 PM

You create a copy of the existing one in your theme's views folder and modify that. That's what's meant by "overriding the template".

Oct 17, 2011 at 11:03 PM

yes, I understood the meaning of "overriding the template" but what I am asking is.. there is no user.cshtml in view folder of existing or any theme except "ADMIN" theme.

So what should I do ? Code the user.cshtml from "Admin" theme to my theme's view folder ?

Coordinator
Oct 17, 2011 at 11:10 PM

Actually, there are two others. The one you should override is in Core/Shapes/Views. I've copied it here so you don't have to go digging for it:

@using System.Web.Mvc;

<div class="user-display">
    @if (WorkContext.CurrentUser != null) {
        <span class="user-actions welcome">
            @T("Welcome, <strong>{0}</strong>!", new HtmlString(Html.ActionLink( WorkContext.CurrentUser.UserName, "ChangePassword", new { Controller = "Account", Area = "Orchard.Users" }).ToString()))
        </span>
        <span class="user-actions">
            @Html.ActionLink(T("Sign Out").ToString(), "LogOff", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl })
            @Html.ActionLink(T("Dashboard").ToString(), "Index", new { Area = "Dashboard", Controller = "Admin" })
        </span>
    } else {
        <span class="user-actions">@Html.ActionLink(T("Sign In").ToString(), "LogOn", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = (Request.QueryString["ReturnUrl"] ?? Request.RawUrl) })</span>
    }
</div>

Oct 18, 2011 at 1:43 PM

thank a lot bertrandleroy, it worked...the only problem is that if I am moving and formatting link at the top (before header zone) - it is moving the footer sign in link too.

I deeply appreciate your help..you helped me patiently and answered all my newbie questions.

Thank you so much.

Oct 18, 2011 at 8:03 PM

Is there any way to prevent footer link from moving if I am moving the link at the top ? Logically I know "Sign" in coming from same code so if I do anything with it on header it will affect footer but still is there any way ? You guys know better than me...

Coordinator
Oct 19, 2011 at 12:27 AM

And by moving you mean changing? Well, no, why would you want that? Doesn't seem to make any sense.

Oct 19, 2011 at 1:41 PM

Sorry for the confusion, may be my question is little vague.

Like you guided me above, I copied /pasted the user.cshtml in my theme folder and now I am able to see the "Signin" link on the zone where I moved it, ie. BeforeHeaderZone

I applied formatting to that link like this:

.signinlink
{
color: #ffffff;
    font-weight: bold;

text-align: right;

margin-right: 20px;

}

 

In BeforeHeader Zone, this moved the "Signin" link to the right, but at the same time "Signin" link exists in the Footer too. That is also being moved to right side (by default it was in the center)

That is exactly what I meant by "moving"...

Once again sorry for the confusion.

Oct 19, 2011 at 2:43 PM
Edited Oct 19, 2011 at 2:44 PM

Since both of you links is styled with the class "signinlink" both of them will move, because you say that all items with class "signinlink" should have text-align: right;

You can override this by being more specific for the Footer. If your footer, for example, has class="footer" you could:

.footer .signinlink
{
    text-align: center;
}

which will only move signinlink if it is in footer, and the BeforeHeader one will stay to the right.

Oct 23, 2011 at 11:07 PM

I tried but NOT WORKING :(

 

Here is my layout.cshtml:

 

@functions {
    // To support the layout classifaction below. Implementing as a razor function because we can, could otherwise be a Func 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=Pacifico");
    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();
   
    /* Some useful shortcuts or settings
    ***************************************************************/

    Func 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
@{WorkContext.Layout.BeforeHeader.Add(New.User(), "10");}
@if (Model.Header != null) { @Zone(Model.BeforeHeader) @if (Model.SocialLinks != null) { } } @if (Model.Featured != null) { } @if (Model.BeforeMain != null) {
@Zone(Model.BeforeMain)
}
@if (Model.Messages != null) {
@Zone(Model.Messages)
} @if (Model.BeforeContent != null) {
@Zone(Model.BeforeContent)
} @* the model content for the page is in the Content zone @ the default position (nothing, zero, zilch) *@ @if (Model.Content != null) {
@Zone(Model.Content)
} @if (Model.AfterContent != null) {
@Zone(Model.AfterContent)
}
@if (Model.Sidebar != null) { @Zone(Model.Sidebar) }
@if (Model.AfterMain != null) {
@Zone(Model.AfterMain)
} @if (Model.TripelFirst != null || Model.TripelSecond != null || Model.TripelThird != null) {
@* as in beer *@ @if (Model.TripelFirst != null) {
@Zone(Model.TripelFirst)
} @if (Model.TripelSecond != null) {
@Zone(Model.TripelSecond)
} @if (Model.TripelThird != null) {
@Zone(Model.TripelThird)
}
} @tag.EndElement

 

 

 

This is my User.cshtml

 

@using System.Web.Mvc;

@if (WorkContext.CurrentUser != null) {
@T("Welcome, {0}!", new HtmlString(Html.ActionLink( WorkContext.CurrentUser.UserName, "ChangePassword", new { Controller = "Account", Area = "Orchard.Users" }).ToString())) @Html.ActionLink(T("Sign Out").ToString(), "LogOff", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl }) @Html.ActionLink(T("Dashboard").ToString(), "Index", new { Area = "Dashboard", Controller = "Admin" })
} else {
@Html.ActionLink(T("Sign In").ToString(), "LogOn", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = (Request.QueryString["ReturnUrl"] ?? Request.RawUrl) })
}

 

This is my Site.css (style sheet)

 

.signinlink
{
color: #ffffff;
    font-weight: bold;
text-align: right;
margin-right: 50px;
}

.signinlink a
{
color: #ffffff;
    font-weight: bold;
text-align: right;
}


.footer1
{
    text-align: center;
}

.footer1 a
{
    text-align: center;
}

.footer1 .signinlink
{
    text-align: center;
}

.footer1 .signinlink a
{
    text-align: center;
}
Oct 23, 2011 at 11:49 PM
Edited Oct 24, 2011 at 12:03 AM

If the div (in the footer) where your signinlink exists has the class footer1 it just should work. Can you provide an address to the site you are developing?

Then, you should (still) not place <div> around the @{WorkContext.Layout.BeforeHeader.Add(New.User(), "10");}, because it will not be rendered where you put it, it will be rendered in the zone you specify.