Rich Text Editor: Ordered list start at different no

Tags

, ,

We have used a very good feature of Microsoft word for setting a start number for the ordered list.

Our site editor wanted a similar feature in our Rich Text Editor in Sitecore.

Numbered list in the Rich Text Editor.

<ol >
<li>Third Line</li>
<li>Fourth Line</li>
</ol>

 

This will be displayed as below.

  1. Third Line
  2. Fourth Line

What should I do if I want to start the no from 3?

We googled for some OOB solution in Sitecore, didn’t find any. Then tried for Rich Text Editor again not much info. And then came across one article http://www.plausiblenonsense.com/2015/12/starting-numbered-list-at-different.html.

The Solution is very simple. In Rich Text Editor, move to HTML tab and add start=”number“. Where number is the starting no. See the Example below.

<ol start="3">
<li>Third Line</li>
<li>Fourth Line</li>
</ol>

 

  1. Third Line
  2. Fourth Line

This looks much more simpler than we thought.

Advertisements

Adding a Custom Button in the Rich Text Editor in Sitecore 8.1

Tags

, , , ,

I have been working on multiple things right now. And came across an issue where our site manager wanted a specific class to be added in A tag when we are adding the Sitecore Link.

We found multiple solutions while googling and tried the same. But most of the code was in earlier version of Sitecore so one or other thing was missing.

Another important thing was, to add any button or anything we needed to make changes in Sitecore files. Our team which manages the Sitecore upgrades asked to find a solution where we don’t need to modify any Sitecore files. This way it would be much more easier task during the Sitecore upgrade.

I have achieved the same so mentioning the process step by step.

  • Create a button in Sitecore – core database – in HTML Editor profiles
  • Create code behind – if needed
  • Create an XML file
  • Create a JS file
  • Create config file

 

Steps in Detail

  1. Login to Sitecore admin panel. Change to Core DB. Go to “/sitecore/system/Settings/Html Editor Profiles/”. You will find multiple profiles. Go to the profile you want to modify. Suggestion: Create your custom profile and then change. insert_dialog_in_html_editor
  2. Add below code in a Class file in your .Net project – This will be referred in the XML file in CodeBeside tag.
    public class InsertDialogForm : DialogForm
    
    {
    protected DataContext DialogFolderDataContext;
    protected TreeviewEx DialogContentItems;
    protected string Mode
    {
    get
    {
    string mode = StringUtil.GetString(base.ServerProperties["Mode"]);
    if (!string.IsNullOrEmpty(mode))
    {
    return mode;
    }
    return "shell";
    }
    set
    {
    Assert.ArgumentNotNull(value, "value");
    base.ServerProperties["Mode"] = value;
    }
    }
    protected override void OnLoad(EventArgs e)
    {
    Assert.ArgumentNotNull(e, "e");
    base.OnLoad(e);
    if (!Context.ClientPage.IsEvent)
    {
    Inialize();
    }
    }
    
    private void Inialize()
    {
    SetMode();
    SetDialogFolderDataContextFromQueryString();
    }
    private void SetMode()
    {
    Mode = WebUtil.GetQueryString("mo");
    }
    private void SetDialogFolderDataContextFromQueryString()
    {
    DialogFolderDataContext.GetFromQueryString();
    }
    protected override void OnOK(object sender, EventArgs args)
    {
    Assert.ArgumentNotNull(sender, "sender");
    Assert.ArgumentNotNull(args, "args");
    string selectedItemID = GetSelectedItemIDAsString();
    if (string.IsNullOrEmpty(selectedItemID))
    {
    return;
    }
    string selectedItemName = GetSelectedItemName();
    string javascriptArguments = string.Format("{0}, {1}", EscapeJavascriptString(selectedItemID), EscapeJavascriptString(selectedItemName));
    if (IsWebEditMode())
    {
    SheerResponse.SetDialogValue(javascriptArguments);
    base.OnOK(sender, args);
    }
    else
    {
    string closeJavascript = string.Format("scClose({0})", javascriptArguments);
    SheerResponse.Eval(closeJavascript);
    }
    }
    
    private string GetSelectedItemIDAsString()
    {
    ID selectedID = GetSelectedItemID();
    if (selectedID != ID.Null)
    {
    return selectedID.ToString();
    }
    return string.Empty;
    }
    private ID GetSelectedItemID()
    {
    Item selectedItem = GetSelectedItem();
    if (selectedItem != null)
    {
    return selectedItem.ID;
    }
    return ID.Null;
    }
    private string GetSelectedItemName()
    {
    Item selectedItem = GetSelectedItem();
    if (selectedItem != null)
    {
    return selectedItem.Name;
    }
    return string.Empty;
    }
    private string GetSelectedItemPath()
    {
    Item selectedItem = GetSelectedItem();
    if (selectedItem != null)
    {
    return selectedItem.Paths.FullPath;
    }
    return string.Empty;
    }
    private Item GetSelectedItem()
    {
    return DialogContentItems.GetSelectionItem();
    }
    private static string EscapeJavascriptString(string stringToEscape)
    {
    return StringUtil.EscapeJavascriptString(stringToEscape);
    }
    protected override void OnCancel(object sender, EventArgs args)
    {
    Assert.ArgumentNotNull(sender, "sender");
    Assert.ArgumentNotNull(args, "args");
    if (IsWebEditMode())
    {
    base.OnCancel(sender, args);
    }
    else
    {
    SheerResponse.Eval("scCancel()");
    }
    }
    private bool IsWebEditMode()
    
    {
    return string.Equals(Mode, "webedit", StringComparison.InvariantCultureIgnoreCase);
    }
    }

     

  3. Open path in your Website : Sitecore\shell\Controls\Rich Text Editor. Create a Folder named InsertDialog. Create an XML file in this folder. Copy below mentioned code in the XML file.
    <?xml version="1.0" encoding="utf-8" ?>
    <control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
     <RichText.InsertDialog>
     <FormDialog Icon="Network/32x32/arrow_join.png" Header="Insert Dialog"
     Text="Select the dialog content item you want to insert." OKButton="Insert">
    
    < script Type="text/javascript" Language="javascript" Src="/sitecore/shell/Controls/Rich Text Editor/InsertDialog/InsertDialog.js">.</ script>
    <!--Remove space from above line -->
    
    <CodeBeside Type="SND81.SC.Extensions.InsertDialog.InsertDialogForm,SND81.SC.Extensions" />
    
    <DataContext ID="InternalLinkDataContext"/>
     <DataContext ID="DialogFolderDataContext" Root="{A58A9251-9CA3-4CF0-8BBA-FEB606CD0C5A}" />
    
    <Tabstrip ID="Tabs" Width="100%" Height="100%">
     <Tab ID="InternalLinkTab" Header="Internal Link">
     <Scrollbox Width="100%" Height="100%" Background="white" Border="none" Padding="0">
     <TreeviewEx ID="DialogContentItems" DataContext="DialogFolderDataContext" Root="true" />
     </Scrollbox>
    
    </Tab>
     </Tabstrip>
    </FormDialog>
     </RichText.InsertDialog>
    </control>
  4. Open path in your Website : Sitecore\shell\Controls\Rich Text Editor\InsertDialog. Create a JS file in this folder. Copy below mentioned code in the JS file.
    function GetDialogArguments() {
     return getRadWindow().ClientParameters;
    }
     
    function getRadWindow() {
     if (window.radWindow) {
     return window.radWindow;
     }
     
     if (window.frameElement && window.frameElement.radWindow) {
     return window.frameElement.radWindow;
     }
     
     return null;
    }
     
    var isRadWindow = true;
     
    var radWindow = getRadWindow();
     
    if (radWindow) { 
     if (window.dialogArguments) { 
     radWindow.Window = window;
     } 
    }
     
    function scClose(url, text) {
     var returnValue = {
     url:url,
     text:text
     };
     
     getRadWindow().close(returnValue);
    }
     
    function scCancel() {
     getRadWindow().close();
    }
     
    function scCloseWebEdit(url) {
     window.top.returnValue = window.returnValue = url;
     window.top.close();
    }
    
    if (window.focus && Prototype.Browser.Gecko) {
     window.focus();
    }
  5. Create a JS file at any location in the website. Can be in JS folder or Sitecore folder. Add below code in the file. Suggestion: Create a single file like RTECustomization.js and place all such code in a single file.
    Telerik.Web.UI.Editor.CommandList["InsertDialog"] = function(commandName, editor, args) {
     var d = Telerik.Web.UI.Editor.CommandList._getLinkArgument(editor);
     Telerik.Web.UI.Editor.CommandList._getDialogArguments(d, "A", editor, "DocumentManager");
    
    var html = editor.getSelectionHtml();
    var id;
    // internal link in form of <a href="~/link.aspx?_id=110D559FDEA542EA9C1C8A5DF7E70EF9">...</a>
     if (html) {
     id = GetMediaID(html);
     }
    // link to media in form of <a href="-/media/CC2393E7CA004EADB4A155BE4761086B.ashx">...</a>
     if (!id) {
     var regex = /~\/media\/([\w\d]+)\.ashx/;
     var match = regex.exec(html);
     if (match && match.length >= 1 && match[1]) {
     id = match[1];
     }
     }
    if (!id) {
     id = scItemID;
     }
    id = scFormatId(id);
    scEditor = editor;
    editor.showExternalDialog(
     "/sitecore/shell/default.aspx?xmlcontrol=RichText.InsertDialog&la=" + scLanguage + "&fo=" + id + (scDatabase ? "&databasename=" + scDatabase : ""),
     null, //argument
     1100,
     700,
     scInsertDialog, //callback
     null, // callback args
     "Insert Dialog",
     true, //modal
     Telerik.Web.UI.WindowBehaviors.Close, // behaviors
     false, //showStatusBar
     false //showTitleBar
     );
    };
    function scInsertDialog(sender, returnValue) {
     if (!returnValue) {
     return;
     }
    var d = scEditor.getSelection().getParentElement();
    if ($telerik.isFirefox && d.tagName == "A") {
     d.parentNode.removeChild(d);
     } else {
     scEditor.fire("Unlink");
     }
    var text = scEditor.getSelectionHtml();
    if ($telerik.isIE) {
     text = scIEFixRTETextRange(scEditor);
     }
    var returnURL = returnValue.url.replace("{", "").replace("}", "").replace('-', '');
    
    if (text == "" || text == null || ((text != null) && (text.length == 15) && (text.substring(2, 15).toLowerCase() == "<p>&nbsp;</p>"))) {
     text = returnValue.text;
     }
     else {
     // if selected string is a full paragraph, we want to insert the link inside the paragraph, and not the other way around.
     var regex = /^[\s]*<p>(.+)<\/p>[\s]*$/i;
     var match = regex.exec(text);
     if (match && match.length >= 2) {
     var placeholderHtml = "<a class=\"Green Goblin\""
     + " href=\"~/link.aspx?_id=" + returnURL
     + "&amp;_z=z\""
     + match[0]
     + "</a>";
    
    scEditor.pasteHtml(placeholderHtml, "DocumentManager");
     return;
     }
     }
    var placeholderHtml = "<a class=\"Green Goblin\""
     + " href=\"~/link.aspx?_id=" + returnURL
     + "&amp;_z=z\""
     + text
     + "</a>";
    
    scEditor.pasteHtml(placeholderHtml, "DocumentManager");
    }
  6. Now comes the most important thing. Code in Step 5 can be added directly in the RichText Commands.js file located at . But we don’t want to do that. We don’t want to touch any Sitecore file. So we will use the Config. Add a config file in the Include folder.
    <?xml version="1.0" encoding="utf-8"?>
    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
     <sitecore>
     <clientscripts>
     <htmleditor>
     <script src="sitecore\shell\Controls\Rich Text Editor\RTECustomization.js" language="javascript" key="customJs" />
     </htmleditor>
     </clientscripts>
     </sitecore>
    </configuration>


    IMP points
    :
    Telerik.Web.UI.Editor.CommandList[“InsertDialog”] – Here Telerik.Web.UI.Editor.CommandList is the new change in Sitecore 8.0 onwards. If you have upgraded the site and you have RTE customization then it will fail because of this change. Earlier it was RadEditorCommandList. “InsertDialog” in the bracket is the same as we mentioned in the Sitecore Button.

Install Mongo DB using PowerShell

Tags

, , , ,

This article provides quick way to install Mongo DB using PowerShell script.

 

Most important thing you need when you start working on Sitecore is a Database. 🙂

Earlier you needed only SQL but now you need Mongo DB as well for all the Analytics data (To store user interaction on the website).

While working on the local development machine you need to install the Mongo DB.

What are the steps involved to get the Mongo up and Running?

  1. Download Mongo DB
  2. Install Mongo DB
  3. Create Data folder to store all the data of the Mongo DB
  4. Create the configuration file which tells that what is the DB Path and what is the Log path
  5. Create a Service to keep the Mongo running.
  6. Start the Service.

Once all the above steps are complete then Mongo is up and running.

This is a bit time consuming task. So I created a PowerShell script to do these tasks and without any manual interaction. This script will do all the steps from 2 to 6.

You just need to run the powershell script and it will take care of everything.

You can download the folder from below link

https://app.box.com/s/wuurfry37wo3h194tv73cc5nmny3t4op

  1. Once you download, unzip the file.
  2. Open the PowerShell as administrator
  3. Run the Powershell script – Install-MongoDB.ps1

What it does? Script installs the Mongo

Disclaimer: This is my first try at PowerShell. I am learning PowerShell scripting so the script might look like a Hard Code script. But for me and my team this is serving the purpose. Please do not use this script for Production deployment as this is not tested on any server environment.

Sitecore All about images : Part 3

  1. Default Background Color  Sitecore All about images
  2. Disable upload media as file Sitecore All about images : Part 2
  3. New security Hash in media

 

After Sitecore version 7.5, Sitecore has come up with the security feature for the images on the website. For earlier version of Sitecore, we can just add some parameters in the URL and get the different size, different background image. It was a really great feature but some of the site complained that people are using their images on different sites and that creates issue on Servers.

What is the new feature?

Sitecore has included a file Website\App_Config\Include\Sitecore.Media.RequestProtection.config

This file contains multiple settings related to Media Request Parameters and Request Protection.

<!– MEDIA – REQUEST PROTECTION – ENABLED
Specifies whether media request protection is enabled or not.
Default value: true
–>
<setting name=”Media.RequestProtection.Enabled” value=”true” />

When this setting is enabled, Sitecore will parse the request and will add a hash code for all the Parameters we have passed. If we pass any additional parameters directly in the URL then it will fail and Sitecore will return original unchanged image.

If you want to generate the Image links due to some reason then Sitecore has provided a Tool out of the box.

You can visit the tool in below folder in your Sitecore site.

http://SitecoreSite/sitecore/admin/mediahash.aspx

Insert the media URL and click on the “Generate hash”

http://SitecoreSite/-/media/Default%20Website/sc_logo.ashx?w=400&h=100&hash=443FF4A7B69D44133****FFAF275FD69957F1975

Open the /App_Config/Include/Sitecore.Media.RequestProtection.config file and change the Media.RequestProtection.SharedSecret setting to a random string

Found this from below link:

https://doc.sitecore.net/sitecore_experience_platform/setting_up__maintaining/security_hardening/configuring/protect_media_request

Sitecore All about images : Part 2

Tags

  1. Default Background Color  Sitecore All about images
  2. Disable upload media as file
  3. New security Hash in media (Sitecore All about images : Part 3)

Disable Upload Media as Files

We have come across a situation when Content Manager uploads the Image(s) and checks the box – Uplaod as file

The media is now uploaded as file and is not available in Database. In this situation, When we publish the Item, some time the file is not getting published on the Production environment. And it creates big issue when there are load balanced servers / multiple servers in Production.

To avoid this, Sitecore provides 2 settings

  1. Media.UploadAsFiles – Default false
  2. Media.DisableFileMedia – Default false

We tried both the options.

UploadAsFiles does not work as expected so we choose to use the DisableFileMedia. When we set that to True, checkbox for Upload as File was hidden/removed from the file upload advanced dialog box.

<!– MEDIA – DISABLE FILE MEDIA
Enables or disables storage of media as files rather than database records.
If true, user interfaces do not present options to store media as files.
All files will be stored in the database, disregarding the value of the Media.UploadAsFiles setting.

Default value: false
–>
<setting name=”Media.DisableFileMedia” value=”true”/>

upload-as-files-checkbox

What we believe, removing the checkbox will solve the issue of “Media being uploaded as file *accidentally*”

 

Uploading a whole folder with Images

  • Zip the Folder.
  • Go to the Upload files (advanced)
  •  Browse and select the Zipped folder
  • Click on the “Unpack ZIP archives”

Need a faster way?? (Fastest way to upload multiple images in Sitecore)

Just Put the folder in the “Upload” folder.

All the images in the folder will be automatically uploaded in Media Library.

 

Sitecore All about images

Hi Friends,

Today I am going to cover a few points at one place for Sitecore Media.

  1. Default Background Color
  2. Disable upload media as file Sitecore All about images : Part 2
  3. New security Hash in media Sitecore All about images : Part 3

Default Background color for Sitecore optimized image

When we use the Sitecore image optimizer, it adds black background when resizing the images. How to fix this?

For Sitecore 8.0/8.1 find a file named Sitecore.config in App_config/Include directory. Open the file in your favourite text editor with admin rights (Required some time).

Find the value with name “DefaultImageBackgroundColor”. Set the value as you desired.

 

Continue reading

Sitecore Session management in SQL

Tags

, , , , , ,

One of the most common thing we used to do in ASP.Net for Web Farm environment for session management was to setup the Session “OutProc” using either state server or SQL Server.

Sitecore also supports the OutProc Session management using SQL. Sitecore has provided a specific database and internally it is managed as well.

This configuration was done using Sitecore 8.0 (XP) or some people say (xDB)

Please find details below to configure the Sitecore Session in SQL.

Steps to do this

  1. Confirm the database named instancenameSitecore_sessions exist.
  2. Add a connection string as below
    <add name=”sharedsession” connectionString=”user id=sa;password=*******;Data Source=SQLDatabase\SQLEXPRESS;Database=instancenameSitecore_Sessions”/>
  3. In web.config make a change as below
    <sessionState mode=”Custom” cookieless=”false” timeout=”20″ customProvider=”mssql” >

<providers>

<!–<add name=”mongo” type=”Sitecore.SessionProvider.MongoDB.MongoSessionStateProvider, Sitecore.SessionProvider.MongoDB” sessionType=”Standard” connectionStringName=”session” pollingInterval=”2″ compression=”true” />–>

<add name=”mssql” type=”Sitecore.SessionProvider.Sql.SqlSessionStateProvider, Sitecore.SessionProvider.Sql” sessionType=”shared” connectionStringName=”sharedsession” pollingInterval=”2″ compression=”true” />

</providers>

</sessionState>

  1. connectionStringName should match the name with the connection string specified.
  2. Run the attached SQL file on your database after replacing your database name in Use Statement and one more place below

Attached is the Docx file which contains the SQL Script provided by Sitecore with installation.

You can find the script in the database folder where you have installed the Sitecore.

Sessions db performance boost

Sitecore and LanguageWire Translation Service

Hi Guys,

I am back after long time.

Till now I have worked on many thing on Sitecore but first time I got a chance to work on the Language Translation Service.

We were asked integrate LanguageWire Service with Sitecore. Our client is a Multinational Organization based in Norway. The site is released in one language and now planning to add 8 more languages to the site.

Some Steps to follow before the setup.

  • Take Backup of your database
  • Get the Update files from LanguageWire. Mostly in below format
    • Codehouse.LanguageWire.TDS.Core_[version number].update.
    • Codehouse.LanguageWire.TDS.System_[version number].update

I loved the Prerequisite information provided in their Installation Guide.

  • Sitecore 6 or above.
  • Above average Sitecore knowledge.
  • Administrator access to your Sitecore.
  • Remote access to your server.
  • Translations module install files.
    • Codehouse.LanguageWire.TDS.Core_[version number].update.
    • Codehouse.LanguageWire.TDS.System_[version number].update.
  • Username, password and Customer ID to Languagewire translation service.

Sitecore User Group UK – 10 April 2013

Sitecore has been arranging a User meet every month in UK and other Cities. I have just heard of such meeting.

During my visit to London in April 2013, I came to know about a meet. I got the link from a Colleague – Tony Kiernan. He was Very excited to attend the event same as me. He attended the similar earlier but it was first visit for me.

Venue was Pizza Express at Holborn.

Details of the Event.

Sitecore User Group

We Reached at the Venue on time.  There were few known face whom I have met in Dreamcore 2011 in London. We sat down on a table got some pizza and a bottle of beer for my Colleague.

We were waiting for the show to begin.

And the show started.

First Session was : Justin Rowe from Fusionworkshop explained “A Content first approach to building Sitecore websites”.

Very informative. Came to know advantage of this approach. How to keep the content? How the content should be?

Second Session was : Sitecore 7 by Tim Ward from Sitecore.

Yes, That’s the one we have been waiting for. The session started with Dynamic Tim ward and his team.

Though there were a lots things to be shown in Sitecore 7, they have kept most of the items for their next session. 🙂

In current session one important part was covered “How to handle millions of items under one node.”. Sitecore has been telling since beginning that You should not have more than 100 items under one node. Recommended this for performance. Thought there is no limit as we had 1000s of item under one node and it was not slow. Some time finding a particular item for editing from 1000s of items was a time consuming task, Searching, Displaying etc were no issue.

But using concept of “Item Bucket” this case is handled.

Third Session:

It was for ECM 2 – Email Campaign Manager V2.

It was really informative. ECM2 is a totally revamped product.

Few more Technical Details extracted from the Sessions:

  • .Net 4.5 compiled DLLs
  • Supports Parallel Processing
  • New Version of Lucene
  • Verbose logging Search
  • IFilter Support – We can use any Custom Search provider
  • Indexing Manager
  • Indexing Developer Tools
  • Item buckets
  • Content Tagging
  • Content Faceting
  • New Search :
  • Datasource : can be a query now
  • LINQ to Lucene
  • LINQ to SOLR

Few Developer Tools

  • Filldb.aspx – Can be used to add millions of data at one go. useful for testing on local / Staging
  • LinqScratchPad
  • Verbose Logging

DMS

  • Search based Data Source

There were many more good moments. Got a chance to meet many Sitecore MVPs. Discussed with Sitecore Developers.

It was Really a great event. I am lucky to be part of the such a great event.

Waiting for the Slides to be available.

Sitecore Badge Sitecore Event 1 Sitecore Event 2

Will the Mobile Internet replace the Desktop?

Mobile domain is growing a lot.

Currently Mobile + Tablet sale has crossed the total desktop sales.

1 Million users

  • AOL took 9 years to reach this mark.
  • FACEBOOK took 9 Months.
  • DRAW SOMETHING (App on Android and iOs) took 9 days.

Find such interesting facts in below infographics from 34sp.com

Mobile_Internet_Infographic_3

Source of the Picture

http://www.34sp.com/blog/chit-chat/will-the-mobile-internet-overtake-the-desktop/