mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 01:33:02 +00:00
Merge pull request #4 from facebookexperimental/deltice
Add new translation functionality and run prettier
This commit is contained in:
commit
a7258f990c
|
|
@ -0,0 +1,194 @@
|
|||
---
|
||||
id: getting-started
|
||||
title: Docusaurus
|
||||
layout: docs
|
||||
category: Docusaurus
|
||||
permalink: docs/en/doc1.html
|
||||
next: translation
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Project Structure
|
||||
|
||||
In your project repo, all of your documentation files should be placed inside a `docs` folder. Any blog posts should be inside a `blog` folder. Create a `website` folder inside which you will install and run docusaurus.
|
||||
|
||||
### Installation
|
||||
|
||||
Inside of your `website` folder, create a `package.json` file with the following scripts for Docusaurus:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"start": "docusaurus-start",
|
||||
"build": "docusaurus-build",
|
||||
"publish-gh-pages": "docusaurus-publish",
|
||||
"examples": "docusaurus-examples"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Install Docusaurus using `npm` or `yarn`:
|
||||
|
||||
```
|
||||
npm install --save-dev docusaurus
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn add docusaurus -dev
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Generate Examples
|
||||
|
||||
To create example files for configuration, run `examples` using `npm` or `yarn`:
|
||||
|
||||
```
|
||||
npm run examples
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn run examples
|
||||
```
|
||||
|
||||
|
||||
This will create the following files/folders in your website folder:
|
||||
|
||||
```
|
||||
core/Footer.js
|
||||
example-blog/...
|
||||
example-docs/...
|
||||
pages/...
|
||||
static/img/...
|
||||
siteConfig.js
|
||||
```
|
||||
|
||||
`examples` will not overwrite any existing files of the same name in your website folder.
|
||||
|
||||
The provided example files contain configurations for an example site.
|
||||
The `core/Footer.js` file is a React component that acts as the footer for the site generated by Docusaurus and should be customized by the user.
|
||||
The `example-blog` folder contains examples of blog posts written in markdown.
|
||||
The `example-docs` folder contains example documentation files written in markdown.
|
||||
The `pages` folder contains example top-level pages for the site.
|
||||
The `static` folder contains static assets used by the example site.
|
||||
The `siteConfig.js` file is the main configuration file used by Docusaurus.
|
||||
|
||||
### How to Configure Your Site
|
||||
|
||||
Configure the `siteConfig.js` file which has comments guiding you through what needs to be done and how each configuration affects your website.
|
||||
|
||||
Customize `core/Footer.js` which will serve as the footer for each page on your website.
|
||||
|
||||
Include your own top-level pages as React components in `pages`.
|
||||
- These components should just be the body sections of the pages you want, and they will be included with the header and footer that the rest of Docusaurus uses.
|
||||
- Currently, if you want to add other React components to your pages, you must include all of it inside that file due to how `require` paths are set-up.
|
||||
- You may also include `.html` files directly, but this is not recommended, and these will just be served as is and will not have any of the header/footer/styles shared by the rest of Docusaurus.
|
||||
|
||||
All images and other static assets you wish to include should be placed inside the `static` folder. Any `.css` files provided in `static` will be concatenated to the standard styles provided by Docusaurus and used site-wide.
|
||||
|
||||
### Document and Blog Front Matters
|
||||
|
||||
Documentation should contain front matter that follows this example:
|
||||
```
|
||||
---
|
||||
id: doc1 <!-- used for docs to find each other and to map links -->
|
||||
title: Document Title
|
||||
layout: docs1 <!-- used to determine different sidebar groupings -->
|
||||
category: Sidebar Category 1 <!-- category on the sidebar under which this doc goes -->
|
||||
permalink: docs/en/doc1.html <!-- link to the document that is used for site -->
|
||||
previous: doc0 <!-- previous doc on sidebar for navigation -->
|
||||
next: doc2 <!-- next doc on the sidebar for navigation -->
|
||||
<!-- don't include next if this is the last doc; don't include previous if first doc -->
|
||||
---
|
||||
```
|
||||
|
||||
Blog posts should be written as markdown files with the following front matter:
|
||||
```
|
||||
---
|
||||
title: Blog Post Title
|
||||
author: Author Name
|
||||
authorURL: http://twitter.com/author <!-- (or some other link) -->
|
||||
authorFBID: 21315325 <!-- id to get author's picture -->
|
||||
---
|
||||
```
|
||||
In the blog post you should include a line `<!--truncate-->`. This will determine under which point text will be ignored when generating the preview of your blog post. Blog posts should have the file name format: `yyyy-mm-dd-your-file-name.md`.
|
||||
|
||||
|
||||
## Using Docusaurus
|
||||
|
||||
### Run the Server
|
||||
|
||||
To run your website locally run the script:
|
||||
|
||||
```
|
||||
npm run start
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn run start
|
||||
```
|
||||
|
||||
|
||||
This will start a server hosting your website locally at `localhost:3000`. This server will ignore any occurences `siteConfig.baseUrl` in URLs, e.g. `localhost:3000/your-site/index.html` will be the same as `localhost:3000/index.html`. Any changes to configured files will be reflected by refreshing the page, i.e. the server does not need to be restarted to show changes. You may also specify a different port to start your server on as a command line argument, e.g. `npm run start 9000`.
|
||||
|
||||
|
||||
### Build Static Pages
|
||||
|
||||
To create a static build of your website, run the script:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn run build
|
||||
```
|
||||
|
||||
This will generate `.html` files from all of your docs and other pages included in `pages`. This allows you to check whether or not all your files are being generated correctly. The build folder is inside Docusaurus's directory inside `node_modules`.
|
||||
|
||||
### Publishing Your Website
|
||||
|
||||
Use CircleCI to publish your website whenever your project repo is updated. Configure your circle.yml file in your project repo to run commands to publish to GitHub Pages. An example is shown here:
|
||||
|
||||
```yaml
|
||||
machine:
|
||||
node:
|
||||
version: 6.10.3
|
||||
npm:
|
||||
version: 3.10.10
|
||||
|
||||
test:
|
||||
override:
|
||||
- "true"
|
||||
|
||||
deployment:
|
||||
website:
|
||||
branch: master
|
||||
commands:
|
||||
- git config --global user.email "test-site-bot@users.noreply.github.com"
|
||||
- git config --global user.name "Website Deployment Script"
|
||||
- echo "machine github.com login test-site-bot password $GITHUB_TOKEN" > ~/.netrc
|
||||
- cd website && npm install && GIT_USER=test-site-bot npm run publish-gh-pages
|
||||
```
|
||||
|
||||
Note that in this case a GitHub user `test-site-bot` is created to use just for publishing. Make sure to give your Git user push permissions for your project and to set a GITHUB_TOKEN environment variable in Circle if you choose to publish this way.
|
||||
|
||||
If you wish to manually publish your website with the `publish-gh-pages` script, run the following example command with the appropriate variables for your project:
|
||||
|
||||
```
|
||||
DEPLOY_USER=deltice GIT_USER=test-site-bot CIRCLE_PROJECT_USERNAME=deltice CIRCLE_PROJECT_REPONAME=test-site CIRCLE_BRANCH=master npm run publish-gh-pages
|
||||
```
|
||||
|
||||
## More Information
|
||||
|
||||
For details on how to set up translation support, read here.
|
||||
For more details on how Docusaurus functions, read here.
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
id: search
|
||||
title: Documentation Search
|
||||
layout: docs
|
||||
category: Docusaurus
|
||||
permalink: docs/en/search.html
|
||||
previous: translation
|
||||
---
|
||||
|
||||
## Algolia Search Integration
|
||||
|
||||
Docusaurus supports search using [Algolia DocSearch](https://community.algolia.com/docsearch/). Once you have set up your site, you can use the link above to have Algolia crawl your website's documentation pages. Algolia will then send you an API key and index name for your site.
|
||||
|
||||
Enter your search-only API key and index name into `siteConfig.js` in the `algolia` section to enable search for your site. The search bar will be in the header navigation bar in between internal links and external links. To disable the search bar, delete the `algolia` section in the `siteConfig.js` file.
|
||||
|
||||
```js
|
||||
const siteConfig = {
|
||||
...
|
||||
algolia: {
|
||||
apiKey: "my-search-only-api-key-1234",
|
||||
indexName: "my-index-name"
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
id: translation
|
||||
title: Translations with Docusaurus
|
||||
layout: docs
|
||||
category: Docusaurus
|
||||
permalink: docs/en/translation.html
|
||||
previous: getting-started
|
||||
next: search
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Docusaurus allows for easy translation functionality using Crowdin. Documentation files written in English are uploaded to Crowdin for translation by users. Top-level pages written with English strings can be easily translated by wrapping any strings you want to translate in a `<translate>` tag. Strings found in the site header and in documentation front matter will also be found by Docusaurus and properly translated. Read on for more details.
|
||||
|
||||
## Docusaurus Translation Configurations
|
||||
|
||||
To generate example files for translations with Docusuaurus, run the `examples` script with the command line argument `translations`:
|
||||
|
||||
```
|
||||
npm run examples translations
|
||||
```
|
||||
|
||||
This will create the following files in your website folder:
|
||||
|
||||
```
|
||||
pages/en/help-with-translations.js
|
||||
languages.js
|
||||
crowdin.yaml
|
||||
```
|
||||
|
||||
The `pages/en/help-with-translations.js` file is the same example help page generated by the `examples` script but now using translations tags that are described below.
|
||||
The `languages.js` file tells Docusaurus what languages you want to enable for your site.
|
||||
The `crowdin.yaml` file is used to configure crowdin integration, and should be moved out one level into your project repo.
|
||||
|
||||
|
||||
## How Docusaurus Finds Strings to Translate
|
||||
|
||||
Add the following script to your package.json file:
|
||||
```json
|
||||
...
|
||||
"scripts": {
|
||||
...
|
||||
"write-translations": "docusaurus-write-translations"
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
Running the script will generate an `i18n/en.json` file containing all the strings that will be translated from English into other languages.
|
||||
|
||||
The script will include text from the following places:
|
||||
- title strings and category strings in documentation front matter
|
||||
- tagline in `siteConfig.js`
|
||||
- internal and external header link text strings in `siteConfig.js`
|
||||
|
||||
It will also include any strings in any `.js` files in the `pages` folder that are wrapped in a `<translate>` tag. You can also include an optional description attribute to give more context to a translator about how to translate the string.
|
||||
|
||||
In addition to these strings in the `i18n/en.json` file, the whole documentation files themselves will be translated.
|
||||
|
||||
## How Docusaurus Translates Strings
|
||||
|
||||
Docusaurus itself does not do any translation from one language to another. Instead, it uses Crowdin to manage translations and then downloads appropriately translated files from Crowdin. More information on how to set up Crowdin translations later.
|
||||
|
||||
## How Docusaurus Uses String Translations
|
||||
|
||||
This section provides some more context for how translation works, but is not necessary information for the user to know.
|
||||
|
||||
For things like the strings found in the headers and sidebars of pages, Docusaurus references a translated version of `i18n/en.json` (for example, a `i18n/fr.json` file downloaded from Crowdin).
|
||||
|
||||
For documentation text itself, fully translated markdown files will be compiled in the same way English documentation markdown files would be.
|
||||
|
||||
For other pages, Docusaurus will automatically transform all `<translate>` tags into function calls that will return appropriately translated strings. For each language that is enabled with `languages.js`, Docusaurus will build translated pages using the files in `pages/en` and the language's respective `.json` file in `i18n`.
|
||||
|
||||
## Crowdin Set-Up
|
||||
|
||||
Create your translation project on [Crowdin](https://www.crowdin.com/). You can use [Crowdin's guides](https://support.crowdin.com/translation-process-overview/) to learn more about the translations work flow.
|
||||
|
||||
To automatically get the translations for your files, update the `circle.yml` file in your project directory to include steps to upload English files to be translated and download translated files using the Crowdin CLI. Here is an example `circle.yml` file:
|
||||
|
||||
```yaml
|
||||
machine:
|
||||
node:
|
||||
version: 6.10.3
|
||||
npm:
|
||||
version: 3.10.10
|
||||
|
||||
test:
|
||||
override:
|
||||
- "true"
|
||||
|
||||
deployment:
|
||||
website:
|
||||
branch: master
|
||||
commands:
|
||||
# configure git user
|
||||
- git config --global user.email "test-site-bot@users.noreply.github.com"
|
||||
- git config --global user.name "Website Deployment Script"
|
||||
- echo "machine github.com login test-site-bot password $GITHUB_TOKEN" > ~/.netrc
|
||||
# install Docusaurus and generate file of English strings
|
||||
- cd website && npm install && npm run write-translations && cd ..
|
||||
# crowdin install
|
||||
- sudo apt-get install default-jre
|
||||
- wget https://artifacts.crowdin.com/repo/deb/crowdin.deb -O crowdin.deb
|
||||
- sudo dpkg -i crowdin.deb
|
||||
# translations upload/download
|
||||
- crowdin --config crowdin.yaml upload sources --auto-update -b master
|
||||
- crowdin --config crowdin.yaml download -b master
|
||||
# build and publish website
|
||||
- cd website && GIT_USER=test-site-bot npm run publish-gh-pages
|
||||
```
|
||||
|
||||
The `crowdin` command uses the `crowdin.yaml` file generated with the `examples` script. It should be placed in your project directory to configure how and what files are uploaded/downloaded.
|
||||
|
||||
Note that in the `crowdin.yaml` file, `CROWDIN_PROJECT_ID` and `CROWDIN_API_KEY` are environment variables set-up in Circle for your Crowdin project. They can be found in your Crowdin project settings.
|
||||
|
||||
Now, Circle will help you automatically get translations prior to building your website. If you wish to use crowdin on your machine locally, you can install the [Crowdin CLI tool](https://support.crowdin.com/cli-tool/) and run the same commands found in the `circle.yaml` file, making sure you actually set the `project_identifier` and `api_key`.
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
project_identifier_env: CROWDIN_PROJECT_ID
|
||||
api_key_env: CROWDIN_API_KEY
|
||||
base_path: "./"
|
||||
preserve_hierarchy: true
|
||||
|
||||
files:
|
||||
-
|
||||
source: '/docs/en/*.md'
|
||||
translation: '/docs/%locale%/%original_file_name%'
|
||||
languages_mapping: &anchor
|
||||
locale:
|
||||
'af': 'af'
|
||||
'ar': 'ar'
|
||||
'bs-BA': 'bs-BA'
|
||||
'ca': 'ca'
|
||||
'cs': 'cs'
|
||||
'da': 'da'
|
||||
'de': 'de'
|
||||
'el': 'el'
|
||||
'es-ES': 'es-ES'
|
||||
'fa': 'fa-IR'
|
||||
'fi': 'fi'
|
||||
'fr': 'fr'
|
||||
'he': 'he'
|
||||
'hu': 'hu'
|
||||
'id': 'id-ID'
|
||||
'it': 'it'
|
||||
'ja': 'ja'
|
||||
'ko': 'ko'
|
||||
'mr': 'mr-IN'
|
||||
'nl': 'nl'
|
||||
'no': 'no-NO'
|
||||
'pl': 'pl'
|
||||
'pt-BR': 'pt-BR'
|
||||
'pt-PT': 'pt-PT'
|
||||
'ro': 'ro'
|
||||
'ru': 'ru'
|
||||
'sk': 'sk-SK'
|
||||
'sr': 'sr'
|
||||
'sv-SE': 'sv-SE'
|
||||
'tr': 'tr'
|
||||
'uk': 'uk'
|
||||
'vi': 'vi'
|
||||
'zh-CN': 'zh-Hans'
|
||||
'zh-TW': 'zh-Hant'
|
||||
-
|
||||
source: '/website/i18n/en.json'
|
||||
translation: '/website/i18n/%locale%.json'
|
||||
languages_mapping: *anchor
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require("react");
|
||||
|
||||
const CompLibrary = require("../../core/CompLibrary.js");
|
||||
const Container = CompLibrary.Container;
|
||||
const GridBlock = CompLibrary.GridBlock;
|
||||
|
||||
const translate = require("../../server/translate.js").translate;
|
||||
|
||||
const siteConfig = require(process.cwd() + "/siteConfig.js");
|
||||
|
||||
class Help extends React.Component {
|
||||
render() {
|
||||
const supportLinks = [
|
||||
{
|
||||
content: (
|
||||
<translate>
|
||||
Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)
|
||||
</translate>
|
||||
),
|
||||
title: <translate>Browse Docs</translate>
|
||||
},
|
||||
{
|
||||
content: (
|
||||
<translate>
|
||||
Ask questions about the documentation and project
|
||||
</translate>
|
||||
),
|
||||
title: <translate>Join the community</translate>
|
||||
},
|
||||
{
|
||||
content: <translate>Find out what's new with this project</translate>,
|
||||
title: <translate>Stay up to date</translate>
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="docMainWrapper wrapper">
|
||||
<Container className="mainContainer documentContainer postContainer">
|
||||
<div className="post">
|
||||
<header className="postHeader">
|
||||
<h2>
|
||||
<translate>Need help?</translate>
|
||||
</h2>
|
||||
</header>
|
||||
<p>
|
||||
<translate desc="statement made to reader">
|
||||
This project is maintained by a dedicated group of people.
|
||||
</translate>
|
||||
</p>
|
||||
<GridBlock contents={supportLinks} layout="threeColumn" />
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Help.defaultProps = {
|
||||
language: "en"
|
||||
};
|
||||
|
||||
module.exports = Help;
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
{
|
||||
"localized-strings": {
|
||||
"doc1": "Docusaurus",
|
||||
"doc2": "The Second in a Series of Documents",
|
||||
"doc3": "The Third in a Series of Documents",
|
||||
"doc4": "Separate Sidebar Document 1",
|
||||
"doc5": "Separate Sidebar Document 2",
|
||||
"Docusaurus": "Docusaurus Guide",
|
||||
"First Category": "Example Category 1",
|
||||
"Second Category": "Example Category 2",
|
||||
"previous": "Previous",
|
||||
"next": "Continue Reading",
|
||||
"Docs": "Docs",
|
||||
"API": "API",
|
||||
"GitHub": "GitHub",
|
||||
"Help": "Help",
|
||||
"Blog": "Blog"
|
||||
},
|
||||
"tagline": "Tagline",
|
||||
"pages-strings": {
|
||||
"index": {
|
||||
"My Tagline": "My Tagline",
|
||||
"Try It Out": "Try It Out",
|
||||
"Example Link": "Example Link",
|
||||
"Example Link 2": "Example Link 2",
|
||||
"This is the content of my feature": "This is the content of my feature",
|
||||
"The content of my second feature": "The content of my second feature",
|
||||
"These are features of this project": "These are features of this project",
|
||||
"Talk about learning how to use this": "Talk about learning how to use this",
|
||||
"Talk about trying this out": "Talk about trying this out",
|
||||
"This is another description of how this project is useful": "This is another description of how this project is useful",
|
||||
"This project is used by all these people": "This project is used by all these people",
|
||||
"More \"Docusaurus\" Users": "More \"Docusaurus\" Users",
|
||||
"Feature One": "Feature One",
|
||||
"Feature Two": "Feature Two",
|
||||
"Feature Callout": "Feature Callout",
|
||||
"Learn How": "Learn How",
|
||||
"Try it Out": "Try it Out",
|
||||
"Description": "Description",
|
||||
"Who's Using This?": "Who's Using This?"
|
||||
},
|
||||
"help": {
|
||||
"Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)": "Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)",
|
||||
"Browse Docs": "Browse Docs",
|
||||
"Ask questions about the documentation and project": "Ask questions about the documentation and project",
|
||||
"Join the community": "Join the community",
|
||||
"Find out what's new with this project": "Find out what's new with this project",
|
||||
"Stay up to date": "Stay up to date",
|
||||
"Need help?": "Need help?",
|
||||
"This project is maintained by a dedicated group of people.": "This project is maintained by a dedicated group of people."
|
||||
},
|
||||
"users": {
|
||||
"Who's Using This?": "Who's Using This?",
|
||||
"This project is used by many folks": "This project is used by many folks",
|
||||
"Are you using this project?": "Are you using this project?",
|
||||
"Add your company": "Add your company"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,32 +20,30 @@ class Help extends React.Component {
|
|||
const supportLinks = [
|
||||
{
|
||||
content:
|
||||
"Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)\n",
|
||||
"Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)",
|
||||
title: "Browse Docs"
|
||||
},
|
||||
{
|
||||
content: "Ask questions about the documentation and project\n",
|
||||
content: "Ask questions about the documentation and project",
|
||||
title: "Join the community"
|
||||
},
|
||||
{
|
||||
content: "Find out what's new with this project\n",
|
||||
content: "Find out what's new with this project",
|
||||
title: "Stay up to date"
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="docMainWrapper wrapper">
|
||||
<Container className="mainContainer documentContainer postContainer">
|
||||
<div className="post">
|
||||
<header className="postHeader">
|
||||
<h2>Need help?</h2>
|
||||
</header>
|
||||
<p>This project is maintained by a dedicated group of people.</p>
|
||||
<GridBlock contents={supportLinks} layout="threeColumn" />
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
<div className="docMainWrapper wrapper">
|
||||
<Container className="mainContainer documentContainer postContainer">
|
||||
<div className="post">
|
||||
<header className="postHeader">
|
||||
<h2>Need help?</h2>
|
||||
</header>
|
||||
<p>This project is maintained by a dedicated group of people.</p>
|
||||
<GridBlock contents={supportLinks} layout="threeColumn" />
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,27 +25,25 @@ class Users extends React.Component {
|
|||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mainContainer">
|
||||
<Container padding={["bottom", "top"]}>
|
||||
<div className="showcaseSection">
|
||||
<div className="prose">
|
||||
<h1>Who's Using This?</h1>
|
||||
<p>This project is used by many folks</p>
|
||||
</div>
|
||||
<div className="logos">
|
||||
{showcase}
|
||||
</div>
|
||||
<p>Are you using this project?</p>
|
||||
<a
|
||||
href="https://github.com/deltice/test-site/edit/master/website/siteConfig.js"
|
||||
className="button"
|
||||
>
|
||||
Add your company
|
||||
</a>
|
||||
<div className="mainContainer">
|
||||
<Container padding={["bottom", "top"]}>
|
||||
<div className="showcaseSection">
|
||||
<div className="prose">
|
||||
<h1>Who's Using This?</h1>
|
||||
<p>This project is used by many folks</p>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
<div className="logos">
|
||||
{showcase}
|
||||
</div>
|
||||
<p>Are you using this project?</p>
|
||||
<a
|
||||
href="https://github.com/deltice/test-site/edit/master/website/siteConfig.js"
|
||||
className="button"
|
||||
>
|
||||
Add your company
|
||||
</a>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
|
||||
/* List of projects/orgs using your project for the users page */
|
||||
const users = [
|
||||
{
|
||||
|
|
@ -66,35 +64,16 @@ const siteConfig = {
|
|||
"rgba(46, 133, 85, 0.03)" /* primaryColor in rgba form, with 0.03 alpha */
|
||||
},
|
||||
tagline: "My Tagline",
|
||||
recruitingLink: "https://crowdin.com/project/test-site" /* translation site "help translate" link */,
|
||||
recruitingLink:
|
||||
"https://crowdin.com/project/test-site" /* translation site "help translate" link */,
|
||||
/* remove this section to disable search bar */
|
||||
algolia: {
|
||||
apiKey: "0f9f28b9ab9efae89810921a351753b5", /* use your search-only api key */
|
||||
apiKey:
|
||||
"0f9f28b9ab9efae89810921a351753b5" /* use your search-only api key */,
|
||||
indexName: "github"
|
||||
},
|
||||
}
|
||||
/* remove this to disable google analytics tracking */
|
||||
/* gaTrackingId: "" */
|
||||
};
|
||||
|
||||
let languages;
|
||||
if (fs.existsSync("./languages.js")) {
|
||||
languages = require("./languages.js");
|
||||
siteConfig["en"] = require("./i18n/en.json");
|
||||
} else {
|
||||
languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: "English",
|
||||
tag: "en"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
const enabledLanguages = languages.filter(lang => lang.enabled);
|
||||
|
||||
siteConfig["languages"] = enabledLanguages;
|
||||
|
||||
/* INJECT LOCALIZED FILES BEGIN */
|
||||
/* INJECT LOCALIZED FILES END */
|
||||
|
||||
module.exports = siteConfig;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
require('babel-register') ({
|
||||
require("babel-register")({
|
||||
ignore: false,
|
||||
"presets": ["react"]
|
||||
plugins: [require("./server/translate-plugin.js")],
|
||||
presets: ["react"]
|
||||
});
|
||||
|
||||
const generate = require('./server/generate.js');
|
||||
const generate = require("./server/generate.js");
|
||||
generate();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@
|
|||
*/
|
||||
|
||||
const CWD = process.cwd();
|
||||
const fs = require('fs-extra');
|
||||
const fs = require("fs-extra");
|
||||
|
||||
fs.copySync(__dirname + '/../examples/', CWD, {overwrite: false});
|
||||
if (process.argv.indexOf("translations") !== -1) {
|
||||
fs.copySync(__dirname + "/../examples-translations/", CWD, {
|
||||
overwrite: false
|
||||
});
|
||||
} else {
|
||||
fs.copySync(__dirname + "/../examples/", CWD, { overwrite: false });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,44 +7,53 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const BlogPost = require('./BlogPost.js');
|
||||
const BlogSidebar = require('./BlogSidebar.js');
|
||||
const Container = require('./Container.js');
|
||||
const MetadataBlog = require('./MetadataBlog.js');
|
||||
const React = require('react');
|
||||
const Site = require('./Site.js');
|
||||
const BlogPost = require("./BlogPost.js");
|
||||
const BlogSidebar = require("./BlogSidebar.js");
|
||||
const Container = require("./Container.js");
|
||||
const MetadataBlog = require("./MetadataBlog.js");
|
||||
const React = require("react");
|
||||
const Site = require("./Site.js");
|
||||
|
||||
const BlogPageLayout = React.createClass({
|
||||
getPageURL(page) {
|
||||
let url = this.props.config.baseUrl + 'blog/';
|
||||
let url = this.props.config.baseUrl + "blog/";
|
||||
if (page > 0) {
|
||||
url += 'page' + (page + 1) + '/';
|
||||
url += "page" + (page + 1) + "/";
|
||||
}
|
||||
return url + '#content';
|
||||
return url + "#content";
|
||||
},
|
||||
|
||||
render() {
|
||||
const perPage = this.props.metadata.perPage;
|
||||
const page = this.props.metadata.page;
|
||||
return (
|
||||
<Site section="blog" title="Blog" language="en" config={this.props.config} >
|
||||
<Site
|
||||
section="blog"
|
||||
title="Blog"
|
||||
language="en"
|
||||
config={this.props.config}
|
||||
>
|
||||
<div className="docMainWrapper wrapper">
|
||||
<BlogSidebar language={this.props.language} config={this.props.config} />
|
||||
<BlogSidebar
|
||||
language={this.props.language}
|
||||
config={this.props.config}
|
||||
/>
|
||||
<Container className="mainContainer documentContainer postContainer blogContainer">
|
||||
<div className="posts">
|
||||
{MetadataBlog
|
||||
.slice(page * perPage, (page + 1) * perPage)
|
||||
.map(post => {
|
||||
return (
|
||||
<BlogPost
|
||||
post={post}
|
||||
content={post.content}
|
||||
truncate={true}
|
||||
key={post.path + post.title}
|
||||
config={this.props.config}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{MetadataBlog.slice(
|
||||
page * perPage,
|
||||
(page + 1) * perPage
|
||||
).map(post => {
|
||||
return (
|
||||
<BlogPost
|
||||
post={post}
|
||||
content={post.content}
|
||||
truncate={true}
|
||||
key={post.path + post.title}
|
||||
config={this.props.config}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<div className="docs-prevnext">
|
||||
{page > 0 &&
|
||||
<a className="docs-prev" href={this.getPageURL(page - 1)}>
|
||||
|
|
@ -60,7 +69,7 @@ const BlogPageLayout = React.createClass({
|
|||
</div>
|
||||
</Site>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = BlogPageLayout;
|
||||
|
|
|
|||
|
|
@ -7,26 +7,35 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const Marked = require('./Marked.js');
|
||||
const React = require('react');
|
||||
const Marked = require("./Marked.js");
|
||||
const React = require("react");
|
||||
|
||||
class BlogPost extends React.Component {
|
||||
renderContent() {
|
||||
let content = this.props.content;
|
||||
if (this.props.truncate) {
|
||||
content = content.split('<!--truncate-->')[0];
|
||||
content = content.split("<!--truncate-->")[0];
|
||||
return (
|
||||
<article className="post-content">
|
||||
<Marked>{content}</Marked>
|
||||
<Marked>
|
||||
{content}
|
||||
</Marked>
|
||||
<div className="read-more">
|
||||
<a className="button" href={this.props.config.baseUrl + 'blog/' + this.props.post.path}>
|
||||
<a
|
||||
className="button"
|
||||
href={this.props.config.baseUrl + "blog/" + this.props.post.path}
|
||||
>
|
||||
Read More
|
||||
</a>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
return <Marked>{content}</Marked>;
|
||||
return (
|
||||
<Marked>
|
||||
{content}
|
||||
</Marked>
|
||||
);
|
||||
}
|
||||
|
||||
renderAuthorPhoto() {
|
||||
|
|
@ -37,9 +46,9 @@ class BlogPost extends React.Component {
|
|||
<a href={post.authorURL} target="_blank">
|
||||
<img
|
||||
src={
|
||||
'https://graph.facebook.com/' +
|
||||
post.authorFBID +
|
||||
'/picture/?height=200&width=200'
|
||||
"https://graph.facebook.com/" +
|
||||
post.authorFBID +
|
||||
"/picture/?height=200&width=200"
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
|
|
@ -54,7 +63,9 @@ class BlogPost extends React.Component {
|
|||
const post = this.props.post;
|
||||
return (
|
||||
<h1>
|
||||
<a href={this.props.config.baseUrl + 'blog/' + post.path}>{post.title}</a>
|
||||
<a href={this.props.config.baseUrl + "blog/" + post.path}>
|
||||
{post.title}
|
||||
</a>
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
|
@ -65,18 +76,18 @@ class BlogPost extends React.Component {
|
|||
// Because JavaScript sucks at date handling :(
|
||||
const year = match[1];
|
||||
const month = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December"
|
||||
][parseInt(match[2], 10) - 1];
|
||||
const day = parseInt(match[3], 10);
|
||||
|
||||
|
|
@ -84,7 +95,9 @@ class BlogPost extends React.Component {
|
|||
<header className="postHeader">
|
||||
{this.renderAuthorPhoto()}
|
||||
<p className="post-authorName">
|
||||
<a href={post.authorURL} target="_blank">{post.author}</a>
|
||||
<a href={post.authorURL} target="_blank">
|
||||
{post.author}
|
||||
</a>
|
||||
</p>
|
||||
{this.renderTitle()}
|
||||
<p className="post-meta">
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const BlogPost = require('./BlogPost.js');
|
||||
const BlogSidebar = require('./BlogSidebar.js');
|
||||
const Container = require('./Container.js');
|
||||
const Site = require('./Site.js');
|
||||
const React = require("react");
|
||||
const BlogPost = require("./BlogPost.js");
|
||||
const BlogSidebar = require("./BlogSidebar.js");
|
||||
const Container = require("./Container.js");
|
||||
const Site = require("./Site.js");
|
||||
|
||||
class BlogPostLayout extends React.Component {
|
||||
render() {
|
||||
|
|
@ -19,20 +19,24 @@ class BlogPostLayout extends React.Component {
|
|||
<Site
|
||||
className="sideNavVisible"
|
||||
section="blog"
|
||||
url={'blog/' + this.props.metadata.path}
|
||||
url={"blog/" + this.props.metadata.path}
|
||||
title={this.props.metadata.title}
|
||||
language={'en'}
|
||||
description={this.props.children.trim().split('\n')[0]}
|
||||
language={"en"}
|
||||
description={this.props.children.trim().split("\n")[0]}
|
||||
config={this.props.config}
|
||||
>
|
||||
<div className="docMainWrapper wrapper">
|
||||
<BlogSidebar language={'en'} current={this.props.metadata} config={this.props.config}/>
|
||||
<BlogSidebar
|
||||
language={"en"}
|
||||
current={this.props.metadata}
|
||||
config={this.props.config}
|
||||
/>
|
||||
<Container className="mainContainer documentContainer postContainer blogContainer">
|
||||
<div className="lonePost">
|
||||
<BlogPost
|
||||
post={this.props.metadata}
|
||||
content={this.props.children}
|
||||
language={'en'}
|
||||
language={"en"}
|
||||
config={this.props.config}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,22 +7,24 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const Container = require('./Container.js');
|
||||
const SideNav = require('./nav/SideNav.js');
|
||||
const React = require("react");
|
||||
const Container = require("./Container.js");
|
||||
const SideNav = require("./nav/SideNav.js");
|
||||
|
||||
const MetadataBlog = require('./MetadataBlog.js');
|
||||
const MetadataBlog = require("./MetadataBlog.js");
|
||||
|
||||
class BlogSidebar extends React.Component {
|
||||
render() {
|
||||
const contents = [{
|
||||
name: 'Recent Posts',
|
||||
links: MetadataBlog,
|
||||
}];
|
||||
const contents = [
|
||||
{
|
||||
name: "Recent Posts",
|
||||
links: MetadataBlog
|
||||
}
|
||||
];
|
||||
const title = this.props.current && this.props.current.title;
|
||||
const current = {
|
||||
id: title || '',
|
||||
category: 'Recent Posts',
|
||||
id: title || "",
|
||||
category: "Recent Posts"
|
||||
};
|
||||
return (
|
||||
<Container className="docsNavContainer" id="docsNav" wrapper={false}>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const Marked = require('./Marked.js');
|
||||
const Container = require('./Container.js');
|
||||
const GridBlock = require('./GridBlock.js');
|
||||
const Marked = require("./Marked.js");
|
||||
const Container = require("./Container.js");
|
||||
const GridBlock = require("./GridBlock.js");
|
||||
|
||||
module.exports = {
|
||||
Marked: Marked,
|
||||
Container: Container,
|
||||
GridBlock: GridBlock
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,26 +7,29 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const classNames = require('classnames');
|
||||
const React = require("react");
|
||||
const classNames = require("classnames");
|
||||
|
||||
class Container extends React.Component {
|
||||
render() {
|
||||
const containerClasses = classNames('container', this.props.className, {
|
||||
'darkBackground': this.props.background === 'dark',
|
||||
'highlightBackground': this.props.background === 'highlight',
|
||||
'lightBackground': this.props.background === 'light',
|
||||
'paddingAll': this.props.padding.indexOf('all') >= 0,
|
||||
'paddingBottom': this.props.padding.indexOf('bottom') >= 0,
|
||||
'paddingLeft': this.props.padding.indexOf('left') >= 0,
|
||||
'paddingRight': this.props.padding.indexOf('right') >= 0,
|
||||
'paddingTop': this.props.padding.indexOf('top') >= 0,
|
||||
const containerClasses = classNames("container", this.props.className, {
|
||||
darkBackground: this.props.background === "dark",
|
||||
highlightBackground: this.props.background === "highlight",
|
||||
lightBackground: this.props.background === "light",
|
||||
paddingAll: this.props.padding.indexOf("all") >= 0,
|
||||
paddingBottom: this.props.padding.indexOf("bottom") >= 0,
|
||||
paddingLeft: this.props.padding.indexOf("left") >= 0,
|
||||
paddingRight: this.props.padding.indexOf("right") >= 0,
|
||||
paddingTop: this.props.padding.indexOf("top") >= 0
|
||||
});
|
||||
let wrappedChildren;
|
||||
|
||||
if (this.props.wrapper) {
|
||||
wrappedChildren =
|
||||
<div className="wrapper">{this.props.children}</div>;
|
||||
wrappedChildren = (
|
||||
<div className="wrapper">
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
wrappedChildren = this.props.children;
|
||||
}
|
||||
|
|
@ -39,9 +42,9 @@ class Container extends React.Component {
|
|||
}
|
||||
|
||||
Container.defaultProps = {
|
||||
background: 'transparent',
|
||||
background: "transparent",
|
||||
padding: [],
|
||||
wrapper: true,
|
||||
wrapper: true
|
||||
};
|
||||
|
||||
module.exports = Container;
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const Marked = require('./Marked.js');
|
||||
const React = require("react");
|
||||
const Marked = require("./Marked.js");
|
||||
|
||||
class Doc extends React.Component {
|
||||
render() {
|
||||
|
|
@ -17,9 +17,9 @@ class Doc extends React.Component {
|
|||
className="edit-page-link button"
|
||||
href={
|
||||
this.props.config.editUrl +
|
||||
this.props.language +
|
||||
'/' +
|
||||
this.props.source
|
||||
this.props.language +
|
||||
"/" +
|
||||
this.props.source
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
|
|
@ -30,10 +30,14 @@ class Doc extends React.Component {
|
|||
<div className="post">
|
||||
<header className="postHeader">
|
||||
{editLink}
|
||||
<h1>{this.props.title}</h1>
|
||||
<h1>
|
||||
{this.props.title}
|
||||
</h1>
|
||||
</header>
|
||||
<article>
|
||||
<Marked>{this.props.content}</Marked>
|
||||
<Marked>
|
||||
{this.props.content}
|
||||
</Marked>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,28 +7,31 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const Container = require('./Container.js');
|
||||
const Doc = require('./Doc.js');
|
||||
const DocsSidebar = require('./DocsSidebar.js');
|
||||
const Site = require('./Site.js');
|
||||
const React = require("react");
|
||||
const Container = require("./Container.js");
|
||||
const Doc = require("./Doc.js");
|
||||
const DocsSidebar = require("./DocsSidebar.js");
|
||||
const Site = require("./Site.js");
|
||||
const translation = require("../server/translation.js");
|
||||
|
||||
class DocsLayout extends React.Component {
|
||||
render() {
|
||||
const metadata = this.props.metadata;
|
||||
const content = this.props.children;
|
||||
const i18n = this.props.config[this.props.metadata.language];
|
||||
const i18n = translation[this.props.metadata.language];
|
||||
return (
|
||||
<Site
|
||||
config={this.props.config}
|
||||
className="sideNavVisible"
|
||||
section="docs"
|
||||
title={
|
||||
i18n ? this.props.config[this.props.metadata.language]['localized-strings'][
|
||||
this.props.metadata.localized_id
|
||||
] || this.props.metadata.title : this.props.metadata.title
|
||||
i18n
|
||||
? translation[this.props.metadata.language]["localized-strings"][
|
||||
this.props.metadata.localized_id
|
||||
] || this.props.metadata.title
|
||||
: this.props.metadata.title
|
||||
}
|
||||
description={content.trim().split('\n')[0]}
|
||||
description={content.trim().split("\n")[0]}
|
||||
language={metadata.language}
|
||||
>
|
||||
<div className="docMainWrapper wrapper">
|
||||
|
|
@ -39,9 +42,12 @@ class DocsLayout extends React.Component {
|
|||
config={this.props.config}
|
||||
source={metadata.source}
|
||||
title={
|
||||
i18n ? this.props.config[this.props.metadata.language]['localized-strings'][
|
||||
this.props.metadata.localized_id
|
||||
] || this.props.metadata.title : this.props.metadata.title
|
||||
i18n
|
||||
? translation[this.props.metadata.language][
|
||||
"localized-strings"
|
||||
][this.props.metadata.localized_id] ||
|
||||
this.props.metadata.title
|
||||
: this.props.metadata.title
|
||||
}
|
||||
language={metadata.language}
|
||||
/>
|
||||
|
|
@ -49,27 +55,25 @@ class DocsLayout extends React.Component {
|
|||
{metadata.previous_id &&
|
||||
<a
|
||||
className="docs-prev button"
|
||||
href={metadata.previous_id + '.html#content'}
|
||||
href={metadata.previous_id + ".html#content"}
|
||||
>
|
||||
←
|
||||
{' '}
|
||||
{
|
||||
i18n ? this.props.config[this.props.metadata.language][
|
||||
'localized-strings'
|
||||
]['previous'] || 'Previous' : 'Previous'
|
||||
}
|
||||
←{" "}
|
||||
{i18n
|
||||
? translation[this.props.metadata.language][
|
||||
"localized-strings"
|
||||
]["previous"] || "Previous"
|
||||
: "Previous"}
|
||||
</a>}
|
||||
{metadata.next_id &&
|
||||
<a
|
||||
className="docs-next button"
|
||||
href={metadata.next_id + '.html#content'}
|
||||
href={metadata.next_id + ".html#content"}
|
||||
>
|
||||
{
|
||||
i18n ? this.props.config[this.props.metadata.language][
|
||||
'localized-strings'
|
||||
]['next'] || 'Next' : 'Next'
|
||||
}
|
||||
{' '}
|
||||
{i18n
|
||||
? translation[this.props.metadata.language][
|
||||
"localized-strings"
|
||||
]["next"] || "Next"
|
||||
: "Next"}{" "}
|
||||
→
|
||||
</a>}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const Metadata = require('./metadata.js');
|
||||
const React = require('react');
|
||||
const Container = require('./Container.js');
|
||||
const SideNav = require('./nav/SideNav.js');
|
||||
const siteConfig = require(process.cwd() + '/siteConfig.js');
|
||||
const Metadata = require("./metadata.js");
|
||||
const React = require("react");
|
||||
const Container = require("./Container.js");
|
||||
const SideNav = require("./nav/SideNav.js");
|
||||
const siteConfig = require(process.cwd() + "/siteConfig.js");
|
||||
|
||||
class DocsSidebar extends React.Component {
|
||||
render() {
|
||||
let layout = this.props.metadata.layout;
|
||||
let docsCategories = require('./' + layout + 'Categories.js');
|
||||
let docsCategories = require("./" + layout + "Categories.js");
|
||||
return (
|
||||
<Container className="docsNavContainer" id="docsNav" wrapper={false}>
|
||||
<SideNav
|
||||
|
|
@ -34,7 +34,7 @@ class DocsSidebar extends React.Component {
|
|||
DocsSidebar.propTypes = {
|
||||
layout: React.PropTypes.string,
|
||||
root: React.PropTypes.string,
|
||||
title: React.PropTypes.string,
|
||||
title: React.PropTypes.string
|
||||
};
|
||||
|
||||
DocsSidebar.defaultProps = siteConfig.docsSidebarDefaults;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const React = require("react");
|
||||
|
||||
const githubButton = (
|
||||
<a
|
||||
|
|
@ -17,7 +17,8 @@ const githubButton = (
|
|||
data-count-href="/deltice/test-site/stargazers"
|
||||
data-count-api="/repos/deltice/test-site#stargazers_count"
|
||||
data-count-aria-label="# stargazers on GitHub"
|
||||
aria-label="Star this project on GitHub">
|
||||
aria-label="Star this project on GitHub"
|
||||
>
|
||||
Star
|
||||
</a>
|
||||
);
|
||||
|
|
@ -40,21 +41,30 @@ class Footer extends React.Component {
|
|||
<h5>Docs</h5>
|
||||
<a
|
||||
href={
|
||||
this.props.config.baseUrl + 'docs/' + this.props.language + '/doc1.html'
|
||||
this.props.config.baseUrl +
|
||||
"docs/" +
|
||||
this.props.language +
|
||||
"/doc1.html"
|
||||
}
|
||||
>
|
||||
Getting Started (or other categories)
|
||||
</a>
|
||||
<a
|
||||
href={
|
||||
this.props.config.baseUrl + 'docs/' + this.props.language + '/doc2.html'
|
||||
this.props.config.baseUrl +
|
||||
"docs/" +
|
||||
this.props.language +
|
||||
"/doc2.html"
|
||||
}
|
||||
>
|
||||
Guides (or other categories)
|
||||
</a>
|
||||
<a
|
||||
href={
|
||||
this.props.config.baseUrl + 'docs/' + this.props.language + '/doc3.html'
|
||||
this.props.config.baseUrl +
|
||||
"docs/" +
|
||||
this.props.language +
|
||||
"/doc3.html"
|
||||
}
|
||||
>
|
||||
API Reference (or other categories)
|
||||
|
|
@ -62,7 +72,11 @@ class Footer extends React.Component {
|
|||
</div>
|
||||
<div>
|
||||
<h5>Community</h5>
|
||||
<a href={this.props.config.baseUrl + this.props.language + '/users.html'}>
|
||||
<a
|
||||
href={
|
||||
this.props.config.baseUrl + this.props.language + "/users.html"
|
||||
}
|
||||
>
|
||||
User Showcase
|
||||
</a>
|
||||
<a
|
||||
|
|
@ -71,12 +85,10 @@ class Footer extends React.Component {
|
|||
>
|
||||
Stack Overflow
|
||||
</a>
|
||||
<a
|
||||
href="https://discordapp.com/"
|
||||
>
|
||||
Project Chat
|
||||
<a href="https://discordapp.com/">Project Chat</a>
|
||||
<a href="https://twitter.com/" target="_blank">
|
||||
Twitter
|
||||
</a>
|
||||
<a href="https://twitter.com/" target="_blank">Twitter</a>
|
||||
</div>
|
||||
<div>
|
||||
<h5>More</h5>
|
||||
|
|
@ -106,6 +118,4 @@ class Footer extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = Footer;
|
||||
|
|
|
|||
|
|
@ -7,31 +7,32 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const classNames = require('classnames');
|
||||
const React = require("react");
|
||||
const classNames = require("classnames");
|
||||
|
||||
const Marked = require('./Marked.js');
|
||||
const Marked = require("./Marked.js");
|
||||
|
||||
class GridBlock extends React.Component {
|
||||
renderBlock(block) {
|
||||
const blockClasses = classNames('blockElement', this.props.className, {
|
||||
'alignCenter': this.props.align === 'center',
|
||||
'alignRight': this.props.align === 'right',
|
||||
'fourByGridBlock': this.props.layout === 'fourColumn',
|
||||
'imageAlignBottom': (block.image && block.imageAlign === 'bottom'),
|
||||
'imageAlignSide': (block.image && (block.imageAlign === 'left' ||
|
||||
block.imageAlign === 'right')),
|
||||
'imageAlignTop': (block.image && block.imageAlign === 'top'),
|
||||
'threeByGridBlock': this.props.layout === 'threeColumn',
|
||||
'twoByGridBlock': this.props.layout === 'twoColumn',
|
||||
const blockClasses = classNames("blockElement", this.props.className, {
|
||||
alignCenter: this.props.align === "center",
|
||||
alignRight: this.props.align === "right",
|
||||
fourByGridBlock: this.props.layout === "fourColumn",
|
||||
imageAlignBottom: block.image && block.imageAlign === "bottom",
|
||||
imageAlignSide:
|
||||
block.image &&
|
||||
(block.imageAlign === "left" || block.imageAlign === "right"),
|
||||
imageAlignTop: block.image && block.imageAlign === "top",
|
||||
threeByGridBlock: this.props.layout === "threeColumn",
|
||||
twoByGridBlock: this.props.layout === "twoColumn"
|
||||
});
|
||||
|
||||
const topLeftImage = (block.imageAlign === 'top' ||
|
||||
block.imageAlign === 'left') &&
|
||||
const topLeftImage =
|
||||
(block.imageAlign === "top" || block.imageAlign === "left") &&
|
||||
this.renderBlockImage(block.image);
|
||||
|
||||
const bottomRightImage = (block.imageAlign === 'bottom' ||
|
||||
block.imageAlign === 'right') &&
|
||||
const bottomRightImage =
|
||||
(block.imageAlign === "bottom" || block.imageAlign === "right") &&
|
||||
this.renderBlockImage(block.image);
|
||||
|
||||
return (
|
||||
|
|
@ -39,7 +40,9 @@ class GridBlock extends React.Component {
|
|||
{topLeftImage}
|
||||
<div className="blockContent">
|
||||
{this.renderBlockTitle(block.title)}
|
||||
<Marked>{block.content}</Marked>
|
||||
<Marked>
|
||||
{block.content}
|
||||
</Marked>
|
||||
</div>
|
||||
{bottomRightImage}
|
||||
</div>
|
||||
|
|
@ -49,7 +52,9 @@ class GridBlock extends React.Component {
|
|||
renderBlockImage(image) {
|
||||
if (image) {
|
||||
return (
|
||||
<div className="blockImage"><img src={image} /></div>
|
||||
<div className="blockImage">
|
||||
<img src={image} />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
|
|
@ -58,7 +63,11 @@ class GridBlock extends React.Component {
|
|||
|
||||
renderBlockTitle(title) {
|
||||
if (title) {
|
||||
return <h2>{title}</h2>;
|
||||
return (
|
||||
<h2>
|
||||
{title}
|
||||
</h2>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -74,10 +83,10 @@ class GridBlock extends React.Component {
|
|||
}
|
||||
|
||||
GridBlock.defaultProps = {
|
||||
align: 'left',
|
||||
align: "left",
|
||||
contents: [],
|
||||
imagealign: 'top',
|
||||
layout: 'twoColumn',
|
||||
imagealign: "top",
|
||||
layout: "twoColumn"
|
||||
};
|
||||
|
||||
module.exports = GridBlock;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const React = require("react");
|
||||
|
||||
class Head extends React.Component {
|
||||
render() {
|
||||
|
|
@ -29,19 +29,29 @@ class Head extends React.Component {
|
|||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta httpEquiv="X-UA-Compatible" content="IE=edge, chrome=1" />
|
||||
<title>{this.props.title}</title>
|
||||
<title>
|
||||
{this.props.title}
|
||||
</title>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta property="og:title" content={this.props.title} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={this.props.url} />
|
||||
<meta property="og:description" content={this.props.description} />
|
||||
|
||||
<link rel="shortcut icon" href={this.props.config.baseUrl + this.props.config.favicon} />
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
href={this.props.config.baseUrl + this.props.config.favicon}
|
||||
/>
|
||||
{this.props.config.algolia &&
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
|
||||
}
|
||||
<link rel="stylesheet" href={this.props.config.baseUrl + "css/main.css"} />
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"
|
||||
/>}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href={this.props.config.baseUrl + "css/main.css"}
|
||||
/>
|
||||
<script async defer src="https://buttons.github.io/buttons.js" />
|
||||
</head>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,24 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const toSlug = require('./toSlug.js');
|
||||
const React = require("react");
|
||||
const toSlug = require("./toSlug.js");
|
||||
|
||||
const Header = React.createClass({
|
||||
render() {
|
||||
const slug = toSlug(this.props.toSlug || this.props.children);
|
||||
const Heading = 'h' + this.props.level;
|
||||
const Heading = "h" + this.props.level;
|
||||
|
||||
return (
|
||||
<Heading {...this.props}>
|
||||
<a className="anchor" name={slug}></a>
|
||||
{this.props.children}
|
||||
{' '}<a className="hash-link" href={'#' + slug}>#</a>
|
||||
<a className="anchor" name={slug} />
|
||||
{this.props.children}{" "}
|
||||
<a className="hash-link" href={"#" + slug}>
|
||||
#
|
||||
</a>
|
||||
</Heading>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Header;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const Prism = require('./Prism.js');
|
||||
const Header = require('./Header.js');
|
||||
const React = require("react");
|
||||
const Prism = require("./Prism.js");
|
||||
const Header = require("./Header.js");
|
||||
|
||||
/**
|
||||
* Block-Level Grammar
|
||||
|
|
@ -29,23 +29,36 @@ const block = {
|
|||
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
|
||||
table: noop,
|
||||
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
|
||||
text: /^[^\n]+/,
|
||||
text: /^[^\n]+/
|
||||
};
|
||||
|
||||
block.bullet = /(?:[*+-]|\d+\.)/;
|
||||
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
|
||||
block.item = replace(block.item, 'gm')(/bull/g, block.bullet)();
|
||||
block.item = replace(block.item, "gm")(/bull/g, block.bullet)();
|
||||
|
||||
block.list = replace(block.list)(/bull/g, block.bullet)('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)();
|
||||
block.list = replace(block.list)(/bull/g, block.bullet)(
|
||||
"hr",
|
||||
/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/
|
||||
)();
|
||||
|
||||
block._tag = '(?!(?:'
|
||||
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
|
||||
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
|
||||
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
|
||||
block._tag =
|
||||
"(?!(?:" +
|
||||
"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code" +
|
||||
"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo" +
|
||||
"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b";
|
||||
|
||||
block.html = replace(block.html)('comment', /<!--[\s\S]*?-->/)('closed', /<(tag)[\s\S]+?<\/\1>/)('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g, block._tag)();
|
||||
block.html = replace(block.html)("comment", /<!--[\s\S]*?-->/)(
|
||||
"closed",
|
||||
/<(tag)[\s\S]+?<\/\1>/
|
||||
)("closing", /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g, block._tag)();
|
||||
|
||||
block.paragraph = replace(block.paragraph)('hr', block.hr)('heading', block.heading)('lheading', block.lheading)('blockquote', block.blockquote)('tag', '<' + block._tag)('def', block.def)();
|
||||
block.paragraph = replace(block.paragraph)("hr", block.hr)(
|
||||
"heading",
|
||||
block.heading
|
||||
)("lheading", block.lheading)("blockquote", block.blockquote)(
|
||||
"tag",
|
||||
"<" + block._tag
|
||||
)("def", block.def)();
|
||||
|
||||
/**
|
||||
* Normal Block Grammar
|
||||
|
|
@ -59,10 +72,13 @@ block.normal = merge({}, block);
|
|||
|
||||
block.gfm = merge({}, block.normal, {
|
||||
fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
|
||||
paragraph: /^/,
|
||||
paragraph: /^/
|
||||
});
|
||||
|
||||
block.gfm.paragraph = replace(block.paragraph)('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')();
|
||||
block.gfm.paragraph = replace(block.paragraph)(
|
||||
"(?!",
|
||||
"(?!" + block.gfm.fences.source.replace("\\1", "\\2") + "|"
|
||||
)();
|
||||
|
||||
/**
|
||||
* GFM + Tables Block Grammar
|
||||
|
|
@ -70,7 +86,7 @@ block.gfm.paragraph = replace(block.paragraph)('(?!', '(?!' + block.gfm.fences.s
|
|||
|
||||
block.tables = merge({}, block.gfm, {
|
||||
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
|
||||
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/,
|
||||
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -113,10 +129,10 @@ Lexer.lex = function(src, options) {
|
|||
|
||||
Lexer.prototype.lex = function(src) {
|
||||
src = src
|
||||
.replace(/\r\n|\r/g, '\n')
|
||||
.replace(/\t/g, ' ')
|
||||
.replace(/\u00a0/g, ' ')
|
||||
.replace(/\u2424/g, '\n');
|
||||
.replace(/\r\n|\r/g, "\n")
|
||||
.replace(/\t/g, " ")
|
||||
.replace(/\u00a0/g, " ")
|
||||
.replace(/\u2424/g, "\n");
|
||||
|
||||
return this.token(src, true);
|
||||
};
|
||||
|
|
@ -126,7 +142,7 @@ Lexer.prototype.lex = function(src) {
|
|||
*/
|
||||
|
||||
Lexer.prototype.token = function(_src, top) {
|
||||
let src = _src.replace(/^ +$/gm, '');
|
||||
let src = _src.replace(/^ +$/gm, "");
|
||||
let next;
|
||||
let loose;
|
||||
let cap;
|
||||
|
|
@ -139,46 +155,44 @@ Lexer.prototype.token = function(_src, top) {
|
|||
|
||||
while (src) {
|
||||
// newline
|
||||
if (cap = this.rules.newline.exec(src)) {
|
||||
if ((cap = this.rules.newline.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
if (cap[0].length > 1) {
|
||||
this.tokens.push({
|
||||
type: 'space',
|
||||
type: "space"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// code
|
||||
if (cap = this.rules.code.exec(src)) {
|
||||
if ((cap = this.rules.code.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
cap = cap[0].replace(/^ {4}/gm, '');
|
||||
cap = cap[0].replace(/^ {4}/gm, "");
|
||||
this.tokens.push({
|
||||
type: 'code',
|
||||
text: !this.options.pedantic
|
||||
? cap.replace(/\n+$/, '')
|
||||
: cap,
|
||||
type: "code",
|
||||
text: !this.options.pedantic ? cap.replace(/\n+$/, "") : cap
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// fences (gfm)
|
||||
if (cap = this.rules.fences.exec(src)) {
|
||||
if ((cap = this.rules.fences.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'code',
|
||||
type: "code",
|
||||
lang: cap[2],
|
||||
text: cap[3],
|
||||
text: cap[3]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// heading
|
||||
if (cap = this.rules.heading.exec(src)) {
|
||||
if ((cap = this.rules.heading.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'heading',
|
||||
type: "heading",
|
||||
depth: cap[1].length,
|
||||
text: cap[2],
|
||||
text: cap[2]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
|
@ -188,19 +202,19 @@ Lexer.prototype.token = function(_src, top) {
|
|||
src = src.substring(cap[0].length);
|
||||
|
||||
item = {
|
||||
type: 'table',
|
||||
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
||||
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
||||
cells: cap[3].replace(/\n$/, '').split('\n'),
|
||||
type: "table",
|
||||
header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
|
||||
align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
|
||||
cells: cap[3].replace(/\n$/, "").split("\n")
|
||||
};
|
||||
|
||||
for (i = 0; i < item.align.length; i++) {
|
||||
if (/^ *-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'right';
|
||||
item.align[i] = "right";
|
||||
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'center';
|
||||
item.align[i] = "center";
|
||||
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
||||
item.align[i] = 'left';
|
||||
item.align[i] = "left";
|
||||
} else {
|
||||
item.align[i] = null;
|
||||
}
|
||||
|
|
@ -216,34 +230,34 @@ Lexer.prototype.token = function(_src, top) {
|
|||
}
|
||||
|
||||
// lheading
|
||||
if (cap = this.rules.lheading.exec(src)) {
|
||||
if ((cap = this.rules.lheading.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'heading',
|
||||
depth: cap[2] === '=' ? 1 : 2,
|
||||
text: cap[1],
|
||||
type: "heading",
|
||||
depth: cap[2] === "=" ? 1 : 2,
|
||||
text: cap[1]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// hr
|
||||
if (cap = this.rules.hr.exec(src)) {
|
||||
if ((cap = this.rules.hr.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'hr',
|
||||
type: "hr"
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// blockquote
|
||||
if (cap = this.rules.blockquote.exec(src)) {
|
||||
if ((cap = this.rules.blockquote.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
|
||||
this.tokens.push({
|
||||
type: 'blockquote_start',
|
||||
type: "blockquote_start"
|
||||
});
|
||||
|
||||
cap = cap[0].replace(/^ *> ?/gm, '');
|
||||
cap = cap[0].replace(/^ *> ?/gm, "");
|
||||
|
||||
// Pass `top` to keep the current
|
||||
// "toplevel" state. This is exactly
|
||||
|
|
@ -251,20 +265,20 @@ Lexer.prototype.token = function(_src, top) {
|
|||
this.token(cap, top);
|
||||
|
||||
this.tokens.push({
|
||||
type: 'blockquote_end',
|
||||
type: "blockquote_end"
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// list
|
||||
if (cap = this.rules.list.exec(src)) {
|
||||
if ((cap = this.rules.list.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
bull = cap[2];
|
||||
|
||||
this.tokens.push({
|
||||
type: 'list_start',
|
||||
ordered: bull.length > 1,
|
||||
type: "list_start",
|
||||
ordered: bull.length > 1
|
||||
});
|
||||
|
||||
// Get each top-level item.
|
||||
|
|
@ -280,15 +294,16 @@ Lexer.prototype.token = function(_src, top) {
|
|||
// Remove the list item's bullet
|
||||
// so it is seen as the next token.
|
||||
space = item.length;
|
||||
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
|
||||
item = item.replace(/^ *([*+-]|\d+\.) +/, "");
|
||||
|
||||
// Outdent whatever the
|
||||
// list item contains. Hacky.
|
||||
if (~item.indexOf('\n ')) { // eslint-disable-line
|
||||
if (~item.indexOf("\n ")) {
|
||||
// eslint-disable-line
|
||||
space -= item.length;
|
||||
item = !this.options.pedantic
|
||||
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
|
||||
: item.replace(/^ {1,4}/gm, '');
|
||||
? item.replace(new RegExp("^ {1," + space + "}", "gm"), "")
|
||||
: item.replace(/^ {1,4}/gm, "");
|
||||
}
|
||||
|
||||
// Determine whether the next list item belongs here.
|
||||
|
|
@ -296,7 +311,7 @@ Lexer.prototype.token = function(_src, top) {
|
|||
if (this.options.smartLists && i !== l - 1) {
|
||||
b = block.bullet.exec(cap[i + 1])[0];
|
||||
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
|
||||
src = cap.slice(i + 1).join('\n') + src;
|
||||
src = cap.slice(i + 1).join("\n") + src;
|
||||
i = l - 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -306,40 +321,38 @@ Lexer.prototype.token = function(_src, top) {
|
|||
// for discount behavior.
|
||||
loose = next || /\n\n(?!\s*$)/.test(item);
|
||||
if (i !== l - 1) {
|
||||
next = item[item.length - 1] === '\n';
|
||||
if (!loose) {loose = next;}
|
||||
next = item[item.length - 1] === "\n";
|
||||
if (!loose) {
|
||||
loose = next;
|
||||
}
|
||||
}
|
||||
|
||||
this.tokens.push({
|
||||
type: loose
|
||||
? 'loose_item_start'
|
||||
: 'list_item_start',
|
||||
type: loose ? "loose_item_start" : "list_item_start"
|
||||
});
|
||||
|
||||
// Recurse.
|
||||
this.token(item, false);
|
||||
|
||||
this.tokens.push({
|
||||
type: 'list_item_end',
|
||||
type: "list_item_end"
|
||||
});
|
||||
}
|
||||
|
||||
this.tokens.push({
|
||||
type: 'list_end',
|
||||
type: "list_end"
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// html
|
||||
if (cap = this.rules.html.exec(src)) {
|
||||
if ((cap = this.rules.html.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: this.options.sanitize
|
||||
? 'paragraph'
|
||||
: 'html',
|
||||
pre: cap[1] === 'pre' || cap[1] === 'script',
|
||||
text: cap[0],
|
||||
type: this.options.sanitize ? "paragraph" : "html",
|
||||
pre: cap[1] === "pre" || cap[1] === "script",
|
||||
text: cap[0]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
|
@ -349,7 +362,7 @@ Lexer.prototype.token = function(_src, top) {
|
|||
src = src.substring(cap[0].length);
|
||||
this.tokens.links[cap[1].toLowerCase()] = {
|
||||
href: cap[2],
|
||||
title: cap[3],
|
||||
title: cap[3]
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
|
@ -359,19 +372,19 @@ Lexer.prototype.token = function(_src, top) {
|
|||
src = src.substring(cap[0].length);
|
||||
|
||||
item = {
|
||||
type: 'table',
|
||||
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
||||
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
||||
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n'),
|
||||
type: "table",
|
||||
header: cap[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),
|
||||
align: cap[2].replace(/^ *|\| *$/g, "").split(/ *\| */),
|
||||
cells: cap[3].replace(/(?: *\| *)?\n$/, "").split("\n")
|
||||
};
|
||||
|
||||
for (i = 0; i < item.align.length; i++) {
|
||||
if (/^ *-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'right';
|
||||
item.align[i] = "right";
|
||||
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
||||
item.align[i] = 'center';
|
||||
item.align[i] = "center";
|
||||
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
||||
item.align[i] = 'left';
|
||||
item.align[i] = "left";
|
||||
} else {
|
||||
item.align[i] = null;
|
||||
}
|
||||
|
|
@ -379,7 +392,7 @@ Lexer.prototype.token = function(_src, top) {
|
|||
|
||||
for (i = 0; i < item.cells.length; i++) {
|
||||
item.cells[i] = item.cells[i]
|
||||
.replace(/^ *\| *| *\| *$/g, '')
|
||||
.replace(/^ *\| *| *\| *$/g, "")
|
||||
.split(/ *\| */);
|
||||
}
|
||||
|
||||
|
|
@ -392,28 +405,25 @@ Lexer.prototype.token = function(_src, top) {
|
|||
if (top && (cap = this.rules.paragraph.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'paragraph',
|
||||
text: cap[1][cap[1].length - 1] === '\n'
|
||||
? cap[1].slice(0, -1)
|
||||
: cap[1],
|
||||
type: "paragraph",
|
||||
text: cap[1][cap[1].length - 1] === "\n" ? cap[1].slice(0, -1) : cap[1]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// text
|
||||
if (cap = this.rules.text.exec(src)) {
|
||||
if ((cap = this.rules.text.exec(src))) {
|
||||
// Top-level should never reach here.
|
||||
src = src.substring(cap[0].length);
|
||||
this.tokens.push({
|
||||
type: 'text',
|
||||
text: cap[0],
|
||||
type: "text",
|
||||
text: cap[0]
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
throw new
|
||||
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
||||
throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -437,15 +447,18 @@ const inline = {
|
|||
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
|
||||
br: /^ {2,}\n(?!\s*$)/,
|
||||
del: noop,
|
||||
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/,
|
||||
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
|
||||
};
|
||||
|
||||
inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
|
||||
inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
|
||||
|
||||
inline.link = replace(inline.link)('inside', inline._inside)('href', inline._href)();
|
||||
inline.link = replace(inline.link)("inside", inline._inside)(
|
||||
"href",
|
||||
inline._href
|
||||
)();
|
||||
|
||||
inline.reflink = replace(inline.reflink)('inside', inline._inside)();
|
||||
inline.reflink = replace(inline.reflink)("inside", inline._inside)();
|
||||
|
||||
/**
|
||||
* Normal Inline Grammar
|
||||
|
|
@ -459,7 +472,7 @@ inline.normal = merge({}, inline);
|
|||
|
||||
inline.pedantic = merge({}, inline.normal, {
|
||||
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
|
||||
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
|
||||
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -467,10 +480,10 @@ inline.pedantic = merge({}, inline.normal, {
|
|||
*/
|
||||
|
||||
inline.gfm = merge({}, inline.normal, {
|
||||
escape: replace(inline.escape)('])', '~|])')(),
|
||||
escape: replace(inline.escape)("])", "~|])")(),
|
||||
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
|
||||
del: /^~~(?=\S)([\s\S]*?\S)~~/,
|
||||
text: replace(inline.text)(']|', '~]|')('|', '|https?://|')(),
|
||||
text: replace(inline.text)("]|", "~]|")("|", "|https?://|")()
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -478,8 +491,8 @@ inline.gfm = merge({}, inline.normal, {
|
|||
*/
|
||||
|
||||
inline.breaks = merge({}, inline.gfm, {
|
||||
br: replace(inline.br)('{2,}', '*')(),
|
||||
text: replace(inline.gfm.text)('{2,}', '*')(),
|
||||
br: replace(inline.br)("{2,}", "*")(),
|
||||
text: replace(inline.gfm.text)("{2,}", "*")()
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -492,8 +505,7 @@ function InlineLexer(links, options) {
|
|||
this.rules = inline.normal;
|
||||
|
||||
if (!this.links) {
|
||||
throw new
|
||||
Error('Tokens array requires a `links` property.');
|
||||
throw new Error("Tokens array requires a `links` property.");
|
||||
}
|
||||
|
||||
if (this.options.gfm) {
|
||||
|
|
@ -535,39 +547,37 @@ InlineLexer.prototype.output = function(src) {
|
|||
|
||||
while (src) {
|
||||
// escape
|
||||
if (cap = this.rules.escape.exec(src)) {
|
||||
if ((cap = this.rules.escape.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(cap[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// autolink
|
||||
if (cap = this.rules.autolink.exec(src)) {
|
||||
if ((cap = this.rules.autolink.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
if (cap[2] === '@') {
|
||||
text = cap[1][6] === ':'
|
||||
? cap[1].substring(7)
|
||||
: cap[1];
|
||||
href = 'mailto:' + text;
|
||||
if (cap[2] === "@") {
|
||||
text = cap[1][6] === ":" ? cap[1].substring(7) : cap[1];
|
||||
href = "mailto:" + text;
|
||||
} else {
|
||||
text = cap[1];
|
||||
href = text;
|
||||
}
|
||||
out.push(React.DOM.a({href: this.sanitizeUrl(href)}, text));
|
||||
out.push(React.DOM.a({ href: this.sanitizeUrl(href) }, text));
|
||||
continue;
|
||||
}
|
||||
|
||||
// url (gfm)
|
||||
if (cap = this.rules.url.exec(src)) {
|
||||
if ((cap = this.rules.url.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
text = cap[1];
|
||||
href = text;
|
||||
out.push(React.DOM.a({href: this.sanitizeUrl(href)}, text));
|
||||
out.push(React.DOM.a({ href: this.sanitizeUrl(href) }, text));
|
||||
continue;
|
||||
}
|
||||
|
||||
// tag
|
||||
if (cap = this.rules.tag.exec(src)) {
|
||||
if ((cap = this.rules.tag.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
// TODO(alpert): Don't escape if sanitize is false
|
||||
out.push(cap[0]);
|
||||
|
|
@ -575,20 +585,24 @@ InlineLexer.prototype.output = function(src) {
|
|||
}
|
||||
|
||||
// link
|
||||
if (cap = this.rules.link.exec(src)) {
|
||||
if ((cap = this.rules.link.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(this.outputLink(cap, {
|
||||
href: cap[2],
|
||||
title: cap[3],
|
||||
}));
|
||||
out.push(
|
||||
this.outputLink(cap, {
|
||||
href: cap[2],
|
||||
title: cap[3]
|
||||
})
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// reflink, nolink
|
||||
if ((cap = this.rules.reflink.exec(src))
|
||||
|| (cap = this.rules.nolink.exec(src))) {
|
||||
if (
|
||||
(cap = this.rules.reflink.exec(src)) ||
|
||||
(cap = this.rules.nolink.exec(src))
|
||||
) {
|
||||
src = src.substring(cap[0].length);
|
||||
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
|
||||
link = (cap[2] || cap[1]).replace(/\s+/g, " ");
|
||||
link = this.links[link.toLowerCase()];
|
||||
if (!link || !link.href) {
|
||||
out.push.apply(out, this.output(cap[0][0]));
|
||||
|
|
@ -600,50 +614,49 @@ InlineLexer.prototype.output = function(src) {
|
|||
}
|
||||
|
||||
// strong
|
||||
if (cap = this.rules.strong.exec(src)) {
|
||||
if ((cap = this.rules.strong.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(React.DOM.strong(null, this.output(cap[2] || cap[1])));
|
||||
continue;
|
||||
}
|
||||
|
||||
// em
|
||||
if (cap = this.rules.em.exec(src)) {
|
||||
if ((cap = this.rules.em.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(React.DOM.em(null, this.output(cap[2] || cap[1])));
|
||||
continue;
|
||||
}
|
||||
|
||||
// code
|
||||
if (cap = this.rules.code.exec(src)) {
|
||||
if ((cap = this.rules.code.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(React.DOM.code(null, cap[2]));
|
||||
continue;
|
||||
}
|
||||
|
||||
// br
|
||||
if (cap = this.rules.br.exec(src)) {
|
||||
if ((cap = this.rules.br.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(React.DOM.br(null, null));
|
||||
continue;
|
||||
}
|
||||
|
||||
// del (gfm)
|
||||
if (cap = this.rules.del.exec(src)) {
|
||||
if ((cap = this.rules.del.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(React.DOM.del(null, this.output(cap[1])));
|
||||
continue;
|
||||
}
|
||||
|
||||
// text
|
||||
if (cap = this.rules.text.exec(src)) {
|
||||
if ((cap = this.rules.text.exec(src))) {
|
||||
src = src.substring(cap[0].length);
|
||||
out.push(this.smartypants(cap[0]));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
throw new
|
||||
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
||||
throw new Error("Infinite loop on byte: " + src.charCodeAt(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -658,13 +671,14 @@ InlineLexer.prototype.sanitizeUrl = function(url) {
|
|||
if (this.options.sanitize) {
|
||||
try {
|
||||
const prot = decodeURIComponent(url)
|
||||
.replace(/[^A-Za-z0-9:]/g, '')
|
||||
.toLowerCase();
|
||||
if (prot.indexOf('javascript:') === 0) { // eslint-disable-line
|
||||
return '#';
|
||||
.replace(/[^A-Za-z0-9:]/g, "")
|
||||
.toLowerCase();
|
||||
if (prot.indexOf("javascript:") === 0) {
|
||||
// eslint-disable-line
|
||||
return "#";
|
||||
}
|
||||
} catch (e) {
|
||||
return '#';
|
||||
return "#";
|
||||
}
|
||||
}
|
||||
return url;
|
||||
|
|
@ -675,22 +689,27 @@ InlineLexer.prototype.sanitizeUrl = function(url) {
|
|||
*/
|
||||
|
||||
InlineLexer.prototype.outputLink = function(cap, link) {
|
||||
if (cap[0][0] !== '!') {
|
||||
if (cap[0][0] !== "!") {
|
||||
const shouldOpenInNewWindow =
|
||||
link.href.charAt(0) !== '/'
|
||||
&& link.href.charAt(0) !== '#';
|
||||
link.href.charAt(0) !== "/" && link.href.charAt(0) !== "#";
|
||||
|
||||
return React.DOM.a({
|
||||
href: this.sanitizeUrl(link.href),
|
||||
title: link.title,
|
||||
target: shouldOpenInNewWindow ? '_blank' : '',
|
||||
}, this.output(cap[1]));
|
||||
return React.DOM.a(
|
||||
{
|
||||
href: this.sanitizeUrl(link.href),
|
||||
title: link.title,
|
||||
target: shouldOpenInNewWindow ? "_blank" : ""
|
||||
},
|
||||
this.output(cap[1])
|
||||
);
|
||||
} else {
|
||||
return React.DOM.img({
|
||||
src: this.sanitizeUrl(link.href),
|
||||
alt: cap[1],
|
||||
title: link.title,
|
||||
}, null);
|
||||
return React.DOM.img(
|
||||
{
|
||||
src: this.sanitizeUrl(link.href),
|
||||
alt: cap[1],
|
||||
title: link.title
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -699,12 +718,14 @@ InlineLexer.prototype.outputLink = function(cap, link) {
|
|||
*/
|
||||
|
||||
InlineLexer.prototype.smartypants = function(text) {
|
||||
if (!this.options.smartypants) {return text;}
|
||||
if (!this.options.smartypants) {
|
||||
return text;
|
||||
}
|
||||
return text
|
||||
.replace(/--/g, '\u2014')
|
||||
.replace(/'([^']*)'/g, '\u2018$1\u2019')
|
||||
.replace(/"([^"]*)"/g, '\u201C$1\u201D')
|
||||
.replace(/\.{3}/g, '\u2026');
|
||||
.replace(/--/g, "\u2014")
|
||||
.replace(/'([^']*)'/g, "\u2018$1\u2019")
|
||||
.replace(/"([^"]*)"/g, "\u201C$1\u201D")
|
||||
.replace(/\.{3}/g, "\u2026");
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -747,7 +768,7 @@ Parser.prototype.parse = function(src) {
|
|||
*/
|
||||
|
||||
Parser.prototype.next = function() {
|
||||
return this.token = this.tokens.pop();
|
||||
return (this.token = this.tokens.pop());
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -765,8 +786,8 @@ Parser.prototype.peek = function() {
|
|||
Parser.prototype.parseText = function() {
|
||||
let body = this.token.text;
|
||||
|
||||
while (this.peek().type === 'text') {
|
||||
body += '\n' + this.next().text;
|
||||
while (this.peek().type === "text") {
|
||||
body += "\n" + this.next().text;
|
||||
}
|
||||
|
||||
return this.inline.output(body);
|
||||
|
|
@ -776,25 +797,30 @@ Parser.prototype.parseText = function() {
|
|||
* Parse Current Token
|
||||
*/
|
||||
|
||||
Parser.prototype.tok = function() { // eslint-disable-line
|
||||
Parser.prototype.tok = function() {
|
||||
// eslint-disable-line
|
||||
switch (this.token.type) {
|
||||
case 'space': {
|
||||
case "space": {
|
||||
return [];
|
||||
}
|
||||
case 'hr': {
|
||||
case "hr": {
|
||||
return React.DOM.hr(null, null);
|
||||
}
|
||||
case 'heading': {
|
||||
case "heading": {
|
||||
return (
|
||||
<Header level={this.token.depth} toSlug={this.token.text}>
|
||||
{this.inline.output(this.token.text)}
|
||||
</Header>
|
||||
);
|
||||
}
|
||||
case 'code': {
|
||||
return <Prism>{this.token.text}</Prism>;
|
||||
case "code": {
|
||||
return (
|
||||
<Prism>
|
||||
{this.token.text}
|
||||
</Prism>
|
||||
);
|
||||
}
|
||||
case 'table': {
|
||||
case "table": {
|
||||
const table = [];
|
||||
const body = [];
|
||||
let row = [];
|
||||
|
|
@ -806,12 +832,14 @@ Parser.prototype.tok = function() { // eslint-disable-line
|
|||
// header
|
||||
for (i = 0; i < this.token.header.length; i++) {
|
||||
heading = this.inline.output(this.token.header[i]);
|
||||
row.push(React.DOM.th(
|
||||
this.token.align[i]
|
||||
? {style: {textAlign: this.token.align[i]}}
|
||||
: null,
|
||||
heading
|
||||
));
|
||||
row.push(
|
||||
React.DOM.th(
|
||||
this.token.align[i]
|
||||
? { style: { textAlign: this.token.align[i] } }
|
||||
: null,
|
||||
heading
|
||||
)
|
||||
);
|
||||
}
|
||||
table.push(React.DOM.thead(null, React.DOM.tr(null, row)));
|
||||
|
||||
|
|
@ -820,12 +848,14 @@ Parser.prototype.tok = function() { // eslint-disable-line
|
|||
row = [];
|
||||
cells = this.token.cells[i];
|
||||
for (j = 0; j < cells.length; j++) {
|
||||
row.push(React.DOM.td(
|
||||
this.token.align[j]
|
||||
? {style: {textAlign: this.token.align[j]}}
|
||||
: null,
|
||||
this.inline.output(cells[j])
|
||||
));
|
||||
row.push(
|
||||
React.DOM.td(
|
||||
this.token.align[j]
|
||||
? { style: { textAlign: this.token.align[j] } }
|
||||
: null,
|
||||
this.inline.output(cells[j])
|
||||
)
|
||||
);
|
||||
}
|
||||
body.push(React.DOM.tr(null, row));
|
||||
}
|
||||
|
|
@ -833,58 +863,59 @@ Parser.prototype.tok = function() { // eslint-disable-line
|
|||
|
||||
return React.DOM.table(null, table);
|
||||
}
|
||||
case 'blockquote_start': {
|
||||
case "blockquote_start": {
|
||||
const body = [];
|
||||
|
||||
while (this.next().type !== 'blockquote_end') {
|
||||
while (this.next().type !== "blockquote_end") {
|
||||
body.push(this.tok());
|
||||
}
|
||||
|
||||
return React.DOM.blockquote(null, body);
|
||||
}
|
||||
case 'list_start': {
|
||||
const type = this.token.ordered ? 'ol' : 'ul';
|
||||
case "list_start": {
|
||||
const type = this.token.ordered ? "ol" : "ul";
|
||||
const body = [];
|
||||
|
||||
while (this.next().type !== 'list_end') {
|
||||
while (this.next().type !== "list_end") {
|
||||
body.push(this.tok());
|
||||
}
|
||||
|
||||
return React.DOM[type](null, body);
|
||||
}
|
||||
case 'list_item_start': {
|
||||
case "list_item_start": {
|
||||
const body = [];
|
||||
|
||||
while (this.next().type !== 'list_item_end') {
|
||||
body.push(this.token.type === 'text'
|
||||
? this.parseText()
|
||||
: this.tok());
|
||||
while (this.next().type !== "list_item_end") {
|
||||
body.push(this.token.type === "text" ? this.parseText() : this.tok());
|
||||
}
|
||||
|
||||
return React.DOM.li(null, body);
|
||||
}
|
||||
case 'loose_item_start': {
|
||||
case "loose_item_start": {
|
||||
const body = [];
|
||||
|
||||
while (this.next().type !== 'list_item_end') {
|
||||
while (this.next().type !== "list_item_end") {
|
||||
body.push(this.tok());
|
||||
}
|
||||
|
||||
return React.DOM.li(null, body);
|
||||
}
|
||||
case 'html': {
|
||||
case "html": {
|
||||
return React.DOM.div({
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: this.token.text,
|
||||
},
|
||||
__html: this.token.text
|
||||
}
|
||||
});
|
||||
}
|
||||
case 'paragraph': {
|
||||
case "paragraph": {
|
||||
return this.options.paragraphFn
|
||||
? this.options.paragraphFn.call(null, this.inline.output(this.token.text))
|
||||
? this.options.paragraphFn.call(
|
||||
null,
|
||||
this.inline.output(this.token.text)
|
||||
)
|
||||
: React.DOM.p(null, this.inline.output(this.token.text));
|
||||
}
|
||||
case 'text': {
|
||||
case "text": {
|
||||
return this.options.paragraphFn
|
||||
? this.options.paragraphFn.call(null, this.parseText())
|
||||
: React.DOM.p(null, this.parseText());
|
||||
|
|
@ -898,11 +929,13 @@ Parser.prototype.tok = function() { // eslint-disable-line
|
|||
|
||||
function replace(regex, opt) {
|
||||
regex = regex.source;
|
||||
opt = opt || '';
|
||||
opt = opt || "";
|
||||
return function self(name, val) {
|
||||
if (!name) {return new RegExp(regex, opt);}
|
||||
if (!name) {
|
||||
return new RegExp(regex, opt);
|
||||
}
|
||||
val = val.source || val;
|
||||
val = val.replace(/(^|[^\[])\^/g, '$1');
|
||||
val = val.replace(/(^|[^\[])\^/g, "$1");
|
||||
regex = regex.replace(name, val);
|
||||
return self;
|
||||
};
|
||||
|
|
@ -933,13 +966,15 @@ function merge(obj) {
|
|||
*/
|
||||
|
||||
function marked(src, opt, callback) {
|
||||
if (callback || typeof opt === 'function') {
|
||||
if (callback || typeof opt === "function") {
|
||||
if (!callback) {
|
||||
callback = opt;
|
||||
opt = null;
|
||||
}
|
||||
|
||||
if (opt) {opt = merge({}, marked.defaults, opt);}
|
||||
if (opt) {
|
||||
opt = merge({}, marked.defaults, opt);
|
||||
}
|
||||
|
||||
const highlight = opt.highlight;
|
||||
let tokens;
|
||||
|
|
@ -969,20 +1004,20 @@ function marked(src, opt, callback) {
|
|||
|
||||
opt.highlight = highlight;
|
||||
|
||||
return err
|
||||
? callback(err)
|
||||
: callback(null, out);
|
||||
return err ? callback(err) : callback(null, out);
|
||||
};
|
||||
|
||||
if (!highlight || highlight.length < 3) {
|
||||
return done(true);
|
||||
}
|
||||
|
||||
if (!pending) {return done();}
|
||||
if (!pending) {
|
||||
return done();
|
||||
}
|
||||
|
||||
for (; i < tokens.length; i++) {
|
||||
(function(token) {
|
||||
if (token.type !== 'code') {
|
||||
if (token.type !== "code") {
|
||||
return --pending || done();
|
||||
}
|
||||
return highlight(token.text, token.lang, (err, code) => {
|
||||
|
|
@ -1000,13 +1035,17 @@ function marked(src, opt, callback) {
|
|||
return undefined;
|
||||
}
|
||||
try {
|
||||
if (opt) {opt = merge({}, marked.defaults, opt);}
|
||||
if (opt) {
|
||||
opt = merge({}, marked.defaults, opt);
|
||||
}
|
||||
return Parser.parse(Lexer.lex(src, opt), opt);
|
||||
} catch (e) {
|
||||
e.message += '\nPlease report this to https://github.com/chjj/marked.';
|
||||
e.message += "\nPlease report this to https://github.com/chjj/marked.";
|
||||
if ((opt || marked.defaults).silent) {
|
||||
return [React.DOM.p(null, 'An error occurred:'),
|
||||
React.DOM.pre(null, e.message)];
|
||||
return [
|
||||
React.DOM.p(null, "An error occurred:"),
|
||||
React.DOM.pre(null, e.message)
|
||||
];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
|
@ -1016,8 +1055,7 @@ function marked(src, opt, callback) {
|
|||
* Options
|
||||
*/
|
||||
|
||||
marked.options =
|
||||
marked.setOptions = function(opt) {
|
||||
marked.options = marked.setOptions = function(opt) {
|
||||
merge(marked.defaults, opt);
|
||||
return marked;
|
||||
};
|
||||
|
|
@ -1031,9 +1069,9 @@ marked.defaults = {
|
|||
smartLists: false,
|
||||
silent: false,
|
||||
highlight: null,
|
||||
langPrefix: 'lang-',
|
||||
langPrefix: "lang-",
|
||||
smartypants: false,
|
||||
paragraphFn: null,
|
||||
paragraphFn: null
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1053,7 +1091,11 @@ marked.parse = marked;
|
|||
|
||||
class Marked extends React.Component {
|
||||
render() {
|
||||
return <div>{marked(this.props.children, this.props)}</div>;
|
||||
return (
|
||||
<div>
|
||||
{marked(this.props.children, this.props)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const unindent = require('./unindent.js');
|
||||
const React = require("react");
|
||||
const unindent = require("./unindent.js");
|
||||
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=markup+clike+javascript+jsx */
|
||||
/**
|
||||
|
|
@ -20,15 +20,22 @@ const unindent = require('./unindent.js');
|
|||
// Private helper vars
|
||||
const lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
|
||||
|
||||
const _ = Prism = {
|
||||
const _ = (Prism = {
|
||||
util: {
|
||||
encode(tokens) {
|
||||
if (tokens instanceof Token) {
|
||||
return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
|
||||
} else if (_.util.type(tokens) === 'Array') {
|
||||
return new Token(
|
||||
tokens.type,
|
||||
_.util.encode(tokens.content),
|
||||
tokens.alias
|
||||
);
|
||||
} else if (_.util.type(tokens) === "Array") {
|
||||
return tokens.map(_.util.encode);
|
||||
} else {
|
||||
return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' ');
|
||||
return tokens
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/\u00a0/g, " ");
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -41,7 +48,7 @@ const _ = Prism = {
|
|||
const type = _.util.type(o);
|
||||
|
||||
switch (type) {
|
||||
case 'Object':
|
||||
case "Object":
|
||||
var clone = {};
|
||||
|
||||
for (const key in o) {
|
||||
|
|
@ -52,13 +59,18 @@ const _ = Prism = {
|
|||
|
||||
return clone;
|
||||
|
||||
case 'Array':
|
||||
case "Array":
|
||||
// Check for existence for IE8
|
||||
return o.map && o.map(v => { return _.util.clone(v); });
|
||||
return (
|
||||
o.map &&
|
||||
o.map(v => {
|
||||
return _.util.clone(v);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return o;
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
languages: {
|
||||
|
|
@ -100,13 +112,9 @@ const _ = Prism = {
|
|||
const ret = {};
|
||||
|
||||
for (const token in grammar) {
|
||||
|
||||
if (grammar.hasOwnProperty(token)) {
|
||||
|
||||
if (token == before) {
|
||||
|
||||
for (var newToken in insert) {
|
||||
|
||||
if (insert.hasOwnProperty(newToken)) {
|
||||
ret[newToken] = insert[newToken];
|
||||
}
|
||||
|
|
@ -124,7 +132,7 @@ const _ = Prism = {
|
|||
}
|
||||
});
|
||||
|
||||
return root[inside] = ret;
|
||||
return (root[inside] = ret);
|
||||
},
|
||||
|
||||
// Traverse a language definition with Depth First Search
|
||||
|
|
@ -133,45 +141,55 @@ const _ = Prism = {
|
|||
if (o.hasOwnProperty(i)) {
|
||||
callback.call(o, i, o[i], type || i);
|
||||
|
||||
if (_.util.type(o[i]) === 'Object') {
|
||||
if (_.util.type(o[i]) === "Object") {
|
||||
_.languages.DFS(o[i], callback);
|
||||
} else if (_.util.type(o[i]) === 'Array') {
|
||||
} else if (_.util.type(o[i]) === "Array") {
|
||||
_.languages.DFS(o[i], callback, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
highlightAll(async, callback) {
|
||||
const elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');
|
||||
const elements = document.querySelectorAll(
|
||||
'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
|
||||
);
|
||||
|
||||
for (let i = 0, element; element = elements[i++];) {
|
||||
for (let i = 0, element; (element = elements[i++]); ) {
|
||||
_.highlightElement(element, async === true, callback);
|
||||
}
|
||||
},
|
||||
|
||||
highlightElement(element, async, callback) {
|
||||
// Find language
|
||||
let language, grammar, parent = element;
|
||||
let language,
|
||||
grammar,
|
||||
parent = element;
|
||||
|
||||
while (parent && !lang.test(parent.className)) {
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
language = (parent.className.match(lang) || [, ''])[1];
|
||||
language = (parent.className.match(lang) || [, ""])[1];
|
||||
grammar = _.languages[language];
|
||||
}
|
||||
|
||||
// Set language on the element, if not present
|
||||
element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
|
||||
element.className =
|
||||
element.className.replace(lang, "").replace(/\s+/g, " ") +
|
||||
" language-" +
|
||||
language;
|
||||
|
||||
// Set language on the parent, for styling
|
||||
parent = element.parentNode;
|
||||
|
||||
if (/pre/i.test(parent.nodeName)) {
|
||||
parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
|
||||
parent.className =
|
||||
parent.className.replace(lang, "").replace(/\s+/g, " ") +
|
||||
" language-" +
|
||||
language;
|
||||
}
|
||||
|
||||
if (!grammar) {
|
||||
|
|
@ -184,16 +202,16 @@ const _ = Prism = {
|
|||
return;
|
||||
}
|
||||
|
||||
code = code.replace(/^(?:\r?\n|\r)/, '');
|
||||
code = code.replace(/^(?:\r?\n|\r)/, "");
|
||||
|
||||
const env = {
|
||||
element,
|
||||
language,
|
||||
grammar,
|
||||
code,
|
||||
code
|
||||
};
|
||||
|
||||
_.hooks.run('before-highlight', env);
|
||||
_.hooks.run("before-highlight", env);
|
||||
|
||||
if (async && _self.Worker) {
|
||||
const worker = new Worker(_.filename);
|
||||
|
|
@ -201,28 +219,30 @@ const _ = Prism = {
|
|||
worker.onmessage = function(evt) {
|
||||
env.highlightedCode = Token.stringify(JSON.parse(evt.data), language);
|
||||
|
||||
_.hooks.run('before-insert', env);
|
||||
_.hooks.run("before-insert", env);
|
||||
|
||||
env.element.innerHTML = env.highlightedCode;
|
||||
|
||||
callback && callback.call(env.element);
|
||||
_.hooks.run('after-highlight', env);
|
||||
_.hooks.run("after-highlight", env);
|
||||
};
|
||||
|
||||
worker.postMessage(JSON.stringify({
|
||||
language: env.language,
|
||||
code: env.code,
|
||||
}));
|
||||
} else {
|
||||
worker.postMessage(
|
||||
JSON.stringify({
|
||||
language: env.language,
|
||||
code: env.code
|
||||
})
|
||||
);
|
||||
} else {
|
||||
env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
|
||||
|
||||
_.hooks.run('before-insert', env);
|
||||
_.hooks.run("before-insert", env);
|
||||
|
||||
env.element.innerHTML = env.highlightedCode;
|
||||
|
||||
callback && callback.call(element);
|
||||
|
||||
_.hooks.run('after-highlight', env);
|
||||
_.hooks.run("after-highlight", env);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -252,7 +272,7 @@ const _ = Prism = {
|
|||
}
|
||||
|
||||
let patterns = grammar[token];
|
||||
patterns = (_.util.type(patterns) === 'Array') ? patterns : [patterns];
|
||||
patterns = _.util.type(patterns) === "Array" ? patterns : [patterns];
|
||||
|
||||
for (let j = 0; j < patterns.length; ++j) {
|
||||
let pattern = patterns[j],
|
||||
|
|
@ -263,7 +283,8 @@ const _ = Prism = {
|
|||
|
||||
pattern = pattern.pattern || pattern;
|
||||
|
||||
for (let i = 0; i < strarr.length; i++) { // Don't cache length as it changes during the loop
|
||||
for (let i = 0; i < strarr.length; i++) {
|
||||
// Don't cache length as it changes during the loop
|
||||
|
||||
const str = strarr[i];
|
||||
|
||||
|
|
@ -298,7 +319,11 @@ const _ = Prism = {
|
|||
args.push(before);
|
||||
}
|
||||
|
||||
const wrapped = new Token(token, inside ? _.tokenize(match, inside) : match, alias);
|
||||
const wrapped = new Token(
|
||||
token,
|
||||
inside ? _.tokenize(match, inside) : match,
|
||||
alias
|
||||
);
|
||||
|
||||
args.push(wrapped);
|
||||
|
||||
|
|
@ -333,25 +358,25 @@ const _ = Prism = {
|
|||
return;
|
||||
}
|
||||
|
||||
for (let i = 0, callback; callback = callbacks[i++];) {
|
||||
for (let i = 0, callback; (callback = callbacks[i++]); ) {
|
||||
callback(env);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const Token = _.Token = function(type, content, alias) {
|
||||
const Token = (_.Token = function(type, content, alias) {
|
||||
this.type = type;
|
||||
this.content = content;
|
||||
this.alias = alias;
|
||||
};
|
||||
});
|
||||
|
||||
Token.reactify = function(o, language, parent, key) {
|
||||
if (typeof o == 'string') {
|
||||
if (typeof o == "string") {
|
||||
return o;
|
||||
}
|
||||
|
||||
if (_.util.type(o) === 'Array') {
|
||||
if (_.util.type(o) === "Array") {
|
||||
return o.map((element, i) => {
|
||||
return Token.reactify(element, language, o, i);
|
||||
});
|
||||
|
|
@ -360,183 +385,186 @@ Token.reactify = function(o, language, parent, key) {
|
|||
const env = {
|
||||
type: o.type,
|
||||
content: Token.reactify(o.content, language, parent),
|
||||
tag: 'span',
|
||||
classes: ['token', o.type],
|
||||
attributes: {key},
|
||||
tag: "span",
|
||||
classes: ["token", o.type],
|
||||
attributes: { key },
|
||||
language,
|
||||
parent,
|
||||
parent
|
||||
};
|
||||
|
||||
if (env.type == 'comment') {
|
||||
if (env.type == "comment") {
|
||||
env.attributes.spellCheck = true;
|
||||
}
|
||||
|
||||
if (o.alias) {
|
||||
const aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
|
||||
const aliases = _.util.type(o.alias) === "Array" ? o.alias : [o.alias];
|
||||
Array.prototype.push.apply(env.classes, aliases);
|
||||
}
|
||||
|
||||
_.hooks.run('wrap', env);
|
||||
_.hooks.run("wrap", env);
|
||||
|
||||
env.attributes.className = env.classes.join(' ');
|
||||
env.attributes.className = env.classes.join(" ");
|
||||
|
||||
return React.DOM[env.tag](env.attributes, env.content);
|
||||
};
|
||||
|
||||
Prism.languages.markup = {
|
||||
'comment': /<!--[\w\W]*?-->/,
|
||||
'prolog': /<\?[\w\W]+?\?>/,
|
||||
'doctype': /<!DOCTYPE[\w\W]+?>/,
|
||||
'cdata': /<!\[CDATA\[[\w\W]*?]]>/i,
|
||||
'tag': {
|
||||
comment: /<!--[\w\W]*?-->/,
|
||||
prolog: /<\?[\w\W]+?\?>/,
|
||||
doctype: /<!DOCTYPE[\w\W]+?>/,
|
||||
cdata: /<!\[CDATA\[[\w\W]*?]]>/i,
|
||||
tag: {
|
||||
pattern: /<\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,
|
||||
inside: {
|
||||
'tag': {
|
||||
tag: {
|
||||
pattern: /^<\/?[^\s>\/]+/i,
|
||||
inside: {
|
||||
'punctuation': /^<\/?/,
|
||||
'namespace': /^[^\s>\/:]+:/,
|
||||
},
|
||||
punctuation: /^<\/?/,
|
||||
namespace: /^[^\s>\/:]+:/
|
||||
}
|
||||
},
|
||||
'attr-value': {
|
||||
"attr-value": {
|
||||
pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,
|
||||
inside: {
|
||||
'punctuation': /[=>"']/,
|
||||
},
|
||||
punctuation: /[=>"']/
|
||||
}
|
||||
},
|
||||
'punctuation': /\/?>/,
|
||||
'attr-name': {
|
||||
punctuation: /\/?>/,
|
||||
"attr-name": {
|
||||
pattern: /[^\s>\/]+/,
|
||||
inside: {
|
||||
'namespace': /^[^\s>\/:]+:/,
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
namespace: /^[^\s>\/:]+:/
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': /&#?[\da-z]{1,8};/i,
|
||||
entity: /&#?[\da-z]{1,8};/i
|
||||
};
|
||||
|
||||
// Plugin to make entity title show the real entity, idea by Roman Komarov
|
||||
Prism.hooks.add('wrap', env => {
|
||||
|
||||
if (env.type === 'entity') {
|
||||
env.attributes['title'] = env.content.replace(/&/, '&');
|
||||
Prism.hooks.add("wrap", env => {
|
||||
if (env.type === "entity") {
|
||||
env.attributes["title"] = env.content.replace(/&/, "&");
|
||||
}
|
||||
});
|
||||
|
||||
Prism.languages.clike = {
|
||||
'comment': [
|
||||
comment: [
|
||||
{
|
||||
pattern: /(^|[^\\])\/\*[\w\W]*?\*\//,
|
||||
lookbehind: true,
|
||||
lookbehind: true
|
||||
},
|
||||
{
|
||||
pattern: /(^|[^\\:])\/\/.*/,
|
||||
lookbehind: true,
|
||||
},
|
||||
lookbehind: true
|
||||
}
|
||||
],
|
||||
'string': /("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
|
||||
'class-name': {
|
||||
string: /("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
|
||||
"class-name": {
|
||||
pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,
|
||||
lookbehind: true,
|
||||
inside: {
|
||||
punctuation: /(\.|\\)/,
|
||||
},
|
||||
punctuation: /(\.|\\)/
|
||||
}
|
||||
},
|
||||
'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
|
||||
'boolean': /\b(true|false)\b/,
|
||||
'function': /[a-z0-9_]+(?=\()/i,
|
||||
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,
|
||||
'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,
|
||||
'punctuation': /[{}[\];(),.:]/,
|
||||
keyword: /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
|
||||
boolean: /\b(true|false)\b/,
|
||||
function: /[a-z0-9_]+(?=\()/i,
|
||||
number: /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,
|
||||
operator: /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,
|
||||
punctuation: /[{}[\];(),.:]/
|
||||
};
|
||||
|
||||
Prism.languages.javascript = Prism.languages.extend('clike', {
|
||||
'keyword': /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,
|
||||
'number': /\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,
|
||||
'function': /(?!\d)[a-z0-9_$]+(?=\()/i,
|
||||
Prism.languages.javascript = Prism.languages.extend("clike", {
|
||||
keyword: /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,
|
||||
number: /\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,
|
||||
function: /(?!\d)[a-z0-9_$]+(?=\()/i
|
||||
});
|
||||
|
||||
Prism.languages.insertBefore('javascript', 'keyword', {
|
||||
'regex': {
|
||||
Prism.languages.insertBefore("javascript", "keyword", {
|
||||
regex: {
|
||||
pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,
|
||||
lookbehind: true,
|
||||
},
|
||||
lookbehind: true
|
||||
}
|
||||
});
|
||||
|
||||
Prism.languages.insertBefore('javascript', 'class-name', {
|
||||
'template-string': {
|
||||
Prism.languages.insertBefore("javascript", "class-name", {
|
||||
"template-string": {
|
||||
pattern: /`(?:\\`|\\?[^`])*`/,
|
||||
inside: {
|
||||
'interpolation': {
|
||||
interpolation: {
|
||||
pattern: /\$\{[^}]+\}/,
|
||||
inside: {
|
||||
'interpolation-punctuation': {
|
||||
"interpolation-punctuation": {
|
||||
pattern: /^\$\{|\}$/,
|
||||
alias: 'punctuation',
|
||||
alias: "punctuation"
|
||||
},
|
||||
rest: Prism.languages.javascript,
|
||||
},
|
||||
rest: Prism.languages.javascript
|
||||
}
|
||||
},
|
||||
'string': /[\s\S]+/,
|
||||
},
|
||||
},
|
||||
string: /[\s\S]+/
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (Prism.languages.markup) {
|
||||
Prism.languages.insertBefore('markup', 'tag', {
|
||||
'script': {
|
||||
Prism.languages.insertBefore("markup", "tag", {
|
||||
script: {
|
||||
pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/i,
|
||||
inside: {
|
||||
'tag': {
|
||||
tag: {
|
||||
pattern: /<script[\w\W]*?>|<\/script>/i,
|
||||
inside: Prism.languages.markup.tag.inside,
|
||||
inside: Prism.languages.markup.tag.inside
|
||||
},
|
||||
rest: Prism.languages.javascript,
|
||||
rest: Prism.languages.javascript
|
||||
},
|
||||
alias: 'language-javascript',
|
||||
},
|
||||
alias: "language-javascript"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
(function(Prism) {
|
||||
|
||||
const javascript = Prism.util.clone(Prism.languages.javascript);
|
||||
|
||||
Prism.languages.jsx = Prism.languages.extend('markup', javascript);
|
||||
Prism.languages.jsx = Prism.languages.extend("markup", javascript);
|
||||
Prism.languages.jsx.tag.pattern = /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+|(\{[\w\W]*?\})))?\s*)*\/?>/i;
|
||||
|
||||
Prism.languages.jsx.tag.inside['attr-value'].pattern = /=[^\{](?:('|")[\w\W]*?(\1)|[^\s>]+)/i;
|
||||
Prism.languages.jsx.tag.inside[
|
||||
"attr-value"
|
||||
].pattern = /=[^\{](?:('|")[\w\W]*?(\1)|[^\s>]+)/i;
|
||||
|
||||
Prism.languages.insertBefore('inside', 'attr-value', {
|
||||
'script': {
|
||||
pattern: /=(\{[\w\W]*?\})/i,
|
||||
inside: {
|
||||
'function' : Prism.languages.javascript.function,
|
||||
'punctuation': /[={}[\];(),.:]/,
|
||||
'keyword': Prism.languages.javascript.keyword,
|
||||
},
|
||||
'alias': 'language-javascript',
|
||||
Prism.languages.insertBefore(
|
||||
"inside",
|
||||
"attr-value",
|
||||
{
|
||||
script: {
|
||||
pattern: /=(\{[\w\W]*?\})/i,
|
||||
inside: {
|
||||
function: Prism.languages.javascript.function,
|
||||
punctuation: /[={}[\];(),.:]/,
|
||||
keyword: Prism.languages.javascript.keyword
|
||||
},
|
||||
alias: "language-javascript"
|
||||
}
|
||||
},
|
||||
}, Prism.languages.jsx.tag);
|
||||
|
||||
}(Prism));
|
||||
Prism.languages.jsx.tag
|
||||
);
|
||||
})(Prism);
|
||||
|
||||
const PrismComponent = React.createClass({
|
||||
statics: {
|
||||
_,
|
||||
_
|
||||
},
|
||||
getDefaultProps() {
|
||||
return {
|
||||
language: 'javascript',
|
||||
language: "javascript"
|
||||
};
|
||||
},
|
||||
render() {
|
||||
const lines = [];
|
||||
if (this.props.line) {
|
||||
this.props.line.split(',').forEach(range => {
|
||||
const parts = range.split('-');
|
||||
this.props.line.split(",").forEach(range => {
|
||||
const parts = range.split("-");
|
||||
if (parts.length === 1) {
|
||||
lines.push(parts[0].trim());
|
||||
} else {
|
||||
|
|
@ -550,20 +578,20 @@ const PrismComponent = React.createClass({
|
|||
}
|
||||
const grammar = _.languages[this.props.language];
|
||||
return (
|
||||
<pre className={'prism language-' + this.props.language}>
|
||||
<pre className={"prism language-" + this.props.language}>
|
||||
{Token.reactify(_.tokenize(this.props.children, grammar))}
|
||||
{lines.map((line, ii) => {
|
||||
return (
|
||||
<div
|
||||
className="line-highlight"
|
||||
key={ii}
|
||||
style={{height: 20, top: 20 * (line - 1)}}
|
||||
style={{ height: 20, top: 20 * (line - 1) }}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</pre>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = PrismComponent;
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const HeaderNav = require('./nav/HeaderNav.js');
|
||||
const Head = require('./Head.js');
|
||||
const Footer = require(process.cwd() + '/core/Footer.js');
|
||||
const React = require("react");
|
||||
const HeaderNav = require("./nav/HeaderNav.js");
|
||||
const Head = require("./Head.js");
|
||||
const Footer = require(process.cwd() + "/core/Footer.js");
|
||||
const translation = require("../server/translation.js");
|
||||
|
||||
class Site extends React.Component {
|
||||
/*
|
||||
|
|
@ -48,18 +49,26 @@ class Site extends React.Component {
|
|||
*/
|
||||
|
||||
render() {
|
||||
const tagline = this.props.config[this.props.language] ? this.props.config[this.props.language].tagline : this.props.config.tagline;
|
||||
const tagline = translation[this.props.language]
|
||||
? translation[this.props.language]["localized-strings"].tagline
|
||||
: this.props.config.tagline;
|
||||
const title = this.props.title
|
||||
? this.props.title + ' · ' + this.props.config.title
|
||||
: this.props.config.title + ' · ' + tagline;
|
||||
const description =
|
||||
this.props.description || tagline;
|
||||
? this.props.title + " · " + this.props.config.title
|
||||
: this.props.config.title + " · " + tagline;
|
||||
const description = this.props.description || tagline;
|
||||
const url =
|
||||
this.props.config.url + this.props.config.baseUrl + (this.props.url || 'index.html');
|
||||
this.props.config.url +
|
||||
this.props.config.baseUrl +
|
||||
(this.props.url || "index.html");
|
||||
|
||||
return (
|
||||
<html>
|
||||
<Head config={this.props.config} description={description} title={title} url={url} />
|
||||
<Head
|
||||
config={this.props.config}
|
||||
description={description}
|
||||
title={title}
|
||||
url={url}
|
||||
/>
|
||||
<body className={this.props.className}>
|
||||
<HeaderNav
|
||||
config={this.props.config}
|
||||
|
|
@ -76,8 +85,7 @@ class Site extends React.Component {
|
|||
<script
|
||||
type="text/javascript"
|
||||
src="//cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
{this.props.config.gaTrackingId &&
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
|
|
@ -87,25 +95,23 @@ class Site extends React.Component {
|
|||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', '` + this.props.config.gaTrackingId + `', 'auto');
|
||||
ga('create', '${this.props.config.gaTrackingId}', 'auto');
|
||||
ga('send', 'pageview');
|
||||
`,
|
||||
`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
{this.props.config.algolia &&
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
var search = docsearch({
|
||||
apiKey: '` + this.props.config.algolia.apiKey + `',
|
||||
indexName: '` + this.props.config.algolia.indexName + `',
|
||||
apiKey: '${this.props.config.algolia.apiKey}',
|
||||
indexName: '${this.props.config.algolia.indexName}',
|
||||
inputSelector: '#search_input_react'
|
||||
});
|
||||
`,
|
||||
`
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,16 +7,17 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const React = require("react");
|
||||
|
||||
const siteConfig = require(process.cwd() + '/siteConfig.js');
|
||||
const siteConfig = require(process.cwd() + "/siteConfig.js");
|
||||
const translation = require("../../server/translation.js");
|
||||
|
||||
class LanguageDropDown extends React.Component {
|
||||
render() {
|
||||
const enabledLanguages = [];
|
||||
let currentLanguage = 'English';
|
||||
let currentLanguage = "English";
|
||||
|
||||
siteConfig['languages'].map(lang => {
|
||||
translation["languages"].map(lang => {
|
||||
if (lang.tag == this.props.language) {
|
||||
currentLanguage = lang.name;
|
||||
}
|
||||
|
|
@ -48,7 +49,7 @@ class LanguageDropDown extends React.Component {
|
|||
<a id="languages-menu" href="#">
|
||||
<img
|
||||
className="languages-icon"
|
||||
src={this.props.baseUrl + 'img/language.svg'}
|
||||
src={this.props.baseUrl + "img/language.svg"}
|
||||
/>
|
||||
{currentLanguage}
|
||||
</a>
|
||||
|
|
@ -70,7 +71,7 @@ class LanguageDropDown extends React.Component {
|
|||
languagesDropDown.className = "hide";
|
||||
}
|
||||
});
|
||||
`,
|
||||
`
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
|
|
@ -82,21 +83,24 @@ class HeaderNav extends React.Component {
|
|||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
slideoutActive: false,
|
||||
slideoutActive: false
|
||||
};
|
||||
}
|
||||
|
||||
makeLinks(link) {
|
||||
const linkWithLang = link.href.replace(
|
||||
/\/LANGUAGE\//,
|
||||
'\/' + this.props.language + '\/'
|
||||
"/" + this.props.language + "/"
|
||||
);
|
||||
return (
|
||||
<li key={link.section}>
|
||||
<a
|
||||
href={linkWithLang}
|
||||
className={link.section === this.props.section ? 'active' : ''}>
|
||||
{siteConfig[this.props.language] ? siteConfig[this.props.language]['localized-strings'][link.text] : link.text}
|
||||
className={link.section === this.props.section ? "active" : ""}
|
||||
>
|
||||
{translation[this.props.language]
|
||||
? translation[this.props.language]["localized-strings"][link.text]
|
||||
: link.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
|
|
@ -109,7 +113,9 @@ class HeaderNav extends React.Component {
|
|||
<header>
|
||||
<a href={this.props.baseUrl}>
|
||||
<img src={this.props.baseUrl + siteConfig.headerIcon} />
|
||||
<h2>{this.props.title}</h2>
|
||||
<h2>
|
||||
{this.props.title}
|
||||
</h2>
|
||||
</a>
|
||||
{this.renderResponsiveNav()}
|
||||
</header>
|
||||
|
|
@ -130,9 +136,12 @@ class HeaderNav extends React.Component {
|
|||
/>
|
||||
{this.props.config.algolia &&
|
||||
<li className="navSearchWrapper reactNavSearchWrapper">
|
||||
<input id="search_input_react" type="text" placeholder="Search" />
|
||||
</li>
|
||||
}
|
||||
<input
|
||||
id="search_input_react"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
/>
|
||||
</li>}
|
||||
{this.props.config.headerLinksExternal.map(this.makeLinks, this)}
|
||||
</ul>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const React = require('react');
|
||||
const classNames = require('classnames');
|
||||
const React = require("react");
|
||||
const classNames = require("classnames");
|
||||
|
||||
const siteConfig = require(process.cwd() + '/siteConfig.js');
|
||||
const siteConfig = require(process.cwd() + "/siteConfig.js");
|
||||
const translation = require("../../server/translation.js");
|
||||
|
||||
class SideNav extends React.Component {
|
||||
render() {
|
||||
|
|
@ -19,10 +20,14 @@ class SideNav extends React.Component {
|
|||
<div className="toggleNav">
|
||||
<section className="navWrapper wrapper">
|
||||
<div className="navBreadcrumb wrapper">
|
||||
<div className="navToggle" id="navToggler"><i /></div>
|
||||
<div className="navToggle" id="navToggler">
|
||||
<i />
|
||||
</div>
|
||||
<h2>
|
||||
<i>›</i>
|
||||
<span>{this.props.current.category}</span>
|
||||
<span>
|
||||
{this.props.current.category}
|
||||
</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="navGroups">
|
||||
|
|
@ -38,7 +43,7 @@ class SideNav extends React.Component {
|
|||
toggler.onclick = function() {
|
||||
nav.classList.toggle('docsSliderActive');
|
||||
};
|
||||
`,
|
||||
`
|
||||
}}
|
||||
/>
|
||||
</nav>
|
||||
|
|
@ -47,7 +52,9 @@ class SideNav extends React.Component {
|
|||
renderCategory(category) {
|
||||
return (
|
||||
<div className="navGroup navGroupActive" key={category.name}>
|
||||
<h3>{this.getLocalizedCategoryString(category.name)}</h3>
|
||||
<h3>
|
||||
{this.getLocalizedCategoryString(category.name)}
|
||||
</h3>
|
||||
<ul>
|
||||
{category.links.map(this.renderItemLink, this)}
|
||||
</ul>
|
||||
|
|
@ -55,16 +62,17 @@ class SideNav extends React.Component {
|
|||
);
|
||||
}
|
||||
getLocalizedCategoryString(category) {
|
||||
let categoryString =
|
||||
siteConfig[this.props.language] ?
|
||||
siteConfig[this.props.language]['localized-strings'][category] || category
|
||||
let categoryString = translation[this.props.language]
|
||||
? translation[this.props.language]["localized-strings"][category] ||
|
||||
category
|
||||
: category;
|
||||
return categoryString;
|
||||
}
|
||||
getLocalizedString(metadata) {
|
||||
let localizedString =
|
||||
siteConfig[this.props.language] ?
|
||||
siteConfig[this.props.language]['localized-strings'][metadata.localized_id] || metadata.title
|
||||
let localizedString = translation[this.props.language]
|
||||
? translation[this.props.language]["localized-strings"][
|
||||
metadata.localized_id
|
||||
] || metadata.title
|
||||
: metadata.title;
|
||||
|
||||
return localizedString;
|
||||
|
|
@ -74,19 +82,19 @@ class SideNav extends React.Component {
|
|||
if (metadata.permalink.match(/^https?:/)) {
|
||||
return metadata.permalink;
|
||||
}
|
||||
return siteConfig.baseUrl + metadata.permalink + '#content';
|
||||
return siteConfig.baseUrl + metadata.permalink + "#content";
|
||||
}
|
||||
if (metadata.path) {
|
||||
return siteConfig.baseUrl + 'blog/' + metadata.path;
|
||||
return siteConfig.baseUrl + "blog/" + metadata.path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
renderItemLink(link) {
|
||||
const itemClasses = classNames('navListItem', {
|
||||
navListItemActive: link.id === this.props.current.id,
|
||||
const itemClasses = classNames("navListItem", {
|
||||
navListItemActive: link.id === this.props.current.id
|
||||
});
|
||||
const linkClasses = classNames('navItem', {
|
||||
navItemActive: link.id === this.props.current.id,
|
||||
const linkClasses = classNames("navItem", {
|
||||
navItemActive: link.id === this.props.current.id
|
||||
});
|
||||
return (
|
||||
<li className={itemClasses} key={link.id}>
|
||||
|
|
@ -98,6 +106,6 @@ class SideNav extends React.Component {
|
|||
}
|
||||
}
|
||||
SideNav.defaultProps = {
|
||||
contents: [],
|
||||
contents: []
|
||||
};
|
||||
module.exports = SideNav;
|
||||
|
|
|
|||
|
|
@ -9,39 +9,34 @@
|
|||
|
||||
module.exports = string => {
|
||||
// var accents = "àáäâèéëêìíïîòóöôùúüûñç";
|
||||
const accents = '\u00e0\u00e1\u00e4\u00e2\u00e8'
|
||||
+ '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef'
|
||||
+ '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9'
|
||||
+ '\u00fa\u00fc\u00fb\u00f1\u00e7';
|
||||
const accents =
|
||||
"\u00e0\u00e1\u00e4\u00e2\u00e8" +
|
||||
"\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef" +
|
||||
"\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9" +
|
||||
"\u00fa\u00fc\u00fb\u00f1\u00e7";
|
||||
|
||||
const without = 'aaaaeeeeiiiioooouuuunc';
|
||||
const without = "aaaaeeeeiiiioooouuuunc";
|
||||
|
||||
let slug = string
|
||||
.toString()
|
||||
|
||||
// Handle uppercase characters
|
||||
.toLowerCase()
|
||||
|
||||
// Handle accentuated characters
|
||||
.replace(
|
||||
new RegExp('[' + accents + ']', 'g'),
|
||||
c => { return without.charAt(accents.indexOf(c)); })
|
||||
|
||||
.replace(new RegExp("[" + accents + "]", "g"), c => {
|
||||
return without.charAt(accents.indexOf(c));
|
||||
})
|
||||
// Replace `.`, `(` and `?` with blank string like Github does
|
||||
.replace(/\.|\(|\?/g, '')
|
||||
|
||||
.replace(/\.|\(|\?/g, "")
|
||||
// Dash special characters
|
||||
.replace(/[^a-z0-9]/g, '-')
|
||||
|
||||
.replace(/[^a-z0-9]/g, "-")
|
||||
// Compress multiple dash
|
||||
.replace(/-+/g, '-')
|
||||
|
||||
.replace(/-+/g, "-")
|
||||
// Trim dashes
|
||||
.replace(/^-|-$/g, '');
|
||||
.replace(/^-|-$/g, "");
|
||||
|
||||
// Add trailing `-` if string contains ` ...` in the end like Github does
|
||||
if (/\s[.]{1,}/.test(string)) {
|
||||
slug += '-';
|
||||
slug += "-";
|
||||
}
|
||||
|
||||
return slug;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
// Remove the indentation introduced by JSX
|
||||
function unindent(code) {
|
||||
const lines = code.split('\n');
|
||||
if (lines[0] === '') {
|
||||
const lines = code.split("\n");
|
||||
if (lines[0] === "") {
|
||||
lines.shift();
|
||||
}
|
||||
if (lines.length <= 1) {
|
||||
|
|
@ -19,9 +19,9 @@ function unindent(code) {
|
|||
|
||||
const indent = lines[0].match(/^\s*/)[0];
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
lines[i] = lines[i].replace(new RegExp('^' + indent), '');
|
||||
lines[i] = lines[i].replace(new RegExp("^" + indent), "");
|
||||
}
|
||||
return lines.join('\n');
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
module.exports = unindent;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const shell = require('shelljs');
|
||||
const shell = require("shelljs");
|
||||
|
||||
const GIT_USER = process.env.GIT_USER;
|
||||
const CIRCLE_BRANCH = process.env.CIRCLE_BRANCH;
|
||||
|
|
@ -18,54 +18,64 @@ const CIRCLE_PROJECT_REPONAME = process.env.CIRCLE_PROJECT_REPONAME;
|
|||
const CI_PULL_REQUEST = process.env.CI_PULL_REQUEST;
|
||||
const remoteBranch = `https://${GIT_USER}@github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}.git`;
|
||||
|
||||
|
||||
if (!shell.which('git')) {
|
||||
shell.echo('Sorry, this script requires git');
|
||||
if (!shell.which("git")) {
|
||||
shell.echo("Sorry, this script requires git");
|
||||
shell.exit(1);
|
||||
}
|
||||
|
||||
if (CI_PULL_REQUEST || CIRCLE_BRANCH !== `master`) {
|
||||
shell.echo('Skipping deploy');
|
||||
shell.echo("Skipping deploy");
|
||||
shell.exit(0);
|
||||
}
|
||||
|
||||
if (shell.exec('docusaurus-build').code) {
|
||||
shell.echo('Error: generating html failed');
|
||||
if (shell.exec("docusaurus-build").code) {
|
||||
shell.echo("Error: generating html failed");
|
||||
shell.exit(1);
|
||||
}
|
||||
|
||||
shell.cd(__dirname);
|
||||
shell.cd('..');
|
||||
shell.cd('build');
|
||||
shell.cd("..");
|
||||
shell.cd("build");
|
||||
|
||||
if (shell.exec(`git clone ${remoteBranch} ${CIRCLE_PROJECT_REPONAME}-gh-pages`).code !== 0) {
|
||||
shell.echo('Error: git clone failed');
|
||||
if (
|
||||
shell.exec(`git clone ${remoteBranch} ${CIRCLE_PROJECT_REPONAME}-gh-pages`)
|
||||
.code !== 0
|
||||
) {
|
||||
shell.echo("Error: git clone failed");
|
||||
shell.exit(1);
|
||||
}
|
||||
|
||||
shell.cd(`${CIRCLE_PROJECT_REPONAME}-gh-pages`);
|
||||
|
||||
if (shell.exec('git checkout origin/gh-pages').code +
|
||||
shell.exec('git checkout -b gh-pages').code +
|
||||
shell.exec('git branch --set-upstream-to=origin/gh-pages').code !== 0
|
||||
) {
|
||||
shell.echo('Error: Git checkout gh-pages failed');
|
||||
if (
|
||||
shell.exec("git checkout origin/gh-pages").code +
|
||||
shell.exec("git checkout -b gh-pages").code +
|
||||
shell.exec("git branch --set-upstream-to=origin/gh-pages").code !==
|
||||
0
|
||||
) {
|
||||
shell.echo("Error: Git checkout gh-pages failed");
|
||||
shell.exit(1);
|
||||
}
|
||||
|
||||
shell.exec('rm -rf *');
|
||||
shell.exec("rm -rf *");
|
||||
|
||||
shell.cd('../..');
|
||||
shell.cd("../..");
|
||||
|
||||
shell.cp('-R', `build/${CIRCLE_PROJECT_REPONAME}/*`, `build/${CIRCLE_PROJECT_REPONAME}-gh-pages/`);
|
||||
shell.cp(
|
||||
"-R",
|
||||
`build/${CIRCLE_PROJECT_REPONAME}/*`,
|
||||
`build/${CIRCLE_PROJECT_REPONAME}-gh-pages/`
|
||||
);
|
||||
shell.cd(`build/${CIRCLE_PROJECT_REPONAME}-gh-pages`);
|
||||
|
||||
shell.exec('git add --all');
|
||||
shell.exec("git add --all");
|
||||
shell.exec('git commit -m "update website [ci skip]"');
|
||||
if (shell.exec('git push origin gh-pages').code !== 0) {
|
||||
shell.echo('Error: Git push failed');
|
||||
if (shell.exec("git push origin gh-pages").code !== 0) {
|
||||
shell.echo("Error: Git push failed");
|
||||
shell.exit(1);
|
||||
} else {
|
||||
shell.echo(`Website is live at: https://${CIRCLE_PROJECT_USERNAME}.github.io/${CIRCLE_PROJECT_REPONAME}/`);
|
||||
shell.echo(
|
||||
`Website is live at: https://${CIRCLE_PROJECT_USERNAME}.github.io/${CIRCLE_PROJECT_REPONAME}/`
|
||||
);
|
||||
shell.exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,39 +7,39 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
function execute() {
|
||||
const translation = require('./translation.js');
|
||||
translation();
|
||||
|
||||
function execute() {
|
||||
const CWD = process.cwd();
|
||||
const fs = require('fs-extra');
|
||||
const readMetadata = require('./readMetadata.js');
|
||||
const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
|
||||
const path = require('path');
|
||||
const toSlug = require('../core/toSlug.js');
|
||||
const React = require('react');
|
||||
const mkdirp = require('mkdirp');
|
||||
const glob = require('glob');
|
||||
const Site = require('../core/Site.js');
|
||||
const siteConfig = require(CWD + '/siteConfig.js');
|
||||
const fs = require("fs-extra");
|
||||
const readMetadata = require("./readMetadata.js");
|
||||
const renderToStaticMarkup = require("react-dom/server").renderToStaticMarkup;
|
||||
const path = require("path");
|
||||
const toSlug = require("../core/toSlug.js");
|
||||
const React = require("react");
|
||||
const mkdirp = require("mkdirp");
|
||||
const glob = require("glob");
|
||||
const Site = require("../core/Site.js");
|
||||
const siteConfig = require(CWD + "/siteConfig.js");
|
||||
const translate = require("./translate.js");
|
||||
let languages;
|
||||
if (fs.existsSync(CWD + '/languages.js')) {
|
||||
languages = require(CWD + '/languages.js');
|
||||
if (fs.existsSync(CWD + "/languages.js")) {
|
||||
languages = require(CWD + "/languages.js");
|
||||
} else {
|
||||
languages = [{
|
||||
enabled: true,
|
||||
name: 'English',
|
||||
tag: 'en',
|
||||
}];
|
||||
languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: "English",
|
||||
tag: "en"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function writeFileAndCreateFolder(file, content) {
|
||||
mkdirp.sync(file.replace(new RegExp('/[^/]*$'), ''));
|
||||
mkdirp.sync(file.replace(new RegExp("/[^/]*$"), ""));
|
||||
|
||||
fs.writeFileSync(file, content);
|
||||
}
|
||||
|
||||
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
|
||||
const TABLE_OF_CONTENTS_TOKEN = "<AUTOGENERATED_TABLE_OF_CONTENTS>";
|
||||
|
||||
const insertTableOfContents = rawContent => {
|
||||
const regexp = /\n###\s+(`.*`.*)\n/g;
|
||||
|
|
@ -51,12 +51,12 @@
|
|||
|
||||
const tableOfContents = headers
|
||||
.map(header => ` - [${header}](#${toSlug(header)})`)
|
||||
.join('\n');
|
||||
.join("\n");
|
||||
|
||||
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
|
||||
};
|
||||
|
||||
console.log('generate.js triggered...');
|
||||
console.log("generate.js triggered...");
|
||||
|
||||
const regexSubFolder = /docs\/(.*)\/.*/;
|
||||
|
||||
|
|
@ -66,14 +66,15 @@
|
|||
});
|
||||
|
||||
readMetadata.generateDocsMetadata();
|
||||
const Metadata = require('../core/metadata.js');
|
||||
const Metadata = require("../core/metadata.js");
|
||||
let mdToHtml = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
const metadata = Metadata[i];
|
||||
mdToHtml['/docs/' + metadata.language + '/' + metadata.source] = '/' + siteConfig.projectName + '/' + metadata.permalink;
|
||||
mdToHtml["/docs/" + metadata.language + "/" + metadata.source] =
|
||||
"/" + siteConfig.projectName + "/" + metadata.permalink;
|
||||
}
|
||||
|
||||
const readCategories = require('./readCategories.js');
|
||||
const readCategories = require("./readCategories.js");
|
||||
let layouts = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
let layout = Metadata[i].layout;
|
||||
|
|
@ -83,15 +84,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
const DocsLayout = require('../core/DocsLayout.js');
|
||||
const DocsLayout = require("../core/DocsLayout.js");
|
||||
|
||||
fs.removeSync(__dirname + '/../../build');
|
||||
fs.removeSync(__dirname + "/../../build");
|
||||
|
||||
// create html files for all docs
|
||||
let files = glob.sync(CWD + '/../docs/**');
|
||||
let files = glob.sync(CWD + "/../docs/**");
|
||||
files.forEach(file => {
|
||||
// console.log(file);
|
||||
let language = 'en';
|
||||
let language = "en";
|
||||
const match = regexSubFolder.exec(file);
|
||||
if (match) {
|
||||
language = match[1];
|
||||
|
|
@ -103,7 +104,7 @@
|
|||
|
||||
const extension = path.extname(file);
|
||||
|
||||
if (extension === '.md' || extension === '.markdown') {
|
||||
if (extension === ".md" || extension === ".markdown") {
|
||||
const result = readMetadata.processMetadata(file);
|
||||
|
||||
const metadata = result.metadata;
|
||||
|
|
@ -116,149 +117,265 @@
|
|||
|
||||
/* replace any links to markdown files to their website html links */
|
||||
Object.keys(mdToHtml).forEach(function(key, index) {
|
||||
rawContent = rawContent.replace(new RegExp(key,'g'), mdToHtml[key]);
|
||||
rawContent = rawContent.replace(new RegExp(key, "g"), mdToHtml[key]);
|
||||
});
|
||||
|
||||
const docComp = <DocsLayout metadata={metadata} language={language} config={siteConfig}>{rawContent}</DocsLayout>;
|
||||
const docComp = (
|
||||
<DocsLayout metadata={metadata} language={language} config={siteConfig}>
|
||||
{rawContent}
|
||||
</DocsLayout>
|
||||
);
|
||||
const str = renderToStaticMarkup(docComp);
|
||||
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + metadata.permalink;
|
||||
let targetFile =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
metadata.permalink;
|
||||
// console.log(targetFile);
|
||||
writeFileAndCreateFolder(targetFile, str);
|
||||
}
|
||||
});
|
||||
|
||||
// create html files for all blog posts
|
||||
if (fs.existsSync(__dirname + '../core/MetadataBlog.js')) {
|
||||
fs.removeSync(__dirname + '../core/MetadataBlog.js');
|
||||
if (fs.existsSync(__dirname + "../core/MetadataBlog.js")) {
|
||||
fs.removeSync(__dirname + "../core/MetadataBlog.js");
|
||||
}
|
||||
readMetadata.generateBlogMetadata();
|
||||
const MetadataBlog = require('../core/MetadataBlog.js');
|
||||
const BlogPostLayout = require('../core/BlogPostLayout.js');
|
||||
const MetadataBlog = require("../core/MetadataBlog.js");
|
||||
const BlogPostLayout = require("../core/BlogPostLayout.js");
|
||||
|
||||
files = glob.sync(CWD + '/../blog/**/*.*');
|
||||
files = glob.sync(CWD + "/../blog/**/*.*");
|
||||
files.sort().reverse().forEach(file => {
|
||||
/* convert filename ot use slashes */
|
||||
const filePath = path
|
||||
.basename(file)
|
||||
.replace('-', '/')
|
||||
.replace('-', '/')
|
||||
.replace('-', '/')
|
||||
.replace(/\./g, '-')
|
||||
.replace(/\-md$/, '.html');
|
||||
const result = readMetadata.extractMetadata(fs.readFileSync(file, {encoding: 'utf8'}));
|
||||
.replace("-", "/")
|
||||
.replace("-", "/")
|
||||
.replace("-", "/")
|
||||
.replace(/\./g, "-")
|
||||
.replace(/\-md$/, ".html");
|
||||
const result = readMetadata.extractMetadata(
|
||||
fs.readFileSync(file, { encoding: "utf8" })
|
||||
);
|
||||
const rawContent = result.rawContent;
|
||||
const metadata = Object.assign(
|
||||
{path: filePath, content: rawContent},
|
||||
{ path: filePath, content: rawContent },
|
||||
result.metadata
|
||||
);
|
||||
metadata.id = metadata.title;
|
||||
|
||||
let language = 'en';
|
||||
const blogPostComp = <BlogPostLayout metadata={metadata} language={language} config={siteConfig}>{rawContent}</BlogPostLayout>;
|
||||
let language = "en";
|
||||
const blogPostComp = (
|
||||
<BlogPostLayout
|
||||
metadata={metadata}
|
||||
language={language}
|
||||
config={siteConfig}
|
||||
>
|
||||
{rawContent}
|
||||
</BlogPostLayout>
|
||||
);
|
||||
const str = renderToStaticMarkup(blogPostComp);
|
||||
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + 'blog/' + filePath;
|
||||
let targetFile =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
"blog/" +
|
||||
filePath;
|
||||
writeFileAndCreateFolder(targetFile, str);
|
||||
});
|
||||
// create html files for all blog pages
|
||||
const BlogPageLayout = require('../core/BlogPageLayout.js');
|
||||
const BlogPageLayout = require("../core/BlogPageLayout.js");
|
||||
const perPage = 10;
|
||||
for (
|
||||
let page = 0;
|
||||
page < Math.ceil(MetadataBlog.length / perPage);
|
||||
page++
|
||||
) {
|
||||
let language = 'en';
|
||||
const metadata = {page: page, perPage: perPage};
|
||||
const blogPageComp = <BlogPageLayout metadata={metadata} language={language} config={siteConfig}></BlogPageLayout>
|
||||
for (let page = 0; page < Math.ceil(MetadataBlog.length / perPage); page++) {
|
||||
let language = "en";
|
||||
const metadata = { page: page, perPage: perPage };
|
||||
const blogPageComp = (
|
||||
<BlogPageLayout
|
||||
metadata={metadata}
|
||||
language={language}
|
||||
config={siteConfig}
|
||||
/>
|
||||
);
|
||||
const str = renderToStaticMarkup(blogPageComp);
|
||||
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + 'blog' + (page > 0 ? '/page' + (page + 1) : '') + '/index.html';
|
||||
let targetFile =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
"blog" +
|
||||
(page > 0 ? "/page" + (page + 1) : "") +
|
||||
"/index.html";
|
||||
writeFileAndCreateFolder(targetFile, str);
|
||||
}
|
||||
|
||||
/* copy all static files from docusaurus */
|
||||
files = glob.sync(__dirname + '/../static/**');
|
||||
files = glob.sync(__dirname + "/../static/**");
|
||||
files.forEach(file => {
|
||||
let targetFile = file.replace('/lib/static/', '/build' + '/' + siteConfig.projectName + '/');
|
||||
let targetFile = file.replace(
|
||||
"/lib/static/",
|
||||
"/build" + "/" + siteConfig.projectName + "/"
|
||||
);
|
||||
|
||||
if (file.match(/\.css$/)) {
|
||||
let cssContent = fs.readFileSync(file);
|
||||
cssContent = cssContent.toString().replace(new RegExp('{primaryColor}', 'g'), siteConfig.colors.primaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{secondaryColor}', 'g'), siteConfig.colors.secondaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{prismColor}', 'g'), siteConfig.colors.prismColor);
|
||||
cssContent = cssContent
|
||||
.toString()
|
||||
.replace(
|
||||
new RegExp("{primaryColor}", "g"),
|
||||
siteConfig.colors.primaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{secondaryColor}", "g"),
|
||||
siteConfig.colors.secondaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{prismColor}", "g"),
|
||||
siteConfig.colors.prismColor
|
||||
);
|
||||
|
||||
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.writeFileSync(targetFile, cssContent);
|
||||
}
|
||||
else if (!fs.lstatSync(file).isDirectory()) {
|
||||
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
} else if (!fs.lstatSync(file).isDirectory()) {
|
||||
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.copySync(file, targetFile);
|
||||
}
|
||||
});
|
||||
|
||||
/* copy all static files from user */
|
||||
files = glob.sync(CWD + '/static/**');
|
||||
files = glob.sync(CWD + "/static/**");
|
||||
files.forEach(file => {
|
||||
if (file.match(/\.css$/)) {
|
||||
const mainCss = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + 'css/main.css';
|
||||
const mainCss =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
"css/main.css";
|
||||
let cssContent = fs.readFileSync(file);
|
||||
cssContent = fs.readFileSync(mainCss) + '\n' + cssContent;
|
||||
cssContent = fs.readFileSync(mainCss) + "\n" + cssContent;
|
||||
|
||||
cssContent = cssContent.toString().replace(new RegExp('{primaryColor}', 'g'), siteConfig.colors.primaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{secondaryColor}', 'g'), siteConfig.colors.secondaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{prismColor}', 'g'), siteConfig.colors.prismColor);
|
||||
cssContent = cssContent
|
||||
.toString()
|
||||
.replace(
|
||||
new RegExp("{primaryColor}", "g"),
|
||||
siteConfig.colors.primaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{secondaryColor}", "g"),
|
||||
siteConfig.colors.secondaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{prismColor}", "g"),
|
||||
siteConfig.colors.prismColor
|
||||
);
|
||||
|
||||
fs.writeFileSync(mainCss, cssContent);
|
||||
}
|
||||
else if (!fs.lstatSync(file).isDirectory()) {
|
||||
let parts = file.split('static');
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + parts[1];
|
||||
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
} else if (!fs.lstatSync(file).isDirectory()) {
|
||||
let parts = file.split("static");
|
||||
let targetFile =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
parts[1];
|
||||
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.copySync(file, targetFile);
|
||||
}
|
||||
});
|
||||
|
||||
/* compile/copy pages from user */
|
||||
files = glob.sync(CWD + '/pages/**');
|
||||
files = glob.sync(CWD + "/pages/**");
|
||||
files.forEach(file => {
|
||||
if (file.match(/\.js$/)) {
|
||||
let parts = file.split('pages');
|
||||
let tempFile = __dirname +'/../pages' + parts[1];
|
||||
tempFile = tempFile.replace(path.basename(file), 'temp' + path.basename(file));
|
||||
mkdirp.sync(tempFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
/* make temp file for sake of require paths */
|
||||
const parts = file.split("pages");
|
||||
let tempFile = __dirname + "/../pages" + parts[1];
|
||||
tempFile = tempFile.replace(
|
||||
path.basename(file),
|
||||
"temp" + path.basename(file)
|
||||
);
|
||||
mkdirp.sync(tempFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.copySync(file, tempFile);
|
||||
|
||||
let language = 'en';
|
||||
const ReactComp = require(tempFile);
|
||||
|
||||
let targetFile =
|
||||
__dirname + "/../../build/" + siteConfig.projectName + "/" + parts[1];
|
||||
targetFile = targetFile.replace(/\.js$/, ".html");
|
||||
|
||||
const regexLang = /\/pages\/(.*)\//;
|
||||
const match = regexLang.exec(file);
|
||||
let langParts = match[1].split('/');
|
||||
for (let i = 0; i < langParts.length; i++) {
|
||||
if (enabledLanguages.indexOf(langParts[i]) !== -1) {
|
||||
language = langParts[i];
|
||||
const langParts = match[1].split("/");
|
||||
if (langParts.indexOf("en") !== -1) {
|
||||
/* copy and compile a page for each enabled language from the English file */
|
||||
for (let i = 0; i < enabledLanguages.length; i++) {
|
||||
let language = enabledLanguages[i];
|
||||
/* skip conversion from english file if a file exists for this language */
|
||||
if (
|
||||
language !== "en" &&
|
||||
fs.existsSync(file.replace("/en/", "/" + language + "/"))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
translate.setLanguage(language);
|
||||
const str = renderToStaticMarkup(
|
||||
<Site language={language} config={siteConfig}>
|
||||
<ReactComp language={language} />
|
||||
</Site>
|
||||
);
|
||||
writeFileAndCreateFolder(
|
||||
targetFile.replace("/en/", "/" + language + "/"),
|
||||
str
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/* allow for rendering of other files not in pages/en folder */
|
||||
let language = "en";
|
||||
for (let i = 0; i < langParts.length; i++) {
|
||||
if (enabledLanguages.indexOf(langParts[i]) !== -1) {
|
||||
language = langParts[i];
|
||||
}
|
||||
}
|
||||
translate.setLanguage(language);
|
||||
const str = renderToStaticMarkup(
|
||||
<Site language={language} config={siteConfig}>
|
||||
<ReactComp language={language} />
|
||||
</Site>
|
||||
);
|
||||
writeFileAndCreateFolder(targetFile, str);
|
||||
}
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + parts[1];
|
||||
targetFile = targetFile.replace(/\.js$/, '.html');
|
||||
const ReactComp = require(tempFile);
|
||||
const str = renderToStaticMarkup(<Site language={language} config={siteConfig}><ReactComp language={language}/></Site>);
|
||||
writeFileAndCreateFolder(targetFile, str);
|
||||
|
||||
fs.removeSync(tempFile);
|
||||
}
|
||||
else if (!fs.lstatSync(file).isDirectory()) {
|
||||
let parts = file.split('pages');
|
||||
let targetFile = __dirname + '/../../build' + '/' + siteConfig.projectName + '/' + parts[1];
|
||||
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
} else if (!fs.lstatSync(file).isDirectory()) {
|
||||
let parts = file.split("pages");
|
||||
let targetFile =
|
||||
__dirname +
|
||||
"/../../build" +
|
||||
"/" +
|
||||
siteConfig.projectName +
|
||||
"/" +
|
||||
parts[1];
|
||||
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.copySync(file, targetFile);
|
||||
}
|
||||
});
|
||||
|
||||
/* copy html files in 'en' to base level as well */
|
||||
files = glob.sync(__dirname + '/../../build' + '/' + siteConfig.projectName + '/' +'en/**');
|
||||
files = glob.sync(
|
||||
__dirname + "/../../build" + "/" + siteConfig.projectName + "/" + "en/**"
|
||||
);
|
||||
files.forEach(file => {
|
||||
let targetFile = file.replace('en/', '');
|
||||
let targetFile = file.replace("en/", "");
|
||||
if (file.match(/\.html$/)) {
|
||||
fs.copySync(file, targetFile);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,22 +7,23 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const CWD = process.cwd();
|
||||
const CWD = process.cwd();
|
||||
|
||||
const Metadata = require('../core/metadata.js');
|
||||
const fs = require('fs');
|
||||
const Metadata = require("../core/metadata.js");
|
||||
const fs = require("fs");
|
||||
let languages;
|
||||
if (fs.existsSync(CWD + '/languages.js')) {
|
||||
languages = require(CWD + '/languages.js');
|
||||
if (fs.existsSync(CWD + "/languages.js")) {
|
||||
languages = require(CWD + "/languages.js");
|
||||
} else {
|
||||
languages = [{
|
||||
enabled: true,
|
||||
name: 'English',
|
||||
tag: 'en',
|
||||
}];
|
||||
languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: "English",
|
||||
tag: "en"
|
||||
}
|
||||
];
|
||||
}
|
||||
function readCategories(layout) {
|
||||
|
||||
const enabledLanguages = [];
|
||||
languages.filter(lang => lang.enabled).map(lang => {
|
||||
enabledLanguages.push(lang.tag);
|
||||
|
|
@ -34,8 +35,7 @@ function readCategories(layout) {
|
|||
const language = enabledLanguages[k];
|
||||
|
||||
const metadatas = Metadata.filter(metadata => {
|
||||
return metadata.layout === layout &&
|
||||
metadata.language === language;
|
||||
return metadata.layout === layout && metadata.language === language;
|
||||
});
|
||||
|
||||
// Build a hashmap of article_id -> metadata
|
||||
|
|
@ -52,7 +52,7 @@ function readCategories(layout) {
|
|||
if (metadata.next) {
|
||||
if (!articles[metadata.next]) {
|
||||
throw new Error(
|
||||
'`next: ' + metadata.next + '` in ' + metadata.id + " doesn't exist"
|
||||
"`next: " + metadata.next + "` in " + metadata.id + " doesn't exist"
|
||||
);
|
||||
}
|
||||
previous[articles[metadata.next].id] = metadata.id;
|
||||
|
|
@ -79,7 +79,7 @@ function readCategories(layout) {
|
|||
currentCategory && categories.push(currentCategory);
|
||||
currentCategory = {
|
||||
name: metadata.category,
|
||||
links: [],
|
||||
links: []
|
||||
};
|
||||
}
|
||||
currentCategory.links.push(metadata);
|
||||
|
|
@ -91,15 +91,14 @@ function readCategories(layout) {
|
|||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
__dirname + '/../core/' + layout + 'Categories.js',
|
||||
'/**\n' +
|
||||
' * @generated\n' +
|
||||
' */\n' +
|
||||
'module.exports = ' +
|
||||
__dirname + "/../core/" + layout + "Categories.js",
|
||||
"/**\n" +
|
||||
" * @generated\n" +
|
||||
" */\n" +
|
||||
"module.exports = " +
|
||||
JSON.stringify(allCategories, null, 2) +
|
||||
';'
|
||||
";"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
module.exports = readCategories;
|
||||
|
|
|
|||
|
|
@ -7,34 +7,36 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const CWD = process.cwd();
|
||||
const CWD = process.cwd();
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
let languages;
|
||||
if (fs.existsSync(CWD + '/languages.js')) {
|
||||
languages = require(CWD + '/languages.js');
|
||||
if (fs.existsSync(CWD + "/languages.js")) {
|
||||
languages = require(CWD + "/languages.js");
|
||||
} else {
|
||||
languages = [{
|
||||
enabled: true,
|
||||
name: 'English',
|
||||
tag: 'en',
|
||||
}];
|
||||
languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: "English",
|
||||
tag: "en"
|
||||
}
|
||||
];
|
||||
}
|
||||
const glob = require('glob');
|
||||
const glob = require("glob");
|
||||
|
||||
function splitHeader(content) {
|
||||
const lines = content.split(os.EOL);
|
||||
let i = 1;
|
||||
for (; i < lines.length - 1; ++i) {
|
||||
if (lines[i] === '---') {
|
||||
if (lines[i] === "---") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
header: lines.slice(1, i + 1).join('\n'),
|
||||
content: lines.slice(i + 1).join('\n'),
|
||||
header: lines.slice(1, i + 1).join("\n"),
|
||||
content: lines.slice(i + 1).join("\n")
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -42,26 +44,26 @@ function splitHeader(content) {
|
|||
function extractMetadata(content) {
|
||||
const metadata = {};
|
||||
const both = splitHeader(content);
|
||||
const lines = both.header.split('\n');
|
||||
const lines = both.header.split("\n");
|
||||
for (let i = 0; i < lines.length - 1; ++i) {
|
||||
const keyvalue = lines[i].split(':');
|
||||
const keyvalue = lines[i].split(":");
|
||||
const key = keyvalue[0].trim();
|
||||
let value = keyvalue.slice(1).join(':').trim();
|
||||
let value = keyvalue.slice(1).join(":").trim();
|
||||
// Handle the case where you have "Community #10"
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {}
|
||||
metadata[key] = value;
|
||||
}
|
||||
return {metadata, rawContent: both.content};
|
||||
return { metadata, rawContent: both.content };
|
||||
}
|
||||
|
||||
function processMetadata(file) {
|
||||
const result = extractMetadata(fs.readFileSync(file, 'utf8'));
|
||||
const result = extractMetadata(fs.readFileSync(file, "utf8"));
|
||||
|
||||
const regexSubFolder = /docs\/(.*)\/.*/;
|
||||
|
||||
let language = 'en';
|
||||
let language = "en";
|
||||
const match = regexSubFolder.exec(file);
|
||||
if (match) {
|
||||
language = match[1];
|
||||
|
|
@ -74,26 +76,25 @@ function processMetadata(file) {
|
|||
// in permalink replace /en/ language with localized folder
|
||||
metadata.permalink = metadata.permalink.replace(
|
||||
/\/en\//g,
|
||||
'/' + language + '/'
|
||||
"/" + language + "/"
|
||||
);
|
||||
// change ids previous, next
|
||||
metadata.localized_id = metadata.id;
|
||||
metadata.id = language + '-' + metadata.id;
|
||||
metadata.id = language + "-" + metadata.id;
|
||||
if (metadata.previous) {
|
||||
metadata.previous_id = metadata.previous;
|
||||
metadata.previous = language + '-' + metadata.previous;
|
||||
metadata.previous = language + "-" + metadata.previous;
|
||||
}
|
||||
if (metadata.next) {
|
||||
metadata.next_id = metadata.next;
|
||||
metadata.next = language + '-' + metadata.next;
|
||||
metadata.next = language + "-" + metadata.next;
|
||||
}
|
||||
metadata.language = language;
|
||||
|
||||
return {metadata, rawContent: rawContent};
|
||||
return { metadata, rawContent: rawContent };
|
||||
}
|
||||
|
||||
function generateDocsMetadata() {
|
||||
|
||||
const regexSubFolder = /docs\/(.*)\/.*/;
|
||||
|
||||
const enabledLanguages = [];
|
||||
|
|
@ -103,9 +104,9 @@ function generateDocsMetadata() {
|
|||
|
||||
const metadatas = [];
|
||||
|
||||
const files = glob.sync(CWD + '/../docs/**');
|
||||
const files = glob.sync(CWD + "/../docs/**");
|
||||
files.forEach(file => {
|
||||
let language = 'en';
|
||||
let language = "en";
|
||||
const match = regexSubFolder.exec(file);
|
||||
if (match) {
|
||||
language = match[1];
|
||||
|
|
@ -117,29 +118,28 @@ function generateDocsMetadata() {
|
|||
|
||||
const extension = path.extname(file);
|
||||
|
||||
if (extension === '.md' || extension === '.markdown') {
|
||||
if (extension === ".md" || extension === ".markdown") {
|
||||
const res = processMetadata(file);
|
||||
const metadata = res.metadata;
|
||||
metadatas.push(metadata);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
fs.writeFileSync(
|
||||
__dirname + '/../core/metadata.js',
|
||||
'/**\n' +
|
||||
' * @generated\n' +
|
||||
' */\n' +
|
||||
'module.exports = ' +
|
||||
__dirname + "/../core/metadata.js",
|
||||
"/**\n" +
|
||||
" * @generated\n" +
|
||||
" */\n" +
|
||||
"module.exports = " +
|
||||
JSON.stringify(metadatas, null, 2) +
|
||||
';'
|
||||
";"
|
||||
);
|
||||
}
|
||||
|
||||
function generateBlogMetadata() {
|
||||
const metadatas = [];
|
||||
|
||||
let files = glob.sync(CWD + '/../blog/**/*.*');
|
||||
let files = glob.sync(CWD + "/../blog/**/*.*");
|
||||
files.sort().reverse().forEach(file => {
|
||||
// Transform
|
||||
// 2015-08-13-blog-post-name-0.5.md
|
||||
|
|
@ -147,17 +147,17 @@ function generateBlogMetadata() {
|
|||
// 2015/08/13/blog-post-name-0-5.html
|
||||
const filePath = path
|
||||
.basename(file)
|
||||
.replace('-', '/')
|
||||
.replace('-', '/')
|
||||
.replace('-', '/')
|
||||
.replace("-", "/")
|
||||
.replace("-", "/")
|
||||
.replace("-", "/")
|
||||
// react-middleware is broken with files that contains multiple .
|
||||
// like react-0.14.js
|
||||
.replace(/\./g, '-')
|
||||
.replace(/\-md$/, '.html');
|
||||
const result = extractMetadata(fs.readFileSync(file, {encoding: 'utf8'}));
|
||||
.replace(/\./g, "-")
|
||||
.replace(/\-md$/, ".html");
|
||||
const result = extractMetadata(fs.readFileSync(file, { encoding: "utf8" }));
|
||||
const rawContent = result.rawContent;
|
||||
const metadata = Object.assign(
|
||||
{path: filePath, content: rawContent},
|
||||
{ path: filePath, content: rawContent },
|
||||
result.metadata
|
||||
);
|
||||
metadata.id = metadata.title;
|
||||
|
|
@ -165,13 +165,13 @@ function generateBlogMetadata() {
|
|||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
__dirname + '/../core/MetadataBlog.js',
|
||||
'/**\n' +
|
||||
' * @generated\n' +
|
||||
' */\n' +
|
||||
'module.exports = ' +
|
||||
__dirname + "/../core/MetadataBlog.js",
|
||||
"/**\n" +
|
||||
" * @generated\n" +
|
||||
" */\n" +
|
||||
"module.exports = " +
|
||||
JSON.stringify(metadatas, null, 2) +
|
||||
';'
|
||||
";"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,22 +7,22 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
function execute () {
|
||||
const translation = require('./translation.js');
|
||||
translation();
|
||||
function execute(port) {
|
||||
const translation = require("./translation.js");
|
||||
const CWD = process.cwd();
|
||||
const express = require('express');
|
||||
const React = require('react');
|
||||
const request = require('request');
|
||||
const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
|
||||
const fs = require('fs-extra');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const readMetadata = require('./readMetadata.js');
|
||||
const toSlug = require('../core/toSlug.js');
|
||||
const mkdirp = require('mkdirp');
|
||||
const glob = require('glob');
|
||||
let siteConfig = require(CWD + '/siteConfig.js');
|
||||
const express = require("express");
|
||||
const React = require("react");
|
||||
const request = require("request");
|
||||
const renderToStaticMarkup = require("react-dom/server").renderToStaticMarkup;
|
||||
const fs = require("fs-extra");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const readMetadata = require("./readMetadata.js");
|
||||
const toSlug = require("../core/toSlug.js");
|
||||
const mkdirp = require("mkdirp");
|
||||
const glob = require("glob");
|
||||
const translate = require("./translate.js");
|
||||
let siteConfig = require(CWD + "/siteConfig.js");
|
||||
|
||||
/**
|
||||
* Removes a module from the cache
|
||||
|
|
@ -30,17 +30,17 @@
|
|||
function purgeCache(moduleName) {
|
||||
// Traverse the cache looking for the files
|
||||
// loaded by the specified module name
|
||||
searchCache(moduleName, function (mod) {
|
||||
searchCache(moduleName, function(mod) {
|
||||
delete require.cache[mod.id];
|
||||
});
|
||||
|
||||
// Remove cached paths to the module.
|
||||
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
|
||||
if (cacheKey.indexOf(moduleName)>0) {
|
||||
if (cacheKey.indexOf(moduleName) > 0) {
|
||||
delete module.constructor._pathCache[cacheKey];
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses the cache to search for all the cached
|
||||
|
|
@ -52,21 +52,21 @@
|
|||
|
||||
// Check if the module has been resolved and found within
|
||||
// the cache
|
||||
if (mod && ((mod = require.cache[mod]) !== undefined)) {
|
||||
if (mod && (mod = require.cache[mod]) !== undefined) {
|
||||
// Recursively go over the results
|
||||
(function traverse(mod) {
|
||||
// Go over each of the module's children and
|
||||
// traverse them
|
||||
mod.children.forEach(function (child) {
|
||||
traverse(child);
|
||||
mod.children.forEach(function(child) {
|
||||
traverse(child);
|
||||
});
|
||||
|
||||
// Call the specified callback providing the
|
||||
// found cached module
|
||||
callback(mod);
|
||||
}(mod));
|
||||
})(mod);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
|
@ -75,10 +75,10 @@
|
|||
|
||||
function reloadMetadataCategories() {
|
||||
readMetadata.generateDocsMetadata();
|
||||
purgeCache('../core/metadata.js');
|
||||
Metadata = require('../core/metadata.js');
|
||||
purgeCache('./readCategories.js');
|
||||
readCategories = require('./readCategories.js');
|
||||
purgeCache("../core/metadata.js");
|
||||
Metadata = require("../core/metadata.js");
|
||||
purgeCache("./readCategories.js");
|
||||
readCategories = require("./readCategories.js");
|
||||
|
||||
let layouts = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
|
||||
/****************************************************************************/
|
||||
|
||||
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
|
||||
const TABLE_OF_CONTENTS_TOKEN = "<AUTOGENERATED_TABLE_OF_CONTENTS>";
|
||||
|
||||
const insertTableOfContents = rawContent => {
|
||||
const regexp = /\n###\s+(`.*`.*)\n/g;
|
||||
|
|
@ -104,80 +104,82 @@
|
|||
|
||||
const tableOfContents = headers
|
||||
.map(header => ` - [${header}](#${toSlug(header)})`)
|
||||
.join('\n');
|
||||
.join("\n");
|
||||
|
||||
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
console.log('server.js triggered...');
|
||||
|
||||
const port = 3000;
|
||||
console.log("server.js triggered...");
|
||||
|
||||
reloadMetadataCategories();
|
||||
|
||||
/* handle all requests for document pages */
|
||||
const app = express()
|
||||
.get(/docs\/[\s\S]*html$/, (req, res) => {
|
||||
purgeCache(CWD + '/siteConfig.js');
|
||||
siteConfig = require(CWD + '/siteConfig.js');
|
||||
const app = express().get(/docs\/[\s\S]*html$/, (req, res) => {
|
||||
purgeCache(CWD + "/siteConfig.js");
|
||||
siteConfig = require(CWD + "/siteConfig.js");
|
||||
|
||||
console.log(req.path);
|
||||
console.log(req.path);
|
||||
|
||||
reloadMetadataCategories();
|
||||
let links = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
const metadata = Metadata[i];
|
||||
links[metadata.permalink] = 'docs/' + metadata.language + '/' + metadata.source;
|
||||
}
|
||||
let mdToHtml = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
const metadata = Metadata[i];
|
||||
mdToHtml['/docs/' + metadata.language + '/' + metadata.source] = siteConfig.baseUrl + metadata.permalink;
|
||||
}
|
||||
reloadMetadataCategories();
|
||||
let links = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
const metadata = Metadata[i];
|
||||
links[metadata.permalink] =
|
||||
"docs/" + metadata.language + "/" + metadata.source;
|
||||
}
|
||||
let mdToHtml = {};
|
||||
for (let i = 0; i < Metadata.length; i++) {
|
||||
const metadata = Metadata[i];
|
||||
mdToHtml["/docs/" + metadata.language + "/" + metadata.source] =
|
||||
siteConfig.baseUrl + metadata.permalink;
|
||||
}
|
||||
|
||||
let file = links[req.path.toString().replace(siteConfig.baseUrl, '')];
|
||||
file = CWD + '/../' + file;
|
||||
console.log(file);
|
||||
const result = readMetadata.processMetadata(file);
|
||||
let file = links[req.path.toString().replace(siteConfig.baseUrl, "")];
|
||||
file = CWD + "/../" + file;
|
||||
console.log(file);
|
||||
const result = readMetadata.processMetadata(file);
|
||||
|
||||
const metadata = result.metadata;
|
||||
const language = metadata.language;
|
||||
let rawContent = result.rawContent;
|
||||
const metadata = result.metadata;
|
||||
const language = metadata.language;
|
||||
let rawContent = result.rawContent;
|
||||
|
||||
/* generate table of contents if appropriate */
|
||||
if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) {
|
||||
rawContent = insertTableOfContents(rawContent);
|
||||
}
|
||||
/* generate table of contents if appropriate */
|
||||
if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) {
|
||||
rawContent = insertTableOfContents(rawContent);
|
||||
}
|
||||
|
||||
/* replace any links to markdown files to their website html links */
|
||||
Object.keys(mdToHtml).forEach(function(key, index) {
|
||||
rawContent = rawContent.replace(new RegExp(key,'g'), mdToHtml[key]);
|
||||
});
|
||||
|
||||
purgeCache('../core/DocsLayout.js');
|
||||
const DocsLayout = require('../core/DocsLayout.js');
|
||||
const docComp = <DocsLayout metadata={metadata} language={language} config={siteConfig}>{rawContent}</DocsLayout>;
|
||||
|
||||
res.send(renderToStaticMarkup(docComp));
|
||||
/* replace any links to markdown files to their website html links */
|
||||
Object.keys(mdToHtml).forEach(function(key, index) {
|
||||
rawContent = rawContent.replace(new RegExp(key, "g"), mdToHtml[key]);
|
||||
});
|
||||
|
||||
purgeCache("../core/DocsLayout.js");
|
||||
const DocsLayout = require("../core/DocsLayout.js");
|
||||
const docComp = (
|
||||
<DocsLayout metadata={metadata} language={language} config={siteConfig}>
|
||||
{rawContent}
|
||||
</DocsLayout>
|
||||
);
|
||||
|
||||
res.send(renderToStaticMarkup(docComp));
|
||||
});
|
||||
/* handle all requests for blog pages and posts */
|
||||
app.get(/blog\/[\s\S]*html$/, (req, res) => {
|
||||
purgeCache(CWD + '/siteConfig.js');
|
||||
siteConfig = require(CWD + '/siteConfig.js');
|
||||
purgeCache(CWD + "/siteConfig.js");
|
||||
siteConfig = require(CWD + "/siteConfig.js");
|
||||
|
||||
|
||||
if (fs.existsSync(__dirname + '../core/MetadataBlog.js')) {
|
||||
purgeCache('../core/MetadataBlog.js');
|
||||
fs.removeSync(__dirname + '../core/MetadataBlog.js')
|
||||
if (fs.existsSync(__dirname + "../core/MetadataBlog.js")) {
|
||||
purgeCache("../core/MetadataBlog.js");
|
||||
fs.removeSync(__dirname + "../core/MetadataBlog.js");
|
||||
}
|
||||
readMetadata.generateBlogMetadata();
|
||||
MetadataBlog = require('../core/MetadataBlog.js');
|
||||
MetadataBlog = require("../core/MetadataBlog.js");
|
||||
|
||||
/* generate all of the blog pages */
|
||||
purgeCache('../core/BlogPageLayout.js');
|
||||
const BlogPageLayout = require('../core/BlogPageLayout.js');
|
||||
purgeCache("../core/BlogPageLayout.js");
|
||||
const BlogPageLayout = require("../core/BlogPageLayout.js");
|
||||
const blogPages = {};
|
||||
/* make blog pages with 10 posts per page */
|
||||
const perPage = 10;
|
||||
|
|
@ -186,158 +188,217 @@
|
|||
page < Math.ceil(MetadataBlog.length / perPage);
|
||||
page++
|
||||
) {
|
||||
let language = 'en';
|
||||
const metadata = {page: page, perPage: perPage};
|
||||
const blogPageComp = <BlogPageLayout metadata={metadata} language={language} config={siteConfig} />;
|
||||
let language = "en";
|
||||
const metadata = { page: page, perPage: perPage };
|
||||
const blogPageComp = (
|
||||
<BlogPageLayout
|
||||
metadata={metadata}
|
||||
language={language}
|
||||
config={siteConfig}
|
||||
/>
|
||||
);
|
||||
const str = renderToStaticMarkup(blogPageComp);
|
||||
|
||||
let path = (page > 0 ? 'page' + (page + 1) : '') + '/index.html';
|
||||
let path = (page > 0 ? "page" + (page + 1) : "") + "/index.html";
|
||||
blogPages[path] = str;
|
||||
}
|
||||
|
||||
let parts = req.path.toString().split('blog/');
|
||||
let parts = req.path.toString().split("blog/");
|
||||
// send corresponding blog page if appropriate
|
||||
if (parts[1] === 'index.html') {
|
||||
res.send(blogPages['/index.html']);
|
||||
}
|
||||
else if (parts[1].endsWith('/index.html')) {
|
||||
if (parts[1] === "index.html") {
|
||||
res.send(blogPages["/index.html"]);
|
||||
} else if (parts[1].endsWith("/index.html")) {
|
||||
res.send(blogPages[parts[1]]);
|
||||
}
|
||||
else if (parts[1].match(/page([0-9]+)/)) {
|
||||
if (parts[1].endsWith('/')) {
|
||||
res.send(blogPages[parts[1] + 'index.html']);
|
||||
} else if (parts[1].match(/page([0-9]+)/)) {
|
||||
if (parts[1].endsWith("/")) {
|
||||
res.send(blogPages[parts[1] + "index.html"]);
|
||||
} else {
|
||||
res.send(blogPages[parts[1] + '/index.html']);
|
||||
res.send(blogPages[parts[1] + "/index.html"]);
|
||||
}
|
||||
}
|
||||
// else send corresponding blog post
|
||||
else {
|
||||
} else {
|
||||
// else send corresponding blog post
|
||||
let file = parts[1];
|
||||
file = file.replace(/\.html$/, '.md');
|
||||
file = file.replace(new RegExp('/', 'g'), '-');
|
||||
file = CWD + '/../blog/' + file;
|
||||
file = file.replace(/\.html$/, ".md");
|
||||
file = file.replace(new RegExp("/", "g"), "-");
|
||||
file = CWD + "/../blog/" + file;
|
||||
|
||||
const result = readMetadata.extractMetadata(fs.readFileSync(file, {encoding: 'utf8'}));
|
||||
const result = readMetadata.extractMetadata(
|
||||
fs.readFileSync(file, { encoding: "utf8" })
|
||||
);
|
||||
const rawContent = result.rawContent;
|
||||
const metadata = Object.assign(
|
||||
{path: req.path.toString().split('blog/')[1], content: rawContent},
|
||||
{ path: req.path.toString().split("blog/")[1], content: rawContent },
|
||||
result.metadata
|
||||
);
|
||||
metadata.id = metadata.title;
|
||||
|
||||
let language = 'en';
|
||||
purgeCache('../core/BlogPostLayout.js')
|
||||
const BlogPostLayout = require('../core/BlogPostLayout.js');
|
||||
let language = "en";
|
||||
purgeCache("../core/BlogPostLayout.js");
|
||||
const BlogPostLayout = require("../core/BlogPostLayout.js");
|
||||
|
||||
const blogPostComp = <BlogPostLayout metadata={metadata} language={language} config={siteConfig}>{rawContent}</BlogPostLayout>;
|
||||
const blogPostComp = (
|
||||
<BlogPostLayout
|
||||
metadata={metadata}
|
||||
language={language}
|
||||
config={siteConfig}
|
||||
>
|
||||
{rawContent}
|
||||
</BlogPostLayout>
|
||||
);
|
||||
res.send(renderToStaticMarkup(blogPostComp));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* handle all other main pages */
|
||||
app.get('*.html', (req, res) => {
|
||||
purgeCache(CWD + '/siteConfig.js');
|
||||
siteConfig = require(CWD + '/siteConfig.js');
|
||||
app.get("*.html", (req, res) => {
|
||||
purgeCache(CWD + "/siteConfig.js");
|
||||
siteConfig = require(CWD + "/siteConfig.js");
|
||||
|
||||
console.log(req.path);
|
||||
|
||||
/* look for user provided html file first */
|
||||
let htmlFile = req.path.toString().replace(siteConfig.baseUrl, '');
|
||||
htmlFile = CWD + '/pages/' + htmlFile;
|
||||
if (fs.existsSync(htmlFile) ||
|
||||
fs.existsSync(htmlFile=htmlFile.replace(path.basename(htmlFile), 'en/' + path.basename(htmlFile)))) {
|
||||
res.send(fs.readFileSync(htmlFile, {encoding: 'utf8'}));
|
||||
let htmlFile = req.path.toString().replace(siteConfig.baseUrl, "");
|
||||
htmlFile = CWD + "/pages/" + htmlFile;
|
||||
if (
|
||||
fs.existsSync(htmlFile) ||
|
||||
fs.existsSync(
|
||||
(htmlFile = htmlFile.replace(
|
||||
path.basename(htmlFile),
|
||||
"en/" + path.basename(htmlFile)
|
||||
))
|
||||
)
|
||||
) {
|
||||
res.send(fs.readFileSync(htmlFile, { encoding: "utf8" }));
|
||||
return;
|
||||
}
|
||||
|
||||
/* look for user provided react file either in specified path or in path for english files */
|
||||
let file = req.path.toString().replace(/\.html$/, '.js');
|
||||
file = file.replace(siteConfig.baseUrl, '');
|
||||
let userFile = CWD + '/pages/' + file;
|
||||
let file = req.path.toString().replace(/\.html$/, ".js");
|
||||
file = file.replace(siteConfig.baseUrl, "");
|
||||
let userFile = CWD + "/pages/" + file;
|
||||
|
||||
let language = 'en';
|
||||
let language = "en";
|
||||
const regexLang = /(.*)\/.*\.html$/;
|
||||
const match = regexLang.exec(req.path);
|
||||
const parts = match[1].split('/');
|
||||
const parts = match[1].split("/");
|
||||
const enabledLangTags = [];
|
||||
for (let i = 0; i < siteConfig['languages'].length; i++) {
|
||||
enabledLangTags.push(siteConfig['languages'][i].tag);
|
||||
for (let i = 0; i < translation["languages"].length; i++) {
|
||||
enabledLangTags.push(translation["languages"][i].tag);
|
||||
}
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
if (enabledLangTags.indexOf(parts[i]) !== -1) {
|
||||
language = parts[i];
|
||||
}
|
||||
}
|
||||
if (fs.existsSync(userFile) ||
|
||||
fs.existsSync(userFile=userFile.replace(path.basename(userFile), 'en/' + path.basename(userFile)))) {
|
||||
let englishFile = CWD + "/pages/" + file;
|
||||
if (language !== "en") {
|
||||
englishFile = englishFile.replace("/" + language + "/", "/en/");
|
||||
}
|
||||
|
||||
/* check for: a file for the page, an english file for page with unspecified language,
|
||||
english file for the page */
|
||||
if (
|
||||
fs.existsSync(userFile) ||
|
||||
fs.existsSync(
|
||||
(userFile = userFile.replace(
|
||||
path.basename(userFile),
|
||||
"en/" + path.basename(userFile)
|
||||
))
|
||||
) ||
|
||||
fs.existsSync((userFile = englishFile))
|
||||
) {
|
||||
/* copy into docusaurus so require paths work */
|
||||
let parts = userFile.split('pages/');
|
||||
let tempFile = __dirname + '/../pages/' + parts[1];
|
||||
tempFile = tempFile.replace(path.basename(file), 'temp' + path.basename(file));
|
||||
mkdirp.sync(tempFile.replace(new RegExp('/[^/]*$'), ''));
|
||||
let parts = userFile.split("pages/");
|
||||
let tempFile = __dirname + "/../pages/" + parts[1];
|
||||
tempFile = tempFile.replace(
|
||||
path.basename(file),
|
||||
"temp" + path.basename(file)
|
||||
);
|
||||
mkdirp.sync(tempFile.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.copySync(userFile, tempFile);
|
||||
|
||||
/* render into a string */
|
||||
purgeCache(tempFile);
|
||||
const ReactComp = require(tempFile);
|
||||
purgeCache('../core/Site.js');
|
||||
const Site = require('../core/Site.js');
|
||||
const str = renderToStaticMarkup(<Site language={language} config={siteConfig}><ReactComp language={language}/></Site>);
|
||||
purgeCache("../core/Site.js");
|
||||
const Site = require("../core/Site.js");
|
||||
translate.setLanguage(language);
|
||||
const str = renderToStaticMarkup(
|
||||
<Site language={language} config={siteConfig}>
|
||||
<ReactComp language={language} />
|
||||
</Site>
|
||||
);
|
||||
|
||||
fs.removeSync(tempFile);
|
||||
|
||||
res.send(str);
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
console.log(req.path);
|
||||
res.send('No file found');
|
||||
res.send("No file found");
|
||||
}
|
||||
});
|
||||
|
||||
/* generate the main.css file by concatenating user provided css to the end */
|
||||
app.get(/main\.css$/, (req,res) => {
|
||||
const mainCssPath = __dirname +'/../static/' + req.path.toString().replace(siteConfig.baseUrl, '/');
|
||||
let cssContent = fs.readFileSync(mainCssPath, {encoding: 'utf8'});
|
||||
app.get(/main\.css$/, (req, res) => {
|
||||
const mainCssPath =
|
||||
__dirname +
|
||||
"/../static/" +
|
||||
req.path.toString().replace(siteConfig.baseUrl, "/");
|
||||
let cssContent = fs.readFileSync(mainCssPath, { encoding: "utf8" });
|
||||
|
||||
let files = glob.sync(CWD + '/static/**/*.css')
|
||||
let files = glob.sync(CWD + "/static/**/*.css");
|
||||
|
||||
files.forEach(file => {
|
||||
cssContent = cssContent + '\n' + fs.readFileSync(file, {encoding: 'utf8'});
|
||||
cssContent =
|
||||
cssContent + "\n" + fs.readFileSync(file, { encoding: "utf8" });
|
||||
});
|
||||
|
||||
cssContent = cssContent.toString().replace(new RegExp('{primaryColor}', 'g'), siteConfig.colors.primaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{secondaryColor}', 'g'), siteConfig.colors.secondaryColor);
|
||||
cssContent = cssContent.replace(new RegExp('{prismColor}', 'g'), siteConfig.colors.prismColor);
|
||||
cssContent = cssContent
|
||||
.toString()
|
||||
.replace(
|
||||
new RegExp("{primaryColor}", "g"),
|
||||
siteConfig.colors.primaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{secondaryColor}", "g"),
|
||||
siteConfig.colors.secondaryColor
|
||||
);
|
||||
cssContent = cssContent.replace(
|
||||
new RegExp("{prismColor}", "g"),
|
||||
siteConfig.colors.prismColor
|
||||
);
|
||||
|
||||
res.send(cssContent);
|
||||
});
|
||||
|
||||
/* serve static content first from user folder then from docusaurus */
|
||||
app.use(siteConfig.baseUrl, express.static(CWD + '/static'));
|
||||
app.use(siteConfig.baseUrl, express.static(__dirname + '/../static'));
|
||||
app.use(siteConfig.baseUrl, express.static(CWD + "/static"));
|
||||
app.use(siteConfig.baseUrl, express.static(__dirname + "/../static"));
|
||||
|
||||
app.get(/\/[^\.]*\/?$/, (req, res) => {
|
||||
if (req.path.toString().endsWith('/')) {
|
||||
request.get('http://localhost:3000' + req.path + 'index.html', (err, response, body) => {
|
||||
if (!err) {
|
||||
res.send(body);
|
||||
if (req.path.toString().endsWith("/")) {
|
||||
request.get(
|
||||
"http://localhost:3000" + req.path + "index.html",
|
||||
(err, response, body) => {
|
||||
if (!err) {
|
||||
res.send(body);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
} else {
|
||||
request.get('http://localhost:3000' + req.path + '/index.html', (err, response, body) => {
|
||||
if (!err) {
|
||||
res.send(body);
|
||||
request.get(
|
||||
"http://localhost:3000" + req.path + "/index.html",
|
||||
(err, response, body) => {
|
||||
if (!err) {
|
||||
res.send(body);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port);
|
||||
console.log('listening on port: ' + port);
|
||||
|
||||
console.log("listening on port: " + port);
|
||||
}
|
||||
|
||||
module.exports = execute;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* replaces translate tags with calls to translate function */
|
||||
|
||||
module.exports = function translatePlugin(babel) {
|
||||
const { types: t } = babel;
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
JSXElement(path) {
|
||||
if (path.node.openingElement.name.name !== "translate") {
|
||||
return;
|
||||
}
|
||||
/* assume translate element only has one child which is the text */
|
||||
const text = path.node.children[0].value.trim();
|
||||
let description = "no description given";
|
||||
const attributes = path.node.openingElement.attributes;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
if (attributes[i].name.name === "desc") {
|
||||
description = attributes[i].value.value;
|
||||
}
|
||||
}
|
||||
/* use an expression container if inside a jsxelement */
|
||||
if (path.findParent(path => true).node.type === "JSXElement") {
|
||||
path.replaceWith(
|
||||
t.jSXExpressionContainer(
|
||||
t.callExpression(t.identifier("translate"), [
|
||||
t.stringLiteral(text + "|" + description)
|
||||
])
|
||||
)
|
||||
);
|
||||
} else {
|
||||
path.replaceWith(
|
||||
t.callExpression(t.identifier("translate"), [
|
||||
t.stringLiteral(text + "|" + description)
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const translation = require("./translation.js");
|
||||
|
||||
let language = "en";
|
||||
|
||||
function setLanguage(lang) {
|
||||
language = lang;
|
||||
}
|
||||
|
||||
function translate(str) {
|
||||
return translation[language]["pages-strings"][str];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
setLanguage: setLanguage,
|
||||
translate: translate
|
||||
};
|
||||
|
|
@ -1,99 +1,35 @@
|
|||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
const CWD = process.cwd();
|
||||
const fs = require('fs-extra');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
const mkdirp = require('mkdirp');
|
||||
let siteConfig;
|
||||
const fs = require("fs");
|
||||
const glob = require("glob");
|
||||
const path = require("path");
|
||||
|
||||
console.log('translation.js triggered...');
|
||||
|
||||
function writeFileAndCreateFolder(file, content) {
|
||||
mkdirp.sync(file.replace(new RegExp('/[^/]*$'), ''));
|
||||
fs.writeFileSync(file, content);
|
||||
let languages;
|
||||
if (fs.existsSync(CWD + "/languages.js")) {
|
||||
languages = require(CWD + "/languages.js");
|
||||
} else {
|
||||
languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: "English",
|
||||
tag: "en"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
function execute() {
|
||||
if (fs.existsSync(CWD + '/languages.js')) {
|
||||
injectContent();
|
||||
translatePages();
|
||||
} else {
|
||||
console.log('No languages besides English enabled');
|
||||
const enabledLanguages = languages.filter(lang => lang.enabled);
|
||||
|
||||
const translation = { languages: enabledLanguages };
|
||||
|
||||
const files = glob.sync(CWD + "/i18n/**");
|
||||
const langRegex = /\/i18n\/(.*)\.json$/;
|
||||
|
||||
files.forEach(file => {
|
||||
const extension = path.extname(file);
|
||||
if (extension === ".json") {
|
||||
const match = langRegex.exec(file);
|
||||
const language = match[1];
|
||||
translation[language] = require(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function translatePages() {
|
||||
const siteConfig = require(CWD + '/siteConfig.js');
|
||||
|
||||
const files = glob.sync(CWD + '/pages/en/**/*.js');
|
||||
files.forEach(file => {
|
||||
let fileContent = fs.readFileSync(file, 'utf8');
|
||||
let baseName = path.basename(file, '.js');
|
||||
|
||||
for (let i = 0; i < siteConfig['languages'].length; i++) {
|
||||
let language = siteConfig['languages'][i];
|
||||
if (language.tag === 'en') continue;
|
||||
if (siteConfig[language.tag]) {
|
||||
let translatedContent = fileContent.slice(0);
|
||||
|
||||
Object.keys(siteConfig[language.tag]["pages-strings"][baseName])
|
||||
.forEach(function(key) {
|
||||
translatedContent = translatedContent.replace(key, siteConfig[language.tag]["pages-strings"][baseName][key]);
|
||||
});
|
||||
|
||||
let translatedFile = file.replace('/en/', '/' + language.tag + '/');
|
||||
writeFileAndCreateFolder(translatedFile, translatedContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function injectContent() {
|
||||
const I18N_JSON_DIR = CWD + '/i18n/';
|
||||
|
||||
const files = glob.sync(I18N_JSON_DIR + '**');
|
||||
const languages = [];
|
||||
const langRegex = /\/i18n\/(.*)\.json$/;
|
||||
|
||||
files.forEach(file => {
|
||||
const extension = path.extname(file);
|
||||
if (extension == '.json') {
|
||||
const match = langRegex.exec(file);
|
||||
const language = match[1];
|
||||
languages.push(language);
|
||||
}
|
||||
});
|
||||
|
||||
let injectedContent = '';
|
||||
languages.filter(language => language != 'en').forEach(language => {
|
||||
injectedContent +=
|
||||
"\nsiteConfig['" +
|
||||
language +
|
||||
"'] = require('./i18n/" +
|
||||
language +
|
||||
".json');";
|
||||
});
|
||||
|
||||
let siteConfigFile = fs.readFileSync(CWD + '/siteConfig.js', 'utf8');
|
||||
const injectStart = '/* INJECT LOCALIZED FILES BEGIN */';
|
||||
const injectEnd = '/* INJECT LOCALIZED FILES END */';
|
||||
siteConfigFile =
|
||||
siteConfigFile.slice(
|
||||
0,
|
||||
siteConfigFile.indexOf(injectStart) + injectStart.length
|
||||
) +
|
||||
injectedContent +
|
||||
'\n' +
|
||||
siteConfigFile.slice(siteConfigFile.indexOf(injectEnd));
|
||||
fs.writeFileSync(CWD + '/siteConfig.js', siteConfigFile);
|
||||
}
|
||||
|
||||
module.exports = execute;
|
||||
module.exports = translation;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,16 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
require('babel-register') ({
|
||||
require("babel-register")({
|
||||
ignore: false,
|
||||
"presets": ["react"]
|
||||
plugins: [require("./server/translate-plugin.js")],
|
||||
presets: ["react"]
|
||||
});
|
||||
|
||||
const server = require('./server/server.js');
|
||||
server();
|
||||
let port = 3000;
|
||||
if (process.argv.length > 2) {
|
||||
port = process.argv[2];
|
||||
}
|
||||
|
||||
const server = require("./server/server.js");
|
||||
server(port);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (c) 2017-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
/* generate the i18n/en.json file */
|
||||
|
||||
const CWD = process.cwd();
|
||||
const fs = require("fs-extra");
|
||||
const mkdirp = require("mkdirp");
|
||||
const glob = require("glob");
|
||||
const readMetadata = require("./server/readMetadata.js");
|
||||
const path = require("path");
|
||||
const siteConfig = require(CWD + "/siteConfig.js");
|
||||
const babylon = require("babylon");
|
||||
const traverse = require("babel-traverse").default;
|
||||
|
||||
function writeFileAndCreateFolder(file, content) {
|
||||
mkdirp.sync(file.replace(new RegExp("/[^/]*$"), ""));
|
||||
fs.writeFileSync(file, content);
|
||||
}
|
||||
|
||||
function execute() {
|
||||
let translations = {
|
||||
"localized-strings": {
|
||||
next: "Next",
|
||||
previous: "Previous",
|
||||
tagline: siteConfig.tagline
|
||||
},
|
||||
"pages-strings": {}
|
||||
};
|
||||
|
||||
/* look through front matter of docs for titles and categories to translate */
|
||||
let files = glob.sync(CWD + "/../docs/en/**");
|
||||
files.forEach(file => {
|
||||
const extension = path.extname(file);
|
||||
if (extension === ".md" || extension === ".markdown") {
|
||||
const metadata = readMetadata.extractMetadata(
|
||||
fs.readFileSync(file, "utf8")
|
||||
).metadata;
|
||||
|
||||
translations["localized-strings"][metadata.id] = metadata.title;
|
||||
translations["localized-strings"][metadata.category] = metadata.category;
|
||||
}
|
||||
});
|
||||
/* look through header links for text to translate */
|
||||
for (let i = 0; i < siteConfig.headerLinksInternal.length; i++) {
|
||||
translations["localized-strings"][siteConfig.headerLinksInternal[i].text] =
|
||||
siteConfig.headerLinksInternal[i].text;
|
||||
}
|
||||
for (let i = 0; i < siteConfig.headerLinksExternal.length; i++) {
|
||||
translations["localized-strings"][siteConfig.headerLinksExternal[i].text] =
|
||||
siteConfig.headerLinksExternal[i].text;
|
||||
}
|
||||
|
||||
/* go through pages to look for text inside translate tags */
|
||||
files = glob.sync(CWD + "/pages/en/**");
|
||||
files.forEach(file => {
|
||||
const extension = path.extname(file);
|
||||
if (extension === ".js") {
|
||||
const ast = babylon.parse(fs.readFileSync(file, "utf8"), {
|
||||
plugins: ["jsx"]
|
||||
});
|
||||
traverse(ast, {
|
||||
enter(path) {
|
||||
if (
|
||||
path.node.type === "JSXElement" &&
|
||||
path.node.openingElement.name.name === "translate"
|
||||
) {
|
||||
const text = path.node.children[0].value.trim();
|
||||
let description = "no description given";
|
||||
const attributes = path.node.openingElement.attributes;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
if (attributes[i].name.name === "desc") {
|
||||
description = attributes[i].value.value;
|
||||
}
|
||||
}
|
||||
translations["pages-strings"][text + "|" + description] = text;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
writeFileAndCreateFolder(CWD + "/i18n/en.json", JSON.stringify(translations));
|
||||
}
|
||||
|
||||
execute();
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
"dependencies": {
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-register": "^6.24.1",
|
||||
"babel-traverse": "^6.25.0",
|
||||
"babylon": "^6.17.4",
|
||||
"classnames": "^2.2.5",
|
||||
"express": "^4.15.3",
|
||||
"fs-extra": "^3.0.1",
|
||||
|
|
@ -17,16 +19,13 @@
|
|||
"request": "^2.81.0",
|
||||
"shelljs": "^0.7.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1"
|
||||
},
|
||||
"name": "docusaurus",
|
||||
"version": "1.0.0-alpha.12",
|
||||
"bin": {
|
||||
"docusaurus-start": "./lib/start-server.js",
|
||||
"docusaurus-build": "./lib/build-files.js",
|
||||
"docusaurus-publish": "./lib/publish-gh-pages.js",
|
||||
"docusaurus-examples": "./lib/copy-examples.js"
|
||||
"docusaurus-examples": "./lib/copy-examples.js",
|
||||
"docusaurus-write-translations": "./lib/write-translations.js"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue