Pages

Thursday, March 15, 2012

Customising RichTextEditor's Styles and Markup Styles Menu Items

OK, there are a few articles around discussing how to do this, this post by Marc seems to be the definitive article about what, where, how and why but I felt like writing a simplified version for myself.
So here goes...

What are we talking about?
First, I'll try and give my own spin on what the Styles and Markup Styles are and what they affect.
Below is the definition given by many when describing what the differences are between the two, my interpretation of these are given in italics.

Markup Styles
  • Nest the text and its HTML tag within the html tag specified in the style if the tag to nest is a span element. What a mouthful, ok I think it means, if the text you are trying to apply a Markup Style to is a span element, then the text and its surrounding tag (probably div p or h1 etc) will get 'nested' inside the tag specified by the css class you create.
  • Replace the current tag if is is not a span element. If the text is not in a span, then the current tags (again probably div, p etc) will be replaced with the tag in the css class.
  • Remove all the styles for the children elements. This is easy, removes all the children styles so that the selected text will all be rendered using the specified css class.
  • Remove the html tag if the same style is applied a second time (this is a way of removing a Markup style for an end-user). Simple, removes the style.
Styles
  • Nest the text in a span tag with the style class if the text is not already inside an HTML tag.
  • Just add the class to the current HTML tag if this tag is not a span tag.
  • Replace the class of the HTML tag if this tag is a span tag.
  • Remove the html span tag if the same style is applied a second time (this is a way of removing a Style for an end-user) Simple, removes the style.

Clear as mud, good. Now, both these 'styles' are used in the Rich Text Editors of both Wiki Pages and Publishing Pages and by default, the CSS classes live in \14\template\layouts\1036\styles\themable\corev4.css stylesheet.
Right, well how do we change it?
So we now have an idea of what the ribbon controls do, how do we add to or change them?

Syntax
OK, now for the cool way in which this stuff gets pulled together. All styles conform to a naming convention. This convention is then used by the RTE on the client side to build the ribbon control. So all you need to do is follow the convention and you can add a new class/style to the ribbon, easy.

.ms-rteStyle-xxxxx - for styles

.ms-rteElement-xxxxx - for markup styles

Simple? Just add the name of the class you want to create where the x's are and there you go, well almost. Inside the class definition, you need to add

-ms-name:"xxxxx";

Where again, you replace the x's with the name you want to appear in the ribbon control. So if I wanted to add a style like Heading 5, I could do the following:

.ms-rteStyle-H5
{
   -ms-name:"Heading 5";
   FONT-SIZE:14pt;
   FONT-WEIGHT:normal;
}

You get the picture, sky's the limit as to what you can do with your text. Either trawl through the corev4.css or just look at the styles applied to text after you change a markup style using developer tools (F12 in IE).

Well, sounds like we have all the information about these styles that we need so we can pretty much do anything right? Not quite. Removing a style is tricky. Adding and Changing is simple, because its just css. There are some ways to remove styles including custom masterpages, jQuery and custom page layouts etc so there is a way around it. I won't go into that in this article, use bingle.

Solution Management
So now you know what to change, where do you change it? What's best practice for lifecycle management of this solution? Depends :)

Testing / Debugging
Simple, wack the css into a file, upload it to the Styles Library and reference it using the HTML Form Web Part on the page you want to test. Simple, no code changes to pages, solutions etc. And you could get away with doing this in production if it was only on 1 or 2 pages, but having this as a reuseable solution just won't cut it.

MasterPage
In my opinion, the best way to do this is by putting a CSS Registration reference into a master page pointing to a specific css file you want to setup in the Style Library. This way, if you don't want to use any custom styles, you just don't have the css file in the Style Library, but if you do, then you can just edit the file. The added benefit of this is that you can have different files for different Site Collections. Just add the line below to your masterpage, up near the top, there is probably already similar references.

{SharePoint:CssRegistration name="{% $SPUrl:~sitecollection/Style Library/~language/MarkupStyles.css %}" After="corev4.css" runat="server"/}
(don't forget to replace the curly braces with greater than/less than symbols, and change the path where relevant)

Other Options
There are other options available where you are either editing the core files, editing existing pages or page layouts etc. but I wouldn't really go near them.

Removal of the OOTB styles is difficult. This can be done either through JavaScript or by adding server-side code to remove references to corev4.css etc, see Marc's article near the bottom for these.

If you are going to go down the path of modifying a Master Page, then perhaps you can insert your JavaScript in the master page and do some tricky stuff there but that is out of my league :)

SharePoint Search Web Services and anonymous access

Recently had to debug an issue with a 3rd Party app using the /_vti_bin/search.asmx web service which, at the time, stopped working with 'no changes' to the environment. We were receiving the SoapException: 'Server was unable to process request ... Unauthorized Operation'.

This turned out to be not quite the truth and infact Anonymous Access was enabled on the Web Application for use by a monitoring tool. The Farm configuration doesn't use Kerberos (jury is still out on whether Kerberos is needed in this situation anyway), just Ntlm and it seems that once a successful connection is made to another SharePoint web service (in this case /_vti_bin/lists.asmx) then a subsequent call to the search service works.

We did a bit of packet sniffing as well and it looks like the search service trys to authenticate differently than the other web services. Not sure why this is the case. I need to understand more about how Search works.

Here's the post on TechNet.

Moral of the story is to check, and double check the environment before spending time going down rabbit holes. Statements like 'it was working, then it stopped...with no change in the environment' just don't add up.