vscode-markdown-pdf icon indicating copy to clipboard operation
vscode-markdown-pdf copied to clipboard

[idea] Put data for pdf header/footer directly into the <script> section of markdown to get rid of changing header/footer settings each time

Open pediRAM opened this issue 11 months ago • 0 comments

First of all I want to thank all contributers for this amazing plug-in.

My Problem

I work on many different manuals, books and documentations etc. at the same time and I use the same header-template for nearly all markdown files but with different data like title or version for current document. So the reader can see the title or (customized) pdf-creation-date like "2025-01" on every page of PDF, like this:

Image

I had to open the Plug-in settings and change the "Header Template" everytime I opened another markdown file (with completely other topic) and often I forgot to replace the title string in the header template (plug-in settings)... This cost me a lot of attention and time.

My Solution

Why not putting meta-data about the markdown file used for header of PDF pages directly into the markdown file itself? This way each markdown file contains its own data for the header and I don't have to change the header for PDF in plug-in-settings no more!

The value of Markdown PDF Plug-in-Setting Header Template:

<div style="font-size: 9px; margin-left: 1cm; display: display;"> <span>%pdfPageHeaderDate% %pdfPageHeaderTitle%</span></div> <div style="font-size: 9px; margin-left: auto; margin-right: 1cm;  display: display;">%pdfPageHeaderCopyright%</div>

Step 1: Add Data to Script-Section of Markdown file

I put the custom values for current markdown file like title, date, author, copyright etc. directly into the markdown as variable values in a <script> section like this:

<script>
var pdfPageHeaderTitle = "ABC todo Liste";
var pdfPageHeaderVersion = "1.2.3";
var pdfPageHeaderDate = "%yyyy%-%mm%-%dd%";
var pdfPageHeaderAuthor = "John Doe";
var pdfPageHeaderCopyright = "Copyright ©%yyyy% by %pdfPageHeaderAuthor%";
</script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({ tex2jax: {inlineMath: [['$', '$']]}, messageStyle: "none" });
</script>

<!-- Markdown content after this line -->
# To do
> Just some text...

Step 2: Add Variables and Function to extract them into extension.js

'use strict';
var vscode = require('vscode');
var path = require('path');
var fs = require('fs');
var url = require('url');
var os = require('os');
var INSTALL_CHECK = false;
/****************************************** INSERTED CODE FOR PDF-PAGES-HEADER *****************************/
var customPageHeaderVariables = {
  pdfPageHeaderTitle : "?pdfPageHeaderTitle?",
  pdfPageHeaderVersion : "?pdfPageHeaderVersion?",
  pdfPageHeaderCopyright : "?pdfPageHeaderCopyright?",
  pdfPageHeaderDate : "?pdfPageHeaderDate?"
};

function extractVariablesFromMarkdown(markdownContent) {
  const variables = {};
  const scriptRegex = /<script>([\s\S]*?)<\/script>/gi; 
  let match;

  while ((match = scriptRegex.exec(markdownContent)) !== null) {
      const scriptContent = match[1];
      scriptContent.split(';').forEach(line => {
          const [key, value] = line.split('=').map(part => part.trim());
          if (key && value) {
              const cleanKey = key.replace(/var\s+/, '');
              variables[cleanKey] = value.replace(/^["']|["']$/g, ''); 
          }
      });
  }
  return variables;
}
/************************************************************************************************/

Step 3: Modify Function "async function markdownPdf(option_type)"

Search for the above function signature (in extensions.js) and add following line:

          var content = convertMarkdownToHtml(mdfilename, type, text);
         /***************************** ADD THIS LINE *****************************/
          customPageHeaderVariables = extractVariablesFromMarkdown(content);
         /****************************************************************************/
          var html = makeHtml(content, uri);
          await exportPdf(html, filename, type, uri);
         ...

Step 3: Modify Method "function transformTemplate(templateText)" and add new Function "function generateHeaderTemplate(templateText)"

/**
 * Transform the text of the header or footer template, replacing the following supported placeholders:
 *
 * - `%%ISO-DATETIME%%` – For an ISO-based date and time format: `YYYY-MM-DD hh:mm:ss`
 * - `%%ISO-DATE%%` – For an ISO-based date format: `YYYY-MM-DD`
 * - `%%ISO-TIME%%` – For an ISO-based time format: `hh:mm:ss`
 */
function transformTemplate(templateText) {
  // First replace pdf-page-header-parameters by values found from <script> section in markdown,
  //  so we can use date/time parameter keys in pdf-page-header-parameter values (from <script> section).
  templateText = generateHeaderTemplate(templateText);
  let year = new Date().getFullYear().toString();
  let month = new Date().getMonth() + 1;
  let mm = month < 10 ? "0" + month.toString() : month.toString();
  let day = new Date().getDate();
  let dd = day < 10 ? "0" + day : day.toString();

    templateText = templateText
    .replace(/%ISO-DATETIME%/g, new Date().toISOString().substr(0, 19).replace('T', ' ') || '')
    .replace(/%ISO-DATE%/g, new Date().toISOString().substr(0, 10) || '')
    .replace(/%ISO-TIME%/g, new Date().toISOString().substr(11, 8) || '')
    .replace(/%yyyy%/g, year || '')
    .replace(/%mm%/g, mm || '')
    .replace(/%month%/g, month || '')
    .replace(/%day%/g, day || '')
    .replace(/%dd%/g, dd || '')
    .replace(/%yyyy-mm%/g, new Date().getFullYear().toString() + "-" + mm || '');
  return templateText;
}

/********************* NEW FUNCTION *****************/
function generateHeaderTemplate(templateText) {
  let updatedTemplate = templateText;
  updatedTemplate = updatedTemplate
      .replace(/%pdfPageHeaderTitle%/g, customPageHeaderVariables.pdfPageHeaderTitle || '')
      .replace(/%pdfPageHeaderVersion%/g, customPageHeaderVariables.pdfPageHeaderVersion || '')
      .replace(/%pdfPageHeaderDate%/g, customPageHeaderVariables.pdfPageHeaderDate || '')
      .replace(/%pdfPageHeaderCopyright%/g, customPageHeaderVariables.pdfPageHeaderCopyright || '')
      .replace(/%pdfPageHeaderAuthor%/g, customPageHeaderVariables.pdfPageHeaderAuthor || '');
  return updatedTemplate;
}
/***************************************************/
...

Step 4

Restart VS Code!

Last Step

Open your markdown file (containing the

Image

From now on, you don't need to touch the Header Template in the Markdown PDF Plug-in Settings anymore :-)

As you may noticed, I also changed the code to for replacing %%%ISO-DATE%%% etc. in the way of calling replace method (by regular expression), reduced the usage of % character from triple to only one, and also added following keys for more flexibility:

  • %yyyy% for current year, like: 2025
  • %month% for current month, like: 1 (for january)
  • %mm% for current month, like: 01 (for january)
  • %day% for current day, like: 1, ..., 31
  • %dd% for current day, like: 01, ..., 31
  • %yyyy-mm% for current year and mnoth, like: 2025-01

You can also use the date-keys (like %ISO-DATE% or %yyyy% etc.) in the pdf-header-variable-values in the <script> section.

You also can put the author key %pdfPageHeaderAuthor% into the value of pdfPageHeaderCopyright.

I hope this can help some of you with the same problem.

pediRAM avatar Jan 25 '25 01:01 pediRAM