UNPKG

2.79 kBJavaScriptView Raw
1const React = require('react');
2const createClass = require('create-react-class');
3
4const reduce = (obj, fn, init)=>Object.keys(obj).reduce((acc, key)=>fn(acc, obj[key], key), init);
5const map = (obj, fn)=>Object.keys(obj).map((key)=>fn(obj[key], key));
6
7let Storage={meta:[], noscript : []};
8
9const mapProps = (props)=>map(props, (val, key)=>`${key}="${val}"`).join(' ');
10const processData = (data)=>{
11 return reduce(data, (acc, val, key)=>{
12 if(key == 'type') key = '@type';
13 if(key == 'context') key = '@context';
14 acc[key] = (typeof val == 'object'
15 ? processData(val)
16 : val
17 );
18 return acc;
19 }, {});
20};
21
22const HeadTags = {
23 Title : createClass({
24 componentWillMount(){ Storage.title = this.props.children; },
25 componentDidMount(){
26 if(typeof document !== 'undefined') document.title = this.props.children;
27 },
28 render(){ return null; }
29 }),
30 Favicon : createClass({
31 getDefaultProps(){ return { type : 'image/png', href : ''}},
32 componentWillMount(){ Storage.favicon = this.props; },
33 //TODO: Add abiltiy to dynamically modify favicon
34 render(){ return null; }
35 }),
36 Noscript : createClass({
37 componentWillMount(){ Storage.noscript.push(this.props.children); },
38 render(){ return null; }
39 }),
40 Meta : createClass({
41 componentWillMount(){ Storage.meta.push(this.props); },
42 render(){ return null; }
43 }),
44 Structured : createClass({
45 componentWillMount(){ Storage.structuredData = processData(this.props.data); },
46 render(){ return null; }
47 }),
48 Bulk : createClass({
49 componentWillMount(){
50 if(this.props.title) Storage.title = this.props.title;
51 if(this.props.favicon) Storage.favicon = this.props.favicon;
52 if(this.props.meta) Storage.meta = Storage.meta.concat(map(this.props.meta, (content, name)=>{return {content, name}}));
53 if(this.props.structuredData) Storage.structuredData = processData(this.props.structuredData);
54 },
55 componentDidMount(){
56 if(typeof document !== 'undefined' && this.props.title) document.title = this.props.title;
57 },
58 render(){ return null; }
59 }),
60 flush : ()=>Storage = {meta:[], noscript : []},
61 generate : ()=>{
62 let res = [];
63 if(Storage.title) res.push(`<title>${Storage.title}</title>`);
64 if(Storage.favicon) res.push(`<link rel='shortcut icon' type='${Storage.favicon.type}' href='${Storage.favicon.href}' />`);
65 if(Storage.meta && Storage.meta.length){
66 res = res.concat(Storage.meta.map((metaProps)=>`<meta ${mapProps(metaProps)} />`));
67 }
68 if(Storage.noscript && Storage.noscript.length){
69 res = res.concat(`<noscript>${Storage.noscript.join('\n')}</noscript>`);
70 }
71 if(Storage.structuredData){
72 res.push(`<script type='application/ld+json'>${JSON.stringify(Storage.structuredData, null, ' ')}</script>`);
73 }
74 HeadTags.flush();
75 return res.join('\n');
76 }
77};
78
79module.exports = HeadTags;
\No newline at end of file