Skip to content

Commit

Permalink
Merge pull request #361 from Chng-Zhi-Xuan/355-insert-head-files
Browse files Browse the repository at this point in the history
Support content insertion into <head> of a Page
  • Loading branch information
yamgent authored Jul 25, 2018
2 parents d75fd69 + 7c7600f commit 97711ef
Show file tree
Hide file tree
Showing 13 changed files with 94 additions and 3 deletions.
44 changes: 44 additions & 0 deletions docs/userGuide/contentAuthoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,50 @@ Front matter can also be included from a separate file, just like how content ca

This will result in `index.md` having the title `Binary Search Tree` and the specified keywords in order for it to be looked up through the search bar.

### Inserting content into a page's head element

While authoring your website, you may want to have your own CSS or Javascript files to be included in a page.

- Start by creating a head file with Markdown extension (`.md`) in the `_markbind/head` folder.
- More than one head file can be created for different pages.

- Author your `<style>` elements for CSS files and `<link>` elements for Javascript files using HTML as shown below.
- Ensure that your URLs start from the root directory, by using <code>{<span></span>{baseUrl}}/</code> when you are referencing your files.

```css
/* In yourCSSFolder/subfolder/myCustomStyle.css */
p {
background: lightskyblue;
}
```

```js
// In yourScriptFolder/myCustomScript.js
alert("Welcome to my website!");
```

```html
<!-- In _markbind/head/compiledRef.md -->
<link rel="stylesheet" href="{{baseUrl}}/yourCSSFolder/subfolder/myCustomStyle.css">
<script src="{{baseUrl}}/yourScriptFolder/myCustomScript.js"></script>
```

- Specify the head file in pages that uses it, by specifying the [front matter](#front-matter) `head` attribute.

```html
<!-- In the page you want the head file to be in -->
<frontmatter>
head: compiledRef.md
</frontmatter>
```

The head file contents will be placed near the end of the page's head tag.
Your head file will override existing Bootstrap and MarkBind CSS styles if there is an overlap of selectors.

Note:
- You may specify raw `.js` or `.css` files as your head file if you wish to do so.
- Only one head file can be specified in a page, and you **must** include its file extension.

### Site Navigation

A site navigation bar is a fixed menu on the left side of your page contents, that allows the viewer to navigate your site pages.
Expand Down
23 changes: 22 additions & 1 deletion lib/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const MarkBind = require('./markbind/lib/parser');
const md = require('./markbind/lib/markdown-it');

const FOOTERS_FOLDER_PATH = '_markbind/footers';
const HEAD_FOLDER_PATH = '_markbind/head';
const NAVIGATION_FOLDER_PATH = '_markbind/navigation';

const FLEX_BODY_DIV_ID = 'flex-body';
Expand Down Expand Up @@ -59,9 +60,10 @@ function Page(pageConfig) {
this.resultPath = pageConfig.resultPath;

this.frontMatter = {};
this.headFileReferences = '';
this.headings = {};
this.includedFiles = {};
this.headingIndexingLevel = pageConfig.headingIndexingLevel;
this.includedFiles = {};
}

/**
Expand Down Expand Up @@ -160,6 +162,7 @@ Page.prototype.prepareTemplateData = function () {
baseUrl: this.baseUrl,
content: this.content,
faviconUrl: this.faviconUrl,
headFileReferences: this.headFileReferences,
title: prefixedTitle,
};
};
Expand Down Expand Up @@ -325,6 +328,22 @@ Page.prototype.insertSiteNav = function (pageData) {
+ '</div>';
};

Page.prototype.collectHeadFiles = function () {
const { head } = this.frontMatter;
if (!head) {
return;
}
const headFilePath = path.join(this.rootPath, HEAD_FOLDER_PATH, head);
const headFileContent = fs.readFileSync(headFilePath, 'utf8');
// Set head file as an includedFile
this.includedFiles[headFilePath] = true;
// Map variables
const newBaseUrl = calculateNewBaseUrl(this.sourcePath, this.rootPath, this.baseUrlMap) || '';
const userDefinedVariables = this.userDefinedVariablesMap[path.join(this.rootPath, newBaseUrl)];
const headFileMappedData = nunjucks.renderString(headFileContent, userDefinedVariables);
this.headFileReferences = headFileMappedData.trim();
};

Page.prototype.generate = function (builtFiles) {
this.includedFiles = {};
this.includedFiles[this.sourcePath] = true;
Expand Down Expand Up @@ -356,6 +375,8 @@ Page.prototype.generate = function (builtFiles) {
const baseUrl = newBaseUrl ? `${this.baseUrl}/${newBaseUrl}` : this.baseUrl;
const hostBaseUrl = this.baseUrl;

this.collectHeadFiles();
this.headFileReferences = nunjucks.renderString(this.headFileReferences, { baseUrl, hostBaseUrl });
this.content = nunjucks.renderString(this.content, { baseUrl, hostBaseUrl });
return fs.outputFileAsync(this.resultPath, this.template(this.prepareTemplateData()));
})
Expand Down
9 changes: 9 additions & 0 deletions lib/Site.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const FAVICON_DEFAULT_PATH = 'favicon.ico';
const FONT_AWESOME_PATH = 'asset/font-awesome.csv';
const FOOTER_PATH = '_markbind/footers/footer.md';
const GLYPHICONS_PATH = 'asset/glyphicons.csv';
const HEAD_FOLDER_PATH = '_markbind/head';
const INDEX_MARKDOWN_FILE = 'index.md';
const PAGE_TEMPLATE_NAME = 'page.ejs';
const SITE_CONFIG_NAME = 'site.json';
Expand Down Expand Up @@ -170,6 +171,7 @@ Site.initSite = function (rootPath) {
const boilerplatePath = path.join(rootPath, BOILERPLATE_FOLDER_NAME);
const configPath = path.join(rootPath, SITE_CONFIG_NAME);
const footerPath = path.join(rootPath, FOOTER_PATH);
const headFolderPath = path.join(rootPath, HEAD_FOLDER_PATH);
const indexPath = path.join(rootPath, INDEX_MARKDOWN_FILE);
const siteNavPath = path.join(rootPath, SITE_NAV_PATH);
const userDefinedVariablesPath = path.join(rootPath, USER_VARIABLES_PATH);
Expand Down Expand Up @@ -210,6 +212,13 @@ Site.initSite = function (rootPath) {
}
return fs.outputFileAsync(footerPath, FOOTER_DEFAULT);
})
.then(() => fs.accessAsync(headFolderPath))
.catch(() => {
if (fs.existsSync(headFolderPath)) {
return Promise.resolve();
}
return fs.mkdirSync(headFolderPath);
})
.then(() => fs.accessAsync(siteNavPath))
.catch(() => {
if (fs.existsSync(siteNavPath)) {
Expand Down
1 change: 1 addition & 0 deletions lib/template/page.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link rel="stylesheet" href="<%- asset.highlight %>">
<link rel="stylesheet" href="<%- asset.markbind %>">
<link rel="stylesheet" href="<%- asset.siteNavCss %>">
<%- headFileReferences %>
<% if (faviconUrl) { %><link rel="icon" href="<%- faviconUrl %>"><% } %>
</head>
<body>
Expand Down
1 change: 1 addition & 0 deletions test/test_site/_markbind/head/myCustomHead.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script src="{{baseUrl}}\headFiles\customScript.js"></script>
1 change: 1 addition & 0 deletions test/test_site/expected/bugs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link rel="stylesheet" href="..\markbind\css\github.min.css">
<link rel="stylesheet" href="..\markbind\css\markbind.css">
<link rel="stylesheet" href="..\markbind\css\site-nav.css">

<link rel="icon" href="/test_site/favicon.png">
</head>
<body>
Expand Down
2 changes: 2 additions & 0 deletions test/test_site/expected/headFiles/customScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-console
console.info('custom script inserted into head successfully!');
1 change: 1 addition & 0 deletions test/test_site/expected/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link rel="stylesheet" href="markbind\css\github.min.css">
<link rel="stylesheet" href="markbind\css\markbind.css">
<link rel="stylesheet" href="markbind\css\site-nav.css">
<script src="/test_site\headFiles\customScript.js"></script>
<link rel="icon" href="/test_site/favicon.png">
</head>
<body>
Expand Down
1 change: 1 addition & 0 deletions test/test_site/expected/siteData.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"title": "Hello World",
"footer": "footer.md",
"siteNav": "site-nav.md",
"head": "myCustomHead.md",
"src": "index.md"
},
{
Expand Down
1 change: 1 addition & 0 deletions test/test_site/expected/sub_site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<link rel="stylesheet" href="..\markbind\css\github.min.css">
<link rel="stylesheet" href="..\markbind\css\markbind.css">
<link rel="stylesheet" href="..\markbind\css\site-nav.css">

<link rel="icon" href="/test_site/favicon.png">
</head>
<body>
Expand Down
2 changes: 2 additions & 0 deletions test/test_site/headFiles/customScript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line no-console
console.info('custom script inserted into head successfully!');
1 change: 1 addition & 0 deletions test/test_site/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
title: Hello World
footer: footer.md
siteNav: site-nav.md
head: myCustomHead.md
</frontmatter>

<include src="components/header.md" />
Expand Down
10 changes: 8 additions & 2 deletions test/unit/Site.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ test('Site Init in existing directory generates correct assets', async () => {
await Site.initSite('');
const paths = Object.keys(fs.vol.toJSON());
const originalNumFiles = Object.keys(json).length;
const expectedNumBuilt = 6;
const expectedNumBuilt = 7;
expect(paths.length).toEqual(originalNumFiles + expectedNumBuilt);

// _boilerplates
Expand All @@ -84,6 +84,9 @@ test('Site Init in existing directory generates correct assets', async () => {
// footer.md
expect(fs.readFileSync(path.resolve('_markbind/footers/footer.md'), 'utf8')).toEqual(FOOTER_MD_DEFAULT);

// head folder
expect(fs.existsSync(path.resolve('_markbind/head'), 'utf8')).toEqual(true);

// site-nav.md
expect(fs.readFileSync(path.resolve('_markbind/navigation/site-nav.md'), 'utf8'))
.toEqual(SITE_NAV_MD_DEFAULT);
Expand All @@ -107,7 +110,7 @@ test('Site Init in directory which does not exist generates correct assets', asy
await Site.initSite('newDir');
const paths = Object.keys(fs.vol.toJSON());
const originalNumFiles = Object.keys(json).length;
const expectedNumBuilt = 6;
const expectedNumBuilt = 7;

expect(paths.length).toEqual(originalNumFiles + expectedNumBuilt);

Expand All @@ -117,6 +120,9 @@ test('Site Init in directory which does not exist generates correct assets', asy
expect(fs.readFileSync(path.resolve('newDir/_markbind/footers/footer.md'), 'utf8'))
.toEqual(FOOTER_MD_DEFAULT);

// head folder
expect(fs.existsSync(path.resolve('newDir/_markbind/head'), 'utf8')).toEqual(true);

// site-nav.md
expect(fs.readFileSync(path.resolve('newDir/_markbind/navigation/site-nav.md'), 'utf8'))
.toEqual(SITE_NAV_MD_DEFAULT);
Expand Down

0 comments on commit 97711ef

Please sign in to comment.