Tuesday, February 28, 2012

How to avoid removal of empty attributes for HTML elements in TinyMCE

TinyMCE has a habit of removing empty attributes for many HTML elements, and for various reasons this might not always be what you want.

For instance, today a customer ran into an issue where the value attribute of a <option> element was removed if it was empty. The empty value attribute was needed for custom validation purposes, so this caused quite a headache for them.

Another example which is more relevant for other projects, is the empty alt attribute for the <img> element, which is needed for the HTML to validate.

So how can you force TinyMCE to leave these empty attributes be instead of removing them? You can add your rule to extended_valid_elements, which will then be added to the default TinyMCE rule set.

Here’s the solution for allowing an empty value attribute for the <option> element:

extended_valid_elements: 'option[value=]'

And there’s the solution for allowing an empty alt attribute for the <img> element:

extended_valid_elements: 'img[alt=]'

Notice the equals (=) sign after the attribute name, this is what tells TinyMCE that an empty value is allowed. If you remove the equals (=) sign, for example option[value], TinyMCE would interpret the value attribute as being allowed for the option element, but it would still remove it if it contained an empty value.

I recommend having a look at the default rule set for TinyMCE if you’re not sure how TinyMCE treats the different elements and attributes!

Tuesday, February 21, 2012

Webparts in EPiServer: Step by step

At Epinova we’re huge fans of using web parts in EPiServer as this enables the editor to choose what type of content should be displayed on certain pages while at the same time ensuring the editor doesn’t try to break the design of the website.

This is a step by step guide to getting started with web parts in EPiServer using the AlloyTech demo site as an example.

Our goal is to transform the bottom region of the AlloyTech startpage (the pink rectangle) into a web part zone where the editor can choose between several web parts.

AlloyOriginal_2

1) Install EPiCode.WebParts.Core and Epinova.WebParts.Providers from the EPiServer Nuget feed.

NugetInstall

2) Make sure a reference has been added to the following dlls in your project:

EPiCode.WebParts.Core.dll
Epinova.WebParts.Providers.dll
Microsoft.Web.Preview.dll

3) In MasterPage.Master, add a ScriptManagerLowUiImpact control and a EPiWebPartManager control after the opening <form> tag:

1: <form runat="server">

2:    <epicode:ScriptManagerLowUiImpact runat="server" EnablePartialRendering="false" />

3:    <epicode:EpiWebPartManager runat="server" Personalization-InitialScope="Shared" Personalization-Enabled="true" />

4:    <!-- Your markup here -->

5: </form>

4) Create a ManagementConsole.ascx:

Note that the ManagementConsole.ascx file should NOT have a code-behind or designer file, instead it should inherit directly from System.Web.UI.UserControl.

1: <%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.UserControl" %>

2:  

3: <epicode:WebPartManagementConsole ID="WebPartManagementConsole1" runat="server" />

4: <asp:CatalogZone runat="server" ID="ThemeCatalogZone">

5:    <ZoneTemplate>

6:       <asp:DeclarativeCatalogPart ID="DeclarativeCatalogPart1" runat="server">

7:          <WebPartsTemplate>

8:          </WebPartsTemplate>

9:       </asp:DeclarativeCatalogPart>

10:    </ZoneTemplate>

11: </asp:CatalogZone>

What you’ve done here is to declare a CatalogZone called ThemeCatalogZone, and later you will declare the different type of web parts available in this zone by adding them to the WebPartsTemplate.

5) Add the following to the <pages><control> section of your web.config file:

<add tagPrefix="uc" tagName="ManagementConsole" src="~/Templates/AlloyTech/WebParts/Util/ManagementConsole.ascx" />

6) Add the ManagementConsole usercontrol to your MasterPage.Master (directly after the EPiWebPartManager control):

1: <form runat="server">

2:    <epicode:ScriptManagerLowUiImpact runat="server" EnablePartialRendering="false" />

3:    <epicode:EpiWebPartManager runat="server" Personalization-InitialScope="Shared" Personalization-Enabled="true" />

4:    <uc:ManagementConsole runat="server" />

5:    <!-- Your markup here -->

6: </form>

7) Create a banner webpart:

A banner web part will consist of an image, an alternative text and a URL for the image. Create a usercontrol called BannerPart, and add the following code to BannerPart.ascx.cs:

1: public partial class BannerPart : UserControlWebPartBase

2: {

3:    [Personalizable, IsRequired]

4:    public PropertyImageUrl Image { get; set; }

5:  

6:    [Personalizable]

7:    public PropertyString ImageAltText { get; set; }

8:  

9:    [Personalizable, IsRequired]

10:    public PropertyUrl ImageLink { get; set; }

11:  

12:    public BannerPart()

13:    {

14:       Image = new PropertyImageUrl();

15:       ImageAltText = new PropertyString();

16:       ImageLink = new PropertyUrl();

17:    }

18:  

19:    protected override void OnPreRender(EventArgs e)

20:    {

21:       uxImage.ImageUrl = Image.Value != null ? (string)Image.Value : string.Empty;

22:       uxImage.AlternateText = ImageAltText.Value != null ? (string)ImageAltText.Value : string.Empty;

23:       uxLink.NavigateUrl = ImageLink.Value != null ? (string) ImageLink.Value : string.Empty;

24:    }

25: }

Here we have declared the three properties mentioned above: Image, ImageAltText and ImageLink. All the properties are Personalizable, but only Image and ImageLink are required.

Add the following markup to BannerPart.ascx:

1: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="BannerPart.ascx.cs"

2: Inherits="EPiServer.Templates.AlloyTech.WebParts.BannerPart" %>

3:  

4: <asp:HyperLink ID="uxLink" runat="server">

5: <asp:Image ID="uxImage" runat="server" /></asp:HyperLink>

You can add translations to your Banner web part by creating a lang file called WebParts.xml:

1: <?xml version="1.0" encoding="utf-8" ?>

2:    <languages>

3:       <language name="English" id="en">

4:          <webparts>

5:             <webpart name="BannerPart">

6:                <caption>Banner</caption>

7:                <description>Image banner with link and alternative text</description>

8:             </webpart>

9:             <common>

10:               <property name="Image">

11:                 <caption>Image</caption>

12:                 <help></help>

13:               </property>

14:               <property name="ImageAltText">

15:                 <caption>Alternative Text</caption>

16:                 <help></help>

17:               </property>

18:               <property name="ImageLink">

19:                 <caption>Image Link</caption>

20:                 <help></help>

21:               </property>

22:             </common>

23:          </webparts>

24:      </language>

25: </languages>

7) Add BannerPart to the <WebPartsTemplate> in ManagementConsole.ascx:

1: <%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.UserControl" %>

2: <%@ Register TagPrefix="uc" tagName="BannerPart" src="../BannerPart.ascx" %>

3:  

4: <epicode:WebPartManagementConsole ID="WebPartManagementConsole1" runat="server" />

5: <asp:CatalogZone runat="server" ID="ThemeCatalogZone">

6:    <ZoneTemplate>

7:       <asp:DeclarativeCatalogPart ID="DeclarativeCatalogPart1" runat="server">

8:           <WebPartsTemplate>

9:              <uc:BannerPart ID="wpBanner" runat="server" />

10:          </WebPartsTemplate>

11:      </asp:DeclarativeCatalogPart>

12:    </ZoneTemplate>

13: </asp:CatalogZone>

8) Add a webpart zone in your Default.aspx file:

<epicode:ZoneLowUiImpact runat="server" ID="MainContentAreaZone" catalogzoneid="ThemeCatalogZone" layoutorientation="Horizontal" />

Note that the CatalogZoneId is equal to the ID of the CatalogZone in step 7, which means that the editor will be able to create a Banner webpart on the startpage.

9) Create a banner webpart on the startpage of your website:

In order to do this you need to be logged in as an administrator. If you right-click your startpage in view mode, you will see a new option in the context menu called “Edit Web Parts”. Clicking this option will show you an overview of the web part zones on the page:

WebpartZone

You will also see a dropdown list containing all the available web parts for this web part zone, in this case only Banner. Click “Add” and you will be able to create a Banner web part:

AddWebPart

Fill in all the properties and clicking OK will give you a preview of the web part on the page. If you want to publish your new web part, right-click the page and chose “Save and publish”.

10) Create your own web parts:

If you want to create more webparts you need to create a usercontrol for your webpart inheriting from UserControlWebPartBase as explained in step 7. You will also need to add it to the <WebPartsTemplate> of your ManagementConsole.ascx file in order for the administrator to access it in the web part zone.

Saturday, February 11, 2012

Multitasking Saturday with a technical review and Epinova.CRMFramework

DSC_0717

What you see here (apart from the game and my dog) is my new project. I’ve been asked to do a technical review of an upcoming book. I didn’t hesitate for a second when I got the offer as I’m extremely curious to see how the process of publishing a technical book works.

For the next couple of months, I’ll receive a new chapter and a due date weekly. What I have to do is read the chapter and comment on things like: Is the structure of the chapter logical? Are the code examples good enough? Is something too detailed or missing? Will the reader be able to reach the objectives of the chapter after reading it and doing the exercises? Quite a challenge, but so far I love it!

Needless to say, I wasn’t able to concentrate much on the technical review at the end of today’s game. But now it’s time to get back to work and finish the review before I move on to finishing off the upgrade of my CRM Framework.

Friday, February 10, 2012

Files zipped on Mac gave System.UnauthorizedAccessException after transfering to Windows server

I ran into a quite frustrating problem during a deployment of an EPiServer site yesterday, all files in the VPP folder gave me a HTTP 500 error:

“System.UnauthorizedAccessException: Access to the path ‘…’ is denied.”

We’ve all seen this error message before, and the first thing to do is check the access rights on the VPP folders on disk. The access rights were correct, so I went on to checking the VPP and IIS configuration but found nothing wrong.

After double checking configuration, asking everyone available for possible solutions, eating all the cheese in my fridge, checking the configuration yet again, I realized I was clueless. Totally clueless, with Google laughing at me and a customer becoming more and more anxious. At last, however, I found the problem in the most random manner possible.

This is what we did earlier that night:

1) VPP folders were zipped on a Mac
2) The zipped file was transferred to a Windows 2008 server
3) The files were unzipped using the built-in “Extract all” function in Windows.

From what I’ve been able to find out, these steps are what caused the problems. The files zipped on a Mac and extracted using the built-in “Extract all” function in Windows were automatically encrypted!

This does not seem to be an issue if you use WinRAR or 7-Zip, but I haven’t been able to find a more detailed description of why. The closest I’ve come to finding some more information is from this forum thread.

How to decrypt the files:

1) Right-click the VPP folder and choose “Properties”
2) In the General tab, click “Advanced”
3) Uncheck the “Encrypt contents to secure data” checkbox

So it all ended well, but I’d still like to know exactly why Windows encrypted the files during the extraction. If you have the answer, please leave a comment so this can stop annoying me :)

Last, but not least: Thanks to everyone who tried to help!