1 |
|
2 |
|
3 | import React from 'react'
|
4 |
|
5 |
|
6 | import hoistStatics from 'hoist-non-react-statics'
|
7 |
|
8 | let currentMetaTags
|
9 | let everMounted = false
|
10 | let nodeCommentEnd
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | export default (funcGetPageInfo) => (WrappedComponent) => {
|
24 | const getInfo = (store, renderProps) => {
|
25 | if (typeof funcGetPageInfo !== 'function') return
|
26 |
|
27 | const state = store.getState()
|
28 | let infos = funcGetPageInfo(state, renderProps)
|
29 | if (typeof infos !== 'object') infos = {}
|
30 |
|
31 | const {
|
32 | title = '',
|
33 | metas = []
|
34 | } = infos
|
35 |
|
36 | if (state.localeId) {
|
37 | if (!metas.some(meta => {
|
38 | if (meta.name === 'koot-locale-id') {
|
39 | meta.content = state.localeId
|
40 | return true
|
41 | }
|
42 | return false
|
43 | })) {
|
44 | metas.push({
|
45 | name: 'koot-locale-id',
|
46 | content: state.localeId
|
47 | })
|
48 | }
|
49 | }
|
50 |
|
51 | return {
|
52 | title,
|
53 | metas
|
54 | }
|
55 | }
|
56 |
|
57 | class KootPage extends React.Component {
|
58 |
|
59 |
|
60 |
|
61 | static onServerRenderHtmlExtend = ({ store, renderProps = {} }) => {
|
62 | const infos = getInfo(store, renderProps)
|
63 | return{
|
64 | title: infos.title,
|
65 | metas: infos.metas
|
66 | }
|
67 | }
|
68 |
|
69 | updateInfo() {
|
70 | if (__SERVER__) return
|
71 |
|
72 | const infos = getInfo(Store, this.props)
|
73 |
|
74 |
|
75 | document.title = infos.title
|
76 |
|
77 |
|
78 | const head = document.getElementsByTagName('head')[0]
|
79 | if (!Array.isArray(currentMetaTags)) {
|
80 | currentMetaTags = []
|
81 |
|
82 |
|
83 | const childNodes = head.childNodes
|
84 | const nodesToRemove = []
|
85 | let meetStart = false
|
86 | let meetEnd = false
|
87 | let i = 0
|
88 | while (!meetEnd && childNodes[i] instanceof Node) {
|
89 | const node = childNodes[i]
|
90 | if (node.nodeType === Node.COMMENT_NODE) {
|
91 | if (node.nodeValue === __KOOT_INJECT_METAS_START__)
|
92 | meetStart = true
|
93 | if (node.nodeValue === __KOOT_INJECT_METAS_END__) {
|
94 | meetEnd = true
|
95 | nodeCommentEnd = node
|
96 | }
|
97 | } else if (meetStart && node.nodeType === Node.ELEMENT_NODE && node.tagName === 'META') {
|
98 | nodesToRemove.push(node)
|
99 | }
|
100 | i++
|
101 | }
|
102 | nodesToRemove.forEach(el => head.removeChild(el))
|
103 | }
|
104 |
|
105 | currentMetaTags.forEach(el => {
|
106 | if (el && el.parentNode)
|
107 | el.parentNode.removeChild(el)
|
108 | })
|
109 | currentMetaTags = infos.metas
|
110 | .filter(meta => typeof meta === 'object')
|
111 | .map(meta => {
|
112 | const el = document.createElement('meta')
|
113 | for (var key in meta) {
|
114 | el.setAttribute(key, meta[key])
|
115 | }
|
116 |
|
117 | if (nodeCommentEnd) {
|
118 | head.insertBefore(el, nodeCommentEnd)
|
119 | } else {
|
120 | head.appendChild(el)
|
121 | }
|
122 | return el
|
123 | })
|
124 | }
|
125 |
|
126 | componentDidUpdate(prevProps) {
|
127 | if (typeof prevProps.location === 'object' &&
|
128 | typeof this.props.location === 'object' &&
|
129 | prevProps.location.pathname !== this.props.location.pathname
|
130 | )
|
131 | this.updateInfo()
|
132 | }
|
133 |
|
134 | componentDidMount() {
|
135 | if (!everMounted) {
|
136 | everMounted = true
|
137 | return
|
138 | }
|
139 | this.updateInfo()
|
140 | }
|
141 |
|
142 | render = () => <WrappedComponent {...this.props} />
|
143 | }
|
144 |
|
145 | return hoistStatics(KootPage, WrappedComponent)
|
146 | }
|
147 |
|
\ | No newline at end of file |