DotNetNuke - Header, Content and Footer - header

Is there any way, like one does with WordPress, to create a header.php, theme-file.php and footer.php and then combine them using hooks? It seems crazy to me to still duplicate skin files especially when you need to make minor changes to the content of either a header or footer.
Many thanks

A skin is just an ascx control, so you can encapsulate parts of it just like you would any other WebForms view. You can put the header/footer content into their own ascx file, and then just include them in the skin. The only place you'll run into an issue with this is that I don't think DNN supports having panes in separate controls; everything else should be fair game.
You'll want to put them in a separate directory, so that they aren't seen as other skins by DNN.
-MySkin
--Controls
---Header.ascx
---Footer.ascx
--Home.ascx
--Home.doctype.xml
--Interior.ascx
--Interior.doctype.xml
Then, in the skins, include the controls by registering them in the header:
<%# Register TagPrefix="myskin" TagName="Header" Src="Controls/Header.ascx" %>
<%# Register TagPrefix="myskin" TagName="Footer" Src="Controls/Footer.ascx" %>
And include it via the control syntax:
<myskin:Header runat="server" />
....
<myskin:Footer runat="server" />
The control won't automatically have access to any context from the skin, so if you need to use SkinPath or PortalId or anything like that, you'll need to pass it through to the control manually. In the control, define a property to receive the value (using a <script runat="server"> section to write code [set the Language attribute in the control to C# for this]):
<script runat="server">
public string SkinPath { get; set; }
</script>
Then pass the value in the skin:
<myskin:Header runat="server" SkinPath="<%# SkinPath %>" />

Related

Pass (or inject) some HTML/JS or pass some model to shared Net Core Razor Class Library

I would like to have a shared UI project with common interface for other apps, so I don't have to copy/paste the same _Layout.cshtml between all apps which need same UI.
After using this question as reference and this article I have created shared Razor Class Library project. And when I reference this project via NuGet, the _Layout.cshtml in this shared project gets called and renders header with navigation.
But my problem comes then if I want to add some extra HTML to header. Let say I have drop down with some link to main landing page, to user setting, some administration page and etc. But how could I add some extra navigation links specific to concrete app next to all common links? Is there a way to inject HTML? Or maybe to pass some DTO model to this _Layout.cshtml?
Dump image below to help you to see what I try to achieve.
There's two possible approaches. First, you can simply call a partial in your layout:
<partial name="_HeaderExtra" />
Then, just add an empty partial view to the RCL, so it's satisfied, i.e. _HeaderExtra.cshtml. Finally, in your actual application, create the same partial view in the same location as the one in the RCL, and add whatever extra HTML you want there. When the partial is pulled into your layout, it will looking your project first, before falling back to the RCL.
The second option is to use sections. Sections are a little bit more strict, and you must remember to always reimplement them if you do any view inheritance. Essentially, in your layout, at something like:
#await RenderSectionAsync("HeaderExtra", required: false)
Then, in any sublayouts or views:
#section HeaderExtra
{
<!-- add something here -->
}
If you've got a sublayout and you want to be able to further customize this section in views, then you need:
#section HeaderExtra
{
#await RenderSectionAsync("HeaderExtra", required: false)
<!-- add something here -->
}

Ext.Net X.GetCmp method not working with FileUploadField

This is my first question. I am in stack overflow almost every day, but this is the first time I can't find the answer by myself and have to post it here.
I am creating pages with Ext.Net dynamically (in VB.net if it matters), based on a XML configuration, with all kind of controls and any number of them. So, for each field in the XML, I create the control and assign an ID to it (the ID is from the XML). I have a "submit" button that, when clicked, parse the XML again, get the ID of each field, and gets the control for this ID with Ext.Net.X.GetCmp. Then, once I have the control, I get the value and do some stuff with it. Everything works like a charm except for the control type FileUploadField. According to this, for some reason, GetCmp doesn't work with FileUploadField.
So, my question is: Is there some way to get a FileUploadField control based on it's ID? And, just to know, why GetCmp doesn't work with this kind of control?
Thank you very much in advance, and sorry for my bad english.
EDIT:
Ok, I have updated my Ext.Net to the latest version (2.2). Everything now looks strange, but it doesn't matter, if it works. Besides the appearance, I don't see any change in the behavior. GetCmp is still giving me the same. By the way, X.GetCmp(Of Ext.Net.FileUploadField)(ControlID) gives me a FileUploadField, not null, even if I don't create the control. The only thing, is that hasFile=false always, and the filebytes are empty.
EDIT 2:
I have run your example code and it works like a charm. I start thinking that the "isUpload" is the key. I Have been googling all the day trying to see where and why do I have to write this {isUpload=true}, but I didn't see anything useful. Can you explain it to me a little bit? Is only for DirectMethods? Is mandatory? Thanks a lot!
EDIT 3:
I feel sooooo stupid now. It works. Just added a simple isUpload:true in the DirectMethod call in a javascript. So many days to solve this stupid thing. For the next guy: check your isUpload ;).
So, my question is: Is there some way to get a FileUploadField control based on it's ID?
Only recreating that control. You render a control during one AJAX request (DirectEvent/DirectMethod) and it doesn't persist during another AJAX request unless you recreate it manually. It behaves the same as standard ASP.NET controls.
Controls can be recreated in Page_Init and must be recreated with the same IDs. In this case, a control's LoadPostData should extract a correct value from a POST collection. Here is a related discussion.
And, just to know, why GetCmp doesn't work with this kind of control?
It doesn't work in Ext.NET v1, but works in Ext.NET v2. Here is a sample below.
Though, it just extracts a file from the POST. X.GetCmp<>() returns a proxy control, it is not a real control. It is just a convenient way to extract POST values of dynamically rendered controls and, also, updates those controls on client (changing its properties and calling its methods).
<%# Page Language="C#" %>
<%# Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<script runat="server">
protected void RenderFileUploadField(object sender, DirectEventArgs e)
{
FileUploadField fileUploadField = new FileUploadField()
{
ID = "FileUploadField1",
Width = 300,
Listeners =
{
Change =
{
Handler = #"App.direct.GetFileName(this.id, {
isUpload : true
});"
}
}
};
this.Form.Controls.Add(fileUploadField);
fileUploadField.Render();
}
[DirectMethod]
public void GetFileName(string id)
{
X.Msg.Alert("FileName", X.GetCmp<FileUploadField>("FileUploadField1").PostedFile.FileName).Show();
}
</script>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Ext.NET v2 Example</title>
</head>
<body>
<form runat="server">
<ext:ResourceManager runat="server" />
<ext:Button
runat="server"
Text="Create a FileUploadField"
OnDirectClick="RenderFileUploadField" />
</form>
</body>
</html>
you could use simple javascript:
var fileinput = document.getElementById("fileinput");
as javascript does only search the DOM you need to be careful. each Ext.Net component will get a bunch of wrappers and sub-components and "unnecessary" siblings/parents/children (for header, label, bottom- and topbar and so on..)
if you have given an ID to the control you should be able to fetch it via:
App.{control-id}
this will return the constructor. you should be able to fetch FileBytes from ExtJS anytime using the App namespace (see BREAKING CHANGES)
the finished get for the FileBytes would look like this:
App.{control-id}.FileBytes

Remove <div> generated around Shared Block in EPiServer 7

Episerver always wrap shared block in a tag. I would like to get rid of this. So if in my LinkBlock has a Template with only
link
I would not get a
<div>link</div>
in the view for a user.
If this is not possible how can I change <div> to any other tag, or put a CssClass on it. Like it is possible in not shared blocks:
<EPiServer:Property runat="server" PropertyName="RightContentArea" CustomTagName="aside" CssClass="column-2 sidebar"></EPiServer:Property>
I believe it is the rendering of the ContentArea property which adds the div tags around the blocks it contains.
EPiServer suggests that in order to preserve the editing functionality of the block elements themselves they need to have the div around them.
A possible solution might be for you to do your own custom rendering of content areas, but depending on the kind of block templates you're using it can be tricky to get editing to work. The example in the link is for rendering multiple blocks of the same type.
You can use the CustomTagName and CssClass properties of the Property control to format the container element.
You may also use RenderSettings to modify container elements of child elements (where applicable).
I use this trick in cshtml:
#RenderBlocks(Model.CurrentPage.Content1)
#* ---------------------------------------------------------------------------------- *#
#* Render ContentArea without addition DIVs that EpiServer embed. That breaks layout a lot. *#
#helper RenderBlocks(EPiServer.Core.ContentArea content) {
if(null != content){
var blocks = content.FilteredContents.ToArray();
foreach(var block in blocks){
#Html.PropertyFor(x => block)
}
}
}
You can choose the tag using the CustomTagName attribute on the Property Control
Alternatively, if you wanted to remove the tag, you could use a control adapter. A good example is found here
You can also create a custom content area that doesn't render the divs when edited in live mode and only renders them in edit mode.
If you only need to do this once or twice I would still recommend going with the ChildrenCustomTagName route as it's a bit mroe flexible. If you need to do this a lot and you can't change your CSS easily then I would go custom content area. If you are interested in how to remove the div's I wrote a blog post and a sample site on github here Extra divs in content area how to remove them ?
Since i wasn't able to remove the <div>'s i didn't want, i put my own CSS class on them. This did the trick for me in Webforms. (If anyone still uses it)
Use <RenderSettings ChildrenCssClass="yourCssClass" />
<EPiServer:Property runat="server" PropertyName="RightContentArea"CustomTagName="aside" CssClass="column-2 sidebar"><RenderSettings ChildrenCssClass="yourCssClass"></RenderSettings></EPiServer:Property>

Passing Form fields which have been generated by User Control

I'm having real troubles passing form data from a posting page made up of User Controls.
I posted this question before, here, Getting form field names on Submit when form is user control but the answers have not solved my problem, or I have mis-understood them.
Let me try explaining what I am doing more clearly.
I have a page which displays a form to the user. The form is made of several sections, but for simplicity we'll say there are two. Each of these sections is a User Control, thus the actual markup for newSale.aspx is just:
<%# Page Language="VB" MasterPageFile="~/MasterPage.master" CodeFile="newSale.aspx.vb" Inherits="newSale_Default"%>
<%# Register TagPrefix="controls" TagName="customerForm" Src="~/Controls/customerForm.ascx" %>
<%# Register TagPrefix="controls" TagName="itemList" Src="~/Controls/itemList.ascx" %>
<asp:content id="content1" ContentPlaceHolderID="mainContent" runat="server">
<div class="content">
<form id="newSale" method="post" action="saveSale.aspx">
<h1>--- New Sale ---</h1>
<div class="section" id="customerSection">
<controls:customerForm ID='customerForm1' showBankDetails="false" runat='server' />
</div>
<div class="section" id="saleSection">
<controls:itemList ID='itemList1' showShipping="false" showDeposit="false" runat='server' />
<div class="row submitRow">
<div id="submitSale">Submit</div>
</div>
</div>
</form>
</div>
</asp:content>
So you see my two main Controls tags with the IDs "customerForm1" and "itemList1" respectively.
The submit button is deliberately a clickable div and submission is done by jQuery, thus:
$('#submitSale').live('click', function () { $('#newSale').submit(); });
As the User Controls are rendered into the browser, the IDs and Names of the elements are messed about (I understand the reason why) by ASP.NET, so taking one field as an example:
A field named "name" contained within the customerForm control becomes m$mainContent$customerForm1$name
'm' - being the ID of my MasterPage
'mainContent' - being the ID of the PlaceHolder
'customerForm1' - being the ID of the User Control and
'name' being the element's actual name.
I wish to submit this form to a separate file (saveSale.aspx) as per the action attribute of my Form tag declared above.
Within the Code-Behind of saveSale.aspx I need to save the data passed from the form into a dataBase and return it in the aspx file as an HTML page.
How do I reliably get the value of the submitted form fields in saveSale.aspx(.vb)?
<%= request.form("m$mainContent$customerForm1$name") %>
Works, but naturally is a pain to use, especially when I want to replicate this to other purposes.
m.mainContent.customerForm1.name.selectedValue()
tells me that 'm' is not declared
and from the other replies to my previous question I have tried registering the controls at the top of the (saveSale.aspx) page, and explicitly posting the Control into the page again with
<controls:customerForm ID='customerForm1' showBankDetails="false" runat='server' />
Which doesn't work, but even if it did, it makes no sense anyway as I don't want to use the Control anymore, I just want to get the data from it.
I do apologise if I'm being dumb here, but I have tried so many different variations of code and Googled ideas, but I can't seem to make this work in any scalable fashion beyond the Request.Form example above.
I am using .NET 2.0 so can't use the Static Client feature that I've seen mentioned for .NET 4.0
Also, please, I am using VB.NET, so if you can help, please help with a VB example.
Many thanks.

Expanding the use of PlaceHolderMain in Sharepoint 2010?

I want to create a 2 column layout in my master template page. I want both the left and right HTML column < div >'s in my design to have wysiwyg editors. This is what I am picturing...
<div id="container">
<div class="left-side">
<div id="sub-menu">asp:menu</div>
<asp:ContentPlaceHolder id="PlaceHolderMain1" runat="server" />
</div>
<div class="right-side">
<asp:ContentPlaceHolder id="PlaceHolderMain2" runat="server" />
</div>
</div>
but obviously, PlaceHolderMain1 or PlaceHolderMain2 are not optional content placeholders to select by default...
http://office.microsoft.com/en-us/sharepoint-designer-help/working-with-content-placeholder-controls-HA102265026.aspx
Is there a way to create an additional HTML-PlaceHolder with SharePoint?
By creating content types for a content page layout
[configure SharePoint's site settings -> then view content types under 'Site Objects' in SharePoint Designer], you could then take advantage of your "toolbox" located in SharePoint Designer.
Create your types and your page layout under site settings from your browser
Also assign your page layout to a specific master template
Open up your new page layout in SharePoint Designer
Then use the toolbox to drag any of the available content fields into your content page layout.
Save your layout page, check it in as major. Done.
As a result, I was able to drag on a Rich HTML field PLUS a web zone, into each floating div in my content page layout. FYI, you may or may not need to add on additional Tagprefix's to your content page layout, for example, if you are calling the asp:menu into it, be ready for that...
The solution also keeps you from re-creating multiple master templates, just because you need a new HTML layout scheme to choose from.