A Simple Template for a Custom mojoPortal Feature

For a general introduction to developing features for mojoPortal, see the overview article.

The mojoPortal Web project uses the Web Application project type in Visual Studio. In this model, C# code is not inline in the page, it is in codebehind files which are then compiled into mojoPortal.Web.dll in the bin folder. Using this model, you typically do not deploy the C# source code on production servers. Not deploying source code has some security benefits but the tradeoff is that you can't just edit the code on the server, you must compile it and redeploy the dlls.

Some developers may wish for the easy tweakability of inline code so I will explain here how it is possible to create .ascx ModuleControls and supporting .aspx pages with inline code and use them in your mojoPortal development. When using inline code, all the code is self contained within the .aspx file and there are no related code behind files. Instead the code is embedded in the page in <script runat="server"> </script>

The ModuleControl is the part that plugs into a page in the content system. When you add a feature to a page you are putting its ModuleControl on the page.

Here is a template that you can use as a starting point for the ModuleControl for a simple mojoPortal feature:

C# Example

<%@ Control Language="C#" ClassName="MyCustomSiteModule.ascx" Inherits="mojoPortal.Web.SiteModuleControl" %>

<%@ Import Namespace="mojoPortal.Business" %>
<%@ Import Namespace="mojoPortal.Business.WebHelpers" %>
<%@ Import Namespace="mojoPortal.Web.Framework" %>
<%@ Import Namespace="mojoPortal.Web.Controls" %>
<%@ Import Namespace="mojoPortal.Web.Editor" %>
<%@ Import Namespace="mojoPortal.Net" %>

<script runat="server">

protected override void OnInit(EventArgs e)
{
base.OnInit(e);

}

protected void Page_Load(object sender, EventArgs e)
{

LoadSettings();
PopulateLabels();
PopulateControls();

}

protected void Button1_Click(object sender, EventArgs e)
{
TextBox1.Text = "Hello Web";
}

private void PopulateControls()
{
TextBox1.Text = "Click the button";

}


private void PopulateLabels()
{

}

private void LoadSettings()
{

// TODO: if yous feature has an edit page link to it here
//Title1.EditUrl = SiteRoot + "/MyClassEdit.aspx";
//Title1.EditText =

Title1.Visible = !this.RenderInWebPartMode;
if (this.ModuleConfiguration != null)
{
this.Title = this.ModuleConfiguration.ModuleTitle;
this.Description = this.ModuleConfiguration.FeatureName;
}

}

</script>

<portal:OuterWrapperPanel ID="pnlOuterWrap" runat="server">
<mp:CornerRounderTop id="ctop1" runat="server" EnableViewState="false" />
<portal:InnerWrapperPanel ID="pnlInnerWrap" runat="server" CssClass="panelwrapper htmlmodule">
<portal:ModuleTitleControl id="Title1" runat="server" EditUrl="/Modules/HtmlEdit.aspx" EnableViewState="false" />
<portal:OuterBodyPanel ID="pnlOuterBody" runat="server">
<portal:mojoRating runat="server" ID="Rating" Enabled="false" />
<portal:InnerBodyPanel ID="pnlContent" runat="server" CssClass="modulecontent">

Your custom form goes here.
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />

</portal:InnerBodyPanel>
<portal:EmptyPanel id="divFooter" runat="server" CssClass="modulefooter" SkinID="modulefooter"></portal:EmptyPanel>
</portal:OuterBodyPanel>
<portal:EmptyPanel id="divCleared" runat="server" CssClass="cleared" SkinID="cleared"></portal:EmptyPanel>
</portal:InnerWrapperPanel>
<mp:CornerRounderBottom id="cbottom1" runat="server" EnableViewState="false" />
</portal:OuterWrapperPanel>

VB.NET Example

<%@ Control Language="VB" ClassName="PNUserControl.ascx" Inherits="mojoPortal.Web.SiteModuleControl" %>
<%@ Import Namespace="mojoPortal.Business" %>
<%@ Import Namespace="mojoPortal.Business.WebHelpers" %>
<%@ Import Namespace="mojoPortal.Web.Framework" %>
<%@ Import Namespace="mojoPortal.Web.Controls" %>
<%@ Import Namespace="mojoPortal.Web.Editor" %>
<%@ Import Namespace="mojoPortal.Net" %>
<script runat="server">
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
End Sub

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
TextBox1.Text =
"Hello Web"
End Sub
Private Sub PopulateControls()
TextBox1.Text =
"Click the button"
End Sub
Private Sub PopulateLabels()
End Sub
Private Sub LoadSettings()
' TODO: if yous feature has an edit page link to it here
'Title1.EditUrl = SiteRoot + "/MyClassEdit.aspx";
'Title1.EditText =
Title1.Visible = RenderInWebPartMode
If Not ModuleConfiguration Is Nothing Then
Title = ModuleConfiguration.ModuleTitle
Description = ModuleConfiguration.FeatureName
End If
End Sub
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
LoadSettings()
PopulateLabels()
PopulateControls()
End Sub
</script>
<portal:OuterWrapperPanel ID="pnlOuterWrap" runat="server">
<mp:CornerRounderTop id="ctop1" runat="server" EnableViewState="false" />
<portal:InnerWrapperPanel ID="pnlInnerWrap" runat="server" CssClass="panelwrapper htmlmodule">
<portal:ModuleTitleControl id="Title1" runat="server" EditUrl="/Modules/HtmlEdit.aspx" EnableViewState="false" />
<portal:OuterBodyPanel ID="pnlOuterBody" runat="server">
<portal:mojoRating runat="server" ID="Rating" Enabled="false" />
<portal:InnerBodyPanel ID="pnlContent" runat="server" CssClass="modulecontent">

Your custom form goes here.
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />

</portal:InnerBodyPanel>
<portal:EmptyPanel id="divFooter" runat="server" CssClass="modulefooter" SkinID="modulefooter"></portal:EmptyPanel>
</portal:OuterBodyPanel>
<portal:EmptyPanel id="divCleared" runat="server" CssClass="cleared" SkinID="cleared"></portal:EmptyPanel>
</portal:InnerWrapperPanel>
<mp:CornerRounderBottom id="cbottom1" runat="server" EnableViewState="false" />
</portal:OuterWrapperPanel>

Its a basic hello world example. Create a text file, paste this in, save as a YourFeatureName.ascx in the Web/Modules folder, then "install" it in the site by going to (Key icon) Administration Menu > Advanced Tools > Feature Installation. Give it a name and set the path to your .ascx file. Now it will show up in the Features dropdown list.
 

Using Inline Code for Custom Pages

In some cases for more complex features, you may need to link to supporting pages that are outside the content menu.  For example, the Forum feature on this site has a number of supporting pages. The Forum Module Control is the part that plugs into a content system page and from there it links to its own physical pages to provide the various views needed for a forum. When you link to your own custom pages, you should always pass the pagid and the momoduleid of your feature instance in the query string to keep the menu in sync and to know which instance of your feature is in use.  Below is a skeleton page example you can use as a starting point for a supporting page for your feature, using the inline code model. Just create a text file with a .aspx extension and copy and paste the below example as a starting point. Make sure the page name does not conflict with any existing pages and just drop it in to your web folder. Next create a new page in the content system and in the page settings set the Url property to point to your physical page. I think you can use the "~/pagename.aspx" syntax for te url but I'm sure you can use a fully qualified url.

<%@ Page Language="C#"
ClassName="ExampleInlineCodePage"
Inherits="mojoPortal.Web.mojoBasePage"
MasterPageFile="~/App_MasterPages/layout.Master" %>

<%@ Import Namespace="mojoPortal.Business" %>
<%@ Import Namespace="mojoPortal.Business.WebHelpers" %>
<%@ Import Namespace="mojoPortal.Web.Framework" %>
<%@ Import Namespace="mojoPortal.Web.Controls" %>
<%@ Import Namespace="mojoPortal.Web.Editor" %>
<%@ Import Namespace="mojoPortal.Net" %>

<script runat="server">

protected override void OnPreInit(EventArgs e)
{
this.allowSkinOverride = true;
base.OnPreInit(e);
}

protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.SuppressPageMenu();
}

protected void Page_Load(object sender, EventArgs e)
{
TextBox1.Text = "Click the button";

}

protected void Button1_Click(object sender, EventArgs e)
{
TextBox1.Text = "Hello Web";
}

</script>

<asp:Content ContentPlaceHolderID="leftContent" ID="MPLeftPane" runat="server" />
<asp:Content ContentPlaceHolderID="mainContent" ID="MPContent" runat="server">
<portal:OuterWrapperPanel ID="pnlOuterWrap" runat="server">
<mp:CornerRounderTop id="ctop1" runat="server" EnableViewState="false" />
<portal:InnerWrapperPanel ID="pnlInnerWrap" runat="server" CssClass="panelwrapper ">
<portal:HeadingControl ID="heading" runat="server" />
<portal:OuterBodyPanel ID="pnlOuterBody" runat="server">
<portal:InnerBodyPanel ID="pnlInnerBody" runat="server" CssClass="modulecontent">

Your custom form goes here.
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<portal:mojoButton ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />

</portal:InnerBodyPanel>
</portal:OuterBodyPanel>
<portal:EmptyPanel id="divCleared" runat="server" CssClass="cleared" SkinID="cleared"></portal:EmptyPanel>
</portal:InnerWrapperPanel>
<mp:CornerRounderBottom id="cbottom1" runat="server" EnableViewState="false" />
</portal:OuterWrapperPanel>
</asp:Content>
<asp:Content ContentPlaceHolderID="rightContent" ID="MPRightPane" runat="server" />
<asp:Content ContentPlaceHolderID="pageEditContent" ID="MPPageEdit" runat="server" />

Last Updated 2012-03-23 by Joe Audette