diff --git a/server/formatter.js b/server/formatter.js index 805901c1..6e3c4d22 100644 --- a/server/formatter.js +++ b/server/formatter.js @@ -108,19 +108,25 @@ function formatCode(html) { // strip interior

tags added by google content = content.replace(/(?:<\/p>

|)/g, '\n').replace(/<\/?p>/g, '').trim() // try to find language hint within text block - const [, lang] = content.match(/^([^\n]+)\n(.+)/) || [] - if (lang) content = content.replace(`${lang}\n`, '') + const [, lang] = content.match(/^(.+?)\n/) || [] - const formattedContent = formatCodeContent(content) if (lang && hljs.getLanguage(lang)) { - const textOnlyContent = cheerio.load(formattedContent).text() + // if the language hint exists and contains a valid language, remove it from the code block + content = content.replace(`${lang}\n`, '') + + const textOnlyContent = cheerio.load(content).text() const highlighted = hljs.highlight(lang, textOnlyContent, true) - return `

${highlighted.value}
` + return `
${formatCodeContent(highlighted.value)}
` } - return `
${formattedContent}
` + return `
${formatCodeContent(content)}
` + }) + + // Replace double backticks with , for supporting backticks in inline code blocks + html = html.replace(/``(.+?`?)``/g, (match, content) => { + return `${formatCodeContent(content)}` }) - // Replace single backticks with , as long as they are not inside triple backticks + // Replace single backticks with html = html.replace(/`(.+?)`/g, (match, content) => { return `${formatCodeContent(content)}` }) diff --git a/test/fixtures/supportedFormats.html b/test/fixtures/supportedFormats.html index d20774b8..a3c22f92 100644 --- a/test/fixtures/supportedFormats.html +++ b/test/fixtures/supportedFormats.html @@ -1 +1 @@ -

By Ben Koski and the Library Team

This is a documentation site powered by the NYT Library Google Team Drive.

Basic Formatting

Basic text formatting like bold, italic, and underline are supported. These can be combined. Links are supported, both to external pages and other docs in the folder. Text color and highlighting are not supported. (You won’t see them being colored!)

You can use bulleted lists:

  • Item 1
  • Item 2
  • Item 3

Numbered lists:

  1. Item 1
  2. Item 2
  3. Item 3

And nested/combined list styles:

  1. Item 1
  • Item 1.1
  • Item 1.2
  1. Item 2
  • Item 2.1
  • Item 2.2
  1. Item 2.2.1

  • Extended bullet styles are supported
  • Here is a sub-bullet

Tables

Tables are supported and can contain text formats. Coloring and highlighting, however, is removed. See example below:

Growth in Unique Visitors

May 2010

April 2017

June 2017

nytimes.com

32 million

89 million

121 million

washingtonpost.com

17 million

77 million

88 million

theonion.com

1.3 million

6 million

11 million

Code Blocks

```myfakelanguage

1 + 1 == 5

```

```javascript

function megaHoverOver(){

 $(this).find(".sub").stop().fadeTo('fast', 1).show();

         

 //Calculate width of all ul's

 (function($) {

         jQuery.fn.calcSubWidth = function() {

                 rowWidth = 0;

                 //Calculate row

                 $(this).find("ul").each(function() {                                        

                         rowWidth += $(this).width();

                 });        

         };

 })(jQuery);

 if ( $(this).find(".row").length > 0 ) { //If row exists...

         var biggestRow = 0;        

         //Calculate each row

         $(this).find(".row").each(function() {                                                          

                 $(this).calcSubWidth();

                 //Find biggest row

                 if(rowWidth > biggestRow) {

                         biggestRow = rowWidth;

                 }

         });

         //Set width

         $(this).find(".sub").css({'width' :biggestRow});

         $(this).find(".row:last").css({'margin':'0'});

         

 } else { //If row does not exist...

         $(this).calcSubWidth();

         //Set Width

         $(this).find(".sub").css({'width' : rowWidth});

 }

}

// Special characters are of course allowed in code blocks

var specialChars = “&nbsp;”;

// Smart quoting inserted by Google Docs is scrubbed

// If you need a smart quote inside a code block literal,

// you’ll need to use HTML entity instead (“&ldquo;”)

var singleQuotedStr = ‘str’; var doubleQuotedStr = “str”;

```

Here is a `code` word. Perfect for explaining technical reference, such as file or folder name `extension.js`, or maybe a path to something `/docs_old/src/server/getAndParseGoogleDoc`.

Images

As are inline images:

Images will shrink to fit the column width, but won’t be scaled up if they are smaller:

Gifs are also supported.

gif_test.gif

The full set of headers are supported. Please note that any text styled under `Heading 1` and `Heading 2` will be automatically inserted into the Table of Content sidebar. However, this does not apply to `Heading 3`, `Heading 4`, and `Heading 5`. You might want to be mindful on structuring your page so that it looks great as a guide.

Heading 1

Some text under heading 1.

Heading 2

Some text under heading 2.

Heading 3

Some text under heading 3.

Heading 4

Some text under heading 4.

Heading 5

Some text under heading 5.

Comments will be stripped from the reader-facing page.

Advanced Features

If `ALLOW_INLINE_CODE` is enabled, you can add fenced code into your google doc to be rendered directly to the DOM.

```

<%- codeblocks will not be rendered%>

```

<%-

<style>

  .purplePapyrus {

    font-family: papyrus;

    color: purple;

  }

</style>

<div class="purplePapyrus">But this custom style will!</div>

%>

+

By Ben Koski and the Library Team

This is a documentation site powered by the NYT Library Google Team Drive.

Basic Formatting

Basic text formatting like bold, italic, and underline are supported. These can be combined. Links are supported, both to external pages and other docs in the folder. Text color and highlighting are not supported. (You won’t see them being colored!)

You can use bulleted lists:

  • Item 1
  • Item 2
  • Item 3

Numbered lists:

  1. Item 1
  2. Item 2
  3. Item 3

And nested/combined list styles:

  1. Item 1
  • Item 1.1
  • Item 1.2
  1. Item 2
  • Item 2.1
  • Item 2.2
  1. Item 2.2.1

  • Extended bullet styles are supported
  • Here is a sub-bullet

Tables

Tables are supported and can contain text formats. Coloring and highlighting, however, is removed. See example below:

Growth in Unique Visitors

May 2010

April 2017

June 2017

nytimes.com

32 million

89 million

121 million

washingtonpost.com

17 million

77 million

88 million

theonion.com

1.3 million

6 million

11 million

Code Blocks

```myfakelanguage

1 + 1 == 5

```

```javascript

function megaHoverOver(){

 $(this).find(".sub").stop().fadeTo('fast', 1).show();

         

 //Calculate width of all ul's

 (function($) {

         jQuery.fn.calcSubWidth = function() {

                 rowWidth = 0;

                 //Calculate row

                 $(this).find("ul").each(function() {                                        

                         rowWidth += $(this).width();

                 });        

         };

 })(jQuery);

 if ( $(this).find(".row").length > 0 ) { //If row exists...

         var biggestRow = 0;        

         //Calculate each row

         $(this).find(".row").each(function() {                                                          

                 $(this).calcSubWidth();

                 //Find biggest row

                 if(rowWidth > biggestRow) {

                         biggestRow = rowWidth;

                 }

         });

         //Set width

         console.log(`Setting width: ${biggestRow}`);

         $(this).find(".sub").css({'width' :biggestRow});

         $(this).find(".row:last").css({'margin':'0'});

         

 } else { //If row does not exist...

         $(this).calcSubWidth();

         //Set Width

         $(this).find(".sub").css({'width' : rowWidth});

 }

}

// Special characters are of course allowed in code blocks

var specialChars = “&nbsp;”;

// Smart quoting inserted by Google Docs is scrubbed

// If you need a smart quote inside a code block literal,

// you’ll need to use HTML entity instead (“&ldquo;”)

var singleQuotedStr = ‘str’; var doubleQuotedStr = “str”;

```

Here is a `code` word and ``a `backtick` in an inline code snippet``. Perfect for explaining technical reference, such as file or folder name `extension.js`, or maybe a path to something `/docs_old/src/server/getAndParseGoogleDoc`.

Images

As are inline images:

Images will shrink to fit the column width, but won’t be scaled up if they are smaller:

Gifs are also supported.

gif_test.gif

The full set of headers are supported. Please note that any text styled under `Heading 1` and `Heading 2` will be automatically inserted into the Table of Content sidebar. However, this does not apply to `Heading 3`, `Heading 4`, and `Heading 5`. You might want to be mindful on structuring your page so that it looks great as a guide.

Heading 1

Some text under heading 1.

Heading 2

Some text under heading 2.

Heading 3

Some text under heading 3.

Heading 4

Some text under heading 4.

Heading 5

Some text under heading 5.

Comments will be stripped from the reader-facing page.

Advanced Features

If `ALLOW_INLINE_CODE` is enabled, you can add fenced code into your google doc to be rendered directly to the DOM.

```

<%- codeblocks will not be rendered%>

```

<%-

<style>

  .purplePapyrus {

    font-family: papyrus;

    color: purple;

  }

</style>

<div class="purplePapyrus">But this custom style will!</div>

%>

diff --git a/test/unit/htmlProcessing.test.js b/test/unit/htmlProcessing.test.js index f7ac54ac..529c375e 100644 --- a/test/unit/htmlProcessing.test.js +++ b/test/unit/htmlProcessing.test.js @@ -113,6 +113,16 @@ describe('HTML processing', () => { const codeBlock = testGlobal.output('pre') assert.match(codeBlock.html(), /1 \+ 1 == 5/) }) + + it('retains code block backticks', () => { + const codeBlock = testGlobal.output('pre > code[data-lang="javascript"]') + assert.match(codeBlock.html(), /`/) + }) + + it('retains inline code backticks', () => { + const codeBlock = testGlobal.output("code:contains('backtick')") + assert.match(codeBlock.html(), /`backtick`/) + }) }) describe('inline code handling', () => {