November 23, 2010
@ 08:54 PM

A few years ago I needed the ability to “autolink” text – basically, I had a list of keywords and anytime those keywords were displayed on a page I needed to have them turned into a link. The code is relatively straightforward, but I thought it might be of some use to other people.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace RCSSolutions
{
    public class Term
    {
        public string LinkTerm { get; set; }       
        public string Url { get; set; }
        public string Target { get; set; }
    }

    /// <summary>
    /// Adds links to a passed in string based on records in
    /// the SourceAutolink table.
    /// </summary>
    public class AutoLinker
    {            
        private string m_linkStyle = "";

        /// <summary>List of words which auto link</summary>
        public List<Term> LinkWords { get; set; }

        /// <summary>The CSS class to assign to the link tag</summary>
        public string LinkStyle
        {
            get { return this.m_linkStyle; }
            set { this.m_linkStyle = value; }
        }

        public AutoLinker (List<Term> linkWords)
        {
            LinkWords = linkWords;
        }

        /// <summary>
        /// Adds any links to the passed in content.
        /// </summary>
        /// <param name="content">Content to evaluate</param>
        /// <returns>Marked up results</returns>
        /// <developer>Paul Mrozowski</developer>
        /// <created>07/07/2008</created>
        public string AutoLink(string content)
        {
            if (this.LinkWords == null)
                return content;
           
            StringBuilder result = new StringBuilder();

            // Replaces HTML (and html-like) tags with spaces (we want to keep
            // the same relative positions of everything else in the text since
            // we're going to use them to do the final replacements.)
            string newSentence = Regex.Replace(content,
                                     @"<(.|\n)*?>",
                                     match => " ".PadRight(match.Length));

            string tmpContent = content;

            // Loop through each link term, search for matches. Save each of them into a new collection
            // We're going to use the results to sort the matches in decending order by location. That
            // way we can perform the replacements w/o moving the starting location of the other replacements.
            foreach (var linkRow in LinkWords)
            {
                var allMatches = new List<Match>();
                MatchCollection matches = Regex.Matches(newSentence, linkRow.LinkTerm, RegexOptions.IgnoreCase);
                foreach (Match match in matches)
                    allMatches.Add(match);

                var orderedMatches = from m in allMatches
                                     orderby m.Index descending
                                     select m;

                // General idea is to grab all of the text following the match, get the newly
                // link word w/html markup and insert it before the this text. Then truncate
                // the original content to remove everything from the starting position of the
                // match to the end of file - this is basically done so I don't have to track
                // the current position within the file. After we're done with the loop we
                // insert anything that's left to the beginning of the new string.
                foreach (Match item in orderedMatches)
                {
                    string endOfMatchedStringToEOF = tmpContent.Substring(item.Index + item.Length);
                    result.Insert(0, GetAutolinkText(linkRow, item.Value) + endOfMatchedStringToEOF);
                    tmpContent = tmpContent.Substring(0, item.Index);
                }
            }

            result.Insert(0, tmpContent);

            return result.ToString();
        }

        /// <summary>
        /// Get the replacement text.
        /// </summary>
        /// <param name="token">Word token</param>
        /// <param name="content">Original content</param>
        /// <returns>Empty string if no replacement</returns>
        /// <developer>Paul Mrozowski</developer>
        /// <created>07/08/2008</created>
        private string GetAutolinkText(Term linkTo, string match)
        {
            string newWord = match;

            if (this.m_linkStyle.Length == 0)
                newWord = string.Format("<a href='{0}' ", linkTo.Url);
            else
                newWord = string.Format("<a class='{0}' href='{1}' ",
                                        this.LinkStyle,
                                        linkTo.Url);

            if ((linkTo.Target ?? "").Length > 0)
                newWord += string.Format("target='{0}' ", linkTo.Target);

            // We pass in the original match term to maintain its case (the initial match was case-insensitive).
            newWord += string.Format(">{0}</a>", match);

            return newWord;
        }
    }
}

Usage is simple – create a list of terms that you want linked (along with the URL, style (if any), and target) and pass it to the AutoLinker class, then call AutoLink with your source text. It will return the text with the links embedded in it. Here’s a sample from a console application:

        static void Main(string[] args)
        {
            var terms = new List<Term>();
            terms.Add(new Term() { LinkTerm = "Hello", Target = "_blank", Url = "http://www.rcs-solutions.com" });

            string sentence = "Why, hello! This is a sentence where I'm going to link to the word \"hello\".";
            Console.Write(sentence);
            var linker = new AutoLinker(terms);
           
            Console.Write(linker.AutoLink(sentence));
            Console.ReadKey();
        }

 
Categories: .NET

November 19, 2010
@ 09:06 PM

While I was originally planning my jQuery for VFP developer session for South West Fox, I had planning on showing all of the demos hosted inside of a browser hosted in a VFP form (which I did). I also planned on having a link available on each page which would slide out color-coded samples of the code actually running in the page. As part of that, I created a syntax highlighter brush for VFP to work with Alex Gorbatchev’s SynaxHighlighter (since none seemed to be available) – it’s a Javascript based syntax highlighter that lets you embed code samples in things like blog pages and it will color-code the syntax. I ended up deciding that it didn’t really work too well in the context of a session, so I scrapped that portion of my demos.

You can download it from here

 Alex’s site includes more information about use – just make sure you reference the new brush from within your webpage:

<script type="text/javascript" src="/scripts/shBrushVFP.js"></script>

 

 

Links

http://alexgorbatchev.com/SyntaxHighlighter/
http://www.rcs-solutions.com/Download.ashx?File=shBrushVFP.js


 
Categories: Javascript

November 16, 2010
@ 05:54 PM

I’ve updated and tested my plug-ins for CodeRush/Refactor! to make sure they work in Visual Studio 2010 and with the new version of the product. All of them include all the source code and a compiled DLL. Just copy the plug-ins into your \Users\UserName\Documents\DevExpress\IDE Tools\Community\PlugIns folder.

Translate

Have some sample code in C# that you’d rather see in VB? Or vice-versa? Translate converts the code under the current cursor position to the equivalent version.

image

You can find more information about this plug-in here:

http://www.rcs-solutions.com/blog/2008/08/17/TranslateCToVBNETOrViceversaUsingCodeRush.aspx

And you can download it from here:

http://www.rcs-solutions.com/Download.ashx?File=CR_Translator2010.zip

 

Collapse XML

This plug-in collapses multi-line XML comments into one line, so this:

 

image

Becomes this by hitting the Refactor key:

image

You can find more information about this plug-in here:

http://www.rcs-solutions.com/blog/2008/08/08/CollapsingXMLCommentTags.aspx

And download it from here:

http://www.rcs-solutions.com/Download.ashx?File=DX_CollapseComments.zip

 

Developer Initials

I made a few changes based on feedback to the Developer Initials plug-in. You can now configure the format of the comment added.

image

You can find more information about this plug-in here:

http://www.rcs-solutions.com/blog/2008/08/06/CodeRushPluginDeveloperInitials.aspx

And download it from here:

http://www.rcs-solutions.com/Download.ashx?File=CR_Initials2010.zip


 
Categories: CodeRush