Обновлен механизм подсветки исходного кода в блоге

После некоторых поисков и анализа популярных современных сайтов с подсветкой кода сделал выбор. Остановился на довольно старом, но рабочем решении Google google-code-prettify. Удалив все ссылки (скрипты и стили) на старый движок подсветки кода начал интеграцию нового.

Есть вариант подключить google cdn или использовать размещение на своем сервере. В случае с google cdn и размещением ссылки в конце сайта (как рекомендует сам google) - стили этого движка загрузятся последними и их нельзя будет переопределить без ключевого слова !important в css. Что не есть хорошо. Поэтому выбор пал на размещение на своем сайте. Первый способ полключения довольно прост:

<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>

В моем случае необходимо подключить javascript файл. Стили css я подключать не стал.

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

Google в своем примере пишет вызов функции подсветки следующим образом

<body onload="prettyPrint()">

Я же остановился на добавления ссылки на скрипт и вызова функции в конце документа. Для того, чтобы включить подсветку css необходимо подключить дополнительный файл lang-css.js.

<script src="~/content/prettify/prettify.js"></script>
<script src="~/content/prettify/lang-css.js"></script>
<script type="text/javascript">
  prettyPrint();
</script>

Стили prettify как в Visual Studio

Дополнительно хотелось организовать подсветку кода (как минимум C#) как в стандартной теме Visual Studio. Для этого были добавлены следующие стили

pre { padding: 5px; margin: 18px 0 30px; border: 1px dashed #ccc; font-family: "Consolas",monospace; overflow: auto; display: block; white-space: pre; background-color: #f3f3f3; }
    pre .com { color: #008000;}
    pre .str, .tag { color: #A31515; }
    pre .kwd, .atv { color: #0000FF;}
    pre .typ { color: #2B91AF;}
    pre .lit, .atn { color: #FF0000;}
    pre .pun, .pln { color: #000000;}
    pre .dec { color: #800080;}
    pre.lang-css .pun{ color: #686868;}

Обновление контента

Старый движок подсветки кода требовал контента внутри тега <code>, который в свою очередь должен был быть внутри тега <pre>. Получалось 2 вложенных тега. Новый требует 1 тег <pre>, но с дополнительным классом. Был написан метод, который преобразует весь контент на сайте по новым правилам. Используется библиотека HtmlAgilityPack.

class Program
{
    static void Main(string[] args)
    {
        OxoblogEntities db = new OxoblogEntities();
        var blogPosts = db.BlogPosts.ToList();

        foreach (BlogPost blogPost in blogPosts)
        {
            blogPost.Description = Update(blogPost.Description);
            blogPost.Details = Update(blogPost.Details);
        }

        db.SaveChanges();
    }

    private static string Update(string text)
    {
        if (string.IsNullOrEmpty(text))
            return null;

        // Create Html document
        HtmlDocument html = new HtmlDocument();
        html.OptionFixNestedTags = true;
        html.OptionAutoCloseOnEnd = true;
        html.OptionDefaultStreamEncoding = Encoding.UTF8;
        html.LoadHtml(text);

        if (html == null)
            return string.Empty;

        HtmlNode allNodes = html.DocumentNode;

        HightlightSyntaxInNode(allNodes);

        return allNodes.InnerHtml;
    }


    private static void HightlightSyntaxInNode(HtmlNode node)
    {
        if (node.NodeType == HtmlNodeType.Element)
        {
            if (node.Name == "pre" && node.ChildNodes.Count > 0 && node.FirstChild.Name == "code")
            {
                node.InnerHtml = node.FirstChild.InnerHtml;
                node.Attributes.Add("class", "prettyprint");
            }

        }

        // nested nodes
        if (node.HasChildNodes)
            HightlightSyntaxInChildren(node);
    }

    /// <summary>
    /// Apply CleanNodes to each of the child nodes
    /// </summary>
    private static void HightlightSyntaxInChildren(HtmlNode parent)
    {
        for (int i = parent.ChildNodes.Count - 1; i >= 0; i--)
            HightlightSyntaxInNode(parent.ChildNodes[i]);
    }
}

В тег <pre> необходимо добавить класс prettyprint. Пример подсветки можно увидеть и на этой странице.

Комментарии

comments powered by Disqus